From 76bb720394d14503c5406702e23860ea05dbe4d7 Mon Sep 17 00:00:00 2001 From: jsing Date: Mon, 29 Nov 2021 16:00:32 +0000 Subject: [PATCH] Factor out/rewrite DHE key exchange. This follows what was done previously for ECDHE EC point key exchange and will allow for deduplication and further code improvement. Convert the TLSv1.2 client to use the new DHE key exchange functions. ok inoguchi@ tb@ --- lib/libssl/ssl_clnt.c | 84 ++++++------------------ lib/libssl/ssl_kex.c | 145 +++++++++++++++++++++++++++++++++++++++++- lib/libssl/ssl_locl.h | 10 ++- 3 files changed, 173 insertions(+), 66 deletions(-) diff --git a/lib/libssl/ssl_clnt.c b/lib/libssl/ssl_clnt.c index 6fe15dcf1dc..b349f24cb02 100644 --- a/lib/libssl/ssl_clnt.c +++ b/lib/libssl/ssl_clnt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_clnt.c,v 1.119 2021/11/26 16:41:42 tb Exp $ */ +/* $OpenBSD: ssl_clnt.c,v 1.120 2021/11/29 16:00:32 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1223,46 +1223,24 @@ ssl3_get_server_certificate(SSL *s) static int ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, CBS *cbs) { - CBS dhp, dhg, dhpk; - BN_CTX *bn_ctx = NULL; SESS_CERT *sc = NULL; DH *dh = NULL; long alg_a; - int al; alg_a = S3I(s)->hs.cipher->algorithm_auth; sc = s->session->sess_cert; - if ((dh = DH_new()) == NULL) { - SSLerror(s, ERR_R_DH_LIB); - goto err; - } - - if (!CBS_get_u16_length_prefixed(cbs, &dhp)) - goto decode_err; - if ((dh->p = BN_bin2bn(CBS_data(&dhp), CBS_len(&dhp), NULL)) == NULL) { - SSLerror(s, ERR_R_BN_LIB); + if ((dh = DH_new()) == NULL) goto err; - } - if (!CBS_get_u16_length_prefixed(cbs, &dhg)) + if (!ssl_kex_peer_params_dhe(dh, cbs)) goto decode_err; - if ((dh->g = BN_bin2bn(CBS_data(&dhg), CBS_len(&dhg), NULL)) == NULL) { - SSLerror(s, ERR_R_BN_LIB); - goto err; - } - - if (!CBS_get_u16_length_prefixed(cbs, &dhpk)) + if (!ssl_kex_peer_public_dhe(dh, cbs)) goto decode_err; - if ((dh->pub_key = BN_bin2bn(CBS_data(&dhpk), CBS_len(&dhpk), - NULL)) == NULL) { - SSLerror(s, ERR_R_BN_LIB); - goto err; - } /* * Check the strength of the DH key just constructed. - * Discard keys weaker than 1024 bits. + * Reject keys weaker than 1024 bits. */ if (DH_size(dh) < 1024 / 8) { SSLerror(s, SSL_R_BAD_DH_P_LENGTH); @@ -1280,13 +1258,11 @@ ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, CBS *cbs) return (1); decode_err: - al = SSL_AD_DECODE_ERROR; SSLerror(s, SSL_R_BAD_PACKET_LENGTH); - ssl3_send_alert(s, SSL3_AL_FATAL, al); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); err: DH_free(dh); - BN_CTX_free(bn_ctx); return (-1); } @@ -1988,59 +1964,38 @@ ssl3_send_client_kex_rsa(SSL *s, SESS_CERT *sess_cert, CBB *cbb) static int ssl3_send_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb) { - DH *dh_srvr = NULL, *dh_clnt = NULL; - unsigned char *key = NULL; - int key_size = 0, key_len; - unsigned char *data; + DH *dh_clnt = NULL; + DH *dh_srvr; + uint8_t *key = NULL; + size_t key_len = 0; int ret = -1; - CBB dh_Yc; - /* Ensure that we have an ephemeral key for DHE. */ - if (sess_cert->peer_dh_tmp == NULL) { + /* Ensure that we have an ephemeral key from the server for DHE. */ + if ((dh_srvr = sess_cert->peer_dh_tmp) == NULL) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); SSLerror(s, SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); goto err; } - dh_srvr = sess_cert->peer_dh_tmp; - /* Generate a new random key. */ - if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) { - SSLerror(s, ERR_R_DH_LIB); + if ((dh_clnt = DH_new()) == NULL) goto err; - } - if (!DH_generate_key(dh_clnt)) { - SSLerror(s, ERR_R_DH_LIB); - goto err; - } - if ((key_size = DH_size(dh_clnt)) <= 0) { - SSLerror(s, ERR_R_DH_LIB); - goto err; - } - if ((key = malloc(key_size)) == NULL) { - SSLerror(s, ERR_R_MALLOC_FAILURE); + + if (!ssl_kex_generate_dhe(dh_clnt, dh_srvr)) goto err; - } - if ((key_len = DH_compute_key(key, dh_srvr->pub_key, dh_clnt)) <= 0) { - SSLerror(s, ERR_R_DH_LIB); + if (!ssl_kex_public_dhe(dh_clnt, cbb)) goto err; - } - if (!tls12_derive_master_secret(s, key, key_len)) + if (!ssl_kex_derive_dhe(dh_clnt, dh_srvr, &key, &key_len)) goto err; - if (!CBB_add_u16_length_prefixed(cbb, &dh_Yc)) - goto err; - if (!CBB_add_space(&dh_Yc, &data, BN_num_bytes(dh_clnt->pub_key))) - goto err; - BN_bn2bin(dh_clnt->pub_key, data); - if (!CBB_flush(cbb)) + if (!tls12_derive_master_secret(s, key, key_len)) goto err; ret = 1; err: DH_free(dh_clnt); - freezero(key, key_size); + freezero(key, key_len); return (ret); } @@ -2072,6 +2027,7 @@ ssl3_send_client_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, CBB *cbb) if (!ssl_kex_derive_ecdhe_ecp(ecdh, sc->peer_ecdh_tmp, &key, &key_len)) goto err; + if (!tls12_derive_master_secret(s, key, key_len)) goto err; diff --git a/lib/libssl/ssl_kex.c b/lib/libssl/ssl_kex.c index 9f05fd60c9b..26f991f1904 100644 --- a/lib/libssl/ssl_kex.c +++ b/lib/libssl/ssl_kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_kex.c,v 1.2 2020/04/18 14:07:56 jsing Exp $ */ +/* $OpenBSD: ssl_kex.c,v 1.3 2021/11/29 16:00:32 jsing Exp $ */ /* * Copyright (c) 2020 Joel Sing * @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -24,6 +25,148 @@ #include "bytestring.h" +int +ssl_kex_generate_dhe(DH *dh, DH *dh_params) +{ + BN_free(dh->p); + BN_free(dh->g); + dh->p = NULL; + dh->g = NULL; + + if ((dh->p = BN_dup(dh_params->p)) == NULL) + return 0; + if ((dh->g = BN_dup(dh_params->g)) == NULL) + return 0; + + if (!DH_generate_key(dh)) + return 0; + + return 1; +} + +int +ssl_kex_params_dhe(DH *dh, CBB *cbb) +{ + int dh_p_len, dh_g_len; + CBB dh_p, dh_g; + uint8_t *data; + + if ((dh_p_len = BN_num_bytes(dh->p)) <= 0) + return 0; + if ((dh_g_len = BN_num_bytes(dh->g)) <= 0) + return 0; + + if (!CBB_add_u16_length_prefixed(cbb, &dh_p)) + return 0; + if (!CBB_add_space(&dh_p, &data, dh_p_len)) + return 0; + if (BN_bn2bin(dh->p, data) != dh_p_len) + return 0; + + if (!CBB_add_u16_length_prefixed(cbb, &dh_g)) + return 0; + if (!CBB_add_space(&dh_g, &data, dh_g_len)) + return 0; + if (BN_bn2bin(dh->g, data) != dh_g_len) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +ssl_kex_public_dhe(DH *dh, CBB *cbb) +{ + uint8_t *data; + int dh_y_len; + CBB dh_y; + + if ((dh_y_len = BN_num_bytes(dh->pub_key)) <= 0) + return 0; + + if (!CBB_add_u16_length_prefixed(cbb, &dh_y)) + return 0; + if (!CBB_add_space(&dh_y, &data, dh_y_len)) + return 0; + if (BN_bn2bin(dh->pub_key, data) != dh_y_len) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +ssl_kex_peer_params_dhe(DH *dh, CBS *cbs) +{ + CBS dh_p, dh_g; + + BN_free(dh->p); + BN_free(dh->g); + dh->p = NULL; + dh->g = NULL; + + if (!CBS_get_u16_length_prefixed(cbs, &dh_p)) + return 0; + if (!CBS_get_u16_length_prefixed(cbs, &dh_g)) + return 0; + + if ((dh->p = BN_bin2bn(CBS_data(&dh_p), CBS_len(&dh_p), NULL)) == NULL) + return 0; + if ((dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL)) == NULL) + return 0; + + return 1; +} + +int +ssl_kex_peer_public_dhe(DH *dh, CBS *cbs) +{ + CBS dh_y; + + BN_free(dh->pub_key); + dh->pub_key = NULL; + + if (!CBS_get_u16_length_prefixed(cbs, &dh_y)) + return 0; + if ((dh->pub_key = BN_bin2bn(CBS_data(&dh_y), CBS_len(&dh_y), + NULL)) == NULL) + return 0; + + return 1; +} + +int +ssl_kex_derive_dhe(DH *dh, DH *dh_peer, + uint8_t **shared_key, size_t *shared_key_len) +{ + uint8_t *key = NULL; + int key_len = 0; + int ret = 0; + + if ((key_len = DH_size(dh)) <= 0) + goto err; + if ((key = calloc(1, key_len)) == NULL) + goto err; + + if ((key_len = DH_compute_key(key, dh_peer->pub_key, dh)) <= 0) + goto err; + + *shared_key = key; + *shared_key_len = key_len; + key = NULL; + + ret = 1; + + err: + freezero(key, key_len); + + return ret; +} + int ssl_kex_dummy_ecdhe_x25519(EVP_PKEY *pkey) { diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index 27bf5ec41f7..7810bcd05eb 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.368 2021/10/25 10:09:28 jsing Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.369 2021/11/29 16:00:32 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1447,6 +1447,14 @@ int ssl3_get_client_certificate(SSL *s); int ssl3_get_client_key_exchange(SSL *s); int ssl3_get_cert_verify(SSL *s); +int ssl_kex_generate_dhe(DH *dh, DH *dh_params); +int ssl_kex_params_dhe(DH *dh, CBB *cbb); +int ssl_kex_public_dhe(DH *dh, CBB *cbb); +int ssl_kex_peer_params_dhe(DH *dh, CBS *cbs); +int ssl_kex_peer_public_dhe(DH *dh, CBS *cbs); +int ssl_kex_derive_dhe(DH *dh, DH *dh_peer, + uint8_t **shared_key, size_t *shared_key_len); + int ssl_kex_dummy_ecdhe_x25519(EVP_PKEY *pkey); int ssl_kex_generate_ecdhe_ecp(EC_KEY *ecdh, int nid); int ssl_kex_public_ecdhe_ecp(EC_KEY *ecdh, CBB *cbb); -- 2.20.1