diff --git a/spdmlib/src/crypto/x509v3.rs b/spdmlib/src/crypto/x509v3.rs index 042c544..08e6bd7 100644 --- a/spdmlib/src/crypto/x509v3.rs +++ b/spdmlib/src/crypto/x509v3.rs @@ -631,6 +631,82 @@ pub fn is_root_certificate(cert: &[u8]) -> SpdmResult { } } +// verify alias and device model by searching hardware oid in leaf cert +pub fn check_leaf_certificate(cert: &[u8], is_alias_cert_model: bool) -> SpdmResult { + let mut c_walker = 0usize; + + check_tag_is_sequence(cert)?; + c_walker += 1; + + let (_, bytes_consumed) = check_length(&cert[c_walker..])?; + c_walker += bytes_consumed; + + // tbs + let data = &cert[c_walker..]; + let mut t_walker = 0usize; + let len = data.len(); + + check_tag_is_sequence(data)?; + t_walker += 1; + + let (tbs_length, bytes_consumed) = check_length(&data[t_walker..])?; + t_walker += bytes_consumed; + + if len < t_walker + tbs_length { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + // version [0] EXPLICIT Version DEFAULT v1, + let bytes_consumed = check_version(&data[t_walker..])?; + t_walker += bytes_consumed; + + // serialNumber CertificateSerialNumber, + let bytes_consumed = check_and_skip_common_tag(&data[t_walker..])?; + t_walker += bytes_consumed; + + // signature AlgorithmIdentifier, + check_tag_is_sequence(&data[t_walker..])?; + t_walker += 1; + let (signature_id_length, bytes_consumed) = check_length(&data[t_walker..])?; + t_walker += bytes_consumed; + + check_object_identifier(&data[t_walker..], None)?; + t_walker += signature_id_length; + + // issuer Name, + let bytes_consumed = check_name(&data[t_walker..])?; + t_walker += bytes_consumed; + + // validity Validity, + let bytes_consumed = check_validity(&data[t_walker..])?; + t_walker += bytes_consumed; + + // subject Name, + let bytes_consumed = check_name(&data[t_walker..])?; + t_walker += bytes_consumed; + + // subjectPublicKeyInfo SubjectPublicKeyInfo, + let bytes_consumed = check_public_key_info(&data[t_walker..])?; + t_walker += bytes_consumed; + + //extensions EXTENSIONS, + let (_, extension_data) = check_and_get_extensions(&data[t_walker..])?; + + if is_alias_cert_model + && find_target_object_identifiers(extension_data, OID_DMTF_SPDM_HARDWARE_IDENTITY)? + { + info!("Hardware identity OID shall not be present in alias cert!\n"); + Err(SPDM_STATUS_VERIF_FAIL) + } else if !is_alias_cert_model + && !find_target_object_identifiers(extension_data, OID_DMTF_SPDM_HARDWARE_IDENTITY)? + { + info!("Hardware identity OID shall be present in device cert!\n"); + Err(SPDM_STATUS_VERIF_FAIL) + } else { + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -1134,4 +1210,21 @@ mod tests { Ok(false) ); } + + #[test] + fn test_case0_check_leaf_certificate() { + let end1 = std::fs::read("../test_key/rsa2048/end_responder_with_spdm_rsp_eku.cert.der") + .expect("unable to read end cert!"); + let end2 = std::fs::read("../test_key/ecp384/end_responder.cert.der") + .expect("unable to read end cert!"); + + let ct1_wrong = [0x30, 0x82, 0x01, 0xA8, 0xA0]; + + assert!(check_leaf_certificate(&end1, true).is_ok()); + assert!(check_leaf_certificate(&end1, false).is_err()); + assert!(check_leaf_certificate(&end2, false).is_ok()); + assert!(check_leaf_certificate(&end2, true).is_err()); + assert!(check_leaf_certificate(&ct1_wrong, true).is_err()); + assert!(check_leaf_certificate(&ct1_wrong, false).is_err()); + } } diff --git a/spdmlib/src/requester/get_certificate_req.rs b/spdmlib/src/requester/get_certificate_req.rs index f7ac6c0..37eaa20 100644 --- a/spdmlib/src/requester/get_certificate_req.rs +++ b/spdmlib/src/requester/get_certificate_req.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 or MIT -use crate::crypto::{self, is_root_certificate}; +use crate::crypto::{self, check_leaf_certificate, is_root_certificate}; use crate::error::{ SpdmResult, SPDM_STATUS_CRYPTO_ERROR, SPDM_STATUS_ERROR_PEER, SPDM_STATUS_INVALID_CERT, SPDM_STATUS_INVALID_MSG_FIELD, SPDM_STATUS_INVALID_PARAMETER, SPDM_STATUS_INVALID_STATE_LOCAL, @@ -296,6 +296,29 @@ impl RequesterContext { info!("1.2. root cert hash is verified!\n"); } + // + // 1.3 verify the leaf cert + // + let (leaf_cert_begin, leaf_cert_end) = crypto::cert_operation::get_cert_from_cert_chain( + &runtime_peer_cert_chain_data.data[..(runtime_peer_cert_chain_data.data_size as usize)], + -1, + )?; + let leaf_cert = &runtime_peer_cert_chain_data.data[leaf_cert_begin..leaf_cert_end]; + if check_leaf_certificate( + leaf_cert, + self.common + .negotiate_info + .rsp_capabilities_sel + .contains(SpdmResponseCapabilityFlags::ALIAS_CERT_CAP), + ) + .is_ok() + { + info!("1.3. Leaf cert is verified\n"); + } else { + info!("Leaf cert verification - fail! \n"); + return Err(SPDM_STATUS_INVALID_CERT); + } + // // 2. verify the authority of cert chain if provisioned //