PkixCertPathValidator.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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.Security.Certificates;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
  12. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
  13. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Pkix
  14. {
  15. /**
  16. * The <i>Service Provider Interface</i> (<b>SPI</b>)
  17. * for the {@link CertPathValidator CertPathValidator} class. All
  18. * <code>CertPathValidator</code> implementations must include a class (the
  19. * SPI class) that extends this class (<code>CertPathValidatorSpi</code>)
  20. * and implements all of its methods. In general, instances of this class
  21. * should only be accessed through the <code>CertPathValidator</code> class.
  22. * For details, see the Java Cryptography Architecture.<br />
  23. * <br />
  24. * <b>Concurrent Access</b><br />
  25. * <br />
  26. * Instances of this class need not be protected against concurrent
  27. * access from multiple threads. Threads that need to access a single
  28. * <code>CertPathValidatorSpi</code> instance concurrently should synchronize
  29. * amongst themselves and provide the necessary locking before calling the
  30. * wrapping <code>CertPathValidator</code> object.<br />
  31. * <br />
  32. * However, implementations of <code>CertPathValidatorSpi</code> may still
  33. * encounter concurrency issues, since multiple threads each
  34. * manipulating a different <code>CertPathValidatorSpi</code> instance need not
  35. * synchronize.
  36. */
  37. /// <summary>
  38. /// CertPathValidatorSpi implementation for X.509 Certificate validation a la RFC
  39. /// 3280.
  40. /// </summary>
  41. public class PkixCertPathValidator
  42. {
  43. public virtual PkixCertPathValidatorResult Validate(
  44. PkixCertPath certPath,
  45. PkixParameters paramsPkix)
  46. {
  47. if (paramsPkix.GetTrustAnchors() == null)
  48. {
  49. throw new ArgumentException(
  50. "trustAnchors is null, this is not allowed for certification path validation.",
  51. "parameters");
  52. }
  53. //
  54. // 6.1.1 - inputs
  55. //
  56. //
  57. // (a)
  58. //
  59. IList certs = certPath.Certificates;
  60. int n = certs.Count;
  61. if (certs.Count == 0)
  62. throw new PkixCertPathValidatorException("Certification path is empty.", null, certPath, 0);
  63. //
  64. // (b)
  65. //
  66. // DateTime validDate = PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
  67. //
  68. // (c)
  69. //
  70. ISet userInitialPolicySet = paramsPkix.GetInitialPolicies();
  71. //
  72. // (d)
  73. //
  74. TrustAnchor trust;
  75. try
  76. {
  77. trust = PkixCertPathValidatorUtilities.FindTrustAnchor(
  78. (X509Certificate)certs[certs.Count - 1],
  79. paramsPkix.GetTrustAnchors());
  80. if (trust == null)
  81. throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
  82. CheckCertificate(trust.TrustedCert);
  83. }
  84. catch (Exception e)
  85. {
  86. throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, certs.Count - 1);
  87. }
  88. //
  89. // (e), (f), (g) are part of the paramsPkix object.
  90. //
  91. IEnumerator certIter;
  92. int index = 0;
  93. int i;
  94. // Certificate for each interation of the validation loop
  95. // Signature information for each iteration of the validation loop
  96. //
  97. // 6.1.2 - setup
  98. //
  99. //
  100. // (a)
  101. //
  102. IList[] policyNodes = new IList[n + 1];
  103. for (int j = 0; j < policyNodes.Length; j++)
  104. {
  105. policyNodes[j] = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  106. }
  107. ISet policySet = new HashSet();
  108. policySet.Add(Rfc3280CertPathUtilities.ANY_POLICY);
  109. PkixPolicyNode validPolicyTree = new PkixPolicyNode(BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(), 0, policySet, null, new HashSet(),
  110. Rfc3280CertPathUtilities.ANY_POLICY, false);
  111. policyNodes[0].Add(validPolicyTree);
  112. //
  113. // (b) and (c)
  114. //
  115. PkixNameConstraintValidator nameConstraintValidator = new PkixNameConstraintValidator();
  116. // (d)
  117. //
  118. int explicitPolicy;
  119. ISet acceptablePolicies = new HashSet();
  120. if (paramsPkix.IsExplicitPolicyRequired)
  121. {
  122. explicitPolicy = 0;
  123. }
  124. else
  125. {
  126. explicitPolicy = n + 1;
  127. }
  128. //
  129. // (e)
  130. //
  131. int inhibitAnyPolicy;
  132. if (paramsPkix.IsAnyPolicyInhibited)
  133. {
  134. inhibitAnyPolicy = 0;
  135. }
  136. else
  137. {
  138. inhibitAnyPolicy = n + 1;
  139. }
  140. //
  141. // (f)
  142. //
  143. int policyMapping;
  144. if (paramsPkix.IsPolicyMappingInhibited)
  145. {
  146. policyMapping = 0;
  147. }
  148. else
  149. {
  150. policyMapping = n + 1;
  151. }
  152. //
  153. // (g), (h), (i), (j)
  154. //
  155. AsymmetricKeyParameter workingPublicKey;
  156. X509Name workingIssuerName;
  157. X509Certificate sign = trust.TrustedCert;
  158. try
  159. {
  160. if (sign != null)
  161. {
  162. workingIssuerName = sign.SubjectDN;
  163. workingPublicKey = sign.GetPublicKey();
  164. }
  165. else
  166. {
  167. workingIssuerName = new X509Name(trust.CAName);
  168. workingPublicKey = trust.CAPublicKey;
  169. }
  170. }
  171. catch (ArgumentException ex)
  172. {
  173. throw new PkixCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
  174. -1);
  175. }
  176. AlgorithmIdentifier workingAlgId = null;
  177. try
  178. {
  179. workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
  180. }
  181. catch (PkixCertPathValidatorException e)
  182. {
  183. throw new PkixCertPathValidatorException(
  184. "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
  185. }
  186. // DerObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.Algorithm;
  187. // Asn1Encodable workingPublicKeyParameters = workingAlgId.Parameters;
  188. //
  189. // (k)
  190. //
  191. int maxPathLength = n;
  192. //
  193. // 6.1.3
  194. //
  195. X509CertStoreSelector certConstraints = paramsPkix.GetTargetCertConstraints();
  196. if (certConstraints != null && !certConstraints.Match((X509Certificate)certs[0]))
  197. {
  198. throw new PkixCertPathValidatorException(
  199. "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
  200. }
  201. //
  202. // initialize CertPathChecker's
  203. //
  204. IList pathCheckers = paramsPkix.GetCertPathCheckers();
  205. certIter = pathCheckers.GetEnumerator();
  206. while (certIter.MoveNext())
  207. {
  208. ((PkixCertPathChecker)certIter.Current).Init(false);
  209. }
  210. X509Certificate cert = null;
  211. for (index = certs.Count - 1; index >= 0; index--)
  212. {
  213. // try
  214. // {
  215. //
  216. // i as defined in the algorithm description
  217. //
  218. i = n - index;
  219. //
  220. // set certificate to be checked in this round
  221. // sign and workingPublicKey and workingIssuerName are set
  222. // at the end of the for loop and initialized the
  223. // first time from the TrustAnchor
  224. //
  225. cert = (X509Certificate)certs[index];
  226. try
  227. {
  228. CheckCertificate(cert);
  229. }
  230. catch (Exception e)
  231. {
  232. throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, index);
  233. }
  234. //
  235. // 6.1.3
  236. //
  237. Rfc3280CertPathUtilities.ProcessCertA(certPath, paramsPkix, index, workingPublicKey,
  238. workingIssuerName, sign);
  239. Rfc3280CertPathUtilities.ProcessCertBC(certPath, index, nameConstraintValidator);
  240. validPolicyTree = Rfc3280CertPathUtilities.ProcessCertD(certPath, index,
  241. acceptablePolicies, validPolicyTree, policyNodes, inhibitAnyPolicy);
  242. validPolicyTree = Rfc3280CertPathUtilities.ProcessCertE(certPath, index, validPolicyTree);
  243. Rfc3280CertPathUtilities.ProcessCertF(certPath, index, validPolicyTree, explicitPolicy);
  244. //
  245. // 6.1.4
  246. //
  247. if (i != n)
  248. {
  249. if (cert != null && cert.Version == 1)
  250. {
  251. // we've found the trust anchor at the top of the path, ignore and keep going
  252. if ((i == 1) && cert.Equals(trust.TrustedCert))
  253. continue;
  254. throw new PkixCertPathValidatorException(
  255. "Version 1 certificates can't be used as CA ones.", null, certPath, index);
  256. }
  257. Rfc3280CertPathUtilities.PrepareNextCertA(certPath, index);
  258. validPolicyTree = Rfc3280CertPathUtilities.PrepareCertB(certPath, index, policyNodes,
  259. validPolicyTree, policyMapping);
  260. Rfc3280CertPathUtilities.PrepareNextCertG(certPath, index, nameConstraintValidator);
  261. // (h)
  262. explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertH1(certPath, index, explicitPolicy);
  263. policyMapping = Rfc3280CertPathUtilities.PrepareNextCertH2(certPath, index, policyMapping);
  264. inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertH3(certPath, index, inhibitAnyPolicy);
  265. //
  266. // (i)
  267. //
  268. explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertI1(certPath, index, explicitPolicy);
  269. policyMapping = Rfc3280CertPathUtilities.PrepareNextCertI2(certPath, index, policyMapping);
  270. // (j)
  271. inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertJ(certPath, index, inhibitAnyPolicy);
  272. // (k)
  273. Rfc3280CertPathUtilities.PrepareNextCertK(certPath, index);
  274. // (l)
  275. maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertL(certPath, index, maxPathLength);
  276. // (m)
  277. maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertM(certPath, index, maxPathLength);
  278. // (n)
  279. Rfc3280CertPathUtilities.PrepareNextCertN(certPath, index);
  280. ISet criticalExtensions1 = cert.GetCriticalExtensionOids();
  281. if (criticalExtensions1 != null)
  282. {
  283. criticalExtensions1 = new HashSet(criticalExtensions1);
  284. // these extensions are handled by the algorithm
  285. criticalExtensions1.Remove(X509Extensions.KeyUsage.Id);
  286. criticalExtensions1.Remove(X509Extensions.CertificatePolicies.Id);
  287. criticalExtensions1.Remove(X509Extensions.PolicyMappings.Id);
  288. criticalExtensions1.Remove(X509Extensions.InhibitAnyPolicy.Id);
  289. criticalExtensions1.Remove(X509Extensions.IssuingDistributionPoint.Id);
  290. criticalExtensions1.Remove(X509Extensions.DeltaCrlIndicator.Id);
  291. criticalExtensions1.Remove(X509Extensions.PolicyConstraints.Id);
  292. criticalExtensions1.Remove(X509Extensions.BasicConstraints.Id);
  293. criticalExtensions1.Remove(X509Extensions.SubjectAlternativeName.Id);
  294. criticalExtensions1.Remove(X509Extensions.NameConstraints.Id);
  295. }
  296. else
  297. {
  298. criticalExtensions1 = new HashSet();
  299. }
  300. // (o)
  301. Rfc3280CertPathUtilities.PrepareNextCertO(certPath, index, criticalExtensions1, pathCheckers);
  302. // set signing certificate for next round
  303. sign = cert;
  304. // (c)
  305. workingIssuerName = sign.SubjectDN;
  306. // (d)
  307. try
  308. {
  309. workingPublicKey = PkixCertPathValidatorUtilities.GetNextWorkingKey(certPath.Certificates, index);
  310. }
  311. catch (PkixCertPathValidatorException e)
  312. {
  313. throw new PkixCertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
  314. }
  315. workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
  316. // (f)
  317. // workingPublicKeyAlgorithm = workingAlgId.Algorithm;
  318. // (e)
  319. // workingPublicKeyParameters = workingAlgId.Parameters;
  320. }
  321. }
  322. //
  323. // 6.1.5 Wrap-up procedure
  324. //
  325. explicitPolicy = Rfc3280CertPathUtilities.WrapupCertA(explicitPolicy, cert);
  326. explicitPolicy = Rfc3280CertPathUtilities.WrapupCertB(certPath, index + 1, explicitPolicy);
  327. //
  328. // (c) (d) and (e) are already done
  329. //
  330. //
  331. // (f)
  332. //
  333. ISet criticalExtensions = cert.GetCriticalExtensionOids();
  334. if (criticalExtensions != null)
  335. {
  336. criticalExtensions = new HashSet(criticalExtensions);
  337. // Requires .Id
  338. // these extensions are handled by the algorithm
  339. criticalExtensions.Remove(X509Extensions.KeyUsage.Id);
  340. criticalExtensions.Remove(X509Extensions.CertificatePolicies.Id);
  341. criticalExtensions.Remove(X509Extensions.PolicyMappings.Id);
  342. criticalExtensions.Remove(X509Extensions.InhibitAnyPolicy.Id);
  343. criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
  344. criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
  345. criticalExtensions.Remove(X509Extensions.PolicyConstraints.Id);
  346. criticalExtensions.Remove(X509Extensions.BasicConstraints.Id);
  347. criticalExtensions.Remove(X509Extensions.SubjectAlternativeName.Id);
  348. criticalExtensions.Remove(X509Extensions.NameConstraints.Id);
  349. criticalExtensions.Remove(X509Extensions.CrlDistributionPoints.Id);
  350. }
  351. else
  352. {
  353. criticalExtensions = new HashSet();
  354. }
  355. Rfc3280CertPathUtilities.WrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
  356. PkixPolicyNode intersection = Rfc3280CertPathUtilities.WrapupCertG(certPath, paramsPkix, userInitialPolicySet,
  357. index + 1, policyNodes, validPolicyTree, acceptablePolicies);
  358. if ((explicitPolicy > 0) || (intersection != null))
  359. {
  360. return new PkixCertPathValidatorResult(trust, intersection, cert.GetPublicKey());
  361. }
  362. throw new PkixCertPathValidatorException("Path processing failed on policy.", null, certPath, index);
  363. }
  364. internal static void CheckCertificate(X509Certificate cert)
  365. {
  366. try
  367. {
  368. TbsCertificateStructure.GetInstance(cert.CertificateStructure.TbsCertificate);
  369. }
  370. catch (CertificateEncodingException e)
  371. {
  372. throw new Exception("unable to process TBSCertificate", e);
  373. }
  374. }
  375. }
  376. }
  377. #pragma warning restore
  378. #endif