From 6c5680a5710f98575928a055418d1cfbc52aaf97 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 14:52:55 -0600 Subject: [PATCH 01/10] F-9317: remove stale MGF parameter fallback comment in PSS validation --- src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java index 2a806a9b..54f6955a 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java @@ -1249,7 +1249,6 @@ public class WolfCryptSignature extends SignatureSpi { /* Validate spec type and MGF1 inner digest */ AlgorithmParameterSpec mgfParams = pss.getMGFParameters(); if (mgfParams != null) { - /* Different spec type silently falls back to the default digest */ if (!(mgfParams instanceof MGF1ParameterSpec)) { throw new InvalidAlgorithmParameterException( "MGF1 parameters must be of type MGF1ParameterSpec, got " + From 43425fbff77a6af1ea8c04d051e720cb08dc18de Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 15:23:48 -0600 Subject: [PATCH 02/10] F-9318: correct CertPathBuilder revocation checking documentation --- .../jce/WolfCryptPKIXCertPathBuilder.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathBuilder.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathBuilder.java index d1f2ebae..c9dca2a2 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathBuilder.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathBuilder.java @@ -76,11 +76,10 @@ import com.wolfssl.wolfcrypt.WolfCryptException; * 1. Certificate policies, and the related setters/getters. As such, * validation will not return PolicyNode in CertPathBuilderResult * - * Revocation checking is supported via: - * - CRL: If PKIXParameters.isRevocationEnabled() is true and appropriate - * CRLs have been loaded into CertStore Set - * - OCSP: via getRevocationChecker() which returns a - * WolfCryptPKIXRevocationChecker supporting OCSP and options + * 2. CRL and OCSP revocation checking during path building, configured + * CertPathCheckers are not executed by engineBuild(). To check + * revocation, validate the returned CertPath with CertPathValidator + * and PKIXParameters configured for revocation. */ public class WolfCryptPKIXCertPathBuilder extends CertPathBuilderSpi { @@ -1205,14 +1204,13 @@ public class WolfCryptPKIXCertPathBuilder extends CertPathBuilderSpi { } /** - * Returns a CertPathChecker that this implementation uses to check - * the revocation status of certificates. + * Returns a WolfCryptPKIXRevocationChecker supporting OCSP and CRL + * checking. * - * This implementation returns a WolfCryptPKIXRevocationChecker that - * supports both OCSP and CRL checking. + * Path building does not execute this checker. To check revocation, add + * it to PKIXParameters and validate the built path with CertPathValidator. * - * @return a CertPathChecker object that this implementation uses to - * check the revocation status of certificates. + * @return a WolfCryptPKIXRevocationChecker for use with CertPathValidator */ @Override public CertPathChecker engineGetRevocationChecker() { From 99040da417e2844c00c95466190361d1ce1f837c Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 15:55:34 -0600 Subject: [PATCH 03/10] F-9319: distinguish MAC mismatch from operational errors in AesCmac.verify --- .../java/com/wolfssl/wolfcrypt/AesCmac.java | 12 ++++++-- .../wolfssl/wolfcrypt/test/AesCmacTest.java | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/wolfssl/wolfcrypt/AesCmac.java b/src/main/java/com/wolfssl/wolfcrypt/AesCmac.java index 1df2c693..533e2b43 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/AesCmac.java +++ b/src/main/java/com/wolfssl/wolfcrypt/AesCmac.java @@ -336,13 +336,21 @@ public class AesCmac extends NativeStruct { * * @return true if verification succeeds, false otherwise * - * @throws WolfCryptException if native operation fails + * @throws WolfCryptException if the native operation fails for any + * reason other than MAC comparison mismatch */ public static synchronized boolean verify(byte[] mac, byte[] data, byte[] key) throws WolfCryptException { int ret = wc_AesCmacVerify(mac, mac.length, data, data.length, - key, key.length); + key, key.length); + + /* Native returns MAC_CMP_FAILED_E for a MAC mismatch, wolfSSL + * versions before 5.9.2 return 1 */ + if ((ret != 0) && (ret != 1) && + (ret != WolfCryptError.MAC_CMP_FAILED_E.getCode())) { + throw new WolfCryptException(ret); + } return (ret == 0); } diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/AesCmacTest.java b/src/test/java/com/wolfssl/wolfcrypt/test/AesCmacTest.java index 40137d3f..e9677976 100644 --- a/src/test/java/com/wolfssl/wolfcrypt/test/AesCmacTest.java +++ b/src/test/java/com/wolfssl/wolfcrypt/test/AesCmacTest.java @@ -45,6 +45,7 @@ import java.util.concurrent.LinkedBlockingQueue; import com.wolfssl.wolfcrypt.Aes; import com.wolfssl.wolfcrypt.Fips; import com.wolfssl.wolfcrypt.AesCmac; +import com.wolfssl.wolfcrypt.FeatureDetect; import com.wolfssl.wolfcrypt.NativeStruct; import com.wolfssl.wolfcrypt.WolfCryptError; import com.wolfssl.wolfcrypt.WolfCryptException; @@ -220,6 +221,33 @@ public class AesCmacTest { } } + @Test + public void aesCmacVerifyInvalidArgsShouldThrow() { + if (!FeatureDetect.AesCmacEnabled()) { + /* skip test if AES-CMAC is not compiled in native wolfCrypt */ + return; + } + + byte[] mac = new byte[16]; + byte[] data = new byte[16]; + + /* zero length key is an operational error, not a MAC mismatch */ + try { + AesCmac.verify(mac, data, new byte[0]); + fail("verify() should have thrown for zero length key"); + } catch (WolfCryptException e) { + /* expected */ + } + + /* invalid key length is an operational error, not a MAC mismatch */ + try { + AesCmac.verify(mac, data, new byte[5]); + fail("verify() should have thrown for invalid key length"); + } catch (WolfCryptException e) { + /* expected */ + } + } + @Test public void aesCmacAlgorithmInfoShouldWork() { try { From 377b1ae5b7a17c4575559b10d0f04e8adc77d976 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 16:10:34 -0600 Subject: [PATCH 04/10] F-9320: throw on operational errors in RsaPSS CheckPadding wrapper --- jni/jni_rsa.c | 9 ++++++ src/main/java/com/wolfssl/wolfcrypt/Rsa.java | 7 +++-- .../com/wolfssl/wolfcrypt/test/RsaTest.java | 31 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/jni/jni_rsa.c b/jni/jni_rsa.c index d98c030f..ae1c405d 100644 --- a/jni/jni_rsa.c +++ b/jni/jni_rsa.c @@ -1830,6 +1830,10 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPSS_1CheckPadding( } } + if (ret < 0) { + throwWolfCryptExceptionFromError(env, ret); + } + if (ret == 0) { XMEMSET(pssData, 0, pssDataSz); @@ -1843,6 +1847,11 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPSS_1CheckPadding( ret = wc_RsaPSS_CheckPadding_ex(digest, digestSz, pssData, pssDataSz, (enum wc_HashType)hashType, saltLen, 0); } + + /* Throw OutOfMemoryError on memory error, other codes map to false */ + if (ret == MEMORY_E) { + throwWolfCryptExceptionFromError(env, ret); + } } if (ret == 0) { result = JNI_TRUE; diff --git a/src/main/java/com/wolfssl/wolfcrypt/Rsa.java b/src/main/java/com/wolfssl/wolfcrypt/Rsa.java index eb746137..f577c783 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/Rsa.java +++ b/src/main/java/com/wolfssl/wolfcrypt/Rsa.java @@ -950,9 +950,12 @@ public class Rsa extends NativeStruct { * @param mgf mask generation function (WC_MGF1SHA256 for MGF1 with SHA-256) * @param saltLen salt length in bytes, or special value * - * @return true if padding is valid, false otherwise + * @return true if padding is valid, false otherwise, including for + * hashType, mgf, or saltLen values rejected during decode * - * @throws WolfCryptException if native operation fails + * @throws WolfCryptException on invalid arguments detected before + * signature decode + * @throws OutOfMemoryError on memory allocation failure * @throws IllegalStateException if object fails to initialize, or if * releaseNativeStruct() has been called and object has been * released. diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java b/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java index 7ac6acf6..7ff237d4 100644 --- a/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java +++ b/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java @@ -1471,6 +1471,37 @@ public class RsaTest { WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32); assertTrue("RSA-PSS check padding failed", verified); + /* Corrupted signatures must report false, not throw. PSS decode + * of garbage fails with position dependent error codes, exercise + * first, middle and last bytes */ + int[] flipPos = new int[] { 0, signature.length / 2, + signature.length - 1 }; + for (int pos : flipPos) { + byte[] badSig = signature.clone(); + badSig[pos] ^= (byte)0x80; + verified = key.rsaPssCheckPadding(badSig, digest, + WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32); + assertFalse("corrupted signature passed padding check, " + + "flipped byte " + pos, verified); + } + + /* Mismatched digest must report false, not throw */ + byte[] wrongDigest = digest.clone(); + wrongDigest[0] ^= 1; + verified = key.rsaPssCheckPadding(signature, wrongDigest, + WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32); + assertFalse("padding check passed with wrong digest", verified); + + /* Operational errors must throw, not report false */ + try { + key.rsaPssCheckPadding(signature, new byte[0], + WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32); + fail("rsaPssCheckPadding should have thrown for empty " + + "digest"); + } catch (WolfCryptException e) { + /* expected */ + } + } catch (Exception e) { fail("RSA-PSS check padding test failed: " + e.getMessage()); } From 145c212625310ea5a3c620308876c84ba78a8c09 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 16:16:10 -0600 Subject: [PATCH 05/10] F-9321 / F-9322: correct key state precondition in AesCcm and AesGcm javadoc --- src/main/java/com/wolfssl/wolfcrypt/AesCcm.java | 6 +++--- src/main/java/com/wolfssl/wolfcrypt/AesGcm.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/wolfssl/wolfcrypt/AesCcm.java b/src/main/java/com/wolfssl/wolfcrypt/AesCcm.java index 64453200..6d11b861 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/AesCcm.java +++ b/src/main/java/com/wolfssl/wolfcrypt/AesCcm.java @@ -217,10 +217,10 @@ public class AesCcm extends NativeStruct { * @param authIn additional data to be authenticated but not encrypted, * can be null if no additional data desired or available. * - * @return encrypted cipertext buffer + * @return encrypted ciphertext buffer * * @throws WolfCryptException if native operation fails - * @throws IllegalStateException if key has already been set, if object + * @throws IllegalStateException if key has not been set, if object * fails to initialize, or if releaseNativeStruct() has been * called and object has been released. */ @@ -251,7 +251,7 @@ public class AesCcm extends NativeStruct { * @return decrypted plaintext buffer * * @throws WolfCryptException if native operation fails - * @throws IllegalStateException if key has already been set, if object + * @throws IllegalStateException if key has not been set, if object * fails to initialize, or if releaseNativeStruct() has been * called and object has been released. */ diff --git a/src/main/java/com/wolfssl/wolfcrypt/AesGcm.java b/src/main/java/com/wolfssl/wolfcrypt/AesGcm.java index d6cb4b3c..c04f540f 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/AesGcm.java +++ b/src/main/java/com/wolfssl/wolfcrypt/AesGcm.java @@ -218,10 +218,10 @@ public class AesGcm extends NativeStruct { * @param authIn additional data to be authenticated but not encrypted, * can be null if no additional data desired or available. * - * @return encrypted cipertext buffer + * @return encrypted ciphertext buffer * * @throws WolfCryptException if native operation fails - * @throws IllegalStateException if key has already been set, if object + * @throws IllegalStateException if key has not been set, if object * fails to initialize, or if releaseNativeStruct() has been * called and object has been released. */ @@ -252,7 +252,7 @@ public class AesGcm extends NativeStruct { * @return decrypted plaintext buffer * * @throws WolfCryptException if native operation fails - * @throws IllegalStateException if key has already been set, if object + * @throws IllegalStateException if key has not been set, if object * fails to initialize, or if releaseNativeStruct() has been * called and object has been released. */ From ddf3c3f03a5a145a4797012fb7ed249927be6655 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 16:21:30 -0600 Subject: [PATCH 06/10] F-9323: correct FIPS CAST ordering comment in WolfObject init --- jni/jni_wolfobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jni/jni_wolfobject.c b/jni/jni_wolfobject.c index 43afe6cd..564bba2f 100644 --- a/jni/jni_wolfobject.c +++ b/jni/jni_wolfobject.c @@ -44,9 +44,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfObject_init * com.wolfssl.wolfcrypt.Fips.runAllCast_fips() method. runAllCast_fips() * includes a synchronized check that only runs the CASTs once as long * as they were successful. Fips.runAllCast_fips() is called at both - * the JNI-only level (WolfObject.init()), and the JCE level - * (WolfCryptProvider constructor). Both of these runAllCast_fips() - * at JNI/JCE levels are called before this wolfCrypt_Init() below. */ + * the JNI-only level (WolfObject static initializer), and the JCE level + * (WolfCryptProvider constructor). Both of these calls happen after + * this wolfCrypt_Init() below has returned. */ return (jint)wolfCrypt_Init(); } From 076671fe0c3dff01ce47212a91d03cc4564b9344 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 16:24:31 -0600 Subject: [PATCH 07/10] F-9324: allow null password in engineLoad javadoc to match behavior --- src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java b/src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java index 3d128abe..0768de12 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java @@ -2544,8 +2544,8 @@ public class WolfSSLKeyStore extends KeyStoreSpi { * Load the KeyStore from the provided InputStream. * * @param stream InputStream from which to load KeyStore - * @param password password used to check KeyStore integrity, must not - * be null + * @param password password used to check KeyStore integrity, may be + * null or empty to skip the whole KeyStore HMAC integrity check * * @throws IOException on I/O problem or issue with the * KeyStore data format From 687b3396f29f578de61174b18923e637ebb328a2 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 16:28:30 -0600 Subject: [PATCH 08/10] F-9325: match engineValidate sequence comment to implementation order --- .../provider/jce/WolfCryptPKIXCertPathValidator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathValidator.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathValidator.java index 669acc21..928368a5 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathValidator.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathValidator.java @@ -1020,11 +1020,13 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi { * a. CertPath.getType() is "X.509" * b. CertPath.getEncoding() contains "PkiPath" * 3. If wolfCrypt FIPS, verify params.getSigProvider() is wolfJCE - * 4. Sanitize Certificate objects in CertPath chain + * 4. Load TrustAnchors into WolfSSLCertManager, done before checker + * initialization since OCSP needs anchors to verify responses + * 5. Initialize any registered CertPathCheckers + * 6. Sanitize Certificate objects in CertPath chain * a. Check target certificate constraints meet target cert * b. Check cert policies are not used (not supported) - * 5. Call any registered CertPathCheckers - * 6. Load TrustAnchors into WolfSSLCertManager + * c. Call registered CertPathCheckers on each certificate * 7. Enable CRL if requested, load CRLs from getCertStores() * 8. Verify X.509 certificate chain * 9. Find top-most TrustAnchor for return object From 80affed32e8f80315b7db6ac8bc11b5e5cf218d8 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 17:00:16 -0600 Subject: [PATCH 09/10] F-8207: map stapled OCSP revoked status to BasicReason.REVOKED --- .../jce/WolfCryptPKIXRevocationChecker.java | 39 ++++++--- .../WolfCryptPKIXRevocationCheckerTest.java | 84 +++++++++++++++++++ 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXRevocationChecker.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXRevocationChecker.java index f1c3e11f..6de9a68f 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXRevocationChecker.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXRevocationChecker.java @@ -330,16 +330,7 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker { "Failed to encode certificate", e); } catch (WolfCryptException e) { - /* A definitive OCSP "revoked" status must always be a hard fail, - * with BasicReason.REVOKED. Other codes SOFT_FAIL may suppress. */ - if (e.getCode() == WolfCryptError.OCSP_CERT_REVOKED.getCode()) { - throw new CertPathValidatorException( - "Certificate revoked (OCSP): " + e.getMessage(), e, - null, -1, BasicReason.REVOKED); - } - throw new CertPathValidatorException( - "OCSP check failed: " + e.getMessage(), e, - null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); + throw mapOcspException("OCSP check failed", e); } } @@ -503,12 +494,34 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker { "Failed to encode certificate", e); } catch (WolfCryptException e) { - throw new CertPathValidatorException( - "OCSP response check failed: " + e.getMessage(), e, - null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); + throw mapOcspException("OCSP response check failed", e); } } + /** + * Map a native OCSP exception to CertPathValidatorException. An OCSP + * "revoked" status must always be a hard fail with BasicReason.REVOKED. + * Other codes map to UNDETERMINED_REVOCATION_STATUS, which SOFT_FAIL may + * suppress. + * + * @param msgPrefix message prefix for non-revoked failures + * @param e native exception from OCSP check + * + * @return CertPathValidatorException for caller to throw + */ + private CertPathValidatorException mapOcspException(String msgPrefix, + WolfCryptException e) { + + if (e.getCode() == WolfCryptError.OCSP_CERT_REVOKED.getCode()) { + return new CertPathValidatorException( + "Certificate revoked (OCSP): " + e.getMessage(), e, + null, -1, BasicReason.REVOKED); + } + return new CertPathValidatorException( + msgPrefix + ": " + e.getMessage(), e, + null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); + } + /** * Handle exception based on SOFT_FAIL option. * diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptPKIXRevocationCheckerTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptPKIXRevocationCheckerTest.java index f621508f..2f79c284 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptPKIXRevocationCheckerTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptPKIXRevocationCheckerTest.java @@ -55,6 +55,7 @@ import com.wolfssl.wolfcrypt.WolfSSLCertManager; import com.wolfssl.wolfcrypt.WolfCryptException; import com.wolfssl.wolfcrypt.WolfCryptError; import com.wolfssl.wolfcrypt.test.TimedTestWatcher; +import com.wolfssl.wolfcrypt.test.Util; import com.wolfssl.provider.jce.WolfCryptProvider; import com.wolfssl.provider.jce.WolfCryptPKIXRevocationChecker; @@ -873,6 +874,89 @@ public class WolfCryptPKIXRevocationCheckerTest { cm.free(); } + /* DER encoded OCSP response for server-cert.der, status successful, signed + * by ca-cert.pem, generated with openssl ocsp. Contains no nextUpdate so + * it never expires. Only needs to pass native response status parsing, + * response verification itself is mocked below. */ + private static final String OCSP_RESPONSE_HEX = + "308202330a0100a082022c3082022806092b0601050507300101048202193082" + + "02153081fea18197308194310b30090603550406130255533110300e06035504" + + "080c074d6f6e74616e613110300e06035504070c07426f7a656d616e3111300f" + + "060355040a0c08536177746f6f746831133011060355040b0c0a436f6e73756c" + + "74696e673118301606035504030c0f7777772e776f6c6673736c2e636f6d311f" + + "301d06092a864886f70d0109011610696e666f40776f6c6673736c2e636f6d18" + + "0f32303236303831343232353035335a3051304f303a300906052b0e03021a05" + + "000414ff66218a6ec5866184259abad65539fb25512cdd0414278e671174c326" + + "1d3fed3363b3a4d81d30e5e8d50201018000180f323032363038313432323530" + + "35335a300d06092a864886f70d01010b0500038201010076d97a9999d345fc6f" + + "071b127d806865c588e0bea677757ec370396aea7020ef0db922251f8ba6bb45" + + "8abd4aeb310d9ff024b733a483ed8c8b7cfd116e003b5db9ab5d69f640973c93" + + "856562fef0d4eeef3115877c3867bcfbe5910b47fad0e5c9dfa1d487bc6048be" + + "7a0900a7505d9a2a59210921c359a95ebc94f12d2b8def4489a26a39253be4a7" + + "6084f4f42dfc46d800536ebbff8bc85111408e221b6d5e8462588994d4ca338b" + + "62d22bf0496dc53677f91892a6036040216851124f3abdb781d6c96a0358b0ad" + + "a97563122e9c1d8fd99d2cd38b78373f0ad4c841dc11727fdbeac44efd9a75da" + + "060e70d1c02774b5de05d3bd9a9fced3c73d65d3cc750d"; + + /* CertManager that simulates a definitive OCSP "revoked" status for a + * pre-loaded response by throwing WolfCryptException(OCSP_CERT_REVOKED) + * from CertManagerCheckOCSPResponse, like native wolfSSL does for a + * revoked certificate. */ + private static class RevokedOcspResponseCertManager + extends WolfSSLCertManager { + + @Override + public synchronized void CertManagerCheckOCSPResponse( + byte[] response, int responseSz, byte[] cert, int certSz) { + throw new WolfCryptException( + WolfCryptError.OCSP_CERT_REVOKED.getCode()); + } + } + + @Test + public void testPreloadedOcspRevokedUsesRevokedReason() throws Exception { + + if (!WolfCrypt.OcspEnabled()) { + /* Skip test if OCSP not compiled in */ + return; + } + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider); + WolfCryptPKIXRevocationChecker checker = + (WolfCryptPKIXRevocationChecker)cpv.getRevocationChecker(); + + FileInputStream fis = new FileInputStream(caCertDer); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate caCert = (X509Certificate)cf.generateCertificate(fis); + fis.close(); + + fis = new FileInputStream(serverCertDer); + X509Certificate serverCert = + (X509Certificate)cf.generateCertificate(fis); + fis.close(); + + /* Preload OCSP response so check() takes the stapled path */ + Map responses = + new HashMap(); + responses.put(serverCert, Util.h2b(OCSP_RESPONSE_HEX)); + checker.setOcspResponses(responses); + + WolfSSLCertManager cm = new RevokedOcspResponseCertManager(); + cm.CertManagerLoadCA(caCert); + checker.setCertManager(cm); + checker.init(false); + + try { + checker.check(serverCert, null); + fail("A revoked pre-loaded OCSP status must fail validation"); + } catch (CertPathValidatorException e) { + assertEquals("Revoked cert must fail with BasicReason.REVOKED", + BasicReason.REVOKED, e.getReason()); + } + + cm.free(); + } + @Test public void testRevocationCheckerCheckWithCertChain() throws Exception { From 2a516afb53be866b0cb8c47e9ced71c0fa3e3a73 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 14 Aug 2026 17:16:13 -0600 Subject: [PATCH 10/10] F-8208: import DH private key when init given explicit DHParameterSpec --- .../provider/jce/WolfCryptKeyAgreement.java | 42 +++++++++--------- .../jce/test/WolfCryptKeyAgreementTest.java | 44 +++++++++++++++++++ 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java index 29bb8746..0e15c702 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java @@ -470,37 +470,35 @@ public class WolfCryptKeyAgreement extends KeyAgreementSpi { "AlgorithmParameterSpec is not of type DHParameterSpec"); } + /* reject spec that conflicts with the key's own parameters */ + if (dhKey.getParams() != null && + (!dhKey.getParams().getP().equals( + ((DHParameterSpec)params).getP()) || + !dhKey.getParams().getG().equals( + ((DHParameterSpec)params).getG()))) { + throw new InvalidAlgorithmParameterException( + "DHParameterSpec does not match key parameters"); + } + paramP = ((DHParameterSpec)params).getP().toByteArray(); paramG = ((DHParameterSpec)params).getG().toByteArray(); - if (paramP != null && paramG != null) { - - this.dh.setParams(paramP, paramG); - - primeLen = paramP.length; - - /* prime may have leading zero */ - if (paramP[0] == 0x00) { - primeLen--; - } - - return; - - } else { + if (paramP == null || paramG == null) { throw new InvalidParameterException( "AlgorithmParameterSpec does not include required " + "DH parameters (P,G)"); } } + else { + /* try to import params from key */ + paramP = dhKey.getParams().getP().toByteArray(); + paramG = dhKey.getParams().getG().toByteArray(); - /* try to import params from key */ - paramP = dhKey.getParams().getP().toByteArray(); - paramG = dhKey.getParams().getG().toByteArray(); - - if (paramP == null || paramG == null) { - throw new InvalidKeyException( - "Key must include DH parameters when not called " + - "with explicit AlgorithmParameterSpec"); + if (paramP == null || paramG == null) { + throw new InvalidKeyException( + "Key must include DH parameters when not called " + + "with explicit AlgorithmParameterSpec"); + } } this.dh.setParams(paramP, paramG); diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyAgreementTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyAgreementTest.java index d865c796..f8051673 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyAgreementTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyAgreementTest.java @@ -405,6 +405,50 @@ public class WolfCryptKeyAgreementTest { assertArrayEquals(secretA, secretB); } + @Test + public void testDHKeyAgreementWithExplicitParams() + throws NoSuchProviderException, NoSuchAlgorithmException, + InvalidKeyException, InvalidAlgorithmParameterException { + + /* skip test if DH is not compiled in native wolfSSL */ + if (!FeatureDetect.DhEnabled()) { + return; + } + + byte[][] pg = Dh.getNamedDhParams(Dh.WC_FFDHE_2048); + BigInteger p = new BigInteger(1, pg[0]); + BigInteger g = new BigInteger(1, pg[1]); + DHParameterSpec dhParams = new DHParameterSpec(p, g); + + KeyPairGenerator keyGen = + KeyPairGenerator.getInstance("DH", "wolfJCE"); + keyGen.initialize(dhParams); + KeyPair aPair = keyGen.generateKeyPair(); + KeyPair bPair = keyGen.generateKeyPair(); + + /* init() with explicit DHParameterSpec must import private key */ + KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "wolfJCE"); + KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "wolfJCE"); + aKeyAgree.init(aPair.getPrivate(), dhParams); + bKeyAgree.init(bPair.getPrivate(), dhParams); + aKeyAgree.doPhase(bPair.getPublic(), true); + bKeyAgree.doPhase(aPair.getPublic(), true); + + byte secretA[] = aKeyAgree.generateSecret(); + byte secretB[] = bKeyAgree.generateSecret(); + assertTrue(secretA.length > 0); + assertArrayEquals(secretA, secretB); + + /* spec that conflicts with key params must be rejected */ + try { + aKeyAgree.init(aPair.getPrivate(), + new DHParameterSpec(p, g.add(BigInteger.ONE))); + fail("init() should reject mismatched DHParameterSpec"); + } catch (InvalidAlgorithmParameterException e) { + /* expected */ + } + } + /* Minimal DHPublicKey holding a caller-chosen Y, for feeding malicious * peer public key values into engineDoPhase() during testing. */ private static DHPublicKey makeDHPublicKey(final BigInteger y,