summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2016-12-21 16:44:32 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2016-12-21 16:44:32 +0000
commiteddce5bd7db41e4fad671b4dafb7ea75781328b1 (patch)
tree0802607a4bcee6e1b81ceb80bad82e9d74e626a7 /lib
parent2ea2fedf3e342d5bb7236940e1b8267a12dca9f3 (diff)
Add support for ECDHE with X25519.
Testing of an earlier revision by naddy@. ok beck@
Diffstat (limited to 'lib')
-rw-r--r--lib/libssl/s3_clnt.c260
-rw-r--r--lib/libssl/s3_lib.c12
-rw-r--r--lib/libssl/s3_srvr.c117
-rw-r--r--lib/libssl/ssl3.h4
-rw-r--r--lib/libssl/ssl_cert.c3
-rw-r--r--lib/libssl/ssl_locl.h3
-rw-r--r--lib/libssl/t1_lib.c8
7 files changed, 316 insertions, 91 deletions
diff --git a/lib/libssl/s3_clnt.c b/lib/libssl/s3_clnt.c
index be6e461a1e0..07457e95a7a 100644
--- a/lib/libssl/s3_clnt.c
+++ b/lib/libssl/s3_clnt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: s3_clnt.c,v 1.156 2016/12/18 13:52:53 jsing Exp $ */
+/* $OpenBSD: s3_clnt.c,v 1.157 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -156,6 +156,7 @@
#include <openssl/bn.h>
#include <openssl/buffer.h>
+#include <openssl/curve25519.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
@@ -1184,19 +1185,99 @@ ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
}
static int
+ssl3_get_server_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, int nid, CBS *public)
+{
+ const EC_GROUP *group;
+ EC_GROUP *ngroup = NULL;
+ EC_POINT *point = NULL;
+ BN_CTX *bn_ctx = NULL;
+ EC_KEY *ecdh = NULL;
+ int ret = -1;
+
+ /*
+ * Extract the server's ephemeral ECDH public key.
+ */
+
+ if ((ecdh = EC_KEY_new()) == NULL) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((ngroup = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (EC_KEY_set_group(ecdh, ngroup) == 0) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ group = EC_KEY_get0_group(ecdh);
+
+ if ((point = EC_POINT_new(group)) == NULL ||
+ (bn_ctx = BN_CTX_new()) == NULL) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EC_POINT_oct2point(group, point, CBS_data(public),
+ CBS_len(public), bn_ctx) == 0) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ EC_KEY_set_public_key(ecdh, point);
+ sc->peer_ecdh_tmp = ecdh;
+ ecdh = NULL;
+
+ ret = 1;
+
+ err:
+ BN_CTX_free(bn_ctx);
+ EC_GROUP_free(ngroup);
+ EC_POINT_free(point);
+ EC_KEY_free(ecdh);
+
+ return (ret);
+}
+
+static int
+ssl3_get_server_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, int nid, CBS *public)
+{
+ size_t outlen;
+
+ if (nid != NID_X25519) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (CBS_len(public) != X25519_KEY_LENGTH) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (!CBS_stow(public, &sc->peer_x25519_tmp, &outlen)) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ return (1);
+
+ err:
+ return (-1);
+}
+
+static int
ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
{
- CBS cbs, ecpoint;
+ CBS cbs, public;
uint8_t curve_type;
uint16_t curve_id;
- EC_POINT *srvr_ecpoint = NULL;
- EC_KEY *ecdh = NULL;
- BN_CTX *bn_ctx = NULL;
- const EC_GROUP *group;
- EC_GROUP *ngroup = NULL;
SESS_CERT *sc;
- int curve_nid;
long alg_a;
+ int nid;
int al;
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -1207,15 +1288,6 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
CBS_init(&cbs, *pp, *nn);
- /*
- * Extract EC parameters and the server's ephemeral ECDH public key.
- */
-
- if ((ecdh = EC_KEY_new()) == NULL) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
/* Only named curves are supported. */
if (!CBS_get_u8(&cbs, &curve_type) ||
curve_type != NAMED_CURVE_TYPE ||
@@ -1235,39 +1307,22 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
goto f_err;
}
- if ((curve_nid = tls1_ec_curve_id2nid(curve_id)) == 0) {
+ if ((nid = tls1_ec_curve_id2nid(curve_id)) == 0) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
goto f_err;
}
- if ((ngroup = EC_GROUP_new_by_curve_name(curve_nid)) == NULL) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
- goto err;
- }
- if (EC_KEY_set_group(ecdh, ngroup) == 0) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
- goto err;
- }
-
- group = EC_KEY_get0_group(ecdh);
-
- /* Next, get the encoded ECPoint */
- if ((srvr_ecpoint = EC_POINT_new(group)) == NULL ||
- (bn_ctx = BN_CTX_new()) == NULL) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!CBS_get_u8_length_prefixed(&cbs, &ecpoint))
+ if (!CBS_get_u8_length_prefixed(&cbs, &public))
goto truncated;
- if (EC_POINT_oct2point(group, srvr_ecpoint, CBS_data(&ecpoint),
- CBS_len(&ecpoint), bn_ctx) == 0) {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
- goto f_err;
+ if (nid == NID_X25519) {
+ if (ssl3_get_server_kex_ecdhe_ecx(s, sc, nid, &public) != 1)
+ goto err;
+ } else {
+ if (ssl3_get_server_kex_ecdhe_ecp(s, sc, nid, &public) != 1)
+ goto err;
}
/*
@@ -1283,13 +1338,6 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
/* XXX - Anonymous ECDH, so no certificate or pkey. */
*pkey = NULL;
- EC_KEY_set_public_key(ecdh, srvr_ecpoint);
- sc->peer_ecdh_tmp = ecdh;
-
- BN_CTX_free(bn_ctx);
- EC_GROUP_free(ngroup);
- EC_POINT_free(srvr_ecpoint);
-
*nn = CBS_len(&cbs);
*pp = (unsigned char *)CBS_data(&cbs);
@@ -1303,11 +1351,6 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
- BN_CTX_free(bn_ctx);
- EC_GROUP_free(ngroup);
- EC_POINT_free(srvr_ecpoint);
- EC_KEY_free(ecdh);
-
return (-1);
}
@@ -1360,6 +1403,9 @@ ssl3_get_server_key_exchange(SSL *s)
EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
s->session->sess_cert->peer_ecdh_tmp = NULL;
+
+ free(s->session->sess_cert->peer_x25519_tmp);
+ s->session->sess_cert->peer_x25519_tmp = NULL;
} else {
s->session->sess_cert = ssl_sess_cert_new();
if (s->session->sess_cert == NULL)
@@ -2010,11 +2056,11 @@ err:
}
static int
-ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
+ssl3_send_client_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, CBB *cbb)
{
- EC_KEY *clnt_ecdh = NULL;
- const EC_GROUP *srvr_group = NULL;
- const EC_POINT *srvr_ecpoint = NULL;
+ const EC_GROUP *group = NULL;
+ const EC_POINT *point = NULL;
+ EC_KEY *ecdh = NULL;
BN_CTX *bn_ctx = NULL;
unsigned char *key = NULL;
unsigned char *data;
@@ -2023,40 +2069,30 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
int ret = -1;
CBB ecpoint;
- if (sess_cert->peer_ecdh_tmp == NULL) {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ if ((group = EC_KEY_get0_group(sc->peer_ecdh_tmp)) == NULL ||
+ (point = EC_KEY_get0_public_key(sc->peer_ecdh_tmp)) == NULL) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_INTERNAL_ERROR);
goto err;
}
- srvr_group = EC_KEY_get0_group(sess_cert->peer_ecdh_tmp);
- srvr_ecpoint = EC_KEY_get0_public_key(sess_cert->peer_ecdh_tmp);
-
- 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) {
+ if ((ecdh = EC_KEY_new()) == NULL) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_MALLOC_FAILURE);
goto err;
}
- if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
+ if (!EC_KEY_set_group(ecdh, group)) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
goto err;
}
/* Generate a new ECDH key pair. */
- if (!(EC_KEY_generate_key(clnt_ecdh))) {
+ if (!(EC_KEY_generate_key(ecdh))) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
goto err;
}
- key_size = ECDH_size(clnt_ecdh);
- if (key_size <= 0) {
+ if ((key_size = ECDH_size(ecdh)) <= 0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
goto err;
}
@@ -2064,7 +2100,7 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_MALLOC_FAILURE);
}
- key_len = ECDH_compute_key(key, key_size, srvr_ecpoint, clnt_ecdh, NULL);
+ key_len = ECDH_compute_key(key, key_size, point, ecdh, NULL);
if (key_len <= 0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
goto err;
@@ -2075,8 +2111,7 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key, key, key_len);
- encoded_len = EC_POINT_point2oct(srvr_group,
- EC_KEY_get0_public_key(clnt_ecdh),
+ encoded_len = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh),
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
if (encoded_len == 0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
@@ -2094,7 +2129,7 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
goto err;
if (!CBB_add_space(&ecpoint, &data, encoded_len))
goto err;
- if (EC_POINT_point2oct(srvr_group, EC_KEY_get0_public_key(clnt_ecdh),
+ if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh),
POINT_CONVERSION_UNCOMPRESSED, data, encoded_len,
bn_ctx) == 0)
goto err;
@@ -2108,13 +2143,78 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
explicit_bzero(key, key_size);
free(key);
- BN_CTX_free(bn_ctx);
- EC_KEY_free(clnt_ecdh);
+ return (ret);
+}
+
+static int
+ssl3_send_client_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, CBB *cbb)
+{
+ uint8_t *public_key = NULL, *private_key = NULL, *shared_key = NULL;
+ int ret = -1;
+ CBB ecpoint;
+
+ /* Generate X25519 key pair and derive shared key. */
+ if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ X25519_keypair(public_key, private_key);
+ if (!X25519(shared_key, private_key, sc->peer_x25519_tmp))
+ goto err;
+
+ /* Serialize the public key. */
+ if (!CBB_add_u8_length_prefixed(cbb, &ecpoint))
+ goto err;
+ if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH))
+ goto err;
+ if (!CBB_flush(cbb))
+ 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, shared_key, X25519_KEY_LENGTH);
+
+ ret = 1;
+
+ err:
+ if (private_key != NULL)
+ explicit_bzero(private_key, X25519_KEY_LENGTH);
+ if (shared_key != NULL)
+ explicit_bzero(shared_key, X25519_KEY_LENGTH);
+
+ free(public_key);
+ free(private_key);
+ free(shared_key);
return (ret);
}
static int
+ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sc, CBB *cbb)
+{
+ if (sc->peer_x25519_tmp != NULL) {
+ if (ssl3_send_client_kex_ecdhe_ecx(s, sc, cbb) != 1)
+ goto err;
+ } else if (sc->peer_ecdh_tmp != NULL) {
+ if (ssl3_send_client_kex_ecdhe_ecp(s, sc, cbb) != 1)
+ goto err;
+ } else {
+ 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;
+ }
+
+ return (1);
+
+ err:
+ return (-1);
+}
+
+static int
ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
{
unsigned char premaster_secret[32], shared_ukm[32], tmp[256];
diff --git a/lib/libssl/s3_lib.c b/lib/libssl/s3_lib.c
index db9292172d9..212de5f7a44 100644
--- a/lib/libssl/s3_lib.c
+++ b/lib/libssl/s3_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: s3_lib.c,v 1.113 2016/12/06 13:17:52 jsing Exp $ */
+/* $OpenBSD: s3_lib.c,v 1.114 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -151,6 +151,7 @@
#include <limits.h>
#include <stdio.h>
+#include <openssl/curve25519.h>
#include <openssl/dh.h>
#include <openssl/md5.h>
#include <openssl/objects.h>
@@ -1835,6 +1836,10 @@ ssl3_free(SSL *s)
DH_free(s->s3->tmp.dh);
EC_KEY_free(s->s3->tmp.ecdh);
+ if (s->s3->tmp.x25519 != NULL)
+ explicit_bzero(s->s3->tmp.x25519, X25519_KEY_LENGTH);
+ free(s->s3->tmp.x25519);
+
if (s->s3->tmp.ca_names != NULL)
sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
BIO_free(s->s3->handshake_buffer);
@@ -1861,6 +1866,11 @@ ssl3_clear(SSL *s)
EC_KEY_free(s->s3->tmp.ecdh);
s->s3->tmp.ecdh = NULL;
+ if (s->s3->tmp.x25519 != NULL)
+ explicit_bzero(s->s3->tmp.x25519, X25519_KEY_LENGTH);
+ free(s->s3->tmp.x25519);
+ s->s3->tmp.x25519 = NULL;
+
rp = s->s3->rbuf.buf;
wp = s->s3->wbuf.buf;
rlen = s->s3->rbuf.len;
diff --git a/lib/libssl/s3_srvr.c b/lib/libssl/s3_srvr.c
index 3dd085115da..8e3dc11fc1d 100644
--- a/lib/libssl/s3_srvr.c
+++ b/lib/libssl/s3_srvr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: s3_srvr.c,v 1.137 2016/12/07 13:18:38 jsing Exp $ */
+/* $OpenBSD: s3_srvr.c,v 1.138 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -154,6 +154,7 @@
#include <openssl/bn.h>
#include <openssl/buffer.h>
+#include <openssl/curve25519.h>
#include <openssl/evp.h>
#include <openssl/dh.h>
#ifndef OPENSSL_NO_GOST
@@ -1268,8 +1269,8 @@ ssl3_send_server_kex_dhe(SSL *s, CBB *cbb)
return (-1);
}
-int
-ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb)
+static int
+ssl3_send_server_kex_ecdhe_ecp(SSL *s, int nid, CBB *cbb)
{
CBB ecpoint;
unsigned char *data;
@@ -1283,7 +1284,6 @@ ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb)
ecdhp = s->cert->ecdh_tmp;
if (s->cert->ecdh_tmp_auto != 0) {
- int nid = tls1_get_shared_curve(s);
if (nid != NID_undef)
ecdhp = EC_KEY_new_by_curve_name(nid);
} else if (ecdhp == NULL && s->cert->ecdh_tmp_cb != NULL) {
@@ -1404,6 +1404,65 @@ ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb)
return (-1);
}
+static int
+ssl3_send_server_kex_ecdhe_ecx(SSL *s, int nid, CBB *cbb)
+{
+ uint8_t *public_key = NULL;
+ int curve_id;
+ CBB ecpoint;
+ int ret = -1;
+
+ /* Generate an X25519 key pair. */
+ if (s->s3->tmp.x25519 != NULL) {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if ((s->s3->tmp.x25519 = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ X25519_keypair(public_key, s->s3->tmp.x25519);
+
+ /* Serialize public key. */
+ if ((curve_id = tls1_ec_nid2curve_id(nid)) == 0) {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+ SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+ goto err;
+ }
+
+ if (!CBB_add_u8(cbb, NAMED_CURVE_TYPE))
+ goto err;
+ if (!CBB_add_u16(cbb, curve_id))
+ goto err;
+ if (!CBB_add_u8_length_prefixed(cbb, &ecpoint))
+ goto err;
+ if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH))
+ goto err;
+ if (!CBB_flush(cbb))
+ goto err;
+
+ ret = 1;
+
+ err:
+ free(public_key);
+
+ return (ret);
+}
+
+static int
+ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb)
+{
+ int nid;
+
+ nid = tls1_get_shared_curve(s);
+
+ if (s->cert->ecdh_tmp_auto != 0 && nid == NID_X25519)
+ return ssl3_send_server_kex_ecdhe_ecx(s, nid, cbb);
+
+ return ssl3_send_server_kex_ecdhe_ecp(s, nid, cbb);
+}
+
int
ssl3_send_server_key_exchange(SSL *s)
{
@@ -1822,7 +1881,7 @@ ssl3_get_client_kex_dhe(SSL *s, unsigned char *p, long n)
}
static int
-ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n)
+ssl3_get_client_kex_ecdhe_ecp(SSL *s, unsigned char *p, long n)
{
EC_KEY *srvr_ecdh = NULL;
EVP_PKEY *clnt_pub_pkey = NULL;
@@ -1971,6 +2030,54 @@ ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n)
}
static int
+ssl3_get_client_kex_ecdhe_ecx(SSL *s, unsigned char *p, long n)
+{
+ uint8_t *shared_key = NULL;
+ CBS cbs, ecpoint;
+ int ret = -1;
+
+ if (n < 0)
+ goto err;
+
+ CBS_init(&cbs, p, n);
+ if (!CBS_get_u8_length_prefixed(&cbs, &ecpoint))
+ goto err;
+ if (CBS_len(&ecpoint) != X25519_KEY_LENGTH)
+ goto err;
+
+ if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL)
+ goto err;
+ if (!X25519(shared_key, s->s3->tmp.x25519, CBS_data(&ecpoint)))
+ goto err;
+
+ explicit_bzero(s->s3->tmp.x25519, X25519_KEY_LENGTH);
+ free(s->s3->tmp.x25519);
+ s->s3->tmp.x25519 = NULL;
+
+ s->session->master_key_length =
+ s->method->ssl3_enc->generate_master_secret(
+ s, s->session->master_key, shared_key, X25519_KEY_LENGTH);
+
+ ret = 1;
+
+ err:
+ if (shared_key != NULL)
+ explicit_bzero(shared_key, X25519_KEY_LENGTH);
+ free(shared_key);
+
+ return (ret);
+}
+
+static int
+ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n)
+{
+ if (s->s3->tmp.x25519 != NULL)
+ return ssl3_get_client_kex_ecdhe_ecx(s, p, n);
+
+ return ssl3_get_client_kex_ecdhe_ecp(s, p, n);
+}
+
+static int
ssl3_get_client_kex_gost(SSL *s, unsigned char *p, long n)
{
diff --git a/lib/libssl/ssl3.h b/lib/libssl/ssl3.h
index 5ec2fe6f884..90fcae7914e 100644
--- a/lib/libssl/ssl3.h
+++ b/lib/libssl/ssl3.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl3.h,v 1.41 2015/07/19 06:23:51 doug Exp $ */
+/* $OpenBSD: ssl3.h,v 1.42 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -440,6 +440,8 @@ typedef struct ssl3_state_st {
EC_KEY *ecdh; /* holds short lived ECDH key */
+ uint8_t *x25519;
+
/* used when SSL_ST_FLUSH_DATA is entered */
int next_state;
diff --git a/lib/libssl/ssl_cert.c b/lib/libssl/ssl_cert.c
index 7e92812e56a..294745c9f93 100644
--- a/lib/libssl/ssl_cert.c
+++ b/lib/libssl/ssl_cert.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_cert.c,v 1.52 2016/03/11 07:08:45 mmcc Exp $ */
+/* $OpenBSD: ssl_cert.c,v 1.53 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -403,6 +403,7 @@ ssl_sess_cert_free(SESS_CERT *sc)
DH_free(sc->peer_dh_tmp);
EC_KEY_free(sc->peer_ecdh_tmp);
+ free(sc->peer_x25519_tmp);
free(sc);
}
diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h
index d7484dd7a0c..858be716272 100644
--- a/lib/libssl/ssl_locl.h
+++ b/lib/libssl/ssl_locl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_locl.h,v 1.140 2016/12/18 13:52:53 jsing Exp $ */
+/* $OpenBSD: ssl_locl.h,v 1.141 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -468,6 +468,7 @@ typedef struct sess_cert_st {
DH *peer_dh_tmp;
EC_KEY *peer_ecdh_tmp;
+ uint8_t *peer_x25519_tmp;
int references; /* actually always 1 at the moment */
} SESS_CERT;
diff --git a/lib/libssl/t1_lib.c b/lib/libssl/t1_lib.c
index 0a5958341b7..4e4fa216875 100644
--- a/lib/libssl/t1_lib.c
+++ b/lib/libssl/t1_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: t1_lib.c,v 1.95 2016/12/18 13:52:53 jsing Exp $ */
+/* $OpenBSD: t1_lib.c,v 1.96 2016/12/21 16:44:31 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -241,7 +241,8 @@ static int nid_list[] = {
NID_secp521r1, /* secp521r1 (25) */
NID_brainpoolP256r1, /* brainpoolP256r1 (26) */
NID_brainpoolP384r1, /* brainpoolP384r1 (27) */
- NID_brainpoolP512r1 /* brainpoolP512r1 (28) */
+ NID_brainpoolP512r1, /* brainpoolP512r1 (28) */
+ NID_X25519, /* X25519 (29) */
};
static const uint8_t ecformats_default[] = {
@@ -251,6 +252,7 @@ static const uint8_t ecformats_default[] = {
};
static const uint16_t eccurves_default[] = {
+ 29, /* X25519 (29) */
14, /* sect571r1 (14) */
13, /* sect571k1 (13) */
25, /* secp521r1 (25) */
@@ -352,6 +354,8 @@ tls1_ec_nid2curve_id(int nid)
return 27;
case NID_brainpoolP512r1: /* brainpoolP512r1 (28) */
return 28;
+ case NID_X25519: /* X25519 (29) */
+ return 29;
default:
return 0;
}