Skip to content

Commit

Permalink
JCE: add Security property support for wolfjce.mapJKStoWKS and wolfjc…
Browse files Browse the repository at this point in the history
…e.mapPKCS12toWKS
  • Loading branch information
cconlon committed Nov 13, 2024
1 parent b302945 commit c4d9b84
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 0 deletions.
34 changes: 34 additions & 0 deletions README_JCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,40 @@ 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.mapJKStoWKS | UNSET | true | Register fake JKS KeyStore service mapped to WKS |
| wolfjce.mapPKCS12toWKS | UNSET | true | Register fake PKCS12 KeyStore service mapped to WKS |

**wolfjce.mapJKStoWKS** - this Security property should be used with caution.
When enabled, this will register a "JKS" KeyStore type in wolfJCE, which means
calling applications using `KeyStore.getInstance("JKS")` will get a KeyStore
implementation from wolfJCE. BUT, this KeyStore type will actually be a
WolfSSLKeyStore (WKS) type internally. Loading actual JKS files will fail.
This can be helpful when FIPS compliance is required, but existing code gets
a JKS KeyStore instance - and this assumes the caller has the flexibility to
actually load a real WKS KeyStore file into this KeyStore object. If this
property is being set at runtime programatically, the wolfJCE provider services
will need to be refreshed / reloaded, by doing:

```
WolfCryptProvider prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();
```

**wolfjce.mapPKCS12toWKS** - this Security property should be used with caution.
When enabled, this will register a "PKCS12" KeyStore type in wolfJCE, which
means calling applications using `KeyStore.getInstance("PKCS12")` will get a
KeyStore implementation from wolfJCE. BUT, this KeyStore type will actually be a
WolfSSLKeyStore (WKS) type internally. Loading actual PKCS12 files will fail.
This can be helpful when FIPS compliance is required, but existing code gets
a PKCS12 KeyStore instance - and this assumes the caller has the flexibility to
actually load a real WKS KeyStore file into this KeyStore object. If this
property is being set at runtime programatically, the wolfJCE provider services
will need to be refreshed / reloaded, by doing:

```
WolfCryptProvider prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();
```

#### System Property Support

Expand Down
48 changes: 48 additions & 0 deletions src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package com.wolfssl.provider.jce;

import java.security.Provider;
import java.security.Security;
import com.wolfssl.wolfcrypt.FeatureDetect;
import com.wolfssl.wolfcrypt.Fips;

Expand All @@ -37,6 +38,27 @@ public final class WolfCryptProvider extends Provider {
*/
public WolfCryptProvider() {
super("wolfJCE", 1.7, "wolfCrypt JCE Provider");
registerServices();
}

/**
* Refresh the services provided by this JCE provider.
*
* This is required when one of the Security properties has been changed
* that affect the services offered by this provider. For example:
* wolfjce.mapJKStoWKS
* wolfjce.mapPKCS12toWKS
*/
public void refreshServices() {
registerServices();
}

/**
* Register services provided by wolfJCE, called by class constructor.
*/
private void registerServices() {
String mapJksToWks = null;
String mapPkcs12ToWks = null;

/* MessageDigest */
if (FeatureDetect.Md5Enabled()) {
Expand Down Expand Up @@ -222,6 +244,32 @@ public WolfCryptProvider() {
put("KeyStore.WKS",
"com.wolfssl.provider.jce.WolfSSLKeyStore");

/* Fake mapping of JKS to WKS type. Use with caution! This is
* usually used when FIPS compliance is needed but code cannot be
* changed that creates a JKS KeyStore object type. Any files loaded
* into this fake JKS KeyStore MUST be of actual type WKS or failures
* will happen. Remove service first here in case of refresh. */
remove("KeyStore.JKS");
mapJksToWks = Security.getProperty("wolfjce.mapJKStoWKS");
if (mapJksToWks != null && !mapJksToWks.isEmpty() &&
mapJksToWks.equalsIgnoreCase("true")) {
put("KeyStore.JKS",
"com.wolfssl.provider.jce.WolfSSLKeyStore");
}

/* Fake mapping of PKCS12 to WKS type. Use with caution! This is
* usually used when FIPS compliance is needed but code cannot be
* changed that creates a JKS KeyStore object type. Any files loaded
* into this fake JKS KeyStore MUST be of actual type WKS or failures
* will happen. Remove service first here in case of refresh. */
remove("KeyStore.PKCS12");
mapPkcs12ToWks = Security.getProperty("wolfjce.mapPKCS12toWKS");
if (mapPkcs12ToWks != null && !mapPkcs12ToWks.isEmpty() &&
mapPkcs12ToWks.equalsIgnoreCase("true")) {
put("KeyStore.PKCS12",
"com.wolfssl.provider.jce.WolfSSLKeyStore");
}

/* If using a FIPS version of wolfCrypt, allow private key to be
* exported for use. Only applicable to FIPS 140-3 */
if (Fips.enabled) {
Expand Down
142 changes: 142 additions & 0 deletions src/test/java/com/wolfssl/provider/jce/test/WolfSSLKeyStoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ public class WolfSSLKeyStoreTest {
private static Certificate[] eccServerChain = null; /* ECC chain */
private static Certificate[] invalidChain = null;

/* Example .jks KeyStore file paths */
private static String clientJKS = null; /* client.jks */

/* Examnple .p12 KeyStore file paths */
private static String clientP12 = null; /* client.p12 */

/* Example .wks KeyStore file paths */
private static String clientWKS = null; /* client.wks */
private static String clientRsa1024WKS = null; /* client-rsa-1024.wks */
Expand Down Expand Up @@ -381,6 +387,14 @@ public static void testSetupAndProviderInstallation()
intEccInt2CertDer =
certPre.concat("examples/certs/intermediate/ca-int2-ecc-cert.der");

/* Set paths to example JKS KeyStore files */
clientJKS =
certPre.concat("examples/certs/client.jks");

/* Set paths to example PKCS12 KeyStore files */
clientP12 =
certPre.concat("examples/certs/client.p12");

/* Set paths to example WKS KeyStore files */
clientWKS =
certPre.concat("examples/certs/client.wks");
Expand Down Expand Up @@ -1426,6 +1440,134 @@ public void testLoadWKSFromFile()
assertEquals(1, store.size());
}

@Test
public void testLoadWKSasJKSFromFile()
throws KeyStoreException, IOException, FileNotFoundException,
NoSuchProviderException, NoSuchAlgorithmException,
CertificateException, InvalidKeySpecException,
UnrecoverableKeyException {

WolfCryptProvider prov = null;
KeyStore store = null;

/* Use client.wks (clientWKS) to test. Any WKS KeyStore could be used,
* this was just picked since was first used/tested in test above. */

/* If Security property "wolfjce.mapJKStoWKS=true" has been set,
* WolfSSLKeyStore should be able to load a WKS file when using a
* "JKS" KeyStore type. */
String origProperty = Security.getProperty("wolfjce.mapJKStoWKS");

/* The wolfJCE service list needs to be refreshed after changing
* Security properties that will adjust the services we register */
Security.setProperty("wolfjce.mapJKStoWKS", "true");
prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();

/* Load WKS as JKS, should work w/o exception */
store = KeyStore.getInstance("JKS");
assertTrue(store.getProvider().contains("wolfJCE"));
store.load(new FileInputStream(clientWKS), storePass.toCharArray());
assertEquals(2, store.size());

/* Load JKS as JKS when this is set should fail, since using WKS
* implementation underneath fake JKS mapping */
try {
store.load(new FileInputStream(clientJKS), storePass.toCharArray());
fail("Loaded JKS as JKS, but shouldn't with fake mapping set");
} catch (IOException e) {
/* expected */
}

/* Set mapping to false, loading a WKS as JKS should throw exception */
Security.setProperty("wolfjce.mapJKStoWKS", "false");
prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();
store = KeyStore.getInstance("JKS");
assertTrue(!store.getProvider().contains("wolfJCE"));
try {
store.load(new FileInputStream(clientWKS), storePass.toCharArray());
fail("Loaded WKS as JKS, but shouldn't have been able to");
} catch (IOException e) {
/* expected */
}

/* Loading JKS as JKS should work when mapping not set */
store.load(new FileInputStream(clientJKS), storePass.toCharArray());

/* Restore Security property */
if (origProperty == null) {
Security.setProperty("wolfjce.mapJKStoWKS", "");
}
else {
Security.setProperty("wolfjce.mapJKStoWKS", origProperty);
}
}

@Test
public void testLoadWKSasPKCS12FromFile()
throws KeyStoreException, IOException, FileNotFoundException,
NoSuchProviderException, NoSuchAlgorithmException,
CertificateException, InvalidKeySpecException,
UnrecoverableKeyException {

WolfCryptProvider prov = null;
KeyStore store = null;

/* Use client.wks (clientWKS) to test. Any WKS KeyStore could be used,
* this was just picked since was first used/tested in test above. */

/* If Security property "wolfjce.mapPKCS12toWKS=true" has been set,
* WolfSSLKeyStore should be able to load a WKS file when using a
* "PKCS12" KeyStore type. */
String origProperty = Security.getProperty("wolfjce.mapPKCS12toWKS");

/* The wolfJCE service list needs to be refreshed after changing
* Security properties that will adjust the services we register */
Security.setProperty("wolfjce.mapPKCS12toWKS", "true");
prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();

/* Load WKS as PKCS12, should work w/o exception */
store = KeyStore.getInstance("PKCS12");
assertTrue(store.getProvider().contains("wolfJCE"));
store.load(new FileInputStream(clientWKS), storePass.toCharArray());
assertEquals(2, store.size());

/* Load PKCS12 as PKCS12 when this is set should fail, since using WKS
* implementation underneath fake PKCS12 mapping */
try {
store.load(new FileInputStream(clientP12), storePass.toCharArray());
fail("Loaded PKCS12 as PKCS12, but shouldn't with fake mapping set");
} catch (IOException e) {
/* expected */
}

/* Set mapping to false, loading WKS as PKCS12 should throw exception */
Security.setProperty("wolfjce.mapPKCS12toWKS", "false");
prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
prov.refreshServices();
store = KeyStore.getInstance("PKCS12");
assertTrue(!store.getProvider().contains("wolfJCE"));
try {
store.load(new FileInputStream(clientWKS), storePass.toCharArray());
fail("Loaded WKS as PKCS12, but shouldn't have been able to");
} catch (IOException e) {
/* expected */
}

/* Loading PKCS12 as PKCS12 should work when mapping not set */
store.load(new FileInputStream(clientP12), storePass.toCharArray());

/* Restore Security property */
if (origProperty == null) {
Security.setProperty("wolfjce.mapPKCS12toWKS", "");
}
else {
Security.setProperty("wolfjce.mapPKCS12toWKS", origProperty);
}
}

@Test
public void testLoadSystemCAKeyStore()
throws KeyStoreException, IOException, FileNotFoundException,
Expand Down

0 comments on commit c4d9b84

Please sign in to comment.