summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBodo Möller <bodo@openssl.org>2002-08-09 08:56:08 +0000
committerBodo Möller <bodo@openssl.org>2002-08-09 08:56:08 +0000
commitea262260469e49149cb10b25a87dfd6ad3fbb4ba (patch)
tree7032110f80ba1888d7b3047cfbacd2d46e4fb67c
parent17f627931780f000b8dd47fe030c52cc0fa93ef5 (diff)
ECC ciphersuite support
Submitted by: Douglas Stebila <douglas.stebila@sun.com> (Authors: Vipul Gupta and Sumit Gupta, Sun Microsystems Laboratories)
-rw-r--r--CHANGES8
-rw-r--r--apps/s_server.c80
-rw-r--r--ssl/s3_both.c22
-rw-r--r--ssl/s3_clnt.c441
-rw-r--r--ssl/s3_lib.c499
-rw-r--r--ssl/s3_srvr.c492
-rw-r--r--ssl/ssl.h56
-rw-r--r--ssl/ssl3.h17
-rw-r--r--ssl/ssl_algs.c3
-rw-r--r--ssl/ssl_cert.c31
-rw-r--r--ssl/ssl_ciph.c29
-rw-r--r--ssl/ssl_err.c8
-rw-r--r--ssl/ssl_lib.c177
-rw-r--r--ssl/ssl_locl.h79
-rw-r--r--ssl/ssltest.c67
-rw-r--r--ssl/tls1.h107
16 files changed, 2040 insertions, 76 deletions
diff --git a/CHANGES b/CHANGES
index d46903889f..b66616c252 100644
--- 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)]
diff --git a/apps/s_server.c b/apps/s_server.c
index 85d3b30ec1..828d5ef3a0 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -108,6 +108,11 @@
* 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
@@ -303,6 +315,9 @@ static void sv_usage(void)
#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");
BIO_printf(bio_err," -WWW - Respond to a 'GET /<path> HTTP/1.0' with file ./<path>\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;
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8864366f59..a5588360e5 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -108,6 +108,11 @@
* Hudson (tjh@cryptsoft.com).
*
*/
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
#include <limits.h>
#include <string.h>
@@ -520,6 +525,23 @@ 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;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 2b58482484..74e1e529f8 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -108,6 +108,32 @@
* Hudson (tjh@cryptsoft.com).
*
*/
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * In addition, Sun covenants to all licensees who provide a reciprocal
+ * covenant with respect to their own patents if any, not to sue under
+ * current and future patent claims necessarily infringed by the making,
+ * using, practicing, selling, offering for sale and/or otherwise
+ * disposing of the Contribution as delivered hereunder
+ * (or portions thereof), provided that such covenant shall not apply:
+ * 1) for code that a licensee deletes from the Contribution;
+ * 2) separates from the Contribution; or
+ * 3) for infringements caused by:
+ * i) the modification of the Contribution or
+ * ii) the combination of the Contribution with other software or
+ * devices where such combination causes the infringement.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
#include <stdio.h>
#include "ssl_locl.h"
@@ -131,6 +157,12 @@ static int ssl3_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 */
@@ -980,6 +1026,13 @@ static int ssl3_get_key_exchange(SSL *s)
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)
{
@@ -1201,6 +1348,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);
goto err;
@@ -1236,6 +1401,12 @@ err:
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);
}
@@ -1757,6 +2117,23 @@ static int ssl3_send_client_verify(SSL *s)
}
else
#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (pkey->type == EVP_PKEY_ECDSA)
+ {
+ if (!ECDSA_sign(pkey->save_type,
+ &(data[MD5_DIGEST_LENGTH]),
+ SHA_DIGEST_LENGTH,&(p[2]),
+ (unsigned int *)&j,pkey->pkey.eckey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_ECDSA_LIB);
+ goto err;
+ }
+ s2n(j,p);
+ n=j+2;
+ }
+ else
+#endif
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
goto err;
@@ -1888,6 +2265,21 @@ 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
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 14b2f13ae2..40730ca11d 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -108,6 +108,32 @@
* Hudson (tjh@cryptsoft.com).
*
*/
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * In addition, Sun covenants to all licensees who provide a reciprocal
+ * covenant with respect to their own patents if any, not to sue under
+ * current and future patent claims necessarily infringed by the making,
+ * using, practicing, selling, offering for sale and/or otherwise
+ * disposing of the Contribution as delivered hereunder
+ * (or portions thereof), provided that such covenant shall not apply:
+ * 1) for code that a licensee deletes from the Contribution;
+ * 2) separates from the Contribution; or
+ * 3) for infringements caused by:
+ * i) the modification of the Contribution or
+ * ii) the combination of the Contribution with other software or
+ * devices where such combination causes the infringement.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
#include <stdio.h>
#include <openssl/objects.h>
@@ -871,6 +897,356 @@ 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|S