PkixAttrCertPathBuilder.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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.Security.Certificates;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
  10. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Pkix
  11. {
  12. public class PkixAttrCertPathBuilder
  13. {
  14. /**
  15. * Build and validate a CertPath using the given parameter.
  16. *
  17. * @param params PKIXBuilderParameters object containing all information to
  18. * build the CertPath
  19. */
  20. public virtual PkixCertPathBuilderResult Build(PkixBuilderParameters pkixParams)
  21. {
  22. // search target certificates
  23. if (!(pkixParams.GetTargetConstraintsAttrCert() is X509AttrCertStoreSelector attrCertSelector))
  24. {
  25. throw new PkixCertPathBuilderException(
  26. "TargetConstraints must be an instance of "
  27. + typeof(X509AttrCertStoreSelector).FullName
  28. + " for "
  29. + typeof(PkixAttrCertPathBuilder).FullName + " class.");
  30. }
  31. HashSet<X509V2AttributeCertificate> targets;
  32. try
  33. {
  34. targets = FindAttributeCertificates(attrCertSelector, pkixParams.GetStoresAttrCert());
  35. }
  36. catch (Exception e)
  37. {
  38. throw new PkixCertPathBuilderException("Error finding target attribute certificate.", e);
  39. }
  40. if (targets.Count == 0)
  41. throw new PkixCertPathBuilderException("No attribute certificate found matching targetConstraints.");
  42. PkixCertPathBuilderResult result = null;
  43. // check all potential target certificates
  44. foreach (var target in targets)
  45. {
  46. X509CertStoreSelector certSelector = new X509CertStoreSelector();
  47. X509Name[] principals = target.Issuer.GetPrincipals();
  48. var issuers = new HashSet<X509Certificate>();
  49. for (int i = 0; i < principals.Length; i++)
  50. {
  51. // TODO Replace loop with a single multiprincipal selector (or don't even use selector)
  52. try
  53. {
  54. certSelector.Subject = principals[i];
  55. CollectionUtilities.CollectMatches(issuers, certSelector, pkixParams.GetStoresCert());
  56. }
  57. catch (Exception e)
  58. {
  59. throw new PkixCertPathBuilderException(
  60. "Public key certificate for attribute certificate cannot be searched.",
  61. e);
  62. }
  63. }
  64. if (issuers.Count < 1)
  65. throw new PkixCertPathBuilderException("Public key certificate for attribute certificate cannot be found.");
  66. var certPathList = new List<X509Certificate>();
  67. foreach (X509Certificate issuer in issuers)
  68. {
  69. result = Build(target, issuer, pkixParams, certPathList);
  70. if (result != null)
  71. break;
  72. }
  73. if (result != null)
  74. break;
  75. }
  76. if (result == null && certPathException != null)
  77. throw new PkixCertPathBuilderException("Possible certificate chain could not be validated.",
  78. certPathException);
  79. if (result == null && certPathException == null)
  80. throw new PkixCertPathBuilderException("Unable to find certificate chain.");
  81. return result;
  82. }
  83. private Exception certPathException;
  84. private PkixCertPathBuilderResult Build(
  85. X509V2AttributeCertificate attrCert,
  86. X509Certificate tbvCert,
  87. PkixBuilderParameters pkixParams,
  88. IList<X509Certificate> tbvPath)
  89. {
  90. // If tbvCert is readily present in tbvPath, it indicates having run
  91. // into a cycle in the
  92. // PKI graph.
  93. if (tbvPath.Contains(tbvCert))
  94. return null;
  95. // step out, the certificate is not allowed to appear in a certification
  96. // chain
  97. if (pkixParams.GetExcludedCerts().Contains(tbvCert))
  98. return null;
  99. // test if certificate path exceeds maximum length
  100. if (pkixParams.MaxPathLength != -1)
  101. {
  102. if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
  103. return null;
  104. }
  105. tbvPath.Add(tbvCert);
  106. PkixCertPathBuilderResult builderResult = null;
  107. // X509CertificateParser certParser = new X509CertificateParser();
  108. PkixAttrCertPathValidator validator = new PkixAttrCertPathValidator();
  109. try
  110. {
  111. // check whether the issuer of <tbvCert> is a TrustAnchor
  112. if (PkixCertPathValidatorUtilities.IsIssuerTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()))
  113. {
  114. PkixCertPath certPath = new PkixCertPath(tbvPath);
  115. PkixCertPathValidatorResult result;
  116. try
  117. {
  118. result = validator.Validate(certPath, pkixParams);
  119. }
  120. catch (Exception e)
  121. {
  122. throw new Exception("Certification path could not be validated.", e);
  123. }
  124. return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
  125. result.PolicyTree, result.SubjectPublicKey);
  126. }
  127. else
  128. {
  129. // add additional X.509 stores from locations in certificate
  130. try
  131. {
  132. PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(tbvCert, pkixParams);
  133. }
  134. catch (CertificateParsingException e)
  135. {
  136. throw new Exception("No additional X.509 stores can be added from certificate locations.", e);
  137. }
  138. // try to get the issuer certificate from one of the stores
  139. ISet<X509Certificate> issuers;
  140. try
  141. {
  142. issuers = PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams);
  143. }
  144. catch (Exception e)
  145. {
  146. throw new Exception("Cannot find issuer certificate for certificate in certification path.", e);
  147. }
  148. if (issuers.Count < 1)
  149. throw new Exception("No issuer certificate for certificate in certification path found.");
  150. foreach (X509Certificate issuer in issuers)
  151. {
  152. // if untrusted self signed certificate continue
  153. if (PkixCertPathValidatorUtilities.IsSelfIssued(issuer))
  154. continue;
  155. builderResult = Build(attrCert, issuer, pkixParams, tbvPath);
  156. if (builderResult != null)
  157. break;
  158. }
  159. }
  160. }
  161. catch (Exception e)
  162. {
  163. certPathException = new Exception("No valid certification path could be build.", e);
  164. }
  165. if (builderResult == null)
  166. {
  167. tbvPath.Remove(tbvCert);
  168. }
  169. return builderResult;
  170. }
  171. internal static HashSet<X509V2AttributeCertificate> FindAttributeCertificates(
  172. ISelector<X509V2AttributeCertificate> attrCertSelector,
  173. IList<IStore<X509V2AttributeCertificate>> attrCertStores)
  174. {
  175. var attrCerts = new HashSet<X509V2AttributeCertificate>();
  176. foreach (var attrCertStore in attrCertStores)
  177. {
  178. try
  179. {
  180. attrCerts.UnionWith(attrCertStore.EnumerateMatches(attrCertSelector));
  181. }
  182. catch (Exception e)
  183. {
  184. throw new Exception("Problem while picking certificates from X.509 store.", e);
  185. }
  186. }
  187. return attrCerts;
  188. }
  189. }
  190. }
  191. #pragma warning restore
  192. #endif