All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] tls: Don't send Client Hello in l_tls_new
@ 2018-12-19  0:57 Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 2/9] unit: Call l_tls_start in tls tests Andrew Zaborowski
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

Give the user time to set up the tls instance's optional parameters --
those that can not be passed as parameters of l_tls_new, before sending
the Client Hello message in client mode.  We now send the message from
l_tls_start which has to be called after the optional setup is done,
e.g. set_cacert, set_auth_data, set_debug are called.  This way Client
Hello can avoid proposing cipher suites that would not have worked if
they were negotiated, due to bad certificate type.  It also allows us to
output debug messages in the Client Hello sending code, and will allow
to add methods to define security profiles.
---
 ell/ell.sym       |  1 +
 ell/tls-private.h |  1 +
 ell/tls.c         | 48 ++++++++++++++++++++++++++++-------------------
 ell/tls.h         |  3 +++
 4 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/ell/ell.sym b/ell/ell.sym
index a56433d..764cfd1 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -412,6 +412,7 @@ global:
 	l_tls_new;
 	l_tls_free;
 	l_tls_write;
+	l_tls_start;
 	l_tls_close;
 	l_tls_set_cacert;
 	l_tls_set_auth_data;
diff --git a/ell/tls-private.h b/ell/tls-private.h
index f3601e7..16f142b 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -98,6 +98,7 @@ struct tls_compression_method {
 };
 
 enum tls_handshake_state {
+	TLS_HANDSHAKE_WAIT_START,
 	TLS_HANDSHAKE_WAIT_HELLO,
 	TLS_HANDSHAKE_WAIT_CERTIFICATE,
 	TLS_HANDSHAKE_WAIT_KEY_EXCHANGE,
diff --git a/ell/tls.c b/ell/tls.c
index 9945586..e913642 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -195,7 +195,7 @@ static void tls_reset_handshake(struct l_tls *tls)
 	for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
 		tls_drop_handshake_hash(tls, hash);
 
-	TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
+	TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START);
 	tls->cert_requested = 0;
 	tls->cert_sent = 0;
 }
@@ -826,13 +826,6 @@ static bool tls_send_client_hello(struct l_tls *tls)
 
 	*ptr++ = 0; /* No SessionID */
 
-	/*
-	 * FIXME: We do need to filter the cipher suites by key exchange
-	 * mechanism compatibility with the certificate but we don't normally
-	 * have the certificate at this point because we're called from
-	 * l_tls_new.  We also don't know the TLS version that's going to
-	 * be negotiated yet.
-	 */
 	len_ptr = ptr;
 	ptr += 2;
 
@@ -2463,17 +2456,11 @@ LIB_EXPORT struct l_tls *l_tls_new(bool server,
 
 	tls->signature_hash = HANDSHAKE_HASH_SHA256;
 
-	/* If we're the client, start the handshake right away */
-	if (!tls->server) {
-		if (!tls_init_handshake_hash(tls) ||
-				!tls_send_client_hello(tls)) {
-			l_free(tls);
-
-			return NULL;
-		}
-	}
-
-	TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
+	/* If we're the server wait for the Client Hello already */
+	if (tls->server)
+		TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
+	else
+		TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START);
 
 	return tls;
 }
@@ -2652,6 +2639,28 @@ bool tls_handle_message(struct l_tls *tls, const uint8_t *message,
 	return false;
 }
 
+LIB_EXPORT bool l_tls_start(struct l_tls *tls)
+{
+	/* This is a nop in server mode */
+	if (tls->server)
+		return true;
+
+	if (tls->state != TLS_HANDSHAKE_WAIT_START) {
+		TLS_DEBUG("Call invalid in state %s",
+				tls_handshake_state_to_str(tls->state));
+		return false;
+	}
+
+	if (!tls_init_handshake_hash(tls))
+		return false;
+
+	if (!tls_send_client_hello(tls))
+		return false;
+
+	TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
+	return true;
+}
+
 LIB_EXPORT void l_tls_close(struct l_tls *tls)
 {
 	TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, 0, "Closing session");
@@ -2800,6 +2809,7 @@ const char *tls_handshake_state_to_str(enum tls_handshake_state state)
 	static char buf[100];
 
 	switch (state) {
+	SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_START)
 	SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO)
 	SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE)
 	SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE)
diff --git a/ell/tls.h b/ell/tls.h
index 505f0e0..fb33404 100644
--- a/ell/tls.h
+++ b/ell/tls.h
@@ -77,6 +77,9 @@ struct l_tls *l_tls_new(bool server, l_tls_write_cb_t app_data_handler,
 
 void l_tls_free(struct l_tls *tls);
 
+/* Begin sending connection setup messages to the server */
+bool l_tls_start(struct l_tls *tls);
+
 /* Properly disconnect a connected session */
 void l_tls_close(struct l_tls *tls);
 
-- 
2.19.1


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

* [PATCH 2/9] unit: Call l_tls_start in tls tests
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 3/9] tls: Add TLS version number printf macros Andrew Zaborowski
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

---
 unit/test-tls.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/unit/test-tls.c b/unit/test-tls.c
index 813487d..6731a0e 100644
--- a/unit/test-tls.c
+++ b/unit/test-tls.c
@@ -483,6 +483,9 @@ static void test_tls_test(const void *data)
 	assert(l_tls_set_cacert(s[0].tls, test->server_ca_cert_path));
 	assert(l_tls_set_cacert(s[1].tls, test->client_ca_cert_path));
 
+	assert(l_tls_start(s[0].tls));
+	assert(l_tls_start(s[1].tls));
+
 	while (1) {
 		if (s[0].raw_buf_len) {
 			l_tls_handle_rx(s[1].tls, s[0].raw_buf,
-- 
2.19.1


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

* [PATCH 3/9] tls: Add TLS version number printf macros
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 2/9] unit: Call l_tls_start in tls tests Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 4/9] tls: Define and use an enum type for TLS versions Andrew Zaborowski
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

---
 ell/tls-private.h |  3 +++
 ell/tls.c         | 17 +++++++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/ell/tls-private.h b/ell/tls-private.h
index 16f142b..2e254b2 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -257,4 +257,7 @@ int tls_parse_certificate_list(const void *data, size_t len,
 		tls_disconnect(tls, desc, local_desc);	\
 	} while (0)
 
+#define TLS_VER_FMT		"1.%i"
+#define TLS_VER_ARGS(version)	(((version) & 0xff) - 1)
+
 const char *tls_handshake_state_to_str(enum tls_handshake_state state);
diff --git a/ell/tls.c b/ell/tls.c
index e913642..eb459ce 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -535,14 +535,17 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 
 	if (suite->encryption &&
 			suite->encryption->cipher_type == TLS_CIPHER_AEAD) {
-		if (tls->negotiated_version &&
-				tls->negotiated_version < TLS_V12) {
+		uint16_t negotiated = tls->negotiated_version;
+
+		if (negotiated && negotiated < TLS_V12) {
 			if (error) {
 				*error = error_buf;
 				snprintf(error_buf, sizeof(error_buf),
 						"Cipher suite %s uses an AEAD "
-						"cipher but TLS < 1.2 was "
-						"negotiated", suite->name);
+						"cipher (TLS 1.2+) but "
+						TLS_VER_FMT " was negotiated",
+						suite->name,
+						TLS_VER_ARGS(negotiated));
 			}
 
 			return false;
@@ -1587,7 +1590,8 @@ static void tls_handle_client_hello(struct l_tls *tls,
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
 
-	TLS_DEBUG("Negotiated TLS 1.%i", (tls->negotiated_version & 0xff) - 1);
+	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
+			TLS_VER_ARGS(tls->negotiated_version));
 
 	/* Select a cipher suite according to client's preference list */
 	while (cipher_suites_size) {
@@ -1715,7 +1719,8 @@ static void tls_handle_server_hello(struct l_tls *tls,
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
 
-	TLS_DEBUG("Negotiated TLS 1.%i", (tls->negotiated_version & 0xff) - 1);
+	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
+			TLS_VER_ARGS(tls->negotiated_version));
 
 	/* Set the new cipher suite and compression method structs */
 	tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id);
-- 
2.19.1


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

* [PATCH 4/9] tls: Define and use an enum type for TLS versions
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 2/9] unit: Call l_tls_start in tls tests Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 3/9] tls: Add TLS version number printf macros Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 5/9] tls: Implement l_tls_set_version_range Andrew Zaborowski
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

---
 ell/tls-private.h | 18 ++++++++++--------
 ell/tls-record.c  | 10 +++++-----
 ell/tls.c         | 36 ++++++++++++++++++------------------
 3 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/ell/tls-private.h b/ell/tls-private.h
index 2e254b2..0908b9c 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -20,13 +20,15 @@
  *
  */
 
-/* Only TLS 1.2 supported */
-#define TLS_V12		((3 << 8) | 3)
-#define TLS_V11		((3 << 8) | 2)
-#define TLS_V10		((3 << 8) | 1)
+enum l_tls_version {
+	L_TLS_V10 = ((3 << 8) | 1),
+	L_TLS_V11 = ((3 << 8) | 2),
+	L_TLS_V12 = ((3 << 8) | 3),
+	L_TLS_V13 = ((3 << 8) | 4),	/* Not supported */
+};
 
-#define TLS_VERSION	TLS_V12
-#define TLS_MIN_VERSION	TLS_V10
+#define TLS_VERSION	L_TLS_V12
+#define TLS_MIN_VERSION	L_TLS_V10
 
 enum tls_cipher_type {
 	TLS_CIPHER_STREAM,
@@ -169,8 +171,8 @@ struct l_tls {
 	struct l_checksum *handshake_hash[__HANDSHAKE_HASH_COUNT];
 	uint8_t prev_digest[__HANDSHAKE_HASH_COUNT][HANDSHAKE_HASH_MAX_SIZE];
 
-	uint16_t client_version;
-	uint16_t negotiated_version;
+	enum l_tls_version client_version;
+	enum l_tls_version negotiated_version;
 	bool cert_requested, cert_sent;
 	bool peer_authenticated;
 	struct l_cert *peer_cert;
diff --git a/ell/tls-record.c b/ell/tls-record.c
index bffa413..8cb7e57 100644
--- a/ell/tls-record.c
+++ b/ell/tls-record.c
@@ -135,14 +135,14 @@ static void tls_tx_record_plaintext(struct l_tls *tls,
 
 		offset = 0;
 
-		if (tls->negotiated_version >= TLS_V12) {
+		if (tls->negotiated_version >= L_TLS_V12) {
 			l_getrandom(ciphertext, tls->record_iv_length[1]);
 
 			l_cipher_set_iv(tls->cipher[1], ciphertext,
 					tls->record_iv_length[1]);
 
 			offset = tls->record_iv_length[1];
-		} else if (tls->negotiated_version >= TLS_V11) {
+		} else if (tls->negotiated_version >= L_TLS_V11) {
 			l_getrandom(iv, tls->record_iv_length[1]);
 
 			l_cipher_encrypt(tls->cipher[1], iv, ciphertext,
@@ -444,7 +444,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
 
 	case TLS_CIPHER_BLOCK:
 		i = 0;
-		if (tls->negotiated_version >= TLS_V11)
+		if (tls->negotiated_version >= L_TLS_V11)
 			i = tls->record_iv_length[0];
 
 		if (fragment_len <= tls->mac_length[0] + i) {
@@ -470,7 +470,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
 			return false;
 		}
 
-		if (tls->negotiated_version >= TLS_V12) {
+		if (tls->negotiated_version >= L_TLS_V12) {
 			if (!l_cipher_set_iv(tls->cipher[0],
 						tls->record_buf + 5,
 						tls->record_iv_length[0])) {
@@ -478,7 +478,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
 						"Setting fragment IV failed");
 				return false;
 			}
-		} else if (tls->negotiated_version >= TLS_V11)
+		} else if (tls->negotiated_version >= L_TLS_V11)
 			if (!l_cipher_decrypt(tls->cipher[0],
 						tls->record_buf + 5, iv,
 						tls->record_iv_length[0])) {
diff --git a/ell/tls.c b/ell/tls.c
index eb459ce..eab9cc2 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -130,7 +130,7 @@ static bool tls_prf_get_bytes(struct l_tls *tls,
 				const void *seed, size_t seed_len,
 				uint8_t *buf, size_t len)
 {
-	if (tls->negotiated_version >= TLS_V12)
+	if (tls->negotiated_version >= L_TLS_V12)
 		return tls12_prf(tls->prf_hmac->l_id, tls->prf_hmac->length,
 					secret, secret_len, label,
 					seed, seed_len, buf, len);
@@ -332,7 +332,7 @@ static bool tls_change_cipher_spec(struct l_tls *tls, bool txrx,
 			key_offset += 2 * enc->key_length;
 	}
 
-	if (tls->negotiated_version <= TLS_V10 &&
+	if (tls->negotiated_version <= L_TLS_V10 &&
 			tls->cipher_suite[txrx]->encryption &&
 			tls->cipher_suite[txrx]->encryption->cipher_type ==
 			TLS_CIPHER_BLOCK) {
@@ -535,9 +535,9 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 
 	if (suite->encryption &&
 			suite->encryption->cipher_type == TLS_CIPHER_AEAD) {
-		uint16_t negotiated = tls->negotiated_version;
+		enum l_tls_version negotiated = tls->negotiated_version;
 
-		if (negotiated && negotiated < TLS_V12) {
+		if (negotiated && negotiated < L_TLS_V12) {
 			if (error) {
 				*error = error_buf;
 				snprintf(error_buf, sizeof(error_buf),
@@ -589,10 +589,10 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 		return false;
 	}
 
-	if ((tls->negotiated_version && tls->negotiated_version < TLS_V12 &&
+	if ((tls->negotiated_version && tls->negotiated_version < L_TLS_V12 &&
 			(!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
 			 !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
-			(tls->negotiated_version >= TLS_V12 &&
+			(tls->negotiated_version >= L_TLS_V12 &&
 			 !l_checksum_is_supported(
 					suite->prf_hmac != L_CHECKSUM_NONE ?
 					suite->prf_hmac : L_CHECKSUM_SHA256,
@@ -1034,7 +1034,7 @@ static bool tls_send_certificate_request(struct l_tls *tls)
 	 * affect both of these steps so revisit which set we're passing
 	 * here.
 	 */
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		signature_hash_ptr = ptr;
 		ptr += 2;
 
@@ -1112,7 +1112,7 @@ static void tls_generate_master_secret(struct l_tls *tls,
 			tls->pending.cipher_suite->mac->mac_length;
 
 	if (tls->pending.cipher_suite->encryption &&
-			tls->negotiated_version <= TLS_V10 &&
+			tls->negotiated_version <= L_TLS_V10 &&
 			tls->pending.cipher_suite->encryption->cipher_type ==
 			TLS_CIPHER_BLOCK)
 		key_block_size += 2 *
@@ -1198,7 +1198,7 @@ static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
 		return -ENOKEY;
 	}
 
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		const struct tls_hash_algorithm *hash_type =
 			&tls_handshake_hash_data[tls->signature_hash];
 
@@ -1250,7 +1250,7 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 
 	/* 2 bytes for SignatureAndHashAlgorithm if version >= 1.2 */
 	offset = 2;
-	if (tls->negotiated_version < TLS_V12)
+	if (tls->negotiated_version < L_TLS_V12)
 		offset = 0;
 
 	if (len < offset + 2 ||
@@ -1271,7 +1271,7 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 		return false;
 	}
 
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		/* Only RSA supported */
 		if (in[1] != 1 /* RSA_sign */) {
 			TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0,
@@ -1392,7 +1392,7 @@ static bool tls_send_certificate_verify(struct l_tls *tls)
 		return false;
 
 	/* Stop maintaining handshake message hashes other than the PRF hash */
-	if (tls->negotiated_version >= TLS_V12)
+	if (tls->negotiated_version >= L_TLS_V12)
 		for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
 			if (&tls_handshake_hash_data[i] != tls->prf_hmac)
 				tls_drop_handshake_hash(tls, i);
@@ -1417,7 +1417,7 @@ static void tls_send_finished(struct l_tls *tls)
 	uint8_t seed[HANDSHAKE_HASH_MAX_SIZE * 2];
 	size_t seed_len;
 
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		/* Same hash type as that used for the PRF (usually SHA256) */
 		enum handshake_hash_type hash;
 
@@ -1458,7 +1458,7 @@ static bool tls_verify_finished(struct l_tls *tls, const uint8_t *received,
 		return false;
 	}
 
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		enum handshake_hash_type hash;
 
 		for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
@@ -1585,7 +1585,7 @@ static void tls_handle_client_hello(struct l_tls *tls,
 		TLS_VERSION : tls->client_version;
 
 	/* Stop maintaining handshake message hashes other than MD1 and SHA. */
-	if (tls->negotiated_version < TLS_V12)
+	if (tls->negotiated_version < L_TLS_V12)
 		for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
@@ -1714,7 +1714,7 @@ static void tls_handle_server_hello(struct l_tls *tls,
 	}
 
 	/* Stop maintaining handshake message hashes other than MD1 and SHA. */
-	if (tls->negotiated_version < TLS_V12)
+	if (tls->negotiated_version < L_TLS_V12)
 		for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
@@ -1911,7 +1911,7 @@ static void tls_handle_certificate_request(struct l_tls *tls,
 	 * lists for use in tls_send_certificate.
 	 */
 
-	if (tls->negotiated_version >= TLS_V12) {
+	if (tls->negotiated_version >= L_TLS_V12) {
 		/*
 		 * This only makes sense as a variable-length field, assume
 		 * there's a typo in RFC5246 7.4.4 here.
@@ -2125,7 +2125,7 @@ static void tls_handle_certificate_verify(struct l_tls *tls,
 		return;
 
 	/* Stop maintaining handshake message hashes other than the PRF hash */
-	if (tls->negotiated_version >= TLS_V12)
+	if (tls->negotiated_version >= L_TLS_V12)
 		for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
 			if (&tls_handshake_hash_data[i] != tls->prf_hmac)
 				tls_drop_handshake_hash(tls, i);
-- 
2.19.1


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

* [PATCH 5/9] tls: Implement l_tls_set_version_range
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2018-12-19  0:57 ` [PATCH 4/9] tls: Define and use an enum type for TLS versions Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19 16:22   ` Denis Kenzior
  2018-12-19  0:57 ` [PATCH 6/9] unit: Test TLS 1.0, 1.1 and 1.2 Andrew Zaborowski
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

Allow user to set custom min and max TLS version limits, this can be
used to ensure we comply with a specific security profile.
---
 ell/ell.sym       |  1 +
 ell/tls-private.h | 10 ++-----
 ell/tls-record.c  |  4 +--
 ell/tls.c         | 74 +++++++++++++++++++++++++++++++++++++----------
 ell/tls.h         | 11 ++++++-
 5 files changed, 73 insertions(+), 27 deletions(-)

diff --git a/ell/ell.sym b/ell/ell.sym
index 764cfd1..23d2349 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -416,6 +416,7 @@ global:
 	l_tls_close;
 	l_tls_set_cacert;
 	l_tls_set_auth_data;
+	l_tls_set_version_range;
 	l_tls_alert_to_str;
 	l_tls_set_debug;
 	/* uintset */
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 0908b9c..e450ac2 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -20,14 +20,7 @@
  *
  */
 
-enum l_tls_version {
-	L_TLS_V10 = ((3 << 8) | 1),
-	L_TLS_V11 = ((3 << 8) | 2),
-	L_TLS_V12 = ((3 << 8) | 3),
-	L_TLS_V13 = ((3 << 8) | 4),	/* Not supported */
-};
-
-#define TLS_VERSION	L_TLS_V12
+#define TLS_MAX_VERSION	L_TLS_V12
 #define TLS_MIN_VERSION	L_TLS_V10
 
 enum tls_cipher_type {
@@ -147,6 +140,7 @@ struct l_tls {
 	l_tls_debug_cb_t debug_handler;
 	l_tls_destroy_cb_t debug_destroy;
 	void *debug_data;
+	enum l_tls_version min_version, max_version;
 
 	struct l_queue *ca_certs;
 	struct l_certchain *cert;
diff --git a/ell/tls-record.c b/ell/tls-record.c
index 8cb7e57..bdab0c4 100644
--- a/ell/tls-record.c
+++ b/ell/tls-record.c
@@ -223,7 +223,7 @@ void tls_tx_record(struct l_tls *tls, enum tls_content_type type,
 				TX_RECORD_TAILROOM];
 	uint8_t *fragment, *plaintext;
 	uint16_t fragment_len;
-	uint16_t version = tls->negotiated_version ?: TLS_MIN_VERSION;
+	uint16_t version = tls->negotiated_version ?: tls->min_version;
 
 	if (type == TLS_CT_ALERT)
 		tls->record_flush = true;
@@ -393,7 +393,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
 
 	if ((tls->negotiated_version && tls->negotiated_version != version) ||
 			(!tls->negotiated_version &&
-			 tls->record_buf[1] != 0x03 /* Appending E.1 */)) {
+			 tls->record_buf[1] != 0x03 /* Appendix E.1 */)) {
 		TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0,
 				"Record version mismatch: %02x", version);
 		return false;
diff --git a/ell/tls.c b/ell/tls.c
index eab9cc2..47b0157 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -532,10 +532,24 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 {
 	static char error_buf[200];
 	struct l_cert *leaf;
+	enum l_tls_version negotiated = tls->negotiated_version;
 
 	if (suite->encryption &&
 			suite->encryption->cipher_type == TLS_CIPHER_AEAD) {
-		enum l_tls_version negotiated = tls->negotiated_version;
+		if (tls->max_version < L_TLS_V12) {
+			if (error) {
+				*error = error_buf;
+				snprintf(error_buf, sizeof(error_buf),
+						"Cipher suite %s uses an AEAD "
+						"cipher (TLS 1.2+) but "
+						TLS_VER_FMT
+						" is the max version allowed",
+						suite->name,
+						TLS_VER_ARGS(tls->max_version));
+			}
+
+			return false;
+		}
 
 		if (negotiated && negotiated < L_TLS_V12) {
 			if (error) {
@@ -589,10 +603,13 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 		return false;
 	}
 
-	if ((tls->negotiated_version && tls->negotiated_version < L_TLS_V12 &&
-			(!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
-			 !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
-			(tls->negotiated_version >= L_TLS_V12 &&
+	if (
+			((tls->max_version < L_TLS_V12 ||
+			  (negotiated && negotiated < L_TLS_V12)) &&
+			 (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
+			  !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
+			((tls->min_version >= L_TLS_V12 ||
+			  negotiated >= L_TLS_V12) &&
 			 !l_checksum_is_supported(
 					suite->prf_hmac != L_CHECKSUM_NONE ?
 					suite->prf_hmac : L_CHECKSUM_SHA256,
@@ -664,8 +681,14 @@ static const struct tls_hash_algorithm tls_handshake_hash_data[] = {
 static bool tls_init_handshake_hash(struct l_tls *tls)
 {
 	enum handshake_hash_type hash;
+	bool tls10 = tls->max_version < L_TLS_V12;
 
 	for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
+		/* Skip hash types we already know we won't need */
+		if (tls10 && hash != HANDSHAKE_HASH_SHA1 &&
+				hash != HANDSHAKE_HASH_MD5)
+			continue;
+
 		if (tls->handshake_hash[hash]) {
 			TLS_DEBUG("Handshake hash %s already exists",
 					tls_handshake_hash_data[hash].name);
@@ -820,8 +843,8 @@ static bool tls_send_client_hello(struct l_tls *tls)
 
 	/* Fill in the Client Hello body */
 
-	*ptr++ = (uint8_t) (TLS_VERSION >> 8);
-	*ptr++ = (uint8_t) (TLS_VERSION >> 0);
+	*ptr++ = (uint8_t) (tls->max_version >> 8);
+	*ptr++ = (uint8_t) (tls->max_version >> 0);
 
 	tls_write_random(tls->pending.client_random);
 	memcpy(ptr, tls->pending.client_random, 32);
@@ -843,7 +866,8 @@ static bool tls_send_client_hello(struct l_tls *tls)
 	}
 
 	if (ptr == len_ptr + 2) {
-		TLS_DEBUG("No compatible cipher suites, check kernel config");
+		TLS_DEBUG("No compatible cipher suites, check kernel config, "
+				"certificate's key type and TLS version range");
 		return false;
 	}
 
@@ -1147,8 +1171,9 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
 		return false;
 	}
 
-	pre_master_secret[0] = (uint8_t) (TLS_VERSION >> 8);
-	pre_master_secret[1] = (uint8_t) (TLS_VERSION >> 0);
+	/* Must match the version in tls_send_client_hello */
+	pre_master_secret[0] = (uint8_t) (tls->max_version >> 8);
+	pre_master_secret[1] = (uint8_t) (tls->max_version >> 0);
 	l_getrandom(pre_master_secret + 2, 46);
 
 	if (tls->peer_pubkey_size + 32 > (int) sizeof(buf)) {
@@ -1574,15 +1599,15 @@ static void tls_handle_client_hello(struct l_tls *tls,
 	/* Save client_version for Premaster Secret verification */
 	tls->client_version = l_get_be16(buf);
 
-	if (tls->client_version < TLS_MIN_VERSION) {
+	if (tls->client_version < tls->min_version) {
 		TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0,
 				"Client version too low: %02x",
 				tls->client_version);
 		return;
 	}
 
-	tls->negotiated_version = TLS_VERSION < tls->client_version ?
-		TLS_VERSION : tls->client_version;
+	tls->negotiated_version = tls->client_version > tls->max_version ?
+		tls->max_version : tls->client_version;
 
 	/* Stop maintaining handshake message hashes other than MD1 and SHA. */
 	if (tls->negotiated_version < L_TLS_V12)
@@ -1703,9 +1728,9 @@ static void tls_handle_server_hello(struct l_tls *tls,
 
 	tls->negotiated_version = l_get_be16(buf);
 
-	if (tls->negotiated_version < TLS_MIN_VERSION ||
-			tls->negotiated_version > TLS_VERSION) {
-		TLS_DISCONNECT(tls->negotiated_version < TLS_MIN_VERSION ?
+	if (tls->negotiated_version < tls->min_version ||
+			tls->negotiated_version > tls->max_version) {
+		TLS_DISCONNECT(tls->negotiated_version < tls->min_version ?
 				TLS_ALERT_PROTOCOL_VERSION :
 				TLS_ALERT_ILLEGAL_PARAM, 0,
 				"Unsupported version %02x",
@@ -2458,6 +2483,8 @@ LIB_EXPORT struct l_tls *l_tls_new(bool server,
 	tls->ready_handle = ready_handler;
 	tls->disconnected = disconnect_handler;
 	tls->user_data = user_data;
+	tls->min_version = TLS_MIN_VERSION;
+	tls->max_version = TLS_MAX_VERSION;
 
 	tls->signature_hash = HANDSHAKE_HASH_SHA256;
 
@@ -2646,6 +2673,9 @@ bool tls_handle_message(struct l_tls *tls, const uint8_t *message,
 
 LIB_EXPORT bool l_tls_start(struct l_tls *tls)
 {
+	if (tls->max_version < tls->min_version)
+		return false;
+
 	/* This is a nop in server mode */
 	if (tls->server)
 		return true;
@@ -2751,6 +2781,18 @@ LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
 	return true;
 }
 
+LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
+					uint16_t min_version,
+					uint16_t max_version)
+{
+	tls->min_version =
+		(min_version && min_version > TLS_MIN_VERSION) ?
+		min_version : TLS_MIN_VERSION;
+	tls->max_version =
+		(max_version && max_version < TLS_MAX_VERSION) ?
+		max_version : TLS_MAX_VERSION;
+}
+
 LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc)
 {
 	switch (desc) {
diff --git a/ell/tls.h b/ell/tls.h
index fb33404..8414338 100644
--- a/ell/tls.h
+++ b/ell/tls.h
@@ -25,6 +25,13 @@
 extern "C" {
 #endif
 
+enum l_tls_version {
+	L_TLS_V10 = ((3 << 8) | 1),
+	L_TLS_V11 = ((3 << 8) | 2),
+	L_TLS_V12 = ((3 << 8) | 3),
+	L_TLS_V13 = ((3 << 8) | 4),	/* Not supported */
+};
+
 struct l_tls;
 
 enum l_tls_alert_desc {
@@ -63,7 +70,6 @@ typedef void (*l_tls_disconnect_cb_t)(enum l_tls_alert_desc reason,
 typedef void (*l_tls_debug_cb_t)(const char *str, void *user_data);
 typedef void (*l_tls_destroy_cb_t)(void *user_data);
 
-
 /*
  * app_data_handler gets called with newly received decrypted data.
  * tx_handler gets called to send TLS payloads off to remote end.
@@ -107,6 +113,9 @@ bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
 				const char *priv_key_path,
 				const char *priv_key_passphrase);
 
+void l_tls_set_version_range(struct l_tls *tls,
+				uint16_t min_version, uint16_t max_version);
+
 const char *l_tls_alert_to_str(enum l_tls_alert_desc desc);
 
 enum l_checksum_type;
-- 
2.19.1


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

* [PATCH 6/9] unit: Test TLS 1.0, 1.1 and 1.2
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (3 preceding siblings ...)
  2018-12-19  0:57 ` [PATCH 5/9] tls: Implement l_tls_set_version_range Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 7/9] tls: Allow user to set custom list of cipher suites Andrew Zaborowski
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

---
 unit/test-tls.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/unit/test-tls.c b/unit/test-tls.c
index 6731a0e..2b5d16b 100644
--- a/unit/test-tls.c
+++ b/unit/test-tls.c
@@ -431,7 +431,8 @@ static void tls_debug_cb(const char *str, void *user_data)
 	l_info("%s %s", (const char *) user_data, str);
 }
 
-static void test_tls_test(const void *data)
+static void test_tls_with_ver(const void *data,
+				uint16_t server_ver, uint16_t client_ver)
 {
 	bool auth_ok;
 	const struct tls_conn_test *test = data;
@@ -466,6 +467,12 @@ static void test_tls_test(const void *data)
 	assert(s[0].tls);
 	assert(s[1].tls);
 
+	if (server_ver)
+		l_tls_set_version_range(s[0].tls, server_ver, server_ver);
+
+	if (client_ver)
+		l_tls_set_version_range(s[1].tls, client_ver, client_ver);
+
 	if (getenv("TLS_SERVER_DEBUG"))
 		l_tls_set_debug(s[0].tls, tls_debug_cb, "server", NULL);
 
@@ -505,6 +512,18 @@ static void test_tls_test(const void *data)
 	l_tls_free(s[1].tls);
 }
 
+static void test_tls_test(const void *data)
+{
+	/*
+	 * 1.2 should get negotiated in the first case.  If the three
+	 * scenarios succeed that's already good but can be checked with:
+	 * $ TLS_DEBUG=1 unit/test-tls 2>&1 | grep "Negotiated"
+	 */
+	test_tls_with_ver(data, 0, 0);
+	test_tls_with_ver(data, 0, L_TLS_V11);
+	test_tls_with_ver(data, L_TLS_V10, 0);
+}
+
 int main(int argc, char *argv[])
 {
 	l_test_init(&argc, &argv);
-- 
2.19.1


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

* [PATCH 7/9] tls: Allow user to set custom list of cipher suites
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (4 preceding siblings ...)
  2018-12-19  0:57 ` [PATCH 6/9] unit: Test TLS 1.0, 1.1 and 1.2 Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19  0:57 ` [PATCH 8/9] fixme: add mte to the set ci su patch Andrew Zaborowski
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

TLS "security profiles" define which minimum cipher suites and other
parameter values are allowed in a specific usage scenario for TLS, for
example WPA3 in theory requires a specific security profile for its
TLS-based EAP method.  This will also allow the unit tests to test
individual cipher suites.
---
 ell/tls-private.h |   5 +
 ell/tls.c         | 260 +++++++++++++++++++++++++++++++---------------
 2 files changed, 181 insertions(+), 84 deletions(-)

diff --git a/ell/tls-private.h b/ell/tls-private.h
index e450ac2..f7dc263 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -147,6 +147,8 @@ struct l_tls {
 	struct l_key *priv_key;
 	size_t priv_key_size;
 
+	struct tls_cipher_suite **cipher_suite_pref_list;
+
 	/* Record layer */
 
 	uint8_t *record_buf;
@@ -233,6 +235,9 @@ void tls_tx_record(struct l_tls *tls, enum tls_content_type type,
 bool tls_handle_message(struct l_tls *tls, const uint8_t *message,
 			int len, enum tls_content_type type, uint16_t version);
 
+/* Optionally limit allowed cipher suites to a custom set */
+bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list);
+
 int tls_parse_certificate_list(const void *data, size_t len,
 				struct l_certchain **out_certchain);
 
diff --git a/ell/tls.c b/ell/tls.c
index 47b0157..904784e 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -41,6 +41,7 @@
 #include "tls-private.h"
 #include "key.h"
 #include "asn1-private.h"
+#include "strv.h"
 
 bool tls10_prf(const void *secret, size_t secret_len,
 		const char *label,
@@ -452,78 +453,80 @@ static struct tls_mac_algorithm tls_md5 = {
 	.mac_length = 32,
 };
 
-static struct tls_cipher_suite tls_cipher_suite_pref[] = {
-	{
-		.id = { 0x00, 0x35 },
-		.name = "TLS_RSA_WITH_AES_256_CBC_SHA",
-		.verify_data_length = 12,
-		.encryption = &tls_aes256,
-		.mac = &tls_sha,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x2f },
-		.name = "TLS_RSA_WITH_AES_128_CBC_SHA",
-		.verify_data_length = 12,
-		.encryption = &tls_aes128,
-		.mac = &tls_sha,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x3d },
-		.name = "TLS_RSA_WITH_AES_256_CBC_SHA256",
-		.verify_data_length = 12,
-		.encryption = &tls_aes256,
-		.mac = &tls_sha256,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x3c },
-		.name = "TLS_RSA_WITH_AES_128_CBC_SHA256",
-		.verify_data_length = 12,
-		.encryption = &tls_aes128,
-		.mac = &tls_sha256,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x9d },
-		.name = "TLS_RSA_WITH_AES_256_GCM_SHA384",
-		.verify_data_length = 12,
-		.encryption = &tls_aes256_gcm,
-		.prf_hmac = L_CHECKSUM_SHA384,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x9c },
-		.name = "TLS_RSA_WITH_AES_128_GCM_SHA256",
-		.verify_data_length = 12,
-		.encryption = &tls_aes128_gcm,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x0a },
-		.name = "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
-		.verify_data_length = 12,
-		.encryption = &tls_3des_ede,
-		.mac = &tls_sha,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x05 },
-		.name = "TLS_RSA_WITH_RC4_128_SHA",
-		.verify_data_length = 12,
-		.encryption = &tls_rc4,
-		.mac = &tls_sha,
-		.key_xchg = &tls_rsa,
-	},
-	{
-		.id = { 0x00, 0x04 },
-		.name = "TLS_RSA_WITH_RC4_128_MD5",
-		.verify_data_length = 12,
-		.encryption = &tls_rc4,
-		.mac = &tls_md5,
-		.key_xchg = &tls_rsa,
-	},
+static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = {
+	.id = { 0x00, 0x04 },
+	.name = "TLS_RSA_WITH_RC4_128_MD5",
+	.verify_data_length = 12,
+	.encryption = &tls_rc4,
+	.mac = &tls_md5,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_rc4_128_sha = {
+	.id = { 0x00, 0x05 },
+	.name = "TLS_RSA_WITH_RC4_128_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_rc4,
+	.mac = &tls_sha,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_3des_ede_cbc_sha = {
+	.id = { 0x00, 0x0a },
+	.name = "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_3des_ede,
+	.mac = &tls_sha,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_128_cbc_sha = {
+	.id = { 0x00, 0x2f },
+	.name = "TLS_RSA_WITH_AES_128_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128,
+	.mac = &tls_sha,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_256_cbc_sha = {
+	.id = { 0x00, 0x35 },
+	.name = "TLS_RSA_WITH_AES_256_CBC_SHA",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256,
+	.mac = &tls_sha,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_128_cbc_sha256 = {
+	.id = { 0x00, 0x3c },
+	.name = "TLS_RSA_WITH_AES_128_CBC_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128,
+	.mac = &tls_sha256,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_256_cbc_sha256 = {
+	.id = { 0x00, 0x3d },
+	.name = "TLS_RSA_WITH_AES_256_CBC_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256,
+	.mac = &tls_sha256,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_128_gcm_sha256 = {
+	.id = { 0x00, 0x9c },
+	.name = "TLS_RSA_WITH_AES_128_GCM_SHA256",
+	.verify_data_length = 12,
+	.encryption = &tls_aes128_gcm,
+	.key_xchg = &tls_rsa,
+}, tls_rsa_with_aes_256_gcm_sha384 = {
+	.id = { 0x00, 0x9d },
+	.name = "TLS_RSA_WITH_AES_256_GCM_SHA384",
+	.verify_data_length = 12,
+	.encryption = &tls_aes256_gcm,
+	.prf_hmac = L_CHECKSUM_SHA384,
+	.key_xchg = &tls_rsa,
+};
+
+static struct tls_cipher_suite *tls_cipher_suite_pref[] = {
+	&tls_rsa_with_aes_256_cbc_sha,
+	&tls_rsa_with_aes_128_cbc_sha,
+	&tls_rsa_with_aes_256_cbc_sha256,
+	&tls_rsa_with_aes_128_cbc_sha256,
+	&tls_rsa_with_aes_256_gcm_sha384,
+	&tls_rsa_with_aes_128_gcm_sha256,
+	&tls_rsa_with_3des_ede_cbc_sha,
+	&tls_rsa_with_rc4_128_sha,
+	&tls_rsa_with_rc4_128_md5,
 };
 
 static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
@@ -645,9 +648,9 @@ static struct tls_cipher_suite *tls_find_cipher_suite(const uint8_t *id)
 	int i;
 
 	for (i = 0; i < (int) L_ARRAY_SIZE(tls_cipher_suite_pref); i++)
-		if (tls_cipher_suite_pref[i].id[0] == id[0] &&
-				tls_cipher_suite_pref[i].id[1] == id[1])
-			return &tls_cipher_suite_pref[i];
+		if (tls_cipher_suite_pref[i]->id[0] == id[0] &&
+				tls_cipher_suite_pref[i]->id[1] == id[1])
+			return tls_cipher_suite_pref[i];
 
 	return NULL;
 }
@@ -840,6 +843,7 @@ static bool tls_send_client_hello(struct l_tls *tls)
 	uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
 	uint8_t *len_ptr;
 	int i;
+	struct tls_cipher_suite **suite;
 
 	/* Fill in the Client Hello body */
 
@@ -855,14 +859,16 @@ static bool tls_send_client_hello(struct l_tls *tls)
 	len_ptr = ptr;
 	ptr += 2;
 
-	for (i = 0; i < (int) L_ARRAY_SIZE(tls_cipher_suite_pref); i++) {
-		if (!tls_cipher_suite_is_compatible(tls,
-						&tls_cipher_suite_pref[i],
-						NULL))
+	for (suite = tls->cipher_suite_pref_list; *suite; suite++) {
+		const char *error;
+
+		if (!tls_cipher_suite_is_compatible(tls, *suite, &error)) {
+			TLS_DEBUG("non-fatal: %s", error);
 			continue;
+		}
 
-		*ptr++ = tls_cipher_suite_pref[i].id[0];
-		*ptr++ = tls_cipher_suite_pref[i].id[1];
+		*ptr++ = (*suite)->id[0];
+		*ptr++ = (*suite)->id[1];
 	}
 
 	if (ptr == len_ptr + 2) {
@@ -1524,6 +1530,7 @@ static void tls_handle_client_hello(struct l_tls *tls,
 	const uint8_t *cipher_suites;
 	const uint8_t *compression_methods;
 	int i;
+	enum l_tls_alert_desc alert_desc = TLS_ALERT_HANDSHAKE_FAIL;
 
 	/* Do we have enough for ProtocolVersion + Random + SessionID size? */
 	if (len < 2 + 32 + 1)
@@ -1618,12 +1625,39 @@ static void tls_handle_client_hello(struct l_tls *tls,
 	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
 			TLS_VER_ARGS(tls->negotiated_version));
 
+	if (tls->cipher_suite_pref_list) {
+		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+				"No usable cipher suites");
+		return;
+	}
+
 	/* Select a cipher suite according to client's preference list */
 	while (cipher_suites_size) {
 		struct tls_cipher_suite *suite =
 			tls_find_cipher_suite(cipher_suites);
+		struct tls_cipher_suite **iter;
+		const char *error;
 
-		if (suite && tls_cipher_suite_is_compatible(tls, suite, NULL)) {
+		for (iter = tls->cipher_suite_pref_list; *iter; iter++)
+			if (*iter == suite)
+				break;
+
+		if (!suite)
+			TLS_DEBUG("non-fatal: Cipher suite %04x unknown",
+					l_get_be16(cipher_suites));
+		else if (!tls_cipher_suite_is_compatible(tls, suite, &error))
+			TLS_DEBUG("non-fatal: %s", error);
+		else if (!*iter) {
+			/*
+			 * We have at least one matching compatible suite but
+			 * it is not allowed in this security profile.  If the
+			 * handshake ends up failing then we blame the security
+			 * profile.
+			 */
+			alert_desc = TLS_ALERT_INSUFFICIENT_SECURITY;
+			TLS_DEBUG("non-fatal: Cipher suite %s disallowed "
+					"by config", suite->name);
+		} else {
 			tls->pending.cipher_suite = suite;
 			break;
 		}
@@ -1633,7 +1667,7 @@ static void tls_handle_client_hello(struct l_tls *tls,
 	}
 
 	if (!cipher_suites_size) {
-		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
+		TLS_DISCONNECT(alert_desc, 0,
 				"No common cipher suites matching negotiated "
 				"TLS version and our certificate's key type");
 		return;
@@ -1701,6 +1735,7 @@ static void tls_handle_server_hello(struct l_tls *tls,
 {
 	uint8_t session_id_size, cipher_suite_id[2], compression_method_id;
 	const char *error;
+	struct tls_cipher_suite **iter;
 	int i;
 
 	/* Do we have enough for ProtocolVersion + Random + SessionID len ? */
@@ -1756,6 +1791,16 @@ static void tls_handle_server_hello(struct l_tls *tls,
 		return;
 	}
 
+	for (iter = tls->cipher_suite_pref_list; *iter; iter++)
+		if (*iter == tls->pending.cipher_suite)
+			break;
+	if (!*iter) {
+		TLS_DISCONNECT(TLS_ALERT_INSUFFICIENT_SECURITY, 0,
+				"Selected cipher suite %s disallowed by config",
+				tls->pending.cipher_suite->name);
+		return;
+	}
+
 	if (!tls_cipher_suite_is_compatible(tls, tls->pending.cipher_suite,
 						&error)) {
 		TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
@@ -2485,7 +2530,7 @@ LIB_EXPORT struct l_tls *l_tls_new(bool server,
 	tls->user_data = user_data;
 	tls->min_version = TLS_MIN_VERSION;
 	tls->max_version = TLS_MAX_VERSION;
-
+	tls->cipher_suite_pref_list = tls_cipher_suite_pref;
 	tls->signature_hash = HANDSHAKE_HASH_SHA256;
 
 	/* If we're the server wait for the Client Hello already */
@@ -2525,6 +2570,9 @@ LIB_EXPORT void l_tls_free(struct l_tls *tls)
 	if (tls->debug_destroy)
 		tls->debug_destroy(tls->debug_data);
 
+	if (tls->cipher_suite_pref_list != tls_cipher_suite_pref)
+		l_free(tls->cipher_suite_pref_list);
+
 	l_free(tls);
 }
 
@@ -2676,6 +2724,9 @@ LIB_EXPORT bool l_tls_start(struct l_tls *tls)
 	if (tls->max_version < tls->min_version)
 		return false;
 
+	if (!tls->cipher_suite_pref_list)
+		return false;
+
 	/* This is a nop in server mode */
 	if (tls->server)
 		return true;
@@ -2793,6 +2844,47 @@ LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
 		max_version : TLS_MAX_VERSION;
 }
 
+bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list)
+{
+	unsigned int len;
+	struct tls_cipher_suite **suite;
+
+	l_free(tls->cipher_suite_pref_list);
+
+	if (!suite_list) {
+		/* Use our default cipher suite preference list */
+		tls->cipher_suite_pref_list = tls_cipher_suite_pref;
+		return true;
+	}
+
+	len = l_strv_length((char **) suite_list);
+	tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *, len + 1);
+	suite = tls->cipher_suite_pref_list;
+
+	for (; *suite_list; suite_list++) {
+		unsigned int i;
+
+		for (i = 0; i < len; i++)
+			if (!strcmp(tls_cipher_suite_pref[i]->name,
+						*suite_list))
+				break;
+
+		if (i < len)
+			*suite++ = tls_cipher_suite_pref[i];
+		else
+			TLS_DEBUG("Cipher suite %s is not supported",
+					*suite_list);
+	}
+
+	if (suite > tls->cipher_suite_pref_list)
+		return true;
+
+	TLS_DEBUG("None of the supplied suite names is supported");
+	l_free(suite);
+	tls->cipher_suite_pref_list = NULL;
+	return false;
+}
+
 LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc)
 {
 	switch (desc) {
-- 
2.19.1


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

* [PATCH 8/9] fixme: add mte to the set ci su patch
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (5 preceding siblings ...)
  2018-12-19  0:57 ` [PATCH 7/9] tls: Allow user to set custom list of cipher suites Andrew Zaborowski
@ 2018-12-19  0:57 ` Andrew Zaborowski
  2018-12-19 16:24   ` Denis Kenzior
  2018-12-19  0:58 ` [PATCH 9/9] unit: Test many TLS cipher suite and version combinations Andrew Zaborowski
  2018-12-19 16:04 ` [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Denis Kenzior
  8 siblings, 1 reply; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:57 UTC (permalink / raw)
  To: ell

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

---
 ell/tls.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/ell/tls.c b/ell/tls.c
index 904784e..42db275 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -1625,7 +1625,7 @@ static void tls_handle_client_hello(struct l_tls *tls,
 	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
 			TLS_VER_ARGS(tls->negotiated_version));
 
-	if (tls->cipher_suite_pref_list) {
+	if (!tls->cipher_suite_pref_list) {
 		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
 				"No usable cipher suites");
 		return;
@@ -2846,10 +2846,10 @@ LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
 
 bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list)
 {
-	unsigned int len;
 	struct tls_cipher_suite **suite;
 
-	l_free(tls->cipher_suite_pref_list);
+	if (tls->cipher_suite_pref_list != tls_cipher_suite_pref)
+		l_free(tls->cipher_suite_pref_list);
 
 	if (!suite_list) {
 		/* Use our default cipher suite preference list */
@@ -2857,19 +2857,19 @@ bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list)
 		return true;
 	}
 
-	len = l_strv_length((char **) suite_list);
-	tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *, len + 1);
+	tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *,
+				l_strv_length((char **) suite_list) + 1);
 	suite = tls->cipher_suite_pref_list;
 
 	for (; *suite_list; suite_list++) {
 		unsigned int i;
 
-		for (i = 0; i < len; i++)
+		for (i = 0; i < L_ARRAY_SIZE(tls_cipher_suite_pref); i++)
 			if (!strcmp(tls_cipher_suite_pref[i]->name,
 						*suite_list))
 				break;
 
-		if (i < len)
+		if (i < L_ARRAY_SIZE(tls_cipher_suite_pref))
 			*suite++ = tls_cipher_suite_pref[i];
 		else
 			TLS_DEBUG("Cipher suite %s is not supported",
-- 
2.19.1


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

* [PATCH 9/9] unit: Test many TLS cipher suite and version combinations
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (6 preceding siblings ...)
  2018-12-19  0:57 ` [PATCH 8/9] fixme: add mte to the set ci su patch Andrew Zaborowski
@ 2018-12-19  0:58 ` Andrew Zaborowski
  2018-12-19 16:04 ` [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Denis Kenzior
  8 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-19  0:58 UTC (permalink / raw)
  To: ell

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

---
 unit/test-tls.c | 131 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 123 insertions(+), 8 deletions(-)

diff --git a/unit/test-tls.c b/unit/test-tls.c
index 2b5d16b..fb97c44 100644
--- a/unit/test-tls.c
+++ b/unit/test-tls.c
@@ -302,11 +302,16 @@ struct tls_conn_test {
 	const char *server_key_passphrase;
 	const char *server_ca_cert_path;
 	const char *server_expect_identity;
+	const char **server_cipher_suites;
 	const char *client_cert_path;
 	const char *client_key_path;
 	const char *client_key_passphrase;
 	const char *client_ca_cert_path;
 	const char *client_expect_identity;
+	const char **client_cipher_suites;
+	bool expect_alert;
+	bool expect_client_start_fail;
+	enum l_tls_alert_desc alert_desc;
 };
 
 static const struct tls_conn_test tls_conn_test_no_auth = {
@@ -362,6 +367,49 @@ static const struct tls_conn_test tls_conn_test_full_auth = {
 	.client_expect_identity = "Foo Example Organization",
 };
 
+static const struct tls_conn_test tls_conn_test_bad_client_suite = {
+	.server_cert_path = CERTDIR "cert-server.pem",
+	.server_key_path = CERTDIR "cert-server-key-pkcs8.pem",
+	.server_ca_cert_path = CERTDIR "cert-ca.pem",
+	.server_expect_identity = "Bar Example Organization",
+	.client_cert_path = CERTDIR "cert-client.pem",
+	.client_key_path = CERTDIR "cert-client-key-pkcs8.pem",
+	.client_ca_cert_path = CERTDIR "cert-ca.pem",
+	.client_expect_identity = "Foo Example Organization",
+	.client_cipher_suites = (const char *[]) { "UNKNOWN", NULL },
+	.expect_client_start_fail = true,
+};
+
+static const struct tls_conn_test tls_conn_test_suite_mismatch = {
+	.server_cert_path = CERTDIR "cert-server.pem",
+	.server_key_path = CERTDIR "cert-server-key-pkcs8.pem",
+	.server_ca_cert_path = CERTDIR "cert-ca.pem",
+	.server_expect_identity = "Bar Example Organization",
+	.server_cipher_suites =
+		(const char *[]) { "TLS_RSA_WITH_AES_128_CBC_SHA256", NULL },
+	.client_cert_path = CERTDIR "cert-client.pem",
+	.client_key_path = CERTDIR "cert-client-key-pkcs8.pem",
+	.client_ca_cert_path = CERTDIR "cert-ca.pem",
+	.client_expect_identity = "Foo Example Organization",
+	.client_cipher_suites =
+		(const char *[]) { "TLS_RSA_WITH_AES_256_CBC_SHA256", NULL },
+	.expect_alert = true,
+	.alert_desc = TLS_ALERT_INSUFFICIENT_SECURITY,
+};
+
+static const struct tls_conn_test tls_conn_test_version_mismatch = {
+	.server_cert_path = CERTDIR "cert-server.pem",
+	.server_key_path = CERTDIR "cert-server-key-pkcs8.pem",
+	.server_ca_cert_path = CERTDIR "cert-ca.pem",
+	.server_expect_identity = "Bar Example Organization",
+	.client_cert_path = CERTDIR "cert-client.pem",
+	.client_key_path = CERTDIR "cert-client-key-pkcs8.pem",
+	.client_ca_cert_path = CERTDIR "cert-ca.pem",
+	.client_expect_identity = "Foo Example Organization",
+	.expect_alert = true,
+	.alert_desc = TLS_ALERT_PROTOCOL_VERSION,
+};
+
 #define identity_compare(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp(a, b)))
 
 struct tls_test_state {
@@ -378,6 +426,9 @@ struct tls_test_state {
 	const char *send_data;
 	const char *expect_data;
 	const char *expect_peer;
+
+	bool expect_alert;
+	enum l_tls_alert_desc alert_desc;
 };
 
 static void tls_test_new_data(const uint8_t *data, size_t len, void *user_data)
@@ -411,6 +462,7 @@ static void tls_test_ready(const char *peer_identity, void *user_data)
 	struct tls_test_state *s = user_data;
 
 	assert(!s->ready);
+	assert(!s->expect_alert);
 	assert((!s->expect_peer && !peer_identity) ||
 			(s->expect_peer && peer_identity &&
 			 !strcmp(s->expect_peer, peer_identity)));
@@ -423,7 +475,11 @@ static void tls_test_ready(const char *peer_identity, void *user_data)
 static void tls_test_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
-	assert(false);
+	struct tls_test_state *s = user_data;
+
+	assert(s->expect_alert);
+	assert(reason == s->alert_desc);
+	s->success = true;
 }
 
 static void tls_debug_cb(const char *str, void *user_data)
@@ -431,11 +487,10 @@ static void tls_debug_cb(const char *str, void *user_data)
 	l_info("%s %s", (const char *) user_data, str);
 }
 
-static void test_tls_with_ver(const void *data,
+static void test_tls_with_ver(const struct tls_conn_test *test,
 				uint16_t server_ver, uint16_t client_ver)
 {
 	bool auth_ok;
-	const struct tls_conn_test *test = data;
 	struct tls_test_state s[2] = {
 		{
 			.ready = false,
@@ -445,6 +500,8 @@ static void test_tls_with_ver(const void *data,
 			.send_data = "server to client",
 			.expect_data = "client to server",
 			.expect_peer = test->server_expect_identity,
+			.expect_alert = test->expect_alert,
+			.alert_desc = test->alert_desc,
 		},
 		{
 			.ready = false,
@@ -454,6 +511,8 @@ static void test_tls_with_ver(const void *data,
 			.send_data = "client to server",
 			.expect_data = "server to client",
 			.expect_peer = test->client_expect_identity,
+			.expect_alert = test->expect_alert,
+			.alert_desc = test->alert_desc,
 		},
 	};
 
@@ -473,6 +532,12 @@ static void test_tls_with_ver(const void *data,
 	if (client_ver)
 		l_tls_set_version_range(s[1].tls, client_ver, client_ver);
 
+	if (test->server_cipher_suites)
+		tls_set_cipher_suites(s[0].tls, test->server_cipher_suites);
+
+	if (test->client_cipher_suites)
+		tls_set_cipher_suites(s[1].tls, test->client_cipher_suites);
+
 	if (getenv("TLS_SERVER_DEBUG"))
 		l_tls_set_debug(s[0].tls, tls_debug_cb, "server", NULL);
 
@@ -491,9 +556,12 @@ static void test_tls_with_ver(const void *data,
 	assert(l_tls_set_cacert(s[1].tls, test->client_ca_cert_path));
 
 	assert(l_tls_start(s[0].tls));
-	assert(l_tls_start(s[1].tls));
+	assert(!!l_tls_start(s[1].tls) == !test->expect_client_start_fail);
 
-	while (1) {
+	if (test->expect_client_start_fail)
+		goto done;
+
+	while (!(test->expect_alert && s[0].success && s[1].success)) {
 		if (s[0].raw_buf_len) {
 			l_tls_handle_rx(s[1].tls, s[0].raw_buf,
 					s[0].raw_buf_len);
@@ -508,24 +576,60 @@ static void test_tls_with_ver(const void *data,
 
 	assert(s[0].success && s[1].success);
 
+done:
 	l_tls_free(s[0].tls);
 	l_tls_free(s[1].tls);
 }
 
 static void test_tls_test(const void *data)
 {
+	const struct tls_conn_test *test = data;
+
 	/*
 	 * 1.2 should get negotiated in the first case.  If the three
 	 * scenarios succeed that's already good but can be checked with:
 	 * $ TLS_DEBUG=1 unit/test-tls 2>&1 | grep "Negotiated"
 	 */
-	test_tls_with_ver(data, 0, 0);
-	test_tls_with_ver(data, 0, L_TLS_V11);
-	test_tls_with_ver(data, L_TLS_V10, 0);
+	test_tls_with_ver(test, 0, 0);
+	test_tls_with_ver(test, 0, L_TLS_V11);
+	test_tls_with_ver(test, L_TLS_V10, 0);
+}
+
+static void test_tls_version_mismatch_test(const void *data)
+{
+	test_tls_with_ver(&tls_conn_test_version_mismatch,
+				L_TLS_V11, L_TLS_V12);
+	test_tls_with_ver(&tls_conn_test_version_mismatch,
+				L_TLS_V12, L_TLS_V10);
+	test_tls_with_ver(&tls_conn_test_version_mismatch,
+				L_TLS_V10, L_TLS_V11);
+}
+
+static void test_tls_suite_test(const void *data)
+{
+	const char *suite_name = data;
+	const char *client_cipher_suites[] = { suite_name, NULL };
+	struct tls_conn_test test = tls_conn_test_full_auth;
+
+	test.client_cipher_suites = client_cipher_suites;
+	test_tls_with_ver(&test, 0, 0);
 }
 
 int main(int argc, char *argv[])
 {
+	const char *suite_names[] = {
+		"TLS_RSA_WITH_RC4_128_MD5",
+		"TLS_RSA_WITH_RC4_128_SHA",
+		"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+		"TLS_RSA_WITH_AES_128_CBC_SHA",
+		"TLS_RSA_WITH_AES_256_CBC_SHA",
+		"TLS_RSA_WITH_AES_128_CBC_SHA256",
+		"TLS_RSA_WITH_AES_256_CBC_SHA256",
+		"TLS_RSA_WITH_AES_128_GCM_SHA256",
+		"TLS_RSA_WITH_AES_256_GCM_SHA384",
+		NULL
+	}, **name;
+
 	l_test_init(&argc, &argv);
 
 	if (!l_checksum_is_supported(L_CHECKSUM_MD5, false) ||
@@ -584,6 +688,17 @@ int main(int argc, char *argv[])
 	l_test_add("TLS connection full auth", test_tls_test,
 			&tls_conn_test_full_auth);
 
+	l_test_add("TLS connection bad client cipher suite", test_tls_test,
+			&tls_conn_test_bad_client_suite);
+	l_test_add("TLS connection cipher suite mismatch", test_tls_test,
+			&tls_conn_test_suite_mismatch);
+
+	l_test_add("TLS connection version mismatch",
+			test_tls_version_mismatch_test, NULL);
+
+	for (name = suite_names; *name; name++)
+		l_test_add(*name, test_tls_suite_test, *name);
+
 done:
 	return l_test_run();
 }
-- 
2.19.1


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

* Re: [PATCH 1/9] tls: Don't send Client Hello in l_tls_new
  2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
                   ` (7 preceding siblings ...)
  2018-12-19  0:58 ` [PATCH 9/9] unit: Test many TLS cipher suite and version combinations Andrew Zaborowski
@ 2018-12-19 16:04 ` Denis Kenzior
  8 siblings, 0 replies; 17+ messages in thread
From: Denis Kenzior @ 2018-12-19 16:04 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

On 12/18/2018 06:57 PM, Andrew Zaborowski wrote:
> Give the user time to set up the tls instance's optional parameters --
> those that can not be passed as parameters of l_tls_new, before sending
> the Client Hello message in client mode.  We now send the message from
> l_tls_start which has to be called after the optional setup is done,
> e.g. set_cacert, set_auth_data, set_debug are called.  This way Client
> Hello can avoid proposing cipher suites that would not have worked if
> they were negotiated, due to bad certificate type.  It also allows us to
> output debug messages in the Client Hello sending code, and will allow
> to add methods to define security profiles.
> ---
>   ell/ell.sym       |  1 +
>   ell/tls-private.h |  1 +
>   ell/tls.c         | 48 ++++++++++++++++++++++++++++-------------------
>   ell/tls.h         |  3 +++
>   4 files changed, 34 insertions(+), 19 deletions(-)

Patches 1-4 applied, thanks.

Regards,
-Denis

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

* Re: [PATCH 5/9] tls: Implement l_tls_set_version_range
  2018-12-19  0:57 ` [PATCH 5/9] tls: Implement l_tls_set_version_range Andrew Zaborowski
@ 2018-12-19 16:22   ` Denis Kenzior
  2018-12-20  2:35     ` Andrew Zaborowski
  0 siblings, 1 reply; 17+ messages in thread
From: Denis Kenzior @ 2018-12-19 16:22 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

On 12/18/2018 06:57 PM, Andrew Zaborowski wrote:
> Allow user to set custom min and max TLS version limits, this can be
> used to ensure we comply with a specific security profile.
> ---
>   ell/ell.sym       |  1 +
>   ell/tls-private.h | 10 ++-----
>   ell/tls-record.c  |  4 +--
>   ell/tls.c         | 74 +++++++++++++++++++++++++++++++++++++----------
>   ell/tls.h         | 11 ++++++-
>   5 files changed, 73 insertions(+), 27 deletions(-)
> 

<snip>

> diff --git a/ell/tls-private.h b/ell/tls-private.h
> index 0908b9c..e450ac2 100644
> --- a/ell/tls-private.h
> +++ b/ell/tls-private.h
> @@ -20,14 +20,7 @@
>    *
>    */
>   
> -enum l_tls_version {
> -	L_TLS_V10 = ((3 << 8) | 1),
> -	L_TLS_V11 = ((3 << 8) | 2),
> -	L_TLS_V12 = ((3 << 8) | 3),
> -	L_TLS_V13 = ((3 << 8) | 4),	/* Not supported */
> -};
> -
> -#define TLS_VERSION	L_TLS_V12
> +#define TLS_MAX_VERSION	L_TLS_V12
>   #define TLS_MIN_VERSION	L_TLS_V10

So we generally discourage #defines that are used only once.  Are you 
planning to use this outside l_tls_new?  This may also be relevant for 
TLS_MIN_VERSION since you are getting rid of many of its usages as well.

>   
>   enum tls_cipher_type {
> @@ -147,6 +140,7 @@ struct l_tls {
>   	l_tls_debug_cb_t debug_handler;
>   	l_tls_destroy_cb_t debug_destroy;
>   	void *debug_data;
> +	enum l_tls_version min_version, max_version;

Separate lines please :)

>   
>   	struct l_queue *ca_certs;
>   	struct l_certchain *cert;

<snip>

> @@ -393,7 +393,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
>   
>   	if ((tls->negotiated_version && tls->negotiated_version != version) ||
>   			(!tls->negotiated_version &&
> -			 tls->record_buf[1] != 0x03 /* Appending E.1 */)) {
> +			 tls->record_buf[1] != 0x03 /* Appendix E.1 */)) {

Separate patch please

>   		TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0,
>   				"Record version mismatch: %02x", version);
>   		return false;

<snip>

> @@ -589,10 +603,13 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
>   		return false;
>   	}
>   
> -	if ((tls->negotiated_version && tls->negotiated_version < L_TLS_V12 &&
> -			(!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
> -			 !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
> -			(tls->negotiated_version >= L_TLS_V12 &&
> +	if (
> +			((tls->max_version < L_TLS_V12 ||
> +			  (negotiated && negotiated < L_TLS_V12)) &&

So the previous version of this only looked at the negotiated version, 
but this one also looks@the max version.  Should this function take 
the TLS version as an argument and let the caller figure out the policy?

> +			 (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
> +			  !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
> +			((tls->min_version >= L_TLS_V12 ||
> +			  negotiated >= L_TLS_V12) &&
>   			 !l_checksum_is_supported(
>   					suite->prf_hmac != L_CHECKSUM_NONE ?
>   					suite->prf_hmac : L_CHECKSUM_SHA256,

Why is this indented so far to the right?  But really, can we put this 
into a separate function and make this a bit more readable, maybe with a 
few comments?

> @@ -2751,6 +2781,18 @@ LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
>   	return true;
>   }
>   
> +LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
> +					uint16_t min_version,
> +					uint16_t max_version)

Why uint16?

> +{
> +	tls->min_version =
> +		(min_version && min_version > TLS_MIN_VERSION) ?
> +		min_version : TLS_MIN_VERSION;
> +	tls->max_version =
> +		(max_version && max_version < TLS_MAX_VERSION) ?
> +		max_version : TLS_MAX_VERSION;

Yikes.  Again, why not use enums here and skip these checks?  If someone 
wants to pass arbitrary int values to this function, that is their problem.

> +}
> +
>   LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc)
>   {
>   	switch (desc) {

Regards,
-Denis

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

* Re: [PATCH 8/9] fixme: add mte to the set ci su patch
  2018-12-19  0:57 ` [PATCH 8/9] fixme: add mte to the set ci su patch Andrew Zaborowski
@ 2018-12-19 16:24   ` Denis Kenzior
  2018-12-20  1:53     ` Andrew Zaborowski
  0 siblings, 1 reply; 17+ messages in thread
From: Denis Kenzior @ 2018-12-19 16:24 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

On 12/18/2018 06:57 PM, Andrew Zaborowski wrote:
> ---
>   ell/tls.c | 14 +++++++-------
>   1 file changed, 7 insertions(+), 7 deletions(-)
> 

??? :)

Regards,
-Denis


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

* Re: [PATCH 8/9] fixme: add mte to the set ci su patch
  2018-12-19 16:24   ` Denis Kenzior
@ 2018-12-20  1:53     ` Andrew Zaborowski
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-20  1:53 UTC (permalink / raw)
  To: ell

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

Hi Denis,

On Wed, 19 Dec 2018 at 17:24, Denis Kenzior <denkenz@gmail.com> wrote:
> On 12/18/2018 06:57 PM, Andrew Zaborowski wrote:
> > ---
> >   ell/tls.c | 14 +++++++-------
> >   1 file changed, 7 insertions(+), 7 deletions(-)
> >
>
> ??? :)

Somehow I sent out a temporary commit that was supposed to go away in
the rebase, sorry.

Best regards

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

* Re: [PATCH 5/9] tls: Implement l_tls_set_version_range
  2018-12-19 16:22   ` Denis Kenzior
@ 2018-12-20  2:35     ` Andrew Zaborowski
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-20  2:35 UTC (permalink / raw)
  To: ell

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

HI Denis,

On Wed, 19 Dec 2018 at 17:22, Denis Kenzior <denkenz@gmail.com> wrote:
> On 12/18/2018 06:57 PM, Andrew Zaborowski wrote:
> > Allow user to set custom min and max TLS version limits, this can be
> > used to ensure we comply with a specific security profile.
> > ---
> >   ell/ell.sym       |  1 +
> >   ell/tls-private.h | 10 ++-----
> >   ell/tls-record.c  |  4 +--
> >   ell/tls.c         | 74 +++++++++++++++++++++++++++++++++++++----------
> >   ell/tls.h         | 11 ++++++-
> >   5 files changed, 73 insertions(+), 27 deletions(-)
> >
>
> <snip>
>
> > diff --git a/ell/tls-private.h b/ell/tls-private.h
> > index 0908b9c..e450ac2 100644
> > --- a/ell/tls-private.h
> > +++ b/ell/tls-private.h
> > @@ -20,14 +20,7 @@
> >    *
> >    */
> >
> > -enum l_tls_version {
> > -     L_TLS_V10 = ((3 << 8) | 1),
> > -     L_TLS_V11 = ((3 << 8) | 2),
> > -     L_TLS_V12 = ((3 << 8) | 3),
> > -     L_TLS_V13 = ((3 << 8) | 4),     /* Not supported */
> > -};
> > -
> > -#define TLS_VERSION  L_TLS_V12
> > +#define TLS_MAX_VERSION      L_TLS_V12
> >   #define TLS_MIN_VERSION     L_TLS_V10
>
> So we generally discourage #defines that are used only once.  Are you
> planning to use this outside l_tls_new?  This may also be relevant for
> TLS_MIN_VERSION since you are getting rid of many of its usages as well.

Other than l_tls_set_version_range no (although for 1.3 we potentially
may need to move it back to tls-private.h because version negotiation
happens in an extension)

>
> >
> >   enum tls_cipher_type {
> > @@ -147,6 +140,7 @@ struct l_tls {
> >       l_tls_debug_cb_t debug_handler;
> >       l_tls_destroy_cb_t debug_destroy;
> >       void *debug_data;
> > +     enum l_tls_version min_version, max_version;
>
> Separate lines please :)

Okay.

>
> >
> >       struct l_queue *ca_certs;
> >       struct l_certchain *cert;
>
> <snip>
>
> > @@ -393,7 +393,7 @@ static bool tls_handle_ciphertext(struct l_tls *tls)
> >
> >       if ((tls->negotiated_version && tls->negotiated_version != version) ||
> >                       (!tls->negotiated_version &&
> > -                      tls->record_buf[1] != 0x03 /* Appending E.1 */)) {
> > +                      tls->record_buf[1] != 0x03 /* Appendix E.1 */)) {
>
> Separate patch please
>
> >               TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0,
> >                               "Record version mismatch: %02x", version);
> >               return false;
>
> <snip>
>
> > @@ -589,10 +603,13 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
> >               return false;
> >       }
> >
> > -     if ((tls->negotiated_version && tls->negotiated_version < L_TLS_V12 &&
> > -                     (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
> > -                      !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
> > -                     (tls->negotiated_version >= L_TLS_V12 &&
> > +     if (
> > +                     ((tls->max_version < L_TLS_V12 ||
> > +                       (negotiated && negotiated < L_TLS_V12)) &&
>
> So the previous version of this only looked at the negotiated version,
> but this one also looks at the max version.  Should this function take
> the TLS version as an argument and let the caller figure out the policy?

So the idea here is that we can eliminate some suites before
negotiated_version is set but we're dealing with an interval so we
have a min and a max.  I guess we can simplify it locally (so as not
to complicate it for the callers) by setting min and max to either
tls->min/max_version or tls->negotiated_version.

>
> > +                      (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
> > +                       !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
> > +                     ((tls->min_version >= L_TLS_V12 ||
> > +                       negotiated >= L_TLS_V12) &&
> >                        !l_checksum_is_supported(
> >                                       suite->prf_hmac != L_CHECKSUM_NONE ?
> >                                       suite->prf_hmac : L_CHECKSUM_SHA256,
>
> Why is this indented so far to the right?

In an attempt to comply with coding-style.txt :) I'm going with the
editor's auto indent for the other lines where we have no specific
rules.

> But really, can we put this
> into a separate function and make this a bit more readable, maybe with a
> few comments?

Ok.

>
> > @@ -2751,6 +2781,18 @@ LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
> >       return true;
> >   }
> >
> > +LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
> > +                                     uint16_t min_version,
> > +                                     uint16_t max_version)
>
> Why uint16?
>
> > +{
> > +     tls->min_version =
> > +             (min_version && min_version > TLS_MIN_VERSION) ?
> > +             min_version : TLS_MIN_VERSION;
> > +     tls->max_version =
> > +             (max_version && max_version < TLS_MAX_VERSION) ?
> > +             max_version : TLS_MAX_VERSION;
>
> Yikes.  Again, why not use enums here and skip these checks?  If someone
> wants to pass arbitrary int values to this function, that is their problem.

Oops so I was determined to use enum l_tls_version for the parameters
but somehow screwed up a rebase I think.  Still I think these checks
are useful and we should accept possible other values.

With both l_tls_set_version_range and l_tls_set_cipher_suites I think
it's important that the caller does not have to worry about which
versions and suites we actually support internally.  They should be
able to say "for this instance the policy is ok with anything from SSL
2.0 to TLS 1.1 and such and such cipher suites" without diving into
our .c files.  On the other hand our code can trivially limit this to
the features that are actually usable so we don't end up negotiating a
version we don't support.

Best regards

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

* Re: [PATCH 3/9] tls: Add TLS version number printf macros
  2018-12-14 15:53   ` Denis Kenzior
@ 2018-12-14 18:48     ` Andrew Zaborowski
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-14 18:48 UTC (permalink / raw)
  To: ell

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

Hi Denis,

On Fri, 14 Dec 2018 at 16:53, Denis Kenzior <denkenz@gmail.com> wrote:
> On 12/13/2018 01:57 PM, Andrew Zaborowski wrote:
> > ---
> >   ell/tls-private.h |  3 +++
> >   ell/tls.c         | 17 +++++++++++------
> >   2 files changed, 14 insertions(+), 6 deletions(-)
> >
>
> ell/tls.c: In function ‘tls_cipher_suite_is_compatible’:
> ell/tls.c:540:34: error: ‘L_TLS_V12’ undeclared (first use in this
> function); did you mean ‘TLS_V12’?
>     if (negotiated && negotiated < L_TLS_V12) {
>                                    ^~~~~~~~~
>                                    TLS_V12
> ell/tls.c:540:34: note: each undeclared identifier is reported only once
> for each function it appears in
>
> I know we allow breaking compilation if unavoidable, but I think here
> this can be easily avoided.

Ah indeed, I try to not break compilation if possible, will fix this patch.

Best regards

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

* Re: [PATCH 3/9] tls: Add TLS version number printf macros
  2018-12-13 19:57 ` [PATCH 3/9] tls: Add TLS version number printf macros Andrew Zaborowski
@ 2018-12-14 15:53   ` Denis Kenzior
  2018-12-14 18:48     ` Andrew Zaborowski
  0 siblings, 1 reply; 17+ messages in thread
From: Denis Kenzior @ 2018-12-14 15:53 UTC (permalink / raw)
  To: ell

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

Hi Andrew,

On 12/13/2018 01:57 PM, Andrew Zaborowski wrote:
> ---
>   ell/tls-private.h |  3 +++
>   ell/tls.c         | 17 +++++++++++------
>   2 files changed, 14 insertions(+), 6 deletions(-)
> 

ell/tls.c: In function ‘tls_cipher_suite_is_compatible’:
ell/tls.c:540:34: error: ‘L_TLS_V12’ undeclared (first use in this 
function); did you mean ‘TLS_V12’?
    if (negotiated && negotiated < L_TLS_V12) {
                                   ^~~~~~~~~
                                   TLS_V12
ell/tls.c:540:34: note: each undeclared identifier is reported only once 
for each function it appears in

I know we allow breaking compilation if unavoidable, but I think here 
this can be easily avoided.

Can this patch be sent out of order prior to L_TLS_V refactoring and 
then fixed up there?

Regards,
-Denis

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

* [PATCH 3/9] tls: Add TLS version number printf macros
  2018-12-13 19:57 Andrew Zaborowski
@ 2018-12-13 19:57 ` Andrew Zaborowski
  2018-12-14 15:53   ` Denis Kenzior
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Zaborowski @ 2018-12-13 19:57 UTC (permalink / raw)
  To: ell

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

---
 ell/tls-private.h |  3 +++
 ell/tls.c         | 17 +++++++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/ell/tls-private.h b/ell/tls-private.h
index b6d1461..8e6c277 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -258,4 +258,7 @@ int tls_parse_certificate_list(const void *data, size_t len,
 		tls_disconnect(tls, desc, local_desc);	\
 	} while (0)
 
+#define TLS_VER_FMT		"1.%i"
+#define TLS_VER_ARGS(version)	((version & 0xff) - 1)
+
 const char *tls_handshake_state_to_str(enum tls_handshake_state state);
diff --git a/ell/tls.c b/ell/tls.c
index d05ae8d..8099e76 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -535,14 +535,17 @@ static bool tls_cipher_suite_is_compatible(struct l_tls *tls,
 
 	if (suite->encryption &&
 			suite->encryption->cipher_type == TLS_CIPHER_AEAD) {
-		if (tls->negotiated_version &&
-				tls->negotiated_version < TLS_V12) {
+		uint16_t negotiated = tls->negotiated_version;
+
+		if (negotiated && negotiated < L_TLS_V12) {
 			if (error) {
 				*error = error_buf;
 				snprintf(error_buf, sizeof(error_buf),
 						"Cipher suite %s uses an AEAD "
-						"cipher but TLS < 1.2 was "
-						"negotiated", suite->name);
+						"cipher (TLS 1.2+) but "
+						TLS_VER_FMT " was negotiated",
+						suite->name,
+						TLS_VER_ARGS(negotiated));
 			}
 
 			return false;
@@ -1587,7 +1590,8 @@ static void tls_handle_client_hello(struct l_tls *tls,
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
 
-	TLS_DEBUG("Negotiated TLS 1.%i", (tls->negotiated_version & 0xff) - 1);
+	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
+			TLS_VER_ARGS(tls->negotiated_version));
 
 	/* Select a cipher suite according to client's preference list */
 	while (cipher_suites_size) {
@@ -1715,7 +1719,8 @@ static void tls_handle_server_hello(struct l_tls *tls,
 			if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
 				tls_drop_handshake_hash(tls, i);
 
-	TLS_DEBUG("Negotiated TLS 1.%i", (tls->negotiated_version & 0xff) - 1);
+	TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
+			TLS_VER_ARGS(tls->negotiated_version));
 
 	/* Set the new cipher suite and compression method structs */
 	tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id);
-- 
2.19.1


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

end of thread, other threads:[~2018-12-20  2:35 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-19  0:57 [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 2/9] unit: Call l_tls_start in tls tests Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 3/9] tls: Add TLS version number printf macros Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 4/9] tls: Define and use an enum type for TLS versions Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 5/9] tls: Implement l_tls_set_version_range Andrew Zaborowski
2018-12-19 16:22   ` Denis Kenzior
2018-12-20  2:35     ` Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 6/9] unit: Test TLS 1.0, 1.1 and 1.2 Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 7/9] tls: Allow user to set custom list of cipher suites Andrew Zaborowski
2018-12-19  0:57 ` [PATCH 8/9] fixme: add mte to the set ci su patch Andrew Zaborowski
2018-12-19 16:24   ` Denis Kenzior
2018-12-20  1:53     ` Andrew Zaborowski
2018-12-19  0:58 ` [PATCH 9/9] unit: Test many TLS cipher suite and version combinations Andrew Zaborowski
2018-12-19 16:04 ` [PATCH 1/9] tls: Don't send Client Hello in l_tls_new Denis Kenzior
  -- strict thread matches above, loose matches on Subject: below --
2018-12-13 19:57 Andrew Zaborowski
2018-12-13 19:57 ` [PATCH 3/9] tls: Add TLS version number printf macros Andrew Zaborowski
2018-12-14 15:53   ` Denis Kenzior
2018-12-14 18:48     ` Andrew Zaborowski

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.