summary refs log tree commit diff
path: root/crypto/src/pkix/Rfc3281CertPathUtilities.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/pkix/Rfc3281CertPathUtilities.cs')
-rw-r--r--crypto/src/pkix/Rfc3281CertPathUtilities.cs608
1 files changed, 608 insertions, 0 deletions
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;
+			}
+		}
+	}
+}