Add the handler for the ECDHE ServerKeyExchange message rx and a
builder for the ClientKeyExchange message tx, both specified in
RFC 8422.
---
ell/tls-extensions.c | 11 ++++
ell/tls-private.h | 2 +
ell/tls-suites.c | 145 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 158 insertions(+)
diff --git a/ell/tls-extensions.c b/ell/tls-extensions.c
index 3d75037..be2fa10 100644
--- a/ell/tls-extensions.c
+++ b/ell/tls-extensions.c
@@ -148,3 +148,14 @@ const struct tls_hello_extension tls_extensions[] = {
},
{}
};
+
+const struct tls_named_curve *tls_find_curve(uint16_t id)
+{
+ unsigned int i;
+
+ for (i = 0; i < L_ARRAY_SIZE(tls_curve_pref); i++)
+ if (tls_curve_pref[i].id == id)
+ return &tls_curve_pref[i];
+
+ return NULL;
+}
diff --git a/ell/tls-private.h b/ell/tls-private.h
index bb7d58d..3f68a1d 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -305,6 +305,8 @@ void tls_generate_master_secret(struct l_tls *tls,
const uint8_t *pre_master_secret,
int pre_master_secret_len);
+const struct tls_named_curve *tls_find_curve(uint16_t id);
+
int tls_parse_certificate_list(const void *data, size_t len,
struct l_certchain **out_certchain);
diff --git a/ell/tls-suites.c b/ell/tls-suites.c
index d280f32..4ec6d54 100644
--- a/ell/tls-suites.c
+++ b/ell/tls-suites.c
@@ -453,6 +453,149 @@ static bool tls_send_ecdhe_server_key_xchg(struct l_tls *tls)
return true;
}
+static bool tls_send_ecdhe_client_key_xchg(struct l_tls *tls)
+{
+ uint8_t buf[1024];
+ uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
+ uint8_t pre_master_secret[128];
+ ssize_t pre_master_secret_len;
+ struct tls_ecdhe_params *params = tls->pending.key_xchg_params;
+ struct l_ecc_point *our_public;
+ struct l_ecc_scalar *secret;
+
+ /* RFC 8422, Section 5.7 */
+
+ if (!l_ecdh_generate_key_pair(params->curve,
+ ¶ms->private, &our_public)) {
+ TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+ "Generating ECDH key pair failed");
+ return false;
+ }
+
+ ptr += tls_write_ecpoint(ptr, tls->negotiated_curve, our_public);
+ l_ecc_point_free(our_public);
+
+ /*
+ * Neither 5.4 or 5.7 "Actions" paragraphs say when the ECDH shared
+ * secret is calculated but we can either do this in
+ * tls_handle_ecdhe_server_key_xchg or here. In both cases we only
+ * need to store the public key in the client's key_xchg_params and
+ * can free all of the params after sending the ClientKeyExchange.
+ * By doing this calculation here we're aligned with RSA and also
+ * with the server mode where the shared secret can only be
+ * calculated after the ClientKeyExchange is received.
+ */
+ if (!l_ecdh_generate_shared_secret(params->private, params->public,
+ &secret)) {
+ TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+ "Generating ECDH shared-secret failed");
+ return false;
+ }
+
+ tls_free_ecdhe_params(tls);
+ pre_master_secret_len = l_ecc_scalar_get_data(secret,
+ pre_master_secret,
+ sizeof(pre_master_secret));
+ l_ecc_scalar_free(secret);
+
+ if (pre_master_secret_len < 0) {
+ TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+ "l_ecc_scalar_get_data(secret) failed");
+ return false;
+ }
+
+ tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf);
+
+ tls_generate_master_secret(tls, pre_master_secret,
+ pre_master_secret_len);
+ memset(pre_master_secret, 0, pre_master_secret_len);
+
+ return true;
+}
+
+static void tls_handle_ecdhe_server_key_xchg(struct l_tls *tls,
+ const uint8_t *buf, size_t len)
+{
+ struct tls_ecdhe_params *params;
+ uint16_t namedcurve;
+
+ /* RFC 8422, Section 5.4 */
+
+ if (len < 5)
+ goto decode_error;
+
+ if (*buf != 3) {
+ TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0,
+ "Unsupported (deprecated?) ECCurveType %u",
+ *buf);
+ return;
+ }
+
+ namedcurve = l_get_be16(buf + 1);
+ buf += 3;
+ len -= 3;
+
+ tls->negotiated_curve = tls_find_curve(namedcurve);
+
+ if (!tls->negotiated_curve) {
+ TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0,
+ "Unsupported NamedCurve %u", namedcurve);
+ return;
+ }
+
+ TLS_DEBUG("Negotiated %s", tls->negotiated_curve->name);
+
+ if (*buf++ != 1 + tls->negotiated_curve->point_bytes)
+ goto decode_error;
+
+ if (*buf != 4) { /* uncompressed */
+ TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0,
+ "Unsupported (deprecated?) PointConversionForm "
+ "%u", *buf);
+ return;
+ }
+
+ buf++;
+ len -= 2;
+
+ if (len < tls->negotiated_curve->point_bytes)
+ goto decode_error;
+
+ /*
+ * RFC 8422, Section 5.11: "A receiving party MUST check that the
+ * x and y parameters from the peer's public value satisfy the
+ * curve equation, y^2 = x^3 + ax + b mod p."
+ * This happens in l_ecc_point_from_data when the L_ECC_POINT_TYPE_FULL
+ * format is used.
+ */
+ params = l_new(struct tls_ecdhe_params, 1);
+ params->curve = l_ecc_curve_get(tls->negotiated_curve->l_group);
+ params->public = l_ecc_point_from_data(params->curve,
+ L_ECC_POINT_TYPE_FULL,
+ buf, len);
+ tls->pending.key_xchg_params = params;
+ buf += tls->negotiated_curve->point_bytes;
+ len -= tls->negotiated_curve->point_bytes;
+
+ if (!params->public) {
+ TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
+ "ServerKeyExchange.params.public decode error");
+ return;
+ }
+
+ if (!tls->pending.cipher_suite->key_xchg->verify(tls, buf, len,
+ tls_get_server_ecdh_params_hash))
+ return;
+
+ TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE);
+
+ return;
+
+decode_error:
+ TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
+ "ServerKeyExchange decode error");
+}
+
static void tls_handle_ecdhe_client_key_xchg(struct l_tls *tls,
const uint8_t *buf, size_t len)
{
@@ -536,8 +679,10 @@ static struct tls_key_exchange_algorithm tls_ecdhe_rsa = {
.certificate_check = true,
.need_ecc = true,
.validate_cert_key_type = tls_rsa_validate_cert_key,
+ .send_client_key_exchange = tls_send_ecdhe_client_key_xchg,
.handle_client_key_exchange = tls_handle_ecdhe_client_key_xchg,
.send_server_key_exchange = tls_send_ecdhe_server_key_xchg,
+ .handle_server_key_exchange = tls_handle_ecdhe_server_key_xchg,
.free_params = tls_free_ecdhe_params,
.sign = tls_rsa_sign,
.verify = tls_rsa_verify,
--
2.19.1