diff --git a/CHANGES b/CHANGES index 28e929cc28..95ad74f671 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 0.9.3a and 0.9.4 + *) Add a new pair of functions PEM_write_PKCS8PrivateKey() and + PEM_write_bio_PKCS8PrivateKey() that are equivalent to + PEM_write_PrivateKey() and PEM_write_bio_PrivateKey() but use the more + secure PKCS#8 private key format with a high iteration count. + [Steve Henson] + *) Fix determination of Perl interpreter: A perl or perl5 _directory_ in $PATH was also accepted as the interpreter. [Ralf S. Engelschall] diff --git a/crypto/asn1/p5_pbe.c b/crypto/asn1/p5_pbe.c index 5145c6349e..30b9049a45 100644 --- a/crypto/asn1/p5_pbe.c +++ b/crypto/asn1/p5_pbe.c @@ -119,6 +119,7 @@ X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, ASN1err(ASN1_F_ASN1_PBE_SET,ERR_R_MALLOC_FAILURE); return NULL; } + if(iter <= 0) iter = PKCS5_DEFAULT_ITER; ASN1_INTEGER_set (pbe->iter, iter); if (!saltlen) saltlen = PKCS5_SALT_LEN; if (!(pbe->salt->data = Malloc (saltlen))) { diff --git a/crypto/asn1/p5_pbev2.c b/crypto/asn1/p5_pbev2.c index 10364a0561..0fc8df16d0 100644 --- a/crypto/asn1/p5_pbev2.c +++ b/crypto/asn1/p5_pbev2.c @@ -206,6 +206,7 @@ X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, if (salt) memcpy (osalt->data, salt, saltlen); else RAND_bytes (osalt->data, saltlen); + if(iter <= 0) iter = PKCS5_DEFAULT_ITER; if(!ASN1_INTEGER_set(kdf->iter, iter)) goto merr; /* Now include salt in kdf structure */ diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index e7b55a5885..570fe27d39 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -110,6 +110,8 @@ extern "C" { #define EVP_MAX_IV_LENGTH 8 #define PKCS5_SALT_LEN 8 +/* Default PKCS#5 iteration count */ +#define PKCS5_DEFAULT_ITER 2048 #ifndef NO_RSA #include diff --git a/crypto/evp/p5_crpt.c b/crypto/evp/p5_crpt.c index 798cbe9b82..abf6af0435 100644 --- a/crypto/evp/p5_crpt.c +++ b/crypto/evp/p5_crpt.c @@ -100,7 +100,7 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, /* Extract useful info from parameter */ pbuf = param->value.sequence->data; - if (!param || (param->type = V_ASN1_SEQUENCE) || + if (!param || (param->type != V_ASN1_SEQUENCE) || !(pbe = d2i_PBEPARAM (NULL, &pbuf, param->value.sequence->length))) { EVPerr(EVP_F_PKCS5_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); return 0; diff --git a/crypto/pem/pem.h b/crypto/pem/pem.h index 71953241d0..6c7387b604 100644 --- a/crypto/pem/pem.h +++ b/crypto/pem/pem.h @@ -67,6 +67,8 @@ extern "C" { #include #include +#define PEM_BUFSIZE 1024 + #define PEM_OBJ_UNDEF 0 #define PEM_OBJ_X509 1 #define PEM_OBJ_X509_REQ 2 @@ -499,6 +501,8 @@ int PEM_write_DSAPrivateKey(FILE *fp,DSA *x,const EVP_CIPHER *enc, #endif int PEM_write_PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, unsigned char *kstr,int klen, pem_password_cb *); +int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, + unsigned char *kstr,int klen, pem_password_cb *); int PEM_write_PKCS7(FILE *fp,PKCS7 *x); #ifndef NO_DH int PEM_write_DHparams(FILE *fp,DH *x); @@ -548,6 +552,8 @@ int PEM_write_bio_DSAPrivateKey(BIO *fp,DSA *x,const EVP_CIPHER *enc, #endif int PEM_write_bio_PrivateKey(BIO *fp,EVP_PKEY *x,const EVP_CIPHER *enc, unsigned char *kstr,int klen, pem_password_cb *); +int PEM_write_bio_PKCS8PrivateKey(BIO *fp,EVP_PKEY *x,const EVP_CIPHER *enc, + unsigned char *kstr,int klen, pem_password_cb *); int PEM_write_bio_PKCS7(BIO *bp,PKCS7 *x); #ifndef NO_DH int PEM_write_bio_DHparams(BIO *bp,DH *x); @@ -578,6 +584,7 @@ int PEM_write_bio_PKCS8_PRIV_KEY_INFO(BIO *bp,PKCS8_PRIV_KEY_INFO *x); #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_PEM_WRITE_PKCS8PRIVATEKEY 118 #define PEM_F_PEM_GET_EVP_CIPHER_INFO 107 #define PEM_F_PEM_READ 108 #define PEM_F_PEM_READ_BIO 109 @@ -586,6 +593,7 @@ int PEM_write_bio_PKCS8_PRIV_KEY_INFO(BIO *bp,PKCS8_PRIV_KEY_INFO *x); #define PEM_F_PEM_SIGNFINAL 112 #define PEM_F_PEM_WRITE 113 #define PEM_F_PEM_WRITE_BIO 114 +#define PEM_F_PEM_WRITE_BIO_PKCS8PRIVATEKEY 119 #define PEM_F_PEM_X509_INFO_READ 115 #define PEM_F_PEM_X509_INFO_READ_BIO 116 #define PEM_F_PEM_X509_INFO_WRITE_BIO 117 @@ -596,6 +604,7 @@ int PEM_write_bio_PKCS8_PRIV_KEY_INFO(BIO *bp,PKCS8_PRIV_KEY_INFO *x); #define PEM_R_BAD_END_LINE 102 #define PEM_R_BAD_IV_CHARS 103 #define PEM_R_BAD_PASSWORD_READ 104 +#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 115 #define PEM_R_NOT_DEK_INFO 105 #define PEM_R_NOT_ENCRYPTED 106 #define PEM_R_NOT_PROC_TYPE 107 diff --git a/crypto/pem/pem_err.c b/crypto/pem/pem_err.c index dce31c6252..fa70f60998 100644 --- a/crypto/pem/pem_err.c +++ b/crypto/pem/pem_err.c @@ -72,6 +72,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_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"}, {ERR_PACK(0,PEM_F_PEM_READ_BIO,0), "PEM_read_bio"}, @@ -80,6 +81,7 @@ static ERR_STRING_DATA PEM_str_functs[]= {ERR_PACK(0,PEM_F_PEM_SIGNFINAL,0), "PEM_SignFinal"}, {ERR_PACK(0,PEM_F_PEM_WRITE,0), "PEM_write"}, {ERR_PACK(0,PEM_F_PEM_WRITE_BIO,0), "PEM_write_bio"}, +{ERR_PACK(0,PEM_F_PEM_WRITE_BIO_PKCS8PRIVATEKEY,0), "PEM_write_bio_PKCS8PrivateKey"}, {ERR_PACK(0,PEM_F_PEM_X509_INFO_READ,0), "PEM_X509_INFO_read"}, {ERR_PACK(0,PEM_F_PEM_X509_INFO_READ_BIO,0), "PEM_X509_INFO_read_bio"}, {ERR_PACK(0,PEM_F_PEM_X509_INFO_WRITE_BIO,0), "PEM_X509_INFO_write_bio"}, @@ -93,6 +95,7 @@ static ERR_STRING_DATA PEM_str_reasons[]= {PEM_R_BAD_END_LINE ,"bad end line"}, {PEM_R_BAD_IV_CHARS ,"bad iv chars"}, {PEM_R_BAD_PASSWORD_READ ,"bad password read"}, +{PEM_R_ERROR_CONVERTING_PRIVATE_KEY ,"error converting private key"}, {PEM_R_NOT_DEK_INFO ,"not dek info"}, {PEM_R_NOT_ENCRYPTED ,"not encrypted"}, {PEM_R_NOT_PROC_TYPE ,"not proc type"}, diff --git a/crypto/pem/pem_info.c b/crypto/pem/pem_info.c index 0c2af93360..ec392ea39c 100644 --- a/crypto/pem/pem_info.c +++ b/crypto/pem/pem_info.c @@ -272,7 +272,6 @@ int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc, int i,ret=0; unsigned char *data=NULL; const char *objstr=NULL; -#define PEM_BUFSIZE 1024 char buf[PEM_BUFSIZE]; unsigned char *iv=NULL; diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c index a8414566de..96221d869b 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -72,7 +72,6 @@ const char *PEM_version="PEM" OPENSSL_VERSION_PTEXT; #define MIN_LENGTH 4 -#define PEM_BUFSIZE 1024 static int def_callback(char *buf, int num, int w); static int load_iv(unsigned char **fromp,unsigned char *to, int num); @@ -742,3 +741,61 @@ err: BUF_MEM_free(dataB); 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. + */ + +int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, pem_password_cb *cb) +{ + X509_SIG *p8; + PKCS8_PRIV_KEY_INFO *p8inf; + char buf[PEM_BUFSIZE]; + int ret; + if(!(p8inf = EVP_PKEY2PKCS8(x))) { + PEMerr(PEM_F_PEM_WRITE_BIO_PKCS8PRIVATEKEY, + PEM_R_ERROR_CONVERTING_PRIVATE_KEY); + return 0; + } + if(enc) { + if(!kstr) { + if(!cb) klen = def_callback(buf, PEM_BUFSIZE, 1); + else klen = cb(buf, PEM_BUFSIZE, 1); + if(klen <= 0) { + PEMerr(PEM_F_PEM_WRITE_BIO_PKCS8PRIVATEKEY, + PEM_R_READ_KEY); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return 0; + } + + kstr = buf; + } + p8 = PKCS8_encrypt(-1, enc, kstr, klen, NULL, 0, 0, p8inf); + if(kstr == (unsigned char *)buf) memset(buf, 0, klen); + PKCS8_PRIV_KEY_INFO_free(p8inf); + ret = PEM_write_bio_PKCS8(bp, p8); + X509_SIG_free(p8); + return ret; + } else { + ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } +} + +int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, pem_password_cb *cb) +{ + BIO *bp; + int ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + PEMerr(PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY,ERR_R_BUF_LIB); + return(0); + } + ret = PEM_write_bio_PKCS8PrivateKey(bp, x, enc, kstr, klen, cb); + BIO_free(bp); + return ret; +} diff --git a/crypto/pkcs12/p12_crpt.c b/crypto/pkcs12/p12_crpt.c index d94265403a..6de6f8128f 100644 --- a/crypto/pkcs12/p12_crpt.c +++ b/crypto/pkcs12/p12_crpt.c @@ -92,7 +92,7 @@ int PKCS12_PBE_keyivgen (EVP_CIPHER_CTX *ctx, const char *pass, int passlen, /* Extract useful info from parameter */ pbuf = param->value.sequence->data; - if (!param || (param->type = V_ASN1_SEQUENCE) || + if (!param || (param->type != V_ASN1_SEQUENCE) || !(pbe = d2i_PBEPARAM (NULL, &pbuf, param->value.sequence->length))) { EVPerr(PKCS12_F_PKCS12_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); return 0; diff --git a/crypto/pkcs12/pkcs12.h b/crypto/pkcs12/pkcs12.h index 5f3b1148fa..4cfba5e6c6 100644 --- a/crypto/pkcs12/pkcs12.h +++ b/crypto/pkcs12/pkcs12.h @@ -72,7 +72,7 @@ extern "C" { /* Default iteration count */ #ifndef PKCS12_DEFAULT_ITER -#define PKCS12_DEFAULT_ITER 2048 +#define PKCS12_DEFAULT_ITER PKCS5_DEFAULT_ITER #endif #define PKCS12_MAC_KEY_LENGTH 20 diff --git a/util/libeay.num b/util/libeay.num index a4907c1751..0ff1cd9982 100755 --- a/util/libeay.num +++ b/util/libeay.num @@ -1769,3 +1769,5 @@ BIO_s_bio 1793 PKCS5_pbe2_set 1794 PKCS5_PBKDF2_HMAC_SHA1 1795 PKCS5_v2_PBE_keyivgen 1796 +PEM_write_bio_PKCS8PrivateKey 1797 +PEM_write_PKCS8PrivateKey 1798