diff mbox series

[OpenWrt-Devel,ustream-ssl] add support for specifying usable ciphers

Message ID 20200215225453.1652552-1-jo@mein.io
State Under Review
Delegated to: Jo-Philipp Wich
Headers show
Series [OpenWrt-Devel,ustream-ssl] add support for specifying usable ciphers | expand

Commit Message

Jo-Philipp Wich Feb. 15, 2020, 10:54 p.m. UTC
Implement a new ustream_ssl_ops.context_set_ciphers() function which allows
to specify the usable ciphers for TLS context which is useful to restrict
the accepted cipher subset especially for ustream-ssl server applications.

For the OpenSSL backend, the given cipher string is passed as-is to the
SSL_CTX_set_cipher_list().

For mbedTLS, the given string is split on colons and each item of the list
is resolved through mbedtls_ssl_get_ciphersuite_id() to construct a numeric
list of allowed ciphers.

Note that OpenSSL and mbedTLS use different names for their ciphers but both
implementations simply ignore unknown names, so it is possible to specify
cipherstrings which are applicable to either library, e.g. `-ALL:ECDHE-
ECDSA-AES128-GCM-SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` would
enable ChaCha20/Poly1305 in both OpenSSL and mbedTLS.

Another crucial difference between the libraries is that the cipherstring
in mbedTLS is effectively a whitelist of allowed ciphers while, without
additional syntax elements, OpenSSL's cipherstring merely appends ciphers
to the default selection.

Ref: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_cipher_list.html
Ref: https://tls.mbed.org/api/ssl_8h.html#a9914cdf5533e813e1ea7ca52981aa006
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
---
 ustream-internal.h |  1 +
 ustream-mbedtls.c  | 66 ++++++++++++++++++++++++++++++++++++++++++++++
 ustream-mbedtls.h  |  1 +
 ustream-openssl.c  | 11 +++++++-
 ustream-ssl.c      |  1 +
 ustream-ssl.h      |  3 +++
 6 files changed, 82 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/ustream-internal.h b/ustream-internal.h
index 8d5d0db..147141a 100644
--- a/ustream-internal.h
+++ b/ustream-internal.h
@@ -38,6 +38,7 @@  struct ustream_ssl_ctx *__ustream_ssl_context_new(bool server);
 int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file);
 int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file);
 int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file);
+int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers);
 void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx);
 enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us);
 int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len);
diff --git a/ustream-mbedtls.c b/ustream-mbedtls.c
index 74c27a5..9f73c58 100644
--- a/ustream-mbedtls.c
+++ b/ustream-mbedtls.c
@@ -225,6 +225,71 @@  __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char
 	return 0;
 }
 
+__hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers)
+{
+	int *ciphersuites = NULL, *tmp, id;
+	char *cipherstr, *p, *last, c;
+	size_t len = 0;
+
+	if (ciphers == NULL)
+		return -1;
+
+	cipherstr = strdup(ciphers);
+
+	if (cipherstr == NULL)
+		return -1;
+
+	for (p = cipherstr, last = p;; p++) {
+		if (*p == ':' || *p == 0) {
+			c = *p;
+			*p = 0;
+
+			id = mbedtls_ssl_get_ciphersuite_id(last);
+
+			if (id != 0) {
+				tmp = realloc(ciphersuites, (len + 2) * sizeof(int));
+
+				if (tmp == NULL) {
+					free(ciphersuites);
+					free(cipherstr);
+
+					return -1;
+				}
+
+				ciphersuites = tmp;
+				ciphersuites[len++] = id;
+				ciphersuites[len] = 0;
+			}
+
+			if (c == 0)
+				break;
+
+			last = p + 1;
+		}
+
+		/*
+		 * mbedTLS expects cipher names with dashes while many sources elsewhere
+		 * like the Firefox wiki or Wireshark specify ciphers with underscores,
+		 * so simply convert all underscores to dashes to accept both notations.
+		 */
+		else if (*p == '_') {
+			*p = '-';
+		}
+	}
+
+	free(cipherstr);
+
+	if (len == 0)
+		return -1;
+
+	mbedtls_ssl_conf_ciphersuites(&ctx->conf, ciphersuites);
+	free(ctx->ciphersuites);
+
+	ctx->ciphersuites = ciphersuites;
+
+	return 0;
+}
+
 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
 {
 #if defined(MBEDTLS_SSL_CACHE_C)
@@ -234,6 +299,7 @@  __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
 	mbedtls_x509_crt_free(&ctx->ca_cert);
 	mbedtls_x509_crt_free(&ctx->cert);
 	mbedtls_ssl_config_free(&ctx->conf);
+	free(ctx->ciphersuites);
 	free(ctx);
 }
 
diff --git a/ustream-mbedtls.h b/ustream-mbedtls.h
index 0e5988a..e622e5e 100644
--- a/ustream-mbedtls.h
+++ b/ustream-mbedtls.h
@@ -41,6 +41,7 @@  struct ustream_ssl_ctx {
 	mbedtls_ssl_cache_context cache;
 #endif
 	bool server;
+	int *ciphersuites;
 };
 
 static inline char *__ustream_ssl_strerror(int error, char *buffer, int len)
diff --git a/ustream-openssl.c b/ustream-openssl.c
index 1469473..049aa40 100644
--- a/ustream-openssl.c
+++ b/ustream-openssl.c
@@ -190,6 +190,16 @@  __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char
 	return 0;
 }
 
+__hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers)
+{
+	int ret = SSL_CTX_set_cipher_list((void *) ctx, ciphers);
+
+	if (ret == 0)
+		return -1;
+
+	return 0;
+}
+
 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
 {
 	SSL_CTX_free((void *) ctx);
@@ -306,4 +316,3 @@  __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len)
 
 	return ret;
 }
-
diff --git a/ustream-ssl.c b/ustream-ssl.c
index 47f66d6..dbc3bee 100644
--- a/ustream-ssl.c
+++ b/ustream-ssl.c
@@ -231,6 +231,7 @@  const struct ustream_ssl_ops ustream_ssl_ops = {
 	.context_set_crt_file = __ustream_ssl_set_crt_file,
 	.context_set_key_file = __ustream_ssl_set_key_file,
 	.context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file,
+	.context_set_ciphers = __ustream_ssl_set_ciphers,
 	.context_free = __ustream_ssl_context_free,
 	.init = _ustream_ssl_init,
 	.set_peer_cn = _ustream_ssl_set_peer_cn,
diff --git a/ustream-ssl.h b/ustream-ssl.h
index 7787788..db89297 100644
--- a/ustream-ssl.h
+++ b/ustream-ssl.h
@@ -56,6 +56,8 @@  struct ustream_ssl_ops {
 
 	int (*init)(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server);
 	int (*set_peer_cn)(struct ustream_ssl *conn, const char *name);
+
+	int (*context_set_ciphers)(struct ustream_ssl_ctx *ctx, const char *ciphers);
 };
 
 extern const struct ustream_ssl_ops ustream_ssl_ops;
@@ -64,6 +66,7 @@  extern const struct ustream_ssl_ops ustream_ssl_ops;
 #define ustream_ssl_context_set_crt_file	ustream_ssl_ops.context_set_crt_file
 #define ustream_ssl_context_set_key_file	ustream_ssl_ops.context_set_key_file
 #define ustream_ssl_context_add_ca_crt_file	ustream_ssl_ops.context_add_ca_crt_file
+#define ustream_ssl_context_set_ciphers		ustream_ssl_ops.context_set_ciphers
 #define ustream_ssl_context_free		ustream_ssl_ops.context_free
 #define ustream_ssl_init			ustream_ssl_ops.init
 #define ustream_ssl_set_peer_cn			ustream_ssl_ops.set_peer_cn