Merge branch 'master' into kazuho/session-ticket-context
diff --git a/include/picotls.h b/include/picotls.h
index 8af9da1..70abcf8 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -248,6 +248,7 @@
#define PTLS_ERROR_REJECT_EARLY_DATA (PTLS_ERROR_CLASS_INTERNAL + 9)
#define PTLS_ERROR_DELEGATE (PTLS_ERROR_CLASS_INTERNAL + 10)
#define PTLS_ERROR_ASYNC_OPERATION (PTLS_ERROR_CLASS_INTERNAL + 11)
+#define PTLS_ERROR_BLOCK_OVERFLOW (PTLS_ERROR_CLASS_INTERNAL + 12)
#define PTLS_ERROR_INCORRECT_BASE64 (PTLS_ERROR_CLASS_INTERNAL + 50)
#define PTLS_ERROR_PEM_LABEL_NOT_FOUND (PTLS_ERROR_CLASS_INTERNAL + 51)
@@ -919,8 +920,7 @@
*/
unsigned send_change_cipher_spec : 1;
/**
- * if set, the server requests client certificates
- * to authenticate the client.
+ * if set, the server requests client certificates to authenticate the client
*/
unsigned require_client_authentication : 1;
/**
@@ -988,6 +988,14 @@
uint8_t bytes[PTLS_SHA256_DIGEST_SIZE];
uint8_t is_set : 1;
} ticket_context;
+ /**
+ * (optional) list of CAs advertised to clients as supported in the CertificateRequest message; each item must be DNs in DER
+ * format. The values are sent to the client only when `ptls_context_t::require_client_authentication` is set to true.
+ */
+ struct {
+ const ptls_iovec_t *list;
+ size_t count;
+ } client_ca_names;
};
typedef struct st_ptls_raw_extension_t {
@@ -1210,6 +1218,10 @@
} while (0); \
size_t body_size = (buf)->off - body_start; \
if (capacity != -1) { \
+ if (capacity < sizeof(size_t) && body_size >= (size_t)1 << (capacity * 8)) { \
+ ret = PTLS_ERROR_BLOCK_OVERFLOW; \
+ goto Exit; \
+ } \
for (; capacity != 0; --capacity) \
(buf)->base[body_start - capacity] = (uint8_t)(body_size >> (8 * (capacity - 1))); \
} else { \
diff --git a/lib/picotls.c b/lib/picotls.c
index 9ba15c7..7f8fd9a 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -67,6 +67,7 @@
#define PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS 43
#define PTLS_EXTENSION_TYPE_COOKIE 44
#define PTLS_EXTENSION_TYPE_PSK_KEY_EXCHANGE_MODES 45
+#define PTLS_EXTENSION_TYPE_CERTIFICATE_AUTHORITIES 47
#define PTLS_EXTENSION_TYPE_KEY_SHARE 51
#define PTLS_EXTENSION_TYPE_ECH_OUTER_EXTENSIONS 0xfd00
#define PTLS_EXTENSION_TYPE_ENCRYPTED_CLIENT_HELLO 0xfe0d
@@ -4683,10 +4684,9 @@
/* send certificate request if client authentication is activated */
if (tls->ctx->require_client_authentication) {
ptls_push_message(emitter, tls->key_schedule, PTLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST, {
- /* certificate_request_context, this field SHALL be zero length, unless the certificate
- * request is used for post-handshake authentication.
- */
ptls_buffer_t *sendbuf = emitter->buf;
+ /* certificate_request_context: this field SHALL be zero length, unless the certificate request is used for post-
+ * handshake authentication. */
ptls_buffer_push(sendbuf, 0);
/* extensions */
ptls_buffer_push_block(sendbuf, 2, {
@@ -4694,6 +4694,19 @@
if ((ret = push_signature_algorithms(tls->ctx->verify_certificate, sendbuf)) != 0)
goto Exit;
});
+ /* certificate authorities entension */
+ if (tls->ctx->client_ca_names.count > 0) {
+ buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_CERTIFICATE_AUTHORITIES, {
+ ptls_buffer_push_block(sendbuf, 2, {
+ for (size_t i = 0; i != tls->ctx->client_ca_names.count; ++i) {
+ ptls_buffer_push_block(sendbuf, 2, {
+ ptls_iovec_t name = tls->ctx->client_ca_names.list[i];
+ ptls_buffer_pushv(sendbuf, name.base, name.len);
+ });
+ }
+ });
+ });
+ }
});
});
diff --git a/t/picotls.c b/t/picotls.c
index c82cc41..8bc5ab4 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -1901,6 +1901,60 @@
ctx->sign_certificate = second_sc_orig;
}
+static void do_test_tlsblock(size_t len_encoded, size_t max_bytes)
+{
+ ptls_buffer_t buf;
+ const uint8_t *src, *end;
+ int expect_overflow = 0, ret;
+
+ /* block that fits in */
+ ptls_buffer_init(&buf, "", 0);
+ ptls_buffer_push_block(&buf, len_encoded, {
+ for (size_t i = 0; i < max_bytes; ++i)
+ ptls_buffer_push(&buf, (uint8_t)i);
+ });
+ src = buf.base;
+ end = buf.base + buf.off;
+ ptls_decode_block(src, end, len_encoded, {
+ ok(end - src == max_bytes);
+ int bytes_eq = 1;
+ for (size_t i = 0; i < max_bytes; ++i) {
+ if (src[i] != (uint8_t)i)
+ bytes_eq = 0;
+ }
+ ok(bytes_eq);
+ src = end;
+ });
+
+ /* block that does not fit in */
+ ptls_buffer_push_block(&buf, len_encoded, {
+ for (size_t i = 0; i < max_bytes + 1; i++)
+ ptls_buffer_push(&buf, 1);
+ expect_overflow = 1;
+ });
+ ok(!"fail");
+
+Exit:
+ if (ret != 0) {
+ if (expect_overflow) {
+ ok(ret == PTLS_ERROR_BLOCK_OVERFLOW);
+ } else {
+ ok(!"fail");
+ }
+ }
+ ptls_buffer_dispose(&buf);
+}
+
+static void test_tlsblock8(void)
+{
+ do_test_tlsblock(1, 255);
+}
+
+static void test_tlsblock16(void)
+{
+ do_test_tlsblock(2, 65535);
+}
+
static void test_quicint(void)
{
#define CHECK_PATTERN(output, ...) \
@@ -2161,6 +2215,8 @@
subtest("chacha20", test_chacha20);
subtest("ffx", test_ffx);
subtest("base64-decode", test_base64_decode);
+ subtest("tls-block8", test_tlsblock8);
+ subtest("tls-block16", test_tlsblock16);
subtest("ech", test_ech);
subtest("fragmented-message", test_fragmented_message);
subtest("handshake", test_all_handshakes);