Skip to content

Commit 0ad90c3

Browse files
committed
Add support for ECDHE with X25519.
Testing of an earlier revision by naddy@. ok beck@
1 parent a90a934 commit 0ad90c3

File tree

7 files changed

+316
-91
lines changed

7 files changed

+316
-91
lines changed

lib/libssl/s3_clnt.c

Lines changed: 180 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: s3_clnt.c,v 1.156 2016/12/18 13:52:53 jsing Exp $ */
1+
/* $OpenBSD: s3_clnt.c,v 1.157 2016/12/21 16:44:31 jsing Exp $ */
22
/* Copyright (C) 1995-1998 Eric Young ([email protected])
33
* All rights reserved.
44
*
@@ -156,6 +156,7 @@
156156

157157
#include <openssl/bn.h>
158158
#include <openssl/buffer.h>
159+
#include <openssl/curve25519.h>
159160
#include <openssl/dh.h>
160161
#include <openssl/evp.h>
161162
#include <openssl/md5.h>
@@ -1183,20 +1184,100 @@ ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
11831184
return (-1);
11841185
}
11851186

1187+
static int
1188+
ssl3_get_server_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, int nid, CBS *public)
1189+
{
1190+
const EC_GROUP *group;
1191+
EC_GROUP *ngroup = NULL;
1192+
EC_POINT *point = NULL;
1193+
BN_CTX *bn_ctx = NULL;
1194+
EC_KEY *ecdh = NULL;
1195+
int ret = -1;
1196+
1197+
/*
1198+
* Extract the server's ephemeral ECDH public key.
1199+
*/
1200+
1201+
if ((ecdh = EC_KEY_new()) == NULL) {
1202+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
1203+
goto err;
1204+
}
1205+
1206+
if ((ngroup = EC_GROUP_new_by_curve_name(nid)) == NULL) {
1207+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
1208+
goto err;
1209+
}
1210+
if (EC_KEY_set_group(ecdh, ngroup) == 0) {
1211+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
1212+
goto err;
1213+
}
1214+
1215+
group = EC_KEY_get0_group(ecdh);
1216+
1217+
if ((point = EC_POINT_new(group)) == NULL ||
1218+
(bn_ctx = BN_CTX_new()) == NULL) {
1219+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
1220+
goto err;
1221+
}
1222+
1223+
if (EC_POINT_oct2point(group, point, CBS_data(public),
1224+
CBS_len(public), bn_ctx) == 0) {
1225+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
1226+
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
1227+
goto err;
1228+
}
1229+
1230+
EC_KEY_set_public_key(ecdh, point);
1231+
sc->peer_ecdh_tmp = ecdh;
1232+
ecdh = NULL;
1233+
1234+
ret = 1;
1235+
1236+
err:
1237+
BN_CTX_free(bn_ctx);
1238+
EC_GROUP_free(ngroup);
1239+
EC_POINT_free(point);
1240+
EC_KEY_free(ecdh);
1241+
1242+
return (ret);
1243+
}
1244+
1245+
static int
1246+
ssl3_get_server_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, int nid, CBS *public)
1247+
{
1248+
size_t outlen;
1249+
1250+
if (nid != NID_X25519) {
1251+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
1252+
goto err;
1253+
}
1254+
1255+
if (CBS_len(public) != X25519_KEY_LENGTH) {
1256+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
1257+
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
1258+
goto err;
1259+
}
1260+
1261+
if (!CBS_stow(public, &sc->peer_x25519_tmp, &outlen)) {
1262+
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
1263+
goto err;
1264+
}
1265+
1266+
return (1);
1267+
1268+
err:
1269+
return (-1);
1270+
}
1271+
11861272
static int
11871273
ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
11881274
{
1189-
CBS cbs, ecpoint;
1275+
CBS cbs, public;
11901276
uint8_t curve_type;
11911277
uint16_t curve_id;
1192-
EC_POINT *srvr_ecpoint = NULL;
1193-
EC_KEY *ecdh = NULL;
1194-
BN_CTX *bn_ctx = NULL;
1195-
const EC_GROUP *group;
1196-
EC_GROUP *ngroup = NULL;
11971278
SESS_CERT *sc;
1198-
int curve_nid;
11991279
long alg_a;
1280+
int nid;
12001281
int al;
12011282

12021283
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)
12071288

12081289
CBS_init(&cbs, *pp, *nn);
12091290

1210-
/*
1211-
* Extract EC parameters and the server's ephemeral ECDH public key.
1212-
*/
1213-
1214-
if ((ecdh = EC_KEY_new()) == NULL) {
1215-
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
1216-
goto err;
1217-
}
1218-
12191291
/* Only named curves are supported. */
12201292
if (!CBS_get_u8(&cbs, &curve_type) ||
12211293
curve_type != NAMED_CURVE_TYPE ||
@@ -1235,39 +1307,22 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
12351307
goto f_err;
12361308
}
12371309

1238-
if ((curve_nid = tls1_ec_curve_id2nid(curve_id)) == 0) {
1310+
if ((nid = tls1_ec_curve_id2nid(curve_id)) == 0) {
12391311
al = SSL_AD_INTERNAL_ERROR;
12401312
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
12411313
SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
12421314
goto f_err;
12431315
}
12441316

1245-
if ((ngroup = EC_GROUP_new_by_curve_name(curve_nid)) == NULL) {
1246-
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
1247-
goto err;
1248-
}
1249-
if (EC_KEY_set_group(ecdh, ngroup) == 0) {
1250-
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
1251-
goto err;
1252-
}
1253-
1254-
group = EC_KEY_get0_group(ecdh);
1255-
1256-
/* Next, get the encoded ECPoint */
1257-
if ((srvr_ecpoint = EC_POINT_new(group)) == NULL ||
1258-
(bn_ctx = BN_CTX_new()) == NULL) {
1259-
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
1260-
goto err;
1261-
}
1262-
1263-
if (!CBS_get_u8_length_prefixed(&cbs, &ecpoint))
1317+
if (!CBS_get_u8_length_prefixed(&cbs, &public))
12641318
goto truncated;
12651319

1266-
if (EC_POINT_oct2point(group, srvr_ecpoint, CBS_data(&ecpoint),
1267-
CBS_len(&ecpoint), bn_ctx) == 0) {
1268-
al = SSL_AD_DECODE_ERROR;
1269-
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
1270-
goto f_err;
1320+
if (nid == NID_X25519) {
1321+
if (ssl3_get_server_kex_ecdhe_ecx(s, sc, nid, &public) != 1)
1322+
goto err;
1323+
} else {
1324+
if (ssl3_get_server_kex_ecdhe_ecp(s, sc, nid, &public) != 1)
1325+
goto err;
12711326
}
12721327

12731328
/*
@@ -1283,13 +1338,6 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
12831338
/* XXX - Anonymous ECDH, so no certificate or pkey. */
12841339
*pkey = NULL;
12851340

1286-
EC_KEY_set_public_key(ecdh, srvr_ecpoint);
1287-
sc->peer_ecdh_tmp = ecdh;
1288-
1289-
BN_CTX_free(bn_ctx);
1290-
EC_GROUP_free(ngroup);
1291-
EC_POINT_free(srvr_ecpoint);
1292-
12931341
*nn = CBS_len(&cbs);
12941342
*pp = (unsigned char *)CBS_data(&cbs);
12951343

@@ -1303,11 +1351,6 @@ ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn)
13031351
ssl3_send_alert(s, SSL3_AL_FATAL, al);
13041352

13051353
err:
1306-
BN_CTX_free(bn_ctx);
1307-
EC_GROUP_free(ngroup);
1308-
EC_POINT_free(srvr_ecpoint);
1309-
EC_KEY_free(ecdh);
1310-
13111354
return (-1);
13121355
}
13131356

@@ -1360,6 +1403,9 @@ ssl3_get_server_key_exchange(SSL *s)
13601403

13611404
EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
13621405
s->session->sess_cert->peer_ecdh_tmp = NULL;
1406+
1407+
free(s->session->sess_cert->peer_x25519_tmp);
1408+
s->session->sess_cert->peer_x25519_tmp = NULL;
13631409
} else {
13641410
s->session->sess_cert = ssl_sess_cert_new();
13651411
if (s->session->sess_cert == NULL)
@@ -2010,11 +2056,11 @@ ssl3_send_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
20102056
}
20112057

20122058
static int
2013-
ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
2059+
ssl3_send_client_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, CBB *cbb)
20142060
{
2015-
EC_KEY *clnt_ecdh = NULL;
2016-
const EC_GROUP *srvr_group = NULL;
2017-
const EC_POINT *srvr_ecpoint = NULL;
2061+
const EC_GROUP *group = NULL;
2062+
const EC_POINT *point = NULL;
2063+
EC_KEY *ecdh = NULL;
20182064
BN_CTX *bn_ctx = NULL;
20192065
unsigned char *key = NULL;
20202066
unsigned char *data;
@@ -2023,48 +2069,38 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
20232069
int ret = -1;
20242070
CBB ecpoint;
20252071

2026-
if (sess_cert->peer_ecdh_tmp == NULL) {
2027-
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
2072+
if ((group = EC_KEY_get0_group(sc->peer_ecdh_tmp)) == NULL ||
2073+
(point = EC_KEY_get0_public_key(sc->peer_ecdh_tmp)) == NULL) {
20282074
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
20292075
ERR_R_INTERNAL_ERROR);
20302076
goto err;
20312077
}
20322078

2033-
srvr_group = EC_KEY_get0_group(sess_cert->peer_ecdh_tmp);
2034-
srvr_ecpoint = EC_KEY_get0_public_key(sess_cert->peer_ecdh_tmp);
2035-
2036-
if (srvr_group == NULL || srvr_ecpoint == NULL) {
2037-
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
2038-
ERR_R_INTERNAL_ERROR);
2039-
goto err;
2040-
}
2041-
2042-
if ((clnt_ecdh = EC_KEY_new()) == NULL) {
2079+
if ((ecdh = EC_KEY_new()) == NULL) {
20432080
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
20442081
ERR_R_MALLOC_FAILURE);
20452082
goto err;
20462083
}
20472084

2048-
if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
2085+
if (!EC_KEY_set_group(ecdh, group)) {
20492086
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
20502087
goto err;
20512088
}
20522089

20532090
/* Generate a new ECDH key pair. */
2054-
if (!(EC_KEY_generate_key(clnt_ecdh))) {
2091+
if (!(EC_KEY_generate_key(ecdh))) {
20552092
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
20562093
goto err;
20572094
}
2058-
key_size = ECDH_size(clnt_ecdh);
2059-
if (key_size <= 0) {
2095+
if ((key_size = ECDH_size(ecdh)) <= 0) {
20602096
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
20612097
goto err;
20622098
}
20632099
if ((key = malloc(key_size)) == NULL) {
20642100
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
20652101
ERR_R_MALLOC_FAILURE);
20662102
}
2067-
key_len = ECDH_compute_key(key, key_size, srvr_ecpoint, clnt_ecdh, NULL);
2103+
key_len = ECDH_compute_key(key, key_size, point, ecdh, NULL);
20682104
if (key_len <= 0) {
20692105
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
20702106
goto err;
@@ -2075,8 +2111,7 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
20752111
s->method->ssl3_enc->generate_master_secret(s,
20762112
s->session->master_key, key, key_len);
20772113

2078-
encoded_len = EC_POINT_point2oct(srvr_group,
2079-
EC_KEY_get0_public_key(clnt_ecdh),
2114+
encoded_len = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh),
20802115
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
20812116
if (encoded_len == 0) {
20822117
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)
20942129
goto err;
20952130
if (!CBB_add_space(&ecpoint, &data, encoded_len))
20962131
goto err;
2097-
if (EC_POINT_point2oct(srvr_group, EC_KEY_get0_public_key(clnt_ecdh),
2132+
if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh),
20982133
POINT_CONVERSION_UNCOMPRESSED, data, encoded_len,
20992134
bn_ctx) == 0)
21002135
goto err;
@@ -2108,12 +2143,77 @@ ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
21082143
explicit_bzero(key, key_size);
21092144
free(key);
21102145

2111-
BN_CTX_free(bn_ctx);
2112-
EC_KEY_free(clnt_ecdh);
2146+
return (ret);
2147+
}
2148+
2149+
static int
2150+
ssl3_send_client_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, CBB *cbb)
2151+
{
2152+
uint8_t *public_key = NULL, *private_key = NULL, *shared_key = NULL;
2153+
int ret = -1;
2154+
CBB ecpoint;
2155+
2156+
/* Generate X25519 key pair and derive shared key. */
2157+
if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL)
2158+
goto err;
2159+
if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL)
2160+
goto err;
2161+
if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL)
2162+
goto err;
2163+
X25519_keypair(public_key, private_key);
2164+
if (!X25519(shared_key, private_key, sc->peer_x25519_tmp))
2165+
goto err;
2166+
2167+
/* Serialize the public key. */
2168+
if (!CBB_add_u8_length_prefixed(cbb, &ecpoint))
2169+
goto err;
2170+
if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH))
2171+
goto err;
2172+
if (!CBB_flush(cbb))
2173+
goto err;
2174+
2175+
/* Generate master key from the result. */
2176+
s->session->master_key_length =
2177+
s->method->ssl3_enc->generate_master_secret(s,
2178+
s->session->master_key, shared_key, X25519_KEY_LENGTH);
2179+
2180+
ret = 1;
2181+
2182+
err:
2183+
if (private_key != NULL)
2184+
explicit_bzero(private_key, X25519_KEY_LENGTH);
2185+
if (shared_key != NULL)
2186+
explicit_bzero(shared_key, X25519_KEY_LENGTH);
2187+
2188+
free(public_key);
2189+
free(private_key);
2190+
free(shared_key);
21132191

21142192
return (ret);
21152193
}
21162194

2195+
static int
2196+
ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sc, CBB *cbb)
2197+
{
2198+
if (sc->peer_x25519_tmp != NULL) {
2199+
if (ssl3_send_client_kex_ecdhe_ecx(s, sc, cbb) != 1)
2200+
goto err;
2201+
} else if (sc->peer_ecdh_tmp != NULL) {
2202+
if (ssl3_send_client_kex_ecdhe_ecp(s, sc, cbb) != 1)
2203+
goto err;
2204+
} else {
2205+
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
2206+
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
2207+
ERR_R_INTERNAL_ERROR);
2208+
goto err;
2209+
}
2210+
2211+
return (1);
2212+
2213+
err:
2214+
return (-1);
2215+
}
2216+
21172217
static int
21182218
ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb)
21192219
{

0 commit comments

Comments
 (0)