ECC ciphersuite support

Submitted by: Douglas Stebila <douglas.stebila@sun.com>
(Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories)
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8864366..a558836 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -108,6 +108,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #include <limits.h>
 #include <string.h>
@@ -520,6 +525,23 @@
 			else ret= -1;
 			}
 		}
+#ifndef OPENSSL_NO_EC
+	/* XXX: Structurally, there is no distinction between 
+	 * ECDSA and ECDH public keys (both are ECPoints).
+	 * So EVP_PKEY_ECDSA should really be renamed EVP_PKEY_ECC
+	 * (or similar). As for ECC certificates, additional
+	 * information (e.g. in the optional key usage X509v3 
+	 * extension) could be used when available to distinguish
+	 * between ECDH and ECDSA certificates. For now, we do not
+	 * make that distinction here. Instead, we shift the burden
+	 * of checking for appropriate key usage to the SSL code
+	 * responsible for sending/processing ECC certificates.
+	 */
+	else if (i == EVP_PKEY_ECDSA)
+		{
+		ret = SSL_PKEY_ECC;
+		}
+#endif
 	else
 		ret= -1;
 
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 2b58482..74e1e52 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -108,6 +108,32 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * 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.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
 
 #include <stdio.h>
 #include "ssl_locl.h"
@@ -131,6 +157,12 @@
 static int ssl3_get_key_exchange(SSL *s);
 static int ssl3_get_server_certificate(SSL *s);
 static int ssl3_check_cert_and_algorithm(SSL *s);
+
+#ifndef OPENSSL_NO_ECDH
+static int curve_id2nid(int curve_id);
+int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs);
+#endif
+
 static SSL_METHOD *ssl3_get_client_method(int ver)
 	{
 	if (ver == SSL3_VERSION)
@@ -262,7 +294,7 @@
 
 		case SSL3_ST_CR_CERT_A:
 		case SSL3_ST_CR_CERT_B:
-			/* Check if it is anon DH */
+			/* Check if it is anon DH/ECDH */
 			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
 				{
 				ret=ssl3_get_server_certificate(s);
@@ -329,6 +361,13 @@
 			 * sent back */
 			/* For TLS, cert_req is set to 2, so a cert chain
 			 * of nothing is sent, but no verify packet is sent */
+			/* XXX: For now, we do not support client 
+			 * authentication in ECDH cipher suites with
+			 * ECDH (rather than ECDSA) certificates.
+			 * We need to skip the certificate verify 
+			 * message when client's ECDH public key is sent 
+			 * inside the client certificate.
+			 */
 			if (s->s3->tmp.cert_req == 1)
 				{
 				s->state=SSL3_ST_CW_CERT_VRFY_A;
@@ -944,6 +983,13 @@
 #ifndef OPENSSL_NO_DH
 	DH *dh=NULL;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh = NULL;
+	BN_CTX *bn_ctx = NULL;
+	EC_POINT *srvr_ecpoint = NULL;
+	int curve_nid = 0;
+	int encoded_pt_len = 0;
+#endif
 
 	/* use same message size as in ssl3_get_certificate_request()
 	 * as ServerKeyExchange message may be skipped */
@@ -980,6 +1026,13 @@
 			s->session->sess_cert->peer_dh_tmp=NULL;
 			}
 #endif
+#ifndef OPENSSL_NO_ECDH
+		if (s->session->sess_cert->peer_ecdh_tmp)
+			{
+			EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
+			s->session->sess_cert->peer_ecdh_tmp=NULL;
+			}
+#endif
 		}
 	else
 		{
@@ -1121,6 +1174,101 @@
 		goto f_err;
 		}
 #endif /* !OPENSSL_NO_DH */
+
+#ifndef OPENSSL_NO_ECDH
+	else if (alg & SSL_kECDHE)
+		{
+		if ((ecdh=EC_KEY_new()) == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		/* Extract elliptic curve parameters and the
+		 * server's ephemeral ECDH public key.
+		 * Keep accumulating lengths of various components in
+		 * param_len and make sure it never exceeds n.
+		 */
+
+		/* XXX: For now we only support named (not generic) curves
+		 * and the ECParameters in this case is just two bytes.
+		 */
+		param_len=2;
+		if ((param_len > n) ||
+		    (*p != NAMED_CURVE_TYPE) || 
+		    ((curve_nid = curve_id2nid(*(p + 1))) == 0)) 
+			{
+			al=SSL_AD_INTERNAL_ERROR;
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+			goto f_err;
+			}
+
+		if (!(ecdh->group=EC_GROUP_new_by_nid(curve_nid)))
+			{
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_EC_LIB);
+			goto err;
+			}
+
+		if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+		    (EC_GROUP_get_degree(ecdh->group) > 163))
+			{
+			al=SSL_AD_EXPORT_RESTRICTION;
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+			goto f_err;
+			}
+
+		p+=2;
+
+		/* Next, get the encoded ECPoint */
+		if (((srvr_ecpoint = EC_POINT_new(ecdh->group)) == NULL) ||
+		    ((bn_ctx = BN_CTX_new()) == NULL))
+			{
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		encoded_pt_len = *p;  /* length of encoded point */
+		p+=1;
+		param_len += (1 + encoded_pt_len);
+		if ((param_len > n) ||
+		    (EC_POINT_oct2point(ecdh->group, srvr_ecpoint, 
+			p, encoded_pt_len, bn_ctx) == 0))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_ECPOINT);
+			goto f_err;
+			}
+
+		n-=param_len;
+		p+=encoded_pt_len;
+
+		/* The ECC/TLS specification does not mention
+		 * the use of DSA to sign ECParameters in the server
+		 * key exchange message. We do support RSA and ECDSA.
+		 */
+		if (0) ;
+#ifndef OPENSSL_NO_RSA
+		else if (alg & SSL_aRSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		else if (alg & SSL_aECDSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+#endif
+		/* else anonymous ECDH, so no certificate or pkey. */
+		ecdh->pub_key = srvr_ecpoint;
+		s->session->sess_cert->peer_ecdh_tmp=ecdh;
+		ecdh=NULL;
+		BN_CTX_free(bn_ctx);
+		srvr_ecpoint = NULL;
+		}
+	else if (alg & SSL_kECDH)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+		goto f_err;
+		}
+#endif /* !OPENSSL_NO_ECDH */
 	if (alg & SSL_aFZA)
 		{
 		al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1131,7 +1279,6 @@
 
 	/* p points to the next byte, there are 'n' bytes left */
 
-
 	/* if it was signed, check the signature */
 	if (pkey != NULL)
 		{
@@ -1201,6 +1348,24 @@
 			}
 		else
 #endif
+#ifndef OPENSSL_NO_ECDSA
+			if (pkey->type == EVP_PKEY_ECDSA)
+			{
+			/* let's do ECDSA */
+			EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+			EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+			EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+			EVP_VerifyUpdate(&md_ctx,param,param_len);
+			if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey))
+				{
+				/* bad signature */
+				al=SSL_AD_DECRYPT_ERROR;
+				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
+				goto f_err;
+				}
+			}
+		else
+#endif
 			{
 			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
 			goto err;
@@ -1236,6 +1401,12 @@
 	if (dh != NULL)
 		DH_free(dh);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	BN_CTX_free(bn_ctx);
+	EC_POINT_free(srvr_ecpoint);
+	if (ecdh != NULL)
+		EC_KEY_free(ecdh);
+#endif
 	EVP_MD_CTX_cleanup(&md_ctx);
 	return(-1);
 	}
@@ -1423,6 +1594,14 @@
 #ifndef OPENSSL_NO_KRB5
         KSSL_ERR kssl_err;
 #endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *clnt_ecdh = NULL;
+	EC_POINT *srvr_ecpoint = NULL;
+	EVP_PKEY *srvr_pub_pkey = NULL;
+	unsigned char *encodedPoint = NULL;
+	int encoded_pt_len = 0;
+	BN_CTX * bn_ctx = NULL;
+#endif
 
 	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
 		{
@@ -1680,10 +1859,180 @@
 			/* perhaps clean things up a bit EAY EAY EAY EAY*/
 			}
 #endif
+
+#ifndef OPENSSL_NO_ECDH 
+		else if ((l & SSL_kECDH) || (l & SSL_kECDHE))
+			{
+			EC_GROUP *srvr_group = NULL;
+			int ecdh_clnt_cert = 0;
+
+			/* Did we send out the client's
+			 * ECDH share for use in premaster
+			 * computation as part of client certificate?
+			 * If so, set ecdh_clnt_cert to 1.
+			 */
+			if ((l & SSL_kECDH) && (s->cert != NULL)) 
+				{
+				/* XXX: For now, we do not support client
+				 * authentication using ECDH certificates.
+				 * To add such support, one needs to add
+				 * code that checks for appropriate 
+				 * conditions and sets ecdh_clnt_cert to 1.
+				 * For example, the cert have an ECC
+				 * key on the same curve as the server's
+				 * and the key should be authorized for
+				 * key agreement.
+				 *
+				 * One also needs to add code in ssl3_connect
+				 * to skip sending the certificate verify
+				 * message.
+				 *
+				 * if ((s->cert->key->privatekey != NULL) &&
+				 *     (s->cert->key->privatekey->type ==
+				 *      EVP_PKEY_ECC) && ...)
+				 * ecdh_clnt_cert = 1;
+				 */
+				}
+
+			if (s->session->sess_cert->peer_ecdh_tmp != NULL)
+				{
+				srvr_group = s->session->sess_cert-> \
+				    peer_ecdh_tmp->group;
+				srvr_ecpoint = s->session->sess_cert-> \
+				    peer_ecdh_tmp->pub_key;
+				}
+			else
+				{
+				/* Get the Server Public Key from Cert */
+				srvr_pub_pkey = X509_get_pubkey(s->session-> \
+				    sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+				if ((srvr_pub_pkey == NULL) ||
+				    (srvr_pub_pkey->type != EVP_PKEY_ECDSA) ||
+				    (srvr_pub_pkey->pkey.eckey == NULL))
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					    ERR_R_INTERNAL_ERROR);
+					goto err;
+					}
+
+				srvr_group = srvr_pub_pkey->pkey.eckey->group;
+				srvr_ecpoint = 
+				    srvr_pub_pkey->pkey.eckey->pub_key;
+				}
+
+			if ((srvr_group == NULL) || (srvr_ecpoint == NULL))
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+				    ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			if ((clnt_ecdh=EC_KEY_new()) == NULL) 
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+			clnt_ecdh->group = srvr_group;
+			if (ecdh_clnt_cert) 
+				{ 
+                                /* Reuse key info from our certificate
+				 * We only need our private key to perform
+				 * the ECDH computation.
+				 */
+				clnt_ecdh->priv_key = BN_dup(s->cert->key-> \
+				    privatekey->pkey.eckey->priv_key);
+				}
+			else 
+				{
+				/* Generate a new ECDH key pair */
+				if (!(EC_KEY_generate_key(clnt_ecdh)))
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+					goto err;
+					}
+				}
+
+                        /* use the 'p' output buffer for the ECDH key, but
+                         * make sure to clear it out afterwards
+			 */
+
+                        n=ECDH_compute_key(p, srvr_ecpoint, clnt_ecdh);
+			if (n <= 0)
+                                {
+                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, 
+				       ERR_R_ECDH_LIB);
+                                goto err;
+				}
+
+                        /* generate master key from the result */
+                        s->session->master_key_length = s->method->ssl3_enc \
+			    -> generate_master_secret(s, 
+				s->session->master_key,
+				p, n);
+
+                        memset(p, 0, n); /* clean up */
+
+			if (ecdh_clnt_cert) 
+				{
+				/* Send empty client key exch message */
+				n = 0;
+				}
+			else 
+				{
+				/* First check the size of encoding and
+				 * allocate memory accordingly.
+				 */
+				encoded_pt_len = 
+				    EC_POINT_point2oct(clnt_ecdh->group, 
+					clnt_ecdh->pub_key, 
+					POINT_CONVERSION_UNCOMPRESSED, 
+					NULL, 0, NULL);
+
+				encodedPoint = (unsigned char *) 
+				    OPENSSL_malloc(encoded_pt_len * 
+					sizeof(unsigned char)); 
+				bn_ctx = BN_CTX_new();
+				if ((encodedPoint == NULL) || 
+				    (bn_ctx == NULL)) 
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+					goto err;
+					}
+
+				/* Encode the public key */
+				n = EC_POINT_point2oct(clnt_ecdh->group, 
+				    clnt_ecdh->pub_key, 
+				    POINT_CONVERSION_UNCOMPRESSED, 
+				    encodedPoint, encoded_pt_len, bn_ctx);
+
+				*p = n; /* length of encoded point */
+                                /* Encoded point will be copied here */
+				p += 1; 
+				/* copy the point */
+				memcpy((unsigned char *)p, encodedPoint, n);
+				/* increment n to account for length field */
+				n += 1; 
+				}
+
+			/* Free allocated memory */
+			BN_CTX_free(bn_ctx);
+			if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+			if (clnt_ecdh != NULL) 
+				{
+                                 /* group is shared */
+				 clnt_ecdh->group = NULL; 
+				 EC_KEY_free(clnt_ecdh);
+				}
+			EVP_PKEY_free(srvr_pub_pkey);
+			}
+#endif /* !OPENSSL_NO_ECDH */
 		else
 			{
-			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
-			SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+			ssl3_send_alert(s, SSL3_AL_FATAL,
+			    SSL_AD_HANDSHAKE_FAILURE);
+			SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+			    ERR_R_INTERNAL_ERROR);
 			goto err;
 			}
 		
@@ -1699,6 +2048,17 @@
 	/* SSL3_ST_CW_KEY_EXCH_B */
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 err:
+#ifndef OPENSSL_NO_ECDH
+	BN_CTX_free(bn_ctx);
+	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+	if (clnt_ecdh != NULL) 
+		{
+		/* group is shared */
+		clnt_ecdh->group = NULL; 
+		EC_KEY_free(clnt_ecdh);
+		}
+        EVP_PKEY_free(srvr_pub_pkey);
+#endif
 	return(-1);
 	}
 
@@ -1757,6 +2117,23 @@
 			}
 		else
 #endif
+#ifndef OPENSSL_NO_ECDSA
+			if (pkey->type == EVP_PKEY_ECDSA)
+			{
+			if (!ECDSA_sign(pkey->save_type,
+				&(data[MD5_DIGEST_LENGTH]),
+				SHA_DIGEST_LENGTH,&(p[2]),
+				(unsigned int *)&j,pkey->pkey.eckey))
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+				    ERR_R_ECDSA_LIB);
+				goto err;
+				}
+			s2n(j,p);
+			n=j+2;
+			}
+		else
+#endif
 			{
 			SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
 			goto err;
@@ -1888,6 +2265,21 @@
 	/* This is the passed certificate */
 
 	idx=sc->peer_cert_type;
+#ifndef OPENSSL_NO_ECDH
+	if (idx == SSL_PKEY_ECC)
+		{
+		if (check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
+		    s->s3->tmp.new_cipher) == 0) 
+			{ /* check failed */
+			SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
+			goto f_err;			
+			}
+		else 
+			{
+			return 1;
+			}
+		}
+#endif
 	pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
 	i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
 	EVP_PKEY_free(pkey);
@@ -1973,3 +2365,44 @@
 	return(0);
 	}
 
+
+#ifndef OPENSSL_NO_ECDH
+/* This is the complement of nid2curve_id in s3_srvr.c. */
+static int curve_id2nid(int curve_id)
+{
+	/* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+	static int nid_list[26] =
+	{
+		0,
+		NID_sect163k1, /* sect163k1 (1) */
+		NID_sect163r1, /* sect163r1 (2) */
+		NID_sect163r2, /* sect163r2 (3) */
+		NID_sect193r1, /* sect193r1 (4) */ 
+		NID_sect193r2, /* sect193r2 (5) */ 
+		NID_sect233k1, /* sect233k1 (6) */
+		NID_sect233r1, /* sect233r1 (7) */ 
+		NID_sect239k1, /* sect239k1 (8) */ 
+		NID_sect283k1, /* sect283k1 (9) */
+		NID_sect283r1, /* sect283r1 (10) */ 
+		NID_sect409k1, /* sect409k1 (11) */ 
+		NID_sect409r1, /* sect409r1 (12) */
+		NID_sect571k1, /* sect571k1 (13) */ 
+		NID_sect571r1, /* sect571r1 (14) */ 
+		NID_secp160k1, /* secp160k1 (15) */
+		NID_secp160r1, /* secp160r1 (16) */ 
+		NID_secp160r2, /* secp160r2 (17) */ 
+		NID_secp192k1, /* secp192k1 (18) */
+		NID_X9_62_prime192v1, /* secp192r1 (19) */ 
+		NID_secp224k1, /* secp224k1 (20) */ 
+		NID_secp224r1, /* secp224r1 (21) */
+		NID_secp256k1, /* secp256k1 (22) */ 
+		NID_X9_62_prime256v1, /* secp256r1 (23) */ 
+		NID_secp384r1, /* secp384r1 (24) */
+		NID_secp521r1  /* secp521r1 (25) */	
+	};
+	
+	if ((curve_id < 1) || (curve_id > 25)) return 0;
+
+	return nid_list[curve_id];
+}
+#endif
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 14b2f13..40730ca 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -108,6 +108,32 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * 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.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
 
 #include <stdio.h>
 #include <openssl/objects.h>
@@ -871,6 +897,356 @@
 	    SSL_ALL_STRENGTHS,
 	    },
 
+#ifndef OPENSSL_NO_ECDH
+	/* Cipher 47 */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_eNULL|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            0,
+            0,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 48 */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 49 */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_DES_CBC_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_DES_CBC_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_LOW,
+            0,
+            56,
+            56,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4A */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_3DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_HIGH,
+            0,
+            168,
+            168,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4B */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_MEDIUM,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4C */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+            TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_HIGH,
+            0,
+            256,
+            256,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 5B */
+	/* XXX NOTE: The ECC/TLS draft has a bug and reuses 4B for this */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA,
+            TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP40,
+            0,
+            40,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 5C */
+	/* XXX NOTE: The ECC/TLS draft has a bug and reuses 4C for this */
+	    {
+            1,
+            TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA,
+            TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA,
+            SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP56,
+            0,
+            56,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4D */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_NULL_SHA,
+            TLS1_CK_ECDH_RSA_WITH_NULL_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_eNULL|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            0,
+            0,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4E */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA,
+            TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 4F */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_DES_CBC_SHA,
+            TLS1_CK_ECDH_RSA_WITH_DES_CBC_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_LOW,
+            0,
+            56,
+            56,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 50 */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA,
+            TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_3DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_HIGH,
+            0,
+            168,
+            168,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 51 */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA,
+            TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_MEDIUM,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 52 */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA,
+            TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_HIGH,
+            0,
+            256,
+            256,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 53 */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_40_SHA,
+            TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_40_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP40,
+            0,
+            40,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 54 */
+	    {
+            1,
+            TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_56_SHA,
+            TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_56_SHA,
+            SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP56,
+            0,
+            56,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 55 */
+            {
+            1,
+            TLS1_TXT_ECDH_anon_WITH_NULL_SHA,
+            TLS1_CK_ECDH_anon_WITH_NULL_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_eNULL|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            0,
+            0,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+	    },
+
+	/* Cipher 56 */
+            {
+            1,
+            TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA,
+            TLS1_CK_ECDH_anon_WITH_RC4_128_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+	    },
+
+	/* Cipher 57 */
+	    {
+            1,
+            TLS1_TXT_ECDH_anon_WITH_DES_CBC_SHA,
+            TLS1_CK_ECDH_anon_WITH_DES_CBC_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_LOW,
+            0,
+            56,
+            56,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 58 */
+	    {
+            1,
+            TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA,
+            TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_3DES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_HIGH,
+            0,
+            168,
+            168,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 59 */
+	    {
+            1,
+            TLS1_TXT_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA,
+            TLS1_CK_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_DES|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP40,
+            0,
+            40,
+            56,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 5A */
+	    {
+            1,
+            TLS1_TXT_ECDH_anon_EXPORT_WITH_RC4_40_SHA,
+            TLS1_CK_ECDH_anon_EXPORT_WITH_RC4_40_SHA,
+            SSL_kECDHE|SSL_aNULL|SSL_RC4|SSL_SHA|SSL_TLSV1,
+            SSL_EXPORT|SSL_EXP40,
+            0,
+            40,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 77 XXX: ECC ciphersuites offering forward secrecy
+	 * are not yet specified in the ECC/TLS draft but our code
+	 * allows them to be implemented very easily. To add such
+	 * a cipher suite, one needs to add two constant definitions
+	 * to tls1.h and a new structure in this file as shown below. We 
+	 * illustrate the process for the made-up cipher
+	 * ECDHE-ECDSA-AES128-SHA.
+	 */
+	    {
+            1,
+            TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+            TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+            SSL_kECDHE|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_MEDIUM,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+	/* Cipher 78 XXX: Another made-up ECC cipher suite that
+	 * offers forward secrecy (ECDHE-RSA-AES128-SHA).
+	 */
+	    {
+            1,
+            TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+            TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+            SSL_kECDHE|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1,
+            SSL_NOT_EXP|SSL_MEDIUM,
+            0,
+            128,
+            128,
+            SSL_ALL_CIPHERS,
+            SSL_ALL_STRENGTHS,
+            },
+
+#endif /* !OPENSSL_NO_ECDH */
+
 /* end of list */
 	};
 
@@ -982,6 +1358,11 @@
 	if (s->s3->tmp.dh != NULL)
 		DH_free(s->s3->tmp.dh);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	if (s->s3->tmp.ecdh != NULL)
+		EC_KEY_free(s->s3->tmp.ecdh);
+#endif
+
 	if (s->s3->tmp.ca_names != NULL)
 		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
 	EVP_MD_CTX_cleanup(&s->s3->finish_dgst1);
@@ -1009,6 +1390,10 @@
 	if (s->s3->tmp.dh != NULL)
 		DH_free(s->s3->tmp.dh);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	if (s->s3->tmp.ecdh != NULL)
+		EC_KEY_free(s->s3->tmp.ecdh);
+#endif
 
 	rp = s->s3->rbuf.buf;
 	wp = s->s3->wbuf.buf;
@@ -1147,6 +1532,44 @@
 		}
 		break;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH:
+		{
+		EC_KEY *ecdh = NULL;
+ 			
+		if (parg == NULL)
+			{
+			SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER);
+			return(ret);
+			}
+		if (!EC_KEY_up_ref((EC_KEY *)parg))
+			{
+			SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB);
+			return(ret);
+			}
+		ecdh = (EC_KEY *)parg;
+		if (!(s->options & SSL_OP_SINGLE_ECDH_USE))
+			{
+			if (!EC_KEY_generate_key(ecdh))
+				{
+				EC_KEY_free(ecdh);
+				SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB);
+				return(ret);
+				}
+			}
+		if (s->cert->ecdh_tmp != NULL)
+			EC_KEY_free(s->cert->ecdh_tmp);
+		s->cert->ecdh_tmp = ecdh;
+		ret = 1;
+		}
+		break;
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
+		}
+		break;
+#endif /* !OPENSSL_NO_ECDH */
 	default:
 		break;
 		}
@@ -1191,6 +1614,13 @@
 		}
 		break;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
 	default:
 		break;
 		}
@@ -1283,6 +1713,47 @@
 		}
 		break;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH:
+		{
+		EC_KEY *ecdh = NULL;
+ 			
+		if (parg == NULL)
+			{
+			SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_ECDH_LIB);
+			return 0;
+			}
+		if (!EC_KEY_up_ref((EC_KEY *)parg))
+			{
+			SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB);
+			return 0;
+			}
+		ecdh = (EC_KEY *)parg;
+		if (!(ctx->options & SSL_OP_SINGLE_ECDH_USE))
+			{
+			if (!EC_KEY_generate_key(ecdh))
+				{
+				EC_KEY_free(ecdh);
+				SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_ECDH_LIB);
+				return 0;
+				}
+			}
+
+		if (cert->ecdh_tmp != NULL)
+			{
+			EC_KEY_free(cert->ecdh_tmp);
+			}
+		cert->ecdh_tmp = ecdh;
+		return 1;
+		}
+		/* break; */
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
+		}
+		break;
+#endif /* !OPENSSL_NO_ECDH */
 	/* A Thawte special :-) */
 	case SSL_CTRL_EXTRA_CHAIN_CERT:
 		if (ctx->extra_certs == NULL)
@@ -1321,6 +1792,13 @@
 		}
 		break;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
 	default:
 		return(0);
 		}
@@ -1465,7 +1943,6 @@
 			}
 
 		if (!ok) continue;
-	
 		j=sk_SSL_CIPHER_find(allow,c);
 		if (j >= 0)
 			{
@@ -1510,6 +1987,26 @@
 #ifndef OPENSSL_NO_DSA
 	p[ret++]=SSL3_CT_DSS_SIGN;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	/* We should ask for fixed ECDH certificates only
+	 * for SSL_kECDH (and not SSL_kECDHE)
+	 */
+	if ((alg & SSL_kECDH) && (s->version >= TLS1_VERSION))
+		{
+		p[ret++]=TLS_CT_RSA_FIXED_ECDH;
+		p[ret++]=TLS_CT_ECDSA_FIXED_ECDH;
+		}
+#endif
+
+#ifndef OPENSSL_NO_ECDSA
+	/* ECDSA certs can be used with RSA cipher suites as well 
+	 * so we don't need to check for SSL_kECDH or SSL_kECDHE
+	 */
+	if (s->version >= TLS1_VERSION)
+		{
+		p[ret++]=TLS_CT_ECDSA_SIGN;
+		}
+#endif	
 	return(ret);
 	}
 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 20d716f..d26790a 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -108,11 +108,36 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * 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.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
 
 #define REUSE_CIPHER_BUG
 #define NETSCAPE_HANG_BUG
 
-
 #include <stdio.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
@@ -137,6 +162,10 @@
 static int ssl3_get_cert_verify(SSL *s);
 static int ssl3_send_hello_request(SSL *s);
 
+#ifndef OPENSSL_NO_ECDH
+static int nid2curve_id(int nid);
+#endif
+
 static SSL_METHOD *ssl3_get_server_method(int ver)
 	{
 	if (ver == SSL3_VERSION)
@@ -300,7 +329,7 @@
 
 		case SSL3_ST_SW_CERT_A:
 		case SSL3_ST_SW_CERT_B:
-			/* Check if it is anon DH */
+			/* Check if it is anon DH or anon ECDH */
 			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
 				{
 				ret=ssl3_send_server_certificate(s);
@@ -331,9 +360,18 @@
 			else
 				s->s3->tmp.use_rsa_tmp=0;
 
+
 			/* only send if a DH key exchange, fortezza or
-			 * RSA but we have a sign only certificate */
+			 * RSA but we have a sign only certificate
+			 *
+			 * For ECC ciphersuites, we send a serverKeyExchange
+			 * message only if the cipher suite is either
+			 * ECDH-anon or ECDHE. In other cases, the
+			 * server certificate contains the server's 
+			 * public key for key exchange.
+			 */
 			if (s->s3->tmp.use_rsa_tmp
+			    || (l & SSL_kECDHE)
 			    || (l & (SSL_DH|SSL_kFZA))
 			    || ((l & SSL_kRSA)
 				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
@@ -436,19 +474,33 @@
 		case SSL3_ST_SR_KEY_EXCH_A:
 		case SSL3_ST_SR_KEY_EXCH_B:
 			ret=ssl3_get_client_key_exchange(s);
-			if (ret <= 0) goto end;
-			s->state=SSL3_ST_SR_CERT_VRFY_A;
-			s->init_num=0;
+			if (ret <= 0) 
+				goto end;
+			if (ret == 2)
+				{
+				/* For the ECDH ciphersuites when
+				 * the client sends its ECDH pub key in
+				 * a certificate, the CertificateVerify
+				 * message is not sent.
+				 */
+				s->state=SSL3_ST_SR_FINISHED_A;
+				s->init_num = 0;
+				}
+			else   
+				{
+				s->state=SSL3_ST_SR_CERT_VRFY_A;
+				s->init_num=0;
 
-			/* We need to get hashes here so if there is
-			 * a client cert, it can be verified */ 
-			s->method->ssl3_enc->cert_verify_mac(s,
-				&(s->s3->finish_dgst1),
-				&(s->s3->tmp.cert_verify_md[0]));
-			s->method->ssl3_enc->cert_verify_mac(s,
-				&(s->s3->finish_dgst2),
-				&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
-
+				/* We need to get hashes here so if there is
+				 * a client cert, it can be verified
+				 */ 
+				s->method->ssl3_enc->cert_verify_mac(s,
+				    &(s->s3->finish_dgst1),
+				    &(s->s3->tmp.cert_verify_md[0]));
+				s->method->ssl3_enc->cert_verify_mac(s,
+				    &(s->s3->finish_dgst2),
+				    &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+				}
 			break;
 
 		case SSL3_ST_SR_CERT_VRFY_A:
@@ -1036,6 +1088,13 @@
 #ifndef OPENSSL_NO_DH
 	DH *dh=NULL,*dhp;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh=NULL, *ecdhp;
+	unsigned char *encodedPoint = NULL;
+	int encodedlen = 0;
+	int curve_id = 0;
+	BN_CTX *bn_ctx = NULL; 
+#endif
 	EVP_PKEY *pkey;
 	unsigned char *p,*d;
 	int al,i;
@@ -1144,6 +1203,131 @@
 			}
 		else 
 #endif
+#ifndef OPENSSL_NO_ECDH
+			if (type & SSL_kECDHE)
+			{
+			ecdhp=cert->ecdh_tmp;
+			if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+				{
+				ecdhp=s->cert->ecdh_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+				}
+			if (ecdhp == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.ecdh != NULL)
+				{
+				EC_KEY_free(s->s3->tmp.ecdh); 
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			/* Duplicate the ECDH structure. */
+			if (ecdhp == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+			if (!EC_KEY_up_ref(ecdhp))
+				{
+				SSLerr(SSL_F_SSL3_CTRL,ERR_R_ECDH_LIB);
+				goto err;
+				}
+			ecdh = ecdhp;
+
+			s->s3->tmp.ecdh=ecdh;
+			if ((ecdh->pub_key == NULL) ||
+			    (ecdh->priv_key == NULL) ||
+			    (s->options & SSL_OP_SINGLE_ECDH_USE))
+				{
+				if(!EC_KEY_generate_key(ecdh))
+				    {
+				    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				    goto err;
+				    }
+				}
+
+			if ((ecdh->group == NULL) ||
+			    (ecdh->pub_key == NULL) ||
+			    (ecdh->priv_key == NULL))
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+
+			if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+			    (EC_GROUP_get_degree(ecdh->group) > 163)) 
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+				goto err;
+				}
+
+			/* XXX: For now, we only support ephemeral ECDH
+			 * keys over named (not generic) curves. For 
+			 * supported named curves, curve_id is non-zero.
+			 */
+			if ((curve_id = 
+			    nid2curve_id(EC_GROUP_get_nid(ecdh->group)))
+			    == 0)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+				goto err;
+				}
+
+			/* Encode the public key.
+			 * First check the size of encoding and
+			 * allocate memory accordingly.
+			 */
+			encodedlen = EC_POINT_point2oct(ecdh->group, 
+			    ecdh->pub_key, 
+			    POINT_CONVERSION_UNCOMPRESSED, 
+			    NULL, 0, NULL);
+
+			encodedPoint = (unsigned char *) 
+			    OPENSSL_malloc(encodedlen*sizeof(unsigned char)); 
+			bn_ctx = BN_CTX_new();
+			if ((encodedPoint == NULL) || (bn_ctx == NULL))
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+
+			encodedlen = EC_POINT_point2oct(ecdh->group, 
+			    ecdh->pub_key, 
+			    POINT_CONVERSION_UNCOMPRESSED, 
+			    encodedPoint, encodedlen, bn_ctx);
+
+			if (encodedlen == 0) 
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+
+			BN_CTX_free(bn_ctx);  bn_ctx=NULL;
+
+			/* XXX: For now, we only support named (not 
+			 * generic) curves in ECDH ephemeral key exchanges.
+			 * In this situation, we need three additional bytes
+			 * to encode the entire ServerECDHParams
+			 * structure. 
+			 */
+			n = 3 + encodedlen;
+
+			/* We'll generate the serverKeyExchange message
+			 * explicitly so we can set these to NULLs
+			 */
+			r[0]=NULL;
+			r[1]=NULL;
+			r[2]=NULL;
+			}
+		else 
+#endif /* !OPENSSL_NO_ECDH */
 			{
 			al=SSL_AD_HANDSHAKE_FAILURE;
 			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
@@ -1186,6 +1370,29 @@
 			p+=nr[i];
 			}
 
+#ifndef OPENSSL_NO_ECDH
+		if (type & SSL_kECDHE) 
+			{
+			/* XXX: For now, we only support named (not generic) curves.
+			 * In this situation, the serverKeyExchange message has:
+			 * [1 byte CurveType], [1 byte CurveName]
+			 * [1 byte length of encoded point], followed by
+			 * the actual encoded point itself
+			 */
+			*p = NAMED_CURVE_TYPE;
+			p += 1;
+			*p = curve_id;
+			p += 1;
+			*p = encodedlen;
+			p += 1;
+			memcpy((unsigned char*)p, 
+			    (unsigned char *)encodedPoint, 
+			    encodedlen);
+			OPENSSL_free(encodedPoint);
+			p += encodedlen;
+			}
+#endif
+
 		/* not anonymous */
 		if (pkey != NULL)
 			{
@@ -1238,6 +1445,25 @@
 				}
 			else
 #endif
+#if !defined(OPENSSL_NO_ECDSA)
+				if (pkey->type == EVP_PKEY_ECDSA)
+				{
+				/* let's do ECDSA */
+				EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+				EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(d[4]),n);
+				if (!EVP_SignFinal(&md_ctx,&(p[2]),
+					(unsigned int *)&i,pkey))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
+					goto err;
+					}
+				s2n(i,p);
+				n+=i+2;
+				}
+			else
+#endif
 				{
 				/* Is this error check actually needed? */
 				al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1261,6 +1487,10 @@
 f_err:
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
+#ifndef OPENSSL_NO_ECDH
+	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+	BN_CTX_free(bn_ctx);
+#endif
 	EVP_MD_CTX_cleanup(&md_ctx);
 	return(-1);
 	}
@@ -1371,6 +1601,13 @@
         KSSL_ERR kssl_err;
 #endif /* OPENSSL_NO_KRB5 */
 
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *srvr_ecdh = NULL;
+	EVP_PKEY *clnt_pub_pkey = NULL;
+	EC_POINT *clnt_ecpoint = NULL;
+	BN_CTX *bn_ctx = NULL; 
+#endif
+
 	n=ssl3_get_message(s,
 		SSL3_ST_SR_KEY_EXCH_A,
 		SSL3_ST_SR_KEY_EXCH_B,
@@ -1711,6 +1948,138 @@
                 }
 	else
 #endif	/* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_ECDH
+		if ((l & SSL_kECDH) || (l & SSL_kECDHE))
+		{
+		int ret = 1;
+
+                /* initialize structures for server's ECDH key pair */
+		if ((srvr_ecdh = EC_KEY_new()) == NULL) 
+			{
+                	SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_MALLOC_FAILURE);
+                	goto err;
+			}
+
+		/* Let's get server private key and group information */
+		if (l & SSL_kECDH) 
+			{ 
+                        /* use the certificate */
+			srvr_ecdh->group = s->cert->key->privatekey-> \
+			    pkey.eckey->group;
+			srvr_ecdh->priv_key = s->cert->key->privatekey-> \
+			    pkey.eckey->priv_key;
+			}
+		else
+			{
+			/* use the ephermeral values we saved when
+			 * generating the ServerKeyExchange msg.
+			 */
+			srvr_ecdh->group = s->s3->tmp.ecdh->group;
+			srvr_ecdh->priv_key = s->s3->tmp.ecdh->priv_key;
+			}
+
+		/* Let's get client's public key */
+		if ((clnt_ecpoint = EC_POINT_new(srvr_ecdh->group))
+		    == NULL) 
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+                if (n == 0L) 
+                        {
+			/* Client Publickey was in Client Certificate */
+
+			 if (l & SSL_kECDHE) 
+				 {
+				 al=SSL_AD_HANDSHAKE_FAILURE;
+				 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+				 goto f_err;
+				 }
+                        if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
+			    == NULL) || 
+			    (clnt_pub_pkey->type != EVP_PKEY_ECDSA))
+                        	{
+				/* XXX: For now, we do not support client
+				 * authentication using ECDH certificates
+				 * so this branch (n == 0L) of the code is
+				 * never executed. When that support is
+				 * added, we ought to ensure the key 
+				 * received in the certificate is 
+				 * authorized for key agreement.
+				 * ECDH_compute_key implicitly checks that
+				 * the two ECDH shares are for the same
+				 * group.
+				 */
+                           	al=SSL_AD_HANDSHAKE_FAILURE;
+                           	SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+                           	goto f_err;
+                           	}
+
+			EC_POINT_copy(clnt_ecpoint,
+			    clnt_pub_pkey->pkey.eckey->pub_key);
+                        ret = 2; /* Skip certificate verify processing */
+                        }
+                else
+                        {
+			/* Get client's public key from encoded point
+			 * in the ClientKeyExchange message.
+			 */
+			if ((bn_ctx = BN_CTX_new()) == NULL)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+                        /* Get encoded point length */
+                        i = *p; 
+			p += 1;
+                        if (EC_POINT_oct2point(srvr_ecdh->group, 
+			    clnt_ecpoint, p, i, bn_ctx) == 0)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    ERR_R_EC_LIB);
+				goto err;
+				}
+                        /* p is pointing to somewhere in the buffer
+                         * currently, so set it to the start 
+                         */ 
+                        p=(unsigned char *)s->init_buf->data;
+                        }
+
+		/* Compute the shared pre-master secret */
+                i = ECDH_compute_key(p, clnt_ecpoint, srvr_ecdh);
+                if (i <= 0)
+                        {
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_ECDH_LIB);
+                        goto err;
+                        }
+
+		EVP_PKEY_free(clnt_pub_pkey);
+		EC_POINT_free(clnt_ecpoint);
+		if (srvr_ecdh != NULL) 
+			{
+			srvr_ecdh->priv_key = NULL;
+			srvr_ecdh->group = NULL;
+			EC_KEY_free(srvr_ecdh);
+			}
+		BN_CTX_free(bn_ctx);
+
+		/* Compute the master secret */
+                s->session->master_key_length = s->method->ssl3_enc-> \
+		    generate_master_secret(s, s->session->master_key, p, i);
+		
+                memset(p, 0, i);
+                return (ret);
+		}
+	else
+#endif
 		{
 		al=SSL_AD_HANDSHAKE_FAILURE;
 		SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
@@ -1721,9 +2090,20 @@
 	return(1);
 f_err:
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA)
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH)
 err:
 #endif
+#ifndef NO_OPENSSL_ECDH
+	EVP_PKEY_free(clnt_pub_pkey);
+	EC_POINT_free(clnt_ecpoint);
+	if (srvr_ecdh != NULL) 
+		{
+		srvr_ecdh->priv_key = NULL;
+		srvr_ecdh->group = NULL;
+		EC_KEY_free(srvr_ecdh);
+		}
+	BN_CTX_free(bn_ctx);
+#endif
 	return(-1);
 	}
 
@@ -1847,6 +2227,23 @@
 		}
 	else
 #endif
+#ifndef OPENSSL_NO_ECDSA
+		if (pkey->type == EVP_PKEY_ECDSA)
+		{
+		j=ECDSA_verify(pkey->save_type,
+			&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+			SHA_DIGEST_LENGTH,p,i,pkey->pkey.eckey);
+		if (j <= 0)
+			{
+			/* bad signature */
+			al=SSL_AD_DECRYPT_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
+			    SSL_R_BAD_ECDSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
 		{
 		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
 		al=SSL_AD_UNSUPPORTED_CERTIFICATE;
@@ -2047,3 +2444,66 @@
 	/* SSL3_ST_SW_CERT_B */
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 	}
+
+
+#ifndef OPENSSL_NO_ECDH
+/* This is the complement of curve_id2nid in s3_clnt.c. */
+static int nid2curve_id(int nid)
+{
+	/* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+	switch (nid) {
+	case NID_sect163k1: /* sect163k1 (1) */
+		return 1;
+	case NID_sect163r1: /* sect163r1 (2) */
+		return 2;
+	case NID_sect163r2: /* sect163r2 (3) */
+		return 3;
+	case NID_sect193r1: /* sect193r1 (4) */ 
+		return 4;
+	case NID_sect193r2: /* sect193r2 (5) */ 
+		return 5;
+	case NID_sect233k1: /* sect233k1 (6) */
+		return 6;
+	case NID_sect233r1: /* sect233r1 (7) */ 
+		return 7;
+	case NID_sect239k1: /* sect239k1 (8) */ 
+		return 8;
+	case NID_sect283k1: /* sect283k1 (9) */
+		return 9;
+	case NID_sect283r1: /* sect283r1 (10) */ 
+		return 10;
+	case NID_sect409k1: /* sect409k1 (11) */ 
+		return 11;
+	case NID_sect409r1: /* sect409r1 (12) */
+		return 12;
+	case NID_sect571k1: /* sect571k1 (13) */ 
+		return 13;
+	case NID_sect571r1: /* sect571r1 (14) */ 
+		return 14;
+	case NID_secp160k1: /* secp160k1 (15) */
+		return 15;
+	case NID_secp160r1: /* secp160r1 (16) */ 
+		return 16;
+	case NID_secp160r2: /* secp160r2 (17) */ 
+		return 17;
+	case NID_secp192k1: /* secp192k1 (18) */
+		return 18;
+	case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+		return 19;
+	case NID_secp224k1: /* secp224k1 (20) */ 
+		return 20;
+	case NID_secp224r1: /* secp224r1 (21) */
+		return 21;
+	case NID_secp256k1: /* secp256k1 (22) */ 
+		return 22;
+	case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+		return 23;
+	case NID_secp384r1: /* secp384r1 (24) */
+		return 24;
+	case NID_secp521r1:  /* secp521r1 (25) */	
+		return 25;
+	default:
+		return 0;
+	}
+}
+#endif
diff --git a/ssl/ssl.h b/ssl/ssl.h
index e9d1e89..49e3c52 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -161,6 +161,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #ifndef HEADER_SSL_H 
 #define HEADER_SSL_H 
@@ -265,6 +270,7 @@
 #define SSL_TXT_SSLV3		"SSLv3"
 #define SSL_TXT_TLSV1		"TLSv1"
 #define SSL_TXT_ALL		"ALL"
+#define SSL_TXT_ECC		"ECCdraft" /* ECC ciphersuites are not yet official */
 
 /*
  * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
@@ -470,6 +476,8 @@
 
 /* As server, disallow session resumption on renegotiation */
 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
+/* If set, always create a new key when using tmp_ecdh parameters */
+#define SSL_OP_SINGLE_ECDH_USE				0x00080000L
 /* If set, always create a new key when using tmp_dh parameters */
 #define SSL_OP_SINGLE_DH_USE				0x00100000L
 /* Set to always use the tmp_rsa key when doing RSA operations,
@@ -1074,19 +1082,21 @@
 #define SSL_CTRL_NEED_TMP_RSA			1
 #define SSL_CTRL_SET_TMP_RSA			2
 #define SSL_CTRL_SET_TMP_DH			3
-#define SSL_CTRL_SET_TMP_RSA_CB			4
-#define SSL_CTRL_SET_TMP_DH_CB			5
+#define SSL_CTRL_SET_TMP_ECDH			4
+#define SSL_CTRL_SET_TMP_RSA_CB			5
+#define SSL_CTRL_SET_TMP_DH_CB			6
+#define SSL_CTRL_SET_TMP_ECDH_CB		7
 
-#define SSL_CTRL_GET_SESSION_REUSED		6
-#define SSL_CTRL_GET_CLIENT_CERT_REQUEST	7
-#define SSL_CTRL_GET_NUM_RENEGOTIATIONS		8
-#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS	9
-#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS	10
-#define SSL_CTRL_GET_FLAGS			11
-#define SSL_CTRL_EXTRA_CHAIN_CERT		12
+#define SSL_CTRL_GET_SESSION_REUSED		8
+#define SSL_CTRL_GET_CLIENT_CERT_REQUEST	9
+#define SSL_CTRL_GET_NUM_RENEGOTIATIONS		10
+#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS	11
+#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS	12
+#define SSL_CTRL_GET_FLAGS			13
+#define SSL_CTRL_EXTRA_CHAIN_CERT		14
 
-#define SSL_CTRL_SET_MSG_CALLBACK               13
-#define SSL_CTRL_SET_MSG_CALLBACK_ARG           14
+#define SSL_CTRL_SET_MSG_CALLBACK               15
+#define SSL_CTRL_SET_MSG_CALLBACK_ARG           16
 
 /* Stats */
 #define SSL_CTRL_SESS_NUMBER			20
@@ -1129,6 +1139,8 @@
 	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
 #define SSL_CTX_set_tmp_dh(ctx,dh) \
 	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
 
 #define SSL_need_tmp_RSA(ssl) \
 	SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
@@ -1136,6 +1148,8 @@
 	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
 #define SSL_set_tmp_dh(ssl,dh) \
 	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_set_tmp_ecdh(ssl,ecdh) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
 
 #define SSL_CTX_add_extra_chain_cert(ctx,x509) \
 	SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
@@ -1445,6 +1459,14 @@
 				 DH *(*dh)(SSL *ssl,int is_export,
 					   int keylength));
 #endif
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+void SSL_set_tmp_ecdh_callback(SSL *ssl,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+#endif
 
 #ifndef OPENSSL_NO_COMP
 int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm);
@@ -1619,6 +1641,9 @@
 #define SSL_R_BAD_DH_P_LENGTH				 110
 #define SSL_R_BAD_DIGEST_LENGTH				 111
 #define SSL_R_BAD_DSA_SIGNATURE				 112
+#define SSL_R_BAD_ECC_CERT				 1117
+#define SSL_R_BAD_ECDSA_SIGNATURE			 1112
+#define SSL_R_BAD_ECPOINT				 1113
 #define SSL_R_BAD_HELLO_REQUEST				 105
 #define SSL_R_BAD_LENGTH				 271
 #define SSL_R_BAD_MAC_DECODE				 113
@@ -1659,6 +1684,7 @@
 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC	 1109
 #define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG		 148
 #define SSL_R_DIGEST_CHECK_FAILED			 149
+#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER		 1119
 #define SSL_R_ENCRYPTED_LENGTH_TOO_LONG			 150
 #define SSL_R_ERROR_GENERATING_TMP_RSA_KEY		 1092
 #define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST		 151
@@ -1699,6 +1725,7 @@
 #define SSL_R_MISSING_RSA_ENCRYPTING_CERT		 169
 #define SSL_R_MISSING_RSA_SIGNING_CERT			 170
 #define SSL_R_MISSING_TMP_DH_KEY			 171
+#define SSL_R_MISSING_TMP_ECDH_KEY			 1114
 #define SSL_R_MISSING_TMP_RSA_KEY			 172
 #define SSL_R_MISSING_TMP_RSA_PKEY			 173
 #define SSL_R_MISSING_VERIFY_MESSAGE			 174
@@ -1796,8 +1823,10 @@
 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG	 234
 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER		 235
 #define SSL_R_UNABLE_TO_DECODE_DH_CERTS			 236
+#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS		 1115
 #define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY		 237
 #define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS		 238
+#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS		 1116
 #define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS	 239
 #define SSL_R_UNABLE_TO_FIND_SSL_METHOD			 240
 #define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES		 241
@@ -1818,6 +1847,7 @@
 #define SSL_R_UNKNOWN_STATE				 255
 #define SSL_R_UNSUPPORTED_CIPHER			 256
 #define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM		 257
+#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE		 1118
 #define SSL_R_UNSUPPORTED_OPTION			 1091
 #define SSL_R_UNSUPPORTED_PROTOCOL			 258
 #define SSL_R_UNSUPPORTED_SSL_VERSION			 259
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 8fd6951..59211fe 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -108,6 +108,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #ifndef HEADER_SSL3_H 
 #define HEADER_SSL3_H 
@@ -285,7 +290,12 @@
 #define SSL3_CT_RSA_EPHEMERAL_DH		5
 #define SSL3_CT_DSS_EPHEMERAL_DH		6
 #define SSL3_CT_FORTEZZA_DMS			20
-#define SSL3_CT_NUMBER				7
+/* SSL3_CT_NUMBER is used to size arrays and it must be large
+ * enough to contain all of the cert types defined either for
+ * SSLv3 and TLSv1.
+ */
+#define SSL3_CT_NUMBER			7
+
 
 #define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
 #define SSL3_FLAGS_DELAY_CLIENT_FINISHED	0x0002
@@ -370,6 +380,11 @@
 #ifndef OPENSSL_NO_DH
 		DH *dh;
 #endif
+
+#ifndef OPENSSL_NO_ECDH
+		EC_KEY *ecdh; /* holds short lived ECDH key */
+#endif
+
 		/* used when SSL_ST_FLUSH_DATA is entered */
 		int next_state;			
 
diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c
index 3d1299e..7c8a451 100644
--- a/ssl/ssl_algs.c
+++ b/ssl/ssl_algs.c
@@ -101,6 +101,9 @@
 	EVP_add_digest_alias(SN_dsaWithSHA1,"DSS1");
 	EVP_add_digest_alias(SN_dsaWithSHA1,"dss1");
 #endif
+#ifndef OPENSSL_NO_ECDSA
+	EVP_add_digest(EVP_ecdsa());
+#endif
 	/* If you want support for phased out ciphers, add the following */
 #if 0
 	EVP_add_digest(EVP_sha());
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 263a1dc..c6dbc94 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -103,6 +103,11 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  * ====================================================================
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #include <stdio.h>
 
@@ -234,6 +239,15 @@
 	ret->dh_tmp_cb = cert->dh_tmp_cb;
 #endif
 
+#ifndef OPENSSL_NO_ECDH
+	if (cert->ecdh_tmp)
+		{
+		EC_KEY_up_ref(cert->ecdh_tmp);
+		ret->ecdh_tmp = cert->ecdh_tmp;
+		}
+	ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
+#endif
+
 	for (i = 0; i < SSL_PKEY_NUM; i++)
 		{
 		if (cert->pkeys[i].x509 != NULL)
@@ -268,7 +282,11 @@
 			case SSL_PKEY_DH_DSA:
 				/* We have a DH key. */
 				break;
-				
+
+			case SSL_PKEY_ECC:
+				/* We have an ECC key */
+				break;
+
 			default:
 				/* Can't happen. */
 				SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG);
@@ -294,6 +312,10 @@
 	if (ret->dh_tmp != NULL)
 		DH_free(ret->dh_tmp);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	if (ret->ecdh_tmp != NULL)
+		EC_KEY_free(ret->ecdh_tmp);
+#endif
 
 	for (i = 0; i < SSL_PKEY_NUM; i++)
 		{
@@ -333,6 +355,9 @@
 #ifndef OPENSSL_NO_DH
 	if (c->dh_tmp) DH_free(c->dh_tmp);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
+#endif
 
 	for (i=0; i<SSL_PKEY_NUM; i++)
 		{
@@ -439,6 +464,10 @@
 	if (sc->peer_dh_tmp != NULL)
 		DH_free(sc->peer_dh_tmp);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	if (sc->peer_ecdh_tmp != NULL)
+		EC_KEY_free(sc->peer_ecdh_tmp);
+#endif
 
 	OPENSSL_free(sc);
 	}
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 37f5888..0660275 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -55,7 +55,11 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
-
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 #include <stdio.h>
 #include <openssl/objects.h>
 #include <openssl/comp.h>
@@ -101,18 +105,20 @@
 
 static const SSL_CIPHER cipher_aliases[]={
 	/* Don't include eNULL unless specifically enabled. */
-	{0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL}, /* must be first */
-        {0,SSL_TXT_CMPALL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0},  /* COMPLEMENT OF ALL */
+	/* Don't include ECC in ALL because these ciphers are not yet official. */
+	{0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL & ~SSL_kECDH & ~SSL_kECDHE, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL}, /* must be first */
+	/* TODO: COMPLEMENT OF ALL and COMPLEMENT OF DEFAULT do not have ECC cipher suites handled properly. */
+	{0,SSL_TXT_CMPALL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0},  /* COMPLEMENT OF ALL */
 	{0,SSL_TXT_CMPDEF,0,SSL_ADH, 0,0,0,0,SSL_AUTH_MASK,0},
-        {0,SSL_TXT_kKRB5,0,SSL_kKRB5,0,0,0,0,SSL_MKEY_MASK,0},  /* VRS Kerberos5 */
+	{0,SSL_TXT_kKRB5,0,SSL_kKRB5,0,0,0,0,SSL_MKEY_MASK,0},  /* VRS Kerberos5 */
 	{0,SSL_TXT_kRSA,0,SSL_kRSA,  0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_kDHr,0,SSL_kDHr,  0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_kDHd,0,SSL_kDHd,  0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_kEDH,0,SSL_kEDH,  0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_kFZA,0,SSL_kFZA,  0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_DH,	0,SSL_DH,    0,0,0,0,SSL_MKEY_MASK,0},
+	{0,SSL_TXT_ECC,	0,(SSL_kECDH|SSL_kECDHE), 0,0,0,0,SSL_MKEY_MASK,0},
 	{0,SSL_TXT_EDH,	0,SSL_EDH,   0,0,0,0,SSL_MKEY_MASK|SSL_AUTH_MASK,0},
-
 	{0,SSL_TXT_aKRB5,0,SSL_aKRB5,0,0,0,0,SSL_AUTH_MASK,0},  /* VRS Kerberos5 */
 	{0,SSL_TXT_aRSA,0,SSL_aRSA,  0,0,0,0,SSL_AUTH_MASK,0},
 	{0,SSL_TXT_aDSS,0,SSL_aDSS,  0,0,0,0,SSL_AUTH_MASK,0},
@@ -314,7 +320,9 @@
 #ifdef OPENSSL_NO_KRB5
 	mask |= SSL_kKRB5|SSL_aKRB5;
 #endif
-
+#ifdef OPENSSL_NO_ECDH
+	mask |= SSL_kECDH|SSL_kECDHE;
+#endif
 #ifdef SSL_FORBID_ENULL
 	mask |= SSL_eNULL;
 #endif
@@ -916,7 +924,7 @@
 	pkl=SSL_C_EXPORT_PKEYLENGTH(cipher);
 	kl=SSL_C_EXPORT_KEYLENGTH(cipher);
 	exp=is_export?" export":"";
-
+	
 	if (alg & SSL_SSLV2)
 		ver="SSLv2";
 	else if (alg & SSL_SSLV3)
@@ -945,6 +953,10 @@
 	case SSL_kEDH:
 		kx=is_export?(pkl == 512 ? "DH(512)" : "DH(1024)"):"DH";
 		break;
+	case SSL_kECDH:
+	case SSL_kECDHE:
+		kx=is_export?"ECDH(<=163)":"ECDH";
+		break;
 	default:
 		kx="unknown";
 		}
@@ -968,6 +980,9 @@
 	case SSL_aNULL:
 		au="None";
 		break;
+	case SSL_aECDSA:
+		au="ECDSA";
+		break;
 	default:
 		au="unknown";
 		break;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 7067a74..18aea72 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -227,6 +227,9 @@
 {SSL_R_BAD_DH_P_LENGTH                   ,"bad dh p length"},
 {SSL_R_BAD_DIGEST_LENGTH                 ,"bad digest length"},
 {SSL_R_BAD_DSA_SIGNATURE                 ,"bad dsa signature"},
+{SSL_R_BAD_ECC_CERT                      ,"bad ecc cert"},
+{SSL_R_BAD_ECDSA_SIGNATURE               ,"bad ecdsa signature"},
+{SSL_R_BAD_ECPOINT                       ,"bad ecpoint"},
 {SSL_R_BAD_HELLO_REQUEST                 ,"bad hello request"},
 {SSL_R_BAD_LENGTH                        ,"bad length"},
 {SSL_R_BAD_MAC_DECODE                    ,"bad mac decode"},
@@ -267,6 +270,7 @@
 {SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC,"decryption failed or bad record mac"},
 {SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG   ,"dh public value length is wrong"},
 {SSL_R_DIGEST_CHECK_FAILED               ,"digest check failed"},
+{SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER      ,"ecgroup too large for cipher"},
 {SSL_R_ENCRYPTED_LENGTH_TOO_LONG         ,"encrypted length too long"},
 {SSL_R_ERROR_GENERATING_TMP_RSA_KEY      ,"error generating tmp rsa key"},
 {SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST     ,"error in received cipher list"},
@@ -307,6 +311,7 @@
 {SSL_R_MISSING_RSA_ENCRYPTING_CERT       ,"missing rsa encrypting cert"},
 {SSL_R_MISSING_RSA_SIGNING_CERT          ,"missing rsa signing cert"},
 {SSL_R_MISSING_TMP_DH_KEY                ,"missing tmp dh key"},
+{SSL_R_MISSING_TMP_ECDH_KEY              ,"missing tmp ecdh key"},
 {SSL_R_MISSING_TMP_RSA_KEY               ,"missing tmp rsa key"},
 {SSL_R_MISSING_TMP_RSA_PKEY              ,"missing tmp rsa pkey"},
 {SSL_R_MISSING_VERIFY_MESSAGE            ,"missing verify message"},
@@ -404,8 +409,10 @@
 {SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG,"tls rsa encrypted value length is wrong"},
 {SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER   ,"tried to use unsupported cipher"},
 {SSL_R_UNABLE_TO_DECODE_DH_CERTS         ,"unable to decode dh certs"},
+{SSL_R_UNABLE_TO_DECODE_ECDH_CERTS       ,"unable to decode ecdh certs"},
 {SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY      ,"unable to extract public key"},
 {SSL_R_UNABLE_TO_FIND_DH_PARAMETERS      ,"unable to find dh parameters"},
+{SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS    ,"unable to find ecdh parameters"},
 {SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS,"unable to find public key parameters"},
 {SSL_R_UNABLE_TO_FIND_SSL_METHOD         ,"unable to find ssl method"},
 {SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES  ,"unable to load ssl2 md5 routines"},
@@ -426,6 +433,7 @@
 {SSL_R_UNKNOWN_STATE                     ,"unknown state"},
 {SSL_R_UNSUPPORTED_CIPHER                ,"unsupported cipher"},
 {SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM ,"unsupported compression algorithm"},
+{SSL_R_UNSUPPORTED_ELLIPTIC_CURVE        ,"unsupported elliptic curve"},
 {SSL_R_UNSUPPORTED_OPTION                ,"unsupported option"},
 {SSL_R_UNSUPPORTED_PROTOCOL              ,"unsupported protocol"},
 {SSL_R_UNSUPPORTED_SSL_VERSION           ,"unsupported ssl version"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index ab172ae..b50fc46 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -110,7 +110,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
-
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #ifdef REF_CHECK
 #  include <assert.h>
@@ -1467,6 +1471,10 @@
 	int rsa_enc_export,dh_rsa_export,dh_dsa_export;
 	int rsa_tmp_export,dh_tmp_export,kl;
 	unsigned long mask,emask;
+	int have_ecc_cert, have_ecdh_tmp, ecdh_ok, ecdsa_ok, ecc_pkey_size;
+	X509 *x = NULL;
+	EVP_PKEY *ecc_pkey = NULL;
+	int signature_nid = 0;
 
 	if (c == NULL) return;
 
@@ -1487,6 +1495,9 @@
 	dh_tmp=dh_tmp_export=0;
 #endif
 
+#ifndef OPENSSL_NO_ECDH
+	have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
+#endif
 	cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
 	rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
 	rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
@@ -1501,7 +1512,8 @@
 /* FIX THIS EAY EAY EAY */
 	dh_dsa=  (cpk->x509 != NULL && cpk->privatekey != NULL);
 	dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
-
+	cpk= &(c->pkeys[SSL_PKEY_ECC]);
+	have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL);
 	mask=0;
 	emask=0;
 
@@ -1541,7 +1553,7 @@
 	if (rsa_enc || rsa_sign)
 		{
 		mask|=SSL_aRSA;
-		emask|=SSL_aRSA;
+		mask|=SSL_aRSA;
 		}
 
 	if (dsa_sign)
@@ -1558,11 +1570,131 @@
 	emask|=SSL_kKRB5|SSL_aKRB5;
 #endif
 
+	/* An ECC certificate may be usable for ECDH and/or
+	 * ECDSA cipher suites depending on the key usage extension.
+	 */
+	if (have_ecc_cert)
+		{
+                /* This call populates extension flags (ex_flags) */
+		x = (c->pkeys[SSL_PKEY_ECC]).x509;
+		X509_check_purpose(x, -1, 0);
+		ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1;
+		ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
+		ecc_pkey = X509_get_pubkey(x);
+		ecc_pkey_size = (ecc_pkey != NULL) ? 
+		    EVP_PKEY_bits(ecc_pkey) : 0;
+		EVP_PKEY_free(ecc_pkey);
+		if ((x->sig_alg) && (x->sig_alg->algorithm))
+			signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+#ifndef OPENSSL_NO_ECDH
+		if (ecdh_ok)
+			{
+			if ((signature_nid == NID_md5WithRSAEncryption) ||
+			    (signature_nid == NID_md4WithRSAEncryption) ||
+			    (signature_nid == NID_md2WithRSAEncryption))
+				{
+				mask|=SSL_kECDH|SSL_aRSA;
+				if (ecc_pkey_size <= 163)
+					emask|=SSL_kECDH|SSL_aRSA;
+				}
+			if (signature_nid == NID_ecdsa_with_SHA1)
+				{
+				mask|=SSL_kECDH|SSL_aECDSA;
+				if (ecc_pkey_size <= 163)
+					emask|=SSL_kECDH|SSL_aECDSA;
+				}
+			}
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (ecdsa_ok)
+			{
+			mask|=SSL_aECDSA;
+			emask|=SSL_aECDSA;
+			}
+#endif
+		}
+
+#ifndef OPENSSL_NO_ECDH
+	if (have_ecdh_tmp)
+		{
+		mask|=SSL_kECDHE;
+		emask|=SSL_kECDHE;
+		}
+#endif
 	c->mask=mask;
 	c->export_mask=emask;
 	c->valid=1;
 	}
 
+/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
+#define ku_reject(x, usage) \
+	(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+
+int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs)
+	{
+	unsigned long alg = cs->algorithms;
+	EVP_PKEY *pkey = NULL;
+	int keysize = 0;
+	int signature_nid = 0;
+
+	if (SSL_C_IS_EXPORT(cs))
+		{
+		/* ECDH key length in export ciphers must be <= 163 bits */
+		pkey = X509_get_pubkey(x);
+		if (pkey == NULL) return 0;
+		keysize = EVP_PKEY_bits(pkey);
+		EVP_PKEY_free(pkey);
+		if (keysize > 163) return 0;
+		}
+
+	/* This call populates the ex_flags field correctly */
+	X509_check_purpose(x, -1, 0);
+	if ((x->sig_alg) && (x->sig_alg->algorithm))
+		signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+	if (alg & SSL_kECDH) 
+		{
+		/* key usage, if present, must allow key agreement */
+		if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
+			{
+			printf("ECC cert not authorized for key agreement\n");
+			return 0;
+			}
+		if (alg & SSL_aECDSA) 
+			{
+			/* signature alg must be ECDSA */
+			if (signature_nid != NID_ecdsa_with_SHA1)
+				{
+				printf("ECC cert not signed w/ ECDSA\n");
+				return 0;
+				}
+			}
+		if (alg & SSL_aRSA)
+			{
+			/* signature alg must be RSA */
+			if ((signature_nid != NID_md5WithRSAEncryption) &&
+			    (signature_nid != NID_md4WithRSAEncryption) &&
+			    (signature_nid != NID_md2WithRSAEncryption))
+				{
+				printf("ECC cert not signed w/ RSA\n");
+				return 0;
+				}
+			}
+		} 
+	else if (alg & SSL_aECDSA)
+		{
+		/* key usage, if present, must allow signing */
+		if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
+			{
+			printf("ECC cert not authorized for signature\n");
+			return 0;
+			}
+		}
+
+	return 1;  /* all checks are ok */
+	}
+
 /* THIS NEEDS CLEANING UP */
 X509 *ssl_get_server_send_cert(SSL *s)
 	{
@@ -1577,7 +1709,26 @@
 	mask=is_export?c->export_mask:c->mask;
 	kalg=alg&(SSL_MKEY_MASK|SSL_AUTH_MASK);
 
-	if 	(kalg & SSL_kDHr)
+	if (kalg & SSL_kECDH)
+		{
+		/* we don't need to look at SSL_kECDHE 
+		 * since no certificate is needed for
+		 * anon ECDH and for authenticated
+		 * ECDHE, the check for the auth 
+		 * algorithm will set i correctly
+		 * NOTE: For ECDH-RSA, we need an ECC
+		 * not an RSA cert but for ECDHE-RSA
+		 * we need an RSA cert. Placing the
+		 * checks for SSL_kECDH before RSA
+		 * checks ensures the correct cert is chosen.
+		 */
+		i=SSL_PKEY_ECC;
+		}
+	else if (kalg & SSL_aECDSA)
+		{
+		i=SSL_PKEY_ECC;
+		}
+	else if (kalg & SSL_kDHr)
 		i=SSL_PKEY_DH_RSA;
 	else if (kalg & SSL_kDHd)
 		i=SSL_PKEY_DH_DSA;
@@ -1601,6 +1752,7 @@
 		return(NULL);
 		}
 	if (c->pkeys[i].x509 == NULL) return(NULL);
+
 	return(c->pkeys[i].x509);
 	}
 
@@ -1624,6 +1776,9 @@
 		else
 			return(NULL);
 		}
+	else if ((alg & SSL_aECDSA) &&
+	         (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
+		return(c->pkeys[SSL_PKEY_ECC].privatekey);
 	else /* if (alg & SSL_aNULL) */
 		{
 		SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
@@ -2271,6 +2426,20 @@
 	}
 #endif
 
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+							int keylength))
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)())ecdh);
+	}
+
+void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+						int keylength))
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)())ecdh);
+	}
+#endif
+
 
 void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
 	{
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index dd6c7a7..a990bb1 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -108,6 +108,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #ifndef HEADER_SSL_LOCL_H
 #define HEADER_SSL_LOCL_H
@@ -227,52 +232,56 @@
  * that the different entities within are mutually exclusive:
  * ONLY ONE BIT PER MASK CAN BE SET AT A TIME.
  */
-#define SSL_MKEY_MASK		0x0000003FL
+#define SSL_MKEY_MASK		0x000000FFL
 #define SSL_kRSA		0x00000001L /* RSA key exchange */
 #define SSL_kDHr		0x00000002L /* DH cert RSA CA cert */
 #define SSL_kDHd		0x00000004L /* DH cert DSA CA cert */
 #define SSL_kFZA		0x00000008L
 #define SSL_kEDH		0x00000010L /* tmp DH key no DH cert */
 #define SSL_kKRB5		0x00000020L /* Kerberos5 key exchange */
+#define SSL_kECDH               0x00000040L /* ECDH w/ long-term keys */
+#define SSL_kECDHE              0x00000080L /* ephemeral ECDH */
 #define SSL_EDH			(SSL_kEDH|(SSL_AUTH_MASK^SSL_aNULL))
 
-#define SSL_AUTH_MASK		0x00000FC0L
-#define SSL_aRSA		0x00000040L /* Authenticate with RSA */
-#define SSL_aDSS 		0x00000080L /* Authenticate with DSS */
+#define SSL_AUTH_MASK		0x00007F00L
+#define SSL_aRSA		0x00000100L /* Authenticate with RSA */
+#define SSL_aDSS 		0x00000200L /* Authenticate with DSS */
 #define SSL_DSS 		SSL_aDSS
-#define SSL_aFZA 		0x00000100L
-#define SSL_aNULL 		0x00000200L /* no Authenticate, ADH */
-#define SSL_aDH 		0x00000400L /* no Authenticate, ADH */
-#define SSL_aKRB5               0x00000800L /* Authenticate with KRB5 */
+#define SSL_aFZA 		0x00000400L
+#define SSL_aNULL 		0x00000800L /* no Authenticate, ADH */
+#define SSL_aDH 		0x00001000L /* no Authenticate, ADH */
+#define SSL_aKRB5               0x00002000L /* Authenticate with KRB5 */
+#define SSL_aECDSA              0x00004000L /* Authenticate with ECDSA */
 
 #define SSL_NULL		(SSL_eNULL)
 #define SSL_ADH			(SSL_kEDH|SSL_aNULL)
 #define SSL_RSA			(SSL_kRSA|SSL_aRSA)
 #define SSL_DH			(SSL_kDHr|SSL_kDHd|SSL_kEDH)
+#define SSL_ECDH		(SSL_kECDH|SSL_kECDHE)
 #define SSL_FZA			(SSL_aFZA|SSL_kFZA|SSL_eFZA)
 #define SSL_KRB5                (SSL_kKRB5|SSL_aKRB5)
 
-#define SSL_ENC_MASK		0x0087F000L
-#define SSL_DES			0x00001000L
-#define SSL_3DES		0x00002000L
-#define SSL_RC4			0x00004000L
-#define SSL_RC2			0x00008000L
-#define SSL_IDEA		0x00010000L
-#define SSL_eFZA		0x00020000L
-#define SSL_eNULL		0x00040000L
-#define SSL_AES			0x00800000L
+#define SSL_ENC_MASK		0x043F8000L
+#define SSL_DES			0x00008000L
+#define SSL_3DES		0x00010000L
+#define SSL_RC4			0x00020000L
+#define SSL_RC2			0x00040000L
+#define SSL_IDEA		0x00080000L
+#define SSL_eFZA		0x00100000L
+#define SSL_eNULL		0x00200000L
+#define SSL_AES			0x04000000L
 
-#define SSL_MAC_MASK		0x00180000L
-#define SSL_MD5			0x00080000L
-#define SSL_SHA1		0x00100000L
+#define SSL_MAC_MASK		0x00c00000L
+#define SSL_MD5			0x00400000L
+#define SSL_SHA1		0x00800000L
 #define SSL_SHA			(SSL_SHA1)
 
-#define SSL_SSL_MASK		0x00600000L
-#define SSL_SSLV2		0x00200000L
-#define SSL_SSLV3		0x00400000L
+#define SSL_SSL_MASK		0x03000000L
+#define SSL_SSLV2		0x01000000L
+#define SSL_SSLV3		0x02000000L
 #define SSL_TLSV1		SSL_SSLV3	/* for now */
 
-/* we have used 007fffff - 9 bits left to go */
+/* we have used 07ffffff - 5 bits left to go. */
 
 /*
  * Export and cipher strength information. For each cipher we have to decide
@@ -344,7 +353,8 @@
 #define SSL_PKEY_DSA_SIGN	2
 #define SSL_PKEY_DH_RSA		3
 #define SSL_PKEY_DH_DSA		4
-#define SSL_PKEY_NUM		5
+#define SSL_PKEY_ECC            5
+#define SSL_PKEY_NUM		6
 
 /* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) |
  * 	    <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN)
@@ -360,6 +370,15 @@
 #define CERT_PRIVATE_KEY	2
 */
 
+#ifndef OPENSSL_NO_EC
+/* From ECC-TLS draft, used in encoding the curve type in 
+ * ECParameters
+ */
+#define EXPLICIT_PRIME_CURVE_TYPE  1   
+#define EXPLICIT_CHAR2_CURVE_TYPE  2
+#define NAMED_CURVE_TYPE           3
+#endif  /* OPENSSL_NO_EC */
+
 typedef struct cert_pkey_st
 	{
 	X509 *x509;
@@ -386,6 +405,11 @@
 	DH *dh_tmp;
 	DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize);
 #endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh_tmp;
+	/* Callback for generating ephemeral ECDH keys */
+	EC_KEY *(*ecdh_tmp_cb)(SSL *ssl,int is_export,int keysize);
+#endif
 
 	CERT_PKEY pkeys[SSL_PKEY_NUM];
 
@@ -411,6 +435,9 @@
 #ifndef OPENSSL_NO_DH
 	DH *peer_dh_tmp; /* not used for SSL 2 */
 #endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *peer_ecdh_tmp;
+#endif
 
 	int references; /* actually always 1 at the moment */
 	} SESS_CERT;
diff --git a/ssl/ssltest.c b/ssl/ssltest.c
index 1afdfa7..30473b5 100644
--- a/ssl/ssltest.c
+++ b/ssl/ssltest.c
@@ -108,6 +108,11 @@
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #define _XOPEN_SOURCE 600	/* Or gethostname won't be declared properly
 				   on Linux and GNU platforms. */
@@ -201,6 +206,9 @@
 	fprintf(stderr," -dhe1024dsa   - use 1024 bit key (with 160-bit subprime) for DHE\n");
 	fprintf(stderr," -no_dhe       - disable DHE\n");
 #endif
+#ifndef OPENSSL_NO_ECDH
+	fprintf(stderr," -no_ecdhe     - disable ECDHE\n");
+#endif
 #ifndef OPENSSL_NO_SSL2
 	fprintf(stderr," -ssl2         - use SSLv2\n");
 #endif
@@ -221,7 +229,12 @@
 	fprintf(stderr," -f            - Test even cases that can't work\n");
 	fprintf(stderr," -time         - measure processor time used by client and server\n");
 	fprintf(stderr," -zlib         - use zlib compression\n");
-	fprintf(stderr," -time         - use rle compression\n");
+	fprintf(stderr," -rle          - use rle compression\n");
+#ifndef OPENSSL_NO_ECDH
+	fprintf(stderr," -named_curve arg  - Elliptic curve name to use for ephemeral ECDH keys.\n" \
+	               "                 Use \"openssl ecparam -list_curves\" for all names\n"  \
+	               "                 (default is sect163r2).\n");
+#endif
 	}
 
 static void print_details(SSL *c_ssl, const char *prefix)
@@ -345,6 +358,7 @@
 	char *server_key=NULL;
 	char *client_cert=TEST_CLIENT_CERT;
 	char *client_key=NULL;
+	char *named_curve = NULL;
 	SSL_CTX *s_ctx=NULL;
 	SSL_CTX *c_ctx=NULL;
 	SSL_METHOD *meth=NULL;
@@ -355,7 +369,11 @@
 	DH *dh;
 	int dhe1024 = 0, dhe1024dsa = 0;
 #endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh = NULL;
+#endif
 	int no_dhe = 0;
+	int no_ecdhe = 0;
 	int print_time = 0;
 	clock_t s_time = 0, c_time = 0;
 	int comp = 0;
@@ -408,6 +426,8 @@
 #endif
 		else if	(strcmp(*argv,"-no_dhe") == 0)
 			no_dhe=1;
+		else if	(strcmp(*argv,"-no_ecdhe") == 0)
+			no_ecdhe=1;
 		else if	(strcmp(*argv,"-ssl2") == 0)
 			ssl2=1;
 		else if	(strcmp(*argv,"-tls1") == 0)
@@ -494,6 +514,13 @@
 			{
 			comp = COMP_RLE;
 			}
+#ifndef OPENSSL_NO_ECDH		
+		else if	(strcmp(*argv,"-named_curve") == 0)
+			{
+			if (--argc < 1) goto bad;
+			named_curve = *(++argv);
+			}
+#endif
 		else if	(strcmp(*argv,"-app_verify") == 0)
 			{
 			app_verify = 1;
@@ -609,6 +636,44 @@
 	(void)no_dhe;
 #endif
 
+#ifndef OPENSSL_NO_ECDH
+	if (!no_ecdhe)
+		{
+		ecdh = EC_KEY_new();
+		if (ecdh != NULL)
+			{
+			if (named_curve)
+				{
+				int nid = OBJ_sn2nid(named_curve);
+
+				if (nid == 0)
+					{
+					BIO_printf(bio_err, "unknown curve name (%s)\n", named_curve);
+					EC_KEY_free(ecdh);
+					goto end;
+					}
+
+				ecdh->group = EC_GROUP_new_by_nid(nid);
+				if (ecdh->group == NULL)
+					{
+					BIO_printf(bio_err, "unable to create curve (%s)\n", named_curve);
+					EC_KEY_free(ecdh);
+					goto end;
+					}
+				}
+			
+			if (ecdh->group == NULL)
+				ecdh->group=EC_GROUP_new_by_nid(NID_sect163r2);
+
+			SSL_CTX_set_tmp_ecdh(s_ctx, ecdh);
+			SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_ECDH_USE);
+			EC_KEY_free(ecdh);
+			}
+		}
+#else
+	(void)no_ecdhe;
+#endif
+
 #ifndef OPENSSL_NO_RSA
 	SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
 #endif
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 38838ea..4d7c9a1 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -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.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
 
 #ifndef HEADER_TLS1_H 
 #define HEADER_TLS1_H 
@@ -112,6 +138,48 @@
 #define TLS1_CK_DHE_RSA_WITH_AES_256_SHA		0x03000039
 #define TLS1_CK_ADH_WITH_AES_256_SHA			0x0300003A
 
+/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001).
+ * XXX NOTE: There is a bug in the draft, cipher numbers 4B, and 4C
+ * are defined twice so we define ECDH_ECDSA_EXPORT cipher
+ * suites to use 5B and 5C instead (this may change with future
+ * updates to the IETF draft).
+ */
+#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA                0x03000047
+#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA             0x03000048
+#define TLS1_CK_ECDH_ECDSA_WITH_DES_CBC_SHA             0x03000049
+#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA        0x0300004A
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA         0x0300004B
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA         0x0300004C
+#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA       0x0300005B
+#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA       0x0300005C
+
+#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA                  0x0300004D
+#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA               0x0300004E
+#define TLS1_CK_ECDH_RSA_WITH_DES_CBC_SHA               0x0300004F
+#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA          0x03000050
+#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA           0x03000051
+#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA           0x03000052
+#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_40_SHA         0x03000053
+#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_56_SHA         0x03000054
+
+#define TLS1_CK_ECDH_anon_WITH_NULL_SHA                 0x03000055
+#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA              0x03000056
+#define TLS1_CK_ECDH_anon_WITH_DES_CBC_SHA              0x03000057
+#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA         0x03000058
+#define TLS1_CK_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA    0x03000059
+#define TLS1_CK_ECDH_anon_EXPORT_WITH_RC4_40_SHA        0x0300005A
+
+/* XXX: ECC ciphersuites offering forward secrecy are not yet specified
+ * in the ECC/TLS draft but our code allows them to be implemented
+ * very easily. To add such a cipher suite, one needs to add two constant
+ * definitions to this file and a new structure in s3_lib.c. We illustrate
+ * the process for the made-up ciphers ECDHE-ECDSA-AES128-SHA and
+ * ECDHE-RSA-AES128-SHA.
+ */
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA        0x03000077
+#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA          0x03000078
+
+
 /* XXX
  * Inconsistency alert:
  * The OpenSSL names of ciphers with ephemeral DH here include the string
@@ -142,12 +210,47 @@
 #define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA		"DHE-RSA-AES256-SHA"
 #define TLS1_TXT_ADH_WITH_AES_256_SHA			"ADH-AES256-SHA"
 
+/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA               "ECDH-ECDSA-NULL-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA            "ECDH-ECDSA-RC4-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_DES_CBC_SHA            "ECDH-ECDSA-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA       "ECDH-ECDSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA        "ECDH-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA        "ECDH-ECDSA-AES256-SHA"
+#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA      "EXP-ECDH-ECDSA-RC4-40-SHA"
+#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA      "EXP-ECDH-ECDSA-RC4-56-SHA"
+
+#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA                 "ECDH-RSA-NULL-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA              "ECDH-RSA-RC4-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_DES_CBC_SHA              "ECDH-RSA-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA         "ECDH-RSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA          "ECDH-RSA-AES128-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA          "ECDH-RSA-AES256-SHA"
+#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_40_SHA        "EXP-ECDH-RSA-RC4-40-SHA"
+#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_56_SHA        "EXP-ECDH-RSA-RC4-56-SHA"
+
+#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA                "AECDH-NULL-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA             "AECDH-RC4-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_DES_CBC_SHA             "AECDH-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA        "AECDH-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA   "EXP-AECDH-DES-40-CBC-SHA"
+#define TLS1_TXT_ECDH_anon_EXPORT_WITH_RC4_40_SHA       "EXP-AECDH-RC4-40-SHA"
+
+/* XXX: Made-up ECC cipher suites offering forward secrecy. This is for 
+ * illustration only. 
+ */
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA       "ECDHE-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA         "ECDHE-RSA-AES128-SHA"
+
 
 #define TLS_CT_RSA_SIGN			1
 #define TLS_CT_DSS_SIGN			2
 #define TLS_CT_RSA_FIXED_DH		3
 #define TLS_CT_DSS_FIXED_DH		4
-#define TLS_CT_NUMBER			4
+#define TLS_CT_ECDSA_SIGN		5
+#define TLS_CT_RSA_FIXED_ECDH		6
+#define TLS_CT_ECDSA_FIXED_ECDH 	7
+#define TLS_CT_NUMBER			7
 
 #define TLS1_FINISH_MAC_LENGTH		12
 
@@ -193,3 +296,5 @@
 #endif
 #endif
 
+
+