Merge pull request #265 from cconlon/fenrirAug24

Fenrir fixes across AES, ECC, RSA, SLH-DSA, DH, and PKIX revocation
pull/266/merge
Ruby Martin 2026-09-11 17:11:37 -05:00 committed by GitHub
commit b8392ced50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 946 additions and 142 deletions

View File

@ -888,6 +888,10 @@ revoked, validation will fail. The difference only affects behavior when one
method succeeds and the other would have failed (e.g., OCSP unreachable but
CRL available).
A `PKIXRevocationChecker` added with `addCertPathChecker()` applies
irregardless of if `setRevocationEnabled()` is set, so `PREFER_CRLS` with CRLs
in the `CertStore` list performs CRL checking even when revocation is disabled.
#### Indirect CRL Not Supported
Native wolfSSL does not support indirect CRLs. An indirect CRL is a CRL signed

View File

@ -64,17 +64,19 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_native_1init(
JNIEnv* env, jobject this)
{
#ifdef HAVE_AESGCM
int ret = 0;
Gmac* gmac = (Gmac*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
/* GMAC struct is already zero-initialized in mallocNativeStruct_internal */
/* Actual initialization happens in wc_GmacSetKey when we have the key */
ret = wc_AesInit(&gmac->aes, NULL, INVALID_DEVID);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("native_init(gmac=%p)\n", gmac);
(void)gmac; /* suppress unused variable warning */
#else
throwNotCompiledInException(env);
#endif
@ -93,9 +95,9 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_native_1free(
LogStr("free Gmac %p\n", gmac);
if (gmac) {
/* Only clear the GMAC struct - do NOT free the memory here.
* The base class NativeStruct.xfree() will handle the actual
* memory deallocation to avoid double-free. */
/* Free AES backend resources, then clear the struct.
* NativeStruct.xfree() frees Gmac struct. */
wc_AesFree(&gmac->aes);
XMEMSET(gmac, 0, sizeof(Gmac));
}
#else
@ -242,8 +244,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1Gmac(
authInSz = getByteArrayLength(env, authIn_object);
authTagSz = getByteArrayLength(env, authTag_object);
/* Set the key */
ret = wc_GmacSetKey(&gmac, key, keySz);
ret = wc_AesInit(&gmac.aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_GmacSetKey(&gmac, key, keySz);
}
if (ret == 0) {
/* Use a local buffer for the auth tag result to avoid
@ -319,8 +323,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacVerify(
authInSz = getByteArrayLength(env, authIn_object);
authTagSz = getByteArrayLength(env, authTag_object);
/* Set the key */
ret = wc_GmacSetKey(&gmac, key, keySz);
ret = wc_AesInit(&gmac.aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_GmacSetKey(&gmac, key, keySz);
}
if (ret == 0) {
/* Generate the expected tag and compare */

View File

@ -71,6 +71,7 @@ Java_com_wolfssl_wolfcrypt_AesOfb_native_1set_1key_1internal(
byte* key = NULL;
byte* iv = NULL;
word32 keySz = 0;
(void)opmode;
aes = (Aes*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -87,7 +88,7 @@ Java_com_wolfssl_wolfcrypt_AesOfb_native_1set_1key_1internal(
}
if (ret == 0) {
ret = wc_AesSetKey(aes, key, keySz, iv, opmode);
ret = wc_AesSetKey(aes, key, keySz, iv, AES_ENCRYPTION);
}
if (ret != 0) {

View File

@ -320,7 +320,6 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhGenerateKeyPair(
LogStr("wc_DhGenerateKeyPair(key, rng, priv, privSz, pub, pubSz) = %d\n",
ret);
LogStr("private[%u]: [%p]\n", privSz, priv);
LogHex(priv, 0, privSz);
LogStr("public[%u]: [%p]\n", pubSz, pub);
LogHex(pub, 0, pubSz);
@ -455,7 +454,6 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
LogStr("wc_DhAgree(key, secret, secretSz, priv, privSz, pub, pubSz) = %d\n",
ret);
LogStr("secret[%u]: [%p]\n", secretSz, secret);
LogHex(secret, 0, secretSz);
if (secret != NULL) {
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \

View File

@ -164,6 +164,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1make_1key_1ex
{
#ifdef HAVE_ECC
int ret = 0;
int curveId = 0;
ecc_key* ecc = NULL;
RNG* rng = NULL;
const char* name = NULL;
@ -188,29 +189,26 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1make_1key_1ex
if (ret == 0) {
name = (*env)->GetStringUTFChars(env, curveName, 0);
if (name == NULL) {
ret = BAD_FUNC_ARG;
/* GetStringUTFChars failed with an exception already pending */
return;
}
}
if (ret == 0) {
ret = wc_ecc_get_curve_id_from_name(name);
curveId = wc_ecc_get_curve_id_from_name(name);
(*env)->ReleaseStringUTFChars(env, curveName, name);
if (curveId < 0) {
throwWolfCryptException(env,
"ECC curve unsupported or not enabled");
return;
}
/* Pass keysize 0 so the curve_id sets the key size, required for
* FIPS where approved curves need keysize 0 */
ret = wc_ecc_make_key_ex(rng, 0, ecc, curveId);
}
if (ret < 0) {
throwWolfCryptException(env, "ECC curve unsupported or not enabled");
} else {
/* When using a specific curve_id, pass keysize as 0 to let the
* curve_id determine the key size. This is required for FIPS mode
* compatibility where keysize must be 0 when using approved curves.
* The 'size' parameter from Java is ignored here since curve_id
* (stored in ret) defines the actual key size. */
ret = wc_ecc_make_key_ex(rng, 0, ecc, ret);
if (ret < 0) {
throwWolfCryptExceptionFromError(env, ret);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("ecc_make_key_ex(rng, size, ecc=%p) = %d\n", ecc, ret);

View File

@ -527,7 +527,11 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_RsaPssLongSa
{
(void)env;
(void)jcl;
#if !defined(NO_RSA) && defined(WC_RSA_PSS) && defined(WOLFSSL_PSS_LONG_SALT)
/* FIPS v7 and later cap the PSS salt at the digest length, even when
* WOLFSSL_PSS_LONG_SALT is defined */
#if !defined(NO_RSA) && defined(WC_RSA_PSS) && \
defined(WOLFSSL_PSS_LONG_SALT) && \
!(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 7))
return JNI_TRUE;
#else
return JNI_FALSE;

View File

@ -561,23 +561,6 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyToP
}
}
/* Get PKCS#8 output size, into pkcs8Sz */
if (ret == 0) {
ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, derKey, derKeySz, algoID,
curveOID, oidSz);
if (ret == LENGTH_ONLY_E) {
pkcs8 = (byte*)XMALLOC(pkcs8Sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (pkcs8 == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(pkcs8, 0, pkcs8Sz);
pkcs8BufSz = pkcs8Sz;
ret = 0;
}
}
}
if (ret == 0) {
/* Allocate temp buffer to hold DER encoded key */
derKey = (byte*)XMALLOC(derKeySz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@ -599,6 +582,23 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyToP
}
}
/* Get PKCS#8 output size, into pkcs8Sz. */
if (ret == 0) {
ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, derKey, derKeySz, algoID,
curveOID, oidSz);
if (ret == LENGTH_ONLY_E) {
pkcs8 = (byte*)XMALLOC(pkcs8Sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (pkcs8 == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(pkcs8, 0, pkcs8Sz);
pkcs8BufSz = pkcs8Sz;
ret = 0;
}
}
}
/* Create PKCS#8 from DER key */
if (ret == 0) {
ret = wc_CreatePKCS8Key(pkcs8, &pkcs8Sz, derKey, derKeySz,

View File

@ -50,6 +50,12 @@
/* #define WOLFCRYPT_JNI_DEBUG_ON */
#include <wolfcrypt_jni_debug.h>
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && !defined(WOLFSSL_NO_FORCE_ZERO)
#define SLHDSA_FORCE_ZERO(p, len) wc_ForceZero((p), (len))
#else
#define SLHDSA_FORCE_ZERO(p, len) XMEMSET((p), 0, (len))
#endif
/* A WOLFSSL_SLHDSA_VERIFY_ONLY build provides only public-key verify. DER
* encode (KeyToDer / PublicKeyToDer) additionally needs
* WC_ENABLE_ASYM_KEY_EXPORT. */
@ -1258,7 +1264,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_SlhDsa_wc_1SlhDsaKey_1ex
LogStr("wc_SlhDsaKey_ExportPrivate(key=%p) = %d\n", key, ret);
wc_ForceZero(output, outputBufSz);
SLHDSA_FORCE_ZERO(output, outputBufSz);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
@ -1463,7 +1469,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_SlhDsa_wc_1SlhDsaKey_1Ke
LogStr("wc_SlhDsaKey_KeyToDer(key=%p) = %d\n", key, ret);
wc_ForceZero(output, outputBufSz);
SLHDSA_FORCE_ZERO(output, outputBufSz);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
@ -1558,7 +1564,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_SlhDsa_wc_1SlhDsaKey_1PrivateK
LogStr("wc_SlhDsaKey_PrivateKeyDecode(key=%p) = %d\n", key, ret);
if (derCopy != NULL) {
wc_ForceZero(derCopy, derLen);
SLHDSA_FORCE_ZERO(derCopy, derLen);
XFREE(derCopy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
releaseByteArray(env, der_object, der, JNI_ABORT);

View File

@ -523,6 +523,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLCertManager_CertManager
}
buff = (byte*)(*env)->GetByteArrayElements(env, in, NULL);
if (buff == NULL) {
return MEMORY_E;
}
buffSz = (word32)sz;
ret = wolfSSL_CertManagerLoadCABuffer(cm, buff, buffSz, format);
@ -547,6 +550,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLCertManager_CertManager
}
buff = (byte*)(*env)->GetByteArrayElements(env, in, NULL);
if (buff == NULL) {
return MEMORY_E;
}
buffSz = (word32)sz;
ret = wolfSSL_CertManagerLoadCABuffer_ex(cm, buff, buffSz, format, 0,
@ -588,6 +594,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLCertManager_CertManager
}
buff = (byte*)(*env)->GetByteArrayElements(env, in, NULL);
if (buff == NULL) {
return MEMORY_E;
}
buffSz = (word32)sz;
ret = wolfSSL_CertManagerVerifyBuffer(cm, buff, buffSz, format);
@ -656,6 +665,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLCertManager_CertManager
}
buff = (byte*)(*env)->GetByteArrayElements(env, in, NULL);
if (buff == NULL) {
return MEMORY_E;
}
buffSz = (word32)sz;
ret = wolfSSL_CertManagerLoadCRLBuffer(cm, buff, buffSz, type);

View File

@ -73,7 +73,8 @@ import java.security.cert.CertificateException;
* validation will not return PolicyNode in CertPathValidatorResult
*
* Revocation checking is supported via:
* - CRL: If PKIXParameters.isRevocationEnabled() is true and appropriate
* - CRL: If PKIXParameters.isRevocationEnabled() is true, or a
* PKIXRevocationChecker with PREFER_CRLS is registered, and appropriate
* CRLs have been loaded into CertStore Set
* - OCSP: via getRevocationChecker() which returns a
* WolfCryptPKIXRevocationChecker supporting OCSP and options
@ -839,25 +840,71 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
CertPath certPath, List<X509Certificate> certs)
throws CertPathValidatorException {
/* Report index of last cert in path (closest to trust anchor)
* to match SunJCE behavior. */
int failIndex = 0;
if (certs != null && certs.size() > 1) {
failIndex = certs.size() - 1;
}
throw new CertPathValidatorException(message, null, certPath,
failIndex, BasicReason.UNDETERMINED_REVOCATION_STATUS);
lastCertIndex(certs), BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
/**
* Check if revocation has been enabled in PKIXParameters, and if so
* find and load any CRLs in params.getCertStores().
* Index of cert closest to the trust anchor.
*
* When a PKIXRevocationChecker is registered via addCertPathChecker(),
* that checker handles revocation checking. CRL checking in the native
* CertManager is only enabled if:
* - No PKIXRevocationChecker is present (default CRL behavior), or
* - PKIXRevocationChecker has PREFER_CRLS option set
* @param certs certificate list from the CertPath
*
* @return index of the last cert, or 0 for a single-cert path
*/
private static int lastCertIndex(List<X509Certificate> certs) {
if (certs != null && certs.size() > 1) {
return certs.size() - 1;
}
return 0;
}
/**
* Disable native CRL checking after a PREFER_CRLS checker found no CRL
* to load, so wolfSSL doesn't fail chain validation on a missing CRL. With
* NO_FALLBACK set, revocation is undetermined, which fails validation
* unless SOFT_FAIL is set. Without NO_FALLBACK, the OCSP result the
* checker already produced in check() propogates.
*
* @param revChecker the registered PREFER_CRLS checker
* @param noFallback true if the checker has NO_FALLBACK set
* @param cm WolfSSLCertManager with CRL checking enabled
* @param certPath the CertPath being validated, for exception reporting
* @param failIndex index of the cert to report
*
* @throws CertPathValidatorException if revocation is undetermined and
* SOFT_FAIL is not set, or native CRL checking cannot be disabled
*/
private void handleMissingCrl(WolfCryptPKIXRevocationChecker revChecker,
boolean noFallback, WolfSSLCertManager cm, CertPath certPath,
int failIndex) throws CertPathValidatorException {
if (noFallback) {
revChecker.handleMissingCrlRevocation(certPath, failIndex);
}
else {
log("no CRL loaded, PREFER_CRLS checker falls back to OCSP");
}
try {
cm.CertManagerDisableCRL();
}
catch (WolfCryptException e) {
throw new CertPathValidatorException("Failed to disable CRL " +
"checking in native WolfSSLCertManager", e);
}
}
/**
* Check if CRL checking is wanted and, if so, find and load any CRLs in
* params.getCertStores().
*
* CRL checking in the native CertManager is enabled when
* PKIXParameters.isRevocationEnabled() is true, or when a
* PKIXRevocationChecker with PREFER_CRLS is registered, which applies
* irregardless of the revocation flag. A registered checker without
* PREFER_CRLS handles revocation itself via OCSP.
*
* @param params parameters used to check if revocation is enabled and,
* if so load any CRLs available
@ -877,10 +924,13 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
int i = 0;
int loadedCount = 0;
int certCount = 0;
int failIndex = lastCertIndex(certs);
List<CertStore> stores = null;
Collection<? extends CRL> crls = null;
boolean hasRevocationChecker = false;
boolean preferCrls = false;
boolean noFallback = false;
WolfCryptPKIXRevocationChecker revChecker = null;
if (params == null || cm == null) {
throw new CertPathValidatorException(
@ -894,13 +944,14 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
for (PKIXCertPathChecker checker : pathCheckers) {
if (checker instanceof WolfCryptPKIXRevocationChecker) {
hasRevocationChecker = true;
WolfCryptPKIXRevocationChecker revChecker =
(WolfCryptPKIXRevocationChecker)checker;
revChecker = (WolfCryptPKIXRevocationChecker)checker;
Set<PKIXRevocationChecker.Option> options =
revChecker.getOptions();
if (options != null && options.contains(
PKIXRevocationChecker.Option.PREFER_CRLS)) {
preferCrls = true;
if (options != null) {
preferCrls = options.contains(
PKIXRevocationChecker.Option.PREFER_CRLS);
noFallback = options.contains(
PKIXRevocationChecker.Option.NO_FALLBACK);
}
break;
}
@ -913,18 +964,24 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
return;
}
if (params.isRevocationEnabled()) {
log("revocation enabled in PKIXParameters, checking for CRLs " +
"to load");
if (params.isRevocationEnabled() || preferCrls) {
log("revocation enabled or PREFER_CRLS checker registered, " +
"checking for CRLs to load");
if (!WolfCrypt.CrlEnabled()) {
throw new CertPathValidatorException(
"Revocation enabled in PKIXParameters but native " +
"wolfCrypt CRL not compiled in");
"CRL checking requested but native wolfCrypt CRL not " +
"compiled in");
}
/* Enable CRL in native WolfSSLCertManager */
cm.CertManagerEnableCRL(WolfCrypt.WOLFSSL_CRL_CHECK);
try {
cm.CertManagerEnableCRL(WolfCrypt.WOLFSSL_CRL_CHECK);
}
catch (WolfCryptException e) {
throw new CertPathValidatorException("Failed to enable CRL " +
"checking in native WolfSSLCertManager", e);
}
log("CRL support enabled in native WolfSSLCertManager");
stores = params.getCertStores();
@ -940,6 +997,10 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
"and no PKIXRevocationChecker configured for OCSP",
certPath, certs);
}
else {
handleMissingCrl(revChecker, noFallback, cm, certPath,
failIndex);
}
return;
}
@ -990,22 +1051,32 @@ public class WolfCryptPKIXCertPathValidator extends CertPathValidatorSpi {
}
} catch (CertStoreException e) {
throw new CertPathValidatorException(e);
} catch (WolfCryptException e) {
throw new CertPathValidatorException(
"Failed to load CRL into native WolfSSLCertManager", e);
}
log("loaded " + loadedCount + " CRLs into WolfSSLCertManager");
/* If no CRLs were loaded and no PKIXRevocationChecker is handling
* OCSP, we cannot determine revocation status. */
if (loadedCount == 0 && !hasRevocationChecker) {
throwUndeterminedRevocationStatus(
"Revocation checking enabled but no CRLs found in " +
"CertStores and no PKIXRevocationChecker configured " +
"for OCSP",
certPath, certs);
if (loadedCount == 0) {
if (!hasRevocationChecker) {
throwUndeterminedRevocationStatus(
"Revocation checking enabled but no CRLs found in " +
"CertStores and no PKIXRevocationChecker configured " +
"for OCSP",
certPath, certs);
}
else {
handleMissingCrl(revChecker, noFallback, cm, certPath,
failIndex);
}
}
}
else {
log("revocation not enabled in PKIXParameters");
log("revocation not enabled in PKIXParameters and no PREFER_CRLS" +
"checker registered");
}
}

View File

@ -24,6 +24,7 @@ package com.wolfssl.provider.jce;
import java.net.URI;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.Extension;
@ -543,6 +544,27 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker {
}
}
/**
* Fail closed when a PREFER_CRLS/NO_FALLBACK checker has no CRL source.
*
* check() runs before CRLs are loaded and cannot see whether a CRL source
* is configured, so the validator calls this after CRL setup. With OCSP
* suppressed by NO_FALLBACK and no CRL to check, revocation status is
* undetermined. Honors SOFT_FAIL via handleException().
*
* @param certPath the CertPath being validated, for exception reporting
* @param index index of the cert whose revocation status is undetermined
*
* @throws CertPathValidatorException if SOFT_FAIL is not set
*/
void handleMissingCrlRevocation(CertPath certPath, int index)
throws CertPathValidatorException {
handleException(new CertPathValidatorException(
"PREFER_CRLS with NO_FALLBACK selected but no CRL source is " +
"available, revocation status cannot be determined", null,
certPath, index, BasicReason.UNDETERMINED_REVOCATION_STATUS));
}
/**
* Set OCSP responder URI override.
*

View File

@ -904,11 +904,10 @@ public class WolfCryptUtil {
* Get minimum key size limit from disabled algorithms security property
* for specified algorithm.
*
* Parses constraints like "RSA keySize &lt; 1024" from the security
* property and returns the minimum allowed key size. Entries are
* matched on their leading algorithm name, any algorithm name may be
* used. Only the "&lt;" and "&lt;=" operators are supported, entries
* using other operators are ignored.
* Parses constraints (ex: {@code RSA keySize < 1024}) from the security
* property and returns the minimum allowed key size. Match entries on their
* leading algorithm name. Only {@code <} and {@code <=} operators are
* supported, entries using other operators are ignored.
*
* @param algo Algorithm to search for key size limitation for
* (ex: "RSA", "DH", "DSA", "EC")
@ -920,30 +919,38 @@ public class WolfCryptUtil {
public static int getDisabledAlgorithmsKeySizeLimit(String algo,
String propertyName) {
return getDisabledAlgorithmsKeySizeLimit(algo, propertyName, false);
return getDisabledAlgorithmsKeySizeLimit(algo, propertyName, false, 0);
}
/**
* Internal implementation of getDisabledAlgorithmsKeySizeLimit().
*
* Matches entries on their leading algorithm name so that, for
* Matches entries on leading algorithm name so that, for
* example, an "ECDH keySize" entry does not set the "DH" limit.
*
* With a known keySize, an entry disables the key only when all of its
* keySize constraints match. denyAfter and jdkCA qualifiers are treated as
* satisfied rather than evaluated, so an entry using them fails closed.
* With keySize 0, only the floor from the first {@code <} or {@code <=}
* constraint is returned.
*
* @param algo Algorithm to search for key size limitation for
* (ex: "RSA", "DH", "DSA", "EC")
* @param propertyName Security property name to check
* @param certPathContext true when checking for CertPath validation,
* skips entries scoped to usage contexts that can never apply
* there
* @param keySize actual key size in bits, or 0 to compute the floor only
*
* @return minimum key size allowed, or 0 if not set in property
* @return -1 if keySize is disabled, the min-size floor when keySize is
* 0, or 0 when no constraint applies
*/
private static int getDisabledAlgorithmsKeySizeLimit(String algo,
String propertyName, boolean certPathContext) {
String propertyName, boolean certPathContext, int keySize) {
int ret = 0;
List<String> disabledList = null;
Pattern p = Pattern.compile("keySize\\s*<(=?)\\s*(\\d+)",
Pattern p = Pattern.compile("keySize\\s*(>=|<=|==|!=|>|<)\\s*(\\d+)",
Pattern.CASE_INSENSITIVE);
Matcher match = null;
@ -959,8 +966,7 @@ public class WolfCryptUtil {
disabledList = getExpandedDisabledEntries(propertyName);
for (String s : disabledList) {
/* Match on the leading algorithm name only, so "ECDH keySize"
* does not match algo "DH" */
/* Match on leading algorithm name only */
String disabledName = extractDisabledAlgorithmName(s);
if (disabledName == null || !disabledName.equalsIgnoreCase(algo)) {
continue;
@ -973,20 +979,54 @@ public class WolfCryptUtil {
}
match = p.matcher(s);
if (match.find()) {
try {
int limit = Integer.parseInt(match.group(2));
if (match.group(1).equals("=") &&
limit < Integer.MAX_VALUE) {
/* "keySize <= N" disables through N, minimum allowed
* size is N + 1 */
limit = limit + 1;
if (keySize > 0) {
boolean anyConstraint = false;
boolean allMatch = true;
while (match.find()) {
String op = match.group(1);
int limit;
try {
limit = Integer.parseInt(match.group(2));
} catch (NumberFormatException e) {
/* Exceeds Integer.MAX_VALUE, ignore this constraint */
continue;
}
/* Keep the strictest of multiple matching entries */
ret = Math.max(ret, limit);
} catch (NumberFormatException e) {
/* Number exceeds Integer.MAX_VALUE, ignore malformed
* number and leave ret unchanged. */
anyConstraint = true;
boolean matches =
(op.equals("<") && keySize < limit) ||
(op.equals("<=") && keySize <= limit) ||
(op.equals(">") && keySize > limit) ||
(op.equals(">=") && keySize >= limit) ||
(op.equals("==") && keySize == limit) ||
(op.equals("!=") && keySize != limit);
if (!matches) {
allMatch = false;
break;
}
}
if (anyConstraint && allMatch) {
return -1;
}
}
else {
/* keySize unknown, derive floor from first < or <= */
while (match.find()) {
String op = match.group(1);
if (!op.equals("<") && !op.equals("<=")) {
continue;
}
try {
int limit = Integer.parseInt(match.group(2));
if (op.equals("<=") && limit < Integer.MAX_VALUE) {
/* "keySize <= N" disables N, min allowed N + 1 */
limit = limit + 1;
}
ret = Math.max(ret, limit);
} catch (NumberFormatException e) {
/* Number exceeds Integer.MAX_VALUE, ignore */
}
break;
}
}
}
@ -1049,7 +1089,7 @@ public class WolfCryptUtil {
boolean certPathContext) {
int keySize = 0;
int minSize = 0;
int sizeLimit = 0;
String algorithm = null;
if (key == null) {
@ -1067,8 +1107,8 @@ public class WolfCryptUtil {
if (key instanceof RSAPublicKey) {
RSAPublicKey rsaKey = (RSAPublicKey)key;
keySize = rsaKey.getModulus().bitLength();
minSize = getDisabledAlgorithmsKeySizeLimit("RSA", propertyName,
certPathContext);
sizeLimit = getDisabledAlgorithmsKeySizeLimit("RSA", propertyName,
certPathContext, keySize);
}
else if (key instanceof ECPublicKey) {
ECPublicKey ecKey = (ECPublicKey)key;
@ -1097,24 +1137,24 @@ public class WolfCryptUtil {
}
}
minSize = getDisabledAlgorithmsKeySizeLimit("EC", propertyName,
certPathContext);
sizeLimit = getDisabledAlgorithmsKeySizeLimit("EC", propertyName,
certPathContext, keySize);
}
else if (key instanceof DSAPublicKey) {
DSAPublicKey dsaKey = (DSAPublicKey)key;
if (dsaKey.getParams() != null) {
keySize = dsaKey.getParams().getP().bitLength();
}
minSize = getDisabledAlgorithmsKeySizeLimit("DSA", propertyName,
certPathContext);
sizeLimit = getDisabledAlgorithmsKeySizeLimit("DSA", propertyName,
certPathContext, keySize);
}
else if (key instanceof DHPublicKey) {
DHPublicKey dhKey = (DHPublicKey)key;
if (dhKey.getParams() != null) {
keySize = dhKey.getParams().getP().bitLength();
}
minSize = getDisabledAlgorithmsKeySizeLimit("DH", propertyName,
certPathContext);
sizeLimit = getDisabledAlgorithmsKeySizeLimit("DH", propertyName,
certPathContext, keySize);
}
else if (key instanceof WolfCryptMlDsaPublicKey) {
/* ML-DSA uses fixed parameter sets, no key size constraints */
@ -1136,8 +1176,13 @@ public class WolfCryptUtil {
certPathContext);
}
/* If minimum size constraint exists and key is smaller, reject */
if (minSize > 0 && keySize < minSize) {
/* Negative limit means a >/>=/==/!= disabled this size. */
if (sizeLimit < 0) {
return false;
}
/* Reject a key below the min size floor */
if (sizeLimit > 0 && keySize < sizeLimit) {
return false;
}

View File

@ -66,10 +66,18 @@ public class AesGmac extends NativeStruct {
}
@Override
public void releaseNativeStruct() {
public synchronized void releaseNativeStruct() {
synchronized (stateLock) {
native_free();
super.releaseNativeStruct();
if (state == WolfCryptState.RELEASED) {
return;
}
synchronized (pointerLock) {
if (state != WolfCryptState.UNINITIALIZED) {
native_free();
}
super.releaseNativeStruct();
}
state = WolfCryptState.RELEASED;
}
}
@ -225,8 +233,10 @@ public class AesGmac extends NativeStruct {
}
private void throwIfKeyNotLoaded() throws IllegalStateException {
if (state != WolfCryptState.READY) {
throw new IllegalStateException("No key available");
synchronized (stateLock) {
if (state != WolfCryptState.READY) {
throw new IllegalStateException("No key available");
}
}
}

View File

@ -326,10 +326,10 @@ public class FeatureDetect {
public static native boolean RsaPssEnabled();
/**
* Tests if RSA-PSS salt lengths longer than the digest are compiled into
* the native wolfSSL library (WOLFSSL_PSS_LONG_SALT).
* Tests if RSA-PSS salt lengths longer than the digest are supported by
* the native wolfSSL library.
*
* @return true if enabled, otherwise false if not compiled in.
* @return true if supported, otherwise false.
*/
public static native boolean RsaPssLongSaltEnabled();

View File

@ -33,6 +33,7 @@ import org.junit.BeforeClass;
import java.util.List;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@ -41,6 +42,10 @@ import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.util.Arrays;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import java.io.FileNotFoundException;
import java.security.Security;
import java.security.Provider;
@ -57,6 +62,7 @@ import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorResult;
import java.security.cert.PKIXParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.CertificateException;
@ -97,6 +103,7 @@ public class WolfCryptPKIXCertPathValidatorTest {
protected static String caCertDer = null; /* ca-cert.der */
protected static String caEccCertDer = null; /* ca-ecc-cert.der */
protected static String crlDer = null; /* crl.der */
protected static String crlRevoked = null; /* crl.revoked */
/* RSA-based cert chain with intermediates:
* server/peer: server-int-cert.pem/der
@ -208,6 +215,8 @@ public class WolfCryptPKIXCertPathValidatorTest {
crlDer =
certPre.concat("examples/certs/crl/crl.der");
crlRevoked =
certPre.concat("examples/certs/crl/crl.revoked");
}
/**
@ -314,6 +323,312 @@ public class WolfCryptPKIXCertPathValidatorTest {
checkPKIXCertPathValidatorResult(result, caCert, certPubKey);
}
/* Build a single server-cert path validated against the RSA CA anchor. */
private CertPath singleServerCertPath(CertificateFactory certFactory)
throws Exception {
List<Certificate> certList = new ArrayList<>();
InputStream fis = new FileInputStream(serverCertDer);
certList.add(certFactory.generateCertificate(fis));
fis.close();
return certFactory.generateCertPath(certList);
}
/**
* PREFER_CRLS with NO_FALLBACK and no CRL source must fail closed with
* UNDETERMINED_REVOCATION_STATUS.
*/
@Test
public void testPreferCrlsNoFallbackWithoutCrlFailsClosed()
throws Exception {
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(false);
params.addCertPathChecker(rc);
try {
cpv.validate(path, params);
fail("Validation should fail closed with no CRL source");
} catch (CertPathValidatorException e) {
assertEquals(BasicReason.UNDETERMINED_REVOCATION_STATUS,
e.getReason());
}
}
/**
* With SOFT_FAIL, the missing-CRL determination is soft, so validation
* completes instead of failing closed. The soft-fail exception is not
* asserted here because addCertPathChecker() clones rc, so it lands on
* the clone rather than rc.
*/
@Test
public void testPreferCrlsNoFallbackWithoutCrlSoftFailPasses()
throws Exception {
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv =
CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK,
PKIXRevocationChecker.Option.SOFT_FAIL));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(false);
params.addCertPathChecker(rc);
cpv.validate(path, params);
}
/**
* SOFT_FAIL with revocation enabled but no CRL source must also complete.
* Revocation turns on the native CRL check, so the missing-CRL path must
* disable it under SOFT_FAIL to avoid a hard CRL_MISSING failure.
*/
@Test
public void testPreferCrlsNoFallbackRevocationEnabledSoftFailPasses()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println("CertPathValidator revocation status test " +
"skipped, CRL not compiled in");
return;
}
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK,
PKIXRevocationChecker.Option.SOFT_FAIL));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(true);
params.addCertPathChecker(rc);
cpv.validate(path, params);
}
/**
* Load a CRL from a file. Some CRL files carry a PEM text dump ahead
* of the PEM block, which not every CertificateFactory skips, so start
* at the PEM header when one is present.
*/
private CRL crlFromFile(CertificateFactory certFactory, String path)
throws Exception {
byte[] data = Files.readAllBytes(Paths.get(path));
int begin = new String(data, StandardCharsets.US_ASCII)
.indexOf("-----BEGIN X509 CRL-----");
if (begin > 0) {
data = Arrays.copyOfRange(data, begin, data.length);
}
return certFactory.generateCRL(new ByteArrayInputStream(data));
}
/**
* Validate the single server cert with a PREFER_CRLS/NO_FALLBACK checker
* and the given CRL supplied through a CertStore.
*/
private void validatePreferCrlsNoFallbackWithCrl(String crlPath,
boolean revocationEnabled) throws Exception {
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK));
/* CRL files are issued by ca-cert.der, the root for server-cert */
Collection<CRL> crls = new HashSet<>();
crls.add(crlFromFile(certFactory, crlPath));
List<CertStore> certStores = new ArrayList<>();
certStores.add(CertStore.getInstance("Collection",
new CollectionCertStoreParameters(crls)));
PKIXParameters params = new PKIXParameters(store);
params.setCertStores(certStores);
params.setRevocationEnabled(revocationEnabled);
params.addCertPathChecker(rc);
cpv.validate(path, params);
}
/**
* Validate a server cert with a PREFER_CRLS checker that allows OCSP
* fallback, SOFT_FAIL set, and no CRL source.
*/
private void validatePreferCrlsFallbackSoftFailWithoutCrl(
boolean revocationEnabled) throws Exception {
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.SOFT_FAIL));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(revocationEnabled);
params.addCertPathChecker(rc);
cpv.validate(path, params);
}
/**
* PREFER_CRLS with fallback allowed and no CRL source must not fail on
* a missing CRL, revocation is then determined by OCSP alone. With
* SOFT_FAIL an unreachable OCSP responder is not fatal, so validation
* should complete successfully.
*/
@Test
public void testPreferCrlsFallbackWithoutCrlSoftFailPasses()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println(
"PREFER_CRLS fallback test skipped, CRL not compiled in");
return;
}
validatePreferCrlsFallbackSoftFailWithoutCrl(false);
}
/**
* PREFER_CRLS with fallback allowed, SOFT_FAIL, no CRL source, and
* revocation enabled must not fail on the missing CRL, revocation is
* then determined only by OCSP.
*/
@Test
public void testPreferCrlsFallbackEnabledWithoutCrlSoftFailPasses()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println(
"PREFER_CRLS fallback test skipped, CRL not compiled in");
return;
}
validatePreferCrlsFallbackSoftFailWithoutCrl(true);
}
/**
* A PREFER_CRLS/NO_FALLBACK checker with CRLs actually loaded must still
* validate a non-revoked cert. The missing-CRL fail-closed path must not
* fire when a CRL source is present.
*/
@Test
public void testPreferCrlsNoFallbackWithCrlValidates()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println(
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
return;
}
validatePreferCrlsNoFallbackWithCrl(crlDer, true);
}
/**
* A checker added with addCertPathChecker() applies irrespective of
* setRevocationEnabled(), so PREFER_CRLS with a CRL in the CertStores is
* a supported CRL-only setup even with revocation disabled.
*/
@Test
public void testPreferCrlsNoFallbackRevocationDisabledWithCrlValidates()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println(
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
return;
}
validatePreferCrlsNoFallbackWithCrl(crlDer, false);
}
/**
* PREFER_CRLS with NO_FALLBACK, revocation disabled, and a CRL in the
* CertStores that revokes the server cert must fail validation, proving
* the supplied CRL is checked and not just ignored.
*/
@Test
public void testPreferCrlsNoFallbackRevocationDisabledRevokedFails()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println(
"PREFER_CRLS with CRL test skipped, CRL not compiled in");
return;
}
try {
validatePreferCrlsNoFallbackWithCrl(crlRevoked, false);
fail("Revoked cert should fail with revocation disabled and " +
"PREFER_CRLS");
} catch (CertPathValidatorException e) {
/* expected */
}
}
/**
* Test that setting the target cert constraints with
* PKIXParameters.setTargetCertConstraints() passes with correct cert
@ -2049,6 +2364,96 @@ public class WolfCryptPKIXCertPathValidatorTest {
}
}
/**
* PREFER_CRLS/NO_FALLBACK with revocation enabled and a CertStore that
* loads no matching CRL (loadedCount == 0) must fail closed.
*/
@Test
public void testPreferCrlsNoFallbackEmptyCertStoreFailsClosed()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println("CertPathValidator revocation status test " +
"skipped, CRL not compiled in");
return;
}
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(true);
params.addCertPathChecker(rc);
/* Non-empty store list holding no matching CRL drives loadedCount 0 */
List<CertStore> certStores = new ArrayList<>();
certStores.add(CertStore.getInstance("Collection",
new CollectionCertStoreParameters(new HashSet<CRL>())));
params.setCertStores(certStores);
try {
cpv.validate(path, params);
fail("Expected UNDETERMINED_REVOCATION_STATUS");
} catch (CertPathValidatorException e) {
assertEquals(BasicReason.UNDETERMINED_REVOCATION_STATUS,
e.getReason());
}
}
/**
* Same as above with SOFT_FAIL, validation must complete because the
* missing-CRL path disables the native CRL check.
*/
@Test
public void testPreferCrlsNoFallbackEmptyCertStoreSoftFailPasses()
throws Exception {
if (!WolfCrypt.CrlEnabled()) {
System.out.println("CertPathValidator revocation status test " +
"skipped, CRL not compiled in");
return;
}
KeyStore store = createKeyStoreFromFile(jksCaServerRSA2048,
keyStorePass);
if (store == null || store.size() != 1) {
throw new Exception("Error creating KeyStore");
}
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
CertPath path = singleServerCertPath(certFactory);
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
PKIXRevocationChecker rc =
(PKIXRevocationChecker) cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,
PKIXRevocationChecker.Option.NO_FALLBACK,
PKIXRevocationChecker.Option.SOFT_FAIL));
PKIXParameters params = new PKIXParameters(store);
params.setRevocationEnabled(true);
params.addCertPathChecker(rc);
List<CertStore> certStores = new ArrayList<>();
certStores.add(CertStore.getInstance("Collection",
new CollectionCertStoreParameters(new HashSet<CRL>())));
params.setCertStores(certStores);
cpv.validate(path, params);
}
/**
* Test that zero-length cert paths are valid per RFC 5280. This occurs
* when CertPathBuilder determines the trust anchor itself is the target.

View File

@ -1821,7 +1821,7 @@ public class WolfCryptSignatureTest {
if (!FeatureDetect.RsaPssLongSaltEnabled()) {
System.out.println("\tSkipping max salt lengths, " +
"WOLFSSL_PSS_LONG_SALT not compiled in");
"long PSS salts not supported by native wolfSSL");
return;
}
@ -2218,7 +2218,7 @@ public class WolfCryptSignatureTest {
/* Uses the maximum salt length for each digest */
if (!FeatureDetect.RsaPssLongSaltEnabled()) {
System.out.println(
"\tSkipping, WOLFSSL_PSS_LONG_SALT not compiled in");
"\tSkipping, long PSS salts not supported by native wolfSSL");
return;
}

View File

@ -1196,10 +1196,17 @@ public class WolfCryptUtilTest {
WolfCryptUtil.getDisabledAlgorithmsKeySizeLimit(
"RSA", "jdk.certpath.disabledAlgorithms"));
/* Unsupported operators are ignored */
/* The floor overload returns 0 for non-floor operators */
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 8192");
assertEquals("Unsupported operator should be ignored", 0,
assertEquals("keySize >= sets no minimum-size floor", 0,
WolfCryptUtil.getDisabledAlgorithmsKeySizeLimit(
"RSA", "jdk.certpath.disabledAlgorithms"));
/* An & chain still yields the floor from its < constraint */
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 1024 & keySize < 2048");
assertEquals("floor comes from the < half of an & chain", 2048,
WolfCryptUtil.getDisabledAlgorithmsKeySizeLimit(
"RSA", "jdk.certpath.disabledAlgorithms"));
@ -1290,6 +1297,126 @@ public class WolfCryptUtilTest {
}
}
@Test
public void testIsKeyAllowedKeySizeOperators() throws Exception {
String origProperty = Security.getProperty(
"jdk.certpath.disabledAlgorithms");
PublicKey rsaPub = null;
try {
KeyPairGenerator kpg =
KeyPairGenerator.getInstance("RSA", "wolfJCE");
kpg.initialize(2048);
rsaPub = kpg.generateKeyPair().getPublic();
} catch (Exception e) {
/* skip, RSA key generation not available */
return;
}
try {
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize == 2048");
assertFalse("keySize == N must reject a key of size N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize == 4096");
assertTrue("keySize == N must allow a key of a different size",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 2048");
assertFalse("keySize >= N must reject a key of size N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 4096");
assertTrue("keySize >= N must allow a key below N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize > 1024");
assertFalse("keySize > N must reject a key above N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize > 2048");
assertTrue("keySize > N must allow a key of size N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize != 4096");
assertFalse("keySize != N must reject a key of a different size",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize != 2048");
assertTrue("keySize != N must allow a key of size N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
/* < and <= remain handled by the minimum-size floor */
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize < 4096");
assertFalse("keySize < N must reject a key below N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize < 2048");
assertTrue("keySize < N must allow a key of size N",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize < 1024, RSA keySize > 4096");
assertTrue("floor plus a non-matching range must allow the key",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize < 1024, RSA keySize >= 2048");
assertFalse("floor plus a matching range must reject the key",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 2048");
assertFalse("keySize >= N rejects via CertPath overload",
WolfCryptUtil.isKeyAllowedForCertPath(rsaPub,
"jdk.certpath.disabledAlgorithms"));
/* & chains AND their keySize constraints, an entry disables the
* key only when every constraint holds */
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 1024 & keySize < 2048");
assertTrue("key outside an AND range must be allowed",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize >= 1024 & keySize <= 2048");
assertFalse("key inside an AND range must be rejected",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
/* denyAfter is not evaluated, the entry fails closed on keySize */
Security.setProperty("jdk.certpath.disabledAlgorithms",
"RSA keySize == 2048 & denyAfter 2999-01-01");
assertFalse("denyAfter entry applies unconditionally on keySize",
WolfCryptUtil.isKeyAllowed(rsaPub,
"jdk.certpath.disabledAlgorithms"));
} finally {
if (origProperty != null) {
Security.setProperty("jdk.certpath.disabledAlgorithms",
origProperty);
} else {
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
}
}
}
@Test
public void testIsKeyAllowedECNamedCurve() throws Exception {

View File

@ -2104,6 +2104,10 @@ public class WolfSSLKeyStoreTest {
WolfCryptProvider prov = null;
KeyStore store = null;
/* The Android platform PKCS12 provider cannot read the PBES2/PBKDF2
* client.p12, matching testLoadWKSasJKSFromFile which also skips. */
Assume.assumeTrue(!isAndroid());
/* Use client.wks (clientWKS) to test. Any WKS KeyStore could be used,
* this was just picked since was first used/tested in test above. */

View File

@ -377,6 +377,46 @@ public class AesGmacTest {
gmac.releaseNativeStruct();
}
@Test
public void testAesGmacSetKeyAfterReleaseThrows() {
if (!FeatureDetect.AesGmacEnabled()) {
/* skip test if AES-GMAC is not compiled in native wolfCrypt */
return;
}
AesGmac gmac = new AesGmac();
gmac.setKey(new byte[16]);
gmac.releaseNativeStruct();
/* Re-keying a released object must throw, its AES was freed */
try {
gmac.setKey(new byte[16]);
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
/* Expected */
}
}
@Test
public void testAesGmacReleaseBeforeSetKey() {
if (!FeatureDetect.AesGmacEnabled()) {
/* skip test if AES-GMAC is not compiled in native wolfCrypt */
return;
}
/* Release with no key set must free quietly, twice is harmless */
AesGmac gmac = new AesGmac();
gmac.releaseNativeStruct();
gmac.releaseNativeStruct();
try {
gmac.setKey(new byte[16]);
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
/* Expected */
}
}
@Test
public void testAesGmacInvalidInputs() {
if (!FeatureDetect.AesGmacEnabled()) {

View File

@ -207,6 +207,25 @@ public class AesOfbTest {
aesOfb.releaseNativeStruct();
}
/**
* A DECRYPT_MODE key schedule must still recover ciphertext produced
* under ENCRYPT_MODE.
*/
@Test
public void aes128OfbDecryptModeSetKeyRoundTrip() {
AesOfb enc = new AesOfb();
enc.setKey(KEY_128, IV_128, AesOfb.ENCRYPT_MODE);
byte[] ciphertext = enc.encrypt(PLAINTEXT_128);
assertArrayEquals(CIPHERTEXT_128, ciphertext);
enc.releaseNativeStruct();
AesOfb dec = new AesOfb();
dec.setKey(KEY_128, IV_128, AesOfb.DECRYPT_MODE);
byte[] decrypted = dec.decrypt(ciphertext);
assertArrayEquals(PLAINTEXT_128, decrypted);
dec.releaseNativeStruct();
}
@Test
public void aes128OfbLongDataTest() {
AesOfb aesOfb = new AesOfb();

View File

@ -297,6 +297,19 @@ public class EccTest {
}
}
@Test
public void eccMakeKeyOnCurveNullRngReportsBadFuncArg() {
Ecc alice = new Ecc();
try {
/* A null Rng is an argument error, not a curve problem, so it
* must be reported as BAD_FUNC_ARG */
alice.makeKeyOnCurve(null, 32, "secp256r1");
fail("null Rng should fail with exception");
} catch (WolfCryptException e) {
assertEquals(WolfCryptError.BAD_FUNC_ARG, e.getError());
}
}
@Test
public void eccPrivateToPkcs8() {
Ecc alice = new Ecc();

View File

@ -423,6 +423,21 @@ public class RsaTest {
pub.releaseNativeStruct();
}
@Test
public void rsaPrivateKeyToPkcs8RoundTrip() {
Rsa key = makeKeyWithRetry(2048, 65537, rng);
byte[] pkcs8 = key.privateKeyEncodePKCS8();
assertNotNull(pkcs8);
assertTrue(pkcs8.length > 0);
key.releaseNativeStruct();
/* PKCS8 output must decode back into a usable private key */
Rsa decoded = new Rsa();
decoded.decodePrivateKeyPKCS8(pkcs8);
decoded.releaseNativeStruct();
}
@Test
public void publicKeyDecodeAndEncodeWithByteBuffer() {
Rsa key = new Rsa();

View File

@ -36,6 +36,7 @@ import com.wolfssl.wolfcrypt.FeatureDetect;
import com.wolfssl.wolfcrypt.SlhDsa;
import com.wolfssl.wolfcrypt.Rng;
import com.wolfssl.wolfcrypt.Sha256;
import com.wolfssl.wolfcrypt.Sha384;
import com.wolfssl.wolfcrypt.Sha512;
import com.wolfssl.wolfcrypt.WolfCrypt;
import com.wolfssl.wolfcrypt.WolfCryptError;
@ -766,20 +767,17 @@ public class SlhDsaTest {
byte[] msg = "pre-hash pairing check".getBytes();
/* Independently validate the FIPS 205 Section 10.2.2 pre-hash pairing
* for the SHA2 sets. signPreHash() chooses the hash in native C. Here
* we reconstruct the expected digest and hashType in Java and confirm
* the signature verifies through the explicit-digest verifyHash()
* path, then that the other SHA-2 hash does NOT verify. Sign and verify
* do not share the digest helper, so a wrong-but-consistent pairing is
* caught (128-bit sets use SHA-256, 192/256-bit sets use SHA-512). The
* SHAKE sets cannot be cross-checked here (no Java SHAKE digest). */
/* Confirm the pre-hash signPreHash() picks natively (SHA-256 for
* 128-bit sets, SHA-512 for 192/256-bit) by verifying with the
* expected digest, then with a mismatched one. The mismatch must be
* at least as strong as the set, weaker hashes are rejected with
* BAD_FUNC_ARG. SHAKE sets are not checked (no Java SHAKE digest). */
checkSha2Pairing(SlhDsa.SLH_DSA_SHA2_128F, msg,
sha256(msg), WolfCrypt.WC_HASH_TYPE_SHA256,
sha512(msg), WolfCrypt.WC_HASH_TYPE_SHA512);
checkSha2Pairing(SlhDsa.SLH_DSA_SHA2_192F, msg,
sha512(msg), WolfCrypt.WC_HASH_TYPE_SHA512,
sha256(msg), WolfCrypt.WC_HASH_TYPE_SHA256);
sha384(msg), WolfCrypt.WC_HASH_TYPE_SHA384);
}
@Test
@ -888,6 +886,12 @@ public class SlhDsaTest {
return sha.digest();
}
private static byte[] sha384(byte[] in) {
Sha384 sha = new Sha384();
sha.update(in);
return sha.digest();
}
private static byte[] sha512(byte[] in) {
Sha512 sha = new Sha512();
sha.update(in);