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 fc85641
Show file tree
Hide file tree
Showing 13 changed files with 239 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ protected void onCreate(Bundle savedInstanceState) {
public void testFindProvider(TextView tv)
throws NoSuchProviderException, NoSuchAlgorithmException {

Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
if (p == null) {
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public static void testProviderInstallationAtRuntime() {
System.out.println("JCE WolfCryptKeyAgreementTest Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMac Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMessageDigestMd5Test");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMessageDigestSha256 Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMessageDigestSha384 Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMessageDigestSha512 Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptMessageDigestSha Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static void testProviderInstallationAtRuntime()
/* Install wolfJCE provider at runtime. Not registering as top priority
* provider so we can still likely get SunJCE or platform provider
* when not specifying wolfJCE explicitly. */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider(provider);
assertNotNull(p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static void testProviderInstallationAtRuntime()
System.out.println("JCE WolfCryptSignature Class");

/* install wolfJCE provider at runtime */
Security.addProvider(new WolfCryptProvider());
Security.insertProviderAt(new WolfCryptProvider(), 1);

Provider p = Security.getProvider("wolfJCE");
assertNotNull(p);
Expand Down
147 changes: 147 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,139 @@ public void testLoadWKSFromFile()
assertEquals(1, store.size());
}

//CHRIS
@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");
assertNotNull(store);
assertNotNull(store.getProvider());
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");
assertNotNull(store);
assertNotNull(store.getProvider());
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 fc85641

Please sign in to comment.