X509Name.cs 37 KB

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