Skip to content

Commit 87f44e9

Browse files
tie in use of check_time with x509 store
1 parent 6c5e841 commit 87f44e9

File tree

4 files changed

+217
-29
lines changed

4 files changed

+217
-29
lines changed

src/x509_str.c

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,18 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx,
230230
XMEMSET(ctx->param, 0, sizeof(*ctx->param));
231231
}
232232

233+
/* Copy check_time from store parameters if available */
234+
if (store != NULL && store->param != NULL) {
235+
if ((store->param->flags & WOLFSSL_USE_CHECK_TIME) != 0 &&
236+
store->param->check_time != 0) {
237+
ctx->param->check_time = store->param->check_time;
238+
ctx->param->flags |= WOLFSSL_USE_CHECK_TIME;
239+
}
240+
if ((store->param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
241+
ctx->param->flags |= WOLFSSL_NO_CHECK_TIME;
242+
}
243+
}
244+
233245
return WOLFSSL_SUCCESS;
234246
}
235247
return WOLFSSL_FAILURE;
@@ -321,6 +333,74 @@ static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret)
321333
SetupStoreCtxError_ex(ctx, ret, depth);
322334
}
323335

336+
#ifndef NO_ASN_TIME
337+
/* Post certificate validation date handling. This function is called after the
338+
* certificate has been verified by the certificate manager. It then checks if
339+
* X509 store parameters are set for date validation override.
340+
* @param ctx The certificate store context
341+
* @param ret The return value from the certificate manager verify
342+
* @return The return value for the certificate date validation after override
343+
*/
344+
static int X509StoreVerifyCertDate(WOLFSSL_X509_STORE_CTX* ctx, int ret)
345+
{
346+
byte *afterDate = ctx->current_cert->notAfter.data;
347+
byte *beforeDate = ctx->current_cert->notBefore.data;
348+
349+
/* Only override existing date errors or WOLFSSL_SUCCESS. */
350+
if (ret == WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) ||
351+
ret == WC_NO_ERR_TRACE(ASN_AFTER_DATE_E) ||
352+
ret == WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
353+
#ifdef USE_WOLF_VALIDDATE
354+
WOLFSSL_X509_VERIFY_PARAM* param = NULL;
355+
356+
/* If no external XVALIDATE_DATE was defined then use param for date
357+
validation overrides. */
358+
if (ctx->param != NULL) {
359+
param = ctx->param;
360+
}
361+
else if (ctx->store != NULL && ctx->store->param != NULL) {
362+
param = ctx->store->param;
363+
}
364+
365+
if (param != NULL) {
366+
if ((param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
367+
WOLFSSL_MSG("Overriding date validation WOLFSSL_NO_CHECK_TIME");
368+
ret = WOLFSSL_SUCCESS;
369+
}
370+
else if ((param->flags & WOLFSSL_USE_CHECK_TIME) != 0 &&
371+
(param->check_time != 0)) {
372+
time_t checkTime = param->check_time;
373+
ret = WOLFSSL_SUCCESS; /* override date error and use custom set
374+
time for validating certificate dates */
375+
WOLFSSL_MSG("Override date validation, WOLFSSL_USE_CHECK_TIME");
376+
if (wc_ValidateDateWithTime(afterDate,
377+
(byte)ctx->current_cert->notAfter.type, ASN_AFTER,
378+
checkTime) < 1) {
379+
ret = ASN_AFTER_DATE_E;
380+
}
381+
else if (wc_ValidateDateWithTime(beforeDate,
382+
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE,
383+
checkTime) < 1) {
384+
ret = ASN_BEFORE_DATE_E;
385+
}
386+
}
387+
}
388+
#else
389+
if (XVALIDATE_DATE(afterDate,
390+
(byte)ctx->current_cert->notAfter.type, ASN_AFTER) < 1) {
391+
ret = ASN_AFTER_DATE_E;
392+
}
393+
else if (XVALIDATE_DATE(beforeDate,
394+
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE) < 1) {
395+
ret = ASN_BEFORE_DATE_E;
396+
}
397+
#endif /* USE_WOLF_VALIDDATE */
398+
}
399+
400+
return ret;
401+
}
402+
#endif /* NO_ASN_TIME */
403+
324404
static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx)
325405
{
326406
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
@@ -331,39 +411,16 @@ static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx)
331411
ctx->current_cert->derCert->buffer,
332412
ctx->current_cert->derCert->length,
333413
WOLFSSL_FILETYPE_ASN1);
414+
#ifndef NO_ASN_TIME
415+
/* update return value with any date validation overrides */
416+
ret = X509StoreVerifyCertDate(ctx, ret);
417+
#endif
334418
SetupStoreCtxError(ctx, ret);
335419
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
336420
if (ctx->store->verify_cb)
337421
ret = ctx->store->verify_cb(ret >= 0 ? 1 : 0, ctx) == 1 ?
338422
WOLFSSL_SUCCESS : ret;
339423
#endif
340-
341-
#ifndef NO_ASN_TIME
342-
if (ret != WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) &&
343-
ret != WC_NO_ERR_TRACE(ASN_AFTER_DATE_E)) {
344-
/* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or
345-
* ASN_BEFORE_DATE_E if there are no additional errors found in the
346-
* cert. Therefore, check if the cert is expired or not yet valid
347-
* in order to return the correct expected error. */
348-
byte *afterDate = ctx->current_cert->notAfter.data;
349-
byte *beforeDate = ctx->current_cert->notBefore.data;
350-
351-
if (XVALIDATE_DATE(afterDate,
352-
(byte)ctx->current_cert->notAfter.type, ASN_AFTER) < 1) {
353-
ret = ASN_AFTER_DATE_E;
354-
}
355-
else if (XVALIDATE_DATE(beforeDate,
356-
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE) < 1) {
357-
ret = ASN_BEFORE_DATE_E;
358-
}
359-
SetupStoreCtxError(ctx, ret);
360-
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
361-
if (ctx->store->verify_cb)
362-
ret = ctx->store->verify_cb(ret >= 0 ? 1 : 0,
363-
ctx) == 1 ? WOLFSSL_SUCCESS : -1;
364-
#endif
365-
}
366-
#endif
367424
}
368425

369426
return ret;
@@ -1445,16 +1502,22 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
14451502
{
14461503
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
14471504
DerBuffer* derCert = NULL;
1505+
int verify = VERIFY;
14481506

14491507
WOLFSSL_ENTER("X509StoreAddCa");
14501508
if (store != NULL && x509 != NULL && x509->derCert != NULL) {
1509+
/* Check if NO_CHECK_TIME flag is set - if so, skip date validation */
1510+
if (store->param != NULL &&
1511+
(store->param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
1512+
verify = VERIFY_SKIP_DATE;
1513+
}
14511514
result = AllocDer(&derCert, x509->derCert->length,
14521515
x509->derCert->type, NULL);
14531516
if (result == 0) {
14541517
/* AddCA() frees the buffer. */
14551518
XMEMCPY(derCert->buffer,
14561519
x509->derCert->buffer, x509->derCert->length);
1457-
result = AddCA(store->cm, &derCert, type, VERIFY);
1520+
result = AddCA(store->cm, &derCert, type, verify);
14581521
}
14591522
}
14601523

tests/api.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21024,6 +21024,115 @@ static int test_wolfSSL_X509_STORE_CTX_set_time(void)
2102421024
return EXPECT_RESULT();
2102521025
}
2102621026

21027+
static int test_wolfSSL_X509_STORE_check_time(void)
21028+
{
21029+
EXPECT_DECLS;
21030+
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_ASN_TIME)
21031+
WOLFSSL_X509_STORE* store = NULL;
21032+
WOLFSSL_X509_STORE_CTX* ctx = NULL;
21033+
WOLFSSL_X509* ca = NULL;
21034+
WOLFSSL_X509* cert = NULL;
21035+
int ret;
21036+
time_t check_time;
21037+
const char* srvCertFile = "./certs/server-cert.pem";
21038+
const char* expiredCertFile = "./certs/test/expired/expired-cert.pem";
21039+
21040+
/* Set check_time to May 26, 2000 - should fail "not yet valid" check */
21041+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
21042+
if (store != NULL) {
21043+
/* Load CA certificate - should validate with current time by default */
21044+
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
21045+
SSL_FILETYPE_PEM));
21046+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
21047+
21048+
/* Set check_time to May 26, 2000 (timestamp: 959320800) */
21049+
check_time = (time_t)959320800; /* May 26, 2000 00:00:00 UTC */
21050+
store->param->check_time = check_time;
21051+
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
21052+
WOLFSSL_USE_CHECK_TIME);
21053+
ExpectTrue(store->param->check_time == check_time);
21054+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
21055+
SSL_FILETYPE_PEM));
21056+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
21057+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
21058+
WOLFSSL_SUCCESS);
21059+
21060+
/* Verify that check_time was copied to context */
21061+
ExpectTrue((ctx->param->flags & WOLFSSL_USE_CHECK_TIME) ==
21062+
WOLFSSL_USE_CHECK_TIME);
21063+
ExpectTrue(ctx->param->check_time == check_time);
21064+
21065+
/* Verify certificate using the custom check_time - should fail because
21066+
* certificate is not yet valid (use before check fails) */
21067+
ret = wolfSSL_X509_verify_cert(ctx);
21068+
ExpectIntNE(ret, WOLFSSL_SUCCESS);
21069+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
21070+
WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID);
21071+
wolfSSL_X509_STORE_CTX_free(ctx);
21072+
ctx = NULL;
21073+
}
21074+
wolfSSL_X509_STORE_free(store);
21075+
store = NULL;
21076+
wolfSSL_X509_free(cert);
21077+
cert = NULL;
21078+
wolfSSL_X509_free(ca);
21079+
ca = NULL;
21080+
21081+
/* Verify without setting check_time - should work with current time */
21082+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
21083+
if (store != NULL) {
21084+
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
21085+
SSL_FILETYPE_PEM));
21086+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
21087+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
21088+
SSL_FILETYPE_PEM));
21089+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
21090+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
21091+
WOLFSSL_SUCCESS);
21092+
ret = wolfSSL_X509_verify_cert(ctx);
21093+
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
21094+
wolfSSL_X509_STORE_CTX_free(ctx);
21095+
ctx = NULL;
21096+
}
21097+
wolfSSL_X509_STORE_free(store);
21098+
store = NULL;
21099+
wolfSSL_X509_free(cert);
21100+
cert = NULL;
21101+
wolfSSL_X509_free(ca);
21102+
ca = NULL;
21103+
21104+
/* Test WOLFSSL_NO_CHECK_TIME flag with expired certificate */
21105+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
21106+
if (store != NULL) {
21107+
/* Set NO_CHECK_TIME flag to skip time validation */
21108+
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param, WOLFSSL_NO_CHECK_TIME);
21109+
ExpectTrue((store->param->flags & WOLFSSL_NO_CHECK_TIME) ==
21110+
WOLFSSL_NO_CHECK_TIME);
21111+
21112+
/* Load expired certificate (self-signed) */
21113+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
21114+
SSL_FILETYPE_PEM));
21115+
/* Add expired certificate as trusted CA (self-signed, so it's its own issuer) */
21116+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, cert), WOLFSSL_SUCCESS);
21117+
21118+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
21119+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
21120+
WOLFSSL_SUCCESS);
21121+
/* Verify expired certificate with NO_CHECK_TIME - should succeed
21122+
* because time validation is skipped */
21123+
ret = wolfSSL_X509_verify_cert(ctx);
21124+
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
21125+
}
21126+
wolfSSL_X509_STORE_CTX_free(ctx);
21127+
ctx = NULL;
21128+
wolfSSL_X509_STORE_free(store);
21129+
store = NULL;
21130+
wolfSSL_X509_free(cert);
21131+
cert = NULL;
21132+
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_ASN_TIME) */
21133+
return EXPECT_RESULT();
21134+
}
21135+
2102721136
static int test_wolfSSL_CTX_get0_set1_param(void)
2102821137
{
2102921138
EXPECT_DECLS;
@@ -51086,6 +51195,7 @@ TEST_CASE testCases[] = {
5108651195
TEST_DECL(test_wolfSSL_X509_LOOKUP_ctrl_hash_dir),
5108751196
TEST_DECL(test_wolfSSL_X509_NID),
5108851197
TEST_DECL(test_wolfSSL_X509_STORE_CTX_set_time),
51198+
TEST_DECL(test_wolfSSL_X509_STORE_check_time),
5108951199
TEST_DECL(test_wolfSSL_get0_param),
5109051200
TEST_DECL(test_wolfSSL_X509_VERIFY_PARAM_set1_host),
5109151201
TEST_DECL(test_wolfSSL_set1_host),

wolfcrypt/src/asn.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16574,6 +16574,12 @@ static WC_INLINE int DateLessThan(const struct tm* a, const struct tm* b)
1657416574
/* format = ASN_UTC_TIME or ASN_GENERALIZED_TIME */
1657516575
/* dateType = ASN_AFTER or ASN_BEFORE */
1657616576
int wc_ValidateDate(const byte* date, byte format, int dateType)
16577+
{
16578+
return wc_ValidateDateWithTime(date, format, dateType, 0);
16579+
}
16580+
16581+
int wc_ValidateDateWithTime(const byte* date, byte format, int dateType,
16582+
time_t check_time)
1657716583
{
1657816584
time_t ltime;
1657916585
struct tm certTime;
@@ -16591,7 +16597,14 @@ int wc_ValidateDate(const byte* date, byte format, int dateType)
1659116597
#endif
1659216598
(void)tmpTime;
1659316599

16594-
ltime = wc_Time(0);
16600+
/* Use check_time if provided (non-zero), otherwise use current time */
16601+
if (check_time != 0) {
16602+
ltime = check_time;
16603+
}
16604+
else {
16605+
ltime = wc_Time(0);
16606+
}
16607+
1659516608
#ifndef NO_TIME_SIGNEDNESS_CHECK
1659616609
if (sizeof(ltime) == sizeof(word32) && (sword32)ltime < 0){
1659716610
/* A negative response here could be due to a 32-bit time_t

wolfssl/wolfcrypt/asn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,6 +2255,8 @@ WOLFSSL_LOCAL int ExtractDate(const unsigned char* date, unsigned char format,
22552255
wolfssl_tm* certTime, int* idx);
22562256
WOLFSSL_LOCAL int DateGreaterThan(const struct tm* a, const struct tm* b);
22572257
WOLFSSL_LOCAL int wc_ValidateDate(const byte* date, byte format, int dateType);
2258+
WOLFSSL_LOCAL int wc_ValidateDateWithTime(const byte* date, byte format,
2259+
int dateType, time_t check_time);
22582260
WOLFSSL_TEST_VIS int wc_AsnSetSkipDateCheck(int skip_p);
22592261
WOLFSSL_LOCAL int wc_AsnGetSkipDateCheck(void);
22602262

0 commit comments

Comments
 (0)