Fix some of the command line password stuff. New function that can automatically determine the type of a DER encoded "traditional" format private key and change some of the d2i functions to use it instead of requiring the application to work out the key type.
diff --git a/CHANGES b/CHANGES index 4f8cd17..ec2ccfa 100644 --- a/CHANGES +++ b/CHANGES
@@ -4,6 +4,14 @@ Changes between 0.9.4 and 0.9.5 [xx XXX 1999] + *) Add a function 'd2i_AutoPrivateKey()' this will automatically decide + if a DER encoded private key is RSA or DSA traditional format. Changed + d2i_PrivateKey_bio() to use it. This is only needed for the "traditional" + format DER encoded private key. Newer code should use PKCS#8 format which + has the key type encoded in the ASN1 structure. Added DER private key + support to pkcs8 application. + [Steve Henson] + *) SSL 3/TLS 1 servers now don't request certificates when an anonymous ciphersuites has been selected (as required by the SSL 3/TLS 1 specifications). Exception: When SSL_VERIFY_FAIL_IF_NO_PEER_CERT @@ -36,7 +44,7 @@ check for an object with the same NID as the passed id. Functions can be provided to override either the default behaviour or the behaviour for a given id. SSL client, server and email already have functions - in place for compatability: they check the NID and also return "trusted" + in place for compatibility: they check the NID and also return "trusted" if the certificate is self signed. [Steve Henson]
diff --git a/apps/dsa.c b/apps/dsa.c index 94f71b5..c9b9d71 100644 --- a/apps/dsa.c +++ b/apps/dsa.c
@@ -140,7 +140,7 @@ else if (strcmp(*argv,"-envpassin") == 0) { if (--argc < 1) goto bad; - if(!(passin= getenv(*(++argv)))) + if(!(passin= getenv(*(++argv)))) { BIO_printf(bio_err, "Can't read environment variable %s\n", @@ -151,14 +151,13 @@ else if (strcmp(*argv,"-envpassout") == 0) { if (--argc < 1) goto bad; - if(!(passout= getenv(*(++argv)))) + if(!(passout= getenv(*(++argv)))) { BIO_printf(bio_err, "Can't read environment variable %s\n", *argv); badops = 1; } - argv++; } else if (strcmp(*argv,"-passout") == 0) {
diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 9070329..13aeb9b 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf
@@ -7,7 +7,9 @@ # defined. HOME = . RANDFILE = $ENV::HOME/.rnd -oid_file = $ENV::HOME/.oid + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the
diff --git a/apps/pkcs8.c b/apps/pkcs8.c index 8ac9e12..a958333 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c
@@ -57,6 +57,7 @@ */ #include <stdio.h> #include <string.h> +#include "apps.h" #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/evp.h> @@ -80,7 +81,7 @@ X509_SIG *p8; PKCS8_PRIV_KEY_INFO *p8inf; EVP_PKEY *pkey; - char pass[50]; + char pass[50], *passin = NULL, *passout = NULL; int badarg = 0; if (bio_err == NULL) bio_err = BIO_new_fp (stderr, BIO_NOCLOSE); informat=FORMAT_PEM; @@ -123,6 +124,38 @@ else if (!strcmp (*args, "-noiter")) iter = 1; else if (!strcmp (*args, "-nocrypt")) nocrypt = 1; else if (!strcmp (*args, "-nooct")) p8_broken = PKCS8_NO_OCTET; + else if (!strcmp(*args,"-passin")) + { + if (!args[1]) goto bad; + passin= *(++args); + } + else if (!strcmp(*args,"-envpassin")) + { + if (!args[1]) goto bad; + if(!(passin= getenv(*(++args)))) + { + BIO_printf(bio_err, + "Can't read environment variable %s\n", + *args); + badarg = 1; + } + } + else if (strcmp(*args,"-envpassout") == 0) + { + if (!args[1]) goto bad; + if(!(passout= getenv(*(++args)))) + { + BIO_printf(bio_err, + "Can't read environment variable %s\n", + *args); + badarg = 1; + } + } + else if (!strcmp(*args,"-passout")) + { + if (!args[1]) goto bad; + passout= *(++args); + } else if (!strcmp (*args, "-in")) { if (args[1]) { args++; @@ -138,26 +171,31 @@ } if (badarg) { - BIO_printf (bio_err, "Usage pkcs8 [options]\n"); - BIO_printf (bio_err, "where options are\n"); - BIO_printf (bio_err, "-in file input file\n"); - BIO_printf (bio_err, "-inform X input format (DER or PEM)\n"); - BIO_printf (bio_err, "-outform X output format (DER or PEM)\n"); - BIO_printf (bio_err, "-out file output file\n"); - BIO_printf (bio_err, "-topk8 output PKCS8 file\n"); - BIO_printf (bio_err, "-nooct use (broken) no octet form\n"); - BIO_printf (bio_err, "-noiter use 1 as iteration count\n"); - BIO_printf (bio_err, "-nocrypt use or expect unencrypted private key\n"); - BIO_printf (bio_err, "-v2 alg use PKCS#5 v2.0 and cipher \"alg\"\n"); - BIO_printf (bio_err, "-v1 obj use PKCS#5 v1.5 and cipher \"alg\"\n"); + bad: + BIO_printf(bio_err, "Usage pkcs8 [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-inform X input format (DER or PEM)\n"); + BIO_printf(bio_err, "-passin arg input file pass phrase\n"); + BIO_printf(bio_err, "-envpassin arg environment variable containing input file pass phrase\n"); + BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-passout arg input file pass phrase\n"); + BIO_printf(bio_err, "-envpassout arg environment variable containing input file pass phrase\n"); + BIO_printf(bio_err, "-topk8 output PKCS8 file\n"); + BIO_printf(bio_err, "-nooct use (broken) no octet form\n"); + BIO_printf(bio_err, "-noiter use 1 as iteration count\n"); + BIO_printf(bio_err, "-nocrypt use or expect unencrypted private key\n"); + BIO_printf(bio_err, "-v2 alg use PKCS#5 v2.0 and cipher \"alg\"\n"); + BIO_printf(bio_err, "-v1 obj use PKCS#5 v1.5 and cipher \"alg\"\n"); return (1); } if ((pbe_nid == -1) && !cipher) pbe_nid = NID_pbeWithMD5AndDES_CBC; if (infile) { - if (!(in = BIO_new_file (infile, "rb"))) { - BIO_printf (bio_err, + if (!(in = BIO_new_file(infile, "rb"))) { + BIO_printf(bio_err, "Can't open input file %s\n", infile); return (1); } @@ -165,21 +203,29 @@ if (outfile) { if (!(out = BIO_new_file (outfile, "wb"))) { - BIO_printf (bio_err, + BIO_printf(bio_err, "Can't open output file %s\n", outfile); return (1); } } else out = BIO_new_fp (stdout, BIO_NOCLOSE); if (topk8) { - if (!(pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL))) { - BIO_printf (bio_err, "Error reading key\n", outfile); + if(informat == FORMAT_PEM) + pkey = PEM_read_bio_PrivateKey(in, NULL, PEM_cb, passin); + else if(informat == FORMAT_ASN1) + pkey = d2i_PrivateKey_bio(in, NULL); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + return (1); + } + if (!pkey) { + BIO_printf(bio_err, "Error reading key\n", outfile); ERR_print_errors(bio_err); return (1); } BIO_free(in); if (!(p8inf = EVP_PKEY2PKCS8(pkey))) { - BIO_printf (bio_err, "Error converting key\n", outfile); + BIO_printf(bio_err, "Error converting key\n", outfile); ERR_print_errors(bio_err); return (1); } @@ -194,17 +240,20 @@ return (1); } } else { - EVP_read_pw_string(pass, 50, "Enter Encryption Password:", 1); + if(!passout) { + passout = pass; + EVP_read_pw_string(pass, 50, "Enter Encryption Password:", 1); + } if (!(p8 = PKCS8_encrypt(pbe_nid, cipher, - pass, strlen(pass), + passout, strlen(passout), NULL, 0, iter, p8inf))) { - BIO_printf (bio_err, "Error encrypting key\n", + BIO_printf(bio_err, "Error encrypting key\n", outfile); ERR_print_errors(bio_err); return (1); } if(outformat == FORMAT_PEM) - PEM_write_bio_PKCS8 (out, p8); + PEM_write_bio_PKCS8(out, p8); else if(outformat == FORMAT_ASN1) i2d_PKCS8_bio(out, p8); else { @@ -243,8 +292,11 @@ ERR_print_errors(bio_err); return (1); } - EVP_read_pw_string(pass, 50, "Enter Password:", 0); - p8inf = M_PKCS8_decrypt(p8, pass, strlen(pass)); + if(!passin) { + passin = pass; + EVP_read_pw_string(pass, 50, "Enter Password:", 0); + } + p8inf = M_PKCS8_decrypt(p8, passin, strlen(passin)); X509_SIG_free(p8); } @@ -274,8 +326,14 @@ } PKCS8_PRIV_KEY_INFO_free(p8inf); - - PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL); + if(outformat == FORMAT_PEM) + PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, PEM_cb, passout); + else if(outformat == FORMAT_ASN1) + i2d_PrivateKey_bio(out, pkey); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + return (1); + } EVP_PKEY_free(pkey); BIO_free(out);
diff --git a/apps/req.c b/apps/req.c index 24e666f..5c14c71 100644 --- a/apps/req.c +++ b/apps/req.c
@@ -237,14 +237,13 @@ else if (strcmp(*argv,"-envpassout") == 0) { if (--argc < 1) goto bad; - if(!(passout= getenv(*(++argv)))) + if(!(passout= getenv(*(++argv)))) { BIO_printf(bio_err, "Can't read environment variable %s\n", *argv); badops = 1; } - argv++; } else if (strcmp(*argv,"-passout") == 0) { @@ -527,10 +526,9 @@ goto end; } -/* if (keyform == FORMAT_ASN1) - rsa=d2i_RSAPrivateKey_bio(in,NULL); - else */ - if (keyform == FORMAT_PEM) + if (keyform == FORMAT_ASN1) + pkey=d2i_PrivateKey_bio(in,NULL); + else if (keyform == FORMAT_PEM) { pkey=PEM_read_bio_PrivateKey(in,NULL,PEM_cb,passin); }
diff --git a/apps/rsa.c b/apps/rsa.c index 684252c..7d58b17 100644 --- a/apps/rsa.c +++ b/apps/rsa.c
@@ -161,7 +161,6 @@ *argv); badops = 1; } - argv++; } else if (strcmp(*argv,"-passout") == 0) {
diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index a24775d..c9500a6 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h
@@ -890,8 +890,6 @@ #define ASN1_F_D2I_POLICYINFO 269 #define ASN1_F_D2I_POLICYQUALINFO 270 #define ASN1_F_D2I_PRIVATEKEY 155 -#define ASN1_F_D2I_PRIVATEKEY_BIO 293 -#define ASN1_F_D2I_PRIVATEKEY_FP 294 #define ASN1_F_D2I_PUBLICKEY 156 #define ASN1_F_D2I_RSAPRIVATEKEY 157 #define ASN1_F_D2I_RSAPUBLICKEY 158
diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 62aa5f4..e7ac614 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c
@@ -163,8 +163,6 @@ {ERR_PACK(0,ASN1_F_D2I_POLICYINFO,0), "d2i_POLICYINFO"}, {ERR_PACK(0,ASN1_F_D2I_POLICYQUALINFO,0), "d2i_POLICYQUALINFO"}, {ERR_PACK(0,ASN1_F_D2I_PRIVATEKEY,0), "d2i_PrivateKey"}, -{ERR_PACK(0,ASN1_F_D2I_PRIVATEKEY_BIO,0), "d2i_PrivateKey_bio"}, -{ERR_PACK(0,ASN1_F_D2I_PRIVATEKEY_FP,0), "d2i_PrivateKey_fp"}, {ERR_PACK(0,ASN1_F_D2I_PUBLICKEY,0), "d2i_PublicKey"}, {ERR_PACK(0,ASN1_F_D2I_RSAPRIVATEKEY,0), "d2i_RSAPrivateKey"}, {ERR_PACK(0,ASN1_F_D2I_RSAPUBLICKEY,0), "d2i_RSAPublicKey"},
diff --git a/crypto/asn1/d2i_pr.c b/crypto/asn1/d2i_pr.c index f3d1aa6..7ae8781 100644 --- a/crypto/asn1/d2i_pr.c +++ b/crypto/asn1/d2i_pr.c
@@ -112,3 +112,26 @@ return(NULL); } +/* This works like d2i_PrivateKey() except it automatically works out the type */ + +EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, unsigned char **pp, + long length) +{ + STACK_OF(ASN1_TYPE) *inkey; + unsigned char *p; + int keytype; + p = *pp; + /* Dirty trick: read in the ASN1 data into a STACK_OF(ASN1_TYPE): + * by analysing it we can determine the passed structure: this + * assumes the input is surrounded by an ASN1 SEQUENCE. + */ + inkey = d2i_ASN1_SET_OF_ASN1_TYPE(NULL, &p, length, d2i_ASN1_TYPE, + ASN1_TYPE_free, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL); + /* Since we only need to discern "traditional format" RSA and DSA + * keys we can just count the elements. + */ + if(sk_ASN1_TYPE_num(inkey) == 6) keytype = EVP_PKEY_DSA; + else keytype = EVP_PKEY_RSA; + sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); + return d2i_PrivateKey(keytype, a, pp, length); +}
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 2191aee..a4ed6c7 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h
@@ -632,6 +632,8 @@ EVP_PKEY * d2i_PrivateKey(int type,EVP_PKEY **a, unsigned char **pp, long length); +EVP_PKEY * d2i_AutoPrivateKey(EVP_PKEY **a, unsigned char **pp, + long length); int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp); int EVP_PKEY_copy_parameters(EVP_PKEY *to,EVP_PKEY *from);
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index a11f9bc..2e6d207 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h
@@ -656,7 +656,7 @@ int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); -EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, int type, EVP_PKEY **a); +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); #endif #ifdef HEADER_BIO_H @@ -687,7 +687,7 @@ int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); -EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, int type, EVP_PKEY **a); +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); #endif X509 *X509_dup(X509 *x509);
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index e1d70df..d2bf3c8 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c
@@ -486,17 +486,10 @@ return(ASN1_i2d_fp(i2d_PrivateKey,fp,(unsigned char *)pkey)); } -EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, int type, EVP_PKEY **a) +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) { - BIO *bp; - EVP_PKEY *ret; - if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { - ASN1err(ASN1_F_D2I_PRIVATEKEY_FP,ERR_R_MALLOC_FAILURE); - return NULL; - } - ret = d2i_PrivateKey_bio(bp, type, a); - BIO_free(bp); - return ret; + return((EVP_PKEY *)ASN1_d2i_fp((char *(*)())EVP_PKEY_new, + (char *(*)())d2i_AutoPrivateKey, (fp),(unsigned char **)(a))); } #endif @@ -531,50 +524,8 @@ return(ASN1_i2d_bio(i2d_PrivateKey,bp,(unsigned char *)pkey)); } -EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, int type, EVP_PKEY **a) +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) { - EVP_PKEY *ret; - - if ((a == NULL) || (*a == NULL)) - { - if ((ret=EVP_PKEY_new()) == NULL) - { - ASN1err(ASN1_F_D2I_PRIVATEKEY_BIO,ERR_R_EVP_LIB); - return(NULL); - } - } - else ret= *a; - - ret->save_type=type; - ret->type=EVP_PKEY_type(type); - switch (ret->type) - { -#ifndef NO_RSA - case EVP_PKEY_RSA: - if ((ret->pkey.rsa=d2i_RSAPrivateKey_bio(bp,NULL)) == NULL) - { - ASN1err(ASN1_F_D2I_PRIVATEKEY_BIO,ERR_R_ASN1_LIB); - goto err; - } - break; -#endif -#ifndef NO_DSA - case EVP_PKEY_DSA: - if ((ret->pkey.dsa=d2i_DSAPrivateKey_bio(bp, NULL)) == NULL) - { - ASN1err(ASN1_F_D2I_PRIVATEKEY_BIO,ERR_R_ASN1_LIB); - goto err; - } - break; -#endif - default: - ASN1err(ASN1_F_D2I_PRIVATEKEY_BIO,ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE); - goto err; - /* break; */ - } - if (a != NULL) (*a)=ret; - return(ret); -err: - if ((ret != NULL) && ((a == NULL) || (*a != ret))) EVP_PKEY_free(ret); - return(NULL); + return((EVP_PKEY *)ASN1_d2i_bio((char *(*)())EVP_PKEY_new, + (char *(*)())d2i_AutoPrivateKey, (bp),(unsigned char **)(a))); }
diff --git a/doc/man/pkcs8.pod b/doc/man/pkcs8.pod index e2cc86e..3d58856 100644 --- a/doc/man/pkcs8.pod +++ b/doc/man/pkcs8.pod
@@ -11,7 +11,11 @@ [B<-inform PEM|DER>] [B<-outform PEM|DER>] [B<-in filename>] +[B<-passin password>] +[B<-envpassin var>] [B<-out filename>] +[B<-passout password>] +[B<-envpassout var>] [B<-noiter>] [B<-nocrypt>] [B<-nooct>] @@ -53,6 +57,15 @@ option is not specified. If the key is encrypted a pass phrase will be prompted for. +=item B<-passin password> + +the input file password. Since certain utilities like "ps" make the command line +visible this option should be used with caution. + +=item B<-envpassin var> + +read the input file password from the environment variable B<var>. + =item B<-out filename> This specifies the output filename to write a key to or standard output by @@ -60,6 +73,15 @@ prompted for. The output filename should B<not> be the same as the input filename. +=item B<-passout password> + +the output file password. Since certain utilities like "ps" make the command line +visible this option should be used with caution. + +=item B<-envpassout var> + +read the output file password from the environment variable B<var>. + =item B<-nocrypt> PKCS#8 keys generated or input are normally PKCS#8 EncryptedPrivateKeyInfo
diff --git a/doc/man/req.pod b/doc/man/req.pod index 9ca1025..0211530 100644 --- a/doc/man/req.pod +++ b/doc/man/req.pod
@@ -11,7 +11,11 @@ [B<-inform PEM|DER>] [B<-outform PEM|DER>] [B<-in filename>] +[B<-passin password>] +[B<-envpassin var>] [B<-out filename>] +[B<-passout password>] +[B<-envpassout var>] [B<-text>] [B<-noout>] [B<-verify>] @@ -59,11 +63,29 @@ if this option is not specified. A request is only read if the creation options (B<-new> and B<-newkey>) are not specified. +=item B<-passin password> + +the input file password. Since certain utilities like "ps" make the command line +visible this option should be used with caution. + +=item B<-envpassin var> + +read the input file password from the environment variable B<var>. + =item B<-out filename> This specifies the output filename to write to or standard output by default. +=item B<-passout password> + +the output file password. Since certain utilities like "ps" make the command line +visible this option should be used with caution. + +=item B<-envpassout var> + +read the output file password from the environment variable B<var>. + =item B<-text> prints out the certificate request in text form. @@ -269,7 +291,7 @@ fieldName_min= 2 fieldName_max= 4 -"fieldName" is the field name being used, for example commonName. +"fieldName" is the field name being used, for example commonName (or CN). The "prompt" string is used to ask the user to enter the relvant details. If the user enters nothing then the default value is used if no default value is present then the field is omitted. A field can
diff --git a/util/libeay.num b/util/libeay.num index a83b493..263f227 100755 --- a/util/libeay.num +++ b/util/libeay.num
@@ -2158,3 +2158,4 @@ i2d_PrivateKey_bio 2183 X509_reject_clear 2184 X509_TRUST_set_default 2185 +d2i_AutoPrivateKey 2186