[openssl-dev] [openssl.org #3887] PATCH: rsautl and intelligent retry for Public Key parse after Traditional/Subject Public Key Info parse fails
noloader@gmail.com via RT
rt at openssl.org
Mon Jun 1 03:07:08 UTC 2015
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 <noloader at 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.
>
> ...
-------------- next part --------------
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:
More information about the openssl-dev
mailing list