ECC ciphersuite support
authorBodo Möller <bodo@openssl.org>
Fri, 9 Aug 2002 08:56:08 +0000 (08:56 +0000)
committerBodo Möller <bodo@openssl.org>
Fri, 9 Aug 2002 08:56:08 +0000 (08:56 +0000)
Submitted by: Douglas Stebila <douglas.stebila@sun.com>
(Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories)

16 files changed:
CHANGES
apps/s_server.c
ssl/s3_both.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_algs.c
ssl/ssl_cert.c
ssl/ssl_ciph.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssltest.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index d469038..b66616c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,14 @@
 
  Changes between 0.9.7 and 0.9.8  [xx XXX 2002]
 
+  *) Add support for ECC-based ciphersuites from draft-ietf-tls-ecc-01.txt.
+     As these are not official, they are not included in "ALL";
+     the "ECCdraft" ciphersuite group alias can be used to select them.
+     [Vipul Gupta and Sumit Gupta (Sun Microsystems Laboratories)]
+
+TODO: COMPLEMENTOFALL and COMPLEMENTOFDEFAULT do not handle ECCdraft
+cipher suites correctly.
+
   *) Add ECDH engine support.
      [Nils Gura and Douglas Stebila (Sun Microsystems Laboratories)]
 
index 85d3b30..828d5ef 100644 (file)
  * Hudson (tjh@cryptsoft.com).
  *
  */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECDH support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
 
 #include <assert.h>
 #include <stdio.h>
@@ -164,6 +169,7 @@ static int generate_session_id(const SSL *ssl, unsigned char *id,
 static DH *load_dh_param(char *dhfile);
 static DH *get_dh512(void);
 #endif
+
 #ifdef MONOLITH
 static void s_server_init(void);
 #endif
@@ -202,6 +208,7 @@ static DH *get_dh512(void)
        }
 #endif
 
+
 /* static int load_CA(SSL_CTX *ctx, char *file);*/
 
 #undef BUFSIZZ
@@ -279,6 +286,11 @@ static void sv_usage(void)
        BIO_printf(bio_err," -dkey arg     - second private key file to use (usually for DSA)\n");
        BIO_printf(bio_err," -dhparam arg  - DH parameter file to use, in cert file if not specified\n");
        BIO_printf(bio_err,"                 or a default set of parameters is used\n");
+#ifndef OPENSSL_NO_ECDH
+       BIO_printf(bio_err," -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
 #ifdef FIONBIO
        BIO_printf(bio_err," -nbio         - Run with non-blocking IO\n");
 #endif
@@ -302,6 +314,9 @@ static void sv_usage(void)
        BIO_printf(bio_err," -no_tls1      - Just disable TLSv1\n");
 #ifndef OPENSSL_NO_DH
        BIO_printf(bio_err," -no_dhe       - Disable ephemeral DH\n");
+#endif
+#ifndef OPENSSL_NO_ECDH
+       BIO_printf(bio_err," -no_ecdhe     - Disable ephemeral ECDH\n");
 #endif
        BIO_printf(bio_err," -bugs         - Turn on SSL bug compatibility\n");
        BIO_printf(bio_err," -www          - Respond to a 'GET /' with a status page\n");
@@ -476,10 +491,11 @@ int MAIN(int argc, char *argv[])
        char *CApath=NULL,*CAfile=NULL;
        char *context = NULL;
        char *dhfile = NULL;
+       char *named_curve = NULL;
        int badop=0,bugs=0;
        int ret=1;
        int off=0;
-       int no_tmp_rsa=0,no_dhe=0,nocert=0;
+       int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0;
        int state=0;
        SSL_METHOD *meth=NULL;
        ENGINE *e=NULL;
@@ -560,6 +576,13 @@ int MAIN(int argc, char *argv[])
                        if (--argc < 1) goto bad;
                        dhfile = *(++argv);
                        }
+#ifndef OPENSSL_NO_ECDH                
+               else if (strcmp(*argv,"-named_curve") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       named_curve = *(++argv);
+                       }
+#endif
                else if (strcmp(*argv,"-dcert") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -628,6 +651,8 @@ int MAIN(int argc, char *argv[])
                        { no_tmp_rsa=1; }
                else if (strcmp(*argv,"-no_dhe") == 0)
                        { no_dhe=1; }
+               else if (strcmp(*argv,"-no_ecdhe") == 0)
+                       { no_ecdhe=1; }
                else if (strcmp(*argv,"-www") == 0)
                        { www=1; }
                else if (strcmp(*argv,"-WWW") == 0)
@@ -798,6 +823,59 @@ bad:
                DH_free(dh);
                }
 #endif
+
+#ifndef OPENSSL_NO_ECDH
+       if (!no_ecdhe)
+               {
+               EC_KEY *ecdh=NULL;
+
+               ecdh = EC_KEY_new();
+               if (ecdh == NULL)
+                       {
+                       BIO_printf(bio_err,"Could not create ECDH struct.\n");
+                       goto end;
+                       }
+
+               if (named_curve)
+                       {
+                       int nid = OBJ_sn2nid(named_curve);
+
+                       if (nid == 0)
+                               {
+                               BIO_printf(bio_err, "unknown curve name (%s)\n", 
+                                       named_curve);
+                               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);
+                               goto end;
+                               }
+                       }
+
+               if (ecdh->group != NULL)
+                       {
+                       BIO_printf(bio_s_out,"Setting temp ECDH parameters\n");
+                       }
+               else
+                       {
+                       BIO_printf(bio_s_out,"Using default temp ECDH parameters\n");
+                       ecdh->group=EC_GROUP_new_by_nid(NID_sect163r2);
+                       if (ecdh->group == NULL) 
+                               {
+                               BIO_printf(bio_err, "unable to create curve (sect163r2)\n");
+                               goto end;
+                               }
+                       }
+               (void)BIO_flush(bio_s_out);
+
+               SSL_CTX_set_tmp_ecdh(ctx,ecdh);
+               EC_KEY_free(ecdh);
+               }
+#endif
        
        if (!set_cert_stuff(ctx,s_cert_file,s_key_file))
                goto end;
index 8864366..a558836 100644 (file)
  * 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 @@ int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
                        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;
 
index 2b58482..74e1e52 100644 (file)
  * 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_send_client_key_exchange(SSL *s);
 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 @@ int ssl3_connect(SSL *s)
 
                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 @@ int ssl3_connect(SSL *s)
                         * 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 @@ static int ssl3_get_key_exchange(SSL *s)
 #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 */
@@ -979,6 +1025,13 @@ static int ssl3_get_key_exchange(SSL *s)
                        DH_free(s->session->sess_cert->peer_dh_tmp);
                        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 @@ static int ssl3_get_key_exchange(SSL *s)
                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 @@ static int ssl3_get_key_exchange(SSL *s)
 
        /* p points to the next byte, there are 'n' bytes left */
 
-
        /* if it was signed, check the signature */
        if (pkey != NULL)
                {
@@ -1200,6 +1347,24 @@ static int ssl3_get_key_exchange(SSL *s)
                                }
                        }
                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);
@@ -1235,6 +1400,12 @@ err:
 #ifndef OPENSSL_NO_DH
        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 @@ static int ssl3_send_client_key_exchange(SSL *s)
 #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 @@ static int ssl3_send_client_key_exchange(SSL *s)
                        /* 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 @@ static int ssl3_send_client_key_exchange(SSL *s)
        /* 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);
        }
 
@@ -1756,6 +2116,23 @@ static int ssl3_send_client_verify(SSL *s)
                        n=j+2;
                        }
                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);
@@ -1888,6 +2265,21 @@ static int ssl3_check_cert_and_algorithm(SSL *s)
        /* 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 @@ err:
        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
index 14b2f13..40730ca 100644 (file)
  * 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 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]={
            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 @@ void ssl3_free(SSL *s)
        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 @@ void ssl3_clear(SSL *s)
        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 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                }
                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;
                }
@@ -1190,6 +1613,13 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)())
                s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
                }
                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 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                }
                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)
@@ -1320,6 +1791,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)())
                cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
                }
                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 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
                        }
 
                if (!ok) continue;
-       
                j=sk_SSL_CIPHER_find(allow,c);
                if (j >= 0)
                        {
@@ -1510,6 +1987,26 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
 #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);
        }
 
index 20d716f..d26790a 100644 (file)
  * 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_client_certificate(SSL *s);
 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 @@ int ssl3_accept(SSL *s)
 
                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 @@ int ssl3_accept(SSL *s)
                        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 @@ int ssl3_accept(SSL *s)
                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;
-
-                       /* 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]));
+                       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]));
+                               }
                        break;
 
                case SSL3_ST_SR_CERT_VRFY_A:
@@ -1035,6 +1087,13 @@ static int ssl3_send_server_key_exchange(SSL *s)
 #endif
 #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;
@@ -1144,6 +1203,131 @@ static int ssl3_send_server_key_exchange(SSL *s)
                        }
                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 @@ static int ssl3_send_server_key_exchange(SSL *s)
                        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)
                        {
@@ -1237,6 +1444,25 @@ static int ssl3_send_server_key_exchange(SSL *s)
                                n+=i+2;
                                }
                        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? */
@@ -1261,6 +1487,10 @@ static int ssl3_send_server_key_exchange(SSL *s)
 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 @@ static int ssl3_get_client_key_exchange(SSL *s)
         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 @@ static int ssl3_get_client_key_exchange(SSL *s)
                 }
        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,8 +2090,19 @@ static int ssl3_get_client_key_exchange(SSL *s)
        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);
        }
@@ -1846,6 +2226,23 @@ static int ssl3_get_cert_verify(SSL *s)
                        }
                }
        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);
@@ -2047,3 +2444,66 @@ int ssl3_send_server_certificate(SSL *s)
        /* 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
index e9d1e89..49e3c52 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
  * 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 @@ extern "C" {
 #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 @@ typedef struct ssl_session_st
 
 /* 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 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count);
 #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_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_SET_MSG_CALLBACK               13
-#define SSL_CTRL_SET_MSG_CALLBACK_ARG           14
+#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            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               15
+#define SSL_CTRL_SET_MSG_CALLBACK_ARG           16
 
 /* Stats */
 #define SSL_CTRL_SESS_NUMBER                   20
@@ -1129,6 +1139,8 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count);
        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 @@ size_t SSL_get_peer_finished(SSL *s, void *buf, size_t count);
        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 @@ void SSL_set_tmp_dh_callback(SSL *ssl,
                                 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 @@ void ERR_load_SSL_strings(void);
 #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 @@ void ERR_load_SSL_strings(void);
 #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 @@ void ERR_load_SSL_strings(void);
 #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 @@ void ERR_load_SSL_strings(void);
 #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 @@ void ERR_load_SSL_strings(void);
 #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
index 8fd6951..59211fe 100644 (file)
  * 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 @@ typedef struct ssl3_buffer_st
 #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 @@ typedef struct ssl3_state_st
 #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;                 
 
index 3d1299e..7c8a451 100644 (file)
@@ -100,6 +100,9 @@ int SSL_library_init(void)
        EVP_add_digest_alias(SN_dsaWithSHA1,SN_dsaWithSHA1_2);
        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
index 263a1dc..c6dbc94 100644 (file)
  * 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 @@ CERT *ssl_cert_dup(CERT *cert)
        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 @@ CERT *ssl_cert_dup(CERT *cert)
                        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 @@ err:
        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 @@ void ssl_cert_free(CERT *c)
 #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 @@ void ssl_sess_cert_free(SESS_CERT *sc)
        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);
        }
index 37f5888..0660275 100644 (file)
  * 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 @@ typedef struct cipher_order_st
 
 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 @@ static unsigned long ssl_cipher_get_disabled(void)
 #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 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len)
        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 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len)
        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 @@ char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len)
        case SSL_aNULL:
                au="None";
                break;
+       case SSL_aECDSA:
+               au="ECDSA";
+               break;
        default:
                au="unknown";
                break;
index 7067a74..18aea72 100644 (file)
@@ -227,6 +227,9 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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"},
index ab172ae..b50fc46 100644 (file)
  * 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 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
        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 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
        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 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
 /* 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 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
        if (rsa_enc || rsa_sign)
                {
                mask|=SSL_aRSA;
-               emask|=SSL_aRSA;
+               mask|=SSL_aRSA;
                }
 
        if (dsa_sign)
@@ -1558,11 +1570,131 @@ void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
        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 @@ X509 *ssl_get_server_send_cert(SSL *s)
        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 @@ X509 *ssl_get_server_send_cert(SSL *s)
                return(NULL);
                }
        if (c->pkeys[i].x509 == NULL) return(NULL);
+
        return(c->pkeys[i].x509);
        }
 
@@ -1624,6 +1776,9 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s,SSL_CIPHER *cipher)
                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 @@ void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
        }
 #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))
        {
index dd6c7a7..a990bb1 100644 (file)
  * 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
  * 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_MAC_MASK           0x00180000L
-#define SSL_MD5                        0x00080000L
-#define SSL_SHA1               0x00100000L
+#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           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
 #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)
 #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 @@ typedef struct cert_st
        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 @@ typedef struct sess_cert_st
 #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;
index 1afdfa7..30473b5 100644 (file)
  * 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 @@ static void sv_usage(void)
        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 @@ static void sv_usage(void)
        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 @@ int main(int argc, char *argv[])
        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;
@@ -354,8 +368,12 @@ int main(int argc, char *argv[])
 #ifndef OPENSSL_NO_DH
        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 @@ int main(int argc, char *argv[])
 #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 @@ int main(int argc, char *argv[])
                        {
                        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 @@ bad:
        (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
index 38838ea..4d7c9a1 100644 (file)
  * 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 @@ extern "C" {
 #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 @@ extern "C" {
 #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 @@ extern "C" {
 #endif
 #endif
 
+
+