Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 91 additions & 28 deletions src/x509_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down
111 changes: 111 additions & 0 deletions tests/api/test_ossl_x509_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_ossl_x509_str.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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), \
Expand Down
15 changes: 14 additions & 1 deletion wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions wolfssl/wolfcrypt/asn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down