apps/x509 etc.: allow private key input when public key is expected
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Fri, 26 Aug 2022 18:40:48 +0000 (20:40 +0200)
committerDr. David von Oheimb <dev@ddvo.net>
Tue, 14 Mar 2023 16:26:49 +0000 (17:26 +0100)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/19076)

14 files changed:
apps/include/apps.h
apps/lib/apps.c
apps/pkeyutl.c
apps/rsautl.c
apps/x509.c
doc/man1/openssl-dsa.pod.in
doc/man1/openssl-ec.pod.in
doc/man1/openssl-pkey.pod.in
doc/man1/openssl-pkeyutl.pod.in
doc/man1/openssl-rsa.pod.in
doc/man1/openssl-rsautl.pod.in
doc/man1/openssl-x509.pod.in
test/recipes/25-test_x509.t
test/smime-certs/mksmime-certs.sh

index a8b63fea8d445d75a06fdc8c70583961df91dbbb..e603d07868f13801a8d4c42f5b209de5d1829bf1 100644 (file)
@@ -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);
index 6b4f9e586a0fd6c40c3f8b9e207550325cde9754..69bf5b4e37b0d54f30b6bc9593bf24906041ebdd 100644 (file)
@@ -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, &params, 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 : "<stdin>");
+        if (!quiet)
+            BIO_printf(bio_err, "Internal error: nothing to load from %s\n",
+                       uri != NULL ? uri : "<stdin>");
         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 = "<stdin>";
@@ -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;
             }
index a11e1e7c8aa1de890f34c439992f5debbe17adbd..d8b2ad5f652d78767741b407207ad1e2d18c0d62 100644 (file)
@@ -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)"},
index 2e3aa003076f13b68a9818f65221c7bc78422e7f..ad5df2e36ae20e42ff42505d88cc89195e1b28e6 100644 (file)
@@ -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"},
index b9087fc27a3ee84fd21e9322cc6f8e0d44042427..e10afc59f6df13ad1b6bf64fa384bc59f354cbf3 100644 (file)
@@ -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;
index 6d15e950b935ac53a018491f0eaaa32abf7e3745..cdcbbc206c59b3ffc9a4e093a8d96fa63d4f3e7a 100644 (file)
@@ -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>
 
index f6f1e3882ed76bcbaeed860460ba5c969f032191..083a3f6e4274ab4d8515c38a61a7b64426fc05eb 100644 (file)
@@ -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>
 
index 34d57f7d14226e1cbe362d674f624e669ea753bf..042862b9602058457a6d066cc8a3fcb7876d87e9 100644 (file)
@@ -89,7 +89,8 @@ see L<openssl-passphrase-options(1)>.
 =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
 
index dd878297987220c00879426b73e9c2e87d17f5c8..4b8e3fc574a79cda3948e81ee1478573785a6bbf 100644 (file)
@@ -108,7 +108,9 @@ See L<openssl-format-options(1)> 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>
 
index 35bd300429074a70cbfcafe7b49c82adf0905aae..5d7af53d0b6102dad9b3bd37bb94616a06bd017e 100644 (file)
@@ -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>
 
index eab34979de38b2dc6cbc4fe02df53470f35d131c..720bb220f8d18a7534288453ba189e9ac5a28d05 100644 (file)
@@ -76,7 +76,9 @@ See L<openssl-format-options(1)> 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>
 
index 84110d24f56357e9e31c2fcb1470bcb7a03c8bee..8fb1917bfcd53524df98a5a4c9fe4e4a5cdbd827 100644 (file)
@@ -84,7 +84,7 @@ B<openssl> B<x509>
 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<openssl-passphrase-options(1)>.
 =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</DC=org/DC=OpenSSL/DC=users/UID=123456+CN=John Doe>
 
-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<filename>
 
-When a certificate is created set its public key to the key in I<filename>
+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>
 
index c843d3870a0949d14b61e234694bfd0ed96ebe97..01f5086404cf8723eb43e88ef160e70853d72ebb 100644 (file)
@@ -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") );
index 6396f6f70449b55fd48c8efae94c52c4a0dc9517..160fcbfb4fb9ca218ab9d050161048bac57df865 100644 (file)
@@ -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