From 0e89b396197f75993c8d64c07b4af6aa2d97e2af Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 26 Aug 2022 20:40:48 +0200 Subject: [PATCH] apps/x509 etc.: allow private key input when public key is expected Reviewed-by: Tomas Mraz Reviewed-by: Dmitry Belyavskiy Reviewed-by: David von Oheimb (Merged from https://github.com/openssl/openssl/pull/19076) --- apps/include/apps.h | 35 +++++++---------- apps/lib/apps.c | 65 +++++++++++++++++-------------- apps/pkeyutl.c | 4 +- apps/rsautl.c | 4 +- apps/x509.c | 16 ++++---- doc/man1/openssl-dsa.pod.in | 5 ++- doc/man1/openssl-ec.pod.in | 5 ++- doc/man1/openssl-pkey.pod.in | 3 +- doc/man1/openssl-pkeyutl.pod.in | 4 +- doc/man1/openssl-rsa.pod.in | 5 ++- doc/man1/openssl-rsautl.pod.in | 4 +- doc/man1/openssl-x509.pod.in | 25 ++++++------ test/recipes/25-test_x509.t | 17 +++++--- test/smime-certs/mksmime-certs.sh | 42 +++++++++----------- 14 files changed, 123 insertions(+), 111 deletions(-) diff --git a/apps/include/apps.h b/apps/include/apps.h index a8b63fea8d..e603d07868 100644 --- a/apps/include/apps.h +++ b/apps/include/apps.h @@ -66,8 +66,8 @@ BIO *bio_open_owner(const char *filename, int format, int private); BIO *bio_open_default(const char *filename, char mode, int format); BIO *bio_open_default_quiet(const char *filename, char mode, int format); CONF *app_load_config_bio(BIO *in, const char *filename); -#define app_load_config(filename) app_load_config_internal(filename, 0) -#define app_load_config_quiet(filename) app_load_config_internal(filename, 1) +# define app_load_config(filename) app_load_config_internal(filename, 0) +# define app_load_config_quiet(filename) app_load_config_internal(filename, 1) CONF *app_load_config_internal(const char *filename, int quiet); CONF *app_load_config_verbose(const char *filename, int verbose); int app_load_modules(const CONF *config); @@ -100,7 +100,7 @@ int progress_cb(EVP_PKEY_CTX *ctx); int chopup_args(ARGS *arg, char *buf); void dump_cert_text(BIO *out, X509 *x); void print_name(BIO *out, const char *title, const X509_NAME *nm); -void print_bignum_var(BIO *, const BIGNUM *, const char*, +void print_bignum_var(BIO *, const BIGNUM *, const char *, int, unsigned char *); void print_array(BIO *, const char *, int, const unsigned char *); int set_nameopt(const char *arg); @@ -117,13 +117,14 @@ X509_REQ *load_csr(const char *file, int format, const char *desc); X509_REQ *load_csr_autofmt(const char *infile, int format, const char *desc); X509 *load_cert_pass(const char *uri, int format, int maybe_stdin, const char *pass, const char *desc); -#define load_cert(uri, format, desc) load_cert_pass(uri, format, 1, NULL, desc) +# define load_cert(uri, format, desc) load_cert_pass(uri, format, 1, NULL, desc) X509_CRL *load_crl(const char *uri, int format, int maybe_stdin, const char *desc); void cleanse(char *str); void clear_free(char *str); EVP_PKEY *load_key(const char *uri, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *desc); +/* first try reading public key, on failure resort to loading private key */ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *desc); EVP_PKEY *load_keyparams(const char *uri, int format, int maybe_stdin, @@ -145,15 +146,11 @@ int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs, int load_crls(const char *uri, STACK_OF(X509_CRL) **crls, const char *pass, const char *desc); int load_key_certs_crls(const char *uri, int format, int maybe_stdin, - const char *pass, const char *desc, + const char *pass, const char *desc, int quiet, EVP_PKEY **ppkey, EVP_PKEY **ppubkey, EVP_PKEY **pparams, X509 **pcert, STACK_OF(X509) **pcerts, X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls); -int load_key_cert_crl(const char *uri, int format, int maybe_stdin, - const char *pass, const char *desc, - EVP_PKEY **ppkey, EVP_PKEY **ppubkey, - X509 **pcert, X509_CRL **pcrl); X509_STORE *setup_verify(const char *CAfile, int noCAfile, const char *CApath, int noCApath, const char *CAstore, int noCAstore); @@ -199,10 +196,9 @@ int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, # define DB_type 0 # define DB_exp_date 1 # define DB_rev_date 2 -# define DB_serial 3 /* index - unique */ +# define DB_serial 3 /* index - unique */ # define DB_file 4 -# define DB_name 5 /* index - unique when active and not - * disabled */ +# define DB_name 5 /* index - unique when active and not disabled */ # define DB_NUMBER 6 # define DB_TYPE_REV 'R' /* Revoked */ @@ -243,8 +239,8 @@ int rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix); void free_index(CA_DB *db); # define index_name_cmp_noconst(a, b) \ - index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ - (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) + index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ + (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b); int parse_yesno(const char *str, int def); @@ -271,12 +267,11 @@ int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const char *md, extern char *psk_key; - unsigned char *next_protos_parse(size_t *outlen, const char *in); int check_cert_attributes(BIO *bio, X509 *x, - const char *checkhost, - const char *checkemail, const char *checkip, int print); + const char *checkhost, const char *checkemail, + const char *checkip, int print); void store_setup_crl_download(X509_STORE *st); @@ -310,16 +305,16 @@ ASN1_VALUE *app_http_post_asn1(const char *host, const char *port, # define EXT_COPY_ADD 1 # define EXT_COPY_ALL 2 -# define NETSCAPE_CERT_HDR "certificate" +# define NETSCAPE_CERT_HDR "certificate" -# define APP_PASS_LEN 1024 +# define APP_PASS_LEN 1024 /* * IETF RFC 5280 says serial number must be <= 20 bytes. Use 159 bits * so that the first bit will never be one, so that the DER encoding * rules won't force a leading octet. */ -# define SERIAL_RAND_BITS 159 +# define SERIAL_RAND_BITS 159 int app_isdir(const char *); int app_access(const char *, int flag); diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 6b4f9e586a..69bf5b4e37 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -469,7 +469,7 @@ X509 *load_cert_pass(const char *uri, int format, int maybe_stdin, BIO_printf(bio_err, "Unable to load %s from %s\n", desc, uri); } } else { - (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, + (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 0, NULL, NULL, NULL, &cert, NULL, NULL, NULL); } return cert; @@ -491,7 +491,7 @@ X509_CRL *load_crl(const char *uri, int format, int maybe_stdin, BIO_printf(bio_err, "Unable to load %s from %s\n", desc, uri); } } else { - (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc, + (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc, 0, NULL, NULL, NULL, NULL, NULL, &crl, NULL); } return crl; @@ -582,16 +582,16 @@ EVP_PKEY *load_key(const char *uri, int format, int may_stdin, if (desc == NULL) desc = "private key"; - if (format == FORMAT_ENGINE) { + if (format == FORMAT_ENGINE) uri = allocated_uri = make_engine_uri(e, uri, desc); - } - (void)load_key_certs_crls(uri, format, may_stdin, pass, desc, + (void)load_key_certs_crls(uri, format, may_stdin, pass, desc, 0, &pkey, NULL, NULL, NULL, NULL, NULL, NULL); OPENSSL_free(allocated_uri); return pkey; } +/* first try reading public key, on failure resort to loading private key */ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *desc) { @@ -601,12 +601,13 @@ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, if (desc == NULL) desc = "public key"; - if (format == FORMAT_ENGINE) { + if (format == FORMAT_ENGINE) uri = allocated_uri = make_engine_uri(e, uri, desc); - } - (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, + (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 1, NULL, &pkey, NULL, NULL, NULL, NULL, NULL); - + if (pkey == NULL) + (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 0, + &pkey, NULL, NULL, NULL, NULL, NULL, NULL); OPENSSL_free(allocated_uri); return pkey; } @@ -616,13 +617,11 @@ EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin, int suppress_decode_errors) { EVP_PKEY *params = NULL; - BIO *bio_bak = bio_err; if (desc == NULL) desc = "key parameters"; - if (suppress_decode_errors) - bio_err = NULL; (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc, + suppress_decode_errors, NULL, NULL, ¶ms, NULL, NULL, NULL, NULL); if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) { ERR_print_errors(bio_err); @@ -632,7 +631,6 @@ EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin, EVP_PKEY_free(params); params = NULL; } - bio_err = bio_bak; return params; } @@ -725,7 +723,7 @@ int load_cert_certs(const char *uri, return ret; } pass_string = get_passwd(pass, desc); - ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass_string, desc, + ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass_string, desc, 0, NULL, NULL, NULL, pcert, pcerts, NULL, NULL); clear_free(pass_string); @@ -833,7 +831,7 @@ int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs, if (desc == NULL) desc = "certificates"; - ret = load_key_certs_crls(uri, FORMAT_UNDEF, maybe_stdin, pass, desc, + ret = load_key_certs_crls(uri, FORMAT_UNDEF, maybe_stdin, pass, desc, 0, NULL, NULL, NULL, NULL, certs, NULL, NULL); if (!ret && was_NULL) { @@ -854,7 +852,7 @@ int load_crls(const char *uri, STACK_OF(X509_CRL) **crls, if (desc == NULL) desc = "CRLs"; - ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass, desc, + ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass, desc, 0, NULL, NULL, NULL, NULL, NULL, NULL, crls); if (!ret && was_NULL) { @@ -902,8 +900,9 @@ static const char *format2string(int format) * of *pcerts and *pcrls (as far as they are not NULL). */ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, - const char *pass, const char *desc, EVP_PKEY **ppkey, - EVP_PKEY **ppubkey, EVP_PKEY **pparams, + const char *pass, const char *desc, int quiet, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + EVP_PKEY **pparams, X509 **pcert, STACK_OF(X509) **pcerts, X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls) { @@ -918,8 +917,9 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, const OSSL_PARAM *params = NULL; if (failed == NULL) { - BIO_printf(bio_err, "Internal error: nothing to load from %s\n", - uri != NULL ? uri : ""); + if (!quiet) + BIO_printf(bio_err, "Internal error: nothing to load from %s\n", + uri != NULL ? uri : ""); return 0; } ERR_set_mark(); @@ -930,7 +930,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, SET_EXPECT1(pcert, OSSL_STORE_INFO_CERT); if (pcerts != NULL) { if (*pcerts == NULL && (*pcerts = sk_X509_new_null()) == NULL) { - BIO_printf(bio_err, "Out of memory loading"); + if (!quiet) + BIO_printf(bio_err, "Out of memory loading"); goto end; } SET_EXPECT(OSSL_STORE_INFO_CERT); @@ -938,7 +939,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, SET_EXPECT1(pcrl, OSSL_STORE_INFO_CRL); if (pcrls != NULL) { if (*pcrls == NULL && (*pcrls = sk_X509_CRL_new_null()) == NULL) { - BIO_printf(bio_err, "Out of memory loading"); + if (!quiet) + BIO_printf(bio_err, "Out of memory loading"); goto end; } SET_EXPECT(OSSL_STORE_INFO_CRL); @@ -958,7 +960,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, BIO *bio; if (!maybe_stdin) { - BIO_printf(bio_err, "No filename or uri specified for loading"); + if (!quiet) + BIO_printf(bio_err, "No filename or uri specified for loading"); goto end; } uri = ""; @@ -975,7 +978,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, params, NULL, NULL); } if (ctx == NULL) { - BIO_printf(bio_err, "Could not open file or uri for loading"); + if (!quiet) + BIO_printf(bio_err, "Could not open file or uri for loading"); goto end; } if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) @@ -1057,7 +1061,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, OSSL_STORE_INFO_free(info); if (!ok) { failed = OSSL_STORE_INFO_type_string(type); - BIO_printf(bio_err, "Error reading"); + if (!quiet) + BIO_printf(bio_err, "Error reading"); break; } } @@ -1070,12 +1075,12 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, pcrls = NULL; if (failed == NULL) { failed = FAIL_NAME; - if (failed != NULL) + if (failed != NULL && !quiet) BIO_printf(bio_err, "Could not find"); - } else { + } else if (!quiet) { BIO_printf(bio_err, "Could not read"); } - if (failed != NULL) { + if (failed != NULL && !quiet) { unsigned long err = ERR_peek_last_error(); if (desc != NULL && strstr(desc, failed) != NULL) { @@ -1096,7 +1101,7 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, BIO_printf(bio_err, "\n"); ERR_print_errors(bio_err); } - if (bio_err == NULL || failed == NULL) + if (quiet || failed == NULL) /* clear any suppressed or spurious errors */ ERR_pop_to_mark(); else @@ -1373,7 +1378,7 @@ X509_STORE *setup_verify(const char *CAfile, int noCAfile, goto end; if (CAfile != NULL) { if (X509_LOOKUP_load_file_ex(lookup, CAfile, X509_FILETYPE_PEM, - libctx, propq) <= 0) { + libctx, propq) <= 0) { BIO_printf(bio_err, "Error loading file %s\n", CAfile); goto end; } diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index a11e1e7c8a..d8b2ad5f65 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -69,8 +69,8 @@ const OPTIONS pkeyutl_options[] = { OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file - default stdin"}, {"rawin", OPT_RAWIN, '-', "Indicate the input data is in raw form"}, - {"pubin", OPT_PUBIN, '-', "Input is a public key"}, - {"inkey", OPT_INKEY, 's', "Input private key file"}, + {"inkey", OPT_INKEY, 's', "Input key, by default private key"}, + {"pubin", OPT_PUBIN, '-', "Input key is a public key"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, {"peerkey", OPT_PEERKEY, 's', "Peer key file used in key derivation"}, {"peerform", OPT_PEERFORM, 'E', "Peer key format (DER/PEM/P12/ENGINE)"}, diff --git a/apps/rsautl.c b/apps/rsautl.c index 2e3aa00307..ad5df2e36a 100644 --- a/apps/rsautl.c +++ b/apps/rsautl.c @@ -47,9 +47,9 @@ const OPTIONS rsautl_options[] = { OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, - {"inkey", OPT_INKEY, 's', "Input key"}, + {"inkey", OPT_INKEY, 's', "Input key, by default an RSA private key"}, {"keyform", OPT_KEYFORM, 'E', "Private key format (ENGINE, other values ignored)"}, - {"pubin", OPT_PUBIN, '-', "Input is an RSA public"}, + {"pubin", OPT_PUBIN, '-', "Input key is an RSA public pkey"}, {"certin", OPT_CERTIN, '-', "Input is a cert carrying an RSA public key"}, {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, diff --git a/apps/x509.c b/apps/x509.c index b9087fc27a..e10afc59f6 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -87,7 +87,8 @@ const OPTIONS x509_options[] = { OPT_SECTION("Certificate printing"), {"text", OPT_TEXT, '-', "Print the certificate in text form"}, - {"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."}, + {"dateopt", OPT_DATEOPT, 's', + "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."}, {"certopt", OPT_CERTOPT, 's', "Various certificate text printing options"}, {"fingerprint", OPT_FINGERPRINT, '-', "Print the certificate fingerprint"}, {"alias", OPT_ALIAS, '-', "Print certificate alias"}, @@ -139,7 +140,7 @@ const OPTIONS x509_options[] = { "Preserve existing validity dates"}, {"subj", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, {"force_pubkey", OPT_FORCE_PUBKEY, '<', - "Place the given key in new certificate"}, + "Key to be placed in new certificate or certificate request"}, {"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"}, @@ -624,8 +625,7 @@ int x509_main(int argc, char **argv) goto err; } if (newcert && reqfile) { - BIO_printf(bio_err, - "The -req option cannot be used with -new\n"); + BIO_printf(bio_err, "The -req option cannot be used with -new\n"); goto err; } if (privkeyfile != NULL) { @@ -757,7 +757,7 @@ int x509_main(int argc, char **argv) } else { if (infile == NULL) BIO_printf(bio_err, - "Warning: Reading certificate from stdin since no -in option is given\n"); + "Warning: Reading certificate from stdin since no -in or -new option is given\n"); x = load_cert_pass(infile, informat, 1, passin, "certificate"); if (x == NULL) goto end; @@ -893,9 +893,6 @@ int x509_main(int argc, char **argv) } } noout = 1; - } else if (privkey != NULL) { - if (!do_X509_sign(x, 0, privkey, digest, sigopts, &ext_ctx)) - goto end; } else if (CAfile != NULL) { if ((CAkey = load_key(CAkeyfile, CAkeyformat, 0, passin, e, "CA private key")) == NULL) @@ -908,6 +905,9 @@ int x509_main(int argc, char **argv) if (!do_X509_sign(x, 0, CAkey, digest, sigopts, &ext_ctx)) goto end; + } else if (privkey != NULL) { + if (!do_X509_sign(x, 0, privkey, digest, sigopts, &ext_ctx)) + goto end; } if (badsig) { const ASN1_BIT_STRING *signature; diff --git a/doc/man1/openssl-dsa.pod.in b/doc/man1/openssl-dsa.pod.in index 6d15e950b9..cdcbbc206c 100644 --- a/doc/man1/openssl-dsa.pod.in +++ b/doc/man1/openssl-dsa.pod.in @@ -115,8 +115,9 @@ This option prints out the value of the public key component of the key. =item B<-pubin> -By default, a private key is read from the input file. With this option a -public key is read instead. +By default, a private key is read from the input. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =item B<-pubout> diff --git a/doc/man1/openssl-ec.pod.in b/doc/man1/openssl-ec.pod.in index f6f1e3882e..083a3f6e42 100644 --- a/doc/man1/openssl-ec.pod.in +++ b/doc/man1/openssl-ec.pod.in @@ -106,8 +106,9 @@ Print the elliptic curve parameters. =item B<-pubin> -By default, a private key is read from the input file. With this option a -public key is read instead. +By default a private key is read from the input. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =item B<-pubout> diff --git a/doc/man1/openssl-pkey.pod.in b/doc/man1/openssl-pkey.pod.in index 34d57f7d14..042862b960 100644 --- a/doc/man1/openssl-pkey.pod.in +++ b/doc/man1/openssl-pkey.pod.in @@ -89,7 +89,8 @@ see L. =item B<-pubin> By default a private key is read from the input. -With this option only the public components are read. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =back diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in index dd87829798..4b8e3fc574 100644 --- a/doc/man1/openssl-pkeyutl.pod.in +++ b/doc/man1/openssl-pkeyutl.pod.in @@ -108,7 +108,9 @@ See L for details. =item B<-pubin> -The input file is a public key. +By default a private key is read from the key input. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =item B<-certin> diff --git a/doc/man1/openssl-rsa.pod.in b/doc/man1/openssl-rsa.pod.in index 35bd300429..5d7af53d0b 100644 --- a/doc/man1/openssl-rsa.pod.in +++ b/doc/man1/openssl-rsa.pod.in @@ -121,8 +121,9 @@ This option checks the consistency of an RSA private key. =item B<-pubin> -By default a private key is read from the input file: with this -option a public key is read instead. +By default a private key is read from the input. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =item B<-pubout> diff --git a/doc/man1/openssl-rsautl.pod.in b/doc/man1/openssl-rsautl.pod.in index eab34979de..720bb220f8 100644 --- a/doc/man1/openssl-rsautl.pod.in +++ b/doc/man1/openssl-rsautl.pod.in @@ -76,7 +76,9 @@ See L for details. =item B<-pubin> -The input file is an RSA public key. +By default a private key is read from the key input. +With this option a public key is read instead. +If the input contains no public key but a private key, its public part is used. =item B<-certin> diff --git a/doc/man1/openssl-x509.pod.in b/doc/man1/openssl-x509.pod.in index 84110d24f5..8fb1917bfc 100644 --- a/doc/man1/openssl-x509.pod.in +++ b/doc/man1/openssl-x509.pod.in @@ -84,7 +84,7 @@ B B This command is a multi-purposes certificate handling command. It can be used to print certificate information, convert certificates to various forms, edit certificate trust settings, -generate certificates from scratch or from certificating requests +generate certificates from scratch or from certification requests and then self-signing them or signing them like a "micro CA". Generated certificates bear X.509 version 3. @@ -121,7 +121,8 @@ see L. =item B<-new> Generate a certificate from scratch, not using an input certificate -or certificate request. So the B<-in> option must not be used in this case. +or certificate request. +So this excludes the B<-in> and B<-req> options. Instead, the B<-subj> 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, @@ -176,9 +177,7 @@ the new certificate or certificate request, resulting in a self-signature. This option cannot be used in conjunction with the B<-CA> option. -It sets the issuer name to the subject name (i.e., makes it self-issued) -and changes the public key to the supplied value (unless overridden -by B<-force_pubkey>). +It sets the issuer name to the subject name (i.e., makes it self-issued). Unless the B<-preserve_dates> option is supplied, it sets the validity start date to the current time and the end date to a value determined by the B<-days> option. @@ -403,20 +402,22 @@ Example: C -This option can be used in conjunction with the B<-force_pubkey> option -to create a certificate even without providing an input certificate -or certificate request. +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<-force_pubkey> I -When a certificate is created set its public key to the key in I +When a new certificate or certificate request is created +set its public key to the given key 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> +to directly generate a certificate containing any desired public key. -This option is useful for creating self-issued certificates that are not +This option is also useful for creating self-issued certificates that are not self-signed, for instance when the key cannot be used for signing, such as DH. -It can also be used in conjunction with B<-new> and B<-subj> to directly -generate a certificate containing any desired public key. =item B<-clrext> diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index c843d3870a..01f5086404 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 => 32; +plan tests => 33; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -70,18 +70,25 @@ my $extfile = srctop_file("test", "v3_ca_exts.cnf"); my $pkey = srctop_file(@certs, "ca-key.pem"); # issuer private key my $pubkey = "ca-pubkey.pem"; # the corresponding issuer public key # use any (different) key for signing our self-issued cert: -my $signkey = srctop_file(@certs, "serverkey.pem"); +my $key = srctop_file(@certs, "serverkey.pem"); my $selfout = "self-issued.out"; my $testcert = srctop_file(@certs, "ee-cert.pem"); ok(run(app(["openssl", "pkey", "-in", $pkey, "-pubout", "-out", $pubkey])) -&& run(app(["openssl", "x509", "-new", "-force_pubkey", $pubkey, - "-subj", $subj, "-extfile", $extfile, - "-signkey", $signkey, "-out", $selfout])) +&& run(app(["openssl", "x509", "-new", "-force_pubkey", $pubkey, "-subj", $subj, + "-extfile", $extfile, "-key", $key, "-out", $selfout])) && run(app(["openssl", "verify", "-no_check_time", "-trusted", $selfout, "-partial_chain", $testcert]))); # not unlinking $pubkey # not unlinking $selfout +# 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"; +ok(run(app(["openssl", "x509", "-new", "-force_pubkey", $key, "-subj", "/CN=EE", + "-extfile", $extfile, "-CA", $ca, "-CAkey", $pkey, "-out", $caout])) +&& run(app(["openssl", "verify", "-no_check_time", + "-trusted", $ca, "-partial_chain", $caout]))); + subtest 'x509 -- x.509 v1 certificate' => sub { tconversion( -type => 'x509', -prefix => 'x509v1', -in => srctop_file("test", "testx509.pem") ); diff --git a/test/smime-certs/mksmime-certs.sh b/test/smime-certs/mksmime-certs.sh index 6396f6f704..160fcbfb4f 100644 --- a/test/smime-certs/mksmime-certs.sh +++ b/test/smime-certs/mksmime-certs.sh @@ -6,11 +6,17 @@ # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html -# Utility to recreate S/MIME certificates +# Utility to recreate S/MIME certificates in this directory. +# Invoke when changes are need from within this directory. OPENSSL=../../apps/openssl -OPENSSL_CONF=./ca.cnf -export OPENSSL_CONF +CONF=ca.cnf +export OPENSSL_CONF=./$CONF + +gen() { + $OPENSSL x509 -CA smroot.pem -new -days 36524 -force_pubkey $1 -subj "$2" \ + -extfile $CONF -extensions $3 +} # Root CA: create certificate directly CN="Test S/MIME RSA Root" $OPENSSL req -config ca.cnf -x509 -noenc \ @@ -18,35 +24,27 @@ CN="Test S/MIME RSA Root" $OPENSSL req -config ca.cnf -x509 -noenc \ # EE RSA certificates with respective extensions cp ../certs/ee-key.pem smrsa1.pem -$OPENSSL x509 -new -key smrsa1.pem -subj "/CN=Test SMIME EE RSA #1" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions usr_rsa_cert >>smrsa1.pem +gen smrsa1.pem "/CN=Test SMIME EE RSA #1" usr_rsa_cert >>smrsa1.pem cp ../certs/ee-key-3072.pem smrsa2.pem -$OPENSSL x509 -new -key smrsa2.pem -subj "/CN=Test SMIME EE RSA #2" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions usr_rsa_cert >>smrsa2.pem +gen smrsa2.pem "/CN=Test SMIME EE RSA #2" usr_rsa_cert >>smrsa2.pem cp ../certs/ee-key-4096.pem smrsa3.pem -$OPENSSL x509 -new -key smrsa3.pem -subj "/CN=Test SMIME EE RSA #3" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions usr_rsa_cert >>smrsa3.pem +gen smrsa3.pem "/CN=Test SMIME EE RSA #3" usr_rsa_cert >>smrsa3.pem # Create DSA certificates with respective extensions cp ../certs/server-dsa-key.pem smdsa1.pem -$OPENSSL x509 -new -key smdsa1.pem -subj "/CN=Test SMIME EE DSA #1" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions signer_cert >>smdsa1.pem +gen smdsa1.pem "/CN=Test SMIME EE DSA #1" signer_cert >>smdsa1.pem cp ../certs/server-dsa-key.pem smdsa2.pem -$OPENSSL x509 -new -key smdsa2.pem -subj "/CN=Test SMIME EE DSA #1" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions signer_cert >>smdsa2.pem +gen smdsa2.pem "/CN=Test SMIME EE DSA #1" signer_cert >>smdsa2.pem cp ../certs/server-dsa-key.pem smdsa3.pem -$OPENSSL x509 -new -key smdsa3.pem -subj "/CN=Test SMIME EE DSA #1" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions signer_cert >>smdsa3.pem +gen smdsa3.pem "/CN=Test SMIME EE DSA #1" signer_cert >>smdsa3.pem # Create EC certificates with respective extensions cp ../certs/ee-ecdsa-key.pem smec1.pem -$OPENSSL x509 -new -key smec1.pem -subj "/CN=Test SMIME EE EC #1" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions signer_cert >>smec1.pem +gen smec1.pem "/CN=Test SMIME EE EC #1" signer_cert >>smec1.pem cp ../certs/server-ecdsa-key.pem smec2.pem -$OPENSSL x509 -new -key smec2.pem -subj "/CN=Test SMIME EE EC #2" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions signer_cert >>smec2.pem +gen smec2.pem "/CN=Test SMIME EE EC #2" signer_cert >>smec2.pem # Do not renew this cert as it is used for legacy data decrypt test #$OPENSSL ecparam -out ecp.pem -name P-256 @@ -61,10 +59,8 @@ $OPENSSL genpkey -genparam -algorithm DHX -out dhp.pem $OPENSSL genpkey -paramfile dhp.pem -out smdh.pem rm dhp.pem # Create X9.42 DH certificate with respective extensions -$OPENSSL x509 -new -key smdh.pem -subj "/CN=Test SMIME EE DH" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions dh_cert >>smdh.pem +gen smdh.pem "/CN=Test SMIME EE DH" dh_cert >>smdh.pem # EE RSA code signing end entity certificate with respective extensions cp ../certs/ee-key.pem csrsa1.pem -$OPENSSL x509 -new -key csrsa1.pem -subj "/CN=Test CodeSign EE RSA" -days 36524 \ - -CA smroot.pem -extfile ca.cnf -extensions codesign_cert >>csrsa1.pem +gen csrsa1.pem "/CN=Test CodeSign EE RSA" codesign_cert >>csrsa1.pem -- 2.39.2