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>
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);
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)
mbedtls_x509_crt_free(&ctx->ca_cert);
mbedtls_x509_crt_free(&ctx->cert);
mbedtls_ssl_config_free(&ctx->conf);
+ free(ctx->ciphersuites);
free(ctx);
}
mbedtls_ssl_cache_context cache;
#endif
bool server;
+ int *ciphersuites;
};
static inline char *__ustream_ssl_strerror(int error, char *buffer, int len)
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);
return ret;
}
-
.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,
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;
#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