优化时间表示
This commit is contained in:
parent
a58e507f92
commit
7be865d7f1
@ -1,6 +1,8 @@
|
|||||||
use x509_parser::asn1_rs::Tag;
|
use x509_parser::asn1_rs::Tag;
|
||||||
use x509_parser::x509::AlgorithmIdentifier;
|
use x509_parser::x509::AlgorithmIdentifier;
|
||||||
|
|
||||||
|
pub type UtcTime = time::OffsetDateTime;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Asn1TimeEncoding {
|
pub enum Asn1TimeEncoding {
|
||||||
UtcTime,
|
UtcTime,
|
||||||
@ -9,7 +11,7 @@ pub enum Asn1TimeEncoding {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct Asn1TimeUtc {
|
pub struct Asn1TimeUtc {
|
||||||
pub utc: time::OffsetDateTime,
|
pub utc: UtcTime,
|
||||||
pub encoding: Asn1TimeEncoding,
|
pub encoding: Asn1TimeEncoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::data_model::common::BigUnsigned;
|
use crate::data_model::common::{BigUnsigned, UtcTime};
|
||||||
use crate::data_model::oid::{OID_CT_RPKI_MANIFEST, OID_SHA256};
|
use crate::data_model::oid::{OID_CT_RPKI_MANIFEST, OID_SHA256};
|
||||||
use crate::data_model::rc::ResourceCertificate;
|
use crate::data_model::rc::ResourceCertificate;
|
||||||
use crate::data_model::signed_object::{
|
use crate::data_model::signed_object::{
|
||||||
@ -6,7 +6,6 @@ use crate::data_model::signed_object::{
|
|||||||
};
|
};
|
||||||
use der_parser::ber::BerObjectContent;
|
use der_parser::ber::BerObjectContent;
|
||||||
use der_parser::der::{DerObject, Tag, parse_der};
|
use der_parser::der::{DerObject, Tag, parse_der};
|
||||||
use time::OffsetDateTime;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct ManifestObject {
|
pub struct ManifestObject {
|
||||||
@ -26,8 +25,8 @@ pub struct ManifestObjectParsed {
|
|||||||
pub struct ManifestEContent {
|
pub struct ManifestEContent {
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub manifest_number: BigUnsigned,
|
pub manifest_number: BigUnsigned,
|
||||||
pub this_update: OffsetDateTime,
|
pub this_update: UtcTime,
|
||||||
pub next_update: OffsetDateTime,
|
pub next_update: UtcTime,
|
||||||
pub file_hash_alg: String,
|
pub file_hash_alg: String,
|
||||||
pub files: Vec<FileAndHash>,
|
pub files: Vec<FileAndHash>,
|
||||||
}
|
}
|
||||||
@ -378,7 +377,7 @@ fn parse_manifest_number(obj: &DerObject<'_>) -> Result<BigUnsigned, ManifestPro
|
|||||||
fn parse_generalized_time(
|
fn parse_generalized_time(
|
||||||
obj: &DerObject<'_>,
|
obj: &DerObject<'_>,
|
||||||
err: ManifestProfileError,
|
err: ManifestProfileError,
|
||||||
) -> Result<OffsetDateTime, ManifestProfileError> {
|
) -> Result<UtcTime, ManifestProfileError> {
|
||||||
match &obj.content {
|
match &obj.content {
|
||||||
BerObjectContent::GeneralizedTime(dt) => dt
|
BerObjectContent::GeneralizedTime(dt) => dt
|
||||||
.to_datetime()
|
.to_datetime()
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
use der_parser::ber::{BerObjectContent, Class};
|
use der_parser::ber::{BerObjectContent, Class};
|
||||||
use der_parser::der::{DerObject, Tag, parse_der};
|
use der_parser::der::{DerObject, Tag, parse_der};
|
||||||
use der_parser::num_bigint::BigUint;
|
use der_parser::num_bigint::BigUint;
|
||||||
use time::OffsetDateTime;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use x509_parser::asn1_rs::{Class as Asn1Class, Tag as Asn1Tag};
|
use x509_parser::asn1_rs::{Class as Asn1Class, Tag as Asn1Tag};
|
||||||
use x509_parser::extensions::ParsedExtension;
|
use x509_parser::extensions::ParsedExtension;
|
||||||
use x509_parser::prelude::{FromDer, X509Certificate, X509Extension, X509Version};
|
use x509_parser::prelude::{FromDer, X509Certificate, X509Extension, X509Version};
|
||||||
|
|
||||||
|
use crate::data_model::common::{
|
||||||
|
Asn1TimeUtc, InvalidTimeEncodingError, UtcTime, asn1_time_to_model,
|
||||||
|
};
|
||||||
use crate::data_model::oid::{
|
use crate::data_model::oid::{
|
||||||
OID_AD_SIGNED_OBJECT, OID_AUTONOMOUS_SYS_IDS, OID_CP_IPADDR_ASNUMBER, OID_IP_ADDR_BLOCKS,
|
OID_AD_SIGNED_OBJECT, OID_AUTONOMOUS_SYS_IDS, OID_CP_IPADDR_ASNUMBER, OID_IP_ADDR_BLOCKS,
|
||||||
OID_SHA256_WITH_RSA_ENCRYPTION, OID_SUBJECT_INFO_ACCESS, OID_SUBJECT_KEY_IDENTIFIER,
|
OID_SHA256_WITH_RSA_ENCRYPTION, OID_SUBJECT_INFO_ACCESS, OID_SUBJECT_KEY_IDENTIFIER,
|
||||||
@ -41,8 +43,8 @@ pub struct RpkixTbsCertificate {
|
|||||||
pub signature_algorithm: String,
|
pub signature_algorithm: String,
|
||||||
pub issuer_dn: String,
|
pub issuer_dn: String,
|
||||||
pub subject_dn: String,
|
pub subject_dn: String,
|
||||||
pub validity_not_before: OffsetDateTime,
|
pub validity_not_before: UtcTime,
|
||||||
pub validity_not_after: OffsetDateTime,
|
pub validity_not_after: UtcTime,
|
||||||
/// DER encoding of SubjectPublicKeyInfo.
|
/// DER encoding of SubjectPublicKeyInfo.
|
||||||
pub subject_public_key_info: Vec<u8>,
|
pub subject_public_key_info: Vec<u8>,
|
||||||
pub extensions: RcExtensions,
|
pub extensions: RcExtensions,
|
||||||
@ -68,8 +70,8 @@ pub struct ResourceCertificateParsed {
|
|||||||
pub tbs_signature_algorithm: AlgorithmIdentifierValue,
|
pub tbs_signature_algorithm: AlgorithmIdentifierValue,
|
||||||
pub issuer_dn: String,
|
pub issuer_dn: String,
|
||||||
pub subject_dn: String,
|
pub subject_dn: String,
|
||||||
pub validity_not_before: OffsetDateTime,
|
pub validity_not_before: Asn1TimeUtc,
|
||||||
pub validity_not_after: OffsetDateTime,
|
pub validity_not_after: Asn1TimeUtc,
|
||||||
/// DER encoding of SubjectPublicKeyInfo.
|
/// DER encoding of SubjectPublicKeyInfo.
|
||||||
pub subject_public_key_info: Vec<u8>,
|
pub subject_public_key_info: Vec<u8>,
|
||||||
pub extensions: RcExtensionsParsed,
|
pub extensions: RcExtensionsParsed,
|
||||||
@ -326,6 +328,9 @@ pub enum ResourceCertificateParseError {
|
|||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum ResourceCertificateProfileError {
|
pub enum ResourceCertificateProfileError {
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidTimeEncoding(#[from] InvalidTimeEncodingError),
|
||||||
|
|
||||||
#[error("certificate version must be v3 (RFC 5280 §4.1; RFC 6487 §4)")]
|
#[error("certificate version must be v3 (RFC 5280 §4.1; RFC 6487 §4)")]
|
||||||
InvalidVersion,
|
InvalidVersion,
|
||||||
|
|
||||||
@ -394,8 +399,8 @@ impl ResourceCertificate {
|
|||||||
return Err(ResourceCertificateParseError::TrailingBytes(rem.len()));
|
return Err(ResourceCertificateParseError::TrailingBytes(rem.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let validity_not_before = cert.validity().not_before.to_datetime();
|
let validity_not_before = asn1_time_to_model(cert.validity().not_before);
|
||||||
let validity_not_after = cert.validity().not_after.to_datetime();
|
let validity_not_after = asn1_time_to_model(cert.validity().not_after);
|
||||||
|
|
||||||
let subject_public_key_info = cert.tbs_certificate.subject_pki.raw.to_vec();
|
let subject_public_key_info = cert.tbs_certificate.subject_pki.raw.to_vec();
|
||||||
|
|
||||||
@ -444,6 +449,11 @@ impl ResourceCertificateParsed {
|
|||||||
_ => return Err(ResourceCertificateProfileError::InvalidVersion),
|
_ => return Err(ResourceCertificateProfileError::InvalidVersion),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.validity_not_before
|
||||||
|
.validate_encoding_rfc5280("notBefore")?;
|
||||||
|
self.validity_not_after
|
||||||
|
.validate_encoding_rfc5280("notAfter")?;
|
||||||
|
|
||||||
if self.signature_algorithm != self.tbs_signature_algorithm {
|
if self.signature_algorithm != self.tbs_signature_algorithm {
|
||||||
return Err(ResourceCertificateProfileError::SignatureAlgorithmMismatch);
|
return Err(ResourceCertificateProfileError::SignatureAlgorithmMismatch);
|
||||||
}
|
}
|
||||||
@ -469,8 +479,8 @@ impl ResourceCertificateParsed {
|
|||||||
signature_algorithm: self.signature_algorithm.oid,
|
signature_algorithm: self.signature_algorithm.oid,
|
||||||
issuer_dn: self.issuer_dn,
|
issuer_dn: self.issuer_dn,
|
||||||
subject_dn: self.subject_dn,
|
subject_dn: self.subject_dn,
|
||||||
validity_not_before: self.validity_not_before,
|
validity_not_before: self.validity_not_before.utc,
|
||||||
validity_not_after: self.validity_not_after,
|
validity_not_after: self.validity_not_after.utc,
|
||||||
subject_public_key_info: self.subject_public_key_info,
|
subject_public_key_info: self.subject_public_key_info,
|
||||||
extensions,
|
extensions,
|
||||||
},
|
},
|
||||||
|
|||||||
24
tests/test_rc_time_encoding.rs
Normal file
24
tests/test_rc_time_encoding.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use rpki::data_model::common::Asn1TimeEncoding;
|
||||||
|
use rpki::data_model::rc::{ResourceCertificate, ResourceCertificateProfileError};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rc_validity_time_encoding_is_validated() {
|
||||||
|
let der = std::fs::read(
|
||||||
|
"tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer",
|
||||||
|
)
|
||||||
|
.expect("read RC fixture");
|
||||||
|
|
||||||
|
let mut parsed = ResourceCertificate::parse_der(&der).expect("parse RC fixture");
|
||||||
|
parsed.validity_not_before.encoding = match parsed.validity_not_before.encoding {
|
||||||
|
Asn1TimeEncoding::UtcTime => Asn1TimeEncoding::GeneralizedTime,
|
||||||
|
Asn1TimeEncoding::GeneralizedTime => Asn1TimeEncoding::UtcTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
match parsed.validate_profile() {
|
||||||
|
Ok(_rc) => panic!("expected time-encoding validation error"),
|
||||||
|
Err(ResourceCertificateProfileError::InvalidTimeEncoding(e)) => {
|
||||||
|
assert_eq!(e.field, "notBefore");
|
||||||
|
}
|
||||||
|
Err(e) => panic!("unexpected error: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user