summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-01-12 18:15:17 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-01-12 18:15:17 +0700
commit515f53364796324fc2b024e1ccab9b5adc4bcd7b (patch)
treed68c43f121785e680101c11f55ee9d1cb53b4d87
parentRefactoring around ParametersWithRandom (diff)
downloadBouncyCastle.NET-ed25519-515f53364796324fc2b024e1ccab9b5adc4bcd7b.tar.xz
Improvements to EdDSA use cases
- see https://github.com/bcgit/bc-csharp/issues/406
-rw-r--r--crypto/src/cms/CMSSignedDataStreamGenerator.cs20
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs4
-rw-r--r--crypto/src/ocsp/OCSPReqGenerator.cs54
-rw-r--r--crypto/src/openpgp/PgpSignatureGenerator.cs24
-rw-r--r--crypto/src/openpgp/PgpV3SignatureGenerator.cs23
-rw-r--r--crypto/src/security/SignerUtilities.cs121
6 files changed, 144 insertions, 102 deletions
diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
index 33b661761..48abfbfa2 100644
--- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -102,18 +102,18 @@ namespace Org.BouncyCastle.Cms
 
 				if (_sAttr != null)
 				{
-            		_sig = Helper.GetSignatureInstance(signatureName);
-				}
-				else
+                    _sig = SignerUtilities.InitSigner(signatureName, true, key, outer.m_random);
+                }
+                else
 				{
 					// Note: Need to use raw signatures here since we have already calculated the digest
 					if (_encName.Equals("RSA"))
 					{
-						_sig = Helper.GetSignatureInstance("RSA");
-					}
-					else if (_encName.Equals("DSA"))
+                        _sig = SignerUtilities.InitSigner("RSA", true, key, outer.m_random);
+                    }
+                    else if (_encName.Equals("DSA"))
 					{
-						_sig = Helper.GetSignatureInstance("NONEwithDSA");
+                        _sig = SignerUtilities.InitSigner("NONEwithDSA", true, key, outer.m_random);
 					}
 					// TODO Add support for raw PSS
 //					else if (_encName.equals("RSAandMGF1"))
@@ -135,10 +135,8 @@ namespace Org.BouncyCastle.Cms
 					{
 						throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
 					}
-				}
-
-				_sig.Init(true, new ParametersWithRandom(key, outer.m_random));
-			}
+                }
+            }
 
 			public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
         		byte[] calculatedDigest)
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
index ea8d28771..acbeb12e8 100644
--- a/crypto/src/crypto/operators/Asn1Signature.cs
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
@@ -97,6 +98,9 @@ namespace Org.BouncyCastle.Crypto.Operators
             m_algorithms.Add("GOST3411-2012-256WITHECGOST3410-2012-256", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256);
             m_algorithms.Add("GOST3411-2012-512WITHECGOST3410", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
             m_algorithms.Add("GOST3411-2012-512WITHECGOST3410-2012-512", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
+            m_algorithms.Add("Ed25519", EdECObjectIdentifiers.id_Ed25519);
+            m_algorithms.Add("Ed448", EdECObjectIdentifiers.id_Ed448);
+            // TODO Ed25519ctx, Ed25519ph, Ed448ph
 
             //
             // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
diff --git a/crypto/src/ocsp/OCSPReqGenerator.cs b/crypto/src/ocsp/OCSPReqGenerator.cs
index dda1625e5..9a5d72ae8 100644
--- a/crypto/src/ocsp/OCSPReqGenerator.cs
+++ b/crypto/src/ocsp/OCSPReqGenerator.cs
@@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Ocsp;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
@@ -93,13 +94,10 @@ namespace Org.BouncyCastle.Ocsp
 			this.requestExtensions = requestExtensions;
 		}
 
-		private OcspReq GenerateRequest(
-			DerObjectIdentifier		signingAlgorithm,
-			AsymmetricKeyParameter	privateKey,
-			X509Certificate[]		chain,
-			SecureRandom			random)
+		private OcspReq GenerateRequest(DerObjectIdentifier signingAlgorithm, AsymmetricKeyParameter privateKey,
+			X509Certificate[] chain, SecureRandom random)
 		{
-			Asn1EncodableVector requests = new Asn1EncodableVector();
+			Asn1EncodableVector requests = new Asn1EncodableVector(list.Count);
 
 			foreach (RequestObject reqObj in list)
 			{
@@ -114,42 +112,29 @@ namespace Org.BouncyCastle.Ocsp
 			}
 
 			TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions);
-
-			ISigner sig = null;
 			Signature signature = null;
 
 			if (signingAlgorithm != null)
 			{
 				if (requestorName == null)
-				{
 					throw new OcspException("requestorName must be specified if request is signed.");
-				}
 
-				try
-				{
-					sig = SignerUtilities.GetSigner(signingAlgorithm.Id);
-					if (random != null)
-					{
-						sig.Init(true, new ParametersWithRandom(privateKey, random));
-					}
-					else
-					{
-						sig.Init(true, privateKey);
-					}
+                ISigner signer;
+                try
+                {
+					signer = SignerUtilities.InitSigner(signingAlgorithm, true, privateKey, random);
 				}
 				catch (Exception e)
 				{
 					throw new OcspException("exception creating signature: " + e, e);
 				}
 
-				DerBitString bitSig = null;
-
+				DerBitString bitSig;
 				try
 				{
-					byte[] encoded = tbsReq.GetEncoded();
-					sig.BlockUpdate(encoded, 0, encoded.Length);
+					tbsReq.EncodeTo(new SignerSink(signer), Asn1Encodable.Der);
 
-					bitSig = new DerBitString(sig.GenerateSignature());
+					bitSig = new DerBitString(signer.GenerateSignature());
 				}
 				catch (Exception e)
 				{
@@ -158,9 +143,10 @@ namespace Org.BouncyCastle.Ocsp
 
 				AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance);
 
-				if (chain != null && chain.Length > 0)
+				Asn1Sequence certs = null;
+				if (!Arrays.IsNullOrEmpty(chain))
 				{
-					Asn1EncodableVector v = new Asn1EncodableVector();
+					Asn1EncodableVector v = new Asn1EncodableVector(chain.Length);
 					try
 					{
 						for (int i = 0; i != chain.Length; i++)
@@ -177,15 +163,13 @@ namespace Org.BouncyCastle.Ocsp
 						throw new OcspException("error encoding certs", e);
 					}
 
-					signature = new Signature(sigAlgId, bitSig, new DerSequence(v));
+					certs = new DerSequence(v);
 				}
-				else
-				{
-					signature = new Signature(sigAlgId, bitSig);
-				}
-			}
 
-			return new OcspReq(new OcspRequest(tbsReq, signature));
+                signature = new Signature(sigAlgId, bitSig, certs);
+            }
+
+            return new OcspReq(new OcspRequest(tbsReq, signature));
 		}
 
 		/**
diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs
index 12edf9f89..64d256653 100644
--- a/crypto/src/openpgp/PgpSignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -40,36 +40,34 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
-        public void InitSign(
-            int				sigType,
-            PgpPrivateKey	privKey)
+        public void InitSign(int sigType, PgpPrivateKey privKey)
         {
 			InitSign(sigType, privKey, null);
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
-		public void InitSign(
-			int				sigType,
-			PgpPrivateKey privKey,
-			SecureRandom	random)
+		public void InitSign(int sigType, PgpPrivateKey privKey, SecureRandom random)
 		{
 			this.privKey = privKey;
 			this.signatureType = sigType;
 
 			AsymmetricKeyParameter key = privKey.Key;
 
-			if (sig == null)
-			{
-                this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
-            }
+            this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
 
             try
 			{
 				ICipherParameters cp = key;
-				if (random != null)
+
+				// TODO Ask SignerUtilities whether random is permitted?
+				if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
 				{
-					cp = new ParametersWithRandom(cp, random);
+					// EdDSA signers don't expect a SecureRandom
 				}
+				else
+				{
+                    cp = ParameterUtilities.WithRandom(cp, random);
+                }
 
 				sig.Init(true, cp);
 			}
diff --git a/crypto/src/openpgp/PgpV3SignatureGenerator.cs b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
index 324dbd768..03dd8795d 100644
--- a/crypto/src/openpgp/PgpV3SignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
@@ -47,20 +47,23 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
             AsymmetricKeyParameter key = privKey.Key;
 
-            if (sig == null)
-            {
-                this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
-            }
+            this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
 
             try
             {
-				ICipherParameters cp = key;
-				if (random != null)
-				{
-					cp = new ParametersWithRandom(cp, random);
-				}
+                ICipherParameters cp = key;
+
+                // TODO Ask SignerUtilities whether random is permitted?
+                if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
+                {
+                    // EdDSA signers don't expect a SecureRandom
+                }
+                else
+                {
+                    cp = ParameterUtilities.WithRandom(cp, random);
+                }
 
-				sig.Init(true, cp);
+                sig.Init(true, cp);
             }
             catch (InvalidKeyException e)
             {
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 6500cdf13..917759a8e 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -10,16 +10,16 @@ using Org.BouncyCastle.Asn1.GM;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
-using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Signers;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
-using Org.BouncyCastle.Asn1.Rosstandart;
 
 namespace Org.BouncyCastle.Security
 {
@@ -28,9 +28,10 @@ namespace Org.BouncyCastle.Security
     /// </summary>
     public static class SignerUtilities
     {
-        internal static readonly IDictionary<string, string> AlgorithmMap =
+        private static readonly IDictionary<string, string> AlgorithmMap =
             new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        internal static readonly IDictionary<string, DerObjectIdentifier> Oids =
+        private static readonly HashSet<string> NoRandom = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+        private static readonly IDictionary<string, DerObjectIdentifier> Oids =
             new Dictionary<string, DerObjectIdentifier>(StringComparer.OrdinalIgnoreCase);
 
         static SignerUtilities()
@@ -408,6 +409,14 @@ namespace Org.BouncyCastle.Security
             AlgorithmMap["SM3WITHSM2"] = "SM3withSM2";
             AlgorithmMap[GMObjectIdentifiers.sm2sign_with_sm3.Id] = "SM3withSM2";
 
+            NoRandom.Add("Ed25519");
+            NoRandom.Add(EdECObjectIdentifiers.id_Ed25519.Id);
+            NoRandom.Add("Ed25519ctx");
+            NoRandom.Add("Ed25519ph");
+            NoRandom.Add("Ed448");
+            NoRandom.Add(EdECObjectIdentifiers.id_Ed448.Id);
+            NoRandom.Add("Ed448ph");
+
             Oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
             Oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
             Oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
@@ -519,6 +528,11 @@ namespace Org.BouncyCastle.Security
             return DerNull.Instance;
         }
 
+        private static string GetMechanism(string algorithm)
+        {
+            return AlgorithmMap.TryGetValue(algorithm, out var v) ? v : algorithm.ToUpperInvariant();
+        }
+
         private static Asn1Encodable GetPssX509Parameters(
             string	digestName)
         {
@@ -536,6 +550,9 @@ namespace Org.BouncyCastle.Security
 
         public static ISigner GetSigner(DerObjectIdentifier id)
         {
+            if (id == null)
+                throw new ArgumentNullException(nameof(id));
+
             return GetSigner(id.Id);
         }
 
@@ -544,8 +561,17 @@ namespace Org.BouncyCastle.Security
             if (algorithm == null)
                 throw new ArgumentNullException(nameof(algorithm));
 
-            string mechanism = CollectionUtilities.GetValueOrKey(AlgorithmMap, algorithm.ToUpperInvariant());
+            string mechanism = GetMechanism(algorithm);
+
+            var signer = GetSignerForMechanism(mechanism);
+            if (signer == null)
+                throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+
+            return signer;
+        }
 
+        private static ISigner GetSignerForMechanism(string mechanism)
+        {
             if (Platform.StartsWith(mechanism, "Ed"))
             {
                 if (mechanism.Equals("Ed25519"))
@@ -638,30 +664,37 @@ namespace Org.BouncyCastle.Security
             {
                 return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
             }
-            if (mechanism.Equals("ECGOST3410"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
-            }
-            if (mechanism.Equals("ECGOST3410-2012-256"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_256Digest());
-            }
-            if (mechanism.Equals("ECGOST3410-2012-512"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_512Digest());
-            }
 
-            if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
-            {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
-            }
-            if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+            if (Platform.StartsWith(mechanism, "ECGOST3410"))
             {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+                if (mechanism.Equals("ECGOST3410"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+                }
+                if (mechanism.Equals("ECGOST3410-2012-256"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_256Digest());
+                }
+                if (mechanism.Equals("ECGOST3410-2012-512"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_512Digest());
+                }
             }
-            if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+
+            if (Platform.EndsWith(mechanism, "/ISO9796-2"))
             {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+                if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+                }
+                if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+                }
+                if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+                }
             }
 
             if (Platform.EndsWith(mechanism, "/X9.31"))
@@ -672,19 +705,20 @@ namespace Org.BouncyCastle.Security
                 {
                     int endPos = withPos + "WITH".Length;
 
-                    string digestName = x931.Substring(0, withPos);
-                    IDigest digest = DigestUtilities.GetDigest(digestName);
-
                     string cipherName = x931.Substring(endPos, x931.Length - endPos);
                     if (cipherName.Equals("RSA"))
                     {
                         IAsymmetricBlockCipher cipher = new RsaBlindedEngine();
+
+                        string digestName = x931.Substring(0, withPos);
+                        IDigest digest = DigestUtilities.GetDigest(digestName);
+
                         return new X931Signer(cipher, digest);
                     }
                 }
             }
 
-            throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+            return null;
         }
 
         public static string GetEncodingName(DerObjectIdentifier oid)
@@ -692,15 +726,36 @@ namespace Org.BouncyCastle.Security
             return CollectionUtilities.GetValueOrNull(AlgorithmMap, oid.Id);
         }
 
-        public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random)
+        // TODO Rename 'privateKey' to 'key'
+        public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigning,
+            AsymmetricKeyParameter privateKey, SecureRandom random)
         {
+            if (algorithmOid == null)
+                throw new ArgumentNullException(nameof(algorithmOid));
+
             return InitSigner(algorithmOid.Id, forSigning, privateKey, random);
         }
 
-        public static ISigner InitSigner(string algorithm, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random)
+        // TODO Rename 'privateKey' to 'key'
+        public static ISigner InitSigner(string algorithm, bool forSigning, AsymmetricKeyParameter privateKey,
+            SecureRandom random)
         {
-            ISigner signer = GetSigner(algorithm);
-            signer.Init(forSigning, ParameterUtilities.WithRandom(privateKey, random));
+            if (algorithm == null)
+                throw new ArgumentNullException(nameof(algorithm));
+
+            string mechanism = GetMechanism(algorithm);
+
+            var signer = GetSignerForMechanism(mechanism);
+            if (signer == null)
+                throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+
+            ICipherParameters cipherParameters = privateKey;
+            if (forSigning && !NoRandom.Contains(mechanism))
+            {
+                cipherParameters = ParameterUtilities.WithRandom(cipherParameters, random);
+            }
+
+            signer.Init(forSigning, cipherParameters);
             return signer;
         }
     }