I submitted this earlier, but I forgot to tweak the docs. The docs were missing the -keyform option, and they needed the behavior change documented.
I also fixed a typo in the patch. The following was missing an 'else if': if(keyformat == FORMAT_PEM) { next_format = FORMAT_PEMRSA; } else if(keyformat == FORMAT_ASN1) { next_format = FORMAT_ASN1RSA; } else { next_format = -1; } Attached is the updated patch. If the patch is rejected, you might consider taking the documentation updates (sans the behavioral changes). On Sat, May 30, 2015 at 6:17 PM, Jeffrey Walton <noloa...@gmail.com> wrote: > apps.c has a couple of parsing routines called load_pubkey and > load_key. rsautl uses those routines. > > However, there's no option in rsautil to use anything other than a > ASN.1/DER or PEM encoded traditional key (or subject public key info). > The code paths are present, we just can't seem to get to them. > > ...
diff --git a/apps/apps.c b/apps/apps.c index 60f71c3..f80767a 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -763,7 +763,7 @@ X509_CRL *load_crl(const char *infile, int format) } EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) + const char *pass, ENGINE *e, const char *key_descrip, int last_try) { BIO *key = NULL; EVP_PKEY *pkey = NULL; @@ -773,7 +773,7 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, cb_data.prompt_info = file; if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); + if(last_try) { BIO_printf(bio_err, "no keyfile specified\n"); } goto end; } #ifndef OPENSSL_NO_ENGINE @@ -827,7 +827,7 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, } end: BIO_free(key); - if (pkey == NULL) { + if (pkey == NULL && last_try) { BIO_printf(bio_err, "unable to load %s\n", key_descrip); ERR_print_errors(bio_err); } @@ -842,7 +842,7 @@ static const char *key_file_format(int format) } EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) + const char *pass, ENGINE *e, const char *key_descrip, int last_try) { BIO *key = NULL; EVP_PKEY *pkey = NULL; @@ -852,7 +852,7 @@ EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, cb_data.prompt_info = file; if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); + if(last_try) { BIO_printf(bio_err, "no keyfile specified\n"); } goto end; } #ifndef OPENSSL_NO_ENGINE @@ -914,8 +914,9 @@ EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, #endif end: BIO_free(key); - if (pkey == NULL) + if (pkey == NULL && last_try) { BIO_printf(bio_err, "unable to load %s\n", key_descrip); + } return (pkey); } diff --git a/apps/apps.h b/apps/apps.h index a8652a1..0cd563a 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -427,9 +427,9 @@ X509 *load_cert(const char *file, int format, X509_CRL *load_crl(const char *infile, int format); int load_cert_crl_http(const char *url, X509 **pcert, X509_CRL **pcrl); EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip); + const char *pass, ENGINE *e, const char *key_descrip, int last_try); EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip); + const char *pass, ENGINE *e, const char *key_descrip, int last_try); STACK_OF(X509) *load_certs(const char *file, int format, const char *pass, ENGINE *e, const char *cert_descrip); diff --git a/apps/ca.c b/apps/ca.c index 4dc9176..8c03efd 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -587,7 +587,7 @@ end_of_options: goto end; } } - pkey = load_key(keyfile, keyformat, 0, key, e, "CA private key"); + pkey = load_key(keyfile, keyformat, 0, key, e, "CA private key", 1 /*last_try*/); if (key) OPENSSL_cleanse(key, strlen(key)); if (pkey == NULL) { diff --git a/apps/cms.c b/apps/cms.c index 7ccca5b..5966873 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -762,7 +762,7 @@ int cms_main(int argc, char **argv) keyfile = NULL; if (keyfile) { - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key file", 1 /*last_try*/); if (!key) goto end; } @@ -966,7 +966,7 @@ int cms_main(int argc, char **argv) e, "signer certificate"); if (!signer) goto end; - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key file", 1 /*last_try*/); if (!key) goto end; for (kparam = key_first; kparam; kparam = kparam->next) { diff --git a/apps/crl.c b/apps/crl.c index 17391e2..cc82ac2 100644 --- a/apps/crl.c +++ b/apps/crl.c @@ -266,7 +266,7 @@ int crl_main(int argc, char **argv) newcrl = load_crl(crldiff, informat); if (!newcrl) goto end; - pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key"); + pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key", 1 /*last_try*/); if (!pkey) { X509_CRL_free(newcrl); goto end; diff --git a/apps/dgst.c b/apps/dgst.c index 308555c..03f0f3f 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -286,9 +286,9 @@ int dgst_main(int argc, char **argv) if (keyfile) { if (want_pub) - sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file"); + sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file", 1 /*last_try*/); else - sigkey = load_key(keyfile, keyform, 0, passin, e, "key file"); + sigkey = load_key(keyfile, keyform, 0, passin, e, "key file", 1 /*last_try*/); if (!sigkey) { /* * load_[pub]key() has already printed an appropriate message diff --git a/apps/dsa.c b/apps/dsa.c index f02f293..34d8e0b 100644 --- a/apps/dsa.c +++ b/apps/dsa.c @@ -204,9 +204,9 @@ int dsa_main(int argc, char **argv) EVP_PKEY *pkey; if (pubin) - pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); + pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key", 1 /*last_try*/); else - pkey = load_key(infile, informat, 1, passin, e, "Private Key"); + pkey = load_key(infile, informat, 1, passin, e, "Private Key", 1 /*last_try*/); if (pkey) { dsa = EVP_PKEY_get1_DSA(pkey); diff --git a/apps/ocsp.c b/apps/ocsp.c index 4c3aa39..944b14c 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -528,7 +528,7 @@ int ocsp_main(int argc, char **argv) goto end; } rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL, - "responder private key"); + "responder private key", 1 /*last_try*/); if (!rkey) goto end; } @@ -573,7 +573,7 @@ int ocsp_main(int argc, char **argv) goto end; } key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL, - "signer private key"); + "signer private key", 1 /*last_try*/); if (!key) goto end; diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 82131e8..b603794 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -386,7 +386,7 @@ int pkcs12_main(int argc, char **argv) if (!(options & NOKEYS)) { key = load_key(keyname ? keyname : infile, - FORMAT_PEM, 1, passin, e, "private key"); + FORMAT_PEM, 1, passin, e, "private key", 1 /*last_try*/); if (!key) goto export_end; } diff --git a/apps/pkcs8.c b/apps/pkcs8.c index f8a340e..ddc2062 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c @@ -236,7 +236,7 @@ int pkcs8_main(int argc, char **argv) if (out == NULL) goto end; if (topk8) { - pkey = load_key(infile, informat, 1, passin, e, "key"); + pkey = load_key(infile, informat, 1, passin, e, "key", 1 /*last_try*/); if (!pkey) goto end; if ((p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken)) == NULL) { diff --git a/apps/pkey.c b/apps/pkey.c index 875087f..cde83ec 100644 --- a/apps/pkey.c +++ b/apps/pkey.c @@ -173,9 +173,9 @@ int pkey_main(int argc, char **argv) goto end; if (pubin) - pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); + pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key", 1 /*last_try*/); else - pkey = load_key(infile, informat, 1, passin, e, "key"); + pkey = load_key(infile, informat, 1, passin, e, "key", 1 /*last_try*/); if (!pkey) goto end; diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index 4c267c1..d6c7e19 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -352,11 +352,11 @@ static EVP_PKEY_CTX *init_ctx(int *pkeysize, } switch (key_type) { case KEY_PRIVKEY: - pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); + pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key", 1 /*last_try*/); break; case KEY_PUBKEY: - pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key"); + pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key", 1 /*last_try*/); break; case KEY_CERT: @@ -427,7 +427,7 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file) return 0; } - peer = load_pubkey(file, peerform, 0, NULL, NULL, "Peer Key"); + peer = load_pubkey(file, peerform, 0, NULL, NULL, "Peer Key", 1 /*last_try*/); if (!peer) { BIO_printf(bio_err, "Error reading peer key %s\n", file); diff --git a/apps/req.c b/apps/req.c index 3bae59e..dd3c629 100644 --- a/apps/req.c +++ b/apps/req.c @@ -481,7 +481,7 @@ int req_main(int argc, char **argv) } if (keyfile != NULL) { - pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); + pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key", 1 /*last_try*/); if (!pkey) { /* load_key() has already printed an appropriate message */ goto end; diff --git a/apps/rsa.c b/apps/rsa.c index 87cb702..dae59f2 100644 --- a/apps/rsa.c +++ b/apps/rsa.c @@ -275,9 +275,9 @@ int rsa_main(int argc, char **argv) } else tmpformat = informat; - pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key"); + pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key", 1 /*last_try*/); } else - pkey = load_key(infile, informat, 1, passin, e, "Private Key"); + pkey = load_key(infile, informat, 1, passin, e, "Private Key", 1 /*last_try*/); if (pkey != NULL) rsa = EVP_PKEY_get1_RSA(pkey); diff --git a/apps/rsautl.c b/apps/rsautl.c index 8ba838b..4d029be 100644 --- a/apps/rsautl.c +++ b/apps/rsautl.c @@ -120,7 +120,7 @@ int rsautl_main(int argc, char **argv) char *passinarg = NULL, *passin = NULL, *prog; char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY; unsigned char *rsa_in = NULL, *rsa_out = NULL, pad = RSA_PKCS1_PADDING; - int rsa_inlen, keyformat = FORMAT_PEM, keysize, ret = 1; + int rsa_inlen, keyformat = FORMAT_PEM, next_format, keysize, ret = 1; int rsa_outlen = 0, hexdump = 0, asn1parse = 0, need_priv = 0, rev = 0; OPTION_CHOICE o; @@ -217,16 +217,30 @@ int rsautl_main(int argc, char **argv) if (!app_load_modules(NULL)) goto end; -/* FIXME: seed PRNG only if needed */ + /* FIXME: seed PRNG only if needed */ app_RAND_load_file(NULL, 0); + + /* rsautl does not offer a way to specify just a public key. It requires a */ + /* subjectPublicKeyInfo, and there's no argument or option to switch to */ + /* the a non-traditional key in either ASN.1/DER or PEM format. This */ + /* attempts to make an intelligent retry. */ + if(keyformat == FORMAT_PEM) { + next_format = FORMAT_PEMRSA; + } else if(keyformat == FORMAT_ASN1) { + next_format = FORMAT_ASN1RSA; + } else { + next_format = -1; + } switch (key_type) { case KEY_PRIVKEY: - pkey = load_key(keyfile, keyformat, 0, passin, e, "Private Key"); + pkey = load_key(keyfile, keyformat, 0, passin, e, "Private Key", 0 /*last_try*/); + if(!pkey && next_format != -1) { pkey = load_key(keyfile, next_format, 0, passin, e, "Private Key", 1 /*last_try*/); } break; case KEY_PUBKEY: - pkey = load_pubkey(keyfile, keyformat, 0, NULL, e, "Public Key"); + pkey = load_pubkey(keyfile, keyformat, 0, NULL, e, "Public Key", 0 /*last_try*/); + if(!pkey && next_format != -1) { pkey = load_pubkey(keyfile, next_format, 0, NULL, e, "Public Key", 1 /*last_try*/); } break; case KEY_CERT: diff --git a/apps/s_cb.c b/apps/s_cb.c index 35366c5..10e6c0a 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -1050,10 +1050,10 @@ int load_excert(SSL_EXCERT **pexc) return 0; if (exc->keyfile) { exc->key = load_key(exc->keyfile, exc->keyform, - 0, NULL, NULL, "Server Key"); + 0, NULL, NULL, "Server Key", 1 /*last_try*/); } else { exc->key = load_key(exc->certfile, exc->certform, - 0, NULL, NULL, "Server Key"); + 0, NULL, NULL, "Server Key", 1 /*last_try*/); } if (!exc->key) return 0; diff --git a/apps/s_client.c b/apps/s_client.c index 009e5fe..85a9e39 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1112,7 +1112,7 @@ int s_client_main(int argc, char **argv) if (key_file) { key = load_key(key_file, key_format, 0, pass, e, - "client certificate private key file"); + "client certificate private key file", 1 /*last_try*/); if (key == NULL) { ERR_print_errors(bio_err); goto end; diff --git a/apps/s_server.c b/apps/s_server.c index 189019d..3469add 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1452,7 +1452,7 @@ int s_server_main(int argc, char *argv[]) if (nocert == 0) { s_key = load_key(s_key_file, s_key_format, 0, pass, e, - "server certificate private key file"); + "server certificate private key file", 1 /*last_try*/); if (!s_key) { ERR_print_errors(bio_err); goto end; @@ -1474,7 +1474,7 @@ int s_server_main(int argc, char *argv[]) if (tlsextcbp.servername) { s_key2 = load_key(s_key_file2, s_key_format, 0, pass, e, - "second server certificate private key file"); + "second server certificate private key file", 1 /*last_try*/); if (!s_key2) { ERR_print_errors(bio_err); goto end; @@ -1532,7 +1532,7 @@ int s_server_main(int argc, char *argv[]) s_dkey_file = s_dcert_file; s_dkey = load_key(s_dkey_file, s_dkey_format, - 0, dpass, e, "second certificate private key file"); + 0, dpass, e, "second certificate private key file", 1 /*last_try*/); if (!s_dkey) { ERR_print_errors(bio_err); goto end; diff --git a/apps/smime.c b/apps/smime.c index 45898de..f74105f 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -491,7 +491,7 @@ int smime_main(int argc, char **argv) keyfile = NULL; if (keyfile) { - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key file", 1 /*last_try*/); if (!key) goto end; } @@ -574,7 +574,7 @@ int smime_main(int argc, char **argv) e, "signer certificate"); if (!signer) goto end; - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key file", 1 /*last_try*/); if (!key) goto end; if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags)) diff --git a/apps/spkac.c b/apps/spkac.c index d41331c..72f8b3a 100644 --- a/apps/spkac.c +++ b/apps/spkac.c @@ -163,7 +163,7 @@ int spkac_main(int argc, char **argv) if (keyfile) { pkey = load_key(strcmp(keyfile, "-") ? keyfile : NULL, - FORMAT_PEM, 1, passin, e, "private key"); + FORMAT_PEM, 1, passin, e, "private key", 1 /*last_try*/); if (!pkey) { goto end; } diff --git a/apps/x509.c b/apps/x509.c index 77a2a6b..0c7a810 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -510,7 +510,7 @@ int x509_main(int argc, char **argv) } if (fkeyfile) { - fkey = load_pubkey(fkeyfile, keyformat, 0, NULL, e, "Forced key"); + fkey = load_pubkey(fkeyfile, keyformat, 0, NULL, e, "Forced key", 1 /*last_try*/); if (fkey == NULL) goto end; } @@ -823,7 +823,7 @@ int x509_main(int argc, char **argv) BIO_printf(bio_err, "Getting Private key\n"); if (Upkey == NULL) { Upkey = load_key(keyfile, keyformat, 0, - passin, e, "Private key"); + passin, e, "Private key", 1 /*last_try*/); if (Upkey == NULL) goto end; } @@ -835,7 +835,7 @@ int x509_main(int argc, char **argv) BIO_printf(bio_err, "Getting CA Private Key\n"); if (CAkeyfile != NULL) { CApkey = load_key(CAkeyfile, CAkeyformat, - 0, passin, e, "CA Private Key"); + 0, passin, e, "CA Private Key", 1 /*last_try*/); if (CApkey == NULL) goto end; } @@ -855,7 +855,7 @@ int x509_main(int argc, char **argv) goto end; } else { pk = load_key(keyfile, keyformat, 0, - passin, e, "request key"); + passin, e, "request key", 1 /*last_try*/); if (pk == NULL) goto end; } diff --git a/doc/apps/rsautl.pod b/doc/apps/rsautl.pod index 1a498c2..5699af5 100644 --- a/doc/apps/rsautl.pod +++ b/doc/apps/rsautl.pod @@ -10,6 +10,7 @@ B<openssl> B<rsautl> [B<-in file>] [B<-out file>] [B<-inkey file>] +[B<-keyform format>] [B<-pubin>] [B<-certin>] [B<-sign>] @@ -33,17 +34,21 @@ data using the RSA algorithm. =item B<-in filename> -This specifies the input filename to read data from or standard input +the input filename to read data from or standard input if this option is not specified. =item B<-out filename> -specifies the output filename to write to or standard output by +the output filename to write to or standard output by default. =item B<-inkey file> -the input key file, by default it should be an RSA private key. +input key file, and by default it should be a RSA private key. The key can be in any supported format, including PEM and DER (ASN.1). The key should be in traditional format. + +=item B<-keyform format> + +the format of the key files, by default PEM. =item B<-pubin> @@ -55,12 +60,13 @@ the input is a certificate containing an RSA public key. =item B<-sign> -sign the input data and output the signed result. This requires -and RSA private key. +sign the input data and output the signed result. This operation requires +a RSA private key. =item B<-verify> -verify the input data and output the recovered data. +verify the input data and output the recovered data. This operation can +use either a RSA public key or private key. =item B<-encrypt> @@ -93,6 +99,14 @@ B<-verify> option. B<rsautl> because it uses the RSA algorithm directly can only be used to sign or verify small pieces of data. +Prior to OpenSSL 1.0.2c, the keys had to be in traditional format +in a supported encoding, like PEM or DER. OpenSSL 1.0.2c added an +intelligent fallback so that both traditional and non-traditional +format can be utilized without command line arguments (the command +line options were never present). Traditional format means +subjectPublicKeyInfo with an algorithm OID and public key; while +non-traditional means just a public key. + =head1 EXAMPLES Sign some data using a private key:
_______________________________________________ openssl-dev mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev