From 89e04f3a8b0cfbadd8ff1cca8de77c6393ebfdb6 Mon Sep 17 00:00:00 2001 From: Alexander Scheel Date: Wed, 14 Feb 2024 09:33:03 -0500 Subject: 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 --- crypto/src/cms/CMSEnvelopedGenerator.cs | 30 ++++++++++++++++++- crypto/src/crypto/operators/Asn1KeyWrapper.cs | 7 ++++- crypto/test/src/cms/test/AuthenticatedDataTest.cs | 35 ++++++++++++++++++++++- 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)); } /** @@ -173,6 +186,21 @@ namespace Org.BouncyCastle.Cms new KeyTransRecipientInfoGenerator(subKeyId, new Asn1KeyWrapper(info.Algorithm, pubKey))); } + /** + * 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 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"); -- cgit 1.4.1