diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2021-01-08 17:43:13 +0100 |
---|---|---|
committer | Dr. David von Oheimb <dev@ddvo.net> | 2021-01-20 15:59:22 +0100 |
commit | 05458fdb73dcca30edace5ad727a15d6d919e215 (patch) | |
tree | 481b7b5ba0e6b184d76b0ca208d96e45eb41a129 /apps | |
parent | b9fbacaa7bdce2083186211b3cdf8511ad4cb91d (diff) | |
download | openssl-05458fdb73dcca30edace5ad727a15d6d919e215.tar.gz |
apps/x509.c: Make -x509toreq respect -clrext, -sigopt, and -extfile options
Also prevent copying SKID and AKID extension, which make no sense in CSRs
and extend the use -ext to select with extensions are copied.
Further simplifiy the overall structure of the code.
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13711)
Diffstat (limited to 'apps')
-rw-r--r-- | apps/lib/apps.c | 5 | ||||
-rw-r--r-- | apps/x509.c | 247 |
2 files changed, 125 insertions, 127 deletions
diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 6a8ee415f9..30d026bdef 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -989,10 +989,7 @@ int copy_extensions(X509 *x, X509_REQ *req, int copy_type) continue; /* Delete all extensions of same type */ do { - X509_EXTENSION *tmpext = X509_get_ext(x, idx); - - X509_delete_ext(x, idx); - X509_EXTENSION_free(tmpext); + X509_EXTENSION_free(X509_delete_ext(x, idx)); idx = X509_get_ext_by_OBJ(x, obj, -1); } while (idx != -1); } diff --git a/apps/x509.c b/apps/x509.c index 6b2e5cfe28..7ffcc121af 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -33,18 +33,8 @@ #define EXT_COPY_UNSET -1 static int callb(int ok, X509_STORE_CTX *ctx); -static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer, - STACK_OF(OPENSSL_STRING) *sigopts, - int days, int clrext, - const EVP_MD *digest, CONF *conf, const char *section, - int preserve_dates); -static int x509_certify(X509_STORE *ctx, const char *CAfile, - const EVP_MD *digest, - X509 *x, X509 *xca, EVP_PKEY *pkey, - STACK_OF(OPENSSL_STRING) *sigopts, - const char *serialfile, int create, - int days, int clrext, CONF *conf, const char *section, - ASN1_INTEGER *sno, int preserve_dates); +static ASN1_INTEGER *x509_load_serial(const char *CAfile, + const char *serialfile, int create); static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt); static int print_x509v3_exts(BIO *bio, X509 *x, const char *ext_names); @@ -118,7 +108,8 @@ const OPTIONS x509_options[] = { {"issuer_hash_old", OPT_ISSUER_HASH_OLD, '-', "Print old-style (MD5) issuer hash value"}, #endif - {"ext", OPT_EXT, 's', "Print the specified X509V3 extensions"}, + {"ext", OPT_EXT, 's', + "Restrict which X.509 extensions to print and/or copy"}, {"ocspid", OPT_OCSPID, '-', "Print OCSP hash values for the subject name and public key"}, {"ocsp_uri", OPT_OCSP_URI, '-', "Print OCSP Responder URL(s)"}, @@ -146,11 +137,12 @@ const OPTIONS x509_options[] = { {"subj", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, {"force_pubkey", OPT_FORCE_PUBKEY, '<', "Place the given key in new certificate"}, - {"clrext", OPT_CLREXT, '-', "Clear all extensions when producing a certificate "}, + {"clrext", OPT_CLREXT, '-', + "Do not take over any extensions from the source certificate or request"}, {"extfile", OPT_EXTFILE, '<', "Config file with X509V3 extensions to add"}, {"extensions", OPT_EXTENSIONS, 's', "Section of extfile to use - default: unnamed section"}, - {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter, in n:v form"}, {"badsig", OPT_BADSIG, '-', "Corrupt last byte of certificate signature (for test)"}, {"", OPT_MD, '-', "Any supported digest, used for signing and printing"}, @@ -185,6 +177,65 @@ const OPTIONS x509_options[] = { {NULL} }; +static void warn_copying(ASN1_OBJECT *excluded, const char *names) +{ + const char *sn = OBJ_nid2sn(OBJ_obj2nid(excluded)); + + if (names != NULL && strstr(names, sn) != NULL) + BIO_printf(bio_err, + "Warning: -ext should not specify copying %s extension to CSR; ignoring this\n", + sn); +} + +static X509_REQ *x509_to_req(X509 *cert, EVP_PKEY *pkey, const EVP_MD *digest, + STACK_OF(OPENSSL_STRING) *sigopts, + int ext_copy, const char *names) +{ + const STACK_OF(X509_EXTENSION) *cert_exts = X509_get0_extensions(cert); + int i, n = sk_X509_EXTENSION_num(cert_exts /* may be NULL */); + ASN1_OBJECT *skid = OBJ_nid2obj(NID_subject_key_identifier); + ASN1_OBJECT *akid = OBJ_nid2obj(NID_authority_key_identifier); + STACK_OF(X509_EXTENSION) *exts; + X509_REQ *req = X509_to_X509_REQ(cert, NULL, NULL); + + if (req == NULL) + return NULL; + + /* + * Filter out SKID and AKID extensions, which make no sense in a CSR. + * If names is not NULL, copy only those extensions listed there. + */ + warn_copying(skid, names); + warn_copying(akid, names); + if ((exts = sk_X509_EXTENSION_new_reserve(NULL, n)) == NULL) + goto err; + for (i = 0; i < n; i++) { + X509_EXTENSION *ex = sk_X509_EXTENSION_value(cert_exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + + if (OBJ_cmp(obj, skid) != 0 && OBJ_cmp(obj, akid) != 0 + && !sk_X509_EXTENSION_push(exts, ex)) + goto err; + } + + if (sk_X509_EXTENSION_num(exts) > 0) { + if (ext_copy != EXT_COPY_UNSET && ext_copy != EXT_COPY_NONE + && !X509_REQ_add_extensions(req, exts)) { + BIO_printf(bio_err, "Error copying extensions from certificate\n"); + goto err; + } + } + if (!do_X509_REQ_sign(req, pkey, digest, sigopts)) + goto err; + sk_X509_EXTENSION_free(exts); + return req; + + err: + sk_X509_EXTENSION_free(exts); + X509_REQ_free(req); + return NULL; +} + int x509_main(int argc, char **argv) { ASN1_INTEGER *sno = NULL; @@ -192,6 +243,7 @@ int x509_main(int argc, char **argv) BIO *out = NULL; CONF *extconf = NULL; int ext_copy = EXT_COPY_UNSET; + X509V3_CTX ext_ctx; EVP_PKEY *signkey = NULL, *CAkey = NULL, *pubkey = NULL; int newcert = 0; char *subj = NULL; @@ -200,7 +252,7 @@ int x509_main(int argc, char **argv) const int multirdn = 1; STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; STACK_OF(OPENSSL_STRING) *sigopts = NULL, *vfyopts = NULL; - X509 *x = NULL, *xca = NULL; + X509 *x = NULL, *xca = NULL, *issuer_cert; X509_REQ *req = NULL, *rq = NULL; X509_STORE *ctx = NULL; const EVP_MD *digest = NULL; @@ -644,7 +696,7 @@ int x509_main(int argc, char **argv) print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), get_nameopt()); } else if (!x509toreq && ext_copy != EXT_COPY_UNSET) { - BIO_printf(bio_err, "Ignoring -copy_extensions since neither -x509toreq nor -req is given\n"); + BIO_printf(bio_err, "Warning: ignoring -copy_extensions since neither -x509toreq nor -req is given\n"); } if (reqfile || newcert) { @@ -663,18 +715,9 @@ int x509_main(int argc, char **argv) sno = ASN1_INTEGER_new(); if (sno == NULL || !rand_serial(NULL, sno)) goto end; - if (!X509_set_serialNumber(x, sno)) - goto end; - ASN1_INTEGER_free(sno); - sno = NULL; - } else if (!X509_set_serialNumber(x, sno)) { - goto end; } - if (req != NULL) { - if (ext_copy == EXT_COPY_UNSET) { - BIO_printf(bio_err, - "Warning: ignoring any extensions in the request since -copy_extensions is not given\n"); - } else if (clrext && ext_copy != EXT_COPY_NONE) { + if (req != NULL && ext_copy != EXT_COPY_UNSET) { + if (clrext && ext_copy != EXT_COPY_NONE) { BIO_printf(bio_err, "Must not use -clrext together with -copy_extensions\n"); goto end; } else if (!copy_extensions(x, req, ext_copy)) { @@ -735,32 +778,58 @@ int x509_main(int argc, char **argv) objtmp = NULL; } - if (x509toreq) { /* also works but makes little sense together with -req */ - const STACK_OF(X509_EXTENSION) *exts; + if (clrext && ext_names != NULL) + BIO_printf(bio_err, "Warning: Ignoring -ext since -clrext is given\n"); + for (i = X509_get_ext_count(x) - 1; i >= 0; i--) { + X509_EXTENSION *ex = X509_get_ext(x, i); + const char *sn = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ex))); + + if (clrext || (ext_names != NULL && strstr(ext_names, sn) == NULL)) + X509_EXTENSION_free(X509_delete_ext(x, i)); + } + + if ((reqfile || newcert || signkey != NULL || CAfile != NULL) + && !preserve_dates && !set_cert_times(x, NULL, NULL, days)) + goto end; + issuer_cert = x; + if (CAfile != NULL) { + issuer_cert = xca; + if (sno == NULL) + sno = x509_load_serial(CAfile, CAserial, CA_createserial); + if (sno == NULL) + goto end; + } + + if (sno != NULL && !X509_set_serialNumber(x, sno)) + goto end; + + if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) + goto end; + + X509V3_set_ctx(&ext_ctx, issuer_cert, x, req, NULL, X509V3_CTX_REPLACE); + if (extconf != NULL) { + X509V3_set_nconf(&ext_ctx, extconf); + if (!X509V3_EXT_add_nconf(extconf, &ext_ctx, extsect, x)) { + BIO_printf(bio_err, + "Error adding extensions from section %s\n", extsect); + goto end; + } + } + + /* At this point the contents of the certificate x have been finished. */ + + if (x509toreq) { /* also works in conjunction with -req */ if (signkey == NULL) { BIO_printf(bio_err, "Must specify request key using -signkey\n"); goto end; } - if (clrext) - BIO_printf(bio_err, - "Warning: the -clrext option is ignored when producing a request\n"); - - if ((rq = X509_to_X509_REQ(x, NULL, NULL)) == NULL) + if (clrext && ext_copy != EXT_COPY_NONE) { + BIO_printf(bio_err, "Must not use -clrext together with -copy_extensions\n"); goto end; - exts = X509_get0_extensions(x); - if (sk_X509_EXTENSION_num(exts /* may be NULL */) > 0) { - if (ext_copy == EXT_COPY_UNSET) { - BIO_printf(bio_err, - "Warning: ignoring extensions in the certificate since -copy_extensions is not given\n"); - } else if (ext_copy != EXT_COPY_NONE - && !X509_REQ_add_extensions(rq, exts)) { - BIO_printf(bio_err, - "Error copying extensions from certificate\n"); - goto end; - } } - if (!X509_REQ_sign(rq, signkey, digest)) + if ((rq = x509_to_req(x, signkey, digest, sigopts, + ext_copy, ext_names)) == NULL) goto end; if (!noout) { if (outformat == FORMAT_ASN1) { @@ -777,8 +846,7 @@ int x509_main(int argc, char **argv) } noout = 1; } else if (signkey != NULL) { - if (!sign(x, signkey, x /* self-issuing */, sigopts, days, clrext, - digest, extconf, extsect, preserve_dates)) + if (!do_X509_sign(x, signkey, digest, sigopts, &ext_ctx)) goto end; } else if (CAfile != NULL) { if (!reqfile && !newcert) { /* certificate should be self-signed */ @@ -799,9 +867,13 @@ int x509_main(int argc, char **argv) if ((CAkey = load_key(CAkeyfile, CAkeyformat, 0, passin, e, "CA private key")) == NULL) goto end; - if (!x509_certify(ctx, CAfile, digest, x, xca, CAkey, sigopts, - CAserial, CA_createserial, days, clrext, - extconf, extsect, sno, preserve_dates)) + if (!X509_check_private_key(xca, CAkey)) { + BIO_printf(bio_err, + "CA certificate and CA private key do not match\n"); + goto end; + } + + if (!do_X509_sign(x, CAkey, digest, sigopts, &ext_ctx)) goto end; } if (badsig) { @@ -1051,41 +1123,6 @@ static ASN1_INTEGER *x509_load_serial(const char *CAfile, return bs; } -static int x509_certify(X509_STORE *ctx, const char *CAfile, - const EVP_MD *digest, - X509 *x, X509 *xca, EVP_PKEY *pkey, - STACK_OF(OPENSSL_STRING) *sigopts, - const char *serialfile, int create, - int days, int clrext, CONF *conf, const char *section, - ASN1_INTEGER *sno, int preserve_dates) -{ - int ret = 0; - ASN1_INTEGER *bs = NULL; - - if (!X509_check_private_key(xca, pkey)) { - BIO_printf(bio_err, - "CA certificate and CA private key do not match\n"); - goto end; - } - - if (sno) - bs = sno; - else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL) - goto end; - if (!X509_set_serialNumber(x, bs)) - goto end; - - if (!sign(x, pkey, xca, sigopts, days, clrext, digest, - conf, section, preserve_dates)) - goto end; - - ret = 1; - end: - if (!sno) - ASN1_INTEGER_free(bs); - return ret; -} - static int callb(int ok, X509_STORE_CTX *ctx) { int err; @@ -1119,42 +1156,6 @@ static int callb(int ok, X509_STORE_CTX *ctx) } } -static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer, - STACK_OF(OPENSSL_STRING) *sigopts, - int days, int clrext, - const EVP_MD *digest, CONF *conf, const char *section, - int preserve_dates) -{ - X509V3_CTX ext_ctx; - - if (!X509_set_issuer_name(x, X509_get_subject_name(issuer))) - return 0; - - if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) - return 0; - - if (clrext) { - while (X509_get_ext_count(x) > 0) - X509_delete_ext(x, 0); - } - - X509V3_set_ctx(&ext_ctx, issuer, x, NULL, NULL, X509V3_CTX_REPLACE); - if (issuer == x - /* prepare the correct AKID of self-issued, possibly self-signed cert */ - && !X509V3_set_issuer_pkey(&ext_ctx, pkey)) - return 0; - - if (conf != NULL) { - X509V3_set_nconf(&ext_ctx, conf); - if (!X509V3_EXT_add_nconf(conf, &ext_ctx, section, x)) { - BIO_printf(bio_err, - "Error adding extensions from section %s\n", section); - return 0; - } - } - return do_X509_sign(x, pkey, digest, sigopts, &ext_ctx); -} - static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt) { int id, i, idret; |