summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Venekamp <1422460+jan2000@users.noreply.github.com>2021-12-06 18:36:03 +0100
committerDaniel Stenberg <daniel@haxx.se>2022-03-12 22:59:45 +0100
commitf5d79619b109d7181c266d8d1f50a3ca729b97aa (patch)
tree6e1b0137f7146e222aedef7c09f41142ebbc8575
parent3055c4c814e5ea5dfebe41bd827456c8ade12958 (diff)
downloadcurl-f5d79619b109d7181c266d8d1f50a3ca729b97aa.tar.gz
BearSSL: add CURLOPT_SSL_CIPHER_LIST support
Closes #8477
-rw-r--r--docs/CIPHERS.md58
-rw-r--r--docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.39
-rw-r--r--docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.39
-rw-r--r--lib/vtls/bearssl.c220
4 files changed, 295 insertions, 1 deletions
diff --git a/docs/CIPHERS.md b/docs/CIPHERS.md
index ad5b56091..e1df7642c 100644
--- a/docs/CIPHERS.md
+++ b/docs/CIPHERS.md
@@ -520,3 +520,61 @@ to [constrain the set of available ciphers as specified in the schannel
documentation](https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022).
Note that the supported ciphers in this case follow the OS version, so if you
are running an outdated OS you might still be supporting weak ciphers.
+
+## BearSSL
+
+BearSSL ciphers can be specified by either the OpenSSL name (`ECDHE-RSA-AES128-GCM-SHA256`) or the IANA name (`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`).
+
+Since BearSSL 0.1:
+
+`DES-CBC3-SHA`
+`AES128-SHA`
+`AES256-SHA`
+`AES128-SHA256`
+`AES256-SHA256`
+`AES128-GCM-SHA256`
+`AES256-GCM-SHA384`
+`ECDH-ECDSA-DES-CBC3-SHA`
+`ECDH-ECDSA-AES128-SHA`
+`ECDH-ECDSA-AES256-SHA`
+`ECDHE-ECDSA-DES-CBC3-SHA`
+`ECDHE-ECDSA-AES128-SHA`
+`ECDHE-ECDSA-AES256-SHA`
+`ECDH-RSA-DES-CBC3-SHA`
+`ECDH-RSA-AES128-SHA`
+`ECDH-RSA-AES256-SHA`
+`ECDHE-RSA-DES-CBC3-SHA`
+`ECDHE-RSA-AES128-SHA`
+`ECDHE-RSA-AES256-SHA`
+`ECDHE-ECDSA-AES128-SHA256`
+`ECDHE-ECDSA-AES256-SHA384`
+`ECDH-ECDSA-AES128-SHA256`
+`ECDH-ECDSA-AES256-SHA384`
+`ECDHE-RSA-AES128-SHA256`
+`ECDHE-RSA-AES256-SHA384`
+`ECDH-RSA-AES128-SHA256`
+`ECDH-RSA-AES256-SHA384`
+`ECDHE-ECDSA-AES128-GCM-SHA256`
+`ECDHE-ECDSA-AES256-GCM-SHA384`
+`ECDH-ECDSA-AES128-GCM-SHA256`
+`ECDH-ECDSA-AES256-GCM-SHA384`
+`ECDHE-RSA-AES128-GCM-SHA256`
+`ECDHE-RSA-AES256-GCM-SHA384`
+`ECDH-RSA-AES128-GCM-SHA256`
+`ECDH-RSA-AES256-GCM-SHA384`
+
+Since BearSSL 0.2:
+
+`ECDHE-RSA-CHACHA20-POLY1305`
+`ECDHE-ECDSA-CHACHA20-POLY1305`
+
+Since BearSSL 0.6:
+
+`AES128-CCM`
+`AES256-CCM`
+`AES128-CCM8`
+`AES256-CCM8`
+`ECDHE-ECDSA-AES128-CCM`
+`ECDHE-ECDSA-AES256-CCM`
+`ECDHE-ECDSA-AES128-CCM8`
+`ECDHE-ECDSA-AES256-CCM8`
diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3
index 6c1f754db..c5e10396b 100644
--- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3
+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3
@@ -49,6 +49,13 @@ enabled.
For WolfSSL, valid examples of cipher lists include \fBECDHE-RSA-RC4-SHA\fP,
\fBAES256-SHA:AES256-SHA256\fP, etc.
+For BearSSL, valid examples of cipher lists include
+\fBECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256\fP, or when using IANA names
+\fBTLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\fP,
+etc.
+With BearSSL you do not add/remove ciphers. If one uses this option then all
+known ciphers are disabled and only those passed in are enabled.
+
you will find more details about cipher lists on this URL:
https://curl.se/docs/ssl-ciphers.html
@@ -71,7 +78,7 @@ if(curl) {
}
.fi
.SH AVAILABILITY
-Added in 7.52.0
+Added in 7.52.0, in 7.83.0 for BearSSL
If built TLS enabled.
.SH RETURN VALUE
diff --git a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3 b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3
index 0b1c61f40..90ee684a3 100644
--- a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3
+++ b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3
@@ -48,6 +48,13 @@ enabled.
For WolfSSL, valid examples of cipher lists include \fBECDHE-RSA-RC4-SHA\fP,
\fBAES256-SHA:AES256-SHA256\fP, etc.
+For BearSSL, valid examples of cipher lists include
+\fBECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256\fP, or when using IANA names
+\fBTLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\fP,
+etc.
+With BearSSL you do not add/remove ciphers. If one uses this option then all
+known ciphers are disabled and only those passed in are enabled.
+
you will find more details about cipher lists on this URL:
https://curl.se/docs/ssl-ciphers.html
@@ -69,6 +76,8 @@ if(curl) {
}
.fi
.SH AVAILABILITY
+Added in 7.9, in 7.83.0 for BearSSL
+
If built TLS enabled.
.SH RETURN VALUE
Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 77e22cf3e..c06f85bdf 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -35,6 +35,7 @@
#include "multiif.h"
#include "curl_printf.h"
#include "curl_memory.h"
+#include "strcase.h"
struct x509_context {
const br_x509_class *vtable;
@@ -353,6 +354,216 @@ static const br_x509_class x509_vtable = {
x509_get_pkey
};
+struct st_cipher {
+ const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+ const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+ uint16_t num; /* BearSSL cipher suite */
+};
+
+/* Macro to initialize st_cipher data structure */
+#define CIPHER_DEF(num, alias) { #num, alias, BR_##num }
+
+static const struct st_cipher ciphertable[] = {
+ /* RFC 2246 TLS 1.0 */
+ CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ "DES-CBC3-SHA"),
+
+ /* RFC 3268 TLS 1.0 AES */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ "AES128-SHA"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+ "AES256-SHA"),
+
+ /* RFC 5246 TLS 1.2 */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ "AES128-SHA256"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ "AES256-SHA256"),
+
+ /* RFC 5288 TLS 1.2 AES GCM */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ "AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ "AES256-GCM-SHA384"),
+
+ /* RFC 4492 TLS 1.0 ECC */
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ "ECDH-ECDSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ "ECDH-ECDSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ "ECDH-ECDSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ "ECDHE-ECDSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ "ECDHE-ECDSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ "ECDHE-ECDSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ "ECDH-RSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ "ECDH-RSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ "ECDH-RSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ "ECDHE-RSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ "ECDHE-RSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ "ECDHE-RSA-AES256-SHA"),
+
+ /* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ "ECDHE-ECDSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ "ECDHE-ECDSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ "ECDH-ECDSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ "ECDH-ECDSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ "ECDHE-RSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ "ECDHE-RSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ "ECDH-RSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
+ "ECDH-RSA-AES256-SHA384"),
+
+ /* RFC 5289 TLS 1.2 GCM */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ "ECDHE-ECDSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ "ECDHE-ECDSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ "ECDH-ECDSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ "ECDH-ECDSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ "ECDHE-RSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ "ECDHE-RSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ "ECDH-RSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+ "ECDH-RSA-AES256-GCM-SHA384"),
+#ifdef BR_TLS_RSA_WITH_AES_128_CCM
+
+ /* RFC 6655 TLS 1.2 CCM
+ Supported since BearSSL 0.6 */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
+ "AES128-CCM"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
+ "AES256-CCM"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
+ "AES128-CCM8"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
+ "AES256-CCM8"),
+
+ /* RFC 7251 TLS 1.2 ECC CCM
+ Supported since BearSSL 0.6 */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
+ "ECDHE-ECDSA-AES128-CCM"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
+ "ECDHE-ECDSA-AES256-CCM"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
+ "ECDHE-ECDSA-AES128-CCM8"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
+ "ECDHE-ECDSA-AES256-CCM8"),
+#endif
+
+ /* RFC 7905 TLS 1.2 ChaCha20-Poly1305
+ Supported since BearSSL 0.2 */
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ "ECDHE-RSA-CHACHA20-POLY1305"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+ "ECDHE-ECDSA-CHACHA20-POLY1305"),
+};
+
+#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
+#define CIPHER_NAME_BUF_LEN 64
+
+static bool is_separator(char c)
+{
+ /* Return whether character is a cipher list separator. */
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ }
+ return false;
+}
+
+static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
+ br_ssl_engine_context *ssl_eng,
+ const char *ciphers)
+{
+ uint16_t selected_ciphers[NUM_OF_CIPHERS];
+ size_t selected_count = 0;
+ char cipher_name[CIPHER_NAME_BUF_LEN];
+ const char *cipher_start = ciphers;
+ const char *cipher_end;
+ size_t i, j;
+
+ if(!cipher_start)
+ return CURLE_SSL_CIPHER;
+
+ while(true) {
+ /* Extract the next cipher name from the ciphers string */
+ while(is_separator(*cipher_start))
+ ++cipher_start;
+ if(*cipher_start == '\0')
+ break;
+ cipher_end = cipher_start;
+ while(*cipher_end != '\0' && !is_separator(*cipher_end))
+ ++cipher_end;
+ j = cipher_end - cipher_start < CIPHER_NAME_BUF_LEN - 1 ?
+ cipher_end - cipher_start : CIPHER_NAME_BUF_LEN - 1;
+ strncpy(cipher_name, cipher_start, j);
+ cipher_name[j] = '\0';
+ cipher_start = cipher_end;
+
+ /* Lookup the cipher name in the table of available ciphers. If the cipher
+ name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try
+ to match cipher name by an (OpenSSL) alias. */
+ if(strncasecompare(cipher_name, "TLS_", 4)) {
+ for(i = 0; i < NUM_OF_CIPHERS &&
+ !strcasecompare(cipher_name, ciphertable[i].name); ++i);
+ }
+ else {
+ for(i = 0; i < NUM_OF_CIPHERS &&
+ !strcasecompare(cipher_name, ciphertable[i].alias_name); ++i);
+ }
+ if(i == NUM_OF_CIPHERS) {
+ infof(data, "BearSSL: unknown cipher in list: %s", cipher_name);
+ continue;
+ }
+
+ /* No duplicates allowed */
+ for(j = 0; j < selected_count &&
+ selected_ciphers[j] != ciphertable[i].num; j++);
+ if(j < selected_count) {
+ infof(data, "BearSSL: duplicate cipher in list: %s", cipher_name);
+ continue;
+ }
+
+ DEBUGASSERT(selected_count < NUM_OF_CIPHERS);
+ selected_ciphers[selected_count] = ciphertable[i].num;
+ ++selected_count;
+ }
+
+ if(selected_count == 0) {
+ failf(data, "BearSSL: no supported cipher in list");
+ return CURLE_SSL_CIPHER;
+ }
+
+ br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count);
+ return CURLE_OK;
+}
+
static CURLcode bearssl_connect_step1(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
{
@@ -446,6 +657,15 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
sizeof(backend->buf), 1);
+ if(SSL_CONN_CONFIG(cipher_list)) {
+ /* Override the ciphers as specified. For the default cipher list see the
+ BearSSL source code of br_ssl_client_init_full() */
+ ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
+ SSL_CONN_CONFIG(cipher_list));
+ if(ret)
+ return ret;
+ }
+
/* initialize X.509 context */
backend->x509.vtable = &x509_vtable;
backend->x509.verifypeer = verifypeer;