diff --git a/Cargo.toml b/Cargo.toml index f993af6..e1beeee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,6 @@ members = [ "crates/quote-verifier", "crates/pcs", "crates/collaterals", + "./livyimpl", ] exclude = ["zkvm/risc0", "zkvm/risc0/guest"] diff --git a/crates/pcs/src/client.rs b/crates/pcs/src/client.rs index 2adf0db..cf639f9 100644 --- a/crates/pcs/src/client.rs +++ b/crates/pcs/src/client.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, bail, Error}; use dcap_quote_verifier::cert::{ - is_sgx_pck_platform_ca_dn, is_sgx_pck_processor_ca_dn, parse_certchain, + is_sgx_pck_platform_ca_dn, is_sgx_pck_processor_ca_dn, parse_certchain, parse_der_certchain, }; use dcap_quote_verifier::collateral::QvCollateral; use dcap_quote_verifier::sgx_extensions::extract_sgx_extensions; @@ -66,21 +66,29 @@ impl PCSClient { } else { format!("{pcs_url}/tdx/certification/v4") }; - if qe_cert_data.cert_data_type != 5 { - bail!("QE Cert Type must be 5".to_string()); + if ![4, 5].contains(&qe_cert_data.cert_data_type) { + bail!("QE Cert Type must be 4 or 5".to_string()); } - let certchain_pems = parse_pem(&qe_cert_data.cert_data) - .map_err(|e| anyhow!("cannot parse QE cert chain: {}", e))?; + + let certchain = if qe_cert_data.cert_data_type == 5 { + // Type 5: PEM format + let certchain_pems = parse_pem(&qe_cert_data.cert_data) + .map_err(|e| anyhow!("cannot parse QE cert chain: {}", e))?; + parse_certchain(&certchain_pems) + .map_err(|e| anyhow!("cannot parse QE cert chain: {}", e))? + } else { + // Type 4: DER format + parse_der_certchain(&qe_cert_data.cert_data) + .map_err(|e| anyhow!("cannot parse QE cert chain: {}", e))? + }; - let certchain = parse_certchain(&certchain_pems) - .map_err(|e| anyhow!("cannot parse QE cert chain: {}", e))?; if certchain.len() != 3 { bail!("QE Cert chain must have 3 certs".to_string()); } // get the pck certificate - let pck_cert = &certchain[0]; - let pck_cert_issuer = &certchain[1]; + let pck_cert = certchain[0].as_x509(); + let pck_cert_issuer = certchain[1].as_x509(); // get the SGX extension let sgx_extensions = extract_sgx_extensions(pck_cert) diff --git a/crates/quote-verifier/Cargo.toml b/crates/quote-verifier/Cargo.toml index f63615f..d407b03 100644 --- a/crates/quote-verifier/Cargo.toml +++ b/crates/quote-verifier/Cargo.toml @@ -19,9 +19,12 @@ sha3 = { version = "0.10.8" } alloy-sol-types = { version = "0.8.12" } dcap-types = { path = "../types" } + [features] default = [] [dev-dependencies] serde_json = { version = "1.0", features = ["preserve_order"] } dcap-collaterals = { path = "../collaterals" } +dcap-pcs = { path = "../pcs" } +chrono = "0.4.41" diff --git a/crates/quote-verifier/src/cert.rs b/crates/quote-verifier/src/cert.rs index f752348..f86bdcb 100644 --- a/crates/quote-verifier/src/cert.rs +++ b/crates/quote-verifier/src/cert.rs @@ -60,12 +60,62 @@ impl BitAnd for KeyUsageFlags { } } +#[derive(Clone, Debug)] +pub struct OwnedX509Certificate { + der: Vec, + cert: X509Certificate<'static>, +} + +impl OwnedX509Certificate { + pub fn new(der: &[u8]) -> crate::Result { + let (rest, cert) = X509Certificate::from_der(der)?; + if !rest.is_empty() { + bail!("Extra data after certificate"); + } + let owned_cert = unsafe { std::mem::transmute::>(cert) }; + Ok(Self { + der: der.to_vec(), + cert: owned_cert, + }) + } + + pub fn as_x509(&self) -> &X509Certificate<'static> { + &self.cert + } +} + /// Parse a PEM-encoded certificate chain into a vector of `X509Certificate`. -pub fn parse_certchain(pem_certs: &[Pem]) -> crate::Result> { - Ok(pem_certs +pub fn parse_certchain(pem_certs: &[Pem]) -> crate::Result> { + pem_certs .iter() - .map(|pem| pem.parse_x509()) - .collect::>()?) + .map(|pem| OwnedX509Certificate::new(&pem.contents)) + .collect::>() +} + +/// Parse a DER-encoded certificate chain into a vector of `X509Certificate`. +/// This is used for Type 4 certificates which contain concatenated DER certificates. +pub fn parse_der_certchain(der_data: &[u8]) -> crate::Result> { + let mut certs = Vec::new(); + let mut remaining = der_data; + + while !remaining.is_empty() { + match OwnedX509Certificate::new(remaining) { + Ok(owned_cert) => { + let len = owned_cert.der.len(); + certs.push(owned_cert); + remaining = &remaining[len..]; + } + Err(_) => { + break; + } + } + } + + if certs.is_empty() { + bail!("No valid certificates found in DER data"); + } + + Ok(certs) } /// Verifies the signature of a certificate using the public key of the signer certificate. diff --git a/crates/quote-verifier/src/quotes.rs b/crates/quote-verifier/src/quotes.rs index c89fea5..8cc98bb 100644 --- a/crates/quote-verifier/src/quotes.rs +++ b/crates/quote-verifier/src/quotes.rs @@ -1,7 +1,7 @@ pub mod version_3; pub mod version_4; -use crate::cert::{parse_certchain, verify_crl_signature}; +use crate::cert::{parse_certchain, parse_der_certchain, verify_crl_signature}; use crate::collateral::QvCollateral; use crate::crl::IntelSgxCrls; use crate::crypto::{sha256sum, verify_p256_signature_bytes}; @@ -24,6 +24,7 @@ use dcap_types::EnclaveIdentityV2TcbStatus; use version_3::verify_quote_v3; use version_4::verify_quote_v4; use x509_parser::certificate::X509Certificate; +use dcap_types::quotes::QeReportCertData; /// Verify the quote with the given collateral data and return the verification output. /// @@ -93,23 +94,58 @@ fn verify_quote_common( current_time: u64, ) -> Result<(QeTcb, SgxExtensions, TcbInfo, Validity)> { // get the certchain embedded in the ecda quote signature data - // this can be one of 5 types, and we only support type 5 + // this can be one of 5 types, and we support types 4 and 5 // https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/aa239d25a437a28f3f4de92c38f5b6809faac842/QuoteGeneration/quote_wrapper/common/inc/sgx_quote_3.h#L63C4-L63C112 - if qe_cert_data.cert_data_type != 5 { - bail!("QE Cert Type must be 5"); + if ![4, 5].contains(&qe_cert_data.cert_data_type) { + bail!("QE Cert Type must be 4 or 5"); } - let certchain_pems = parse_pem(&qe_cert_data.cert_data)?; - let (pck_leaf_cert, pck_issuer_cert) = { - let mut certchain = parse_certchain(&certchain_pems)?; - // certchain in the cert_data whose type is 5 should have 3 certificates: - // PCK leaf, PCK issuer, and Root CA - if certchain.len() != 3 { - bail!("Invalid Certchain length"); + + // Update the parsing logic to handle type 6 recursively + + let (pck_leaf_cert, pck_issuer_cert) = match qe_cert_data.cert_data_type { + 5 => { + // Type 5: PEM format + let certchain_pems = parse_pem(&qe_cert_data.cert_data)?; + let certchain = parse_certchain(&certchain_pems)?; + if certchain.len() != 3 { + bail!("Invalid Certchain length for Type 5"); + } + (certchain[0].clone(), certchain[1].clone()) + } + 4 => { + // Type 4: DER format + let certchain = parse_der_certchain(&qe_cert_data.cert_data)?; + if certchain.len() != 3 { + bail!("Invalid Certchain length for Type 4"); + } + (certchain[0].clone(), certchain[1].clone()) } - // extract the leaf and issuer certificates, but ignore the root cert as we already have it - (certchain.remove(0), certchain.remove(0)) + 6 => { + // Type 6: QeReportCertData - recursive parsing + let qe_report_cert_data = QeReportCertData::from_bytes(&qe_cert_data.cert_data)?; + // Recursively parse the nested cert_data + let nested_cert_type = qe_report_cert_data.qe_cert_data.cert_data_type; + if ![4, 5].contains(&nested_cert_type) { + bail!("Nested QE Cert Type in Type 6 must be 4 or 5"); + } + let nested_cert_data = &qe_report_cert_data.qe_cert_data.cert_data; + let certchain = if nested_cert_type == 5 { + let certchain_pems = parse_pem(nested_cert_data)?; + parse_certchain(&certchain_pems)? + } else { + parse_der_certchain(nested_cert_data)? + }; + if certchain.len() != 3 { + bail!("Invalid Certchain length for Type 6"); + } + (certchain[0].clone(), certchain[1].clone()) + } + _ => bail!("QE Cert Type must be 4, 5, or 6"), }; + let pck_leaf_cert = pck_leaf_cert.as_x509(); + let pck_issuer_cert = pck_issuer_cert.as_x509(); + let intel_sgx_root_cert = collateral.get_sgx_intel_root_ca()?; let intel_crls = { let sgx_root_ca_crl = collateral.get_sgx_intel_root_ca_crl()?; diff --git a/crates/quote-verifier/src/quotes/livyquotes/livy.json b/crates/quote-verifier/src/quotes/livyquotes/livy.json new file mode 100644 index 0000000..250083d --- /dev/null +++ b/crates/quote-verifier/src/quotes/livyquotes/livy.json @@ -0,0 +1 @@ +{"quote":"040002008100000000000000939a7233f79c4ca9940a0db3957f0607ac666ed993e70e31ff5f5a8a2c743b220000000007010300000000000000000000000000c51e5cb16c461fe29b60394984755325ecd05a9a7a8fb3a116f1c3cf0aca4b0eb9edefb9b404deeaee4b7d454372d17a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000702000000000000c68518a0ebb42136c12b2275164f8c72f25fa9a34392228687ed6e9caeb9c0f1dbd895e9cf475121c029dc47e70e91fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000079207fa707c5bbf697d579bbd44c2ba14f8565d528aff0de407c58fd34815b67a35cfbb0a0d996b1c7b911a2c8ae806c4a7db64a609c77e85f603c23e9a9fd03bfd9e6b52ce527f774a598e66d58386026cea79b2aea13b81a0b70cfacdec0ca8a4fe048fea22663152ef128853caa5c033cbe66baf32ba1ff7f6b1afc1624c279f50a4cbc522a735ca6f69551e61ef2b7bb6ea0e8bbb639fde4a333160c387a40bf62033fc9e02735d740297ae3216118200a6e27f3a07e6b44c8bae69bc63d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064656661756c742d757365722d64617461cc10000021022ffae1d84aecc81437001c44351399f64adf5b9522a3b788e5ee6aeb5865282a9524f2b4b93761202211cb3416ad4fb542cae828cbd55f5b979001244356e6bcb0c5f4b03f0563c797747f7ddd25d92d4f120bee4a829daca986bbc03c155b3d158f6a386bca7ee49ceb3ec31494b792e0cf22fc4e561ddc57156da1b77a0600461000000303070704ff00020000000000000000000000000000000000000000000000000000000000000000000000000000000015000000000000000700000000000000e5a3a7b5d830c2953b98534c6c59a3a34fdc34e933f7f5898f0a85cf08846bca0000000000000000000000000000000000000000000000000000000000000000dc9e2a7c6f948f17474e34a7fc43ed030f7c1563f1babddf6340c82e0e54a8c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005d2eb8ae211693884eadaea0be0392c5532c7ff55429e4696c84954444d62ed60000000000000000000000000000000000000000000000000000000000000000a95ac16978553ab5849837fcca4151a3138852c782df5f665b3ad12ff015d9a0ac6140698cf0a178ff5aa2ec063772dfe8a0bd33c497f58e5e5912ee02406cc82000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f05005e0e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d49494538544343424a656741774942416749554439426b736e734170713045567861464a59785a56794f6774664d77436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a55774d6a41334d5463774f4441325768634e4d7a49774d6a41334d5463774f4441320a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424853770a3977506a72554532734f4a644c5653415434686565414a572b31796c6473615556696b5a4c485832506235777374326a79697539414f5865576a7a6a6d585a4c0a4343742b457858716f53394e45476c6b52724b6a67674d4e4d4949444354416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464d6a464e59626f7464634b636859487258467966774b460a774e534d4d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f67594a4b6f5a496876684e415130420a424949434b7a4343416963774867594b4b6f5a496876684e41513042415151514134346b35686a336951797044574873756f5a474144434341575147436971470a534962345451454e41514977676746554d42414743797147534962345451454e41514942416745434d42414743797147534962345451454e41514943416745430a4d42414743797147534962345451454e41514944416745434d42414743797147534962345451454e41514945416745434d42414743797147534962345451454e0a41514946416745434d42454743797147534962345451454e41514947416749412f7a415142677371686b69472b453042445145434277494241444151426773710a686b69472b4530424451454343414942416a415142677371686b69472b45304244514543435149424144415142677371686b69472b45304244514543436749420a4144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69472b4530420a44514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b453042445145434477494241444151426773710a686b69472b45304244514543454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b45304244514543456751510a4167494341674c2f4141494141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b453042445145450a424159676f473841414141774477594b4b6f5a496876684e4151304242516f424154416542676f71686b69472b453042445145474242414b496f456755387a650a486d2b49596f7a686c337a314d45514743697147534962345451454e415163774e6a415142677371686b69472b45304244514548415145422f7a4151426773710a686b69472b45304244514548416745422f7a415142677371686b69472b45304244514548417745422f7a414b42676771686b6a4f5051514441674e49414442460a4169417362735a44796d2f72455a30476c454c62442f6e64755061536a485341746e5871567453313047486255774968414d585666784b334b666f4b675131660a4578397478765331314362363662323467424344523963477942562b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","eventLog":"[{\"imr\":0,\"event_type\":2147483659,\"digest\":\"02a008e63d55a77823c04a5513a5810d4e592dc41bf2596267c09eae5d4b4e3b329ae614973fb192297d8833d37a08fd\",\"event\":\"\",\"event_payload\":\"095464785461626c65000100000000000000af96bb93f2b9b84e9462e0ba745642360090800000000000\"},{\"imr\":0,\"event_type\":2147483658,\"digest\":\"344bc51c980ba621aaa00da3ed7436f7d6e549197dfe699515dfa2c6583d95e6412af21c097d473155875ffd561d6790\",\"event\":\"\",\"event_payload\":\"2946762858585858585858582d585858582d585858582d585858582d58585858585858585858585829000000c0ff000000000040080000000000\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"9dc3a1f80bcec915391dcda5ffbb15e7419f77eab462bbf72b42166fb70d50325e37b36f93537a863769bcf9bedae6fb\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0a00000000000000000000000000000053006500630075007200650042006f006f007400\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"6f2e3cbc14f9def86980f5f66fd85e99d63e69a73014ed8a5633ce56eca5b64b692108c56110e22acadcef58c3250f1b\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0200000000000000000000000000000050004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"d607c0efb41c0d757d69bca0615c3a9ac0b1db06c557d992e906c6b7dee40e0e031640c7bfd7bcd35844ef9edeadc6f9\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c030000000000000000000000000000004b0045004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"08a74f8963b337acb6c93682f934496373679dd26af1089cb4eaf0c30cf260a12e814856385ab8843e56a9acea19e127\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f0200000000000000000000000000000064006200\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"18cc6e01f0c6ea99aa23f8a280423e94ad81d96d0aeb5180504fc0f7a40cb3619dd39bd6a95ec1680a86ed6ab0f9828d\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f03000000000000000000000000000000640062007800\"},{\"imr\":0,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":0,\"event_type\":10,\"digest\":\"142aa9710a7187d649bfafab0a4226e554859c7fb0cd3e6707f31291e332e399b4ae8f851876ef0af8e607a59b60cc8e\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"07d867a2ead8d8e3b1240f17e461089b819ab63ac34eff3b29459445c67409c2342dfdc9335d2335a5aaf591fe1483e1\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"da8447b3b4ae0110934f6b7fb9cb017962243eb62e3a971243fde4fd878f26f6ead8e59eba4a1a5b2211a5073cd66506\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":1,\"event_type\":2147483651,\"digest\":\"f51c5215e1ae1e5202fb0a710248e13c2bf2824b7f0b2a1675f63e9fd37befb93fbb97a4f8630879168b76aee3b198e2\",\"event\":\"\",\"event_payload\":\"18e0437b0000000000f4b2000000000000000000000000002a000000000000000403140072f728144ab61e44b8c39ebdd7f893c7040412006b00650072006e0065006c0000007fff0400\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"1dd6f7b457ad880d840d41c961283bab688e94e4b59359ea45686581e90feccea3c624b1226113f824f315eb60ae0a7c\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0900000000000000020000000000000042006f006f0074004f0072006400650072000000\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"23ada07f5261f12f34a0bd8e46760962d6b4d576a416f1fea1c64bc656b1d28eacf7047ae6e967c58fd2a98bfa74c298\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c08000000000000003e0000000000000042006f006f0074003000300030003000090100002c0055006900410070007000000004071400c9bdb87cebf8344faaea3ee4af6516a10406140021aa2c4614760345836e8ab6f46623317fff0400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"77a0dab2312b4e1e57a84d865a21e5b2ee8d677a21012ada819d0a98988078d3d740f6346bfe0abaa938ca20439a8d71\",\"event\":\"\",\"event_payload\":\"43616c6c696e6720454649204170706c69636174696f6e2066726f6d20426f6f74204f7074696f6e\"},{\"imr\":1,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":2,\"event_type\":6,\"digest\":\"a68ac6d65dd62f392826c2ae44f6846363ced3418c96574b3e168de9205c8553b8198c3b9d206bc432d70a923c25b098\",\"event\":\"\",\"event_payload\":\"ed223b8f1a0000004c4f414445445f494d4147453a3a4c6f61644f7074696f6e7300\"},{\"imr\":2,\"event_type\":6,\"digest\":\"21a1d39f7395e15c35b91dacf14714cf2e9ead77e69f076ce164798272c1838312b2d82b3307b91929a4d7dbc6f1e48b\",\"event\":\"\",\"event_payload\":\"ec223b8f0d0000004c696e757820696e6974726400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0\",\"event\":\"\",\"event_payload\":\"4578697420426f6f7420536572766963657320496e766f636174696f6e\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74\",\"event\":\"\",\"event_payload\":\"4578697420426f6f742053657276696365732052657475726e656420776974682053756363657373\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"738ae348dbf674b3399300c0b9416c203e9b645c6ffee233035d09003cccad12f71becc805ad8d97575bc790c6819216\",\"event\":\"rootfs-hash\",\"event_payload\":\"4a89dadfa8c6be6d312beb51e24ef5bd4b3aeb695f11f4e2ff9c87eac907389b\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"2c2e7b4c9f231cb9a1aecae00a1e9ed524bf1351c2561f20c9944a2d111b675e396184ce4261b183ee4d6f2ae7365d64\",\"event\":\"app-id\",\"event_payload\":\"53e12e9b2ae22b96423490687f1edfc3adc20a26\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"7d51b2be4596726038708130a1448ca8799e526b96d1338794ef91ccbc134a271bcdc18a69713c921b2dcc17fc1065a8\",\"event\":\"compose-hash\",\"event_payload\":\"2f5a71531a8c96da1d8a4b583abcf06564832f590df1080bcf9804d181917dc4\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"5b6a576d1da40f04179ad469e00f90a1c0044bc9e8472d0da2776acb108dc98a73560d42cea6b8b763eb4a0e6d4d82d5\",\"event\":\"ca-cert-hash\",\"event_payload\":\"d2d9c7c29e3f18e69cba87438cef21eea084c2110858230cd39c5decc629a958\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"c049d2b83a781e72277a32b2353ca7001a173e00c1f6420ccc0f0c1cbfc71c7310e4ac678492d864cbbc62f4b438f5e1\",\"event\":\"instance-id\",\"event_payload\":\"5f54745f28d778352511bb3c8c422a1e25160dae\"}]","rtmrs":["79207fa707c5bbf697d579bbd44c2ba14f8565d528aff0de407c58fd34815b67a35cfbb0a0d996b1c7b911a2c8ae806c","4a7db64a609c77e85f603c23e9a9fd03bfd9e6b52ce527f774a598e66d58386026cea79b2aea13b81a0b70cfacdec0ca","8a4fe048fea22663152ef128853caa5c033cbe66baf32ba1ff7f6b1afc1624c279f50a4cbc522a735ca6f69551e61ef2","b7bb6ea0e8bbb639fde4a333160c387a40bf62033fc9e02735d740297ae3216118200a6e27f3a07e6b44c8bae69bc63d"]} \ No newline at end of file diff --git a/crates/quote-verifier/src/quotes/version_4.rs b/crates/quote-verifier/src/quotes/version_4.rs index 9c9ebf8..5eb3831 100644 --- a/crates/quote-verifier/src/quotes/version_4.rs +++ b/crates/quote-verifier/src/quotes/version_4.rs @@ -145,6 +145,8 @@ fn validate_quote_header_v4(quote_header: &QuoteHeader) -> Result<()> { mod tests { use super::*; use dcap_types::utils::pem_to_der; + use chrono::Utc; + use dcap_pcs::client::PCSClient; #[test] fn test_verify_quote_v4_intel() { @@ -179,4 +181,29 @@ mod tests { let vo = res.unwrap(); assert_eq!(verified_output, vo); } + + #[test] + fn test_livy_quote_v4() { + #[derive(serde::Deserialize)] + struct LivyAttestation { + quote: String, + } + + let attestation: LivyAttestation = serde_json::from_str(&include_str!("./livyquotes/livy.json")).unwrap(); + let hex_quote = hex::decode(attestation.quote).unwrap(); + let quote = QuoteV4::from_bytes(&hex_quote).unwrap().0; + let raw_collateral = PCSClient::default().get_collateral(false, "e.signature.qe_cert_data).unwrap(); + let collaterals = QvCollateral { + tcb_info_json: raw_collateral.tcb_info_json, + qe_identity_json: raw_collateral.qe_identity_json, + sgx_intel_root_ca_der: raw_collateral.sgx_intel_root_ca_der, + sgx_tcb_signing_der: raw_collateral.sgx_tcb_signing_der, + sgx_intel_root_ca_crl_der: raw_collateral.sgx_intel_root_ca_crl_der, + sgx_pck_crl_der: raw_collateral.sgx_pck_crl_der, + }; + + let current_time = Utc::now().timestamp().try_into().unwrap(); + let res = verify_quote_v4("e, &collaterals, current_time); + assert!(res.is_ok(), "{:?}", res); + } } diff --git a/livyimpl/Cargo.toml b/livyimpl/Cargo.toml new file mode 100644 index 0000000..7385e33 --- /dev/null +++ b/livyimpl/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "livyimpl" +version = "0.1.0" +edition = "2021" + +[dependencies] +dcap-types = { path = "../crates/types" } +dcap-quote-verifier = { path = "../crates/quote-verifier" } +dcap-pcs = { path = "../crates/pcs" } +dcap-collaterals = { path = "../crates/collaterals" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +hex = "0.4" +chrono = "0.4" +anyhow = "1" +tokio = { version = "1.0", features = ["full"] } +dcap-qvl = "0.3.2" +pem = "3.0" +rustls-webpki = "0.102.8" +base64 = "0.22.1" + + + + +[[bin]] +name = "livyimpl" +path = "src/main.rs" diff --git a/livyimpl/TrustedRootCA.der b/livyimpl/TrustedRootCA.der new file mode 100644 index 0000000..768806c Binary files /dev/null and b/livyimpl/TrustedRootCA.der differ diff --git a/livyimpl/src/main.rs b/livyimpl/src/main.rs new file mode 100644 index 0000000..411eaa0 --- /dev/null +++ b/livyimpl/src/main.rs @@ -0,0 +1,83 @@ +use dcap_quote_verifier::{ + collateral::QvCollateral, + quotes::version_4::verify_quote_v4, +}; +use dcap_types::quotes::version_4::QuoteV4; +use serde::Deserialize; +use chrono::Utc; +use dcap_pcs::client::PCSClient; +use anyhow::Context; + +#[derive(Deserialize)] +struct LivyAttestation { + quote: String, +} + +fn main() -> Result<(), Box> { + println!("Testing Livy Quote V4 verification..."); + + // Load the livy quote from the JSON file + let attestation: LivyAttestation = serde_json::from_str( + include_str!("../../crates/quote-verifier/src/quotes/livyquotes/livy.json") + )?; + + // Decode the hex quote + let hex_quote = hex::decode(&attestation.quote)?; + let quote = QuoteV4::from_bytes(&hex_quote)?.0; + + println!("Quote parsed successfully"); + println!("Quote header version: {}", quote.header.version); + println!("Quote header TEE type: {}", quote.header.tee_type); + println!("Quote header att key type: {}", quote.header.att_key_type); + println!("Quote header QE vendor ID: {:?}", quote.header.qe_vendor_id); + println!("Quote cert data type: {}", quote.signature.qe_cert_data.cert_data_type); + + // Get collateral using PCSClient (same as working test) + let raw_collateral = PCSClient::default().get_collateral(false, "e.signature.qe_cert_data)?; + + println!("Quote Collateral tcb info: {:?}", raw_collateral.tcb_info_json); + println!("QE Identity: {:?}", raw_collateral.qe_identity_json); + + // Use the collateral directly (no transformation needed) + let collateral = QvCollateral { + tcb_info_json: raw_collateral.tcb_info_json, + qe_identity_json: raw_collateral.qe_identity_json, + sgx_intel_root_ca_der: raw_collateral.sgx_intel_root_ca_der, + sgx_tcb_signing_der: raw_collateral.sgx_tcb_signing_der, + sgx_intel_root_ca_crl_der: raw_collateral.sgx_intel_root_ca_crl_der, + sgx_pck_crl_der: raw_collateral.sgx_pck_crl_der, + }; + + println!("Collateral created successfully"); + println!("Root CA DER length: {}", collateral.sgx_intel_root_ca_der.len()); + println!("TCB signing cert length: {}", collateral.sgx_tcb_signing_der.len()); + + // Get current timestamp + let current_time = Utc::now().timestamp().try_into()?; + + // Verify the quote + let res = verify_quote_v4("e, &collateral, current_time); + + if res.is_ok() { + println!("Quote verification successful!"); + let output = res.unwrap(); + println!("Status: {:?}", output.status); + println!("TEE Type: {:?}", output.tee_type); + } else { + println!("Quote verification failed: {:?}", res.err()); + } + + Ok(()) +} + +pub fn extract_raw_certs(cert_chain: &[u8]) -> Result>, Box> { + Ok(pem::parse_many(cert_chain) + .context("Failed to parse certs")? + .iter() + .map(|i| i.contents().to_vec()) + .collect()) +} + +pub fn extract_certs<'a>(cert_chain: &'a [u8]) -> Result>, Box> { + extract_raw_certs(cert_chain) +} diff --git a/zkvm/risc0/artifacts/dcap-quote-verifier b/zkvm/risc0/artifacts/dcap-quote-verifier index f46e176..d7775d2 100644 Binary files a/zkvm/risc0/artifacts/dcap-quote-verifier and b/zkvm/risc0/artifacts/dcap-quote-verifier differ diff --git a/zkvm/risc0/src/methods.rs b/zkvm/risc0/src/methods.rs index 22ec83c..267f6b0 100644 --- a/zkvm/risc0/src/methods.rs +++ b/zkvm/risc0/src/methods.rs @@ -1,4 +1,4 @@ -pub const DCAP_QUOTE_VERIFIER_ID: [u32; 8] = [1519563173, 766144868, 376996947, 1575798712, 1430650633, 1722721411, 708861073, 2650936882]; -pub const DCAP_QUOTE_VERIFIER_ID_STR: &str = "a5b1925a6471aa2d53847816b8c7ec5d09ff455583a4ae66915c402a3216029e"; +pub const DCAP_QUOTE_VERIFIER_ID: [u32; 8] = [117788011, 3653947158, 2684564209, 296244330, 1777556421, 2743419902, 3558065736, 916374292]; +pub const DCAP_QUOTE_VERIFIER_ID_STR: &str = "6b4d050716cfcad9f13203a06a54a811c55bf369fe4385a348c613d414c39e36"; pub const DCAP_QUOTE_VERIFIER_ELF: &[u8] = include_bytes!("../artifacts/dcap-quote-verifier");