PkixCertPathValidator.cs 16 KB

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