BearSSL: add CURLOPT_SSL_CIPHER_LIST support

Closes #8477
This commit is contained in:
Jan Venekamp 2021-12-06 18:36:03 +01:00 committed by Daniel Stenberg
parent 3055c4c814
commit f5d79619b1
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
4 changed files with 295 additions and 1 deletions

View file

@ -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;