add a new boolean flag to determine if chacha20 should be reprioritized to the top of the server cipher list in case it happens to appear at the top of the client cipher list
diff --git a/include/picotls.h b/include/picotls.h
index 0cadb17..0ad6f87 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -870,6 +870,11 @@
*/
unsigned server_cipher_preference : 1;
/**
+ * boolean indicating if ChaCha20-Poly1305 should be reprioritized to the top of the server cipher list if a ChaCha20-Poly1305
+ * cipher is at the top of the client cipher list
+ */
+ unsigned server_cipher_chacha_priority : 1;
+ /**
*
*/
ptls_encrypt_ticket_t *encrypt_ticket;
diff --git a/lib/picotls.c b/lib/picotls.c
index a172289..d07fa79 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -1979,16 +1979,27 @@
}
static int select_cipher(ptls_cipher_suite_t **selected, ptls_cipher_suite_t **candidates, const uint8_t *src,
- const uint8_t *const end, int server_preference)
+ const uint8_t *const end, int server_preference, int server_chacha_priority)
{
size_t found_index = SIZE_MAX;
int ret;
+ int is_first_cipher = 1;
while (src != end) {
uint16_t id;
if ((ret = ptls_decode16(&id, &src, end)) != 0)
goto Exit;
+ if (is_first_cipher && server_chacha_priority) {
+ if (id != PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256)
+ server_chacha_priority = 0;
+ is_first_cipher = 0;
+ }
for (size_t i = 0; candidates[i] != NULL; ++i) {
+ if (server_chacha_priority && candidates[i]->id == PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256) {
+ /* return the pointer matching chacha20 cipher found in the server list */
+ *selected = candidates[i];
+ goto Exit;
+ }
if (candidates[i]->id == id) {
if (server_preference) {
/* preserve smallest matching index, and proceed to the next input */
@@ -2003,6 +2014,9 @@
}
}
}
+ /* first position of the server list matched (server_preference) */
+ if (found_index == 0)
+ break;
}
if (found_index != SIZE_MAX) {
*selected = candidates[found_index];
@@ -4353,7 +4367,7 @@
{ /* select (or check) cipher-suite, create key_schedule */
ptls_cipher_suite_t *cs;
if ((ret = select_cipher(&cs, tls->ctx->cipher_suites, ch->cipher_suites.base,
- ch->cipher_suites.base + ch->cipher_suites.len, tls->ctx->server_cipher_preference)) != 0)
+ ch->cipher_suites.base + ch->cipher_suites.len, tls->ctx->server_cipher_preference, tls->ctx->server_cipher_chacha_priority)) != 0)
goto Exit;
if (!is_second_flight) {
tls->cipher_suite = cs;
diff --git a/t/picotls.c b/t/picotls.c
index b81f835..467ea20 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -60,30 +60,59 @@
{
#define C(x) ((x) >> 8) & 0xff, (x)&0xff
- ptls_cipher_suite_t *selected,
- *candidates[] = {&ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
+ ptls_cipher_suite_t *selected;
{
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
static const uint8_t input; /* `input[0]` is preferable, but prohibited by MSVC */
- ok(select_cipher(&selected, candidates, &input, &input, 0) == PTLS_ALERT_HANDSHAKE_FAILURE);
+ ok(select_cipher(&selected, candidates, &input, &input, 0, 0) == PTLS_ALERT_HANDSHAKE_FAILURE);
}
{
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
static const uint8_t input[] = {C(PTLS_CIPHER_SUITE_AES_128_GCM_SHA256), C(PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256)};
- ok(select_cipher(&selected, candidates, input, input + sizeof(input), 0) == 0);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 0, 0) == 0);
ok(selected == &ptls_minicrypto_aes128gcmsha256);
- ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1) == 0);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 0) == 0);
ok(selected == &ptls_minicrypto_chacha20poly1305sha256);
}
{
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
static const uint8_t input[] = {C(PTLS_CIPHER_SUITE_AES_256_GCM_SHA384), C(PTLS_CIPHER_SUITE_AES_128_GCM_SHA256)};
- ok(select_cipher(&selected, candidates, input, input + sizeof(input), 0) == 0);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 0, 0) == 0);
ok(selected == &ptls_minicrypto_aes128gcmsha256);
- ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1) == 0);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 0) == 0);
ok(selected == &ptls_minicrypto_aes128gcmsha256);
}
+ {
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_aes128gcmsha256, &ptls_minicrypto_aes256gcmsha384, &ptls_minicrypto_chacha20poly1305sha256, NULL};
+ static const uint8_t input[] = {C(PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256), C(PTLS_CIPHER_SUITE_AES_128_GCM_SHA256)};
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 0) == 0);
+ ok(selected == &ptls_minicrypto_aes128gcmsha256);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 1) == 0);
+ ok(selected == &ptls_minicrypto_chacha20poly1305sha256);
+ }
+
+ {
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_aes256gcmsha384, &ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
+ static const uint8_t input[] = {C(PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256), C(PTLS_CIPHER_SUITE_AES_128_GCM_SHA256), C(PTLS_CIPHER_SUITE_AES_256_GCM_SHA384)};
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 0) == 0);
+ ok(selected == &ptls_minicrypto_aes256gcmsha384);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 1) == 0);
+ ok(selected == &ptls_minicrypto_chacha20poly1305sha256);
+ }
+
+ {
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_aes256gcmsha384, &ptls_minicrypto_chacha20poly1305sha256, &ptls_minicrypto_aes128gcmsha256, NULL};
+ static const uint8_t input[] = {C(PTLS_CIPHER_SUITE_AES_128_GCM_SHA256), C(PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256), C(PTLS_CIPHER_SUITE_AES_256_GCM_SHA384)};
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 1) == 0);
+ ok(selected == &ptls_minicrypto_aes256gcmsha384);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 1, 1) == 0);
+ ok(selected == &ptls_minicrypto_aes256gcmsha384);
+ }
+
#undef C
}