From a80f3e0f1493294c7b736b88c7c4f48d6f2a04dc Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 5 Jun 2025 17:27:46 -0700 Subject: [PATCH 1/4] Fix X509 load locations to handle PEM files with multiple certs --- src/x509.c | 50 +++++++++++++++++---------- src/x509_str.c | 86 ++-------------------------------------------- tests/api.c | 34 ++++++++++++++++++ wolfssl/internal.h | 1 + 4 files changed, 69 insertions(+), 102 deletions(-) diff --git a/src/x509.c b/src/x509.c index 2dbc7587cd9..9c6e53fde6b 100644 --- a/src/x509.c +++ b/src/x509.c @@ -7590,19 +7590,7 @@ const char* wolfSSL_X509_verify_cert_error_string(long err) #ifdef OPENSSL_EXTRA -/* Add directory path that will be used for loading certs and CRLs - * which have the .rn name format. - * type may be WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. - * returns WOLFSSL_SUCCESS on successful, otherwise negative or zero. */ -int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP* lookup, const char* dir, - long type) -{ - return wolfSSL_X509_LOOKUP_ctrl(lookup, WOLFSSL_X509_L_ADD_DIR, dir, type, - NULL); -} - -int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, - const char* file, long type) +int X509LoadPemFile(WOLFSSL_X509_STORE *store, const char* file) { #if !defined(NO_FILESYSTEM) && \ (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) @@ -7615,9 +7603,6 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, const char* header = NULL; const char* footer = NULL; - if (type != WOLFSSL_FILETYPE_PEM) - return WS_RETURN_CODE(BAD_FUNC_ARG, (int)WOLFSSL_FAILURE); - fp = XFOPEN(file, "rb"); if (fp == XBADFILE) return WS_RETURN_CODE(BAD_FUNC_ARG, (int)WOLFSSL_FAILURE); @@ -7653,7 +7638,7 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { #ifdef HAVE_CRL - WOLFSSL_CERT_MANAGER* cm = lookup->store->cm; + WOLFSSL_CERT_MANAGER* cm = store->cm; if (cm->crl == NULL) { if (wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECK) @@ -7672,7 +7657,7 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, } else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { - ret = X509StoreLoadCertBuffer(lookup->store, curr, + ret = X509StoreLoadCertBuffer(store, curr, (word32)sz, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) goto end; @@ -7702,6 +7687,35 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, #endif } +/* Add directory path that will be used for loading certs and CRLs + * which have the .rn name format. + * type may be WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * returns WOLFSSL_SUCCESS on successful, otherwise negative or zero. */ +int wolfSSL_X509_LOOKUP_add_dir(WOLFSSL_X509_LOOKUP* lookup, const char* dir, + long type) +{ + return wolfSSL_X509_LOOKUP_ctrl(lookup, WOLFSSL_X509_L_ADD_DIR, dir, type, + NULL); +} + +int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, + const char* file, long type) +{ +#if !defined(NO_FILESYSTEM) && \ + (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) + + if (type != WOLFSSL_FILETYPE_PEM) + return WS_RETURN_CODE(BAD_FUNC_ARG, (int)WOLFSSL_FAILURE); + + return X509LoadPemFile(lookup->store, file); +#else + (void)lookup; + (void)file; + (void)type; + return WS_RETURN_CODE(WOLFSSL_FAILURE,WOLFSSL_FAILURE); +#endif +} + WOLFSSL_X509_LOOKUP_METHOD* wolfSSL_X509_LOOKUP_hash_dir(void) { /* Method implementation in functions. */ diff --git a/src/x509_str.c b/src/x509_str.c index 9fec690b383..f88d43345f9 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1510,74 +1510,6 @@ int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, #if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) -static int X509StoreReadFile(const char *fname, - StaticBuffer *content, word32 *bytesRead, int *type) -{ - int ret = -1; - long sz = 0; -#ifdef HAVE_CRL - const char* header = NULL; - const char* footer = NULL; -#endif - - ret = wolfssl_read_file_static(fname, content, NULL, DYNAMIC_TYPE_FILE, - &sz); - if (ret == 0) { - *type = CERT_TYPE; - *bytesRead = (word32)sz; -#ifdef HAVE_CRL - /* Look for CRL header and footer. */ - if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && - (XSTRNSTR((char*)content->buffer, header, (word32)sz) != - NULL)) { - *type = CRL_TYPE; - } -#endif - } - - return (ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); -} - -static int X509StoreLoadFile(WOLFSSL_X509_STORE *str, - const char *fname) -{ - int ret = WOLFSSL_SUCCESS; - int type = 0; -#ifndef WOLFSSL_SMALL_STACK - byte stackBuffer[FILE_BUFFER_SIZE]; -#endif - StaticBuffer content; - word32 contentLen = 0; - -#ifdef WOLFSSL_SMALL_STACK - static_buffer_init(&content); -#else - static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE); -#endif - - WOLFSSL_MSG_EX("X509StoreLoadFile: Loading file: %s", fname); - - ret = X509StoreReadFile(fname, &content, &contentLen, &type); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Failed to load file"); - ret = WOLFSSL_FAILURE; - } - - if ((ret == WOLFSSL_SUCCESS) && (type == CERT_TYPE)) { - ret = X509StoreLoadCertBuffer(str, content.buffer, - contentLen, WOLFSSL_FILETYPE_PEM); - } -#ifdef HAVE_CRL - else if ((ret == WOLFSSL_SUCCESS) && (type == CRL_TYPE)) { - ret = BufferLoadCRL(str->cm->crl, content.buffer, contentLen, - WOLFSSL_FILETYPE_PEM, 0); - } -#endif - - static_buffer_free(&content, NULL, DYNAMIC_TYPE_FILE); - return ret; -} - /* Loads certificate(s) files in pem format into X509_STORE struct from either * a file or directory. * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE if an error occurs. @@ -1607,23 +1539,9 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, wolfSSL_CertManagerFree(ctx->cm); ctx->cm = str->cm; -#ifdef HAVE_CRL - if (str->cm->crl == NULL) { - /* Workaround to allocate the internals to load CRL's but don't enable - * CRL checking by default */ - if (wolfSSL_CertManagerEnableCRL(str->cm, WOLFSSL_CRL_CHECK) - != WOLFSSL_SUCCESS || - wolfSSL_CertManagerDisableCRL(str->cm) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Enable CRL failed"); - wolfSSL_CTX_free(ctx); - return WOLFSSL_FAILURE; - } - } -#endif - /* Load individual file */ if (file) { - ret = X509StoreLoadFile(str, file); + ret = X509LoadPemFile(str, file); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to load file"); ret = WOLFSSL_FAILURE; @@ -1649,7 +1567,7 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, while (ret == 0 && name) { WOLFSSL_MSG(name); - ret = X509StoreLoadFile(str, name); + ret = X509LoadPemFile(str, name); /* Not failing on load errors */ if (ret != WOLFSSL_SUCCESS) WOLFSSL_MSG("Failed to load file in path, continuing"); diff --git a/tests/api.c b/tests/api.c index 5a1db8a3370..d4883d14d5b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -28968,6 +28968,39 @@ static int test_wolfSSL_X509_STORE_load_locations(void) return EXPECT_RESULT(); } +static int test_wolfSSL_X509_STORE_load_multiple_certs(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && \ + !defined(NO_WOLFSSL_DIR) && !defined(NO_CERTS) && \ + defined(WOLFSSL_SIGNER_DER_CERT) + X509_STORE *store = NULL; + STACK_OF(X509_OBJECT) *objs = NULL; + const char multi_cert_file[] = "./certs/intermediate/server-chain.pem"; + int cert_count = 0; + int i; + + /* The server-chain.pem file contains 3 certificates, ensure they + * all load into the store correctly */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_load_locations(store, multi_cert_file, NULL), + WOLFSSL_SUCCESS); + + /* Count X509 certificate objects in store */ + ExpectNotNull(objs = X509_STORE_get0_objects(store)); + for (i = 0; i < sk_X509_OBJECT_num(objs) && EXPECT_SUCCESS(); i++) { + X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); + if (obj && X509_OBJECT_get_type(obj) == X509_LU_X509) { + cert_count++; + } + } + + ExpectIntEQ(cert_count, 3); + X509_STORE_free(store); +#endif + return EXPECT_RESULT(); +} + static int test_X509_STORE_get0_objects(void) { EXPECT_DECLS; @@ -67535,6 +67568,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_X509_STORE_CTX_get0_store), TEST_DECL(test_wolfSSL_X509_STORE), TEST_DECL(test_wolfSSL_X509_STORE_load_locations), + TEST_DECL(test_wolfSSL_X509_STORE_load_multiple_certs), TEST_DECL(test_X509_STORE_get0_objects), TEST_DECL(test_wolfSSL_X509_load_crl_file), TEST_DECL(test_wolfSSL_X509_STORE_get1_certs), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 52a075efd87..0d3008b321d 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2779,6 +2779,7 @@ WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store, #endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */ WOLFSSL_LOCAL int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, byte *buf, word32 bufLen, int type); +WOLFSSL_LOCAL int X509LoadPemFile(WOLFSSL_X509_STORE *str, const char* file); #endif /* !defined NO_CERTS */ /* wolfSSL Sock Addr */ From 723b99dbe7972b507bb91b553229d05aaa6c5f5e Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 5 Jun 2025 17:52:01 -0700 Subject: [PATCH 2/4] Fix cast error --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index d4883d14d5b..7bcd7dc669a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -28989,7 +28989,7 @@ static int test_wolfSSL_X509_STORE_load_multiple_certs(void) /* Count X509 certificate objects in store */ ExpectNotNull(objs = X509_STORE_get0_objects(store)); for (i = 0; i < sk_X509_OBJECT_num(objs) && EXPECT_SUCCESS(); i++) { - X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); + X509_OBJECT *obj = (X509_OBJECT*)sk_X509_OBJECT_value(objs, i); if (obj && X509_OBJECT_get_type(obj) == X509_LU_X509) { cert_count++; } From 5da8b532c7a2699dc71dfc8fd02150789ac83e6b Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 5 Jun 2025 19:35:17 -0700 Subject: [PATCH 3/4] Fix else leg of X509LoadPemFile --- src/x509.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/x509.c b/src/x509.c index 9c6e53fde6b..c5e13069ce1 100644 --- a/src/x509.c +++ b/src/x509.c @@ -7680,9 +7680,8 @@ int X509LoadPemFile(WOLFSSL_X509_STORE *store, const char* file) XFCLOSE(fp); return WS_RETURN_CODE(ret, (int)WOLFSSL_FAILURE); #else - (void)lookup; + (void)store; (void)file; - (void)type; return WS_RETURN_CODE(WOLFSSL_FAILURE,WOLFSSL_FAILURE); #endif } From 184aa0a7f63ff0a112c983e1afcfb66c3e84b424 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 30 Jun 2025 11:57:27 -0700 Subject: [PATCH 4/4] Move test to test_x509.c, add subject name check to test --- tests/api.c | 34 ---------------------------------- tests/api/test_x509.c | 41 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_x509.h | 4 +++- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/tests/api.c b/tests/api.c index be29717a7bc..506087a7e3c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -29078,39 +29078,6 @@ static int test_wolfSSL_X509_STORE_load_locations(void) return EXPECT_RESULT(); } -static int test_wolfSSL_X509_STORE_load_multiple_certs(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && \ - !defined(NO_WOLFSSL_DIR) && !defined(NO_CERTS) && \ - defined(WOLFSSL_SIGNER_DER_CERT) - X509_STORE *store = NULL; - STACK_OF(X509_OBJECT) *objs = NULL; - const char multi_cert_file[] = "./certs/intermediate/server-chain.pem"; - int cert_count = 0; - int i; - - /* The server-chain.pem file contains 3 certificates, ensure they - * all load into the store correctly */ - ExpectNotNull(store = X509_STORE_new()); - ExpectIntEQ(X509_STORE_load_locations(store, multi_cert_file, NULL), - WOLFSSL_SUCCESS); - - /* Count X509 certificate objects in store */ - ExpectNotNull(objs = X509_STORE_get0_objects(store)); - for (i = 0; i < sk_X509_OBJECT_num(objs) && EXPECT_SUCCESS(); i++) { - X509_OBJECT *obj = (X509_OBJECT*)sk_X509_OBJECT_value(objs, i); - if (obj && X509_OBJECT_get_type(obj) == X509_LU_X509) { - cert_count++; - } - } - - ExpectIntEQ(cert_count, 3); - X509_STORE_free(store); -#endif - return EXPECT_RESULT(); -} - static int test_X509_STORE_get0_objects(void) { EXPECT_DECLS; @@ -67845,7 +67812,6 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_X509_STORE_CTX_get0_store), TEST_DECL(test_wolfSSL_X509_STORE), TEST_DECL(test_wolfSSL_X509_STORE_load_locations), - TEST_DECL(test_wolfSSL_X509_STORE_load_multiple_certs), TEST_DECL(test_X509_STORE_get0_objects), TEST_DECL(test_wolfSSL_X509_load_crl_file), TEST_DECL(test_wolfSSL_X509_STORE_get1_certs), diff --git a/tests/api/test_x509.c b/tests/api/test_x509.c index 319ef8c07d3..1c05f5625e8 100644 --- a/tests/api/test_x509.c +++ b/tests/api/test_x509.c @@ -148,3 +148,44 @@ int test_x509_rfc2818_verification_callback(void) #endif return EXPECT_RESULT(); } + +int test_wolfSSL_X509_STORE_load_multiple_certs(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && \ + !defined(NO_WOLFSSL_DIR) && !defined(NO_CERTS) && \ + defined(WOLFSSL_SIGNER_DER_CERT) + X509_STORE *store = NULL; + STACK_OF(X509_OBJECT) *objs = NULL; + const char multi_cert_file[] = "./certs/intermediate/server-chain.pem"; + int cert_count = 0; + int i; + + /* The server-chain.pem file contains 3 certificates, ensure they + * all load into the store correctly */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_load_locations(store, multi_cert_file, NULL), + WOLFSSL_SUCCESS); + + /* Count X509 certificate objects in store and verify subject names */ + ExpectNotNull(objs = X509_STORE_get0_objects(store)); + for (i = 0; i < sk_X509_OBJECT_num(objs) && EXPECT_SUCCESS(); i++) { + X509_OBJECT *obj = (X509_OBJECT*)sk_X509_OBJECT_value(objs, i); + if (obj && X509_OBJECT_get_type(obj) == X509_LU_X509) { + WOLFSSL_X509* cert = X509_OBJECT_get0_X509(obj); + WOLFSSL_X509_NAME* name = X509_get_subject_name(cert); + char* subject = X509_NAME_oneline(name, NULL, 0); + + ExpectNotNull(subject); + ExpectIntNE(XSTRLEN(subject), 0); + + XFREE(subject, NULL, DYNAMIC_TYPE_OPENSSL); + cert_count++; + } + } + + ExpectIntEQ(cert_count, 3); + X509_STORE_free(store); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_x509.h b/tests/api/test_x509.h index 1728fd1db75..cc3b58f9a55 100644 --- a/tests/api/test_x509.h +++ b/tests/api/test_x509.h @@ -23,8 +23,10 @@ #define WOLFCRYPT_TEST_X509_H int test_x509_rfc2818_verification_callback(void); +int test_wolfSSL_X509_STORE_load_multiple_certs(void); #define TEST_X509_DECLS \ - TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback) + TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback), \ + TEST_DECL_GROUP("x509", test_wolfSSL_X509_STORE_load_multiple_certs) #endif /* WOLFCRYPT_TEST_X509_H */