Merge pull request #476 from robguima/robguima/chacha_priority_feature
Add support for chacha20 cipher prioritization
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..14ea227 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -1979,7 +1979,7 @@
}
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;
@@ -1990,7 +1990,7 @@
goto Exit;
for (size_t i = 0; candidates[i] != NULL; ++i) {
if (candidates[i]->id == id) {
- if (server_preference) {
+ if (server_preference && !(server_chacha_priority && id == PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256)) {
/* preserve smallest matching index, and proceed to the next input */
if (i < found_index) {
found_index = i;
@@ -2003,6 +2003,11 @@
}
}
}
+ /* first position of the server list matched (server_preference) */
+ if (found_index == 0)
+ break;
+ /* server preference is overridden only if the first entry of client-provided list is chachapoly */
+ server_chacha_priority = 0;
}
if (found_index != SIZE_MAX) {
*selected = candidates[found_index];
@@ -4353,7 +4358,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..6116de0 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -60,27 +60,71 @@
{
#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);
+ ok(select_cipher(&selected, candidates, input, input + sizeof(input), 0, 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);
+ }
+
+ {
+ ptls_cipher_suite_t *candidates[] = {&ptls_minicrypto_aes256gcmsha384, &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_aes256gcmsha384);
+ 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), 0, 1) == 0);
ok(selected == &ptls_minicrypto_aes128gcmsha256);
}