summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexander Scheel <alexander.scheel@keyfactor.com>2024-02-14 09:33:03 -0500
committerAlexander Scheel <alexander.scheel@keyfactor.com>2024-02-14 10:22:16 -0500
commit89e04f3a8b0cfbadd8ff1cca8de77c6393ebfdb6 (patch)
tree24e41b35c011ba105b0a7ea6c7bb5ee23358e9ca
parentRefactoring in Pqc.Crypto.Utilities (diff)
downloadBouncyCastle.NET-ed25519-89e04f3a8b0cfbadd8ff1cca8de77c6393ebfdb6.tar.xz
Add explicit algorithm parameter in AddKeyTransRecipient
This allows callers to select between OAEP and PKCS#1v1.5 independent
of the underlying certificate OID. In some instances, callers may wish
to use OAEP for transport (e.g., due to FIPS sunset) with PKCS#1v1.5
OID certificates for compatibility.

Note that Asn1KeyWrapper involves /NONE/ in the parameter name
(whereas some other places reference it with just //).

Signed-off-by: Alexander Scheel <alexander.scheel@keyfactor.com>
-rw-r--r--crypto/src/cms/CMSEnvelopedGenerator.cs30
-rw-r--r--crypto/src/crypto/operators/Asn1KeyWrapper.cs7
-rw-r--r--crypto/test/src/cms/test/AuthenticatedDataTest.cs35
3 files changed, 69 insertions, 3 deletions
diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs
index 89a7f4576..a0c73be67 100644
--- a/crypto/src/cms/CMSEnvelopedGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -156,7 +156,20 @@ namespace Org.BouncyCastle.Cms
 		{
 			var algorithm = cert.SubjectPublicKeyInfo.Algorithm;
 			var keyWrapper = new Asn1KeyWrapper(algorithm, cert);
-            AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(cert, keyWrapper));
+			AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(cert, keyWrapper));
+		}
+
+		/**
+		 * add a recipient.
+		 *
+		 * @param algorithm to override automatic selection (useful for OAEP with PKCS#1v1.5 certs)
+		 * @param cert recipient's public key certificate
+		 * @exception ArgumentException if there is a problem with the certificate
+		 */
+		public void AddKeyTransRecipient(string algorithm, X509Certificate cert)
+		{
+			var keyWrapper = new Asn1KeyWrapper(algorithm, cert);
+			AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(cert, keyWrapper));
 		}
 
 		/**
@@ -174,6 +187,21 @@ namespace Org.BouncyCastle.Cms
 		}
 
 		/**
+		* add a recipient
+		*
+		* @param algorithm to override automatic selection (useful for OAEP with PKCS#1v1.5 certs)
+		* @param key the public key used by the recipient
+		* @param subKeyId the identifier for the recipient's public key
+		* @exception ArgumentException if there is a problem with the key
+		*/
+		public void AddKeyTransRecipient(string algorithm, AsymmetricKeyParameter pubKey, byte[] subKeyId)
+		{
+			SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+			AddRecipientInfoGenerator(
+				new KeyTransRecipientInfoGenerator(subKeyId, new Asn1KeyWrapper(algorithm, pubKey)));
+		}
+
+		/**
 		 * add a KEK recipient.
 		 * @param key the secret key to use for wrapping
 		 * @param keyIdentifier the byte string that identifies the key
diff --git a/crypto/src/crypto/operators/Asn1KeyWrapper.cs b/crypto/src/crypto/operators/Asn1KeyWrapper.cs
index 440c1502a..0049d153f 100644
--- a/crypto/src/crypto/operators/Asn1KeyWrapper.cs
+++ b/crypto/src/crypto/operators/Asn1KeyWrapper.cs
@@ -20,9 +20,14 @@ namespace Org.BouncyCastle.Crypto.Operators
         private IKeyWrapper wrapper;
 
         public Asn1KeyWrapper(string algorithm, X509Certificate cert)
+             : this(algorithm, cert.GetPublicKey())
+        {
+        }
+
+        public Asn1KeyWrapper(string algorithm, ICipherParameters key)
         {
             this.algorithm = algorithm;
-            wrapper = KeyWrapperUtil.WrapperForName(algorithm, cert.GetPublicKey());
+            wrapper = KeyWrapperUtil.WrapperForName(algorithm, key);
         }
 
         public Asn1KeyWrapper(DerObjectIdentifier algorithm, X509Certificate cert)
diff --git a/crypto/test/src/cms/test/AuthenticatedDataTest.cs b/crypto/test/src/cms/test/AuthenticatedDataTest.cs
index f1e7103b2..e9364d3aa 100644
--- a/crypto/test/src/cms/test/AuthenticatedDataTest.cs
+++ b/crypto/test/src/cms/test/AuthenticatedDataTest.cs
@@ -135,6 +135,7 @@ namespace Org.BouncyCastle.Cms.Tests
 		public void TestKeyTransDESede()
 		{
 			tryKeyTrans(CmsAuthenticatedDataGenerator.DesEde3Cbc);
+			tryKeyTransWithOaepOverride(CmsAuthenticatedDataGenerator.DesEde3Cbc);
 		}
 		
 		[Test]
@@ -243,7 +244,39 @@ namespace Org.BouncyCastle.Cms.Tests
 				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
 			}
 		}
-		
+
+		private void tryKeyTransWithOaepOverride(string macAlg)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			adGen.AddKeyTransRecipient("RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING", ReciCert);
+
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				macAlg);
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(ad.MacAlgOid, macAlg);
+
+			var c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.IdRsaesOaep.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+
+
 		private void tryKekAlgorithm(KeyParameter kek, DerObjectIdentifier algOid)
 		{
 			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");