All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Zaborowski <andrew.zaborowski@intel.com>
To: ell@lists.01.org
Subject: [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
Date: Wed, 09 Jan 2019 11:43:48 +0100	[thread overview]
Message-ID: <20190109104349.11763-3-andrew.zaborowski@intel.com> (raw)
In-Reply-To: <20190109104349.11763-1-andrew.zaborowski@intel.com>

[-- Attachment #1: Type: text/plain, Size: 7940 bytes --]

Add the handler for the ClientKeyExchange message and a builder callback
for the ServerKeyExchange message for DHE_RSA.
---
 ell/tls-suites.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 187 insertions(+)

diff --git a/ell/tls-suites.c b/ell/tls-suites.c
index 14ea470..b9fdc0f 100644
--- a/ell/tls-suites.c
+++ b/ell/tls-suites.c
@@ -691,6 +691,34 @@ static struct tls_key_exchange_algorithm tls_ecdhe_rsa = {
 /* Maximum FF DH prime modulus size in bytes */
 #define TLS_DHE_MAX_SIZE 1024
 
+/* RFC 3526, Section 3 */
+static const uint8_t tls_dh14_prime[] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2,
+	0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
+	0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
+	0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
+	0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d,
+	0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
+	0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9,
+	0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
+	0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11,
+	0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d,
+	0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36,
+	0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
+	0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56,
+	0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d,
+	0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08,
+	0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
+	0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2,
+	0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9,
+	0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c,
+	0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
+	0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+};
+
+static const unsigned int tls_dh14_generator = 2;
+
 struct tls_dhe_params {
 	size_t prime_len;
 	struct l_key *prime;
@@ -758,6 +786,100 @@ static bool tls_get_server_dh_params_hash(struct l_tls *tls, uint8_t tls_id,
 	return true;
 }
 
+static bool tls_send_dhe_server_key_xchg(struct l_tls *tls)
+{
+	uint8_t buf[1024 + TLS_DHE_MAX_SIZE * 3];
+	uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
+	struct tls_dhe_params *params;
+	const uint8_t *prime_buf;
+	uint8_t generator_buf = tls_dh14_generator;
+	uint8_t public_buf[TLS_DHE_MAX_SIZE];
+	size_t public_len;
+	unsigned int zeros = 0;
+	ssize_t sign_len;
+
+	params = l_new(struct tls_dhe_params, 1);
+
+	/*
+	 * For now hardcode the Oakley Group 14 parameters like some other
+	 * TLS implementations do without RFC 7919, which is actually a
+	 * downside because the more common the group parameters are the
+	 * less secure they are assumed to be, but also is a test that the
+	 * group is sufficiently good.
+	 *
+	 * Eventually we should make this configurable so that a unique
+	 * likely-prime number generated by either 'openssl dhparam' or
+	 * 'ssh-keygen -G' can be set, or parse /etc/ssh/moduli to select
+	 * a random pre-generated FFDH group each time.
+	 */
+	prime_buf = tls_dh14_prime;
+	params->prime_len = sizeof(tls_dh14_prime);
+
+	params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len);
+	params->generator = l_key_new(L_KEY_RAW, &generator_buf, 1);
+
+	if (!params->prime || !params->generator) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed");
+		goto free_params;
+	}
+
+	params->private = l_key_generate_dh_private(prime_buf, params->prime_len);
+	if (!params->private) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+				"l_key_generate_dh_private failed");
+		goto free_params;
+	}
+
+	public_len = params->prime_len;
+
+	if (!l_key_compute_dh_public(params->generator, params->private,
+					params->prime, public_buf,
+					&public_len)) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+				"l_key_compute_dh_public failed");
+		goto free_params;
+	}
+
+	while (zeros < public_len && public_buf[zeros] == 0x00)
+		zeros++;
+
+	params->server_dh_params_buf = ptr;
+
+	/* RFC 5246, Section 7.4.3 */
+
+	l_put_be16(params->prime_len, ptr);
+	memcpy(ptr + 2, prime_buf, params->prime_len);
+	ptr += 2 + params->prime_len;
+
+	l_put_be16(1, ptr);
+	memcpy(ptr + 2, &generator_buf, 1);
+	ptr += 2 + 1;
+
+	l_put_be16(public_len - zeros, ptr);
+	memcpy(ptr + 2, public_buf + zeros, public_len - zeros);
+	ptr += 2 + public_len - zeros;
+
+	params->server_dh_params_len = ptr - params->server_dh_params_buf;
+	tls->pending.key_xchg_params = params;
+
+	sign_len = tls->pending.cipher_suite->key_xchg->sign(tls, ptr,
+					buf + sizeof(buf) - ptr,
+					tls_get_server_dh_params_hash);
+	if (sign_len < 0)
+		return false;
+
+	ptr += sign_len;
+	tls_tx_handshake(tls, TLS_SERVER_KEY_EXCHANGE, buf, ptr - buf);
+	return true;
+
+free_params:
+	l_key_free(params->prime);
+	l_key_free(params->generator);
+	l_key_free(params->private);
+	l_free(params);
+	return false;
+}
+
 static void tls_handle_dhe_server_key_xchg(struct l_tls *tls,
 						const uint8_t *buf, size_t len)
 {
@@ -937,13 +1059,78 @@ static bool tls_send_dhe_client_key_xchg(struct l_tls *tls)
 	return true;
 }
 
+static void tls_handle_dhe_client_key_xchg(struct l_tls *tls,
+						const uint8_t *buf, size_t len)
+{
+	struct tls_dhe_params *params = tls->pending.key_xchg_params;
+	uint8_t pre_master_secret[params->prime_len];
+	size_t pre_master_secret_len;
+	size_t public_len;
+	unsigned int zeros = 0;
+
+	if (len < 2)
+		goto decode_error;
+
+	public_len = l_get_be16(buf);
+	buf += 2;
+	len -= 2;
+
+	if (public_len != len)
+		goto decode_error;
+
+	/*
+	 * RFC 7919 Section 4:
+	 * "the server MUST verify that 1 < dh_Yc < dh_p - 1.  If dh_Yc is
+	 * out of range, the server MUST terminate the connection with
+	 * a fatal handshake_failure(40) alert."
+	 */
+	if (!l_key_validate_dh_payload(buf, public_len,
+					tls_dh14_prime, params->prime_len)) {
+		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
+				"Client DH public value invalid");
+		return;
+	}
+
+	params->public = l_key_new(L_KEY_RAW, buf, public_len);
+	if (!params->prime) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed");
+		return;
+	}
+
+	pre_master_secret_len = params->prime_len;
+
+	if (!l_key_compute_dh_secret(params->public, params->private,
+					params->prime, pre_master_secret,
+					&pre_master_secret_len)) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+				"Generating DH shared-secret failed");
+		return;
+	}
+
+	while (zeros < pre_master_secret_len &&
+			pre_master_secret[zeros] == 0x00)
+		zeros++;
+
+	tls_free_dhe_params(tls);
+	tls_generate_master_secret(tls, pre_master_secret + zeros,
+					pre_master_secret_len - zeros);
+	memset(pre_master_secret, 0, pre_master_secret_len);
+	return;
+
+decode_error:
+	TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
+			"ClientKeyExchange decode error");
+}
+
 static struct tls_key_exchange_algorithm tls_dhe_rsa = {
 	.id = 1, /* RSA_sign */
 	.certificate_check = true,
 	.need_ecc = true,
 	.validate_cert_key_type = tls_rsa_validate_cert_key,
+	.send_server_key_exchange = tls_send_dhe_server_key_xchg,
 	.handle_server_key_exchange = tls_handle_dhe_server_key_xchg,
 	.send_client_key_exchange = tls_send_dhe_client_key_xchg,
+	.handle_client_key_exchange = tls_handle_dhe_client_key_xchg,
 	.free_params = tls_free_dhe_params,
 	.sign = tls_rsa_sign,
 	.verify = tls_rsa_verify,
-- 
2.19.1


  parent reply	other threads:[~2019-01-09 10:43 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-09 10:43 [PATCH 1/4] key: Add l_key_validate_dh_payload Andrew Zaborowski
2019-01-09 10:43 ` [PATCH 2/4] tls: DHE_RSA key exchange implementation client side Andrew Zaborowski
2019-01-09 10:43 ` Andrew Zaborowski [this message]
2019-01-09 17:12   ` [PATCH 3/4] tls: DHE_RSA key exchange implementation server side Denis Kenzior
2019-01-10  1:21     ` Andrew Zaborowski
2019-01-10 17:24       ` Denis Kenzior
2019-01-11 10:50         ` Andrew Zaborowski
2019-01-09 10:43 ` [PATCH 4/4] tls: Add DHE_RSA-based cipher suites Andrew Zaborowski
2019-01-09 13:40 ` [PATCH 1/4] key: Add l_key_validate_dh_payload Jan Engelhardt
2019-01-09 14:54   ` Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190109104349.11763-3-andrew.zaborowski@intel.com \
    --to=andrew.zaborowski@intel.com \
    --cc=ell@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.