From 45895076bcaa1f665f9bd65bf81a286f78964d3c Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Tue, 16 Jun 2026 14:15:24 -0600 Subject: [PATCH 1/2] fix to avoid use after free edge case with X509_EXTENSION_create_by_OBJ() --- src/x509.c | 22 +++++++++++++++++----- tests/api/test_ossl_x509_ext.c | 8 ++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/x509.c b/src/x509.c index fd87b1da4a..9dd5c53954 100644 --- a/src/x509.c +++ b/src/x509.c @@ -298,6 +298,7 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( { int err = 0; WOLFSSL_X509_EXTENSION *ret = ex; + WOLFSSL_ASN1_OBJECT *newObj = NULL; WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_create_by_OBJ"); @@ -311,7 +312,18 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( err = 1; } } - else { + + /* Duplicate the source object before freeing the existing one so that a + * caller passing the extension's own object (e.g. obtained via + * wolfSSL_X509_EXTENSION_get_object(ex)) does not read freed memory. */ + if (err == 0) { + newObj = wolfSSL_ASN1_OBJECT_dup(obj); + if (newObj == NULL) { + err = 1; + } + } + + if ((err == 0) && (ret == ex)) { /* Prevent potential memory leaks and dangling pointers. */ wolfSSL_ASN1_OBJECT_free(ret->obj); ret->obj = NULL; @@ -320,10 +332,8 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( if (err == 0) { ret->crit = crit; - ret->obj = wolfSSL_ASN1_OBJECT_dup(obj); - if (ret->obj == NULL) { - err = 1; - } + ret->obj = newObj; + newObj = NULL; } if (err == 0) { @@ -333,6 +343,8 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( } if (err == 1) { + /* Free the duplicate if it was created but not assigned to ret. */ + wolfSSL_ASN1_OBJECT_free(newObj); if (ret != ex) { wolfSSL_X509_EXTENSION_free(ret); } diff --git a/tests/api/test_ossl_x509_ext.c b/tests/api/test_ossl_x509_ext.c index 05d2370a87..631cd59154 100644 --- a/tests/api/test_ossl_x509_ext.c +++ b/tests/api/test_ossl_x509_ext.c @@ -905,6 +905,14 @@ int test_wolfSSL_X509_EXTENSION_create_by_OBJ(void) if (ext3 == NULL) { wolfSSL_X509_EXTENSION_free(ext2); } + /* Reuse the extension passing its own object as the source. This must not + * read freed memory (the source object aliases ext3's current object). */ + if (ext3 != NULL) { + WOLFSSL_ASN1_OBJECT* self = NULL; + ExpectNotNull(self = wolfSSL_X509_EXTENSION_get_object(ext3)); + ExpectNotNull(ext3 = wolfSSL_X509_EXTENSION_create_by_OBJ(ext3, self, + crit, str)); + } wolfSSL_X509_EXTENSION_free(ext3); ExpectIntEQ(wolfSSL_X509_get_ext_by_OBJ(NULL, NULL, -1), From 42d0bb319323e8313cdd5b890e082046d423e6ee Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Tue, 16 Jun 2026 14:48:35 -0600 Subject: [PATCH 2/2] additional sanity check on input arguments --- tests/api/test_evp.c | 12 ++++++++++++ wolfcrypt/src/evp.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/api/test_evp.c b/tests/api/test_evp.c index 172bf3d2c1..109a508030 100644 --- a/tests/api/test_evp.c +++ b/tests/api/test_evp.c @@ -385,6 +385,18 @@ int test_wolfSSL_EVP_DecodeUpdate(void) ); ExpectIntEQ( outl, 0); + /* pass negative length */ + ExpectIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc1, + -1), /* negative inl */ + -1 /* expected result code -1: fail */ + ); + ExpectIntEQ( outl, 0); + ExpectIntEQ(EVP_DecodeBlock(NULL, NULL, 0), -1); /* pass zero length input */ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 5001288338..7851e9d842 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -13457,7 +13457,7 @@ int wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, if (outl == NULL) return -1; - if (ctx == NULL || out == NULL || in == NULL) { + if (ctx == NULL || out == NULL || in == NULL || inl < 0) { *outl = 0; return -1; }