JCE: add Security property support for wolfjce.mapJKStoWKS and wolfjce.mapPKCS12toWKS

pull/83/head
Chris Conlon 2024-11-13 10:55:07 -07:00
parent b302945e5b
commit fc85641fab
13 changed files with 239 additions and 10 deletions

View File

@ -80,7 +80,7 @@ public class MainActivity extends AppCompatActivity {
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) {

View File

@ -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

View File

@ -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;
@ -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()) {
@ -222,6 +244,32 @@ public final class WolfCryptProvider extends Provider {
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) {

View File

@ -140,7 +140,7 @@ public class WolfCryptKeyAgreementTest {
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);

View File

@ -92,7 +92,7 @@ public class WolfCryptMacTest {
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);

View File

@ -64,7 +64,7 @@ public class WolfCryptMessageDigestMd5Test {
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);

View File

@ -64,7 +64,7 @@ public class WolfCryptMessageDigestSha256Test {
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);

View File

@ -64,7 +64,7 @@ public class WolfCryptMessageDigestSha384Test {
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);

View File

@ -64,7 +64,7 @@ public class WolfCryptMessageDigestSha512Test {
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);

View File

@ -65,7 +65,7 @@ public class WolfCryptMessageDigestShaTest {
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);

View File

@ -95,7 +95,7 @@ public class WolfCryptSecretKeyFactoryTest {
/* 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);

View File

@ -93,7 +93,7 @@ public class WolfCryptSignatureTest {
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);

View File

@ -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 */
@ -381,6 +387,14 @@ public class WolfSSLKeyStoreTest {
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");
@ -1426,6 +1440,139 @@ public class WolfSSLKeyStoreTest {
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,