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