summaryrefslogtreecommitdiffstats
path: root/debian/vendor-h2o/deps/picotls/lib
diff options
context:
space:
mode:
Diffstat (limited to 'debian/vendor-h2o/deps/picotls/lib')
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/asn1.c295
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/cifra.c530
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/minicrypto-pem.c339
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/openssl.c1066
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/pembase64.c373
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/picotls.c3761
-rw-r--r--debian/vendor-h2o/deps/picotls/lib/uecc.c190
7 files changed, 0 insertions, 6554 deletions
diff --git a/debian/vendor-h2o/deps/picotls/lib/asn1.c b/debian/vendor-h2o/deps/picotls/lib/asn1.c
deleted file mode 100644
index 4422bed..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/asn1.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-* Copyright (c) 2016 Christian Huitema <huitema@huitema.net>
-*
-* Permission to use, copy, modify, and distribute this software for any
-* purpose with or without fee is hereby granted, provided that the above
-* copyright notice and this permission notice appear in all copies.
-*
-* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-/*
-* Basic ASN1 validation and optional print-out
-*/
-
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "picotls.h"
-#include "picotls/minicrypto.h"
-#include "picotls/asn1.h"
-
-static char const *asn1_type_classes[4] = {"Universal", "Application", "Context-specific", "Private"};
-
-static char const *asn1_universal_types[] = {
- "End-of-Content", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", "NULL",
- "OBJECT IDENTIFIER", "Object Descriptor", "EXTERNAL", "REAL", "ENUMERATED", "EMBEDDED PDV",
- "UTF8String", "RELATIVE-OID", "Reserved (16)", "Reserved (17)", "SEQUENCE", "SET",
- "NumericString", "PrintableString", "T61String", "VideotexString", "IA5String", "UTCTime",
- "GeneralizedTime", "GraphicString", "VisibleString", "GeneralString", "UniversalString", "CHARACTER STRING",
- "BMPString"};
-
-static size_t nb_asn1_universal_types = sizeof(asn1_universal_types) / sizeof(char const *);
-
-static void ptls_asn1_print_indent(int level, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- for (int indent = 0; indent <= level; indent++) {
- log_ctx->fn(log_ctx->ctx, " ");
- }
-}
-
-size_t ptls_asn1_error_message(char const *error_label, size_t bytes_max, size_t byte_index, int level,
- ptls_minicrypto_log_ctx_t *log_ctx)
-{
- if (log_ctx != NULL) {
- ptls_asn1_print_indent(level, log_ctx);
- log_ctx->fn(log_ctx->ctx, "Error: %s (near position: %d (0x%x) out of %d)", error_label, (int)byte_index,
- (uint32_t)byte_index, (int)bytes_max);
- }
- return byte_index;
-}
-
-void ptls_asn1_dump_content(const uint8_t *bytes, size_t bytes_max, size_t byte_index, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- if (log_ctx != NULL && bytes_max > byte_index) {
- size_t nb_bytes = bytes_max - byte_index;
-
- log_ctx->fn(log_ctx->ctx, " ");
-
- for (size_t i = 0; i < 16 && i < nb_bytes; i++) {
- log_ctx->fn(log_ctx->ctx, "%02x", bytes[byte_index + i]);
- }
-
- if (nb_bytes > 16) {
- log_ctx->fn(log_ctx->ctx, "...");
- }
- }
-}
-
-size_t ptls_asn1_read_type(const uint8_t *bytes, size_t bytes_max, int *structure_bit, int *type_class, uint32_t *type_number,
- int *decode_error, int level, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- /* Get the type byte */
- size_t byte_index = 1;
- uint8_t first_byte = bytes[0];
- *structure_bit = (first_byte >> 5) & 1;
- *type_class = (first_byte >> 6) & 3;
- *type_number = first_byte & 31;
-
- if (*type_number == 31) {
- uint32_t long_type = 0;
- const uint32_t type_number_limit = 0x07FFFFFFF;
- int next_byte;
- int end_found = 0;
-
- while (byte_index < bytes_max && long_type <= type_number_limit) {
- next_byte = bytes[byte_index++];
- long_type <<= 7;
- long_type |= next_byte & 127;
- if ((next_byte & 128) == 0) {
- end_found = 1;
- break;
- }
- }
-
- if (end_found) {
- *type_number = long_type;
- } else {
- /* This is an error */
- byte_index = ptls_asn1_error_message("Incorrect type coding", bytes_max, byte_index, level, log_ctx);
- *decode_error = PTLS_ERROR_BER_MALFORMED_TYPE;
- }
- }
-
- return byte_index;
-}
-
-void ptls_asn1_print_type(int type_class, uint32_t type_number, int level, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- /* Print the type */
- ptls_asn1_print_indent(level, log_ctx);
- if (type_class == 0 && type_number < nb_asn1_universal_types) {
- log_ctx->fn(log_ctx->ctx, "%s", asn1_universal_types[type_number]);
- } else if (type_class == 2) {
- log_ctx->fn(log_ctx->ctx, "[%d]", type_number);
- } else {
- log_ctx->fn(log_ctx->ctx, "%s[%d]", asn1_type_classes[type_class], type_number);
- }
-}
-
-size_t ptls_asn1_read_length(const uint8_t *bytes, size_t bytes_max, size_t byte_index, uint32_t *length, int *indefinite_length,
- size_t *last_byte, int *decode_error, int level, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- int length_of_length = 0;
-
- *indefinite_length = 0;
- *length = 0;
- *last_byte = bytes_max;
-
- if (byte_index < bytes_max) {
- *length = bytes[byte_index++];
- if ((*length & 128) != 0) {
- length_of_length = *length & 127;
- *length = 0;
-
- if (byte_index + length_of_length >= bytes_max) {
- /* This is an error */
- byte_index = ptls_asn1_error_message("Incorrect length coding", bytes_max, byte_index, level, log_ctx);
- *decode_error = PTLS_ERROR_BER_MALFORMED_LENGTH;
- } else {
- for (int i = 0; i < length_of_length && byte_index < bytes_max; i++) {
- *length <<= 8;
- *length |= bytes[byte_index++];
- }
-
- if (length_of_length == 0) {
- *last_byte = bytes_max;
- *indefinite_length = 1;
- } else {
- *last_byte = byte_index + *length;
- }
- }
- } else {
- *last_byte = byte_index + *length;
- }
-
- if (*decode_error == 0) {
- /* TODO: verify that the length makes sense */
- if (*last_byte > bytes_max) {
- byte_index = ptls_asn1_error_message("Length larger than message", bytes_max, byte_index, level, log_ctx);
- *decode_error = PTLS_ERROR_BER_EXCESSIVE_LENGTH;
- }
- }
- }
-
- return byte_index;
-}
-
-size_t ptls_asn1_get_expected_type_and_length(const uint8_t *bytes, size_t bytes_max, size_t byte_index, uint8_t expected_type,
- uint32_t *length, int *indefinite_length, size_t *last_byte, int *decode_error,
- ptls_minicrypto_log_ctx_t *log_ctx)
-{
- int is_indefinite = 0;
-
- /* Check that the expected type is present */
- if (bytes[byte_index] != expected_type) {
- byte_index = ptls_asn1_error_message("Unexpected type", bytes_max, byte_index, 0, log_ctx);
- *decode_error = PTLS_ERROR_INCORRECT_ASN1_SYNTAX;
- } else {
- /* get length of element */
- byte_index++;
- byte_index =
- ptls_asn1_read_length(bytes, bytes_max, byte_index, length, &is_indefinite, last_byte, decode_error, 0, log_ctx);
-
- if (indefinite_length != NULL) {
- *indefinite_length = is_indefinite;
- } else if (is_indefinite) {
- byte_index = ptls_asn1_error_message("Incorrect length for DER", bytes_max, byte_index, 0, log_ctx);
- *decode_error = PTLS_ERROR_DER_INDEFINITE_LENGTH;
- }
- }
-
- return byte_index;
-}
-
-size_t ptls_asn1_validation_recursive(const uint8_t *bytes, size_t bytes_max, int *decode_error, int level,
- ptls_minicrypto_log_ctx_t *log_ctx)
-{
- /* Get the type byte */
- int structure_bit = 0;
- int type_class = 0;
- uint32_t type_number = 0;
- uint32_t length = 0;
- int indefinite_length = 0;
- size_t last_byte = 0;
- /* Decode the type */
- size_t byte_index =
- ptls_asn1_read_type(bytes, bytes_max, &structure_bit, &type_class, &type_number, decode_error, level, log_ctx);
-
- if (*decode_error == 0 && log_ctx != NULL) {
- ptls_asn1_print_type(type_class, type_number, level, log_ctx);
- }
-
- /* Get the length */
- byte_index =
- ptls_asn1_read_length(bytes, bytes_max, byte_index, &length, &indefinite_length, &last_byte, decode_error, level, log_ctx);
-
- if (last_byte <= bytes_max) {
- if (structure_bit) {
- /* If structured, recurse on a loop */
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, " {\n");
- }
-
- while (byte_index < last_byte) {
- if (indefinite_length != 0 && bytes[byte_index] == 0) {
- if (byte_index + 2 > bytes_max || bytes[byte_index + 1] != 0) {
- byte_index =
- ptls_asn1_error_message("EOC: unexpected end of content", bytes_max, byte_index, level + 1, log_ctx);
-
- *decode_error = PTLS_ERROR_BER_UNEXPECTED_EOC;
- } else {
- if (log_ctx != NULL) {
- ptls_asn1_print_indent(level, log_ctx);
- log_ctx->fn(log_ctx->ctx, "EOC\n");
- }
- byte_index += 2;
- break;
- }
- } else {
- byte_index += ptls_asn1_validation_recursive(bytes + byte_index, last_byte - byte_index, decode_error,
- level + 1, log_ctx);
-
- if (*decode_error) {
- byte_index = bytes_max;
- break;
- }
- }
-
- if (log_ctx != NULL) {
- if (byte_index < last_byte) {
- log_ctx->fn(log_ctx->ctx, ",");
- }
- log_ctx->fn(log_ctx->ctx, "\n");
- }
- }
-
- if (log_ctx != NULL) {
- ptls_asn1_print_indent(level, log_ctx);
- log_ctx->fn(log_ctx->ctx, "}");
- }
- } else {
- ptls_asn1_dump_content(bytes, last_byte, byte_index, log_ctx);
- byte_index = last_byte;
- }
- }
-
- return byte_index;
-}
-
-int ptls_asn1_validation(const uint8_t *bytes, size_t length, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- int decode_error = 0;
- size_t decoded = ptls_asn1_validation_recursive(bytes, length, &decode_error, 0, log_ctx);
-
- if (decode_error == 0 && decoded < length) {
- decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT;
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "Type too short, %d bytes only out of %d\n", (int)decoded, (int)length);
- }
- }
-
- return decode_error;
-}
diff --git a/debian/vendor-h2o/deps/picotls/lib/cifra.c b/debian/vendor-h2o/deps/picotls/lib/cifra.c
deleted file mode 100644
index af33c33..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/cifra.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 700 /* required for glibc to use getaddrinfo, etc. */
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <unistd.h>
-#endif
-#include "aes.h"
-#include "bitops.h"
-#include "drbg.h"
-#include "curve25519.h"
-#include "../deps/cifra/src/ext/handy.h"
-#include "modes.h"
-#include "poly1305.h"
-#include "salsa20.h"
-#include "sha2.h"
-#include "picotls.h"
-#include "picotls/minicrypto.h"
-
-#ifdef _WINDOWS
-#include <wincrypt.h>
-static void read_entropy(uint8_t *entropy, size_t size)
-{
- HCRYPTPROV hCryptProv = 0;
- BOOL ret = FALSE;
-
- if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
- ret = CryptGenRandom(hCryptProv, (DWORD)size, entropy);
- (void)CryptReleaseContext(hCryptProv, 0);
- }
-
- if (ret == FALSE) {
- abort();
- }
-}
-#else
-static void read_entropy(uint8_t *entropy, size_t size)
-{
- int fd;
-
- if ((fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) == -1) {
- if ((fd = open("/dev/random", O_RDONLY | O_CLOEXEC)) == -1) {
- perror("ptls_minicrypto_random_bytes: could not open neither /dev/random or /dev/urandom");
- abort();
- }
- }
-
- while (size != 0) {
- ssize_t rret;
- while ((rret = read(fd, entropy, size)) == -1 && errno == EINTR)
- ;
- if (rret < 0) {
- perror("ptls_minicrypto_random_bytes");
- abort();
- }
- entropy += rret;
- size -= rret;
- }
-
- close(fd);
-}
-#endif
-
-void ptls_minicrypto_random_bytes(void *buf, size_t len)
-{
-#ifdef _WINDOWS
- static __declspec(thread) cf_hash_drbg_sha256 ctx;
-#else
- static __thread cf_hash_drbg_sha256 ctx;
-#endif
-
- if (cf_hash_drbg_sha256_needs_reseed(&ctx)) {
- uint8_t entropy[256];
- read_entropy(entropy, sizeof(entropy));
- cf_hash_drbg_sha256_init(&ctx, entropy, sizeof(entropy) / 2, entropy + sizeof(entropy) / 2, sizeof(entropy) / 2, "ptls", 4);
- }
- cf_hash_drbg_sha256_gen(&ctx, buf, len);
-}
-
-#define X25519_KEY_SIZE 32
-
-struct st_x25519_key_exchange_t {
- ptls_key_exchange_context_t super;
- uint8_t priv[X25519_KEY_SIZE];
- uint8_t pub[X25519_KEY_SIZE];
-};
-
-static void x25519_create_keypair(uint8_t *priv, uint8_t *pub)
-{
- ptls_minicrypto_random_bytes(priv, X25519_KEY_SIZE);
- cf_curve25519_mul_base(pub, priv);
-}
-
-static int x25519_derive_secret(ptls_iovec_t *secret, const uint8_t *clientpriv, const uint8_t *clientpub,
- const uint8_t *serverpriv, const uint8_t *serverpub)
-{
- if ((secret->base = malloc(X25519_KEY_SIZE)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
-
- cf_curve25519_mul(secret->base, clientpriv != NULL ? clientpriv : serverpriv, clientpriv != NULL ? serverpub : clientpub);
- secret->len = X25519_KEY_SIZE;
- return 0;
-}
-
-static int x25519_on_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- struct st_x25519_key_exchange_t *ctx = (struct st_x25519_key_exchange_t *)*_ctx;
- int ret;
-
- *_ctx = NULL;
-
- if (secret == NULL) {
- ret = 0;
- goto Exit;
- }
-
- if (peerkey.len != X25519_KEY_SIZE) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- ret = x25519_derive_secret(secret, ctx->priv, ctx->pub, NULL, peerkey.base);
-
-Exit:
- ptls_clear_memory(ctx->priv, sizeof(ctx->priv));
- free(ctx);
- return ret;
-}
-
-static int x25519_create_key_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *pubkey)
-{
- struct st_x25519_key_exchange_t *ctx;
-
- if ((ctx = (struct st_x25519_key_exchange_t *)malloc(sizeof(*ctx))) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- ctx->super = (ptls_key_exchange_context_t){x25519_on_exchange};
- x25519_create_keypair(ctx->priv, ctx->pub);
-
- *_ctx = &ctx->super;
- *pubkey = ptls_iovec_init(ctx->pub, sizeof(ctx->pub));
- return 0;
-}
-
-static int x25519_key_exchange(ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- uint8_t priv[X25519_KEY_SIZE], *pub = NULL;
- int ret;
-
- if (peerkey.len != X25519_KEY_SIZE) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- if ((pub = malloc(X25519_KEY_SIZE)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- x25519_create_keypair(priv, pub);
- if ((ret = x25519_derive_secret(secret, NULL, peerkey.base, priv, pub)) != 0)
- goto Exit;
-
- *pubkey = ptls_iovec_init(pub, X25519_KEY_SIZE);
- ret = 0;
-
-Exit:
- ptls_clear_memory(priv, sizeof(priv));
- if (pub != NULL && ret != 0)
- ptls_clear_memory(pub, X25519_KEY_SIZE);
- return ret;
-}
-
-struct aesctr_context_t {
- ptls_cipher_context_t super;
- cf_aes_context aes;
- cf_ctr ctr;
-};
-
-static void aesctr_dispose(ptls_cipher_context_t *_ctx)
-{
- struct aesctr_context_t *ctx = (struct aesctr_context_t *)_ctx;
- ptls_clear_memory(ctx, sizeof(*ctx));
-}
-
-static void aesctr_init(ptls_cipher_context_t *_ctx, const void *iv)
-{
- struct aesctr_context_t *ctx = (struct aesctr_context_t *)_ctx;
- cf_ctr_init(&ctx->ctr, &cf_aes, &ctx->aes, iv);
-}
-
-static void aesctr_transform(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
-{
- struct aesctr_context_t *ctx = (struct aesctr_context_t *)_ctx;
- cf_ctr_cipher(&ctx->ctr, input, output, len);
-}
-
-static int aesctr_setup_crypto(ptls_cipher_context_t *_ctx, int is_enc, const void *key, size_t key_size)
-{
- struct aesctr_context_t *ctx = (struct aesctr_context_t *)_ctx;
- ctx->super.do_dispose = aesctr_dispose;
- ctx->super.do_init = aesctr_init;
- ctx->super.do_transform = aesctr_transform;
- cf_aes_init(&ctx->aes, key, key_size);
- return 0;
-}
-
-static int aes128ctr_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
-{
- return aesctr_setup_crypto(ctx, is_enc, key, PTLS_AES128_KEY_SIZE);
-}
-
-static int aes256ctr_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
-{
- return aesctr_setup_crypto(ctx, is_enc, key, PTLS_AES256_KEY_SIZE);
-}
-
-struct aesgcm_context_t {
- ptls_aead_context_t super;
- cf_aes_context aes;
- cf_gcm_ctx gcm;
-};
-
-static void aesgcm_dispose_crypto(ptls_aead_context_t *_ctx)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- /* clear all memory except super */
- ptls_clear_memory((uint8_t *)ctx + sizeof(ctx->super), sizeof(*ctx) - sizeof(ctx->super));
-}
-
-static void aesgcm_encrypt_init(ptls_aead_context_t *_ctx, const void *iv, const void *aad, size_t aadlen)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- cf_gcm_encrypt_init(&cf_aes, &ctx->aes, &ctx->gcm, aad, aadlen, iv, PTLS_AESGCM_IV_SIZE);
-}
-
-static size_t aesgcm_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- cf_gcm_encrypt_update(&ctx->gcm, input, inlen, output);
- return inlen;
-}
-
-static size_t aesgcm_encrypt_final(ptls_aead_context_t *_ctx, void *output)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- cf_gcm_encrypt_final(&ctx->gcm, output, PTLS_AESGCM_TAG_SIZE);
- return PTLS_AESGCM_TAG_SIZE;
-}
-
-static size_t aesgcm_decrypt(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, const void *iv,
- const void *aad, size_t aadlen)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- if (inlen < PTLS_AESGCM_TAG_SIZE)
- return SIZE_MAX;
- size_t tag_offset = inlen - PTLS_AESGCM_TAG_SIZE;
-
- if (cf_gcm_decrypt(&cf_aes, &ctx->aes, input, tag_offset, aad, aadlen, iv, PTLS_AESGCM_IV_SIZE, (uint8_t *)input + tag_offset,
- PTLS_AESGCM_TAG_SIZE, output) != 0)
- return SIZE_MAX;
-
- return tag_offset;
-}
-
-static int aead_aesgcm_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, size_t key_size)
-{
- struct aesgcm_context_t *ctx = (struct aesgcm_context_t *)_ctx;
-
- ctx->super.dispose_crypto = aesgcm_dispose_crypto;
- if (is_enc) {
- ctx->super.do_encrypt_init = aesgcm_encrypt_init;
- ctx->super.do_encrypt_update = aesgcm_encrypt_update;
- ctx->super.do_encrypt_final = aesgcm_encrypt_final;
- ctx->super.do_decrypt = NULL;
- } else {
- ctx->super.do_encrypt_init = NULL;
- ctx->super.do_encrypt_update = NULL;
- ctx->super.do_encrypt_final = NULL;
- ctx->super.do_decrypt = aesgcm_decrypt;
- }
-
- cf_aes_init(&ctx->aes, key, key_size);
- return 0;
-}
-
-static int aead_aes128gcm_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key)
-{
- return aead_aesgcm_setup_crypto(ctx, is_enc, key, PTLS_AES128_KEY_SIZE);
-}
-
-static int aead_aes256gcm_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key)
-{
- return aead_aesgcm_setup_crypto(ctx, is_enc, key, PTLS_AES256_KEY_SIZE);
-}
-
-struct chacha20_context_t {
- ptls_cipher_context_t super;
- cf_chacha20_ctx chacha;
- uint8_t key[PTLS_CHACHA20_KEY_SIZE];
-};
-
-static void chacha20_dispose(ptls_cipher_context_t *_ctx)
-{
- struct chacha20_context_t *ctx = (struct chacha20_context_t *)_ctx;
- ptls_clear_memory(ctx, sizeof(*ctx));
-}
-
-static void chacha20_init(ptls_cipher_context_t *_ctx, const void *iv)
-{
- struct chacha20_context_t *ctx = (struct chacha20_context_t *)_ctx;
- ctx->chacha.nblock = 0;
- ctx->chacha.ncounter = 0;
- memcpy(ctx->chacha.nonce, iv, sizeof ctx->chacha.nonce);
-}
-
-static void chacha20_transform(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
-{
- struct chacha20_context_t *ctx = (struct chacha20_context_t *)_ctx;
- cf_chacha20_cipher(&ctx->chacha, input, output, len);
-}
-
-static int chacha20_setup_crypto(ptls_cipher_context_t *_ctx, int is_enc, const void *key)
-{
- struct chacha20_context_t *ctx = (struct chacha20_context_t *)_ctx;
- ctx->super.do_dispose = chacha20_dispose;
- ctx->super.do_init = chacha20_init;
- ctx->super.do_transform = chacha20_transform;
- cf_chacha20_init(&ctx->chacha, key, PTLS_CHACHA20_KEY_SIZE, (const uint8_t *)"01234567" /* not used */);
- return 0;
-}
-
-struct chacha20poly1305_context_t {
- ptls_aead_context_t super;
- uint8_t key[PTLS_CHACHA20_KEY_SIZE];
- cf_chacha20_ctx chacha;
- cf_poly1305 poly;
- size_t aadlen;
- size_t textlen;
-};
-
-static void chacha20poly1305_dispose_crypto(ptls_aead_context_t *_ctx)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- /* clear all memory except super */
- ptls_clear_memory(&ctx->key, sizeof(*ctx) - offsetof(struct chacha20poly1305_context_t, key));
-}
-
-static const uint8_t zeros64[64] = {0};
-
-static void chacha20poly1305_encrypt_pad(cf_poly1305 *poly, size_t n)
-{
- if (n % 16 != 0)
- cf_poly1305_update(poly, zeros64, 16 - (n % 16));
-}
-
-static void chacha20poly1305_finalize(struct chacha20poly1305_context_t *ctx, uint8_t *tag)
-{
- uint8_t lenbuf[16];
-
- chacha20poly1305_encrypt_pad(&ctx->poly, ctx->textlen);
-
- write64_le(ctx->aadlen, lenbuf);
- write64_le(ctx->textlen, lenbuf + 8);
- cf_poly1305_update(&ctx->poly, lenbuf, sizeof(lenbuf));
-
- cf_poly1305_finish(&ctx->poly, tag);
-}
-
-static void chacha20poly1305_init(ptls_aead_context_t *_ctx, const void *iv, const void *aad, size_t aadlen)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
- uint8_t tmpbuf[64];
-
- /* init chacha */
- memset(tmpbuf, 0, 16 - PTLS_CHACHA20POLY1305_IV_SIZE);
- memcpy(tmpbuf + 16 - PTLS_CHACHA20POLY1305_IV_SIZE, iv, PTLS_CHACHA20POLY1305_IV_SIZE);
- cf_chacha20_init_custom(&ctx->chacha, ctx->key, sizeof(ctx->key), tmpbuf, 4);
-
- /* init poly1305 (by using first 16 bytes of the key stream of the first block) */
- cf_chacha20_cipher(&ctx->chacha, zeros64, tmpbuf, 64);
- cf_poly1305_init(&ctx->poly, tmpbuf, tmpbuf + 16);
-
- ptls_clear_memory(tmpbuf, sizeof(tmpbuf));
-
- /* aad */
- if (aadlen != 0) {
- cf_poly1305_update(&ctx->poly, aad, aadlen);
- chacha20poly1305_encrypt_pad(&ctx->poly, aadlen);
- }
-
- ctx->aadlen = aadlen;
- ctx->textlen = 0;
-}
-
-static size_t chacha20poly1305_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- cf_chacha20_cipher(&ctx->chacha, input, output, inlen);
- cf_poly1305_update(&ctx->poly, output, inlen);
- ctx->textlen += inlen;
-
- return inlen;
-}
-
-static size_t chacha20poly1305_encrypt_final(ptls_aead_context_t *_ctx, void *output)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- chacha20poly1305_finalize(ctx, output);
-
- ptls_clear_memory(&ctx->chacha, sizeof(ctx->chacha));
- return PTLS_CHACHA20POLY1305_TAG_SIZE;
-}
-
-static size_t chacha20poly1305_decrypt(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, const void *iv,
- const void *aad, size_t aadlen)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
- uint8_t tag[PTLS_CHACHA20POLY1305_TAG_SIZE];
- size_t ret;
-
- if (inlen < sizeof(tag))
- return SIZE_MAX;
-
- chacha20poly1305_init(&ctx->super, iv, aad, aadlen);
-
- cf_poly1305_update(&ctx->poly, input, inlen - sizeof(tag));
- ctx->textlen = inlen - sizeof(tag);
-
- chacha20poly1305_finalize(ctx, tag);
- if (mem_eq(tag, (const uint8_t *)input + inlen - sizeof(tag), sizeof(tag))) {
- cf_chacha20_cipher(&ctx->chacha, input, output, inlen - sizeof(tag));
- ret = inlen - sizeof(tag);
- } else {
- ret = SIZE_MAX;
- }
-
- ptls_clear_memory(tag, sizeof(tag));
- ptls_clear_memory(&ctx->poly, sizeof(ctx->poly));
-
- return ret;
-}
-
-static int aead_chacha20poly1305_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- ctx->super.dispose_crypto = chacha20poly1305_dispose_crypto;
- if (is_enc) {
- ctx->super.do_encrypt_init = chacha20poly1305_init;
- ctx->super.do_encrypt_update = chacha20poly1305_encrypt_update;
- ctx->super.do_encrypt_final = chacha20poly1305_encrypt_final;
- ctx->super.do_decrypt = NULL;
- } else {
- ctx->super.do_encrypt_init = NULL;
- ctx->super.do_encrypt_update = NULL;
- ctx->super.do_encrypt_final = NULL;
- ctx->super.do_decrypt = chacha20poly1305_decrypt;
- }
-
- memcpy(ctx->key, key, sizeof(ctx->key));
- return 0;
-}
-
-ptls_define_hash(sha256, cf_sha256_context, cf_sha256_init, cf_sha256_update, cf_sha256_digest_final);
-ptls_define_hash(sha384, cf_sha512_context, cf_sha384_init, cf_sha384_update, cf_sha384_digest_final);
-
-ptls_key_exchange_algorithm_t ptls_minicrypto_x25519 = {PTLS_GROUP_X25519, x25519_create_key_exchange, x25519_key_exchange};
-ptls_cipher_algorithm_t ptls_minicrypto_aes128ctr = {"AES128-CTR", PTLS_AES128_KEY_SIZE, PTLS_AES_IV_SIZE,
- sizeof(struct aesctr_context_t), aes128ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_minicrypto_aes128gcm = {
- "AES128-GCM", &ptls_minicrypto_aes128ctr, PTLS_AES128_KEY_SIZE, PTLS_AESGCM_IV_SIZE,
- PTLS_AESGCM_TAG_SIZE, sizeof(struct aesgcm_context_t), aead_aes128gcm_setup_crypto};
-ptls_cipher_algorithm_t ptls_minicrypto_aes256ctr = {"AES256-CTR", PTLS_AES256_KEY_SIZE, PTLS_AES_IV_SIZE,
- sizeof(struct aesctr_context_t), aes256ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_minicrypto_aes256gcm = {
- "AES256-GCM", &ptls_minicrypto_aes256ctr, PTLS_AES256_KEY_SIZE, PTLS_AESGCM_IV_SIZE,
- PTLS_AESGCM_TAG_SIZE, sizeof(struct aesgcm_context_t), aead_aes256gcm_setup_crypto};
-ptls_hash_algorithm_t ptls_minicrypto_sha256 = {PTLS_SHA256_BLOCK_SIZE, PTLS_SHA256_DIGEST_SIZE, sha256_create,
- PTLS_ZERO_DIGEST_SHA256};
-ptls_hash_algorithm_t ptls_minicrypto_sha384 = {PTLS_SHA384_BLOCK_SIZE, PTLS_SHA384_DIGEST_SIZE, sha384_create,
- PTLS_ZERO_DIGEST_SHA384};
-ptls_cipher_algorithm_t ptls_minicrypto_chacha20 = {"CHACHA20", PTLS_CHACHA20_KEY_SIZE, PTLS_CHACHA20_IV_SIZE,
- sizeof(struct chacha20_context_t), chacha20_setup_crypto};
-ptls_aead_algorithm_t ptls_minicrypto_chacha20poly1305 = {"CHACHA20-POLY1305",
- &ptls_minicrypto_chacha20,
- PTLS_CHACHA20_KEY_SIZE,
- PTLS_CHACHA20POLY1305_IV_SIZE,
- PTLS_CHACHA20POLY1305_TAG_SIZE,
- sizeof(struct chacha20poly1305_context_t),
- aead_chacha20poly1305_setup_crypto};
-ptls_cipher_suite_t ptls_minicrypto_aes128gcmsha256 = {PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, &ptls_minicrypto_aes128gcm,
- &ptls_minicrypto_sha256};
-ptls_cipher_suite_t ptls_minicrypto_aes256gcmsha384 = {PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, &ptls_minicrypto_aes256gcm,
- &ptls_minicrypto_sha384};
-ptls_cipher_suite_t ptls_minicrypto_chacha20poly1305sha256 = {PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256,
- &ptls_minicrypto_chacha20poly1305, &ptls_minicrypto_sha256};
-ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = {&ptls_minicrypto_aes256gcmsha384, &ptls_minicrypto_aes128gcmsha256,
- &ptls_minicrypto_chacha20poly1305sha256, NULL};
diff --git a/debian/vendor-h2o/deps/picotls/lib/minicrypto-pem.c b/debian/vendor-h2o/deps/picotls/lib/minicrypto-pem.c
deleted file mode 100644
index 2b82a91..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/minicrypto-pem.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (c) 2017,2018 Christian Huitema
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <unistd.h>
-#endif
-#include "picotls.h"
-#include "picotls/minicrypto.h"
-#include "picotls/asn1.h"
-#include "picotls/pembase64.h"
-
-
-/*
- * This function could be declared as static, but we want to access it
- * in the unit tests.
- */
-size_t ptls_minicrypto_asn1_decode_private_key(ptls_asn1_pkcs8_private_key_t *pkey, int *decode_error,
- ptls_minicrypto_log_ctx_t *log_ctx)
-{
- uint8_t *bytes = pkey->vec.base;
- size_t bytes_max = pkey->vec.len;
-
- /* read the ASN1 messages */
- size_t byte_index = 0;
- uint32_t seq0_length = 0;
- size_t last_byte0;
- uint32_t seq1_length = 0;
- size_t last_byte1 = 0;
- uint32_t oid_length;
- size_t last_oid_byte;
- uint32_t key_data_length;
- size_t key_data_last;
-
- /* start with sequence */
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq0_length, NULL, &last_byte0,
- decode_error, log_ctx);
-
- if (*decode_error == 0 && bytes_max != last_byte0) {
- byte_index = ptls_asn1_error_message("Length larger than message", bytes_max, byte_index, 0, log_ctx);
- *decode_error = PTLS_ERROR_BER_EXCESSIVE_LENGTH;
- }
-
- if (*decode_error == 0) {
- /* get first component: version, INTEGER, expect value 0 */
- if (byte_index + 3 > bytes_max) {
- byte_index = ptls_asn1_error_message("Cannot find key version", bytes_max, byte_index, 0, log_ctx);
- *decode_error = PTLS_ERROR_INCORRECT_PEM_KEY_VERSION;
- } else if (bytes[byte_index] != 0x02 || bytes[byte_index + 1] != 0x01 || bytes[byte_index + 2] != 0x00) {
- *decode_error = PTLS_ERROR_INCORRECT_PEM_KEY_VERSION;
- byte_index = ptls_asn1_error_message("Incorrect PEM Version", bytes_max, byte_index, 0, log_ctx);
- } else {
- byte_index += 3;
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, " Version = 1,\n");
- }
- }
- }
-
- if (*decode_error == 0) {
- /* open embedded sequence */
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq1_length, NULL, &last_byte1,
- decode_error, log_ctx);
- }
-
- if (*decode_error == 0) {
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, " Algorithm Identifier:\n");
- }
- /* get length of OID */
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte1, byte_index, 0x06, &oid_length, NULL, &last_oid_byte,
- decode_error, log_ctx);
-
- if (*decode_error == 0) {
- if (log_ctx != NULL) {
- /* print the OID value */
- log_ctx->fn(log_ctx->ctx, " Algorithm:");
- ptls_asn1_dump_content(bytes + byte_index, oid_length, 0, log_ctx);
- log_ctx->fn(log_ctx->ctx, ",\n");
- }
- pkey->algorithm_index = byte_index;
- pkey->algorithm_length = oid_length;
- byte_index += oid_length;
- }
- }
-
- if (*decode_error == 0) {
- /* get parameters, ANY */
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, " Parameters:\n");
- }
-
- pkey->parameters_index = byte_index;
-
- pkey->parameters_length =
- ptls_asn1_validation_recursive(bytes + byte_index, last_byte1 - byte_index, decode_error, 2, log_ctx);
-
- byte_index += pkey->parameters_length;
-
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "\n");
- }
- /* close sequence */
- if (byte_index != last_byte1) {
- byte_index = ptls_asn1_error_message("Length larger than element", bytes_max, byte_index, 2, log_ctx);
- *decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT;
- }
- }
-
- /* get octet string, key */
- if (*decode_error == 0) {
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte0, byte_index, 0x04, &key_data_length, NULL,
- &key_data_last, decode_error, log_ctx);
-
- if (*decode_error == 0) {
- pkey->key_data_index = byte_index;
- pkey->key_data_length = key_data_length;
- byte_index += key_data_length;
-
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, " Key data (%d bytes):\n", key_data_length);
-
- (void)ptls_asn1_validation_recursive(bytes + pkey->key_data_index, key_data_length, decode_error, 1, log_ctx);
- log_ctx->fn(log_ctx->ctx, "\n");
- }
- }
- }
-
- if (*decode_error == 0 && byte_index != last_byte0) {
- byte_index = ptls_asn1_error_message("Length larger than element", bytes_max, byte_index, 0, log_ctx);
- *decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT;
- }
-
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "\n");
- }
-
- return byte_index;
-}
-
-static int ptls_pem_parse_private_key(char const *pem_fname, ptls_asn1_pkcs8_private_key_t *pkey,
- ptls_minicrypto_log_ctx_t *log_ctx)
-{
- size_t nb_keys = 0;
- int ret = ptls_load_pem_objects(pem_fname, "PRIVATE KEY", &pkey->vec, 1, &nb_keys);
-
- if (ret == 0) {
- if (nb_keys != 1) {
- ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
- }
- }
-
- if (ret == 0 && nb_keys == 1) {
- int decode_error = 0;
-
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "\nFound PRIVATE KEY, length = %d bytes\n", (int)pkey->vec.len);
- }
-
- (void)ptls_minicrypto_asn1_decode_private_key(pkey, &decode_error, log_ctx);
-
- if (decode_error != 0) {
- ret = decode_error;
- }
- }
-
- return ret;
-}
-
-static const uint8_t ptls_asn1_algorithm_ecdsa[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01};
-
-static const uint8_t ptls_asn1_curve_secp256r1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
-
-static int ptls_set_ecdsa_private_key(ptls_context_t *ctx, ptls_asn1_pkcs8_private_key_t *pkey, ptls_minicrypto_log_ctx_t *log_ctx)
-{
- uint8_t *bytes = pkey->vec.base + pkey->parameters_index;
- size_t bytes_max = pkey->parameters_length;
- size_t byte_index = 0;
- uint8_t *curve_id = NULL;
- uint32_t curve_id_length = 0;
- int decode_error = 0;
- uint32_t seq_length;
- size_t last_byte = 0;
- uint8_t *ecdsa_key_data = NULL;
- uint32_t ecdsa_key_data_length = 0;
- size_t ecdsa_key_data_last = 0;
-
- /* We expect the parameters to include just the curve ID */
-
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x06, &curve_id_length, NULL, &last_byte,
- &decode_error, log_ctx);
-
- if (decode_error == 0 && bytes_max != last_byte) {
- byte_index = ptls_asn1_error_message("Length larger than parameters", bytes_max, byte_index, 0, log_ctx);
- decode_error = PTLS_ERROR_BER_EXCESSIVE_LENGTH;
- }
-
- if (decode_error == 0) {
- curve_id = bytes + byte_index;
-
- if (log_ctx != NULL) {
- /* print the OID value */
- log_ctx->fn(log_ctx->ctx, "Curve: ");
- ptls_asn1_dump_content(curve_id, curve_id_length, 0, log_ctx);
- log_ctx->fn(log_ctx->ctx, "\n");
- }
- }
-
- /* We expect the key data to follow the ECDSA structure per RFC 5915 */
- bytes = pkey->vec.base + pkey->key_data_index;
- bytes_max = pkey->key_data_length;
- byte_index = 0;
-
- /* decode the wrapping sequence */
- if (decode_error == 0) {
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq_length, NULL, &last_byte,
- &decode_error, log_ctx);
- }
-
- if (decode_error == 0 && bytes_max != last_byte) {
- byte_index = ptls_asn1_error_message("Length larger than key data", bytes_max, byte_index, 0, log_ctx);
- decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT;
- }
-
- /* verify and skip the version number 1 */
- if (decode_error == 0) {
- /* get first component: version, INTEGER, expect value 0 */
- if (byte_index + 3 > bytes_max) {
- byte_index = ptls_asn1_error_message("Cannot find ECDSA Key Data Version", bytes_max, byte_index, 0, log_ctx);
- decode_error = PTLS_ERROR_INCORRECT_ASN1_ECDSA_KEY_SYNTAX;
- } else if (bytes[byte_index] != 0x02 || bytes[byte_index + 1] != 0x01 || bytes[byte_index + 2] != 0x01) {
- decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_KEY_VERSION;
- byte_index = ptls_asn1_error_message("Incorrect ECDSA Key Data Version", bytes_max, byte_index, 0, log_ctx);
- } else {
- byte_index += 3;
- if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "ECDSA Version = 1,\n");
- }
- }
- }
-
- /* obtain the octet string that contains the ECDSA private key */
- if (decode_error == 0) {
- byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte, byte_index, 0x04, &ecdsa_key_data_length, NULL,
- &ecdsa_key_data_last, &decode_error, log_ctx);
-
- if (decode_error == 0) {
- ecdsa_key_data = bytes + byte_index;
- }
- }
-
- /* If everything is fine, associate the ECDSA key with the context */
- if (curve_id_length == sizeof(ptls_asn1_curve_secp256r1) && curve_id != NULL &&
- memcmp(curve_id, ptls_asn1_curve_secp256r1, sizeof(ptls_asn1_curve_secp256r1)) == 0) {
- if (SECP256R1_PRIVATE_KEY_SIZE != ecdsa_key_data_length) {
- decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_KEYSIZE;
- if (log_ctx != NULL) {
- /* print the OID value */
- log_ctx->fn(log_ctx->ctx, "Wrong SECP256R1 key length, %d instead of %d.\n", ecdsa_key_data_length,
- SECP256R1_PRIVATE_KEY_SIZE);
- }
- } else {
- ptls_minicrypto_secp256r1sha256_sign_certificate_t *minicrypto_sign_certificate;
-
- minicrypto_sign_certificate = (ptls_minicrypto_secp256r1sha256_sign_certificate_t *)malloc(
- sizeof(ptls_minicrypto_secp256r1sha256_sign_certificate_t));
-
- if (minicrypto_sign_certificate == NULL) {
- decode_error = PTLS_ERROR_NO_MEMORY;
- } else {
- memset(minicrypto_sign_certificate, 0, sizeof(ptls_minicrypto_secp256r1sha256_sign_certificate_t));
- decode_error = ptls_minicrypto_init_secp256r1sha256_sign_certificate(
- minicrypto_sign_certificate, ptls_iovec_init(ecdsa_key_data, ecdsa_key_data_length));
- }
- if (decode_error == 0) {
- ctx->sign_certificate = &minicrypto_sign_certificate->super;
-
- if (log_ctx != NULL) {
- /* print the OID value */
- log_ctx->fn(log_ctx->ctx, "Initialized SECP512R1 signing key with %d bytes.\n", ecdsa_key_data_length);
- }
- } else if (log_ctx != NULL) {
- log_ctx->fn(log_ctx->ctx, "SECP512R1 init with %d bytes returns %d.\n", ecdsa_key_data_length, decode_error);
- }
- }
- } else {
- decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_CURVE;
- if (log_ctx != NULL) {
- /* print the OID value */
- log_ctx->fn(log_ctx->ctx, "Curve is not supported for signatures.\n");
- }
- }
-
- return decode_error;
-}
-
-int ptls_minicrypto_load_private_key(ptls_context_t *ctx, char const *pem_fname)
-{
- ptls_asn1_pkcs8_private_key_t pkey = {{0}};
- int ret = ptls_pem_parse_private_key(pem_fname, &pkey, NULL);
-
- /* Check that this is the expected key type.
- * At this point, the minicrypto library only supports ECDSA keys.
- * In theory, we could add support for RSA keys at some point.
- */
- if (ret == 0) {
- if (pkey.algorithm_length == sizeof(ptls_asn1_algorithm_ecdsa) &&
- memcmp(pkey.vec.base + pkey.algorithm_index, ptls_asn1_algorithm_ecdsa, sizeof(ptls_asn1_algorithm_ecdsa)) == 0) {
- ret = ptls_set_ecdsa_private_key(ctx, &pkey, NULL);
- } else {
- ret = -1;
- }
- }
-
- return ret;
-}
diff --git a/debian/vendor-h2o/deps/picotls/lib/openssl.c b/debian/vendor-h2o/deps/picotls/lib/openssl.c
deleted file mode 100644
index 2c9ee70..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/openssl.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*
- * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <unistd.h>
-#endif
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <openssl/bn.h>
-#include <openssl/crypto.h>
-#include <openssl/ec.h>
-#include <openssl/ecdh.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/objects.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/x509_vfy.h>
-#include "picotls.h"
-#include "picotls/openssl.h"
-
-#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
-#define OPENSSL_1_1_API 1
-#elif defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL
-#define OPENSSL_1_1_API 1
-#else
-#define OPENSSL_1_1_API 0
-#endif
-
-#if !OPENSSL_1_1_API
-
-#define EVP_PKEY_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_EVP_PKEY)
-#define X509_STORE_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_X509_STORE)
-
-static HMAC_CTX *HMAC_CTX_new(void)
-{
- HMAC_CTX *ctx;
-
- if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL)
- return NULL;
- HMAC_CTX_init(ctx);
- return ctx;
-}
-
-static void HMAC_CTX_free(HMAC_CTX *ctx)
-{
- HMAC_CTX_cleanup(ctx);
- OPENSSL_free(ctx);
-}
-
-#endif
-
-void ptls_openssl_random_bytes(void *buf, size_t len)
-{
- RAND_bytes(buf, (int)len);
-}
-
-static EC_KEY *ecdh_gerenate_key(EC_GROUP *group)
-{
- EC_KEY *key;
-
- if ((key = EC_KEY_new()) == NULL)
- return NULL;
- if (!EC_KEY_set_group(key, group) || !EC_KEY_generate_key(key)) {
- EC_KEY_free(key);
- return NULL;
- }
-
- return key;
-}
-
-static int ecdh_calc_secret(ptls_iovec_t *out, EC_GROUP *group, EC_KEY *privkey, EC_POINT *peer_point)
-{
- ptls_iovec_t secret;
- int ret;
-
- secret.len = (EC_GROUP_get_degree(group) + 7) / 8;
- if ((secret.base = malloc(secret.len)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (ECDH_compute_key(secret.base, secret.len, peer_point, privkey, NULL) <= 0) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE; /* ??? */
- goto Exit;
- }
- ret = 0;
-
-Exit:
- if (ret == 0) {
- *out = secret;
- } else {
- free(secret.base);
- *out = (ptls_iovec_t){NULL};
- }
- return ret;
-}
-
-static EC_POINT *x9_62_decode_point(EC_GROUP *group, ptls_iovec_t vec, BN_CTX *bn_ctx)
-{
- EC_POINT *point = NULL;
-
- if ((point = EC_POINT_new(group)) == NULL)
- return NULL;
- if (!EC_POINT_oct2point(group, point, vec.base, vec.len, bn_ctx)) {
- EC_POINT_free(point);
- return NULL;
- }
-
- return point;
-}
-
-static ptls_iovec_t x9_62_encode_point(EC_GROUP *group, const EC_POINT *point, BN_CTX *bn_ctx)
-{
- ptls_iovec_t vec;
-
- if ((vec.len = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx)) == 0)
- return (ptls_iovec_t){NULL};
- if ((vec.base = malloc(vec.len)) == NULL)
- return (ptls_iovec_t){NULL};
- if (EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, vec.base, vec.len, bn_ctx) != vec.len) {
- free(vec.base);
- return (ptls_iovec_t){NULL};
- }
-
- return vec;
-}
-
-struct st_x9_62_keyex_context_t {
- ptls_key_exchange_context_t super;
- BN_CTX *bn_ctx;
- EC_GROUP *group;
- EC_KEY *privkey;
- ptls_iovec_t pubkey;
-};
-
-static void x9_62_free_context(struct st_x9_62_keyex_context_t *ctx)
-{
- free(ctx->pubkey.base);
- if (ctx->privkey != NULL)
- EC_KEY_free(ctx->privkey);
- if (ctx->group != NULL)
- EC_GROUP_free(ctx->group);
- if (ctx->bn_ctx != NULL)
- BN_CTX_free(ctx->bn_ctx);
- free(ctx);
-}
-
-static int x9_62_on_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- struct st_x9_62_keyex_context_t *ctx = (struct st_x9_62_keyex_context_t *)*_ctx;
- EC_POINT *peer_point = NULL;
- int ret;
-
- *_ctx = NULL;
-
- if ((peer_point = x9_62_decode_point(ctx->group, peerkey, ctx->bn_ctx)) == NULL) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if ((ret = ecdh_calc_secret(secret, ctx->group, ctx->privkey, peer_point)) != 0)
- goto Exit;
-
-Exit:
- if (peer_point != NULL)
- EC_POINT_free(peer_point);
- x9_62_free_context(ctx);
- return ret;
-}
-
-static int x9_62_create_key_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *pubkey, int nid)
-{
- struct st_x9_62_keyex_context_t *ctx = NULL;
- int ret;
-
- if ((ctx = (struct st_x9_62_keyex_context_t *)malloc(sizeof(*ctx))) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- *ctx = (struct st_x9_62_keyex_context_t){{x9_62_on_exchange}};
-
- if ((ctx->bn_ctx = BN_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((ctx->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if ((ctx->privkey = ecdh_gerenate_key(ctx->group)) == NULL) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
-
- if ((ctx->pubkey = x9_62_encode_point(ctx->group, EC_KEY_get0_public_key(ctx->privkey), ctx->bn_ctx)).base == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- *pubkey = ctx->pubkey;
- ret = 0;
-
-Exit:
- if (ret == 0) {
- *_ctx = &ctx->super;
- } else {
- if (ctx != NULL)
- x9_62_free_context(ctx);
- *_ctx = NULL;
- *pubkey = (ptls_iovec_t){NULL};
- }
-
- return ret;
-}
-
-static int secp256r1_create_key_exchange(ptls_key_exchange_context_t **ctx, ptls_iovec_t *pubkey)
-{
- return x9_62_create_key_exchange(ctx, pubkey, NID_X9_62_prime256v1);
-}
-
-static int x9_62_key_exchange(EC_GROUP *group, ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey, BN_CTX *bn_ctx)
-{
- EC_POINT *peer_point = NULL;
- EC_KEY *privkey = NULL;
- int ret;
-
- *pubkey = (ptls_iovec_t){NULL};
- *secret = (ptls_iovec_t){NULL};
-
- /* decode peer key */
- if ((peer_point = x9_62_decode_point(group, peerkey, bn_ctx)) == NULL) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
-
- /* create private key */
- if ((privkey = ecdh_gerenate_key(group)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- /* encode public key */
- if ((*pubkey = x9_62_encode_point(group, EC_KEY_get0_public_key(privkey), bn_ctx)).base == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- /* calc secret */
- secret->len = (EC_GROUP_get_degree(group) + 7) / 8;
- if ((secret->base = malloc(secret->len)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- /* ecdh! */
- if (ECDH_compute_key(secret->base, secret->len, peer_point, privkey, NULL) <= 0) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE; /* ??? */
- goto Exit;
- }
-
- ret = 0;
-
-Exit:
- if (peer_point != NULL)
- EC_POINT_free(peer_point);
- if (privkey != NULL)
- EC_KEY_free(privkey);
- if (ret != 0) {
- free(pubkey->base);
- *pubkey = (ptls_iovec_t){NULL};
- free(secret->base);
- *secret = (ptls_iovec_t){NULL};
- }
- return ret;
-}
-
-static int secp_key_exchange(int nid, ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- EC_GROUP *group = NULL;
- BN_CTX *bn_ctx = NULL;
- int ret;
-
- if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if ((bn_ctx = BN_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- ret = x9_62_key_exchange(group, pubkey, secret, peerkey, bn_ctx);
-
-Exit:
- if (bn_ctx != NULL)
- BN_CTX_free(bn_ctx);
- if (group != NULL)
- EC_GROUP_free(group);
- return ret;
-}
-
-static int secp256r1_key_exchange(ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- return secp_key_exchange(NID_X9_62_prime256v1, pubkey, secret, peerkey);
-}
-
-static int do_sign(EVP_PKEY *key, ptls_buffer_t *outbuf, ptls_iovec_t input, const EVP_MD *md)
-{
- EVP_MD_CTX *ctx = NULL;
- EVP_PKEY_CTX *pkey_ctx;
- size_t siglen;
- int ret;
-
- if ((ctx = EVP_MD_CTX_create()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (EVP_DigestSignInit(ctx, &pkey_ctx, md, NULL, key) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_id(key) == EVP_PKEY_RSA) {
- if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256()) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- }
- if (EVP_DigestSignUpdate(ctx, input.base, input.len) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_DigestSignFinal(ctx, NULL, &siglen) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if ((ret = ptls_buffer_reserve(outbuf, siglen)) != 0)
- goto Exit;
- if (EVP_DigestSignFinal(ctx, outbuf->base + outbuf->off, &siglen) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- outbuf->off += siglen;
-
- ret = 0;
-Exit:
- if (ctx != NULL)
- EVP_MD_CTX_destroy(ctx);
- return ret;
-}
-
-struct cipher_context_t {
- ptls_cipher_context_t super;
- EVP_CIPHER_CTX *evp;
-};
-
-static void cipher_dispose(ptls_cipher_context_t *_ctx)
-{
- struct cipher_context_t *ctx = (struct cipher_context_t *)_ctx;
- EVP_CIPHER_CTX_free(ctx->evp);
-}
-
-static void cipher_do_init(ptls_cipher_context_t *_ctx, const void *iv)
-{
- struct cipher_context_t *ctx = (struct cipher_context_t *)_ctx;
- int ret;
- ret = EVP_EncryptInit_ex(ctx->evp, NULL, NULL, NULL, iv);
- assert(ret);
-}
-
-static int cipher_setup_crypto(ptls_cipher_context_t *_ctx, const void *key, const EVP_CIPHER *cipher,
- void (*do_transform)(ptls_cipher_context_t *, void *, const void *, size_t))
-{
- struct cipher_context_t *ctx = (struct cipher_context_t *)_ctx;
-
- ctx->super.do_dispose = cipher_dispose;
- ctx->super.do_init = cipher_do_init;
- ctx->super.do_transform = do_transform;
-
- if ((ctx->evp = EVP_CIPHER_CTX_new()) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- if (!EVP_EncryptInit_ex(ctx->evp, cipher, NULL, key, NULL)) {
- EVP_CIPHER_CTX_free(ctx->evp);
- return PTLS_ERROR_LIBRARY;
- }
-
- return 0;
-}
-
-static void cipher_encrypt(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t _len)
-{
- struct cipher_context_t *ctx = (struct cipher_context_t *)_ctx;
- int len = (int)_len, ret = EVP_EncryptUpdate(ctx->evp, output, &len, input, len);
- assert(ret);
-}
-
-static int aes128ctr_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
-{
- return cipher_setup_crypto(ctx, key, EVP_aes_128_ctr(), cipher_encrypt);
-}
-
-static int aes256ctr_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
-{
- return cipher_setup_crypto(ctx, key, EVP_aes_256_ctr(), cipher_encrypt);
-}
-
-#if defined(PTLS_OPENSSL_HAVE_CHACHA20_POLY1305)
-
-static int chacha20_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
-{
- return cipher_setup_crypto(ctx, key, EVP_chacha20(), cipher_encrypt);
-}
-
-#endif
-
-struct aead_crypto_context_t {
- ptls_aead_context_t super;
- EVP_CIPHER_CTX *evp_ctx;
-};
-
-static void aead_dispose_crypto(ptls_aead_context_t *_ctx)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
-
- if (ctx->evp_ctx != NULL)
- EVP_CIPHER_CTX_free(ctx->evp_ctx);
-}
-
-static void aead_do_encrypt_init(ptls_aead_context_t *_ctx, const void *iv, const void *aad, size_t aadlen)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
- int ret;
-
- /* FIXME for performance, preserve the expanded key instead of the raw key */
- ret = EVP_EncryptInit_ex(ctx->evp_ctx, NULL, NULL, NULL, iv);
- assert(ret);
-
- if (aadlen != 0) {
- int blocklen;
- ret = EVP_EncryptUpdate(ctx->evp_ctx, NULL, &blocklen, aad, (int)aadlen);
- assert(ret);
- }
-}
-
-static size_t aead_do_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
- int blocklen, ret;
-
- ret = EVP_EncryptUpdate(ctx->evp_ctx, output, &blocklen, input, (int)inlen);
- assert(ret);
-
- return blocklen;
-}
-
-static size_t aead_do_encrypt_final(ptls_aead_context_t *_ctx, void *_output)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
- uint8_t *output = _output;
- size_t off = 0, tag_size = ctx->super.algo->tag_size;
- int blocklen, ret;
-
- ret = EVP_EncryptFinal_ex(ctx->evp_ctx, output + off, &blocklen);
- assert(ret);
- off += blocklen;
- ret = EVP_CIPHER_CTX_ctrl(ctx->evp_ctx, EVP_CTRL_GCM_GET_TAG, (int)tag_size, output + off);
- assert(ret);
- off += tag_size;
-
- return off;
-}
-
-static size_t aead_do_decrypt(ptls_aead_context_t *_ctx, void *_output, const void *input, size_t inlen, const void *iv,
- const void *aad, size_t aadlen)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
- uint8_t *output = _output;
- size_t off = 0, tag_size = ctx->super.algo->tag_size;
- int blocklen, ret;
-
- if (inlen < tag_size)
- return SIZE_MAX;
-
- ret = EVP_DecryptInit_ex(ctx->evp_ctx, NULL, NULL, NULL, iv);
- assert(ret);
- if (aadlen != 0) {
- ret = EVP_DecryptUpdate(ctx->evp_ctx, NULL, &blocklen, aad, (int)aadlen);
- assert(ret);
- }
- ret = EVP_DecryptUpdate(ctx->evp_ctx, output + off, &blocklen, input, (int)(inlen - tag_size));
- assert(ret);
- off += blocklen;
- if (!EVP_CIPHER_CTX_ctrl(ctx->evp_ctx, EVP_CTRL_GCM_SET_TAG, (int)tag_size, (void *)((uint8_t *)input + inlen - tag_size)))
- return SIZE_MAX;
- if (!EVP_DecryptFinal_ex(ctx->evp_ctx, output + off, &blocklen))
- return SIZE_MAX;
- off += blocklen;
-
- return off;
-}
-
-static int aead_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const EVP_CIPHER *cipher)
-{
- struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *)_ctx;
- int ret;
-
- ctx->super.dispose_crypto = aead_dispose_crypto;
- if (is_enc) {
- ctx->super.do_encrypt_init = aead_do_encrypt_init;
- ctx->super.do_encrypt_update = aead_do_encrypt_update;
- ctx->super.do_encrypt_final = aead_do_encrypt_final;
- ctx->super.do_decrypt = NULL;
- } else {
- ctx->super.do_encrypt_init = NULL;
- ctx->super.do_encrypt_update = NULL;
- ctx->super.do_encrypt_final = NULL;
- ctx->super.do_decrypt = aead_do_decrypt;
- }
- ctx->evp_ctx = NULL;
-
- if ((ctx->evp_ctx = EVP_CIPHER_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Error;
- }
- if (is_enc) {
- if (!EVP_EncryptInit_ex(ctx->evp_ctx, cipher, NULL, key, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Error;
- }
- } else {
- if (!EVP_DecryptInit_ex(ctx->evp_ctx, cipher, NULL, key, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Error;
- }
- }
- if (!EVP_CIPHER_CTX_ctrl(ctx->evp_ctx, EVP_CTRL_GCM_SET_IVLEN, (int)ctx->super.algo->iv_size, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Error;
- }
-
- return 0;
-
-Error:
- aead_dispose_crypto(&ctx->super);
- return ret;
-}
-
-static int aead_aes128gcm_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key)
-{
- return aead_setup_crypto(ctx, is_enc, key, EVP_aes_128_gcm());
-}
-
-static int aead_aes256gcm_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key)
-{
- return aead_setup_crypto(ctx, is_enc, key, EVP_aes_256_gcm());
-}
-
-#if defined(PTLS_OPENSSL_HAVE_CHACHA20_POLY1305)
-static int aead_chacha20poly1305_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key)
-{
- return aead_setup_crypto(ctx, is_enc, key, EVP_chacha20_poly1305());
-}
-#endif
-
-#define _sha256_final(ctx, md) SHA256_Final((md), (ctx))
-ptls_define_hash(sha256, SHA256_CTX, SHA256_Init, SHA256_Update, _sha256_final);
-
-#define _sha384_final(ctx, md) SHA384_Final((md), (ctx))
-ptls_define_hash(sha384, SHA512_CTX, SHA384_Init, SHA384_Update, _sha384_final);
-
-static int sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, uint16_t *selected_algorithm, ptls_buffer_t *outbuf,
- ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms)
-{
- ptls_openssl_sign_certificate_t *self = (ptls_openssl_sign_certificate_t *)_self;
- const struct st_ptls_openssl_signature_scheme_t *scheme;
-
- /* select the algorithm */
- for (scheme = self->schemes; scheme->scheme_id != UINT16_MAX; ++scheme) {
- size_t i;
- for (i = 0; i != num_algorithms; ++i)
- if (algorithms[i] == scheme->scheme_id)
- goto Found;
- }
- return PTLS_ALERT_HANDSHAKE_FAILURE;
-
-Found:
- *selected_algorithm = scheme->scheme_id;
- return do_sign(self->key, outbuf, input, scheme->scheme_md);
-}
-
-static X509 *to_x509(ptls_iovec_t vec)
-{
- const uint8_t *p = vec.base;
- return d2i_X509(NULL, &p, vec.len);
-}
-
-static int verify_sign(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t signature)
-{
- EVP_PKEY *key = verify_ctx;
- EVP_MD_CTX *ctx = NULL;
- EVP_PKEY_CTX *pkey_ctx = NULL;
- int ret = 0;
-
- if (data.base == NULL)
- goto Exit;
-
- if ((ctx = EVP_MD_CTX_create()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (EVP_DigestVerifyInit(ctx, &pkey_ctx, EVP_sha256(), NULL, key) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_id(key) == EVP_PKEY_RSA) {
- if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256()) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- }
- if (EVP_DigestVerifyUpdate(ctx, data.base, data.len) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (EVP_DigestVerifyFinal(ctx, signature.base, signature.len) != 1) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- ret = 0;
-
-Exit:
- if (ctx != NULL)
- EVP_MD_CTX_destroy(ctx);
- EVP_PKEY_free(key);
- return ret;
-}
-
-int ptls_openssl_init_sign_certificate(ptls_openssl_sign_certificate_t *self, EVP_PKEY *key)
-{
- *self = (ptls_openssl_sign_certificate_t){{sign_certificate}};
- size_t scheme_index = 0;
-
-#define PUSH_SCHEME(id, md) \
- self->schemes[scheme_index++] = (struct st_ptls_openssl_signature_scheme_t) \
- { \
- id, md \
- }
-
- switch (EVP_PKEY_id(key)) {
- case EVP_PKEY_RSA:
- PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, EVP_sha256());
- PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384, EVP_sha384());
- PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512, EVP_sha512());
- break;
- case EVP_PKEY_EC: {
- EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(key);
- switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))) {
- case NID_X9_62_prime256v1:
- PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256, EVP_sha256());
- break;
-#if defined(NID_secp384r1) && !OPENSSL_NO_SHA384
- case NID_secp384r1:
- PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384, EVP_sha384());
- break;
-#endif
-#if defined(NID_secp384r1) && !OPENSSL_NO_SHA512
- case NID_secp521r1:
- PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512, EVP_sha512());
- break;
-#endif
- default:
- EC_KEY_free(eckey);
- return PTLS_ERROR_INCOMPATIBLE_KEY;
- }
- EC_KEY_free(eckey);
- } break;
- default:
- return PTLS_ERROR_INCOMPATIBLE_KEY;
- }
- PUSH_SCHEME(UINT16_MAX, NULL);
- assert(scheme_index <= sizeof(self->schemes) / sizeof(self->schemes[0]));
-
-#undef PUSH_SCHEME
-
- EVP_PKEY_up_ref(key);
- self->key = key;
-
- return 0;
-}
-
-void ptls_openssl_dispose_sign_certificate(ptls_openssl_sign_certificate_t *self)
-{
- EVP_PKEY_free(self->key);
-}
-
-static int serialize_cert(X509 *cert, ptls_iovec_t *dst)
-{
- int len = i2d_X509(cert, NULL);
- assert(len > 0);
-
- if ((dst->base = malloc(len)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- unsigned char *p = dst->base;
- dst->len = i2d_X509(cert, &p);
- assert(len == dst->len);
-
- return 0;
-}
-
-int ptls_openssl_load_certificates(ptls_context_t *ctx, X509 *cert, STACK_OF(X509) * chain)
-{
- ptls_iovec_t *list = NULL;
- size_t slot = 0, count = (cert != NULL) + (chain != NULL ? sk_X509_num(chain) : 0);
- int ret;
-
- assert(ctx->certificates.list == NULL);
-
- if ((list = malloc(sizeof(*list) * count)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (cert != NULL) {
- if ((ret = serialize_cert(cert, list + slot++)) != 0)
- goto Exit;
- }
- if (chain != NULL) {
- int i;
- for (i = 0; i != sk_X509_num(chain); ++i) {
- if ((ret = serialize_cert(sk_X509_value(chain, i), list + slot++)) != 0)
- goto Exit;
- }
- }
-
- assert(slot == count);
-
- ctx->certificates.list = list;
- ctx->certificates.count = count;
- ret = 0;
-
-Exit:
- if (ret != 0 && list != NULL) {
- size_t i;
- for (i = 0; i != slot; ++i)
- free(list[i].base);
- free(list);
- }
- return ret;
-}
-
-static int verify_certificate(ptls_verify_certificate_t *_self, ptls_t *tls, int (**verifier)(void *, ptls_iovec_t, ptls_iovec_t),
- void **verify_data, ptls_iovec_t *certs, size_t num_certs)
-{
- ptls_openssl_verify_certificate_t *self = (ptls_openssl_verify_certificate_t *)_self;
- X509 *cert = NULL;
- STACK_OF(X509) *chain = NULL;
- X509_STORE_CTX *verify_ctx = NULL;
- int ret = 0;
-
- assert(num_certs != 0);
-
- if ((cert = to_x509(certs[0])) == NULL) {
- ret = PTLS_ALERT_BAD_CERTIFICATE;
- goto Exit;
- }
-
- if (self->cert_store != NULL) {
- size_t i;
- for (i = 1; i != num_certs; ++i) {
- X509 *interm = to_x509(certs[i]);
- if (interm == NULL) {
- ret = PTLS_ALERT_BAD_CERTIFICATE;
- goto Exit;
- }
- }
- if ((verify_ctx = X509_STORE_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (X509_STORE_CTX_init(verify_ctx, self->cert_store, cert, chain) != 1) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- X509_STORE_CTX_set_purpose(verify_ctx, X509_PURPOSE_SSL_CLIENT);
- if (X509_verify_cert(verify_ctx) == 1) {
- ret = 0;
- } else {
- switch (X509_STORE_CTX_get_error(verify_ctx)) {
- case X509_V_ERR_OUT_OF_MEM:
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- case X509_V_ERR_CERT_REVOKED:
- ret = PTLS_ALERT_CERTIFICATE_REVOKED;
- goto Exit;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- ret = PTLS_ALERT_CERTIFICATE_EXPIRED;
- goto Exit;
- default:
- ret = PTLS_ALERT_CERTIFICATE_UNKNOWN;
- goto Exit;
- }
- }
- }
-
- if ((*verify_data = X509_get_pubkey(cert)) == NULL) {
- ret = PTLS_ALERT_BAD_CERTIFICATE;
- goto Exit;
- }
- *verifier = verify_sign;
-
-Exit:
- if (verify_ctx != NULL)
- X509_STORE_CTX_free(verify_ctx);
- if (chain != NULL)
- sk_X509_free(chain);
- if (cert != NULL)
- X509_free(cert);
- return ret;
-}
-
-int ptls_openssl_init_verify_certificate(ptls_openssl_verify_certificate_t *self, X509_STORE *store)
-{
- *self = (ptls_openssl_verify_certificate_t){{verify_certificate}};
-
- if (store != NULL) {
- if (store != PTLS_OPENSSL_DEFAULT_CERTIFICATE_STORE) {
- X509_STORE_up_ref(store);
- self->cert_store = store;
- } else {
- X509_LOOKUP *lookup;
- if ((self->cert_store = X509_STORE_new()) == NULL)
- return -1;
- if ((lookup = X509_STORE_add_lookup(self->cert_store, X509_LOOKUP_file())) == NULL)
- return -1;
- X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
- if ((lookup = X509_STORE_add_lookup(self->cert_store, X509_LOOKUP_hash_dir())) == NULL)
- return -1;
- X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
- }
- }
-
- return 0;
-}
-
-void ptls_openssl_dispose_verify_certificate(ptls_openssl_verify_certificate_t *self)
-{
- X509_STORE_free(self->cert_store);
- free(self);
-}
-
-#define TICKET_LABEL_SIZE 16
-#define TICKET_IV_SIZE EVP_MAX_IV_LENGTH
-
-int ptls_openssl_encrypt_ticket(ptls_buffer_t *buf, ptls_iovec_t src,
- int (*cb)(unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc))
-{
- EVP_CIPHER_CTX *cctx = NULL;
- HMAC_CTX *hctx = NULL;
- uint8_t *dst;
- int clen, ret;
-
- if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((hctx = HMAC_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- if ((ret = ptls_buffer_reserve(buf, TICKET_LABEL_SIZE + TICKET_IV_SIZE + src.len + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE)) !=
- 0)
- goto Exit;
- dst = buf->base + buf->off;
-
- /* fill label and iv, as well as obtaining the keys */
- if (!(*cb)(dst, dst + TICKET_LABEL_SIZE, cctx, hctx, 1)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += TICKET_LABEL_SIZE + TICKET_IV_SIZE;
-
- /* encrypt */
- if (!EVP_EncryptUpdate(cctx, dst, &clen, src.base, (int)src.len)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += clen;
- if (!EVP_EncryptFinal_ex(cctx, dst, &clen)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += clen;
-
- /* append hmac */
- if (!HMAC_Update(hctx, buf->base + buf->off, dst - (buf->base + buf->off)) || !HMAC_Final(hctx, dst, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += HMAC_size(hctx);
-
- assert(dst <= buf->base + buf->capacity);
- buf->off += dst - (buf->base + buf->off);
- ret = 0;
-
-Exit:
- if (cctx != NULL)
- EVP_CIPHER_CTX_cleanup(cctx);
- if (hctx != NULL)
- HMAC_CTX_free(hctx);
- return ret;
-}
-
-int ptls_openssl_decrypt_ticket(ptls_buffer_t *buf, ptls_iovec_t src,
- int (*cb)(unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc))
-{
- EVP_CIPHER_CTX *cctx = NULL;
- HMAC_CTX *hctx = NULL;
- int clen, ret;
-
- if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((hctx = HMAC_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- /* obtain cipher and hash context.
- * Note: no need to handle renew, since in picotls we always send a new ticket to minimize the chance of ticket reuse */
- if (src.len < TICKET_LABEL_SIZE + TICKET_IV_SIZE) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if (!(*cb)(src.base, src.base + TICKET_LABEL_SIZE, cctx, hctx, 0)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
-
- /* check hmac, and exclude label, iv, hmac */
- size_t hmac_size = HMAC_size(hctx);
- if (src.len < TICKET_LABEL_SIZE + TICKET_IV_SIZE + hmac_size) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- src.len -= hmac_size;
- uint8_t hmac[EVP_MAX_MD_SIZE];
- if (!HMAC_Update(hctx, src.base, src.len) || !HMAC_Final(hctx, hmac, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (memcmp(src.base + src.len, hmac, hmac_size) != 0) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- src.base += TICKET_LABEL_SIZE + TICKET_IV_SIZE;
- src.len -= TICKET_LABEL_SIZE + TICKET_IV_SIZE;
-
- /* decrypt */
- if ((ret = ptls_buffer_reserve(buf, src.len)) != 0)
- goto Exit;
- if (!EVP_DecryptUpdate(cctx, buf->base + buf->off, &clen, src.base, (int)src.len)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- buf->off += clen;
- if (!EVP_DecryptFinal_ex(cctx, buf->base + buf->off, &clen)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- buf->off += clen;
-
- ret = 0;
-
-Exit:
- if (cctx != NULL)
- EVP_CIPHER_CTX_cleanup(cctx);
- if (hctx != NULL)
- HMAC_CTX_free(hctx);
- return ret;
-}
-
-ptls_key_exchange_algorithm_t ptls_openssl_secp256r1 = {PTLS_GROUP_SECP256R1, secp256r1_create_key_exchange,
- secp256r1_key_exchange};
-ptls_key_exchange_algorithm_t *ptls_openssl_key_exchanges[] = {&ptls_openssl_secp256r1, NULL};
-ptls_cipher_algorithm_t ptls_openssl_aes128ctr = {"AES128-CTR", PTLS_AES128_KEY_SIZE, PTLS_AES_IV_SIZE,
- sizeof(struct cipher_context_t), aes128ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_openssl_aes128gcm = {"AES128-GCM",
- &ptls_openssl_aes128ctr,
- PTLS_AES128_KEY_SIZE,
- PTLS_AESGCM_IV_SIZE,
- PTLS_AESGCM_TAG_SIZE,
- sizeof(struct aead_crypto_context_t),
- aead_aes128gcm_setup_crypto};
-ptls_cipher_algorithm_t ptls_openssl_aes256ctr = {"AES256-CTR", PTLS_AES256_KEY_SIZE, PTLS_AES_IV_SIZE,
- sizeof(struct cipher_context_t), aes256ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_openssl_aes256gcm = {"AES256-GCM",
- &ptls_openssl_aes256ctr,
- PTLS_AES256_KEY_SIZE,
- PTLS_AESGCM_IV_SIZE,
- PTLS_AESGCM_TAG_SIZE,
- sizeof(struct aead_crypto_context_t),
- aead_aes256gcm_setup_crypto};
-ptls_hash_algorithm_t ptls_openssl_sha256 = {PTLS_SHA256_BLOCK_SIZE, PTLS_SHA256_DIGEST_SIZE, sha256_create,
- PTLS_ZERO_DIGEST_SHA256};
-ptls_hash_algorithm_t ptls_openssl_sha384 = {PTLS_SHA384_BLOCK_SIZE, PTLS_SHA384_DIGEST_SIZE, sha384_create,
- PTLS_ZERO_DIGEST_SHA384};
-ptls_cipher_suite_t ptls_openssl_aes128gcmsha256 = {PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, &ptls_openssl_aes128gcm,
- &ptls_openssl_sha256};
-ptls_cipher_suite_t ptls_openssl_aes256gcmsha384 = {PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, &ptls_openssl_aes256gcm,
- &ptls_openssl_sha384};
-#if defined(PTLS_OPENSSL_HAVE_CHACHA20_POLY1305)
-ptls_cipher_algorithm_t ptls_openssl_chacha20 = {"CHACHA20", PTLS_CHACHA20_KEY_SIZE, PTLS_CHACHA20_IV_SIZE,
- sizeof(struct cipher_context_t), chacha20_setup_crypto};
-ptls_aead_algorithm_t ptls_openssl_chacha20poly1305 = {"CHACHA20-POLY1305",
- &ptls_openssl_chacha20,
- PTLS_CHACHA20_KEY_SIZE,
- PTLS_CHACHA20POLY1305_IV_SIZE,
- PTLS_CHACHA20POLY1305_TAG_SIZE,
- sizeof(struct aead_crypto_context_t),
- aead_chacha20poly1305_setup_crypto};
-ptls_cipher_suite_t ptls_openssl_chacha20poly1305sha256 = {PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256,
- &ptls_openssl_chacha20poly1305, &ptls_openssl_sha256};
-#endif
-ptls_cipher_suite_t *ptls_openssl_cipher_suites[] = {&ptls_openssl_aes256gcmsha384, &ptls_openssl_aes128gcmsha256,
-#if defined(PTLS_OPENSSL_HAVE_CHACHA20_POLY1305)
- &ptls_openssl_chacha20poly1305sha256,
-#endif
- NULL};
diff --git a/debian/vendor-h2o/deps/picotls/lib/pembase64.c b/debian/vendor-h2o/deps/picotls/lib/pembase64.c
deleted file mode 100644
index de44c53..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/pembase64.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
-* Copyright (c) 2016 Christian Huitema <huitema@huitema.net>
-*
-* Permission to use, copy, modify, and distribute this software for any
-* purpose with or without fee is hereby granted, provided that the above
-* copyright notice and this permission notice appear in all copies.
-*
-* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-/*
- * Manage Base64 encoding.
- */
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "picotls.h"
-#include "picotls/pembase64.h"
-
-static char ptls_base64_alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
-
-static char ptls_base64_values[] = {
- /* 0x00 to 0x0F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- /* 0x10 to 0x1F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- /* 0x20 to 0x2F. '+' at 2B, '/' at 2F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- /* 0x30 to 0x3F -- digits 0 to 9 at 0x30 to 0x39*/
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- /* 0x40 to 0x4F -- chars 'A' to 'O' at 0x41 to 0x4F */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- /* 0x50 to 0x5F -- chars 'P' to 'Z' at 0x50 to 0x5A */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- /* 0x60 to 0x6F -- chars 'a' to 'o' at 0x61 to 0x6F */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 0x70 to 0x7F -- chars 'p' to 'z' at 0x70 to 0x7A */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1};
-
-static void ptls_base64_cell(const uint8_t *data, char *text)
-{
- int n[4];
-
- n[0] = data[0] >> 2;
- n[1] = ((data[0] & 3) << 4) | (data[1] >> 4);
- n[2] = ((data[1] & 15) << 2) | (data[2] >> 6);
- n[3] = data[2] & 63;
-
- for (int i = 0; i < 4; i++) {
- text[i] = ptls_base64_alphabet[n[i]];
- }
-}
-
-size_t ptls_base64_howlong(size_t data_length)
-{
- return (((data_length + 2) / 3) * 4);
-}
-
-int ptls_base64_encode(const uint8_t *data, size_t data_len, char *ptls_base64_text)
-{
- int l = 0;
- int lt = 0;
-
- while ((data_len - l) >= 3) {
- ptls_base64_cell(data + l, ptls_base64_text + lt);
- l += 3;
- lt += 4;
- }
-
- switch (data_len - l) {
- case 0:
- break;
- case 1:
- ptls_base64_text[lt++] = ptls_base64_alphabet[data[l] >> 2];
- ptls_base64_text[lt++] = ptls_base64_alphabet[(data[l] & 3) << 4];
- ptls_base64_text[lt++] = '=';
- ptls_base64_text[lt++] = '=';
- break;
- case 2:
- ptls_base64_text[lt++] = ptls_base64_alphabet[data[l] >> 2];
- ptls_base64_text[lt++] = ptls_base64_alphabet[((data[l] & 3) << 4) | (data[l + 1] >> 4)];
- ptls_base64_text[lt++] = ptls_base64_alphabet[((data[l + 1] & 15) << 2)];
- ptls_base64_text[lt++] = '=';
- break;
- default:
- break;
- }
- ptls_base64_text[lt++] = 0;
-
- return lt;
-}
-
-/*
- * Take into input a line of text, so as to work by increments.
- * The intermediate text of the decoding is kept in a state variable.
- * The decoded data is accumulated in a PTLS buffer.
- * The parsing is consistent with the lax definition in RFC 7468
- */
-
-void ptls_base64_decode_init(ptls_base64_decode_state_t *state)
-{
- state->nbc = 0;
- state->nbo = 3;
- state->v = 0;
- state->status = PTLS_BASE64_DECODE_IN_PROGRESS;
-}
-
-int ptls_base64_decode(const char *text, ptls_base64_decode_state_t *state, ptls_buffer_t *buf)
-{
- int ret = 0;
- uint8_t decoded[3];
- size_t text_index = 0;
- int c;
- char vc;
-
- /* skip initial blanks */
- while (text[text_index] != 0) {
- c = text[text_index];
-
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
- text_index++;
- } else {
- break;
- }
- }
-
- while (text[text_index] != 0 && ret == 0 && state->status == PTLS_BASE64_DECODE_IN_PROGRESS) {
- c = text[text_index++];
-
- vc = 0 < c && c < 0x7f ? ptls_base64_values[c] : -1;
- if (vc == -1) {
- if (state->nbc == 2 && c == '=' && text[text_index] == '=') {
- state->nbc = 4;
- text_index++;
- state->nbo = 1;
- state->v <<= 12;
- } else if (state->nbc == 3 && c == '=') {
- state->nbc = 4;
- state->nbo = 2;
- state->v <<= 6;
- } else {
- /* Skip final blanks */
- text_index--;
- while (text[text_index] != 0) {
- c = text[text_index++];
-
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0x0B || c == 0x0C) {
- continue;
- }
- }
-
- /* Should now be at end of buffer */
- if (text[text_index] == 0) {
- break;
- } else {
- /* Not at end of buffer, signal a decoding error */
- state->nbo = 0;
- state->status = PTLS_BASE64_DECODE_FAILED;
- ret = PTLS_ERROR_INCORRECT_BASE64;
- }
- }
- } else {
- state->nbc++;
- state->v <<= 6;
- state->v |= vc;
- }
-
- if (ret == 0 && state->nbc == 4) {
- /* Convert to up to 3 octets */
- for (int j = 0; j < state->nbo; j++) {
- decoded[j] = (uint8_t)(state->v >> (8 * (2 - j)));
- }
-
- ret = ptls_buffer__do_pushv(buf, decoded, state->nbo);
-
- if (ret == 0) {
- /* test for fin or continuation */
- if (state->nbo < 3) {
- /* Check that there are only trainling blanks on this line */
- while (text[text_index] != 0) {
- c = text[text_index++];
-
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0x0B || c == 0x0C) {
- continue;
- }
- }
- if (text[text_index] == 0) {
- state->status = PTLS_BASE64_DECODE_DONE;
- } else {
- state->status = PTLS_BASE64_DECODE_FAILED;
- ret = PTLS_ERROR_INCORRECT_BASE64;
- }
- break;
- } else {
- state->v = 0;
- state->nbo = 3;
- state->nbc = 0;
- }
- }
- }
- }
- return ret;
-}
-
-/*
- * Reading a PEM file, to get an object:
- *
- * - Find first object, get the object name.
- * - If object label is what the application expects, parse, else skip to end.
- *
- * The following labels are defined in RFC 7468:
- *
- * Sec. Label ASN.1 Type Reference Module
- * ----+----------------------+-----------------------+---------+----------
- * 5 CERTIFICATE Certificate [RFC5280] id-pkix1-e
- * 6 X509 CRL CertificateList [RFC5280] id-pkix1-e
- * 7 CERTIFICATE REQUEST CertificationRequest [RFC2986] id-pkcs10
- * 8 PKCS7 ContentInfo [RFC2315] id-pkcs7*
- * 9 CMS ContentInfo [RFC5652] id-cms2004
- * 10 PRIVATE KEY PrivateKeyInfo ::= [RFC5208] id-pkcs8
- * OneAsymmetricKey [RFC5958] id-aKPV1
- * 11 ENCRYPTED PRIVATE KEY EncryptedPrivateKeyInfo [RFC5958] id-aKPV1
- * 12 ATTRIBUTE CERTIFICATE AttributeCertificate [RFC5755] id-acv2
- * 13 PUBLIC KEY SubjectPublicKeyInfo [RFC5280] id-pkix1-e
- */
-
-static int ptls_compare_separator_line(const char *line, const char *begin_or_end, const char *label)
-{
- int ret = strncmp(line, "-----", 5);
- size_t text_index = 5;
-
- if (ret == 0) {
- size_t begin_or_end_length = strlen(begin_or_end);
- ret = strncmp(line + text_index, begin_or_end, begin_or_end_length);
- text_index += begin_or_end_length;
- }
-
- if (ret == 0) {
- ret = line[text_index] - ' ';
- text_index++;
- }
-
- if (ret == 0) {
- size_t label_length = strlen(label);
- ret = strncmp(line + text_index, label, label_length);
- text_index += label_length;
- }
-
- if (ret == 0) {
- ret = strncmp(line + text_index, "-----", 5);
- }
-
- return ret;
-}
-
-static int ptls_get_pem_object(FILE *F, const char *label, ptls_buffer_t *buf)
-{
- int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
- char line[256];
- ptls_base64_decode_state_t state;
-
- /* Get the label on a line by itself */
- while (fgets(line, 256, F)) {
- if (ptls_compare_separator_line(line, "BEGIN", label) == 0) {
- ret = 0;
- ptls_base64_decode_init(&state);
- break;
- }
- }
- /* Get the data in the buffer */
- while (ret == 0 && fgets(line, 256, F)) {
- if (ptls_compare_separator_line(line, "END", label) == 0) {
- if (state.status == PTLS_BASE64_DECODE_DONE || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS && state.nbc == 0)) {
- ret = 0;
- } else {
- ret = PTLS_ERROR_INCORRECT_BASE64;
- }
- break;
- } else {
- ret = ptls_base64_decode(line, &state, buf);
- }
- }
-
- return ret;
-}
-
-int ptls_load_pem_objects(char const *pem_fname, const char *label, ptls_iovec_t *list, size_t list_max, size_t *nb_objects)
-{
- FILE *F;
- int ret = 0;
- size_t count = 0;
-#ifdef _WINDOWS
- errno_t err = fopen_s(&F, pem_fname, "r");
- if (err != 0) {
- ret = -1;
- }
-#else
- F = fopen(pem_fname, "r");
- if (F == NULL) {
- ret = -1;
- }
-#endif
-
- *nb_objects = 0;
-
- if (ret == 0) {
- while (count < list_max) {
- ptls_buffer_t buf;
-
- ptls_buffer_init(&buf, "", 0);
-
- ret = ptls_get_pem_object(F, label, &buf);
-
- if (ret == 0) {
- if (buf.off > 0 && buf.is_allocated) {
- list[count].base = buf.base;
- list[count].len = buf.off;
- count++;
- } else {
- ptls_buffer_dispose(&buf);
- }
- } else {
- ptls_buffer_dispose(&buf);
- break;
- }
- }
- }
-
- if (ret == PTLS_ERROR_PEM_LABEL_NOT_FOUND && count > 0) {
- ret = 0;
- }
-
- *nb_objects = count;
-
- if (F != NULL) {
- fclose(F);
- }
-
- return ret;
-}
-
-#define PTLS_MAX_CERTS_IN_CONTEXT 16
-
-int ptls_load_certificates(ptls_context_t *ctx, char *cert_pem_file)
-{
- int ret = 0;
-
- ctx->certificates.list = (ptls_iovec_t *)malloc(PTLS_MAX_CERTS_IN_CONTEXT * sizeof(ptls_iovec_t));
-
- if (ctx->certificates.list == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- } else {
- ret = ptls_load_pem_objects(cert_pem_file, "CERTIFICATE", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT,
- &ctx->certificates.count);
- }
-
- return ret;
-}
diff --git a/debian/vendor-h2o/deps/picotls/lib/picotls.c b/debian/vendor-h2o/deps/picotls/lib/picotls.c
deleted file mode 100644
index d328aaa..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/picotls.c
+++ /dev/null
@@ -1,3761 +0,0 @@
-/*
- * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#include <assert.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <sys/time.h>
-#endif
-#include "picotls.h"
-
-#define PTLS_MAX_PLAINTEXT_RECORD_SIZE 16384
-#define PTLS_MAX_ENCRYPTED_RECORD_SIZE (16384 + 256)
-
-#define PTLS_RECORD_VERSION_MAJOR 3
-#define PTLS_RECORD_VERSION_MINOR 3
-
-#define PTLS_HELLO_RANDOM_SIZE 32
-
-#define PTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC 20
-#define PTLS_CONTENT_TYPE_ALERT 21
-#define PTLS_CONTENT_TYPE_HANDSHAKE 22
-#define PTLS_CONTENT_TYPE_APPDATA 23
-
-#define PTLS_HANDSHAKE_TYPE_CLIENT_HELLO 1
-#define PTLS_HANDSHAKE_TYPE_SERVER_HELLO 2
-#define PTLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET 4
-#define PTLS_HANDSHAKE_TYPE_END_OF_EARLY_DATA 5
-#define PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS 8
-#define PTLS_HANDSHAKE_TYPE_CERTIFICATE 11
-#define PTLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST 13
-#define PTLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY 15
-#define PTLS_HANDSHAKE_TYPE_FINISHED 20
-#define PTLS_HANDSHAKE_TYPE_KEY_UPDATE 24
-#define PTLS_HANDSHAKE_TYPE_MESSAGE_HASH 254
-
-#define PTLS_PSK_KE_MODE_PSK 0
-#define PTLS_PSK_KE_MODE_PSK_DHE 1
-
-#define PTLS_HANDSHAKE_HEADER_SIZE 4
-
-#define PTLS_EXTENSION_TYPE_SERVER_NAME 0
-#define PTLS_EXTENSION_TYPE_STATUS_REQUEST 5
-#define PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS 10
-#define PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS 13
-#define PTLS_EXTENSION_TYPE_ALPN 16
-#define PTLS_EXTENSION_TYPE_PRE_SHARED_KEY 41
-#define PTLS_EXTENSION_TYPE_EARLY_DATA 42
-#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_KEY_SHARE 51
-
-#define PTLS_PROTOCOL_VERSION_DRAFT26 0x7f1a
-#define PTLS_PROTOCOL_VERSION_DRAFT27 0x7f1b
-#define PTLS_PROTOCOL_VERSION_DRAFT28 0x7f1c
-
-#define PTLS_SERVER_NAME_TYPE_HOSTNAME 0
-
-#define PTLS_SERVER_CERTIFICATE_VERIFY_CONTEXT_STRING "TLS 1.3, server CertificateVerify"
-#define PTLS_CLIENT_CERTIFICATE_VERIFY_CONTEXT_STRING "TLS 1.3, client CertificateVerify"
-#define PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE \
- (64 + sizeof(PTLS_SERVER_CERTIFICATE_VERIFY_CONTEXT_STRING) + PTLS_MAX_DIGEST_SIZE * 2)
-
-#define PTLS_EARLY_DATA_MAX_DELAY 10000 /* max. RTT (in msec) to permit early data */
-
-#if defined(PTLS_DEBUG) && PTLS_DEBUG
-#define PTLS_DEBUGF(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define PTLS_DEBUGF(...)
-#endif
-
-#ifndef PTLS_MEMORY_DEBUG
-#define PTLS_MEMORY_DEBUG 0
-#endif
-
-/**
- * list of supported versions in the preferred order
- */
-static const uint16_t supported_versions[] = {PTLS_PROTOCOL_VERSION_DRAFT28, PTLS_PROTOCOL_VERSION_DRAFT27,
- PTLS_PROTOCOL_VERSION_DRAFT26};
-
-static const uint8_t hello_retry_random[PTLS_HELLO_RANDOM_SIZE] = {0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C,
- 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB,
- 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
-
-struct st_ptls_traffic_protection_t {
- uint8_t secret[PTLS_MAX_DIGEST_SIZE];
- ptls_aead_context_t *aead;
- uint64_t seq;
-};
-
-struct st_ptls_early_data_t {
- uint8_t next_secret[PTLS_MAX_DIGEST_SIZE];
-};
-
-struct st_ptls_t {
- /**
- * the context
- */
- ptls_context_t *ctx;
- /**
- * the state
- */
- enum {
- PTLS_STATE_CLIENT_HANDSHAKE_START,
- PTLS_STATE_CLIENT_EXPECT_SERVER_HELLO,
- PTLS_STATE_CLIENT_EXPECT_SECOND_SERVER_HELLO,
- PTLS_STATE_CLIENT_EXPECT_ENCRYPTED_EXTENSIONS,
- PTLS_STATE_CLIENT_EXPECT_CERTIFICATE,
- PTLS_STATE_CLIENT_EXPECT_CERTIFICATE_VERIFY,
- PTLS_STATE_CLIENT_EXPECT_FINISHED,
- PTLS_STATE_SERVER_EXPECT_CLIENT_HELLO,
- PTLS_STATE_SERVER_EXPECT_SECOND_CLIENT_HELLO,
- /* ptls_send can be called if the state is below here */
- PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA,
- PTLS_STATE_SERVER_EXPECT_FINISHED,
- PTLS_STATE_POST_HANDSHAKE_MIN,
- PTLS_STATE_CLIENT_POST_HANDSHAKE = PTLS_STATE_POST_HANDSHAKE_MIN,
- PTLS_STATE_SERVER_POST_HANDSHAKE
- } state;
- /**
- * receive buffers
- */
- struct {
- ptls_buffer_t rec;
- ptls_buffer_t mess;
- } recvbuf;
- /**
- * key schedule
- */
- struct st_ptls_key_schedule_t *key_schedule;
- /**
- * values used for record protection
- */
- struct {
- struct st_ptls_traffic_protection_t dec;
- struct st_ptls_traffic_protection_t enc;
- } traffic_protection;
- /**
- * server-name passed using SNI
- */
- char *server_name;
- /**
- * result of ALPN
- */
- char *negotiated_protocol;
- /**
- * selected key-exchange
- */
- ptls_key_exchange_algorithm_t *key_share;
- /**
- * selected cipher-suite
- */
- ptls_cipher_suite_t *cipher_suite;
- /**
- * clienthello.random
- */
- uint8_t client_random[PTLS_HELLO_RANDOM_SIZE];
- /* flags */
- unsigned is_server : 1;
- unsigned is_psk_handshake : 1;
- unsigned skip_early_data : 1; /* if early-data is not recognized by the server */
- unsigned send_change_cipher_spec : 1;
- /**
- * exporter master secret (either 0rtt or 1rtt)
- */
- struct {
- uint8_t *early;
- uint8_t *one_rtt;
- } exporter_master_secret;
- /**
- * misc.
- */
- union {
- struct {
- uint8_t legacy_session_id[16];
- ptls_key_exchange_context_t *key_share_ctx;
- struct {
- int (*cb)(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t signature);
- void *verify_ctx;
- } certificate_verify;
- unsigned offered_psk : 1;
- } client;
- struct {
- uint8_t pending_traffic_secret[PTLS_MAX_DIGEST_SIZE];
- } server;
- };
- /**
- * the value contains the traffic secret to be commisioned after END_OF_EARLY_DATA
- * END_OF_EARLY_DATA
- */
- struct st_ptls_early_data_t *early_data;
- /**
- * user data
- */
- void *data_ptr;
-};
-
-struct st_ptls_record_t {
- uint8_t type;
- uint16_t version;
- size_t length;
- const uint8_t *fragment;
-};
-
-struct st_ptls_client_hello_psk_t {
- ptls_iovec_t identity;
- uint32_t obfuscated_ticket_age;
- ptls_iovec_t binder;
-};
-
-#define MAX_UNKNOWN_EXTENSIONS 16
-
-struct st_ptls_client_hello_t {
- const uint8_t *random_bytes;
- ptls_iovec_t legacy_session_id;
- struct {
- const uint8_t *ids;
- size_t count;
- } compression_methods;
- uint16_t selected_version;
- ptls_iovec_t cipher_suites;
- ptls_iovec_t negotiated_groups;
- ptls_iovec_t key_shares;
- struct {
- uint16_t list[16]; /* expand? */
- size_t count;
- } signature_algorithms;
- ptls_iovec_t server_name;
- struct {
- ptls_iovec_t list[16];
- size_t count;
- } alpn;
- struct {
- ptls_iovec_t all;
- ptls_iovec_t tbs;
- ptls_iovec_t ch1_hash;
- ptls_iovec_t signature;
- unsigned sent_key_share : 1;
- } cookie;
- struct {
- const uint8_t *hash_end;
- struct {
- struct st_ptls_client_hello_psk_t list[4];
- size_t count;
- } identities;
- unsigned ke_modes;
- int early_data_indication;
- } psk;
- ptls_raw_extension_t unknown_extensions[MAX_UNKNOWN_EXTENSIONS + 1];
- unsigned status_request : 1;
-};
-
-struct st_ptls_server_hello_t {
- uint8_t random_[PTLS_HELLO_RANDOM_SIZE];
- ptls_iovec_t legacy_session_id;
- int is_retry_request;
- union {
- ptls_iovec_t peerkey;
- struct {
- uint16_t selected_group;
- ptls_iovec_t cookie;
- } retry_request;
- };
-};
-
-struct st_ptls_key_schedule_t {
- unsigned generation; /* early secret (1), hanshake secret (2), master secret (3) */
- uint8_t secret[PTLS_MAX_DIGEST_SIZE];
- size_t num_hashes;
- struct {
- ptls_hash_algorithm_t *algo;
- ptls_hash_context_t *ctx;
- } hashes[1];
-};
-
-struct st_ptls_extension_decoder_t {
- uint16_t type;
- int (*cb)(ptls_t *tls, void *arg, const uint8_t *src, const uint8_t *const end);
-};
-
-struct st_ptls_extension_bitmap_t {
- uint8_t bits[8]; /* only ids below 64 is tracked */
-};
-
-static uint8_t zeroes_of_max_digest_size[PTLS_MAX_DIGEST_SIZE] = {0};
-
-static int is_supported_version(uint16_t v)
-{
- size_t i;
- for (i = 0; i != sizeof(supported_versions) / sizeof(supported_versions[0]); ++i)
- if (supported_versions[i] == v)
- return 1;
- return 0;
-}
-
-static inline int extension_bitmap_is_set(struct st_ptls_extension_bitmap_t *bitmap, uint16_t id)
-{
- if (id < sizeof(bitmap->bits) * 8)
- return (bitmap->bits[id / 8] & (1 << (id % 8))) != 0;
- return 0;
-}
-
-static inline void extension_bitmap_set(struct st_ptls_extension_bitmap_t *bitmap, uint16_t id)
-{
- if (id < sizeof(bitmap->bits) * 8)
- bitmap->bits[id / 8] |= 1 << (id % 8);
-}
-
-static inline void init_extension_bitmap(struct st_ptls_extension_bitmap_t *bitmap, uint8_t hstype)
-{
- *bitmap = (struct st_ptls_extension_bitmap_t){{0}};
-
-#define EXT(extid, proc) \
- do { \
- int _found = 0; \
- do { \
- proc \
- } while (0); \
- if (!_found) \
- extension_bitmap_set(bitmap, PTLS_EXTENSION_TYPE_##extid); \
- } while (0)
-#define ALLOW(allowed_hstype) _found = _found || hstype == PTLS_HANDSHAKE_TYPE_##allowed_hstype
-
- /* Implements the table found in section 4.2 of draft-19; "If an implementation receives an extension which it recognizes and
- * which is not specified for the message in which it appears it MUST abort the handshake with an “illegal_parameter” alert."
- */
- EXT(SERVER_NAME, {
- ALLOW(CLIENT_HELLO);
- ALLOW(ENCRYPTED_EXTENSIONS);
- });
- EXT(STATUS_REQUEST, {
- ALLOW(CLIENT_HELLO);
- ALLOW(CERTIFICATE);
- });
- EXT(SUPPORTED_GROUPS, {
- ALLOW(CLIENT_HELLO);
- ALLOW(ENCRYPTED_EXTENSIONS);
- });
- EXT(SIGNATURE_ALGORITHMS, { ALLOW(CLIENT_HELLO); });
- EXT(ALPN, {
- ALLOW(CLIENT_HELLO);
- ALLOW(ENCRYPTED_EXTENSIONS);
- });
- EXT(KEY_SHARE, {
- ALLOW(CLIENT_HELLO);
- ALLOW(SERVER_HELLO);
- });
- EXT(PRE_SHARED_KEY, {
- ALLOW(CLIENT_HELLO);
- ALLOW(SERVER_HELLO);
- });
- EXT(PSK_KEY_EXCHANGE_MODES, { ALLOW(CLIENT_HELLO); });
- EXT(EARLY_DATA, {
- ALLOW(CLIENT_HELLO);
- ALLOW(ENCRYPTED_EXTENSIONS);
- ALLOW(NEW_SESSION_TICKET);
- });
- EXT(COOKIE, {
- ALLOW(CLIENT_HELLO);
- ALLOW(SERVER_HELLO);
- });
- EXT(SUPPORTED_VERSIONS, {
- ALLOW(CLIENT_HELLO);
- ALLOW(SERVER_HELLO);
- });
-
-#undef ALLOW
-#undef EXT
-}
-
-static uint16_t ntoh16(const uint8_t *src)
-{
- return (uint16_t)src[0] << 8 | src[1];
-}
-
-static uint32_t ntoh24(const uint8_t *src)
-{
- return (uint32_t)src[0] << 16 | (uint32_t)src[1] << 8 | src[2];
-}
-
-static uint32_t ntoh32(const uint8_t *src)
-{
- return (uint32_t)src[0] << 24 | (uint32_t)src[1] << 16 | (uint32_t)src[2] << 8 | src[3];
-}
-
-static uint64_t ntoh64(const uint8_t *src)
-{
- return (uint64_t)src[0] << 56 | (uint64_t)src[1] << 48 | (uint64_t)src[2] << 40 | (uint64_t)src[3] << 32 |
- (uint64_t)src[4] << 24 | (uint64_t)src[5] << 16 | (uint64_t)src[6] << 8 | src[7];
-}
-
-void ptls_buffer__release_memory(ptls_buffer_t *buf)
-{
- ptls_clear_memory(buf->base, buf->off);
- if (buf->is_allocated)
- free(buf->base);
-}
-
-int ptls_buffer_reserve(ptls_buffer_t *buf, size_t delta)
-{
- if (buf->base == NULL)
- return PTLS_ERROR_NO_MEMORY;
-
- if (PTLS_MEMORY_DEBUG || buf->capacity < buf->off + delta) {
- uint8_t *newp;
- size_t new_capacity = buf->capacity;
- if (new_capacity < 1024)
- new_capacity = 1024;
- while (new_capacity < buf->off + delta) {
- new_capacity *= 2;
- }
- if ((newp = malloc(new_capacity)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- memcpy(newp, buf->base, buf->off);
- ptls_buffer__release_memory(buf);
- buf->base = newp;
- buf->capacity = new_capacity;
- buf->is_allocated = 1;
- }
-
- return 0;
-}
-
-int ptls_buffer__do_pushv(ptls_buffer_t *buf, const void *src, size_t len)
-{
- int ret;
-
- if (len == 0)
- return 0;
- if ((ret = ptls_buffer_reserve(buf, len)) != 0)
- return ret;
- memcpy(buf->base + buf->off, src, len);
- buf->off += len;
- return 0;
-}
-
-int ptls_buffer__adjust_asn1_blocksize(ptls_buffer_t *buf, size_t body_size)
-{
- fprintf(stderr, "unimplemented\n");
- abort();
-}
-
-int ptls_buffer_push_asn1_ubigint(ptls_buffer_t *buf, const void *bignum, size_t size)
-{
- const uint8_t *p = bignum, *const end = p + size;
- int ret;
-
- /* skip zeroes */
- for (; end - p >= 1; ++p)
- if (*p != 0)
- break;
-
- /* emit */
- ptls_buffer_push(buf, 2);
- ptls_buffer_push_asn1_block(buf, {
- if (*p >= 0x80)
- ptls_buffer_push(buf, 0);
- if (p != end) {
- ptls_buffer_pushv(buf, p, end - p);
- } else {
- ptls_buffer_pushv(buf, "", 1);
- }
- });
- ret = 0;
-
-Exit:
- return ret;
-}
-
-static void build_aad(uint8_t aad[5], size_t reclen)
-{
- aad[0] = PTLS_CONTENT_TYPE_APPDATA;
- aad[1] = PTLS_RECORD_VERSION_MAJOR;
- aad[2] = PTLS_RECORD_VERSION_MINOR;
- aad[3] = (uint8_t)(reclen >> 8);
- aad[4] = (uint8_t)reclen;
-}
-
-static size_t aead_encrypt(struct st_ptls_traffic_protection_t *ctx, void *output, const void *input, size_t inlen,
- uint8_t content_type)
-{
- uint8_t aad[5];
- size_t off = 0;
-
- build_aad(aad, inlen + 1 + ctx->aead->algo->tag_size);
- ptls_aead_encrypt_init(ctx->aead, ctx->seq++, aad, sizeof(aad));
- off += ptls_aead_encrypt_update(ctx->aead, ((uint8_t *)output) + off, input, inlen);
- off += ptls_aead_encrypt_update(ctx->aead, ((uint8_t *)output) + off, &content_type, 1);
- off += ptls_aead_encrypt_final(ctx->aead, ((uint8_t *)output) + off);
-
- return off;
-}
-
-static int aead_decrypt(struct st_ptls_traffic_protection_t *ctx, void *output, size_t *outlen, const void *input, size_t inlen)
-{
- uint8_t aad[5];
-
- build_aad(aad, inlen);
- if ((*outlen = ptls_aead_decrypt(ctx->aead, output, input, inlen, ctx->seq, aad, sizeof(aad))) == SIZE_MAX)
- return PTLS_ALERT_BAD_RECORD_MAC;
- ++ctx->seq;
- return 0;
-}
-
-#define buffer_push_record(buf, type, block) \
- do { \
- ptls_buffer_push((buf), (type), PTLS_RECORD_VERSION_MAJOR, PTLS_RECORD_VERSION_MINOR); \
- ptls_buffer_push_block((buf), 2, block); \
- } while (0)
-
-static int buffer_push_encrypted_records(ptls_buffer_t *buf, uint8_t type, const uint8_t *src, size_t len,
- struct st_ptls_traffic_protection_t *enc)
-{
- int ret = 0;
-
- while (len != 0) {
- size_t chunk_size = len;
- if (chunk_size > PTLS_MAX_PLAINTEXT_RECORD_SIZE)
- chunk_size = PTLS_MAX_PLAINTEXT_RECORD_SIZE;
- buffer_push_record(buf, PTLS_CONTENT_TYPE_APPDATA, {
- if ((ret = ptls_buffer_reserve(buf, chunk_size + enc->aead->algo->tag_size + 1)) != 0)
- goto Exit;
- buf->off += aead_encrypt(enc, buf->base + buf->off, src, chunk_size, type);
- });
- src += chunk_size;
- len -= chunk_size;
- }
-
-Exit:
- return ret;
-}
-
-static int buffer_encrypt_record(ptls_buffer_t *buf, size_t rec_start, struct st_ptls_traffic_protection_t *enc)
-{
- size_t bodylen = buf->off - rec_start - 5;
- uint8_t *tmpbuf, type = buf->base[rec_start];
- int ret;
-
- /* fast path: do in-place encryption if only one record needs to be emitted */
- if (bodylen <= PTLS_MAX_PLAINTEXT_RECORD_SIZE) {
- size_t overhead = 1 + enc->aead->algo->tag_size;
- if ((ret = ptls_buffer_reserve(buf, overhead)) != 0)
- return ret;
- size_t encrypted_len = aead_encrypt(enc, buf->base + rec_start + 5, buf->base + rec_start + 5, bodylen, type);
- assert(encrypted_len == bodylen + overhead);
- buf->off += overhead;
- buf->base[rec_start] = PTLS_CONTENT_TYPE_APPDATA;
- buf->base[rec_start + 3] = (encrypted_len >> 8) & 0xff;
- buf->base[rec_start + 4] = encrypted_len & 0xff;
- return 0;
- }
-
- /* move plaintext to temporary buffer */
- if ((tmpbuf = malloc(bodylen)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- memcpy(tmpbuf, buf->base + rec_start + 5, bodylen);
- ptls_clear_memory(buf->base + rec_start, bodylen + 5);
- buf->off = rec_start;
-
- /* push encrypted records */
- ret = buffer_push_encrypted_records(buf, type, tmpbuf, bodylen, enc);
-
-Exit:
- if (tmpbuf != NULL) {
- ptls_clear_memory(tmpbuf, bodylen);
- free(tmpbuf);
- }
- return ret;
-}
-
-#define buffer_push_handshake_body(buf, key_sched, type, block) \
- do { \
- size_t mess_start = (buf)->off; \
- ptls_buffer_push((buf), (type)); \
- ptls_buffer_push_block((buf), 3, { \
- do { \
- block \
- } while (0); \
- }); \
- if ((key_sched) != NULL) \
- key_schedule_update_hash((key_sched), (buf)->base + (mess_start), (buf)->off - (mess_start)); \
- } while (0)
-
-#define buffer_push_handshake(buf, key_sched, enc, type, block) \
- do { \
- size_t rec_start = (buf)->off; \
- buffer_push_record((buf), PTLS_CONTENT_TYPE_HANDSHAKE, \
- { buffer_push_handshake_body((buf), (key_sched), (type), block); }); \
- if ((enc) != NULL) { \
- if ((ret = buffer_encrypt_record((buf), rec_start, (enc))) != 0) \
- goto Exit; \
- } \
- } while (0)
-
-#define buffer_push_extension(buf, type, block) \
- do { \
- ptls_buffer_push16((buf), (type)); \
- ptls_buffer_push_block((buf), 2, block); \
- } while (0);
-
-#define decode_open_extensions(src, end, hstype, exttype, block) \
- do { \
- struct st_ptls_extension_bitmap_t bitmap; \
- init_extension_bitmap(&bitmap, (hstype)); \
- ptls_decode_open_block((src), end, 2, { \
- while ((src) != end) { \
- if ((ret = ptls_decode16((exttype), &(src), end)) != 0) \
- goto Exit; \
- if (extension_bitmap_is_set(&bitmap, *(exttype)) != 0) { \
- ret = PTLS_ALERT_ILLEGAL_PARAMETER; \
- goto Exit; \
- } \
- extension_bitmap_set(&bitmap, *(exttype)); \
- ptls_decode_open_block((src), end, 2, block); \
- } \
- }); \
- } while (0)
-
-#define decode_extensions(src, end, hstype, exttype, block) \
- do { \
- decode_open_extensions((src), end, hstype, exttype, block); \
- ptls_decode_assert_block_close((src), end); \
- } while (0)
-
-int ptls_decode16(uint16_t *value, const uint8_t **src, const uint8_t *end)
-{
- if (end - *src < 2)
- return PTLS_ALERT_DECODE_ERROR;
- *value = ntoh16(*src);
- *src += 2;
- return 0;
-}
-
-int ptls_decode32(uint32_t *value, const uint8_t **src, const uint8_t *end)
-{
- if (end - *src < 4)
- return PTLS_ALERT_DECODE_ERROR;
- *value = ntoh32(*src);
- *src += 4;
- return 0;
-}
-
-int ptls_decode64(uint64_t *value, const uint8_t **src, const uint8_t *end)
-{
- if (end - *src < 8)
- return PTLS_ALERT_DECODE_ERROR;
- *value = ntoh64(*src);
- *src += 8;
- return 0;
-}
-
-static void key_schedule_free(struct st_ptls_key_schedule_t *sched)
-{
- size_t i;
- ptls_clear_memory(sched->secret, sizeof(sched->secret));
- for (i = 0; i != sched->num_hashes; ++i)
- sched->hashes[i].ctx->final(sched->hashes[i].ctx, NULL, PTLS_HASH_FINAL_MODE_FREE);
- free(sched);
-}
-
-static struct st_ptls_key_schedule_t *key_schedule_new(ptls_cipher_suite_t *preferred, ptls_cipher_suite_t **offered)
-{
-#define FOREACH_HASH(block) \
- do { \
- ptls_cipher_suite_t *cs; \
- if ((cs = preferred) != NULL) { \
- block \
- } \
- if (offered != NULL) { \
- size_t i, j; \
- for (i = 0; (cs = offered[i]) != NULL; ++i) { \
- if (preferred == NULL || cs->hash != preferred->hash) { \
- for (j = 0; j != i; ++j) \
- if (cs->hash == offered[j]->hash) \
- break; \
- if (j == i) { \
- block \
- } \
- } \
- } \
- } \
- } while (0)
-
- struct st_ptls_key_schedule_t *sched;
-
- { /* allocate */
- size_t num_hashes = 0;
- FOREACH_HASH({ ++num_hashes; });
- if ((sched = malloc(offsetof(struct st_ptls_key_schedule_t, hashes) + sizeof(sched->hashes[0]) * num_hashes)) == NULL)
- return NULL;
- *sched = (struct st_ptls_key_schedule_t){0};
- }
-
- /* setup the hash algos and contexts */
- FOREACH_HASH({
- sched->hashes[sched->num_hashes].algo = cs->hash;
- if ((sched->hashes[sched->num_hashes].ctx = cs->hash->create()) == NULL)
- goto Fail;
- ++sched->num_hashes;
- });
-
- return sched;
-Fail:
- key_schedule_free(sched);
- return NULL;
-
-#undef FOREACH_HASH
-}
-
-static int key_schedule_extract(struct st_ptls_key_schedule_t *sched, ptls_iovec_t ikm)
-{
- int ret;
-
- if (ikm.base == NULL)
- ikm = ptls_iovec_init(zeroes_of_max_digest_size, sched->hashes[0].algo->digest_size);
-
- if (sched->generation != 0 &&
- (ret = ptls_hkdf_expand_label(sched->hashes[0].algo, sched->secret, sched->hashes[0].algo->digest_size,
- ptls_iovec_init(sched->secret, sched->hashes[0].algo->digest_size), "derived",
- ptls_iovec_init(sched->hashes[0].algo->empty_digest, sched->hashes[0].algo->digest_size),
- NULL)) != 0)
- return ret;
-
- ++sched->generation;
- ret = ptls_hkdf_extract(sched->hashes[0].algo, sched->secret,
- ptls_iovec_init(sched->secret, sched->hashes[0].algo->digest_size), ikm);
- PTLS_DEBUGF("%s: %u, %02x%02x\n", __FUNCTION__, sched->generation, (int)sched->secret[0], (int)sched->secret[1]);
- return ret;
-}
-
-static int key_schedule_select_one(struct st_ptls_key_schedule_t *sched, ptls_cipher_suite_t *cs, int reset)
-{
- size_t found_slot = SIZE_MAX, i;
- int ret;
-
- assert(sched->generation == 1);
-
- /* find the one, while freeing others */
- for (i = 0; i != sched->num_hashes; ++i) {
- if (sched->hashes[i].algo == cs->hash) {
- assert(found_slot == SIZE_MAX);
- found_slot = i;
- } else {
- sched->hashes[i].ctx->final(sched->hashes[i].ctx, NULL, PTLS_HASH_FINAL_MODE_FREE);
- }
- }
- if (found_slot != 0) {
- sched->hashes[0] = sched->hashes[found_slot];
- reset = 1;
- }
- sched->num_hashes = 1;
-
- /* recalculate the hash if a different hash as been selected than the one we used for calculating the early secrets */
- if (reset) {
- --sched->generation;
- memset(sched->secret, 0, sizeof(sched->secret));
- if ((ret = key_schedule_extract(sched, ptls_iovec_init(NULL, 0))) != 0)
- goto Exit;
- }
-
- ret = 0;
-Exit:
- return ret;
-}
-
-static void key_schedule_update_hash(struct st_ptls_key_schedule_t *sched, const uint8_t *msg, size_t msglen)
-{
- size_t i;
-
- PTLS_DEBUGF("%s:%zu\n", __FUNCTION__, msglen);
- for (i = 0; i != sched->num_hashes; ++i)
- sched->hashes[i].ctx->update(sched->hashes[i].ctx, msg, msglen);
-}
-
-static void key_schedule_update_ch1hash_prefix(struct st_ptls_key_schedule_t *sched)
-{
- uint8_t prefix[4] = {PTLS_HANDSHAKE_TYPE_MESSAGE_HASH, 0, 0, (uint8_t)sched->hashes[0].algo->digest_size};
- key_schedule_update_hash(sched, prefix, sizeof(prefix));
-}
-
-static void key_schedule_extract_ch1hash(struct st_ptls_key_schedule_t *sched, uint8_t *hash)
-{
- sched->hashes[0].ctx->final(sched->hashes[0].ctx, hash, PTLS_HASH_FINAL_MODE_RESET);
-}
-
-static void key_schedule_transform_post_ch1hash(struct st_ptls_key_schedule_t *sched)
-{
- uint8_t ch1hash[PTLS_MAX_DIGEST_SIZE];
-
- key_schedule_extract_ch1hash(sched, ch1hash);
-
- key_schedule_update_ch1hash_prefix(sched);
- key_schedule_update_hash(sched, ch1hash, sched->hashes[0].algo->digest_size);
-}
-
-static int derive_secret_with_hash(struct st_ptls_key_schedule_t *sched, void *secret, const char *label, const uint8_t *hash)
-{
- int ret = ptls_hkdf_expand_label(sched->hashes[0].algo, secret, sched->hashes[0].algo->digest_size,
- ptls_iovec_init(sched->secret, sched->hashes[0].algo->digest_size), label,
- ptls_iovec_init(hash, sched->hashes[0].algo->digest_size), NULL);
- PTLS_DEBUGF("%s: (label=%s, hash=%02x%02x) => %02x%02x\n", __FUNCTION__, label, hash[0], hash[1], ((uint8_t *)secret)[0],
- ((uint8_t *)secret)[1]);
- return ret;
-}
-
-static int derive_secret(struct st_ptls_key_schedule_t *sched, void *secret, const char *label)
-{
- uint8_t hash_value[PTLS_MAX_DIGEST_SIZE];
-
- sched->hashes[0].ctx->final(sched->hashes[0].ctx, hash_value, PTLS_HASH_FINAL_MODE_SNAPSHOT);
- int ret = derive_secret_with_hash(sched, secret, label, hash_value);
- ptls_clear_memory(hash_value, sizeof(hash_value));
- return ret;
-}
-
-static int derive_secret_with_empty_digest(struct st_ptls_key_schedule_t *sched, void *secret, const char *label)
-{
- return derive_secret_with_hash(sched, secret, label, sched->hashes[0].algo->empty_digest);
-}
-
-static int derive_exporter_secret(ptls_t *tls, int is_early)
-{
- if (tls->ctx->use_exporter)
- return 0;
-
- uint8_t **slot = is_early ? &tls->exporter_master_secret.early : &tls->exporter_master_secret.one_rtt;
- assert(*slot == NULL);
- if ((*slot = malloc(tls->key_schedule->hashes[0].algo->digest_size)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- return derive_secret(tls->key_schedule, *slot, is_early ? "e exp master" : "exp master");
-}
-
-static void free_exporter_master_secret(ptls_t *tls, int is_early)
-{
- uint8_t *slot = is_early ? tls->exporter_master_secret.early : tls->exporter_master_secret.one_rtt;
- if (slot == NULL)
- return;
- assert(tls->key_schedule != NULL);
- ptls_clear_memory(slot, tls->key_schedule->hashes[0].algo->digest_size);
- free(slot);
-}
-
-static int derive_resumption_secret(struct st_ptls_key_schedule_t *sched, uint8_t *secret, ptls_iovec_t nonce)
-{
- int ret;
-
- if ((ret = derive_secret(sched, secret, "res master")) != 0)
- goto Exit;
- if ((ret = ptls_hkdf_expand_label(sched->hashes[0].algo, secret, sched->hashes[0].algo->digest_size,
- ptls_iovec_init(secret, sched->hashes[0].algo->digest_size), "resumption", nonce, NULL)) != 0)
- goto Exit;
-
-Exit:
- if (ret != 0)
- ptls_clear_memory(secret, sched->hashes[0].algo->digest_size);
- return ret;
-}
-
-static int decode_new_session_ticket(uint32_t *lifetime, uint32_t *age_add, ptls_iovec_t *nonce, ptls_iovec_t *ticket,
- uint32_t *max_early_data_size, const uint8_t *src, const uint8_t *const end)
-{
- uint16_t exttype;
- int ret;
-
- if ((ret = ptls_decode32(lifetime, &src, end)) != 0)
- goto Exit;
- if ((ret = ptls_decode32(age_add, &src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(src, end, 1, {
- *nonce = ptls_iovec_init(src, end - src);
- src = end;
- });
- ptls_decode_open_block(src, end, 2, {
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- *ticket = ptls_iovec_init(src, end - src);
- src = end;
- });
-
- *max_early_data_size = 0;
- decode_extensions(src, end, PTLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET, &exttype, {
- switch (exttype) {
- case PTLS_EXTENSION_TYPE_EARLY_DATA:
- if ((ret = ptls_decode32(max_early_data_size, &src, end)) != 0)
- goto Exit;
- break;
- default:
- src = end;
- break;
- }
- });
-
- ret = 0;
-Exit:
- return ret;
-}
-
-static int decode_stored_session_ticket(ptls_context_t *ctx, ptls_key_exchange_algorithm_t **key_share, ptls_cipher_suite_t **cs,
- ptls_iovec_t *secret, uint32_t *obfuscated_ticket_age, ptls_iovec_t *ticket,
- uint32_t *max_early_data_size, const uint8_t *src, const uint8_t *const end)
-{
- uint16_t kxid, csid;
- uint32_t lifetime, age_add;
- uint64_t obtained_at, now;
- ptls_iovec_t nonce;
- int ret;
-
- /* decode */
- if ((ret = ptls_decode64(&obtained_at, &src, end)) != 0)
- goto Exit;
- if ((ret = ptls_decode16(&kxid, &src, end)) != 0)
- goto Exit;
- if ((ret = ptls_decode16(&csid, &src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(src, end, 3, {
- if ((ret = decode_new_session_ticket(&lifetime, &age_add, &nonce, ticket, max_early_data_size, src, end)) != 0)
- goto Exit;
- src = end;
- });
- ptls_decode_block(src, end, 2, {
- *secret = ptls_iovec_init(src, end - src);
- src = end;
- });
-
- { /* determine the key-exchange */
- ptls_key_exchange_algorithm_t **cand;
- for (cand = ctx->key_exchanges; *cand != NULL; ++cand)
- if ((*cand)->id == kxid)
- break;
- if (*cand == NULL) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- *key_share = *cand;
- }
-
- { /* determine the cipher-suite */
- ptls_cipher_suite_t **cand;
- for (cand = ctx->cipher_suites; *cand != NULL; ++cand)
- if ((*cand)->id == csid)
- break;
- if (*cand == NULL) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- *cs = *cand;
- }
-
- /* calculate obfuscated_ticket_age */
- now = ctx->get_time->cb(ctx->get_time);
- if (!(obtained_at <= now && now - obtained_at < 7 * 86400 * 1000)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- *obfuscated_ticket_age = (uint32_t)(now - obtained_at) + age_add;
-
- ret = 0;
-Exit:
- return ret;
-}
-
-static int get_traffic_key(ptls_hash_algorithm_t *algo, void *key, size_t key_size, int is_iv, const void *secret,
- const char *base_label)
-{
- return ptls_hkdf_expand_label(algo, key, key_size, ptls_iovec_init(secret, algo->digest_size), is_iv ? "iv" : "key",
- ptls_iovec_init(NULL, 0), base_label);
-}
-
-static int setup_traffic_protection(ptls_t *tls, int is_enc, const char *secret_label, const char *log_label)
-{
- struct st_ptls_traffic_protection_t *ctx = is_enc ? &tls->traffic_protection.enc : &tls->traffic_protection.dec;
-
- if (secret_label != NULL) {
- int ret;
- if ((ret = derive_secret(tls->key_schedule, ctx->secret, secret_label)) != 0)
- return ret;
- }
-
- if (ctx->aead != NULL)
- ptls_aead_free(ctx->aead);
- if ((ctx->aead = ptls_aead_new(tls->cipher_suite->aead, tls->cipher_suite->hash, is_enc, ctx->secret, NULL)) == NULL)
- return PTLS_ERROR_NO_MEMORY; /* TODO obtain error from ptls_aead_new */
- ctx->seq = 0;
-
- if (tls->ctx->log_secret != NULL)
- tls->ctx->log_secret->cb(tls->ctx->log_secret, tls, log_label,
- ptls_iovec_init(ctx->secret, tls->key_schedule->hashes[0].algo->digest_size));
- PTLS_DEBUGF("[%s] %02x%02x,%02x%02x\n", log_label, (unsigned)ctx->secret[0], (unsigned)ctx->secret[1],
- (unsigned)ctx->aead->static_iv[0], (unsigned)ctx->aead->static_iv[1]);
-
- return 0;
-}
-
-static int retire_early_data_secret(ptls_t *tls, int is_enc)
-{
- assert(tls->early_data != NULL);
- memcpy((is_enc ? &tls->traffic_protection.enc : &tls->traffic_protection.dec)->secret, tls->early_data->next_secret,
- PTLS_MAX_DIGEST_SIZE);
- ptls_clear_memory(tls->early_data, sizeof(*tls->early_data));
- free(tls->early_data);
- tls->early_data = NULL;
-
- return setup_traffic_protection(tls, is_enc, NULL, "CLIENT_HANDSHAKE_TRAFFIC_SECRET");
-}
-
-#define SESSION_IDENTIFIER_MAGIC "ptls0001" /* the number should be changed upon incompatible format change */
-#define SESSION_IDENTIFIER_MAGIC_SIZE (sizeof(SESSION_IDENTIFIER_MAGIC) - 1)
-
-static int encode_session_identifier(ptls_context_t *ctx, ptls_buffer_t *buf, uint32_t ticket_age_add, ptls_iovec_t ticket_nonce,
- struct st_ptls_key_schedule_t *sched, const char *server_name, uint16_t key_exchange_id,
- uint16_t csid, const char *negotiated_protocol)
-{
- int ret = 0;
-
- ptls_buffer_push_block(buf, 2, {
- /* format id */
- ptls_buffer_pushv(buf, SESSION_IDENTIFIER_MAGIC, SESSION_IDENTIFIER_MAGIC_SIZE);
- /* date */
- ptls_buffer_push64(buf, ctx->get_time->cb(ctx->get_time));
- /* resumption master secret */
- ptls_buffer_push_block(buf, 2, {
- if ((ret = ptls_buffer_reserve(buf, sched->hashes[0].algo->digest_size)) != 0)
- goto Exit;
- if ((ret = derive_resumption_secret(sched, buf->base + buf->off, ticket_nonce)) != 0)
- goto Exit;
- buf->off += sched->hashes[0].algo->digest_size;
- });
- /* key-exchange */
- ptls_buffer_push16(buf, key_exchange_id);
- /* cipher-suite */
- ptls_buffer_push16(buf, csid);
- /* ticket_age_add */
- ptls_buffer_push32(buf, ticket_age_add);
- /* server-name */
- ptls_buffer_push_block(buf, 2, {
- if (server_name != NULL)
- ptls_buffer_pushv(buf, server_name, strlen(server_name));
- });
- /* alpn */
- ptls_buffer_push_block(buf, 1, {
- if (negotiated_protocol != NULL)
- ptls_buffer_pushv(buf, negotiated_protocol, strlen(negotiated_protocol));
- });
- });
-
-Exit:
- return ret;
-}
-
-int decode_session_identifier(uint64_t *issued_at, ptls_iovec_t *psk, uint32_t *ticket_age_add, ptls_iovec_t *server_name,
- uint16_t *key_exchange_id, uint16_t *csid, ptls_iovec_t *negotiated_protocol, const uint8_t *src,
- const uint8_t *const end)
-{
- int ret = 0;
-
- ptls_decode_block(src, end, 2, {
- if (end - src < SESSION_IDENTIFIER_MAGIC_SIZE ||
- memcmp(src, SESSION_IDENTIFIER_MAGIC, SESSION_IDENTIFIER_MAGIC_SIZE) != 0) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- src += SESSION_IDENTIFIER_MAGIC_SIZE;
- if ((ret = ptls_decode64(issued_at, &src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(src, end, 2, {
- *psk = ptls_iovec_init(src, end - src);
- src = end;
- });
- if ((ret = ptls_decode16(key_exchange_id, &src, end)) != 0)
- goto Exit;
- if ((ret = ptls_decode16(csid, &src, end)) != 0)
- goto Exit;
- if ((ret = ptls_decode32(ticket_age_add, &src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(src, end, 2, {
- *server_name = ptls_iovec_init(src, end - src);
- src = end;
- });
- ptls_decode_open_block(src, end, 1, {
- *negotiated_protocol = ptls_iovec_init(src, end - src);
- src = end;
- });
- });
-
-Exit:
- return ret;
-}
-
-static size_t build_certificate_verify_signdata(uint8_t *data, struct st_ptls_key_schedule_t *sched, const char *context_string)
-{
- size_t datalen = 0;
-
- memset(data + datalen, 32, 64);
- datalen += 64;
- memcpy(data + datalen, context_string, strlen(context_string) + 1);
- datalen += strlen(context_string) + 1;
- sched->hashes[0].ctx->final(sched->hashes[0].ctx, data + datalen, PTLS_HASH_FINAL_MODE_SNAPSHOT);
- datalen += sched->hashes[0].algo->digest_size;
- assert(datalen <= PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE);
-
- return datalen;
-}
-
-static int calc_verify_data(void *output, struct st_ptls_key_schedule_t *sched, const void *secret)
-{
- ptls_hash_context_t *hmac;
- uint8_t digest[PTLS_MAX_DIGEST_SIZE];
- int ret;
-
- if ((ret = ptls_hkdf_expand_label(sched->hashes[0].algo, digest, sched->hashes[0].algo->digest_size,
- ptls_iovec_init(secret, sched->hashes[0].algo->digest_size), "finished",
- ptls_iovec_init(NULL, 0), NULL)) != 0)
- return ret;
- if ((hmac = ptls_hmac_create(sched->hashes[0].algo, digest, sched->hashes[0].algo->digest_size)) == NULL) {
- ptls_clear_memory(digest, sizeof(digest));
- return PTLS_ERROR_NO_MEMORY;
- }
-
- sched->hashes[0].ctx->final(sched->hashes[0].ctx, digest, PTLS_HASH_FINAL_MODE_SNAPSHOT);
- PTLS_DEBUGF("%s: %02x%02x,%02x%02x\n", __FUNCTION__, ((uint8_t *)secret)[0], ((uint8_t *)secret)[1], digest[0], digest[1]);
- hmac->update(hmac, digest, sched->hashes[0].algo->digest_size);
- ptls_clear_memory(digest, sizeof(digest));
- hmac->final(hmac, output, PTLS_HASH_FINAL_MODE_FREE);
-
- return 0;
-}
-
-static int verify_finished(ptls_t *tls, ptls_iovec_t message)
-{
- uint8_t verify_data[PTLS_MAX_DIGEST_SIZE];
- int ret;
-
- if (PTLS_HANDSHAKE_HEADER_SIZE + tls->key_schedule->hashes[0].algo->digest_size != message.len) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
-
- if ((ret = calc_verify_data(verify_data, tls->key_schedule, tls->traffic_protection.dec.secret)) != 0)
- goto Exit;
- if (memcmp(message.base + PTLS_HANDSHAKE_HEADER_SIZE, verify_data, tls->key_schedule->hashes[0].algo->digest_size) != 0) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
-
-Exit:
- ptls_clear_memory(verify_data, sizeof(verify_data));
- return ret;
-}
-
-static int send_finished(ptls_t *tls, ptls_buffer_t *sendbuf)
-{
- int ret;
-
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_FINISHED, {
- if ((ret = ptls_buffer_reserve(sendbuf, tls->key_schedule->hashes[0].algo->digest_size)) != 0)
- goto Exit;
- if ((ret = calc_verify_data(sendbuf->base + sendbuf->off, tls->key_schedule, tls->traffic_protection.enc.secret)) != 0)
- goto Exit;
- sendbuf->off += tls->key_schedule->hashes[0].algo->digest_size;
- });
-
-Exit:
- return ret;
-}
-
-static int send_session_ticket(ptls_t *tls, ptls_buffer_t *sendbuf)
-{
- ptls_hash_context_t *msghash_backup = tls->key_schedule->hashes[0].ctx->clone_(tls->key_schedule->hashes[0].ctx);
- ptls_buffer_t session_id;
- char session_id_smallbuf[128];
- uint32_t ticket_age_add;
- int ret = 0;
-
- assert(tls->ctx->ticket_lifetime != 0);
- assert(tls->ctx->encrypt_ticket != NULL);
-
- { /* calculate verify-data that will be sent by the client */
- size_t orig_off = sendbuf->off;
- if (tls->early_data != NULL) {
- assert(tls->state == PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA);
- buffer_push_handshake_body(sendbuf, tls->key_schedule, PTLS_HANDSHAKE_TYPE_END_OF_EARLY_DATA, {});
- sendbuf->off = orig_off;
- }
- buffer_push_handshake_body(sendbuf, tls->key_schedule, PTLS_HANDSHAKE_TYPE_FINISHED, {
- if ((ret = ptls_buffer_reserve(sendbuf, tls->key_schedule->hashes[0].algo->digest_size)) != 0)
- goto Exit;
- if ((ret = calc_verify_data(sendbuf->base + sendbuf->off, tls->key_schedule,
- tls->early_data != NULL ? tls->early_data->next_secret
- : tls->traffic_protection.dec.secret)) != 0)
- goto Exit;
- sendbuf->off += tls->key_schedule->hashes[0].algo->digest_size;
- });
- sendbuf->off = orig_off;
- }
-
- tls->ctx->random_bytes(&ticket_age_add, sizeof(ticket_age_add));
-
- /* build the raw nsk */
- ptls_buffer_init(&session_id, session_id_smallbuf, sizeof(session_id_smallbuf));
- ret = encode_session_identifier(tls->ctx, &session_id, ticket_age_add, ptls_iovec_init(NULL, 0), tls->key_schedule,
- tls->server_name, tls->key_share->id, tls->cipher_suite->id, tls->negotiated_protocol);
- if (ret != 0)
- goto Exit;
-
- /* encrypt and send */
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET, {
- ptls_buffer_push32(sendbuf, tls->ctx->ticket_lifetime);
- ptls_buffer_push32(sendbuf, ticket_age_add);
- ptls_buffer_push_block(sendbuf, 1, {});
- ptls_buffer_push_block(sendbuf, 2, {
- if ((ret = tls->ctx->encrypt_ticket->cb(tls->ctx->encrypt_ticket, tls, 1, sendbuf,
- ptls_iovec_init(session_id.base, session_id.off))) != 0)
- goto Exit;
- });
- ptls_buffer_push_block(sendbuf, 2, {
- if (tls->ctx->max_early_data_size != 0)
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_EARLY_DATA,
- { ptls_buffer_push32(sendbuf, tls->ctx->max_early_data_size); });
- });
- });
-
-Exit:
- ptls_buffer_dispose(&session_id);
-
- /* restore handshake state */
- tls->key_schedule->hashes[0].ctx->final(tls->key_schedule->hashes[0].ctx, NULL, PTLS_HASH_FINAL_MODE_FREE);
- tls->key_schedule->hashes[0].ctx = msghash_backup;
-
- return ret;
-}
-
-static int push_change_cipher_spec(ptls_t *tls, ptls_buffer_t *sendbuf)
-{
- int ret = 0;
-
- if (!tls->send_change_cipher_spec)
- goto Exit;
- buffer_push_record(sendbuf, PTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, { ptls_buffer_push(sendbuf, 1); });
- tls->send_change_cipher_spec = 0;
-Exit:
- return ret;
-}
-
-static int push_additional_extensions(ptls_handshake_properties_t *properties, ptls_buffer_t *sendbuf)
-{
- int ret;
-
- if (properties != NULL && properties->additional_extensions != NULL) {
- ptls_raw_extension_t *ext;
- for (ext = properties->additional_extensions; ext->type != UINT16_MAX; ++ext) {
- buffer_push_extension(sendbuf, ext->type, { ptls_buffer_pushv(sendbuf, ext->data.base, ext->data.len); });
- }
- }
- ret = 0;
-Exit:
- return ret;
-}
-
-static int send_client_hello(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_handshake_properties_t *properties, ptls_iovec_t *cookie)
-{
- ptls_iovec_t resumption_secret = {NULL}, resumption_ticket;
- uint32_t obfuscated_ticket_age = 0;
- size_t msghash_off;
- uint8_t binder_key[PTLS_MAX_DIGEST_SIZE];
- int ret, is_second_flight = tls->key_schedule != NULL;
-
- if (properties != NULL) {
- /* setup resumption-related data. If successful, resumption_secret becomes a non-zero value. */
- if (properties->client.session_ticket.base != NULL) {
- ptls_key_exchange_algorithm_t *key_share = NULL;
- ptls_cipher_suite_t *cipher_suite = NULL;
- uint32_t max_early_data_size;
- if (decode_stored_session_ticket(tls->ctx, &key_share, &cipher_suite, &resumption_secret, &obfuscated_ticket_age,
- &resumption_ticket, &max_early_data_size, properties->client.session_ticket.base,
- properties->client.session_ticket.base + properties->client.session_ticket.len) == 0) {
- tls->client.offered_psk = 1;
- tls->key_share = key_share;
- tls->cipher_suite = cipher_suite;
- if (!is_second_flight && max_early_data_size != 0 && properties->client.max_early_data_size != NULL) {
- *properties->client.max_early_data_size = max_early_data_size;
- if ((tls->early_data = malloc(sizeof(*tls->early_data))) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- }
- } else {
- resumption_secret = ptls_iovec_init(NULL, 0);
- }
- }
- if (properties->client.max_early_data_size != NULL && tls->early_data == NULL)
- *properties->client.max_early_data_size = 0;
- }
-
- /* use the default key share if still not undetermined */
- if (tls->key_share == NULL && !(properties != NULL && properties->client.negotiate_before_key_exchange))
- tls->key_share = tls->ctx->key_exchanges[0];
-
- if (!is_second_flight) {
- tls->key_schedule = key_schedule_new(tls->cipher_suite, tls->ctx->cipher_suites);
- if ((ret = key_schedule_extract(tls->key_schedule, resumption_secret)) != 0)
- goto Exit;
- }
-
- msghash_off = sendbuf->off + 5;
- buffer_push_handshake(sendbuf, NULL, NULL, PTLS_HANDSHAKE_TYPE_CLIENT_HELLO, {
- /* legacy_version */
- ptls_buffer_push16(sendbuf, 0x0303);
- /* random_bytes */
- ptls_buffer_pushv(sendbuf, tls->client_random, sizeof(tls->client_random));
- /* lecagy_session_id */
- ptls_buffer_push_block(
- sendbuf, 1, { ptls_buffer_pushv(sendbuf, tls->client.legacy_session_id, sizeof(tls->client.legacy_session_id)); });
- /* cipher_suites */
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_cipher_suite_t **cs = tls->ctx->cipher_suites;
- for (; *cs != NULL; ++cs)
- ptls_buffer_push16(sendbuf, (*cs)->id);
- });
- /* legacy_compression_methods */
- ptls_buffer_push_block(sendbuf, 1, { ptls_buffer_push(sendbuf, 0); });
- /* extensions */
- ptls_buffer_push_block(sendbuf, 2, {
- if (tls->server_name != NULL) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_NAME, {
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_buffer_push(sendbuf, PTLS_SERVER_NAME_TYPE_HOSTNAME);
- ptls_buffer_push_block(sendbuf, 2,
- { ptls_buffer_pushv(sendbuf, tls->server_name, strlen(tls->server_name)); });
- });
- });
- }
- if (properties != NULL && properties->client.negotiated_protocols.count != 0) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_ALPN, {
- ptls_buffer_push_block(sendbuf, 2, {
- size_t i;
- for (i = 0; i != properties->client.negotiated_protocols.count; ++i) {
- ptls_buffer_push_block(sendbuf, 1, {
- ptls_iovec_t p = properties->client.negotiated_protocols.list[i];
- ptls_buffer_pushv(sendbuf, p.base, p.len);
- });
- }
- });
- });
- }
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS, {
- ptls_buffer_push_block(sendbuf, 1, {
- size_t i;
- for (i = 0; i != sizeof(supported_versions) / sizeof(supported_versions[0]); ++i)
- ptls_buffer_push16(sendbuf, supported_versions[i]);
- });
- });
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS, {
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256);
- ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256);
- ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PKCS1_SHA256);
- ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PKCS1_SHA1);
- });
- });
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS, {
- ptls_key_exchange_algorithm_t **algo = tls->ctx->key_exchanges;
- ptls_buffer_push_block(sendbuf, 2, {
- for (; *algo != NULL; ++algo)
- ptls_buffer_push16(sendbuf, (*algo)->id);
- });
- });
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_KEY_SHARE, {
- ptls_buffer_push_block(sendbuf, 2, {
- if (tls->key_share != NULL) {
- ptls_iovec_t pubkey;
- if ((ret = tls->key_share->create(&tls->client.key_share_ctx, &pubkey)) != 0)
- goto Exit;
- ptls_buffer_push16(sendbuf, tls->key_share->id);
- ptls_buffer_push_block(sendbuf, 2, { ptls_buffer_pushv(sendbuf, pubkey.base, pubkey.len); });
- }
- });
- });
- if (cookie != NULL && cookie->base != NULL) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_COOKIE, {
- ptls_buffer_push_block(sendbuf, 2, { ptls_buffer_pushv(sendbuf, cookie->base, cookie->len); });
- });
- }
- if ((ret = push_additional_extensions(properties, sendbuf)) != 0)
- goto Exit;
- if (tls->ctx->save_ticket != NULL) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_PSK_KEY_EXCHANGE_MODES, {
- ptls_buffer_push_block(sendbuf, 1, {
- if (!tls->ctx->require_dhe_on_psk)
- ptls_buffer_push(sendbuf, PTLS_PSK_KE_MODE_PSK);
- ptls_buffer_push(sendbuf, PTLS_PSK_KE_MODE_PSK_DHE);
- });
- });
- if (resumption_secret.base != NULL) {
- if (tls->early_data != NULL && !is_second_flight)
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_EARLY_DATA, {});
- /* pre-shared key "MUST be the last extension in the ClientHello" (draft-17 section 4.2.6) */
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_PRE_SHARED_KEY, {
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_buffer_push_block(sendbuf, 2,
- { ptls_buffer_pushv(sendbuf, resumption_ticket.base, resumption_ticket.len); });
- ptls_buffer_push32(sendbuf, obfuscated_ticket_age);
- });
- /* allocate space for PSK binder. the space is filled at the bottom of the function */
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_buffer_push_block(sendbuf, 1, {
- if ((ret = ptls_buffer_reserve(sendbuf, tls->key_schedule->hashes[0].algo->digest_size)) != 0)
- goto Exit;
- sendbuf->off += tls->key_schedule->hashes[0].algo->digest_size;
- });
- });
- });
- }
- }
- });
- });
-
- /* update the message hash, filling in the PSK binder HMAC if necessary */
- if (resumption_secret.base != NULL) {
- size_t psk_binder_off = sendbuf->off - (3 + tls->key_schedule->hashes[0].algo->digest_size);
- if ((ret = derive_secret_with_empty_digest(tls->key_schedule, binder_key, "res binder")) != 0)
- goto Exit;
- key_schedule_update_hash(tls->key_schedule, sendbuf->base + msghash_off, psk_binder_off - msghash_off);
- msghash_off = psk_binder_off;
- if ((ret = calc_verify_data(sendbuf->base + psk_binder_off + 3, tls->key_schedule, binder_key)) != 0)
- goto Exit;
- }
- key_schedule_update_hash(tls->key_schedule, sendbuf->base + msghash_off, sendbuf->off - msghash_off);
-
- if (tls->early_data != NULL) {
- if ((ret = setup_traffic_protection(tls, 1, "c e traffic", "CLIENT_EARLY_TRAFFIC_SECRET")) != 0)
- goto Exit;
- if ((ret = push_change_cipher_spec(tls, sendbuf)) != 0)
- goto Exit;
- }
- if (resumption_secret.base != NULL && !is_second_flight) {
- if ((ret = derive_exporter_secret(tls, 1)) != 0)
- goto Exit;
- }
- tls->state = cookie == NULL ? PTLS_STATE_CLIENT_EXPECT_SERVER_HELLO : PTLS_STATE_CLIENT_EXPECT_SECOND_SERVER_HELLO;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- ptls_clear_memory(binder_key, sizeof(binder_key));
- return ret;
-}
-
-static int decode_key_share_entry(uint16_t *group, ptls_iovec_t *key_exchange, const uint8_t **src, const uint8_t *const end)
-{
- int ret;
-
- if ((ret = ptls_decode16(group, src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(*src, end, 2, {
- *key_exchange = ptls_iovec_init(*src, end - *src);
- *src = end;
- });
-
-Exit:
- return ret;
-}
-
-static ptls_cipher_suite_t *find_cipher_suite(ptls_context_t *ctx, uint16_t id)
-{
- ptls_cipher_suite_t **cs;
-
- for (cs = ctx->cipher_suites; *cs != NULL && (*cs)->id != id; ++cs)
- ;
- return *cs;
-}
-
-static int decode_server_hello(ptls_t *tls, struct st_ptls_server_hello_t *sh, const uint8_t *src, const uint8_t *const end)
-{
- int ret;
-
- *sh = (struct st_ptls_server_hello_t){{0}};
-
- /* ignore legacy-version */
- if (end - src < 2) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- src += 2;
-
- /* random */
- if (end - src < PTLS_HELLO_RANDOM_SIZE) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- sh->is_retry_request = memcmp(src, hello_retry_random, PTLS_HELLO_RANDOM_SIZE) == 0;
- src += PTLS_HELLO_RANDOM_SIZE;
-
- /* legacy_session_id */
- ptls_decode_open_block(src, end, 1, {
- if (end - src > 32) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- sh->legacy_session_id = ptls_iovec_init(src, end - src);
- src = end;
- });
-
- { /* select cipher_suite */
- uint16_t csid;
- if ((ret = ptls_decode16(&csid, &src, end)) != 0)
- goto Exit;
- if ((tls->cipher_suite = find_cipher_suite(tls->ctx, csid)) == NULL) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- }
-
- /* legacy_compression_method */
- if (src == end || *src++ != 0) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
-
- if (sh->is_retry_request)
- sh->retry_request.selected_group = UINT16_MAX;
-
- uint16_t exttype, found_version = UINT16_MAX, selected_psk_identity = UINT16_MAX;
- decode_extensions(src, end, PTLS_HANDSHAKE_TYPE_SERVER_HELLO, &exttype, {
- switch (exttype) {
- case PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS:
- if ((ret = ptls_decode16(&found_version, &src, end)) != 0)
- goto Exit;
- break;
- case PTLS_EXTENSION_TYPE_KEY_SHARE:
- if (sh->is_retry_request) {
- if ((ret = ptls_decode16(&sh->retry_request.selected_group, &src, end)) != 0)
- goto Exit;
- } else {
- uint16_t group;
- if ((ret = decode_key_share_entry(&group, &sh->peerkey, &src, end)) != 0)
- goto Exit;
- if (src != end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if (tls->key_share == NULL || tls->key_share->id != group) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- }
- break;
- case PTLS_EXTENSION_TYPE_COOKIE:
- if (sh->is_retry_request) {
- ptls_decode_block(src, end, 2, {
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- sh->retry_request.cookie = ptls_iovec_init(src, end - src);
- src = end;
- });
- } else {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- break;
- case PTLS_EXTENSION_TYPE_PRE_SHARED_KEY:
- if (sh->is_retry_request) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- } else {
- if ((ret = ptls_decode16(&selected_psk_identity, &src, end)) != 0)
- goto Exit;
- }
- break;
- default:
- src = end;
- break;
- }
- });
-
- if (!is_supported_version(found_version)) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- if (!sh->is_retry_request) {
- if (selected_psk_identity != UINT16_MAX) {
- if (!tls->client.offered_psk) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- if (selected_psk_identity != 0) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- tls->is_psk_handshake = 1;
- }
- if (sh->peerkey.base == NULL && !tls->is_psk_handshake) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- }
-
- ret = 0;
-Exit:
- return ret;
-}
-
-static int handle_hello_retry_request(ptls_t *tls, ptls_buffer_t *sendbuf, struct st_ptls_server_hello_t *sh, ptls_iovec_t message,
- ptls_handshake_properties_t *properties)
-{
- int ret;
-
- if (tls->client.key_share_ctx != NULL) {
- tls->client.key_share_ctx->on_exchange(&tls->client.key_share_ctx, NULL, ptls_iovec_init(NULL, 0));
- tls->client.key_share_ctx = NULL;
- }
-
- if (sh->retry_request.selected_group != UINT16_MAX) {
- /* we offer the first key_exchanges[0] as KEY_SHARE unless client.negotiate_before_key_exchange is set */
- ptls_key_exchange_algorithm_t **cand;
- for (cand = tls->ctx->key_exchanges; *cand != NULL; ++cand)
- if ((*cand)->id == sh->retry_request.selected_group)
- break;
- if (*cand == NULL) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- tls->key_share = *cand;
- } else if (tls->key_share != NULL) {
- /* retain the key-share using in first CH, if server does not specify one */
- } else {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
-
- key_schedule_transform_post_ch1hash(tls->key_schedule);
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- ret = send_client_hello(tls, sendbuf, properties, &sh->retry_request.cookie);
-
-Exit:
- return ret;
-}
-
-static int client_handle_hello(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_iovec_t message, ptls_handshake_properties_t *properties)
-{
- struct st_ptls_server_hello_t sh;
- ptls_iovec_t ecdh_secret = {NULL};
- int ret;
-
- if ((ret = decode_server_hello(tls, &sh, message.base + PTLS_HANDSHAKE_HEADER_SIZE, message.base + message.len)) != 0)
- goto Exit;
- if (!(sh.legacy_session_id.len == sizeof(tls->client.legacy_session_id) &&
- memcmp(sh.legacy_session_id.base, tls->client.legacy_session_id, sizeof(tls->client.legacy_session_id)) == 0)) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
-
- if (sh.is_retry_request) {
- if ((ret = key_schedule_select_one(tls->key_schedule, tls->cipher_suite, 0)) != 0)
- goto Exit;
- return handle_hello_retry_request(tls, sendbuf, &sh, message, properties);
- }
-
- if ((ret = key_schedule_select_one(tls->key_schedule, tls->cipher_suite, tls->client.offered_psk && !tls->is_psk_handshake)) !=
- 0)
- goto Exit;
-
- if (sh.peerkey.base != NULL) {
- if ((ret = tls->client.key_share_ctx->on_exchange(&tls->client.key_share_ctx, &ecdh_secret, sh.peerkey)) != 0)
- goto Exit;
- }
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
-
- if ((ret = key_schedule_extract(tls->key_schedule, ecdh_secret)) != 0)
- goto Exit;
- if ((ret = setup_traffic_protection(tls, 0, "s hs traffic", "SERVER_HANDSHAKE_TRAFFIC_SECRET")) != 0)
- goto Exit;
-
- tls->state = PTLS_STATE_CLIENT_EXPECT_ENCRYPTED_EXTENSIONS;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- if (ecdh_secret.base != NULL) {
- ptls_clear_memory(ecdh_secret.base, ecdh_secret.len);
- free(ecdh_secret.base);
- }
- return ret;
-}
-
-static int handle_unknown_extension(ptls_t *tls, ptls_handshake_properties_t *properties, uint16_t type, const uint8_t *src,
- const uint8_t *const end, ptls_raw_extension_t *slots)
-{
-
- if (properties != NULL && properties->collect_extension != NULL && properties->collect_extension(tls, properties, type)) {
- size_t i;
- for (i = 0; slots[i].type != UINT16_MAX; ++i) {
- assert(i < MAX_UNKNOWN_EXTENSIONS);
- if (slots[i].type == type)
- return PTLS_ALERT_ILLEGAL_PARAMETER;
- }
- if (i < MAX_UNKNOWN_EXTENSIONS) {
- slots[i].type = type;
- slots[i].data = ptls_iovec_init(src, end - src);
- slots[i + 1].type = UINT16_MAX;
- }
- }
- return 0;
-}
-
-static int report_unknown_extensions(ptls_t *tls, ptls_handshake_properties_t *properties, ptls_raw_extension_t *slots)
-{
- if (properties != NULL && properties->collect_extension != NULL) {
- assert(properties->collected_extensions != NULL);
- return properties->collected_extensions(tls, properties, slots);
- } else {
- return 0;
- }
-}
-
-static int client_handle_encrypted_extensions(ptls_t *tls, ptls_iovec_t message, ptls_handshake_properties_t *properties)
-{
- const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len;
- uint16_t type;
- ptls_raw_extension_t unknown_extensions[MAX_UNKNOWN_EXTENSIONS + 1];
- int ret, skip_early_data = 1;
-
- unknown_extensions[0].type = UINT16_MAX;
-
- decode_extensions(src, end, PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS, &type, {
- switch (type) {
- case PTLS_EXTENSION_TYPE_SERVER_NAME:
- if (src != end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if (tls->server_name == NULL) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- break;
- case PTLS_EXTENSION_TYPE_ALPN:
- ptls_decode_block(src, end, 2, {
- ptls_decode_open_block(src, end, 1, {
- if ((ret = ptls_set_negotiated_protocol(tls, (const char *)src, end - src)) != 0)
- goto Exit;
- src = end;
- });
- if (src != end) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- });
- break;
- case PTLS_EXTENSION_TYPE_EARLY_DATA:
- if (tls->early_data == NULL) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- skip_early_data = 0;
- break;
- default:
- handle_unknown_extension(tls, properties, type, src, end, unknown_extensions);
- break;
- }
- src = end;
- });
-
- if (tls->early_data != NULL) {
- tls->skip_early_data = skip_early_data;
- if (properties != NULL && !skip_early_data)
- properties->client.early_data_accepted_by_peer = 1;
- if ((ret = derive_secret(tls->key_schedule, tls->early_data->next_secret, "c hs traffic")) != 0)
- goto Exit;
- } else {
- if ((ret = setup_traffic_protection(tls, 1, "c hs traffic", "CLIENT_HANDSHAKE_TRAFFIC_SECRET")) != 0)
- goto Exit;
- }
- if ((ret = report_unknown_extensions(tls, properties, unknown_extensions)) != 0)
- goto Exit;
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- tls->state = tls->is_psk_handshake ? PTLS_STATE_CLIENT_EXPECT_FINISHED : PTLS_STATE_CLIENT_EXPECT_CERTIFICATE;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- return ret;
-}
-
-static int client_handle_certificate(ptls_t *tls, ptls_iovec_t message)
-{
- const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len;
- ptls_iovec_t certs[16];
- size_t num_certs = 0;
- int ret;
-
- /* certificate request context */
- ptls_decode_open_block(src, end, 1, {
- if (src != end) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- });
- /* certificate_list */
- ptls_decode_block(src, end, 3, {
- do {
- ptls_decode_open_block(src, end, 3, {
- if (num_certs < sizeof(certs) / sizeof(certs[0]))
- certs[num_certs++] = ptls_iovec_init(src, end - src);
- src = end;
- });
- uint16_t type;
- decode_open_extensions(src, end, PTLS_HANDSHAKE_TYPE_CERTIFICATE, &type, { src = end; });
- } while (src != end);
- });
-
- if (tls->ctx->verify_certificate != NULL) {
- if ((ret = tls->ctx->verify_certificate->cb(tls->ctx->verify_certificate, tls, &tls->client.certificate_verify.cb,
- &tls->client.certificate_verify.verify_ctx, certs, num_certs)) != 0)
- goto Exit;
- }
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- tls->state = PTLS_STATE_CLIENT_EXPECT_CERTIFICATE_VERIFY;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- return ret;
-}
-
-static int client_handle_certificate_verify(ptls_t *tls, ptls_iovec_t message)
-{
- const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len;
- uint16_t algo;
- ptls_iovec_t signature;
- uint8_t signdata[PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE];
- size_t signdata_size;
- int ret;
-
- /* decode */
- if ((ret = ptls_decode16(&algo, &src, end)) != 0)
- goto Exit;
- ptls_decode_block(src, end, 2, {
- signature = ptls_iovec_init(src, end - src);
- src = end;
- });
-
- /* validate */
- switch (algo) {
- case PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256:
- case PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256:
- /* ok */
- break;
- default:
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- signdata_size = build_certificate_verify_signdata(signdata, tls->key_schedule, PTLS_SERVER_CERTIFICATE_VERIFY_CONTEXT_STRING);
- if (tls->client.certificate_verify.cb != NULL) {
- ret = tls->client.certificate_verify.cb(tls->client.certificate_verify.verify_ctx, ptls_iovec_init(signdata, signdata_size),
- signature);
- } else {
- ret = 0;
- }
- ptls_clear_memory(signdata, signdata_size);
- tls->client.certificate_verify.cb = NULL;
- if (ret != 0)
- goto Exit;
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- tls->state = PTLS_STATE_CLIENT_EXPECT_FINISHED;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- return ret;
-}
-
-static int client_handle_finished(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_iovec_t message)
-{
- uint8_t send_secret[PTLS_MAX_DIGEST_SIZE];
- int ret;
-
- if ((ret = verify_finished(tls, message)) != 0)
- goto Exit;
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
-
- /* update traffic keys by using messages upto ServerFinished, but commission them after sending ClientFinished */
- if ((ret = key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0))) != 0)
- goto Exit;
- if ((ret = setup_traffic_protection(tls, 0, "s ap traffic", "SERVER_TRAFFIC_SECRET_0")) != 0)
- goto Exit;
- if ((ret = derive_secret(tls->key_schedule, send_secret, "c ap traffic")) != 0)
- goto Exit;
- if ((ret = derive_exporter_secret(tls, 0)) != 0)
- goto Exit;
-
- /* if sending early data, emit EOED and commision the client handshake traffic secret */
- if (tls->early_data != NULL) {
- assert(tls->traffic_protection.enc.aead != NULL);
- if (!tls->skip_early_data) {
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_END_OF_EARLY_DATA,
- {});
- }
- if ((ret = retire_early_data_secret(tls, 1)) != 0)
- goto Exit;
- }
-
- if ((ret = push_change_cipher_spec(tls, sendbuf)) != 0)
- goto Exit;
- ret = send_finished(tls, sendbuf);
-
- memcpy(tls->traffic_protection.enc.secret, send_secret, sizeof(send_secret));
- if ((ret = setup_traffic_protection(tls, 1, NULL, "CLIENT_TRAFFIC_SECRET_0")) != 0)
- goto Exit;
-
- tls->state = PTLS_STATE_CLIENT_POST_HANDSHAKE;
-
-Exit:
- ptls_clear_memory(send_secret, sizeof(send_secret));
- return ret;
-}
-
-static int client_handle_new_session_ticket(ptls_t *tls, ptls_iovec_t message)
-{
- const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len;
- ptls_iovec_t ticket_nonce;
- int ret;
-
- { /* verify the format */
- uint32_t ticket_lifetime, ticket_age_add, max_early_data_size;
- ptls_iovec_t ticket;
- if ((ret = decode_new_session_ticket(&ticket_lifetime, &ticket_age_add, &ticket_nonce, &ticket, &max_early_data_size, src,
- end)) != 0)
- return ret;
- }
-
- /* do nothing if use of session ticket is disabled */
- if (tls->ctx->save_ticket == NULL)
- return 0;
-
- /* save the extension, along with the key of myself */
- ptls_buffer_t ticket_buf;
- uint8_t ticket_buf_small[512];
- ptls_buffer_init(&ticket_buf, ticket_buf_small, sizeof(ticket_buf_small));
- ptls_buffer_push64(&ticket_buf, tls->ctx->get_time->cb(tls->ctx->get_time));
- ptls_buffer_push16(&ticket_buf, tls->key_share->id);
- ptls_buffer_push16(&ticket_buf, tls->cipher_suite->id);
- ptls_buffer_push_block(&ticket_buf, 3, { ptls_buffer_pushv(&ticket_buf, src, end - src); });
- ptls_buffer_push_block(&ticket_buf, 2, {
- if ((ret = ptls_buffer_reserve(&ticket_buf, tls->key_schedule->hashes[0].algo->digest_size)) != 0)
- goto Exit;
- if ((ret = derive_resumption_secret(tls->key_schedule, ticket_buf.base + ticket_buf.off, ticket_nonce)) != 0)
- goto Exit;
- ticket_buf.off += tls->key_schedule->hashes[0].algo->digest_size;
- });
-
- if ((ret = tls->ctx->save_ticket->cb(tls->ctx->save_ticket, tls, ptls_iovec_init(ticket_buf.base, ticket_buf.off))) != 0)
- goto Exit;
-
- ret = 0;
-Exit:
- ptls_buffer_dispose(&ticket_buf);
- return ret;
-}
-
-static int client_hello_decode_server_name(ptls_iovec_t *name, const uint8_t *src, const uint8_t *const end)
-{
- int ret = 0;
-
- ptls_decode_block(src, end, 2, {
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- do {
- uint8_t type = *src++;
- ptls_decode_open_block(src, end, 2, {
- switch (type) {
- case PTLS_SERVER_NAME_TYPE_HOSTNAME:
- if (memchr(src, '\0', end - src) != 0) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- *name = ptls_iovec_init(src, end - src);
- break;
- default:
- break;
- }
- src = end;
- });
- } while (src != end);
- });
-
-Exit:
- return ret;
-}
-
-static int select_cipher_suite(ptls_cipher_suite_t **selected, ptls_cipher_suite_t **candidates, const uint8_t *src,
- const uint8_t *const end)
-{
- int ret;
-
- ptls_decode_block(src, end, 2, {
- while (src != end) {
- uint16_t id;
- if ((ret = ptls_decode16(&id, &src, end)) != 0)
- goto Exit;
- ptls_cipher_suite_t **c = candidates;
- for (; *c != NULL; ++c) {
- if ((*c)->id == id) {
- *selected = *c;
- return 0;
- }
- }
- }
- });
-
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
-
-Exit:
- return ret;
-}
-
-static int select_key_share(ptls_key_exchange_algorithm_t **selected, ptls_iovec_t *peer_key,
- ptls_key_exchange_algorithm_t **candidates, const uint8_t *src, const uint8_t *const end)
-{
- int ret;
-
- ptls_decode_block(src, end, 2, {
- while (src != end) {
- uint16_t group;
- ptls_iovec_t key;
- if ((ret = decode_key_share_entry(&group, &key, &src, end)) != 0)
- goto Exit;
- ptls_key_exchange_algorithm_t **c = candidates;
- for (; *c != NULL; ++c) {
- if ((*c)->id == group) {
- *selected = *c;
- *peer_key = key;
- return 0;
- }
- }
- }
- });
-
- *selected = NULL;
- ret = 0;
-
-Exit:
- return ret;
-}
-
-static int select_negotiated_group(ptls_key_exchange_algorithm_t **selected, ptls_key_exchange_algorithm_t **candidates,
- const uint8_t *src, const uint8_t *const end)
-{
- int ret;
-
- ptls_decode_block(src, end, 2, {
- while (src != end) {
- uint16_t group;
- if ((ret = ptls_decode16(&group, &src, end)) != 0)
- goto Exit;
- ptls_key_exchange_algorithm_t **c = candidates;
- for (; *c != NULL; ++c) {
- if ((*c)->id == group) {
- *selected = *c;
- return 0;
- }
- }
- }
- });
-
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
-
-Exit:
- return ret;
-}
-
-static int decode_client_hello(ptls_t *tls, struct st_ptls_client_hello_t *ch, const uint8_t *src, const uint8_t *const end,
- ptls_handshake_properties_t *properties)
-{
- uint16_t exttype = 0;
- int ret;
-
- { /* check protocol version */
- uint16_t protver;
- if ((ret = ptls_decode16(&protver, &src, end)) != 0)
- goto Exit;
- if (protver != 0x0303) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- }
-
- /* skip random */
- if (end - src < PTLS_HELLO_RANDOM_SIZE) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- ch->random_bytes = src;
- src += PTLS_HELLO_RANDOM_SIZE;
-
- /* skip legacy_session_id */
- ptls_decode_open_block(src, end, 1, {
- if (end - src > 32) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- ch->legacy_session_id = ptls_iovec_init(src, end - src);
- src = end;
- });
-
- /* decode and select from ciphersuites */
- ptls_decode_open_block(src, end, 2, {
- ch->cipher_suites = ptls_iovec_init(src - 2, end - src + 2);
- src = end;
- });
-
- /* decode legacy_compression_methods */
- ptls_decode_open_block(src, end, 1, {
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- ch->compression_methods.ids = src;
- ch->compression_methods.count = end - src;
- src = end;
- });
-
- /* decode extensions */
- decode_extensions(src, end, PTLS_HANDSHAKE_TYPE_CLIENT_HELLO, &exttype, {
- switch (exttype) {
- case PTLS_EXTENSION_TYPE_SERVER_NAME:
- if ((ret = client_hello_decode_server_name(&ch->server_name, src, end)) != 0)
- goto Exit;
- break;
- case PTLS_EXTENSION_TYPE_ALPN:
- ptls_decode_block(src, end, 2, {
- do {
- ptls_decode_open_block(src, end, 1, {
- if (ch->alpn.count < sizeof(ch->alpn.list) / sizeof(ch->alpn.list[0]))
- ch->alpn.list[ch->alpn.count++] = ptls_iovec_init(src, end - src);
- src = end;
- });
- } while (src != end);
- });
- break;
- case PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS:
- ch->negotiated_groups = ptls_iovec_init(src, end - src);
- break;
- case PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS:
- ptls_decode_block(src, end, 2, {
- do {
- uint16_t id;
- if ((ret = ptls_decode16(&id, &src, end)) != 0)
- goto Exit;
- if (ch->signature_algorithms.count <
- sizeof(ch->signature_algorithms.list) / sizeof(ch->signature_algorithms.list[0]))
- ch->signature_algorithms.list[ch->signature_algorithms.count++] = id;
- } while (src != end);
- });
- break;
- case PTLS_EXTENSION_TYPE_KEY_SHARE:
- ch->key_shares = ptls_iovec_init(src, end - src);
- break;
- case PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS:
- ptls_decode_block(src, end, 1, {
- size_t selected_index = sizeof(supported_versions) / sizeof(supported_versions[0]);
- do {
- size_t i;
- uint16_t v;
- if ((ret = ptls_decode16(&v, &src, end)) != 0)
- goto Exit;
- for (i = 0; i != selected_index; ++i) {
- if (supported_versions[i] == v) {
- selected_index = i;
- break;
- }
- }
- } while (src != end);
- if (selected_index != sizeof(supported_versions) / sizeof(supported_versions[0]))
- ch->selected_version = supported_versions[selected_index];
- });
- break;
- case PTLS_EXTENSION_TYPE_COOKIE:
- if (properties->server.cookie.key == NULL) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- ch->cookie.all = ptls_iovec_init(src, end - src);
- ptls_decode_block(src, end, 2, {
- ch->cookie.tbs.base = (void *)src;
- ptls_decode_open_block(src, end, 2, {
- ptls_decode_open_block(src, end, 1, {
- ch->cookie.ch1_hash = ptls_iovec_init(src, end - src);
- src = end;
- });
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- switch (*src++) {
- case 0:
- assert(!ch->cookie.sent_key_share);
- break;
- case 1:
- ch->cookie.sent_key_share = 1;
- break;
- default:
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- });
- ch->cookie.tbs.len = src - ch->cookie.tbs.base;
- ptls_decode_block(src, end, 1, {
- ch->cookie.signature = ptls_iovec_init(src, end - src);
- src = end;
- });
- });
- break;
- case PTLS_EXTENSION_TYPE_PRE_SHARED_KEY: {
- size_t num_identities = 0;
- ptls_decode_open_block(src, end, 2, {
- do {
- struct st_ptls_client_hello_psk_t psk = {{NULL}};
- ptls_decode_open_block(src, end, 2, {
- psk.identity = ptls_iovec_init(src, end - src);
- src = end;
- });
- if ((ret = ptls_decode32(&psk.obfuscated_ticket_age, &src, end)) != 0)
- goto Exit;
- if (ch->psk.identities.count < sizeof(ch->psk.identities.list) / sizeof(ch->psk.identities.list[0]))
- ch->psk.identities.list[ch->psk.identities.count++] = psk;
- ++num_identities;
- } while (src != end);
- });
- ch->psk.hash_end = src;
- ptls_decode_block(src, end, 2, {
- size_t num_binders = 0;
- do {
- ptls_decode_open_block(src, end, 1, {
- if (num_binders < ch->psk.identities.count)
- ch->psk.identities.list[num_binders].binder = ptls_iovec_init(src, end - src);
- src = end;
- });
- ++num_binders;
- } while (src != end);
- if (num_identities != num_binders) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- });
- } break;
- case PTLS_EXTENSION_TYPE_PSK_KEY_EXCHANGE_MODES:
- ptls_decode_block(src, end, 1, {
- if (src == end) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- for (; src != end; ++src) {
- if (*src < sizeof(ch->psk.ke_modes) * 8)
- ch->psk.ke_modes |= 1u << *src;
- }
- });
- break;
- case PTLS_EXTENSION_TYPE_EARLY_DATA:
- ch->psk.early_data_indication = 1;
- break;
- case PTLS_EXTENSION_TYPE_STATUS_REQUEST:
- ch->status_request = 1;
- break;
- default:
- handle_unknown_extension(tls, properties, exttype, src, end, ch->unknown_extensions);
- break;
- }
- src = end;
- });
-
- /* check if client hello make sense */
- if (is_supported_version(ch->selected_version)) {
- if (!(ch->compression_methods.count == 1 && ch->compression_methods.ids[0] == 0)) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- /* pre-shared key */
- if (ch->psk.hash_end != NULL) {
- /* PSK must be the last extension */
- if (exttype != PTLS_EXTENSION_TYPE_PRE_SHARED_KEY) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- } else {
- if (ch->psk.early_data_indication) {
- ret = PTLS_ALERT_ILLEGAL_PARAMETER;
- goto Exit;
- }
- }
- } else {
- ret = PTLS_ALERT_PROTOCOL_VERSION;
- goto Exit;
- }
-
- ret = 0;
-Exit:
- return ret;
-}
-
-static int vec_is_string(ptls_iovec_t x, const char *y)
-{
- return strncmp((const char *)x.base, y, x.len) == 0 && y[x.len] == '\0';
-}
-
-static int try_psk_handshake(ptls_t *tls, size_t *psk_index, int *accept_early_data, struct st_ptls_client_hello_t *ch,
- ptls_iovec_t ch_trunc)
-{
- ptls_buffer_t decbuf;
- ptls_iovec_t ticket_psk, ticket_server_name, ticket_negotiated_protocol;
- uint64_t issue_at, now = tls->ctx->get_time->cb(tls->ctx->get_time);
- uint32_t age_add;
- uint16_t ticket_key_exchange_id, ticket_csid;
- uint8_t decbuf_small[256], binder_key[PTLS_MAX_DIGEST_SIZE], verify_data[PTLS_MAX_DIGEST_SIZE];
- int ret;
-
- ptls_buffer_init(&decbuf, decbuf_small, sizeof(decbuf_small));
-
- for (*psk_index = 0; *psk_index < ch->psk.identities.count; ++*psk_index) {
- struct st_ptls_client_hello_psk_t *identity = ch->psk.identities.list + *psk_index;
- /* decrypt and decode */
- decbuf.off = 0;
- if ((tls->ctx->encrypt_ticket->cb(tls->ctx->encrypt_ticket, tls, 0, &decbuf, identity->identity)) != 0)
- continue;
- if (decode_session_identifier(&issue_at, &ticket_psk, &age_add, &ticket_server_name, &ticket_key_exchange_id, &ticket_csid,
- &ticket_negotiated_protocol, decbuf.base, decbuf.base + decbuf.off) != 0)
- continue;
- /* check age */
- if (now < issue_at)
- continue;
- if (now - issue_at > (uint64_t)tls->ctx->ticket_lifetime * 1000)
- continue;
- *accept_early_data = 0;
- if (ch->psk.early_data_indication) {
- int64_t delta = (now - issue_at) - (identity->obfuscated_ticket_age - age_add);
- if (delta <= PTLS_EARLY_DATA_MAX_DELAY)
- *accept_early_data = 1;
- }
- /* check server-name */
- if (ticket_server_name.len != 0) {
- if (tls->server_name == NULL)
- continue;
- if (!vec_is_string(ticket_server_name, tls->server_name))
- continue;
- } else {
- if (tls->server_name != NULL)
- continue;
- }
- { /* check key-exchange */
- ptls_key_exchange_algorithm_t **a;
- for (a = tls->ctx->key_exchanges; *a != NULL && (*a)->id != ticket_key_exchange_id; ++a)
- ;
- if (*a == NULL)
- continue;
- tls->key_share = *a;
- }
- /* check cipher-suite */
- if (ticket_csid != tls->cipher_suite->id)
- continue;
- /* check negotiated-protocol */
- if (ticket_negotiated_protocol.len != 0) {
- if (tls->negotiated_protocol == NULL)
- continue;
- if (!vec_is_string(ticket_negotiated_protocol, tls->negotiated_protocol))
- continue;
- }
- /* check the length of the decrypted psk and the PSK binder */
- if (ticket_psk.len != tls->key_schedule->hashes[0].algo->digest_size)
- continue;
- if (ch->psk.identities.list[*psk_index].binder.len != tls->key_schedule->hashes[0].algo->digest_size)
- continue;
-
- /* found */
- goto Found;
- }
-
- /* not found */
- *psk_index = SIZE_MAX;
- *accept_early_data = 0;
- tls->key_share = NULL;
- ret = 0;
- goto Exit;
-
-Found:
- if ((ret = key_schedule_extract(tls->key_schedule, ticket_psk)) != 0)
- goto Exit;
- if ((ret = derive_secret(tls->key_schedule, binder_key, "res binder")) != 0)
- goto Exit;
- key_schedule_update_hash(tls->key_schedule, ch_trunc.base, ch_trunc.len);
- if ((ret = calc_verify_data(verify_data, tls->key_schedule, binder_key)) != 0)
- goto Exit;
- if (memcmp(ch->psk.identities.list[*psk_index].binder.base, verify_data, tls->key_schedule->hashes[0].algo->digest_size) != 0) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- ret = 0;
-
-Exit:
- ptls_buffer_dispose(&decbuf);
- ptls_clear_memory(binder_key, sizeof(binder_key));
- ptls_clear_memory(verify_data, sizeof(verify_data));
- return ret;
-}
-
-static int calc_cookie_signature(ptls_t *tls, ptls_handshake_properties_t *properties,
- ptls_key_exchange_algorithm_t *negotiated_group, ptls_iovec_t tbs, uint8_t *sig)
-{
- ptls_hash_algorithm_t *algo = tls->ctx->cipher_suites[0]->hash;
- ptls_hash_context_t *hctx;
-
- if ((hctx = ptls_hmac_create(algo, properties->server.cookie.key, algo->digest_size)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
-
-#define UPDATE_BLOCK(p, _len) \
- do { \
- size_t len = (_len); \
- assert(len < UINT8_MAX); \
- uint8_t len8 = (uint8_t)len; \
- hctx->update(hctx, &len8, 1); \
- hctx->update(hctx, (p), len); \
- } while (0)
-#define UPDATE16(_v) \
- do { \
- uint16_t v = (_v); \
- uint8_t b[2] = {v >> 8, v & 0xff}; \
- hctx->update(hctx, b, 2); \
- } while (0)
-
- UPDATE_BLOCK(tls->client_random, sizeof(tls->client_random));
- UPDATE_BLOCK(tls->server_name, tls->server_name != NULL ? strlen(tls->server_name) : 0);
- UPDATE16(tls->cipher_suite->id);
- UPDATE16(negotiated_group->id);
- UPDATE_BLOCK(properties->server.cookie.additional_data.base, properties->server.cookie.additional_data.len);
-
- UPDATE_BLOCK(tbs.base, tbs.len);
-
-#undef UPDATE_BLOCK
-#undef UPDATE16
-
- hctx->final(hctx, sig, PTLS_HASH_FINAL_MODE_FREE);
- return 0;
-}
-
-static int server_handle_hello(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_iovec_t message, ptls_handshake_properties_t *properties)
-{
-#define EMIT_SERVER_HELLO(sched, fill_rand, extensions) \
- buffer_push_handshake(sendbuf, (sched), NULL, PTLS_HANDSHAKE_TYPE_SERVER_HELLO, { \
- ptls_buffer_push16(sendbuf, 0x0303 /* legacy version */); \
- if ((ret = ptls_buffer_reserve(sendbuf, PTLS_HELLO_RANDOM_SIZE)) != 0) \
- goto Exit; \
- do { \
- fill_rand \
- } while (0); \
- sendbuf->off += PTLS_HELLO_RANDOM_SIZE; \
- ptls_buffer_push_block(sendbuf, 1, { ptls_buffer_pushv(sendbuf, ch.legacy_session_id.base, ch.legacy_session_id.len); }); \
- ptls_buffer_push16(sendbuf, tls->cipher_suite->id); \
- ptls_buffer_push(sendbuf, 0); \
- ptls_buffer_push_block(sendbuf, 2, { \
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS, \
- { ptls_buffer_push16(sendbuf, ch.selected_version); }); \
- do { \
- extensions \
- } while (0); \
- }); \
- });
-
-#define EMIT_HELLO_RETRY_REQUEST(sched, negotiated_group, additional_extensions) \
- EMIT_SERVER_HELLO((sched), { memcpy(sendbuf->base + sendbuf->off, hello_retry_random, PTLS_HELLO_RANDOM_SIZE); }, \
- { \
- ptls_key_exchange_algorithm_t *_negotiated_group = (negotiated_group); \
- if (_negotiated_group != NULL) { \
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_KEY_SHARE, \
- { ptls_buffer_push16(sendbuf, _negotiated_group->id); }); \
- } \
- do { \
- additional_extensions \
- } while (0); \
- });
-
- struct st_ptls_client_hello_t ch = {NULL, {NULL}, {NULL}, 0, {NULL}, {NULL}, {NULL},
- {{0}}, {NULL}, {{{NULL}}}, {{NULL}}, {NULL}, {{UINT16_MAX}}};
- struct {
- ptls_key_exchange_algorithm_t *algorithm;
- ptls_iovec_t peer_key;
- } key_share = {NULL};
- enum { HANDSHAKE_MODE_FULL, HANDSHAKE_MODE_PSK, HANDSHAKE_MODE_PSK_DHE } mode;
- size_t psk_index = SIZE_MAX;
- ptls_iovec_t pubkey = {0}, ecdh_secret = {0};
- uint8_t finished_key[PTLS_MAX_DIGEST_SIZE];
- int accept_early_data = 0, is_second_flight = tls->state == PTLS_STATE_SERVER_EXPECT_SECOND_CLIENT_HELLO, ret;
-
- /* decode ClientHello */
- if ((ret = decode_client_hello(tls, &ch, message.base + PTLS_HANDSHAKE_HEADER_SIZE, message.base + message.len, properties)) !=
- 0)
- goto Exit;
- if (tls->ctx->require_dhe_on_psk)
- ch.psk.ke_modes &= ~(1u << PTLS_PSK_KE_MODE_PSK);
-
- /* handle client_random and SNI */
- if (!is_second_flight) {
- memcpy(tls->client_random, ch.random_bytes, sizeof(tls->client_random));
- if (ch.server_name.base != NULL) {
- if ((tls->server_name = malloc(ch.server_name.len + 1)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- memcpy(tls->server_name, ch.server_name.base, ch.server_name.len);
- tls->server_name[ch.server_name.len] = '\0';
- }
- if (tls->ctx->on_client_hello != NULL &&
- (ret = tls->ctx->on_client_hello->cb(tls->ctx->on_client_hello, tls, ch.server_name, ch.alpn.list, ch.alpn.count,
- ch.signature_algorithms.list, ch.signature_algorithms.count)) != 0)
- goto Exit;
- } else {
- if (ch.psk.early_data_indication) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if (memcmp(tls->client_random, ch.random_bytes, sizeof(tls->client_random)) != 0 ||
- (tls->server_name != NULL) != (ch.server_name.base != NULL) ||
- (tls->server_name != NULL &&
- !(strncmp(tls->server_name, (char *)ch.server_name.base, ch.server_name.len) == 0 &&
- tls->server_name[ch.server_name.len] == '\0'))) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- }
-
- { /* select (or check) cipher-suite, create key_schedule */
- ptls_cipher_suite_t *cs;
- if ((ret = select_cipher_suite(&cs, tls->ctx->cipher_suites, ch.cipher_suites.base,
- ch.cipher_suites.base + ch.cipher_suites.len)) != 0)
- goto Exit;
- if (!is_second_flight) {
- tls->cipher_suite = cs;
- tls->key_schedule = key_schedule_new(cs, NULL);
- } else {
- if (tls->cipher_suite != cs) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- }
- }
-
- /* select key_share */
- if (ch.key_shares.base != NULL &&
- (ret = select_key_share(&key_share.algorithm, &key_share.peer_key, tls->ctx->key_exchanges, ch.key_shares.base,
- ch.key_shares.base + ch.key_shares.len)) != 0)
- goto Exit;
-
- if (!is_second_flight) {
- if (ch.cookie.all.len != 0 && key_share.algorithm != NULL) {
-
- /* use cookie to check the integrity of the handshake, and update the context */
- uint8_t sig[PTLS_MAX_DIGEST_SIZE];
- size_t sigsize = tls->ctx->cipher_suites[0]->hash->digest_size;
- if ((ret = calc_cookie_signature(tls, properties, key_share.algorithm, ch.cookie.tbs, sig)) != 0)
- goto Exit;
- if (!(ch.cookie.signature.len == sigsize && memcmp(ch.cookie.signature.base, sig, sigsize) == 0)) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- /* integrity check passed; update states */
- key_schedule_update_ch1hash_prefix(tls->key_schedule);
- key_schedule_update_hash(tls->key_schedule, ch.cookie.ch1_hash.base, ch.cookie.ch1_hash.len);
- key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0));
- /* ... reusing sendbuf to rebuild HRR for hash calculation */
- size_t hrr_start = sendbuf->off;
- EMIT_HELLO_RETRY_REQUEST(tls->key_schedule, ch.cookie.sent_key_share ? key_share.algorithm : NULL, {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_COOKIE,
- { ptls_buffer_pushv(sendbuf, ch.cookie.all.base, ch.cookie.all.len); });
- });
- sendbuf->off = hrr_start;
- is_second_flight = 1;
-
- } else if (key_share.algorithm == NULL || (properties != NULL && properties->server.enforce_retry)) {
-
- /* send HelloRetryRequest */
- if (ch.negotiated_groups.base == NULL) {
- ret = PTLS_ALERT_MISSING_EXTENSION;
- goto Exit;
- }
- ptls_key_exchange_algorithm_t *negotiated_group;
- if ((ret = select_negotiated_group(&negotiated_group, tls->ctx->key_exchanges, ch.negotiated_groups.base,
- ch.negotiated_groups.base + ch.negotiated_groups.len)) != 0)
- goto Exit;
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- assert(tls->key_schedule->generation == 0);
- if (properties != NULL && properties->server.retry_uses_cookie) {
- /* emit HRR with cookie (note: we MUST omit KeyShare if the client has specified the correct one; see 46554f0) */
- EMIT_HELLO_RETRY_REQUEST(NULL, key_share.algorithm != NULL ? NULL : negotiated_group, {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_COOKIE, {
- ptls_buffer_push_block(sendbuf, 2, {
- /* push to-be-signed data */
- size_t tbs_start = sendbuf->off;
- ptls_buffer_push_block(sendbuf, 2, {
- /* first block of the cookie data is the hash(ch1) */
- ptls_buffer_push_block(sendbuf, 1, {
- size_t sz = tls->cipher_suite->hash->digest_size;
- if ((ret = ptls_buffer_reserve(sendbuf, sz)) != 0)
- goto Exit;
- key_schedule_extract_ch1hash(tls->key_schedule, sendbuf->base + sendbuf->off);
- sendbuf->off += sz;
- });
- /* second is if we have sent key_share extension */
- ptls_buffer_push(sendbuf, key_share.algorithm == NULL);
- /* we can add more data here */
- });
- size_t tbs_len = sendbuf->off - tbs_start;
- /* push the signature */
- ptls_buffer_push_block(sendbuf, 1, {
- size_t sz = tls->ctx->cipher_suites[0]->hash->digest_size;
- if ((ret = ptls_buffer_reserve(sendbuf, sz)) != 0)
- goto Exit;
- if ((ret = calc_cookie_signature(tls, properties, negotiated_group,
- ptls_iovec_init(sendbuf->base + tbs_start, tbs_len),
- sendbuf->base + sendbuf->off)) != 0)
- goto Exit;
- sendbuf->off += sz;
- });
- });
- });
- });
- if ((ret = push_change_cipher_spec(tls, sendbuf)) != 0)
- goto Exit;
- ret = PTLS_ERROR_STATELESS_RETRY;
- } else {
- /* invoking stateful retry; roll the key schedule and emit HRR */
- key_schedule_transform_post_ch1hash(tls->key_schedule);
- key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0));
- EMIT_HELLO_RETRY_REQUEST(tls->key_schedule, key_share.algorithm != NULL ? NULL : negotiated_group, {});
- if ((ret = push_change_cipher_spec(tls, sendbuf)) != 0)
- goto Exit;
- tls->state = PTLS_STATE_SERVER_EXPECT_SECOND_CLIENT_HELLO;
- if (ch.psk.early_data_indication)
- tls->skip_early_data = 1;
- ret = PTLS_ERROR_IN_PROGRESS;
- }
- goto Exit;
- }
- }
-
- /* handle unknown extensions */
- if ((ret = report_unknown_extensions(tls, properties, ch.unknown_extensions)) != 0)
- goto Exit;
-
- /* try psk handshake */
- if (!is_second_flight && ch.psk.hash_end != 0 &&
- (ch.psk.ke_modes & ((1u << PTLS_PSK_KE_MODE_PSK) | (1u << PTLS_PSK_KE_MODE_PSK_DHE))) != 0 &&
- tls->ctx->encrypt_ticket != NULL) {
- if ((ret = try_psk_handshake(tls, &psk_index, &accept_early_data, &ch,
- ptls_iovec_init(message.base, ch.psk.hash_end - message.base))) != 0)
- goto Exit;
- }
-
- /* adjust key_schedule, determine handshake mode */
- if (psk_index == SIZE_MAX) {
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- if (!is_second_flight) {
- assert(tls->key_schedule->generation == 0);
- key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0));
- }
- mode = HANDSHAKE_MODE_FULL;
- if (properties != NULL)
- properties->server.selected_psk_binder.len = 0;
- } else {
- key_schedule_update_hash(tls->key_schedule, ch.psk.hash_end, message.base + message.len - ch.psk.hash_end);
- if ((ch.psk.ke_modes & (1u << PTLS_PSK_KE_MODE_PSK)) != 0) {
- mode = HANDSHAKE_MODE_PSK;
- } else {
- assert((ch.psk.ke_modes & (1u << PTLS_PSK_KE_MODE_PSK_DHE)) != 0);
- mode = HANDSHAKE_MODE_PSK_DHE;
- }
- tls->is_psk_handshake = 1;
- if (properties != NULL) {
- ptls_iovec_t *selected = &ch.psk.identities.list[psk_index].binder;
- memcpy(properties->server.selected_psk_binder.base, selected->base, selected->len);
- properties->server.selected_psk_binder.len = selected->len;
- }
- if ((ret = derive_exporter_secret(tls, 1)) != 0)
- goto Exit;
- }
-
- if (accept_early_data && tls->ctx->max_early_data_size != 0 && psk_index == 0) {
- if ((tls->early_data = malloc(sizeof(*tls->early_data))) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((ret = setup_traffic_protection(tls, 0, "c e traffic", "CLIENT_EARLY_TRAFFIC_SECRET")) != 0)
- goto Exit;
- }
-
- /* run key-exchange, to obtain pubkey and secret */
- if (mode != HANDSHAKE_MODE_PSK) {
- if (key_share.algorithm == NULL) {
- ret = ch.key_shares.base != NULL ? PTLS_ALERT_HANDSHAKE_FAILURE : PTLS_ALERT_MISSING_EXTENSION;
- goto Exit;
- }
- if ((ret = key_share.algorithm->exchange(&pubkey, &ecdh_secret, key_share.peer_key)) != 0)
- goto Exit;
- tls->key_share = key_share.algorithm;
- }
-
- /* send ServerHello */
- EMIT_SERVER_HELLO(tls->key_schedule, { tls->ctx->random_bytes(sendbuf->base + sendbuf->off, PTLS_HELLO_RANDOM_SIZE); },
- {
- if (mode != HANDSHAKE_MODE_PSK) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_KEY_SHARE, {
- ptls_buffer_push16(sendbuf, key_share.algorithm->id);
- ptls_buffer_push_block(sendbuf, 2, { ptls_buffer_pushv(sendbuf, pubkey.base, pubkey.len); });
- });
- }
- if (mode != HANDSHAKE_MODE_FULL) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_PRE_SHARED_KEY,
- { ptls_buffer_push16(sendbuf, (uint16_t)psk_index); });
- }
- });
- if ((ret = push_change_cipher_spec(tls, sendbuf)) != 0)
- goto Exit;
-
- /* create protection contexts for the handshake */
- assert(tls->key_schedule->generation == 1);
- key_schedule_extract(tls->key_schedule, ecdh_secret);
- if ((ret = setup_traffic_protection(tls, 1, "s hs traffic", "SERVER_HANDSHAKE_TRAFFIC_SECRET")) != 0)
- goto Exit;
- if (tls->early_data != NULL) {
- if ((ret = derive_secret(tls->key_schedule, tls->early_data->next_secret, "c hs traffic")) != 0)
- goto Exit;
- } else {
- if ((ret = setup_traffic_protection(tls, 0, "c hs traffic", "CLIENT_HANDSHAKE_TRAFFIC_SECRET")) != 0)
- goto Exit;
- if (ch.psk.early_data_indication)
- tls->skip_early_data = 1;
- }
-
- /* send EncryptedExtensions */
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS, {
- ptls_buffer_push_block(sendbuf, 2, {
- if (tls->server_name != NULL) {
- /* In this event, the server SHALL include an extension of type "server_name" in the (extended) server
- * hello. The "extension_data" field of this extension SHALL be empty. (RFC 6066 section 3) */
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_NAME, {});
- }
- if (tls->negotiated_protocol != NULL) {
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_ALPN, {
- ptls_buffer_push_block(sendbuf, 2, {
- ptls_buffer_push_block(sendbuf, 1, {
- ptls_buffer_pushv(sendbuf, tls->negotiated_protocol, strlen(tls->negotiated_protocol));
- });
- });
- });
- }
- if (tls->early_data != NULL && tls->traffic_protection.dec.aead != NULL)
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_EARLY_DATA, {});
- if ((ret = push_additional_extensions(properties, sendbuf)) != 0)
- goto Exit;
- });
- });
-
- if (mode == HANDSHAKE_MODE_FULL) {
- if (ch.signature_algorithms.count == 0) {
- ret = PTLS_ALERT_MISSING_EXTENSION;
- goto Exit;
- }
- /* send Certificate */
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_CERTIFICATE, {
- ptls_buffer_push(sendbuf, 0);
- ptls_buffer_push_block(sendbuf, 3, {
- size_t i;
- for (i = 0; i != tls->ctx->certificates.count; ++i) {
- ptls_buffer_push_block(sendbuf, 3, {
- ptls_buffer_pushv(sendbuf, tls->ctx->certificates.list[i].base, tls->ctx->certificates.list[i].len);
- });
- ptls_buffer_push_block(sendbuf, 2, {
- /* emit OCSP stapling only when requested and when the callback successfully returns one */
- if (ch.status_request && i == 0 && tls->ctx->staple_ocsp != NULL) {
- size_t reset_off_to = sendbuf->off;
- buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_STATUS_REQUEST, {
- ptls_buffer_push(sendbuf, 1); /* status_type == ocsp */
- ptls_buffer_push_block(sendbuf, 3, {
- if ((ret = tls->ctx->staple_ocsp->cb(tls->ctx->staple_ocsp, tls, sendbuf, i)) == 0)
- reset_off_to = 0;
- });
- });
- if (reset_off_to != 0)
- sendbuf->off = reset_off_to;
- }
- });
- }
- });
- });
- /* build and send CertificateVerify */
- buffer_push_handshake(sendbuf, tls->key_schedule, &tls->traffic_protection.enc, PTLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY, {
- size_t algo_off = sendbuf->off;
- ptls_buffer_push16(sendbuf, 0); /* filled in later */
- ptls_buffer_push_block(sendbuf, 2, {
- uint16_t algo;
- uint8_t data[PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE];
- size_t datalen =
- build_certificate_verify_signdata(data, tls->key_schedule, PTLS_SERVER_CERTIFICATE_VERIFY_CONTEXT_STRING);
- if ((ret = tls->ctx->sign_certificate->cb(tls->ctx->sign_certificate, tls, &algo, sendbuf,
- ptls_iovec_init(data, datalen), ch.signature_algorithms.list,
- ch.signature_algorithms.count)) != 0)
- goto Exit;
- sendbuf->base[algo_off] = (uint8_t)(algo >> 8);
- sendbuf->base[algo_off + 1] = (uint8_t)algo;
- });
- });
- }
-
- send_finished(tls, sendbuf);
-
- assert(tls->key_schedule->generation == 2);
- if ((ret = key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0))) != 0)
- goto Exit;
- if ((ret = setup_traffic_protection(tls, 1, "s ap traffic", "SERVER_TRAFFIC_SECRET_0")) != 0)
- goto Exit;
- if ((ret = derive_secret(tls->key_schedule, tls->server.pending_traffic_secret, "c ap traffic")) != 0)
- goto Exit;
- if ((ret = derive_exporter_secret(tls, 0)) != 0)
- goto Exit;
-
- tls->state = tls->early_data != NULL ? PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA : PTLS_STATE_SERVER_EXPECT_FINISHED;
-
- /* send session ticket if necessary */
- if (ch.psk.ke_modes != 0 && tls->ctx->ticket_lifetime != 0) {
- if ((ret = send_session_ticket(tls, sendbuf)) != 0)
- goto Exit;
- }
-
- ret = 0;
-
-Exit:
- free(pubkey.base);
- free(ecdh_secret.base);
- ptls_clear_memory(finished_key, sizeof(finished_key));
- return ret;
-
-#undef EMIT_SERVER_HELLO
-#undef EMIT_HELLO_RETRY_REQUEST
-}
-
-static int server_handle_end_of_early_data(ptls_t *tls, ptls_iovec_t message)
-{
- int ret;
-
- if ((ret = retire_early_data_secret(tls, 0)) != 0)
- goto Exit;
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
- tls->state = PTLS_STATE_SERVER_EXPECT_FINISHED;
- ret = PTLS_ERROR_IN_PROGRESS;
-
-Exit:
- return ret;
-}
-
-static int server_handle_finished(ptls_t *tls, ptls_iovec_t message)
-{
- int ret;
-
- if ((ret = verify_finished(tls, message)) != 0)
- return ret;
-
- memcpy(tls->traffic_protection.dec.secret, tls->server.pending_traffic_secret, sizeof(tls->server.pending_traffic_secret));
- ptls_clear_memory(tls->server.pending_traffic_secret, sizeof(tls->server.pending_traffic_secret));
- if ((ret = setup_traffic_protection(tls, 0, NULL, "CLIENT_TRAFFIC_SECRET_0")) != 0)
- return ret;
-
- key_schedule_update_hash(tls->key_schedule, message.base, message.len);
-
- tls->state = PTLS_STATE_SERVER_POST_HANDSHAKE;
- return 0;
-}
-
-static int parse_record_header(struct st_ptls_record_t *rec, const uint8_t *src)
-{
- rec->type = src[0];
- rec->version = ntoh16(src + 1);
- rec->length = ntoh16(src + 3);
-
- if (rec->length >
- (size_t)(rec->type == PTLS_CONTENT_TYPE_APPDATA ? PTLS_MAX_ENCRYPTED_RECORD_SIZE : PTLS_MAX_PLAINTEXT_RECORD_SIZE))
- return PTLS_ALERT_DECODE_ERROR;
-
- return 0;
-}
-
-static int parse_record(ptls_t *tls, struct st_ptls_record_t *rec, const uint8_t *src, size_t *len)
-{
- int ret;
-
- if (tls->recvbuf.rec.base == NULL && *len >= 5) {
- /* fast path */
- if ((ret = parse_record_header(rec, src)) != 0)
- return ret;
- if (5 + rec->length <= *len) {
- rec->fragment = src + 5;
- *len = rec->length + 5;
- return 0;
- }
- }
-
- /* slow path */
- const uint8_t *const end = src + *len;
- *rec = (struct st_ptls_record_t){0};
-
- if (tls->recvbuf.rec.base == NULL) {
- ptls_buffer_init(&tls->recvbuf.rec, "", 0);
- if ((ret = ptls_buffer_reserve(&tls->recvbuf.rec, 5)) != 0)
- return ret;
- }
-
- /* fill and parse the header */
- while (tls->recvbuf.rec.off < 5) {
- if (src == end)
- return PTLS_ERROR_IN_PROGRESS;
- tls->recvbuf.rec.base[tls->recvbuf.rec.off++] = *src++;
- }
- if ((ret = parse_record_header(rec, tls->recvbuf.rec.base)) != 0)
- return ret;
-
- /* fill the fragment */
- size_t addlen = rec->length + 5 - tls->recvbuf.rec.off;
- if (addlen != 0) {
- if ((ret = ptls_buffer_reserve(&tls->recvbuf.rec, addlen)) != 0)
- return ret;
- if (addlen > (size_t)(end - src))
- addlen = end - src;
- if (addlen != 0) {
- memcpy(tls->recvbuf.rec.base + tls->recvbuf.rec.off, src, addlen);
- tls->recvbuf.rec.off += addlen;
- src += addlen;
- }
- }
-
- /* set rec->fragment if a complete record has been parsed */
- if (tls->recvbuf.rec.off == rec->length + 5) {
- rec->fragment = tls->recvbuf.rec.base + 5;
- ret = 0;
- } else {
- ret = PTLS_ERROR_IN_PROGRESS;
- }
-
- *len -= end - src;
- return ret;
-}
-
-static void update_open_count(ptls_context_t *ctx, ssize_t delta)
-{
- if (ctx->update_open_count != NULL)
- ctx->update_open_count->cb(ctx->update_open_count, delta);
-}
-
-ptls_t *ptls_new(ptls_context_t *ctx, int is_server)
-{
- ptls_t *tls;
-
- assert(ctx->get_time != NULL && "please set ctx->get_time to `&ptls_get_time`; see #92");
-
- if ((tls = malloc(sizeof(*tls))) == NULL)
- return NULL;
-
- update_open_count(ctx, 1);
- *tls = (ptls_t){ctx};
- tls->is_server = is_server;
- tls->send_change_cipher_spec = ctx->send_change_cipher_spec;
- if (!is_server) {
- tls->state = PTLS_STATE_CLIENT_HANDSHAKE_START;
- tls->ctx->random_bytes(tls->client_random, sizeof(tls->client_random));
- tls->ctx->random_bytes(tls->client.legacy_session_id, sizeof(tls->client.legacy_session_id));
- } else {
- tls->state = PTLS_STATE_SERVER_EXPECT_CLIENT_HELLO;
- }
-
- return tls;
-}
-
-void ptls_free(ptls_t *tls)
-{
- ptls_buffer_dispose(&tls->recvbuf.rec);
- ptls_buffer_dispose(&tls->recvbuf.mess);
- free_exporter_master_secret(tls, 1);
- free_exporter_master_secret(tls, 0);
- if (tls->key_schedule != NULL)
- key_schedule_free(tls->key_schedule);
- if (tls->traffic_protection.dec.aead != NULL)
- ptls_aead_free(tls->traffic_protection.dec.aead);
- if (tls->traffic_protection.enc.aead != NULL)
- ptls_aead_free(tls->traffic_protection.enc.aead);
- free(tls->server_name);
- free(tls->negotiated_protocol);
- if (tls->is_server) {
- /* nothing to do */
- } else {
- if (tls->client.key_share_ctx != NULL)
- tls->client.key_share_ctx->on_exchange(&tls->client.key_share_ctx, NULL, ptls_iovec_init(NULL, 0));
- if (tls->client.certificate_verify.cb != NULL)
- tls->client.certificate_verify.cb(tls->client.certificate_verify.verify_ctx, ptls_iovec_init(NULL, 0),
- ptls_iovec_init(NULL, 0));
- }
- if (tls->early_data != NULL) {
- ptls_clear_memory(tls->early_data, sizeof(*tls->early_data));
- free(tls->early_data);
- }
- update_open_count(tls->ctx, -1);
- ptls_clear_memory(tls, sizeof(*tls));
- free(tls);
-}
-
-ptls_context_t *ptls_get_context(ptls_t *tls)
-{
- return tls->ctx;
-}
-
-void ptls_set_context(ptls_t *tls, ptls_context_t *ctx)
-{
- update_open_count(ctx, 1);
- update_open_count(tls->ctx, -1);
- tls->ctx = ctx;
-}
-
-ptls_iovec_t ptls_get_client_random(ptls_t *tls)
-{
- return ptls_iovec_init(tls->client_random, PTLS_HELLO_RANDOM_SIZE);
-}
-
-ptls_cipher_suite_t *ptls_get_cipher(ptls_t *tls)
-{
- return tls->cipher_suite;
-}
-
-const char *ptls_get_server_name(ptls_t *tls)
-{
- return tls->server_name;
-}
-
-int ptls_set_server_name(ptls_t *tls, const char *server_name, size_t server_name_len)
-{
- char *duped = NULL;
-
- if (server_name != NULL) {
- if (server_name_len == 0)
- server_name_len = strlen(server_name);
- if ((duped = malloc(server_name_len + 1)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- memcpy(duped, server_name, server_name_len);
- duped[server_name_len] = '\0';
- }
-
- free(tls->server_name);
- tls->server_name = duped;
-
- return 0;
-}
-
-const char *ptls_get_negotiated_protocol(ptls_t *tls)
-{
- return tls->negotiated_protocol;
-}
-
-int ptls_set_negotiated_protocol(ptls_t *tls, const char *protocol, size_t protocol_len)
-{
- char *duped = NULL;
-
- if (protocol != NULL) {
- if (protocol_len == 0)
- protocol_len = strlen(protocol);
- if ((duped = malloc(protocol_len + 1)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- memcpy(duped, protocol, protocol_len);
- duped[protocol_len] = '\0';
- }
-
- free(tls->negotiated_protocol);
- tls->negotiated_protocol = duped;
-
- return 0;
-}
-
-int ptls_handshake_is_complete(ptls_t *tls)
-{
- return tls->state >= PTLS_STATE_POST_HANDSHAKE_MIN;
-}
-
-int ptls_is_psk_handshake(ptls_t *tls)
-{
- return tls->is_psk_handshake;
-}
-
-void **ptls_get_data_ptr(ptls_t *tls)
-{
- return &tls->data_ptr;
-}
-
-static int handle_handshake_message(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_iovec_t message, int is_end_of_record,
- ptls_handshake_properties_t *properties)
-{
- uint8_t type = message.base[0];
- int ret;
-
- switch (tls->state) {
- case PTLS_STATE_CLIENT_EXPECT_SERVER_HELLO:
- case PTLS_STATE_CLIENT_EXPECT_SECOND_SERVER_HELLO:
- if (type == PTLS_HANDSHAKE_TYPE_SERVER_HELLO && is_end_of_record) {
- ret = client_handle_hello(tls, sendbuf, message, properties);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_CLIENT_EXPECT_ENCRYPTED_EXTENSIONS:
- if (type == PTLS_HANDSHAKE_TYPE_ENCRYPTED_EXTENSIONS) {
- ret = client_handle_encrypted_extensions(tls, message, properties);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_CLIENT_EXPECT_CERTIFICATE:
- if (type == PTLS_HANDSHAKE_TYPE_CERTIFICATE) {
- ret = client_handle_certificate(tls, message);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_CLIENT_EXPECT_CERTIFICATE_VERIFY:
- if (type == PTLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
- ret = client_handle_certificate_verify(tls, message);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_CLIENT_EXPECT_FINISHED:
- if (type == PTLS_HANDSHAKE_TYPE_FINISHED && is_end_of_record) {
- ret = client_handle_finished(tls, sendbuf, message);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_SERVER_EXPECT_CLIENT_HELLO:
- case PTLS_STATE_SERVER_EXPECT_SECOND_CLIENT_HELLO:
- if (type == PTLS_HANDSHAKE_TYPE_CLIENT_HELLO && is_end_of_record) {
- ret = server_handle_hello(tls, sendbuf, message, properties);
- } else {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- }
- break;
- case PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA:
- if (type == PTLS_HANDSHAKE_TYPE_END_OF_EARLY_DATA) {
- ret = server_handle_end_of_early_data(tls, message);
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_STATE_SERVER_EXPECT_FINISHED:
- if (type == PTLS_HANDSHAKE_TYPE_FINISHED && is_end_of_record) {
- ret = server_handle_finished(tls, message);
- } else {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- }
- break;
- case PTLS_STATE_CLIENT_POST_HANDSHAKE:
- switch (type) {
- case PTLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET:
- ret = client_handle_new_session_ticket(tls, message);
- break;
- default:
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- break;
- }
- break;
- case PTLS_STATE_SERVER_POST_HANDSHAKE:
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- break;
- default:
- assert(!"unexpected state");
- break;
- }
-
- return ret;
-}
-
-static int handle_alert(ptls_t *tls, const uint8_t *src, size_t len)
-{
- if (len != 2)
- return PTLS_ALERT_DECODE_ERROR;
-
- uint8_t level = src[0], desc = src[1];
-
- /* ignore certain warnings */
- if (level == PTLS_ALERT_LEVEL_WARNING) {
- switch (desc) {
- case PTLS_ALERT_USER_CANCELED:
- return 0;
- default:
- break;
- }
- }
-
- /* all other alerts are considered fatal, regardless of the transmitted level (section 6) */
- return PTLS_ALERT_TO_PEER_ERROR(desc);
-}
-
-static int handle_handshake_record(ptls_t *tls, int (*cb)(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_iovec_t message,
- int is_end_of_record, ptls_handshake_properties_t *properties),
- ptls_buffer_t *sendbuf, struct st_ptls_record_t *rec, ptls_handshake_properties_t *properties)
-{
- int ret;
-
- /* handshake */
- if (rec->type != PTLS_CONTENT_TYPE_HANDSHAKE)
- return PTLS_ALERT_DECODE_ERROR;
-
- /* flatten the unhandled messages */
- const uint8_t *src, *src_end;
- if (tls->recvbuf.mess.base == NULL) {
- src = rec->fragment;
- src_end = src + rec->length;
- } else {
- if ((ret = ptls_buffer_reserve(&tls->recvbuf.mess, rec->length)) != 0)
- return ret;
- memcpy(tls->recvbuf.mess.base + tls->recvbuf.mess.off, rec->fragment, rec->length);
- tls->recvbuf.mess.off += rec->length;
- src = tls->recvbuf.mess.base;
- src_end = src + tls->recvbuf.mess.off;
- }
-
- /* handle the messages */
- ret = PTLS_ERROR_IN_PROGRESS;
- while (src_end - src >= 4) {
- size_t mess_len = 4 + ntoh24(src + 1);
- if (src_end - src < (int)mess_len)
- break;
- ret = cb(tls, sendbuf, ptls_iovec_init(src, mess_len), src_end - src == mess_len, properties);
- switch (ret) {
- case 0:
- case PTLS_ERROR_IN_PROGRESS:
- break;
- default:
- ptls_buffer_dispose(&tls->recvbuf.mess);
- return ret;
- }
- src += mess_len;
- }
-
- /* keep last partial message in buffer */
- if (src != src_end) {
- if (tls->recvbuf.mess.base == NULL) {
- ptls_buffer_init(&tls->recvbuf.mess, "", 0);
- if ((ret = ptls_buffer_reserve(&tls->recvbuf.mess, src_end - src)) != 0)
- return ret;
- memcpy(tls->recvbuf.mess.base, src, src_end - src);
- } else {
- memmove(tls->recvbuf.mess.base, src, src_end - src);
- }
- tls->recvbuf.mess.off = src_end - src;
- ret = PTLS_ERROR_IN_PROGRESS;
- } else {
- ptls_buffer_dispose(&tls->recvbuf.mess);
- }
-
- return ret;
-}
-
-static int handle_input(ptls_t *tls, ptls_buffer_t *sendbuf, ptls_buffer_t *decryptbuf, const void *input, size_t *inlen,
- ptls_handshake_properties_t *properties)
-{
- struct st_ptls_record_t rec;
- int ret;
-
- /* extract the record */
- if ((ret = parse_record(tls, &rec, input, inlen)) != 0)
- return ret;
- assert(rec.fragment != NULL);
-
- /* decrypt the record */
- if (rec.type == PTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- if (tls->state < PTLS_STATE_POST_HANDSHAKE_MIN) {
- if (!(rec.length == 1 && rec.fragment[0] == 0x01))
- return PTLS_ALERT_ILLEGAL_PARAMETER;
- } else {
- return PTLS_ALERT_HANDSHAKE_FAILURE;
- }
- ret = PTLS_ERROR_IN_PROGRESS;
- goto NextRecord;
- }
- if (tls->traffic_protection.dec.aead != NULL && rec.type != PTLS_CONTENT_TYPE_ALERT) {
- if (rec.type != PTLS_CONTENT_TYPE_APPDATA)
- return PTLS_ALERT_HANDSHAKE_FAILURE;
- if ((ret = ptls_buffer_reserve(decryptbuf, 5 + rec.length)) != 0)
- return ret;
- if ((ret = aead_decrypt(&tls->traffic_protection.dec, decryptbuf->base + decryptbuf->off, &rec.length, rec.fragment,
- rec.length)) != 0) {
- if (tls->skip_early_data) {
- ret = PTLS_ERROR_IN_PROGRESS;
- goto NextRecord;
- }
- return ret;
- }
- rec.fragment = decryptbuf->base + decryptbuf->off;
- /* skip padding */
- for (; rec.length != 0; --rec.length)
- if (rec.fragment[rec.length - 1] != 0)
- break;
- if (rec.length == 0)
- return PTLS_ALERT_UNEXPECTED_MESSAGE;
- rec.type = rec.fragment[--rec.length];
- } else if (rec.type == PTLS_CONTENT_TYPE_APPDATA && tls->skip_early_data) {
- ret = PTLS_ERROR_IN_PROGRESS;
- goto NextRecord;
- }
-
- if (tls->recvbuf.mess.base != NULL || rec.type == PTLS_CONTENT_TYPE_HANDSHAKE) {
- /* handshake record */
- ret = handle_handshake_record(tls, handle_handshake_message, sendbuf, &rec, properties);
- } else {
- /* handling of an alert or an application record */
- switch (rec.type) {
- case PTLS_CONTENT_TYPE_APPDATA:
- if (tls->state >= PTLS_STATE_POST_HANDSHAKE_MIN) {
- decryptbuf->off += rec.length;
- ret = 0;
- } else if (tls->state == PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA) {
- if (tls->traffic_protection.dec.aead != NULL)
- decryptbuf->off += rec.length;
- ret = 0;
- } else {
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- }
- break;
- case PTLS_CONTENT_TYPE_ALERT:
- ret = handle_alert(tls, rec.fragment, rec.length);
- break;
- default:
- ret = PTLS_ALERT_UNEXPECTED_MESSAGE;
- break;
- }
- }
-
-NextRecord:
- ptls_buffer_dispose(&tls->recvbuf.rec);
- return ret;
-}
-
-int ptls_handshake(ptls_t *tls, ptls_buffer_t *sendbuf, const void *input, size_t *inlen, ptls_handshake_properties_t *properties)
-{
- size_t sendbuf_orig_off = sendbuf->off;
- int ret;
-
- assert(tls->state < PTLS_STATE_POST_HANDSHAKE_MIN);
-
- /* special handlings */
- switch (tls->state) {
- case PTLS_STATE_CLIENT_HANDSHAKE_START:
- assert(input == NULL || *inlen == 0);
- assert(tls->ctx->key_exchanges[0] != NULL);
- return send_client_hello(tls, sendbuf, properties, NULL);
- default:
- break;
- }
-
- const uint8_t *src = input, *const src_end = src + *inlen;
- ptls_buffer_t decryptbuf;
- uint8_t decryptbuf_small[256];
-
- ptls_buffer_init(&decryptbuf, decryptbuf_small, sizeof(decryptbuf_small));
-
- /* perform handhake until completion or until all the input has been swallowed */
- ret = PTLS_ERROR_IN_PROGRESS;
- while (ret == PTLS_ERROR_IN_PROGRESS && src != src_end) {
- size_t consumed = src_end - src;
- ret = handle_input(tls, sendbuf, &decryptbuf, src, &consumed, properties);
- src += consumed;
- assert(decryptbuf.off == 0);
- }
-
- ptls_buffer_dispose(&decryptbuf);
-
- switch (ret) {
- case 0:
- case PTLS_ERROR_IN_PROGRESS:
- case PTLS_ERROR_STATELESS_RETRY:
- break;
- default:
- /* flush partially written response */
- ptls_clear_memory(sendbuf->base + sendbuf_orig_off, sendbuf->off - sendbuf_orig_off);
- sendbuf->off = sendbuf_orig_off;
- /* send alert immediately */
- if (PTLS_ERROR_GET_CLASS(ret) != PTLS_ERROR_CLASS_PEER_ALERT)
- if (ptls_send_alert(tls, sendbuf, PTLS_ALERT_LEVEL_FATAL,
- PTLS_ERROR_GET_CLASS(ret) == PTLS_ERROR_CLASS_SELF_ALERT ? ret : PTLS_ALERT_INTERNAL_ERROR) != 0)
- sendbuf->off = sendbuf_orig_off;
- break;
- }
-
- *inlen -= src_end - src;
- return ret;
-}
-
-int ptls_receive(ptls_t *tls, ptls_buffer_t *decryptbuf, const void *_input, size_t *inlen)
-{
- const uint8_t *input = (const uint8_t *)_input, *const end = input + *inlen;
- size_t decryptbuf_orig_size = decryptbuf->off;
- int ret = 0;
-
- assert(tls->state >= PTLS_STATE_SERVER_EXPECT_END_OF_EARLY_DATA);
-
- /* loop until we decrypt some application data (or an error) */
- while (ret == 0 && input != end && decryptbuf_orig_size == decryptbuf->off) {
- size_t consumed = end - input;
- ret = handle_input(tls, NULL, decryptbuf, input, &consumed, NULL);
- input += consumed;
-
- switch (ret) {
- case 0:
- break;
- case PTLS_ERROR_IN_PROGRESS:
- ret = 0;
- break;
- case PTLS_ERROR_CLASS_PEER_ALERT + PTLS_ALERT_CLOSE_NOTIFY:
- /* TODO send close alert */
- break;
- default:
- if (PTLS_ERROR_GET_CLASS(ret) == PTLS_ERROR_CLASS_SELF_ALERT) {
- /* TODO send alert */
- }
- break;
- }
- }
-
- *inlen -= end - input;
-
- return ret;
-}
-
-int ptls_send(ptls_t *tls, ptls_buffer_t *sendbuf, const void *input, size_t inlen)
-{
- assert(tls->traffic_protection.enc.aead != NULL);
- return buffer_push_encrypted_records(sendbuf, PTLS_CONTENT_TYPE_APPDATA, input, inlen, &tls->traffic_protection.enc);
-}
-
-size_t ptls_get_record_overhead(ptls_t *tls)
-{
- return 6 + tls->traffic_protection.enc.aead->algo->tag_size;
-}
-
-int ptls_send_alert(ptls_t *tls, ptls_buffer_t *sendbuf, uint8_t level, uint8_t description)
-{
- size_t rec_start = sendbuf->off;
- int ret = 0;
-
- buffer_push_record(sendbuf, PTLS_CONTENT_TYPE_ALERT, { ptls_buffer_push(sendbuf, level, description); });
- /* encrypt the alert if we have the encryption keys, unless when it is the early data key */
- if (tls->traffic_protection.enc.aead != NULL && !(tls->state <= PTLS_STATE_CLIENT_EXPECT_FINISHED)) {
- if ((ret = buffer_encrypt_record(sendbuf, rec_start, &tls->traffic_protection.enc)) != 0)
- goto Exit;
- }
-
-Exit:
- return ret;
-}
-
-int ptls_export_secret(ptls_t *tls, void *output, size_t outlen, const char *label, ptls_iovec_t context_value, int is_early)
-{
- ptls_hash_algorithm_t *algo = tls->key_schedule->hashes[0].algo;
- ptls_hash_context_t *hctx;
- uint8_t *master_secret = is_early ? tls->exporter_master_secret.early : tls->exporter_master_secret.one_rtt,
- derived_secret[PTLS_MAX_DIGEST_SIZE], context_value_hash[PTLS_MAX_DIGEST_SIZE];
- int ret;
-
- if (master_secret == NULL)
- return PTLS_ERROR_IN_PROGRESS;
-
- if ((hctx = algo->create()) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- hctx->update(hctx, context_value.base, context_value.len);
- hctx->final(hctx, context_value_hash, PTLS_HASH_FINAL_MODE_FREE);
-
- if ((ret = ptls_hkdf_expand_label(algo, derived_secret, algo->digest_size, ptls_iovec_init(master_secret, algo->digest_size),
- label, ptls_iovec_init(algo->empty_digest, algo->digest_size), NULL)) != 0)
- goto Exit;
- ret = ptls_hkdf_expand_label(algo, output, outlen, ptls_iovec_init(derived_secret, algo->digest_size), "exporter",
- ptls_iovec_init(context_value_hash, algo->digest_size), NULL);
-
-Exit:
- ptls_clear_memory(derived_secret, sizeof(derived_secret));
- ptls_clear_memory(context_value_hash, sizeof(context_value_hash));
- return ret;
-}
-
-struct st_picotls_hmac_context_t {
- ptls_hash_context_t super;
- ptls_hash_algorithm_t *algo;
- ptls_hash_context_t *hash;
- uint8_t key[1];
-};
-
-static void hmac_update(ptls_hash_context_t *_ctx, const void *src, size_t len)
-{
- struct st_picotls_hmac_context_t *ctx = (struct st_picotls_hmac_context_t *)_ctx;
- ctx->hash->update(ctx->hash, src, len);
-}
-
-static void hmac_apply_key(struct st_picotls_hmac_context_t *ctx, uint8_t pad)
-{
- size_t i;
-
- for (i = 0; i != ctx->algo->block_size; ++i)
- ctx->key[i] ^= pad;
- ctx->hash->update(ctx->hash, ctx->key, ctx->algo->block_size);
- for (i = 0; i != ctx->algo->block_size; ++i)
- ctx->key[i] ^= pad;
-}
-
-static void hmac_final(ptls_hash_context_t *_ctx, void *md, ptls_hash_final_mode_t mode)
-{
- struct st_picotls_hmac_context_t *ctx = (struct st_picotls_hmac_context_t *)_ctx;
-
- assert(mode != PTLS_HASH_FINAL_MODE_SNAPSHOT || !"not supported");
-
- if (md != NULL) {
- ctx->hash->final(ctx->hash, md, PTLS_HASH_FINAL_MODE_RESET);
- hmac_apply_key(ctx, 0x5c);
- ctx->hash->update(ctx->hash, md, ctx->algo->digest_size);
- }
- ctx->hash->final(ctx->hash, md, mode);
-
- switch (mode) {
- case PTLS_HASH_FINAL_MODE_FREE:
- ptls_clear_memory(ctx->key, ctx->algo->block_size);
- free(ctx);
- break;
- case PTLS_HASH_FINAL_MODE_RESET:
- hmac_apply_key(ctx, 0x36);
- break;
- default:
- assert(!"FIXME");
- break;
- }
-}
-
-ptls_hash_context_t *ptls_hmac_create(ptls_hash_algorithm_t *algo, const void *key, size_t key_size)
-{
- struct st_picotls_hmac_context_t *ctx;
-
- if ((ctx = malloc(offsetof(struct st_picotls_hmac_context_t, key) + algo->block_size)) == NULL)
- return NULL;
-
- *ctx = (struct st_picotls_hmac_context_t){{hmac_update, hmac_final}, algo};
- if ((ctx->hash = algo->create()) == NULL) {
- free(ctx);
- return NULL;
- }
- memset(ctx->key, 0, algo->block_size);
- memcpy(ctx->key, key, key_size);
-
- hmac_apply_key(ctx, 0x36);
-
- return &ctx->super;
-}
-
-int ptls_hkdf_extract(ptls_hash_algorithm_t *algo, void *output, ptls_iovec_t salt, ptls_iovec_t ikm)
-{
- ptls_hash_context_t *hash;
-
- if (salt.len == 0)
- salt = ptls_iovec_init(zeroes_of_max_digest_size, algo->digest_size);
-
- if ((hash = ptls_hmac_create(algo, salt.base, salt.len)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- hash->update(hash, ikm.base, ikm.len);
- hash->final(hash, output, PTLS_HASH_FINAL_MODE_FREE);
- return 0;
-}
-
-int ptls_hkdf_expand(ptls_hash_algorithm_t *algo, void *output, size_t outlen, ptls_iovec_t prk, ptls_iovec_t info)
-{
- ptls_hash_context_t *hmac = NULL;
- size_t i;
- uint8_t digest[PTLS_MAX_DIGEST_SIZE];
-
- for (i = 0; (i * algo->digest_size) < outlen; ++i) {
- if (hmac == NULL) {
- if ((hmac = ptls_hmac_create(algo, prk.base, prk.len)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- } else {
- hmac->update(hmac, digest, algo->digest_size);
- }
- hmac->update(hmac, info.base, info.len);
- uint8_t gen = (uint8_t)(i + 1);
- hmac->update(hmac, &gen, 1);
- hmac->final(hmac, digest, 1);
-
- size_t off_start = i * algo->digest_size, off_end = off_start + algo->digest_size;
- if (off_end > outlen)
- off_end = outlen;
- memcpy((uint8_t *)output + off_start, digest, off_end - off_start);
- }
-
- if (hmac != NULL)
- hmac->final(hmac, NULL, PTLS_HASH_FINAL_MODE_FREE);
-
- ptls_clear_memory(digest, algo->digest_size);
-
- return 0;
-}
-
-int ptls_hkdf_expand_label(ptls_hash_algorithm_t *algo, void *output, size_t outlen, ptls_iovec_t secret, const char *label,
- ptls_iovec_t hash_value, const char *base_label)
-{
- ptls_buffer_t hkdf_label;
- uint8_t hkdf_label_buf[512];
- int ret;
-
- ptls_buffer_init(&hkdf_label, hkdf_label_buf, sizeof(hkdf_label_buf));
-
- ptls_buffer_push16(&hkdf_label, (uint16_t)outlen);
- ptls_buffer_push_block(&hkdf_label, 1, {
- if (base_label == NULL)
- base_label = "tls13 ";
- ptls_buffer_pushv(&hkdf_label, base_label, strlen(base_label));
- ptls_buffer_pushv(&hkdf_label, label, strlen(label));
- });
- ptls_buffer_push_block(&hkdf_label, 1, { ptls_buffer_pushv(&hkdf_label, hash_value.base, hash_value.len); });
-
- ret = ptls_hkdf_expand(algo, output, outlen, secret, ptls_iovec_init(hkdf_label.base, hkdf_label.off));
-
-Exit:
- ptls_buffer_dispose(&hkdf_label);
- return ret;
-}
-
-ptls_cipher_context_t *ptls_cipher_new(ptls_cipher_algorithm_t *algo, int is_enc, const void *key)
-{
- ptls_cipher_context_t *ctx;
-
- if ((ctx = (ptls_cipher_context_t *)malloc(algo->context_size)) == NULL)
- return NULL;
- *ctx = (ptls_cipher_context_t){algo};
- if (algo->setup_crypto(ctx, is_enc, key) != 0) {
- free(ctx);
- ctx = NULL;
- }
- return ctx;
-}
-
-void ptls_cipher_free(ptls_cipher_context_t *ctx)
-{
- ctx->do_dispose(ctx);
- free(ctx);
-}
-
-ptls_aead_context_t *ptls_aead_new(ptls_aead_algorithm_t *aead, ptls_hash_algorithm_t *hash, int is_enc, const void *secret,
- const char *base_label)
-{
- ptls_aead_context_t *ctx;
- uint8_t key[PTLS_MAX_SECRET_SIZE];
- int ret;
-
- if ((ctx = (ptls_aead_context_t *)malloc(aead->context_size)) == NULL)
- return NULL;
-
- *ctx = (ptls_aead_context_t){aead};
- if ((ret = get_traffic_key(hash, key, aead->key_size, 0, secret, base_label)) != 0)
- goto Exit;
- if ((ret = get_traffic_key(hash, ctx->static_iv, aead->iv_size, 1, secret, base_label)) != 0)
- goto Exit;
- ret = aead->setup_crypto(ctx, is_enc, key);
-
-Exit:
- ptls_clear_memory(key, aead->key_size);
- if (ret != 0) {
- ptls_clear_memory(ctx->static_iv, aead->iv_size);
- free(ctx);
- ctx = NULL;
- }
-
- return ctx;
-}
-
-void ptls_aead_free(ptls_aead_context_t *ctx)
-{
- ctx->dispose_crypto(ctx);
- ptls_clear_memory(ctx->static_iv, ctx->algo->iv_size);
- free(ctx);
-}
-
-size_t ptls_aead_encrypt(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq, const void *aad,
- size_t aadlen)
-{
- size_t off = 0;
-
- ptls_aead_encrypt_init(ctx, seq, aad, aadlen);
- off += ptls_aead_encrypt_update(ctx, ((uint8_t *)output) + off, input, inlen);
- off += ptls_aead_encrypt_final(ctx, ((uint8_t *)output) + off);
-
- return off;
-}
-
-void ptls_aead__build_iv(ptls_aead_context_t *ctx, uint8_t *iv, uint64_t seq)
-{
- size_t iv_size = ctx->algo->iv_size, i;
- const uint8_t *s = ctx->static_iv;
- uint8_t *d = iv;
-
- /* build iv */
- for (i = iv_size - 8; i != 0; --i)
- *d++ = *s++;
- i = 64;
- do {
- i -= 8;
- *d++ = *s++ ^ (uint8_t)(seq >> i);
- } while (i != 0);
-}
-
-static void clear_memory(void *p, size_t len)
-{
- if (len != 0)
- memset(p, 0, len);
-}
-
-void (*volatile ptls_clear_memory)(void *p, size_t len) = clear_memory;
-
-static uint64_t get_time(ptls_get_time_t *self)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-ptls_get_time_t ptls_get_time = {get_time};
-
diff --git a/debian/vendor-h2o/deps/picotls/lib/uecc.c b/debian/vendor-h2o/deps/picotls/lib/uecc.c
deleted file mode 100644
index 10f3252..0000000
--- a/debian/vendor-h2o/deps/picotls/lib/uecc.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WINDOWS
-#include "wincompat.h"
-#else
-#include <unistd.h>
-#endif
-#include "sha2.h"
-#include "uECC.h"
-#include "uECC_vli.h"
-#include "picotls.h"
-#include "picotls/minicrypto.h"
-
-#define TYPE_UNCOMPRESSED_PUBLIC_KEY 4
-
-struct st_secp256r1_key_exhchange_t {
- ptls_key_exchange_context_t super;
- uint8_t priv[SECP256R1_PRIVATE_KEY_SIZE];
- uint8_t pub[SECP256R1_PUBLIC_KEY_SIZE];
-};
-
-static int secp256r1_on_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- struct st_secp256r1_key_exhchange_t *ctx = (struct st_secp256r1_key_exhchange_t *)*_ctx;
- uint8_t *secbytes = NULL;
- int ret;
-
- *_ctx = NULL;
-
- if (secret == NULL) {
- ret = 0;
- goto Exit;
- }
-
- if (peerkey.len != SECP256R1_PUBLIC_KEY_SIZE || peerkey.base[0] != TYPE_UNCOMPRESSED_PUBLIC_KEY) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- if ((secbytes = (uint8_t *)malloc(SECP256R1_SHARED_SECRET_SIZE)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if (!uECC_shared_secret(peerkey.base + 1, ctx->priv, secbytes, uECC_secp256r1())) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- *secret = ptls_iovec_init(secbytes, SECP256R1_SHARED_SECRET_SIZE);
- ret = 0;
-
-Exit:
- if (ret != 0)
- free(secbytes);
- ptls_clear_memory(ctx->priv, sizeof(ctx->priv));
- free(ctx);
- return ret;
-}
-
-static int secp256r1_create_key_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *pubkey)
-{
- struct st_secp256r1_key_exhchange_t *ctx;
-
- if ((ctx = (struct st_secp256r1_key_exhchange_t *)malloc(sizeof(*ctx))) == NULL)
- return PTLS_ERROR_NO_MEMORY;
- ctx->super = (ptls_key_exchange_context_t){secp256r1_on_exchange};
- ctx->pub[0] = TYPE_UNCOMPRESSED_PUBLIC_KEY;
- uECC_make_key(ctx->pub + 1, ctx->priv, uECC_secp256r1());
-
- *_ctx = &ctx->super;
- *pubkey = ptls_iovec_init(ctx->pub, sizeof(ctx->pub));
- return 0;
-}
-
-static int secp256r1_key_exchange(ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey)
-{
- uint8_t priv[SECP256R1_PRIVATE_KEY_SIZE], *pub = NULL, *secbytes = NULL;
- int ret;
-
- if (peerkey.len != SECP256R1_PUBLIC_KEY_SIZE || peerkey.base[0] != TYPE_UNCOMPRESSED_PUBLIC_KEY) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- if ((pub = malloc(SECP256R1_PUBLIC_KEY_SIZE)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((secbytes = malloc(SECP256R1_SHARED_SECRET_SIZE)) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- pub[0] = TYPE_UNCOMPRESSED_PUBLIC_KEY;
- uECC_make_key(pub + 1, priv, uECC_secp256r1());
- if (!uECC_shared_secret(peerkey.base + 1, priv, secbytes, uECC_secp256r1())) {
- ret = PTLS_ALERT_DECRYPT_ERROR;
- goto Exit;
- }
- *pubkey = ptls_iovec_init(pub, SECP256R1_PUBLIC_KEY_SIZE);
- *secret = ptls_iovec_init(secbytes, SECP256R1_SHARED_SECRET_SIZE);
- ret = 0;
-
-Exit:
- ptls_clear_memory(priv, sizeof(priv));
- if (ret != 0) {
- free(secbytes);
- free(pub);
- }
- return ret;
-}
-
-static int secp256r1sha256_sign(ptls_sign_certificate_t *_self, ptls_t *tls, uint16_t *selected_algorithm, ptls_buffer_t *outbuf,
- ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms)
-{
- ptls_minicrypto_secp256r1sha256_sign_certificate_t *self = (ptls_minicrypto_secp256r1sha256_sign_certificate_t *)_self;
- uint8_t hash[32], sig[64];
- size_t i;
- int ret;
-
- /* check algorithm */
- for (i = 0; i != num_algorithms; ++i)
- if (algorithms[i] == PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256)
- break;
- if (i == num_algorithms)
- return PTLS_ALERT_HANDSHAKE_FAILURE;
-
- { /* calc hash */
- cf_sha256_context ctx;
- cf_sha256_init(&ctx);
- cf_sha256_update(&ctx, input.base, input.len);
- cf_sha256_digest_final(&ctx, hash);
- ptls_clear_memory(&ctx, sizeof(ctx));
- }
-
- /* sign */
- uECC_sign(self->key, hash, sizeof(hash), sig, uECC_secp256r1());
-
- /* encode using DER */
- ptls_buffer_push_asn1_sequence(outbuf, {
- if ((ret = ptls_buffer_push_asn1_ubigint(outbuf, sig, 32)) != 0)
- goto Exit;
- if ((ret = ptls_buffer_push_asn1_ubigint(outbuf, sig + 32, 32)) != 0)
- goto Exit;
- });
-
- *selected_algorithm = PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256;
- ret = 0;
-
-Exit:
- ptls_clear_memory(hash, sizeof(hash));
- ptls_clear_memory(sig, sizeof(sig));
- return ret;
-}
-
-int ptls_minicrypto_init_secp256r1sha256_sign_certificate(ptls_minicrypto_secp256r1sha256_sign_certificate_t *self,
- ptls_iovec_t key)
-{
- if (key.len != sizeof(self->key))
- return PTLS_ERROR_INCOMPATIBLE_KEY;
-
- self->super.cb = secp256r1sha256_sign;
- memcpy(self->key, key.base, sizeof(self->key));
-
- return 0;
-}
-
-ptls_key_exchange_algorithm_t ptls_minicrypto_secp256r1 = {PTLS_GROUP_SECP256R1, secp256r1_create_key_exchange,
- secp256r1_key_exchange};
-ptls_key_exchange_algorithm_t *ptls_minicrypto_key_exchanges[] = {&ptls_minicrypto_secp256r1, NULL};