AttributeCertificateHolder.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  12. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
  13. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.X509
  14. {
  15. /// <remarks>
  16. /// The Holder object.
  17. /// <pre>
  18. /// Holder ::= SEQUENCE {
  19. /// baseCertificateID [0] IssuerSerial OPTIONAL,
  20. /// -- the issuer and serial number of
  21. /// -- the holder's Public Key Certificate
  22. /// entityName [1] GeneralNames OPTIONAL,
  23. /// -- the name of the claimant or role
  24. /// objectDigestInfo [2] ObjectDigestInfo OPTIONAL
  25. /// -- used to directly authenticate the holder,
  26. /// -- for example, an executable
  27. /// }
  28. /// </pre>
  29. /// </remarks>
  30. public class AttributeCertificateHolder
  31. //: CertSelector, Selector
  32. : IX509Selector
  33. {
  34. internal readonly Holder holder;
  35. internal AttributeCertificateHolder(
  36. Asn1Sequence seq)
  37. {
  38. holder = Holder.GetInstance(seq);
  39. }
  40. public AttributeCertificateHolder(
  41. X509Name issuerName,
  42. BigInteger serialNumber)
  43. {
  44. holder = new Holder(
  45. new IssuerSerial(
  46. GenerateGeneralNames(issuerName),
  47. new DerInteger(serialNumber)));
  48. }
  49. public AttributeCertificateHolder(
  50. X509Certificate cert)
  51. {
  52. X509Name name;
  53. try
  54. {
  55. name = PrincipalUtilities.GetIssuerX509Principal(cert);
  56. }
  57. catch (Exception e)
  58. {
  59. throw new CertificateParsingException(e.Message);
  60. }
  61. holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
  62. }
  63. public AttributeCertificateHolder(
  64. X509Name principal)
  65. {
  66. holder = new Holder(GenerateGeneralNames(principal));
  67. }
  68. /**
  69. * Constructs a holder for v2 attribute certificates with a hash value for
  70. * some type of object.
  71. * <p>
  72. * <code>digestedObjectType</code> can be one of the following:
  73. * <ul>
  74. * <li>0 - publicKey - A hash of the public key of the holder must be
  75. * passed.</li>
  76. * <li>1 - publicKeyCert - A hash of the public key certificate of the
  77. * holder must be passed.</li>
  78. * <li>2 - otherObjectDigest - A hash of some other object type must be
  79. * passed. <code>otherObjectTypeID</code> must not be empty.</li>
  80. * </ul>
  81. * </p>
  82. * <p>This cannot be used if a v1 attribute certificate is used.</p>
  83. *
  84. * @param digestedObjectType The digest object type.
  85. * @param digestAlgorithm The algorithm identifier for the hash.
  86. * @param otherObjectTypeID The object type ID if
  87. * <code>digestedObjectType</code> is
  88. * <code>otherObjectDigest</code>.
  89. * @param objectDigest The hash value.
  90. */
  91. public AttributeCertificateHolder(
  92. int digestedObjectType,
  93. string digestAlgorithm,
  94. string otherObjectTypeID,
  95. byte[] objectDigest)
  96. {
  97. // TODO Allow 'objectDigest' to be null?
  98. holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID,
  99. new AlgorithmIdentifier(new DerObjectIdentifier(digestAlgorithm)), Arrays.Clone(objectDigest)));
  100. }
  101. /**
  102. * Returns the digest object type if an object digest info is used.
  103. * <p>
  104. * <ul>
  105. * <li>0 - publicKey - A hash of the public key of the holder must be
  106. * passed.</li>
  107. * <li>1 - publicKeyCert - A hash of the public key certificate of the
  108. * holder must be passed.</li>
  109. * <li>2 - otherObjectDigest - A hash of some other object type must be
  110. * passed. <code>otherObjectTypeID</code> must not be empty.</li>
  111. * </ul>
  112. * </p>
  113. *
  114. * @return The digest object type or -1 if no object digest info is set.
  115. */
  116. public int DigestedObjectType
  117. {
  118. get
  119. {
  120. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  121. return odi == null
  122. ? -1
  123. : odi.DigestedObjectType.IntValueExact;
  124. }
  125. }
  126. /**
  127. * Returns the other object type ID if an object digest info is used.
  128. *
  129. * @return The other object type ID or <code>null</code> if no object
  130. * digest info is set.
  131. */
  132. public string DigestAlgorithm
  133. {
  134. get
  135. {
  136. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  137. return odi == null
  138. ? null
  139. : odi.DigestAlgorithm.Algorithm.Id;
  140. }
  141. }
  142. /**
  143. * Returns the hash if an object digest info is used.
  144. *
  145. * @return The hash or <code>null</code> if no object digest info is set.
  146. */
  147. public byte[] GetObjectDigest()
  148. {
  149. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  150. return odi == null
  151. ? null
  152. : odi.ObjectDigest.GetBytes();
  153. }
  154. /**
  155. * Returns the digest algorithm ID if an object digest info is used.
  156. *
  157. * @return The digest algorithm ID or <code>null</code> if no object
  158. * digest info is set.
  159. */
  160. public string OtherObjectTypeID
  161. {
  162. get
  163. {
  164. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  165. return odi == null
  166. ? null
  167. : odi.OtherObjectTypeID.Id;
  168. }
  169. }
  170. private GeneralNames GenerateGeneralNames(
  171. X509Name principal)
  172. {
  173. // return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
  174. return new GeneralNames(new GeneralName(principal));
  175. }
  176. private bool MatchesDN(
  177. X509Name subject,
  178. GeneralNames targets)
  179. {
  180. GeneralName[] names = targets.GetNames();
  181. for (int i = 0; i != names.Length; i++)
  182. {
  183. GeneralName gn = names[i];
  184. if (gn.TagNo == GeneralName.DirectoryName)
  185. {
  186. try
  187. {
  188. if (X509Name.GetInstance(gn.Name).Equivalent(subject))
  189. {
  190. return true;
  191. }
  192. }
  193. catch (Exception)
  194. {
  195. }
  196. }
  197. }
  198. return false;
  199. }
  200. private object[] GetNames(
  201. GeneralName[] names)
  202. {
  203. int count = 0;
  204. for (int i = 0; i != names.Length; i++)
  205. {
  206. if (names[i].TagNo == GeneralName.DirectoryName)
  207. {
  208. ++count;
  209. }
  210. }
  211. object[] result = new object[count];
  212. int pos = 0;
  213. for (int i = 0; i != names.Length; i++)
  214. {
  215. if (names[i].TagNo == GeneralName.DirectoryName)
  216. {
  217. result[pos++] = X509Name.GetInstance(names[i].Name);
  218. }
  219. }
  220. return result;
  221. }
  222. private X509Name[] GetPrincipals(
  223. GeneralNames names)
  224. {
  225. object[] p = this.GetNames(names.GetNames());
  226. int count = 0;
  227. for (int i = 0; i != p.Length; i++)
  228. {
  229. if (p[i] is X509Name)
  230. {
  231. ++count;
  232. }
  233. }
  234. X509Name[] result = new X509Name[count];
  235. int pos = 0;
  236. for (int i = 0; i != p.Length; i++)
  237. {
  238. if (p[i] is X509Name)
  239. {
  240. result[pos++] = (X509Name)p[i];
  241. }
  242. }
  243. return result;
  244. }
  245. /**
  246. * Return any principal objects inside the attribute certificate holder entity names field.
  247. *
  248. * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
  249. */
  250. public X509Name[] GetEntityNames()
  251. {
  252. if (holder.EntityName != null)
  253. {
  254. return GetPrincipals(holder.EntityName);
  255. }
  256. return null;
  257. }
  258. /**
  259. * Return the principals associated with the issuer attached to this holder
  260. *
  261. * @return an array of principals, null if no BaseCertificateID is set.
  262. */
  263. public X509Name[] GetIssuer()
  264. {
  265. if (holder.BaseCertificateID != null)
  266. {
  267. return GetPrincipals(holder.BaseCertificateID.Issuer);
  268. }
  269. return null;
  270. }
  271. /**
  272. * Return the serial number associated with the issuer attached to this holder.
  273. *
  274. * @return the certificate serial number, null if no BaseCertificateID is set.
  275. */
  276. public BigInteger SerialNumber
  277. {
  278. get
  279. {
  280. if (holder.BaseCertificateID != null)
  281. {
  282. return holder.BaseCertificateID.Serial.Value;
  283. }
  284. return null;
  285. }
  286. }
  287. public object Clone()
  288. {
  289. return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
  290. }
  291. public bool Match(
  292. X509Certificate x509Cert)
  293. {
  294. try
  295. {
  296. if (holder.BaseCertificateID != null)
  297. {
  298. return holder.BaseCertificateID.Serial.HasValue(x509Cert.SerialNumber)
  299. && MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer);
  300. }
  301. if (holder.EntityName != null)
  302. {
  303. if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName))
  304. {
  305. return true;
  306. }
  307. }
  308. if (holder.ObjectDigestInfo != null)
  309. {
  310. IDigest md = null;
  311. try
  312. {
  313. md = DigestUtilities.GetDigest(DigestAlgorithm);
  314. }
  315. catch (Exception)
  316. {
  317. return false;
  318. }
  319. switch (DigestedObjectType)
  320. {
  321. case ObjectDigestInfo.PublicKey:
  322. {
  323. // TODO: DSA Dss-parms
  324. //byte[] b = x509Cert.GetPublicKey().getEncoded();
  325. // TODO Is this the right way to encode?
  326. byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
  327. x509Cert.GetPublicKey()).GetEncoded();
  328. md.BlockUpdate(b, 0, b.Length);
  329. break;
  330. }
  331. case ObjectDigestInfo.PublicKeyCert:
  332. {
  333. byte[] b = x509Cert.GetEncoded();
  334. md.BlockUpdate(b, 0, b.Length);
  335. break;
  336. }
  337. // TODO Default handler?
  338. }
  339. // TODO Shouldn't this be the other way around?
  340. if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest()))
  341. {
  342. return false;
  343. }
  344. }
  345. }
  346. catch (CertificateEncodingException)
  347. {
  348. return false;
  349. }
  350. return false;
  351. }
  352. public override bool Equals(
  353. object obj)
  354. {
  355. if (obj == this)
  356. {
  357. return true;
  358. }
  359. if (!(obj is AttributeCertificateHolder))
  360. {
  361. return false;
  362. }
  363. AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
  364. return this.holder.Equals(other.holder);
  365. }
  366. public override int GetHashCode()
  367. {
  368. return this.holder.GetHashCode();
  369. }
  370. public bool Match(
  371. object obj)
  372. {
  373. if (!(obj is X509Certificate))
  374. {
  375. return false;
  376. }
  377. // return Match((Certificate)obj);
  378. return Match((X509Certificate)obj);
  379. }
  380. }
  381. }
  382. #pragma warning restore
  383. #endif