diff --git a/Crypto/src/pkix/PkixCertPathBuilder.cs b/Crypto/src/pkix/PkixCertPathBuilder.cs
new file mode 100644
index 000000000..7082fe409
--- /dev/null
+++ b/Crypto/src/pkix/PkixCertPathBuilder.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.IsisMtt;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+ *
+ * @see CertPathBuilderSpi
+ */
+ public class PkixCertPathBuilder
+ // : CertPathBuilderSpi
+ {
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public virtual PkixCertPathBuilderResult Build(
+ PkixBuilderParameters pkixParams)
+ {
+ // search target certificates
+
+ IX509Selector certSelect = pkixParams.GetTargetCertConstraints();
+ if (!(certSelect is X509CertStoreSelector))
+ {
+ throw new PkixCertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + typeof(X509CertStoreSelector).FullName + " for "
+ + this.GetType() + " class.");
+ }
+
+ ISet targets = new HashSet();
+ try
+ {
+ targets.AddAll(PkixCertPathValidatorUtilities.FindCertificates((X509CertStoreSelector)certSelect, pkixParams.GetStores()));
+ // TODO Should this include an entry for pkixParams.GetAdditionalStores() too?
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException(
+ "Error finding target certificate.", e);
+ }
+
+ if (targets.IsEmpty)
+ throw new PkixCertPathBuilderException("No certificate found matching targetContraints.");
+
+ PkixCertPathBuilderResult result = null;
+ IList certPathList = Platform.CreateArrayList();
+
+ // check all potential target certificates
+ foreach (X509Certificate cert in targets)
+ {
+ result = Build(cert, pkixParams, certPathList);
+
+ if (result != null)
+ break;
+ }
+
+ if (result == null && certPathException != null)
+ {
+ throw new PkixCertPathBuilderException(certPathException.Message, certPathException.InnerException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new PkixCertPathBuilderException("Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ protected virtual PkixCertPathBuilderResult Build(
+ X509Certificate tbvCert,
+ PkixBuilderParameters pkixParams,
+ IList tbvPath)
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the PKI graph.
+ if (tbvPath.Contains(tbvCert))
+ return null;
+
+ // step out, the certificate is not allowed to appear in a certification
+ // chain.
+ if (pkixParams.GetExcludedCerts().Contains(tbvCert))
+ return null;
+
+ // test if certificate path exceeds maximum length
+ if (pkixParams.MaxPathLength != -1)
+ {
+ if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
+ return null;
+ }
+
+ tbvPath.Add(tbvCert);
+
+// X509CertificateParser certParser = new X509CertificateParser();
+ PkixCertPathBuilderResult builderResult = null;
+ PkixCertPathValidator validator = new PkixCertPathValidator();
+
+ try
+ {
+ // check whether the issuer of <tbvCert> is a TrustAnchor
+ if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+ {
+ // exception message from possibly later tried certification
+ // chains
+ PkixCertPath certPath = null;
+ try
+ {
+ certPath = new PkixCertPath(tbvPath);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Certification path could not be constructed from certificate list.",
+ e);
+ }
+
+ PkixCertPathValidatorResult result = null;
+ try
+ {
+ result = (PkixCertPathValidatorResult)validator.Validate(
+ certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Certification path could not be validated.", e);
+ }
+
+ return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
+ result.PolicyTree, result.SubjectPublicKey);
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(
+ tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new Exception(
+ "No additiontal X.509 stores can be added from certificate locations.",
+ e);
+ }
+
+ // try to get the issuer certificate from one of the stores
+ HashSet issuers = new HashSet();
+ try
+ {
+ issuers.AddAll(PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Cannot find issuer certificate for certificate in certification path.",
+ e);
+ }
+
+ if (issuers.IsEmpty)
+ throw new Exception("No issuer certificate for certificate in certification path found.");
+
+ foreach (X509Certificate issuer in issuers)
+ {
+ builderResult = Build(issuer, pkixParams, tbvPath);
+
+ if (builderResult != null)
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ certPathException = e;
+ }
+
+ if (builderResult == null)
+ {
+ tbvPath.Remove(tbvCert);
+ }
+
+ return builderResult;
+ }
+ }
+}
|