diff --git a/crypto/src/pkix/CertStatus.cs b/crypto/src/pkix/CertStatus.cs
new file mode 100644
index 000000000..4f40b7bc6
--- /dev/null
+++ b/crypto/src/pkix/CertStatus.cs
@@ -0,0 +1,35 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class CertStatus
+ {
+ public const int Unrevoked = 11;
+
+ public const int Undetermined = 12;
+
+ private int status = Unrevoked;
+
+ DateTimeObject revocationDate = null;
+
+ /// <summary>
+ /// Returns the revocationDate.
+ /// </summary>
+ public DateTimeObject RevocationDate
+ {
+ get { return revocationDate; }
+ set { this.revocationDate = value; }
+ }
+
+ /// <summary>
+ /// Returns the certStatus.
+ /// </summary>
+ public int Status
+ {
+ get { return status; }
+ set { this.status = value; }
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixAttrCertChecker.cs b/crypto/src/pkix/PkixAttrCertChecker.cs
new file mode 100644
index 000000000..a6eab8480
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertChecker.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public abstract class PkixAttrCertChecker
+ {
+ /**
+ * Returns an immutable <code>Set</code> of X.509 attribute certificate
+ * extensions that this <code>PkixAttrCertChecker</code> supports or
+ * <code>null</code> if no extensions are supported.
+ * <p>
+ * Each element of the set is a <code>String</code> representing the
+ * Object Identifier (OID) of the X.509 extension that is supported.
+ * </p>
+ * <p>
+ * All X.509 attribute certificate extensions that a
+ * <code>PkixAttrCertChecker</code> might possibly be able to process
+ * should be included in the set.
+ * </p>
+ *
+ * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+ * <code>String</code> format) supported by this
+ * <code>PkixAttrCertChecker</code>, or <code>null</code> if no
+ * extensions are supported
+ */
+ public abstract ISet GetSupportedExtensions();
+
+ /**
+ * Performs checks on the specified attribute certificate. Every handled
+ * extension is rmeoved from the <code>unresolvedCritExts</code>
+ * collection.
+ *
+ * @param attrCert The attribute certificate to be checked.
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param holderCertPath The certificate path which belongs to the holder
+ * certificate.
+ * @param unresolvedCritExts a <code>Collection</code> of OID strings
+ * representing the current set of unresolved critical extensions
+ * @throws CertPathValidatorException if the specified attribute certificate
+ * does not pass the check.
+ */
+ public abstract void Check(IX509AttributeCertificate attrCert, PkixCertPath certPath,
+ PkixCertPath holderCertPath, ICollection unresolvedCritExts);
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return a copy of this <code>PkixAttrCertChecker</code>
+ */
+ public abstract PkixAttrCertChecker Clone();
+ }
+}
diff --git a/crypto/src/pkix/PkixAttrCertPathBuilder.cs b/crypto/src/pkix/PkixAttrCertPathBuilder.cs
new file mode 100644
index 000000000..646cc5db5
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertPathBuilder.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+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
+{
+ public class PkixAttrCertPathBuilder
+ {
+ /**
+ * 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.GetTargetConstraints();
+ if (!(certSelect is X509AttrCertStoreSelector))
+ {
+ throw new PkixCertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + typeof(X509AttrCertStoreSelector).FullName
+ + " for "
+ + typeof(PkixAttrCertPathBuilder).FullName + " class.");
+ }
+
+ ICollection targets;
+ try
+ {
+ targets = PkixCertPathValidatorUtilities.FindCertificates(
+ (X509AttrCertStoreSelector)certSelect, pkixParams.GetStores());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException("Error finding target attribute certificate.", e);
+ }
+
+ if (targets.Count == 0)
+ {
+ throw new PkixCertPathBuilderException(
+ "No attribute certificate found matching targetContraints.");
+ }
+
+ PkixCertPathBuilderResult result = null;
+
+ // check all potential target certificates
+ foreach (IX509AttributeCertificate cert in targets)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ X509Name[] principals = cert.Issuer.GetPrincipals();
+ ISet issuers = new HashSet();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+ selector.Subject = principals[i];
+
+ issuers.AddAll(PkixCertPathValidatorUtilities.FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+
+ if (issuers.IsEmpty)
+ throw new PkixCertPathBuilderException("Public key certificate for attribute certificate cannot be found.");
+
+ IList certPathList = Platform.CreateArrayList();
+
+ foreach (X509Certificate issuer in issuers)
+ {
+ result = Build(cert, issuer, pkixParams, certPathList);
+
+ if (result != null)
+ break;
+ }
+
+ if (result != null)
+ break;
+ }
+
+ if (result == null && certPathException != null)
+ {
+ throw new PkixCertPathBuilderException(
+ "Possible certificate chain could not be validated.",
+ certPathException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new PkixCertPathBuilderException(
+ "Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ private PkixCertPathBuilderResult Build(
+ IX509AttributeCertificate attrCert,
+ 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);
+
+ PkixCertPathBuilderResult builderResult = null;
+
+// X509CertificateParser certParser = new X509CertificateParser();
+ PkixAttrCertPathValidator validator = new PkixAttrCertPathValidator();
+
+ try
+ {
+ // check whether the issuer of <tbvCert> is a TrustAnchor
+ if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+ {
+ PkixCertPath certPath = new PkixCertPath(tbvPath);
+ PkixCertPathValidatorResult result;
+
+ try
+ {
+ result = 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 additional X.509 stores can be added from certificate locations.", e);
+ }
+
+ // try to get the issuer certificate from one of the stores
+ ISet 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)
+ {
+ // if untrusted self signed certificate continue
+ if (PkixCertPathValidatorUtilities.IsSelfIssued(issuer))
+ continue;
+
+ builderResult = Build(attrCert, issuer, pkixParams, tbvPath);
+
+ if (builderResult != null)
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ certPathException = new Exception("No valid certification path could be build.", e);
+ }
+
+ if (builderResult == null)
+ {
+ tbvPath.Remove(tbvCert);
+ }
+
+ return builderResult;
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixAttrCertPathValidator.cs b/crypto/src/pkix/PkixAttrCertPathValidator.cs
new file mode 100644
index 000000000..5f53bcde6
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertPathValidator.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+ *
+ * @see org.bouncycastle.x509.ExtendedPkixParameters
+ */
+ public class PkixAttrCertPathValidator
+ // extends CertPathValidatorSpi
+ {
+ /**
+ * Validates an attribute certificate with the given certificate path.
+ *
+ * <p>
+ * <code>params</code> must be an instance of
+ * <code>ExtendedPkixParameters</code>.
+ * </p><p>
+ * The target constraints in the <code>params</code> must be an
+ * <code>X509AttrCertStoreSelector</code> with at least the attribute
+ * certificate criterion set. Obey that also target informations may be
+ * necessary to correctly validate this attribute certificate.
+ * </p><p>
+ * The attribute certificate issuer must be added to the trusted attribute
+ * issuers with {@link ExtendedPkixParameters#setTrustedACIssuers(Set)}.
+ * </p>
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param params The PKIX parameters.
+ * @return A <code>PKIXCertPathValidatorResult</code> of the result of
+ * validating the <code>certPath</code>.
+ * @throws InvalidAlgorithmParameterException if <code>params</code> is
+ * inappropriate for this validator.
+ * @throws CertPathValidatorException if the verification fails.
+ */
+ public virtual PkixCertPathValidatorResult Validate(
+ PkixCertPath certPath,
+ PkixParameters pkixParams)
+ {
+ IX509Selector certSelect = pkixParams.GetTargetConstraints();
+ if (!(certSelect is X509AttrCertStoreSelector))
+ {
+ throw new ArgumentException(
+ "TargetConstraints must be an instance of " + typeof(X509AttrCertStoreSelector).FullName,
+ "pkixParams");
+ }
+ IX509AttributeCertificate attrCert = ((X509AttrCertStoreSelector) certSelect).AttributeCert;
+
+ PkixCertPath holderCertPath = Rfc3281CertPathUtilities.ProcessAttrCert1(attrCert, pkixParams);
+ PkixCertPathValidatorResult result = Rfc3281CertPathUtilities.ProcessAttrCert2(certPath, pkixParams);
+ X509Certificate issuerCert = (X509Certificate)certPath.Certificates[0];
+ Rfc3281CertPathUtilities.ProcessAttrCert3(issuerCert, pkixParams);
+ Rfc3281CertPathUtilities.ProcessAttrCert4(issuerCert, pkixParams);
+ Rfc3281CertPathUtilities.ProcessAttrCert5(attrCert, pkixParams);
+ // 6 already done in X509AttrCertStoreSelector
+ Rfc3281CertPathUtilities.ProcessAttrCert7(attrCert, certPath, holderCertPath, pkixParams);
+ Rfc3281CertPathUtilities.AdditionalChecks(attrCert, pkixParams);
+ DateTime date;
+ try
+ {
+ date = PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(pkixParams, null, -1);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Could not get validity date from attribute certificate.", e);
+ }
+ Rfc3281CertPathUtilities.CheckCrls(attrCert, pkixParams, issuerCert, date, certPath.Certificates);
+ return result;
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixBuilderParameters.cs b/crypto/src/pkix/PkixBuilderParameters.cs
new file mode 100644
index 000000000..32fc04360
--- /dev/null
+++ b/crypto/src/pkix/PkixBuilderParameters.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509.Store;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixBuilderParameters.
+ /// </summary>
+ public class PkixBuilderParameters
+ : PkixParameters
+ {
+ private int maxPathLength = 5;
+
+ private ISet excludedCerts = new HashSet();
+
+ /**
+ * Returns an instance of <code>PkixBuilderParameters</code>.
+ * <p>
+ * This method can be used to get a copy from other
+ * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+ * and <code>ExtendedPKIXParameters</code> instances.
+ * </p>
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An <code>PkixBuilderParameters</code> instance.
+ */
+ public static PkixBuilderParameters GetInstance(
+ PkixParameters pkixParams)
+ {
+ PkixBuilderParameters parameters = new PkixBuilderParameters(
+ pkixParams.GetTrustAnchors(),
+ new X509CertStoreSelector(pkixParams.GetTargetCertConstraints()));
+ parameters.SetParams(pkixParams);
+ return parameters;
+ }
+
+ public PkixBuilderParameters(
+ ISet trustAnchors,
+ IX509Selector targetConstraints)
+ : base(trustAnchors)
+ {
+ SetTargetCertConstraints(targetConstraints);
+ }
+
+ public virtual int MaxPathLength
+ {
+ get { return maxPathLength; }
+ set
+ {
+ if (value < -1)
+ {
+ throw new InvalidParameterException(
+ "The maximum path length parameter can not be less than -1.");
+ }
+ this.maxPathLength = value;
+ }
+ }
+
+ /// <summary>
+ /// Excluded certificates are not used for building a certification path.
+ /// </summary>
+ /// <returns>the excluded certificates.</returns>
+ public virtual ISet GetExcludedCerts()
+ {
+ return new HashSet(excludedCerts);
+ }
+
+ /// <summary>
+ /// Sets the excluded certificates which are not used for building a
+ /// certification path. If the <code>ISet</code> is <code>null</code> an
+ /// empty set is assumed.
+ /// </summary>
+ /// <remarks>
+ /// The given set is cloned to protect it against subsequent modifications.
+ /// </remarks>
+ /// <param name="excludedCerts">The excluded certificates to set.</param>
+ public virtual void SetExcludedCerts(
+ ISet excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = new HashSet();
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+ * <code>PKIXBuilderParameters</code>.
+ *
+ * @param params Parameters to set.
+ * @see org.bouncycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected override void SetParams(
+ PkixParameters parameters)
+ {
+ base.SetParams(parameters);
+ if (parameters is PkixBuilderParameters)
+ {
+ PkixBuilderParameters _params = (PkixBuilderParameters) parameters;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ }
+
+ /**
+ * Makes a copy of this <code>PKIXParameters</code> object. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>PKIXParameters</code> object
+ */
+ public override object Clone()
+ {
+ PkixBuilderParameters parameters = new PkixBuilderParameters(
+ GetTrustAnchors(), GetTargetCertConstraints());
+ parameters.SetParams(this);
+ return parameters;
+ }
+
+ public override string ToString()
+ {
+ string nl = Platform.NewLine;
+ StringBuilder s = new StringBuilder();
+ s.Append("PkixBuilderParameters [" + nl);
+ s.Append(base.ToString());
+ s.Append(" Maximum Path Length: ");
+ s.Append(MaxPathLength);
+ s.Append(nl + "]" + nl);
+ return s.ToString();
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPath.cs b/crypto/src/pkix/PkixCertPath.cs
new file mode 100644
index 000000000..e3d3ea7fe
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPath.cs
@@ -0,0 +1,460 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * An immutable sequence of certificates (a certification path).<br />
+ * <br />
+ * This is an abstract class that defines the methods common to all CertPaths.
+ * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
+ * <br />
+ * All CertPath objects have a type, a list of Certificates, and one or more
+ * supported encodings. Because the CertPath class is immutable, a CertPath
+ * cannot change in any externally visible way after being constructed. This
+ * stipulation applies to all public fields and methods of this class and any
+ * added or overridden by subclasses.<br />
+ * <br />
+ * The type is a string that identifies the type of Certificates in the
+ * certification path. For each certificate cert in a certification path
+ * certPath, cert.getType().equals(certPath.getType()) must be true.<br />
+ * <br />
+ * The list of Certificates is an ordered List of zero or more Certificates.
+ * This List and all of the Certificates contained in it must be immutable.<br />
+ * <br />
+ * Each CertPath object must support one or more encodings so that the object
+ * can be translated into a byte array for storage or transmission to other
+ * parties. Preferably, these encodings should be well-documented standards
+ * (such as PKCS#7). One of the encodings supported by a CertPath is considered
+ * the default encoding. This encoding is used if no encoding is explicitly
+ * requested (for the {@link #getEncoded()} method, for instance).<br />
+ * <br />
+ * All CertPath objects are also Serializable. CertPath objects are resolved
+ * into an alternate {@link CertPathRep} object during serialization. This
+ * allows a CertPath object to be serialized into an equivalent representation
+ * regardless of its underlying implementation.<br />
+ * <br />
+ * CertPath objects can be created with a CertificateFactory or they can be
+ * returned by other classes, such as a CertPathBuilder.<br />
+ * <br />
+ * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+ * starting with the target certificate and ending with a certificate issued by
+ * the trust anchor. That is, the issuer of one certificate is the subject of
+ * the following one. The certificate representing the
+ * {@link TrustAnchor TrustAnchor} should not be included in the certification
+ * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+ * CertPathValidators will detect any departure from these conventions that
+ * cause the certification path to be invalid and throw a
+ * CertPathValidatorException.<br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * All CertPath objects must be thread-safe. That is, multiple threads may
+ * concurrently invoke the methods defined in this class on a single CertPath
+ * object (or more than one) with no ill effects. This is also true for the List
+ * returned by CertPath.getCertificates.<br />
+ * <br />
+ * Requiring CertPath objects to be immutable and thread-safe allows them to be
+ * passed around to various pieces of code without worrying about coordinating
+ * access. Providing this thread-safety is generally not difficult, since the
+ * CertPath and List objects in question are immutable.
+ *
+ * @see CertificateFactory
+ * @see CertPathBuilder
+ */
+ /// <summary>
+ /// CertPath implementation for X.509 certificates.
+ /// </summary>
+ public class PkixCertPath
+// : CertPath
+ {
+ internal static readonly IList certPathEncodings;
+
+ static PkixCertPath()
+ {
+ IList encodings = Platform.CreateArrayList();
+ encodings.Add("PkiPath");
+ encodings.Add("PEM");
+ encodings.Add("PKCS7");
+ certPathEncodings = CollectionUtilities.ReadOnly(encodings);
+ }
+
+ private readonly IList certificates;
+
+ /**
+ * @param certs
+ */
+ private static IList SortCerts(
+ IList certs)
+ {
+ if (certs.Count < 2)
+ return certs;
+
+ X509Name issuer = ((X509Certificate)certs[0]).IssuerDN;
+ bool okay = true;
+
+ for (int i = 1; i != certs.Count; i++)
+ {
+ X509Certificate cert = (X509Certificate)certs[i];
+
+ if (issuer.Equivalent(cert.SubjectDN, true))
+ {
+ issuer = ((X509Certificate)certs[i]).IssuerDN;
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ return certs;
+
+ // find end-entity cert
+ IList retList = Platform.CreateArrayList(certs.Count);
+ IList orig = Platform.CreateArrayList(certs);
+
+ for (int i = 0; i < certs.Count; i++)
+ {
+ X509Certificate cert = (X509Certificate)certs[i];
+ bool found = false;
+
+ X509Name subject = cert.SubjectDN;
+ foreach (X509Certificate c in certs)
+ {
+ if (c.IssuerDN.Equivalent(subject, true))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.Add(cert);
+ certs.RemoveAt(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.Count > 1)
+ return orig;
+
+ for (int i = 0; i != retList.Count; i++)
+ {
+ issuer = ((X509Certificate)retList[i]).IssuerDN;
+
+ for (int j = 0; j < certs.Count; j++)
+ {
+ X509Certificate c = (X509Certificate)certs[j];
+ if (issuer.Equivalent(c.SubjectDN, true))
+ {
+ retList.Add(c);
+ certs.RemoveAt(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.Count > 0)
+ return orig;
+
+ return retList;
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ * @param type the standard name of the type of Certificatesin this path
+ **/
+ public PkixCertPath(
+ ICollection certificates)
+// : base("X.509")
+ {
+ this.certificates = SortCerts(Platform.CreateArrayList(certificates));
+ }
+
+ public PkixCertPath(
+ Stream inStream)
+ : this(inStream, "PkiPath")
+ {
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ *
+ * @param type the standard name of the type of Certificatesin this path
+ **/
+ public PkixCertPath(
+ Stream inStream,
+ string encoding)
+// : base("X.509")
+ {
+ string upper = encoding.ToUpper();
+
+ IList certs;
+ try
+ {
+ if (upper.Equals("PkiPath".ToUpper()))
+ {
+ Asn1InputStream derInStream = new Asn1InputStream(inStream);
+ Asn1Object derObject = derInStream.ReadObject();
+ if (!(derObject is Asn1Sequence))
+ {
+ throw new CertificateException(
+ "input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+
+ certs = Platform.CreateArrayList();
+
+ foreach (Asn1Encodable ae in (Asn1Sequence)derObject)
+ {
+ byte[] derBytes = ae.GetEncoded(Asn1Encodable.Der);
+ Stream certInStream = new MemoryStream(derBytes, false);
+
+ // TODO Is inserting at the front important (list will be sorted later anyway)?
+ certs.Insert(0, new X509CertificateParser().ReadCertificate(certInStream));
+ }
+ }
+ else if (upper.Equals("PKCS7") || upper.Equals("PEM"))
+ {
+ certs = Platform.CreateArrayList(new X509CertificateParser().ReadCertificates(inStream));
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException(
+ "IOException throw while decoding CertPath:\n"
+ + ex.ToString());
+ }
+
+ this.certificates = SortCerts(certs);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public virtual IEnumerable Encodings
+ {
+ get { return new EnumerableProxy(certPathEncodings); }
+ }
+
+ /**
+ * Compares this certification path for equality with the specified object.
+ * Two CertPaths are equal if and only if their types are equal and their
+ * certificate Lists (and by implication the Certificates in those Lists)
+ * are equal. A CertPath is never equal to an object that is not a CertPath.<br />
+ * <br />
+ * This algorithm is implemented by this method. If it is overridden, the
+ * behavior specified here must be maintained.
+ *
+ * @param other
+ * the object to test for equality with this certification path
+ *
+ * @return true if the specified object is equal to this certification path,
+ * false otherwise
+ *
+ * @see Object#hashCode() Object.hashCode()
+ */
+ public override bool Equals(
+ object obj)
+ {
+ if (this == obj)
+ return true;
+
+ PkixCertPath other = obj as PkixCertPath;
+ if (other == null)
+ return false;
+
+// if (!this.Type.Equals(other.Type))
+// return false;
+
+ //return this.Certificates.Equals(other.Certificates);
+
+ // TODO Extract this to a utility class
+ IList thisCerts = this.Certificates;
+ IList otherCerts = other.Certificates;
+
+ if (thisCerts.Count != otherCerts.Count)
+ return false;
+
+ IEnumerator e1 = thisCerts.GetEnumerator();
+ IEnumerator e2 = thisCerts.GetEnumerator();
+
+ while (e1.MoveNext())
+ {
+ e2.MoveNext();
+
+ if (!Platform.Equals(e1.Current, e2.Current))
+ return false;
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ // FIXME?
+ return this.Certificates.GetHashCode();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception CertificateEncodingException if an encoding error occurs
+ **/
+ public virtual byte[] GetEncoded()
+ {
+ foreach (object enc in Encodings)
+ {
+ if (enc is string)
+ {
+ return GetEncoded((string)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ */
+ public virtual byte[] GetEncoded(
+ string encoding)
+ {
+ if (Platform.CompareIgnoreCase(encoding, "PkiPath") == 0)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ for (int i = certificates.Count - 1; i >= 0; i--)
+ {
+ v.Add(ToAsn1Object((X509Certificate) certificates[i]));
+ }
+
+ return ToDerEncoded(new DerSequence(v));
+ }
+ else if (Platform.CompareIgnoreCase(encoding, "PKCS7") == 0)
+ {
+ Asn1.Pkcs.ContentInfo encInfo = new Asn1.Pkcs.ContentInfo(
+ PkcsObjectIdentifiers.Data, null);
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ for (int i = 0; i != certificates.Count; i++)
+ {
+ v.Add(ToAsn1Object((X509Certificate)certificates[i]));
+ }
+
+ Asn1.Pkcs.SignedData sd = new Asn1.Pkcs.SignedData(
+ new DerInteger(1),
+ new DerSet(),
+ encInfo,
+ new DerSet(v),
+ null,
+ new DerSet());
+
+ return ToDerEncoded(new Asn1.Pkcs.ContentInfo(PkcsObjectIdentifiers.SignedData, sd));
+ }
+ else if (Platform.CompareIgnoreCase(encoding, "PEM") == 0)
+ {
+ MemoryStream bOut = new MemoryStream();
+ PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.Count; i++)
+ {
+ pWrt.WriteObject(certificates[i]);
+ }
+
+ pWrt.Writer.Close();
+ }
+ catch (Exception)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.ToArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /// <summary>
+ /// Returns the list of certificates in this certification
+ /// path.
+ /// </summary>
+ public virtual IList Certificates
+ {
+ get { return CollectionUtilities.ReadOnly(certificates); }
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private Asn1Object ToAsn1Object(
+ X509Certificate cert)
+ {
+ try
+ {
+ return Asn1Object.FromByteArray(cert.GetEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate", e);
+ }
+ }
+
+ private byte[] ToDerEncoded(Asn1Encodable obj)
+ {
+ try
+ {
+ return obj.GetEncoded(Asn1Encodable.Der);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown", e);
+ }
+ }
+ }
+}
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;
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathBuilderException.cs b/crypto/src/pkix/PkixCertPathBuilderException.cs
new file mode 100644
index 000000000..5a4944dd8
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathBuilderException.cs
@@ -0,0 +1,22 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixCertPathBuilderException.
+ /// </summary>
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class PkixCertPathBuilderException : GeneralSecurityException
+ {
+ public PkixCertPathBuilderException() : base() { }
+
+ public PkixCertPathBuilderException(string message) : base(message) { }
+
+ public PkixCertPathBuilderException(string message, Exception exception) : base(message, exception) { }
+
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathBuilderResult.cs b/crypto/src/pkix/PkixCertPathBuilderResult.cs
new file mode 100644
index 000000000..f8003032f
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathBuilderResult.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkix;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixCertPathBuilderResult.
+ /// </summary>
+ public class PkixCertPathBuilderResult
+ : PkixCertPathValidatorResult//, ICertPathBuilderResult
+ {
+ private PkixCertPath certPath;
+
+ public PkixCertPathBuilderResult(
+ PkixCertPath certPath,
+ TrustAnchor trustAnchor,
+ PkixPolicyNode policyTree,
+ AsymmetricKeyParameter subjectPublicKey)
+ : base(trustAnchor, policyTree, subjectPublicKey)
+ {
+ if (certPath == null)
+ throw new ArgumentNullException("certPath");
+
+ this.certPath = certPath;
+ }
+
+ public PkixCertPath CertPath
+ {
+ get { return certPath; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder s = new StringBuilder();
+ s.Append("SimplePKIXCertPathBuilderResult: [\n");
+ s.Append(" Certification Path: ").Append(CertPath).Append('\n');
+ s.Append(" Trust Anchor: ").Append(this.TrustAnchor.TrustedCert.IssuerDN.ToString()).Append('\n');
+ s.Append(" Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+ return s.ToString();
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathChecker.cs b/crypto/src/pkix/PkixCertPathChecker.cs
new file mode 100644
index 000000000..f22738d89
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathChecker.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public abstract class PkixCertPathChecker
+ {
+ protected PkixCertPathChecker()
+ {
+ }
+
+ /**
+ * Initializes the internal state of this <code>PKIXCertPathChecker</code>.
+ * <p>
+ * The <code>forward</code> flag specifies the order that certificates
+ * will be passed to the {@link #check check} method (forward or reverse). A
+ * <code>PKIXCertPathChecker</code> <b>must</b> support reverse checking
+ * and <b>may</b> support forward checking.
+ * </p>
+ *
+ * @param forward
+ * the order that certificates are presented to the
+ * <code>check</code> method. If <code>true</code>,
+ * certificates are presented from target to most-trusted CA
+ * (forward); if <code>false</code>, from most-trusted CA to
+ * target (reverse).
+ * @exception CertPathValidatorException
+ * if this <code>PKIXCertPathChecker</code> is unable to
+ * check certificates in the specified order; it should never
+ * be thrown if the forward flag is false since reverse
+ * checking must be supported
+ */
+ public abstract void Init(bool forward);
+ //throws CertPathValidatorException;
+
+ /**
+ * Indicates if forward checking is supported. Forward checking refers to
+ * the ability of the <code>PKIXCertPathChecker</code> to perform its
+ * checks when certificates are presented to the <code>check</code> method
+ * in the forward direction (from target to most-trusted CA).
+ *
+ * @return <code>true</code> if forward checking is supported,
+ * <code>false</code> otherwise
+ */
+ public abstract bool IsForwardCheckingSupported();
+
+ /**
+ * Returns an immutable <code>Set</code> of X.509 certificate extensions
+ * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes,
+ * is able to process), or <code>null</code> if no extensions are
+ * supported.
+ * <p>
+ * Each element of the set is a <code>String</code> representing the
+ * Object Identifier (OID) of the X.509 extension that is supported. The OID
+ * is represented by a set of nonnegative integers separated by periods.
+ * </p><p>
+ * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code>
+ * might possibly be able to process should be included in the set.
+ * </p>
+ *
+ * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+ * <code>String</code> format) supported by this
+ * <code>PKIXCertPathChecker</code>, or <code>null</code> if no
+ * extensions are supported
+ */
+ public abstract ISet GetSupportedExtensions();
+
+ /**
+ * Performs the check(s) on the specified certificate using its internal
+ * state and removes any critical extensions that it processes from the
+ * specified collection of OID strings that represent the unresolved
+ * critical extensions. The certificates are presented in the order
+ * specified by the <code>init</code> method.
+ *
+ * @param cert
+ * the <code>Certificate</code> to be checked
+ * @param unresolvedCritExts
+ * a <code>Collection</code> of OID strings representing the
+ * current set of unresolved critical extensions
+ * @exception CertPathValidatorException
+ * if the specified certificate does not pass the check
+ */
+ public abstract void Check(X509Certificate cert, ICollection unresolvedCritExts);
+ //throws CertPathValidatorException;
+
+ /**
+ * Returns a clone of this object. Calls the <code>Object.clone()</code>
+ * method. All subclasses which maintain state must support and override
+ * this method, if necessary.
+ *
+ * @return a copy of this <code>PKIXCertPathChecker</code>
+ */
+ public virtual object Clone()
+ {
+ // TODO Check this
+ return base.MemberwiseClone();
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidator.cs b/crypto/src/pkix/PkixCertPathValidator.cs
new file mode 100644
index 000000000..7eb838886
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidator.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertPathValidator CertPathValidator} class. All
+ * <code>CertPathValidator</code> implementations must include a class (the
+ * SPI class) that extends this class (<code>CertPathValidatorSpi</code>)
+ * and implements all of its methods. In general, instances of this class
+ * should only be accessed through the <code>CertPathValidator</code> class.
+ * For details, see the Java Cryptography Architecture.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * <code>CertPathValidatorSpi</code> instance concurrently should synchronize
+ * amongst themselves and provide the necessary locking before calling the
+ * wrapping <code>CertPathValidator</code> object.<br />
+ * <br />
+ * However, implementations of <code>CertPathValidatorSpi</code> may still
+ * encounter concurrency issues, since multiple threads each
+ * manipulating a different <code>CertPathValidatorSpi</code> instance need not
+ * synchronize.
+ */
+ /// <summary>
+ /// CertPathValidatorSpi implementation for X.509 Certificate validation a la RFC
+ /// 3280.
+ /// </summary>
+ public class PkixCertPathValidator
+ {
+ public virtual PkixCertPathValidatorResult Validate(
+ PkixCertPath certPath,
+ PkixParameters paramsPkix)
+ {
+ if (paramsPkix.GetTrustAnchors() == null)
+ {
+ throw new ArgumentException(
+ "trustAnchors is null, this is not allowed for certification path validation.",
+ "parameters");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ IList certs = certPath.Certificates;
+ int n = certs.Count;
+
+ if (certs.Count == 0)
+ throw new PkixCertPathValidatorException("Certification path is empty.", null, certPath, 0);
+
+ //
+ // (b)
+ //
+ // DateTime validDate = PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+
+ //
+ // (c)
+ //
+ ISet userInitialPolicySet = paramsPkix.GetInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = PkixCertPathValidatorUtilities.FindTrustAnchor(
+ (X509Certificate)certs[certs.Count - 1],
+ paramsPkix.GetTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(e.Message, e, certPath, certs.Count - 1);
+ }
+
+ if (trust == null)
+ throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+
+ //
+ // (e), (f), (g) are part of the paramsPkix object.
+ //
+ IEnumerator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ IList[] policyNodes = new IList[n + 1];
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ policyNodes[j] = Platform.CreateArrayList();
+ }
+
+ ISet policySet = new HashSet();
+
+ policySet.Add(Rfc3280CertPathUtilities.ANY_POLICY);
+
+ PkixPolicyNode validPolicyTree = new PkixPolicyNode(Platform.CreateArrayList(), 0, policySet, null, new HashSet(),
+ Rfc3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].Add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PkixNameConstraintValidator nameConstraintValidator = new PkixNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ ISet acceptablePolicies = new HashSet();
+
+ if (paramsPkix.IsExplicitPolicyRequired)
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPkix.IsAnyPolicyInhibited)
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPkix.IsPolicyMappingInhibited)
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ AsymmetricKeyParameter workingPublicKey;
+ X509Name workingIssuerName;
+
+ X509Certificate sign = trust.TrustedCert;
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = sign.SubjectDN;
+ workingPublicKey = sign.GetPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X509Name(trust.CAName);
+ workingPublicKey = trust.CAPublicKey;
+ }
+ }
+ catch (ArgumentException ex)
+ {
+ throw new PkixCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+
+// DerObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.ObjectID;
+// Asn1Encodable workingPublicKeyParameters = workingAlgId.Parameters;
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ X509CertStoreSelector certConstraints = paramsPkix.GetTargetCertConstraints();
+ if (certConstraints != null && !certConstraints.Match((X509Certificate)certs[0]))
+ {
+ throw new PkixCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ IList pathCheckers = paramsPkix.GetCertPathCheckers();
+ certIter = pathCheckers.GetEnumerator();
+
+ while (certIter.MoveNext())
+ {
+ ((PkixCertPathChecker)certIter.Current).Init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.Count - 1; index >= 0; index--)
+ {
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate)certs[index];
+
+ //
+ // 6.1.3
+ //
+
+ Rfc3280CertPathUtilities.ProcessCertA(certPath, paramsPkix, index, workingPublicKey,
+ workingIssuerName, sign);
+
+ Rfc3280CertPathUtilities.ProcessCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = Rfc3280CertPathUtilities.ProcessCertD(certPath, index,
+ acceptablePolicies, validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = Rfc3280CertPathUtilities.ProcessCertE(certPath, index, validPolicyTree);
+
+ Rfc3280CertPathUtilities.ProcessCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.Version == 1)
+ {
+ throw new PkixCertPathValidatorException(
+ "Version 1 certificates can't be used as CA ones.", null, certPath, index);
+ }
+
+ Rfc3280CertPathUtilities.PrepareNextCertA(certPath, index);
+
+ validPolicyTree = Rfc3280CertPathUtilities.PrepareCertB(certPath, index, policyNodes,
+ validPolicyTree, policyMapping);
+
+ Rfc3280CertPathUtilities.PrepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = Rfc3280CertPathUtilities.PrepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = Rfc3280CertPathUtilities.PrepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ Rfc3280CertPathUtilities.PrepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ Rfc3280CertPathUtilities.PrepareNextCertN(certPath, index);
+
+ ISet criticalExtensions1 = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensions1 != null)
+ {
+ criticalExtensions1 = new HashSet(criticalExtensions1);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions1.Remove(X509Extensions.KeyUsage.Id);
+ criticalExtensions1.Remove(X509Extensions.CertificatePolicies.Id);
+ criticalExtensions1.Remove(X509Extensions.PolicyMappings.Id);
+ criticalExtensions1.Remove(X509Extensions.InhibitAnyPolicy.Id);
+ criticalExtensions1.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions1.Remove(X509Extensions.DeltaCrlIndicator.Id);
+ criticalExtensions1.Remove(X509Extensions.PolicyConstraints.Id);
+ criticalExtensions1.Remove(X509Extensions.BasicConstraints.Id);
+ criticalExtensions1.Remove(X509Extensions.SubjectAlternativeName.Id);
+ criticalExtensions1.Remove(X509Extensions.NameConstraints.Id);
+ }
+ else
+ {
+ criticalExtensions1 = new HashSet();
+ }
+
+ // (o)
+ Rfc3280CertPathUtilities.PrepareNextCertO(certPath, index, criticalExtensions1, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = sign.SubjectDN;
+
+ // (d)
+ try
+ {
+ workingPublicKey = PkixCertPathValidatorUtilities.GetNextWorkingKey(certPath.Certificates, index);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+ // (f)
+// workingPublicKeyAlgorithm = workingAlgId.ObjectID;
+ // (e)
+// workingPublicKeyParameters = workingAlgId.Parameters;
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = Rfc3280CertPathUtilities.WrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = Rfc3280CertPathUtilities.WrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ ISet criticalExtensions = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // Requires .Id
+ // these extensions are handled by the algorithm
+ criticalExtensions.Remove(X509Extensions.KeyUsage.Id);
+ criticalExtensions.Remove(X509Extensions.CertificatePolicies.Id);
+ criticalExtensions.Remove(X509Extensions.PolicyMappings.Id);
+ criticalExtensions.Remove(X509Extensions.InhibitAnyPolicy.Id);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+ criticalExtensions.Remove(X509Extensions.PolicyConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.BasicConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.SubjectAlternativeName.Id);
+ criticalExtensions.Remove(X509Extensions.NameConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.CrlDistributionPoints.Id);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ Rfc3280CertPathUtilities.WrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PkixPolicyNode intersection = Rfc3280CertPathUtilities.WrapupCertG(certPath, paramsPkix, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PkixCertPathValidatorResult(trust, intersection, cert.GetPublicKey());
+ }
+
+ throw new PkixCertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidatorException.cs b/crypto/src/pkix/PkixCertPathValidatorException.cs
new file mode 100644
index 000000000..35522c6f8
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidatorException.cs
@@ -0,0 +1,221 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * An exception indicating one of a variety of problems encountered when
+ * validating a certification path. <br />
+ * <br />
+ * A <code>CertPathValidatorException</code> provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown. <br />
+ * <br />
+ * A <code>CertPathValidatorException</code> may also include the
+ * certification path that was being validated when the exception was thrown
+ * and the index of the certificate in the certification path that caused the
+ * exception to be thrown. Use the {@link #getCertPath getCertPath} and
+ * {@link #getIndex getIndex} methods to retrieve this information.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidator
+ **/
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class PkixCertPathValidatorException
+ : GeneralSecurityException
+ {
+ private Exception cause;
+ private PkixCertPath certPath;
+ private int index = -1;
+
+ public PkixCertPathValidatorException() : base() { }
+
+ /// <summary>
+ /// Creates a <code>PkixCertPathValidatorException</code> with the given detail
+ /// message. A detail message is a <code>String</code> that describes this
+ /// particular exception.
+ /// </summary>
+ /// <param name="message">the detail message</param>
+ public PkixCertPathValidatorException(string message) : base(message) { }
+
+ /// <summary>
+ /// Creates a <code>PkixCertPathValidatorException</code> with the specified
+ /// detail message and cause.
+ /// </summary>
+ /// <param name="message">the detail message</param>
+ /// <param name="cause">the cause (which is saved for later retrieval by the
+ /// {@link #getCause getCause()} method). (A <code>null</code>
+ /// value is permitted, and indicates that the cause is
+ /// nonexistent or unknown.)</param>
+ public PkixCertPathValidatorException(string message, Exception cause) : base(message)
+ {
+ this.cause = cause;
+ }
+
+ /// <summary>
+ /// Creates a <code>PkixCertPathValidatorException</code> with the specified
+ /// detail message, cause, certification path, and index.
+ /// </summary>
+ /// <param name="message">the detail message (or <code>null</code> if none)</param>
+ /// <param name="cause">the cause (or <code>null</code> if none)</param>
+ /// <param name="certPath">the certification path that was in the process of being
+ /// validated when the error was encountered</param>
+ /// <param name="index">the index of the certificate in the certification path that</param> *
+ public PkixCertPathValidatorException(
+ string message,
+ Exception cause,
+ PkixCertPath certPath,
+ int index)
+ : base(message)
+ {
+ if (certPath == null && index != -1)
+ {
+ throw new ArgumentNullException(
+ "certPath = null and index != -1");
+ }
+ if (index < -1
+ || (certPath != null && index >= certPath.Certificates.Count))
+ {
+ throw new IndexOutOfRangeException(
+ " index < -1 or out of bound of certPath.getCertificates()");
+ }
+
+ this.cause = cause;
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ //
+ // Prints a stack trace to a <code>PrintWriter</code>, including the
+ // backtrace of the cause, if any.
+ //
+ // @param pw
+ // the <code>PrintWriter</code> to use for output
+ //
+ // public void printStackTrace(PrintWriter pw)
+ // {
+ // super.printStackTrace(pw);
+ // if (getCause() != null)
+ // {
+ // getCause().printStackTrace(pw);
+ // }
+ // }
+ //}
+
+
+ // /**
+ // * Creates a <code>CertPathValidatorException</code> that wraps the
+ // * specified throwable. This allows any exception to be converted into a
+ // * <code>CertPathValidatorException</code>, while retaining information
+ // * about the wrapped exception, which may be useful for debugging. The
+ // * detail message is set to (<code>cause==null ? null : cause.toString()
+ // * </code>)
+ // * (which typically contains the class and detail message of cause).
+ // *
+ // * @param cause
+ // * the cause (which is saved for later retrieval by the
+ // * {@link #getCause getCause()} method). (A <code>null</code>
+ // * value is permitted, and indicates that the cause is
+ // * nonexistent or unknown.)
+ // */
+ // public PkixCertPathValidatorException(Throwable cause)
+ // {
+ // this.cause = cause;
+ // }
+ //
+
+ /// <summary>
+ /// Returns the detail message for this <code>CertPathValidatorException</code>.
+ /// </summary>
+ /// <returns>the detail message, or <code>null</code> if neither the message nor cause were specified</returns>
+ public override string Message
+ {
+ get
+ {
+ string message = base.Message;
+
+ if (message != null)
+ {
+ return message;
+ }
+
+ if (cause != null)
+ {
+ return cause.Message;
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Returns the certification path that was being validated when the
+ * exception was thrown.
+ *
+ * @return the <code>CertPath</code> that was being validated when the
+ * exception was thrown (or <code>null</code> if not specified)
+ */
+ public PkixCertPath CertPath
+ {
+ get { return certPath; }
+ }
+
+ /**
+ * Returns the index of the certificate in the certification path that
+ * caused the exception to be thrown. Note that the list of certificates in
+ * a <code>CertPath</code> is zero based. If no index has been set, -1 is
+ * returned.
+ *
+ * @return the index that has been set, or -1 if none has been set
+ */
+ public int Index
+ {
+ get { return index; }
+ }
+
+// /**
+// * Returns the cause of this <code>CertPathValidatorException</code> or
+// * <code>null</code> if the cause is nonexistent or unknown.
+// *
+// * @return the cause of this throwable or <code>null</code> if the cause
+// * is nonexistent or unknown.
+// */
+// public Throwable getCause()
+// {
+// return cause;
+// }
+//
+// /**
+// * Returns a string describing this exception, including a description of
+// * the internal (wrapped) cause if there is one.
+// *
+// * @return a string representation of this
+// * <code>CertPathValidatorException</code>
+// */
+// public String toString()
+// {
+// StringBuffer sb = new StringBuffer();
+// String s = getMessage();
+// if (s != null)
+// {
+// sb.append(s);
+// }
+// if (getIndex() >= 0)
+// {
+// sb.append("index in certpath: ").append(getIndex()).append('\n');
+// sb.append(getCertPath());
+// }
+// return sb.toString();
+// }
+
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidatorResult.cs b/crypto/src/pkix/PkixCertPathValidatorResult.cs
new file mode 100644
index 000000000..c7d81c7f5
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidatorResult.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixCertPathValidatorResult.
+ /// </summary>
+ public class PkixCertPathValidatorResult
+ //: ICertPathValidatorResult
+ {
+ private TrustAnchor trustAnchor;
+ private PkixPolicyNode policyTree;
+ private AsymmetricKeyParameter subjectPublicKey;
+
+ public PkixPolicyNode PolicyTree
+ {
+ get { return this.policyTree; }
+ }
+
+ public TrustAnchor TrustAnchor
+ {
+ get { return this.trustAnchor; }
+ }
+
+ public AsymmetricKeyParameter SubjectPublicKey
+ {
+ get { return this.subjectPublicKey; }
+ }
+
+ public PkixCertPathValidatorResult(
+ TrustAnchor trustAnchor,
+ PkixPolicyNode policyTree,
+ AsymmetricKeyParameter subjectPublicKey)
+ {
+ if (subjectPublicKey == null)
+ {
+ throw new NullReferenceException("subjectPublicKey must be non-null");
+ }
+ if (trustAnchor == null)
+ {
+ throw new NullReferenceException("trustAnchor must be non-null");
+ }
+
+ this.trustAnchor = trustAnchor;
+ this.policyTree = policyTree;
+ this.subjectPublicKey = subjectPublicKey;
+ }
+
+ public object Clone()
+ {
+ return new PkixCertPathValidatorResult(this.TrustAnchor, this.PolicyTree, this.SubjectPublicKey);
+ }
+
+ public override String ToString()
+ {
+ StringBuilder sB = new StringBuilder();
+ sB.Append("PKIXCertPathValidatorResult: [ \n");
+ sB.Append(" Trust Anchor: ").Append(this.TrustAnchor).Append('\n');
+ sB.Append(" Policy Tree: ").Append(this.PolicyTree).Append('\n');
+ sB.Append(" Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+ return sB.ToString();
+ }
+
+ }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
new file mode 100644
index 000000000..305b2de35
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -0,0 +1,1194 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.IsisMtt;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixCertPathValidatorUtilities.
+ /// </summary>
+ public class PkixCertPathValidatorUtilities
+ {
+ private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+ internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+ internal static readonly string CRL_NUMBER = X509Extensions.CrlNumber.Id;
+
+ /// <summary>
+ /// key usage bits
+ /// </summary>
+ internal static readonly int KEY_CERT_SIGN = 5;
+ internal static readonly int CRL_SIGN = 6;
+
+ internal static readonly string[] crlReasons = new string[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"
+ };
+
+ /// <summary>
+ /// Search the given Set of TrustAnchor's for one that is the
+ /// issuer of the given X509 certificate.
+ /// </summary>
+ /// <param name="cert">the X509 certificate</param>
+ /// <param name="trustAnchors">a Set of TrustAnchor's</param>
+ /// <returns>the <code>TrustAnchor</code> object if found or
+ /// <code>null</code> if not.
+ /// </returns>
+ /// @exception
+ internal static TrustAnchor FindTrustAnchor(
+ X509Certificate cert,
+ ISet trustAnchors)
+ {
+ IEnumerator iter = trustAnchors.GetEnumerator();
+ TrustAnchor trust = null;
+ AsymmetricKeyParameter trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertStoreSelector certSelectX509 = new X509CertStoreSelector();
+
+ try
+ {
+ certSelectX509.Subject = GetIssuerPrincipal(cert);
+ }
+ catch (IOException ex)
+ {
+ throw new Exception("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ while (iter.MoveNext() && trust == null)
+ {
+ trust = (TrustAnchor) iter.Current;
+ if (trust.TrustedCert != null)
+ {
+ if (certSelectX509.Match(trust.TrustedCert))
+ {
+ trustPublicKey = trust.TrustedCert.GetPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.CAName != null && trust.CAPublicKey != null)
+ {
+ try
+ {
+ X509Name certIssuer = GetIssuerPrincipal(cert);
+ X509Name caName = new X509Name(trust.CAName);
+
+ if (certIssuer.Equivalent(caName, true))
+ {
+ trustPublicKey = trust.CAPublicKey;
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (InvalidParameterException)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.Verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new Exception("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ internal static void AddAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ PkixParameters pkixParams)
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+ if (cert.GetIssuerAlternativeNames() != null)
+ {
+ IEnumerator it = cert.GetIssuerAlternativeNames().GetEnumerator();
+ while (it.MoveNext())
+ {
+ // look for URI
+ IList list = (IList)it.Current;
+ //if (list[0].Equals(new Integer(GeneralName.UniformResourceIdentifier)))
+ if (list[0].Equals(GeneralName.UniformResourceIdentifier))
+ {
+ // found
+ string temp = (string)list[1];
+ PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+ }
+
+ internal static DateTime GetValidDate(PkixParameters paramsPKIX)
+ {
+ DateTimeObject validDate = paramsPKIX.Date;
+
+ if (validDate == null)
+ return DateTime.UtcNow;
+
+ return validDate.Value;
+ }
+
+ /// <summary>
+ /// Returns the issuer of an attribute certificate or certificate.
+ /// </summary>
+ /// <param name="cert">The attribute certificate or certificate.</param>
+ /// <returns>The issuer as <code>X500Principal</code>.</returns>
+ internal static X509Name GetIssuerPrincipal(
+ object cert)
+ {
+ if (cert is X509Certificate)
+ {
+ return ((X509Certificate)cert).IssuerDN;
+ }
+ else
+ {
+ return ((IX509AttributeCertificate)cert).Issuer.GetPrincipals()[0];
+ }
+ }
+
+ internal static bool IsSelfIssued(
+ X509Certificate cert)
+ {
+ return cert.SubjectDN.Equivalent(cert.IssuerDN, true);
+ }
+
+ internal static AlgorithmIdentifier GetAlgorithmIdentifier(
+ AsymmetricKeyParameter key)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(key);
+
+ return info.AlgorithmID;
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ internal static bool IsAnyPolicy(
+ ISet policySet)
+ {
+ return policySet == null || policySet.Contains(ANY_POLICY) || policySet.Count == 0;
+ }
+
+ internal static void AddAdditionalStoreFromLocation(
+ string location,
+ PkixParameters pkixParams)
+ {
+ if (pkixParams.IsAdditionalLocationsEnabled)
+ {
+ try
+ {
+ if (location.StartsWith("ldap://"))
+ {
+ // ldap://directory.d-trust.net/CN=D-TRUST
+ // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+ // skip "ldap://"
+ location = location.Substring(7);
+ // after first / baseDN starts
+ string url;//, baseDN;
+ int slashPos = location.IndexOf('/');
+ if (slashPos != -1)
+ {
+ url = "ldap://" + location.Substring(0, slashPos);
+// baseDN = location.Substring(slashPos);
+ }
+ else
+ {
+ url = "ldap://" + location;
+// baseDN = nsull;
+ }
+
+ throw Platform.CreateNotImplementedException("LDAP cert/CRL stores");
+
+ // use all purpose parameters
+ //X509LDAPCertStoreParameters ldapParams = new X509LDAPCertStoreParameters.Builder(
+ // url, baseDN).build();
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CERTIFICATE/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CRL/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "ATTRIBUTECERTIFICATE/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CERTIFICATEPAIR/LDAP", ldapParams));
+ }
+ }
+ catch (Exception)
+ {
+ // cannot happen
+ throw new Exception("Exception adding X.509 stores.");
+ }
+ }
+ }
+
+ private static BigInteger GetSerialNumber(
+ object cert)
+ {
+ if (cert is X509Certificate)
+ {
+ return ((X509Certificate)cert).SerialNumber;
+ }
+ else
+ {
+ return ((X509V2AttributeCertificate)cert).SerialNumber;
+ }
+ }
+
+ //
+ // policy checking
+ //
+
+ internal static ISet GetQualifierSet(Asn1Sequence qualifiers)
+ {
+ ISet pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ foreach (Asn1Encodable ae in qualifiers)
+ {
+ try
+ {
+// pq.Add(PolicyQualifierInfo.GetInstance(Asn1Object.FromByteArray(ae.GetEncoded())));
+ pq.Add(PolicyQualifierInfo.GetInstance(ae.ToAsn1Object()));
+ }
+ catch (IOException ex)
+ {
+ throw new PkixCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+ }
+
+ return pq;
+ }
+
+ internal static PkixPolicyNode RemovePolicyNode(
+ PkixPolicyNode validPolicyTree,
+ IList[] policyNodes,
+ PkixPolicyNode _node)
+ {
+ PkixPolicyNode _parent = (PkixPolicyNode)_node.Parent;
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ policyNodes[j] = Platform.CreateArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.RemoveChild(_node);
+ RemovePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void RemovePolicyNodeRecurse(IList[] policyNodes, PkixPolicyNode _node)
+ {
+ policyNodes[_node.Depth].Remove(_node);
+
+ if (_node.HasChildren)
+ {
+ foreach (PkixPolicyNode _child in _node.Children)
+ {
+ RemovePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+ internal static void PrepareNextCertB1(
+ int i,
+ IList[] policyNodes,
+ string id_p,
+ IDictionary m_idp,
+ X509Certificate cert)
+ {
+ bool idp_found = false;
+ IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ idp_found = true;
+ node.ExpectedPolicies = (ISet)m_idp[id_p];
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (ANY_POLICY.Equals(node.ValidPolicy))
+ {
+ ISet pq = null;
+ Asn1Sequence policies = null;
+ try
+ {
+ policies = DerSequence.GetInstance(GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Certificate policies cannot be decoded.", e);
+ }
+
+ IEnumerator enm = policies.GetEnumerator();
+ while (enm.MoveNext())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.GetInstance(enm.Current);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Policy information cannot be decoded.", ex);
+ }
+
+ if (ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+ {
+ try
+ {
+ pq = GetQualifierSet(pinfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ bool ci = false;
+ ISet critExtOids = cert.GetCriticalExtensionOids();
+ if (critExtOids != null)
+ {
+ ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+ }
+
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ if (ANY_POLICY.Equals(p_node.ValidPolicy))
+ {
+ PkixPolicyNode c_node = new PkixPolicyNode(
+ Platform.CreateArrayList(), i,
+ (ISet)m_idp[id_p],
+ p_node, pq, id_p, ci);
+ p_node.AddChild(c_node);
+ policyNodes[i].Add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ internal static PkixPolicyNode PrepareNextCertB2(
+ int i,
+ IList[] policyNodes,
+ string id_p,
+ PkixPolicyNode validPolicyTree)
+ {
+ int pos = 0;
+
+ // Copy to avoid RemoveAt calls interfering with enumeration
+ foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+ {
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ p_node.RemoveChild(node);
+
+ // Removal of element at current iterator position not supported in C#
+ //nodes_i.remove();
+ policyNodes[i].RemoveAt(pos);
+
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ IList nodes = policyNodes[k];
+ for (int l = 0; l < nodes.Count; l++)
+ {
+ PkixPolicyNode node2 = (PkixPolicyNode)nodes[l];
+ if (!node2.HasChildren)
+ {
+ validPolicyTree = RemovePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ ++pos;
+ }
+ }
+ return validPolicyTree;
+ }
+
+ internal static void GetCertStatus(
+ DateTime validDate,
+ X509Crl crl,
+ Object cert,
+ CertStatus certStatus)
+ {
+ X509Crl bcCRL = null;
+
+ try
+ {
+ bcCRL = new X509Crl(CertificateList.GetInstance((Asn1Sequence)Asn1Sequence.FromByteArray(crl.GetEncoded())));
+ }
+ catch (Exception exception)
+ {
+ throw new Exception("Bouncy Castle X509Crl could not be created.", exception);
+ }
+
+ X509CrlEntry crl_entry = (X509CrlEntry)bcCRL.GetRevokedCertificate(GetSerialNumber(cert));
+
+ if (crl_entry == null)
+ return;
+
+ X509Name issuer = GetIssuerPrincipal(cert);
+
+ if (issuer.Equivalent(crl_entry.GetCertificateIssuer(), true)
+ || issuer.Equivalent(crl.IssuerDN, true))
+ {
+ DerEnumerated reasonCode = null;
+ if (crl_entry.HasExtensions)
+ {
+ try
+ {
+ reasonCode = DerEnumerated.GetInstance(
+ GetExtensionValue(crl_entry, X509Extensions.ReasonCode));
+ }
+ catch (Exception e)
+ {
+ new Exception(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.Ticks < crl_entry.RevocationDate.Ticks)
+ || reasonCode == null
+ || reasonCode.Value.TestBit(0)
+ || reasonCode.Value.TestBit(1)
+ || reasonCode.Value.TestBit(2)
+ || reasonCode.Value.TestBit(8))
+ {
+ if (reasonCode != null) // (i) or (j) (1)
+ {
+ certStatus.Status = reasonCode.Value.SignValue;
+ }
+ else // (i) or (j) (2)
+ {
+ certStatus.Status = CrlReason.Unspecified;
+ }
+ certStatus.RevocationDate = new DateTimeObject(crl_entry.RevocationDate);
+ }
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws Exception if DSA parameters cannot be inherited.
+ */
+ internal static AsymmetricKeyParameter GetNextWorkingKey(
+ IList certs,
+ int index)
+ {
+ //Only X509Certificate
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ AsymmetricKeyParameter pubKey = cert.GetPublicKey();
+
+ if (!(pubKey is DsaPublicKeyParameters))
+ return pubKey;
+
+ DsaPublicKeyParameters dsaPubKey = (DsaPublicKeyParameters)pubKey;
+
+ if (dsaPubKey.Parameters != null)
+ return dsaPubKey;
+
+ for (int i = index + 1; i < certs.Count; i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs[i];
+ pubKey = parentCert.GetPublicKey();
+
+ if (!(pubKey is DsaPublicKeyParameters))
+ {
+ throw new PkixCertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ DsaPublicKeyParameters prevDSAPubKey = (DsaPublicKeyParameters)pubKey;
+
+ if (prevDSAPubKey.Parameters == null)
+ continue;
+
+ DsaParameters dsaParams = prevDSAPubKey.Parameters;
+
+ try
+ {
+ return new DsaPublicKeyParameters(dsaPubKey.Y, dsaParams);
+ }
+ catch (Exception exception)
+ {
+ throw new Exception(exception.Message);
+ }
+ }
+
+ throw new PkixCertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ internal static DateTime GetValidCertDateFromValidityModel(
+ PkixParameters paramsPkix,
+ PkixCertPath certPath,
+ int index)
+ {
+ if (paramsPkix.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ return GetValidDate(paramsPkix);
+ }
+
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+ // else use time when previous cert was created
+ }
+
+ if (index - 1 == 0)
+ {
+ DerGeneralizedTime dateOfCertgen = null;
+ try
+ {
+ X509Certificate cert = (X509Certificate)certPath.Certificates[index - 1];
+ Asn1OctetString extVal = cert.GetExtensionValue(
+ IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen);
+ dateOfCertgen = DerGeneralizedTime.GetInstance(extVal);
+ }
+ catch (ArgumentException)
+ {
+ throw new Exception(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.ToDateTime();
+ }
+ catch (ArgumentException e)
+ {
+ throw new Exception(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ }
+
+ return ((X509Certificate)certPath.Certificates[index - 1]).NotBefore;
+ }
+
+ /// <summary>
+ /// Return a Collection of all certificates or attribute certificates found
+ /// in the X509Store's that are matching the certSelect criteriums.
+ /// </summary>
+ /// <param name="certSelect">a {@link Selector} object that will be used to select
+ /// the certificates</param>
+ /// <param name="certStores">a List containing only X509Store objects. These
+ /// are used to search for certificates.</param>
+ /// <returns>a Collection of all found <see cref="X509Certificate "/> or
+ /// org.bouncycastle.x509.X509AttributeCertificate objects.
+ /// May be empty but never <code>null</code>.</returns>
+ /// <exception cref="Exception"></exception>
+ internal static ICollection FindCertificates(
+ X509CertStoreSelector certSelect,
+ IList certStores)
+ {
+ ISet certs = new HashSet();
+
+ foreach (IX509Store certStore in certStores)
+ {
+ try
+ {
+// certs.AddAll(certStore.GetMatches(certSelect));
+ foreach (X509Certificate c in certStore.GetMatches(certSelect))
+ {
+ certs.Add(c);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Problem while picking certificates from X.509 store.", e);
+ }
+ }
+
+ return certs;
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * <code>selector</code>.
+ * <p>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X500Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X500Principal</code>.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws Exception if an exception occurs while processing.
+ * @throws ClassCastException if <code>issuerPrincipals</code> does not
+ * contain only <code>X500Principal</code>s.
+ */
+ internal static void GetCrlIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ ICollection issuerPrincipals,
+ X509CrlStoreSelector selector,
+ PkixParameters pkixParams)
+ {
+ IList issuers = Platform.CreateArrayList();
+ // indirect CRL
+ if (dp.CrlIssuer != null)
+ {
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ // look for a DN
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ issuers.Add(X509Name.GetInstance(genNames[j].Name.ToAsn1Object()));
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.DistributionPointName == null)
+ {
+ throw new Exception(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+
+ // add and check issuer principals
+ for (IEnumerator it = issuerPrincipals.GetEnumerator(); it.MoveNext(); )
+ {
+ issuers.Add((X509Name)it.Current);
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+ // if (dp.getDistributionPoint() != null)
+ // {
+ // // look for nameRelativeToCRLIssuer
+ // if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ // {
+ // // append fragment to issuer, only one
+ // // issuer can be there, if this is given
+ // if (issuers.size() != 1)
+ // {
+ // throw new AnnotatedException(
+ // "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+ // }
+ // DEREncodable relName = dp.getDistributionPoint().getName();
+ // Iterator it = issuers.iterator();
+ // List issuersTemp = new ArrayList(issuers.size());
+ // while (it.hasNext())
+ // {
+ // Enumeration e = null;
+ // try
+ // {
+ // e = ASN1Sequence.getInstance(
+ // new ASN1InputStream(((X500Principal) it.next())
+ // .getEncoded()).readObject()).getObjects();
+ // }
+ // catch (IOException ex)
+ // {
+ // throw new AnnotatedException(
+ // "Cannot decode CRL issuer information.", ex);
+ // }
+ // ASN1EncodableVector v = new ASN1EncodableVector();
+ // while (e.hasMoreElements())
+ // {
+ // v.add((DEREncodable) e.nextElement());
+ // }
+ // v.add(relName);
+ // issuersTemp.add(new X500Principal(new DERSequence(v)
+ // .getDEREncoded()));
+ // }
+ // issuers.clear();
+ // issuers.addAll(issuersTemp);
+ // }
+ // }
+
+ selector.Issuers = issuers;
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.bouncycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws Exception if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ internal static ISet GetCompleteCrls(
+ DistributionPoint dp,
+ object cert,
+ DateTime currentDate,
+ PkixParameters paramsPKIX)
+ {
+ X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+ try
+ {
+ ISet issuers = new HashSet();
+ if (cert is X509V2AttributeCertificate)
+ {
+ issuers.Add(((X509V2AttributeCertificate)cert)
+ .Issuer.GetPrincipals()[0]);
+ }
+ else
+ {
+ issuers.Add(GetIssuerPrincipal(cert));
+ }
+ PkixCertPathValidatorUtilities.GetCrlIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ new Exception("Could not get issuer information from distribution point.", e);
+ }
+
+ if (cert is X509Certificate)
+ {
+ crlselect.CertificateChecking = (X509Certificate)cert;
+ }
+ else if (cert is X509V2AttributeCertificate)
+ {
+ crlselect.AttrCertChecking = (IX509AttributeCertificate)cert;
+ }
+
+ crlselect.CompleteCrlEnabled = true;
+ ISet crls = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+ if (crls.IsEmpty)
+ {
+ if (cert is IX509AttributeCertificate)
+ {
+ IX509AttributeCertificate aCert = (IX509AttributeCertificate)cert;
+
+ throw new Exception("No CRLs found for issuer \"" + aCert.Issuer.GetPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new Exception("No CRLs found for issuer \"" + xCert.IssuerDN + "\"");
+ }
+ }
+
+ return crls;
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws Exception if an exception occurs while picking the delta
+ * CRLs.
+ */
+ internal static ISet GetDeltaCrls(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Crl completeCRL)
+ {
+ X509CrlStoreSelector deltaSelect = new X509CrlStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ IList deltaSelectIssuer = Platform.CreateArrayList();
+ deltaSelectIssuer.Add(completeCRL.IssuerDN);
+ deltaSelect.Issuers = deltaSelectIssuer;
+ }
+ catch (IOException e)
+ {
+ new Exception("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ Asn1Object asn1Object = GetExtensionValue(completeCRL, X509Extensions.CrlNumber);
+ if (asn1Object != null)
+ {
+ completeCRLNumber = CrlNumber.GetInstance(asn1Object).PositiveValue;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+
+ try
+ {
+ Asn1Object obj = GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint);
+ if (obj != null)
+ {
+ idp = obj.GetDerEncoded();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.MinCrlNumber = (completeCRLNumber == null)
+ ? null
+ : completeCRLNumber.Add(BigInteger.One);
+
+ deltaSelect.IssuingDistributionPoint = idp;
+ deltaSelect.IssuingDistributionPointEnabled = true;
+
+ // 5.2.4 (c)
+ deltaSelect.MaxBaseCrlNumber = completeCRLNumber;
+
+ // find delta CRLs
+ ISet temp = CrlUtilities.FindCrls(deltaSelect, paramsPKIX, currentDate);
+
+ ISet result = new HashSet();
+
+ foreach (X509Crl crl in temp)
+ {
+ if (isDeltaCrl(crl))
+ {
+ result.Add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static bool isDeltaCrl(
+ X509Crl crl)
+ {
+ ISet critical = crl.GetCriticalExtensionOids();
+
+ return critical.Contains(X509Extensions.DeltaCrlIndicator.Id);
+ }
+
+ internal static ICollection FindCertificates(
+ X509AttrCertStoreSelector certSelect,
+ IList certStores)
+ {
+ ISet certs = new HashSet();
+
+ foreach (IX509Store certStore in certStores)
+ {
+ try
+ {
+// certs.AddAll(certStore.GetMatches(certSelect));
+ foreach (X509V2AttributeCertificate ac in certStore.GetMatches(certSelect))
+ {
+ certs.Add(ac);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+
+ return certs;
+ }
+
+ internal static void AddAdditionalStoresFromCrlDistributionPoint(
+ CrlDistPoint crldp,
+ PkixParameters pkixParams)
+ {
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.Length; i++)
+ {
+ DistributionPointName dpn = dps[i].DistributionPointName;
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.PointType == DistributionPointName.FullName)
+ {
+ GeneralName[] genNames = GeneralNames.GetInstance(
+ dpn.Name).GetNames();
+ // look for an URI
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.UniformResourceIdentifier)
+ {
+ string location = DerIA5String.GetInstance(
+ genNames[j].Name).GetString();
+ PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(
+ location, pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ internal static bool ProcessCertD1i(
+ int index,
+ IList[] policyNodes,
+ DerObjectIdentifier pOid,
+ ISet pq)
+ {
+ IList policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.Count; j++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)policyNodeVec[j];
+ ISet expectedPolicies = node.ExpectedPolicies;
+
+ if (expectedPolicies.Contains(pOid.Id))
+ {
+ ISet childExpectedPolicies = new HashSet();
+ childExpectedPolicies.Add(pOid.Id);
+
+ PkixPolicyNode child = new PkixPolicyNode(Platform.CreateArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.Id,
+ false);
+ node.AddChild(child);
+ policyNodes[index].Add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal static void ProcessCertD1ii(
+ int index,
+ IList[] policyNodes,
+ DerObjectIdentifier _poid,
+ ISet _pq)
+ {
+ IList policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.Count; j++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)policyNodeVec[j];
+
+ if (ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ ISet _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.Add(_poid.Id);
+
+ PkixPolicyNode _child = new PkixPolicyNode(Platform.CreateArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.Id,
+ false);
+ _node.AddChild(_child);
+ policyNodes[index].Add(_child);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert
+ * The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ *
+ * @exception Exception
+ * if an error occurs.
+ */
+ internal static ICollection FindIssuerCerts(
+ X509Certificate cert,
+ PkixBuilderParameters pkixParams)
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ ISet certs = new HashSet();
+ try
+ {
+ certSelect.Subject = cert.IssuerDN;
+ }
+ catch (IOException ex)
+ {
+ throw new Exception(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ try
+ {
+ certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetStores()));
+ certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetAdditionalStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer certificate cannot be searched.", e);
+ }
+
+ return certs;
+ }
+
+ /// <summary>
+ /// Extract the value of the given extension, if it exists.
+ /// </summary>
+ /// <param name="ext">The extension object.</param>
+ /// <param name="oid">The object identifier to obtain.</param>
+ /// <returns>Asn1Object</returns>
+ /// <exception cref="Exception">if the extension cannot be read.</exception>
+ internal static Asn1Object GetExtensionValue(
+ IX509Extension ext,
+ DerObjectIdentifier oid)
+ {
+ Asn1OctetString bytes = ext.GetExtensionValue(oid);
+
+ if (bytes == null)
+ return null;
+
+ return X509ExtensionUtilities.FromExtensionValue(bytes);
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixCrlUtilities.cs b/crypto/src/pkix/PkixCrlUtilities.cs
new file mode 100644
index 000000000..c386b8a05
--- /dev/null
+++ b/crypto/src/pkix/PkixCrlUtilities.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class PkixCrlUtilities
+ {
+ public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix, DateTime currentDate)
+ {
+ ISet initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetAdditionalStores()));
+ initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining complete CRLs.", e);
+ }
+
+ ISet finalSet = new HashSet();
+ DateTime validityDate = currentDate;
+
+ if (paramsPkix.Date != null)
+ {
+ validityDate = paramsPkix.Date.Value;
+ }
+
+ // based on RFC 5280 6.3.3
+ foreach (X509Crl crl in initialSet)
+ {
+ if (crl.NextUpdate.Value.CompareTo(validityDate) > 0)
+ {
+ X509Certificate cert = crlselect.CertificateChecking;
+
+ if (cert != null)
+ {
+ if (crl.ThisUpdate.CompareTo(cert.NotAfter) < 0)
+ {
+ finalSet.Add(crl);
+ }
+ }
+ else
+ {
+ finalSet.Add(crl);
+ }
+ }
+ }
+
+ return finalSet;
+ }
+
+ public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix)
+ {
+ ISet completeSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ completeSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining complete CRLs.", e);
+ }
+
+ return completeSet;
+ }
+
+ /// <summary>
+ /// crl checking
+ /// Return a Collection of all CRLs found in the X509Store's that are
+ /// matching the crlSelect criteriums.
+ /// </summary>
+ /// <param name="crlSelect">a {@link X509CRLStoreSelector} object that will be used
+ /// to select the CRLs</param>
+ /// <param name="crlStores">a List containing only {@link org.bouncycastle.x509.X509Store
+ /// X509Store} objects. These are used to search for CRLs</param>
+ /// <returns>a Collection of all found {@link X509CRL X509CRL} objects. May be
+ /// empty but never <code>null</code>.
+ /// </returns>
+ private ICollection FindCrls(X509CrlStoreSelector crlSelect, IList crlStores)
+ {
+ ISet crls = new HashSet();
+
+ Exception lastException = null;
+ bool foundValidStore = false;
+
+ foreach (IX509Store store in crlStores)
+ {
+ try
+ {
+ crls.AddAll(store.GetMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (X509StoreException e)
+ {
+ lastException = new Exception("Exception searching in X.509 CRL store.", e);
+ }
+ }
+
+ if (!foundValidStore && lastException != null)
+ throw lastException;
+
+ return crls;
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixNameConstraintValidator.cs b/crypto/src/pkix/PkixNameConstraintValidator.cs
new file mode 100644
index 000000000..535f95174
--- /dev/null
+++ b/crypto/src/pkix/PkixNameConstraintValidator.cs
@@ -0,0 +1,1937 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class PkixNameConstraintValidator
+ {
+ private ISet excludedSubtreesDN = new HashSet();
+
+ private ISet excludedSubtreesDNS = new HashSet();
+
+ private ISet excludedSubtreesEmail = new HashSet();
+
+ private ISet excludedSubtreesURI = new HashSet();
+
+ private ISet excludedSubtreesIP = new HashSet();
+
+ private ISet permittedSubtreesDN;
+
+ private ISet permittedSubtreesDNS;
+
+ private ISet permittedSubtreesEmail;
+
+ private ISet permittedSubtreesURI;
+
+ private ISet permittedSubtreesIP;
+
+ public PkixNameConstraintValidator()
+ {
+ }
+
+ private static bool WithinDNSubtree(
+ Asn1Sequence dns,
+ Asn1Sequence subtree)
+ {
+ if (subtree.Count < 1)
+ {
+ return false;
+ }
+
+ if (subtree.Count > dns.Count)
+ {
+ return false;
+ }
+
+ for (int j = subtree.Count - 1; j >= 0; j--)
+ {
+ if (!(subtree[j].Equals(dns[j])))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void CheckPermittedDN(Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ CheckPermittedDN(permittedSubtreesDN, dns);
+ }
+
+ public void CheckExcludedDN(Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ CheckExcludedDN(excludedSubtreesDN, dns);
+ }
+
+ private void CheckPermittedDN(ISet permitted, Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ if ((permitted.Count == 0) && dns.Count == 0)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dns, subtree))
+ {
+ return;
+ }
+ }
+
+ throw new PkixNameConstraintValidatorException(
+ "Subject distinguished name is not from a permitted subtree");
+ }
+
+ private void CheckExcludedDN(ISet excluded, Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dns, subtree))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "Subject distinguished name is from an excluded subtree");
+ }
+ }
+ }
+
+ private ISet IntersectDN(ISet permitted, ISet dns)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = dns.GetEnumerator(); it.MoveNext(); )
+ {
+ Asn1Sequence dn = Asn1Sequence.GetInstance(((GeneralSubtree)it
+ .Current).Base.Name.ToAsn1Object());
+ if (permitted == null)
+ {
+ if (dn != null)
+ {
+ intersect.Add(dn);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)_iter.Current;
+
+ if (WithinDNSubtree(dn, subtree))
+ {
+ intersect.Add(dn);
+ }
+ else if (WithinDNSubtree(subtree, dn))
+ {
+ intersect.Add(subtree);
+ }
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet UnionDN(ISet excluded, Asn1Sequence dn)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (dn == null)
+ {
+ return excluded;
+ }
+ excluded.Add(dn);
+
+ return excluded;
+ }
+ else
+ {
+ ISet intersect = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dn, subtree))
+ {
+ intersect.Add(subtree);
+ }
+ else if (WithinDNSubtree(subtree, dn))
+ {
+ intersect.Add(dn);
+ }
+ else
+ {
+ intersect.Add(subtree);
+ intersect.Add(dn);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private ISet IntersectEmail(ISet permitted, ISet emails)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = emails.GetEnumerator(); it.MoveNext(); )
+ {
+ String email = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+
+ if (permitted == null)
+ {
+ if (email != null)
+ {
+ intersect.Add(email);
+ }
+ }
+ else
+ {
+ IEnumerator it2 = permitted.GetEnumerator();
+ while (it2.MoveNext())
+ {
+ String _permitted = (String)it2.Current;
+
+ intersectEmail(email, _permitted, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet UnionEmail(ISet excluded, String email)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (email == null)
+ {
+ return excluded;
+ }
+ excluded.Add(email);
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ String _excluded = (String)it.Current;
+
+ unionEmail(_excluded, email, union);
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Returns the intersection of the permitted IP ranges in
+ * <code>permitted</code> with <code>ip</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ips The IP address with its subnet mask.
+ * @return The <code>Set</code> of permitted IP ranges intersected with
+ * <code>ip</code>.
+ */
+ private ISet IntersectIP(ISet permitted, ISet ips)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+ {
+ byte[] ip = Asn1OctetString.GetInstance(
+ ((GeneralSubtree)it.Current).Base.Name).GetOctets();
+ if (permitted == null)
+ {
+ if (ip != null)
+ {
+ intersect.Add(ip);
+ }
+ }
+ else
+ {
+ IEnumerator it2 = permitted.GetEnumerator();
+ while (it2.MoveNext())
+ {
+ byte[] _permitted = (byte[])it2.Current;
+ intersect.AddAll(IntersectIPRange(_permitted, ip));
+ }
+ }
+ }
+ return intersect;
+ }
+
+ /**
+ * Returns the union of the excluded IP ranges in <code>excluded</code>
+ * with <code>ip</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address with its subnet mask.
+ * @return The <code>Set</code> of excluded IP ranges unified with
+ * <code>ip</code> as byte arrays.
+ */
+ private ISet UnionIP(ISet excluded, byte[] ip)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (ip == null)
+ {
+ return excluded;
+ }
+ excluded.Add(ip);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ byte[] _excluded = (byte[])it.Current;
+ union.AddAll(UnionIPRange(_excluded, ip));
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Calculates the union if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A <code>Set</code> with the union of both addresses.
+ */
+ private ISet UnionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ ISet set = new HashSet();
+
+ // difficult, adding always all IPs is not wrong
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(ipWithSubmask1, ipWithSubmask2))
+ {
+ set.Add(ipWithSubmask1);
+ }
+ else
+ {
+ set.Add(ipWithSubmask1);
+ set.Add(ipWithSubmask2);
+ }
+ return set;
+ }
+
+ /**
+ * Calculates the interesction if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A <code>Set</code> with the single IP address with its subnet
+ * mask as a byte array or an empty <code>Set</code>.
+ */
+ private ISet IntersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ if (ipWithSubmask1.Length != ipWithSubmask2.Length)
+ {
+ //Collections.EMPTY_SET;
+ return new HashSet();
+ }
+
+ byte[][] temp = ExtractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+ byte[] ip1 = temp[0];
+ byte[] subnetmask1 = temp[1];
+ byte[] ip2 = temp[2];
+ byte[] subnetmask2 = temp[3];
+
+ byte[][] minMax = MinMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+ byte[] min;
+ byte[] max;
+ max = Min(minMax[1], minMax[3]);
+ min = Max(minMax[0], minMax[2]);
+
+ // minimum IP address must be bigger than max
+ if (CompareTo(min, max) == 1)
+ {
+ //return Collections.EMPTY_SET;
+ return new HashSet();
+ }
+ // OR keeps all significant bits
+ byte[] ip = Or(minMax[0], minMax[2]);
+ byte[] subnetmask = Or(subnetmask1, subnetmask2);
+
+ //return new HashSet( ICollectionsingleton(IpWithSubnetMask(ip, subnetmask));
+ ISet hs = new HashSet();
+ hs.Add(IpWithSubnetMask(ip, subnetmask));
+
+ return hs;
+ }
+
+ /**
+ * Concatenates the IP address with its subnet mask.
+ *
+ * @param ip The IP address.
+ * @param subnetMask Its subnet mask.
+ * @return The concatenated IP address with its subnet mask.
+ */
+ private byte[] IpWithSubnetMask(byte[] ip, byte[] subnetMask)
+ {
+ int ipLength = ip.Length;
+ byte[] temp = new byte[ipLength * 2];
+ Array.Copy(ip, 0, temp, 0, ipLength);
+ Array.Copy(subnetMask, 0, temp, ipLength, ipLength);
+ return temp;
+ }
+
+ /**
+ * Splits the IP addresses and their subnet mask.
+ *
+ * @param ipWithSubmask1 The first IP address with the subnet mask.
+ * @param ipWithSubmask2 The second IP address with the subnet mask.
+ * @return An array with two elements. Each element contains the IP address
+ * and the subnet mask in this order.
+ */
+ private byte[][] ExtractIPsAndSubnetMasks(
+ byte[] ipWithSubmask1,
+ byte[] ipWithSubmask2)
+ {
+ int ipLength = ipWithSubmask1.Length / 2;
+ byte[] ip1 = new byte[ipLength];
+ byte[] subnetmask1 = new byte[ipLength];
+ Array.Copy(ipWithSubmask1, 0, ip1, 0, ipLength);
+ Array.Copy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+ byte[] ip2 = new byte[ipLength];
+ byte[] subnetmask2 = new byte[ipLength];
+ Array.Copy(ipWithSubmask2, 0, ip2, 0, ipLength);
+ Array.Copy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+ return new byte[][]
+ {ip1, subnetmask1, ip2, subnetmask2};
+ }
+
+ /**
+ * Based on the two IP addresses and their subnet masks the IP range is
+ * computed for each IP address - subnet mask pair and returned as the
+ * minimum IP address and the maximum address of the range.
+ *
+ * @param ip1 The first IP address.
+ * @param subnetmask1 The subnet mask of the first IP address.
+ * @param ip2 The second IP address.
+ * @param subnetmask2 The subnet mask of the second IP address.
+ * @return A array with two elements. The first/second element contains the
+ * min and max IP address of the first/second IP address and its
+ * subnet mask.
+ */
+ private byte[][] MinMaxIPs(
+ byte[] ip1,
+ byte[] subnetmask1,
+ byte[] ip2,
+ byte[] subnetmask2)
+ {
+ int ipLength = ip1.Length;
+ byte[] min1 = new byte[ipLength];
+ byte[] max1 = new byte[ipLength];
+
+ byte[] min2 = new byte[ipLength];
+ byte[] max2 = new byte[ipLength];
+
+ for (int i = 0; i < ipLength; i++)
+ {
+ min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+ max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+ min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+ max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+ }
+
+ return new byte[][] { min1, max1, min2, max2 };
+ }
+
+ private void CheckPermittedEmail(ISet permitted, String email)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (EmailIsConstrained(email, str))
+ {
+ return;
+ }
+ }
+
+ if (email.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+
+ throw new PkixNameConstraintValidatorException(
+ "Subject email address is not from a permitted subtree.");
+ }
+
+ private void CheckExcludedEmail(ISet excluded, String email)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = (String)it.Current;
+
+ if (EmailIsConstrained(email, str))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "Email address is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the permitted ISet
+ * <code>permitted</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PkixNameConstraintValidatorException
+ * if the IP is not permitted.
+ */
+ private void CheckPermittedIP(ISet permitted, byte[] ip)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.Current;
+
+ if (IsIPConstrained(ip, ipWithSubnet))
+ {
+ return;
+ }
+ }
+ if (ip.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "IP is not from a permitted subtree.");
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the excluded ISet
+ * <code>excluded</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PkixNameConstraintValidatorException
+ * if the IP is excluded.
+ */
+ private void checkExcludedIP(ISet excluded, byte[] ip)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.Current;
+
+ if (IsIPConstrained(ip, ipWithSubnet))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "IP is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP address <code>ip</code> is constrained by
+ * <code>constraint</code>.
+ *
+ * @param ip The IP address.
+ * @param constraint The constraint. This is an IP address concatenated with
+ * its subnetmask.
+ * @return <code>true</code> if constrained, <code>false</code>
+ * otherwise.
+ */
+ private bool IsIPConstrained(byte[] ip, byte[] constraint)
+ {
+ int ipLength = ip.Length;
+
+ if (ipLength != (constraint.Length / 2))
+ {
+ return false;
+ }
+
+ byte[] subnetMask = new byte[ipLength];
+ Array.Copy(constraint, ipLength, subnetMask, 0, ipLength);
+
+ byte[] permittedSubnetAddress = new byte[ipLength];
+
+ byte[] ipSubnetAddress = new byte[ipLength];
+
+ // the resulting IP address by applying the subnet mask
+ for (int i = 0; i < ipLength; i++)
+ {
+ permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+ ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+ }
+
+ return Org.BouncyCastle.Utilities.Arrays.AreEqual(permittedSubnetAddress, ipSubnetAddress);
+ }
+
+ private bool EmailIsConstrained(String email, String constraint)
+ {
+ String sub = email.Substring(email.IndexOf('@') + 1);
+ // a particular mailbox
+ if (constraint.IndexOf('@') != -1)
+ {
+ if (email.ToUpper().Equals(constraint.ToUpper()))
+ {
+ return true;
+ }
+ }
+ // on particular host
+ else if (!(constraint[0].Equals('.')))
+ {
+ if (sub.ToUpper().Equals(constraint.ToUpper()))
+ {
+ return true;
+ }
+ }
+ // address in sub domain
+ else if (WithinDomain(sub, constraint))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private bool WithinDomain(String testDomain, String domain)
+ {
+ String tempDomain = domain;
+ if (tempDomain.StartsWith("."))
+ {
+ tempDomain = tempDomain.Substring(1);
+ }
+ String[] domainParts = tempDomain.Split('.'); // Strings.split(tempDomain, '.');
+ String[] testDomainParts = testDomain.Split('.'); // Strings.split(testDomain, '.');
+
+ // must have at least one subdomain
+ if (testDomainParts.Length <= domainParts.Length)
+ {
+ return false;
+ }
+
+ int d = testDomainParts.Length - domainParts.Length;
+ for (int i = -1; i < domainParts.Length; i++)
+ {
+ if (i == -1)
+ {
+ if (testDomainParts[i + d].Equals(""))
+ {
+ return false;
+ }
+ }
+ else if (!(Platform.CompareIgnoreCase(testDomainParts[i + d], domainParts[i]) == 0))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void CheckPermittedDNS(ISet permitted, String dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ // is sub domain
+ if (WithinDomain(dns, str) || dns.ToUpper().Equals(str.ToUpper()))
+ {
+ return;
+ }
+ }
+ if (dns.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "DNS is not from a permitted subtree.");
+ }
+
+ private void checkExcludedDNS(ISet excluded, String dns)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ // is sub domain or the same
+ if (WithinDomain(dns, str) || (Platform.CompareIgnoreCase(dns, str) == 0))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "DNS is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * The common part of <code>email1</code> and <code>email2</code> is
+ * added to the union <code>union</code>. If <code>email1</code> and
+ * <code>email2</code> have nothing in common they are added both.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param union The union.
+ */
+ private void unionEmail(String email1, String email2, ISet union)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(_sub, email2) == 0)
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (email1.StartsWith("."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2) || Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email2);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (Platform.CompareIgnoreCase(_sub, email1) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ }
+
+ private void unionURI(String email1, String email2, ISet union)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(_sub, email2) == 0)
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (email1.StartsWith("."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2) || Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email2);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (Platform.CompareIgnoreCase(_sub, email1) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ }
+
+ private ISet intersectDNS(ISet permitted, ISet dnss)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = dnss.GetEnumerator(); it.MoveNext(); )
+ {
+ String dns = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+ if (permitted == null)
+ {
+ if (dns != null)
+ {
+ intersect.Add(dns);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+
+ if (WithinDomain(_permitted, dns))
+ {
+ intersect.Add(_permitted);
+ }
+ else if (WithinDomain(dns, _permitted))
+ {
+ intersect.Add(dns);
+ }
+ }
+ }
+ }
+
+ return intersect;
+ }
+
+ protected ISet unionDNS(ISet excluded, String dns)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (dns == null)
+ {
+ return excluded;
+ }
+ excluded.Add(dns);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator _iter = excluded.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+
+ if (WithinDomain(_permitted, dns))
+ {
+ union.Add(dns);
+ }
+ else if (WithinDomain(dns, _permitted))
+ {
+ union.Add(_permitted);
+ }
+ else
+ {
+ union.Add(_permitted);
+ union.Add(dns);
+ }
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * The most restricting part from <code>email1</code> and
+ * <code>email2</code> is added to the intersection <code>intersect</code>.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param intersect The intersection.
+ */
+ private void intersectEmail(String email1, String email2, ISet intersect)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(_sub, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (email1.StartsWith("."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2) || (Platform.CompareIgnoreCase(email1, email2) == 0))
+ {
+ intersect.Add(email1);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email2.IndexOf('@') + 1);
+ if (Platform.CompareIgnoreCase(_sub, email1) == 0)
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ }
+
+ private void checkExcludedURI(ISet excluded, String uri)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (IsUriConstrained(uri, str))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "URI is from an excluded subtree.");
+ }
+ }
+ }
+
+ private ISet intersectURI(ISet permitted, ISet uris)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = uris.GetEnumerator(); it.MoveNext(); )
+ {
+ String uri = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+ if (permitted == null)
+ {
+ if (uri != null)
+ {
+ intersect.Add(uri);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+ intersectURI(_permitted, uri, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet unionURI(ISet excluded, String uri)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (uri == null)
+ {
+ return excluded;
+ }
+ excluded.Add(uri);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator _iter = excluded.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _excluded = (String)_iter.Current;
+
+ unionURI(_excluded, uri, union);
+ }
+
+ return union;
+ }
+ }
+
+ private void intersectURI(String email1, String email2, ISet intersect)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(_sub, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (email1.StartsWith("."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2) || (Platform.CompareIgnoreCase(email1, email2) == 0))
+ {
+ intersect.Add(email1);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email2.IndexOf('@') + 1);
+ if (Platform.CompareIgnoreCase(_sub, email1) == 0)
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.StartsWith("."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.CompareIgnoreCase(email1, email2) == 0)
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ }
+
+ private void CheckPermittedURI(ISet permitted, String uri)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (IsUriConstrained(uri, str))
+ {
+ return;
+ }
+ }
+ if (uri.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "URI is not from a permitted subtree.");
+ }
+
+ private bool IsUriConstrained(String uri, String constraint)
+ {
+ String host = ExtractHostFromURL(uri);
+ // a host
+ if (!constraint.StartsWith("."))
+ {
+ if (Platform.CompareIgnoreCase(host, constraint) == 0)
+ {
+ return true;
+ }
+ }
+
+ // in sub domain or domain
+ else if (WithinDomain(host, constraint))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static String ExtractHostFromURL(String url)
+ {
+ // see RFC 1738
+ // remove ':' after protocol, e.g. http:
+ String sub = url.Substring(url.IndexOf(':') + 1);
+ // extract host from Common Internet Scheme Syntax, e.g. http://
+ if (sub.IndexOf("//") != -1)
+ {
+ sub = sub.Substring(sub.IndexOf("//") + 2);
+ }
+ // first remove port, e.g. http://test.com:21
+ if (sub.LastIndexOf(':') != -1)
+ {
+ sub = sub.Substring(0, sub.LastIndexOf(':'));
+ }
+ // remove user and password, e.g. http://john:password@test.com
+ sub = sub.Substring(sub.IndexOf(':') + 1);
+ sub = sub.Substring(sub.IndexOf('@') + 1);
+ // remove local parts, e.g. http://test.com/bla
+ if (sub.IndexOf('/') != -1)
+ {
+ sub = sub.Substring(0, sub.IndexOf('/'));
+ }
+ return sub;
+ }
+
+ /**
+ * Checks if the given GeneralName is in the permitted ISet.
+ *
+ * @param name The GeneralName
+ * @throws PkixNameConstraintValidatorException
+ * If the <code>name</code>
+ */
+ public void checkPermitted(GeneralName name)
+ // throws PkixNameConstraintValidatorException
+ {
+ switch (name.TagNo)
+ {
+ case 1:
+ CheckPermittedEmail(permittedSubtreesEmail,
+ ExtractNameAsString(name));
+ break;
+ case 2:
+ CheckPermittedDNS(permittedSubtreesDNS, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 4:
+ CheckPermittedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+ break;
+ case 6:
+ CheckPermittedURI(permittedSubtreesURI, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 7:
+ byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+ CheckPermittedIP(permittedSubtreesIP, ip);
+ break;
+ }
+ }
+
+ /**
+ * Check if the given GeneralName is contained in the excluded ISet.
+ *
+ * @param name The GeneralName.
+ * @throws PkixNameConstraintValidatorException
+ * If the <code>name</code> is
+ * excluded.
+ */
+ public void checkExcluded(GeneralName name)
+ // throws PkixNameConstraintValidatorException
+ {
+ switch (name.TagNo)
+ {
+ case 1:
+ CheckExcludedEmail(excludedSubtreesEmail, ExtractNameAsString(name));
+ break;
+ case 2:
+ checkExcludedDNS(excludedSubtreesDNS, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 4:
+ CheckExcludedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+ break;
+ case 6:
+ checkExcludedURI(excludedSubtreesURI, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 7:
+ byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+ checkExcludedIP(excludedSubtreesIP, ip);
+ break;
+ }
+ }
+
+ /**
+ * Updates the permitted ISet of these name constraints with the intersection
+ * with the given subtree.
+ *
+ * @param permitted The permitted subtrees
+ */
+
+ public void IntersectPermittedSubtree(Asn1Sequence permitted)
+ {
+ IDictionary subtreesMap = Platform.CreateHashtable();
+
+ // group in ISets in a map ordered by tag no.
+ for (IEnumerator e = permitted.GetEnumerator(); e.MoveNext(); )
+ {
+ GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+
+ int tagNo = subtree.Base.TagNo;
+ if (subtreesMap[tagNo] == null)
+ {
+ subtreesMap[tagNo] = new HashSet();
+ }
+
+ ((ISet)subtreesMap[tagNo]).Add(subtree);
+ }
+
+ for (IEnumerator it = subtreesMap.GetEnumerator(); it.MoveNext(); )
+ {
+ DictionaryEntry entry = (DictionaryEntry)it.Current;
+
+ // go through all subtree groups
+ switch ((int)entry.Key )
+ {
+ case 1:
+ permittedSubtreesEmail = IntersectEmail(permittedSubtreesEmail,
+ (ISet)entry.Value);
+ break;
+ case 2:
+ permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+ (ISet)entry.Value);
+ break;
+ case 4:
+ permittedSubtreesDN = IntersectDN(permittedSubtreesDN,
+ (ISet)entry.Value);
+ break;
+ case 6:
+ permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+ (ISet)entry.Value);
+ break;
+ case 7:
+ permittedSubtreesIP = IntersectIP(permittedSubtreesIP,
+ (ISet)entry.Value);
+ break;
+ }
+ }
+ }
+
+ private String ExtractNameAsString(GeneralName name)
+ {
+ return DerIA5String.GetInstance(name.Name).GetString();
+ }
+
+ public void IntersectEmptyPermittedSubtree(int nameType)
+ {
+ switch (nameType)
+ {
+ case 1:
+ permittedSubtreesEmail = new HashSet();
+ break;
+ case 2:
+ permittedSubtreesDNS = new HashSet();
+ break;
+ case 4:
+ permittedSubtreesDN = new HashSet();
+ break;
+ case 6:
+ permittedSubtreesURI = new HashSet();
+ break;
+ case 7:
+ permittedSubtreesIP = new HashSet();
+ break;
+ }
+ }
+
+ /**
+ * Adds a subtree to the excluded ISet of these name constraints.
+ *
+ * @param subtree A subtree with an excluded GeneralName.
+ */
+ public void AddExcludedSubtree(GeneralSubtree subtree)
+ {
+ GeneralName subTreeBase = subtree.Base;
+
+ switch (subTreeBase.TagNo)
+ {
+ case 1:
+ excludedSubtreesEmail = UnionEmail(excludedSubtreesEmail,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 2:
+ excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 4:
+ excludedSubtreesDN = UnionDN(excludedSubtreesDN,
+ (Asn1Sequence)subTreeBase.Name.ToAsn1Object());
+ break;
+ case 6:
+ excludedSubtreesURI = unionURI(excludedSubtreesURI,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 7:
+ excludedSubtreesIP = UnionIP(excludedSubtreesIP, Asn1OctetString
+ .GetInstance(subTreeBase.Name).GetOctets());
+ break;
+ }
+ }
+
+ /**
+ * Returns the maximum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The maximum IP address.
+ */
+ private static byte[] Max(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Returns the minimum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The minimum IP address.
+ */
+ private static byte[] Min(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1
+ * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+ * otherwise.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+ */
+ private static int CompareTo(byte[] ip1, byte[] ip2)
+ {
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(ip1, ip2))
+ {
+ return 0;
+ }
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(Max(ip1, ip2), ip1))
+ {
+ return 1;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the logical OR of the IP addresses <code>ip1</code> and
+ * <code>ip2</code>.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The OR of <code>ip1</code> and <code>ip2</code>.
+ */
+ private static byte[] Or(byte[] ip1, byte[] ip2)
+ {
+ byte[] temp = new byte[ip1.Length];
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ temp[i] = (byte)(ip1[i] | ip2[i]);
+ }
+ return temp;
+ }
+
+ [Obsolete("Use GetHashCode instead")]
+ public int HashCode()
+ {
+ return GetHashCode();
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCollection(excludedSubtreesDN)
+ + HashCollection(excludedSubtreesDNS)
+ + HashCollection(excludedSubtreesEmail)
+ + HashCollection(excludedSubtreesIP)
+ + HashCollection(excludedSubtreesURI)
+ + HashCollection(permittedSubtreesDN)
+ + HashCollection(permittedSubtreesDNS)
+ + HashCollection(permittedSubtreesEmail)
+ + HashCollection(permittedSubtreesIP)
+ + HashCollection(permittedSubtreesURI);
+ }
+
+ private int HashCollection(ICollection coll)
+ {
+ if (coll == null)
+ {
+ return 0;
+ }
+ int hash = 0;
+ IEnumerator it1 = coll.GetEnumerator();
+ while (it1.MoveNext())
+ {
+ Object o = it1.Current;
+ if (o is byte[])
+ {
+ hash += Org.BouncyCastle.Utilities.Arrays.GetHashCode((byte[])o);
+ }
+ else
+ {
+ hash += o.GetHashCode();
+ }
+ }
+ return hash;
+ }
+
+ public override bool Equals(Object o)
+ {
+ if (!(o is PkixNameConstraintValidator))
+ return false;
+
+ PkixNameConstraintValidator constraintValidator = (PkixNameConstraintValidator)o;
+
+ return CollectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
+ }
+
+ private bool CollectionsAreEqual(ICollection coll1, ICollection coll2)
+ {
+ if (coll1 == coll2)
+ {
+ return true;
+ }
+ if (coll1 == null || coll2 == null)
+ {
+ return false;
+ }
+ if (coll1.Count != coll2.Count)
+ {
+ return false;
+ }
+ IEnumerator it1 = coll1.GetEnumerator();
+
+ while (it1.MoveNext())
+ {
+ Object a = it1.Current;
+ IEnumerator it2 = coll2.GetEnumerator();
+ bool found = false;
+ while (it2.MoveNext())
+ {
+ Object b = it2.Current;
+ if (SpecialEquals(a, b))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool SpecialEquals(Object o1, Object o2)
+ {
+ if (o1 == o2)
+ {
+ return true;
+ }
+ if (o1 == null || o2 == null)
+ {
+ return false;
+ }
+ if ((o1 is byte[]) && (o2 is byte[]))
+ {
+ return Org.BouncyCastle.Utilities.Arrays.AreEqual((byte[])o1, (byte[])o2);
+ }
+ else
+ {
+ return o1.Equals(o2);
+ }
+ }
+
+ /**
+ * Stringifies an IPv4 or v6 address with subnet mask.
+ *
+ * @param ip The IP with subnet mask.
+ * @return The stringified IP address.
+ */
+ private String StringifyIP(byte[] ip)
+ {
+ String temp = "";
+ for (int i = 0; i < ip.Length / 2; i++)
+ {
+ //temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ temp += (ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.Substring(0, temp.Length - 1);
+ temp += "/";
+ for (int i = ip.Length / 2; i < ip.Length; i++)
+ {
+ //temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ temp += (ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.Substring(0, temp.Length - 1);
+ return temp;
+ }
+
+ private String StringifyIPCollection(ISet ips)
+ {
+ String temp = "";
+ temp += "[";
+ for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+ {
+ temp += StringifyIP((byte[])it.Current) + ",";
+ }
+ if (temp.Length > 1)
+ {
+ temp = temp.Substring(0, temp.Length - 1);
+ }
+ temp += "]";
+
+ return temp;
+ }
+
+ public override String ToString()
+ {
+ String temp = "";
+
+ temp += "permitted:\n";
+ if (permittedSubtreesDN != null)
+ {
+ temp += "DN:\n";
+ temp += permittedSubtreesDN.ToString() + "\n";
+ }
+ if (permittedSubtreesDNS != null)
+ {
+ temp += "DNS:\n";
+ temp += permittedSubtreesDNS.ToString() + "\n";
+ }
+ if (permittedSubtreesEmail != null)
+ {
+ temp += "Email:\n";
+ temp += permittedSubtreesEmail.ToString() + "\n";
+ }
+ if (permittedSubtreesURI != null)
+ {
+ temp += "URI:\n";
+ temp += permittedSubtreesURI.ToString() + "\n";
+ }
+ if (permittedSubtreesIP != null)
+ {
+ temp += "IP:\n";
+ temp += StringifyIPCollection(permittedSubtreesIP) + "\n";
+ }
+ temp += "excluded:\n";
+ if (!(excludedSubtreesDN.IsEmpty))
+ {
+ temp += "DN:\n";
+ temp += excludedSubtreesDN.ToString() + "\n";
+ }
+ if (!excludedSubtreesDNS.IsEmpty)
+ {
+ temp += "DNS:\n";
+ temp += excludedSubtreesDNS.ToString() + "\n";
+ }
+ if (!excludedSubtreesEmail.IsEmpty)
+ {
+ temp += "Email:\n";
+ temp += excludedSubtreesEmail.ToString() + "\n";
+ }
+ if (!excludedSubtreesURI.IsEmpty)
+ {
+ temp += "URI:\n";
+ temp += excludedSubtreesURI.ToString() + "\n";
+ }
+ if (!excludedSubtreesIP.IsEmpty)
+ {
+ temp += "IP:\n";
+ temp += StringifyIPCollection(excludedSubtreesIP) + "\n";
+ }
+ return temp;
+ }
+
+ }
+}
diff --git a/crypto/src/pkix/PkixNameConstraintValidatorException.cs b/crypto/src/pkix/PkixNameConstraintValidatorException.cs
new file mode 100644
index 000000000..432d7bd6b
--- /dev/null
+++ b/crypto/src/pkix/PkixNameConstraintValidatorException.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Pkix
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+ [Serializable]
+#endif
+ public class PkixNameConstraintValidatorException
+ : Exception
+ {
+ public PkixNameConstraintValidatorException(String msg)
+ : base(msg)
+ {
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixParameters.cs b/crypto/src/pkix/PkixParameters.cs
new file mode 100644
index 000000000..6df1b646f
--- /dev/null
+++ b/crypto/src/pkix/PkixParameters.cs
@@ -0,0 +1,893 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixParameters.
+ /// </summary>
+ public class PkixParameters
+// : ICertPathParameters
+ {
+ /**
+ * This is the default PKIX validity model. Actually there are two variants
+ * of this: The PKIX model and the modified PKIX model. The PKIX model
+ * verifies that all involved certificates must have been valid at the
+ * current time. The modified PKIX model verifies that all involved
+ * certificates were valid at the signing time. Both are indirectly choosen
+ * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+ * methods sets the Date when <em>all</em> certificates must have been
+ * valid.
+ */
+ public const int PkixValidityModel = 0;
+
+ /**
+ * This model uses the following validity model. Each certificate must have
+ * been valid at the moment where is was used. That means the end
+ * certificate must have been valid at the time the signature was done. The
+ * CA certificate which signed the end certificate must have been valid,
+ * when the end certificate was signed. The CA (or Root CA) certificate must
+ * have been valid, when the CA certificate was signed and so on. So the
+ * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+ * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
+ * in the German signature law.
+ */
+ public const int ChainValidityModel = 1;
+
+ private ISet trustAnchors;
+ private DateTimeObject date;
+ private IList certPathCheckers;
+ private bool revocationEnabled = true;
+ private ISet initialPolicies;
+ //private bool checkOnlyEECertificateCrl = false;
+ private bool explicitPolicyRequired = false;
+ private bool anyPolicyInhibited = false;
+ private bool policyMappingInhibited = false;
+ private bool policyQualifiersRejected = true;
+ private IX509Selector certSelector;
+ private IList stores;
+ private IX509Selector selector;
+ private bool additionalLocationsEnabled;
+ private IList additionalStores;
+ private ISet trustedACIssuers;
+ private ISet necessaryACAttributes;
+ private ISet prohibitedACAttributes;
+ private ISet attrCertCheckers;
+ private int validityModel = PkixValidityModel;
+ private bool useDeltas = false;
+
+ /**
+ * Creates an instance of PKIXParameters with the specified Set of
+ * most-trusted CAs. Each element of the set is a TrustAnchor.<br />
+ * <br />
+ * Note that the Set is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors
+ * a Set of TrustAnchors
+ *
+ * @exception InvalidAlgorithmParameterException
+ * if the specified Set is empty
+ * <code>(trustAnchors.isEmpty() == true)</code>
+ * @exception NullPointerException
+ * if the specified Set is <code>null</code>
+ * @exception ClassCastException
+ * if any of the elements in the Set are not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public PkixParameters(
+ ISet trustAnchors)
+ {
+ SetTrustAnchors(trustAnchors);
+
+ this.initialPolicies = new HashSet();
+ this.certPathCheckers = Platform.CreateArrayList();
+ this.stores = Platform.CreateArrayList();
+ this.additionalStores = Platform.CreateArrayList();
+ this.trustedACIssuers = new HashSet();
+ this.necessaryACAttributes = new HashSet();
+ this.prohibitedACAttributes = new HashSet();
+ this.attrCertCheckers = new HashSet();
+ }
+
+// // TODO implement for other keystores (see Java build)?
+// /**
+// * Creates an instance of <code>PKIXParameters</code> that
+// * populates the set of most-trusted CAs from the trusted
+// * certificate entries contained in the specified <code>KeyStore</code>.
+// * Only keystore entries that contain trusted <code>X509Certificates</code>
+// * are considered; all other certificate types are ignored.
+// *
+// * @param keystore a <code>KeyStore</code> from which the set of
+// * most-trusted CAs will be populated
+// * @throws KeyStoreException if the keystore has not been initialized
+// * @throws InvalidAlgorithmParameterException if the keystore does
+// * not contain at least one trusted certificate entry
+// * @throws NullPointerException if the keystore is <code>null</code>
+// */
+// public PkixParameters(
+// Pkcs12Store keystore)
+//// throws KeyStoreException, InvalidAlgorithmParameterException
+// {
+// if (keystore == null)
+// throw new ArgumentNullException("keystore");
+// ISet trustAnchors = new HashSet();
+// foreach (string alias in keystore.Aliases)
+// {
+// if (keystore.IsCertificateEntry(alias))
+// {
+// X509CertificateEntry x509Entry = keystore.GetCertificate(alias);
+// trustAnchors.Add(new TrustAnchor(x509Entry.Certificate, null));
+// }
+// }
+// SetTrustAnchors(trustAnchors);
+//
+// this.initialPolicies = new HashSet();
+// this.certPathCheckers = new ArrayList();
+// this.stores = new ArrayList();
+// this.additionalStores = new ArrayList();
+// this.trustedACIssuers = new HashSet();
+// this.necessaryACAttributes = new HashSet();
+// this.prohibitedACAttributes = new HashSet();
+// this.attrCertCheckers = new HashSet();
+// }
+
+ public virtual bool IsRevocationEnabled
+ {
+ get { return revocationEnabled; }
+ set { revocationEnabled = value; }
+ }
+
+ public virtual bool IsExplicitPolicyRequired
+ {
+ get { return explicitPolicyRequired; }
+ set { this.explicitPolicyRequired = value; }
+ }
+
+ public virtual bool IsAnyPolicyInhibited
+ {
+ get { return anyPolicyInhibited; }
+ set { this.anyPolicyInhibited = value; }
+ }
+
+ public virtual bool IsPolicyMappingInhibited
+ {
+ get { return policyMappingInhibited; }
+ set { this.policyMappingInhibited = value; }
+ }
+
+ public virtual bool IsPolicyQualifiersRejected
+ {
+ get { return policyQualifiersRejected; }
+ set { this.policyQualifiersRejected = value; }
+ }
+
+ //public bool IsCheckOnlyEECertificateCrl
+ //{
+ // get { return this.checkOnlyEECertificateCrl; }
+ // set { this.checkOnlyEECertificateCrl = value; }
+ //}
+
+ public virtual DateTimeObject Date
+ {
+ get { return this.date; }
+ set { this.date = value; }
+ }
+
+ // Returns a Set of the most-trusted CAs.
+ public virtual ISet GetTrustAnchors()
+ {
+ return new HashSet(this.trustAnchors);
+ }
+
+ // Sets the set of most-trusted CAs.
+ // Set is copied to protect against subsequent modifications.
+ public virtual void SetTrustAnchors(
+ ISet tas)
+ {
+ if (tas == null)
+ throw new ArgumentNullException("value");
+ if (tas.IsEmpty)
+ throw new ArgumentException("non-empty set required", "value");
+
+ // Explicit copy to enforce type-safety
+ this.trustAnchors = new HashSet();
+ foreach (TrustAnchor ta in tas)
+ {
+ if (ta != null)
+ {
+ trustAnchors.Add(ta);
+ }
+ }
+ }
+
+ /**
+ * Returns the required constraints on the target certificate. The
+ * constraints are returned as an instance of CertSelector. If
+ * <code>null</code>, no constraints are defined.<br />
+ * <br />
+ * Note that the CertSelector returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return a CertSelector specifying the constraints on the target
+ * certificate (or <code>null</code>)
+ *
+ * @see #setTargetCertConstraints(CertSelector)
+ */
+ public virtual X509CertStoreSelector GetTargetCertConstraints()
+ {
+ if (certSelector == null)
+ {
+ return null;
+ }
+
+ return (X509CertStoreSelector)certSelector.Clone();
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of CertSelector. If null, no constraints are
+ * defined.<br />
+ * <br />
+ * Note that the CertSelector specified is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param selector
+ * a CertSelector specifying the constraints on the target
+ * certificate (or <code>null</code>)
+ *
+ * @see #getTargetCertConstraints()
+ */
+ public virtual void SetTargetCertConstraints(
+ IX509Selector selector)
+ {
+ if (selector == null)
+ {
+ certSelector = null;
+ }
+ else
+ {
+ certSelector = (IX509Selector)selector.Clone();
+ }
+ }
+
+ /**
+ * Returns an immutable Set of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. The
+ * default return value is an empty <code>Set</code>, which is
+ * interpreted as meaning that any policy would be acceptable.
+ *
+ * @return an immutable <code>Set</code> of initial policy OIDs in String
+ * format, or an empty <code>Set</code> (implying any policy is
+ * acceptable). Never returns <code>null</code>.
+ *
+ * @see #setInitialPolicies(java.util.Set)
+ */
+ public virtual ISet GetInitialPolicies()
+ {
+ ISet returnSet = initialPolicies;
+
+ // TODO Can it really be null?
+ if (initialPolicies == null)
+ {
+ returnSet = new HashSet();
+ }
+
+ return new HashSet(returnSet);
+ }
+
+ /**
+ * Sets the <code>Set</code> of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. By
+ * default, any policy is acceptable (i.e. all policies), so a user that
+ * wants to allow any policy as acceptable does not need to call this
+ * method, or can call it with an empty <code>Set</code> (or
+ * <code>null</code>).<br />
+ * <br />
+ * Note that the Set is copied to protect against subsequent modifications.<br />
+ * <br />
+ *
+ * @param initialPolicies
+ * a Set of initial policy OIDs in String format (or
+ * <code>null</code>)
+ *
+ * @exception ClassCastException
+ * if any of the elements in the set are not of type String
+ *
+ * @see #getInitialPolicies()
+ */
+ public virtual void SetInitialPolicies(
+ ISet initialPolicies)
+ {
+ this.initialPolicies = new HashSet();
+ if (initialPolicies != null)
+ {
+ foreach (string obj in initialPolicies)
+ {
+ if (obj != null)
+ {
+ this.initialPolicies.Add(obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets a <code>List</code> of additional certification path checkers. If
+ * the specified List contains an object that is not a PKIXCertPathChecker,
+ * it is ignored.<br />
+ * <br />
+ * Each <code>PKIXCertPathChecker</code> specified implements additional
+ * checks on a certificate. Typically, these are checks to process and
+ * verify private extensions contained in certificates. Each
+ * <code>PKIXCertPathChecker</code> should be instantiated with any
+ * initialization parameters needed to execute the check.<br />
+ * <br />
+ * This method allows sophisticated applications to extend a PKIX
+ * <code>CertPathValidator</code> or <code>CertPathBuilder</code>. Each
+ * of the specified PKIXCertPathCheckers will be called, in turn, by a PKIX
+ * <code>CertPathValidator</code> or <code>CertPathBuilder</code> for
+ * each certificate processed or validated.<br />
+ * <br />
+ * Regardless of whether these additional PKIXCertPathCheckers are set, a
+ * PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code>
+ * must perform all of the required PKIX checks on each certificate. The one
+ * exception to this rule is if the RevocationEnabled flag is set to false
+ * (see the {@link #setRevocationEnabled(boolean) setRevocationEnabled}
+ * method).<br />
+ * <br />
+ * Note that the List supplied here is copied and each PKIXCertPathChecker
+ * in the list is cloned to protect against subsequent modifications.
+ *
+ * @param checkers
+ * a List of PKIXCertPathCheckers. May be null, in which case no
+ * additional checkers will be used.
+ * @exception ClassCastException
+ * if any of the elements in the list are not of type
+ * <code>java.security.cert.PKIXCertPathChecker</code>
+ * @see #getCertPathCheckers()
+ */
+ public virtual void SetCertPathCheckers(IList checkers)
+ {
+ certPathCheckers = Platform.CreateArrayList();
+ if (checkers != null)
+ {
+ foreach (PkixCertPathChecker obj in checkers)
+ {
+ certPathCheckers.Add(obj.Clone());
+ }
+ }
+ }
+
+ /**
+ * Returns the List of certification path checkers. Each PKIXCertPathChecker
+ * in the returned IList is cloned to protect against subsequent modifications.
+ *
+ * @return an immutable List of PKIXCertPathCheckers (may be empty, but not
+ * <code>null</code>)
+ *
+ * @see #setCertPathCheckers(java.util.List)
+ */
+ public virtual IList GetCertPathCheckers()
+ {
+ IList checkers = Platform.CreateArrayList();
+ foreach (PkixCertPathChecker obj in certPathCheckers)
+ {
+ checkers.Add(obj.Clone());
+ }
+ return checkers;
+ }
+
+ /**
+ * Adds a <code>PKIXCertPathChecker</code> to the list of certification
+ * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
+ * method for more details.
+ * <p>
+ * Note that the <code>PKIXCertPathChecker</code> is cloned to protect
+ * against subsequent modifications.</p>
+ *
+ * @param checker a <code>PKIXCertPathChecker</code> to add to the list of
+ * checks. If <code>null</code>, the checker is ignored (not added to list).
+ */
+ public virtual void AddCertPathChecker(
+ PkixCertPathChecker checker)
+ {
+ if (checker != null)
+ {
+ certPathCheckers.Add(checker.Clone());
+ }
+ }
+
+ public virtual object Clone()
+ {
+ // FIXME Check this whole method against the Java implementation!
+
+ PkixParameters parameters = new PkixParameters(GetTrustAnchors());
+ parameters.SetParams(this);
+ return parameters;
+
+
+// PkixParameters obj = new PkixParameters(new HashSet());
+//// (PkixParameters) this.MemberwiseClone();
+// obj.x509Stores = new ArrayList(x509Stores);
+// obj.certPathCheckers = new ArrayList(certPathCheckers);
+//
+// //Iterator iter = certPathCheckers.iterator();
+// //obj.certPathCheckers = new ArrayList();
+// //while (iter.hasNext())
+// //{
+// // obj.certPathCheckers.add(((PKIXCertPathChecker)iter.next())
+// // .clone());
+// //}
+// //if (initialPolicies != null)
+// //{
+// // obj.initialPolicies = new HashSet(initialPolicies);
+// //}
+//// if (trustAnchors != null)
+//// {
+//// obj.trustAnchors = new HashSet(trustAnchors);
+//// }
+//// if (certSelector != null)
+//// {
+//// obj.certSelector = (X509CertStoreSelector) certSelector.Clone();
+//// }
+// return obj;
+ }
+
+ /**
+ * Method to support <code>Clone()</code> under J2ME.
+ * <code>super.Clone()</code> does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * <code>ExtendedPkixParameters</code> they are copied to.
+ */
+ protected virtual void SetParams(
+ PkixParameters parameters)
+ {
+ Date = parameters.Date;
+ SetCertPathCheckers(parameters.GetCertPathCheckers());
+ IsAnyPolicyInhibited = parameters.IsAnyPolicyInhibited;
+ IsExplicitPolicyRequired = parameters.IsExplicitPolicyRequired;
+ IsPolicyMappingInhibited = parameters.IsPolicyMappingInhibited;
+ IsRevocationEnabled = parameters.IsRevocationEnabled;
+ SetInitialPolicies(parameters.GetInitialPolicies());
+ IsPolicyQualifiersRejected = parameters.IsPolicyQualifiersRejected;
+ SetTargetCertConstraints(parameters.GetTargetCertConstraints());
+ SetTrustAnchors(parameters.GetTrustAnchors());
+
+ validityModel = parameters.validityModel;
+ useDeltas = parameters.useDeltas;
+ additionalLocationsEnabled = parameters.additionalLocationsEnabled;
+ selector = parameters.selector == null ? null
+ : (IX509Selector) parameters.selector.Clone();
+ stores = Platform.CreateArrayList(parameters.stores);
+ additionalStores = Platform.CreateArrayList(parameters.additionalStores);
+ trustedACIssuers = new HashSet(parameters.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(parameters.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(parameters.necessaryACAttributes);
+ attrCertCheckers = new HashSet(parameters.attrCertCheckers);
+ }
+
+ /**
+ * Whether delta CRLs should be used for checking the revocation status.
+ * Defaults to <code>false</code>.
+ */
+ public virtual bool IsUseDeltasEnabled
+ {
+ get { return useDeltas; }
+ set { useDeltas = value; }
+ }
+
+ /**
+ * The validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public virtual int ValidityModel
+ {
+ get { return validityModel; }
+ set { validityModel = value; }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * The <code>IList</code> is cloned.
+ * </p>
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a {@link Store}.
+ */
+ public virtual void SetStores(
+ IList stores)
+ {
+ if (stores == null)
+ {
+ this.stores = Platform.CreateArrayList();
+ }
+ else
+ {
+ foreach (object obj in stores)
+ {
+ if (!(obj is IX509Store))
+ {
+ throw new InvalidCastException(
+ "All elements of list must be of type " + typeof(IX509Store).FullName);
+ }
+ }
+ this.stores = Platform.CreateArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ * </p><p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ * </p>
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public virtual void AddStore(
+ IX509Store store)
+ {
+ if (store != null)
+ {
+ stores.Add(store);
+ }
+ }
+
+ /**
+ * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ * <p>
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ * </p><p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ * </p>
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public virtual void AddAdditionalStore(
+ IX509Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.Add(store);
+ }
+ }
+
+ /**
+ * Returns an <code>IList</code> of additional Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>IList</code> of additional Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #addAddionalStore(Store)
+ */
+ public virtual IList GetAdditionalStores()
+ {
+ return Platform.CreateArrayList(additionalStores);
+ }
+
+ /**
+ * Returns an <code>IList</code> of Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>IList</code> of Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #setStores(IList)
+ */
+ public virtual IList GetStores()
+ {
+ return Platform.CreateArrayList(stores);
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns <code>true</code> if additional stores are used.
+ */
+ public virtual bool IsAdditionalLocationsEnabled
+ {
+ get { return additionalLocationsEnabled; }
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled <code>true</code> if additional stores are used.
+ */
+ public virtual void SetAdditionalLocationsEnabled(
+ bool enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * <code>IX509Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ *
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * </p><p>
+ * Note that the <code>IX509Selector</code> returned is cloned to protect
+ * against subsequent modifications.
+ * </p>
+ * @return a <code>IX509Selector</code> specifying the constraints on the
+ * target certificate or attribute certificate (or <code>null</code>)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public virtual IX509Selector GetTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (IX509Selector) selector.Clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * <code>IX509Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * </p><p>
+ * Note that the <code>IX509Selector</code> specified is cloned to protect
+ * against subsequent modifications.
+ * </p>
+ *
+ * @param selector a <code>IX509Selector</code> specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * <code>null</code>)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public virtual void SetTargetConstraints(IX509Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (IX509Selector) selector.Clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ * <p>
+ * The returned <code>ISet</code> consists of <code>TrustAnchor</code>s.
+ * </p><p>
+ * The returned <code>ISet</code> is immutable. Never <code>null</code>
+ * </p>
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public virtual ISet GetTrustedACIssuers()
+ {
+ return new HashSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ * <p>
+ * The <code>trustedACIssuers</code> must be a <code>ISet</code> of
+ * <code>TrustAnchor</code>
+ * </p><p>
+ * The given set is cloned.
+ * </p>
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * <code>null</code>.
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>TrustAnchor</code>.
+ */
+ public virtual void SetTrustedACIssuers(
+ ISet trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ this.trustedACIssuers = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in trustedACIssuers)
+ {
+ if (!(obj is TrustAnchor))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type " + typeof(TrustAnchor).Name + ".");
+ }
+ }
+ this.trustedACIssuers = new HashSet(trustedACIssuers);
+ }
+ }
+
+ /**
+ * Returns the neccessary attributes which must be contained in an attribute
+ * certificate.
+ * <p>
+ * The returned <code>ISet</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ * </p>
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public virtual ISet GetNecessaryACAttributes()
+ {
+ return new HashSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the neccessary which must be contained in an attribute certificate.
+ * <p>
+ * The <code>ISet</code> must contain <code>String</code>s with the
+ * OIDs.
+ * </p><p>
+ * The set is cloned.
+ * </p>
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>necessaryACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public virtual void SetNecessaryACAttributes(
+ ISet necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in necessaryACAttributes)
+ {
+ if (!(obj is string))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type string.");
+ }
+ }
+ this.necessaryACAttributes = new HashSet(necessaryACAttributes);
+ }
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ * <p>
+ * The returned <code>ISet</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ * </p>
+ *
+ * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+ */
+ public virtual ISet GetProhibitedACAttributes()
+ {
+ return new HashSet(prohibitedACAttributes);
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ * <p>
+ * The <code>ISet</code> must contain <code>String</code>s with the
+ * OIDs.
+ * </p><p>
+ * The set is cloned.
+ * </p>
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>prohibitedACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public virtual void SetProhibitedACAttributes(
+ ISet prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in prohibitedACAttributes)
+ {
+ if (!(obj is String))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type string.");
+ }
+ }
+ this.prohibitedACAttributes = new HashSet(prohibitedACAttributes);
+ }
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * <code>null</code>.
+ */
+ public virtual ISet GetAttrCertCheckers()
+ {
+ return new HashSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ * <p>
+ * All elements in the <code>ISet</code> must a {@link PKIXAttrCertChecker}.
+ * </p>
+ * <p>
+ * The given set is cloned.
+ * </p>
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never <code>null</code>.
+ * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+ * is not a <code>PKIXAttrCertChecker</code>.
+ */
+ public virtual void SetAttrCertCheckers(
+ ISet attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in attrCertCheckers)
+ {
+ if (!(obj is PkixAttrCertChecker))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type " + typeof(PkixAttrCertChecker).FullName + ".");
+ }
+ }
+ this.attrCertCheckers = new HashSet(attrCertCheckers);
+ }
+ }
+ }
+}
diff --git a/crypto/src/pkix/PkixPolicyNode.cs b/crypto/src/pkix/PkixPolicyNode.cs
new file mode 100644
index 000000000..fc5b82f6f
--- /dev/null
+++ b/crypto/src/pkix/PkixPolicyNode.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// Summary description for PkixPolicyNode.
+ /// </summary>
+ public class PkixPolicyNode
+// : IPolicyNode
+ {
+ protected IList mChildren;
+ protected int mDepth;
+ protected ISet mExpectedPolicies;
+ protected PkixPolicyNode mParent;
+ protected ISet mPolicyQualifiers;
+ protected string mValidPolicy;
+ protected bool mCritical;
+
+ public virtual int Depth
+ {
+ get { return this.mDepth; }
+ }
+
+ public virtual IEnumerable Children
+ {
+ get { return new EnumerableProxy(mChildren); }
+ }
+
+ public virtual bool IsCritical
+ {
+ get { return this.mCritical; }
+ set { this.mCritical = value; }
+ }
+
+ public virtual ISet PolicyQualifiers
+ {
+ get { return new HashSet(this.mPolicyQualifiers); }
+ }
+
+ public virtual string ValidPolicy
+ {
+ get { return this.mValidPolicy; }
+ }
+
+ public virtual bool HasChildren
+ {
+ get { return mChildren.Count != 0; }
+ }
+
+ public virtual ISet ExpectedPolicies
+ {
+ get { return new HashSet(this.mExpectedPolicies); }
+ set { this.mExpectedPolicies = new HashSet(value); }
+ }
+
+ public virtual PkixPolicyNode Parent
+ {
+ get { return this.mParent; }
+ set { this.mParent = value; }
+ }
+
+ /// Constructors
+ public PkixPolicyNode(
+ IList children,
+ int depth,
+ ISet expectedPolicies,
+ PkixPolicyNode parent,
+ ISet policyQualifiers,
+ string validPolicy,
+ bool critical)
+ {
+ if (children == null)
+ {
+ this.mChildren = Platform.CreateArrayList();
+ }
+ else
+ {
+ this.mChildren = Platform.CreateArrayList(children);
+ }
+
+ this.mDepth = depth;
+ this.mExpectedPolicies = expectedPolicies;
+ this.mParent = parent;
+ this.mPolicyQualifiers = policyQualifiers;
+ this.mValidPolicy = validPolicy;
+ this.mCritical = critical;
+ }
+
+ public virtual void AddChild(
+ PkixPolicyNode child)
+ {
+ child.Parent = this;
+ mChildren.Add(child);
+ }
+
+ public virtual void RemoveChild(
+ PkixPolicyNode child)
+ {
+ mChildren.Remove(child);
+ }
+
+ public override string ToString()
+ {
+ return ToString("");
+ }
+
+ public virtual string ToString(
+ string indent)
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.Append(indent);
+ buf.Append(mValidPolicy);
+ buf.Append(" {");
+ buf.Append(Platform.NewLine);
+
+ foreach (PkixPolicyNode child in mChildren)
+ {
+ buf.Append(child.ToString(indent + " "));
+ }
+
+ buf.Append(indent);
+ buf.Append("}");
+ buf.Append(Platform.NewLine);
+ return buf.ToString();
+ }
+
+ public virtual object Clone()
+ {
+ return Copy();
+ }
+
+ public virtual PkixPolicyNode Copy()
+ {
+ PkixPolicyNode node = new PkixPolicyNode(
+ Platform.CreateArrayList(),
+ mDepth,
+ new HashSet(mExpectedPolicies),
+ null,
+ new HashSet(mPolicyQualifiers),
+ mValidPolicy,
+ mCritical);
+
+ foreach (PkixPolicyNode child in mChildren)
+ {
+ PkixPolicyNode copy = child.Copy();
+ copy.Parent = node;
+ node.AddChild(copy);
+ }
+
+ return node;
+ }
+ }
+}
diff --git a/crypto/src/pkix/ReasonsMask.cs b/crypto/src/pkix/ReasonsMask.cs
new file mode 100644
index 000000000..e389bfe11
--- /dev/null
+++ b/crypto/src/pkix/ReasonsMask.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// This class helps to handle CRL revocation reasons mask. Each CRL handles a
+ /// certain set of revocation reasons.
+ /// </summary>
+ internal class ReasonsMask
+ {
+ private int _reasons;
+
+ /// <summary>
+ /// Constructs are reason mask with the reasons.
+ /// </summary>
+ /// <param name="reasons">The reasons.</param>
+ internal ReasonsMask(
+ int reasons)
+ {
+ _reasons = reasons;
+ }
+
+ /// <summary>
+ /// A reason mask with no reason.
+ /// </summary>
+ internal ReasonsMask()
+ : this(0)
+ {
+ }
+
+ /// <summary>
+ /// A mask with all revocation reasons.
+ /// </summary>
+ internal static readonly ReasonsMask AllReasons = new ReasonsMask(
+ ReasonFlags.AACompromise | ReasonFlags.AffiliationChanged | ReasonFlags.CACompromise
+ | ReasonFlags.CertificateHold | ReasonFlags.CessationOfOperation
+ | ReasonFlags.KeyCompromise | ReasonFlags.PrivilegeWithdrawn | ReasonFlags.Unused
+ | ReasonFlags.Superseded);
+
+ /**
+ * Adds all reasons from the reasons mask to this mask.
+ *
+ * @param mask The reasons mask to add.
+ */
+ internal void AddReasons(
+ ReasonsMask mask)
+ {
+ _reasons = _reasons | mask.Reasons.IntValue;
+ }
+
+ /// <summary>
+ /// Returns <code>true</code> if this reasons mask contains all possible
+ /// reasons.
+ /// </summary>
+ /// <returns>true if this reasons mask contains all possible reasons.
+ /// </returns>
+ internal bool IsAllReasons
+ {
+ get { return _reasons == AllReasons._reasons; }
+ }
+
+ /// <summary>
+ /// Intersects this mask with the given reasons mask.
+ /// </summary>
+ /// <param name="mask">mask The mask to intersect with.</param>
+ /// <returns>The intersection of this and teh given mask.</returns>
+ internal ReasonsMask Intersect(
+ ReasonsMask mask)
+ {
+ ReasonsMask _mask = new ReasonsMask();
+ _mask.AddReasons(new ReasonsMask(_reasons & mask.Reasons.IntValue));
+ return _mask;
+ }
+
+ /// <summary>
+ /// Returns <c>true</c> if the passed reasons mask has new reasons.
+ /// </summary>
+ /// <param name="mask">The reasons mask which should be tested for new reasons.</param>
+ /// <returns><c>true</c> if the passed reasons mask has new reasons.</returns>
+ internal bool HasNewReasons(
+ ReasonsMask mask)
+ {
+ return ((_reasons | mask.Reasons.IntValue ^ _reasons) != 0);
+ }
+
+ /// <summary>
+ /// Returns the reasons in this mask.
+ /// </summary>
+ public ReasonFlags Reasons
+ {
+ get { return new ReasonFlags(_reasons); }
+ }
+ }
+}
diff --git a/crypto/src/pkix/Rfc3280CertPathUtilities.cs b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
new file mode 100644
index 000000000..bae657d90
--- /dev/null
+++ b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
@@ -0,0 +1,2448 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class Rfc3280CertPathUtilities
+ {
+ private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+ internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+ // key usage bits
+ internal static readonly int KEY_CERT_SIGN = 5;
+ internal static readonly int CRL_SIGN = 6;
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ * <p>
+ * (i) If the distribution point name is present in the IDP CRL extension
+ * and the distribution field is present in the DP, then verify that one of
+ * the names in the IDP matches one of the names in the DP. If the
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ * </p>
+ * <p>
+ * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate does not include the basic
+ * constraints extension with the cA boolean asserted.
+ * </p>
+ * <p>
+ * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate includes the basic constraints
+ * extension with the cA boolean asserted.
+ * </p>
+ * <p>
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ internal static void ProcessCrlB2(
+ DistributionPoint dp,
+ object cert,
+ X509Crl crl)
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("0 Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.DistributionPoint != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.GetInstance(idp).DistributionPoint;
+ IList names = Platform.CreateArrayList();
+
+ if (dpName.PointType == DistributionPointName.FullName)
+ {
+ GeneralName[] genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ names.Add(genNames[j]);
+ }
+ }
+ if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ try
+ {
+ IEnumerator e = Asn1Sequence.GetInstance(
+ Asn1Sequence.FromByteArray(crl.IssuerDN.GetEncoded())).GetEnumerator();
+ while (e.MoveNext())
+ {
+ vec.Add((Asn1Encodable)e.Current);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Could not read CRL issuer.", e);
+ }
+ vec.Add(dpName.Name);
+ names.Add(new GeneralName(X509Name.GetInstance(new DerSequence(vec))));
+ }
+ bool matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.DistributionPointName != null)
+ {
+ dpName = dp.DistributionPointName;
+ GeneralName[] genNames = null;
+ if (dpName.PointType == DistributionPointName.FullName)
+ {
+ genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+ }
+ if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+ {
+ if (dp.CrlIssuer != null)
+ {
+ genNames = dp.CrlIssuer.GetNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(
+ PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert));
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ IEnumerator e = Asn1Sequence.GetInstance(genNames[j].Name.ToAsn1Object()).GetEnumerator();
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ while (e.MoveNext())
+ {
+ vec.Add((Asn1Encodable)e.Current);
+ }
+ vec.Add(dpName.Name);
+ genNames[j] = new GeneralName(X509Name.GetInstance(new DerSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (names.Contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new Exception(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.CrlIssuer == null)
+ {
+ throw new Exception("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (names.Contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new Exception(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(
+ (IX509Extension)cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Basic constraints extension could not be decoded.", e);
+ }
+
+ //if (cert is X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.OnlyContainsUserCerts && ((bc != null) && bc.IsCA()))
+ {
+ throw new Exception("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.OnlyContainsCACerts && (bc == null || !bc.IsCA()))
+ {
+ throw new Exception("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.OnlyContainsAttributeCerts)
+ {
+ throw new Exception("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ internal static void ProcessCertBC(
+ PkixCertPath certPath,
+ int index,
+ PkixNameConstraintValidator nameConstraintValidator)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (i < n)))
+ {
+ X509Name principal = cert.SubjectDN;
+ Asn1InputStream aIn = new Asn1InputStream(principal.GetEncoded());
+ Asn1Sequence dns;
+
+ try
+ {
+ dns = DerSequence.GetInstance(aIn.ReadObject());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Exception extracting subject name when checking subtrees.", e, certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.CheckPermittedDN(dns);
+ nameConstraintValidator.CheckExcludedDN(dns);
+ }
+ catch (PkixNameConstraintValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject failed.", e, certPath, index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.SubjectAlternativeName));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subject alternative name extension could not be decoded.", e, certPath, index);
+ }
+
+ IList emails = X509Name.GetInstance(dns).GetValueList(X509Name.EmailAddress);
+ foreach (string email in emails)
+ {
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.Rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PkixNameConstraintValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.GetNames();
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subject alternative name contents could not be decoded.", e, certPath, index);
+ }
+ foreach (GeneralName genName in genNames)
+ {
+ try
+ {
+ nameConstraintValidator.checkPermitted(genName);
+ nameConstraintValidator.checkExcluded(genName);
+ }
+ catch (PkixNameConstraintValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ internal static void PrepareNextCertA(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ //
+ // (a) check the policy mappings
+ //
+ Asn1Sequence pm = null;
+ try
+ {
+ pm = Asn1Sequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension could not be decoded.", ex, certPath, index);
+ }
+ if (pm != null)
+ {
+ Asn1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.Count; j++)
+ {
+ DerObjectIdentifier issuerDomainPolicy = null;
+ DerObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ Asn1Sequence mapping = DerSequence.GetInstance(mappings[j]);
+
+ issuerDomainPolicy = DerObjectIdentifier.GetInstance(mapping[0]);
+ subjectDomainPolicy = DerObjectIdentifier.GetInstance(mapping[1]);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension contents could not be decoded.", e, certPath, index);
+ }
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(issuerDomainPolicy.Id))
+ throw new PkixCertPathValidatorException(
+ "IssuerDomainPolicy is anyPolicy", null, certPath, index);
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(subjectDomainPolicy.Id))
+ throw new PkixCertPathValidatorException(
+ "SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+
+ internal static PkixPolicyNode ProcessCertD(
+ PkixCertPath certPath,
+ int index,
+ ISet acceptablePolicies,
+ PkixPolicyNode validPolicyTree,
+ IList[] policyNodes,
+ int inhibitAnyPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ Asn1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Could not read certificate policies extension from certificate.", e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ ISet pols = new HashSet();
+
+ foreach (Asn1Encodable ae in certPolicies)
+ {
+ PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ DerObjectIdentifier pOid = pInfo.PolicyIdentifier;
+
+ pols.Add(pOid.Id);
+
+ if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(pOid.Id))
+ {
+ ISet pq = null;
+ try
+ {
+ pq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be build.", ex, certPath, index);
+ }
+
+ bool match = PkixCertPathValidatorUtilities.ProcessCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ PkixCertPathValidatorUtilities.ProcessCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.IsEmpty || acceptablePolicies.Contains(Rfc3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.Clear();
+ acceptablePolicies.AddAll(pols);
+ }
+ else
+ {
+ ISet t1 = new HashSet();
+
+ foreach (object o in acceptablePolicies)
+ {
+ if (pols.Contains(o))
+ {
+ t1.Add(o);
+ }
+ }
+ acceptablePolicies.Clear();
+ acceptablePolicies.AddAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && PkixCertPathValidatorUtilities.IsSelfIssued(cert)))
+ {
+ foreach (Asn1Encodable ae in certPolicies)
+ {
+ PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pInfo.PolicyIdentifier.Id))
+ {
+ ISet _apq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+ IList _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodes[k];
+
+ IEnumerator _policySetIter = _node.ExpectedPolicies.GetEnumerator();
+ while (_policySetIter.MoveNext())
+ {
+ object _tmp = _policySetIter.Current;
+
+ string _policy;
+ if (_tmp is string)
+ {
+ _policy = (string)_tmp;
+ }
+ else if (_tmp is DerObjectIdentifier)
+ {
+ _policy = ((DerObjectIdentifier)_tmp).Id;
+ }
+ else
+ {
+ continue;
+ }
+
+ bool _found = false;
+
+ foreach (PkixPolicyNode _child in _node.Children)
+ {
+ if (_policy.Equals(_child.ValidPolicy))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ ISet _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.Add(_policy);
+
+ PkixPolicyNode _newChild = new PkixPolicyNode(Platform.CreateArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.AddChild(_newChild);
+ policyNodes[i].Add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PkixPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ _validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ ISet criticalExtensionOids = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensionOids != null)
+ {
+ bool critical = criticalExtensionOids.Contains(X509Extensions.CertificatePolicies.Id);
+
+ IList nodes = policyNodes[i];
+ for (int j = 0; j < nodes.Count; j++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[j];
+ node.IsCritical = critical;
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an
+ * g distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for <code>cert</code>.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ internal static void ProcessCrlB1(
+ DistributionPoint dp,
+ object cert,
+ X509Crl crl)
+ {
+ Asn1Object idp = PkixCertPathValidatorUtilities.GetExtensionValue(
+ crl, X509Extensions.IssuingDistributionPoint);
+
+ bool isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.GetInstance(idp).IsIndirectCrl)
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = crl.IssuerDN.GetEncoded();
+
+ bool matchIssuer = false;
+ if (dp.CrlIssuer != null)
+ {
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(genNames[j].Name.ToAsn1Object().GetEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new Exception("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new Exception("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (crl.IssuerDN.Equivalent(PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert), true))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new Exception("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ internal static ReasonsMask ProcessCrlD(
+ X509Crl crl,
+ DistributionPoint dp)
+ //throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("issuing distribution point extension could not be decoded.", e);
+ }
+
+ // (d) (1)
+ if (idp != null && idp.OnlySomeReasons != null && dp.Reasons != null)
+ {
+ return new ReasonsMask(dp.Reasons.IntValue).Intersect(new ReasonsMask(idp.OnlySomeReasons
+ .IntValue));
+ }
+ // (d) (4)
+ if ((idp == null || idp.OnlySomeReasons == null) && dp.Reasons == null)
+ {
+ return ReasonsMask.AllReasons;
+ }
+
+ // (d) (2) and (d)(3)
+
+ ReasonsMask dpReasons = null;
+
+ if (dp.Reasons == null)
+ {
+ dpReasons = ReasonsMask.AllReasons;
+ }
+ else
+ {
+ dpReasons = new ReasonsMask(dp.Reasons.IntValue);
+ }
+
+ ReasonsMask idpReasons = null;
+
+ if (idp == null)
+ {
+ idpReasons = ReasonsMask.AllReasons;
+ }
+ else
+ {
+ idpReasons = new ReasonsMask(idp.OnlySomeReasons.IntValue);
+ }
+
+ return dpReasons.Intersect(idpReasons);
+ }
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * <code>cert</code>.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A <code>Set</code> with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ internal static ISet ProcessCrlF(
+ X509Crl crl,
+ object cert,
+ X509Certificate defaultCRLSignCert,
+ AsymmetricKeyParameter defaultCRLSignKey,
+ PkixParameters paramsPKIX,
+ IList certPathCerts)
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ selector.Subject = crl.IssuerDN;
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ IList coll = Platform.CreateArrayList();
+
+ try
+ {
+ CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetStores()));
+ CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetAdditionalStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.Add(defaultCRLSignCert);
+
+ IEnumerator cert_it = coll.GetEnumerator();
+
+ IList validCerts = Platform.CreateArrayList();
+ IList validKeys = Platform.CreateArrayList();
+
+ while (cert_it.MoveNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.Current;
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.Equals(defaultCRLSignCert))
+ {
+ validCerts.Add(signingCert);
+ validKeys.Add(defaultCRLSignKey);
+ continue;
+ }
+ try
+ {
+// CertPathBuilder builder = CertPathBuilder.GetInstance("PKIX");
+ PkixCertPathBuilder builder = new PkixCertPathBuilder();
+ selector = new X509CertStoreSelector();
+ selector.Certificate = signingCert;
+
+ PkixParameters temp = (PkixParameters)paramsPKIX.Clone();
+ temp.SetTargetCertConstraints(selector);
+
+ PkixBuilderParameters parameters = (PkixBuilderParameters)
+ PkixBuilderParameters.GetInstance(temp);
+
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.Contains(signingCert))
+ {
+ parameters.IsRevocationEnabled = false;
+ }
+ else
+ {
+ parameters.IsRevocationEnabled = true;
+ }
+ IList certs = builder.Build(parameters).CertPath.Certificates;
+ validCerts.Add(signingCert);
+ validKeys.Add(PkixCertPathValidatorUtilities.GetNextWorkingKey(certs, 0));
+ }
+ catch (PkixCertPathBuilderException e)
+ {
+ throw new Exception("Internal error.", e);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new Exception("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ //catch (Exception e)
+ //{
+ // throw new Exception(e.Message);
+ //}
+ }
+
+ ISet checkKeys = new HashSet();
+
+ Exception lastException = null;
+ for (int i = 0; i < validCerts.Count; i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts[i];
+ bool[] keyusage = signCert.GetKeyUsage();
+
+ if (keyusage != null && (keyusage.Length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new Exception(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.Add(validKeys[i]);
+ }
+ }
+
+ if ((checkKeys.Count == 0) && lastException == null)
+ {
+ throw new Exception("Cannot find a valid issuer certificate.");
+ }
+ if ((checkKeys.Count == 0) && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ internal static AsymmetricKeyParameter ProcessCrlG(
+ X509Crl crl,
+ ISet keys)
+ {
+ Exception lastException = null;
+ foreach (AsymmetricKeyParameter key in keys)
+ {
+ try
+ {
+ crl.Verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new Exception("Cannot verify CRL.", lastException);
+ }
+
+ internal static X509Crl ProcessCrlH(
+ ISet deltaCrls,
+ AsymmetricKeyParameter key)
+ {
+ Exception lastException = null;
+ foreach (X509Crl crl in deltaCrls)
+ {
+ try
+ {
+ crl.Verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (lastException != null)
+ {
+ throw new Exception("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate <code>cert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void CheckCrl(
+ DistributionPoint dp,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ DateTime validDate,
+ X509Certificate defaultCRLSignCert,
+ AsymmetricKeyParameter defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ IList certPathCerts)
+ //throws AnnotatedException
+ {
+ DateTime currentDate = DateTime.UtcNow;
+
+ if (validDate.Ticks > currentDate.Ticks)
+ {
+ throw new Exception("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, cert, currentDate, paramsPKIX);
+ bool validCrlFound = false;
+ Exception lastException = null;
+
+ IEnumerator crl_iter = crls.GetEnumerator();
+
+ while (crl_iter.MoveNext() && certStatus.Status == CertStatus.Unrevoked && !reasonMask.IsAllReasons)
+ {
+ try
+ {
+ X509Crl crl = (X509Crl)crl_iter.Current;
+
+ // (d)
+ ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.HasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ AsymmetricKeyParameter key = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+ X509Crl deltaCRL = null;
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRLs
+ ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.NotAfter.Ticks < crl.ThisUpdate.Ticks)
+ {
+ throw new Exception("No valid CRL for current time found.");
+ }
+ }
+
+ Rfc3280CertPathUtilities.ProcessCrlB1(dp, cert, crl);
+
+ // (b) (2)
+ Rfc3280CertPathUtilities.ProcessCrlB2(dp, cert, crl);
+
+ // (c)
+ Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.Status == CrlReason.RemoveFromCrl)
+ {
+ certStatus.Status = CertStatus.Unrevoked;
+ }
+
+ // update reasons mask
+ reasonMask.AddReasons(interimReasonsMask);
+
+ ISet criticalExtensions = crl.GetCriticalExtensionOids();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+ if (!criticalExtensions.IsEmpty)
+ throw new Exception("CRL contains unsupported critical extensions.");
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.GetCriticalExtensionOids();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+ if (!criticalExtensions.IsEmpty)
+ throw new Exception("Delta CRL contains unsupported critical extension.");
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate <code>cert</code>.
+ * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void CheckCrls(
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ DateTime validDate,
+ X509Certificate sign,
+ AsymmetricKeyParameter workingPublicKey,
+ IList certPathCerts)
+ {
+ Exception lastException = null;
+ CrlDistPoint crldp = null;
+
+ try
+ {
+ crldp = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CrlDistributionPoints));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("CRL distribution point extension could not be read.", e);
+ }
+
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ bool validCrlFound = false;
+
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ for (int i = 0; i < dps.Length && certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons; i++)
+ {
+ PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+ try
+ {
+ CheckCrl(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons)
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ Asn1Object issuer = null;
+ try
+ {
+ issuer = new Asn1InputStream(cert.IssuerDN.GetEncoded()).ReadObject();
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+ PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+
+ CheckCrl(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ if (certStatus.Status != CertStatus.Unrevoked)
+ {
+ // TODO This format is forced by the NistCertPath tests
+ string formattedDate = certStatus.RevocationDate.Value.ToString(
+ "G", new CultureInfo("en-us"));
+ string message = "Certificate revocation after " + formattedDate;
+ message += ", reason: " + CrlReasons[certStatus.Status];
+ throw new Exception(message);
+ }
+
+ if (!reasonsMask.IsAllReasons && certStatus.Status == CertStatus.Unrevoked)
+ {
+ certStatus.Status = CertStatus.Undetermined;
+ }
+
+ if (certStatus.Status == CertStatus.Undetermined)
+ {
+ throw new Exception("Certificate status could not be determined.");
+ }
+ }
+
+ internal static PkixPolicyNode PrepareCertB(
+ PkixCertPath certPath,
+ int index,
+ IList[] policyNodes,
+ PkixPolicyNode validPolicyTree,
+ int policyMapping)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ Asn1Sequence pm = null;
+ try
+ {
+ pm = (Asn1Sequence)Asn1Sequence.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension could not be decoded.", ex, certPath, index);
+ }
+ PkixPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ Asn1Sequence mappings = (Asn1Sequence)pm;
+ IDictionary m_idp = Platform.CreateHashtable();
+ ISet s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.Count; j++)
+ {
+ Asn1Sequence mapping = (Asn1Sequence) mappings[j];
+ string id_p = ((DerObjectIdentifier) mapping[0]).Id;
+ string sd_p = ((DerObjectIdentifier) mapping[1]).Id;
+ ISet tmp;
+
+ if (!m_idp.Contains(id_p))
+ {
+ tmp = new HashSet();
+ tmp.Add(sd_p);
+ m_idp[id_p] = tmp;
+ s_idp.Add(id_p);
+ }
+ else
+ {
+ tmp = (ISet)m_idp[id_p];
+ tmp.Add(sd_p);
+ }
+ }
+
+ IEnumerator it_idp = s_idp.GetEnumerator();
+ while (it_idp.MoveNext())
+ {
+ string id_p = (string)it_idp.Current;
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ bool idp_found = false;
+ IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ idp_found = true;
+ node.ExpectedPolicies = (ISet)m_idp[id_p];
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(node.ValidPolicy))
+ {
+ ISet pq = null;
+ Asn1Sequence policies = null;
+ try
+ {
+ policies = (Asn1Sequence)PkixCertPathValidatorUtilities.GetExtensionValue(cert,
+ X509Extensions.CertificatePolicies);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+
+ foreach (Asn1Encodable ae in policies)
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+ {
+ try
+ {
+ pq = PkixCertPathValidatorUtilities
+ .GetQualifierSet(pinfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ bool ci = false;
+ ISet critExtOids = cert.GetCriticalExtensionOids();
+ if (critExtOids != null)
+ {
+ ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+ }
+
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(p_node.ValidPolicy))
+ {
+ PkixPolicyNode c_node = new PkixPolicyNode(Platform.CreateArrayList(), i,
+ (ISet)m_idp[id_p], p_node, pq, id_p, ci);
+ p_node.AddChild(c_node);
+ policyNodes[i].Add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+ {
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ node.Parent.RemoveChild(node);
+
+ for (int k = i - 1; k >= 0; k--)
+ {
+ foreach (PkixPolicyNode node2 in Platform.CreateArrayList(policyNodes[k]))
+ {
+ if (!node2.HasChildren)
+ {
+ _validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+
+ if (_validPolicyTree == null)
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ internal static ISet[] ProcessCrlA1ii(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ X509Crl crl)
+ {
+ ISet deltaSet = new HashSet();
+ X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+ crlselect.CertificateChecking = cert;
+
+ try
+ {
+ IList issuer = Platform.CreateArrayList();
+ issuer.Add(crl.IssuerDN);
+ crlselect.Issuers = issuer;
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Cannot extract issuer from CRL." + e, e);
+ }
+
+ crlselect.CompleteCrlEnabled = true;
+ ISet completeSet = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining delta CRLs.", e);
+ }
+ }
+
+ return new ISet[]{ completeSet, deltaSet };
+ }
+
+ internal static ISet ProcessCrlA1i(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ X509Crl crl)
+ {
+ ISet deltaSet = new HashSet();
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ CrlDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CrlDistPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.FreshestCrl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.FreshestCrl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "No new delta CRL locations could be added from Freshest CRL extension.", e);
+ }
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return deltaSet;
+ }
+
+ internal static void ProcessCertF(
+ PkixCertPath certPath,
+ int index,
+ PkixPolicyNode validPolicyTree,
+ int explicitPolicy)
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new PkixCertPathValidatorException(
+ "No valid policy tree found when one expected.", null, certPath, index);
+ }
+ }
+
+ internal static void ProcessCertA(
+ PkixCertPath certPath,
+ PkixParameters paramsPKIX,
+ int index,
+ AsymmetricKeyParameter workingPublicKey,
+ X509Name workingIssuerName,
+ X509Certificate sign)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (a) verify
+ //
+ try
+ {
+ // (a) (1)
+ //
+ cert.Verify(workingPublicKey);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.CheckValidity(PkixCertPathValidatorUtilities
+ .GetValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.IsRevocationEnabled)
+ {
+ try
+ {
+ CheckCrls(paramsPKIX, cert, PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (Exception e)
+ {
+ Exception cause = e.InnerException;
+ if (cause == null)
+ {
+ cause = e;
+ }
+ throw new PkixCertPathValidatorException(e.Message, cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ X509Name issuer = PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert);
+ if (!issuer.Equivalent(workingIssuerName, true))
+ {
+ throw new PkixCertPathValidatorException("IssuerName(" + issuer
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ internal static int PrepareNextCertI1(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (i)
+ //
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension cannot be decoded.", e, certPath, index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ try
+ {
+ Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+ if (constraint.TagNo == 0)
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (ArgumentException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension contents cannot be decoded.", e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ internal static int PrepareNextCertI2(
+ PkixCertPath certPath,
+ int index,
+ int policyMapping)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (i)
+ //
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension cannot be decoded.", e, certPath, index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ try
+ {
+ Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+ if (constraint.TagNo == 1)
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (ArgumentException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension contents cannot be decoded.", e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ internal static void PrepareNextCertG(
+ PkixCertPath certPath,
+ int index,
+ PkixNameConstraintValidator nameConstraintValidator)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ Asn1Sequence ncSeq = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.NameConstraints));
+ if (ncSeq != null)
+ {
+ nc = new NameConstraints(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Name constraints extension could not be decoded.", e, certPath, index);
+ }
+ if (nc != null)
+ {
+ //
+ // (g) (1) permitted subtrees
+ //
+ Asn1Sequence permitted = nc.PermittedSubtrees;
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.IntersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ Asn1Sequence excluded = nc.ExcludedSubtrees;
+ if (excluded != null)
+ {
+ IEnumerator e = excluded.GetEnumerator();
+ try
+ {
+ while (e.MoveNext())
+ {
+ GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+ nameConstraintValidator.AddExcludedSubtree(subtree);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ internal static int PrepareNextCertJ(
+ PkixCertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (j)
+ //
+ DerInteger iap = null;
+ try
+ {
+ iap = DerInteger.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.InhibitAnyPolicy));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Inhibit any-policy extension cannot be decoded.", e, certPath, index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.Value.IntValue;
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ return _inhibitAnyPolicy;
+ }
+ return inhibitAnyPolicy;
+ }
+
+ internal static void PrepareNextCertK(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.IsCA()))
+ throw new PkixCertPathValidatorException("Not a CA certificate");
+ }
+ else
+ {
+ throw new PkixCertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ internal static int PrepareNextCertL(
+ PkixCertPath certPath,
+ int index,
+ int maxPathLength)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (l)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new PkixCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ internal static int PrepareNextCertM(
+ PkixCertPath certPath,
+ int index,
+ int maxPathLength)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.PathLenConstraint;
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.IntValue;
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ internal static void PrepareNextCertN(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (n)
+ //
+ bool[] _usage = cert.GetKeyUsage();
+
+ if ((_usage != null) && !_usage[Rfc3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new PkixCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ internal static void PrepareNextCertO(
+ PkixCertPath certPath,
+ int index,
+ ISet criticalExtensions,
+ IList pathCheckers)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (o)
+ //
+ IEnumerator tmpIter = pathCheckers.GetEnumerator();
+ while (tmpIter.MoveNext())
+ {
+ try
+ {
+ ((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, index);
+ }
+ }
+ if (!criticalExtensions.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException("Certificate has unsupported critical extension.", null, certPath,
+ index);
+ }
+ }
+
+ internal static int PrepareNextCertH1(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ return explicitPolicy - 1;
+ }
+ return explicitPolicy;
+ }
+
+ internal static int PrepareNextCertH2(
+ PkixCertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ return policyMapping - 1;
+ }
+ return policyMapping;
+ }
+
+
+ internal static int PrepareNextCertH3(
+ PkixCertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ return inhibitAnyPolicy - 1;
+ }
+ return inhibitAnyPolicy;
+ }
+
+ internal static int WrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ internal static int WrapupCertB(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (b)
+ //
+ int tmpInt;
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ Asn1TaggedObject constraint = (Asn1TaggedObject)policyConstraints.Current;
+ switch (constraint.TagNo)
+ {
+ case 0:
+ try
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ internal static void WrapupCertF(
+ PkixCertPath certPath,
+ int index,
+ IList pathCheckers,
+ ISet criticalExtensions)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ IEnumerator tmpIter = pathCheckers.GetEnumerator();
+
+ while (tmpIter.MoveNext())
+ {
+ try
+ {
+ ((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException("Certificate has unsupported critical extension",
+ null, certPath, index);
+ }
+ }
+
+ internal static PkixPolicyNode WrapupCertG(
+ PkixCertPath certPath,
+ PkixParameters paramsPKIX,
+ ISet userInitialPolicySet,
+ int index,
+ IList[] policyNodes,
+ PkixPolicyNode validPolicyTree,
+ ISet acceptablePolicies)
+ {
+ int n = certPath.Certificates.Count;
+
+ //
+ // (g)
+ //
+ PkixPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.IsExplicitPolicyRequired)
+ {
+ throw new PkixCertPathValidatorException(
+ "Explicit policy requested but none available.", null, certPath, index);
+ }
+ intersection = null;
+ }
+ else if (PkixCertPathValidatorUtilities.IsAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.IsExplicitPolicyRequired)
+ {
+ if (acceptablePolicies.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Explicit policy requested but none available.", null, certPath, index);
+ }
+ else
+ {
+ ISet _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ IList _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ foreach (object o in _node.Children)
+ {
+ _validPolicyNodeSet.Add(o);
+ }
+ }
+ }
+ }
+
+ foreach (PkixPolicyNode _node in _validPolicyNodeSet)
+ {
+ string _validPolicy = _node.ValidPolicy;
+
+ if (!acceptablePolicies.Contains(_validPolicy))
+ {
+ // TODO?
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ ISet _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ IList _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ foreach (PkixPolicyNode _c_node in _node.Children)
+ {
+ if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(_c_node.ValidPolicy))
+ {
+ _validPolicyNodeSet.Add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ IEnumerator _vpnsIter = _validPolicyNodeSet.GetEnumerator();
+ while (_vpnsIter.MoveNext())
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_vpnsIter.Current;
+ string _validPolicy = _node.ValidPolicy;
+
+ if (!userInitialPolicySet.Contains(_validPolicy))
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ internal static void ProcessCrlC(
+ X509Crl deltaCRL,
+ X509Crl completeCRL,
+ PkixParameters pkixParams)
+ {
+ if (deltaCRL == null)
+ return;
+
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("000 Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.IsUseDeltasEnabled)
+ {
+ // (c) (1)
+ if (!deltaCRL.IssuerDN.Equivalent(completeCRL.IssuerDN, true))
+ throw new Exception("Complete CRL issuer does not match delta CRL issuer.");
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(deltaCRL, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ if (!Platform.Equals(completeidp, deltaidp))
+ {
+ throw new Exception(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ Asn1Object completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+ completeCRL, X509Extensions.AuthorityKeyIdentifier);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ Asn1Object deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+ deltaCRL, X509Extensions.AuthorityKeyIdentifier);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ throw new Exception("CRL authority key identifier is null.");
+
+ if (deltaKeyIdentifier == null)
+ throw new Exception("Delta CRL authority key identifier is null.");
+
+ if (!completeKeyIdentifier.Equals(deltaKeyIdentifier))
+ {
+ throw new Exception(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ internal static void ProcessCrlI(
+ DateTime validDate,
+ X509Crl deltacrl,
+ object cert,
+ CertStatus certStatus,
+ PkixParameters pkixParams)
+ {
+ if (pkixParams.IsUseDeltasEnabled && deltacrl != null)
+ {
+ PkixCertPathValidatorUtilities.GetCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ internal static void ProcessCrlJ(
+ DateTime validDate,
+ X509Crl completecrl,
+ object cert,
+ CertStatus certStatus)
+ {
+ if (certStatus.Status == CertStatus.Unrevoked)
+ {
+ PkixCertPathValidatorUtilities.GetCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ internal static PkixPolicyNode ProcessCertE(
+ PkixCertPath certPath,
+ int index,
+ PkixPolicyNode validPolicyTree)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (e)
+ //
+ Asn1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ internal static readonly string[] CrlReasons = new string[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"
+ };
+ }
+}
diff --git a/crypto/src/pkix/Rfc3281CertPathUtilities.cs b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
new file mode 100644
index 000000000..bda2aa737
--- /dev/null
+++ b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
@@ -0,0 +1,608 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ internal class Rfc3281CertPathUtilities
+ {
+ internal static void ProcessAttrCert7(
+ IX509AttributeCertificate attrCert,
+ PkixCertPath certPath,
+ PkixCertPath holderCertPath,
+ PkixParameters pkixParams)
+ {
+ // TODO:
+ // AA Controls
+ // Attribute encryption
+ // Proxy
+ ISet critExtOids = attrCert.GetCriticalExtensionOids();
+
+ // 7.1
+ // process extensions
+
+ // target information checked in step 6 / X509AttributeCertStoreSelector
+ if (critExtOids.Contains(X509Extensions.TargetInformation.Id))
+ {
+ try
+ {
+ TargetInformation.GetInstance(PkixCertPathValidatorUtilities
+ .GetExtensionValue(attrCert, X509Extensions.TargetInformation));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ }
+ critExtOids.Remove(X509Extensions.TargetInformation.Id);
+ foreach (PkixAttrCertChecker checker in pkixParams.GetAttrCertCheckers())
+ {
+ checker.Check(attrCert, certPath, holderCertPath, critExtOids);
+ }
+ if (!critExtOids.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate contains unsupported critical extensions: "
+ + critExtOids);
+ }
+ }
+
+ /**
+ * Checks if an attribute certificate is revoked.
+ *
+ * @param attrCert Attribute certificate to check if it is revoked.
+ * @param paramsPKIX PKIX parameters.
+ * @param issuerCert The issuer certificate of the attribute certificate
+ * <code>attrCert</code>.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ *
+ * @throws CertPathValidatorException if the certificate is revoked or the
+ * status cannot be checked or some error occurs.
+ */
+ internal static void CheckCrls(
+ IX509AttributeCertificate attrCert,
+ PkixParameters paramsPKIX,
+ X509Certificate issuerCert,
+ DateTime validDate,
+ IList certPathCerts)
+ {
+ if (paramsPKIX.IsRevocationEnabled)
+ {
+ // check if revocation is available
+ if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) == null)
+ {
+ CrlDistPoint crldp = null;
+ try
+ {
+ crldp = CrlDistPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(
+ attrCert, X509Extensions.CrlDistributionPoints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ PkixCertPathValidatorUtilities
+ .AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ Exception lastException = null;
+ bool validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Distribution points could not be read.", e);
+ }
+ try
+ {
+ for (int i = 0; i < dps.Length
+ && certStatus.Status == CertStatus.Unrevoked
+ && !reasonsMask.IsAllReasons; i++)
+ {
+ PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX
+ .Clone();
+ CheckCrl(dps[i], attrCert, paramsPKIXClone,
+ validDate, issuerCert, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ }
+ catch (Exception e)
+ {
+ lastException = new Exception(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the
+ * process above with any available CRLs not specified in a
+ * distribution point but issued by the certificate issuer.
+ */
+
+ if (certStatus.Status == CertStatus.Unrevoked
+ && !reasonsMask.IsAllReasons)
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer
+ * fields omitted and a distribution point name of the
+ * certificate issuer.
+ */
+ Asn1Object issuer = null;
+ try
+ {
+ issuer = new Asn1InputStream(
+ attrCert.Issuer.GetPrincipals()[0].GetEncoded()).ReadObject();
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuer from certificate for CRL could not be reencoded.",
+ e);
+ }
+ DistributionPoint dp = new DistributionPoint(
+ new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+ PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX.Clone();
+ CheckCrl(dp, attrCert, paramsPKIXClone, validDate,
+ issuerCert, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = new Exception(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw new PkixCertPathValidatorException(
+ "No valid CRL found.", lastException);
+ }
+ if (certStatus.Status != CertStatus.Unrevoked)
+ {
+ // TODO This format is forced by the NistCertPath tests
+ string formattedDate = certStatus.RevocationDate.Value.ToString(
+ "G", new CultureInfo("en-us"));
+ string message = "Attribute certificate revocation after "
+ + formattedDate;
+ message += ", reason: "
+ + Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
+ throw new PkixCertPathValidatorException(message);
+ }
+ if (!reasonsMask.IsAllReasons
+ && certStatus.Status == CertStatus.Unrevoked)
+ {
+ certStatus.Status = CertStatus.Undetermined;
+ }
+ if (certStatus.Status == CertStatus.Undetermined)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate status could not be determined.");
+ }
+
+ }
+ else
+ {
+ if (attrCert.GetExtensionValue(X509Extensions.CrlDistributionPoints) != null
+ || attrCert.GetExtensionValue(X509Extensions.AuthorityInfoAccess) != null)
+ {
+ throw new PkixCertPathValidatorException(
+ "No rev avail extension is set, but also an AC revocation pointer.");
+ }
+ }
+ }
+ }
+
+ internal static void AdditionalChecks(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ // 1
+ foreach (string oid in pkixParams.GetProhibitedACAttributes())
+ {
+ if (attrCert.GetAttributes(oid) != null)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate contains prohibited attribute: "
+ + oid + ".");
+ }
+ }
+ foreach (string oid in pkixParams.GetNecessaryACAttributes())
+ {
+ if (attrCert.GetAttributes(oid) == null)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate does not contain necessary attribute: "
+ + oid + ".");
+ }
+ }
+ }
+
+ internal static void ProcessAttrCert5(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ try
+ {
+ attrCert.CheckValidity(PkixCertPathValidatorUtilities.GetValidDate(pkixParams));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ }
+
+ internal static void ProcessAttrCert4(
+ X509Certificate acIssuerCert,
+ PkixParameters pkixParams)
+ {
+ ISet set = pkixParams.GetTrustedACIssuers();
+ bool trusted = false;
+ foreach (TrustAnchor anchor in set)
+ {
+ IDictionary symbols = X509Name.RFC2253Symbols;
+ if (acIssuerCert.SubjectDN.ToString(false, symbols).Equals(anchor.CAName)
+ || acIssuerCert.Equals(anchor.TrustedCert))
+ {
+ trusted = true;
+ }
+ }
+ if (!trusted)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer is not directly trusted.");
+ }
+ }
+
+ internal static void ProcessAttrCert3(
+ X509Certificate acIssuerCert,
+ PkixParameters pkixParams)
+ {
+ if (acIssuerCert.GetKeyUsage() != null
+ && (!acIssuerCert.GetKeyUsage()[0] && !acIssuerCert.GetKeyUsage()[1]))
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer public key cannot be used to validate digital signatures.");
+ }
+ if (acIssuerCert.GetBasicConstraints() != -1)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer is also a public key certificate issuer.");
+ }
+ }
+
+ internal static PkixCertPathValidatorResult ProcessAttrCert2(
+ PkixCertPath certPath,
+ PkixParameters pkixParams)
+ {
+ PkixCertPathValidator validator = new PkixCertPathValidator();
+
+ try
+ {
+ return validator.Validate(certPath, pkixParams);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Certification path for issuer certificate of attribute certificate could not be validated.",
+ e);
+ }
+ }
+
+ /**
+ * Searches for a holder public key certificate and verifies its
+ * certification path.
+ *
+ * @param attrCert the attribute certificate.
+ * @param pkixParams The PKIX parameters.
+ * @return The certificate path of the holder certificate.
+ * @throws Exception if
+ * <ul>
+ * <li>no public key certificate can be found although holder
+ * information is given by an entity name or a base certificate
+ * ID</li>
+ * <li>support classes cannot be created</li>
+ * <li>no certification path for the public key certificate can
+ * be built</li>
+ * </ul>
+ */
+ internal static PkixCertPath ProcessAttrCert1(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ PkixCertPathBuilderResult result = null;
+ // find holder PKCs
+ ISet holderPKCs = new HashSet();
+ if (attrCert.Holder.GetIssuer() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.SerialNumber = attrCert.Holder.SerialNumber;
+ X509Name[] principals = attrCert.Holder.GetIssuer();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+// if (principals[i] is X500Principal)
+ {
+ selector.Issuer = principals[i];
+ }
+ holderPKCs.AddAll(PkixCertPathValidatorUtilities
+ .FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+ if (holderPKCs.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
+ }
+ }
+ if (attrCert.Holder.GetEntityNames() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ X509Name[] principals = attrCert.Holder.GetEntityNames();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+// if (principals[i] is X500Principal)
+ {
+ selector.Issuer = principals[i];
+ }
+ holderPKCs.AddAll(PkixCertPathValidatorUtilities
+ .FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+ if (holderPKCs.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate specified in entity name for attribute certificate cannot be found.");
+ }
+ }
+
+ // verify cert paths for PKCs
+ PkixBuilderParameters parameters = (PkixBuilderParameters)
+ PkixBuilderParameters.GetInstance(pkixParams);
+
+ PkixCertPathValidatorException lastException = null;
+ foreach (X509Certificate cert in holderPKCs)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.Certificate = cert;
+ parameters.SetTargetConstraints(selector);
+
+ PkixCertPathBuilder builder = new PkixCertPathBuilder();
+
+ try
+ {
+ result = builder.Build(PkixBuilderParameters.GetInstance(parameters));
+ }
+ catch (PkixCertPathBuilderException e)
+ {
+ lastException = new PkixCertPathValidatorException(
+ "Certification path for public key certificate of attribute certificate could not be build.",
+ e);
+ }
+ }
+ if (lastException != null)
+ {
+ throw lastException;
+ }
+ return result.CertPath;
+ }
+
+ /**
+ *
+ * Checks a distribution point for revocation information for the
+ * certificate <code>attrCert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param attrCert The attribute certificate which should be checked.
+ * @param paramsPKIX PKIX parameters.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param issuerCert Certificate to check if it is revoked.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ * @throws Exception if the certificate is revoked or the status
+ * cannot be checked or some error occurs.
+ */
+ private static void CheckCrl(
+ DistributionPoint dp,
+ IX509AttributeCertificate attrCert,
+ PkixParameters paramsPKIX,
+ DateTime validDate,
+ X509Certificate issuerCert,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ IList certPathCerts)
+ {
+ /*
+ * 4.3.6 No Revocation Available
+ *
+ * The noRevAvail extension, defined in [X.509-2000], allows an AC
+ * issuer to indicate that no revocation information will be made
+ * available for this AC.
+ */
+ if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) != null)
+ {
+ return;
+ }
+
+ DateTime currentDate = DateTime.UtcNow;
+ if (validDate.CompareTo(currentDate) > 0)
+ {
+ throw new Exception("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPkixParameters and are in
+ * getAdditionalStore()
+ */
+ ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, attrCert,
+ currentDate, paramsPKIX);
+ bool validCrlFound = false;
+ Exception lastException = null;
+
+ IEnumerator crl_iter = crls.GetEnumerator();
+
+ while (crl_iter.MoveNext()
+ && certStatus.Status == CertStatus.Unrevoked
+ && !reasonMask.IsAllReasons)
+ {
+ try
+ {
+ X509Crl crl = (X509Crl) crl_iter.Current;
+
+ // (d)
+ ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.HasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, attrCert,
+ null, null, paramsPKIX, certPathCerts);
+ // (g)
+ AsymmetricKeyParameter pubKey = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+ X509Crl deltaCRL = null;
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRLs
+ ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(
+ currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, pubKey);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL vality time
+ */
+ if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (attrCert.NotAfter.CompareTo(crl.ThisUpdate) < 0)
+ {
+ throw new Exception(
+ "No valid CRL for current time found.");
+ }
+ }
+
+ Rfc3280CertPathUtilities.ProcessCrlB1(dp, attrCert, crl);
+
+ // (b) (2)
+ Rfc3280CertPathUtilities.ProcessCrlB2(dp, attrCert, crl);
+
+ // (c)
+ Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL,
+ attrCert, certStatus, paramsPKIX);
+
+ // (j)
+ Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, attrCert,
+ certStatus);
+
+ // (k)
+ if (certStatus.Status == CrlReason.RemoveFromCrl)
+ {
+ certStatus.Status = CertStatus.Unrevoked;
+ }
+
+ // update reasons mask
+ reasonMask.AddReasons(interimReasonsMask);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+ }
+}
diff --git a/crypto/src/pkix/TrustAnchor.cs b/crypto/src/pkix/TrustAnchor.cs
new file mode 100644
index 000000000..22078baf2
--- /dev/null
+++ b/crypto/src/pkix/TrustAnchor.cs
@@ -0,0 +1,259 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /// <summary>
+ /// A trust anchor or most-trusted Certification Authority (CA).
+ ///
+ /// This class represents a "most-trusted CA", which is used as a trust anchor
+ /// for validating X.509 certification paths. A most-trusted CA includes the
+ /// public key of the CA, the CA's name, and any constraints upon the set of
+ /// paths which may be validated using this key. These parameters can be
+ /// specified in the form of a trusted X509Certificate or as individual
+ /// parameters.
+ /// </summary>
+ public class TrustAnchor
+ {
+ private readonly AsymmetricKeyParameter pubKey;
+ private readonly string caName;
+ private readonly X509Name caPrincipal;
+ private readonly X509Certificate trustedCert;
+ private byte[] ncBytes;
+ private NameConstraints nc;
+
+ /// <summary>
+ /// Creates an instance of TrustAnchor with the specified X509Certificate and
+ /// optional name constraints, which are intended to be used as additional
+ /// constraints when validating an X.509 certification path.
+ /// The name constraints are specified as a byte array. This byte array
+ /// should contain the DER encoded form of the name constraints, as they
+ /// would appear in the NameConstraints structure defined in RFC 2459 and
+ /// X.509. The ASN.1 definition of this structure appears below.
+ ///
+ /// <pre>
+ /// NameConstraints ::= SEQUENCE {
+ /// permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ /// excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ ///
+ /// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ ///
+ /// GeneralSubtree ::= SEQUENCE {
+ /// base GeneralName,
+ /// minimum [0] BaseDistance DEFAULT 0,
+ /// maximum [1] BaseDistance OPTIONAL }
+ ///
+ /// BaseDistance ::= INTEGER (0..MAX)
+ ///
+ /// GeneralName ::= CHOICE {
+ /// otherName [0] OtherName,
+ /// rfc822Name [1] IA5String,
+ /// dNSName [2] IA5String,
+ /// x400Address [3] ORAddress,
+ /// directoryName [4] Name,
+ /// ediPartyName [5] EDIPartyName,
+ /// uniformResourceIdentifier [6] IA5String,
+ /// iPAddress [7] OCTET STRING,
+ /// registeredID [8] OBJECT IDENTIFIER}
+ /// </pre>
+ ///
+ /// Note that the name constraints byte array supplied is cloned to protect
+ /// against subsequent modifications.
+ /// </summary>
+ /// <param name="trustedCert">a trusted X509Certificate</param>
+ /// <param name="nameConstraints">a byte array containing the ASN.1 DER encoding of a
+ /// NameConstraints extension to be used for checking name
+ /// constraints. Only the value of the extension is included, not
+ /// the OID or criticality flag. Specify null to omit the
+ /// parameter.</param>
+ /// <exception cref="ArgumentNullException">if the specified X509Certificate is null</exception>
+ public TrustAnchor(
+ X509Certificate trustedCert,
+ byte[] nameConstraints)
+ {
+ if (trustedCert == null)
+ throw new ArgumentNullException("trustedCert");
+
+ this.trustedCert = trustedCert;
+ this.pubKey = null;
+ this.caName = null;
+ this.caPrincipal = null;
+ setNameConstraints(nameConstraints);
+ }
+
+ /// <summary>
+ /// Creates an instance of <c>TrustAnchor</c> where the
+ /// most-trusted CA is specified as an X500Principal and public key.
+ /// </summary>
+ /// <remarks>
+ /// <p>
+ /// Name constraints are an optional parameter, and are intended to be used
+ /// as additional constraints when validating an X.509 certification path.
+ /// </p><p>
+ /// The name constraints are specified as a byte array. This byte array
+ /// contains the DER encoded form of the name constraints, as they
+ /// would appear in the NameConstraints structure defined in RFC 2459
+ /// and X.509. The ASN.1 notation for this structure is supplied in the
+ /// documentation for the other constructors.
+ /// </p><p>
+ /// Note that the name constraints byte array supplied here is cloned to
+ /// protect against subsequent modifications.
+ /// </p>
+ /// </remarks>
+ /// <param name="caPrincipal">the name of the most-trusted CA as X509Name</param>
+ /// <param name="pubKey">the public key of the most-trusted CA</param>
+ /// <param name="nameConstraints">
+ /// a byte array containing the ASN.1 DER encoding of a NameConstraints extension to
+ /// be used for checking name constraints. Only the value of the extension is included,
+ /// not the OID or criticality flag. Specify <c>null</c> to omit the parameter.
+ /// </param>
+ /// <exception cref="ArgumentNullException">
+ /// if <c>caPrincipal</c> or <c>pubKey</c> is null
+ /// </exception>
+ public TrustAnchor(
+ X509Name caPrincipal,
+ AsymmetricKeyParameter pubKey,
+ byte[] nameConstraints)
+ {
+ if (caPrincipal == null)
+ throw new ArgumentNullException("caPrincipal");
+ if (pubKey == null)
+ throw new ArgumentNullException("pubKey");
+
+ this.trustedCert = null;
+ this.caPrincipal = caPrincipal;
+ this.caName = caPrincipal.ToString();
+ this.pubKey = pubKey;
+ setNameConstraints(nameConstraints);
+ }
+
+ /// <summary>
+ /// Creates an instance of <code>TrustAnchor</code> where the most-trusted
+ /// CA is specified as a distinguished name and public key. Name constraints
+ /// are an optional parameter, and are intended to be used as additional
+ /// constraints when validating an X.509 certification path.
+ /// <br/>
+ /// The name constraints are specified as a byte array. This byte array
+ /// contains the DER encoded form of the name constraints, as they would
+ /// appear in the NameConstraints structure defined in RFC 2459 and X.509.
+ /// </summary>
+ /// <param name="caName">the X.500 distinguished name of the most-trusted CA in RFC
+ /// 2253 string format</param>
+ /// <param name="pubKey">the public key of the most-trusted CA</param>
+ /// <param name="nameConstraints">a byte array containing the ASN.1 DER encoding of a
+ /// NameConstraints extension to be used for checking name
+ /// constraints. Only the value of the extension is included, not
+ /// the OID or criticality flag. Specify null to omit the
+ /// parameter.</param>
+ /// throws NullPointerException, IllegalArgumentException
+ public TrustAnchor(
+ string caName,
+ AsymmetricKeyParameter pubKey,
+ byte[] nameConstraints)
+ {
+ if (caName == null)
+ throw new ArgumentNullException("caName");
+ if (pubKey == null)
+ throw new ArgumentNullException("pubKey");
+ if (caName.Length == 0)
+ throw new ArgumentException("caName can not be an empty string");
+
+ this.caPrincipal = new X509Name(caName);
+ this.pubKey = pubKey;
+ this.caName = caName;
+ this.trustedCert = null;
+ setNameConstraints(nameConstraints);
+ }
+
+ /// <summary>
+ /// Returns the most-trusted CA certificate.
+ /// </summary>
+ public X509Certificate TrustedCert
+ {
+ get { return this.trustedCert; }
+ }
+
+ /// <summary>
+ /// Returns the name of the most-trusted CA as an X509Name.
+ /// </summary>
+ public X509Name CA
+ {
+ get { return this.caPrincipal; }
+ }
+
+ /// <summary>
+ /// Returns the name of the most-trusted CA in RFC 2253 string format.
+ /// </summary>
+ public string CAName
+ {
+ get { return this.caName; }
+ }
+
+ /// <summary>
+ /// Returns the public key of the most-trusted CA.
+ /// </summary>
+ public AsymmetricKeyParameter CAPublicKey
+ {
+ get { return this.pubKey; }
+ }
+
+ /// <summary>
+ /// Decode the name constraints and clone them if not null.
+ /// </summary>
+ private void setNameConstraints(
+ byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ ncBytes = null;
+ nc = null;
+ }
+ else
+ {
+ ncBytes = (byte[]) bytes.Clone();
+ // validate DER encoding
+ //nc = new NameConstraintsExtension(Boolean.FALSE, bytes);
+ nc = NameConstraints.GetInstance(Asn1Object.FromByteArray(bytes));
+ }
+ }
+
+ public byte[] GetNameConstraints
+ {
+ get { return Arrays.Clone(ncBytes); }
+ }
+
+ /// <summary>
+ /// Returns a formatted string describing the <code>TrustAnchor</code>.
+ /// </summary>
+ /// <returns>a formatted string describing the <code>TrustAnchor</code></returns>
+ public override string ToString()
+ {
+ // TODO Some of the sub-objects might not implement ToString() properly
+ string nl = Platform.NewLine;
+ StringBuilder sb = new StringBuilder();
+ sb.Append("[");
+ sb.Append(nl);
+ if (this.pubKey != null)
+ {
+ sb.Append(" Trusted CA Public Key: ").Append(this.pubKey).Append(nl);
+ sb.Append(" Trusted CA Issuer Name: ").Append(this.caName).Append(nl);
+ }
+ else
+ {
+ sb.Append(" Trusted CA cert: ").Append(this.TrustedCert).Append(nl);
+ }
+ if (nc != null)
+ {
+ sb.Append(" Name Constraints: ").Append(nc).Append(nl);
+ }
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
|