diff --git a/Server/src/main/java/org/openas2/lib/helper/BCCryptoHelper.java b/Server/src/main/java/org/openas2/lib/helper/BCCryptoHelper.java index be8a3bf31..317560982 100644 --- a/Server/src/main/java/org/openas2/lib/helper/BCCryptoHelper.java +++ b/Server/src/main/java/org/openas2/lib/helper/BCCryptoHelper.java @@ -12,20 +12,18 @@ import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cms.*; -import org.bouncycastle.cms.bc.BcRSAKeyTransEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; import org.bouncycastle.cms.jcajce.JceKeyAgreeEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator; +import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; import org.bouncycastle.cms.jcajce.ZlibCompressor; import org.bouncycastle.cms.jcajce.ZlibExpanderProvider; -import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.mail.smime.SMIMECompressed; import org.bouncycastle.mail.smime.SMIMECompressedGenerator; @@ -238,9 +236,11 @@ public MimeBodyPart decrypt(MimeBodyPart part, Certificate receiverCert, Key rec KeyTransRecipientId certRecId = new KeyTransRecipientId(x500Name, x509Cert.getSerialNumber()); if (certRecId.match(recipientInfo) && !foundRecipient) { foundRecipient = true; + // The JCE recipient honours the key-encryption algorithm in the envelope + // (RSA PKCS#1 v1.5 or RSAES-OAEP); the lightweight BcRSAKeyTransEnvelopedRecipient + // always unwraps with PKCS#1 v1.5, so an OAEP-wrapped key fails with "block incorrect". byte[] decryptedData = recipientInfo.getContent( - new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey( - PrivateKeyInfo.getInstance(receiverKey.getEncoded()))) + new JceKeyTransEnvelopedRecipient((PrivateKey) receiverKey).setProvider("BC") ); return SMIMEUtil.toMimeBodyPart(decryptedData); } diff --git a/Server/src/test/java/org/openas2/lib/helper/KeyTransportDecryptionTest.java b/Server/src/test/java/org/openas2/lib/helper/KeyTransportDecryptionTest.java new file mode 100644 index 000000000..b69b630d4 --- /dev/null +++ b/Server/src/test/java/org/openas2/lib/helper/KeyTransportDecryptionTest.java @@ -0,0 +1,102 @@ +package org.openas2.lib.helper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.cert.X509Certificate; +import java.security.spec.MGF1ParameterSpec; +import java.util.Date; + +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; + +import jakarta.mail.internet.MimeBodyPart; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.cms.CMSAlgorithm; +import org.bouncycastle.cms.RecipientInfoGenerator; +import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; +import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; +import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator; +import org.bouncycastle.operator.jcajce.JcaAlgorithmParametersConverter; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.openas2.util.AS2Util; + +/** + * Verifies that an inbound message decrypts whichever RSA key transport the sender wrapped its content key with. + *
+ * PKCS#1 v1.5 is what OpenAS2 itself sends, but RSAES-OAEP is what others send by default: Microsoft BizTalk is
+ * one. The algorithm is named in the envelope's recipient info, so decryption has to honour it rather than
+ * assume PKCS#1 v1.5, which fails an OAEP-wrapped key with "block incorrect".
+ */
+public class KeyTransportDecryptionTest {
+
+ private static final String PAYLOAD = "