Two new functions to write out PKCS#8 private keys. Also fixes for some of
authorDr. Stephen Henson <steve@openssl.org>
Thu, 10 Jun 1999 17:32:52 +0000 (17:32 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 10 Jun 1999 17:32:52 +0000 (17:32 +0000)
the the PBE code and a new constant PKCS5_DEFAULT_ITER for the default
iteration count if it is passed as zero.

12 files changed:
CHANGES
crypto/asn1/p5_pbe.c
crypto/asn1/p5_pbev2.c
crypto/evp/evp.h
crypto/evp/p5_crpt.c
crypto/pem/pem.h
crypto/pem/pem_err.c
crypto/pem/pem_info.c
crypto/pem/pem_lib.c
crypto/pkcs12/p12_crpt.c
crypto/pkcs12/pkcs12.h
util/libeay.num

diff --git a/CHANGES b/CHANGES
index 28e929c..95ad74f 100644 (file)
--- 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]
index 5145c63..30b9049 100644 (file)
@@ -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))) {
index 10364a0..0fc8df1 100644 (file)
@@ -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 */
index e7b55a5..570fe27 100644 (file)
@@ -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 <openssl/rsa.h>
index 798cbe9..abf6af0 100644 (file)
@@ -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;
index 7195324..6c7387b 100644 (file)
@@ -67,6 +67,8 @@ extern "C" {
 #include <openssl/x509.h>
 #include <openssl/pem2.h>
 
+#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
index dce31c6..fa70f60 100644 (file)
@@ -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"},
index 0c2af93..ec392ea 100644 (file)
@@ -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;
        
index a841456..96221d8 100644 (file)
@@ -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;
+}
index d942654..6de6f81 100644 (file)
@@ -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;
index 5f3b114..4cfba5e 100644 (file)
@@ -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
index a4907c1..0ff1cd9 100755 (executable)
@@ -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