use crate::X25519PublicKey;
use blake2::{Blake2b, Blake2b512, Digest};
use codec::{Decode, Encode};
pub const MEASUREMENT_VALUE_MOCK_QUOTE: [u8; 32] = [
91, 172, 96, 209, 130, 160, 167, 174, 152, 184, 193, 27, 88, 59, 117, 235, 74, 39, 194, 69,
147, 72, 129, 25, 224, 24, 189, 103, 224, 20, 107, 116,
];
pub struct QuoteInputData(pub [u8; 64]);
impl QuoteInputData {
pub fn new<T: Encode>(
tss_account_id: T,
x25519_public_key: X25519PublicKey,
nonce: [u8; 32],
context: QuoteContext,
) -> Self {
let mut hasher = Blake2b512::new();
hasher.update(tss_account_id.encode());
hasher.update(x25519_public_key);
hasher.update(nonce);
hasher.update(context.encode());
Self(hasher.finalize().into())
}
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum QuoteContext {
Validate,
ChangeEndpoint,
ChangeThresholdAccounts,
EncryptionKeyRecoveryRequest,
}
#[cfg(any(feature = "std", feature = "wasm"))]
impl std::fmt::Display for QuoteContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
QuoteContext::Validate => write!(f, "validate"),
QuoteContext::ChangeEndpoint => write!(f, "change_endpoint"),
QuoteContext::ChangeThresholdAccounts => write!(f, "change_threshold_accounts"),
QuoteContext::EncryptionKeyRecoveryRequest => {
write!(f, "encryption_key_recovery_request")
},
}
}
}
#[cfg(feature = "wasm-no-std")]
use sp_std::vec::Vec;
#[cfg(not(feature = "wasm"))]
pub trait AttestationHandler<AccountId> {
fn verify_quote(
attestee: &AccountId,
x25519_public_key: X25519PublicKey,
quote: Vec<u8>,
context: QuoteContext,
) -> Result<crate::BoundedVecEncodedVerifyingKey, VerifyQuoteError>;
fn request_quote(attestee: &AccountId, nonce: [u8; 32]);
}
#[cfg(not(feature = "wasm"))]
impl<AccountId> AttestationHandler<AccountId> for () {
fn verify_quote(
_attestee: &AccountId,
_x25519_public_key: X25519PublicKey,
_quote: Vec<u8>,
_context: QuoteContext,
) -> Result<crate::BoundedVecEncodedVerifyingKey, VerifyQuoteError> {
Ok(crate::BoundedVecEncodedVerifyingKey::try_from([0; 33].to_vec()).unwrap())
}
fn request_quote(_attestee: &AccountId, _nonce: [u8; 32]) {}
}
#[cfg(not(feature = "wasm"))]
#[derive(Debug, Eq, PartialEq)]
pub enum VerifyQuoteError {
BadQuote,
UnexpectedAttestation,
IncorrectInputData,
BadMeasurementValue,
CannotEncodeVerifyingKey,
CannotDecodeVerifyingKey,
PckCertificateParse,
PckCertificateVerify,
PckCertificateBadPublicKey,
PckCertificateNoCertificate,
}
#[cfg(feature = "std")]
impl std::fmt::Display for VerifyQuoteError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VerifyQuoteError::BadQuote => write!(f, "Quote could not be parsed of verified"),
VerifyQuoteError::UnexpectedAttestation => {
write!(f, "Attestation extrinsic submitted when not requested")
},
VerifyQuoteError::IncorrectInputData => {
write!(f, "Hashed input data does not match what was expected")
},
VerifyQuoteError::BadMeasurementValue => write!(f, "Unacceptable VM image running"),
VerifyQuoteError::CannotEncodeVerifyingKey => {
write!(f, "Cannot encode verifying key (PCK)")
},
VerifyQuoteError::CannotDecodeVerifyingKey => {
write!(f, "Cannot decode verifying key (PCK)")
},
VerifyQuoteError::PckCertificateParse => {
write!(f, "PCK certificate chain cannot be parsed")
},
VerifyQuoteError::PckCertificateVerify => {
write!(f, "PCK certificate chain cannot be verified")
},
VerifyQuoteError::PckCertificateBadPublicKey => {
write!(f, "PCK certificate chain public key is not well formed")
},
VerifyQuoteError::PckCertificateNoCertificate => {
write!(f, "PCK certificate could not be extracted from quote")
},
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for VerifyQuoteError {}
#[cfg(feature = "production")]
pub fn verify_pck_certificate_chain(
quote: &tdx_quote::Quote,
) -> Result<tdx_quote::VerifyingKey, VerifyQuoteError> {
quote.verify().map_err(|_| VerifyQuoteError::PckCertificateVerify)
}
#[cfg(not(any(feature = "production", feature = "wasm")))]
pub fn verify_pck_certificate_chain(
quote: &tdx_quote::Quote,
) -> Result<tdx_quote::VerifyingKey, VerifyQuoteError> {
let provisioning_certification_key =
quote.pck_cert_chain().map_err(|_| VerifyQuoteError::PckCertificateNoCertificate)?;
let provisioning_certification_key = tdx_quote::decode_verifying_key(
&provisioning_certification_key
.try_into()
.map_err(|_| VerifyQuoteError::CannotDecodeVerifyingKey)?,
)
.map_err(|_| VerifyQuoteError::CannotDecodeVerifyingKey)?;
quote
.verify_with_pck(&provisioning_certification_key)
.map_err(|_| VerifyQuoteError::PckCertificateVerify)?;
Ok(provisioning_certification_key)
}
pub fn compute_quote_measurement(quote: &tdx_quote::Quote) -> [u8; 32] {
let mut hasher = Blake2b::new();
hasher.update(quote.mrtd());
hasher.update(quote.rtmr0());
hasher.update(quote.rtmr1());
hasher.update(quote.rtmr2());
hasher.update(quote.rtmr3());
hasher.finalize().into()
}