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;
+ }
+ }
+ }
+}
|