From 88dc6bb4df421a809305d9c6639c474b43a999ae Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 5 Aug 2026 11:23:38 -0600 Subject: [PATCH] wolfCrypt JNI/JCE: update manual for current wolfcrypt-jni (PQC, WKS, JPMS, properties) --- common/table-code.css | 20 +++ wolfCrypt-JNI/mkdocs.yml | 4 +- wolfCrypt-JNI/src/chapter02.md | 24 ++- wolfCrypt-JNI/src/chapter03.md | 42 ++++- wolfCrypt-JNI/src/chapter04.md | 63 +++++++- wolfCrypt-JNI/src/chapter05.md | 12 +- wolfCrypt-JNI/src/chapter06.md | 139 ++++++++++++++++- wolfCrypt-JNI/src/chapter08.md | 88 ++++++++++- wolfCrypt-JNI/src/chapter09.md | 272 ++++++++++++++++++++++++++++----- 9 files changed, 607 insertions(+), 57 deletions(-) create mode 100644 common/table-code.css diff --git a/common/table-code.css b/common/table-code.css new file mode 100644 index 00000000..389c3679 --- /dev/null +++ b/common/table-code.css @@ -0,0 +1,20 @@ +/* Keep inline code spans (configure options, property names, etc.) on a + * single line inside tables. The code column then sizes to its content and + * prose columns absorb the wrapping instead. Opt in per manual via the + * extra_css list in its mkdocs.yml. */ +/* display: inline-block is required for WebKit (Safari): it otherwise sizes + * table columns using the hyphen break opportunities inside code spans, then + * line-breaks the span (e.g. --enable-slhdsa) even under white-space: nowrap. + * As an inline-block atom the span's full width feeds into column sizing. + * The word-break/hyphens resets guard the wrapped-prose case (Notes columns), + * where WebKit can still honor the theme's `code { word-break: break-word }` + * break opportunities inside a nowrap inline element. */ +.md-typeset table:not([class]) th code, +.md-typeset table:not([class]) td code { + display: inline-block; + white-space: nowrap; + word-break: normal; + overflow-wrap: normal; + -webkit-hyphens: none; + hyphens: none; +} diff --git a/wolfCrypt-JNI/mkdocs.yml b/wolfCrypt-JNI/mkdocs.yml index 8630382b..55db00d6 100644 --- a/wolfCrypt-JNI/mkdocs.yml +++ b/wolfCrypt-JNI/mkdocs.yml @@ -2,7 +2,7 @@ site_name: wolfCrypt JCE Provider and JNI Manual site_url: https://wolfssl.com/ docs_dir: build/html/ site_dir: html/ -copyright: wolfSSL Inc. 2024 +copyright: wolfSSL Inc. 2026 nav: - "1. Introduction": index.md - "2. Requirements": chapter02.md @@ -28,7 +28,7 @@ theme: favicon: logo.png feature: tabs: true -extra_css: [skin.css] +extra_css: [skin.css, table-code.css] extra: generator: false use_directory_urls: false diff --git a/wolfCrypt-JNI/src/chapter02.md b/wolfCrypt-JNI/src/chapter02.md index 3051456d..06999d98 100644 --- a/wolfCrypt-JNI/src/chapter02.md +++ b/wolfCrypt-JNI/src/chapter02.md @@ -28,12 +28,34 @@ $ export JUNIT_HOME=/path/to/jar/files As a wrapper around the native wolfCrypt library, [wolfSSL](https://www.wolfssl.com/products/wolfssl/) must be installed and placed on the include and library search paths. wolfJCE can be compiled against either the FIPS 140-2/3 or non-FIPS version of the wolfSSL/wolfCrypt native library. -### Compiling wolfSSL/wolfCrypt +### Compiling wolfSSL/wolfCrypt To compile and install native wolfSSL in a Unix/Linux environment, please follow build instructions in the [wolfSSL Manual](https://www.wolfssl.com/documentation/manuals/wolfssl/index.html). The most common way to compile wolfSSL is with the Autoconf system using configure. You can build and install a wolfSSL (wolfssl-x.x.x), wolfSSL FIPS release (wolfssl-x.x.x-commercial-fips), or wolfSSL FIPS Ready release. With any of these archives, you will need to use the `--enable-jni` ./configure option in addition to any other package-specific configure option requirements (ex: `--enable-fips`). +The `--enable-jni` option includes all native wolfSSL features needed by both wolfCrypt JNI/JCE (this package) as well as wolfSSL JNI/JSSE (a separate package). If you want the minimal set of requirements needed for only wolfJCE, you can instead use `--enable-keygen --enable-crl`, where CRL support is needed for the JCE `CertPathValidator (PKIX)` CRL support. + +#### Native Feature Requirements for Post-Quantum and Hash-Based Algorithms + +Several algorithms supported by wolfJCE are **not** enabled by `--enable-jni` alone and require additional native wolfSSL configure options. If the matching native feature is not compiled into wolfSSL, wolfJCE will still compile and run normally, but the corresponding services will not be registered by the provider. + +| Algorithm | Native wolfSSL configure option | Notes | +| --- | --- | --- | +| ML-KEM (FIPS 203) | `--enable-mlkem` | The `javax.crypto.KEM` service additionally requires running on JDK 21 or later | +| ML-DSA (FIPS 204) | `--enable-mldsa` | The older `--enable-dilithium` is an accepted alias | +| SLH-DSA (FIPS 205) | `--enable-slhdsa` | `--enable-slhdsa` builds the six SHAKE parameter sets. Use `--enable-slhdsa=yes,sha2` to build all twelve (recommended, since the `SLH-DSA-SHA2-128f` default lives in the SHA2 family) | +| XMSS / XMSS^MT (RFC 8391) | `--enable-xmss` | Requires wolfSSL 5.9.2 or later. SHAKE-based parameter sets additionally require `--enable-sha3`. Verify-only in wolfJCE | +| LMS / HSS (RFC 8554) | `--enable-lms` | `--enable-lms=verify-only` is also sufficient. SHAKE256 parameter sets additionally require `--enable-sha3`. Verify-only in wolfJCE | + +Note that these algorithms are **not** enabled by `--enable-all` or +`--enable-all-crypto`. On wolfSSL versions newer than 5.9.2, all five algorithm +families in the table above can be enabled at once with +`--enable-all-quantum-crypto`, which enables ML-KEM, ML-DSA, XMSS, LMS, and all +twelve SLH-DSA parameter sets (`yes,sha2`). + +XMSS/XMSS^MT and LMS/HSS support in wolfJCE is signature **verification** and public-key handling only. Key generation and signing are not supported, since stateful hash-based signing belongs in hardware (NIST SP 800-208). + **wolfSSL Standard Build**: ``` $ cd wolfssl-x.x.x diff --git a/wolfCrypt-JNI/src/chapter03.md b/wolfCrypt-JNI/src/chapter03.md index c2e6086c..c61ab4ea 100644 --- a/wolfCrypt-JNI/src/chapter03.md +++ b/wolfCrypt-JNI/src/chapter03.md @@ -2,7 +2,7 @@ Before following steps in this section, please ensure that the dependencies in [Chapter 2](chapter02.md#requirements) above are installed. -Before running `make`, copy the correct “makefile” for your system, depending if you are on Linux/Unix or MacOS. For example, if you were on Linux: +Before running `make`, copy the correct “makefile” for your system, depending if you are on Linux/Unix or macOS. For example, if you were on Linux: ``` $ cd wolfcrypt-jni @@ -87,16 +87,52 @@ To install the JAR into the local Maven repository: $ mvn install ``` -After installation, the package can be included as a dependency in other Maven projects: +After installation, the package can be included as a dependency in other Maven +projects, where the version number will change depending on the current release: ``` com.wolfssl wolfcrypt-jni - 1.9.0-SNAPSHOT + 1.10.0-SNAPSHOT ``` +## Java 9+ Module Support (JPMS) + +wolfCrypt JNI/JCE supports the Java Platform Module System (JPMS) introduced +in Java 9. This enables use with `jlink` for creating custom, minimal Java +runtimes. + +**Module Information:** + +- Module name: `com.wolfssl.wolfcrypt` +- Exported packages: `com.wolfssl.wolfcrypt`, `com.wolfssl.provider.jce` +- Service provider: `java.security.Provider` (WolfCryptProvider) + +The `module-info.java` (located under `src/java9`) is conditionally compiled +based on the JDK version used to build. When building with Java 9 or later, +a modular JAR is produced that includes `module-info.class`. When building +with Java 8, `module-info.java` is automatically excluded from compilation +and the resulting JAR works as a standard classpath JAR. + +When built with Java 9+, the wolfCrypt JNI/JCE JAR can be used with `jlink` +to create a custom Java runtime that includes the wolfCrypt module: + +``` +$ jlink \ + --module-path lib/wolfcrypt-jni.jar:$JAVA_HOME/jmods \ + --add-modules com.wolfssl.wolfcrypt \ + --output custom-runtime \ + --no-header-files \ + --no-man-pages + +$ ./custom-runtime/bin/java --list-modules +``` + +Note that the native wolfCrypt JNI shared library (`libwolfcryptjni.so/dylib`) +must still be available on the native library search path at runtime. + ## API Javadocs Running `ant` will generate a set of Javadocs under the `wolfcrypt-jni/docs/javadoc` diff --git a/wolfCrypt-JNI/src/chapter04.md b/wolfCrypt-JNI/src/chapter04.md index 02127ef1..c75338bc 100644 --- a/wolfCrypt-JNI/src/chapter04.md +++ b/wolfCrypt-JNI/src/chapter04.md @@ -7,7 +7,7 @@ applications to use. ## Installation at Runtime To install and use wolfJCE at runtime inside a single application, first make -sure that "**libwolfcryptjni.so**" (or "**libwolfcryptjni.dylib**" if on MacOS) +sure that "**libwolfcryptjni.so**" (or "**libwolfcryptjni.dylib**" if on macOS) is on your system library search path. On Linux, you can modify this path with: @@ -16,7 +16,7 @@ On Linux, you can modify this path with: $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/add ``` -On MacOS, you can use `DYLD_LIBRARY_PATH` instead: +On macOS, you can use `DYLD_LIBRARY_PATH` instead: ``` $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/path/to/add @@ -58,6 +58,13 @@ for (Provider prov:providers) { } ``` +wolfJCE also registers itself as a `java.security.Provider` service +(`META-INF/services/java.security.Provider`), which allows the provider to be +discovered through the Java `ServiceLoader` mechanism and used with the Java +Platform Module System (JPMS). See +[Chapter 3](chapter03.md#java-9-module-support-jpms) for more details on module +support. + ## Installation at OS / System Level (Java <= 8) wolfJCE can be installed at the system level so that any Java application @@ -66,7 +73,7 @@ consuming Java Security APIs for cryptography can leverage wolfJCE. To install the wolfJCE provider at the system level, copy the JAR into the correct Java installation directory for your OS and JDK and verify the shared library is on your library search path. - + Add the wolfCrypt JNI/JCE JAR file (**wolfcrypt-jni.jar**) and shared library (**libwolfcryptjni.so** or **libwolfcryptjni.dylib**) to the following directory: @@ -97,3 +104,53 @@ $JAVA_HOME/jre/lib/security/java.security Replacing “N” with the order of precedence you would like the WolfCryptProvider to have in comparison to other providers in the file. +## Installation at OS / System Level (Java > 8) + +Note that the `$JAVA_HOME/jre/lib/ext` extension mechanism was removed in +Java 9. On Java 9 and later, place `wolfcrypt-jni.jar` on the application +classpath (or module path) instead, and add the +`security.provider.N=com.wolfssl.provider.jce.WolfCryptProvider` entry to the +`java.security` file located at `$JAVA_HOME/conf/security/java.security`. + +## Custom Native Library Loading + +By default, wolfCrypt JNI/JCE loads the native `wolfcryptjni` library using +`System.loadLibrary()`. This requires the native library to be located on +the system library search path. + +For applications that need custom library loading behavior, such as bundling +native libraries inside a JAR file and extracting them at runtime, wolfCrypt +JNI/JCE supports skipping the automatic library loading via the +`wolfssl.skipLibraryLoad` System property. When set to `true`, wolfCrypt +JNI/JCE will skip calling `System.loadLibrary()` for the native libraries, +and the application is then responsible for loading the native libraries +before any wolfCrypt classes are accessed. + +This property must be set before any wolfCrypt JNI/JCE classes are loaded by +the JVM, as the native library loading occurs in static initializer blocks: + +``` +/* Option 1: Set via command line */ +/* java -Dwolfssl.skipLibraryLoad=true -jar myapp.jar */ + +/* Option 2: Load libraries manually with absolute paths, then set property. + * This must happen at application startup, BEFORE any wolfCrypt classes + * are accessed or loaded by the JVM. */ +System.load("/path/to/libwolfssl.so"); +System.load("/path/to/libwolfcryptjni.so"); +System.setProperty("wolfssl.skipLibraryLoad", "true"); + +/* Now wolfCrypt classes can be used normally */ +``` + +Applications can check if library loading was skipped using the +`WolfObject.isLibraryLoadSkipped()` method: + +``` +import com.wolfssl.wolfcrypt.WolfObject; + +if (WolfObject.isLibraryLoadSkipped()) { + System.out.println("Native library loading was skipped"); +} +``` + diff --git a/wolfCrypt-JNI/src/chapter05.md b/wolfCrypt-JNI/src/chapter05.md index 96225c35..8d2ce9eb 100644 --- a/wolfCrypt-JNI/src/chapter05.md +++ b/wolfCrypt-JNI/src/chapter05.md @@ -10,20 +10,24 @@ version of “wolfcrypt-jni.jar” that does not include the JCE provider classe **wolfJCE / wolfCrypt JNI package structure:** ``` -wolfcrypt-jni / +wolfcrypt-jni/ .github GitHub Actions workflows AUTHORS COPYING ChangeLog.md Version ChangeLog IDE/ IDE Project Files + Android/ Example Android Studio project WIN/ Visual Studio Project Files LICENSING README.md Main README README_JCE.md wolfJCE README build.xml ant build script - docs / Javadocs + docs/ Javadocs and design documents + design/ Design documents (WKS KeyStore, etc) + javadoc/ Generated Javadocs examples/ Example applications and certs/keys certs/ Example cert/keys/KeyStores + filtered-providers/ Filtered Sun provider examples (FIPS) provider/ JCE example apps jni/ Native C JNI binding source files lib/ Compiled library artifacts @@ -33,14 +37,16 @@ wolfcrypt-jni / rpm/ Linux rpm files scripts/ Test scripts (Facebook Infer, etc) src/ Source code + java9/ module-info.java (Java 9+ JPMS support) main/java Java source files + test/java JUnit test source files ``` The wolfJCE provider source code is located in the `src/main/java/com/wolfssl/provider/jce` directory, and is part of the “**com.wolfssl.provider.jce**” Java package. - + The wolfCrypt JNI wrapper is located in the `src/main/java/com/wolfssl/wolfcrypt` directory and is part of the “**com.wolfssl.wolfcrypt**” Java package. Users of JCE will not need to use diff --git a/wolfCrypt-JNI/src/chapter06.md b/wolfCrypt-JNI/src/chapter06.md index c90b125c..6e368d64 100644 --- a/wolfCrypt-JNI/src/chapter06.md +++ b/wolfCrypt-JNI/src/chapter06.md @@ -79,6 +79,39 @@ wolfJCE currently supports the following algorithms and classes: SHA3-256withECDSAinP1363Format SHA3-384withECDSAinP1363Format SHA3-512withECDSAinP1363Format + ML-DSA (any ML-DSA-44/65/87 key) + ML-DSA-44 + ML-DSA-65 + ML-DSA-87 + XMSS (verify-only) + XMSSMT (verify-only) + LMS (aliased also as: HSS/LMS, verify-only) + SLH-DSA (any SLH-DSA parameter set key) + SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128f + SLH-DSA-SHA2-192s + SLH-DSA-SHA2-192f + SLH-DSA-SHA2-256s + SLH-DSA-SHA2-256f + SLH-DSA-SHAKE-128s + SLH-DSA-SHAKE-128f + SLH-DSA-SHAKE-192s + SLH-DSA-SHAKE-192f + SLH-DSA-SHAKE-256s + SLH-DSA-SHAKE-256f + HASH-SLH-DSA (pre-hash, any SLH-DSA parameter set key) + SLH-DSA-SHA2-128s-WITH-SHA256 + SLH-DSA-SHA2-128f-WITH-SHA256 + SLH-DSA-SHA2-192s-WITH-SHA512 + SLH-DSA-SHA2-192f-WITH-SHA512 + SLH-DSA-SHA2-256s-WITH-SHA512 + SLH-DSA-SHA2-256f-WITH-SHA512 + SLH-DSA-SHAKE-128s-WITH-SHAKE128 + SLH-DSA-SHAKE-128f-WITH-SHAKE128 + SLH-DSA-SHAKE-192s-WITH-SHAKE256 + SLH-DSA-SHAKE-192f-WITH-SHAKE256 + SLH-DSA-SHAKE-256s-WITH-SHAKE256 + SLH-DSA-SHAKE-256f-WITH-SHAKE256 KeyAgreement Class DiffieHellman @@ -102,14 +135,65 @@ wolfJCE currently supports the following algorithms and classes: RSASSA-PSS EC DH (aliased also as: DiffieHellman) + ML-DSA (defaults to ML-DSA-65, level overridable via init()) + ML-DSA-44 + ML-DSA-65 + ML-DSA-87 + SLH-DSA (defaults to SLH-DSA-SHA2-128f, set overridable via init()) + SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128f + SLH-DSA-SHA2-192s + SLH-DSA-SHA2-192f + SLH-DSA-SHA2-256s + SLH-DSA-SHA2-256f + SLH-DSA-SHAKE-128s + SLH-DSA-SHAKE-128f + SLH-DSA-SHAKE-192s + SLH-DSA-SHAKE-192f + SLH-DSA-SHAKE-256s + SLH-DSA-SHAKE-256f + ML-KEM (defaults to ML-KEM-768, level overridable via init()) + ML-KEM-512 + ML-KEM-768 + ML-KEM-1024 KeyFactory Class RSA EC DH (aliased also as: DiffieHellman) + ML-DSA + ML-DSA-44 + ML-DSA-65 + ML-DSA-87 + SLH-DSA + SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128f + SLH-DSA-SHA2-192s + SLH-DSA-SHA2-192f + SLH-DSA-SHA2-256s + SLH-DSA-SHA2-256f + SLH-DSA-SHAKE-128s + SLH-DSA-SHAKE-128f + SLH-DSA-SHAKE-192s + SLH-DSA-SHAKE-192f + SLH-DSA-SHAKE-256s + SLH-DSA-SHAKE-256f + ML-KEM + ML-KEM-512 + ML-KEM-768 + ML-KEM-1024 + XMSS (verify-only) + XMSSMT (verify-only) + LMS (aliased also as: HSS/LMS) + + KEM Class (javax.crypto.KEM, requires JDK 21 or later) + ML-KEM + ML-KEM-512 + ML-KEM-768 + ML-KEM-1024 CertPathValidator Class - PKIX + PKIX (with PKIXRevocationChecker via getRevocationChecker()) CertPathBuilder Class PKIX @@ -124,6 +208,8 @@ wolfJCE currently supports the following algorithms and classes: PBKDF2WithHmacSHA3-256 PBKDF2WithHmacSHA3-384 PBKDF2WithHmacSHA3-512 + AES + DESede KeyStore Class WKS @@ -137,3 +223,54 @@ wolfJCE currently supports the following algorithms and classes: AlgorithmParameterGenerator Class DH (aliased also as: DiffieHellman) +In addition to the algorithm names above, many services are also registered +under their standard OID aliases (for example, `Cipher` AES OIDs, +`MessageDigest` SHA-2 OIDs, `Mac` HMAC OIDs, and the ML-DSA, SLH-DSA, ML-KEM, +XMSS, and LMS object identifiers), allowing lookup by OID string. A complete +list of aliases can be found in the wolfcrypt-jni `README_JCE.md` file. + +The RSA `Cipher` implementations also support `Cipher.WRAP_MODE` and +`Cipher.UNWRAP_MODE` for RSA-based key wrapping and unwrapping. + +## Native wolfSSL Feature Requirements + +The ML-KEM, ML-DSA, SLH-DSA, XMSS/XMSS^MT, and LMS/HSS services require the +matching algorithm support to be compiled into the native wolfSSL library. +If native support is missing, wolfJCE will still compile and run normally, +but the corresponding services will not be registered. See +[Chapter 2](chapter02.md#native-feature-requirements-for-post-quantum-and-hash-based-algorithms) +for the native wolfSSL configure options required for each algorithm. + +## ML-KEM (FIPS 203) Notes + +wolfJCE supports ML-KEM, the Module-Lattice-Based Key Encapsulation Mechanism +from FIPS 203 (formerly Kyber). The `KeyPairGenerator`, `KeyFactory`, and key +classes work on Java 8 and later. The `KEM` service (`javax.crypto.KEM`) +requires JDK 21 or later - on earlier JDKs the KEM service is not registered, +but key generation and key encoding are still available. + +To select a parameter set, either use the parameter-set-specific names +directly (ex: `KeyPairGenerator.getInstance("ML-KEM-768", "wolfJCE")`), or use +the family name `ML-KEM` (defaults to ML-KEM-768) and initialize with a +parameter spec. On JDK 11+ use `java.security.spec.NamedParameterSpec.ML_KEM_768`, +and on Java 8 use `com.wolfssl.provider.jce.WolfPQCParameterSpec.ML_KEM_768`. +As with the JDK reference implementation, ML-KEM does not accept an integer +key size via `initialize(int)`. + +Generated keys report `getAlgorithm()` of `ML-KEM` (matching the JDK +reference implementation) regardless of parameter set. Public keys use X.509 +SubjectPublicKeyInfo encoding and private keys use PKCS#8, per RFC 9935. On +input, wolfJCE accepts all three RFC 9935 private key CHOICE forms (`seed`, +`expandedKey`, and `both`). On output, the form is controlled by the +`jdk.mlkem.pkcs8.encoding` property (the same property the JDK reference +implementation uses), defaulting to `expandedKey`, which is importable by the +widest range of providers. + +## Example Applications + +The `examples/provider` directory in the wolfcrypt-jni package contains +example applications demonstrating several of the algorithm classes above, +including `MlKemExample.java` (ML-KEM encapsulation/decapsulation and key +encoding), `MlDsaExample.java`, `SlhDsaExample.java`, `XmssExample.java`, +and `CertPathBuilderExample.java`. + diff --git a/wolfCrypt-JNI/src/chapter08.md b/wolfCrypt-JNI/src/chapter08.md index ce1945e9..cc49b8b2 100644 --- a/wolfCrypt-JNI/src/chapter08.md +++ b/wolfCrypt-JNI/src/chapter08.md @@ -1,14 +1,92 @@ # Usage For usage, please follow the Oracle/OpenJDK Javadocs for the classes -specified in [Chapter 6](chapter06#supported-algorithms-and-classes). Note that -you will need to explicitly request the `wolfJCE` provider if it has been set -lower in precedence than other providers that offer the same algorithm in the -`java.security` file. For example, to use the wolfJCE provider with the +specified in [Chapter 6](chapter06.md#supported-jce-algorithms-and-classes). +Note that you will need to explicitly request the `wolfJCE` provider if it has +been set lower in precedence than other providers that offer the same algorithm +in the `java.security` file. For example, to use the wolfJCE provider with the MessageDigest class for SHA-1 you would create a MessageDigest object like so: ``` -MessageDigest md = MessageDigest.getInstance(“SHA-1”, “wolfJCE”); +MessageDigest md = MessageDigest.getInstance("SHA-1", "wolfJCE"); ``` +## System and Security Property Support + +wolfJCE supports the following Java System and Security properties for +behavior customization and debugging. + +### Security Property Support + +The following Java Security properties can be set in the `java.security` +file for JCE provider customization: + +| Security Property | Default | To Enable | Description | +| --- | --- | --- | --- | +| 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 | +| wolfjce.mapPKCS12toWKS | UNSET | true | Register fake PKCS12 KeyStore service mapped to WKS | + +The WKS-related Security properties are described in more detail in +[Chapter 9](chapter09.md#keystore-implementations). + +### System Property Support + +The following Java System properties can be set on the command line or +programmatically for JCE provider customization: + +| System Property | Default | To Enable | Description | +| --- | --- | --- | --- | +| wolfjce.debug | "false" | "true" | Enable wolfJCE debug logging | +| wolfjce.ioTimeout | UNSET | Integer (seconds) | I/O timeout for OCSP and CRL HTTP operations (0-3600) | +| wolfssl.skipLibraryLoad | "false" | "true" | Skip automatic native library loading (see [Chapter 4](chapter04.md#custom-native-library-loading)) | + +**wolfjce.ioTimeout** - sets the I/O timeout (in seconds) used by native wolfSSL +for HTTP-based OCSP lookups and CRL fetching. Wraps native +`wolfIO_SetTimeout()`, and requires native wolfSSL to be compiled with +`HAVE_IO_TIMEOUT`. Valid values are 0 to 3600 inclusive, where 0 disables the +timeout (default behavior). The property is read during +`PKIXRevocationChecker.init()`, which occurs at certificate path validation +time, so it can be set or changed after provider registration and will be +picked up on the next validation. Invalid values (non-numeric, negative, +exceeding 3600) will cause revocation checker initialization to fail with +`CertPathValidatorException`. This property replaces the Sun-specific +`com.sun.security.ocsp.timeout` and `com.sun.security.crl.timeout` properties +(which use milliseconds) with a single wolfJCE-specific property in seconds +that applies to both OCSP and CRL operations. + +## SecureRandom.getInstanceStrong() + +When registered as the highest priority security provider, wolfJCE will +provide `SecureRandom` with the underlying `HashDRBG` algorithm. + +Java applications can alternatively call the +`SecureRandom.getInstanceStrong()` API to get a "known strong SecureRandom +implementation". To provide this with wolfJCE, the `java.security` file needs +to be modified by setting the `securerandom.strongAlgorithms` property to: + +``` +securerandom.strongAlgorithms=HashDRBG:wolfJCE +``` + +Note that the `securerandom.source` property in `java.security` has no effect +on the wolfJCE provider. + +## Removing Sun Cryptographic Services in Hardened Environments + +For hardened JREs, such as FIPS 140-3 Java containers where non-FIPS +validated Sun cryptography must be removed but certain non-cryptographic Sun +services (ex: `CertificateFactory.X.509`, `CertStore.Collection`) are still +needed, the wolfcrypt-jni package ships example "filtered" providers under +the `examples/filtered-providers` directory. These wrap the JDK `SUN`, +`SunEC`, and `SunRsaSign` providers and expose only their non-cryptographic +services. They require Java 9 or later, are not part of the published +`wolfcrypt-jni.jar`, and build into a standalone +`lib/filtered-providers/filtered-providers.jar`. See the README.md in that +directory for build and integration details. + Please email support@wolfssl.com with any questions or feedback. diff --git a/wolfCrypt-JNI/src/chapter09.md b/wolfCrypt-JNI/src/chapter09.md index 46203367..3a9e82c5 100644 --- a/wolfCrypt-JNI/src/chapter09.md +++ b/wolfCrypt-JNI/src/chapter09.md @@ -1,45 +1,142 @@ # KeyStore Implementations -wolfJCE includes one Java KeyStore implementation, WolfSSLKeyStore (WKS). It has been designed to be compatible with wolfCrypt FIPS 140-2 / 140-3 validated modules, using cryptography algorithms and key sizes within the FIPS validated boundary. The WKS KeyStore type can also be used with non-FIPS versions of wolfSSL and wolfCrypt. WolfSSLKeyStore (WKS) KeyStores can be used along with wolfSSL JNI/JSSE as well. +wolfJCE includes one Java KeyStore implementation, WolfSSLKeyStore (WKS). It +has been designed to be compatible with wolfCrypt FIPS 140-2 / 140-3 validated +modules, using cryptography algorithms and key sizes within the FIPS validated +boundary. The WKS KeyStore type can also be used with non-FIPS versions of +wolfSSL and wolfCrypt. WolfSSLKeyStore (WKS) KeyStores can be used along with +wolfSSL JNI/JSSE as well. ## JKS to WKS Migration Guide -Users of wolfJCE may wish to migrate from existing Java KeyStore files over to WolfSSLKeyStore (WKS) format to ensure use of FIPS 140-2/3 validated algorithms if using wolfCrypt FIPS. This migration guide will outline some of the steps and considerations to take into account when migrating KeyStore formats. +Users of wolfJCE may wish to migrate from existing Java KeyStore files over to +WolfSSLKeyStore (WKS) format to ensure use of FIPS 140-2/3 validated algorithms +if using wolfCrypt FIPS. This migration guide will outline some of the steps +and considerations to take into account when migrating KeyStore formats. ### FIPS 140-2 / 140-3 Algorithm Requirement Considerations -FIPS 140-2 / 140-3 validation compliance from an application perspective typically means that all cryptography being called or used should come from a FIPS validated cryptographic module. Oftentimes the strictness of what cryptography needs to be FIPS validated is decided by the end consumer of the application or product. In some cases, not 100% of the cryptography in a system needs to be FIPS validated. For example an end consumer may only require cryptography used to secure data in transit be FIPS validated, and other cryptography (such as the algorithms used for key storage on the device) do not have the same FIPS requirements. +FIPS 140-2 / 140-3 validation compliance from an application perspective +typically means that all cryptography being called or used should come from a +FIPS validated cryptographic module. Oftentimes the strictness of what +cryptography needs to be FIPS validated is decided by the end consumer of the +application or product. In some cases, not 100% of the cryptography in a system +needs to be FIPS validated. For example an end consumer may only require +cryptography used to secure data in transit be FIPS validated, and other +cryptography (such as the algorithms used for key storage on the device) do not +have the same FIPS requirements. + +There are some use cases where the Java KeyStore objects and files being used +are out of scope of the FIPS validation requirement. In those cases, it may be +simpler and require fewer changes to a system to use the existing KeyStore +files on a system. Typically these will be JKS or PKCS#12 format stores, as +those are typically generated and consumed by Java applications using Oracle’s +SunJSSE and SunJCE cryptographic provider implementations. + +Other applications and use cases will require all cryptography on the system to +be FIPS validated. For these use cases, wolfSSL has created the WolfSSLKeyStore +(WKS) store type. This migration guide will walk through some common areas and +considerations when switching from other KeyStore types (ex: JKS, PKCS#12) over +to the WKS type. -There are some use cases where the Java KeyStore objects and files being used are out of scope of the FIPS validation requirement. In those cases, it may be simpler and require fewer changes to a system to use the existing KeyStore files on a system. Typically these will be JKS or PKCS#12 format stores, as those are typically generated and consumed by Java applications using Oracle’s SunJSSE and SunJCE cryptographic provider implementations. +### WolfSSLKeyStore Format (WKS) -Other applications and use cases will require all cryptography on the system to be FIPS validated. For these use cases, wolfSSL has created the WolfSSLKeyStore (WKS) store type. This migration guide will walk through some common areas and considerations when switching from other KeyStore types (ex: JKS, PKCS#12) over to the WKS type. +The WKS KeyStore format is unique and different than other Java KeyStore types. +It has been designed to use FIPS 140-2 / 140-3 validated algorithms from the +wolfCrypt FIPS module to maintain FIPS validation conformance. + +The WKS implementation uses AES-CBC-256 along with HMAC-SHA512 in an +Encrypt-then-MAC format for encryption of PrivateKey and SecretKey objects. It +uses HMAC-SHA512 for KeyStore integrity. PKCS#5 PBKDF2-HMAC-SHA512 is used to +generate 96 bytes of key material which is split between a 32-byte AES-CBC-256 +key and 64-byte HMAC-SHA512 key. The PBKDF2 salt is 16 bytes, randomly +generated for each key storage operation, and the AES-CBC IV is also randomly +generated for each key storage operation. The PBKDF2 iteration count defaults +to 210,000 (current OWASP recommendation), but is user overridable with the +`wolfjce.wks.iterationCount` Security property in the `java.security` file +(10,000 minimum). More details on the design of the WKS type can be found in +the WolfSSLKeyStore design document (`docs/design/WolfSSLKeyStore.md` in the +wolfcrypt-jni package). + +WKS KeyStores support storage of PrivateKey, Certificate, and SecretKey objects. +PrivateKey storage includes RSA, RSASSA-PSS, ECC, ML-DSA (FIPS 204), and +SLH-DSA (FIPS 205) keys. ML-DSA and SLH-DSA key support requires native wolfSSL +to be built with the respective algorithm enabled +(see [Chapter 2](chapter02.md#native-feature-requirements-for-post-quantum-and-hash-based-algorithms)). + +### WKS Security Properties + +The behavior of the WKS KeyStore can be customized with the following Java +Security properties, set in the `java.security` file: + +| Security Property | Default | Description | +| --- | --- | --- | +| wolfjce.wks.iterationCount | 210,000 | PBKDF2 iteration count (10,000 minimum) | +| wolfjce.wks.maxCertChainLength | 100 | Max cert chain length | +| wolfjce.wks.maxEntrySize | 10485760 | Max encoded entry size in bytes when loading WKS (10 MB default) | +| wolfjce.keystore.kekCacheEnabled | false | Enable KEK caching for performance | +| wolfjce.keystore.kekCacheTtlSec | 300 | KEK cache TTL in seconds (1 second minimum) | + +### KEK Caching for Performance + +The `wolfjce.keystore.kekCacheEnabled` Security property enables KEK (Key +Encryption Key) caching in the WKS KeyStore to improve performance when making +repeated `getKey()` calls. When disabled (default), each `getKey()` call +performs full PBKDF2 key derivation. When enabled, derived keys are cached in +memory with a configurable TTL (`wolfjce.keystore.kekCacheTtlSec`). The cache +is automatically cleared on entry deletion, overwrite, KeyStore reload, TTL +expiration, and garbage collection of the KeyStore object. Because +`KeyStore.getInstance()` returns the standard `java.security.KeyStore` +wrapper, the underlying WolfSSLKeyStore implementation object is not directly +accessible. To deterministically clear the cache, reload the KeyStore with +`load()` (any call to `load()` first clears the KEK cache, and loading `null` +resets the object to an empty KeyStore): -### WolfSSLKeyStore Format (WKS) +``` +/* Enable KEK caching with 10 minute TTL */ +Security.setProperty("wolfjce.keystore.kekCacheEnabled", "true"); +Security.setProperty("wolfjce.keystore.kekCacheTtlSec", "600"); -The WKS KeyStore format is unique and different than other Java KeyStore types. It has been designed to use FIPS 140-2 / 140-3 validated algorithms from the wolfCrypt FIPS module to maintain FIPS validation conformance. +KeyStore store = KeyStore.getInstance("WKS", "wolfJCE"); +store.load(new FileInputStream("keystore.wks"), password); +/* ... use KeyStore ... */ + +/* Explicitly clear cached keys when done (optional) */ +store.load(null, null); +``` -The WKS implementation uses AES-CBC-256 along with HMAC-SHA512 in an Encrypt-then-MAC format for encryption of PrivateKey and SecretKey objects. It uses HMAC-SHA512 for KeyStore integrity. More details on the design of the WKS type can be found in the WolfSSLKeyStore design document (WolfSSLKeyStore.md). +Security consideration: cached derived keys remain in memory for the TTL +duration. Only enable KEK caching in trusted environments where the performance +benefits outweigh the increased memory exposure. ### Converting Existing KeyStore Files to WKS -Existing JKS (.jks), PKCS#12 (.p12), and other Java KeyStore files will need to be converted to WKS type. This can easily be done using the Java `keytool` application. +Existing JKS (.jks), PKCS#12 (.p12), and other Java KeyStore files will need to +be converted to WKS type. This can easily be done using the Java `keytool` +application. -For `keytool` to convert KeyStore files to WKS, it will need access to compiled wolfCrypt JNI/JSSE library files (.so/.dylib and .jar). After compiling wolfCrypt JNI/JCE, make sure the native JNI shared library is on the native library search path. For Linux, add the location of `libwolfcryptjni.so` to `LD_LIBRARY_PATH`, for example: +For `keytool` to convert KeyStore files to WKS, it will need access to compiled +wolfCrypt JNI/JSSE library files (.so/.dylib and .jar). After compiling +wolfCrypt JNI/JCE, make sure the native JNI shared library is on the native +library search path. For Linux, add the location of `libwolfcryptjni.so` to +`LD_LIBRARY_PATH`, for example: ``` $ export LD_LIBRARY_PATH=/path/to/wolfcryptjni/lib:$LD_LIBRARY_PATH -``` +``` -If on MacOS, add the location of `libwolfcryptjni.dylib` to `DYLD_LIBRARY_PATH`, for example: +If on macOS, add the location of `libwolfcryptjni.dylib` to `DYLD_LIBRARY_PATH`, +for example: ``` $ export DYLD_LIBRARY_PATH=/path/to/wolfcryptjni/lib:$DYLD_LIBRARY_PATH ``` -`keytool` can then be used to convert between KeyStore types. Usage will be similar to: +`keytool` can then be used to convert between KeyStore types. Usage will be +similar to: ``` -$ keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.wks -srcstoretype JKS -deststoretype WKS -srcstorepass “password -deststorepass “password” -provider com.wolfssl.provider.jce.WolfCryptProvider --providerpath /path/to/wolfcryptjni/lib/wolfcrypt-jni.jar +$ keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.wks -srcstoretype JKS -deststoretype WKS -srcstorepass "password" -deststorepass "password" -provider com.wolfssl.provider.jce.WolfCryptProvider --providerpath /path/to/wolfcryptjni/lib/wolfcrypt-jni.jar ``` The `keytool` options that need to be used are: @@ -58,62 +155,138 @@ The `keytool` options that need to be used are: After converting KeyStore files, you should have new equivalent KeyStore files but in the .wks (WolfSSLKeyStore) format. +### Converting KeyStore Files Programmatically + +In addition to `keytool`, wolfJCE provides a utility method +`WolfCryptUtil.convertKeyStoreToWKS()` that can be used programmatically to +convert KeyStore formats. This method supports converting from JKS, PKCS12, and +WKS formats to WKS format, automatically detecting the input KeyStore format. +All certificates and keys from the source KeyStore are transferred to a newly +created WKS KeyStore, including both key entries (with certificate chains) and +certificate-only entries. This also applies when the input is already in WKS +format. The input stream is read to the end but not closed, and the returned +stream is always a new InputStream. + +Example usage: + +``` +import com.wolfssl.provider.jce.WolfCryptUtil; +import java.io.InputStream; +import java.security.KeyStore; + +/* Load your source KeyStore (JKS, PKCS12, or WKS) */ +InputStream sourceStream = ...; +char[] oldPassword = "your_password".toCharArray(); +char[] newPassword = "your_new_password".toCharArray(); + +/* Convert to WKS format, fail on insert errors */ +InputStream wksStream = WolfCryptUtil.convertKeyStoreToWKS(sourceStream, + oldPassword, newPassword, true); + +/* Load the converted WKS KeyStore */ +KeyStore wksStore = KeyStore.getInstance("WKS", "wolfJCE"); +wksStore.load(wksStream, newPassword); +``` + +**FIPS NOTE:** This utility method will call Sun provider code for JKS and +PKCS12 parsing. This means that if using wolfCrypt FIPS, these calls will make +calls into non-FIPS compliant cryptography for the conversion. Please take this +into consideration when being used in a FIPS compliant environment. When used +with wolfCrypt FIPS, the new password must also meet FIPS minimum HMAC key +size requirements and be at least 14 characters. + +### Mapping JKS and PKCS12 KeyStore Types to WKS + +For applications that request `KeyStore.getInstance("JKS")` or +`KeyStore.getInstance("PKCS12")` and cannot easily be changed, wolfJCE supports +two Java Security properties, `wolfjce.mapJKStoWKS` and +`wolfjce.mapPKCS12toWKS`. When set to `true` in the `java.security` file, +wolfJCE will register a "JKS" and/or "PKCS12" KeyStore type which is actually a +WolfSSLKeyStore (WKS) implementation internally. + +These properties should be used with caution - loading actual JKS or PKCS12 +files through these mapped KeyStore types will fail. They are helpful when FIPS +compliance is required but existing application code gets a JKS or PKCS12 +KeyStore instance, and assumes the caller has the flexibility to load a real +WKS KeyStore file into that KeyStore object. If one of these properties is set +at runtime programmatically, the wolfJCE provider services will need to be +refreshed / reloaded: + +``` +WolfCryptProvider prov = (WolfCryptProvider)Security.getProvider("wolfJCE"); +prov.refreshServices(); +``` + ### Viewing Contents of WolfSSLKeyStore (WKS) File -The Java `keytool` command can be used to view the contents of a WKS KeyStore file. Usage will be similar to: +The Java `keytool` command can be used to view the contents of a WKS KeyStore +file. Usage will be similar to: ``` -keytool -list -provider com.wolfssl.provider.jce.WolfCryptProvider --providerpath /path/to/wolfcryptjni/lib/wolfcrypt-jni.jar -storetype WKS -storepass “password” -keystore keystore.wks +keytool -list -provider com.wolfssl.provider.jce.WolfCryptProvider --providerpath /path/to/wolfcryptjni/lib/wolfcrypt-jni.jar -storetype WKS -storepass "password" -keystore keystore.wks ``` ### Changing Application Usage of KeyStore Type -Java application code typically either creates new KeyStore objects to store keys and certificates into, or opens existing KeyStore files for use. +Java application code typically either creates new KeyStore objects to store +keys and certificates into, or opens existing KeyStore files for use. #### Creating New KeyStore Objects -Java application code will typically create new KeyStore objects with code similar to the following, explicitly getting the a KeyStore instance of type “JKS”, or other KeyStore type: +Java application code will typically create new KeyStore objects with code +similar to the following, explicitly getting a KeyStore instance of type +“JKS”, or other KeyStore type: ``` import java.security.KeyStore; ... -String storePass = “mypassword”; -KeyStore store = KeyStore.getInstance(“JKS”); +String storePass = "mypassword"; +KeyStore store = KeyStore.getInstance("JKS"); store.load(null, storePass.toCharArray()); ``` -To convert this code to creating a KeyStore of type “WKS”, only the type passed to `getInstance()` will need to be updated: +To convert this code to creating a KeyStore of type “WKS”, only the type passed +to `getInstance()` will need to be updated: ``` -KeyStore store = KeyStore.getInstance(“WKS”); +KeyStore store = KeyStore.getInstance("WKS"); ``` -All application code that uses the KeyStore object should work as-is since the WolfSSLKeyStore implementation extends `KeyStoreSpi` and implements the methods in that abstract class. +All application code that uses the KeyStore object should work as-is since the +WolfSSLKeyStore implementation extends `KeyStoreSpi` and implements the methods +in that abstract class. #### Opening Existing KeyStore Files for Use -Java application code that opens existing KeyStore files for use will typically do so with similar code to below: +Java application code that opens existing KeyStore files for use will typically +do so with similar code to below: ``` import java.security.KeyStore; ... -String storePass = “mypassword”; -KeyStore store = KeyStore.getInstance(“JKS”); +String storePass = "mypassword"; +KeyStore store = KeyStore.getInstance("JKS"); store.load(new FileInputStream(keystoreFilePath), storePass.toCharArray()); ``` -To convert this code to use `WKS` type, change the call to `getInstance()` to request a KeyStore instance of `WKS`: +To convert this code to use `WKS` type, change the call to `getInstance()` to +request a KeyStore instance of `WKS`: ``` -KeyStore store = KeyStore.getInstance(“WKS”); +KeyStore store = KeyStore.getInstance("WKS"); ``` -Then, the actual KeyStore file on disk being read will need to already be in WolfSSLKeyStore (WKS) format. See te section above about converting KeyStore files to WKS type for instructions on how to do this. +Then, the actual KeyStore file on disk being read will need to already be in +WolfSSLKeyStore (WKS) format. See the section above about converting KeyStore +files to WKS type for instructions on how to do this. ### Converting System CA Certificate KeyStore Files -Java JDK implementations commonly ship with their own KeyStore containing known trusted CA certificates. This will typically be either in a file called `cacerts` or `jssecacerts`. The location of this file will vary depending on Java version, but can typically be found at the following locations. +Java JDK implementations commonly ship with their own KeyStore containing known +trusted CA certificates. This will typically be either in a file called +`cacerts` or `jssecacerts`. The location of this file will vary depending on +Java version, but can typically be found at the following locations. **cacerts:** @@ -129,15 +302,25 @@ $JAVA_HOME/lib/security/jssecacerts (JDK 9+) $JAVA_HOME/jre/lib/security/jssecacerts (JDK <= 8) ``` -The default `cacerts.jks` password is "**changeit**". If using wolfCrypt FIPS 140-2 / 140-3 the minimum HMAC key size is 14 bytes. Since HMAC is used for the KeyStore integrity checks and MAC on PrivateKey/SecretKey objects, KeyStore passwords must be at least 14 characters. Because of this restriction, when converting system CA KeyStore files to WKS type, the password should be updated, to something like “**changeitchangeit**" for example. +The default `cacerts.jks` password is "**changeit**". If using wolfCrypt FIPS +140-2 / 140-3 the minimum HMAC key size is 14 bytes. Since HMAC is used for the +KeyStore integrity checks and MAC on PrivateKey/SecretKey objects, KeyStore +passwords must be at least 14 characters. Because of this restriction, when +converting system CA KeyStore files to WKS type, the password should be updated, +to something like "**changeitchangeit**" for example. -wolfCrypt JNI/JCE includes a helper bash script which has been set up to try and detect system CA KeyStore files and convert them to WKS type. This script is located at: +wolfCrypt JNI/JCE includes a helper bash script which has been set up to try +and detect system CA KeyStore files and convert them to WKS type. This script +is located at: ``` wolfcryptjni/examples/certs/systemcerts/system-cacerts-to-wks.sh ``` -This script should be run from the directory where it resides. Successful execution will result in local copies of the `cacerts` and/or `jssecacerts` KeyStore files created and placed in the same directory as the script, but in WKS format. +This script should be run from the directory where it resides. Successful +execution will result in local copies of the `cacerts` and/or `jssecacerts` +KeyStore files created and placed in the same directory as the script, but in +WKS format. ``` ./system-cacerts-to-wks.sh @@ -157,19 +340,30 @@ System cacerts found, converting from JKS to WKS: Successfully converted JKS to WKS ``` -You can then copy this `cacerts.wks` file over to your system JDK location if desired. +You can then copy this `cacerts.wks` file over to your system JDK location if +desired. ### WKS KeyStore Use with wolfJSSE -wolfSSL JNI/JSSE, as of [PR 178](https://github.com/wolfSSL/wolfssljni/pull/178) has been modified to give preference to loading and using WolfSSLKeyStore (WKS) KeyStore types. +wolfSSL JNI/JSSE, as of +[PR 178](https://github.com/wolfSSL/wolfssljni/pull/178) has been modified to +give preference to loading and using WolfSSLKeyStore (WKS) KeyStore types. -When auto-loading the system CA/root certificates (ex: jssecacerts, cacerts), wolfJSSE first tries to find and load a WKS equivalent file at the same location (ex: jssecacerts.wks, cacerts.wks). +When auto-loading the system CA/root certificates (ex: jssecacerts, cacerts), +wolfJSSE first tries to find and load a WKS equivalent file at the same +location (ex: jssecacerts.wks, cacerts.wks). -Support for a new Java Security property has been added (`wolfjsse.keystore.type.required`) which can be used to restrict use of KeyStore type to the one set in this property. This can be used for example to help conform to wolfCrypt FIPS 140-2/3 crypto usage by setting to “**WKS**” when wolfJCE is also used and installed on the system. +Support for a new Java Security property has been added +(`wolfjsse.keystore.type.required`) which can be used to restrict use of +KeyStore type to the one set in this property. This can be used for example to +help conform to wolfCrypt FIPS 140-2/3 crypto usage by setting to "**WKS**" +when wolfJCE is also used and installed on the system. -The wolfJSSE provider example `ClientJSSE.java` and `ServerJSSE.java` have been updated with a new option to specify the KeyStore type (``-ksformat`). +The wolfJSSE provider example `ClientJSSE.java` and `ServerJSSE.java` have been +updated with a new option to specify the KeyStore type (``-ksformat`). ### Support -For support or assistance in converting JKS or other KeyStore file types over to WolfSSLKeyStore (WKS) types, please email support@wolfssl.com. +For support or assistance in converting JKS or other KeyStore file types over +to WolfSSLKeyStore (WKS) types, please email support@wolfssl.com.