Commit 80218e15fd for openssl.org

commit 80218e15fd9855029128f8f8086be468ba31c0c7
Author: Greensi7 <adam.tabak04@gmail.com>
Date:   Tue Aug 11 02:19:39 2026 +0200

    fuzz: add store fuzzer

    Targets OSSL_STORE_attach() followed by OSSL_STORE_load().
    Covers automatic format detection and explicit PEM and DER decoding.
    Also includes filtering for params, public and private keys, certs,
    CRLs, and SKEYs.

    Assisted-by: ChatGPT:gpt-5.6
    Reviewed-by: Milan Broz <mbroz@openssl.org>
    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Merge-date: Sat Nov  7 11:41:47 2026
    Merged-from: https://github.com/openssl/openssl/pull/33210

diff --git a/fuzz/build.info b/fuzz/build.info
index 90954aad0e..fd654c5da0 100644
--- a/fuzz/build.info
+++ b/fuzz/build.info
@@ -11,6 +11,7 @@
 IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}]
   PROGRAMS{noinst}=asn1 asn1parse bignum bndiv client conf crl server smime
   PROGRAMS{noinst}=pkcs7_verify
+  PROGRAMS{noinst}=store
   PROGRAMS{noinst}=pkcs12 punycode pem decoder hashtable acert
   PROGRAMS{noinst}=v3name x509v3
   PROGRAMS{noinst}=provider
@@ -95,6 +96,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}]
   INCLUDE[pkcs12]=../include {- $ex_inc -}
   DEPEND[pkcs12]=../libcrypto {- $ex_lib -}

+  SOURCE[store]=store.c driver.c fuzz_rand.c
+  INCLUDE[store]=../include {- $ex_inc -}
+  DEPEND[store]=../libcrypto {- $ex_lib -}
+
   SOURCE[conf]=conf.c driver.c
   INCLUDE[conf]=../include {- $ex_inc -}
   DEPEND[conf]=../libcrypto {- $ex_lib -}
@@ -201,6 +206,7 @@ IF[{- !$disabled{tests} -}]

   PROGRAMS{noinst}=asn1-test asn1parse-test bignum-test bndiv-test client-test conf-test crl-test server-test smime-test
   PROGRAMS{noinst}=pkcs7_verify-test
+  PROGRAMS{noinst}=store-test
   PROGRAMS{noinst}=pkcs12-test punycode-test pem-test decoder-test hashtable-test acert-test
   PROGRAMS{noinst}=v3name-test x509v3-test
   PROGRAMS{noinst}=provider-test
@@ -298,6 +304,10 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[pkcs12-test]=../include ../test/mfail
   DEPEND[pkcs12-test]=../libcrypto.a

+  SOURCE[store-test]=store.c $FUZZTESTSRC fuzz_rand.c
+  INCLUDE[store-test]=../include ../test/mfail
+  DEPEND[store-test]=../libcrypto.a
+
   SOURCE[conf-test]=conf.c $FUZZTESTSRC
   INCLUDE[conf-test]=../include ../test/mfail
   DEPEND[conf-test]=../libcrypto.a
diff --git a/fuzz/corpora b/fuzz/corpora
index 5aad44f590..9f780c2b4b 160000
--- a/fuzz/corpora
+++ b/fuzz/corpora
@@ -1 +1 @@
-Subproject commit 5aad44f59020f6b08e8af0c03eacb1e766970ed0
+Subproject commit 9f780c2b4b8e96cdcf17792f3d6ade354cccb04a
diff --git a/fuzz/store.c b/fuzz/store.c
new file mode 100644
index 0000000000..a688226be1
--- /dev/null
+++ b/fuzz/store.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2026 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 may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+#include <limits.h>
+#include <openssl/bio.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/params.h>
+#include <openssl/store.h>
+#include <openssl/ui.h>
+#include <openssl/x509.h>
+#include "fuzzer.h"
+
+#define MAX_INPUT_SIZE 16384
+#define MAX_LOADS 4
+
+#define MODE_EXPECT_MASK 7u
+#define MODE_INPUT_SHIFT 3u
+#define MODE_INPUT_MASK 3u
+
+/*
+ * OSSL_STORE_INFO_NAME is excluded, because it links
+ * to other files/URIs which wouldn't be practical for fuzzing.
+ */
+static const int expected_types[] = {
+    0, /* any */
+    OSSL_STORE_INFO_PARAMS,
+    OSSL_STORE_INFO_PUBKEY,
+    OSSL_STORE_INFO_PKEY,
+    OSSL_STORE_INFO_CERT,
+    OSSL_STORE_INFO_CRL,
+    OSSL_STORE_INFO_SKEY,
+    0, /* any */
+};
+
+int FuzzerInitialize(int *argc, char ***argv)
+{
+    FuzzerSetRand();
+    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+    ERR_clear_error();
+    return 1;
+}
+
+int FuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+    BIO *in = NULL;
+    OSSL_STORE_CTX *ctx = NULL;
+    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+    const OSSL_PARAM *attach_params = NULL;
+    char *input_type = NULL;
+    unsigned int mode = 0;
+    int expected_type = 0;
+    size_t i;
+
+    if (len < 2 || len > MAX_INPUT_SIZE)
+        return 0;
+
+    /*
+     * The first input byte selects the STORE configuration:
+     *   mode bits 0-2: any, params, pubkey, pkey, cert, crl, skey, any
+     */
+    expected_type = expected_types[buf[0] & MODE_EXPECT_MASK];
+    /*
+     *  mode bits 3-4: auto, PEM, DER, auto
+     */
+    mode = ((buf[0] >> MODE_INPUT_SHIFT) & MODE_INPUT_MASK);
+    input_type = mode == 1u ? "PEM" : mode == 2u ? "DER"
+                                                 : NULL;
+    buf++;
+    len--;
+
+    if (input_type != NULL) {
+        params[0] = OSSL_PARAM_construct_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE, input_type, 0);
+        attach_params = params;
+    }
+
+    in = BIO_new_mem_buf(buf, (int)len);
+    if (in == NULL)
+        goto end;
+
+    ctx = OSSL_STORE_attach(in, "file", NULL, NULL, UI_null(), NULL,
+        attach_params, NULL, NULL);
+    if (ctx == NULL)
+        goto end;
+
+    if (!OSSL_STORE_expect(ctx, expected_type))
+        goto end;
+
+    for (i = 0; i < MAX_LOADS && !OSSL_STORE_eof(ctx); i++) {
+        OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
+
+        if (info == NULL) {
+            if (OSSL_STORE_error(ctx))
+                break;
+            continue;
+        }
+
+        switch (OSSL_STORE_INFO_get_type(info)) {
+        case OSSL_STORE_INFO_NAME:
+            OPENSSL_free(OSSL_STORE_INFO_get1_NAME(info));
+            OPENSSL_free(OSSL_STORE_INFO_get1_NAME_description(info));
+            break;
+        case OSSL_STORE_INFO_PARAMS:
+            EVP_PKEY_free(OSSL_STORE_INFO_get1_PARAMS(info));
+            break;
+        case OSSL_STORE_INFO_PUBKEY:
+            EVP_PKEY_free(OSSL_STORE_INFO_get1_PUBKEY(info));
+            break;
+        case OSSL_STORE_INFO_PKEY:
+            EVP_PKEY_free(OSSL_STORE_INFO_get1_PKEY(info));
+            break;
+        case OSSL_STORE_INFO_CERT:
+            X509_free(OSSL_STORE_INFO_get1_CERT(info));
+            break;
+        case OSSL_STORE_INFO_CRL:
+            X509_CRL_free(OSSL_STORE_INFO_get1_CRL(info));
+            break;
+        case OSSL_STORE_INFO_SKEY:
+            EVP_SKEY_free(OSSL_STORE_INFO_get1_SKEY(info));
+            break;
+        default:
+            break;
+        }
+        OSSL_STORE_INFO_free(info);
+    }
+
+end:
+    OSSL_STORE_close(ctx);
+    BIO_free(in);
+    ERR_clear_error();
+    return 0;
+}
+
+void FuzzerCleanup(void)
+{
+    FuzzerClearRand();
+}
diff --git a/test/recipes/99-test_fuzz_store.t b/test/recipes/99-test_fuzz_store.t
new file mode 100644
index 0000000000..161f05d43d
--- /dev/null
+++ b/test/recipes/99-test_fuzz_store.t
@@ -0,0 +1,22 @@
+#!/usr/bin/env perl
+# Copyright 2026 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
+
+use strict;
+use warnings;
+
+use OpenSSL::Test qw/:DEFAULT srctop_file/;
+use OpenSSL::Test::Utils;
+
+my $fuzzer = "store";
+setup("test_fuzz_${fuzzer}");
+
+plan tests => 2; # one more due to below require_ok(...)
+
+require_ok(srctop_file('test','recipes','fuzz.pl'));
+
+fuzz_ok($fuzzer);