Enhance EVP code to generate random symmetric keys of the
appropriate form, for example correct DES parity.

Update S/MIME code and EVP_SealInit to use new functions.

PR: 700
diff --git a/CHANGES b/CHANGES
index c5c2ebb..a72d5d6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 0.9.7c and 0.9.8  [xx XXX xxxx]
 
+  *) Add new EVP function EVP_CIPHER_CTX_rand_key and associated functionality.
+     This will generate a random key of the appropriate length based on the 
+     cipher context. The EVP_CIPHER can provide its own random key generation
+     routine to support keys of a specific form. This is used in the des and 
+     3des routines to generate a key of the correct parity. Update S/MIME
+     code to use new functions and hence generate correct parity DES keys.
+     Add EVP_CHECK_DES_KEY #define to return an error if the key is not 
+     valid (weak or incorrect parity).
+     [Steve Henson]
+
   *) Add a local set of CRLs that can be used by X509_verify_cert() as well
      as looking them up. This is useful when the verified structure may contain
      CRLs, for example PKCS#7 signedData. Modify PKCS7_verify() to use any CRLs
diff --git a/crypto/evp/e_des.c b/crypto/evp/e_des.c
index f2554ec..8563236 100644
--- a/crypto/evp/e_des.c
+++ b/crypto/evp/e_des.c
@@ -63,9 +63,11 @@
 #include <openssl/objects.h>
 #include "evp_locl.h"
 #include <openssl/des.h>
+#include <openssl/rand.h>
 
 static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 			const unsigned char *iv, int enc);
+static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
 
 /* Because of various casts and different names can't use IMPLEMENT_BLOCK_CIPHER */
 
@@ -127,26 +129,48 @@
     }
 
 BLOCK_CIPHER_defs(des, DES_key_schedule, NID_des, 8, 8, 8, 64,
-			0, des_init_key, NULL,
+			EVP_CIPH_RAND_KEY, des_init_key, NULL,
 			EVP_CIPHER_set_asn1_iv,
 			EVP_CIPHER_get_asn1_iv,
-			NULL)
+			des_ctrl)
 
-BLOCK_CIPHER_def_cfb(des,DES_key_schedule,NID_des,8,8,1,0,des_init_key,NULL,
+BLOCK_CIPHER_def_cfb(des,DES_key_schedule,NID_des,8,8,1,
+		     EVP_CIPH_RAND_KEY, des_init_key,NULL,
 		     EVP_CIPHER_set_asn1_iv,
-		     EVP_CIPHER_get_asn1_iv,NULL)
+		     EVP_CIPHER_get_asn1_iv,des_ctrl)
 
-BLOCK_CIPHER_def_cfb(des,DES_key_schedule,NID_des,8,8,8,0,des_init_key,NULL,
+BLOCK_CIPHER_def_cfb(des,DES_key_schedule,NID_des,8,8,8,
+		     EVP_CIPH_RAND_KEY,des_init_key,NULL,
 		     EVP_CIPHER_set_asn1_iv,
-		     EVP_CIPHER_get_asn1_iv,NULL)
+		     EVP_CIPHER_get_asn1_iv,des_ctrl)
 
 static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 			const unsigned char *iv, int enc)
 	{
 	DES_cblock *deskey = (DES_cblock *)key;
-
+#ifdef EVP_CHECK_DES_KEY
+	if(DES_set_key_checked(deskey,ctx->cipher_data) != 0)
+		return 0;
+#else
 	DES_set_key_unchecked(deskey,ctx->cipher_data);
+#endif
 	return 1;
 	}
 
+static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
+	{
+	
+	switch(type)
+		{
+	case EVP_CTRL_RAND_KEY:
+		if (RAND_bytes(ptr, 8) <= 0)
+			return 0;
+		DES_set_odd_parity((DES_cblock *)ptr);
+		return 1;
+
+	default:
+		return -1;
+		}
+	}
+
 #endif
diff --git a/crypto/evp/e_des3.c b/crypto/evp/e_des3.c
index 86342fb..ac148ef 100644
--- a/crypto/evp/e_des3.c
+++ b/crypto/evp/e_des3.c
@@ -63,6 +63,7 @@
 #include <openssl/objects.h>
 #include "evp_locl.h"
 #include <openssl/des.h>
+#include <openssl/rand.h>
 
 static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 			    const unsigned char *iv,int enc);
@@ -70,6 +71,8 @@
 static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 			     const unsigned char *iv,int enc);
 
+static int des3_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
+
 typedef struct
     {
     DES_key_schedule ks1;/* key schedule */
@@ -161,10 +164,10 @@
     }
 
 BLOCK_CIPHER_defs(des_ede, DES_EDE_KEY, NID_des_ede, 8, 16, 8, 64,
-			0, des_ede_init_key, NULL, 
+			EVP_CIPH_RAND_KEY, des_ede_init_key, NULL, 
 			EVP_CIPHER_set_asn1_iv,
 			EVP_CIPHER_get_asn1_iv,
-			NULL)
+			des3_ctrl)
 
 #define des_ede3_cfb64_cipher des_ede_cfb64_cipher
 #define des_ede3_ofb_cipher des_ede_ofb_cipher
@@ -172,28 +175,35 @@
 #define des_ede3_ecb_cipher des_ede_ecb_cipher
 
 BLOCK_CIPHER_defs(des_ede3, DES_EDE_KEY, NID_des_ede3, 8, 24, 8, 64,
-			0, des_ede3_init_key, NULL, 
+			EVP_CIPH_RAND_KEY, des_ede3_init_key, NULL, 
 			EVP_CIPHER_set_asn1_iv,
 			EVP_CIPHER_get_asn1_iv,
-			NULL)
+			des3_ctrl)
 
-BLOCK_CIPHER_def_cfb(des_ede3,DES_EDE_KEY,NID_des_ede3,24,8,1,0,
-		     des_ede3_init_key,NULL,
+BLOCK_CIPHER_def_cfb(des_ede3,DES_EDE_KEY,NID_des_ede3,24,8,1,
+		     EVP_CIPH_RAND_KEY, des_ede3_init_key,NULL,
 		     EVP_CIPHER_set_asn1_iv,
-		     EVP_CIPHER_get_asn1_iv,NULL)
+		     EVP_CIPHER_get_asn1_iv,
+		     des3_ctrl)
 
-BLOCK_CIPHER_def_cfb(des_ede3,DES_EDE_KEY,NID_des_ede3,24,8,8,0,
-		     des_ede3_init_key,NULL,
+BLOCK_CIPHER_def_cfb(des_ede3,DES_EDE_KEY,NID_des_ede3,24,8,8,
+		     EVP_CIPH_RAND_KEY, des_ede3_init_key,NULL,
 		     EVP_CIPHER_set_asn1_iv,
-		     EVP_CIPHER_get_asn1_iv,NULL)
+		     EVP_CIPHER_get_asn1_iv,
+		     des3_ctrl)
 
 static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 			    const unsigned char *iv, int enc)
 	{
 	DES_cblock *deskey = (DES_cblock *)key;
-
+#ifdef EVP_CHECK_DES_KEY
+	if (DES_set_key_checked(&deskey[0],&data(ctx)->ks1)
+		!! DES_set_key_checked(&deskey[1],&data(ctx)->ks2))
+		return 0;
+#else
 	DES_set_key_unchecked(&deskey[0],&data(ctx)->ks1);
 	DES_set_key_unchecked(&deskey[1],&data(ctx)->ks2);
+#endif
 	memcpy(&data(ctx)->ks3,&data(ctx)->ks1,
 	       sizeof(data(ctx)->ks1));
 	return 1;
@@ -214,13 +224,41 @@
 	}
 #endif	/* KSSL_DEBUG */
 
+#ifdef EVP_CHECK_DES_KEY
+	if (DES_set_key_checked(&deskey[0],&data(ctx)->ks1)
+		|| DES_set_key_checked(&deskey[1],&data(ctx)->ks2)
+		|| DES_set_key_checked(&deskey[2],&data(ctx)->ks3))
+		return 0;
+#else
 	DES_set_key_unchecked(&deskey[0],&data(ctx)->ks1);
 	DES_set_key_unchecked(&deskey[1],&data(ctx)->ks2);
 	DES_set_key_unchecked(&deskey[2],&data(ctx)->ks3);
-
+#endif
 	return 1;
 	}
 
+static int des3_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
+	{
+
+	DES_cblock *deskey = ptr;
+
+	switch(type)
+		{
+	case EVP_CTRL_RAND_KEY:
+		if (RAND_bytes(ptr, c->key_len) <= 0)
+			return 0;
+		DES_set_odd_parity(deskey);
+		if (c->key_len >= 16)
+			DES_set_odd_parity(deskey + 1);
+		if (c->key_len >= 24)
+			DES_set_odd_parity(deskey + 2);
+		return 1;
+
+	default:
+		return -1;
+		}
+	}
+
 const EVP_CIPHER *EVP_des_ede(void)
 {
 	return &des_ede_ecb;
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index ce5c210..6adbe89 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -332,6 +332,8 @@
 #define 	EVP_CIPH_CUSTOM_KEY_LENGTH	0x80
 /* Don't use standard block padding */
 #define 	EVP_CIPH_NO_PADDING		0x100
+/* cipher handles random key generation */
+#define 	EVP_CIPH_RAND_KEY		0x200
 
 /* ctrl() values */
 
@@ -341,6 +343,7 @@
 #define 	EVP_CTRL_SET_RC2_KEY_BITS	0x3
 #define 	EVP_CTRL_GET_RC5_ROUNDS		0x4
 #define 	EVP_CTRL_SET_RC5_ROUNDS		0x5
+#define 	EVP_CTRL_RAND_KEY		0x6
 
 typedef struct evp_cipher_info_st
 	{
@@ -567,6 +570,7 @@
 int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
 int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
 int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key);
 
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_md(void);
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index cecb09c..b5236b9 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -534,3 +534,13 @@
 	}
 	return ret;
 }
+
+int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
+	{
+	if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
+		return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key);
+	if (RAND_bytes(key, ctx->key_len) <= 0)
+		return 0;
+	return 1;
+	}
+
diff --git a/crypto/evp/p_seal.c b/crypto/evp/p_seal.c
index 37e547f..8cc8fcb 100644
--- a/crypto/evp/p_seal.c
+++ b/crypto/evp/p_seal.c
@@ -78,7 +78,7 @@
 	}
 	if ((npubk <= 0) || !pubk)
 		return 1;
-	if (RAND_bytes(key,EVP_MAX_KEY_LENGTH) <= 0)
+	if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
 		return 0;
 	if (EVP_CIPHER_CTX_iv_length(ctx))
 		RAND_pseudo_bytes(iv,EVP_CIPHER_CTX_iv_length(ctx));
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index 0b262fa..25483bc 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -215,11 +215,14 @@
 		BIO_get_cipher_ctx(btmp, &ctx);
 		keylen=EVP_CIPHER_key_length(evp_cipher);
 		ivlen=EVP_CIPHER_iv_length(evp_cipher);
-		if (RAND_bytes(key,keylen) <= 0)
-			goto err;
 		xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
 		if (ivlen > 0) RAND_pseudo_bytes(iv,ivlen);
-		EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, 1);
+		if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0)
+			goto err;
+		if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
+			goto err;
+		if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
+			goto err;
 
 		if (ivlen > 0) {
 			if (xalg->parameter == NULL) 
@@ -440,7 +443,8 @@
 
 		evp_ctx=NULL;
 		BIO_get_cipher_ctx(etmp,&evp_ctx);
-		EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0);
+		if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
+			goto err;
 		if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
 			goto err;
 
@@ -456,7 +460,8 @@
 				goto err;
 				}
 		} 
-		EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0);
+		if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
+			goto err;
 
 		OPENSSL_cleanse(tmp,jj);