using System; using System.Collections; using System.IO; using System.Text; #if SILVERLIGHT || PORTABLE using System.Collections.Generic; #endif using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; namespace Org.BouncyCastle.Asn1.X509 { /** *
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName * * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue * * AttributeTypeAndValue ::= SEQUENCE { * type OBJECT IDENTIFIER, * value ANY } **/ public class X509Name : Asn1Encodable { /** * country code - StringType(SIZE(2)) */ public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); /** * organization - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); /** * organizational unit name - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); /** * Title */ public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); /** * common name - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); /** * street - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9"); /** * device serial number name - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5"); /** * locality name - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); /** * state, or province name - StringType(SIZE(1..64)) */ public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); /** * Naming attributes of type X520name */ public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4"); public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42"); public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43"); public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44"); public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45"); /** * businessCategory - DirectoryString(SIZE(1..128) */ public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier( "2.5.4.15"); /** * postalCode - DirectoryString(SIZE(1..40) */ public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier( "2.5.4.17"); /** * dnQualifier - DirectoryString(SIZE(1..64) */ public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier( "2.5.4.46"); /** * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) */ public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier( "2.5.4.65"); /** * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z */ public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier( "1.3.6.1.5.5.7.9.1"); /** * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) */ public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier( "1.3.6.1.5.5.7.9.2"); /** * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" */ public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier( "1.3.6.1.5.5.7.9.3"); /** * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier( "1.3.6.1.5.5.7.9.4"); /** * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier( "1.3.6.1.5.5.7.9.5"); /** * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) */ public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14"); /** * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF * DirectoryString(SIZE(1..30)) */ public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16"); /** * RFC 2256 dmdName */ public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54"); /** * id-at-telephoneNumber */ public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber; /** * id-at-name */ public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name; /** * Email address (RSA PKCS#9 extension) - IA5String. *
Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
*/ public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress; /** * more from PKCS#9 */ public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName; public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress; /** * email address in Verisign certificates */ public static readonly DerObjectIdentifier E = EmailAddress; /* * others... */ public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); /** * LDAP User id. */ public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); /** * determines whether or not strings should be processed and printed * from back to front. */ // public static bool DefaultReverse = false; public static bool DefaultReverse { get { return defaultReverse[0]; } set { defaultReverse[0] = value; } } private static readonly bool[] defaultReverse = { false }; #if SILVERLIGHT || PORTABLE /** * default look up table translating OID values into their common symbols following * the convention in RFC 2253 with a few extras */ public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable(); /** * look up table translating OID values into their common symbols following the convention in RFC 2253 */ public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable(); /** * look up table translating OID values into their common symbols following the convention in RFC 1779 * */ public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable(); /** * look up table translating common symbols into their OIDS. */ public static readonly IDictionary DefaultLookup = Platform.CreateHashtable(); #else /** * default look up table translating OID values into their common symbols following * the convention in RFC 2253 with a few extras */ public static readonly Hashtable DefaultSymbols = new Hashtable(); /** * look up table translating OID values into their common symbols following the convention in RFC 2253 */ public static readonly Hashtable RFC2253Symbols = new Hashtable(); /** * look up table translating OID values into their common symbols following the convention in RFC 1779 * */ public static readonly Hashtable RFC1779Symbols = new Hashtable(); /** * look up table translating common symbols into their OIDS. */ public static readonly Hashtable DefaultLookup = new Hashtable(); #endif static X509Name() { DefaultSymbols.Add(C, "C"); DefaultSymbols.Add(O, "O"); DefaultSymbols.Add(T, "T"); DefaultSymbols.Add(OU, "OU"); DefaultSymbols.Add(CN, "CN"); DefaultSymbols.Add(L, "L"); DefaultSymbols.Add(ST, "ST"); DefaultSymbols.Add(SerialNumber, "SERIALNUMBER"); DefaultSymbols.Add(EmailAddress, "E"); DefaultSymbols.Add(DC, "DC"); DefaultSymbols.Add(UID, "UID"); DefaultSymbols.Add(Street, "STREET"); DefaultSymbols.Add(Surname, "SURNAME"); DefaultSymbols.Add(GivenName, "GIVENNAME"); DefaultSymbols.Add(Initials, "INITIALS"); DefaultSymbols.Add(Generation, "GENERATION"); DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress"); DefaultSymbols.Add(UnstructuredName, "unstructuredName"); DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier"); DefaultSymbols.Add(DnQualifier, "DN"); DefaultSymbols.Add(Pseudonym, "Pseudonym"); DefaultSymbols.Add(PostalAddress, "PostalAddress"); DefaultSymbols.Add(NameAtBirth, "NameAtBirth"); DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship"); DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence"); DefaultSymbols.Add(Gender, "Gender"); DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth"); DefaultSymbols.Add(DateOfBirth, "DateOfBirth"); DefaultSymbols.Add(PostalCode, "PostalCode"); DefaultSymbols.Add(BusinessCategory, "BusinessCategory"); DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber"); RFC2253Symbols.Add(C, "C"); RFC2253Symbols.Add(O, "O"); RFC2253Symbols.Add(OU, "OU"); RFC2253Symbols.Add(CN, "CN"); RFC2253Symbols.Add(L, "L"); RFC2253Symbols.Add(ST, "ST"); RFC2253Symbols.Add(Street, "STREET"); RFC2253Symbols.Add(DC, "DC"); RFC2253Symbols.Add(UID, "UID"); RFC1779Symbols.Add(C, "C"); RFC1779Symbols.Add(O, "O"); RFC1779Symbols.Add(OU, "OU"); RFC1779Symbols.Add(CN, "CN"); RFC1779Symbols.Add(L, "L"); RFC1779Symbols.Add(ST, "ST"); RFC1779Symbols.Add(Street, "STREET"); DefaultLookup.Add("c", C); DefaultLookup.Add("o", O); DefaultLookup.Add("t", T); DefaultLookup.Add("ou", OU); DefaultLookup.Add("cn", CN); DefaultLookup.Add("l", L); DefaultLookup.Add("st", ST); DefaultLookup.Add("serialnumber", SerialNumber); DefaultLookup.Add("street", Street); DefaultLookup.Add("emailaddress", E); DefaultLookup.Add("dc", DC); DefaultLookup.Add("e", E); DefaultLookup.Add("uid", UID); DefaultLookup.Add("surname", Surname); DefaultLookup.Add("givenname", GivenName); DefaultLookup.Add("initials", Initials); DefaultLookup.Add("generation", Generation); DefaultLookup.Add("unstructuredaddress", UnstructuredAddress); DefaultLookup.Add("unstructuredname", UnstructuredName); DefaultLookup.Add("uniqueidentifier", UniqueIdentifier); DefaultLookup.Add("dn", DnQualifier); DefaultLookup.Add("pseudonym", Pseudonym); DefaultLookup.Add("postaladdress", PostalAddress); DefaultLookup.Add("nameofbirth", NameAtBirth); DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship); DefaultLookup.Add("countryofresidence", CountryOfResidence); DefaultLookup.Add("gender", Gender); DefaultLookup.Add("placeofbirth", PlaceOfBirth); DefaultLookup.Add("dateofbirth", DateOfBirth); DefaultLookup.Add("postalcode", PostalCode); DefaultLookup.Add("businesscategory", BusinessCategory); DefaultLookup.Add("telephonenumber", TelephoneNumber); } private readonly IList ordering = Platform.CreateArrayList(); private readonly X509NameEntryConverter converter; private IList values = Platform.CreateArrayList(); private IList added = Platform.CreateArrayList(); private Asn1Sequence seq; /** * Return a X509Name based on the passed in tagged object. * * @param obj tag object holding name. * @param explicitly true if explicitly tagged false otherwise. * @return the X509Name */ public static X509Name GetInstance( Asn1TaggedObject obj, bool explicitly) { return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); } public static X509Name GetInstance( object obj) { if (obj == null || obj is X509Name) return (X509Name)obj; if (obj != null) return new X509Name(Asn1Sequence.GetInstance(obj)); throw new ArgumentException("null object in factory", "obj"); } protected X509Name() { } /** * Constructor from Asn1Sequence * * the principal will be a list of constructed sets, each containing an (OID, string) pair. */ protected X509Name( Asn1Sequence seq) { this.seq = seq; foreach (Asn1Encodable asn1Obj in seq) { Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object()); for (int i = 0; i < asn1Set.Count; i++) { Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object()); if (s.Count != 2) throw new ArgumentException("badly sized pair"); ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object())); Asn1Object derValue = s[1].ToAsn1Object(); if (derValue is IAsn1String && !(derValue is DerUniversalString)) { string v = ((IAsn1String)derValue).GetString(); if (v.StartsWith("#")) { v = "\\" + v; } values.Add(v); } else { values.Add("#" + Hex.ToHexString(derValue.GetEncoded())); } added.Add(i != 0); } } } /** * Constructor from a table of attributes with ordering. ** it's is assumed the table contains OID/string pairs, and the contents * of the table are copied into an internal table as part of the * construction process. The ordering ArrayList should contain the OIDs * in the order they are meant to be encoded or printed in ToString.
*/ public X509Name( IList ordering, IDictionary attributes) : this(ordering, attributes, new X509DefaultEntryConverter()) { } /** * Constructor from a table of attributes with ordering. ** it's is assumed the table contains OID/string pairs, and the contents * of the table are copied into an internal table as part of the * construction process. The ordering ArrayList should contain the OIDs * in the order they are meant to be encoded or printed in ToString.
** The passed in converter will be used to convert the strings into their * ASN.1 counterparts.
*/ public X509Name( IList ordering, IDictionary attributes, X509NameEntryConverter converter) { this.converter = converter; foreach (DerObjectIdentifier oid in ordering) { object attribute = attributes[oid]; if (attribute == null) { throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name"); } this.ordering.Add(oid); this.added.Add(false); this.values.Add(attribute); // copy the hash table } } /** * Takes two vectors one of the oids and the other of the values. */ public X509Name( IList oids, IList values) : this(oids, values, new X509DefaultEntryConverter()) { } /** * Takes two vectors one of the oids and the other of the values. ** The passed in converter will be used to convert the strings into their * ASN.1 counterparts.
*/ public X509Name( IList oids, IList values, X509NameEntryConverter converter) { this.converter = converter; if (oids.Count != values.Count) { throw new ArgumentException("'oids' must be same length as 'values'."); } for (int i = 0; i < oids.Count; i++) { this.ordering.Add(oids[i]); this.values.Add(values[i]); this.added.Add(false); } } // private static bool IsEncoded( // string s) // { // return s.StartsWith("#"); // } /** * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or * some such, converting it into an ordered set of name attributes. */ public X509Name( string dirName) : this(DefaultReverse, (IDictionary)DefaultLookup, dirName) { } /** * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or * some such, converting it into an ordered set of name attributes with each * string value being converted to its associated ASN.1 type using the passed * in converter. */ public X509Name( string dirName, X509NameEntryConverter converter) : this(DefaultReverse, DefaultLookup, dirName, converter) { } /** * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or * some such, converting it into an ordered set of name attributes. If reverse * is true, create the encoded version of the sequence starting from the * last element in the string. */ public X509Name( bool reverse, string dirName) : this(reverse, (IDictionary)DefaultLookup, dirName) { } /** * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or * some such, converting it into an ordered set of name attributes with each * string value being converted to its associated ASN.1 type using the passed * in converter. If reverse is true the ASN.1 sequence representing the DN will * be built by starting at the end of the string, rather than the start. */ public X509Name( bool reverse, string dirName, X509NameEntryConverter converter) : this(reverse, DefaultLookup, dirName, converter) { } /** * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or * some such, converting it into an ordered set of name attributes. lookUp * should provide a table of lookups, indexed by lowercase only strings and * yielding a DerObjectIdentifier, other than that OID. and numeric oids * will be processed automatically. *