Rfc3281CertPathUtilities.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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.Utilities.Collections;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
  11. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Pkix
  12. {
  13. internal static class Rfc3281CertPathUtilities
  14. {
  15. internal static void ProcessAttrCert7(
  16. X509V2AttributeCertificate attrCert,
  17. PkixCertPath certPath,
  18. PkixCertPath holderCertPath,
  19. PkixParameters pkixParams)
  20. {
  21. // TODO:
  22. // AA Controls
  23. // Attribute encryption
  24. // Proxy
  25. var critExtOids = attrCert.GetCriticalExtensionOids();
  26. // 7.1
  27. // process extensions
  28. // target information checked in step 6 / X509AttributeCertStoreSelector
  29. if (critExtOids.Contains(X509Extensions.TargetInformation.Id))
  30. {
  31. try
  32. {
  33. TargetInformation.GetInstance(PkixCertPathValidatorUtilities
  34. .GetExtensionValue(attrCert, X509Extensions.TargetInformation));
  35. }
  36. catch (Exception e)
  37. {
  38. throw new PkixCertPathValidatorException(
  39. "Target information extension could not be read.", e);
  40. }
  41. }
  42. critExtOids.Remove(X509Extensions.TargetInformation.Id);
  43. foreach (PkixAttrCertChecker checker in pkixParams.GetAttrCertCheckers())
  44. {
  45. checker.Check(attrCert, certPath, holderCertPath, critExtOids);
  46. }
  47. if (critExtOids.Count > 0)
  48. {
  49. throw new PkixCertPathValidatorException(
  50. "Attribute certificate contains unsupported critical extensions: " + critExtOids);
  51. }
  52. }
  53. /**
  54. * Checks if an attribute certificate is revoked.
  55. *
  56. * @param attrCert Attribute certificate to check if it is revoked.
  57. * @param paramsPKIX PKIX parameters.
  58. * @param issuerCert The issuer certificate of the attribute certificate
  59. * <code>attrCert</code>.
  60. * @param validDate The date when the certificate revocation status should
  61. * be checked.
  62. * @param certPathCerts The certificates of the certification path to be
  63. * checked.
  64. *
  65. * @throws CertPathValidatorException if the certificate is revoked or the
  66. * status cannot be checked or some error occurs.
  67. */
  68. internal static void CheckCrls(
  69. X509V2AttributeCertificate attrCert,
  70. PkixParameters paramsPKIX,
  71. X509Certificate issuerCert,
  72. DateTime validDate,
  73. IList<X509Certificate> certPathCerts)
  74. {
  75. if (!paramsPKIX.IsRevocationEnabled)
  76. return;
  77. // check if revocation is available
  78. if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) != null)
  79. {
  80. if (attrCert.GetExtensionValue(X509Extensions.CrlDistributionPoints) != null ||
  81. attrCert.GetExtensionValue(X509Extensions.AuthorityInfoAccess) != null)
  82. {
  83. throw new PkixCertPathValidatorException(
  84. "No rev avail extension is set, but also an AC revocation pointer.");
  85. }
  86. return;
  87. }
  88. CrlDistPoint crldp;
  89. try
  90. {
  91. crldp = CrlDistPoint.GetInstance(
  92. PkixCertPathValidatorUtilities.GetExtensionValue(attrCert, X509Extensions.CrlDistributionPoints));
  93. }
  94. catch (Exception e)
  95. {
  96. throw new PkixCertPathValidatorException("CRL distribution point extension could not be read.", e);
  97. }
  98. try
  99. {
  100. PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
  101. }
  102. catch (Exception e)
  103. {
  104. throw new PkixCertPathValidatorException(
  105. "No additional CRL locations could be decoded from CRL distribution point extension.", e);
  106. }
  107. CertStatus certStatus = new CertStatus();
  108. ReasonsMask reasonsMask = new ReasonsMask();
  109. Exception lastException = null;
  110. bool validCrlFound = false;
  111. // for each distribution point
  112. if (crldp != null)
  113. {
  114. DistributionPoint[] dps;
  115. try
  116. {
  117. dps = crldp.GetDistributionPoints();
  118. }
  119. catch (Exception e)
  120. {
  121. throw new PkixCertPathValidatorException("Distribution points could not be read.", e);
  122. }
  123. try
  124. {
  125. for (int i = 0;
  126. i < dps.Length && certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons;
  127. i++)
  128. {
  129. PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
  130. CheckCrl(dps[i], attrCert, paramsPKIXClone,validDate, issuerCert, certStatus, reasonsMask,
  131. certPathCerts);
  132. validCrlFound = true;
  133. }
  134. }
  135. catch (Exception e)
  136. {
  137. lastException = new Exception("No valid CRL for distribution point found.", e);
  138. }
  139. }
  140. /*
  141. * If the revocation status has not been determined, repeat the
  142. * process above with any available CRLs not specified in a
  143. * distribution point but issued by the certificate issuer.
  144. */
  145. if (certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons)
  146. {
  147. try
  148. {
  149. /*
  150. * assume a DP with both the reasons and the cRLIssuer
  151. * fields omitted and a distribution point name of the
  152. * certificate issuer.
  153. */
  154. X509Name issuer;
  155. try
  156. {
  157. issuer = X509Name.GetInstance(attrCert.Issuer.GetPrincipals()[0].GetEncoded());
  158. }
  159. catch (Exception e)
  160. {
  161. throw new Exception("Issuer from certificate for CRL could not be reencoded.", e);
  162. }
  163. DistributionPoint dp = new DistributionPoint(
  164. new DistributionPointName(0, new GeneralNames(
  165. new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
  166. PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX.Clone();
  167. CheckCrl(dp, attrCert, paramsPKIXClone, validDate,
  168. issuerCert, certStatus, reasonsMask, certPathCerts);
  169. validCrlFound = true;
  170. }
  171. catch (Exception e)
  172. {
  173. lastException = new Exception("No valid CRL for distribution point found.", e);
  174. }
  175. }
  176. if (!validCrlFound)
  177. throw new PkixCertPathValidatorException("No valid CRL found.", lastException);
  178. if (certStatus.Status != CertStatus.Unrevoked)
  179. {
  180. // This format is enforced by the NistCertPath tests
  181. string formattedDate = certStatus.RevocationDate.Value.ToString("ddd MMM dd HH:mm:ss K yyyy");
  182. string message = "Attribute certificate revocation after " + formattedDate + ", reason: "
  183. + Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
  184. throw new PkixCertPathValidatorException(message);
  185. }
  186. if (!reasonsMask.IsAllReasons
  187. && certStatus.Status == CertStatus.Unrevoked)
  188. {
  189. certStatus.Status = CertStatus.Undetermined;
  190. }
  191. if (certStatus.Status == CertStatus.Undetermined)
  192. {
  193. throw new PkixCertPathValidatorException(
  194. "Attribute certificate status could not be determined.");
  195. }
  196. }
  197. internal static void AdditionalChecks(
  198. X509V2AttributeCertificate attrCert,
  199. PkixParameters pkixParams)
  200. {
  201. // 1
  202. foreach (string oid in pkixParams.GetProhibitedACAttributes())
  203. {
  204. if (attrCert.GetAttributes(oid) != null)
  205. {
  206. throw new PkixCertPathValidatorException(
  207. "Attribute certificate contains prohibited attribute: "
  208. + oid + ".");
  209. }
  210. }
  211. foreach (string oid in pkixParams.GetNecessaryACAttributes())
  212. {
  213. if (attrCert.GetAttributes(oid) == null)
  214. {
  215. throw new PkixCertPathValidatorException(
  216. "Attribute certificate does not contain necessary attribute: "
  217. + oid + ".");
  218. }
  219. }
  220. }
  221. internal static void ProcessAttrCert5(
  222. X509V2AttributeCertificate attrCert,
  223. PkixParameters pkixParams)
  224. {
  225. try
  226. {
  227. attrCert.CheckValidity(PkixCertPathValidatorUtilities.GetValidDate(pkixParams));
  228. }
  229. catch (CertificateExpiredException e)
  230. {
  231. throw new PkixCertPathValidatorException(
  232. "Attribute certificate is not valid.", e);
  233. }
  234. catch (CertificateNotYetValidException e)
  235. {
  236. throw new PkixCertPathValidatorException(
  237. "Attribute certificate is not valid.", e);
  238. }
  239. }
  240. internal static void ProcessAttrCert4(
  241. X509Certificate acIssuerCert,
  242. PkixParameters pkixParams)
  243. {
  244. var set = pkixParams.GetTrustedACIssuers();
  245. bool trusted = false;
  246. foreach (TrustAnchor anchor in set)
  247. {
  248. var symbols = X509Name.RFC2253Symbols;
  249. if (acIssuerCert.SubjectDN.ToString(false, symbols).Equals(anchor.CAName)
  250. || acIssuerCert.Equals(anchor.TrustedCert))
  251. {
  252. trusted = true;
  253. }
  254. }
  255. if (!trusted)
  256. {
  257. throw new PkixCertPathValidatorException(
  258. "Attribute certificate issuer is not directly trusted.");
  259. }
  260. }
  261. internal static void ProcessAttrCert3(
  262. X509Certificate acIssuerCert,
  263. PkixParameters pkixParams)
  264. {
  265. if (acIssuerCert.GetKeyUsage() != null
  266. && (!acIssuerCert.GetKeyUsage()[0] && !acIssuerCert.GetKeyUsage()[1]))
  267. {
  268. throw new PkixCertPathValidatorException(
  269. "Attribute certificate issuer public key cannot be used to validate digital signatures.");
  270. }
  271. if (acIssuerCert.GetBasicConstraints() != -1)
  272. {
  273. throw new PkixCertPathValidatorException(
  274. "Attribute certificate issuer is also a public key certificate issuer.");
  275. }
  276. }
  277. internal static PkixCertPathValidatorResult ProcessAttrCert2(
  278. PkixCertPath certPath,
  279. PkixParameters pkixParams)
  280. {
  281. PkixCertPathValidator validator = new PkixCertPathValidator();
  282. try
  283. {
  284. return validator.Validate(certPath, pkixParams);
  285. }
  286. catch (PkixCertPathValidatorException e)
  287. {
  288. throw new PkixCertPathValidatorException(
  289. "Certification path for issuer certificate of attribute certificate could not be validated.",
  290. e);
  291. }
  292. }
  293. /**
  294. * Searches for a holder public key certificate and verifies its
  295. * certification path.
  296. *
  297. * @param attrCert the attribute certificate.
  298. * @param pkixParams The PKIX parameters.
  299. * @return The certificate path of the holder certificate.
  300. * @throws Exception if
  301. * <ul>
  302. * <li>no public key certificate can be found although holder
  303. * information is given by an entity name or a base certificate
  304. * ID</li>
  305. * <li>support classes cannot be created</li>
  306. * <li>no certification path for the public key certificate can
  307. * be built</li>
  308. * </ul>
  309. */
  310. internal static PkixCertPath ProcessAttrCert1(
  311. X509V2AttributeCertificate attrCert,
  312. PkixParameters pkixParams)
  313. {
  314. PkixCertPathBuilderResult result = null;
  315. // find holder PKCs
  316. var holderPKCs = new HashSet<X509Certificate>();
  317. if (attrCert.Holder.GetIssuer() != null)
  318. {
  319. X509CertStoreSelector selector = new X509CertStoreSelector();
  320. selector.SerialNumber = attrCert.Holder.SerialNumber;
  321. X509Name[] principals = attrCert.Holder.GetIssuer();
  322. for (int i = 0; i < principals.Length; i++)
  323. {
  324. // TODO Replace loop with a single multiprincipal selector (or don't even use selector)
  325. try
  326. {
  327. selector.Issuer = principals[i];
  328. CollectionUtilities.CollectMatches(holderPKCs, selector, pkixParams.GetStoresCert());
  329. }
  330. catch (Exception e)
  331. {
  332. throw new PkixCertPathValidatorException(
  333. "Public key certificate for attribute certificate cannot be searched.",
  334. e);
  335. }
  336. }
  337. if (holderPKCs.Count < 1)
  338. {
  339. throw new PkixCertPathValidatorException(
  340. "Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
  341. }
  342. }
  343. if (attrCert.Holder.GetEntityNames() != null)
  344. {
  345. X509CertStoreSelector selector = new X509CertStoreSelector();
  346. X509Name[] principals = attrCert.Holder.GetEntityNames();
  347. for (int i = 0; i < principals.Length; i++)
  348. {
  349. // TODO Replace loop with a single multiprincipal selector (or don't even use selector)
  350. try
  351. {
  352. selector.Issuer = principals[i];
  353. CollectionUtilities.CollectMatches(holderPKCs, selector, pkixParams.GetStoresCert());
  354. }
  355. catch (Exception e)
  356. {
  357. throw new PkixCertPathValidatorException(
  358. "Public key certificate for attribute certificate cannot be searched.",
  359. e);
  360. }
  361. }
  362. if (holderPKCs.Count < 1)
  363. {
  364. throw new PkixCertPathValidatorException(
  365. "Public key certificate specified in entity name for attribute certificate cannot be found.");
  366. }
  367. }
  368. // verify cert paths for PKCs
  369. PkixBuilderParameters parameters = PkixBuilderParameters.GetInstance(pkixParams);
  370. PkixCertPathValidatorException lastException = null;
  371. foreach (X509Certificate cert in holderPKCs)
  372. {
  373. X509CertStoreSelector certSelector = new X509CertStoreSelector();
  374. certSelector.Certificate = cert;
  375. parameters.SetTargetConstraintsCert(certSelector);
  376. PkixCertPathBuilder builder = new PkixCertPathBuilder();
  377. try
  378. {
  379. result = builder.Build(parameters);
  380. }
  381. catch (PkixCertPathBuilderException e)
  382. {
  383. lastException = new PkixCertPathValidatorException(
  384. "Certification path for public key certificate of attribute certificate could not be build.",
  385. e);
  386. }
  387. }
  388. if (lastException != null)
  389. {
  390. throw lastException;
  391. }
  392. return result.CertPath;
  393. }
  394. /**
  395. *
  396. * Checks a distribution point for revocation information for the
  397. * certificate <code>attrCert</code>.
  398. *
  399. * @param dp The distribution point to consider.
  400. * @param attrCert The attribute certificate which should be checked.
  401. * @param paramsPKIX PKIX parameters.
  402. * @param validDate The date when the certificate revocation status should
  403. * be checked.
  404. * @param issuerCert Certificate to check if it is revoked.
  405. * @param reasonMask The reasons mask which is already checked.
  406. * @param certPathCerts The certificates of the certification path to be
  407. * checked.
  408. * @throws Exception if the certificate is revoked or the status
  409. * cannot be checked or some error occurs.
  410. */
  411. private static void CheckCrl(
  412. DistributionPoint dp,
  413. X509V2AttributeCertificate attrCert,
  414. PkixParameters paramsPKIX,
  415. DateTime validDate,
  416. X509Certificate issuerCert,
  417. CertStatus certStatus,
  418. ReasonsMask reasonMask,
  419. IList<X509Certificate> certPathCerts)
  420. {
  421. /*
  422. * 4.3.6 No Revocation Available
  423. *
  424. * The noRevAvail extension, defined in [X.509-2000], allows an AC
  425. * issuer to indicate that no revocation information will be made
  426. * available for this AC.
  427. */
  428. if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) != null)
  429. return;
  430. DateTime currentDate = DateTime.UtcNow;
  431. if (validDate.CompareTo(currentDate) > 0)
  432. throw new Exception("Validation time is in future.");
  433. // (a)
  434. /*
  435. * We always get timely valid CRLs, so there is no step (a) (1).
  436. * "locally cached" CRLs are assumed to be in getStore(), additional
  437. * CRLs must be enabled in the ExtendedPkixParameters and are in
  438. * getAdditionalStore()
  439. */
  440. var crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, attrCert, currentDate, paramsPKIX);
  441. bool validCrlFound = false;
  442. Exception lastException = null;
  443. var crl_iter = crls.GetEnumerator();
  444. while (crl_iter.MoveNext()
  445. && certStatus.Status == CertStatus.Unrevoked
  446. && !reasonMask.IsAllReasons)
  447. {
  448. try
  449. {
  450. X509Crl crl = crl_iter.Current;
  451. // (d)
  452. ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
  453. // (e)
  454. /*
  455. * The reasons mask is updated at the end, so only valid CRLs
  456. * can update it. If this CRL does not contain new reasons it
  457. * must be ignored.
  458. */
  459. if (!interimReasonsMask.HasNewReasons(reasonMask))
  460. continue;
  461. // (f)
  462. var keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, attrCert,null, null, paramsPKIX,
  463. certPathCerts);
  464. // (g)
  465. AsymmetricKeyParameter pubKey = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
  466. X509Crl deltaCRL = null;
  467. if (paramsPKIX.IsUseDeltasEnabled)
  468. {
  469. // get delta CRLs
  470. var deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl);
  471. // we only want one valid delta CRL
  472. // (h)
  473. deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, pubKey);
  474. }
  475. /*
  476. * CRL must be be valid at the current time, not the validation
  477. * time. If a certificate is revoked with reason keyCompromise,
  478. * cACompromise, it can be used for forgery, also for the past.
  479. * This reason may not be contained in older CRLs.
  480. */
  481. /*
  482. * in the chain model signatures stay valid also after the
  483. * certificate has been expired, so they do not have to be in
  484. * the CRL vality time
  485. */
  486. if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
  487. {
  488. /*
  489. * if a certificate has expired, but was revoked, it is not
  490. * more in the CRL, so it would be regarded as valid if the
  491. * first check is not done
  492. */
  493. if (attrCert.NotAfter.CompareTo(crl.ThisUpdate) < 0)
  494. throw new Exception("No valid CRL for current time found.");
  495. }
  496. Rfc3280CertPathUtilities.ProcessCrlB1(dp, attrCert, crl);
  497. // (b) (2)
  498. Rfc3280CertPathUtilities.ProcessCrlB2(dp, attrCert, crl);
  499. // (c)
  500. Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
  501. // (i)
  502. Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL,
  503. attrCert, certStatus, paramsPKIX);
  504. // (j)
  505. Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, attrCert,
  506. certStatus);
  507. // (k)
  508. if (certStatus.Status == CrlReason.RemoveFromCrl)
  509. {
  510. certStatus.Status = CertStatus.Unrevoked;
  511. }
  512. // update reasons mask
  513. reasonMask.AddReasons(interimReasonsMask);
  514. validCrlFound = true;
  515. }
  516. catch (Exception e)
  517. {
  518. lastException = e;
  519. }
  520. }
  521. if (!validCrlFound)
  522. throw lastException;
  523. }
  524. }
  525. }
  526. #pragma warning restore
  527. #endif