|
|
|
|
@@ -13,11 +13,14 @@ use crate::data_model::common::{
|
|
|
|
|
use crate::data_model::oid::{
|
|
|
|
|
OID_AD_CA_ISSUERS_RAW, OID_AD_CA_REPOSITORY, OID_AD_CA_REPOSITORY_RAW, OID_AD_RPKI_MANIFEST,
|
|
|
|
|
OID_AD_RPKI_MANIFEST_RAW, OID_AD_RPKI_NOTIFY, OID_AD_RPKI_NOTIFY_RAW, OID_AD_SIGNED_OBJECT,
|
|
|
|
|
OID_AD_SIGNED_OBJECT_RAW, OID_AUTHORITY_INFO_ACCESS_RAW, OID_AUTHORITY_KEY_IDENTIFIER_RAW,
|
|
|
|
|
OID_AUTONOMOUS_SYS_IDS_RAW, OID_BASIC_CONSTRAINTS_RAW, OID_CERTIFICATE_POLICIES_RAW,
|
|
|
|
|
OID_CP_IPADDR_ASNUMBER, OID_CP_IPADDR_ASNUMBER_RAW, OID_CRL_DISTRIBUTION_POINTS_RAW,
|
|
|
|
|
OID_IP_ADDR_BLOCKS_RAW, OID_SHA256_WITH_RSA_ENCRYPTION, OID_SHA256_WITH_RSA_ENCRYPTION_RAW,
|
|
|
|
|
OID_SUBJECT_INFO_ACCESS_RAW, OID_SUBJECT_KEY_IDENTIFIER_RAW,
|
|
|
|
|
OID_AD_SIGNED_OBJECT_RAW, OID_AUTHORITY_INFO_ACCESS, OID_AUTHORITY_INFO_ACCESS_RAW,
|
|
|
|
|
OID_AUTHORITY_KEY_IDENTIFIER, OID_AUTHORITY_KEY_IDENTIFIER_RAW, OID_AUTONOMOUS_SYS_IDS,
|
|
|
|
|
OID_AUTONOMOUS_SYS_IDS_RAW, OID_BASIC_CONSTRAINTS, OID_BASIC_CONSTRAINTS_RAW,
|
|
|
|
|
OID_CERTIFICATE_POLICIES, OID_CERTIFICATE_POLICIES_RAW, OID_CP_IPADDR_ASNUMBER,
|
|
|
|
|
OID_CP_IPADDR_ASNUMBER_RAW, OID_CRL_DISTRIBUTION_POINTS, OID_CRL_DISTRIBUTION_POINTS_RAW,
|
|
|
|
|
OID_EXTENDED_KEY_USAGE, OID_IP_ADDR_BLOCKS, OID_IP_ADDR_BLOCKS_RAW, OID_KEY_USAGE, OID_QT_CPS,
|
|
|
|
|
OID_SHA256_WITH_RSA_ENCRYPTION, OID_SHA256_WITH_RSA_ENCRYPTION_RAW, OID_SUBJECT_INFO_ACCESS,
|
|
|
|
|
OID_SUBJECT_INFO_ACCESS_RAW, OID_SUBJECT_KEY_IDENTIFIER, OID_SUBJECT_KEY_IDENTIFIER_RAW,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Resource Certificate kind (semantic classification).
|
|
|
|
|
@@ -27,6 +30,14 @@ pub enum ResourceCertKind {
|
|
|
|
|
Ee,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
|
pub enum ResourceCertificateRole {
|
|
|
|
|
TrustAnchor,
|
|
|
|
|
Ca,
|
|
|
|
|
SignedObjectEe,
|
|
|
|
|
RouterEe,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A parsed RPKI Resource Certificate (RFC 6487) data model.
|
|
|
|
|
///
|
|
|
|
|
/// This module intentionally focuses on the semantics needed by Signed Object validation and
|
|
|
|
|
@@ -59,6 +70,7 @@ pub struct RpkixTbsCertificate {
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct RcExtensions {
|
|
|
|
|
pub basic_constraints_ca: bool,
|
|
|
|
|
pub basic_constraints: Option<BasicConstraintsProfile>,
|
|
|
|
|
pub subject_key_identifier: Option<Vec<u8>>,
|
|
|
|
|
/// Authority Key Identifier (AKI) keyIdentifier value.
|
|
|
|
|
pub authority_key_identifier: Option<Vec<u8>>,
|
|
|
|
|
@@ -68,11 +80,26 @@ pub struct RcExtensions {
|
|
|
|
|
pub ca_issuers_uris: Option<Vec<String>>,
|
|
|
|
|
pub subject_info_access: Option<SubjectInfoAccess>,
|
|
|
|
|
pub certificate_policies_oid: Option<String>,
|
|
|
|
|
pub certificate_policies: Option<CertificatePoliciesProfile>,
|
|
|
|
|
pub extension_oids: Vec<String>,
|
|
|
|
|
|
|
|
|
|
pub ip_resources: Option<IpResourceSet>,
|
|
|
|
|
pub as_resources: Option<AsResourceSet>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct BasicConstraintsProfile {
|
|
|
|
|
pub ca: bool,
|
|
|
|
|
pub critical: bool,
|
|
|
|
|
pub path_len_constraint: Option<u32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct CertificatePoliciesProfile {
|
|
|
|
|
pub policy_oid: String,
|
|
|
|
|
pub qualifier_oids: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct ResourceCertificateParsed {
|
|
|
|
|
pub raw_der: Vec<u8>,
|
|
|
|
|
@@ -114,13 +141,14 @@ impl AlgorithmIdentifierValue {
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct RcExtensionsParsed {
|
|
|
|
|
pub basic_constraints_ca: Vec<bool>,
|
|
|
|
|
pub basic_constraints: Vec<BasicConstraintsProfile>,
|
|
|
|
|
pub subject_key_identifier: Vec<(Vec<u8>, bool)>,
|
|
|
|
|
pub authority_key_identifier: Vec<(AuthorityKeyIdentifierParsed, bool)>,
|
|
|
|
|
pub crl_distribution_points: Vec<(CrlDistributionPointsParsed, bool)>,
|
|
|
|
|
pub authority_info_access: Vec<(AuthorityInfoAccessParsed, bool)>,
|
|
|
|
|
pub subject_info_access: Vec<(SubjectInfoAccessParsed, bool)>,
|
|
|
|
|
pub certificate_policies: Vec<(Vec<String>, bool)>,
|
|
|
|
|
pub certificate_policies: Vec<(Vec<CertificatePoliciesProfile>, bool)>,
|
|
|
|
|
pub extension_oids: Vec<String>,
|
|
|
|
|
pub ip_resources: Vec<(IpResourceSet, bool)>,
|
|
|
|
|
pub as_resources: Vec<(AsResourceSet, bool)>,
|
|
|
|
|
}
|
|
|
|
|
@@ -406,11 +434,45 @@ pub enum ResourceCertificateProfileError {
|
|
|
|
|
#[error("certificatePolicies criticality must be critical (RFC 6487 §4.8.9)")]
|
|
|
|
|
CertificatePoliciesCriticality,
|
|
|
|
|
|
|
|
|
|
#[error("certificatePolicies must be present (RFC 6487 §4.8.9)")]
|
|
|
|
|
CertificatePoliciesMissing,
|
|
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
|
"certificatePolicies must contain RPKI policy OID {OID_CP_IPADDR_ASNUMBER}, got {0} (RFC 6487 §4.8.9)"
|
|
|
|
|
)]
|
|
|
|
|
InvalidCertificatePolicy(String),
|
|
|
|
|
|
|
|
|
|
#[error("certificatePolicies may contain at most one CPS qualifier (RFC 6487 §4.8.9)")]
|
|
|
|
|
CertificatePoliciesTooManyQualifiers,
|
|
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
|
"certificatePolicies qualifier must be id-qt-cps ({OID_QT_CPS}), got {0} (RFC 6487 §4.8.9)"
|
|
|
|
|
)]
|
|
|
|
|
CertificatePoliciesInvalidQualifier(String),
|
|
|
|
|
|
|
|
|
|
#[error("basicConstraints must be present in CA certificates (RFC 6487 §4.8.1)")]
|
|
|
|
|
BasicConstraintsMissing,
|
|
|
|
|
|
|
|
|
|
#[error("basicConstraints criticality must be critical in CA certificates (RFC 6487 §4.8.1)")]
|
|
|
|
|
BasicConstraintsCriticality,
|
|
|
|
|
|
|
|
|
|
#[error("basicConstraints cA must be TRUE in CA certificates (RFC 6487 §4.8.1)")]
|
|
|
|
|
BasicConstraintsCaFalse,
|
|
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
|
"basicConstraints pathLenConstraint must be absent in CA certificates (RFC 6487 §4.8.1)"
|
|
|
|
|
)]
|
|
|
|
|
BasicConstraintsPathLenPresent,
|
|
|
|
|
|
|
|
|
|
#[error("basicConstraints must be absent in EE certificates (RFC 6487 §4.8.1)")]
|
|
|
|
|
BasicConstraintsEeMustOmit,
|
|
|
|
|
|
|
|
|
|
#[error("extension {oid} is not permitted for {role} resource certificates (RFC 6487 §4.8)")]
|
|
|
|
|
DisallowedExtension { role: &'static str, oid: String },
|
|
|
|
|
|
|
|
|
|
#[error("autonomousSysIds RDI field must be absent (RFC 6487 §4.8.11; RFC 3779 §3.2.3)")]
|
|
|
|
|
AsResourcesRdiPresent,
|
|
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
|
"SIA id-ad-signedObject accessLocation must be URI (RFC 6487 §4.8.8.2; RFC 5280 §4.2.2.2)"
|
|
|
|
|
)]
|
|
|
|
|
@@ -567,6 +629,87 @@ impl ResourceCertificate {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn validate_rfc6487_profile(
|
|
|
|
|
&self,
|
|
|
|
|
role: ResourceCertificateRole,
|
|
|
|
|
) -> Result<(), ResourceCertificateProfileError> {
|
|
|
|
|
let role_name = match role {
|
|
|
|
|
ResourceCertificateRole::TrustAnchor => "trust anchor CA",
|
|
|
|
|
ResourceCertificateRole::Ca => "CA",
|
|
|
|
|
ResourceCertificateRole::SignedObjectEe => "signed-object EE",
|
|
|
|
|
ResourceCertificateRole::RouterEe => "router EE",
|
|
|
|
|
};
|
|
|
|
|
let ca_role = matches!(
|
|
|
|
|
role,
|
|
|
|
|
ResourceCertificateRole::TrustAnchor | ResourceCertificateRole::Ca
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ca_role {
|
|
|
|
|
let constraints = self
|
|
|
|
|
.tbs
|
|
|
|
|
.extensions
|
|
|
|
|
.basic_constraints
|
|
|
|
|
.as_ref()
|
|
|
|
|
.ok_or(ResourceCertificateProfileError::BasicConstraintsMissing)?;
|
|
|
|
|
if !constraints.critical {
|
|
|
|
|
return Err(ResourceCertificateProfileError::BasicConstraintsCriticality);
|
|
|
|
|
}
|
|
|
|
|
if !constraints.ca {
|
|
|
|
|
return Err(ResourceCertificateProfileError::BasicConstraintsCaFalse);
|
|
|
|
|
}
|
|
|
|
|
if constraints.path_len_constraint.is_some() {
|
|
|
|
|
return Err(ResourceCertificateProfileError::BasicConstraintsPathLenPresent);
|
|
|
|
|
}
|
|
|
|
|
} else if self.tbs.extensions.basic_constraints.is_some() {
|
|
|
|
|
return Err(ResourceCertificateProfileError::BasicConstraintsEeMustOmit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for oid in &self.tbs.extensions.extension_oids {
|
|
|
|
|
if !is_permitted_extension(oid, role) {
|
|
|
|
|
return Err(ResourceCertificateProfileError::DisallowedExtension {
|
|
|
|
|
role: role_name,
|
|
|
|
|
oid: oid.clone(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let policies = self
|
|
|
|
|
.tbs
|
|
|
|
|
.extensions
|
|
|
|
|
.certificate_policies
|
|
|
|
|
.as_ref()
|
|
|
|
|
.ok_or(ResourceCertificateProfileError::CertificatePoliciesMissing)?;
|
|
|
|
|
if policies.policy_oid != OID_CP_IPADDR_ASNUMBER {
|
|
|
|
|
return Err(ResourceCertificateProfileError::InvalidCertificatePolicy(
|
|
|
|
|
policies.policy_oid.clone(),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
if policies.qualifier_oids.len() > 1 {
|
|
|
|
|
return Err(ResourceCertificateProfileError::CertificatePoliciesTooManyQualifiers);
|
|
|
|
|
}
|
|
|
|
|
if let Some(qualifier_oid) = policies.qualifier_oids.first() {
|
|
|
|
|
if qualifier_oid != OID_QT_CPS {
|
|
|
|
|
return Err(
|
|
|
|
|
ResourceCertificateProfileError::CertificatePoliciesInvalidQualifier(
|
|
|
|
|
qualifier_oid.clone(),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self
|
|
|
|
|
.tbs
|
|
|
|
|
.extensions
|
|
|
|
|
.as_resources
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|resources| resources.rdi.is_some())
|
|
|
|
|
{
|
|
|
|
|
return Err(ResourceCertificateProfileError::AsResourcesRdiPresent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn validate_strict_name_profile(&self) -> Result<(), ResourceCertificateProfileError> {
|
|
|
|
|
validate_strict_rpki_name(&self.tbs.issuer_name, "issuer")?;
|
|
|
|
|
validate_strict_rpki_name(&self.tbs.subject_name, "subject")?;
|
|
|
|
|
@@ -590,6 +733,22 @@ impl ResourceCertificate {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_permitted_extension(oid: &str, role: ResourceCertificateRole) -> bool {
|
|
|
|
|
matches!(
|
|
|
|
|
oid,
|
|
|
|
|
OID_BASIC_CONSTRAINTS
|
|
|
|
|
| OID_KEY_USAGE
|
|
|
|
|
| OID_SUBJECT_KEY_IDENTIFIER
|
|
|
|
|
| OID_AUTHORITY_KEY_IDENTIFIER
|
|
|
|
|
| OID_CRL_DISTRIBUTION_POINTS
|
|
|
|
|
| OID_AUTHORITY_INFO_ACCESS
|
|
|
|
|
| OID_SUBJECT_INFO_ACCESS
|
|
|
|
|
| OID_CERTIFICATE_POLICIES
|
|
|
|
|
| OID_IP_ADDR_BLOCKS
|
|
|
|
|
| OID_AUTONOMOUS_SYS_IDS
|
|
|
|
|
) || (role == ResourceCertificateRole::RouterEe && oid == OID_EXTENDED_KEY_USAGE)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn validate_strict_rpki_name(
|
|
|
|
|
name: &X509NameDer,
|
|
|
|
|
role: &'static str,
|
|
|
|
|
@@ -744,13 +903,24 @@ mod strict_name_tests {
|
|
|
|
|
#[test]
|
|
|
|
|
fn profile_rejects_rfc8360_v2_policy_oid() {
|
|
|
|
|
let extensions = RcExtensionsParsed {
|
|
|
|
|
basic_constraints_ca: vec![true],
|
|
|
|
|
basic_constraints: vec![BasicConstraintsProfile {
|
|
|
|
|
ca: true,
|
|
|
|
|
critical: true,
|
|
|
|
|
path_len_constraint: None,
|
|
|
|
|
}],
|
|
|
|
|
subject_key_identifier: Vec::new(),
|
|
|
|
|
authority_key_identifier: Vec::new(),
|
|
|
|
|
crl_distribution_points: Vec::new(),
|
|
|
|
|
authority_info_access: Vec::new(),
|
|
|
|
|
subject_info_access: Vec::new(),
|
|
|
|
|
certificate_policies: vec![(vec!["1.3.6.1.5.5.7.14.3".to_string()], true)],
|
|
|
|
|
certificate_policies: vec![(
|
|
|
|
|
vec![CertificatePoliciesProfile {
|
|
|
|
|
policy_oid: "1.3.6.1.5.5.7.14.3".to_string(),
|
|
|
|
|
qualifier_oids: Vec::new(),
|
|
|
|
|
}],
|
|
|
|
|
true,
|
|
|
|
|
)],
|
|
|
|
|
extension_oids: Vec::new(),
|
|
|
|
|
ip_resources: Vec::new(),
|
|
|
|
|
as_resources: Vec::new(),
|
|
|
|
|
};
|
|
|
|
|
@@ -821,23 +991,25 @@ impl RcExtensionsParsed {
|
|
|
|
|
// NOTE(perf): `self` is consumed. Prefer moving decoded fields out rather than cloning,
|
|
|
|
|
// especially for large resource sets and URI lists.
|
|
|
|
|
let RcExtensionsParsed {
|
|
|
|
|
basic_constraints_ca,
|
|
|
|
|
basic_constraints,
|
|
|
|
|
subject_key_identifier,
|
|
|
|
|
authority_key_identifier,
|
|
|
|
|
crl_distribution_points,
|
|
|
|
|
authority_info_access,
|
|
|
|
|
subject_info_access,
|
|
|
|
|
certificate_policies,
|
|
|
|
|
extension_oids,
|
|
|
|
|
ip_resources,
|
|
|
|
|
as_resources,
|
|
|
|
|
} = self;
|
|
|
|
|
|
|
|
|
|
if basic_constraints_ca.len() > 1 {
|
|
|
|
|
if basic_constraints.len() > 1 {
|
|
|
|
|
return Err(ResourceCertificateProfileError::DuplicateExtension(
|
|
|
|
|
"basicConstraints",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
let basic_constraints_ca = basic_constraints_ca.first().copied().unwrap_or(false);
|
|
|
|
|
let basic_constraints = basic_constraints.into_iter().next();
|
|
|
|
|
let basic_constraints_ca = basic_constraints.as_ref().is_some_and(|bc| bc.ca);
|
|
|
|
|
|
|
|
|
|
let subject_key_identifier = match subject_key_identifier.len() {
|
|
|
|
|
0 => None,
|
|
|
|
|
@@ -1032,25 +1204,25 @@ impl RcExtensionsParsed {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let certificate_policies_oid = match certificate_policies.len() {
|
|
|
|
|
let certificate_policies = match certificate_policies.len() {
|
|
|
|
|
0 => None,
|
|
|
|
|
1 => {
|
|
|
|
|
let (oids, critical) = certificate_policies.into_iter().next().expect("len==1");
|
|
|
|
|
let (policies, critical) = certificate_policies.into_iter().next().expect("len==1");
|
|
|
|
|
if !critical {
|
|
|
|
|
return Err(ResourceCertificateProfileError::CertificatePoliciesCriticality);
|
|
|
|
|
}
|
|
|
|
|
if oids.len() != 1 {
|
|
|
|
|
if policies.len() != 1 {
|
|
|
|
|
return Err(ResourceCertificateProfileError::InvalidCertificatePolicy(
|
|
|
|
|
"expected exactly one policy".into(),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
let policy_oid = oids.into_iter().next().expect("len==1");
|
|
|
|
|
if policy_oid != OID_CP_IPADDR_ASNUMBER {
|
|
|
|
|
let policy = policies.into_iter().next().expect("len==1");
|
|
|
|
|
if policy.policy_oid != OID_CP_IPADDR_ASNUMBER {
|
|
|
|
|
return Err(ResourceCertificateProfileError::InvalidCertificatePolicy(
|
|
|
|
|
policy_oid,
|
|
|
|
|
policy.policy_oid,
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
Some(OID_CP_IPADDR_ASNUMBER.to_string())
|
|
|
|
|
Some(policy)
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
return Err(ResourceCertificateProfileError::DuplicateExtension(
|
|
|
|
|
@@ -1093,12 +1265,17 @@ impl RcExtensionsParsed {
|
|
|
|
|
|
|
|
|
|
Ok(RcExtensions {
|
|
|
|
|
basic_constraints_ca,
|
|
|
|
|
basic_constraints,
|
|
|
|
|
subject_key_identifier,
|
|
|
|
|
authority_key_identifier,
|
|
|
|
|
crl_distribution_points_uris,
|
|
|
|
|
ca_issuers_uris,
|
|
|
|
|
subject_info_access,
|
|
|
|
|
certificate_policies_oid,
|
|
|
|
|
certificate_policies_oid: certificate_policies
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|_| OID_CP_IPADDR_ASNUMBER.to_string()),
|
|
|
|
|
certificate_policies,
|
|
|
|
|
extension_oids,
|
|
|
|
|
ip_resources,
|
|
|
|
|
as_resources,
|
|
|
|
|
})
|
|
|
|
|
@@ -1127,26 +1304,32 @@ fn algorithm_identifier_value(
|
|
|
|
|
fn parse_extensions_parse(
|
|
|
|
|
exts: &[X509Extension<'_>],
|
|
|
|
|
) -> Result<RcExtensionsParsed, ResourceCertificateParseError> {
|
|
|
|
|
let mut basic_constraints_ca: Vec<bool> = Vec::new();
|
|
|
|
|
let mut basic_constraints: Vec<BasicConstraintsProfile> = Vec::new();
|
|
|
|
|
let mut ski: Vec<(Vec<u8>, bool)> = Vec::new();
|
|
|
|
|
let mut aki: Vec<(AuthorityKeyIdentifierParsed, bool)> = Vec::new();
|
|
|
|
|
let mut crldp: Vec<(CrlDistributionPointsParsed, bool)> = Vec::new();
|
|
|
|
|
let mut aia: Vec<(AuthorityInfoAccessParsed, bool)> = Vec::new();
|
|
|
|
|
let mut sia: Vec<(SubjectInfoAccessParsed, bool)> = Vec::new();
|
|
|
|
|
let mut cert_policies: Vec<(Vec<String>, bool)> = Vec::new();
|
|
|
|
|
let mut cert_policies: Vec<(Vec<CertificatePoliciesProfile>, bool)> = Vec::new();
|
|
|
|
|
let mut extension_oids: Vec<String> = Vec::with_capacity(exts.len());
|
|
|
|
|
|
|
|
|
|
let mut ip_resources: Vec<(IpResourceSet, bool)> = Vec::new();
|
|
|
|
|
let mut as_resources: Vec<(AsResourceSet, bool)> = Vec::new();
|
|
|
|
|
|
|
|
|
|
for ext in exts {
|
|
|
|
|
let oid = ext.oid.as_bytes();
|
|
|
|
|
extension_oids.push(ext.oid.to_id_string());
|
|
|
|
|
if oid == OID_BASIC_CONSTRAINTS_RAW {
|
|
|
|
|
let ParsedExtension::BasicConstraints(bc) = ext.parsed_extension() else {
|
|
|
|
|
return Err(ResourceCertificateParseError::Parse(
|
|
|
|
|
"basicConstraints parse failed".into(),
|
|
|
|
|
));
|
|
|
|
|
};
|
|
|
|
|
basic_constraints_ca.push(bc.ca);
|
|
|
|
|
basic_constraints.push(BasicConstraintsProfile {
|
|
|
|
|
ca: bc.ca,
|
|
|
|
|
critical: ext.critical,
|
|
|
|
|
path_len_constraint: bc.path_len_constraint,
|
|
|
|
|
});
|
|
|
|
|
} else if oid == OID_SUBJECT_KEY_IDENTIFIER_RAW {
|
|
|
|
|
let ParsedExtension::SubjectKeyIdentifier(s) = ext.parsed_extension() else {
|
|
|
|
|
return Err(ResourceCertificateParseError::Parse(
|
|
|
|
|
@@ -1195,16 +1378,30 @@ fn parse_extensions_parse(
|
|
|
|
|
"certificatePolicies parse failed".into(),
|
|
|
|
|
));
|
|
|
|
|
};
|
|
|
|
|
let mut oids: Vec<String> = Vec::with_capacity(cp.len());
|
|
|
|
|
let mut policies: Vec<CertificatePoliciesProfile> = Vec::with_capacity(cp.len());
|
|
|
|
|
for p in cp.iter() {
|
|
|
|
|
let b = p.policy_id.as_bytes();
|
|
|
|
|
if b == OID_CP_IPADDR_ASNUMBER_RAW {
|
|
|
|
|
oids.push(OID_CP_IPADDR_ASNUMBER.to_string());
|
|
|
|
|
let policy_oid = if b == OID_CP_IPADDR_ASNUMBER_RAW {
|
|
|
|
|
OID_CP_IPADDR_ASNUMBER.to_string()
|
|
|
|
|
} else {
|
|
|
|
|
oids.push(p.policy_id.to_id_string());
|
|
|
|
|
}
|
|
|
|
|
p.policy_id.to_id_string()
|
|
|
|
|
};
|
|
|
|
|
let qualifier_oids = p
|
|
|
|
|
.policy_qualifiers
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|qualifiers| {
|
|
|
|
|
qualifiers
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|qualifier| qualifier.policy_qualifier_id.to_id_string())
|
|
|
|
|
.collect()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
policies.push(CertificatePoliciesProfile {
|
|
|
|
|
policy_oid,
|
|
|
|
|
qualifier_oids,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
cert_policies.push((oids, ext.critical));
|
|
|
|
|
cert_policies.push((policies, ext.critical));
|
|
|
|
|
} else if oid == OID_IP_ADDR_BLOCKS_RAW {
|
|
|
|
|
let parsed = IpResourceSet::decode_extn_value(ext.value)
|
|
|
|
|
.map_err(|_e| ResourceCertificateParseError::InvalidIpResourcesEncoding)?;
|
|
|
|
|
@@ -1217,13 +1414,14 @@ fn parse_extensions_parse(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(RcExtensionsParsed {
|
|
|
|
|
basic_constraints_ca,
|
|
|
|
|
basic_constraints,
|
|
|
|
|
subject_key_identifier: ski,
|
|
|
|
|
authority_key_identifier: aki,
|
|
|
|
|
crl_distribution_points: crldp,
|
|
|
|
|
authority_info_access: aia,
|
|
|
|
|
subject_info_access: sia,
|
|
|
|
|
certificate_policies: cert_policies,
|
|
|
|
|
extension_oids,
|
|
|
|
|
ip_resources,
|
|
|
|
|
as_resources,
|
|
|
|
|
})
|
|
|
|
|
|