From b0f93773189c0330320b3d3fa91f2825d619eebd Mon Sep 17 00:00:00 2001 From: Kevin Hwang Date: Mon, 2 Oct 2023 11:43:19 -0700 Subject: [PATCH] CMS: Add support for sha-1WithRSAEncryption and other (aliases) digest algorithm. Per RFC 3279 / RFC 8017, this digest algorithm computes the SHA-1 digest on the encoded `DigestInfo` whose `digestAlgorithm` is set to the `id-sha1` OID. --- .../bouncycastle/cms/SignerInformation.java | 24 ++++++- .../cms/test/NewSignedDataTest.java | 71 +++++++++++++------ .../jcajce/util/MessageDigestUtils.java | 4 ++ 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java index 59d4054eb2..90d0a1dc8a 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java +++ b/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java @@ -6,6 +6,8 @@ import java.util.Enumeration; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.HashMap; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; @@ -24,6 +26,7 @@ import org.bouncycastle.asn1.cms.SignerIdentifier; import org.bouncycastle.asn1.cms.SignerInfo; import org.bouncycastle.asn1.cms.Time; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DigestInfo; import org.bouncycastle.cert.X509CertificateHolder; @@ -39,6 +42,14 @@ */ public class SignerInformation { + private static final Map digestOidMap = new HashMap<>(); + + static { + // sha-1WithRSAEncryption (RFC 3279 2.2.1) + digestOidMap.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1); + // sha-1WithRSASignature (RFC 8017 A.2.4) + digestOidMap.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), OIWObjectIdentifiers.idSHA1); + } private final SignerId sid; private final CMSProcessable content; private final byte[] signature; @@ -460,7 +471,7 @@ else if (signedAttributeSet != null) if (encName.equals("RSA")) { - DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digestAlgorithm.getAlgorithm(), DERNull.INSTANCE), resultDigest); + DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digestAlgorithmForDigestInfoDataEncoding(), DERNull.INSTANCE), resultDigest); return rawVerifier.verify(digInfo.getEncoded(ASN1Encoding.DER), this.getSignature()); } @@ -477,6 +488,17 @@ else if (signedAttributeSet != null) } } + /** + * Computes the `digestAlgorithm (DigestAlgorithmIdentifier)` field of the `DigestInfo` as specified in + * RFC 2313 10.1.2. + * This pertains to the digest algorithm, not signature algorithm. + */ + private ASN1ObjectIdentifier digestAlgorithmForDigestInfoDataEncoding() { + ASN1ObjectIdentifier originalAlgorithm = digestAlgorithm.getAlgorithm(); + ASN1ObjectIdentifier digestAlgorithmForDataEncoding = digestOidMap.get(originalAlgorithm); + return digestAlgorithmForDataEncoding != null ? digestAlgorithmForDataEncoding : originalAlgorithm; + } + /** * RFC 3852 11.1 Check the content-type attribute is correct * diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java index 009e0618ea..f9c24ed206 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java @@ -18,6 +18,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import junit.framework.Assert; @@ -1590,70 +1591,86 @@ public void testSHA3_384WithRSAPSS() rsaPSSTest("SHA3-384withRSAandMGF1"); } - public void testSHA1WithRSADigest() + public void testSHA1WithRSASignature() throws Exception { - rsaDigestTest("SHA1withRSA"); + rsaSignatureTest("SHA1withRSA"); } - public void testSHA224WithRSADigest() + public void testSHA256WithRSASignatureAndSHA1WithRSAEncryptionDigest() + throws Exception + { + rsaSignatureAndDigestTest("SHA256withRSA", + // sha-1WithRSAEncryption (RFC 3279 2.2.1) + Optional.of(new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.29")))); + } + + public void testSHA256WithRSASignatureAndSHA1WithRSASignatureDigest() + throws Exception + { + rsaSignatureAndDigestTest("SHA256withRSA", + // sha-1WithRSASignature (RFC 8017 A.2.4) + Optional.of(new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")))); + } + + public void testSHA224WithRSASignature() throws Exception { - rsaDigestTest("SHA224withRSA"); + rsaSignatureTest("SHA224withRSA"); } - public void testSHA256WithRSADigest() + public void testSHA256WithRSASignature() throws Exception { - rsaDigestTest("SHA256withRSA"); + rsaSignatureTest("SHA256withRSA"); } - public void testSHA384WithRSADigest() + public void testSHA384WithRSASignature() throws Exception { - rsaDigestTest("SHA384withRSA"); + rsaSignatureTest("SHA384withRSA"); } - public void testSHA512WithRSADigest() + public void testSHA512WithRSASignature() throws Exception { - rsaDigestTest("SHA512withRSA"); + rsaSignatureTest("SHA512withRSA"); } - public void testSHA3_224WithRSADigest() + public void testSHA3_224WithRSASignature() throws Exception { - rsaDigestTest("SHA3-224withRSA"); + rsaSignatureTest("SHA3-224withRSA"); } - public void testSHA3_256WithRSADigest() + public void testSHA3_256WithRSASignature() throws Exception { - rsaDigestTest("SHA3-256withRSA"); + rsaSignatureTest("SHA3-256withRSA"); } - public void testSHA3_384WithRSADigest() + public void testSHA3_384WithRSASignature() throws Exception { - rsaDigestTest("SHA3-384withRSA"); + rsaSignatureTest("SHA3-384withRSA"); } - public void testSHA3_512WithRSADigest() + public void testSHA3_512WithRSASignature() throws Exception { - rsaDigestTest("SHA3-512withRSA"); + rsaSignatureTest("SHA3-512withRSA"); } - public void testSHA512_224ithRSADigest() + public void testSHA512_224ithRSASignature() throws Exception { - rsaDigestTest("SHA512(224)withRSA"); + rsaSignatureTest("SHA512(224)withRSA"); } - public void testSHA512_256ithRSADigest() + public void testSHA512_256ithRSASignature() throws Exception { - rsaDigestTest("SHA512(256)withRSA"); + rsaSignatureTest("SHA512(256)withRSA"); } public void testEd25519() @@ -2174,8 +2191,14 @@ private void rsaPSSTest(String signatureAlgorithmName) verifySignatures(s, md.digest("Hello world!".getBytes())); } - private void rsaDigestTest(String signatureAlgorithmName) + private void rsaSignatureTest(String signatureAlgorithmName) throws Exception + { + rsaSignatureAndDigestTest(signatureAlgorithmName, Optional.empty()); + } + + private void rsaSignatureAndDigestTest(String signatureAlgorithmName, Optional digestAlgorithm) + throws Exception { List certList = new ArrayList(); CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes()); @@ -2193,6 +2216,8 @@ private void rsaDigestTest(String signatureAlgorithmName) gen.addSignerInfoGenerator(siBuilder.build(contentSigner, _origCert)); + digestAlgorithm.ifPresent(siBuilder::setContentDigest); + gen.addCertificates(certs); CMSSignedData s = gen.generate(msg, false); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java index 9ca15cffdc..3a75a3112a 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java @@ -49,6 +49,10 @@ public class MessageDigestUtils digestOidMap.put(NISTObjectIdentifiers.id_shake256, "SHAKE256"); digestOidMap.put(GMObjectIdentifiers.sm3, "SM3"); digestOidMap.put(MiscObjectIdentifiers.blake3_256, "BLAKE3-256"); + // sha-1WithRSAEncryption (RFC 3279 2.2.1) + digestOidMap.put(OIWObjectIdentifiers.sha1WithRSA, "SHA-1"); + // sha-1WithRSASignature (RFC 8017 A.2.4) + digestOidMap.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA-1"); digestAlgIdMap.put("SHA-1", new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)); digestAlgIdMap.put("SHA-224", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224));