diff --git a/spdmlib/src/crypto/x509v3.rs b/spdmlib/src/crypto/x509v3.rs index e4e679c..80cd22f 100644 --- a/spdmlib/src/crypto/x509v3.rs +++ b/spdmlib/src/crypto/x509v3.rs @@ -14,8 +14,10 @@ const ASN1_TAG_CLASS_CONTEXT_SPECIFIC_MASK: u8 = 0x80; const ASN1_FORM_CONSTRUCTED_MASK: u8 = 0x20; +const ASN1_TAG_BOOLEAN: u8 = 0x1; const ASN1_TAG_NUMBER_INTEGER: u8 = 0x2; const ASN1_TAG_BIT_STRING: u8 = 0x3; +const ASN1_TAG_OCTET_STRING: u8 = 0x4; const ASN1_TAG_NUMBER_OBJECT_IDENTIFIER: u8 = 0x6; const ASN1_TAG_NUMBER_SEQUENCE: u8 = 0x10; @@ -224,6 +226,36 @@ fn check_tag_is_sequence(data: &[u8]) -> SpdmResult { } } +fn check_tag_is_num_oid(data: &[u8]) -> SpdmResult { + if data.is_empty() { + Err(SPDM_STATUS_VERIF_FAIL) + } else if data[0] == ASN1_TAG_NUMBER_OBJECT_IDENTIFIER { + Ok(()) + } else { + Err(SPDM_STATUS_VERIF_FAIL) + } +} + +fn check_tag_is_bool(data: &[u8]) -> SpdmResult { + if data.is_empty() { + Err(SPDM_STATUS_VERIF_FAIL) + } else if data[0] == ASN1_TAG_BOOLEAN { + Ok(()) + } else { + Err(SPDM_STATUS_VERIF_FAIL) + } +} + +fn check_tag_is_octet_string(data: &[u8]) -> SpdmResult { + if data.is_empty() { + Err(SPDM_STATUS_VERIF_FAIL) + } else if data[0] == ASN1_TAG_OCTET_STRING { + Ok(()) + } else { + Err(SPDM_STATUS_VERIF_FAIL) + } +} + // IN bytes slice // OUT Ok (length, bytes consumed) // OUT Error Mulformed certificate found @@ -470,6 +502,144 @@ fn find_target_object_identifiers(data: &[u8], target_oid: &[u8]) -> SpdmResult< Ok(target_oid_find_success) } +// IN extension sequences slice +// OUT true when find hardware oid +// OUT false when not find hardware oid +fn find_hardware_object_identifiers_in_extensions(data: &[u8]) -> SpdmResult { + let len = data.len(); + let mut walker = 0usize; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + check_tag_is_sequence(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (payload_length, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker + payload_length > len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let data = &data[walker..walker + payload_length]; + let len = payload_length; + walker = 0; + while walker < len { + check_tag_is_sequence(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (extension_length, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let next_ext_walker = walker + extension_length; + + check_tag_is_num_oid(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (payload_length, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + if walker + payload_length < len + && object_identifiers_are_same( + &data[walker..walker + payload_length], + OID_DMTF_SPDM_EXTENSION, + ) + { + walker += payload_length; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + // check critical, it is optional + if check_tag_is_bool(&data[walker..]).is_ok() { + walker += 3; // tag, length, value + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + } + + // next find hardware oid + check_tag_is_octet_string(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (_, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + // sequence + check_tag_is_sequence(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (_, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + // sequence + check_tag_is_sequence(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (_, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + check_tag_is_num_oid(&data[walker..])?; + walker += 1; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + let (target_oid_length, bytes_consumed) = check_length(&data[walker..])?; + walker += bytes_consumed; + if walker >= len { + return Err(SPDM_STATUS_VERIF_FAIL); + } + + if walker + target_oid_length <= len + && object_identifiers_are_same( + &data[walker..walker + target_oid_length], + OID_DMTF_SPDM_HARDWARE_IDENTITY, + ) + { + return Ok(true); + } + } + + walker = next_ext_walker; + } + + Ok(false) +} + // IN extension sequence slice // OUT Ok (extnID, extn sequence length) // OUT Error not found extnID, verify fail @@ -692,13 +862,11 @@ pub fn check_leaf_certificate(cert: &[u8], is_alias_cert_model: bool) -> SpdmRes //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)? - { + if is_alias_cert_model && find_hardware_object_identifiers_in_extensions(extension_data)? { 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)? + && !find_hardware_object_identifiers_in_extensions(extension_data)? { info!("Hardware identity OID should be present in device cert!\n"); Ok(())