Skip to content

Commit 8ae8c40

Browse files
authored
Merge pull request #192 from cconlon/pkixBuilderSetDate
Add PKIXBuilderParameters.setDate() support for CertPathBuilder
2 parents 0265a61 + 1e31540 commit 8ae8c40

6 files changed

Lines changed: 573 additions & 5 deletions

File tree

README_JCE.md

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,10 +624,29 @@ TrustAnchor trustAnchor = result.getTrustAnchor();
624624
- Target certificate selection by certificate or subject name
625625
- Target certificate as trust anchor (returns empty path)
626626

627+
#### Date Override with PKIXBuilderParameters.setDate()
628+
629+
The `PKIXBuilderParameters.setDate()` method allows applications to validate
630+
certificate paths as if the current date were the specified date. This is
631+
useful for testing with expired certificates or validating certificates at a
632+
specific point in time.
633+
634+
wolfJCE supports `PKIXBuilderParameters.setDate()` for certificate validity
635+
checking during chain verification. When a date override is set:
636+
637+
1. Date validation is skipped when adding certificates to the internal store
638+
2. The custom date is used during chain verification via wolfSSL's
639+
`wolfSSL_X509_verify_cert()` function
640+
641+
This allows testing with expired certificates by specifying a date when the
642+
certificates were valid.
643+
644+
**Note:** See "CertPathBuilder Certificate Date Validation Timing" in the
645+
"Behavior Discrepancies with SunJCE" section for details on how this differs
646+
from SunJCE behavior.
647+
627648
#### Limitations
628649

629-
- **Date Override**: `PKIXBuilderParameters.setDate()` is not passed to native
630-
wolfSSL verification. Certificates are validated against current system time.
631650
- **TrustAnchor Name Constraints**: Name constraints on TrustAnchors are not
632651
supported. An `InvalidAlgorithmParameterException` is thrown if any
633652
TrustAnchor has name constraints set.
@@ -717,6 +736,38 @@ constraint violation will pass validation in wolfJCE.
717736
If this behavior is needed, please submit a feature request to
718737
support@wolfssl.com.
719738

739+
#### CertPathBuilder Certificate Date Validation Timing
740+
741+
When building certificate paths, SunJCE and wolfJCE differ in **when**
742+
certificate date validation occurs:
743+
744+
**SunJCE behavior:**
745+
- Trust anchors are loaded without date validation
746+
- Date validation occurs only during path verification
747+
- The date from `PKIXBuilderParameters.getDate()` (or current time if not set)
748+
is used for all date checks
749+
750+
**wolfJCE behavior:**
751+
- Native wolfSSL validates certificate dates when certificates are added to
752+
the internal `X509_STORE` via `wolfSSL_X509_STORE_add_cert()`
753+
- This validation uses the current system time, not a custom date
754+
- If no custom date is specified via `PKIXBuilderParameters.setDate()`,
755+
certificates are validated against the current system time at both add time
756+
and verification time
757+
- If a custom date is specified, wolfJCE skips date validation at add time
758+
and performs date validation during chain verification using the custom date
759+
760+
**Practical impact:**
761+
- Without a date override: Expired certificates will be rejected when added
762+
to the store (stricter than SunJCE)
763+
- With a date override: Behavior matches SunJCE - expired certificates can be
764+
added and will be validated against the custom date during verification
765+
766+
This difference exists because wolfSSL's `wolfSSL_X509_STORE_add_cert()`
767+
function validates certificate dates at addition time and does not support
768+
passing a custom validation date. The wolfJCE implementation works around
769+
this by skipping add-time validation when a custom date is specified.
770+
720771
### Support
721772
---------
722773

jni/include/com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx.h

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

jni/jni_wolfssl_x509_store_ctx.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,66 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_isCertPath
6767
return 0;
6868
}
6969

70+
/* Check if wolfSSL supports custom verification time (check_time)
71+
* in WOLFSSL_X509_STORE. This was added in wolfSSL after 5.8.4 and is
72+
* needed for PKIXBuilderParameters.setDate() support.
73+
*
74+
* To detect support, we set check_time on a WOLFSSL_X509_STORE, init a
75+
* WOLFSSL_X509_STORE_CTX from it, and verify that check_time was propagated
76+
* to the context. Older wolfSSL versions do not propagate. */
77+
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_isNativeStoreCheckTimeSupported
78+
(JNIEnv* env, jclass jcl)
79+
{
80+
#ifdef OPENSSL_EXTRA
81+
WOLFSSL_X509_STORE* store = NULL;
82+
WOLFSSL_X509_STORE_CTX* ctx = NULL;
83+
int supported = 0;
84+
85+
(void)env;
86+
(void)jcl;
87+
88+
if (!isCertPathBuilderAvailable()) {
89+
return 0;
90+
}
91+
92+
store = wolfSSL_X509_STORE_new();
93+
if (store == NULL) {
94+
return 0;
95+
}
96+
97+
ctx = wolfSSL_X509_STORE_CTX_new();
98+
if (ctx == NULL) {
99+
wolfSSL_X509_STORE_free(store);
100+
return 0;
101+
}
102+
103+
/* Set a test check_time on the store, using 1000000 just to test */
104+
if (store->param != NULL) {
105+
store->param->check_time = (time_t)1000000;
106+
store->param->flags |= WOLFSSL_USE_CHECK_TIME;
107+
}
108+
109+
/* Init ctx with the store and check if check_time
110+
* was propagated from store->param to ctx->param */
111+
if (wolfSSL_X509_STORE_CTX_init(ctx, store, NULL, NULL) ==
112+
WOLFSSL_SUCCESS) {
113+
if (ctx->param != NULL &&
114+
ctx->param->check_time == (time_t)1000000) {
115+
supported = 1;
116+
}
117+
}
118+
119+
wolfSSL_X509_STORE_CTX_free(ctx);
120+
wolfSSL_X509_STORE_free(store);
121+
122+
return supported;
123+
#else
124+
(void)env;
125+
(void)jcl;
126+
return 0;
127+
#endif
128+
}
129+
70130
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wolfSSL_1X509_1STORE_1new
71131
(JNIEnv* env, jclass jcl)
72132
{
@@ -90,6 +150,71 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wolfSSL_1
90150
return (jlong)(uintptr_t)store;
91151
}
92152

153+
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wolfSSL_1X509_1STORE_1set_1flags
154+
(JNIEnv* env, jclass jcl, jlong storePtr, jlong flags)
155+
{
156+
int ret = 0;
157+
#ifdef OPENSSL_EXTRA
158+
WOLFSSL_X509_STORE* store = (WOLFSSL_X509_STORE*)(uintptr_t)storePtr;
159+
160+
(void)env;
161+
(void)jcl;
162+
163+
if (store == NULL) {
164+
return BAD_FUNC_ARG;
165+
}
166+
167+
if (store->param == NULL) {
168+
return BAD_FUNC_ARG;
169+
}
170+
171+
/* Set flags directly on store->param->flags for NO_CHECK_TIME */
172+
store->param->flags |= (unsigned long)flags;
173+
174+
#else
175+
(void)env;
176+
(void)jcl;
177+
(void)storePtr;
178+
(void)flags;
179+
ret = NOT_COMPILED_IN;
180+
#endif
181+
182+
return ret;
183+
}
184+
185+
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wolfSSL_1X509_1STORE_1set_1time
186+
(JNIEnv* env, jclass jcl, jlong storePtr, jlong epochSeconds)
187+
{
188+
int ret = 0;
189+
#ifdef OPENSSL_EXTRA
190+
WOLFSSL_X509_STORE* store = (WOLFSSL_X509_STORE*)(uintptr_t)storePtr;
191+
192+
(void)env;
193+
(void)jcl;
194+
195+
if (store == NULL) {
196+
return BAD_FUNC_ARG;
197+
}
198+
199+
if (store->param == NULL) {
200+
return BAD_FUNC_ARG;
201+
}
202+
203+
/* Set custom check time and enable the flag */
204+
store->param->check_time = (time_t)epochSeconds;
205+
store->param->flags |= WOLFSSL_USE_CHECK_TIME;
206+
207+
#else
208+
(void)env;
209+
(void)jcl;
210+
(void)storePtr;
211+
(void)epochSeconds;
212+
ret = NOT_COMPILED_IN;
213+
#endif
214+
215+
return ret;
216+
}
217+
93218
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wolfSSL_1X509_1STORE_1free
94219
(JNIEnv* env, jclass jcl, jlong storePtr)
95220
{

src/main/java/com/wolfssl/provider/jce/WolfCryptPKIXCertPathBuilder.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -689,9 +689,10 @@ private NativeChainResult buildAndVerifyPathNative(
689689
Set<TrustAnchor> anchors = null;
690690
List<CertStore> certStores = null;
691691
int maxPathLength = 0;
692+
Date validationDate = null;
693+
WolfSSLX509StoreCtx storeCtx = null;
692694

693-
log("building and verifying path using native wolfSSL X509_STORE");
694-
695+
log("building and verifying path using native WOLFSSL_X509_STORE");
695696

696697
if (targetCert == null || params == null) {
697698
throw new CertPathBuilderException(
@@ -701,11 +702,36 @@ private NativeChainResult buildAndVerifyPathNative(
701702
anchors = params.getTrustAnchors();
702703
certStores = params.getCertStores();
703704
maxPathLength = params.getMaxPathLength();
705+
validationDate = params.getDate();
704706

705-
WolfSSLX509StoreCtx storeCtx = null;
706707
try {
707708
storeCtx = new WolfSSLX509StoreCtx();
708709

710+
/* If a custom validation date is specified, we skip date
711+
* validation when adding certificates, then set the custom
712+
* verification time for chain verification.
713+
*
714+
* This allows for testing/use of expired certs if desired,
715+
* or validating against a specific date.
716+
*
717+
* SunJCE only validates expiration dates on chain verification,
718+
* not cert loading, so our default behavior already does some
719+
* extra validation here in the case when a custom date is not
720+
* set. */
721+
if (validationDate != null) {
722+
if (!WolfSSLX509StoreCtx.isStoreCheckTimeSupported()) {
723+
throw new CertPathBuilderException(
724+
"PKIXBuilderParameters.setDate() requires " +
725+
"a wolfSSL version that supports X509_STORE " +
726+
"check_time propagation (> 5.8.4)");
727+
}
728+
log("using custom validation date: " + validationDate);
729+
storeCtx.setFlags(
730+
WolfSSLX509StoreCtx.WOLFSSL_NO_CHECK_TIME);
731+
storeCtx.setVerificationTime(
732+
validationDate.getTime() / 1000);
733+
}
734+
709735
/* Add trust anchors to the store */
710736
for (TrustAnchor anchor : anchors) {
711737

0 commit comments

Comments
 (0)