diff --git a/certs/crl/bad_time_fmt.pem b/certs/crl/bad_time_fmt.pem new file mode 100644 index 0000000000..589771d8f5 --- /dev/null +++ b/certs/crl/bad_time_fmt.pem @@ -0,0 +1,13 @@ +-----BEGIN X509 CRL----- +MIIB7DCB1QIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzELMAkGA1UE +CAwCVVMxCzAJBgNVBAcMAlVTMQswCQYDVQQKDAJVUzELMAkGA1UEAwwCVVMxCzAJ +BgNVBAsMAlVTGA0yNDAxMjMwMDAwMDBaGA0zNDAxMjAwMDAwMDBaMDUwMwIUHIAC +LvgfJAXulqYS3LYf4KxwHl4XDTI1MDMxMzAyNDQ0MFowDDAKBgNVHRUEAwoBBqAc +MBowGAYDVR0UBBECDxnP/97adO3y9qRGDM7hQDANBgkqhkiG9w0BAQsFAAOCAQEA +aDY9jBdAJiAujUkaLYLVtzNWF/0SxD5CB4dYIcZMqtPKLn5ykcxkXvnRbVihJ+Kn +AAv9Fkn5iwj77EGwxNjyZktQ4gAmcMhCTBEcAHbmi92tHttot9Sr44+CN+0NaaQD +OflIeVw7Zir90TWufjScy8/e7FkVm+aD5CicrbJWqoe21pB1Q1jS49iNrZzqZ2vw +HLiqNAzpecxwUih/YPe5+CBk5Nq4vICeieGVC/JO9r5SkdDwWQTl0I3kSK6n4Jh7 +53FmIen80F2ZZuZu4/fhJ7C4rlr6W9i6FrK06s5mk1PeYFHKhCkwI8wp8cIudJQD +lLsK2u4CTcuTKdbDLsszYA== +-----END X509 CRL----- diff --git a/certs/crl/include.am b/certs/crl/include.am index d3194933a4..6f7f6f26bf 100644 --- a/certs/crl/include.am +++ b/certs/crl/include.am @@ -16,7 +16,8 @@ EXTRA_DIST += \ certs/crl/wolfssl.cnf \ certs/crl/crl.der \ certs/crl/crl2.der \ - certs/crl/crl_rsapss.pem + certs/crl/crl_rsapss.pem \ + certs/crl/bad_time_fmt.pem EXTRA_DIST += \ certs/crl/crl.revoked \ diff --git a/src/crl.c b/src/crl.c index 9056bd1c6c..8b3e319ffc 100644 --- a/src/crl.c +++ b/src/crl.c @@ -446,7 +446,8 @@ static int CheckCertCRLList(WOLFSSL_CRL* crl, byte* issuerHash, byte* serial, #endif { #if !defined(NO_ASN_TIME) && !defined(WOLFSSL_NO_CRL_DATE_CHECK) - if (!XVALIDATE_DATE(crle->nextDate,crle->nextDateFormat, ASN_AFTER)) { + if (!XVALIDATE_DATE(crle->nextDate, crle->nextDateFormat, + ASN_AFTER, MAX_DATE_SIZE)) { WOLFSSL_MSG("CRL next date is no longer valid"); nextDateValid = 0; } diff --git a/src/ocsp.c b/src/ocsp.c index 2348af7df1..77cce2b1a7 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -296,10 +296,10 @@ static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request, else if (*status) { #ifndef NO_ASN_TIME if (XVALIDATE_DATE((*status)->thisDate, - (*status)->thisDateFormat, ASN_BEFORE) + (*status)->thisDateFormat, ASN_BEFORE, MAX_DATE_SIZE) && ((*status)->nextDate[0] != 0) && XVALIDATE_DATE((*status)->nextDate, - (*status)->nextDateFormat, ASN_AFTER)) + (*status)->nextDateFormat, ASN_AFTER, MAX_DATE_SIZE)) #endif { ret = xstat2err((*status)->status); diff --git a/src/ssl.c b/src/ssl.c index 0d265f999a..c71b188ac8 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -22021,7 +22021,8 @@ int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { return BAD_FUNC_ARG; if (ExtractDate(ssl->ocspProducedDate, - (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx)) + (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx, + MAX_DATE_SZ)) return 0; else return ASN_PARSE_E; diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index d501b6a681..2fe3cab470 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -4194,7 +4194,7 @@ char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len) } /* Get time as human readable string. */ - if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len)) { + if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len, t->length)) { buf = NULL; } diff --git a/src/x509.c b/src/x509.c index 8fc94f5f1d..5efc5fe0cd 100644 --- a/src/x509.c +++ b/src/x509.c @@ -6440,9 +6440,9 @@ static int X509PrintValidity(WOLFSSL_BIO* bio, WOLFSSL_ASN1_TIME * notBefore, } if (notBefore->length > 0) { if (GetTimeString(notBefore->data, ASN_UTC_TIME, - tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + tmp, sizeof(tmp), notBefore->length) != WOLFSSL_SUCCESS) { if (GetTimeString(notBefore->data, ASN_GENERALIZED_TIME, - tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + tmp, sizeof(tmp), notBefore->length) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error getting not before date"); return WOLFSSL_FAILURE; } @@ -6462,9 +6462,9 @@ static int X509PrintValidity(WOLFSSL_BIO* bio, WOLFSSL_ASN1_TIME * notBefore, } if (notAfter->length > 0) { if (GetTimeString(notAfter->data, ASN_UTC_TIME, - tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + tmp, sizeof(tmp), notAfter->length) != WOLFSSL_SUCCESS) { if (GetTimeString(notAfter->data, ASN_GENERALIZED_TIME, - tmp, sizeof(tmp)) != WOLFSSL_SUCCESS) { + tmp, sizeof(tmp), notAfter->length) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error getting not after date"); return WOLFSSL_FAILURE; } @@ -9018,9 +9018,9 @@ static int X509CRLPrintRevoked(WOLFSSL_BIO* bio, WOLFSSL_X509_CRL* crl, if (revoked->revDate[0] != 0) { if (GetTimeString(revoked->revDate, ASN_UTC_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { + tmp, MAX_WIDTH, MAX_DATE_SIZE) != WOLFSSL_SUCCESS) { if (GetTimeString(revoked->revDate, ASN_GENERALIZED_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { + tmp, MAX_WIDTH, MAX_DATE_SIZE) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error getting revocation date"); return WOLFSSL_FAILURE; } @@ -9071,13 +9071,10 @@ static int X509CRLPrintDates(WOLFSSL_BIO* bio, WOLFSSL_X509_CRL* crl, } if (crl->crlList->lastDate[0] != 0) { - if (GetTimeString(crl->crlList->lastDate, ASN_UTC_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { - if (GetTimeString(crl->crlList->lastDate, ASN_GENERALIZED_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error getting last update date"); - return WOLFSSL_FAILURE; - } + if (GetTimeString(crl->crlList->lastDate, crl->crlList->lastDateFormat, + tmp, MAX_WIDTH, MAX_DATE_SIZE) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting last update date"); + return WOLFSSL_FAILURE; } } else { @@ -9102,13 +9099,10 @@ static int X509CRLPrintDates(WOLFSSL_BIO* bio, WOLFSSL_X509_CRL* crl, } if (crl->crlList->nextDate[0] != 0) { - if (GetTimeString(crl->crlList->nextDate, ASN_UTC_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { - if (GetTimeString(crl->crlList->nextDate, ASN_GENERALIZED_TIME, - tmp, MAX_WIDTH) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error getting next update date"); - return WOLFSSL_FAILURE; - } + if (GetTimeString(crl->crlList->nextDate, crl->crlList->nextDateFormat, + tmp, MAX_WIDTH, MAX_DATE_SIZE) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error getting next update date"); + return WOLFSSL_FAILURE; } } else { diff --git a/src/x509_str.c b/src/x509_str.c index 432a48897d..6432bab2d8 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -375,23 +375,25 @@ static int X509StoreVerifyCertDate(WOLFSSL_X509_STORE_CTX* ctx, int ret) WOLFSSL_MSG("Override date validation, WOLFSSL_USE_CHECK_TIME"); if (wc_ValidateDateWithTime(afterDate, (byte)ctx->current_cert->notAfter.type, ASN_AFTER, - checkTime) < 1) { + checkTime, ctx->current_cert->notAfter.length) < 1) { ret = ASN_AFTER_DATE_E; } else if (wc_ValidateDateWithTime(beforeDate, (byte)ctx->current_cert->notBefore.type, ASN_BEFORE, - checkTime) < 1) { + checkTime, ctx->current_cert->notBefore.length) < 1) { ret = ASN_BEFORE_DATE_E; } } } #else if (XVALIDATE_DATE(afterDate, - (byte)ctx->current_cert->notAfter.type, ASN_AFTER) < 1) { + (byte)ctx->current_cert->notAfter.type, ASN_AFTER, + ctx->current_cert->notAfter.length) < 1) { ret = ASN_AFTER_DATE_E; } else if (XVALIDATE_DATE(beforeDate, - (byte)ctx->current_cert->notBefore.type, ASN_BEFORE) < 1) { + (byte)ctx->current_cert->notBefore.type, ASN_BEFORE, + ctx->current_cert->notBefore.length) < 1) { ret = ASN_BEFORE_DATE_E; } #endif /* USE_WOLF_VALIDDATE */ diff --git a/tests/api.c b/tests/api.c index 10631d5e9b..c96d373b38 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27601,10 +27601,25 @@ static int test_sk_X509_CRL(void) ExpectIntEQ(BIO_get_mem_data(bio, NULL), 1324); #endif BIO_free(bio); + bio = NULL; + wolfSSL_X509_CRL_free(crl); + crl = NULL; + +#ifndef NO_ASN_TIME + /* Test CRL with invalid GeneralizedTime */ + ExpectNotNull(bio = BIO_new_file("./certs/crl/bad_time_fmt.pem", "rb")); + ExpectNotNull(crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)); + BIO_free(bio); + bio = NULL; + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + ExpectIntEQ(wolfSSL_X509_CRL_print(bio, crl), WOLFSSL_FAILURE); + BIO_free(bio); + bio = NULL; wolfSSL_X509_CRL_free(crl); crl = NULL; -#endif +#endif /* !NO_ASN_TIME */ +#endif /* !NO_BIO */ #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) ExpectTrue((fp = XFOPEN("./certs/crl/crl.der", "rb")) != XBADFILE); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e64f278922..dc17a3357a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -16271,8 +16271,38 @@ static WC_INLINE int GetTime_Long(long* value, const byte* date, int* idx) * Reminder: idx is incremented in each call to GetTime() * Return 0 on failure, 1 for success. */ int ExtractDate(const unsigned char* date, unsigned char format, - struct tm* certTime, int* idx) + struct tm* certTime, int* idx, int len) { + int i = *idx; + + /* Validate date string length based on format. Can not assume null + * terminated strings. Must check for the 'Z'. + * Subtract 2; one for zero indexing and one to exclude null terminator + * built into macro values. */ + if (format == ASN_UTC_TIME) { + /* UTCTime format requires YYMMDDHHMMSSZ (13 chars). */ + /* Bounds check: ensure we have enough data before accessing. */ + if (len < i + ASN_UTC_TIME_SIZE - 1) { + return 0; + } + if (date[i + ASN_UTC_TIME_SIZE - 2] != 'Z') { + return 0; + } + } + else if (format == ASN_GENERALIZED_TIME) { + /* GeneralizedTime format requires YYYYMMDDHHMMSSZ (15 chars). */ + /* Bounds check: ensure we have enough data before accessing. */ + if (len < i + ASN_GENERALIZED_TIME_SIZE - 1) { + return 0; + } + if (date[ i + ASN_GENERALIZED_TIME_SIZE - 2] != 'Z') { + return 0; + } + } + else { + return 0; + } + XMEMSET(certTime, 0, sizeof(struct tm)); /* Get the first two bytes of the year (century) */ @@ -16341,12 +16371,12 @@ int ExtractDate(const unsigned char* date, unsigned char format, #ifdef WOLFSSL_ASN_TIME_STRING -int GetTimeString(byte* date, int format, char* buf, int len) +int GetTimeString(byte* date, int format, char* buf, int len, int dateLen) { struct tm t; int idx = 0; - if (!ExtractDate(date, (unsigned char)format, &t, &idx)) { + if (!ExtractDate(date, (unsigned char)format, &t, &idx, dateLen)) { return 0; } @@ -16576,13 +16606,13 @@ static WC_INLINE int DateLessThan(const struct tm* a, const struct tm* b) /* date = ASN.1 raw */ /* format = ASN_UTC_TIME or ASN_GENERALIZED_TIME */ /* dateType = ASN_AFTER or ASN_BEFORE */ -int wc_ValidateDate(const byte* date, byte format, int dateType) +int wc_ValidateDate(const byte* date, byte format, int dateType, int len) { - return wc_ValidateDateWithTime(date, format, dateType, 0); + return wc_ValidateDateWithTime(date, format, dateType, 0, len); } int wc_ValidateDateWithTime(const byte* date, byte format, int dateType, - time_t checkTime) + time_t checkTime, int len) { time_t ltime; struct tm certTime; @@ -16631,7 +16661,7 @@ int wc_ValidateDateWithTime(const byte* date, byte format, int dateType, } #endif - if (!ExtractDate(date, format, &certTime, &i)) { + if (!ExtractDate(date, format, &certTime, &i, len)) { WOLFSSL_MSG("Error extracting the date"); return 0; } @@ -16853,7 +16883,7 @@ static int GetDate(DecodedCert* cert, int dateType, int verify, int maxIdx) #ifndef NO_ASN_TIME_CHECK if (verify != NO_VERIFY && verify != VERIFY_SKIP_DATE && (! AsnSkipDateCheck) && - !XVALIDATE_DATE(date, format, dateType)) { + !XVALIDATE_DATE(date, format, dateType, length)) { if (dateType == ASN_BEFORE) { WOLFSSL_ERROR_VERBOSE(ASN_BEFORE_DATE_E); return ASN_BEFORE_DATE_E; @@ -16911,7 +16941,7 @@ int wc_GetDateAsCalendarTime(const byte* date, int length, byte format, { int idx = 0; (void)length; - if (!ExtractDate(date, format, timearg, &idx)) + if (!ExtractDate(date, format, timearg, &idx, length)) return ASN_TIME_E; return 0; } @@ -23590,7 +23620,8 @@ static int CheckDate(ASNGetData *dataASN, int dateType) #ifndef NO_ASN_TIME_CHECK /* Check date is a valid string and ASN_BEFORE or ASN_AFTER now. */ if ((ret == 0) && (! AsnSkipDateCheck)) { - if (!XVALIDATE_DATE(dataASN->data.ref.data, dataASN->tag, dateType)) { + if (!XVALIDATE_DATE(dataASN->data.ref.data, dataASN->tag, dateType, + (int)dataASN->data.ref.length)) { if (dateType == ASN_BEFORE) { ret = ASN_BEFORE_DATE_E; } @@ -38381,7 +38412,7 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, #ifndef NO_ASN_TIME_CHECK #ifndef WOLFSSL_NO_OCSP_DATE_CHECK if ((! AsnSkipDateCheck) && !XVALIDATE_DATE(single->status->thisDate, - single->status->thisDateFormat, ASN_BEFORE)) + single->status->thisDateFormat, ASN_BEFORE, MAX_DATE_SIZE)) return ASN_BEFORE_DATE_E; #endif #endif @@ -38419,7 +38450,7 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, #ifndef WOLFSSL_NO_OCSP_DATE_CHECK if ((! AsnSkipDateCheck) && !XVALIDATE_DATE(single->status->nextDate, - single->status->nextDateFormat, ASN_AFTER)) + single->status->nextDateFormat, ASN_AFTER, MAX_DATE_SIZE)) return ASN_AFTER_DATE_E; #endif #endif @@ -38493,7 +38524,8 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, #if !defined(NO_ASN_TIME_CHECK) && !defined(WOLFSSL_NO_OCSP_DATE_CHECK) /* Check date is a valid string and ASN_BEFORE now. */ if ((! AsnSkipDateCheck) && - !XVALIDATE_DATE(cs->thisDate, ASN_GENERALIZED_TIME, ASN_BEFORE)) + !XVALIDATE_DATE(cs->thisDate, ASN_GENERALIZED_TIME, ASN_BEFORE, + MAX_DATE_SIZE)) { ret = ASN_BEFORE_DATE_E; } @@ -38518,7 +38550,8 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, #if !defined(NO_ASN_TIME_CHECK) && !defined(WOLFSSL_NO_OCSP_DATE_CHECK) /* Check date is a valid string and ASN_AFTER now. */ if ((! AsnSkipDateCheck) && - !XVALIDATE_DATE(cs->nextDate, ASN_GENERALIZED_TIME, ASN_AFTER)) + !XVALIDATE_DATE(cs->nextDate, ASN_GENERALIZED_TIME, ASN_AFTER, + MAX_DATE_SIZE)) { ret = ASN_AFTER_DATE_E; } @@ -40605,7 +40638,8 @@ static int ParseCRL_CertList(RevokedCert* rcert, DecodedCRL* dcrl, #if !defined(NO_ASN_TIME) && !defined(WOLFSSL_NO_CRL_DATE_CHECK) if (verify != NO_VERIFY && (! AsnSkipDateCheck) && - !XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, ASN_AFTER)) { + !XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, ASN_AFTER, + MAX_DATE_SIZE)) { WOLFSSL_MSG("CRL after date is no longer valid"); WOLFSSL_ERROR_VERBOSE(CRL_CERT_DATE_ERR); return CRL_CERT_DATE_ERR; @@ -41267,7 +41301,8 @@ int ParseCRL(RevokedCert* rcert, DecodedCRL* dcrl, const byte* buff, word32 sz, /* Next date was set, so validate it. */ if (verify != NO_VERIFY && (! AsnSkipDateCheck) && - !XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, ASN_AFTER)) { + !XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, ASN_AFTER, + MAX_DATE_SIZE)) { WOLFSSL_MSG("CRL after date is no longer valid"); ret = CRL_CERT_DATE_ERR; WOLFSSL_ERROR_VERBOSE(ret); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 84ad93f1bb..99da1e84fa 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2244,7 +2244,8 @@ WOLFSSL_LOCAL int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, typedef struct tm wolfssl_tm; #ifdef WOLFSSL_ASN_TIME_STRING -WOLFSSL_LOCAL int GetTimeString(byte* date, int format, char* buf, int len); +WOLFSSL_LOCAL int GetTimeString(byte* date, int format, char* buf, int len, + int dateLen); #endif #if !defined(NO_ASN_TIME) && !defined(USER_TIME) && \ !defined(TIME_OVERRIDES) && (defined(OPENSSL_EXTRA) || defined(HAVE_PKCS7)) @@ -2252,12 +2253,13 @@ WOLFSSL_LOCAL int GetFormattedTime(void* currTime, byte* buf, word32 len); WOLFSSL_LOCAL int GetAsnTimeString(void* currTime, byte* buf, word32 len); #endif WOLFSSL_LOCAL int ExtractDate(const unsigned char* date, unsigned char format, - wolfssl_tm* certTime, int* idx); + wolfssl_tm* certTime, int* idx, int len); WOLFSSL_LOCAL int DateGreaterThan(const struct tm* a, const struct tm* b); -WOLFSSL_LOCAL int wc_ValidateDate(const byte* date, byte format, int dateType); +WOLFSSL_LOCAL int wc_ValidateDate(const byte* date, byte format, int dateType, + int len); #ifndef NO_ASN_TIME WOLFSSL_LOCAL int wc_ValidateDateWithTime(const byte* date, byte format, - int dateType, time_t checkTime); + int dateType, time_t checkTime, int len); #endif WOLFSSL_TEST_VIS int wc_AsnSetSkipDateCheck(int skip_p); WOLFSSL_LOCAL int wc_AsnGetSkipDateCheck(void); diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index d9d97f3085..ff9cd730d2 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1586,7 +1586,7 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #endif #if !defined(XVALIDATE_DATE) && !defined(HAVE_VALIDATE_DATE) #define USE_WOLF_VALIDDATE - #define XVALIDATE_DATE(d, f, t) wc_ValidateDate((d), (f), (t)) + #define XVALIDATE_DATE(d, f, t, l) wc_ValidateDate((d), (f), (t), (l)) #endif /* wolf struct tm and time_t */