@@ -33,7 +33,6 @@ println!("{}", key_pair.serialize_pem());
3333#![ cfg_attr( docsrs, feature( doc_cfg, doc_auto_cfg) ) ]
3434#![ warn( unreachable_pub) ]
3535
36- use std:: collections:: HashMap ;
3736use std:: fmt;
3837use std:: hash:: Hash ;
3938use std:: net:: IpAddr ;
@@ -299,8 +298,7 @@ See also the RFC 5280 sections on the [issuer](https://tools.ietf.org/html/rfc52
299298and [subject](https://tools.ietf.org/html/rfc5280#section-4.1.2.6) fields.
300299*/
301300pub struct DistinguishedName {
302- entries : HashMap < DnType , DnValue > ,
303- order : Vec < DnType > ,
301+ entries : Vec < ( DnType , DnValue ) > ,
304302}
305303
306304impl DistinguishedName {
@@ -309,20 +307,22 @@ impl DistinguishedName {
309307 Self :: default ( )
310308 }
311309 /// Obtains the attribute value for the given attribute type
312- pub fn get ( & self , ty : & DnType ) -> Option < & DnValue > {
313- self . entries . get ( ty)
310+ pub fn get ( & self , ty : & DnType ) -> Vec < & DnValue > {
311+ self . entries
312+ . iter ( )
313+ . filter_map ( |( dn_type, dn_value) | if ty == dn_type { Some ( dn_value) } else { None } )
314+ . collect ( )
314315 }
315- /// Removes the attribute with the specified DnType
316+ /// Removes all attributes with the specified DnType
316317 ///
317318 /// Returns true when an actual removal happened, false
318319 /// when no attribute with the specified DnType was
319320 /// found.
320321 pub fn remove ( & mut self , ty : DnType ) -> bool {
321- let removed = self . entries . remove ( & ty) . is_some ( ) ;
322- if removed {
323- self . order . retain ( |ty_o| & ty != ty_o) ;
324- }
325- removed
322+ let prev_len = self . entries . len ( ) ;
323+ self . entries . retain ( |( dn_type, _dn_val) | dn_type != & ty) ;
324+
325+ prev_len != self . entries . len ( )
326326 }
327327 /// Inserts or updates an attribute that consists of type and name
328328 ///
@@ -331,20 +331,41 @@ impl DistinguishedName {
331331 /// let mut dn = DistinguishedName::new();
332332 /// dn.push(DnType::OrganizationName, "Crab widgits SE");
333333 /// dn.push(DnType::CommonName, DnValue::PrintableString("Master Cert".try_into().unwrap()));
334- /// assert_eq!(dn.get(&DnType::OrganizationName), Some(&DnValue::Utf8String("Crab widgits SE".to_string())));
335- /// assert_eq!(dn.get(&DnType::CommonName), Some(&DnValue::PrintableString("Master Cert".try_into().unwrap())));
334+ /// assert_eq!(dn.get(&DnType::OrganizationName).get(0) , Some(&DnValue::Utf8String("Crab widgits SE".to_string())).as_ref( ));
335+ /// assert_eq!(dn.get(&DnType::CommonName).get(0) , Some(&DnValue::PrintableString("Master Cert".try_into().unwrap())).as_ref( ));
336336 /// ```
337337 pub fn push ( & mut self , ty : DnType , s : impl Into < DnValue > ) {
338- if !self . entries . contains_key ( & ty) {
339- self . order . push ( ty. clone ( ) ) ;
338+ self . entries . push ( ( ty, s. into ( ) ) ) ;
339+ }
340+
341+ /// Replaces the *fist occurrence* of a type with a new value.
342+ /// This is a convenience function to avoid duplicating values.
343+ ///
344+ /// If there are multiple occurrences of a type there is currently no way of changing the besides iterating over the types and values of an existing instance and creating a new instance.
345+ ///
346+ /// ```
347+ /// # use rcgen::{DistinguishedName, DnType, DnValue};
348+ /// let mut dn = DistinguishedName::new();
349+ /// dn.push(DnType::CommonName, DnValue::PrintableString("Master Cert".try_into().unwrap()));
350+ /// assert_eq!(dn.get(&DnType::CommonName).get(0), Some(&DnValue::PrintableString("Master Cert".try_into().unwrap())).as_ref());
351+ /// dn.push(DnType::CommonName, DnValue::PrintableString("Other Master Cert".try_into().unwrap()));
352+ /// assert_eq!(dn.get(&DnType::CommonName).get(1), Some(&DnValue::PrintableString("Other Master Cert".try_into().unwrap())).as_ref());
353+ /// ```
354+ pub fn replace_or_push ( & mut self , ty : DnType , s : impl Into < DnValue > ) {
355+ for ( dn_type, dn_value) in self . entries . iter_mut ( ) {
356+ if * dn_type == ty {
357+ * dn_value = s. into ( ) ;
358+ return ;
359+ }
340360 }
341- self . entries . insert ( ty, s. into ( ) ) ;
361+
362+ self . push ( ty, s)
342363 }
364+
343365 /// Iterate over the entries
344366 pub fn iter ( & self ) -> DistinguishedNameIterator < ' _ > {
345367 DistinguishedNameIterator {
346- distinguished_name : self ,
347- iter : self . order . iter ( ) ,
368+ iter : self . entries . iter ( ) ,
348369 }
349370 }
350371
@@ -397,17 +418,14 @@ impl DistinguishedName {
397418Iterator over [`DistinguishedName`] entries
398419*/
399420pub struct DistinguishedNameIterator < ' a > {
400- distinguished_name : & ' a DistinguishedName ,
401- iter : std:: slice:: Iter < ' a , DnType > ,
421+ iter : std:: slice:: Iter < ' a , ( DnType , DnValue ) > ,
402422}
403423
404424impl < ' a > Iterator for DistinguishedNameIterator < ' a > {
405425 type Item = ( & ' a DnType , & ' a DnValue ) ;
406426
407427 fn next ( & mut self ) -> Option < Self :: Item > {
408- self . iter
409- . next ( )
410- . and_then ( |ty| self . distinguished_name . entries . get ( ty) . map ( |v| ( ty, v) ) )
428+ self . iter . next ( ) . map ( |( key, value) | ( key, value) )
411429 }
412430}
413431
@@ -568,7 +586,7 @@ fn write_dt_utc_or_generalized(writer: DERWriter, dt: OffsetDateTime) {
568586 }
569587}
570588
571- fn write_distinguished_name ( writer : DERWriter , dn : & DistinguishedName ) {
589+ fn write_distinguished_name ( writer : DERWriter , dn : DistinguishedName ) {
572590 writer. write_sequence ( |writer| {
573591 for ( ty, content) in dn. iter ( ) {
574592 writer. next ( ) . write_set ( |writer| {
@@ -596,7 +614,7 @@ fn write_distinguished_name(writer: DERWriter, dn: &DistinguishedName) {
596614 . write_tagged_implicit ( TAG_UNIVERSALSTRING , |writer| {
597615 writer. write_bytes ( s. as_bytes ( ) )
598616 } ) ,
599- DnValue :: Utf8String ( s) => writer. next ( ) . write_utf8_string ( s) ,
617+ DnValue :: Utf8String ( s) => writer. next ( ) . write_utf8_string ( s. as_str ( ) ) ,
600618 }
601619 } ) ;
602620 } ) ;
@@ -776,6 +794,83 @@ mod tests {
776794 }
777795 }
778796
797+ #[ test]
798+ fn distinguished_name_remove_no_match ( ) {
799+ let mut dn = DistinguishedName :: new ( ) ;
800+ // Domain Component (DC)
801+ let dc_type = DnType :: CustomDnType ( vec ! [ 0 , 9 , 2342 , 19200300 , 100 , 1 , 25 ] ) ;
802+
803+ dn. push (
804+ DnType :: CommonName ,
805+ DnValue :: PrintableString ( "Master Cert" . try_into ( ) . unwrap ( ) ) ,
806+ ) ;
807+
808+ let removed = dn. remove ( dc_type. clone ( ) ) ;
809+ assert ! ( !removed) ;
810+ assert_eq ! (
811+ dn. get( & DnType :: CommonName ) . get( 0 ) ,
812+ Some ( & DnValue :: PrintableString ( "Master Cert" . try_into( ) . unwrap( ) ) ) . as_ref( )
813+ ) ;
814+ assert_eq ! ( dn. entries. len( ) , 1 ) ;
815+ assert_eq ! ( dn. get( & dc_type) . get( 0 ) , None ) ;
816+ }
817+
818+ #[ test]
819+ fn distinguished_name_remove_single_attribute ( ) {
820+ let mut dn = DistinguishedName :: new ( ) ;
821+ // Domain Component (DC)
822+ let dc_type = DnType :: CustomDnType ( vec ! [ 0 , 9 , 2342 , 19200300 , 100 , 1 , 25 ] ) ;
823+
824+ dn. push (
825+ DnType :: CommonName ,
826+ DnValue :: PrintableString ( "Master Cert" . try_into ( ) . unwrap ( ) ) ,
827+ ) ;
828+ dn. push (
829+ dc_type. clone ( ) ,
830+ DnValue :: PrintableString ( "example" . try_into ( ) . unwrap ( ) ) ,
831+ ) ;
832+
833+ let removed = dn. remove ( dc_type. clone ( ) ) ;
834+ assert ! ( removed) ;
835+ assert_eq ! (
836+ dn. get( & DnType :: CommonName ) . get( 0 ) ,
837+ Some ( & DnValue :: PrintableString ( "Master Cert" . try_into( ) . unwrap( ) ) ) . as_ref( )
838+ ) ;
839+ assert_eq ! ( dn. entries. len( ) , 1 ) ;
840+ assert_eq ! ( dn. get( & dc_type) . get( 0 ) , None ) ;
841+ }
842+
843+ #[ test]
844+ fn distinguished_name_remove_multiple_attributes_of_same_type ( ) {
845+ let mut dn = DistinguishedName :: new ( ) ;
846+ // Domain Component (DC)
847+ let dc_type = DnType :: CustomDnType ( vec ! [ 0 , 9 , 2342 , 19200300 , 100 , 1 , 25 ] ) ;
848+
849+ dn. push (
850+ DnType :: CommonName ,
851+ DnValue :: PrintableString ( "Master Cert" . try_into ( ) . unwrap ( ) ) ,
852+ ) ;
853+ dn. push (
854+ // Domain Component (DC)
855+ dc_type. clone ( ) ,
856+ DnValue :: PrintableString ( "example" . try_into ( ) . unwrap ( ) ) ,
857+ ) ;
858+ dn. push (
859+ dc_type. clone ( ) ,
860+ DnValue :: PrintableString ( "com" . try_into ( ) . unwrap ( ) ) ,
861+ ) ;
862+
863+ let removed = dn. remove ( dc_type. clone ( ) ) ;
864+ assert ! ( removed) ;
865+ assert_eq ! (
866+ dn. get( & DnType :: CommonName ) . get( 0 ) ,
867+ Some ( & DnValue :: PrintableString ( "Master Cert" . try_into( ) . unwrap( ) ) ) . as_ref( )
868+ ) ;
869+ assert_eq ! ( dn. entries. len( ) , 1 ) ;
870+ assert_eq ! ( dn. get( & dc_type) . get( 0 ) , None ) ;
871+ assert_eq ! ( dn. get( & dc_type) . get( 1 ) , None ) ;
872+ }
873+
779874 #[ cfg( feature = "x509-parser" ) ]
780875 mod test_ip_address_from_octets {
781876 use super :: super :: ip_addr_from_octets;
0 commit comments