From f7f93addafb8a2a45c601d9cffe249eb6c73de23 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 15 Feb 2020 21:25:26 +0100 Subject: [PATCH] add support for specifying usable ciphers 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 --- 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 --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 -- 2.25.1