Skip to content

Commit 55040a9

Browse files
authored
Merge pull request wolfSSL#198 from cconlon/certPathBuilderDateFix
Fix for CertPathBuilder `setDate()` custom date validation and add boundary tests
2 parents ad62699 + 32ce48e commit 55040a9

File tree

4 files changed

+170
-134
lines changed

4 files changed

+170
-134
lines changed

IDE/Android/app/src/main/cpp/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,14 @@ aux_source_directory(${wolfssl_DIR}/src TLS_SOURCES)
255255
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/bio.c)
256256
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/conf.c)
257257
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/pk.c)
258+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/pk_ec.c)
259+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/pk_rsa.c)
258260
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_bn.c)
261+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_api_cert.c)
262+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_api_crl_ocsp.c)
263+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_api_pk.c)
259264
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_asn1.c)
265+
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_ech.c)
260266
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_certman.c)
261267
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_crypto.c)
262268
list(REMOVE_ITEM TLS_SOURCES ${wolfssl_DIR}/src/ssl_load.c)
@@ -271,6 +277,7 @@ if ("${WOLFSSL_PKG_TYPE}" MATCHES "normal")
271277
# Add crypto sources to CRYPTO_SOURCES, remove files that are included inline by other files
272278
aux_source_directory(${wolfssl_DIR}/wolfcrypt/src CRYPTO_SOURCES)
273279
list(REMOVE_ITEM CRYPTO_SOURCES ${wolfssl_DIR}/wolfcrypt/src/evp.c)
280+
list(REMOVE_ITEM CRYPTO_SOURCES ${wolfssl_DIR}/wolfcrypt/src/evp_pk.c)
274281
list(REMOVE_ITEM CRYPTO_SOURCES ${wolfssl_DIR}/wolfcrypt/src/misc.c)
275282

276283
elseif("${WOLFSSL_PKG_TYPE}" MATCHES "fipsready")

jni/jni_wolfssl_x509_store_ctx.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,16 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_wolfcrypt_WolfSSLX509StoreCtx_wo
447447
return NULL;
448448
}
449449

450+
/* When USE_CHECK_TIME is set (custom verification date), clear
451+
* NO_CHECK_TIME from ctx->param so X509StoreVerifyCertDate()
452+
* validates cert dates against check_time. NO_CHECK_TIME is still set on
453+
* store->param so X509StoreAddCa() can still accept expired certs
454+
* into the store. */
455+
if (ctx->param != NULL &&
456+
(ctx->param->flags & WOLFSSL_USE_CHECK_TIME) != 0) {
457+
ctx->param->flags &= (unsigned long)(~WOLFSSL_NO_CHECK_TIME);
458+
}
459+
450460
/* Set max path length if specified.
451461
* Depth = max intermediates + 1 for root CA.
452462
* Check for overflow when adding 1 to maxPathLength. */

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

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959

6060
import com.wolfssl.wolfcrypt.Fips;
6161
import com.wolfssl.wolfcrypt.WolfCrypt;
62-
import com.wolfssl.wolfcrypt.WolfSSLCertManager;
6362
import com.wolfssl.wolfcrypt.WolfSSLX509StoreCtx;
6463
import com.wolfssl.wolfcrypt.WolfCryptException;
6564

@@ -524,77 +523,6 @@ private TrustAnchor findPathTrustAnchor(List<X509Certificate> path,
524523
return anchor;
525524
}
526525

527-
/**
528-
* Validate the built certificate path.
529-
*
530-
* @param path the certificate path to validate
531-
* @param params the PKIX builder parameters
532-
* @param anchor the trust anchor
533-
*
534-
* @throws CertPathBuilderException if validation fails
535-
*/
536-
private void validatePath(List<X509Certificate> path,
537-
PKIXBuilderParameters params, TrustAnchor anchor)
538-
throws CertPathBuilderException {
539-
540-
WolfSSLCertManager cm = null;
541-
542-
log("validating built path (" + path.size() + " certificates)");
543-
544-
if (path == null || anchor == null) {
545-
throw new CertPathBuilderException(
546-
"Path or TrustAnchor is null");
547-
}
548-
549-
try {
550-
cm = new WolfSSLCertManager();
551-
552-
/* Load trust anchor as CA */
553-
X509Certificate anchorCert = anchor.getTrustedCert();
554-
if (anchorCert != null) {
555-
cm.CertManagerLoadCA(anchorCert);
556-
log("loaded trust anchor: " +
557-
anchorCert.getSubjectX500Principal().getName());
558-
}
559-
560-
/* Verify certificates from top (closest to anchor) to target */
561-
for (int i = path.size() - 1; i >= 0; i--) {
562-
X509Certificate cert = path.get(i);
563-
564-
try {
565-
cm.CertManagerVerify(cert);
566-
log("verified: " +
567-
cert.getSubjectX500Principal().getName());
568-
569-
} catch (WolfCryptException e) {
570-
throw new CertPathBuilderException(
571-
"Certificate verification failed: " +
572-
cert.getSubjectX500Principal().getName(), e);
573-
}
574-
575-
/* Load verified cert as CA for next verification */
576-
if (i > 0 && cert.getBasicConstraints() >= 0) {
577-
try {
578-
cm.CertManagerLoadCA(cert);
579-
580-
} catch (WolfCryptException e) {
581-
/* continue */
582-
log("Warning: failed to load verified cert as CA");
583-
}
584-
}
585-
}
586-
587-
} catch (WolfCryptException e) {
588-
throw new CertPathBuilderException(
589-
"Failed to create or use WolfSSLCertManager", e);
590-
591-
} finally {
592-
if (cm != null) {
593-
cm.free();
594-
}
595-
}
596-
}
597-
598526
/**
599527
* Helper class to hold chain building result with trust anchor.
600528
*/

src/test/java/com/wolfssl/provider/jce/test/WolfCryptPKIXCertPathBuilderTest.java

Lines changed: 153 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,6 +3450,52 @@ private X509Certificate loadCertFromPEM(String pem)
34503450
return (X509Certificate) cf.generateCertificate(bis);
34513451
}
34523452

3453+
/**
3454+
* Helper to create PKIXBuilderParameters for expired cert tests.
3455+
*
3456+
* Loads expired test certificates (valid May 2014 - April 2016)
3457+
* and sets up trust anchors, CertStore, and target selector.
3458+
*
3459+
* @param dateMillis custom validation date in epoch millis,
3460+
* or -1 to use current system time
3461+
*
3462+
* @return configured PKIXBuilderParameters
3463+
*/
3464+
private PKIXBuilderParameters createExpiredCertParams(long dateMillis)
3465+
throws CertificateException, InvalidAlgorithmParameterException,
3466+
NoSuchAlgorithmException {
3467+
3468+
X509Certificate rootCert =
3469+
loadCertFromPEM(EXPIRED_ROOT_PEM);
3470+
X509Certificate intermediateCert =
3471+
loadCertFromPEM(EXPIRED_INTERMEDIATE_PEM);
3472+
X509Certificate userCert =
3473+
loadCertFromPEM(EXPIRED_USER_PEM);
3474+
3475+
Set<TrustAnchor> anchors = new HashSet<>();
3476+
anchors.add(new TrustAnchor(rootCert, null));
3477+
3478+
Collection<Certificate> certs = new ArrayList<>();
3479+
certs.add(userCert);
3480+
certs.add(intermediateCert);
3481+
CertStore certStore = CertStore.getInstance("Collection",
3482+
new CollectionCertStoreParameters(certs));
3483+
3484+
X509CertSelector selector = new X509CertSelector();
3485+
selector.setCertificate(userCert);
3486+
3487+
PKIXBuilderParameters params =
3488+
new PKIXBuilderParameters(anchors, selector);
3489+
params.setRevocationEnabled(false);
3490+
params.addCertStore(certStore);
3491+
3492+
if (dateMillis >= 0) {
3493+
params.setDate(new Date(dateMillis));
3494+
}
3495+
3496+
return params;
3497+
}
3498+
34533499
/**
34543500
* Test building a cert path with expired certificates using
34553501
* a custom validation date set via PKIXBuilderParameters.setDate().
@@ -3473,47 +3519,34 @@ public void testExpiredCertsWithCustomValidationDate()
34733519
"this wolfSSL version",
34743520
WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
34753521

3476-
/* Load expired test certificates */
3477-
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
3522+
/* Load certs separately for result assertions below */
3523+
X509Certificate rootCert =
3524+
loadCertFromPEM(EXPIRED_ROOT_PEM);
34783525
X509Certificate intermediateCert =
34793526
loadCertFromPEM(EXPIRED_INTERMEDIATE_PEM);
3480-
X509Certificate userCert = loadCertFromPEM(EXPIRED_USER_PEM);
3481-
3482-
/* Set up trust anchors with the expired root */
3483-
Set<TrustAnchor> anchors = new HashSet<>();
3484-
anchors.add(new TrustAnchor(rootCert, null));
3485-
3486-
/* Set up CertStore with intermediate and target certs */
3487-
Collection<Certificate> certs = new ArrayList<>();
3488-
certs.add(userCert);
3489-
certs.add(intermediateCert);
3490-
CertStore certStore = CertStore.getInstance("Collection",
3491-
new CollectionCertStoreParameters(certs));
3527+
X509Certificate userCert =
3528+
loadCertFromPEM(EXPIRED_USER_PEM);
34923529

3493-
/* Create target selector for user cert */
3494-
X509CertSelector selector = new X509CertSelector();
3495-
selector.setCertificate(userCert);
3496-
3497-
/* Create PKIXBuilderParameters with custom validation date.
3498-
* Date is March 15, 2015 (within cert validity period 2014-2016).
3499-
* Epoch time 1426399200000L = Sun Mar 15 2015 06:00:00 GMT */
3530+
/* Date is March 15, 2015 (within cert validity 2014-2016).
3531+
* Epoch time 1426399200000L = Sun Mar 15 2015 06:00:00 */
35003532
PKIXBuilderParameters params =
3501-
new PKIXBuilderParameters(anchors, selector);
3502-
params.setRevocationEnabled(false);
3503-
params.addCertStore(certStore);
3504-
params.setDate(new Date(1426399200000L));
3533+
createExpiredCertParams(1426399200000L);
35053534

35063535
/* Build cert path - should succeed with custom date */
3507-
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
3536+
CertPathBuilder cpb =
3537+
CertPathBuilder.getInstance("PKIX", provider);
35083538
CertPathBuilderResult result = cpb.build(params);
35093539

35103540
/* Verify result */
3511-
assertNotNull("CertPathBuilderResult should not be null", result);
3512-
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
3541+
assertNotNull(
3542+
"CertPathBuilderResult should not be null", result);
3543+
PKIXCertPathBuilderResult pResult =
3544+
(PKIXCertPathBuilderResult) result;
35133545

35143546
/* Verify trust anchor is the root cert */
35153547
assertEquals("Trust anchor should be the root cert",
3516-
rootCert, pResult.getTrustAnchor().getTrustedCert());
3548+
rootCert,
3549+
pResult.getTrustAnchor().getTrustedCert());
35173550

35183551
/* Verify path contains user and intermediate certs
35193552
* (root/trust anchor is not included in the path) */
@@ -3525,60 +3558,118 @@ public void testExpiredCertsWithCustomValidationDate()
35253558
/* Verify path order: user -> intermediate */
35263559
assertEquals("First cert in path should be user cert",
35273560
userCert, path.getCertificates().get(0));
3528-
assertEquals("Second cert in path should be intermediate cert",
3561+
assertEquals(
3562+
"Second cert in path should be intermediate cert",
35293563
intermediateCert, path.getCertificates().get(1));
35303564
}
35313565

35323566
/**
3533-
* Test that expired certs fail validation when no custom date
3534-
* is set (using current system time).
3567+
* Test that setDate() with a date after cert expiry still fails.
35353568
*
3536-
* This test verifies that wolfJCE properly rejects expired certificates
3537-
* when validating against the current system time.
3569+
* Uses expired certificates (valid 2014-2016) and sets a validation
3570+
* date of March 15, 2017 (after the certificates expired). This
3571+
* verifies that setDate() properly validates against the custom date.
35383572
*/
35393573
@Test
3540-
public void testExpiredCertsFailWithoutCustomDate()
3574+
public void testExpiredCertsFailWithDateAfterExpiry()
35413575
throws CertificateException, InvalidAlgorithmParameterException,
35423576
NoSuchAlgorithmException, NoSuchProviderException {
35433577

3544-
/* Load expired test certificates */
3545-
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
3546-
X509Certificate intermediateCert =
3547-
loadCertFromPEM(EXPIRED_INTERMEDIATE_PEM);
3548-
X509Certificate userCert = loadCertFromPEM(EXPIRED_USER_PEM);
3578+
Assume.assumeTrue("X509_STORE check_time support not available in " +
3579+
"this wolfSSL version",
3580+
WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
35493581

3550-
/* Set up trust anchors with the expired root */
3551-
Set<TrustAnchor> anchors = new HashSet<>();
3552-
anchors.add(new TrustAnchor(rootCert, null));
3582+
/* Date is March 15, 2017 (certs expired April 30, 2016).
3583+
* Epoch time 1489561200000L = Wed Mar 15 2017 06:00:00 */
3584+
PKIXBuilderParameters params = createExpiredCertParams(1489561200000L);
35533585

3554-
/* Set up CertStore with intermediate and target certs */
3555-
Collection<Certificate> certs = new ArrayList<>();
3556-
certs.add(userCert);
3557-
certs.add(intermediateCert);
3558-
CertStore certStore = CertStore.getInstance("Collection",
3559-
new CollectionCertStoreParameters(certs));
3586+
/* Build cert path, should fail because custom date after cert expiry */
3587+
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
3588+
try {
3589+
cpb.build(params);
3590+
fail("Expected CertPathBuilderException when custom " +
3591+
"date is after cert expiry");
3592+
} catch (CertPathBuilderException e) {
3593+
/* Expected, date is after cert validity */
3594+
assertNotNull("Exception message should not be null",
3595+
e.getMessage());
3596+
assertTrue("Exception should indicate cert expired, got: " +
3597+
e.getMessage(), e.getMessage().contains("expired"));
3598+
}
3599+
}
35603600

3561-
/* Create target selector for user cert */
3562-
X509CertSelector selector = new X509CertSelector();
3563-
selector.setCertificate(userCert);
3601+
/**
3602+
* Test that setDate() with a date before cert validity still fails.
3603+
*
3604+
* Uses expired certificates (valid May 1, 2014 - April 30, 2016)
3605+
* and sets a validation date of January 1, 2014 (before notBefore).
3606+
* This verifies that setDate() also checks the notBefore boundary.
3607+
*/
3608+
@Test
3609+
public void testExpiredCertsFailWithDateBeforeValidity()
3610+
throws CertificateException, InvalidAlgorithmParameterException,
3611+
NoSuchAlgorithmException, NoSuchProviderException {
35643612

3565-
/* Create PKIXBuilderParameters WITHOUT custom date.
3566-
* This will use current system time for validation. */
3613+
Assume.assumeTrue(
3614+
"X509_STORE check_time support not available in " +
3615+
"this wolfSSL version",
3616+
WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
3617+
3618+
/* Date is January 1, 2014 (certs valid from May 1, 2014).
3619+
* Epoch time 1388534400000L = Wed Jan 01 2014 00:00:00 */
35673620
PKIXBuilderParameters params =
3568-
new PKIXBuilderParameters(anchors, selector);
3569-
params.setRevocationEnabled(false);
3570-
params.addCertStore(certStore);
3571-
/* Note: NOT calling params.setDate() - uses current time */
3621+
createExpiredCertParams(1388534400000L);
3622+
3623+
/* Build cert path - should FAIL because custom date is
3624+
* before cert notBefore */
3625+
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
3626+
try {
3627+
cpb.build(params);
3628+
fail("Expected CertPathBuilderException when custom " +
3629+
"date is before cert notBefore");
3630+
} catch (CertPathBuilderException e) {
3631+
/* Expected, date is before cert validity */
3632+
assertNotNull("Exception message should not be null",
3633+
e.getMessage());
3634+
assertTrue("Exception should indicate cert not yet valid" +
3635+
", got: " + e.getMessage(),
3636+
e.getMessage().contains("not yet valid"));
3637+
}
3638+
}
3639+
3640+
/**
3641+
* Test that expired certs fail validation when no custom date
3642+
* is set (using current system time).
3643+
*
3644+
* This test verifies that wolfJCE properly rejects expired certificates
3645+
* when validating against the current system time.
3646+
*/
3647+
@Test
3648+
public void testExpiredCertsFailWithoutCustomDate()
3649+
throws CertificateException, InvalidAlgorithmParameterException,
3650+
NoSuchAlgorithmException, NoSuchProviderException {
3651+
3652+
/* No custom date (-1), uses current system time */
3653+
PKIXBuilderParameters params = createExpiredCertParams(-1);
35723654

35733655
/* Build cert path - should FAIL because certs are expired */
35743656
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
35753657
try {
35763658
cpb.build(params);
3577-
fail("Expected CertPathBuilderException for expired certificates");
3659+
fail("Expected CertPathBuilderException for " +
3660+
"expired certificates");
35783661
} catch (CertPathBuilderException e) {
3579-
/* Expected - certificates are expired */
3580-
assertTrue("Exception message should indicate certificate issue",
3581-
e.getMessage() != null);
3662+
/* Expected, certificates are expired. May fail
3663+
* during store addition ("Failed to add certificate")
3664+
* or during verification ("expired"), depending on
3665+
* wolfSSL version and configuration. */
3666+
assertNotNull("Exception message should not be null",
3667+
e.getMessage());
3668+
assertTrue("Exception should indicate cert date issue" +
3669+
", got: " + e.getMessage(),
3670+
e.getMessage().contains("expired") ||
3671+
e.getMessage().contains(
3672+
"Failed to add certificate"));
35823673
}
35833674
}
35843675
}

0 commit comments

Comments
 (0)