Add ECDH support.

Additional changes:
 - use EC_GROUP_get_degree() in apps/req.c
 - add ECDSA and ECDH to apps/speed.c
 - adds support for EC curves over binary fields to ECDSA
 - new function EC_KEY_up_ref() in crypto/ec/ec_key.c
 - reorganize crypto/ecdsa/ecdsatest.c
 - add engine support for ECDH
 - fix a few bugs in ECDSA engine support

Submitted by: Douglas Stebila <douglas.stebila@sun.com>
diff --git a/apps/speed.c b/apps/speed.c
index fea0ffe..05d2b31 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -55,6 +55,32 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * In addition, Sun covenants to all licensees who provide a reciprocal
+ * covenant with respect to their own patents if any, not to sue under
+ * current and future patent claims necessarily infringed by the making,
+ * using, practicing, selling, offering for sale and/or otherwise
+ * disposing of the Contribution as delivered hereunder 
+ * (or portions thereof), provided that such covenant shall not apply:
+ *  1) for code that a licensee deletes from the Contribution;
+ *  2) separates from the Contribution; or
+ *  3) for infringements caused by:
+ *       i) the modification of the Contribution or
+ *      ii) the combination of the Contribution with other software or
+ *          devices where such combination causes the infringement.
+ *
+ * The ECDH and ECDSA speed test software is originally written by 
+ * Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
 
 /* most of this code has been pilfered from my libdes speed.c program */
 
@@ -62,6 +88,8 @@
 #define SECONDS		3	
 #define RSA_SECONDS	10
 #define DSA_SECONDS	10
+#define ECDSA_SECONDS   10
+#define ECDH_SECONDS    10
 
 /* 11-Sep-92 Andrew Daviel   Support for Silicon Graphics IRIX added */
 /* 06-Apr-92 Luke Brennan    Support for VMS and add extra signal calls */
@@ -184,6 +212,12 @@
 #ifndef OPENSSL_NO_DSA
 #include "./testdsa.h"
 #endif
+#ifndef OPENSSL_NO_ECDSA
+#include <openssl/ecdsa.h>
+#endif
+#ifndef OPENSSL_NO_ECDH
+#include <openssl/ecdh.h>
+#endif
 
 /* The following if from times(3) man page.  It may need to be changed */
 #ifndef HZ
@@ -226,6 +260,10 @@
 #define SIZE_NUM	5
 #define RSA_NUM		4
 #define DSA_NUM		3
+
+#define EC_NUM       15
+#define MAX_ECDH_SIZE 256
+
 static const char *names[ALGOR_NUM]={
   "md2","mdc2","md4","md5","hmac(md5)","sha1","rmd160","rc4",
   "des cbc","des ede3","idea cbc",
@@ -235,6 +273,9 @@
 static int lengths[SIZE_NUM]={16,64,256,1024,8*1024};
 static double rsa_results[RSA_NUM][2];
 static double dsa_results[DSA_NUM][2];
+static double ecdsa_results[EC_NUM][2];
+static double ecdh_results[EC_NUM][1];
+
 
 #ifdef SIGALRM
 #if defined(__STDC__) || defined(sgi) || defined(_AIX)
@@ -477,6 +518,23 @@
 #define	R_RSA_1024	1
 #define	R_RSA_2048	2
 #define	R_RSA_4096	3
+
+#define R_EC_P160    0
+#define R_EC_P224    1
+#define R_EC_P256    2
+#define R_EC_P384    3
+#define R_EC_P521    4
+#define R_EC_K163    5
+#define R_EC_K233    6
+#define R_EC_K283    7
+#define R_EC_K409    8
+#define R_EC_K571    9
+#define R_EC_B163    10
+#define R_EC_B233    11
+#define R_EC_B283    12
+#define R_EC_B409    13
+#define R_EC_B571    14
+
 #ifndef OPENSSL_NO_RSA
 	RSA *rsa_key[RSA_NUM];
 	long rsa_c[RSA_NUM][2];
@@ -492,8 +550,81 @@
 	long dsa_c[DSA_NUM][2];
 	static unsigned int dsa_bits[DSA_NUM]={512,1024,2048};
 #endif
+#ifndef OPENSSL_NO_EC
+	/* We only test over the following curves as they are representative, 
+	 * To add tests over more curves, simply add the curve NID
+	 * and curve name to the following arrays and increase the 
+	 * EC_NUM value accordingly. 
+	 */
+	static unsigned int test_curves[EC_NUM] = 
+	{	
+	/* Prime Curves */
+	EC_GROUP_SECG_PRIME_160R1,
+	EC_GROUP_NIST_PRIME_224,
+	EC_GROUP_NIST_PRIME_256,
+	EC_GROUP_NIST_PRIME_384,
+	EC_GROUP_NIST_PRIME_521,
+	/* Binary Curves */
+	EC_GROUP_NIST_CHAR2_K163,
+	EC_GROUP_NIST_CHAR2_K233,
+	EC_GROUP_NIST_CHAR2_K283,
+	EC_GROUP_NIST_CHAR2_K409,
+	EC_GROUP_NIST_CHAR2_K571,
+	EC_GROUP_NIST_CHAR2_B163,
+	EC_GROUP_NIST_CHAR2_B233,
+	EC_GROUP_NIST_CHAR2_B283,
+	EC_GROUP_NIST_CHAR2_B409,
+	EC_GROUP_NIST_CHAR2_B571
+	}; 
+	static char * test_curves_names[EC_NUM] = 
+	{
+	/* Prime Curves */
+	"secp160r1",
+	"nistp224",
+	"nistp256",
+	"nistp384",
+	"nistp521",
+	/* Binary Curves */
+	"nistk163",
+	"nistk233",
+	"nistk283",
+	"nistk409",
+	"nistk571",
+	"nistb163",
+	"nistb233",
+	"nistb283",
+	"nistb409",
+	"nistb571"
+	};
+	static int test_curves_bits[EC_NUM] =
+        {
+        160, 224, 256, 384, 521,
+        163, 233, 283, 409, 571,
+        163, 233, 283, 409, 571
+        };
+
+#endif
+
+#ifndef OPENSSL_NO_ECDSA
+        unsigned char ecdsasig[256];
+        unsigned int ecdsasiglen;
+        EC_KEY *ecdsa[EC_NUM];
+        long ecdsa_c[EC_NUM][2];
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+        EC_KEY *ecdh_a[EC_NUM], *ecdh_b[EC_NUM];
+        unsigned char secret_a[MAX_ECDH_SIZE], secret_b[MAX_ECDH_SIZE];
+        int secret_size_a, secret_size_b;
+        int ecdh_check = 0;
+        int secret_idx = 0;
+        long ecdh_c[EC_NUM][2];
+#endif
+
 	int rsa_doit[RSA_NUM];
 	int dsa_doit[DSA_NUM];
+	int ecdsa_doit[EC_NUM];
+        int ecdh_doit[EC_NUM];
 	int doit[ALGOR_NUM];
 	int pr_header=0;
 	const EVP_CIPHER *evp_cipher=NULL;
@@ -512,6 +643,17 @@
 #ifndef OPENSSL_NO_DSA
 	memset(dsa_key,0,sizeof(dsa_key));
 #endif
+#ifndef OPENSSL_NO_ECDSA
+	for (i=0; i<EC_NUM; i++) ecdsa[i] = NULL;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	for (i=0; i<EC_NUM; i++)
+		{
+		ecdh_a[i] = NULL;
+		ecdh_b[i] = NULL;
+		}
+#endif
+
 
 	if (bio_err == NULL)
 		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
@@ -550,6 +692,15 @@
 		rsa_doit[i]=0;
 	for (i=0; i<DSA_NUM; i++)
 		dsa_doit[i]=0;
+#ifndef OPENSSL_NO_ECDSA
+	for (i=0; i<EC_NUM; i++)
+		ecdsa_doit[i]=0;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	for (i=0; i<EC_NUM; i++)
+		ecdh_doit[i]=0;
+#endif
+
 	
 	j=0;
 	argc--;
@@ -769,6 +920,52 @@
 			}
 		else
 #endif
+#ifndef OPENSSL_NO_ECDSA
+		     if (strcmp(*argv,"ecdsap160") == 0) ecdsa_doit[R_EC_P160]=2;
+		else if (strcmp(*argv,"ecdsap224") == 0) ecdsa_doit[R_EC_P224]=2;
+		else if (strcmp(*argv,"ecdsap256") == 0) ecdsa_doit[R_EC_P256]=2;
+		else if (strcmp(*argv,"ecdsap384") == 0) ecdsa_doit[R_EC_P384]=2;
+		else if (strcmp(*argv,"ecdsap521") == 0) ecdsa_doit[R_EC_P521]=2;
+		else if (strcmp(*argv,"ecdsak163") == 0) ecdsa_doit[R_EC_K163]=2;
+		else if (strcmp(*argv,"ecdsak233") == 0) ecdsa_doit[R_EC_K233]=2;
+		else if (strcmp(*argv,"ecdsak283") == 0) ecdsa_doit[R_EC_K283]=2;
+		else if (strcmp(*argv,"ecdsak409") == 0) ecdsa_doit[R_EC_K409]=2;
+		else if (strcmp(*argv,"ecdsak571") == 0) ecdsa_doit[R_EC_K571]=2;
+		else if (strcmp(*argv,"ecdsab163") == 0) ecdsa_doit[R_EC_B163]=2;
+		else if (strcmp(*argv,"ecdsab233") == 0) ecdsa_doit[R_EC_B233]=2;
+		else if (strcmp(*argv,"ecdsab283") == 0) ecdsa_doit[R_EC_B283]=2;
+		else if (strcmp(*argv,"ecdsab409") == 0) ecdsa_doit[R_EC_B409]=2;
+		else if (strcmp(*argv,"ecdsab571") == 0) ecdsa_doit[R_EC_B571]=2;
+		else if (strcmp(*argv,"ecdsa") == 0)
+			{
+			for (i=0; i < EC_NUM; i++)
+				ecdsa_doit[i]=1;
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_ECDH
+		     if (strcmp(*argv,"ecdhp160") == 0) ecdh_doit[R_EC_P160]=2;
+		else if (strcmp(*argv,"ecdhp224") == 0) ecdh_doit[R_EC_P224]=2;
+		else if (strcmp(*argv,"ecdhp256") == 0) ecdh_doit[R_EC_P256]=2;
+		else if (strcmp(*argv,"ecdhp384") == 0) ecdh_doit[R_EC_P384]=2;
+		else if (strcmp(*argv,"ecdhp521") == 0) ecdh_doit[R_EC_P521]=2;
+		else if (strcmp(*argv,"ecdhk163") == 0) ecdh_doit[R_EC_K163]=2;
+		else if (strcmp(*argv,"ecdhk233") == 0) ecdh_doit[R_EC_K233]=2;
+		else if (strcmp(*argv,"ecdhk283") == 0) ecdh_doit[R_EC_K283]=2;
+		else if (strcmp(*argv,"ecdhk409") == 0) ecdh_doit[R_EC_K409]=2;
+		else if (strcmp(*argv,"ecdhk571") == 0) ecdh_doit[R_EC_K571]=2;
+		else if (strcmp(*argv,"ecdhb163") == 0) ecdh_doit[R_EC_B163]=2;
+		else if (strcmp(*argv,"ecdhb233") == 0) ecdh_doit[R_EC_B233]=2;
+		else if (strcmp(*argv,"ecdhb283") == 0) ecdh_doit[R_EC_B283]=2;
+		else if (strcmp(*argv,"ecdhb409") == 0) ecdh_doit[R_EC_B409]=2;
+		else if (strcmp(*argv,"ecdhb571") == 0) ecdh_doit[R_EC_B571]=2;
+		else if (strcmp(*argv,"ecdh") == 0)
+			{
+			for (i=0; i < EC_NUM; i++)
+				ecdh_doit[i]=1;
+			}
+		else
+#endif
 			{
 			BIO_printf(bio_err,"Error: bad option or value\n");
 			BIO_printf(bio_err,"\n");
@@ -834,6 +1031,18 @@
 #ifndef OPENSSL_NO_DSA
 			BIO_printf(bio_err,"dsa512   dsa1024  dsa2048\n");
 #endif
+#ifndef OPENSSL_NO_ECDSA
+			BIO_printf(bio_err,"ecdsap160 ecdsap224 ecdsap256 ecdsap384 ecdsap521\n");
+			BIO_printf(bio_err,"ecdsak163 ecdsak233 ecdsak283 ecdsak409 ecdsak571\n");
+			BIO_printf(bio_err,"ecdsab163 ecdsab233 ecdsab283 ecdsab409 ecdsab571\n");
+			BIO_printf(bio_err,"ecdsa\n");
+#endif
+#ifndef OPENSSL_NO_ECDH
+			BIO_printf(bio_err,"ecdhp160  ecdhp224  ecdhp256  ecdhp384  ecdhp521\n");
+			BIO_printf(bio_err,"ecdhk163  ecdhk233  ecdhk283  ecdhk409  ecdhk571\n");
+			BIO_printf(bio_err,"ecdhb163  ecdhb233  ecdhb283  ecdhb409  ecdhb571\n");
+			BIO_printf(bio_err,"ecdh\n");
+#endif
 
 #ifndef OPENSSL_NO_IDEA
 			BIO_printf(bio_err,"idea     ");
@@ -1063,6 +1272,114 @@
 		}
 #endif
 
+#ifndef OPENSSL_NO_ECDSA
+	ecdsa_c[R_EC_P160][0]=count/1000;
+	ecdsa_c[R_EC_P160][1]=count/1000/2;
+	for (i=R_EC_P224; i<=R_EC_P521; i++)
+		{
+		ecdsa_c[i][0]=ecdsa_c[i-1][0]/2;
+		ecdsa_c[i][1]=ecdsa_c[i-1][1]/2;
+		if ((ecdsa_doit[i] <= 1) && (ecdsa_c[i][0] == 0))
+			ecdsa_doit[i]=0;
+		else
+			{
+			if (ecdsa_c[i] == 0)
+				{
+				ecdsa_c[i][0]=1;
+				ecdsa_c[i][1]=1;
+				}
+			}
+		}
+	ecdsa_c[R_EC_K163][0]=count/1000;
+	ecdsa_c[R_EC_K163][1]=count/1000/2;
+	for (i=R_EC_K233; i<=R_EC_K571; i++)
+		{
+		ecdsa_c[i][0]=ecdsa_c[i-1][0]/2;
+		ecdsa_c[i][1]=ecdsa_c[i-1][1]/2;
+		if ((ecdsa_doit[i] <= 1) && (ecdsa_c[i][0] == 0))
+			ecdsa_doit[i]=0;
+		else
+			{
+			if (ecdsa_c[i] == 0)
+				{
+				ecdsa_c[i][0]=1;
+				ecdsa_c[i][1]=1;
+				}
+			}
+		}
+	ecdsa_c[R_EC_B163][0]=count/1000;
+	ecdsa_c[R_EC_B163][1]=count/1000/2;
+	for (i=R_EC_B233; i<=R_EC_B571; i++)
+		{
+		ecdsa_c[i][0]=ecdsa_c[i-1][0]/2;
+		ecdsa_c[i][1]=ecdsa_c[i-1][1]/2;
+		if ((ecdsa_doit[i] <= 1) && (ecdsa_c[i][0] == 0))
+			ecdsa_doit[i]=0;
+		else
+			{
+			if (ecdsa_c[i] == 0)
+				{
+				ecdsa_c[i][0]=1;
+				ecdsa_c[i][1]=1;
+				}
+			}
+		}
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	ecdh_c[R_EC_P160][0]=count/1000;
+	ecdh_c[R_EC_P160][1]=count/1000;
+	for (i=R_EC_P224; i<=R_EC_P521; i++)
+		{
+		ecdh_c[i][0]=ecdh_c[i-1][0]/2;
+		ecdh_c[i][1]=ecdh_c[i-1][1]/2;
+		if ((ecdh_doit[i] <= 1) && (ecdh_c[i][0] == 0))
+			ecdh_doit[i]=0;
+		else
+			{
+			if (ecdh_c[i] == 0)
+				{
+				ecdh_c[i][0]=1;
+				ecdh_c[i][1]=1;
+				}
+			}
+		}
+	ecdh_c[R_EC_K163][0]=count/1000;
+	ecdh_c[R_EC_K163][1]=count/1000;
+	for (i=R_EC_K233; i<=R_EC_K571; i++)
+		{
+		ecdh_c[i][0]=ecdh_c[i-1][0]/2;
+		ecdh_c[i][1]=ecdh_c[i-1][1]/2;
+		if ((ecdh_doit[i] <= 1) && (ecdh_c[i][0] == 0))
+			ecdh_doit[i]=0;
+		else
+			{
+			if (ecdh_c[i] == 0)
+				{
+				ecdh_c[i][0]=1;
+				ecdh_c[i][1]=1;
+				}
+			}
+		}
+	ecdh_c[R_EC_B163][0]=count/1000;
+	ecdh_c[R_EC_B163][1]=count/1000;
+	for (i=R_EC_B233; i<=R_EC_B571; i++)
+		{
+		ecdh_c[i][0]=ecdh_c[i-1][0]/2;
+		ecdh_c[i][1]=ecdh_c[i-1][1]/2;
+		if ((ecdh_doit[i] <= 1) && (ecdh_c[i][0] == 0))
+			ecdh_doit[i]=0;
+		else
+			{
+			if (ecdh_c[i] == 0)
+				{
+				ecdh_c[i][0]=1;
+				ecdh_c[i][1]=1;
+				}
+			}
+		}
+#endif
+
 #define COND(d)	(count < (d))
 #define COUNT(d) (d)
 #else
@@ -1587,6 +1904,215 @@
 		}
 	if (rnd_fake) RAND_cleanup();
 #endif
+
+#ifndef OPENSSL_NO_ECDSA
+	if (RAND_status() != 1) 
+		{
+		RAND_seed(rnd_seed, sizeof rnd_seed);
+		rnd_fake = 1;
+		}
+	for (j=0; j<EC_NUM; j++) 
+		{
+		int ret;
+
+		if (!ecdsa_doit[j]) continue; /* Ignore Curve */ 
+		ecdsa[j] = EC_KEY_new();
+		if (ecdsa[j] == NULL) 
+			{
+			BIO_printf(bio_err,"ECDSA failure.\n");
+			ERR_print_errors(bio_err);
+			rsa_count=1;
+			} 
+		else 
+			{
+			ecdsa[j]->group = EC_GROUP_new_by_nid(test_curves[j]);
+			/* Could not obtain group information */
+			if (ecdsa[j]->group == NULL) 
+				{
+				BIO_printf(bio_err,"ECDSA failure.Could not obtain group information\n");
+				ERR_print_errors(bio_err);
+				rsa_count=1;
+				} 
+			else 
+				{
+				/* Perform ECDSA signature test */
+				EC_KEY_generate_key(ecdsa[j]);
+				ret = ECDSA_sign(EVP_PKEY_ECDSA, buf, 20, ecdsasig, 
+					&ecdsasiglen, ecdsa[j]);
+				if (ret == 0) 
+					{
+					BIO_printf(bio_err,"ECDSA sign failure.  No ECDSA sign will be done.\n");
+					ERR_print_errors(bio_err);
+					rsa_count=1;
+					} 
+				else 
+					{
+					pkey_print_message("sign","ecdsa",
+						ecdsa_c[j][0], 
+						test_curves_bits[j],
+						ECDSA_SECONDS);
+
+					Time_F(START);
+					for (count=0,run=1; COND(ecdsa_c[j][0]); count++) 
+						{
+						ret=ECDSA_sign(EVP_PKEY_ECDSA, buf, 20, ecdsasig, &ecdsasiglen, ecdsa[j]);
+						if (ret == 0) 
+							{
+							BIO_printf(bio_err, "ECDSA sign failure\n");
+							ERR_print_errors(bio_err);
+							count=1;
+							break;
+							}
+						}
+						d=Time_F(STOP);
+
+						BIO_printf(bio_err, mr ? "+R5:%ld:%d:%.2f\n" :
+						"%ld %d bit ECDSA signs in %.2fs \n", 
+						count, test_curves_bits[j], d);
+						ecdsa_results[j][0]=d/(double)count;
+						rsa_count=count;
+					}
+
+				/* Perform ECDSA verification test */
+				ret=ECDSA_verify(EVP_PKEY_ECDSA, buf, 20, ecdsasig, ecdsasiglen, ecdsa[j]);
+				if (ret != 1) 
+					{
+					BIO_printf(bio_err,"ECDSA verify failure.  No ECDSA verify will be done.\n");
+					ERR_print_errors(bio_err);
+					ecdsa_doit[j] = 0;
+					} 
+				else 
+					{
+					pkey_print_message("verify","ecdsa",
+					ecdsa_c[j][1],
+					test_curves_bits[j],
+					ECDSA_SECONDS);
+					Time_F(START);
+					for (count=0,run=1; COND(ecdsa_c[j][1]); count++) 
+						{
+						ret=ECDSA_verify(0, buf, 20, ecdsasig, ecdsasiglen, ecdsa[j]);
+						if (ret != 1) 
+							{
+							BIO_printf(bio_err, "ECDSA verify failure\n");
+							ERR_print_errors(bio_err);
+							count=1;
+							break;
+							}
+						}
+						d=Time_F(STOP);
+						BIO_printf(bio_err, mr? "+R6:%ld:%d:%.2f\n"
+							: "%ld %d bit ECDSA verify in %.2fs\n",
+						count, test_curves_bits[j], d);
+						ecdsa_results[j][1]=d/(double)count;
+					}
+
+				if (rsa_count <= 1) 
+					{
+					/* if longer than 10s, don't do any more */
+					for (j++; j<EC_NUM; j++)
+					ecdsa_doit[j]=0;
+					}
+				}
+			}
+		}
+	if (rnd_fake) RAND_cleanup();
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	if (RAND_status() != 1)
+		{
+		RAND_seed(rnd_seed, sizeof rnd_seed);
+		rnd_fake = 1;
+		}
+	for (j=0; j<EC_NUM; j++)
+		{
+		if (!ecdh_doit[j]) continue;
+		ecdh_a[j] = EC_KEY_new();
+		ecdh_b[j] = EC_KEY_new();
+		if ((ecdh_a[j] == NULL) || (ecdh_b[j] == NULL))
+			{
+			BIO_printf(bio_err,"ECDH failure.\n");
+			ERR_print_errors(bio_err);
+			rsa_count=1;
+			}
+		else
+			{
+			ecdh_a[j]->group = EC_GROUP_new_by_nid(test_curves[j]);
+			if (ecdh_a[j]->group == NULL)
+				{
+				BIO_printf(bio_err,"ECDH failure.\n");
+				ERR_print_errors(bio_err);
+				rsa_count=1;
+				}
+			else
+				{
+				ecdh_b[j]->group = ecdh_a[j]->group;
+
+				/* generate two ECDH key pairs */
+				if (!EC_KEY_generate_key(ecdh_a[j]) ||
+					!EC_KEY_generate_key(ecdh_b[j]))
+					{
+					BIO_printf(bio_err,"ECDH key generation failure.\n");
+					ERR_print_errors(bio_err);
+					rsa_count=1;		
+					}
+				else
+					{
+					secret_size_a = ECDH_compute_key(secret_a, 
+						ecdh_b[j]->pub_key,
+						ecdh_a[j]);
+					secret_size_b = ECDH_compute_key(secret_b, 
+						ecdh_a[j]->pub_key,
+						ecdh_b[j]);
+					if (secret_size_a != secret_size_b) 
+						ecdh_check = 0;
+					else
+						ecdh_check = 1;
+
+					for (secret_idx = 0; 
+					    (secret_idx < secret_size_a) && (ecdh_check == 1);
+					    secret_idx++)
+						{
+						if (secret_a[secret_idx] != secret_b[secret_idx])
+						ecdh_check = 0;
+						}
+
+					if (ecdh_check == 0)
+						{
+						BIO_printf(bio_err,"ECDH computations don't match.\n");
+						ERR_print_errors(bio_err);
+						rsa_count=1;		
+						}
+
+					pkey_print_message("","ecdh",
+					ecdh_c[j][0], 
+					test_curves_bits[j],
+					ECDH_SECONDS);
+					Time_F(START);
+					for (count=0,run=1; COND(ecdh_c[j][0]); count++)
+						{
+						ECDH_compute_key(secret_a, 
+						ecdh_b[j]->pub_key,
+						ecdh_a[j]);
+						}
+					d=Time_F(STOP);
+					BIO_printf(bio_err, mr ? "+R7:%ld:%d:%.2f\n" :"%ld %d-bit ECDH ops in %.2fs\n",
+					count, test_curves_bits[j], d);
+					ecdh_results[j][0]=d/(double)count;
+					rsa_count=count;
+					}
+				}
+			}
+
+		if (rsa_count <= 1)
+			{
+			/* if longer than 10s, don't do any more */
+			for (j++; j<EC_NUM; j++)
+			ecdh_doit[j]=0;
+			}
+		}
+	if (rnd_fake) RAND_cleanup();
+#endif
 #ifdef HAVE_FORK
 show_res:
 #endif
@@ -1712,7 +2238,57 @@
 				1.0/dsa_results[k][0],1.0/dsa_results[k][1]);
 		}
 #endif
+#ifndef OPENSSL_NO_ECDSA
+	j=1;
+	for (k=0; k<EC_NUM; k++)
+		{
+		if (!ecdsa_doit[k]) continue;
+		if (j && !mr)
+			{
+			printf("%30ssign    verify    sign/s verify/s\n"," ");
+			j=0;
+			}
+
+		if (mr)
+			fprintf(stdout,"+F4:%u:%u:%f:%f\n", 
+				k, test_curves_bits[k],
+				ecdsa_results[k][0],ecdsa_results[k][1]);
+		else
+			fprintf(stdout,
+				"%4u bit ecdsa (%s) %8.4fs %8.4fs %8.1f %8.1f\n", 
+				test_curves_bits[k],
+				test_curves_names[k],
+				ecdsa_results[k][0],ecdsa_results[k][1], 
+				1.0/ecdsa_results[k][0],1.0/ecdsa_results[k][1]);
+		}
+#endif
+
+
+#ifndef OPENSSL_NO_ECDH
+	j=1;
+	for (k=0; k<EC_NUM; k++)
+		{
+		if (!ecdh_doit[k]) continue;
+		if (j && !mr)
+			{
+			printf("%30sop      op/s\n"," ");
+			j=0;
+			}
+		if (mr)
+			fprintf(stdout,"+F5:%u:%u:%f:%f\n",
+				k, test_curves_bits[k],
+				ecdh_results[k][0], 1.0/ecdh_results[k][0]);
+
+		else
+			fprintf(stdout,"%4u bit ecdh (%s) %8.4fs %8.1f\n",
+				test_curves_bits[k],
+				test_curves_names[k],
+				ecdh_results[k][0], 1.0/ecdh_results[k][0]);
+		}
+#endif
+
 	mret=0;
+
 end:
 	ERR_print_errors(bio_err);
 	if (buf != NULL) OPENSSL_free(buf);
@@ -1727,6 +2303,22 @@
 		if (dsa_key[i] != NULL)
 			DSA_free(dsa_key[i]);
 #endif
+
+#ifndef OPENSSL_NO_ECDSA
+	for (i=0; i<EC_NUM; i++)
+		if (ecdsa[i] != NULL)
+			EC_KEY_free(ecdsa[i]);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	for (i=0; i<EC_NUM; i++)
+	{
+		if (ecdh_a[i] != NULL)
+			EC_KEY_free(ecdh_a[i]);
+		if (ecdh_b[i] != NULL)
+			EC_KEY_free(ecdh_b[i]);
+	}
+#endif
+
 	apps_shutdown();
 	EXIT(mret);
 	}
@@ -1928,6 +2520,49 @@
 				else
 					dsa_results[k][1]=d;
 				}
+#ifndef OPENSSL_NO_ECDSA
+			else if(!strncmp(buf,"+F4:",4))
+				{
+				int k;
+				double d;
+				
+				p=buf+4;
+				k=atoi(sstrsep(&p,sep));
+				sstrsep(&p,sep);
+
+				d=atof(sstrsep(&p,sep));
+				if(n)
+					ecdsa_results[k][0]=1/(1/ecdsa_results[k][0]+1/d);
+				else
+					ecdsa_results[k][0]=d;
+
+				d=atof(sstrsep(&p,sep));
+				if(n)
+					ecdsa_results[k][1]=1/(1/ecdsa_results[k][1]+1/d);
+				else
+					ecdsa_results[k][1]=d;
+				}
+#endif 
+
+#ifndef OPENSSL_NO_ECDH
+			else if(!strncmp(buf,"+F5:",4))
+				{
+				int k;
+				double d;
+				
+				p=buf+4;
+				k=atoi(sstrsep(&p,sep));
+				sstrsep(&p,sep);
+
+				d=atof(sstrsep(&p,sep));
+				if(n)
+					ecdh_results[k][0]=1/(1/ecdh_results[k][0]+1/d);
+				else
+					ecdh_results[k][0]=d;
+
+				}
+#endif
+
 			else if(!strncmp(buf,"+H:",3))
 				{
 				}