summary refs log tree commit diff
path: root/crypto/src/x509
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-04-04 21:20:26 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-04-04 21:20:26 +0700
commitaa027f072fe8f7871950cd256b2e04f12c1d4551 (patch)
tree47c4bb1a5b813f7cb82a68ed6b87f431d075a97a /crypto/src/x509
parentAdd constructor from template CRL (diff)
downloadBouncyCastle.NET-ed25519-aa027f072fe8f7871950cd256b2e04f12c1d4551.tar.xz
X509: generation/validation of alternative signatures for certs and CRLs.
Diffstat (limited to 'crypto/src/x509')
-rw-r--r--crypto/src/x509/X509Certificate.cs54
-rw-r--r--crypto/src/x509/X509Crl.cs58
-rw-r--r--crypto/src/x509/X509Utilities.cs43
-rw-r--r--crypto/src/x509/X509V2AttributeCertificate.cs29
-rw-r--r--crypto/src/x509/X509V2AttributeCertificateGenerator.cs21
-rw-r--r--crypto/src/x509/X509V2CRLGenerator.cs38
-rw-r--r--crypto/src/x509/X509V3CertificateGenerator.cs37
7 files changed, 198 insertions, 82 deletions
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
index cd3d6d680..39df381df 100644
--- a/crypto/src/x509/X509Certificate.cs
+++ b/crypto/src/x509/X509Certificate.cs
@@ -638,8 +638,7 @@ namespace Org.BouncyCastle.X509
         /// <param name="key">An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters</param>
         /// <returns>True if the signature is valid.</returns>
         /// <exception cref="Exception">If key submitted is not of the above nominated types.</exception>
-        public virtual void Verify(
-            AsymmetricKeyParameter key)
+        public virtual void Verify(AsymmetricKeyParameter key)
         {
             CheckSignature(new Asn1VerifierFactory(c.SignatureAlgorithm, key));
         }
@@ -648,27 +647,54 @@ namespace Org.BouncyCastle.X509
         /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
         /// </summary>
         /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
-        /// <returns>True if the signature is valid.</returns>
-        /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
-        public virtual void Verify(
-            IVerifierFactoryProvider verifierProvider)
+        /// <exception cref="Exception">If verifier provider is not appropriate or the certificate signature algorithm
+        /// is invalid.</exception>
+        public virtual void Verify(IVerifierFactoryProvider verifierProvider)
         {
             CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm));
         }
 
-        protected virtual void CheckSignature(
-            IVerifierFactory verifier)
+        /// <summary>Verify the certificate's alternative signature using a verifier created using the passed in
+        /// verifier provider.</summary>
+        /// <param name="verifierProvider">An appropriate provider for verifying the certificate's alternative
+        /// signature.</param>
+        /// <exception cref="Exception">If verifier provider is not appropriate or the certificate alternative signature
+        /// algorithm is invalid.</exception>
+        public virtual void VerifyAltSignature(IVerifierFactoryProvider verifierProvider)
         {
-            if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
-                throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+            var tbsCertificate = c.TbsCertificate;
+            var extensions = tbsCertificate.Extensions;
+
+            AltSignatureAlgorithm altSigAlg = AltSignatureAlgorithm.FromExtensions(extensions);
+            AltSignatureValue altSigValue = AltSignatureValue.FromExtensions(extensions);
+
+            var verifier = verifierProvider.CreateVerifierFactory(altSigAlg.Algorithm);
 
-            IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
-            using (var stream = streamCalculator.Stream)
+            Asn1Sequence tbsSeq = Asn1Sequence.GetInstance(tbsCertificate.ToAsn1Object());
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            for (int i = 0; i < tbsSeq.Count - 1; i++)
             {
-                c.TbsCertificate.EncodeTo(stream, Asn1Encodable.Der);
+                if (i != 2) // signature field - must be ver 3 so version always present
+                {
+                    v.Add(tbsSeq[i]);
+                }
             }
 
-            if (!streamCalculator.GetResult().IsVerified(GetSignature()))
+            v.Add(X509Utilities.TrimExtensions(3, extensions));
+
+            if (!X509Utilities.VerifySignature(verifier, new DerSequence(v), altSigValue.Signature))
+                throw new InvalidKeyException("Public key presented not for certificate alternative signature");
+        }
+
+        protected virtual void CheckSignature(IVerifierFactory verifier)
+        {
+            var tbsCertificate = c.TbsCertificate;
+
+            if (!IsAlgIDEqual(c.SignatureAlgorithm, tbsCertificate.Signature))
+                throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+
+            if (!X509Utilities.VerifySignature(verifier, tbsCertificate, c.Signature))
                 throw new InvalidKeyException("Public key presented not for certificate signature");
         }
 
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
index 81dd1c20e..1fc13a0a2 100644
--- a/crypto/src/x509/X509Crl.cs
+++ b/crypto/src/x509/X509Crl.cs
@@ -104,8 +104,7 @@ namespace Org.BouncyCastle.X509
 				:	null;
 		}
 
-		public virtual void Verify(
-			AsymmetricKeyParameter publicKey)
+		public virtual void Verify(AsymmetricKeyParameter publicKey)
 		{
             Verify(new Asn1VerifierFactoryProvider(publicKey));
 		}
@@ -116,26 +115,57 @@ namespace Org.BouncyCastle.X509
         /// <param name="verifierProvider">An appropriate provider for verifying the CRL's signature.</param>
         /// <returns>True if the signature is valid.</returns>
         /// <exception cref="Exception">If verifier provider is not appropriate or the CRL algorithm is invalid.</exception>
-        public virtual void Verify(
-            IVerifierFactoryProvider verifierProvider)
+        public virtual void Verify(IVerifierFactoryProvider verifierProvider)
         {
             CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm));
         }
 
-        protected virtual void CheckSignature(
-            IVerifierFactory verifier)
+        /// <summary>Verify the CRL's alternative signature using a verifier created using the passed in
+        /// verifier provider.</summary>
+        /// <param name="verifierProvider">An appropriate provider for verifying the CRL's alternative signature.
+		/// </param>
+        /// <exception cref="Exception">If verifier provider is not appropriate or the CRL alternative signature
+        /// algorithm is invalid.</exception>
+        public virtual void VerifyAltSignature(IVerifierFactoryProvider verifierProvider)
         {
-            // TODO Compare IsAlgIDEqual in X509Certificate.CheckSignature
-            if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
-                throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+            var tbsCertList = c.TbsCertList;
+            var extensions = tbsCertList.Extensions;
+
+            AltSignatureAlgorithm altSigAlg = AltSignatureAlgorithm.FromExtensions(extensions);
+            AltSignatureValue altSigValue = AltSignatureValue.FromExtensions(extensions);
+
+            var verifier = verifierProvider.CreateVerifierFactory(altSigAlg.Algorithm);
+
+			Asn1Sequence tbsSeq = Asn1Sequence.GetInstance(tbsCertList.ToAsn1Object());
+			Asn1EncodableVector v = new Asn1EncodableVector();
 
-            IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
-			using (var stream = streamCalculator.Stream)
+			int start = 1;    //  want to skip signature field
+			if (tbsSeq[0] is DerInteger derInteger)
+            {
+				v.Add(derInteger);
+				start++;
+			}
+
+			for (int i = start; i < tbsSeq.Count - 1; i++)
 			{
-				c.TbsCertList.EncodeTo(stream, Asn1Encodable.Der);
-            }
+				v.Add(tbsSeq[i]);
+			}
+
+            v.Add(X509Utilities.TrimExtensions(0, extensions));
+
+            if (!X509Utilities.VerifySignature(verifier, new DerSequence(v), altSigValue.Signature))
+                throw new InvalidKeyException("CRL alternative signature does not verify with supplied public key.");
+        }
+
+        protected virtual void CheckSignature(IVerifierFactory verifier)
+        {
+			var tbsCertList = c.TbsCertList;
+
+            // TODO Compare IsAlgIDEqual in X509Certificate.CheckSignature
+            if (!c.SignatureAlgorithm.Equals(tbsCertList.Signature))
+                throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
 
-            if (!streamCalculator.GetResult().IsVerified(GetSignature()))
+			if (!X509Utilities.VerifySignature(verifier, tbsCertList, c.Signature))
                 throw new InvalidKeyException("CRL does not verify with supplied public key.");
         }
 
diff --git a/crypto/src/x509/X509Utilities.cs b/crypto/src/x509/X509Utilities.cs
index 30ca0b080..bb9b7155f 100644
--- a/crypto/src/x509/X509Utilities.cs
+++ b/crypto/src/x509/X509Utilities.cs
@@ -9,6 +9,7 @@ using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.X509
@@ -159,5 +160,45 @@ namespace Org.BouncyCastle.X509
 		{
 			return CollectionUtilities.Proxy(m_algorithms.Keys);
 		}
-	}
+
+        internal static DerBitString GenerateSignature(ISignatureFactory signatureFactory, Asn1Encodable asn1Encodable)
+        {
+			var result = CalculateResult(signatureFactory.CreateCalculator(), asn1Encodable);
+            return new DerBitString(result.Collect());
+        }
+
+        internal static bool VerifySignature(IVerifierFactory verifierFactory, Asn1Encodable asn1Encodable,
+			DerBitString signature)
+        {
+            var result = CalculateResult(verifierFactory.CreateCalculator(), asn1Encodable);
+			return result.IsVerified(signature.GetOctets());
+        }
+
+        internal static Asn1TaggedObject TrimExtensions(int tagNo, X509Extensions exts)
+        {
+            Asn1Sequence extSeq = Asn1Sequence.GetInstance(exts.ToAsn1Object());
+            Asn1EncodableVector extV = new Asn1EncodableVector();
+			foreach (var extEntry in extSeq)
+			{
+				Asn1Sequence ext = Asn1Sequence.GetInstance(extEntry);
+
+                if (!X509Extensions.AltSignatureValue.Equals(ext[0]))
+                {
+                    extV.Add(ext);
+                }
+            }
+
+            return new DerTaggedObject(true, tagNo, new DerSequence(extV));
+        }
+
+		private static TResult CalculateResult<TResult>(IStreamCalculator<TResult> streamCalculator,
+			Asn1Encodable asn1Encodable)
+		{
+            using (var stream = streamCalculator.Stream)
+            {
+                asn1Encodable.EncodeTo(stream, Asn1Encodable.Der);
+            }
+            return streamCalculator.GetResult();
+        }
+    }
 }
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
index 836213fdc..963f1ea4f 100644
--- a/crypto/src/x509/X509V2AttributeCertificate.cs
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -161,8 +161,7 @@ namespace Org.BouncyCastle.X509
             return cert.GetSignatureOctets();
 		}
 
-        public virtual void Verify(
-            AsymmetricKeyParameter key)
+        public virtual void Verify(AsymmetricKeyParameter key)
         {
             CheckSignature(new Asn1VerifierFactory(cert.SignatureAlgorithm, key));
         }
@@ -173,34 +172,20 @@ namespace Org.BouncyCastle.X509
         /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
         /// <returns>True if the signature is valid.</returns>
         /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
-        public virtual void Verify(
-            IVerifierFactoryProvider verifierProvider)
+        public virtual void Verify(IVerifierFactoryProvider verifierProvider)
         {
             CheckSignature(verifierProvider.CreateVerifierFactory(cert.SignatureAlgorithm));
         }
 
-        protected virtual void CheckSignature(
-            IVerifierFactory verifier)
+        protected virtual void CheckSignature(IVerifierFactory verifier)
         {
+			var acInfo = cert.ACInfo;
+
             // TODO Compare IsAlgIDEqual in X509Certificate.CheckSignature
-            if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+            if (!cert.SignatureAlgorithm.Equals(acInfo.Signature))
 				throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
 
-            IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
-
-			try
-			{
-				using (var stream = streamCalculator.Stream)
-				{
-					cert.ACInfo.EncodeTo(stream);
-                }
-            }
-			catch (IOException e)
-			{
-				throw new SignatureException("Exception encoding certificate info object", e);
-			}
-
-			if (!streamCalculator.GetResult().IsVerified(GetSignature()))
+			if (!X509Utilities.VerifySignature(verifier, acInfo, cert.SignatureValue))
 				throw new InvalidKeyException("Public key presented not for certificate signature");
 		}
 
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
index f1f4c0473..bbb246273 100644
--- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -117,24 +117,17 @@ namespace Org.BouncyCastle.X509
 				acInfoGen.SetExtensions(extGenerator.Generate());
 			}
 
-            AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
+            var acInfo = acInfoGen.GenerateAttributeCertificateInfo();
 
-			IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (var sigStream = streamCalculator.Stream)
-			{
-				acInfo.EncodeTo(sigStream, Asn1Encodable.Der);
-			}
-
-			var signature = streamCalculator.GetResult().Collect();
+			var signature = X509Utilities.GenerateSignature(signatureFactory, acInfo);
 
-			return new X509V2AttributeCertificate(
-				new AttributeCertificate(acInfo, sigAlgID, new DerBitString(signature)));
+			return new X509V2AttributeCertificate(new AttributeCertificate(acInfo, sigAlgID, signature));
 		}
 
-		/// <summary>
-		/// Allows enumeration of the signature names supported by the generator.
-		/// </summary>
-		public IEnumerable<string> SignatureAlgNames
+        /// <summary>
+        /// Allows enumeration of the signature names supported by the generator.
+        /// </summary>
+        public IEnumerable<string> SignatureAlgNames
 		{
 			get { return X509Utilities.GetAlgNames(); }
 		}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
index d7c72d673..358dc63de 100644
--- a/crypto/src/x509/X509V2CRLGenerator.cs
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -217,18 +217,38 @@ namespace Org.BouncyCastle.X509
 				tbsGen.SetExtensions(extGenerator.Generate());
 			}
 
-			TbsCertificateList tbsCertList = tbsGen.GenerateTbsCertList();
+			var tbsCertList = tbsGen.GenerateTbsCertList();
 
-            IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (var sigStream = streamCalculator.Stream)
-			{
-				tbsCertList.EncodeTo(sigStream, Asn1Encodable.Der);
-			}
+			var signature = X509Utilities.GenerateSignature(signatureFactory, tbsCertList);
+
+			return new X509Crl(CertificateList.GetInstance(new DerSequence(tbsCertList, sigAlgID, signature)));
+		}
+
+        /// <summary>
+        /// Generate a new <see cref="X509Crl"/> using the provided <see cref="ISignatureFactory"/> and
+        /// containing altSignatureAlgorithm and altSignatureValue extensions based on the passed
+        /// <paramref name="altSignatureFactory"/>.
+        /// </summary>
+        /// <param name="signatureFactory">A <see cref="ISignatureFactory">signature factory</see> with the necessary
+        /// algorithm details.</param>
+        /// <param name="isCritical">Whether the 'alt' extensions should be marked critical.</param>
+        /// <param name="altSignatureFactory">A <see cref="ISignatureFactory">signature factory</see> used to create the
+        /// altSignatureAlgorithm and altSignatureValue extensions.</param>
+        /// <returns>An <see cref="X509Certificate"/>.</returns>
+        public X509Crl Generate(ISignatureFactory signatureFactory, bool isCritical,
+            ISignatureFactory altSignatureFactory)
+		{
+            tbsGen.SetSignature(null);
+
+            var altSigAlgID = (AlgorithmIdentifier)altSignatureFactory.AlgorithmDetails;
+            extGenerator.AddExtension(X509Extensions.AltSignatureAlgorithm, isCritical, altSigAlgID);
+
+            tbsGen.SetExtensions(extGenerator.Generate());
 
-			var signature = streamCalculator.GetResult().Collect();
+            var altSignature = X509Utilities.GenerateSignature(altSignatureFactory, tbsGen.GeneratePreTbsCertList());
+            extGenerator.AddExtension(X509Extensions.AltSignatureValue, isCritical, altSignature);
 
-			return new X509Crl(
-				CertificateList.GetInstance(new DerSequence(tbsCertList, sigAlgID, new DerBitString(signature))));
+            return Generate(signatureFactory);
 		}
 
 		/// <summary>
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
index d5c9ffe92..65e3c9177 100644
--- a/crypto/src/x509/X509V3CertificateGenerator.cs
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -290,17 +290,38 @@ namespace Org.BouncyCastle.X509
                 tbsGen.SetExtensions(extGenerator.Generate());
             }
 
-            TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+            var tbsCertificate = tbsGen.GenerateTbsCertificate();
 
-			IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (var sigStream = streamCalculator.Stream)
-            {
-				tbsCert.EncodeTo(sigStream, Asn1Encodable.Der);
-			}
+			var signature = X509Utilities.GenerateSignature(signatureFactory, tbsCertificate);
+
+			return new X509Certificate(new X509CertificateStructure(tbsCertificate, sigAlgID, signature));
+        }
+
+        /// <summary>
+        /// Generate a new <see cref="X509Certificate"/> using the provided <see cref="ISignatureFactory"/> and
+        /// containing altSignatureAlgorithm and altSignatureValue extensions based on the passed
+        /// <paramref name="altSignatureFactory"/>.
+        /// </summary>
+        /// <param name="signatureFactory">A <see cref="ISignatureFactory">signature factory</see> with the necessary
+        /// algorithm details.</param>
+		/// <param name="isCritical">Whether the 'alt' extensions should be marked critical.</param>
+        /// <param name="altSignatureFactory">A <see cref="ISignatureFactory">signature factory</see> used to create the
+		/// altSignatureAlgorithm and altSignatureValue extensions.</param>
+        /// <returns>An <see cref="X509Certificate"/>.</returns>
+        public X509Certificate Generate(ISignatureFactory signatureFactory, bool isCritical,
+			ISignatureFactory altSignatureFactory)
+		{
+            tbsGen.SetSignature(null);
+
+            var altSigAlgID = (AlgorithmIdentifier)altSignatureFactory.AlgorithmDetails;
+			extGenerator.AddExtension(X509Extensions.AltSignatureAlgorithm, isCritical, altSigAlgID);
+
+            tbsGen.SetExtensions(extGenerator.Generate());
 
-			var signature = streamCalculator.GetResult().Collect();
+			var altSignature = X509Utilities.GenerateSignature(altSignatureFactory, tbsGen.GeneratePreTbsCertificate());
+			extGenerator.AddExtension(X509Extensions.AltSignatureValue, isCritical, altSignature);
 
-			return new X509Certificate(new X509CertificateStructure(tbsCert, sigAlgID, new DerBitString(signature)));
+			return Generate(signatureFactory);
 		}
 
 		/// <summary>