1use crate::X25519PublicKey;
18use blake2::{Blake2b, Blake2b512, Digest};
19use codec::{Decode, Encode};
20
21pub const MEASUREMENT_VALUE_MOCK_QUOTE: [u8; 32] = [
26 91, 172, 96, 209, 130, 160, 167, 174, 152, 184, 193, 27, 88, 59, 117, 235, 74, 39, 194, 69,
27 147, 72, 129, 25, 224, 24, 189, 103, 224, 20, 107, 116,
28];
29
30pub struct QuoteInputData(pub [u8; 64]);
32
33impl QuoteInputData {
34 pub fn new<T: Encode>(
35 tss_account_id: T,
36 x25519_public_key: X25519PublicKey,
37 nonce: [u8; 32],
38 context: QuoteContext,
39 ) -> Self {
40 let mut hasher = Blake2b512::new();
41 hasher.update(tss_account_id.encode());
42 hasher.update(x25519_public_key);
43 hasher.update(nonce);
44 hasher.update(context.encode());
45 Self(hasher.finalize().into())
46 }
47}
48
49#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
51#[non_exhaustive]
52pub enum QuoteContext {
53 Validate,
55 ChangeEndpoint,
57 ChangeThresholdAccounts,
59 EncryptionKeyRecoveryRequest,
61}
62
63#[cfg(any(feature = "std", feature = "wasm"))]
64impl std::fmt::Display for QuoteContext {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 QuoteContext::Validate => write!(f, "validate"),
69 QuoteContext::ChangeEndpoint => write!(f, "change_endpoint"),
70 QuoteContext::ChangeThresholdAccounts => write!(f, "change_threshold_accounts"),
71 QuoteContext::EncryptionKeyRecoveryRequest => {
72 write!(f, "encryption_key_recovery_request")
73 },
74 }
75 }
76}
77
78#[cfg(feature = "wasm-no-std")]
79use sp_std::vec::Vec;
80
81#[cfg(not(feature = "wasm"))]
83pub trait AttestationHandler<AccountId> {
84 fn verify_quote(
88 attestee: &AccountId,
89 x25519_public_key: X25519PublicKey,
90 quote: Vec<u8>,
91 context: QuoteContext,
92 ) -> Result<crate::BoundedVecEncodedVerifyingKey, VerifyQuoteError>;
93
94 fn request_quote(attestee: &AccountId, nonce: [u8; 32]);
99}
100
101#[cfg(not(feature = "wasm"))]
103impl<AccountId> AttestationHandler<AccountId> for () {
104 fn verify_quote(
105 _attestee: &AccountId,
106 _x25519_public_key: X25519PublicKey,
107 _quote: Vec<u8>,
108 _context: QuoteContext,
109 ) -> Result<crate::BoundedVecEncodedVerifyingKey, VerifyQuoteError> {
110 Ok(crate::BoundedVecEncodedVerifyingKey::try_from([0; 33].to_vec()).unwrap())
111 }
112
113 fn request_quote(_attestee: &AccountId, _nonce: [u8; 32]) {}
114}
115
116#[cfg(not(feature = "wasm"))]
118#[derive(Debug, Eq, PartialEq)]
119pub enum VerifyQuoteError {
120 BadQuote,
122 UnexpectedAttestation,
124 IncorrectInputData,
126 BadMeasurementValue,
128 CannotEncodeVerifyingKey,
130 CannotDecodeVerifyingKey,
132 PckCertificateParse,
134 PckCertificateVerify,
136 PckCertificateBadPublicKey,
138 PckCertificateNoCertificate,
140}
141
142#[cfg(feature = "std")]
143impl std::fmt::Display for VerifyQuoteError {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 match self {
146 VerifyQuoteError::BadQuote => write!(f, "Quote could not be parsed of verified"),
147 VerifyQuoteError::UnexpectedAttestation => {
148 write!(f, "Attestation extrinsic submitted when not requested")
149 },
150 VerifyQuoteError::IncorrectInputData => {
151 write!(f, "Hashed input data does not match what was expected")
152 },
153 VerifyQuoteError::BadMeasurementValue => write!(f, "Unacceptable VM image running"),
154 VerifyQuoteError::CannotEncodeVerifyingKey => {
155 write!(f, "Cannot encode verifying key (PCK)")
156 },
157 VerifyQuoteError::CannotDecodeVerifyingKey => {
158 write!(f, "Cannot decode verifying key (PCK)")
159 },
160 VerifyQuoteError::PckCertificateParse => {
161 write!(f, "PCK certificate chain cannot be parsed")
162 },
163 VerifyQuoteError::PckCertificateVerify => {
164 write!(f, "PCK certificate chain cannot be verified")
165 },
166 VerifyQuoteError::PckCertificateBadPublicKey => {
167 write!(f, "PCK certificate chain public key is not well formed")
168 },
169 VerifyQuoteError::PckCertificateNoCertificate => {
170 write!(f, "PCK certificate could not be extracted from quote")
171 },
172 }
173 }
174}
175
176#[cfg(feature = "std")]
177impl std::error::Error for VerifyQuoteError {}
178
179#[cfg(feature = "production")]
181pub fn verify_pck_certificate_chain(
182 quote: &tdx_quote::Quote,
183) -> Result<tdx_quote::VerifyingKey, VerifyQuoteError> {
184 quote.verify().map_err(|_| VerifyQuoteError::PckCertificateVerify)
185}
186
187#[cfg(not(any(feature = "production", feature = "wasm")))]
191pub fn verify_pck_certificate_chain(
192 quote: &tdx_quote::Quote,
193) -> Result<tdx_quote::VerifyingKey, VerifyQuoteError> {
194 let provisioning_certification_key =
195 quote.pck_cert_chain().map_err(|_| VerifyQuoteError::PckCertificateNoCertificate)?;
196 let provisioning_certification_key = tdx_quote::decode_verifying_key(
197 &provisioning_certification_key
198 .try_into()
199 .map_err(|_| VerifyQuoteError::CannotDecodeVerifyingKey)?,
200 )
201 .map_err(|_| VerifyQuoteError::CannotDecodeVerifyingKey)?;
202
203 quote
204 .verify_with_pck(&provisioning_certification_key)
205 .map_err(|_| VerifyQuoteError::PckCertificateVerify)?;
206 Ok(provisioning_certification_key)
207}
208
209pub fn compute_quote_measurement(quote: &tdx_quote::Quote) -> [u8; 32] {
211 let mut hasher = Blake2b::new();
212 hasher.update(quote.mrtd());
213 hasher.update(quote.rtmr0());
214 hasher.update(quote.rtmr1());
215 hasher.update(quote.rtmr2());
216 hasher.update(quote.rtmr3());
217 hasher.finalize().into()
218}