diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 02:49:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 02:49:40 +0000 |
commit | c96f16e8103783f6b98d9f844ea3a7f2195e4834 (patch) | |
tree | 479bef5e7eb5d4f04ba171931c8b47335734e161 /debian/vendor-h2o/deps/picotls/lib | |
parent | Merging upstream version 1.9.4. (diff) | |
download | dnsdist-debian/1.9.4-1.tar.xz dnsdist-debian/1.9.4-1.zip |
Adding debian version 1.9.4-1.debian/1.9.4-1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/vendor-h2o/deps/picotls/lib')
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/asn1.c | 295 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/cifra.c | 530 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/minicrypto-pem.c | 339 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/openssl.c | 1066 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/pembase64.c | 373 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/picotls.c | 3761 | ||||
-rw-r--r-- | debian/vendor-h2o/deps/picotls/lib/uecc.c | 190 |
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}; |