F-4354 / F-4355: bound encoded entry and HMAC sizes in WolfSSLKeyStore.engineLoad
parent
43c0058a8e
commit
865c769427
|
|
@ -36,6 +36,7 @@ file for JCE provider customization:
|
|||
| --- | --- | --- | --- |
|
||||
| wolfjce.wks.iterationCount | 210,000 | Numeric | PBKDF2 iteration count (10,000 minimum) |
|
||||
| wolfjce.wks.maxCertChainLength | 100 | Integer | Max cert chain length |
|
||||
| wolfjce.wks.maxEntrySize | 10485760 | Integer | Max encoded entry size in bytes when loading WKS (10 MB default) |
|
||||
| wolfjce.keystore.kekCacheEnabled | false | true | Enable KEK caching in WKS KeyStore for performance |
|
||||
| wolfjce.keystore.kekCacheTtlSec | 300 | Integer | KEK cache TTL in seconds (1 second minimum) |
|
||||
| wolfjce.mapJKStoWKS | UNSET | true | Register fake JKS KeyStore service mapped to WKS |
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ please reference the appropriate Security Policy or contact fips@wolfssl.com.
|
|||
| --- | --- | --- | --- |
|
||||
| `wolfjce.wks.iterationCount` | 210,000 | 10,000 | PBKDF2 iteration count |
|
||||
| `wolfjce.wks.maxCertChainLength` | 100 | N/A | Max cert chain length |
|
||||
| `wolfjce.wks.maxEntrySize` | 10485760 | N/A | Max encoded entry size in bytes |
|
||||
| `wolfjce.keystore.kekCacheEnabled` | false | N/A | Enable KEK caching |
|
||||
| `wolfjce.keystore.kekCacheTtlSec` | 300 | 1 | Cache TTL in seconds |
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ extern "C" {
|
|||
#define com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_HMAC_KEY_LENGTH 64L
|
||||
#undef com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_DEFAULT_MAX_CHAIN_COUNT
|
||||
#define com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_DEFAULT_MAX_CHAIN_COUNT 100L
|
||||
#undef com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_DEFAULT_MAX_ENTRY_SIZE
|
||||
#define com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_DEFAULT_MAX_ENTRY_SIZE 10485760L
|
||||
#undef com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_MAGIC_NUMBER
|
||||
#define com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_MAGIC_NUMBER 7L
|
||||
#undef com_wolfssl_provider_jce_WolfSSLKeyStore_WKS_STORE_VERSION
|
||||
|
|
|
|||
|
|
@ -224,6 +224,11 @@ public class WolfSSLKeyStore extends KeyStoreSpi {
|
|||
private static final int WKS_DEFAULT_MAX_CHAIN_COUNT = 100;
|
||||
private static final int WKS_MAX_CHAIN_COUNT;
|
||||
|
||||
/* Max encoded entry size in bytes, configurable via
|
||||
* 'wolfjce.wks.maxEntrySize' Security property */
|
||||
private static final int WKS_DEFAULT_MAX_ENTRY_SIZE = 10 * 1024 * 1024;
|
||||
private static final int WKS_MAX_ENTRY_SIZE;
|
||||
|
||||
/* WKS magic number, used when storing KeyStore to OutputStream */
|
||||
private static final int WKS_MAGIC_NUMBER = 7;
|
||||
|
||||
|
|
@ -341,8 +346,10 @@ public class WolfSSLKeyStore extends KeyStoreSpi {
|
|||
static {
|
||||
int iCount = WKS_PBKDF2_DEFAULT_ITERATIONS;
|
||||
int cLength = WKS_DEFAULT_MAX_CHAIN_COUNT;
|
||||
int eLength = WKS_DEFAULT_MAX_ENTRY_SIZE;
|
||||
String iterations = null;
|
||||
String chainCount = null;
|
||||
String entrySize = null;
|
||||
|
||||
/* Set PBKDF2 iteration count, using default or one set by
|
||||
* user in 'wolfjce.wks.iterationCount' Security property in
|
||||
|
|
@ -389,6 +396,27 @@ public class WolfSSLKeyStore extends KeyStoreSpi {
|
|||
|
||||
log("setting max cert chain length: " + cLength);
|
||||
WKS_MAX_CHAIN_COUNT = cLength;
|
||||
|
||||
/* Set max encoded entry size limit, using default or one set with
|
||||
* `wolfjce.wks.maxEntrySize` Security property */
|
||||
entrySize = Security.getProperty("wolfjce.wks.maxEntrySize");
|
||||
if (entrySize != null && !entrySize.isEmpty()) {
|
||||
try {
|
||||
eLength = Integer.parseInt(entrySize);
|
||||
if (eLength <= 0) {
|
||||
log("wolfjce.wks.maxEntrySize (" + eLength +
|
||||
") lower than 0, using default");
|
||||
eLength = WKS_DEFAULT_MAX_ENTRY_SIZE;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
/* Error parsing property, fall back to default */
|
||||
log("error parsing wolfjce.wks.maxEntrySize property, " +
|
||||
"using default instead");
|
||||
}
|
||||
}
|
||||
|
||||
log("setting max entry size: " + eLength);
|
||||
WKS_MAX_ENTRY_SIZE = eLength;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2385,6 +2413,12 @@ public class WolfSSLKeyStore extends KeyStoreSpi {
|
|||
throw new IOException("Invalid encoded length, negative");
|
||||
}
|
||||
|
||||
if (encodedLen > WKS_MAX_ENTRY_SIZE) {
|
||||
throw new IOException("Encoded entry length (" +
|
||||
encodedLen + ") is larger than max allowed: " +
|
||||
WKS_MAX_ENTRY_SIZE);
|
||||
}
|
||||
|
||||
/* encoded entry */
|
||||
encodedEntry = new byte[encodedLen];
|
||||
bytesRead = dis.read(encodedEntry);
|
||||
|
|
@ -2444,8 +2478,10 @@ public class WolfSSLKeyStore extends KeyStoreSpi {
|
|||
|
||||
/* HMAC len and HMAC */
|
||||
hmacLen = dis.readInt();
|
||||
if (hmacLen < 0) {
|
||||
throw new IOException("Invalid HMAC length, negative");
|
||||
if (hmacLen != WKS_HMAC_KEY_LENGTH) {
|
||||
throw new IOException(
|
||||
"HMAC length (" + hmacLen + ") is different than " +
|
||||
"expected (" + WKS_HMAC_KEY_LENGTH + ")");
|
||||
}
|
||||
hmac = new byte[hmacLen];
|
||||
hmacLen = dis.read(hmac);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
|
@ -401,6 +402,62 @@ public class WolfSSLKeyStoreTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A crafted WKS stream with an oversized encoded entry length must be
|
||||
* rejected with an IOException, not trigger an unbounded allocation.
|
||||
* Uses a null password so the HMAC integrity check is skipped.
|
||||
*/
|
||||
@Test
|
||||
public void testEngineLoadRejectsOversizedEntry() throws Exception {
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeInt(7); /* WKS magic number */
|
||||
dos.writeInt(1); /* WKS store version */
|
||||
dos.writeInt(1); /* entry count */
|
||||
dos.writeInt(2); /* entry type: certificate */
|
||||
dos.writeUTF("evil"); /* alias */
|
||||
dos.writeInt(Integer.MAX_VALUE); /* encoded entry length */
|
||||
dos.flush();
|
||||
|
||||
KeyStore store = KeyStore.getInstance("WKS", "wolfJCE");
|
||||
try {
|
||||
store.load(new ByteArrayInputStream(bos.toByteArray()), null);
|
||||
fail("oversized encoded entry length should throw IOException");
|
||||
} catch (IOException e) {
|
||||
/* expected, allocation must be bounded before it happens */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A crafted WKS stream with an HMAC length that is not the expected
|
||||
* HMAC-SHA512 size must be rejected with an IOException, not trigger an
|
||||
* unbounded allocation. Uses a null password so the HMAC integrity
|
||||
* check is skipped.
|
||||
*/
|
||||
@Test
|
||||
public void testEngineLoadRejectsInvalidHmacLength() throws Exception {
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeInt(7); /* WKS magic number */
|
||||
dos.writeInt(1); /* WKS store version */
|
||||
dos.writeInt(0); /* entry count */
|
||||
dos.writeInt(16); /* salt length */
|
||||
dos.write(new byte[16]); /* salt */
|
||||
dos.writeInt(10000); /* PBKDF2 iterations */
|
||||
dos.writeInt(Integer.MAX_VALUE); /* HMAC length */
|
||||
dos.flush();
|
||||
|
||||
KeyStore store = KeyStore.getInstance("WKS", "wolfJCE");
|
||||
try {
|
||||
store.load(new ByteArrayInputStream(bos.toByteArray()), null);
|
||||
fail("invalid HMAC length should throw IOException");
|
||||
} catch (IOException e) {
|
||||
/* expected, allocation must be bounded before it happens */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create PrivateKey and Certificate objects based on files.
|
||||
|
|
|
|||
Loading…
Reference in New Issue