From 525f51f6c98751de4db3b81789044d32e3686cda Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 23 Dec 1999 02:02:42 +0000 Subject: Add PKCS#8 utility functions and add PBE options. --- CHANGES | 6 ++ apps/pkcs12.c | 28 +++++++++- apps/pkcs8.c | 11 ++++ crypto/asn1/Makefile.ssl | 7 +++ crypto/objects/obj_dat.h | 52 ++++++++++------- crypto/objects/objects.h | 12 ++++ crypto/pem/pem.h | 27 +++++++++ crypto/pem/pem_err.c | 3 + crypto/pem/pem_lib.c | 141 +++++++++++++++++++++++++++++++++++++++++++---- doc/man/pkcs8.pod | 41 +++++++++++++- util/libeay.num | 12 ++++ util/mkerr.pl | 2 +- 12 files changed, 303 insertions(+), 39 deletions(-) diff --git a/CHANGES b/CHANGES index 7ef8de235b..e19ea183b7 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 0.9.4 and 0.9.5 [xx XXX 1999] + *) Add a bunch of DER and PEM functions to handle PKCS#8 format private + keys. Add some short names for PKCS#8 PBE algorithms and allow them + to be specified on the command line for the pkcs8 and pkcs12 utilities. + Update documentation. + [Steve Henson] + *) Support for ASN1 "NULL" type. This could be handled before by using ASN1_TYPE but there wasn't any function that would try to read a NULL and produce an error if it couldn't. For compatibility we also have diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 9fb290d7f5..65276f5229 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -104,6 +104,7 @@ int MAIN(int argc, char **argv) int twopass = 0; int keytype = 0; int cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; + int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; int ret = 1; int macver = 1; int noprompt = 0; @@ -143,7 +144,27 @@ int MAIN(int argc, char **argv) else if (!strcmp (*args, "-maciter")) maciter = PKCS12_DEFAULT_ITER; else if (!strcmp (*args, "-nodes")) enc=NULL; - else if (!strcmp (*args, "-inkey")) { + else if (!strcmp (*args, "-certpbe")) { + if (args[1]) { + args++; + cert_pbe=OBJ_txt2nid(*args); + if(cert_pbe == NID_undef) { + BIO_printf(bio_err, + "Unknown PBE algorithm %s\n", *args); + badarg = 1; + } + } else badarg = 1; + } else if (!strcmp (*args, "-keypbe")) { + if (args[1]) { + args++; + key_pbe=OBJ_txt2nid(*args); + if(key_pbe == NID_undef) { + BIO_printf(bio_err, + "Unknown PBE algorithm %s\n", *args); + badarg = 1; + } + } else badarg = 1; + } else if (!strcmp (*args, "-inkey")) { if (args[1]) { args++; keyname = *args; @@ -224,6 +245,8 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-maciter use MAC iteration\n"); BIO_printf (bio_err, "-twopass separate MAC, encryption passwords\n"); BIO_printf (bio_err, "-descert encrypt PKCS#12 certificates with triple DES (default RC2-40)\n"); + BIO_printf (bio_err, "-certpbe alg specify certificate PBE algorithm (default RC2-40)\n"); + BIO_printf (bio_err, "-keypbe alg specify private key PBE algorithm (default 3DES)\n"); BIO_printf (bio_err, "-keyex set MS key exchange type\n"); BIO_printf (bio_err, "-keysig set MS key signature type\n"); BIO_printf (bio_err, "-password p set import/export password (NOT RECOMMENDED)\n"); @@ -391,8 +414,7 @@ int MAIN(int argc, char **argv) p8 = EVP_PKEY2PKCS8 (key); EVP_PKEY_free(key); if(keytype) PKCS8_add_keyusage(p8, keytype); - bag = PKCS12_MAKE_SHKEYBAG(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, - cpass, -1, NULL, 0, iter, p8); + bag = PKCS12_MAKE_SHKEYBAG(key_pbe, cpass, -1, NULL, 0, iter, p8); PKCS8_PRIV_KEY_INFO_free(p8); if (name) PKCS12_add_friendlyname (bag, name, -1); PKCS12_add_localkeyid (bag, keyid, keyidlen); diff --git a/apps/pkcs8.c b/apps/pkcs8.c index a05388300a..8ac9e1238d 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c @@ -99,6 +99,16 @@ int MAIN(int argc, char **argv) badarg = 1; } } else badarg = 1; + } else if (!strcmp(*args,"-v1")) { + if (args[1]) { + args++; + pbe_nid=OBJ_txt2nid(*args); + if(pbe_nid == NID_undef) { + BIO_printf(bio_err, + "Unknown PBE algorithm %s\n", *args); + badarg = 1; + } + } else badarg = 1; } else if (!strcmp(*args,"-inform")) { if (args[1]) { args++; @@ -139,6 +149,7 @@ int MAIN(int argc, char **argv) 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); } diff --git a/crypto/asn1/Makefile.ssl b/crypto/asn1/Makefile.ssl index f4e9f83cc0..74f057b5e3 100644 --- a/crypto/asn1/Makefile.ssl +++ b/crypto/asn1/Makefile.ssl @@ -223,6 +223,13 @@ a_meth.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h a_meth.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h a_meth.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h a_meth.o: ../cryptlib.h +a_null.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +a_null.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h +a_null.o: ../../include/openssl/crypto.h ../../include/openssl/e_os.h +a_null.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h +a_null.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h +a_null.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +a_null.o: ../cryptlib.h a_object.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h a_object.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h a_object.o: ../../include/openssl/crypto.h ../../include/openssl/e_os.h diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index c45574d218..27e3e5e297 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -62,7 +62,7 @@ */ #define NUM_NID 181 -#define NUM_SN 128 +#define NUM_SN 140 #define NUM_LN 175 #define NUM_OBJ 152 @@ -233,10 +233,10 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ &(lvalues[47]),0}, {"RSA-MD5","md5WithRSAEncryption",NID_md5WithRSAEncryption,9, &(lvalues[56]),0}, -{"pbeWithMD2AndDES-CBC","pbeWithMD2AndDES-CBC", - NID_pbeWithMD2AndDES_CBC,9,&(lvalues[65]),0}, -{"pbeWithMD5AndDES-CBC","pbeWithMD5AndDES-CBC", - NID_pbeWithMD5AndDES_CBC,9,&(lvalues[74]),0}, +{"PBE-MD2-DES","pbeWithMD2AndDES-CBC",NID_pbeWithMD2AndDES_CBC,9, + &(lvalues[65]),0}, +{"PBE-MD5-DES","pbeWithMD5AndDES-CBC",NID_pbeWithMD5AndDES_CBC,9, + &(lvalues[74]),0}, {"X500","X500",NID_X500,1,&(lvalues[83]),0}, {"X509","X509",NID_X509,2,&(lvalues[84]),0}, {"CN","commonName",NID_commonName,3,&(lvalues[86]),0}, @@ -312,8 +312,8 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ &(lvalues[355]),0}, {"DSA-SHA","dsaWithSHA",NID_dsaWithSHA,5,&(lvalues[364]),0}, {"DSA-old","dsaEncryption-old",NID_dsa_2,5,&(lvalues[369]),0}, -{"pbeWithSHA1AndRC2-CBC","pbeWithSHA1AndRC2-CBC", - NID_pbeWithSHA1AndRC2_CBC,9,&(lvalues[374]),0}, +{"PBE-SHA1-RC2-64","pbeWithSHA1AndRC2-CBC",NID_pbeWithSHA1AndRC2_CBC, + 9,&(lvalues[374]),0}, {"PBKDF2","PBKDF2",NID_id_pbkdf2,9,&(lvalues[383]),0}, {"DSA-SHA1-old","dsaWithSHA1-old",NID_dsaWithSHA1_2,5,&(lvalues[392]),0}, {"nsCertType","Netscape Cert Type",NID_netscape_cert_type,9, @@ -417,19 +417,17 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ {"invalidityDate","Invalidity Date",NID_invalidity_date,3, &(lvalues[733]),0}, {"SXNetID","Strong Extranet ID",NID_sxnet,5,&(lvalues[736]),0}, -{"pbeWithSHA1And128BitRC4","pbeWithSHA1And128BitRC4", +{"PBE-SHA1-RC4-128","pbeWithSHA1And128BitRC4", NID_pbe_WithSHA1And128BitRC4,10,&(lvalues[741]),0}, -{"pbeWithSHA1And40BitRC4","pbeWithSHA1And40BitRC4", +{"PBE-SHA1-RC4-40","pbeWithSHA1And40BitRC4", NID_pbe_WithSHA1And40BitRC4,10,&(lvalues[751]),0}, -{"pbeWithSHA1And3-KeyTripleDES-CBC", - "pbeWithSHA1And3-KeyTripleDES-CBC", +{"PBE-SHA1-3DES","pbeWithSHA1And3-KeyTripleDES-CBC", NID_pbe_WithSHA1And3_Key_TripleDES_CBC,10,&(lvalues[761]),0}, -{"pbeWithSHA1And2-KeyTripleDES-CBC", - "pbeWithSHA1And2-KeyTripleDES-CBC", +{"PBE-SHA1-2DES","pbeWithSHA1And2-KeyTripleDES-CBC", NID_pbe_WithSHA1And2_Key_TripleDES_CBC,10,&(lvalues[771]),0}, -{"pbeWithSHA1And128BitRC2-CBC","pbeWithSHA1And128BitRC2-CBC", +{"PBE-SHA1-RC2-128","pbeWithSHA1And128BitRC2-CBC", NID_pbe_WithSHA1And128BitRC2_CBC,10,&(lvalues[781]),0}, -{"pbeWithSHA1And40BitRC2-CBC","pbeWithSHA1And40BitRC2-CBC", +{"PBE-SHA1-RC2-40","pbeWithSHA1And40BitRC2-CBC", NID_pbe_WithSHA1And40BitRC2_CBC,10,&(lvalues[791]),0}, {"keyBag","keyBag",NID_keyBag,11,&(lvalues[801]),0}, {"pkcs8ShroudedKeyBag","pkcs8ShroudedKeyBag",NID_pkcs8ShroudedKeyBag, @@ -455,12 +453,12 @@ static ASN1_OBJECT nid_objs[NUM_NID]={ {"RC2-64-CBC","rc2-64-cbc",NID_rc2_64_cbc,0,NULL}, {"SMIME-CAPS","S/MIME Capabilities",NID_SMIMECapabilities,9, &(lvalues[957]),0}, -{"pbeWithMD2AndRC2-CBC","pbeWithMD2AndRC2-CBC", - NID_pbeWithMD2AndRC2_CBC,9,&(lvalues[966]),0}, -{"pbeWithMD5AndRC2-CBC","pbeWithMD5AndRC2-CBC", - NID_pbeWithMD5AndRC2_CBC,9,&(lvalues[975]),0}, -{"pbeWithSHA1AndDES-CBC","pbeWithSHA1AndDES-CBC", - NID_pbeWithSHA1AndDES_CBC,9,&(lvalues[984]),0}, +{"PBE-MD2-RC2-64","pbeWithMD2AndRC2-CBC",NID_pbeWithMD2AndRC2_CBC,9, + &(lvalues[966]),0}, +{"PBE-MD5-RC2-64","pbeWithMD5AndRC2-CBC",NID_pbeWithMD5AndRC2_CBC,9, + &(lvalues[975]),0}, +{"PBE-SHA1-DES","pbeWithSHA1AndDES-CBC",NID_pbeWithSHA1AndDES_CBC,9, + &(lvalues[984]),0}, {"msExtReq","Microsoft Extension Request",NID_ms_ext_req,10, &(lvalues[993]),0}, {"extReq","Extension Request",NID_ext_req,9,&(lvalues[1003]),0}, @@ -522,6 +520,18 @@ static ASN1_OBJECT *sn_objs[NUM_SN]={ &(nid_objs[17]),/* "O" */ &(nid_objs[178]),/* "OCSP" */ &(nid_objs[18]),/* "OU" */ +&(nid_objs[ 9]),/* "PBE-MD2-DES" */ +&(nid_objs[168]),/* "PBE-MD2-RC2-64" */ +&(nid_objs[10]),/* "PBE-MD5-DES" */ +&(nid_objs[169]),/* "PBE-MD5-RC2-64" */ +&(nid_objs[147]),/* "PBE-SHA1-2DES" */ +&(nid_objs[146]),/* "PBE-SHA1-3DES" */ +&(nid_objs[170]),/* "PBE-SHA1-DES" */ +&(nid_objs[148]),/* "PBE-SHA1-RC2-128" */ +&(nid_objs[149]),/* "PBE-SHA1-RC2-40" */ +&(nid_objs[68]),/* "PBE-SHA1-RC2-64" */ +&(nid_objs[144]),/* "PBE-SHA1-RC4-128" */ +&(nid_objs[145]),/* "PBE-SHA1-RC4-40" */ &(nid_objs[127]),/* "PKIX" */ &(nid_objs[98]),/* "RC2-40-CBC" */ &(nid_objs[166]),/* "RC2-64-CBC" */ diff --git a/crypto/objects/objects.h b/crypto/objects/objects.h index 325128813d..644716b16e 100644 --- a/crypto/objects/objects.h +++ b/crypto/objects/objects.h @@ -110,10 +110,12 @@ extern "C" { #define NID_md5WithRSAEncryption 8 #define OBJ_md5WithRSAEncryption OBJ_pkcs,1L,4L +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" #define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" #define NID_pbeWithMD2AndDES_CBC 9 #define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs,5L,1L +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" #define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" #define NID_pbeWithMD5AndDES_CBC 10 #define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs,5L,3L @@ -380,6 +382,7 @@ extern "C" { #define OBJ_dsa_2 OBJ_algorithm,12L /* proposed by microsoft to RSA */ +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" #define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" #define NID_pbeWithSHA1AndRC2_CBC 68 #define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs,5L,11L @@ -767,26 +770,32 @@ extern "C" { #define OBJ_pkcs12 OBJ_pkcs,12L #define OBJ_pkcs12_pbeids OBJ_pkcs12, 1 +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" #define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" #define NID_pbe_WithSHA1And128BitRC4 144 #define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids, 1L +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" #define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" #define NID_pbe_WithSHA1And40BitRC4 145 #define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids, 2L +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" #define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" #define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 #define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 3L +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" #define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" #define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 #define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 4L +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" #define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" #define NID_pbe_WithSHA1And128BitRC2_CBC 148 #define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids, 5L +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" #define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" #define NID_pbe_WithSHA1And40BitRC2_CBC 149 #define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids, 6L @@ -878,14 +887,17 @@ extern "C" { #define NID_SMIMECapabilities 167 #define OBJ_SMIMECapabilities OBJ_pkcs9,15L +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" #define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" #define NID_pbeWithMD2AndRC2_CBC 168 #define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs,5L,4L +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" #define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" #define NID_pbeWithMD5AndRC2_CBC 169 #define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs,5L,6L +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" #define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" #define NID_pbeWithSHA1AndDES_CBC 170 #define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs,5L,10L diff --git a/crypto/pem/pem.h b/crypto/pem/pem.h index 8ae1e9acc7..26c313b2ef 100644 --- a/crypto/pem/pem.h +++ b/crypto/pem/pem.h @@ -574,10 +574,34 @@ DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) DECLARE_PEM_rw(PUBKEY, EVP_PKEY) +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, char *kstr,int klen, pem_password_cb *cd, void *u); + #endif /* SSLEAY_MACROS */ @@ -589,6 +613,8 @@ int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, /* Error codes for the PEM functions. */ /* Function codes. */ +#define PEM_F_D2I_PKCS8PRIVATEKEY_BIO 120 +#define PEM_F_D2I_PKCS8PRIVATEKEY_FP 121 #define PEM_F_DEF_CALLBACK 100 #define PEM_F_LOAD_IV 101 #define PEM_F_PEM_ASN1_READ 102 @@ -596,6 +622,7 @@ int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, #define PEM_F_PEM_ASN1_WRITE 104 #define PEM_F_PEM_ASN1_WRITE_BIO 105 #define PEM_F_PEM_DO_HEADER 106 +#define PEM_F_PEM_F_DO_PK8KEY_FP 122 #define PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY 118 #define PEM_F_PEM_GET_EVP_CIPHER_INFO 107 #define PEM_F_PEM_READ 108 diff --git a/crypto/pem/pem_err.c b/crypto/pem/pem_err.c index fa70f60998..642129da20 100644 --- a/crypto/pem/pem_err.c +++ b/crypto/pem/pem_err.c @@ -65,6 +65,8 @@ #ifndef NO_ERR static ERR_STRING_DATA PEM_str_functs[]= { +{ERR_PACK(0,PEM_F_D2I_PKCS8PRIVATEKEY_BIO,0), "d2i_PKCS8PrivateKey_bio"}, +{ERR_PACK(0,PEM_F_D2I_PKCS8PRIVATEKEY_FP,0), "d2i_PKCS8PrivateKey_fp"}, {ERR_PACK(0,PEM_F_DEF_CALLBACK,0), "DEF_CALLBACK"}, {ERR_PACK(0,PEM_F_LOAD_IV,0), "LOAD_IV"}, {ERR_PACK(0,PEM_F_PEM_ASN1_READ,0), "PEM_ASN1_read"}, @@ -72,6 +74,7 @@ static ERR_STRING_DATA PEM_str_functs[]= {ERR_PACK(0,PEM_F_PEM_ASN1_WRITE,0), "PEM_ASN1_write"}, {ERR_PACK(0,PEM_F_PEM_ASN1_WRITE_BIO,0), "PEM_ASN1_write_bio"}, {ERR_PACK(0,PEM_F_PEM_DO_HEADER,0), "PEM_do_header"}, +{ERR_PACK(0,PEM_F_PEM_F_DO_PK8KEY_FP,0), "PEM_F_DO_PK8KEY_FP"}, {ERR_PACK(0,PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY,0), "PEM_F_PEM_WRITE_PKCS8PRIVATEKEY"}, {ERR_PACK(0,PEM_F_PEM_GET_EVP_CIPHER_INFO,0), "PEM_get_EVP_CIPHER_INFO"}, {ERR_PACK(0,PEM_F_PEM_READ,0), "PEM_read"}, diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c index 0bc1752482..2bafb5e735 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -76,6 +76,14 @@ const char *PEM_version="PEM" OPENSSL_VERSION_PTEXT; static int def_callback(char *buf, int num, int w, void *userdata); static int load_iv(unsigned char **fromp,unsigned char *to, int num); static int check_pem(const char *nm, const char *name); +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +static int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); static int def_callback(char *buf, int num, int w, void *userdata) { @@ -247,7 +255,7 @@ char *PEM_ASN1_read_bio(char *(*d2i)(), const char *name, BIO *bp, char **x, X509_SIG *p8; int klen; char psbuf[PEM_BUFSIZE]; - p8 = d2i_X509_SIG((X509_SIG **)x, &p, len); + p8 = d2i_X509_SIG(NULL, &p, len); if(!p8) goto p8err; if (cb) klen=cb(psbuf,PEM_BUFSIZE,0,u); else klen=def_callback(psbuf,PEM_BUFSIZE,0,u); @@ -260,6 +268,10 @@ char *PEM_ASN1_read_bio(char *(*d2i)(), const char *name, BIO *bp, char **x, X509_SIG_free(p8); if(!p8inf) goto p8err; ret = (char *)EVP_PKCS82PKEY(p8inf); + if(x) { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } PKCS8_PRIV_KEY_INFO_free(p8inf); } } else ret=d2i(x,&p,len); @@ -772,15 +784,43 @@ err: return(0); } -/* This function writes a private key in PKCS#8 format: it is a "drop in" - * replacement for PEM_write_bio_PrivateKey(). As usual if 'enc' is NULL then - * it uses the unencrypted private key form. It uses PKCS#5 v2.0 password based - * encryption algorithms. +/* These functions write a private key in PKCS#8 format: it is a "drop in" + * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc' + * is NULL then it uses the unencrypted private key form. The 'nid' versions + * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0. */ +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u); +} + int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) { X509_SIG *p8; PKCS8_PRIV_KEY_INFO *p8inf; @@ -791,7 +831,7 @@ int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, PEM_R_ERROR_CONVERTING_PRIVATE_KEY); return 0; } - if(enc) { + if(enc || (nid != -1)) { if(!kstr) { if(!cb) klen = def_callback(buf, PEM_BUFSIZE, 1, u); else klen = cb(buf, PEM_BUFSIZE, 1, u); @@ -804,30 +844,109 @@ int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, kstr = buf; } - p8 = PKCS8_encrypt(-1, enc, kstr, klen, NULL, 0, 0, p8inf); + p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf); if(kstr == buf) memset(buf, 0, klen); PKCS8_PRIV_KEY_INFO_free(p8inf); - ret = PEM_write_bio_PKCS8(bp, p8); + if(isder) ret = i2d_PKCS8_bio(bp, p8); + else ret = PEM_write_bio_PKCS8(bp, p8); X509_SIG_free(p8); return ret; } else { - ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); + if(isder) ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); + else ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); PKCS8_PRIV_KEY_INFO_free(p8inf); return ret; } } + +/* Finally the DER version to read PKCS#8 encrypted private keys. It has to be + * here to access the default callback. + */ + +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + X509_SIG *p8 = NULL; + int klen; + EVP_PKEY *ret; + char psbuf[PEM_BUFSIZE]; + p8 = d2i_PKCS8_bio(bp, NULL); + if(!p8) return NULL; + if (cb) klen=cb(psbuf,PEM_BUFSIZE,0,u); + else klen=def_callback(psbuf,PEM_BUFSIZE,0,u); + if (klen <= 0) { + PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + return NULL; + } + p8inf = M_PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if(!p8inf) return NULL; + ret = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if(!ret) return NULL; + if(x) { + if(*x) EVP_PKEY_free(*x); + *x = ret; + } + return ret; +} + #ifndef NO_FP_API + +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u); +} + int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u); +} + +static int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) { BIO *bp; int ret; if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { - PEMerr(PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY,ERR_R_BUF_LIB); + PEMerr(PEM_F_PEM_F_DO_PK8KEY_FP,ERR_R_BUF_LIB); return(0); } - ret = PEM_write_bio_PKCS8PrivateKey(bp, x, enc, kstr, klen, cb, u); + ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u); BIO_free(bp); return ret; } + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + BIO *bp; + EVP_PKEY *ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_FP,ERR_R_BUF_LIB); + return NULL; + } + ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u); + BIO_free(bp); + return ret; +} + #endif diff --git a/doc/man/pkcs8.pod b/doc/man/pkcs8.pod index eadfe31fbb..e2cc86e0e3 100644 --- a/doc/man/pkcs8.pod +++ b/doc/man/pkcs8.pod @@ -16,6 +16,7 @@ B B [B<-nocrypt>] [B<-nooct>] [B<-v2 alg>] +[B<-v1 alg>] =head1 DESCRIPTION @@ -89,6 +90,11 @@ private keys with OpenSSL then this doesn't matter. The B argument is the encryption algorithm to use, valid values include B, B and B. It is recommended that B is used. +=item B<-v1 alg> + +This option specifies a PKCS#5 v1.5 or PKCS#12 algorithm to use. A complete +list of possible algorithms is included below. + =back =head1 NOTES @@ -120,6 +126,33 @@ It is possible to write out DER encoded encrypted private keys in PKCS#8 format because the encryption details are included at an ASN1 level whereas the traditional format includes them at a PEM level. +=head1 PKCS#5 v1.5 and PKCS#12 algorithms. + +Various algorithms can be used with the B<-v1> command line option, +including PKCS#5 v1.5 and PKCS#12. These are described in more detail +below. + +=over 4 + +=item B + +These algorithms were included in the original PKCS#5 v1.5 specification. +They only offer 56 bits of protection since they both use DES. + +=item B + +These algorithms are not mentioned in the original PKCS#5 v1.5 specification +but they use the same key derivation algorithm and are supported by some +software. They are mentioned in PKCS#5 v1.5. They use either 64 bit RC2 or +56 bit DES. + +=item B + +These algorithms use the PKCS#12 password based encryption algorithm and +allow strong encryption algorithms like triple DES or 128 bit RC2 to be used. + +=back + =head1 EXAMPLES Convert a private from traditional to PKCS#5 v2.0 format using triple @@ -132,6 +165,11 @@ Convert a private key to PKCS#8 using a PKCS#5 1.5 compatible algorithm openssl pkcs8 -in key.pem -topk8 -out enckey.pem +Convert a private key to PKCS#8 using a PKCS#12 compatible algorithm +(3DES): + + openssl pkcs8 -in key.pem -topk8 -out enckey.pem -v1 PBE-SHA1-3DES + Read a DER unencrypted PKCS#8 format private key: openssl pkcs8 -inform DER -nocrypt -in key.der -out key.pem @@ -150,9 +188,6 @@ reasonably accurate at least as far as these algorithms are concerned. =head1 BUGS -It isn't possible to produce keys encrypted using PKCS#5 v1.5 algorithms -other than B using this utility. - There should be an option that prints out the encryption algorithm in use and other details such as the iteration count. diff --git a/util/libeay.num b/util/libeay.num index 1c371fdb74..3c2c06bce9 100755 --- a/util/libeay.num +++ b/util/libeay.num @@ -2137,3 +2137,15 @@ CRYPTO_set_mem_debug_functions 2161 CRYPTO_pop_info 2162 CRYPTO_push_info_ 2163 CRYPTO_set_mem_debug_options 2164 +PEM_write_PKCS8PrivateKey_nid 2165 +PEM_write_bio_PKCS8PrivateKey_nid 2166 +d2i_PKCS8PrivateKey_bio 2167 +ASN1_NULL_free 2168 +d2i_ASN1_NULL 2169 +ASN1_NULL_new 2170 +i2d_PKCS8PrivateKey_bio 2171 +i2d_PKCS8PrivateKey_fp 2172 +i2d_ASN1_NULL 2173 +i2d_PKCS8PrivateKey_nid_fp 2174 +d2i_PKCS8PrivateKey_fp 2175 +i2d_PKCS8PrivateKey_nid_bio 2176 diff --git a/util/mkerr.pl b/util/mkerr.pl index 4b3bccb13e..ebc059ef22 100644 --- a/util/mkerr.pl +++ b/util/mkerr.pl @@ -450,7 +450,7 @@ void ERR_load_${lib}_strings(void) #ifdef ${lib}_LIB_NAME ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code,0,0); ERR_load_strings(0,${lib}_lib_name); -#endif; +#endif } } -- cgit v1.2.3