All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] key: Add l_key_validate_dh_payload
@ 2019-01-09 10:43 Andrew Zaborowski
  2019-01-09 10:43 ` [PATCH 2/4] tls: DHE_RSA key exchange implementation client side Andrew Zaborowski
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-09 10:43 UTC (permalink / raw)
  To: ell

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

Add a function to validate public values received from the DH peer
against the minimum and maximum values depending on the group's
prime modulus.  This is only necessary ~temporarily as the kernel
*should* be validating the public value in the keyctl operation,
however due to the shape of the syscall keyctl API it can't do that
now so fixing it is not easy and may take a while.  We also can't
do this easily inside l_key_compute_dh_secret because we don't have
the prime's raw value there.  We could perhaps do that if we created
a new "DH group" type (simliar to l_ecc_curve for ECDH) and made the
API more like the ECDH API.

Additionally even after that is fixed in the kernel the additional
check can't hurt and lets user code report a more specific error
because the user code can only assume "internal error" when
l_key_compute_dh_secret fails while this is not an internal error.
---
 ell/ell.sym |  1 +
 ell/key.c   | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/key.h   |  3 +++
 3 files changed, 57 insertions(+)

diff --git a/ell/ell.sym b/ell/ell.sym
index 5f7c4ee..95e1a3b 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -304,6 +304,7 @@ global:
 	l_key_generate_dh_private;
 	l_key_compute_dh_public;
 	l_key_compute_dh_secret;
+	l_key_validate_dh_payload;
 	l_key_encrypt;
 	l_key_decrypt;
 	l_key_sign;
diff --git a/ell/key.c b/ell/key.c
index 3f3db43..06c7a98 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -504,6 +504,59 @@ LIB_EXPORT bool l_key_compute_dh_secret(struct l_key *other_public,
 	return compute_common(other_public, private, prime, payload, len);
 }
 
+static int be_bignum_compare(const uint8_t *a, size_t a_len,
+				const uint8_t *b, size_t b_len)
+{
+	unsigned int i;
+
+	if (a_len >= b_len) {
+		for (i = 0; i < a_len - b_len; i++)
+			if (a[i])
+				return 1;
+
+		return memcmp(a + i, b, b_len);
+	} else {
+		for (i = 0; i < b_len - a_len; i++)
+			if (b[i])
+				return -1;
+
+		return memcmp(a, b + i, a_len);
+	}
+}
+
+/*
+ * Validate that @payload is within range for a private and public key for
+ * a DH computation in the finite field group defined by modulus @prime_buf,
+ * both numbers stored as big-endian integers.  We require a key in the
+ * [2, prime - 2] (inclusive) interval.  PKCS #3 does not exclude 1 as a
+ * private key but other specs do.
+ */
+LIB_EXPORT bool l_key_validate_dh_payload(const void *payload, size_t len,
+				const void *prime_buf, size_t prime_len)
+{
+	static const uint8_t one[] = { 1 };
+	uint8_t prime_1[prime_len];
+
+	/*
+	 * Produce prime - 1 for the payload < prime - 1 check.
+	 * prime is odd so just zero the LSB.
+	 */
+	memcpy(prime_1, prime_buf, prime_len);
+
+	if (prime_len < 1 || !(prime_1[prime_len - 1] & 1))
+		return false;
+
+	prime_1[prime_len - 1] &= ~1;
+
+	if (be_bignum_compare(payload, len, one, 1) <= 0)
+		return false;
+
+	if (be_bignum_compare(payload, len, prime_1, prime_len) >= 0)
+		return false;
+
+	return true;
+}
+
 /* Common code for encrypt/decrypt/sign */
 static ssize_t eds_common(struct l_key *key,
 				enum l_key_cipher_type cipher,
diff --git a/ell/key.h b/ell/key.h
index aefcfb7..024afc6 100644
--- a/ell/key.h
+++ b/ell/key.h
@@ -83,6 +83,9 @@ bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key *private,
 				struct l_key *prime,
 				void *payload, size_t *len);
 
+bool l_key_validate_dh_payload(const void *payload, size_t len,
+				const void *prime_buf, size_t prime_len);
+
 ssize_t l_key_encrypt(struct l_key *key, enum l_key_cipher_type cipher,
 			enum l_checksum_type checksum, const void *in,
 			void *out, size_t len_in, size_t len_out);
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/4] tls: DHE_RSA key exchange implementation client side
  2019-01-09 10:43 [PATCH 1/4] key: Add l_key_validate_dh_payload Andrew Zaborowski
@ 2019-01-09 10:43 ` Andrew Zaborowski
  2019-01-09 10:43 ` [PATCH 3/4] tls: DHE_RSA key exchange implementation server side Andrew Zaborowski
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-09 10:43 UTC (permalink / raw)
  To: ell

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

Add a new key exchange definition with the callbacks needed to handle the
client side of the DHE_RSA key exchange.
---
 ell/tls-suites.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 261 insertions(+)

diff --git a/ell/tls-suites.c b/ell/tls-suites.c
index af8cbcd..14ea470 100644
--- a/ell/tls-suites.c
+++ b/ell/tls-suites.c
@@ -688,6 +688,267 @@ static struct tls_key_exchange_algorithm tls_ecdhe_rsa = {
 	.verify = tls_rsa_verify,
 };
 
+/* Maximum FF DH prime modulus size in bytes */
+#define TLS_DHE_MAX_SIZE 1024
+
+struct tls_dhe_params {
+	size_t prime_len;
+	struct l_key *prime;
+	struct l_key *generator;
+	struct l_key *private;
+	struct l_key *public;
+	const uint8_t *server_dh_params_buf;
+	size_t server_dh_params_len;
+};
+
+static void tls_free_dhe_params(struct l_tls *tls)
+{
+	struct tls_dhe_params *params = tls->pending.key_xchg_params;
+
+	if (!params)
+		return;
+
+	tls->pending.key_xchg_params = NULL;
+
+	l_key_free(params->prime);
+	l_key_free(params->generator);
+	l_key_free(params->private);
+	l_key_free(params->public);
+	l_free(params);
+}
+
+static bool tls_get_server_dh_params_hash(struct l_tls *tls, uint8_t tls_id,
+						uint8_t *out, size_t *len,
+						enum l_checksum_type *type)
+{
+	unsigned int hash;
+	struct l_checksum *checksum;
+	struct tls_dhe_params *params = tls->pending.key_xchg_params;
+	ssize_t hash_len, ret;
+
+	for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
+		if (tls_handshake_hash_data[hash].tls_id == tls_id)
+			break;
+
+	if (hash == __HANDSHAKE_HASH_COUNT)
+		return false;
+
+	hash_len = tls_handshake_hash_data[hash].length;
+
+	checksum = l_checksum_new(tls_handshake_hash_data[hash].l_id);
+	if (!checksum)
+		return false;
+
+	l_checksum_update(checksum, tls->pending.client_random, 32);
+	l_checksum_update(checksum, tls->pending.server_random, 32);
+	l_checksum_update(checksum, params->server_dh_params_buf,
+				params->server_dh_params_len);
+	ret = l_checksum_get_digest(checksum, out, hash_len);
+	l_checksum_free(checksum);
+
+	if (ret != (ssize_t) hash_len)
+		return false;
+
+	if (len)
+		*len = hash_len;
+
+	if (type)
+		*type = tls_handshake_hash_data[hash].l_id;
+
+	return true;
+}
+
+static void tls_handle_dhe_server_key_xchg(struct l_tls *tls,
+						const uint8_t *buf, size_t len)
+{
+	struct tls_dhe_params *params = NULL;
+	const uint8_t *prime_buf;
+	const uint8_t *generator_buf;
+	size_t generator_len;
+	const uint8_t *public_buf;
+	size_t public_len;
+
+	if (len < 2)
+		goto decode_error;
+
+	params = l_new(struct tls_dhe_params, 1);
+	params->server_dh_params_buf = buf;
+
+	params->prime_len = l_get_be16(buf);
+	if (len < 2 + params->prime_len + 2)
+		goto decode_error;
+
+	prime_buf = buf + 2;
+	buf += 2 + params->prime_len;
+	len -= 2 + params->prime_len;
+
+	/* Strip leading zeros for the length checks later */
+	while (params->prime_len && prime_buf[0] == 0x00) {
+		prime_buf++;
+		params->prime_len--;
+	}
+
+	generator_len = l_get_be16(buf);
+	if (len < 2 + generator_len + 2)
+		goto decode_error;
+
+	generator_buf = buf + 2;
+	buf += 2 + generator_len;
+	len -= 2 + generator_len;
+
+	public_len = l_get_be16(buf);
+	if (len < 2 + public_len)
+		goto decode_error;
+
+	public_buf = buf + 2;
+	buf += 2 + public_len;
+	len -= 2 + public_len;
+
+	params->server_dh_params_len = buf - params->server_dh_params_buf;
+
+	/*
+	 * Validate the values received.  Without RFC 7919 we basically have
+	 * to blindly accept the provided prime value.  We have no way to
+	 * confirm that it's actually prime or that it's a "safe prime" or
+	 * that it forms a group without small sub-groups.  There's also no
+	 * way to whitelist all valid values.  But we do a basic sanity
+	 * check and require it to be 1024-bit or longer (see weakdh.org),
+	 * might need to move to 2048 bits actually.
+	 * The generator must also be at least within the min & max interval
+	 * for the private/public values.
+	 */
+
+	if (params->prime_len > TLS_DHE_MAX_SIZE || params->prime_len < 128 ||
+			!(prime_buf[params->prime_len - 1] & 1)) {
+		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
+				"Server DH prime modulus invalid");
+		goto free_params;
+	}
+
+	if (!l_key_validate_dh_payload(generator_buf, generator_len,
+					prime_buf, params->prime_len)) {
+		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
+				"Server DH generator value invalid");
+		goto free_params;
+	}
+
+	/*
+	 * RFC 7919 Section 3.0:
+	 * "the client MUST verify that dh_Ys is in the range
+	 * 1 < dh_Ys < dh_p - 1.  If dh_Ys is not in this range, the client
+	 * MUST terminate the connection with a fatal handshake_failure(40)
+	 * alert."
+	 */
+	if (!l_key_validate_dh_payload(public_buf, public_len,
+					prime_buf, params->prime_len)) {
+		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
+				"Server DH public value invalid");
+		goto free_params;
+	}
+
+	params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len);
+	params->generator = l_key_new(L_KEY_RAW, generator_buf, generator_len);
+	params->public = l_key_new(L_KEY_RAW, public_buf, public_len);
+
+	if (!params->prime || !params->generator || !params->public) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed");
+		goto free_params;
+	}
+
+	/* Do this now so we don't need prime_buf in send_client_key_xchg */
+	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;
+	}
+
+	tls->pending.key_xchg_params = params;
+
+	if (!tls->pending.cipher_suite->key_xchg->verify(tls, buf, len,
+						tls_get_server_dh_params_hash))
+		return;
+
+	TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE);
+	return;
+
+decode_error:
+	TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
+			"ServerKeyExchange decode error");
+
+free_params:
+	if (params) {
+		l_key_free(params->prime);
+		l_key_free(params->generator);
+		l_key_free(params->public);
+		l_free(params);
+	}
+}
+
+static bool tls_send_dhe_client_key_xchg(struct l_tls *tls)
+{
+	struct tls_dhe_params *params = tls->pending.key_xchg_params;
+	uint8_t buf[128 + params->prime_len];
+	uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
+	uint8_t public_buf[params->prime_len];
+	size_t public_len;
+	unsigned int zeros = 0;
+	uint8_t pre_master_secret[params->prime_len];
+	size_t pre_master_secret_len;
+
+	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");
+		return false;
+	}
+
+	while (zeros < public_len && public_buf[zeros] == 0x00)
+		zeros++;
+
+	l_put_be16(public_len - zeros, ptr);
+	memcpy(ptr + 2, public_buf + zeros, public_len - zeros);
+	ptr += 2 + public_len - zeros;
+
+	pre_master_secret_len = params->prime_len;
+	zeros = 0;
+
+	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 false;
+	}
+
+	while (zeros < pre_master_secret_len &&
+			pre_master_secret[zeros] == 0x00)
+		zeros++;
+
+	tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf);
+
+	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 true;
+}
+
+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,
+	.handle_server_key_exchange = tls_handle_dhe_server_key_xchg,
+	.send_client_key_exchange = tls_send_dhe_client_key_xchg,
+	.free_params = tls_free_dhe_params,
+	.sign = tls_rsa_sign,
+	.verify = tls_rsa_verify,
+};
+
 static struct tls_bulk_encryption_algorithm tls_rc4 = {
 	.cipher_type = TLS_CIPHER_STREAM,
 	.l_id = L_CIPHER_ARC4,
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
  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
  2019-01-09 17:12   ` Denis Kenzior
  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
  3 siblings, 1 reply; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-09 10:43 UTC (permalink / raw)
  To: ell

[-- 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


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] tls: Add DHE_RSA-based cipher suites
  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 ` [PATCH 3/4] tls: DHE_RSA key exchange implementation server side Andrew Zaborowski
@ 2019-01-09 10:43 ` Andrew Zaborowski
  2019-01-09 13:40 ` [PATCH 1/4] key: Add l_key_validate_dh_payload Jan Engelhardt
  3 siblings, 0 replies; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-09 10:43 UTC (permalink / raw)
  To: ell

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

Add the 5 DHE_RSA suites defined in RFC 5246 and the 2 defined in
RFC 5288.
---
 ell/tls-suites.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/ell/tls-suites.c b/ell/tls-suites.c
index b9fdc0f..2ae13ea 100644
--- a/ell/tls-suites.c
+++ b/ell/tls-suites.c
@@ -1213,6 +1213,13 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 	.encryption = &tls_3des_ede,
 	.mac = &tls_sha,
 	.key_xchg = &tls_rsa,
+}, tls_dhe_rsa_with_3des_ede_cbc_sha = {
+	.id = { 0x00, 0x16 },
+	.name = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_3des_ede,
+	.mac = &tls_sha,
+	.key_xchg = &tls_dhe_rsa,
 }, tls_rsa_with_aes_128_cbc_sha = {
 	.id = { 0x00, 0x2f },
 	.name = "TLS_RSA_WITH_AES_128_CBC_SHA",
@@ -1220,6 +1227,13 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 	.encryption = &tls_aes128,
 	.mac = &tls_sha,
 	.key_xchg = &tls_rsa,
+}, tls_dhe_rsa_with_aes_128_cbc_sha = {
+	.id = { 0x00, 0x33 },
+	.name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128,
+	.mac = &tls_sha,
+	.key_xchg = &tls_dhe_rsa,
 }, tls_rsa_with_aes_256_cbc_sha = {
 	.id = { 0x00, 0x35 },
 	.name = "TLS_RSA_WITH_AES_256_CBC_SHA",
@@ -1227,6 +1241,13 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 	.encryption = &tls_aes256,
 	.mac = &tls_sha,
 	.key_xchg = &tls_rsa,
+}, tls_dhe_rsa_with_aes_256_cbc_sha = {
+	.id = { 0x00, 0x39 },
+	.name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256,
+	.mac = &tls_sha,
+	.key_xchg = &tls_dhe_rsa,
 }, tls_rsa_with_aes_128_cbc_sha256 = {
 	.id = { 0x00, 0x3c },
 	.name = "TLS_RSA_WITH_AES_128_CBC_SHA256",
@@ -1241,6 +1262,20 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 	.encryption = &tls_aes256,
 	.mac = &tls_sha256,
 	.key_xchg = &tls_rsa,
+}, tls_dhe_rsa_with_aes_128_cbc_sha256 = {
+	.id = { 0x00, 0x67 },
+	.name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128,
+	.mac = &tls_sha256,
+	.key_xchg = &tls_dhe_rsa,
+}, tls_dhe_rsa_with_aes_256_cbc_sha256 = {
+	.id = { 0x00, 0x6b },
+	.name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256,
+	.mac = &tls_sha256,
+	.key_xchg = &tls_dhe_rsa,
 }, tls_rsa_with_aes_128_gcm_sha256 = {
 	.id = { 0x00, 0x9c },
 	.name = "TLS_RSA_WITH_AES_128_GCM_SHA256",
@@ -1254,6 +1289,19 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 	.encryption = &tls_aes256_gcm,
 	.prf_hmac = L_CHECKSUM_SHA384,
 	.key_xchg = &tls_rsa,
+}, tls_dhe_rsa_with_aes_128_gcm_sha256 = {
+	.id = { 0x00, 0x9e },
+	.name = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128_gcm,
+	.key_xchg = &tls_dhe_rsa,
+}, tls_dhe_rsa_with_aes_256_gcm_sha384 = {
+	.id = { 0x00, 0x9f },
+	.name = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256_gcm,
+	.prf_hmac = L_CHECKSUM_SHA384,
+	.key_xchg = &tls_dhe_rsa,
 }, tls_ecdhe_rsa_with_rc4_128_sha = {
 	.id = { 0xc0, 0x11 },
 	.name = "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
@@ -1315,17 +1363,24 @@ static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
 struct tls_cipher_suite *tls_cipher_suite_pref[] = {
 	&tls_ecdhe_rsa_with_aes_256_cbc_sha,
 	&tls_ecdhe_rsa_with_aes_128_cbc_sha,
+	&tls_dhe_rsa_with_aes_256_cbc_sha,
+	&tls_dhe_rsa_with_aes_128_cbc_sha,
 	&tls_rsa_with_aes_256_cbc_sha,
 	&tls_rsa_with_aes_128_cbc_sha,
 	&tls_ecdhe_rsa_with_aes_256_cbc_sha384,
 	&tls_ecdhe_rsa_with_aes_128_cbc_sha256,
+	&tls_dhe_rsa_with_aes_256_cbc_sha256,
+	&tls_dhe_rsa_with_aes_128_cbc_sha256,
 	&tls_rsa_with_aes_256_cbc_sha256,
 	&tls_rsa_with_aes_128_cbc_sha256,
 	&tls_ecdhe_rsa_with_aes_256_gcm_sha384,
 	&tls_ecdhe_rsa_with_aes_128_gcm_sha256,
+	&tls_dhe_rsa_with_aes_256_gcm_sha384,
+	&tls_dhe_rsa_with_aes_128_gcm_sha256,
 	&tls_rsa_with_aes_256_gcm_sha384,
 	&tls_rsa_with_aes_128_gcm_sha256,
 	&tls_ecdhe_rsa_with_3des_ede_cbc_sha,
+	&tls_dhe_rsa_with_3des_ede_cbc_sha,
 	&tls_rsa_with_3des_ede_cbc_sha,
 	&tls_ecdhe_rsa_with_rc4_128_sha,
 	&tls_rsa_with_rc4_128_sha,
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] key: Add l_key_validate_dh_payload
  2019-01-09 10:43 [PATCH 1/4] key: Add l_key_validate_dh_payload Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2019-01-09 10:43 ` [PATCH 4/4] tls: Add DHE_RSA-based cipher suites Andrew Zaborowski
@ 2019-01-09 13:40 ` Jan Engelhardt
  2019-01-09 14:54   ` Denis Kenzior
  3 siblings, 1 reply; 10+ messages in thread
From: Jan Engelhardt @ 2019-01-09 13:40 UTC (permalink / raw)
  To: ell

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


On Wednesday 2019-01-09 11:43, Andrew Zaborowski wrote:

>Add a function to validate public values received from the DH peer
>against the minimum and maximum values depending on the group's
>prime modulus.  This is only necessary ~temporarily as the kernel
>*should* be validating the public value in the keyctl operation,
>however due to the shape of the syscall keyctl API it can't do that
>now so fixing it is not easy and may take a while.  We also can't
>do this easily inside l_key_compute_dh_secret because we don't have
>the prime's raw value there.  We could perhaps do that if we created
>a new "DH group" type (simliar to l_ecc_curve for ECDH) and made the
>API more like the ECDH API.

Excuse my ignorance, but isn't this something a library like
openssl/libressl/etc. should be doing instead?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] key: Add l_key_validate_dh_payload
  2019-01-09 13:40 ` [PATCH 1/4] key: Add l_key_validate_dh_payload Jan Engelhardt
@ 2019-01-09 14:54   ` Denis Kenzior
  0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2019-01-09 14:54 UTC (permalink / raw)
  To: ell

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

hi Jan,

> 
> Excuse my ignorance, but isn't this something a library like
> openssl/libressl/etc. should be doing instead?

We do not use openssl/libressl and do not want to.  Instead we utilize 
the Linux Kernel for most crypto primitives and just implement the bare 
minimum TLS protocol needed for our main projects.

This allows us to have a rather functional TLS stack in about ~5kloc, 
compared to depending on something like OpenSSL 540+ kloc.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
  2019-01-09 10:43 ` [PATCH 3/4] tls: DHE_RSA key exchange implementation server side Andrew Zaborowski
@ 2019-01-09 17:12   ` Denis Kenzior
  2019-01-10  1:21     ` Andrew Zaborowski
  0 siblings, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2019-01-09 17:12 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

On 01/09/2019 04:43 AM, Andrew Zaborowski wrote:
> 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(+)

<snip>

> +
> +	params->server_dh_params_buf = ptr;

This part seems a bit hacky..

> +
> +	/* 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);

The way you did it in ecdh seems to be much cleaner.  Perhaps the 
sign/verify operation should be receiving the data to be hashed directly 
(maybe as an iovec), instead of having get_hash function lookup the hash 
id, create the checksum, run it, check for errors, etc).  You are 
already duplicating these steps in tls_get_server_ecdh_params_hash and 
tls_get_server_dh_params_hash.  Admittedly, tls_get_prev_digest_by_id is 
a bit of a special case.

At the very least can we zero out the server_dh_params & 
server_dh_params_len after you're done here (and similarly in patch 2)?

> +	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;
> +}
> +

Anyway, I applied all 4 of these.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
  2019-01-09 17:12   ` Denis Kenzior
@ 2019-01-10  1:21     ` Andrew Zaborowski
  2019-01-10 17:24       ` Denis Kenzior
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-10  1:21 UTC (permalink / raw)
  To: ell

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

Hi Denis,

On Wed, 9 Jan 2019 at 18:12, Denis Kenzior <denkenz@gmail.com> wrote:
> On 01/09/2019 04:43 AM, Andrew Zaborowski wrote:
> > Add the handler for the ClientKeyExchange message and a builder callback
> > +     params->server_dh_params_buf = ptr;
>
> This part seems a bit hacky..

Would the same mechanism with a comment be better?  It saves us from
rebuilding this structure in tls_get_server_dh_params like in the
previous version of the patch.

>
> > +
> > +     /* 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);
>
> The way you did it in ecdh seems to be much cleaner.

I had it done this way in the previous version but when you suggested
keeping the buffer in the params struct I noticed we could avoid
rebuilding the buffer, and that means we also don't have to keep the
pointers to the raw values of the three l_keys in the params struct so
in the end I'd say it's about as clean.

> Perhaps the
> sign/verify operation should be receiving the data to be hashed directly
> (maybe as an iovec), instead of having get_hash function lookup the hash
> id, create the checksum, run it, check for errors, etc).  You are
> already duplicating these steps in tls_get_server_ecdh_params_hash and
> tls_get_server_dh_params_hash.  Admittedly, tls_get_prev_digest_by_id is
> a bit of a special case.

Yes, this API needed to be universal because we don't want to keep
copies of all the handshake messages for tls_get_prev_digest_by_id and
tls_get_handshake_hash_by_id.  We can move the hash lookups from the
callbacks to the sign/verify although there'd then be duplication in
those functions and any new signature methods added, same if those
functions have to deal with an iovec (I guess we couldn't know we'd
have new key exchange mechanisms before we have new signature
mechanisms).  What we also could do is pass two callbacks to
sign/verify, one to return the data to be hashed if we have it and
another to do the hashing which would be common.  Personally I
wouldn't worry if it's just about tls_get_server_ecdh_params and
tls_get_server_dh_params.

>
> At the very least can we zero out the server_dh_params &
> server_dh_params_len after you're done here (and similarly in patch 2)?

Ok, so as to not leave pointers to data that was on stack (in the
previous version I think I was committing the same sin with the
pointers to the raw key data)

>
> > +     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;
> > +}
> > +
>
> Anyway, I applied all 4 of these.

Thank you.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
  2019-01-10  1:21     ` Andrew Zaborowski
@ 2019-01-10 17:24       ` Denis Kenzior
  2019-01-11 10:50         ` Andrew Zaborowski
  0 siblings, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2019-01-10 17:24 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

> Would the same mechanism with a comment be better?  It saves us from
> rebuilding this structure in tls_get_server_dh_params like in the
> previous version of the patch.

Comment might be helpful, though I'm more picking on the use of space in 
the session permanent storage data structure that is only used to pass a 
value that is on the stack.  It doesn't feel elegant.

>> Perhaps the
>> sign/verify operation should be receiving the data to be hashed directly
>> (maybe as an iovec), instead of having get_hash function lookup the hash
>> id, create the checksum, run it, check for errors, etc).  You are
>> already duplicating these steps in tls_get_server_ecdh_params_hash and
>> tls_get_server_dh_params_hash.  Admittedly, tls_get_prev_digest_by_id is
>> a bit of a special case.
> 
> Yes, this API needed to be universal because we don't want to keep
> copies of all the handshake messages for tls_get_prev_digest_by_id and
> tls_get_handshake_hash_by_id.  We can move the hash lookups from the

Right I remember that.

> callbacks to the sign/verify although there'd then be duplication in
> those functions and any new signature methods added, same if those

Well those lookups can be combined to a single static utility function, no?

> functions have to deal with an iovec (I guess we couldn't know we'd
> have new key exchange mechanisms before we have new signature

Hmm, I don't quite understand ?  iovec would make things easy.  Just 
figure out the l_checksum you need to create and call l_checksum_updatev.

> mechanisms).  What we also could do is pass two callbacks to
> sign/verify, one to return the data to be hashed if we have it and
> another to do the hashing which would be common.  Personally I
> wouldn't worry if it's just about tls_get_server_ecdh_params and
> tls_get_server_dh_params.

I keep trying to think of something that would be a bit more elegant.

Would splitting up the verify into two steps be helpful?  So first step 
would pre-check the input/length and figure out which hash types are 
desired and return that (with one being MD5/SHA1 combination)

Then step two could be invoked with the actual hash data.

With such a setup we could support a helper function that would receive 
an iovec and can take care of calling the two steps.

> 
>>
>> At the very least can we zero out the server_dh_params &
>> server_dh_params_len after you're done here (and similarly in patch 2)?
> 
> Ok, so as to not leave pointers to data that was on stack (in the
> previous version I think I was committing the same sin with the
> pointers to the raw key data)
> 

Right.  I noticed these two instances.  We should at least fix these 
ASAP.  If we have others, then we should fix them as well.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] tls: DHE_RSA key exchange implementation server side
  2019-01-10 17:24       ` Denis Kenzior
@ 2019-01-11 10:50         ` Andrew Zaborowski
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Zaborowski @ 2019-01-11 10:50 UTC (permalink / raw)
  To: ell

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

Hi Denis,

On Thu, 10 Jan 2019 at 18:24, Denis Kenzior <denkenz@gmail.com> wrote:
> > Would the same mechanism with a comment be better?  It saves us from
> > rebuilding this structure in tls_get_server_dh_params like in the
> > previous version of the patch.
>
> Comment might be helpful, though I'm more picking on the use of space in
> the session permanent storage data structure that is only used to pass a
> value that is on the stack.  It doesn't feel elegant.
>
> >> Perhaps the
> >> sign/verify operation should be receiving the data to be hashed directly
> >> (maybe as an iovec), instead of having get_hash function lookup the hash
> >> id, create the checksum, run it, check for errors, etc).  You are
> >> already duplicating these steps in tls_get_server_ecdh_params_hash and
> >> tls_get_server_dh_params_hash.  Admittedly, tls_get_prev_digest_by_id is
> >> a bit of a special case.
> >
> > Yes, this API needed to be universal because we don't want to keep
> > copies of all the handshake messages for tls_get_prev_digest_by_id and
> > tls_get_handshake_hash_by_id.  We can move the hash lookups from the
>
> Right I remember that.
>
> > callbacks to the sign/verify although there'd then be duplication in
> > those functions and any new signature methods added, same if those
>
> Well those lookups can be combined to a single static utility function, no?
>
> > functions have to deal with an iovec (I guess we couldn't know we'd
> > have new key exchange mechanisms before we have new signature
>
> Hmm, I don't quite understand ?  iovec would make things easy.  Just
> figure out the l_checksum you need to create and call l_checksum_updatev.

If we do this in a common utility function then yes, we can avoid
duplicating those lines, at least for the case where we do have a
buffer with the data to be hashed.

What I meant is that we couldn't know we'd have new get hash callbacks
for the RSA sign/verify functions before we have new sign/verify
functions for other signature algorithms, hence I preferred to push
the logic out of those functions.

> > mechanisms).  What we also could do is pass two callbacks to
> > sign/verify, one to return the data to be hashed if we have it and
> > another to do the hashing which would be common.  Personally I
> > wouldn't worry if it's just about tls_get_server_ecdh_params and
> > tls_get_server_dh_params.
>
> I keep trying to think of something that would be a bit more elegant.
>
> Would splitting up the verify into two steps be helpful?  So first step
> would pre-check the input/length and figure out which hash types are
> desired and return that (with one being MD5/SHA1 combination)
>
> Then step two could be invoked with the actual hash data.
>
> With such a setup we could support a helper function that would receive
> an iovec and can take care of calling the two steps.

So I think it can be done more simply, why not pass the
tls_rsa_sign/verify an optional input buffer, the output buffer and
the get_hash callback?  The callback would receive the input buffer.

So for the handshake hash the input buffer would be null and the
get_hash callbacks would only change their signatures.

For the ServerDHParams / ServerECDHParams hashes we'd pass the pointer
to those structs and we'd pass the same get_hash function for all 4
use cases.

The buffer can be an iovec although that doesn't help much as we only
need one fragment (possibly complicates it).

Making it "elegant" with too many callbacks has a potential to make it
less readable in the sense that it's not easy to figure out what is
going on in the code, and in this case if I understand your idea
correctly you'd still need a third callback to actually do the RSA
verification.

Best regards

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-01-11 10:50 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 3/4] tls: DHE_RSA key exchange implementation server side Andrew Zaborowski
2019-01-09 17:12   ` 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

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.