Commit eaa4a57017 for openssl.org
commit eaa4a57017ce9bca0e1130611f48f27a2b29dac7
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date: Thu Jul 9 00:03:22 2026 +0200
x509: replace x509_memfail with in-tree mfail tests
The standalone x509_memfail is superseded by mfail tests. They cover
the certificate parse, self-signature verification and issuer name
hashing paths.
Two new mfail tests still need NO_CHECK because a certificate still
parses with an undecoded public key, and EVP_DigestVerifyFinal falls
back to the original context when its EVP_PKEY_CTX_dup optimisation
fails. The issuer name hashing propagates cleanly and runs checked.
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.foundation>
MergeDate: Mon Jul 27 10:13:22 2026
(Merged from https://github.com/openssl/openssl/pull/31901)
diff --git a/test/build.info b/test/build.info
index 4fbe25030f..58f626f209 100644
--- a/test/build.info
+++ b/test/build.info
@@ -86,7 +86,7 @@ IF[{- !$disabled{tests} -}]
ENDIF
IF[{- !$disabled{'allocfail-tests'} -}]
- PROGRAMS{noinst}=handshake-memfail x509-memfail load_key_certs_crls_memfail
+ PROGRAMS{noinst}=handshake-memfail load_key_certs_crls_memfail
ENDIF
IF[{- !$disabled{quic} -}]
@@ -648,10 +648,6 @@ IF[{- !$disabled{tests} -}]
INCLUDE[handshake-memfail]=../include ../apps/include
DEPEND[handshake-memfail]=../libcrypto.a ../libssl.a libtestutil.a
- SOURCE[x509-memfail]=x509_memfail.c
- INCLUDE[x509-memfail]=../include ../apps/include
- DEPEND[x509-memfail]=../libcrypto.a libtestutil.a
-
SOURCE[load_key_certs_crls_memfail]=load_key_certs_crls_memfail.c ../apps/lib/apps.c \
../apps/lib/app_rand.c ../apps/lib/app_provider.c ../apps/lib/app_libctx.c \
../apps/lib/fmt.c ../apps/lib/apps_ui.c ../apps/lib/app_x509.c \
diff --git a/test/recipes/90-test_memfail.t b/test/recipes/90-test_memfail.t
index fefc2771b6..d0ce5e0363 100644
--- a/test/recipes/90-test_memfail.t
+++ b/test/recipes/90-test_memfail.t
@@ -31,8 +31,6 @@ $ENV{OPENSSL_TEST_MFAIL_DISABLE} = "1";
run(test(["handshake-memfail", "count", srctop_dir("test", "certs")], stderr => "$resultdir/hscountinfo.txt"));
-run(test(["x509-memfail", "count", srctop_file("test", "certs", "servercert.pem")], stderr => "$resultdir/x509countinfo.txt"));
-
run(test(["load_key_certs_crls_memfail", "count", srctop_file("test", "certs", "servercert.pem")], stderr => "$resultdir/load_key_certs_crls_countinfo.txt"));
sub get_count_info {
@@ -57,11 +55,9 @@ sub get_count_info {
my ($hsskipcount, $hsmalloccount) = get_count_info("$resultdir/hscountinfo.txt");
-my ($x509skipcount, $x509malloccount) = get_count_info("$resultdir/x509countinfo.txt");
-
my ($load_key_certs_crls_skipcount, $load_key_certs_crls_malloccount) = get_count_info("$resultdir/load_key_certs_crls_countinfo.txt");
-my $total_malloccount = $hsmalloccount + $x509malloccount
+my $total_malloccount = $hsmalloccount
+ $load_key_certs_crls_malloccount;
plan skip_all => "could not get malloc counts (one or more count runs failed or output format changed)"
if $total_malloccount == 0;
@@ -94,6 +90,4 @@ sub run_memfail_test {
run_memfail_test($hsskipcount, $hsmalloccount, ["handshake-memfail", "run", srctop_dir("test", "certs")]);
-run_memfail_test($x509skipcount, $x509malloccount, ["x509-memfail", "run", srctop_file("test", "certs", "servercert.pem")]);
-
run_memfail_test($load_key_certs_crls_skipcount, $load_key_certs_crls_malloccount, ["load_key_certs_crls_memfail", "run", srctop_file("test", "certs", "servercert.pem")]);
diff --git a/test/x509_load_cert_file_test.c b/test/x509_load_cert_file_test.c
index f9656aaa31..bfcd3521f5 100644
--- a/test/x509_load_cert_file_test.c
+++ b/test/x509_load_cert_file_test.c
@@ -230,6 +230,19 @@ err:
return ret;
}
+/* Trigger memory failures while parsing a PEM certificate. */
+static int test_x509_pem_read_mfail(void)
+{
+ X509 *cert;
+
+ MFAIL_start();
+ cert = X509_from_strings(cn_cert1);
+ MFAIL_end();
+
+ X509_free(cert);
+ return 1;
+}
+
OPT_TEST_DECLARE_USAGE("cert.pem [crl.pem]\n")
int setup_tests(void)
@@ -247,6 +260,7 @@ int setup_tests(void)
ADD_TEST(test_load_cert_file);
ADD_TEST(test_load_same_cn_certs);
+ ADD_MFAIL_NO_CHECK_TEST(test_x509_pem_read_mfail);
ADD_MFAIL_TEST(test_x509_store_add_mfail);
ADD_MFAIL_TEST(test_x509_get1_objects_mfail);
diff --git a/test/x509_memfail.c b/test/x509_memfail.c
deleted file mode 100644
index 41b2c098dc..0000000000
--- a/test/x509_memfail.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#define OPENSSL_SUPPRESS_DEPRECATED /* EVP_PKEY_get1/set1_RSA */
-
-#include <openssl/x509.h>
-#include <openssl/asn1.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include "crypto/x509.h" /* x509_st definition */
-#include "testutil.h"
-
-static char *certfile = NULL;
-static int mcount, rcount, fcount, scount, srcount;
-
-static int do_x509(int allow_failure)
-{
- int ret = (allow_failure == 1) ? 0 : 1;
- BIO *bio = NULL;
- X509 *x509 = NULL;
- const ASN1_BIT_STRING *sig = NULL;
- const X509_ALGOR *alg = NULL;
- EVP_PKEY *pkey;
-#ifndef OPENSSL_NO_DEPRECATED_3_0
- RSA *rsa = NULL;
-#endif
-
- if (!TEST_ptr(bio = BIO_new_file(certfile, "r"))
- || !TEST_ptr(x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))
- || !TEST_ptr(pkey = X509_get0_pubkey(x509)))
- goto err;
-
-#ifndef OPENSSL_NO_DEPRECATED_3_0
- /* Issue #24575 requires legacy key but the test is useful anyway */
- if (!TEST_ptr(rsa = EVP_PKEY_get1_RSA(pkey)))
- goto err;
-
- if (!TEST_int_gt(EVP_PKEY_set1_RSA(pkey, rsa), 0))
- goto err;
-#endif
-
- X509_get0_signature(&sig, &alg, x509);
-
- if (!TEST_int_gt(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),
- (X509_ALGOR *)alg, (ASN1_BIT_STRING *)sig,
- &x509->cert_info, pkey),
- 0))
- goto err;
-
- if (!TEST_int_lt(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),
- (X509_ALGOR *)alg, (ASN1_BIT_STRING *)sig,
- NULL, pkey),
- 0))
- goto err;
-
- X509_issuer_name_hash(x509);
-
- ret = 1;
-
-err:
-#ifndef OPENSSL_NO_DEPRECATED_3_0
- RSA_free(rsa);
-#endif
- X509_free(x509);
- BIO_free(bio);
- return ret;
-}
-
-static int test_record_alloc_counts(void)
-{
- return do_x509(1);
-}
-
-static int test_alloc_failures(void)
-{
- return do_x509(0);
-}
-
-static int test_report_alloc_counts(void)
-{
- CRYPTO_get_alloc_counts(&mcount, &rcount, &fcount);
- /*
- * Report our memory allocations from the count run
- * NOTE: We report a number of (re)allocations to skip here
- * (the scount + srcount value). These are the allocations
- * that took place while the test harness itself was getting
- * setup (i.e. calling OPENSSL_init_crypto/etc). We can't fail
- * those allocations as they will cause the test to fail before
- * we have even run the workload. So report them so we can
- * allow them to function before we start doing any real testing
- */
- TEST_info("skip: %d count %d\n",
- scount + srcount, mcount + rcount - scount - srcount);
- return 1;
-}
-
-int setup_tests(void)
-{
- int ret = 0;
- char *opmode = NULL;
-
- if (!TEST_ptr(opmode = test_get_argument(0)))
- goto err;
-
- if (!TEST_ptr(certfile = test_get_argument(1)))
- goto err;
-
- if (strcmp(opmode, "count") == 0) {
- CRYPTO_get_alloc_counts(&scount, &srcount, &fcount);
- ADD_TEST(test_record_alloc_counts);
- ADD_TEST(test_report_alloc_counts);
- } else {
- ADD_TEST(test_alloc_failures);
- }
- ret = 1;
-err:
- return ret;
-}
-
-void cleanup_tests(void)
-{
-}
diff --git a/test/x509_test.c b/test/x509_test.c
index a5beb7ca2f..7d2eb757e5 100644
--- a/test/x509_test.c
+++ b/test/x509_test.c
@@ -194,6 +194,62 @@ err:
return ret;
}
+/* Load the self-signed certificate passed on the command line. */
+static X509 *load_arg_cert(void)
+{
+ const char *certfile;
+ BIO *bio;
+ X509 *x509;
+
+ if ((certfile = test_get_argument(0)) == NULL
+ || (bio = BIO_new_file(certfile, "r")) == NULL)
+ return NULL;
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ return x509;
+}
+
+/* Trigger memory failures during certificate self-signature verification. */
+static int test_x509_asn1_item_verify_mfail(void)
+{
+ X509 *x509;
+ EVP_PKEY *pkey;
+ const ASN1_BIT_STRING *sig = NULL;
+ const X509_ALGOR *alg = NULL;
+
+ if (!TEST_ptr(x509 = load_arg_cert())
+ || !TEST_ptr(pkey = X509_get0_pubkey(x509))) {
+ X509_free(x509);
+ return -1;
+ }
+ X509_get0_signature(&sig, &alg, x509);
+
+ MFAIL_start();
+ (void)ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), alg, sig,
+ &x509->cert_info, pkey);
+ MFAIL_end();
+
+ X509_free(x509);
+ return 1;
+}
+
+/* Trigger memory failures while hashing the issuer name. */
+static int test_x509_issuer_name_hash_mfail(void)
+{
+ X509 *x509;
+ int ret = -1;
+
+ if (!TEST_ptr(x509 = load_arg_cert()))
+ return -1;
+
+ MFAIL_start();
+ ret = X509_issuer_name_hash(x509) != 0 ? 1 : 0;
+ MFAIL_end();
+
+ X509_free(x509);
+ return ret;
+}
+
static int test_x509_delete_last_extension(void)
{
int ret = 0;
@@ -679,6 +735,8 @@ int setup_tests(void)
ADD_TEST(test_x509_tbs_cache);
ADD_TEST(test_x509_crl_tbs_cache);
ADD_TEST(test_asn1_item_verify);
+ ADD_MFAIL_NO_CHECK_TEST(test_x509_asn1_item_verify_mfail);
+ ADD_MFAIL_TEST(test_x509_issuer_name_hash_mfail);
ADD_TEST(test_x509_delete_last_extension);
ADD_TEST(test_x509_crl_delete_last_extension);
ADD_TEST(test_x509_revoked_delete_last_extension);