Skip to content

Commit 4592dd2

Browse files
authored
Merge pull request #177 from cconlon/rsaPrivKeyFix
PKIXCertPathValidator improvements
2 parents fd03d2c + 1f6a02c commit 4592dd2

23 files changed

+5657
-49
lines changed

README_JCE.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ The JCE provider currently supports the following algorithms:
205205
DH (aliases: DiffieHellman, 1.2.840.113549.1.3.1)
206206

207207
CertPathValidator Class
208-
PKIX
208+
PKIX (with PKIXRevocationChecker via getRevocationChecker())
209209

210210
SecretKeyFactory
211211
PBKDF2WithHmacSHA1
@@ -497,6 +497,40 @@ $ cd wolfcrypt-jni-X.X.X
497497
$ cp ./lib/signed/release/wolfcrypt-jni.jar ./lib
498498
$ ant test
499499

500+
### CertPathValidator (PKIX) Implementation Notes
501+
---------
502+
503+
wolfJCE provides a PKIX CertPathValidator implementation that supports
504+
certificate path validation with revocation checking via OCSP and CRL.
505+
506+
#### Date Override with PKIXParameters.setDate()
507+
508+
The `PKIXParameters.setDate()` method allows applications to validate
509+
certificate paths as if the current date were the specified date. This is
510+
useful for testing or validating certificates at a specific point in time.
511+
512+
wolfJCE supports `PKIXParameters.setDate()` for **certificate validity
513+
checking**. When a date override is set, certificates will be validated
514+
against that date rather than the current system time.
515+
516+
**Note:** The date override only applies to certificate validity checking,
517+
not to OCSP response validation. OCSP responses are always validated against
518+
the current system time by wolfSSL. This means that preloaded OCSP responses
519+
(via `PKIXRevocationChecker.setOcspResponses()`) must have current/valid
520+
thisUpdate and nextUpdate dates. Historical OCSP responses with expired dates
521+
cannot be used, even with a date override.
522+
523+
#### TrustAnchor Name Constraints
524+
525+
Name constraints specified directly on a TrustAnchor (via the
526+
`TrustAnchor(X509Certificate, byte[])` constructor) are not supported.
527+
wolfJCE throws `InvalidAlgorithmParameterException` if any TrustAnchor in
528+
PKIXParameters has name constraints set. This matches SunJCE behavior.
529+
530+
Applications should use TrustAnchors without explicit name constraints; if
531+
name constraint enforcement is needed, the constraints should be embedded in
532+
the trust anchor certificate itself.
533+
500534
### Behavior Discrepancies with SunJCE
501535
---------
502536

@@ -522,6 +556,60 @@ This descrepancy should not be an issue, since `doFinal()` returns the
522556
actual number of bytes written to the output buffer, so applications can use
523557
that to know the true output size in the output buffer returned.
524558

559+
#### PKIXRevocationChecker `PREFER_CRLS` Check Order
560+
561+
When using `PKIXRevocationChecker` with the `PREFER_CRLS` option and fallback
562+
enabled (i.e., `NO_FALLBACK` is not set), the SunJCE implementation checks
563+
CRL first, then falls back to OCSP if CRL checking fails.
564+
565+
wolfJCE cannot replicate this exact order due to how native wolfSSL handles
566+
CRL checking. The wolfSSL CertManager does not expose a separate API to
567+
explicitly check CRLs - instead, CRL checking happens automatically during
568+
certificate chain verification (`wolfSSL_CertManagerVerifyBuffer()`). This
569+
verification occurs after the `PKIXRevocationChecker.check()` method returns.
570+
571+
As a result, when `PREFER_CRLS` is set with fallback enabled:
572+
- **SunJCE**: CRL first, then OCSP fallback
573+
- **wolfJCE**: OCSP runs in `check()`, CRL runs during cert verification
574+
575+
Both revocation methods are still checked when fallback is enabled, but the
576+
order differs. In practice, if either method determines the certificate is
577+
revoked, validation will fail. The difference only affects behavior when one
578+
method succeeds and the other would have failed (e.g., OCSP unreachable but
579+
CRL available).
580+
581+
#### Indirect CRL Not Supported
582+
583+
Native wolfSSL does not support indirect CRLs. An indirect CRL is a CRL signed
584+
by a different entity than the certificate issuer, identified by the Issuing
585+
Distribution Point (IDP) extension with the `indirectCRL` flag set to TRUE.
586+
587+
wolfSSL matches CRLs to certificates by comparing the CRL issuer hash with the
588+
certificate's issuer hash. For indirect CRLs, these hashes are different (the
589+
certificate was issued by one CA, but the CRL is signed by a separate CRL
590+
issuer entity), so wolfSSL will not find a matching CRL for the certificate.
591+
592+
As a result, certificates that should be detected as revoked via an indirect
593+
CRL will pass validation in wolfJCE. The certificate chain verification
594+
succeeds because no matching CRL is found (from wolfSSL's perspective, there
595+
is simply no CRL available for that certificate).
596+
597+
If this behavior is needed, please submit a feature request to
598+
599+
600+
#### Name Constraints with RegisteredID Not Supported
601+
602+
Native wolfSSL validates Name Constraints for email (rfc822Name), DNS, and
603+
directory name types, but does not enforce name constraints for registeredID
604+
(RID) types. If a CA certificate contains a Name Constraint that excludes or
605+
permits specific registeredID values, certificates with subjectAltName entries
606+
of type registeredID will not be validated against these constraints.
607+
608+
As a result, certificates that should be rejected due to a registeredID name
609+
constraint violation will pass validation in wolfJCE.
610+
611+
If this behavior is needed, please submit a feature request to
612+
525613

526614
### Support
527615
---------

jni/include/com_wolfssl_wolfcrypt_WolfCrypt.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni/include/com_wolfssl_wolfcrypt_WolfSSLCertManager.h

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni/jni_error.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@
2525
#include <wolfssl/options.h>
2626
#endif
2727

28+
#include <wolfssl/ssl.h>
2829
#include <com_wolfssl_wolfcrypt_WolfCryptError.h>
2930
#include <wolfcrypt_jni_error.h>
3031

3132
JNIEXPORT jstring JNICALL Java_com_wolfssl_wolfcrypt_WolfCryptError_wc_1GetErrorString
3233
(JNIEnv* env, jclass obj, jint error)
3334
{
34-
return (*env)->NewStringUTF(env, wc_GetErrorString(error));
35+
/* wolfSSL_ERR_reason_error_string handles wolfCrypt and wolfSSL layer
36+
* error codes, using here instead of wc_GetErrorString() */
37+
return (*env)->NewStringUTF(env,
38+
wolfSSL_ERR_reason_error_string((unsigned long)error));
3539
}
3640

3741
void throwWolfCryptExceptionFromError(JNIEnv* env, int code)
@@ -74,6 +78,7 @@ void throwWolfCryptExceptionFromError(JNIEnv* env, int code)
7478
}
7579
}
7680

77-
throwWolfCryptException(env, wc_GetErrorString(code));
81+
throwWolfCryptException(env,
82+
wolfSSL_ERR_reason_error_string((unsigned long)code));
7883
}
7984

jni/jni_native_struct.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,39 @@
4040

4141
JavaVM* g_vm = NULL;
4242

43+
/* Forward declarations for WolfSSLCertManager init/cleanup */
44+
extern int wolfSSL_CertManager_init(void);
45+
extern void wolfSSL_CertManager_cleanup(void);
46+
4347
/* called when native library is loaded */
4448
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
4549
{
50+
(void)reserved;
51+
4652
/* store JavaVM */
4753
g_vm = vm;
54+
55+
/* Initialize WolfSSLCertManager global mutex for thread-safe callback
56+
* handling. Done here so it is before any CertManager ops happen. */
57+
if (wolfSSL_CertManager_init() != 0) {
58+
return JNI_ERR;
59+
}
60+
4861
return JNI_VERSION_1_6;
4962
}
5063

64+
/* called when native library is unloaded */
65+
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
66+
{
67+
(void)vm;
68+
(void)reserved;
69+
70+
/* Cleanup WolfSSLCertManager global mutex */
71+
wolfSSL_CertManager_cleanup();
72+
73+
g_vm = NULL;
74+
}
75+
5176
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_NativeStruct_xfree(
5277
JNIEnv* env, jobject this, jlong ptr)
5378
{

jni/jni_wolfcrypt.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#endif
2929

3030
#include <wolfssl/wolfcrypt/types.h>
31+
#include <wolfssl/wolfcrypt/asn.h>
3132
#include <com_wolfssl_wolfcrypt_WolfCrypt.h>
3233
#include <wolfcrypt_jni_error.h>
3334

@@ -131,3 +132,16 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_WolfCrypt_CrlEnabled
131132
#endif
132133
}
133134

135+
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_WolfCrypt_OcspEnabled
136+
(JNIEnv* env, jclass jcl)
137+
{
138+
(void)env;
139+
(void)jcl;
140+
141+
#ifdef HAVE_OCSP
142+
return JNI_TRUE;
143+
#else
144+
return JNI_FALSE;
145+
#endif
146+
}
147+

0 commit comments

Comments
 (0)