]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
extend X509_REQ_add_extensions_nid() and thuis APPS/req to support augmenting/overrid...
authorDr. David von Oheimb <dev@ddvo.net>
Thu, 4 Jul 2024 07:42:00 +0000 (09:42 +0200)
committerTomas Mraz <tomas@openssl.org>
Wed, 10 Jul 2024 14:19:26 +0000 (16:19 +0200)
Fixes #11169

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24792)

crypto/x509/x509_req.c
doc/man1/openssl-req.pod.in
doc/man3/X509_REQ_get_extensions.pod
test/recipes/25-test_req.t
test/test.cnf

index f96a89d6713655a8e4d8bbd8c47fe8e68a8f5fad..4085b587a5e185e2b3f3936f89c2b3c370608a3e 100644 (file)
@@ -168,14 +168,39 @@ int X509_REQ_add_extensions_nid(X509_REQ *req,
     int extlen;
     int rv = 0;
     unsigned char *ext = NULL;
+    STACK_OF(X509_EXTENSION) *mod_exts = NULL;
+    int loc;
+
+    if (sk_X509_EXTENSION_num(exts) <= 0)
+        return 1; /* adding NULL or empty list of exts is a no-op */
+
+    loc = X509at_get_attr_by_NID(req->req_info.attributes, nid, -1);
+    if (loc != -1) {
+        if ((mod_exts = get_extensions_by_nid(req, nid)) == NULL)
+            return 0;
+        if (X509v3_add_extensions(&mod_exts, exts) == NULL)
+            goto end;
+    }
 
     /* Generate encoding of extensions */
-    extlen = ASN1_item_i2d((const ASN1_VALUE *)exts, &ext,
-                           ASN1_ITEM_rptr(X509_EXTENSIONS));
+    extlen = ASN1_item_i2d((const ASN1_VALUE *)
+                           (mod_exts == NULL ? exts : mod_exts),
+                           &ext, ASN1_ITEM_rptr(X509_EXTENSIONS));
     if (extlen <= 0)
-        return 0;
+        goto end;
+    if (mod_exts != NULL) {
+        X509_ATTRIBUTE *att = X509at_delete_attr(req->req_info.attributes, loc);
+
+        if (att == NULL)
+            goto end;
+        X509_ATTRIBUTE_free(att);
+    }
+
     rv = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext, extlen);
     OPENSSL_free(ext);
+
+ end:
+    sk_X509_EXTENSION_pop_free(mod_exts, X509_EXTENSION_free);
     return rv;
 }
 
index 808801348fd59546f22954bc91ce67ebdafdff32..0eacfc51a4c4f836ef5c4076b9402151b0e54054 100644 (file)
@@ -392,7 +392,11 @@ Add a specific extension to the certificate (if B<-x509> is in use)
 or certificate request.  The argument must have the form of
 a C<key=value> pair as it would appear in a config file.
 
+If an extension is added using this option that has the same OID as one
+defined in the extension section of the config file, it overrides that one.
+
 This option can be given multiple times.
+Doing so, the same key most not be given more than once.
 
 =item B<-precert>
 
@@ -552,7 +556,7 @@ BMPStrings and UTF8Strings.
 
 This specifies the configuration file section containing a list of
 extensions to add to the certificate request. It can be overridden
-by the B<-reqexts> command line switch. See the
+by the B<-reqexts> (or B<-extensions>) command line switch. See the
 L<x509v3_config(5)> manual page for details of the
 extension section format.
 
index 73e2ea698a7b030de522fd6ce692563ac82a1275..bd50faa63d15566df270c39440b83696e569025a 100644 (file)
@@ -22,13 +22,15 @@ found in the attributes of I<req>.
 The returned list is empty if there are no such extensions in I<req>.
 The caller is responsible for freeing the list obtained.
 
-X509_REQ_add_extensions() adds to I<req> a list of X.509 extensions I<exts>,
-which must not be NULL, using the default B<NID_ext_req>.
-This function must not be called more than once on the same I<req>.
-
-X509_REQ_add_extensions_nid() is like X509_REQ_add_extensions()
-except that I<nid> is used to identify the extensions attribute.
-This function must not be called more than once with the same I<req> and I<nid>.
+X509_REQ_add_extensions_nid() adds to I<req> a list of X.509 extensions I<exts>,
+using I<nid> to identify the extensions attribute.
+I<req> is unchanged if I<exts> is NULL or an empty list.
+This function may be called more than once on the same I<req> and I<nid>.
+In such case any previous extensions are augmented, where an extension to be
+added that has the same OID as a pre-existing one replaces this earlier one.
+
+X509_REQ_add_extensions() is like X509_REQ_add_extensions_nid()
+except that the default B<NID_ext_req> is used.
 
 =head1 RETURN VALUES
 
index 872ed316fc73c35134c93bb5a2cb50498b822aad..a0f1efdab1e0d59af9c86e6eb81462ffcbe1d94e 100644 (file)
@@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/;
 
 setup("test_req");
 
-plan tests => 109;
+plan tests => 110;
 
 require_ok(srctop_file('test', 'recipes', 'tconversion.pl'));
 
@@ -36,7 +36,7 @@ if (disabled("rsa")) {
 $ENV{MSYS2_ARG_CONV_EXCL} = "/CN=";
 
 # Check for duplicate -addext parameters, and one "working" case.
-my @addext_args = ( "openssl", "req", "-new", "-out", "testreq.pem",
+my @addext_args = ( "openssl", "req", "-new", "-out", "testreq-addexts.pem",
                     "-key",  srctop_file(@certs, "ee-key.pem"),
     "-config", srctop_file("test", "test.cnf"), @req_new );
 my $val = "subjectAltName=DNS:example.com";
@@ -55,6 +55,9 @@ ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3])));
 ok(run(app([@addext_args, "-addext", "SXNetID=1:one, 2:two, 3:three"])));
 ok(run(app([@addext_args, "-addext", "subjectAltName=dirName:dirname_sec"])));
 
+ok(run(app([@addext_args, "-addext", "keyUsage=digitalSignature",
+           "-reqexts", "reqexts"]))); # referring to section in test.cnf
+
 # If a CSR is provided with neither of -key or -CA/-CAkey, this should fail.
 ok(!run(app(["openssl", "req", "-x509",
                 "-in", srctop_file(@certs, "x509-check.csr"),
index 8f68982a9fa1fc76642d733c58e68fcb5a779554..e0135ca206594ad5cb60dc1bfa216cf849d89a89 100644 (file)
@@ -78,3 +78,6 @@ C  = UK
 O  = My Organization
 OU = My Unit
 CN = My Name
+
+[ reqexts ]
+keyUsage = critical,digitalSignature,keyEncipherment