Two new functions to write out PKCS#8 private keys. Also fixes for some of
the the PBE code and a new constant PKCS5_DEFAULT_ITER for the default
iteration count if it is passed as zero.
diff --git a/CHANGES b/CHANGES
index 28e929c..95ad74f 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 5145c63..30b9049 100644
--- a/crypto/asn1/p5_pbe.c
+++ b/crypto/asn1/p5_pbe.c
@@ -119,6 +119,7 @@
 		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 10364a0..0fc8df1 100644
--- a/crypto/asn1/p5_pbev2.c
+++ b/crypto/asn1/p5_pbev2.c
@@ -206,6 +206,7 @@
 	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 e7b55a58..570fe27 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -110,6 +110,8 @@
 #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>
diff --git a/crypto/evp/p5_crpt.c b/crypto/evp/p5_crpt.c
index 798cbe9..abf6af0 100644
--- a/crypto/evp/p5_crpt.c
+++ b/crypto/evp/p5_crpt.c
@@ -100,7 +100,7 @@
 
 	/* 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 7195324..6c7387b 100644
--- a/crypto/pem/pem.h
+++ b/crypto/pem/pem.h
@@ -67,6 +67,8 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 dce31c6..fa70f60 100644
--- a/crypto/pem/pem_err.c
+++ b/crypto/pem/pem_err.c
@@ -72,6 +72,7 @@
 {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 @@
 {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 @@
 {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 0c2af93..ec392ea 100644
--- a/crypto/pem/pem_info.c
+++ b/crypto/pem/pem_info.c
@@ -272,7 +272,6 @@
 	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 a841456..96221d8 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 @@
 	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 d942654..6de6f81 100644
--- a/crypto/pkcs12/p12_crpt.c
+++ b/crypto/pkcs12/p12_crpt.c
@@ -92,7 +92,7 @@
 
 	/* 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 5f3b114..4cfba5e 100644
--- a/crypto/pkcs12/pkcs12.h
+++ b/crypto/pkcs12/pkcs12.h
@@ -72,7 +72,7 @@
 
 /* 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 a4907c1..0ff1cd9 100755
--- a/util/libeay.num
+++ b/util/libeay.num
@@ -1769,3 +1769,5 @@
 PKCS5_pbe2_set                          1794
 PKCS5_PBKDF2_HMAC_SHA1                  1795
 PKCS5_v2_PBE_keyivgen                   1796
+PEM_write_bio_PKCS8PrivateKey           1797
+PEM_write_PKCS8PrivateKey               1798