Skip to content

Commit

Permalink
Add RFC5380 DistinguishedName behavior
Browse files Browse the repository at this point in the history
RFC5280 section
[4.2.1.4](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.4),
calls out specific behavior on how issuer and subject names should be
compared. It calls these fields `DistinguishedName`. This change
implements most of this behavior with the exception of prohibited
unicode code points and ignoring bidi code points.
  • Loading branch information
nick-mobilecoin committed May 5, 2023
1 parent 673afbd commit 118565d
Show file tree
Hide file tree
Showing 7 changed files with 579 additions and 4 deletions.
4 changes: 3 additions & 1 deletion verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ repository = { workspace = true }
rust-version = { workspace = true }

[features]
alloc = ["pem-rfc7468/alloc", "dep:const-oid", "dep:p256", "dep:x509-cert", "dep:rsa"]
alloc = ["pem-rfc7468/alloc", "dep:const-oid", "dep:p256", "dep:x509-cert", "dep:rsa", "dep:caseless", "dep:unicode-normalization"]

[dependencies]
caseless = { version = "0.2.1", default-features = false, optional = true }
const-oid = { version = "0.9.2", default-features = false, optional = true }
displaydoc = { version = "0.2.1", default-features = false }
mc-sgx-core-types = "0.6.0"
p256 = { version = "0.13.0", default-features = false, features = ["ecdsa"], optional = true }
pem-rfc7468 = { version = "0.7.0", default-features = false, optional = true }
rsa = { version = "0.9.0", default-features = false, features = ["sha2"], optional = true }
subtle = { version = "2.4.0", default-features = false }
unicode-normalization = { version = "0.1.22", default-features = false, optional = true }
x509-cert = { version = "0.2.0", default-features = false, optional = true }

[dev-dependencies]
Expand Down
2 changes: 2 additions & 0 deletions verifier/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ mod certs;
mod chain;
mod crl;
mod error;
mod name;
mod rfc4518;

pub use algorithm::{PublicKey, Signature};
pub use certs::{UnverifiedCertificate, VerifiedCertificate};
Expand Down
5 changes: 5 additions & 0 deletions verifier/src/x509/certs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ impl VerifiedCertificate {
&self.key
}

/// Get the issuer of the certificate
pub fn issuer(&self) -> &Name {
&self.certificate.tbs_certificate.issuer
}

/// Get the subject name of the certificate
pub fn subject_name(&self) -> &Name {
&self.certificate.tbs_certificate.subject
Expand Down
26 changes: 23 additions & 3 deletions verifier/src/x509/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use super::{Error, Result};
use crate::x509::algorithm::PublicKey;
use crate::x509::certs::VerifiedCertificate;
use crate::x509::crl::UnverifiedCrl;
use crate::x509::name::DistinguishedName;
use alloc::vec::Vec;
use core::time::Duration;

Expand Down Expand Up @@ -56,6 +57,7 @@ impl CertificateChain {
for cert in &self.certificates {
let key = signing_cert.public_key();
let verified_cert = cert.verify(key, unix_time)?;
verify_name_chain(&verified_cert, &signing_cert)?;
verify_certificate_not_revoked(&verified_cert, &signing_cert, crls, unix_time)?;
signing_cert = verified_cert;
}
Expand Down Expand Up @@ -105,15 +107,33 @@ impl TryFrom<&[&[u8]]> for CertificateChain {
}
}

/// See https://datatracker.ietf.org/doc/html/rfc5280#section-7.1
/// The following are required, the others won't be supported
/// * UTF8String
/// * PrintableString
///
/// * Case folding, https://datatracker.ietf.org/doc/html/rfc3454#appendix-B.2
/// * Space handling, https://datatracker.ietf.org/doc/html/rfc4518#section-2.6.1
fn verify_name_chain(cert: &VerifiedCertificate, ca: &VerifiedCertificate) -> Result<()> {
let issuer = DistinguishedName::from(cert.issuer());
let subject = DistinguishedName::from(ca.subject_name());

if issuer == subject {
Ok(())
} else {
Err(Error::NameChaining)
}
}

fn verify_certificate_not_revoked(
cert: &VerifiedCertificate,
trust_anchor: &VerifiedCertificate,
ca: &VerifiedCertificate,
crls: &[UnverifiedCrl],
unix_time: Duration,
) -> Result<()> {
for crl in crls {
if crl.issuer() == trust_anchor.subject_name() {
let verified_crl = crl.verify(trust_anchor.public_key(), unix_time)?;
if crl.issuer() == ca.subject_name() {
let verified_crl = crl.verify(ca.public_key(), unix_time)?;
if verified_crl.is_cert_revoked(cert.serial_number()) {
return Err(Error::CertificateRevoked);
}
Expand Down
2 changes: 2 additions & 0 deletions verifier/src/x509/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum Error {
CrlNotYetValid,
/// Certificate revocation list missing next update time
CrlMissingNextUpdate,
/// Issuer name does not match CAs subject name
NameChaining,
}

impl From<x509_cert::der::Error> for Error {
Expand Down
Loading

0 comments on commit 118565d

Please sign in to comment.