AttributeCertificateHolder.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
  12. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.X509
  13. {
  14. /// <remarks>
  15. /// The Holder object.
  16. /// <pre>
  17. /// Holder ::= SEQUENCE {
  18. /// baseCertificateID [0] IssuerSerial OPTIONAL,
  19. /// -- the issuer and serial number of
  20. /// -- the holder's Public Key Certificate
  21. /// entityName [1] GeneralNames OPTIONAL,
  22. /// -- the name of the claimant or role
  23. /// objectDigestInfo [2] ObjectDigestInfo OPTIONAL
  24. /// -- used to directly authenticate the holder,
  25. /// -- for example, an executable
  26. /// }
  27. /// </pre>
  28. /// </remarks>
  29. public class AttributeCertificateHolder
  30. //: CertSelector, Selector
  31. : ISelector<X509Certificate>
  32. {
  33. internal readonly Holder holder;
  34. internal AttributeCertificateHolder(
  35. Asn1Sequence seq)
  36. {
  37. holder = Holder.GetInstance(seq);
  38. }
  39. public AttributeCertificateHolder(
  40. X509Name issuerName,
  41. BigInteger serialNumber)
  42. {
  43. holder = new Holder(
  44. new IssuerSerial(
  45. GenerateGeneralNames(issuerName),
  46. new DerInteger(serialNumber)));
  47. }
  48. public AttributeCertificateHolder(
  49. X509Certificate cert)
  50. {
  51. X509Name name;
  52. try
  53. {
  54. name = PrincipalUtilities.GetIssuerX509Principal(cert);
  55. }
  56. catch (Exception e)
  57. {
  58. throw new CertificateParsingException(e.Message);
  59. }
  60. holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
  61. }
  62. public AttributeCertificateHolder(
  63. X509Name principal)
  64. {
  65. holder = new Holder(GenerateGeneralNames(principal));
  66. }
  67. /**
  68. * Constructs a holder for v2 attribute certificates with a hash value for
  69. * some type of object.
  70. * <p>
  71. * <code>digestedObjectType</code> can be one of the following:
  72. * <ul>
  73. * <li>0 - publicKey - A hash of the public key of the holder must be
  74. * passed.</li>
  75. * <li>1 - publicKeyCert - A hash of the public key certificate of the
  76. * holder must be passed.</li>
  77. * <li>2 - otherObjectDigest - A hash of some other object type must be
  78. * passed. <code>otherObjectTypeID</code> must not be empty.</li>
  79. * </ul>
  80. * </p>
  81. * <p>This cannot be used if a v1 attribute certificate is used.</p>
  82. *
  83. * @param digestedObjectType The digest object type.
  84. * @param digestAlgorithm The algorithm identifier for the hash.
  85. * @param otherObjectTypeID The object type ID if
  86. * <code>digestedObjectType</code> is
  87. * <code>otherObjectDigest</code>.
  88. * @param objectDigest The hash value.
  89. */
  90. public AttributeCertificateHolder(
  91. int digestedObjectType,
  92. string digestAlgorithm,
  93. string otherObjectTypeID,
  94. byte[] objectDigest)
  95. {
  96. // TODO Allow 'objectDigest' to be null?
  97. holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID,
  98. new AlgorithmIdentifier(new DerObjectIdentifier(digestAlgorithm)), Arrays.Clone(objectDigest)));
  99. }
  100. /**
  101. * Returns the digest object type if an object digest info is used.
  102. * <p>
  103. * <ul>
  104. * <li>0 - publicKey - A hash of the public key of the holder must be
  105. * passed.</li>
  106. * <li>1 - publicKeyCert - A hash of the public key certificate of the
  107. * holder must be passed.</li>
  108. * <li>2 - otherObjectDigest - A hash of some other object type must be
  109. * passed. <code>otherObjectTypeID</code> must not be empty.</li>
  110. * </ul>
  111. * </p>
  112. *
  113. * @return The digest object type or -1 if no object digest info is set.
  114. */
  115. public int DigestedObjectType
  116. {
  117. get
  118. {
  119. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  120. return odi == null
  121. ? -1
  122. : odi.DigestedObjectType.IntValueExact;
  123. }
  124. }
  125. /**
  126. * Returns the other object type ID if an object digest info is used.
  127. *
  128. * @return The other object type ID or <code>null</code> if no object
  129. * digest info is set.
  130. */
  131. public string DigestAlgorithm
  132. {
  133. get
  134. {
  135. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  136. return odi == null
  137. ? null
  138. : odi.DigestAlgorithm.Algorithm.Id;
  139. }
  140. }
  141. /**
  142. * Returns the hash if an object digest info is used.
  143. *
  144. * @return The hash or <code>null</code> if no object digest info is set.
  145. */
  146. public byte[] GetObjectDigest()
  147. {
  148. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  149. return odi == null
  150. ? null
  151. : odi.ObjectDigest.GetBytes();
  152. }
  153. /**
  154. * Returns the digest algorithm ID if an object digest info is used.
  155. *
  156. * @return The digest algorithm ID or <code>null</code> if no object
  157. * digest info is set.
  158. */
  159. public string OtherObjectTypeID
  160. {
  161. get
  162. {
  163. ObjectDigestInfo odi = holder.ObjectDigestInfo;
  164. return odi == null
  165. ? null
  166. : odi.OtherObjectTypeID.Id;
  167. }
  168. }
  169. private GeneralNames GenerateGeneralNames(
  170. X509Name principal)
  171. {
  172. // return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
  173. return new GeneralNames(new GeneralName(principal));
  174. }
  175. private bool MatchesDN(
  176. X509Name subject,
  177. GeneralNames targets)
  178. {
  179. GeneralName[] names = targets.GetNames();
  180. for (int i = 0; i != names.Length; i++)
  181. {
  182. GeneralName gn = names[i];
  183. if (gn.TagNo == GeneralName.DirectoryName)
  184. {
  185. try
  186. {
  187. if (X509Name.GetInstance(gn.Name).Equivalent(subject))
  188. {
  189. return true;
  190. }
  191. }
  192. catch (Exception)
  193. {
  194. }
  195. }
  196. }
  197. return false;
  198. }
  199. private object[] GetNames(
  200. GeneralName[] names)
  201. {
  202. int count = 0;
  203. for (int i = 0; i != names.Length; i++)
  204. {
  205. if (names[i].TagNo == GeneralName.DirectoryName)
  206. {
  207. ++count;
  208. }
  209. }
  210. object[] result = new object[count];
  211. int pos = 0;
  212. for (int i = 0; i != names.Length; i++)
  213. {
  214. if (names[i].TagNo == GeneralName.DirectoryName)
  215. {
  216. result[pos++] = X509Name.GetInstance(names[i].Name);
  217. }
  218. }
  219. return result;
  220. }
  221. private X509Name[] GetPrincipals(
  222. GeneralNames names)
  223. {
  224. object[] p = this.GetNames(names.GetNames());
  225. int count = 0;
  226. for (int i = 0; i != p.Length; i++)
  227. {
  228. if (p[i] is X509Name)
  229. {
  230. ++count;
  231. }
  232. }
  233. X509Name[] result = new X509Name[count];
  234. int pos = 0;
  235. for (int i = 0; i != p.Length; i++)
  236. {
  237. if (p[i] is X509Name)
  238. {
  239. result[pos++] = (X509Name)p[i];
  240. }
  241. }
  242. return result;
  243. }
  244. /**
  245. * Return any principal objects inside the attribute certificate holder entity names field.
  246. *
  247. * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
  248. */
  249. public X509Name[] GetEntityNames()
  250. {
  251. if (holder.EntityName != null)
  252. {
  253. return GetPrincipals(holder.EntityName);
  254. }
  255. return null;
  256. }
  257. /**
  258. * Return the principals associated with the issuer attached to this holder
  259. *
  260. * @return an array of principals, null if no BaseCertificateID is set.
  261. */
  262. public X509Name[] GetIssuer()
  263. {
  264. if (holder.BaseCertificateID != null)
  265. {
  266. return GetPrincipals(holder.BaseCertificateID.Issuer);
  267. }
  268. return null;
  269. }
  270. /**
  271. * Return the serial number associated with the issuer attached to this holder.
  272. *
  273. * @return the certificate serial number, null if no BaseCertificateID is set.
  274. */
  275. public BigInteger SerialNumber
  276. {
  277. get
  278. {
  279. if (holder.BaseCertificateID != null)
  280. {
  281. return holder.BaseCertificateID.Serial.Value;
  282. }
  283. return null;
  284. }
  285. }
  286. public object Clone()
  287. {
  288. return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
  289. }
  290. public bool Match(X509Certificate x509Cert)
  291. {
  292. if (x509Cert == null)
  293. return false;
  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. }
  371. }
  372. #pragma warning restore
  373. #endif