X509Name.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using System.IO;
  5. using System.Text;
  6. #if SILVERLIGHT || PORTABLE || NETFX_CORE
  7. using System.Collections.Generic;
  8. #endif
  9. using Org.BouncyCastle.Asn1.Pkcs;
  10. using Org.BouncyCastle.Utilities;
  11. using Org.BouncyCastle.Utilities.Encoders;
  12. namespace Org.BouncyCastle.Asn1.X509
  13. {
  14. /**
  15. * <pre>
  16. * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
  17. *
  18. * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
  19. *
  20. * AttributeTypeAndValue ::= SEQUENCE {
  21. * type OBJECT IDENTIFIER,
  22. * value ANY }
  23. * </pre>
  24. */
  25. public class X509Name
  26. : Asn1Encodable
  27. {
  28. /**
  29. * country code - StringType(SIZE(2))
  30. */
  31. public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6");
  32. /**
  33. * organization - StringType(SIZE(1..64))
  34. */
  35. public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10");
  36. /**
  37. * organizational unit name - StringType(SIZE(1..64))
  38. */
  39. public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11");
  40. /**
  41. * Title
  42. */
  43. public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12");
  44. /**
  45. * common name - StringType(SIZE(1..64))
  46. */
  47. public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3");
  48. /**
  49. * street - StringType(SIZE(1..64))
  50. */
  51. public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
  52. /**
  53. * device serial number name - StringType(SIZE(1..64))
  54. */
  55. public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
  56. /**
  57. * locality name - StringType(SIZE(1..64))
  58. */
  59. public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7");
  60. /**
  61. * state, or province name - StringType(SIZE(1..64))
  62. */
  63. public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8");
  64. /**
  65. * Naming attributes of type X520name
  66. */
  67. public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4");
  68. public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42");
  69. public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43");
  70. public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44");
  71. public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45");
  72. /**
  73. * businessCategory - DirectoryString(SIZE(1..128)
  74. */
  75. public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
  76. "2.5.4.15");
  77. /**
  78. * postalCode - DirectoryString(SIZE(1..40)
  79. */
  80. public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
  81. "2.5.4.17");
  82. /**
  83. * dnQualifier - DirectoryString(SIZE(1..64)
  84. */
  85. public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
  86. "2.5.4.46");
  87. /**
  88. * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
  89. */
  90. public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
  91. "2.5.4.65");
  92. /**
  93. * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
  94. */
  95. public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
  96. "1.3.6.1.5.5.7.9.1");
  97. /**
  98. * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
  99. */
  100. public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
  101. "1.3.6.1.5.5.7.9.2");
  102. /**
  103. * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
  104. */
  105. public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
  106. "1.3.6.1.5.5.7.9.3");
  107. /**
  108. * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
  109. * codes only
  110. */
  111. public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
  112. "1.3.6.1.5.5.7.9.4");
  113. /**
  114. * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
  115. * codes only
  116. */
  117. public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
  118. "1.3.6.1.5.5.7.9.5");
  119. /**
  120. * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
  121. */
  122. public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14");
  123. /**
  124. * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
  125. * DirectoryString(SIZE(1..30))
  126. */
  127. public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
  128. /**
  129. * RFC 2256 dmdName
  130. */
  131. public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
  132. /**
  133. * id-at-telephoneNumber
  134. */
  135. public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
  136. /**
  137. * id-at-name
  138. */
  139. public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name;
  140. /**
  141. * Email address (RSA PKCS#9 extension) - IA5String.
  142. * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.</p>
  143. */
  144. public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress;
  145. /**
  146. * more from PKCS#9
  147. */
  148. public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName;
  149. public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress;
  150. /**
  151. * email address in Verisign certificates
  152. */
  153. public static readonly DerObjectIdentifier E = EmailAddress;
  154. /*
  155. * others...
  156. */
  157. public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25");
  158. /**
  159. * LDAP User id.
  160. */
  161. public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1");
  162. /**
  163. * determines whether or not strings should be processed and printed
  164. * from back to front.
  165. */
  166. // public static bool DefaultReverse = false;
  167. public static bool DefaultReverse
  168. {
  169. get { return defaultReverse[0]; }
  170. set { defaultReverse[0] = value; }
  171. }
  172. private static readonly bool[] defaultReverse = { false };
  173. #if SILVERLIGHT || NETFX_CORE || UNITY_WP8 || PORTABLE
  174. /**
  175. * default look up table translating OID values into their common symbols following
  176. * the convention in RFC 2253 with a few extras
  177. */
  178. public static readonly IDictionary DefaultSymbols = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  179. /**
  180. * look up table translating OID values into their common symbols following the convention in RFC 2253
  181. */
  182. public static readonly IDictionary RFC2253Symbols = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  183. /**
  184. * look up table translating OID values into their common symbols following the convention in RFC 1779
  185. *
  186. */
  187. public static readonly IDictionary RFC1779Symbols = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  188. /**
  189. * look up table translating common symbols into their OIDS.
  190. */
  191. public static readonly IDictionary DefaultLookup = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  192. #else
  193. /**
  194. * default look up table translating OID values into their common symbols following
  195. * the convention in RFC 2253 with a few extras
  196. */
  197. public static readonly Hashtable DefaultSymbols = new Hashtable();
  198. /**
  199. * look up table translating OID values into their common symbols following the convention in RFC 2253
  200. */
  201. public static readonly Hashtable RFC2253Symbols = new Hashtable();
  202. /**
  203. * look up table translating OID values into their common symbols following the convention in RFC 1779
  204. *
  205. */
  206. public static readonly Hashtable RFC1779Symbols = new Hashtable();
  207. /**
  208. * look up table translating common symbols into their OIDS.
  209. */
  210. public static readonly Hashtable DefaultLookup = new Hashtable();
  211. #endif
  212. static X509Name()
  213. {
  214. DefaultSymbols.Add(C, "C");
  215. DefaultSymbols.Add(O, "O");
  216. DefaultSymbols.Add(T, "T");
  217. DefaultSymbols.Add(OU, "OU");
  218. DefaultSymbols.Add(CN, "CN");
  219. DefaultSymbols.Add(L, "L");
  220. DefaultSymbols.Add(ST, "ST");
  221. DefaultSymbols.Add(SerialNumber, "SERIALNUMBER");
  222. DefaultSymbols.Add(EmailAddress, "E");
  223. DefaultSymbols.Add(DC, "DC");
  224. DefaultSymbols.Add(UID, "UID");
  225. DefaultSymbols.Add(Street, "STREET");
  226. DefaultSymbols.Add(Surname, "SURNAME");
  227. DefaultSymbols.Add(GivenName, "GIVENNAME");
  228. DefaultSymbols.Add(Initials, "INITIALS");
  229. DefaultSymbols.Add(Generation, "GENERATION");
  230. DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress");
  231. DefaultSymbols.Add(UnstructuredName, "unstructuredName");
  232. DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
  233. DefaultSymbols.Add(DnQualifier, "DN");
  234. DefaultSymbols.Add(Pseudonym, "Pseudonym");
  235. DefaultSymbols.Add(PostalAddress, "PostalAddress");
  236. DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
  237. DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
  238. DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
  239. DefaultSymbols.Add(Gender, "Gender");
  240. DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
  241. DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
  242. DefaultSymbols.Add(PostalCode, "PostalCode");
  243. DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
  244. DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
  245. RFC2253Symbols.Add(C, "C");
  246. RFC2253Symbols.Add(O, "O");
  247. RFC2253Symbols.Add(OU, "OU");
  248. RFC2253Symbols.Add(CN, "CN");
  249. RFC2253Symbols.Add(L, "L");
  250. RFC2253Symbols.Add(ST, "ST");
  251. RFC2253Symbols.Add(Street, "STREET");
  252. RFC2253Symbols.Add(DC, "DC");
  253. RFC2253Symbols.Add(UID, "UID");
  254. RFC1779Symbols.Add(C, "C");
  255. RFC1779Symbols.Add(O, "O");
  256. RFC1779Symbols.Add(OU, "OU");
  257. RFC1779Symbols.Add(CN, "CN");
  258. RFC1779Symbols.Add(L, "L");
  259. RFC1779Symbols.Add(ST, "ST");
  260. RFC1779Symbols.Add(Street, "STREET");
  261. DefaultLookup.Add("c", C);
  262. DefaultLookup.Add("o", O);
  263. DefaultLookup.Add("t", T);
  264. DefaultLookup.Add("ou", OU);
  265. DefaultLookup.Add("cn", CN);
  266. DefaultLookup.Add("l", L);
  267. DefaultLookup.Add("st", ST);
  268. DefaultLookup.Add("serialnumber", SerialNumber);
  269. DefaultLookup.Add("street", Street);
  270. DefaultLookup.Add("emailaddress", E);
  271. DefaultLookup.Add("dc", DC);
  272. DefaultLookup.Add("e", E);
  273. DefaultLookup.Add("uid", UID);
  274. DefaultLookup.Add("surname", Surname);
  275. DefaultLookup.Add("givenname", GivenName);
  276. DefaultLookup.Add("initials", Initials);
  277. DefaultLookup.Add("generation", Generation);
  278. DefaultLookup.Add("unstructuredaddress", UnstructuredAddress);
  279. DefaultLookup.Add("unstructuredname", UnstructuredName);
  280. DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
  281. DefaultLookup.Add("dn", DnQualifier);
  282. DefaultLookup.Add("pseudonym", Pseudonym);
  283. DefaultLookup.Add("postaladdress", PostalAddress);
  284. DefaultLookup.Add("nameofbirth", NameAtBirth);
  285. DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
  286. DefaultLookup.Add("countryofresidence", CountryOfResidence);
  287. DefaultLookup.Add("gender", Gender);
  288. DefaultLookup.Add("placeofbirth", PlaceOfBirth);
  289. DefaultLookup.Add("dateofbirth", DateOfBirth);
  290. DefaultLookup.Add("postalcode", PostalCode);
  291. DefaultLookup.Add("businesscategory", BusinessCategory);
  292. DefaultLookup.Add("telephonenumber", TelephoneNumber);
  293. }
  294. private readonly IList ordering = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  295. private readonly X509NameEntryConverter converter;
  296. private IList values = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  297. private IList added = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  298. private Asn1Sequence seq;
  299. /**
  300. * Return a X509Name based on the passed in tagged object.
  301. *
  302. * @param obj tag object holding name.
  303. * @param explicitly true if explicitly tagged false otherwise.
  304. * @return the X509Name
  305. */
  306. public static X509Name GetInstance(
  307. Asn1TaggedObject obj,
  308. bool explicitly)
  309. {
  310. return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
  311. }
  312. public static X509Name GetInstance(
  313. object obj)
  314. {
  315. if (obj == null || obj is X509Name)
  316. return (X509Name)obj;
  317. if (obj != null)
  318. return new X509Name(Asn1Sequence.GetInstance(obj));
  319. throw new ArgumentException("null object in factory", "obj");
  320. }
  321. protected X509Name()
  322. {
  323. }
  324. /**
  325. * Constructor from Asn1Sequence
  326. *
  327. * the principal will be a list of constructed sets, each containing an (OID, string) pair.
  328. */
  329. protected X509Name(
  330. Asn1Sequence seq)
  331. {
  332. this.seq = seq;
  333. foreach (Asn1Encodable asn1Obj in seq)
  334. {
  335. Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
  336. for (int i = 0; i < asn1Set.Count; i++)
  337. {
  338. Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
  339. if (s.Count != 2)
  340. throw new ArgumentException("badly sized pair");
  341. ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
  342. Asn1Object derValue = s[1].ToAsn1Object();
  343. if (derValue is IAsn1String && !(derValue is DerUniversalString))
  344. {
  345. string v = ((IAsn1String)derValue).GetString();
  346. if (Org.BouncyCastle.Utilities.Platform.StartsWith(v, "#"))
  347. {
  348. v = "\\" + v;
  349. }
  350. values.Add(v);
  351. }
  352. else
  353. {
  354. values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
  355. }
  356. added.Add(i != 0);
  357. }
  358. }
  359. }
  360. /**
  361. * Constructor from a table of attributes with ordering.
  362. * <p>
  363. * it's is assumed the table contains OID/string pairs, and the contents
  364. * of the table are copied into an internal table as part of the
  365. * construction process. The ordering ArrayList should contain the OIDs
  366. * in the order they are meant to be encoded or printed in ToString.</p>
  367. */
  368. public X509Name(
  369. IList ordering,
  370. IDictionary attributes)
  371. : this(ordering, attributes, new X509DefaultEntryConverter())
  372. {
  373. }
  374. /**
  375. * Constructor from a table of attributes with ordering.
  376. * <p>
  377. * it's is assumed the table contains OID/string pairs, and the contents
  378. * of the table are copied into an internal table as part of the
  379. * construction process. The ordering ArrayList should contain the OIDs
  380. * in the order they are meant to be encoded or printed in ToString.</p>
  381. * <p>
  382. * The passed in converter will be used to convert the strings into their
  383. * ASN.1 counterparts.</p>
  384. */
  385. public X509Name(
  386. IList ordering,
  387. IDictionary attributes,
  388. X509NameEntryConverter converter)
  389. {
  390. this.converter = converter;
  391. foreach (DerObjectIdentifier oid in ordering)
  392. {
  393. object attribute = attributes[oid];
  394. if (attribute == null)
  395. {
  396. throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
  397. }
  398. this.ordering.Add(oid);
  399. this.added.Add(false);
  400. this.values.Add(attribute); // copy the hash table
  401. }
  402. }
  403. /**
  404. * Takes two vectors one of the oids and the other of the values.
  405. */
  406. public X509Name(
  407. IList oids,
  408. IList values)
  409. : this(oids, values, new X509DefaultEntryConverter())
  410. {
  411. }
  412. /**
  413. * Takes two vectors one of the oids and the other of the values.
  414. * <p>
  415. * The passed in converter will be used to convert the strings into their
  416. * ASN.1 counterparts.</p>
  417. */
  418. public X509Name(
  419. IList oids,
  420. IList values,
  421. X509NameEntryConverter converter)
  422. {
  423. this.converter = converter;
  424. if (oids.Count != values.Count)
  425. {
  426. throw new ArgumentException("'oids' must be same length as 'values'.");
  427. }
  428. for (int i = 0; i < oids.Count; i++)
  429. {
  430. this.ordering.Add(oids[i]);
  431. this.values.Add(values[i]);
  432. this.added.Add(false);
  433. }
  434. }
  435. /**
  436. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  437. * some such, converting it into an ordered set of name attributes.
  438. */
  439. public X509Name(
  440. string dirName)
  441. : this(DefaultReverse, (IDictionary)DefaultLookup, dirName)
  442. {
  443. }
  444. /**
  445. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  446. * some such, converting it into an ordered set of name attributes with each
  447. * string value being converted to its associated ASN.1 type using the passed
  448. * in converter.
  449. */
  450. public X509Name(
  451. string dirName,
  452. X509NameEntryConverter converter)
  453. : this(DefaultReverse, DefaultLookup, dirName, converter)
  454. {
  455. }
  456. /**
  457. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  458. * some such, converting it into an ordered set of name attributes. If reverse
  459. * is true, create the encoded version of the sequence starting from the
  460. * last element in the string.
  461. */
  462. public X509Name(
  463. bool reverse,
  464. string dirName)
  465. : this(reverse, (IDictionary)DefaultLookup, dirName)
  466. {
  467. }
  468. /**
  469. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  470. * some such, converting it into an ordered set of name attributes with each
  471. * string value being converted to its associated ASN.1 type using the passed
  472. * in converter. If reverse is true the ASN.1 sequence representing the DN will
  473. * be built by starting at the end of the string, rather than the start.
  474. */
  475. public X509Name(
  476. bool reverse,
  477. string dirName,
  478. X509NameEntryConverter converter)
  479. : this(reverse, DefaultLookup, dirName, converter)
  480. {
  481. }
  482. /**
  483. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  484. * some such, converting it into an ordered set of name attributes. lookUp
  485. * should provide a table of lookups, indexed by lowercase only strings and
  486. * yielding a DerObjectIdentifier, other than that OID. and numeric oids
  487. * will be processed automatically.
  488. * <br/>
  489. * If reverse is true, create the encoded version of the sequence
  490. * starting from the last element in the string.
  491. * @param reverse true if we should start scanning from the end (RFC 2553).
  492. * @param lookUp table of names and their oids.
  493. * @param dirName the X.500 string to be parsed.
  494. */
  495. public X509Name(
  496. bool reverse,
  497. IDictionary lookUp,
  498. string dirName)
  499. : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
  500. {
  501. }
  502. private DerObjectIdentifier DecodeOid(
  503. string name,
  504. IDictionary lookUp)
  505. {
  506. if (Org.BouncyCastle.Utilities.Platform.StartsWith(Org.BouncyCastle.Utilities.Platform.ToUpperInvariant(name), "OID."))
  507. {
  508. return new DerObjectIdentifier(name.Substring(4));
  509. }
  510. else if (name[0] >= '0' && name[0] <= '9')
  511. {
  512. return new DerObjectIdentifier(name);
  513. }
  514. DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[Org.BouncyCastle.Utilities.Platform.ToLowerInvariant(name)];
  515. if (oid == null)
  516. {
  517. throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
  518. }
  519. return oid;
  520. }
  521. /**
  522. * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
  523. * some such, converting it into an ordered set of name attributes. lookUp
  524. * should provide a table of lookups, indexed by lowercase only strings and
  525. * yielding a DerObjectIdentifier, other than that OID. and numeric oids
  526. * will be processed automatically. The passed in converter is used to convert the
  527. * string values to the right of each equals sign to their ASN.1 counterparts.
  528. * <br/>
  529. * @param reverse true if we should start scanning from the end, false otherwise.
  530. * @param lookUp table of names and oids.
  531. * @param dirName the string dirName
  532. * @param converter the converter to convert string values into their ASN.1 equivalents
  533. */
  534. public X509Name(
  535. bool reverse,
  536. IDictionary lookUp,
  537. string dirName,
  538. X509NameEntryConverter converter)
  539. {
  540. this.converter = converter;
  541. X509NameTokenizer nTok = new X509NameTokenizer(dirName);
  542. while (nTok.HasMoreTokens())
  543. {
  544. string token = nTok.NextToken();
  545. int index = token.IndexOf('=');
  546. if (index == -1)
  547. {
  548. throw new ArgumentException("badly formated directory string");
  549. }
  550. string name = token.Substring(0, index);
  551. string value = token.Substring(index + 1);
  552. DerObjectIdentifier oid = DecodeOid(name, lookUp);
  553. if (value.IndexOf('+') > 0)
  554. {
  555. X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
  556. string v = vTok.NextToken();
  557. this.ordering.Add(oid);
  558. this.values.Add(v);
  559. this.added.Add(false);
  560. while (vTok.HasMoreTokens())
  561. {
  562. string sv = vTok.NextToken();
  563. int ndx = sv.IndexOf('=');
  564. string nm = sv.Substring(0, ndx);
  565. string vl = sv.Substring(ndx + 1);
  566. this.ordering.Add(DecodeOid(nm, lookUp));
  567. this.values.Add(vl);
  568. this.added.Add(true);
  569. }
  570. }
  571. else
  572. {
  573. this.ordering.Add(oid);
  574. this.values.Add(value);
  575. this.added.Add(false);
  576. }
  577. }
  578. if (reverse)
  579. {
  580. // this.ordering.Reverse();
  581. // this.values.Reverse();
  582. // this.added.Reverse();
  583. IList o = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  584. IList v = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  585. IList a = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  586. int count = 1;
  587. for (int i = 0; i < this.ordering.Count; i++)
  588. {
  589. if (!((bool) this.added[i]))
  590. {
  591. count = 0;
  592. }
  593. int index = count++;
  594. o.Insert(index, this.ordering[i]);
  595. v.Insert(index, this.values[i]);
  596. a.Insert(index, this.added[i]);
  597. }
  598. this.ordering = o;
  599. this.values = v;
  600. this.added = a;
  601. }
  602. }
  603. /**
  604. * return an IList of the oids in the name, in the order they were found.
  605. */
  606. public IList GetOidList()
  607. {
  608. return Org.BouncyCastle.Utilities.Platform.CreateArrayList(ordering);
  609. }
  610. /**
  611. * return an IList of the values found in the name, in the order they
  612. * were found.
  613. */
  614. public IList GetValueList()
  615. {
  616. return GetValueList(null);
  617. }
  618. /**
  619. * return an IList of the values found in the name, in the order they
  620. * were found, with the DN label corresponding to passed in oid.
  621. */
  622. public IList GetValueList(DerObjectIdentifier oid)
  623. {
  624. IList v = Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  625. for (int i = 0; i != values.Count; i++)
  626. {
  627. if (null == oid || oid.Equals(ordering[i]))
  628. {
  629. string val = (string)values[i];
  630. if (Org.BouncyCastle.Utilities.Platform.StartsWith(val, "\\#"))
  631. {
  632. val = val.Substring(1);
  633. }
  634. v.Add(val);
  635. }
  636. }
  637. return v;
  638. }
  639. public override Asn1Object ToAsn1Object()
  640. {
  641. if (seq == null)
  642. {
  643. Asn1EncodableVector vec = new Asn1EncodableVector();
  644. Asn1EncodableVector sVec = new Asn1EncodableVector();
  645. DerObjectIdentifier lstOid = null;
  646. for (int i = 0; i != ordering.Count; i++)
  647. {
  648. DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
  649. string str = (string)values[i];
  650. if (lstOid == null
  651. || ((bool)this.added[i]))
  652. {
  653. }
  654. else
  655. {
  656. vec.Add(new DerSet(sVec));
  657. sVec = new Asn1EncodableVector();
  658. }
  659. sVec.Add(
  660. new DerSequence(
  661. oid,
  662. converter.GetConvertedValue(oid, str)));
  663. lstOid = oid;
  664. }
  665. vec.Add(new DerSet(sVec));
  666. seq = new DerSequence(vec);
  667. }
  668. return seq;
  669. }
  670. /// <param name="other">The X509Name object to test equivalency against.</param>
  671. /// <param name="inOrder">If true, the order of elements must be the same,
  672. /// as well as the values associated with each element.</param>
  673. public bool Equivalent(
  674. X509Name other,
  675. bool inOrder)
  676. {
  677. if (!inOrder)
  678. return this.Equivalent(other);
  679. if (other == null)
  680. return false;
  681. if (other == this)
  682. return true;
  683. int orderingSize = ordering.Count;
  684. if (orderingSize != other.ordering.Count)
  685. return false;
  686. for (int i = 0; i < orderingSize; i++)
  687. {
  688. DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
  689. DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
  690. if (!oid.Equals(oOid))
  691. return false;
  692. string val = (string) values[i];
  693. string oVal = (string) other.values[i];
  694. if (!equivalentStrings(val, oVal))
  695. return false;
  696. }
  697. return true;
  698. }
  699. /**
  700. * test for equivalence - note: case is ignored.
  701. */
  702. public bool Equivalent(
  703. X509Name other)
  704. {
  705. if (other == null)
  706. return false;
  707. if (other == this)
  708. return true;
  709. int orderingSize = ordering.Count;
  710. if (orderingSize != other.ordering.Count)
  711. {
  712. return false;
  713. }
  714. bool[] indexes = new bool[orderingSize];
  715. int start, end, delta;
  716. if (ordering[0].Equals(other.ordering[0])) // guess forward
  717. {
  718. start = 0;
  719. end = orderingSize;
  720. delta = 1;
  721. }
  722. else // guess reversed - most common problem
  723. {
  724. start = orderingSize - 1;
  725. end = -1;
  726. delta = -1;
  727. }
  728. for (int i = start; i != end; i += delta)
  729. {
  730. bool found = false;
  731. DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
  732. string value = (string)values[i];
  733. for (int j = 0; j < orderingSize; j++)
  734. {
  735. if (indexes[j])
  736. {
  737. continue;
  738. }
  739. DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
  740. if (oid.Equals(oOid))
  741. {
  742. string oValue = (string)other.values[j];
  743. if (equivalentStrings(value, oValue))
  744. {
  745. indexes[j] = true;
  746. found = true;
  747. break;
  748. }
  749. }
  750. }
  751. if (!found)
  752. {
  753. return false;
  754. }
  755. }
  756. return true;
  757. }
  758. private static bool equivalentStrings(
  759. string s1,
  760. string s2)
  761. {
  762. string v1 = canonicalize(s1);
  763. string v2 = canonicalize(s2);
  764. if (!v1.Equals(v2))
  765. {
  766. v1 = stripInternalSpaces(v1);
  767. v2 = stripInternalSpaces(v2);
  768. if (!v1.Equals(v2))
  769. {
  770. return false;
  771. }
  772. }
  773. return true;
  774. }
  775. private static string canonicalize(
  776. string s)
  777. {
  778. string v = Org.BouncyCastle.Utilities.Platform.ToLowerInvariant(s).Trim();
  779. if (Org.BouncyCastle.Utilities.Platform.StartsWith(v, "#"))
  780. {
  781. Asn1Object obj = decodeObject(v);
  782. if (obj is IAsn1String)
  783. {
  784. v = Org.BouncyCastle.Utilities.Platform.ToLowerInvariant(((IAsn1String)obj).GetString()).Trim();
  785. }
  786. }
  787. return v;
  788. }
  789. private static Asn1Object decodeObject(
  790. string v)
  791. {
  792. try
  793. {
  794. return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
  795. }
  796. catch (IOException e)
  797. {
  798. throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
  799. }
  800. }
  801. private static string stripInternalSpaces(
  802. string str)
  803. {
  804. StringBuilder res = new StringBuilder();
  805. if (str.Length != 0)
  806. {
  807. char c1 = str[0];
  808. res.Append(c1);
  809. for (int k = 1; k < str.Length; k++)
  810. {
  811. char c2 = str[k];
  812. if (!(c1 == ' ' && c2 == ' '))
  813. {
  814. res.Append(c2);
  815. }
  816. c1 = c2;
  817. }
  818. }
  819. return res.ToString();
  820. }
  821. private void AppendValue(
  822. StringBuilder buf,
  823. IDictionary oidSymbols,
  824. DerObjectIdentifier oid,
  825. string val)
  826. {
  827. string sym = (string)oidSymbols[oid];
  828. if (sym != null)
  829. {
  830. buf.Append(sym);
  831. }
  832. else
  833. {
  834. buf.Append(oid.Id);
  835. }
  836. buf.Append('=');
  837. int index = buf.Length;
  838. buf.Append(val);
  839. int end = buf.Length;
  840. if (Org.BouncyCastle.Utilities.Platform.StartsWith(val, "\\#"))
  841. {
  842. index += 2;
  843. }
  844. while (index != end)
  845. {
  846. if ((buf[index] == ',')
  847. || (buf[index] == '"')
  848. || (buf[index] == '\\')
  849. || (buf[index] == '+')
  850. || (buf[index] == '=')
  851. || (buf[index] == '<')
  852. || (buf[index] == '>')
  853. || (buf[index] == ';'))
  854. {
  855. buf.Insert(index++, "\\");
  856. end++;
  857. }
  858. index++;
  859. }
  860. }
  861. /**
  862. * convert the structure to a string - if reverse is true the
  863. * oids and values are listed out starting with the last element
  864. * in the sequence (ala RFC 2253), otherwise the string will begin
  865. * with the first element of the structure. If no string definition
  866. * for the oid is found in oidSymbols the string value of the oid is
  867. * added. Two standard symbol tables are provided DefaultSymbols, and
  868. * RFC2253Symbols as part of this class.
  869. *
  870. * @param reverse if true start at the end of the sequence and work back.
  871. * @param oidSymbols look up table strings for oids.
  872. */
  873. public string ToString(
  874. bool reverse,
  875. IDictionary oidSymbols)
  876. {
  877. #if SILVERLIGHT || PORTABLE || NETFX_CORE
  878. List<object> components = new List<object>();
  879. #else
  880. ArrayList components = new ArrayList();
  881. #endif
  882. StringBuilder ava = null;
  883. for (int i = 0; i < ordering.Count; i++)
  884. {
  885. if ((bool) added[i])
  886. {
  887. ava.Append('+');
  888. AppendValue(ava, oidSymbols,
  889. (DerObjectIdentifier)ordering[i],
  890. (string)values[i]);
  891. }
  892. else
  893. {
  894. ava = new StringBuilder();
  895. AppendValue(ava, oidSymbols,
  896. (DerObjectIdentifier)ordering[i],
  897. (string)values[i]);
  898. components.Add(ava);
  899. }
  900. }
  901. if (reverse)
  902. {
  903. components.Reverse();
  904. }
  905. StringBuilder buf = new StringBuilder();
  906. if (components.Count > 0)
  907. {
  908. buf.Append(components[0].ToString());
  909. for (int i = 1; i < components.Count; ++i)
  910. {
  911. buf.Append(',');
  912. buf.Append(components[i].ToString());
  913. }
  914. }
  915. return buf.ToString();
  916. }
  917. public override string ToString()
  918. {
  919. return ToString(DefaultReverse, (IDictionary)DefaultSymbols);
  920. }
  921. }
  922. }
  923. #endif