diff --git a/const-oid/src/db.rs b/const-oid/src/db.rs index 85b663896..03bd055b4 100644 --- a/const-oid/src/db.rs +++ b/const-oid/src/db.rs @@ -36,6 +36,7 @@ const fn eq_case(lhs: &[u8], rhs: &[u8]) -> bool { } /// A query interface for OIDs/Names. +#[derive(Copy, Clone)] pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]); impl<'a> Database<'a> { @@ -82,6 +83,43 @@ impl<'a> Database<'a> { None } + + /// Finds the shortest named oid by its associated OID. + pub const fn find_names_for_oid<'o>(&self, oid: &'o ObjectIdentifier) -> Names<'a, 'o> { + Names { + database: *self, + oid, + position: 0, + } + } +} + +/// Iterator returning the multiple names that may be associated with an OID. +pub struct Names<'a, 'o> { + database: Database<'a>, + oid: &'o ObjectIdentifier, + position: usize, +} + +impl<'a, 'o> Iterator for Names<'a, 'o> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + let mut i = self.position; + + while i < self.database.0.len() { + let lhs = self.database.0[i].0; + + if lhs.buffer.eq(&self.oid.buffer) { + self.position = i + 1; + return Some(self.database.0[i].1); + } + + i += 1; + } + + return None; + } } #[cfg(test)] diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index 01bdc0d31..342d32a8d 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" rust-version = "1.65" [dependencies] -const-oid = { version = "0.9.2", features = ["db"] } # TODO: path = "../const-oid" +const-oid = { version = "0.10.0-pre", features = ["db"] } # TODO: path = "../const-oid" der = { version = "0.7.6", features = ["alloc", "derive", "flagset", "oid"] } spki = { version = "0.7.2", features = ["alloc"] } diff --git a/x509-cert/src/attr.rs b/x509-cert/src/attr.rs index 732792fa8..6dd688474 100644 --- a/x509-cert/src/attr.rs +++ b/x509-cert/src/attr.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use const_oid::db::{ rfc4519::{COUNTRY_NAME, DOMAIN_COMPONENT, SERIAL_NUMBER}, - DB, + Database, DB, }; use core::{ fmt::{self, Write}, @@ -260,7 +260,7 @@ impl fmt::Display for AttributeTypeAndValue { _ => None, }; - if let (Some(key), Some(val)) = (DB.by_oid(&self.oid), val) { + if let (Some(key), Some(val)) = (DB.shortest_name_by_oid(&self.oid), val) { write!(f, "{}=", key.to_ascii_uppercase())?; let mut iter = val.char_indices().peekable(); @@ -285,3 +285,26 @@ impl fmt::Display for AttributeTypeAndValue { Ok(()) } } + +/// Helper trait to bring shortest name by oid lookups to Database +trait ShortestName { + fn shortest_name_by_oid(&self, oid: &ObjectIdentifier) -> Option<&str>; +} + +impl<'a> ShortestName for Database<'a> { + fn shortest_name_by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str> { + let mut best_match: Option<&'a str> = None; + + for m in self.find_names_for_oid(oid) { + if let Some(previous) = best_match { + if m.len() < previous.len() { + best_match = Some(m); + } + } else { + best_match = Some(m); + } + } + + best_match + } +} diff --git a/x509-cert/tests/name.rs b/x509-cert/tests/name.rs index ea8757500..27af2b563 100644 --- a/x509-cert/tests/name.rs +++ b/x509-cert/tests/name.rs @@ -85,7 +85,7 @@ fn decode_name() { let rdn1 = Name::from_der(&hex!("3081c0310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e205669657731133011060355040a0c0a476f6f676c65204c4c43311e301c06035504030c154f51464176444e4457732e676f6f676c652e636f6d31243022060355040b0c1b6d616e6167656d656e743a64732e67726f75702e3338393131313131293027060a0992268993f22c6401010c196964656e746974793a64732e67726f75702e33383931313131")[..]); let rdn1a = rdn1.unwrap(); let name = rdn1a.to_string(); - assert_eq!(name, "UID=identity:ds.group.3891111,OU=management:ds.group.3891111,CN=OQFAvDNDWs.google.com,O=Google LLC,L=Mountain View,STATEORPROVINCENAME=California,C=US"); + assert_eq!(name, "UID=identity:ds.group.3891111,OU=management:ds.group.3891111,CN=OQFAvDNDWs.google.com,O=Google LLC,L=Mountain View,ST=California,C=US"); } }