diff --git a/CHANGES.md b/CHANGES.md index eb16a6e24e..58d06ae498 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -36,6 +36,12 @@ OpenSSL 3.3 *Neil Horman* + * Added `-set_issuer` and `-set_subject` options to `openssl x509` to + override the Issuer and Subject when creating a certificate. The `-subj` + option now is an alias for `-set_subject`. + + *Job Snijders, George Michaelson* + * OPENSSL_sk_push() and sk__push() functions now return 0 instead of -1 if called with a NULL stack argument. diff --git a/apps/x509.c b/apps/x509.c index 578af2364f..ce3fda6716 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -43,7 +43,7 @@ typedef enum OPTION_choice { OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM, OPT_CAKEYFORM, OPT_VFYOPT, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE, OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_KEY, OPT_SIGNKEY, OPT_CA, OPT_CAKEY, - OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_SUBJ, + OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_ISSU, OPT_SUBJ, OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_DATEOPT, OPT_NAMEOPT, OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL, OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH, @@ -138,7 +138,9 @@ const OPTIONS x509_options[] = { "Number of days until newly generated certificate expires - default 30"}, {"preserve_dates", OPT_PRESERVE_DATES, '-', "Preserve existing validity dates"}, - {"subj", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, + {"set_issuer", OPT_ISSU, 's', "Set or override certificate issuer"}, + {"set_subject", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, + {"subj", OPT_SUBJ, 's', "Alias for -set_subject"}, {"force_pubkey", OPT_FORCE_PUBKEY, '<', "Key to be placed in new certificate or certificate request"}, {"clrext", OPT_CLREXT, '-', @@ -262,8 +264,8 @@ int x509_main(int argc, char **argv) EVP_PKEY *privkey = NULL, *CAkey = NULL, *pubkey = NULL; EVP_PKEY *pkey; int newcert = 0; - char *subj = NULL, *digest = NULL; - X509_NAME *fsubj = NULL; + char *issu = NULL, *subj = NULL, *digest = NULL; + X509_NAME *fissu = NULL, *fsubj = NULL; const unsigned long chtype = MBSTRING_ASC; const int multirdn = 1; STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; @@ -425,6 +427,9 @@ int x509_main(int argc, char **argv) case OPT_FORCE_PUBKEY: pubkeyfile = opt_arg(); break; + case OPT_ISSU: + issu = opt_arg(); + break; case OPT_SUBJ: subj = opt_arg(); break; @@ -651,6 +656,9 @@ int x509_main(int argc, char **argv) goto err; } } + if (issu != NULL + && (fissu = parse_name(issu, chtype, multirdn, "issuer")) == NULL) + goto end; if (subj != NULL && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL) goto end; @@ -830,8 +838,13 @@ int x509_main(int argc, char **argv) if (reqfile || newcert || privkey != NULL || CAfile != NULL) { if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) goto end; - if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) - goto end; + if (fissu != NULL) { + if (!X509_set_issuer_name(x, fissu)) + goto end; + } else { + if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) + goto end; + } } X509V3_set_ctx(&ext_ctx, issuer_cert, x, NULL, NULL, X509V3_CTX_REPLACE); @@ -1079,6 +1092,7 @@ int x509_main(int argc, char **argv) NCONF_free(extconf); BIO_free_all(out); X509_STORE_free(ctx); + X509_NAME_free(fissu); X509_NAME_free(fsubj); X509_REQ_free(req); X509_free(x); diff --git a/doc/man1/openssl-x509.pod.in b/doc/man1/openssl-x509.pod.in index 2d7a1b859a..3a5bd25d56 100644 --- a/doc/man1/openssl-x509.pod.in +++ b/doc/man1/openssl-x509.pod.in @@ -56,6 +56,8 @@ B B [B<-next_serial>] [B<-days> I] [B<-preserve_dates>] +[B<-set_issuer> I] +[B<-set_subject> I] [B<-subj> I] [B<-force_pubkey> I] [B<-clrext>] @@ -123,7 +125,7 @@ see L. Generate a certificate from scratch, not using an input certificate or certificate request. So this excludes the B<-in> and B<-req> options. -Instead, the B<-subj> option needs to be given. +Instead, the B<-set_subject> option needs to be given. The public key to include can be given with the B<-force_pubkey> option and defaults to the key given with the B<-key> (or B<-signkey>) option, which implies self-signature. @@ -386,10 +388,17 @@ When signing a certificate, preserve "notBefore" and "notAfter" dates of any input certificate instead of adjusting them to current time and duration. Cannot be used together with the B<-days> option. -=item B<-subj> I +=item B<-set_issuer> I + +When a certificate is created set its issuer name to the given value. + +See B<-set_subject> on how the arg must be formatted. + +=item B<-set_subject> I When a certificate is created set its subject name to the given value. -When the certificate is self-signed the issuer name is set to the same value. +When the certificate is self-signed the issuer name is set to the same value, +unless the B<-set_issuer> option is given. The arg must be formatted as C. Special characters may be escaped by C<\> (backslash), whitespace is retained. @@ -405,6 +414,10 @@ C This option can be used with the B<-new> and B<-force_pubkey> options to create a new certificate without providing an input certificate or certificate request. +=item B<-subj> I + +This option is an alias of B<-set_subject>. + =item B<-force_pubkey> I When a new certificate or certificate request is created @@ -413,7 +426,7 @@ instead of the key contained in the input or given with the B<-key> (or B<-signkey>) option. If the input contains no public key but a private key, its public part is used. -This option can be used in conjunction with b<-new> and B<-subj> +This option can be used in conjunction with b<-new> and B<-set_subject> to directly generate a certificate containing any desired public key. This option is also useful for creating self-issued certificates that are not diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 9b11169a98..eeb8083506 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 44; +plan tests => 46; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -81,6 +81,15 @@ ok(run(app(["openssl", "pkey", "-in", $pkey, "-pubout", "-out", $pubkey])) # not unlinking $pubkey # not unlinking $selfout +# test -set_issuer option +my $ca_issu = srctop_file(@certs, "ca-cert.pem"); # issuer cert +my $caout_issu = "ca-issu.out"; +ok(run(app(["openssl", "x509", "-new", "-force_pubkey", $key, "-subj", "/CN=EE", + "-set_issuer", "/CN=TEST-CA", "-extfile", $extfile, "-CA", $ca_issu, + "-CAkey", $pkey, "-text", "-out", $caout_issu]))); +ok(get_issuer($caout_issu) =~ /CN=TEST-CA/); +# not unlinking $caout + # simple way of directly producing a CA-signed cert with private/pubkey input my $ca = srctop_file(@certs, "ca-cert.pem"); # issuer cert my $caout = "ca-issued.out";