From 712a3b435a82ba76f5248d6f8fff7c48002d4cb4 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 9 Feb 2026 15:49:43 -0700 Subject: [PATCH] add Bouncy Castle Migration Guide --- BouncyCastle-Migration/Makefile | 21 + BouncyCastle-Migration/header.txt | 21 + BouncyCastle-Migration/mkdocs.yml | 33 + BouncyCastle-Migration/src/chapter01.md | 44 ++ BouncyCastle-Migration/src/chapter02.md | 65 ++ BouncyCastle-Migration/src/chapter03.md | 243 ++++++++ BouncyCastle-Migration/src/chapter04.md | 128 ++++ BouncyCastle-Migration/src/chapter05.md | 770 ++++++++++++++++++++++++ BouncyCastle-Migration/src/chapter06.md | 52 ++ BouncyCastle-Migration/src/chapter07.md | 103 ++++ BouncyCastle-Migration/src/chapter08.md | 44 ++ Makefile | 8 +- README.md | 1 + 13 files changed, 1532 insertions(+), 1 deletion(-) create mode 100644 BouncyCastle-Migration/Makefile create mode 100644 BouncyCastle-Migration/header.txt create mode 100644 BouncyCastle-Migration/mkdocs.yml create mode 100644 BouncyCastle-Migration/src/chapter01.md create mode 100644 BouncyCastle-Migration/src/chapter02.md create mode 100644 BouncyCastle-Migration/src/chapter03.md create mode 100644 BouncyCastle-Migration/src/chapter04.md create mode 100644 BouncyCastle-Migration/src/chapter05.md create mode 100644 BouncyCastle-Migration/src/chapter06.md create mode 100644 BouncyCastle-Migration/src/chapter07.md create mode 100644 BouncyCastle-Migration/src/chapter08.md diff --git a/BouncyCastle-Migration/Makefile b/BouncyCastle-Migration/Makefile new file mode 100644 index 00000000..7b0cc450 --- /dev/null +++ b/BouncyCastle-Migration/Makefile @@ -0,0 +1,21 @@ +-include ../common/common.am +.DEFAULT_GOAL := all +all: pdf html + + +SOURCES = chapter01.md \ + chapter02.md \ + chapter03.md \ + chapter04.md \ + chapter05.md \ + chapter06.md \ + chapter07.md \ + chapter08.md + +PDF = BouncyCastle-wolfSSL-Migration-Guide.pdf + +.PHONY: html-prep +html-prep: + +.PHONY: pdf-prep +pdf-prep: diff --git a/BouncyCastle-Migration/header.txt b/BouncyCastle-Migration/header.txt new file mode 100644 index 00000000..da497256 --- /dev/null +++ b/BouncyCastle-Migration/header.txt @@ -0,0 +1,21 @@ +% Bouncy Castle Migration Guide ![](logo.png) + +--- +header-includes: + # Blank pages on new sections + - \usepackage{titlesec} + - \newcommand{\sectionbreak}{\clearpage} + # Fancy page headers + - \usepackage{fancyhdr} + - \pagestyle{fancy} + - \fancyfoot[LO,RE]{COPYRIGHT \copyright 2026 wolfSSL Inc.} + # Wrap long syntax highlighting code blocks + - \usepackage{fvextra} + - \DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaklines,commandchars=\\\{\}} + # Wrap long non-syntax highlighted code blocks + - \usepackage{listings} + - \let\verbatim\undefined + - \let\verbatimend\undefined + - \lstnewenvironment{verbatim}{\lstset{breaklines,basicstyle=\ttfamily}}{} +subparagraph: yes +--- diff --git a/BouncyCastle-Migration/mkdocs.yml b/BouncyCastle-Migration/mkdocs.yml new file mode 100644 index 00000000..f67e697b --- /dev/null +++ b/BouncyCastle-Migration/mkdocs.yml @@ -0,0 +1,33 @@ +site_name: Bouncy Castle Migration Guide +site_url: https://wolfssl.com/ +docs_dir: build/html/ +site_dir: html/ +copyright: Copyright © 2026 wolfSSL Inc. +nav: + - "1. Introduction": index.md + - "2. Overview of Differences": chapter02.md + - "3. JCE Provider Migration": chapter03.md + - "4. JSSE Provider Migration": chapter04.md + - "5. BC Proprietary API Migration": chapter05.md + - "6. FIPS 140-3 Considerations": chapter06.md + - "7. Troubleshooting": chapter07.md + - "8. Support": chapter08.md +theme: + name: null + custom_dir: ../mkdocs-material/material + language: en + palette: + primary: indigo + accent: indigo + font: + text: Roboto + code: Roboto Mono + icon: "logo.png" + logo: logo.png + favicon: logo.png + feature: + tabs: true +extra_css: [skin.css] +extra: + generator: false +use_directory_urls: false diff --git a/BouncyCastle-Migration/src/chapter01.md b/BouncyCastle-Migration/src/chapter01.md new file mode 100644 index 00000000..0dffebaa --- /dev/null +++ b/BouncyCastle-Migration/src/chapter01.md @@ -0,0 +1,44 @@ +# Introduction + +This guide provides instructions and reference material for developers migrating +Java applications from the Bouncy Castle JCE provider and/or JSSE provider to +wolfSSL's wolfJCE and wolfJSSE providers. wolfJCE and wolfJSSE are backed by +the wolfCrypt native cryptography library, which includes FIPS 140-3 validated +options for applications requiring certified cryptography. + +## Audience + +This guide is intended for Java developers and architects who currently use +Bouncy Castle for cryptographic operations (JCE) and/or TLS (JSSE) and are +evaluating or planning a migration to wolfJCE and/or wolfJSSE. + +## Why Migrate? + +Common reasons for migrating from Bouncy Castle to wolfJCE/wolfJSSE include: + +- **FIPS 140-3 compliance** - wolfCrypt has FIPS 140-3 validated cryptographic + modules, providing certified cryptography underneath the JCE and JSSE layers. +- **Performance** - wolfCrypt is written in C and can leverage hardware + cryptography acceleration, offering performance advantages over pure-Java + implementations. +- **Reduced footprint** - wolfCrypt's native implementation can offer a smaller + overall footprint compared to Bouncy Castle in resource-constrained + environments. +- **Commercial support** - wolfSSL Inc. provides commercial support, maintenance, + and consulting services. + +## Scope + +This guide covers migration of: + +- **JCE Provider** - Cryptographic operations including ciphers, message digests, + MACs, signatures, key generation, key agreement, and KeyStore implementations + (Bouncy Castle JCE Provider to wolfJCE). +- **JSSE Provider** - TLS/SSL connections including SSLContext, SSLSocket, + SSLServerSocket, SSLEngine, TrustManager, and KeyManager implementations + (Bouncy Castle JSSE Provider to wolfJSSE). + +For detailed reference on each product, see the +[wolfCrypt JCE Provider and JNI Manual](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/) +and the +[wolfSSL JNI and wolfJSSE Manual](https://www.wolfssl.com/documentation/manuals/wolfssljni/). diff --git a/BouncyCastle-Migration/src/chapter02.md b/BouncyCastle-Migration/src/chapter02.md new file mode 100644 index 00000000..54808a16 --- /dev/null +++ b/BouncyCastle-Migration/src/chapter02.md @@ -0,0 +1,65 @@ +# Overview of Differences + +This chapter provides a high-level comparison between Bouncy Castle and the +wolfSSL Java providers (wolfJCE and wolfJSSE) to help frame the migration effort. + +## Architecture Comparison + +### Bouncy Castle + +Bouncy Castle is a pure-Java cryptographic library that includes both a +lightweight crypto API and standard JCE/JSSE provider implementations. All +cryptographic operations are implemented in Java. + +### wolfJCE / wolfJSSE + +wolfJCE and wolfJSSE are JNI-based providers that wrap the native wolfCrypt and +wolfSSL C libraries, respectively. Cryptographic operations are performed in +native code, with Java providing the JCE/JSSE interface layer. + +## Provider Registration + +Both Bouncy Castle and wolfJCE/wolfJSSE follow the standard Java Security +architecture for provider registration. The primary difference is in the +provider class names and the requirement to load native libraries for wolfSSL +providers. + +### Bouncy Castle Provider Registration + +```java +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +Security.addProvider(new BouncyCastleProvider()); +Security.addProvider(new BouncyCastleJsseProvider()); +``` + +### wolfJCE / wolfJSSE Provider Registration + +```java +import com.wolfssl.provider.jce.WolfCryptProvider; +import com.wolfssl.provider.jsse.WolfSSLProvider; + +Security.addProvider(new WolfCryptProvider()); +Security.addProvider(new WolfSSLProvider()); +``` + +## Supported Algorithms + +wolfJCE and wolfJSSE support a focused set of algorithms commonly required +for modern applications and FIPS 140-3 compliance. While Bouncy Castle supports +a very wide range of algorithms including many legacy and niche options, +wolfJCE/wolfJSSE focus on widely-used, standards-based algorithms. + +Consult the following manuals for the current list of supported algorithms +and classes: + +- [wolfJCE Supported Algorithms and Classes](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/chapter06.html) +- [wolfJSSE Supported Algorithms and Classes](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter06.html) + +## KeyStore Comparison + +For FIPS 140-3 deployments, WKS is the recommended KeyStore type since all +of its internal cryptographic operations use FIPS-approved algorithms from the +wolfCrypt FIPS module. See Chapter 3 for KeyStore migration details. + diff --git a/BouncyCastle-Migration/src/chapter03.md b/BouncyCastle-Migration/src/chapter03.md new file mode 100644 index 00000000..90fa36bb --- /dev/null +++ b/BouncyCastle-Migration/src/chapter03.md @@ -0,0 +1,243 @@ +# JCE Provider Migration + +This chapter covers the migration of cryptographic operations from the Bouncy +Castle JCE provider to wolfJCE. + +## Prerequisites + +Before starting the JCE migration, ensure that: + +1. The native wolfSSL library has been compiled and installed. See the + [wolfCrypt JNI/JCE Manual - Compilation](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/chapter03.html) + chapter for instructions. +2. The wolfcrypt-jni JAR has been built and is available on your classpath. +3. The native wolfSSL shared library is accessible via `java.library.path`. + +## Provider Installation + +### Programmatic Registration + +Replace the Bouncy Castle provider registration with wolfJCE: + +**Before (Bouncy Castle):** + +```java +import org.bouncycastle.jce.provider.BouncyCastleProvider; +Security.addProvider(new BouncyCastleProvider()); +``` + +**After (wolfJCE):** + +```java +import com.wolfssl.provider.jce.WolfCryptProvider; +Security.addProvider(new WolfCryptProvider()); +``` + +Or, to register wolfJCE as the highest priority provider: + +```java +import com.wolfssl.provider.jce.WolfCryptProvider; +Security.insertProviderAt(new WolfCryptProvider(), 1); +``` + +### java.security File Registration + +Alternatively, wolfJCE can be registered in the `java.security` file: + +**Before (Bouncy Castle):** + +``` +security.provider.N=org.bouncycastle.jce.provider.BouncyCastleProvider +``` + +**After (wolfJCE):** + +``` +security.provider.N=com.wolfssl.provider.jce.WolfCryptProvider +``` + +Where `N` is the desired provider preference order position. + +## Standard JCE API Migration + +The standard JCE APIs use a provider-based architecture. If your code +explicitly specifies `"BC"` as the provider in `getInstance()` calls, simply +change the provider name to `"wolfJCE"`. The API usage, method calls, and +parameters remain identical. + +The following JCE service classes are supported by wolfJCE and can be migrated +by changing the provider name from `"BC"` to `"wolfJCE"`: + +**JCE Service Classes** + +- Cipher +- Signature +- MessageDigest +- Mac +- KeyPairGenerator +- KeyAgreement +- KeyFactory +- SecureRandom +- KeyStore(WKS) + +For the complete list of supported algorithms under each service class, see +the [wolfJCE Supported Algorithms and Classes](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/chapter06.html) +documentation. + +### Provider Priority: Avoiding Explicit Provider Names + +If your code does not specify a provider name and instead relies on provider +priority (e.g., `Cipher.getInstance("AES/CBC/PKCS5Padding")` without a second +argument), you can configure wolfJCE as a higher-priority provider than Bouncy +Castle. The JCE framework will automatically select wolfJCE for any algorithm +it supports. + +**Programmatic approach — insert wolfJCE at position 1:** + +```java +Security.insertProviderAt(new WolfCryptProvider(), 1); +``` + +**java.security file approach — assign a lower number (higher priority):** + +``` +security.provider.1=com.wolfssl.provider.jce.WolfCryptProvider +``` + +With wolfJCE registered at a higher priority, no code changes are needed for +standard JCE API calls that do not explicitly name the `"BC"` provider. + +## KeyStore Migration + +wolfJCE provides a custom KeyStore type called **WolfSSLKeyStore (WKS)** that +has been designed for compatibility with wolfCrypt FIPS 140-2 and 140-3. All +cryptographic operations used internally by WKS (key protection, integrity +verification) use FIPS-approved algorithms, making it the recommended KeyStore +type for FIPS-compliant deployments. + +Applications using Bouncy Castle's BKS (BouncyCastle KeyStore) format will need +to convert their KeyStores to WKS format. + +### WKS Security Design + +WKS protects stored keys using: + +- **Encryption**: AES-CBC-256 with HMAC-SHA512 (Encrypt-then-MAC) +- **Key Derivation**: PBKDF2-HMAC-SHA512 with 128-bit random salt + (default 210,000 iterations) +- **Integrity**: HMAC computed across all stored data, verified on load + +WKS supports storing PrivateKey, SecretKey, and Certificate objects. + +### Loading a WKS KeyStore + +**Before (Bouncy Castle BKS):** + +```java +KeyStore ks = KeyStore.getInstance("BKS", "BC"); +ks.load(new FileInputStream("keystore.bks"), password); +``` + +**After (wolfJCE WKS):** + +```java +KeyStore ks = KeyStore.getInstance("WKS", "wolfJCE"); +ks.load(new FileInputStream("keystore.wks"), password); +``` + +### Converting Existing KeyStores to WKS + +wolfJCE's `keytool` integration supports importing from JKS, PKCS12, and BKS +source keystores into WKS format. + +**Converting JKS to WKS:** + +``` +keytool -importkeystore -srckeystore keystore.jks -srcstoretype JKS \ + -destkeystore keystore.wks -deststoretype WKS \ + -deststorepass "password" \ + -provider com.wolfssl.provider.jce.WolfCryptProvider \ + --providerpath /path/to/wolfcrypt-jni.jar +``` + +**Converting PKCS12 to WKS:** + +``` +keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 \ + -destkeystore keystore.wks -deststoretype WKS \ + -deststorepass "password" \ + -provider com.wolfssl.provider.jce.WolfCryptProvider \ + --providerpath /path/to/wolfcrypt-jni.jar +``` + +**Converting BKS to WKS:** + +BKS keystores require a two-step process since the BKS format requires the +Bouncy Castle provider to read. First convert BKS to PKCS12, then convert +PKCS12 to WKS: + +``` +/* Step 1: Convert BKS to PKCS12 (using Bouncy Castle) */ +keytool -importkeystore -srckeystore keystore.bks -srcstoretype BKS \ + -srcproviderpath bcprov.jar \ + -destkeystore keystore.p12 -deststoretype PKCS12 + +/* Step 2: Convert PKCS12 to WKS (using wolfJCE) */ +keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 \ + -destkeystore keystore.wks -deststoretype WKS \ + -deststorepass "password" \ + -provider com.wolfssl.provider.jce.WolfCryptProvider \ + --providerpath /path/to/wolfcrypt-jni.jar +``` + +### Programmatic Conversion + +wolfJCE also provides a utility method for programmatic conversion from JKS +or PKCS12 to WKS: + +```java +import com.wolfssl.provider.jce.WolfCryptUtil; + +WolfCryptUtil.convertKeyStoreToWKS(inputPath, outputPath, + inputFormat, inputPassword, outputPassword); +``` + +The `inputFormat` parameter accepts "JKS", "PKCS12", or "WKS" and supports +automatic format detection. + +**FIPS Note:** `WolfCryptUtil.convertKeyStoreToWKS()` internally loads and +reads the source KeyStore using the Sun/default JCE provider (for JKS and +PKCS12 formats), which is **not** FIPS validated cryptography. This conversion +should be performed as a separate offline step outside of your FIPS-compliant +code flow — for example, as a build-time or deployment-time task. Once the WKS +KeyStore has been generated, it can be loaded and used within FIPS-compliant +application code using the wolfJCE provider. + +### Converting System CA Certificates + +For applications that need to use the JVM's default CA certificates in WKS +format, wolfJCE includes a helper script that autodetects the Java installation +and converts the system `cacerts` file: + +``` +./examples/certs/systemcerts/system-cacerts-to-wks.sh +``` + +### WKS Configuration Properties + +WKS behavior can be tuned via `java.security` properties or system properties: + +| Property | Default | Description | +|---|---|---| +| `wolfjce.wks.iterationCount` | 210,000 | PBKDF2 iteration count (minimum 10,000) | +| `wolfjce.wks.maxCertChainLength` | 100 | Maximum certificate chain length | +| `wolfjce.keystore.kekCacheEnabled` | false | Enable derived key caching for performance | +| `wolfjce.keystore.kekCacheTtlSec` | 300 | Cache time-to-live in seconds | + +For high-throughput applications where KeyStore operations are frequent, enabling +KEK caching can improve performance by avoiding repeated PBKDF2 key derivation. + +For further details on the WKS KeyStore implementation, refer to the +[wolfCrypt JNI/JCE Manual - KeyStore Implementations](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/chapter09.html) +chapter. + diff --git a/BouncyCastle-Migration/src/chapter04.md b/BouncyCastle-Migration/src/chapter04.md new file mode 100644 index 00000000..4a1ed873 --- /dev/null +++ b/BouncyCastle-Migration/src/chapter04.md @@ -0,0 +1,128 @@ +# JSSE Provider Migration + +This chapter covers the migration of TLS/SSL functionality from the Bouncy +Castle JSSE provider (bcjsse) to wolfJSSE. + +## Prerequisites + +Before starting the JSSE migration, ensure that: + +1. The native wolfSSL library has been compiled and installed. See the + [wolfSSL JNI/JSSE Manual - Compilation](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter03.html) + chapter for instructions. +2. The wolfssl-jni JAR (which includes wolfJSSE) has been built and is + available on your classpath. +3. The native wolfSSL shared library is accessible via `java.library.path`. + +## Provider Installation + +### Programmatic Registration + +**Before (Bouncy Castle JSSE):** + +```java +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +Security.addProvider(new BouncyCastleJsseProvider()); +``` + +**After (wolfJSSE):** + +```java +import com.wolfssl.provider.jsse.WolfSSLProvider; +Security.addProvider(new WolfSSLProvider()); +``` + +Or, to register wolfJSSE as the highest priority provider: + +```java +import com.wolfssl.provider.jsse.WolfSSLProvider; +Security.insertProviderAt(new WolfSSLProvider(), 1); +``` + +### java.security File Registration + +**Before (Bouncy Castle JSSE):** + +``` +security.provider.N=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider +``` + +**After (wolfJSSE):** + +``` +security.provider.N=com.wolfssl.provider.jsse.WolfSSLProvider +``` + +## Standard JSSE API Migration + +The standard JSSE APIs follow the same provider-based architecture as JCE. If +your code explicitly specifies `"BCJSSE"` as the provider, the migration is +simply changing the provider name to `"wolfJSSE"`. The API usage, method calls, +and parameters remain identical. + +The following JSSE service classes are supported by wolfJSSE and can be migrated +by changing the provider name from `"BCJSSE"` to `"wolfJSSE"`: + +**JSSE Service Classes** + +- SSLContext +- SSLSocket / SSLServerSocket (obtained from SSLContext) +- SSLEngine (obtained from SSLContext) +- TrustManagerFactory +- KeyManagerFactory + +All downstream objects created from these classes (SSLSocketFactory, +SSLServerSocketFactory, SSLEngine, X509TrustManager, X509KeyManager) are +automatically provided by wolfJSSE once the SSLContext or factory is obtained +with the `"wolfJSSE"` provider. + +For the complete list of supported TLS protocol versions and cipher suites, +see the [wolfJSSE Supported Algorithms and Classes](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter06.html) +documentation. + +### Provider Priority: Avoiding Explicit Provider Names + +As with JCE (see Chapter 3), if your code does not explicitly name the +`"BCJSSE"` provider, you can register wolfJSSE at a higher priority and no +code changes are needed: + +```java +Security.insertProviderAt(new WolfSSLProvider(), 1); +``` + +Or in the `java.security` file: + +``` +security.provider.1=com.wolfssl.provider.jsse.WolfSSLProvider +``` + +## Protocol and Cipher Suite Considerations + +### TLS Protocol Versions + +wolfJSSE supports TLS 1.0 through TLS 1.3, depending on how the native wolfSSL +library was compiled. Verify that the TLS protocol versions your application +requires are enabled in the native wolfSSL build. + +wolfSSL does have "old" TLS protocol versions disabled by default, which are +versions less than TLS 1.2. If your application requires TLS 1.0 or TLS 1.1, +you will need to compile native wolfSSL with the `--enable-oldtls` +configure option. + +### Cipher Suite Names + +Cipher suite names may differ between Bouncy Castle and wolfJSSE. wolfJSSE +uses standard IANA cipher suite names. Consult the +[wolfJSSE Supported Algorithms and Classes](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter06.html) +chapter for the list of supported cipher suites. + +If your application explicitly sets cipher suites, verify that the suite names +used are supported by wolfJSSE. + +## System Properties + +wolfJSSE supports several Java system properties for configuration, including +those for specifying KeyStore and TrustStore paths. See the +[wolfSSL JNI/JSSE Manual - Usage](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter07.html) +chapter for details on supported system properties. + diff --git a/BouncyCastle-Migration/src/chapter05.md b/BouncyCastle-Migration/src/chapter05.md new file mode 100644 index 00000000..86809cff --- /dev/null +++ b/BouncyCastle-Migration/src/chapter05.md @@ -0,0 +1,770 @@ +# Bouncy Castle Proprietary API Migration Examples + +Chapters 3 and 4 cover migration of standard JCE and JSSE API usage where the +primary change is swapping the provider name. This chapter addresses migration +of code that uses Bouncy Castle's proprietary (non-standard) APIs directly, +such as classes under `org.bouncycastle.asn1.*`, `org.bouncycastle.cert.*`, +and `org.bouncycastle.crypto.*`. These cases require more significant code +changes since there is no standard Java API equivalent. + +## Bouncy Castle Equivalent Functionality Gaps + +wolfSSL provides functionally equivalent implementations of a subset of +Bouncy Castle API use through the classes and related APIs mentioned below. + +If the Bouncy Castle functionality equivalents you are using are missing +from wolfSSL JNI/JSSE or wolfCrypt JNI/JCE, please contact **wolfSSL support +(support@wolfssl.com)** to request the feature(s) be added. + +## X.509 Certificate Extensions + +The following sections cover migration of Bouncy Castle code that parses +X.509 certificate extensions using `org.bouncycastle.asn1.*` and +`org.bouncycastle.cert.*` classes. wolfSSL handles ASN.1 extension parsing +internally in native code and exposes the results through the +`WolfSSLCertificate` class and its associated types. In each case, the +multi-step ASN.1 decoding required by Bouncy Castle is replaced by direct +method calls on `WolfSSLCertificate`. + +### Name Constraint Validation + +A common use of the Bouncy Castle proprietary API is parsing X.509 Name +Constraints extensions and validating certificate names against permitted and +excluded subtrees. Bouncy Castle exposes this through its ASN.1 and PKI +validation classes. wolfSSL provides equivalent functionality through the +`WolfSSLCertificate` and `WolfSSLNameConstraints` classes. + +#### Bouncy Castle Approach + +Bouncy Castle Name Constraint validation is a multi-step process involving +parsing raw extension bytes, constructing a validator object, populating it +with subtrees, and then checking names against the validator. + +**Parsing the Name Constraints extension:** + +```java +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.NameConstraints; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; + +/* Get raw extension bytes from a X509Certificate */ +byte[] extensionValue = + certificate.getExtensionValue(Extension.nameConstraints.getId()); + +/* Unwrap the OCTET STRING, parse the ASN.1 structure */ +NameConstraints nameConstraints = NameConstraints.getInstance( + JcaX509ExtensionUtils.parseExtensionValue(extensionValue)); +``` + +**Building and populating the validator:** + +```java +import org.bouncycastle.asn1.x509.PKIXNameConstraintValidator; + +PKIXNameConstraintValidator validator = new PKIXNameConstraintValidator(); + +/* Add permitted subtrees */ +if (nameConstraints.getPermittedSubtrees() != null) { + validator.intersectPermittedSubtree( + nameConstraints.getPermittedSubtrees()); +} + +/* Add excluded subtrees */ +if (nameConstraints.getExcludedSubtrees() != null) { + for (int i = 0; + i < nameConstraints.getExcludedSubtrees().length; i++) { + validator.addExcludedSubtree( + nameConstraints.getExcludedSubtrees()[i]); + } +} +``` + +**Checking a name against the constraints:** + +```java +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.NameConstraintValidatorException; + +try { + validator.checkPermitted(name); + validator.checkExcluded(name); + /* Name is valid */ +} catch (NameConstraintValidatorException e) { + /* Name violates constraints */ +} +``` + +#### wolfSSL Approach + +wolfSSL handles ASN.1 parsing and constraint management internally in native +code. Rather than manually extracting the extension, parsing it, and building +a validator, the `WolfSSLCertificate` class parses all extensions when the +certificate is loaded, and `WolfSSLNameConstraints` provides a single method +to check a name against both permitted and excluded subtrees. + +**Parsing the Name Constraints from a certificate:** + +```java +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLNameConstraints; + +WolfSSLCertificate wolfCert = null; +try { + wolfCert = new WolfSSLCertificate(certificate.getEncoded()); + WolfSSLNameConstraints nc = wolfCert.getNameConstraints(); + + /* nc is null if the certificate has no Name Constraints extension */ + if (nc != null) { + /* use nc for validation (see below) */ + } +} finally { + if (wolfCert != null) { + wolfCert.free(); + } +} +``` + +**Checking a name against the constraints:** + +```java +/* Checks both permitted and excluded subtrees in a single call. + * Returns true if the name satisfies all constraints. */ +boolean allowed = nc.checkName(name.getType(), name.getValue()); +``` + +### Extracting Name Constraint Subtree Values + +Beyond validating names, applications often need to extract and display the +permitted or excluded subtree values from a certificate's Name Constraints +extension. With Bouncy Castle this requires manually decoding each +`GeneralSubtree` entry, handling different GeneralName types (DNS names, IP +addresses, etc.) individually. IP address constraints are particularly +involved since they are encoded as raw ASN.1 octets containing both the +address and subnet mask, which must be split and converted separately. + +#### Bouncy Castle Approach + +**Getting the subtree list from a parsed NameConstraints:** + +```java +import org.bouncycastle.asn1.x509.GeneralSubtree; + +/* After parsing NameConstraints (see previous section) */ +GeneralSubtree[] permitted = nameConstraints.getPermittedSubtrees(); +GeneralSubtree[] excluded = nameConstraints.getExcludedSubtrees(); +``` + +**Extracting the value from a GeneralSubtree entry:** + +For most GeneralName types (DNS, email, URI, etc.), the value can be obtained +by calling `toString()` on the name. IP address constraints require additional +decoding since the value is stored as a DER-encoded octet string containing +both the IP address and subnet mask concatenated together: + +```java +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.DEROctetString; +import java.net.InetAddress; + +GeneralName name = subtree.getBase(); + +if (name.getTagNo() == GeneralName.iPAddress) { + /* IP constraints are encoded as raw octets: [address | mask] */ + byte[] octets = DEROctetString.getInstance( + name.getName().toASN1Primitive()).getOctets(); + + /* Split octets in half: first half is IP, second half is subnet mask */ + byte[] ipBytes = Arrays.copyOf(octets, octets.length / 2); + byte[] maskBytes = Arrays.copyOfRange( + octets, octets.length / 2, octets.length); + + String ip = InetAddress.getByAddress(ipBytes).getHostAddress(); + String mask = InetAddress.getByAddress(maskBytes).getHostAddress(); + /* Result example: "192.168.1.0/255.255.255.0" */ + +} else { + /* DNS names, email, URIs, etc. */ + String value = name.getName().toString(); +} +``` + +#### wolfSSL Approach + +wolfSSL handles the ASN.1 decoding internally, including IP address and +subnet mask formatting. `WolfSSLNameConstraints` returns subtree entries as +`WolfSSLGeneralName` objects whose `getValue()` method returns a pre-formatted +string regardless of the GeneralName type. + +**Getting subtree values:** + +```java +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLNameConstraints; +import com.wolfssl.WolfSSLGeneralName; +import java.util.List; + +WolfSSLCertificate wolfCert = null; +try { + wolfCert = new WolfSSLCertificate(certificate.getEncoded()); + WolfSSLNameConstraints nc = wolfCert.getNameConstraints(); + + if (nc != null) { + List permitted = nc.getPermittedSubtrees(); + List excluded = nc.getExcludedSubtrees(); + } +} finally { + if (wolfCert != null) { + wolfCert.free(); + } +} +``` + +**Extracting the value from a subtree entry:** + +```java +/* getValue() returns a formatted string for all GeneralName types, + * including IP address constraints with subnet mask. No manual + * ASN.1 decoding needed. */ +String value = generalName.getValue(); +``` + +### Authority Information Access (AIA) Extension Parsing + +The AIA extension in X.509 certificates contains URIs for OCSP responders +and CA Issuer locations (used to download intermediate certificates for chain +building). With Bouncy Castle, parsing AIA requires unwrapping the extension +bytes, casting through several ASN.1 types, iterating over `AccessDescription` +entries, and filtering by access method OID. wolfSSL parses the AIA extension +internally and provides direct access to the URI lists. + +#### Bouncy Castle Approach + +**Parsing the AIA extension:** + +```java +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.x509.AccessDescription; +import org.bouncycastle.asn1.x509.AuthorityInformationAccess; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; + +byte[] aiaValue = + certificate.getExtensionValue(Extension.authorityInfoAccess.getId()); + +ASN1Primitive extensionValue = + JcaX509ExtensionUtils.parseExtensionValue(aiaValue); + +AuthorityInformationAccess aia = + AuthorityInformationAccess.getInstance(extensionValue); +``` + +**Extracting CA Issuer URIs:** + +```java +for (AccessDescription ad : aia.getAccessDescriptions()) { + if (ad.getAccessMethod().equals( + X509ObjectIdentifiers.id_ad_caIssuers)) { + GeneralName location = ad.getAccessLocation(); + String url = location.getName().toString(); + /* url contains a CA Issuer URI, e.g. "http://ca.example.com/ca.pem" */ + } +} +``` + +**Extracting OCSP responder URIs:** + +```java +for (AccessDescription ad : aia.getAccessDescriptions()) { + if (ad.getAccessMethod().equals( + X509ObjectIdentifiers.id_ad_ocsp)) { + GeneralName location = ad.getAccessLocation(); + String url = location.getName().toString(); + /* url contains an OCSP responder URI */ + } +} +``` + +#### wolfSSL Approach + +`WolfSSLCertificate` parses the AIA extension when the certificate is loaded +and provides separate methods for retrieving CA Issuer URIs and OCSP responder +URIs. No manual ASN.1 parsing or OID filtering is needed. + +**Extracting CA Issuer URIs:** + +```java +import com.wolfssl.WolfSSLCertificate; + +WolfSSLCertificate wolfCert = null; +try { + wolfCert = new WolfSSLCertificate(certificate.getEncoded()); + + String[] caIssuers = wolfCert.getCaIssuerUris(); + if (caIssuers != null) { + for (String url : caIssuers) { + /* url contains a CA Issuer URI */ + } + } +} finally { + if (wolfCert != null) { + wolfCert.free(); + } +} +``` + +**Extracting OCSP responder URIs:** + +```java +String[] ocspUris = wolfCert.getOcspUris(); +if (ocspUris != null) { + for (String url : ocspUris) { + /* url contains an OCSP responder URI */ + } +} +``` + +**Checking for AIA overflow:** + +The native wolfSSL library has an internal limit on the number of AIA URIs +it can parse from a single certificate. Applications handling certificates +with unusually large numbers of AIA entries should check for overflow: + +```java +int overflow = wolfCert.getAiaOverflow(); +if (overflow == 1) { + /* AIA URI list was truncated, certificate has more URIs + * than the internal buffer can hold */ +} +``` + +### Subject Alternative Name (SAN) Parsing + +Applications commonly need to extract Subject Alternative Name values from +client certificates for identity mapping, authorization decisions, or display. +With Bouncy Castle, SAN parsing (especially for non-String types like +`otherName`) requires manual ASN.1 decoding using `ASN1InputStream`, +`ASN1Sequence`, and `ASN1TaggedObject`. This is particularly problematic +with certificates issued by Microsoft Active Directory, which encodes User +Principal Names (UPNs) as `otherName` entries with a Microsoft-specific OID. + +wolfSSL provides `WolfSSLAltName` objects that handle ASN.1 decoding +internally, with explicit support for Microsoft AD UPN entries. + +#### Bouncy Castle Approach + +The standard JCE method `X509Certificate.getSubjectAlternativeNames()` returns +SAN entries as a `Collection>` where each entry is a list containing +an integer type and a value. For simple string types (DNS, email, URI) the +value is a `String`. However, for `otherName` entries (type 0), the value is +returned as a raw `byte[]` requiring manual ASN.1 decoding: + +**Extracting string-based SAN types (DNS, email, URI):** + +```java +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.List; + +Collection> sans = certificate.getSubjectAlternativeNames(); +if (sans != null) { + for (List san : sans) { + int type = (Integer) san.get(0); + if (type == 1 || type == 2 || type == 6) { + /* rfc822Name (1), dNSName (2), URI (6) */ + String value = (String) san.get(1); + } + } +} +``` + +**Decoding otherName entries (e.g., Microsoft AD UPN):** + +When the SAN value is an `otherName` (type 0), the JCE API returns the raw +DER-encoded bytes. Bouncy Castle ASN.1 classes are typically used to decode +these: + +```java +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; + +for (List san : sans) { + int type = (Integer) san.get(0); + + if (type == 0 && san.get(1) instanceof byte[]) { + /* otherName: requires ASN.1 decoding */ + ASN1InputStream decoder = + new ASN1InputStream((byte[]) san.get(1)); + ASN1Encodable encoded = decoder.readObject(); + + /* Navigate the ASN.1 structure: + * SEQUENCE { OID, [0] EXPLICIT value } */ + ASN1Encodable value = + ((ASN1Sequence) encoded).getObjectAt(1); + String name = + ((ASN1TaggedObject) value).getBaseObject().toString(); + decoder.close(); + } +} +``` + +This approach is fragile, the ASN.1 structure must be navigated by position, +casting can fail for unexpected encodings, and different certificate issuers +(particularly Microsoft AD) may encode values in subtly different ways. + +#### wolfSSL Approach + +`WolfSSLCertificate.getSubjectAltNamesArray()` returns `WolfSSLAltName` +objects that provide type-safe access to all SAN types. The `WolfSSLAltName` +class handles ASN.1 decoding internally and includes explicit support for +Microsoft AD UPN detection. + +**Iterating over SAN entries by type:** + +```java +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLAltName; + +WolfSSLCertificate wolfCert = null; +try { + wolfCert = new WolfSSLCertificate(certificate.getEncoded()); + WolfSSLAltName[] sans = wolfCert.getSubjectAltNamesArray(); + + if (sans != null) { + for (WolfSSLAltName san : sans) { + switch (san.getType()) { + case WolfSSLAltName.TYPE_DNS_NAME: + case WolfSSLAltName.TYPE_RFC822_NAME: + case WolfSSLAltName.TYPE_URI: + String value = san.getStringValue(); + break; + case WolfSSLAltName.TYPE_IP_ADDRESS: + String ip = san.getIPAddressString(); + break; + case WolfSSLAltName.TYPE_OTHER_NAME: + String otherValue = + san.getOtherNameValueAsString(); + break; + } + } + } +} finally { + if (wolfCert != null) { + wolfCert.free(); + } +} +``` + +**Detecting and extracting Microsoft AD UPN entries:** + +`WolfSSLAltName` provides `isMicrosoftUPN()` which checks for the Microsoft +UPN OID (`1.3.6.1.4.1.311.20.2.3`) and `getOtherNameValueAsString()` which +decodes the ASN.1 UTF8String value: + +```java +for (WolfSSLAltName san : sans) { + if (san.isMicrosoftUPN()) { + String upn = san.getOtherNameValueAsString(); + /* upn contains the User Principal Name, e.g. "user@domain.com" */ + } +} +``` + +For other `otherName` types, the OID and raw value can be inspected directly: + +```java +if (san.getType() == WolfSSLAltName.TYPE_OTHER_NAME) { + String oid = san.getOtherNameOID(); + String value = san.getOtherNameValueAsString(); + byte[] rawDer = san.getOtherNameValue(); +} +``` + +## RSA Encryption, Decryption, and Signing + +Applications using the Bouncy Castle crypto API for RSA operations +(`RSAEngine`, `PKCS1Encoding`, `RSADigestSigner`, `PublicKeyFactory`, +`PrivateKeyFactory`) can migrate to standard JCE APIs backed by wolfJCE. The +Bouncy Castle API provides its own key representations +(`AsymmetricKeyParameter`) and low-level cipher/signer objects, while the JCE +equivalents use standard `java.security` and `javax.crypto` interfaces. + +### Bouncy Castle Approach + +**RSA encryption with PKCS#1 v1.5 padding:** + +```java +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSAEngine; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.util.PublicKeyFactory; + +/* Convert raw public key bytes to BC key parameter type */ +AsymmetricKeyParameter pubKeyParam = PublicKeyFactory.createKey(publicKeyBytes); + +/* Initialize RSA engine with PKCS#1 padding for encryption */ +PKCS1Encoding rsaEngine = new PKCS1Encoding(new RSAEngine()); +rsaEngine.init(true, pubKeyParam); +byte[] ciphertext = rsaEngine.processBlock(plaintext, 0, plaintext.length); +``` + +**RSA decryption:** + +```java +import org.bouncycastle.crypto.util.PrivateKeyFactory; + +/* Convert standard PrivateKey to BC key parameter type */ +AsymmetricKeyParameter privKeyParam = + PrivateKeyFactory.createKey(privateKey.getEncoded()); + +PKCS1Encoding rsaEngine = new PKCS1Encoding(new RSAEngine()); +rsaEngine.init(false, privKeyParam); +byte[] plaintext = rsaEngine.processBlock(ciphertext, 0, ciphertext.length); +``` + +**RSA signing with SHA-512:** + +```java +import org.bouncycastle.crypto.signers.RSADigestSigner; +import org.bouncycastle.crypto.digests.SHA512Digest; + +RSADigestSigner signer = new RSADigestSigner(new SHA512Digest()); +signer.init(true, PrivateKeyFactory.createKey(privateKey.getEncoded())); +signer.update(data, 0, data.length); +byte[] signature = signer.generateSignature(); +``` + +**RSA signature verification:** + +```java +import org.bouncycastle.crypto.digests.SHA256Digest; + +/* Use SHA256Digest or SHA512Digest depending on the algorithm */ +RSADigestSigner verifier = new RSADigestSigner(new SHA256Digest()); +verifier.init(false, PublicKeyFactory.createKey(publicKey.getEncoded())); +verifier.update(data, 0, data.length); +boolean valid = verifier.verifySignature(signature); +``` + +### wolfJCE Approach + +All of these operations map directly to standard JCE classes. No proprietary +key conversions or engine wrappers are needed - standard +`java.security.PublicKey` and `java.security.PrivateKey` objects are used +directly. + +**RSA encryption with PKCS#1 v1.5 padding:** + +```java +import javax.crypto.Cipher; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; + +/* Convert raw public key bytes to standard PublicKey */ +KeyFactory kf = KeyFactory.getInstance("RSA", "wolfJCE"); +PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyBytes)); + +Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "wolfJCE"); +cipher.init(Cipher.ENCRYPT_MODE, pubKey); +byte[] ciphertext = cipher.doFinal(plaintext); +``` + +**RSA decryption:** + +```java +Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "wolfJCE"); +cipher.init(Cipher.DECRYPT_MODE, privateKey); +byte[] plaintext = cipher.doFinal(ciphertext); +``` + +**RSA signing with SHA-512:** + +```java +import java.security.Signature; + +Signature sig = Signature.getInstance("SHA512withRSA", "wolfJCE"); +sig.initSign(privateKey); +sig.update(data); +byte[] signature = sig.sign(); +``` + +**RSA signature verification:** + +```java +/* Use "SHA256withRSA" or "SHA512withRSA" depending on the algorithm */ +Signature sig = Signature.getInstance("SHA256withRSA", "wolfJCE"); +sig.initVerify(publicKey); +sig.update(data); +boolean valid = sig.verify(signature); +``` + +## Hex String Encoding and Decoding + +Bouncy Castle provides hex encoding utilities in +`org.bouncycastle.util.encoders.Hex` that are commonly used for logging, +debugging, and formatting cryptographic values such as key fingerprints, +hash digests, and certificate serial numbers. wolfSSL provides equivalent +methods in the `com.wolfssl.WolfCrypt` class. + +### Bouncy Castle Approach + +```java +import org.bouncycastle.util.encoders.Hex; + +/* Byte array to hex string */ +String hexStr = Hex.toHexString(data); + +/* Hex string to byte array */ +byte[] decoded = Hex.decode(hexStr); +``` + +### wolfSSL Approach + +```java +import com.wolfssl.wolfcrypt.WolfCrypt; + +/* Byte array to hex string */ +String hexStr = WolfCrypt.toHexString(data); + +/* Hex string to byte array */ +byte[] decoded = WolfCrypt.hexStringToByteArray(hexStr); +``` + +## PEM to DER Conversion + +Bouncy Castle `PEMParser` is commonly used to read PEM-encoded keys and +certificates, extract the underlying ASN.1 structure, and obtain the DER +encoding. This involves parsing the PEM object, casting to the appropriate +Bouncy Castle type (`PEMKeyPair`, `X509CertificateHolder`, +`SubjectPublicKeyInfo`, etc.), and then calling `getEncoded()`. + +wolfCrypt provides direct PEM-to-DER conversion methods in the `WolfCrypt` +class that handle the PEM parsing and DER extraction in a single call. + +### Private Key + +**Bouncy Castle:** + +```java +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.PEMKeyPair; + +PEMParser parser = new PEMParser(new FileReader("key.pem")); +PEMKeyPair keyPair = (PEMKeyPair) parser.readObject(); +byte[] der = keyPair.getPrivateKeyInfo().getEncoded(); +``` + +**wolfCrypt:** + +```java +import com.wolfssl.wolfcrypt.WolfCrypt; +import java.nio.file.Files; +import java.nio.file.Paths; + +byte[] pem = Files.readAllBytes(Paths.get("key.pem")); +byte[] der = WolfCrypt.keyPemToDer(pem, null); +``` + +### Encrypted Private Key (PKCS#8) + +Bouncy Castle requires building a decryptor provider and decrypting through +the PKCS#8 layer before obtaining the DER encoding. wolfCrypt accepts the +password directly. + +**Bouncy Castle:** + +```java +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder; +import org.bouncycastle.operator.InputDecryptorProvider; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; + +PEMParser parser = new PEMParser(new FileReader("key.pem")); +PKCS8EncryptedPrivateKeyInfo encInfo = + (PKCS8EncryptedPrivateKeyInfo) parser.readObject(); + +JceOpenSSLPKCS8DecryptorProviderBuilder builder = + new JceOpenSSLPKCS8DecryptorProviderBuilder(); +InputDecryptorProvider decryptor = + builder.build("password".toCharArray()); + +PrivateKeyInfo keyInfo = encInfo.decryptPrivateKeyInfo(decryptor); +byte[] der = keyInfo.getEncoded(); +``` + +**wolfCrypt:** + +```java +import com.wolfssl.wolfcrypt.WolfCrypt; + +byte[] pem = Files.readAllBytes(Paths.get("key.pem")); +byte[] der = WolfCrypt.keyPemToDer(pem, "password"); +``` + +### Certificate + +**Bouncy Castle:** + +```java +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.cert.X509CertificateHolder; + +PEMParser parser = new PEMParser(new FileReader("cert.pem")); +X509CertificateHolder holder = + (X509CertificateHolder) parser.readObject(); +byte[] der = holder.getEncoded(); +``` + +**wolfCrypt:** + +```java +import com.wolfssl.wolfcrypt.WolfCrypt; + +byte[] pem = Files.readAllBytes(Paths.get("cert.pem")); +byte[] der = WolfCrypt.certPemToDer(pem); +``` + +### Public Key + +**Bouncy Castle:** + +```java +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; + +PEMParser parser = new PEMParser(new FileReader("pubkey.pem")); +SubjectPublicKeyInfo pubKeyInfo = + (SubjectPublicKeyInfo) parser.readObject(); +byte[] der = pubKeyInfo.getEncoded(); +``` + +**wolfCrypt:** + +```java +import com.wolfssl.wolfcrypt.WolfCrypt; + +byte[] pem = Files.readAllBytes(Paths.get("pubkey.pem")); +byte[] der = WolfCrypt.pubKeyPemToDer(pem); +``` + +## RSA Miller-Rabin Primality Test Configuration + +Bouncy Castle allows configuring the number of Miller-Rabin primality test +rounds used during RSA key generation via a security property: + +```java +Security.setProperty("org.bouncycastle.rsa.max_mr_tests", "0"); +``` + +This property has no equivalent in wolfJCE. wolfCrypt's RSA implementation +uses a fixed number of Miller-Rabin rounds that cannot be adjusted at runtime. +When using wolfCrypt FIPS, the primality testing parameters are part of the +validated module and must not be modified in order to remain compliant with +FIPS 140-3 requirements. + +Any code that sets this Bouncy Castle property should simply be removed during +migration. diff --git a/BouncyCastle-Migration/src/chapter06.md b/BouncyCastle-Migration/src/chapter06.md new file mode 100644 index 00000000..5d04b0bd --- /dev/null +++ b/BouncyCastle-Migration/src/chapter06.md @@ -0,0 +1,52 @@ +# FIPS 140-3 Considerations + +One of the most common motivations for migrating from Bouncy Castle to +wolfJCE/wolfJSSE is to leverage wolfCrypt's FIPS 140-3 validated cryptographic +module. This chapter covers important considerations when using wolfJCE and +wolfJSSE in a FIPS-compliant configuration. + +## wolfCrypt FIPS 140-3 Overview + +wolfCrypt has undergone several FIPS 140-3 validations, providing certified +implementations of cryptographic algorithms. When wolfJCE and wolfJSSE are +built against a FIPS-validated version of wolfCrypt, the cryptographic +operations performed through these providers use the validated module. + +For more information on wolfCrypt FIPS 140-3 certificates and validated +platforms, contact wolfSSL at facts@wolfssl.com or visit +[https://www.wolfssl.com/license/fips/](https://www.wolfssl.com/license/fips/). + +wolfSSL can easily add Operating Environments to existing wolfCrypt FIPS 140-3 +certificates. If you have any specific needs or want to discuss this process, +wolfSSL is happy to talk through the details of how these typically work. + +## Building with FIPS Support + +To use FIPS 140-3 validated cryptography: + +1. Obtain a wolfCrypt FIPS 140-3 release from wolfSSL (requires a commercial license). +2. Build the native wolfSSL library with FIPS support enabled. +3. Build wolfCrypt JNI/JCE (and/or wolfSSL JNI/JSSE) against the FIPS-enabled + native library. + +The wolfCrypt FIPS module enforces operational requirements including +power-on self-tests (POST) and algorithm restrictions. These are handled +automatically by the native library and are transparent to Java application +code using the JCE/JSSE APIs. + +wolfCrypt FIPS 140-3 specific code (Conditional Algorithm Self Tests, in-core +integrity check, etc) can also be evaluated under wolfSSL JNI/JSSE and +wolfCrypt JNI/JCE by building the **FIPS Ready** GPLv3 variant of wolfSSL. +That can be downloaded from the [wolfSSL download page](https://wolfssl.com/download/). + +## Algorithm Restrictions Under FIPS + +When operating in FIPS mode, only FIPS-approved algorithms may be used. This +may affect which algorithms and KeyStore types are available through wolfJCE +compared to a non-FIPS build. Reference wolfSSL's [FIPS 140-3 certificates](https://www.wolfssl.com/license/fips/) +for lists of what algorithms are validated on each certificate. + +Applications using non-approved algorithms (e.g., MD5, DES, RC4) through Bouncy +Castle will need to either remove those usages or ensure they are not called +through the FIPS-validated provider. + diff --git a/BouncyCastle-Migration/src/chapter07.md b/BouncyCastle-Migration/src/chapter07.md new file mode 100644 index 00000000..9f5416e7 --- /dev/null +++ b/BouncyCastle-Migration/src/chapter07.md @@ -0,0 +1,103 @@ +# Troubleshooting and Common Issues + +This chapter covers common issues encountered during migration from Bouncy +Castle to wolfJCE/wolfJSSE and their solutions. + +## Native Library Loading Failures + +### UnsatisfiedLinkError + +``` +java.lang.UnsatisfiedLinkError: no wolfssl in java.library.path +``` + +The native wolfSSL shared library cannot be found. Ensure: + +- The wolfSSL shared library is compiled and installed. +- The library path is set correctly via `java.library.path`: + +``` +java -Djava.library.path=/usr/local/lib -jar myapp.jar +``` + +- On Linux, `LD_LIBRARY_PATH` includes the library directory. +- On macOS, `DYLD_LIBRARY_PATH` includes the library directory. + +## Provider Not Found + +``` +java.security.NoSuchProviderException: no such provider: wolfJCE +``` + +Ensure that the wolfJCE provider has been registered before attempting to use +it. Verify that: + +- `Security.addProvider(new WolfCryptProvider())` or + `Security.insertProviderAt(new WolfCryptProvider(), 1)` is called before any + cryptographic operations. +- Or, the provider is registered in the `java.security` configuration file. +- The wolfcrypt-jni JAR is on the classpath. + +## Algorithm Not Available + +``` +java.security.NoSuchAlgorithmException: no such algorithm: +``` + +The requested algorithm may not be supported by wolfJCE/wolfJSSE, or may not +be enabled in the native wolfSSL build. Check: + +- The [wolfJCE Supported Algorithms](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/chapter06.html) + and [wolfJSSE Supported Algorithms](https://www.wolfssl.com/documentation/manuals/wolfssljni/chapter06.html) + documentation. +- The native [wolfSSL library compile-time options](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter02.html) to ensure the algorithm is enabled. + +## Cipher Suite Mismatch + +If TLS connections fail with handshake errors, verify that: + +- The cipher suites used by the peer are supported by wolfJSSE. +- The TLS protocol version is enabled in the native wolfSSL build. +- Certificate types and key sizes are compatible. + +Use wolfJSSE debug logging to diagnose handshake issues: + +``` +java -Dwolfssl.debug=true -Dwolfjsse.debug=true -jar myapp.jar +``` + +## KeyStore Format Compatibility + +Bouncy Castle's BKS (BouncyCastle KeyStore) format is not supported by +wolfJCE. For FIPS 140-3 compatibility, KeyStores should be converted to WKS +(WolfSSLKeyStore) format. See the [KeyStore Migration](chapter03.md#keystore-migration) section in Chapter 3 +for detailed conversion instructions. + +Common KeyStore-related issues: + +### Wrong KeyStore Type + +``` +java.security.KeyStoreException: WKS not found +``` + +The wolfJCE provider must be registered before loading a WKS KeyStore. Ensure +`Security.addProvider(new WolfCryptProvider())` has been called, or that the +provider is configured in `java.security`. + +### BKS KeyStore Cannot Be Loaded Directly + +WKS does not read BKS format files. Convert BKS keystores to PKCS12 first +(using Bouncy Castle / `keytool`), then convert PKCS12 to WKS using wolfJCE. +See Chapter 3 for the step-by-step conversion process. + +### PBKDF2 Iteration Count Too Low + +``` +IllegalArgumentException: PBKDF2 iteration count below minimum +``` + +The WKS KeyStore enforces a minimum PBKDF2 iteration count of 10,000. If you +have set a custom value via `wolfjce.wks.iterationCount`, ensure it meets this +minimum. + diff --git a/BouncyCastle-Migration/src/chapter08.md b/BouncyCastle-Migration/src/chapter08.md new file mode 100644 index 00000000..65b4cb26 --- /dev/null +++ b/BouncyCastle-Migration/src/chapter08.md @@ -0,0 +1,44 @@ +# Support + +wolfSSL offers several support channels for users migrating from Bouncy Castle +to wolfJCE/wolfJSSE. + +## Commercial Support + +wolfSSL Inc. provides commercial support packages that include direct access +to the wolfSSL engineering team. Commercial support is available for: + +- Migration assistance and consulting +- FIPS 140-3 deployment guidance +- Custom feature development +- Platform porting and integration + +Contact wolfSSL for commercial support inquiries: + +- Email: [facts@wolfssl.com](mailto:facts@wolfssl.com) +- Web: [https://www.wolfssl.com/contact/](https://www.wolfssl.com/contact/) + +wolfSSL offers free presales support too! Contact our support team directly +with any questions or problems: + +- Email: [support@wolfssl.com](mailto:support@wolfssl.com) + +## Community Resources + +- **wolfSSL GitHub** - [https://github.com/wolfSSL](https://github.com/wolfSSL) +- **wolfSSL Forums** - [https://www.wolfssl.com/forums/](https://www.wolfssl.com/forums/) + +## Related Documentation + +- [wolfCrypt JCE Provider and JNI Manual](https://www.wolfssl.com/documentation/manuals/wolfcrypt-jni-jce/) +- [wolfSSL JNI and wolfJSSE Manual](https://www.wolfssl.com/documentation/manuals/wolfssljni/) +- [wolfSSL Manual](https://www.wolfssl.com/documentation/manuals/wolfssl/) +- [wolfSSL FIPS FAQ](https://www.wolfssl.com/documentation/manuals/fips-faq/) + +## Reporting Issues + +For bugs or issues with wolfJCE or wolfJSSE, please report them on the +appropriate GitHub repository: + +- wolfCrypt JNI/JCE: [https://github.com/wolfSSL/wolfcrypt-jni](https://github.com/wolfSSL/wolfcrypt-jni) +- wolfSSL JNI/JSSE: [https://github.com/wolfSSL/wolfssljni](https://github.com/wolfSSL/wolfssljni) diff --git a/Makefile b/Makefile index 4c63822f..5d0d3a72 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ endif # Handy debugging trick: `DOCKER_CMD_EXTRA_ARGS="--progress=plain" make` to see all the output DOCKER_CMD=DOCKER_BUILDKIT=1 docker build $(DOCKER_CMD_EXTRA_ARGS) -t doc_build --build-arg MANPATH=$(MANPATH) --build-arg PDFFILE=$(PDFFILE) --build-arg V=$(V) --target=manual --output=build -f Dockerfile . -all: wolfssl wolfssh wolfboot wolfclu wolfcrypt-jni wolfmqtt wolfsentry wolfssl-jni wolftpm wolfhsm wolfengine wolfprovider fips-ready tuning porting faq fips-faq +all: wolfssl wolfssh wolfboot wolfclu wolfcrypt-jni wolfmqtt wolfsentry wolfssl-jni wolftpm wolfhsm wolfengine wolfprovider fips-ready tuning porting faq fips-faq bc-migration build: $(Q)mkdir -p build @@ -113,5 +113,11 @@ fips-faq: PDFFILE=wolfSSL-FIPS-FAQ.pdf fips-faq: build @$(DOCKER_CMD) +.PHONY: bc-migration +bc-migration: MANPATH=BouncyCastle-Migration +bc-migration: PDFFILE=BouncyCastle-wolfSSL-Migration-Guide.pdf +bc-migration: build + $(Q)$(DOCKER_CMD) + clean: $(Q)rm -rf build diff --git a/README.md b/README.md index 5265b031..62b0e65d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ To build the documentation you will need Docker running on your system. In this * `make wolftpm` * `make porting` * `make fips-ready` +* `make bc-migration` ## Contributing