Commit fdab63f538 for openssl.org
commit fdab63f53859695a29c11f7925802a9b78daf161
Author: mi11ione <i@mi11ion.io>
Date: Thu Oct 22 14:58:28 2026 +0200
apps/pkcs12.c: fix double free when -jdktrust OID is used
jdk_trust() passed the OID it gets from pkcs12_main()
to X509_ATTRIBUTE_create(), which takes the ownership of it, and then freed
the attribute, freeing the OID; pkcs12_main() frees the OID again
at export_end. With an OID that is not built in (for example,
-jdktrust 1.2.3), the export aborts on a double free, and with more
than one certificate, the second jdk_trust() call reads the freed OID.
Built-in names are static objects, so they were not affected.
Give the attribute its own copy with OBJ_dup(), and return -1 (failure)
from the callback if the copy or the attribute cannot be created.
Resolves: https://github.com/openssl/openssl/issues/33319
Fixes: e869c867c1c4 "Allow PKCS12 export to set arbitrary bag attributes"
Assisted-by: Claude Code:claude-opus-5-5
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Wed Oct 28 10:34:05 2026
Merged-from: https://github.com/openssl/openssl/pull/33320
diff --git a/apps/pkcs12.c b/apps/pkcs12.c
index f97149f8f7..7213f9c137 100644
--- a/apps/pkcs12.c
+++ b/apps/pkcs12.c
@@ -952,6 +952,7 @@ static int jdk_trust(PKCS12_SAFEBAG *bag, void *cbarg)
{
STACK_OF(X509_ATTRIBUTE) *attrs = NULL;
X509_ATTRIBUTE *attr = NULL;
+ ASN1_OBJECT *obj = NULL;
/* Nothing to do */
if (cbarg == NULL)
@@ -960,8 +961,17 @@ static int jdk_trust(PKCS12_SAFEBAG *bag, void *cbarg)
/* Get the current attrs */
attrs = (STACK_OF(X509_ATTRIBUTE) *)PKCS12_SAFEBAG_get0_attrs(bag);
- /* Create a new attr for the JDK Trusted Usage and add it */
- attr = X509_ATTRIBUTE_create(NID_oracle_jdk_trustedkeyusage, V_ASN1_OBJECT, (ASN1_OBJECT *)cbarg);
+ /*
+ * Create a new attr for the JDK Trusted Usage and add it. The attr owns
+ * its value, so give it a copy: cbarg stays owned by the caller.
+ */
+ if ((obj = OBJ_dup((ASN1_OBJECT *)cbarg)) == NULL)
+ return -1;
+ attr = X509_ATTRIBUTE_create(NID_oracle_jdk_trustedkeyusage, V_ASN1_OBJECT, obj);
+ if (attr == NULL) {
+ ASN1_OBJECT_free(obj);
+ return -1;
+ }
/* Add the new attr, if attrs is NULL, it'll be initialised */
X509at_add1_attr(&attrs, attr);
diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t
index 16652b1fb1..deea098c8b 100644
--- a/test/recipes/80-test_pkcs12.t
+++ b/test/recipes/80-test_pkcs12.t
@@ -57,7 +57,7 @@ $ENV{OPENSSL_WIN32_UTF8}=1;
my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
my $no_err = disabled('err') || disabled('autoerrinit');
-plan tests => 117 + ($no_fips ? 0 : 5);
+plan tests => 119 + ($no_fips ? 0 : 5);
# Test different PKCS#12 formats
ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats");
@@ -333,6 +333,21 @@ with({ exit_checker => sub { return shift == 1; } },
delete $ENV{OPENSSL_CONF}
}
+# Test Oracle Trusted Key Usage with an OID that is not built in, on two certs
+{
+ my $outfile_oid = "out7-custom-oid.p12";
+ ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile_oid,
+ "-jdktrust", "1.2.3", "-in", srctop_file(@path, "ee-cert.pem"),
+ "-certfile", srctop_file(@path, "ca-cert.pem"),
+ "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])),
+ "test nokeys two certs with a custom trusted key usage OID");
+
+ my @pkcs12info = run(app(["openssl", "pkcs12", "-info", "-in", $outfile_oid,
+ "-passin", "pass:"]), capture => 1);
+ ok(grep(/Trusted key usage \(Oracle\): undefined \(1\.2\.3\)$/, @pkcs12info) == 2,
+ "test custom trusted key usage OID is set on both certs");
+}
+
# Test -clcerts/-cacerts cert filtering and the -name friendly name.
subtest "pkcs12 -clcerts/-cacerts filtering and -name" => sub {
plan tests => 7;