Add apps/x509 -set_issuer & -set_subject option to override issuer & subject

This changeset adds the counterpart to the '-subj' option to allow overriding
the Issuer. For consistency, the `-subj` option is aliased to `-set_subject`.

The issuer can be specified as following apps/openssl x509 -new -set_issuer
'/CN=example-nro-ta' -subj '/CN=2a7dd1d787d793e4c8af56e197d4eed92af6ba13' ...

This is useful in constructing specific test-cases or rechaining PKI trees

Joint work with George Michaelson (@geeohgeegeeoh)

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23257)
This commit is contained in:
Job Snijders 2024-01-10 17:15:52 +00:00 committed by Tomas Mraz
parent df04e81794
commit 4e5bf93313
4 changed files with 53 additions and 11 deletions

View File

@ -36,6 +36,12 @@ OpenSSL 3.3
*Neil Horman* *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_<TYPE>_push() functions now return 0 instead of -1 * OPENSSL_sk_push() and sk_<TYPE>_push() functions now return 0 instead of -1
if called with a NULL stack argument. if called with a NULL stack argument.

View File

@ -43,7 +43,7 @@ typedef enum OPTION_choice {
OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM, OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM,
OPT_CAKEYFORM, OPT_VFYOPT, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE, 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_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_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_DATEOPT, OPT_NAMEOPT,
OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL, OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL,
OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH, 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"}, "Number of days until newly generated certificate expires - default 30"},
{"preserve_dates", OPT_PRESERVE_DATES, '-', {"preserve_dates", OPT_PRESERVE_DATES, '-',
"Preserve existing validity 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, '<', {"force_pubkey", OPT_FORCE_PUBKEY, '<',
"Key to be placed in new certificate or certificate request"}, "Key to be placed in new certificate or certificate request"},
{"clrext", OPT_CLREXT, '-', {"clrext", OPT_CLREXT, '-',
@ -262,8 +264,8 @@ int x509_main(int argc, char **argv)
EVP_PKEY *privkey = NULL, *CAkey = NULL, *pubkey = NULL; EVP_PKEY *privkey = NULL, *CAkey = NULL, *pubkey = NULL;
EVP_PKEY *pkey; EVP_PKEY *pkey;
int newcert = 0; int newcert = 0;
char *subj = NULL, *digest = NULL; char *issu = NULL, *subj = NULL, *digest = NULL;
X509_NAME *fsubj = NULL; X509_NAME *fissu = NULL, *fsubj = NULL;
const unsigned long chtype = MBSTRING_ASC; const unsigned long chtype = MBSTRING_ASC;
const int multirdn = 1; const int multirdn = 1;
STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL;
@ -425,6 +427,9 @@ int x509_main(int argc, char **argv)
case OPT_FORCE_PUBKEY: case OPT_FORCE_PUBKEY:
pubkeyfile = opt_arg(); pubkeyfile = opt_arg();
break; break;
case OPT_ISSU:
issu = opt_arg();
break;
case OPT_SUBJ: case OPT_SUBJ:
subj = opt_arg(); subj = opt_arg();
break; break;
@ -651,6 +656,9 @@ int x509_main(int argc, char **argv)
goto err; goto err;
} }
} }
if (issu != NULL
&& (fissu = parse_name(issu, chtype, multirdn, "issuer")) == NULL)
goto end;
if (subj != NULL if (subj != NULL
&& (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL) && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL)
goto end; goto end;
@ -830,8 +838,13 @@ int x509_main(int argc, char **argv)
if (reqfile || newcert || privkey != NULL || CAfile != NULL) { if (reqfile || newcert || privkey != NULL || CAfile != NULL) {
if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) if (!preserve_dates && !set_cert_times(x, NULL, NULL, days))
goto end; goto end;
if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) if (fissu != NULL) {
goto end; 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); 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); NCONF_free(extconf);
BIO_free_all(out); BIO_free_all(out);
X509_STORE_free(ctx); X509_STORE_free(ctx);
X509_NAME_free(fissu);
X509_NAME_free(fsubj); X509_NAME_free(fsubj);
X509_REQ_free(req); X509_REQ_free(req);
X509_free(x); X509_free(x);

View File

@ -56,6 +56,8 @@ B<openssl> B<x509>
[B<-next_serial>] [B<-next_serial>]
[B<-days> I<arg>] [B<-days> I<arg>]
[B<-preserve_dates>] [B<-preserve_dates>]
[B<-set_issuer> I<arg>]
[B<-set_subject> I<arg>]
[B<-subj> I<arg>] [B<-subj> I<arg>]
[B<-force_pubkey> I<filename>] [B<-force_pubkey> I<filename>]
[B<-clrext>] [B<-clrext>]
@ -123,7 +125,7 @@ see L<openssl-passphrase-options(1)>.
Generate a certificate from scratch, not using an input certificate Generate a certificate from scratch, not using an input certificate
or certificate request. or certificate request.
So this excludes the B<-in> and B<-req> options. 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 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, and defaults to the key given with the B<-key> (or B<-signkey>) option,
which implies self-signature. 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. input certificate instead of adjusting them to current time and duration.
Cannot be used together with the B<-days> option. Cannot be used together with the B<-days> option.
=item B<-subj> I<arg> =item B<-set_issuer> I<arg>
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<arg>
When a certificate is created set its subject name to the given value. 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</type0=value0/type1=value1/type2=...>. The arg must be formatted as C</type0=value0/type1=value1/type2=...>.
Special characters may be escaped by C<\> (backslash), whitespace is retained. Special characters may be escaped by C<\> (backslash), whitespace is retained.
@ -405,6 +414,10 @@ C</DC=org/DC=OpenSSL/DC=users/UID=123456+CN=John Doe>
This option can be used with the B<-new> and B<-force_pubkey> options to create 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. a new certificate without providing an input certificate or certificate request.
=item B<-subj> I<arg>
This option is an alias of B<-set_subject>.
=item B<-force_pubkey> I<filename> =item B<-force_pubkey> I<filename>
When a new certificate or certificate request is created 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. 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. 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. to directly generate a certificate containing any desired public key.
This option is also useful for creating self-issued certificates that are not This option is also useful for creating self-issued certificates that are not

View File

@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/;
setup("test_x509"); setup("test_x509");
plan tests => 44; plan tests => 46;
# Prevent MSys2 filename munging for arguments that look like file paths but # Prevent MSys2 filename munging for arguments that look like file paths but
# aren't # aren't
@ -81,6 +81,15 @@ ok(run(app(["openssl", "pkey", "-in", $pkey, "-pubout", "-out", $pubkey]))
# not unlinking $pubkey # not unlinking $pubkey
# not unlinking $selfout # 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 # simple way of directly producing a CA-signed cert with private/pubkey input
my $ca = srctop_file(@certs, "ca-cert.pem"); # issuer cert my $ca = srctop_file(@certs, "ca-cert.pem"); # issuer cert
my $caout = "ca-issued.out"; my $caout = "ca-issued.out";