Skip to content

Commit 85d40c8

Browse files
authored
Merge pull request #9522 from JacobBarthelmeh/time
tie in use of check_time with x509 store
2 parents 52ee001 + 5099e6e commit 85d40c8

File tree

5 files changed

+222
-29
lines changed

5 files changed

+222
-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/test_ossl_x509_str.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,117 @@ int test_wolfSSL_X509_STORE_CTX_set_time(void)
5454
return EXPECT_RESULT();
5555
}
5656

57+
int test_wolfSSL_X509_STORE_check_time(void)
58+
{
59+
EXPECT_DECLS;
60+
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
61+
!defined(NO_ASN_TIME) && !defined(NO_RSA)
62+
WOLFSSL_X509_STORE* store = NULL;
63+
WOLFSSL_X509_STORE_CTX* ctx = NULL;
64+
WOLFSSL_X509* ca = NULL;
65+
WOLFSSL_X509* cert = NULL;
66+
int ret;
67+
time_t check_time;
68+
const char* srvCertFile = "./certs/server-cert.pem";
69+
const char* expiredCertFile = "./certs/test/expired/expired-cert.pem";
70+
71+
/* Set check_time to May 26, 2000 - should fail "not yet valid" check */
72+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
73+
if (store != NULL) {
74+
/* Load CA certificate - should validate with current time by default */
75+
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
76+
SSL_FILETYPE_PEM));
77+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
78+
79+
/* Set check_time to May 26, 2000 (timestamp: 959320800) */
80+
check_time = (time_t)959320800; /* May 26, 2000 00:00:00 UTC */
81+
store->param->check_time = check_time;
82+
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
83+
WOLFSSL_USE_CHECK_TIME);
84+
ExpectTrue(store->param->check_time == check_time);
85+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
86+
SSL_FILETYPE_PEM));
87+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
88+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
89+
WOLFSSL_SUCCESS);
90+
91+
/* Verify that check_time was copied to context */
92+
ExpectTrue((ctx->param->flags & WOLFSSL_USE_CHECK_TIME) ==
93+
WOLFSSL_USE_CHECK_TIME);
94+
ExpectTrue(ctx->param->check_time == check_time);
95+
96+
/* Verify certificate using the custom check_time - should fail because
97+
* certificate is not yet valid (use before check fails) */
98+
ret = wolfSSL_X509_verify_cert(ctx);
99+
ExpectIntNE(ret, WOLFSSL_SUCCESS);
100+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
101+
WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID);
102+
wolfSSL_X509_STORE_CTX_free(ctx);
103+
ctx = NULL;
104+
}
105+
wolfSSL_X509_STORE_free(store);
106+
store = NULL;
107+
wolfSSL_X509_free(cert);
108+
cert = NULL;
109+
wolfSSL_X509_free(ca);
110+
ca = NULL;
111+
112+
/* Verify without setting check_time - should work with current time */
113+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
114+
if (store != NULL) {
115+
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
116+
SSL_FILETYPE_PEM));
117+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
118+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
119+
SSL_FILETYPE_PEM));
120+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
121+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
122+
WOLFSSL_SUCCESS);
123+
ret = wolfSSL_X509_verify_cert(ctx);
124+
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
125+
wolfSSL_X509_STORE_CTX_free(ctx);
126+
ctx = NULL;
127+
}
128+
wolfSSL_X509_STORE_free(store);
129+
store = NULL;
130+
wolfSSL_X509_free(cert);
131+
cert = NULL;
132+
wolfSSL_X509_free(ca);
133+
ca = NULL;
134+
135+
/* Test WOLFSSL_NO_CHECK_TIME flag with expired certificate */
136+
ExpectNotNull(store = wolfSSL_X509_STORE_new());
137+
if (store != NULL) {
138+
/* Set NO_CHECK_TIME flag to skip time validation */
139+
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
140+
WOLFSSL_NO_CHECK_TIME);
141+
ExpectTrue((store->param->flags & WOLFSSL_NO_CHECK_TIME) ==
142+
WOLFSSL_NO_CHECK_TIME);
143+
144+
/* Load expired certificate (self-signed) */
145+
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
146+
SSL_FILETYPE_PEM));
147+
/* Add expired certificate as trusted CA (self-signed) */
148+
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, cert), WOLFSSL_SUCCESS);
149+
150+
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
151+
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
152+
WOLFSSL_SUCCESS);
153+
/* Verify expired certificate with NO_CHECK_TIME - should succeed
154+
* because time validation is skipped */
155+
ret = wolfSSL_X509_verify_cert(ctx);
156+
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
157+
}
158+
wolfSSL_X509_STORE_CTX_free(ctx);
159+
ctx = NULL;
160+
wolfSSL_X509_STORE_free(store);
161+
store = NULL;
162+
wolfSSL_X509_free(cert);
163+
cert = NULL;
164+
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_ASN_TIME && !NO_RSA */
165+
return EXPECT_RESULT();
166+
}
167+
57168
int test_wolfSSL_X509_STORE_CTX_get0_store(void)
58169
{
59170
EXPECT_DECLS;

tests/api/test_ossl_x509_str.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <tests/api/api_decl.h>
2626

2727
int test_wolfSSL_X509_STORE_CTX_set_time(void);
28+
int test_wolfSSL_X509_STORE_check_time(void);
2829
int test_wolfSSL_X509_STORE_CTX_get0_store(void);
2930
int test_wolfSSL_X509_STORE_CTX(void);
3031
int test_wolfSSL_X509_STORE_CTX_ex(void);
@@ -43,6 +44,7 @@ int test_X509_STORE_No_SSL_CTX(void);
4344

4445
#define TEST_OSSL_X509_STORE_DECLS \
4546
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_set_time), \
47+
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_check_time), \
4648
TEST_DECL_GROUP("ossl_x509_store", \
4749
test_wolfSSL_X509_STORE_CTX_get0_store), \
4850
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX), \

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 checkTime)
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 checkTime if provided (non-zero), otherwise use current time */
16601+
if (checkTime != 0) {
16602+
ltime = checkTime;
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,6 +2255,10 @@ 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+
#ifndef NO_ASN_TIME
2259+
WOLFSSL_LOCAL int wc_ValidateDateWithTime(const byte* date, byte format,
2260+
int dateType, time_t checkTime);
2261+
#endif
22582262
WOLFSSL_TEST_VIS int wc_AsnSetSkipDateCheck(int skip_p);
22592263
WOLFSSL_LOCAL int wc_AsnGetSkipDateCheck(void);
22602264

0 commit comments

Comments
 (0)