Merge pull request #9522 from JacobBarthelmeh/time

tie in use of check_time with x509 store
This commit is contained in:
Sean Parkinson
2025-12-16 08:24:49 +10:00
committed by GitHub
5 changed files with 222 additions and 29 deletions
+91 -28
View File
@@ -230,6 +230,18 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx,
XMEMSET(ctx->param, 0, sizeof(*ctx->param));
}
/* Copy check_time from store parameters if available */
if (store != NULL && store->param != NULL) {
if ((store->param->flags & WOLFSSL_USE_CHECK_TIME) != 0 &&
store->param->check_time != 0) {
ctx->param->check_time = store->param->check_time;
ctx->param->flags |= WOLFSSL_USE_CHECK_TIME;
}
if ((store->param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
ctx->param->flags |= WOLFSSL_NO_CHECK_TIME;
}
}
return WOLFSSL_SUCCESS;
}
return WOLFSSL_FAILURE;
@@ -321,6 +333,74 @@ static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret)
SetupStoreCtxError_ex(ctx, ret, depth);
}
#ifndef NO_ASN_TIME
/* Post certificate validation date handling. This function is called after the
* certificate has been verified by the certificate manager. It then checks if
* X509 store parameters are set for date validation override.
* @param ctx The certificate store context
* @param ret The return value from the certificate manager verify
* @return The return value for the certificate date validation after override
*/
static int X509StoreVerifyCertDate(WOLFSSL_X509_STORE_CTX* ctx, int ret)
{
byte *afterDate = ctx->current_cert->notAfter.data;
byte *beforeDate = ctx->current_cert->notBefore.data;
/* Only override existing date errors or WOLFSSL_SUCCESS. */
if (ret == WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) ||
ret == WC_NO_ERR_TRACE(ASN_AFTER_DATE_E) ||
ret == WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
#ifdef USE_WOLF_VALIDDATE
WOLFSSL_X509_VERIFY_PARAM* param = NULL;
/* If no external XVALIDATE_DATE was defined then use param for date
validation overrides. */
if (ctx->param != NULL) {
param = ctx->param;
}
else if (ctx->store != NULL && ctx->store->param != NULL) {
param = ctx->store->param;
}
if (param != NULL) {
if ((param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
WOLFSSL_MSG("Overriding date validation WOLFSSL_NO_CHECK_TIME");
ret = WOLFSSL_SUCCESS;
}
else if ((param->flags & WOLFSSL_USE_CHECK_TIME) != 0 &&
(param->check_time != 0)) {
time_t checkTime = param->check_time;
ret = WOLFSSL_SUCCESS; /* override date error and use custom set
time for validating certificate dates */
WOLFSSL_MSG("Override date validation, WOLFSSL_USE_CHECK_TIME");
if (wc_ValidateDateWithTime(afterDate,
(byte)ctx->current_cert->notAfter.type, ASN_AFTER,
checkTime) < 1) {
ret = ASN_AFTER_DATE_E;
}
else if (wc_ValidateDateWithTime(beforeDate,
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE,
checkTime) < 1) {
ret = ASN_BEFORE_DATE_E;
}
}
}
#else
if (XVALIDATE_DATE(afterDate,
(byte)ctx->current_cert->notAfter.type, ASN_AFTER) < 1) {
ret = ASN_AFTER_DATE_E;
}
else if (XVALIDATE_DATE(beforeDate,
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE) < 1) {
ret = ASN_BEFORE_DATE_E;
}
#endif /* USE_WOLF_VALIDDATE */
}
return ret;
}
#endif /* NO_ASN_TIME */
static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx)
{
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
@@ -331,39 +411,16 @@ static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx)
ctx->current_cert->derCert->buffer,
ctx->current_cert->derCert->length,
WOLFSSL_FILETYPE_ASN1);
#ifndef NO_ASN_TIME
/* update return value with any date validation overrides */
ret = X509StoreVerifyCertDate(ctx, ret);
#endif
SetupStoreCtxError(ctx, ret);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
if (ctx->store->verify_cb)
ret = ctx->store->verify_cb(ret >= 0 ? 1 : 0, ctx) == 1 ?
WOLFSSL_SUCCESS : ret;
#endif
#ifndef NO_ASN_TIME
if (ret != WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) &&
ret != WC_NO_ERR_TRACE(ASN_AFTER_DATE_E)) {
/* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or
* ASN_BEFORE_DATE_E if there are no additional errors found in the
* cert. Therefore, check if the cert is expired or not yet valid
* in order to return the correct expected error. */
byte *afterDate = ctx->current_cert->notAfter.data;
byte *beforeDate = ctx->current_cert->notBefore.data;
if (XVALIDATE_DATE(afterDate,
(byte)ctx->current_cert->notAfter.type, ASN_AFTER) < 1) {
ret = ASN_AFTER_DATE_E;
}
else if (XVALIDATE_DATE(beforeDate,
(byte)ctx->current_cert->notBefore.type, ASN_BEFORE) < 1) {
ret = ASN_BEFORE_DATE_E;
}
SetupStoreCtxError(ctx, ret);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
if (ctx->store->verify_cb)
ret = ctx->store->verify_cb(ret >= 0 ? 1 : 0,
ctx) == 1 ? WOLFSSL_SUCCESS : -1;
#endif
}
#endif
}
return ret;
@@ -1445,16 +1502,22 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
{
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
DerBuffer* derCert = NULL;
int verify = VERIFY;
WOLFSSL_ENTER("X509StoreAddCa");
if (store != NULL && x509 != NULL && x509->derCert != NULL) {
/* Check if NO_CHECK_TIME flag is set - if so, skip date validation */
if (store->param != NULL &&
(store->param->flags & WOLFSSL_NO_CHECK_TIME) != 0) {
verify = VERIFY_SKIP_DATE;
}
result = AllocDer(&derCert, x509->derCert->length,
x509->derCert->type, NULL);
if (result == 0) {
/* AddCA() frees the buffer. */
XMEMCPY(derCert->buffer,
x509->derCert->buffer, x509->derCert->length);
result = AddCA(store->cm, &derCert, type, VERIFY);
result = AddCA(store->cm, &derCert, type, verify);
}
}
+111
View File
@@ -54,6 +54,117 @@ int test_wolfSSL_X509_STORE_CTX_set_time(void)
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_check_time(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
!defined(NO_ASN_TIME) && !defined(NO_RSA)
WOLFSSL_X509_STORE* store = NULL;
WOLFSSL_X509_STORE_CTX* ctx = NULL;
WOLFSSL_X509* ca = NULL;
WOLFSSL_X509* cert = NULL;
int ret;
time_t check_time;
const char* srvCertFile = "./certs/server-cert.pem";
const char* expiredCertFile = "./certs/test/expired/expired-cert.pem";
/* Set check_time to May 26, 2000 - should fail "not yet valid" check */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
/* Load CA certificate - should validate with current time by default */
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
/* Set check_time to May 26, 2000 (timestamp: 959320800) */
check_time = (time_t)959320800; /* May 26, 2000 00:00:00 UTC */
store->param->check_time = check_time;
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
WOLFSSL_USE_CHECK_TIME);
ExpectTrue(store->param->check_time == check_time);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
SSL_FILETYPE_PEM));
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
/* Verify that check_time was copied to context */
ExpectTrue((ctx->param->flags & WOLFSSL_USE_CHECK_TIME) ==
WOLFSSL_USE_CHECK_TIME);
ExpectTrue(ctx->param->check_time == check_time);
/* Verify certificate using the custom check_time - should fail because
* certificate is not yet valid (use before check fails) */
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntNE(ret, WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
}
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
wolfSSL_X509_free(ca);
ca = NULL;
/* Verify without setting check_time - should work with current time */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
SSL_FILETYPE_PEM));
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
}
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
wolfSSL_X509_free(ca);
ca = NULL;
/* Test WOLFSSL_NO_CHECK_TIME flag with expired certificate */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
/* Set NO_CHECK_TIME flag to skip time validation */
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
WOLFSSL_NO_CHECK_TIME);
ExpectTrue((store->param->flags & WOLFSSL_NO_CHECK_TIME) ==
WOLFSSL_NO_CHECK_TIME);
/* Load expired certificate (self-signed) */
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
SSL_FILETYPE_PEM));
/* Add expired certificate as trusted CA (self-signed) */
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, cert), WOLFSSL_SUCCESS);
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
/* Verify expired certificate with NO_CHECK_TIME - should succeed
* because time validation is skipped */
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
}
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_ASN_TIME && !NO_RSA */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_CTX_get0_store(void)
{
EXPECT_DECLS;
+2
View File
@@ -25,6 +25,7 @@
#include <tests/api/api_decl.h>
int test_wolfSSL_X509_STORE_CTX_set_time(void);
int test_wolfSSL_X509_STORE_check_time(void);
int test_wolfSSL_X509_STORE_CTX_get0_store(void);
int test_wolfSSL_X509_STORE_CTX(void);
int test_wolfSSL_X509_STORE_CTX_ex(void);
@@ -43,6 +44,7 @@ int test_X509_STORE_No_SSL_CTX(void);
#define TEST_OSSL_X509_STORE_DECLS \
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_set_time), \
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_check_time), \
TEST_DECL_GROUP("ossl_x509_store", \
test_wolfSSL_X509_STORE_CTX_get0_store), \
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX), \
+14 -1
View File
@@ -16574,6 +16574,12 @@ static WC_INLINE int DateLessThan(const struct tm* a, const struct tm* b)
/* format = ASN_UTC_TIME or ASN_GENERALIZED_TIME */
/* dateType = ASN_AFTER or ASN_BEFORE */
int wc_ValidateDate(const byte* date, byte format, int dateType)
{
return wc_ValidateDateWithTime(date, format, dateType, 0);
}
int wc_ValidateDateWithTime(const byte* date, byte format, int dateType,
time_t checkTime)
{
time_t ltime;
struct tm certTime;
@@ -16591,7 +16597,14 @@ int wc_ValidateDate(const byte* date, byte format, int dateType)
#endif
(void)tmpTime;
ltime = wc_Time(0);
/* Use checkTime if provided (non-zero), otherwise use current time */
if (checkTime != 0) {
ltime = checkTime;
}
else {
ltime = wc_Time(0);
}
#ifndef NO_TIME_SIGNEDNESS_CHECK
if (sizeof(ltime) == sizeof(word32) && (sword32)ltime < 0){
/* A negative response here could be due to a 32-bit time_t
+4
View File
@@ -2255,6 +2255,10 @@ WOLFSSL_LOCAL int ExtractDate(const unsigned char* date, unsigned char format,
wolfssl_tm* certTime, int* idx);
WOLFSSL_LOCAL int DateGreaterThan(const struct tm* a, const struct tm* b);
WOLFSSL_LOCAL int wc_ValidateDate(const byte* date, byte format, int dateType);
#ifndef NO_ASN_TIME
WOLFSSL_LOCAL int wc_ValidateDateWithTime(const byte* date, byte format,
int dateType, time_t checkTime);
#endif
WOLFSSL_TEST_VIS int wc_AsnSetSkipDateCheck(int skip_p);
WOLFSSL_LOCAL int wc_AsnGetSkipDateCheck(void);