diff --git a/CMakeLists.txt b/CMakeLists.txt index 3af816dcb..eda747709 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,11 @@ SET(TEST_EXES test-minicrypto.t) SET(PTLSBENCH_LIBS picotls-minicrypto picotls-core) +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # on Darwin, try and pick up openssl from homebrew + set(CMAKE_PREFIX_PATH /usr/local/opt/openssl@1.1 /usr/local/opt/openssl) +endif() + FIND_PACKAGE(OpenSSL) IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1")) MESSAGE(STATUS " Enabling OpenSSL support") diff --git a/include/picotls.h b/include/picotls.h index c98a0531c..142b3ed6e 100644 --- a/include/picotls.h +++ b/include/picotls.h @@ -60,8 +60,10 @@ extern "C" { #define PTLS_ELEMENTSOF(x) (PTLS_ASSERT_IS_ARRAY_EXPR(x) * sizeof(x) / sizeof((x)[0])) -#ifdef _WINDOWS +#if defined(_WINDOWS) #define PTLS_THREADLOCAL __declspec(thread) +#elif defined(PARTICLE) +#define PTLS_THREADLOCAL #else #define PTLS_THREADLOCAL __thread #define PTLS_HAVE_LOG 1 @@ -71,6 +73,10 @@ extern "C" { #define PTLS_FUZZ_HANDSHAKE 0 #endif +#ifdef PTLS_MINIMIZE_STACK +extern void ptls_cleanup_free(void *p); +#endif + #define PTLS_HELLO_RANDOM_SIZE 32 #define PTLS_AES128_KEY_SIZE 16 @@ -606,6 +612,10 @@ typedef struct st_ptls_on_client_hello_parameters_t { * Raw value of the client_hello message. */ ptls_iovec_t raw_message; + /** + * points to the cipher-suites section of the raw_message (see above) + */ + ptls_iovec_t cipher_suites; /** * */ @@ -621,10 +631,6 @@ typedef struct st_ptls_on_client_hello_parameters_t { const uint16_t *list; size_t count; } certificate_compression_algorithms; - struct { - const uint16_t *list; - size_t count; - } cipher_suites; struct { const uint8_t *list; size_t count; @@ -1234,6 +1240,7 @@ uint64_t ptls_decode_quicint(const uint8_t **src, const uint8_t *end); ptls_decode_assert_block_close((src), end); \ } while (0) +#if PTLS_HAVE_LOG #define PTLS_LOG__DO_LOG(module, type, block) \ do { \ int ptlslog_skip = 0; \ @@ -1252,7 +1259,7 @@ uint64_t ptls_decode_quicint(const uint8_t **src, const uint8_t *end); #define PTLS_LOG(module, type, block) \ do { \ - if (!ptls_log.is_active) \ + if (!PTLS_LOG_IS_ACTIVE(ptls_log)) \ break; \ PTLS_LOG__DO_LOG((module), (type), (block)); \ } while (0) @@ -1260,7 +1267,7 @@ uint64_t ptls_decode_quicint(const uint8_t **src, const uint8_t *end); #define PTLS_LOG_CONN(type, tls, block) \ do { \ ptls_t *_tls = (tls); \ - if (!ptls_log.is_active || ptls_skip_tracing(_tls)) \ + if (!PTLS_LOG_IS_ACTIVE(ptls_log) || ptls_skip_tracing(_tls)) \ break; \ PTLS_LOG__DO_LOG(picotls, type, { \ PTLS_LOG_ELEMENT_PTR(tls, _tls); \ @@ -1360,15 +1367,29 @@ uint64_t ptls_decode_quicint(const uint8_t **src, const uint8_t *end); } \ } \ } while (0) +#else +#define PTLS_LOG_CONN(...) +#define PTLS_LOG__DO_LOG(...) +#endif /** * User API is exposed only when logging is supported by the platform. */ typedef struct st_ptls_log_t { +#if PTLS_HAVE_LOG unsigned is_active : 1; +#else + unsigned : 1; +#endif unsigned include_appdata : 1; } ptls_log_t; +#if PTLS_HAVE_LOG +#define PTLS_LOG_IS_ACTIVE(log) (log.is_active) +#else +#define PTLS_LOG_IS_ACTIVE(log) (0) +#endif + #if PTLS_HAVE_LOG extern volatile ptls_log_t ptls_log; /** @@ -1522,7 +1543,13 @@ int ptls_update_key(ptls_t *tls, int request_update); /** * Returns if the context is a server context. */ +#if defined(PICOTLS_CLIENT) && !defined(PICOTLS_SERVER) +#define ptls_is_server(x) (0) +#elif !defined(PICOTLS_CLIENT) && defined(PICOTLS_SERVER) +#define ptls_is_server(x) (1) +#else int ptls_is_server(ptls_t *tls); +#endif /** * returns per-record overhead */ diff --git a/lib/hpke.c b/lib/hpke.c index d243a5393..daf247526 100644 --- a/lib/hpke.c +++ b/lib/hpke.c @@ -48,10 +48,14 @@ static int labeled_extract(ptls_hpke_kem_t *kem, ptls_hpke_cipher_suite_t *ciphe const char *label, ptls_iovec_t ikm) { ptls_buffer_t labeled_ikm; - uint8_t labeled_ikm_smallbuf[64]; int ret; +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&labeled_ikm, "", 0); +#else + uint8_t labeled_ikm_smallbuf[64]; ptls_buffer_init(&labeled_ikm, labeled_ikm_smallbuf, sizeof(labeled_ikm_smallbuf)); +#endif ptls_buffer_pushv(&labeled_ikm, HPKE_V1_LABEL, strlen(HPKE_V1_LABEL)); if ((ret = build_suite_id(&labeled_ikm, kem, cipher)) != 0) @@ -71,12 +75,16 @@ static int labeled_expand(ptls_hpke_kem_t *kem, ptls_hpke_cipher_suite_t *cipher const char *label, ptls_iovec_t info) { ptls_buffer_t labeled_info; - uint8_t labeled_info_smallbuf[64]; int ret; assert(outlen < UINT16_MAX); +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&labeled_info, "", 0); +#else + uint8_t labeled_info_smallbuf[64]; ptls_buffer_init(&labeled_info, labeled_info_smallbuf, sizeof(labeled_info_smallbuf)); +#endif ptls_buffer_push16(&labeled_info, (uint16_t)outlen); ptls_buffer_pushv(&labeled_info, HPKE_V1_LABEL, strlen(HPKE_V1_LABEL)); @@ -97,10 +105,15 @@ static int extract_and_expand(ptls_hpke_kem_t *kem, void *secret, size_t secret_ ptls_iovec_t dh) { ptls_buffer_t kem_context; - uint8_t kem_context_smallbuf[128], eae_prk[PTLS_MAX_DIGEST_SIZE]; + uint8_t eae_prk[PTLS_MAX_DIGEST_SIZE]; int ret; +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&kem_context, "", 0); +#else + uint8_t kem_context_smallbuf[128]; ptls_buffer_init(&kem_context, kem_context_smallbuf, sizeof(kem_context_smallbuf)); +#endif ptls_buffer_pushv(&kem_context, pk_s.base, pk_s.len); ptls_buffer_pushv(&kem_context, pk_r.base, pk_r.len); @@ -172,13 +185,27 @@ static int key_schedule(ptls_hpke_kem_t *kem, ptls_hpke_cipher_suite_t *cipher, const void *shared_secret, ptls_iovec_t info) { ptls_buffer_t key_schedule_context; - uint8_t key_schedule_context_smallbuf[128], secret[PTLS_MAX_DIGEST_SIZE], key[PTLS_MAX_SECRET_SIZE], - base_nonce[PTLS_MAX_IV_SIZE]; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *tmp __attribute__((__cleanup__(ptls_cleanup_free))) = + malloc(PTLS_MAX_DIGEST_SIZE + PTLS_MAX_SECRET_SIZE + PTLS_MAX_IV_SIZE); + if (tmp == NULL) + return PTLS_ERROR_NO_MEMORY; +#define secret (tmp) +#define key (tmp + PTLS_MAX_DIGEST_SIZE) +#define base_nonce (key + PTLS_MAX_SECRET_SIZE) +#else + uint8_t secret[PTLS_MAX_DIGEST_SIZE], key[PTLS_MAX_SECRET_SIZE], base_nonce[PTLS_MAX_IV_SIZE]; +#endif int ret; *ctx = NULL; +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&key_schedule_context, "", 0); +#else + uint8_t key_schedule_context_smallbuf[128]; ptls_buffer_init(&key_schedule_context, key_schedule_context_smallbuf, sizeof(key_schedule_context_smallbuf)); +#endif /* key_schedule_context = concat(mode, LabeledExtract("", "psk_id_hash", psk_id), LabeledExtract("", "info_hash", info)) */ ptls_buffer_push(&key_schedule_context, PTLS_HPKE_MODE_BASE); @@ -214,6 +241,9 @@ static int key_schedule(ptls_hpke_kem_t *kem, ptls_hpke_cipher_suite_t *cipher, ptls_clear_memory(key, sizeof(key)); ptls_clear_memory(base_nonce, sizeof(base_nonce)); return ret; +#undef secret +#undef key +#undef base_nonce } int ptls_hpke_setup_base_s(ptls_hpke_kem_t *kem, ptls_hpke_cipher_suite_t *cipher, ptls_iovec_t *pk_s, ptls_aead_context_t **ctx, diff --git a/lib/picotls.c b/lib/picotls.c index f8fff8931..25465e0ff 100644 --- a/lib/picotls.c +++ b/lib/picotls.c @@ -34,6 +34,9 @@ #include #include #endif +#ifdef PARTICLE +#include +#endif #include "picotls.h" #if PICOTLS_USE_DTRACE #include "picotls-probes.h" @@ -92,7 +95,12 @@ static const char ech_info_prefix[8] = "tls ech"; #define PTLS_MAX_EARLY_DATA_SKIP_SIZE 65536 #endif #if defined(PTLS_DEBUG) && PTLS_DEBUG +#ifdef PARTICLE +#include +#define PTLS_DEBUGF(...) LOG_PRINTF(INFO, __VA_ARGS__) +#else #define PTLS_DEBUGF(...) fprintf(stderr, __VA_ARGS__) +#endif #else #define PTLS_DEBUGF(...) #endif @@ -120,6 +128,13 @@ static const char ech_info_prefix[8] = "tls ech"; #define PTLS_PROBE(LABEL, tls, ...) #endif +#ifdef PTLS_MINIMIZE_STACK +void ptls_cleanup_free(void *p) +{ + free(*(void **)p); +} +#endif + /** * list of supported versions in the preferred order */ @@ -269,7 +284,11 @@ struct st_ptls_t { */ struct st_ptls_ech_t ech; /* flags */ +#if defined(PICOTLS_CLIENT) == defined(PICOTLS_SERVER) unsigned is_server : 1; +#else + unsigned : 1; +#endif unsigned is_psk_handshake : 1; unsigned send_change_cipher_spec : 1; unsigned needs_key_update : 1; @@ -328,7 +347,6 @@ struct st_ptls_client_hello_psk_t { }; #define MAX_UNKNOWN_EXTENSIONS 16 -#define MAX_CLIENT_CIPHERS 32 #define MAX_CERTIFICATE_TYPES 8 struct st_ptls_client_hello_t { @@ -353,10 +371,6 @@ struct st_ptls_client_hello_t { uint16_t list[16]; size_t count; } cert_compression_algos; - struct { - uint16_t list[MAX_CLIENT_CIPHERS]; - size_t count; - } client_ciphers; struct { ptls_iovec_t all; ptls_iovec_t tbs; @@ -588,9 +602,12 @@ int ptls_buffer_reserve_aligned(ptls_buffer_t *buf, size_t delta, uint8_t align_ new_capacity *= 2; } if (align_bits != 0) { -#ifdef _WINDOWS +#if defined(_WINDOWS) if ((newp = _aligned_malloc(new_capacity, (size_t)1 << align_bits)) == NULL) return PTLS_ERROR_NO_MEMORY; +#elif defined(PARTICLE) + if ((newp = memalign(new_capacity, (size_t)1 << align_bits)) == NULL) + return PTLS_ERROR_NO_MEMORY; #else if (posix_memalign(&newp, 1 << align_bits, new_capacity) != 0) return PTLS_ERROR_NO_MEMORY; @@ -1134,11 +1151,15 @@ static int client_setup_ech(struct st_ptls_ech_t *ech, struct st_decoded_ech_con void (*random_bytes)(void *, size_t)) { ptls_buffer_t infobuf; - uint8_t infobuf_smallbuf[256]; int ret; /* setup `enc` and `aead` by running HPKE */ +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&infobuf, "", 0); +#else + uint8_t infobuf_smallbuf[256]; ptls_buffer_init(&infobuf, infobuf_smallbuf, sizeof(infobuf_smallbuf)); +#endif ptls_buffer_pushv(&infobuf, ech_info_prefix, sizeof(ech_info_prefix)); ptls_buffer_pushv(&infobuf, decoded->bytes.base, decoded->bytes.len); if ((ret = ptls_hpke_setup_base_s(decoded->kem, decoded->cipher, &ech->client.enc, &ech->aead, decoded->public_key, @@ -1843,14 +1864,18 @@ static int send_session_ticket(ptls_t *tls, ptls_message_emitter_t *emitter) { 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); +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&session_id, "", 0); +#else + char session_id_smallbuf[128]; ptls_buffer_init(&session_id, session_id_smallbuf, sizeof(session_id_smallbuf)); +#endif { /* calculate verify-data that will be sent by the client */ size_t orig_off = emitter->buf->off; @@ -2296,11 +2321,22 @@ static int encode_client_hello(ptls_context_t *ctx, ptls_buffer_t *sendbuf, enum static int send_client_hello(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_handshake_properties_t *properties, ptls_iovec_t *cookie) { - ptls_iovec_t resumption_secret = {NULL}, resumption_ticket = {NULL}; uint32_t obfuscated_ticket_age = 0; const char *sni_name = NULL; size_t mess_start, msghash_off; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *binder_key __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(PTLS_MAX_DIGEST_SIZE); + if (binder_key == NULL) + return PTLS_ERROR_NO_MEMORY; + ptls_iovec_t *tmp __attribute__((__cleanup__(ptls_cleanup_free))) = calloc(2, sizeof(ptls_iovec_t)); + if (tmp == NULL) + return PTLS_ERROR_NO_MEMORY; +#define resumption_secret (tmp[0]) +#define resumption_ticket (tmp[1]) +#else + ptls_iovec_t resumption_secret = {NULL}, resumption_ticket = {NULL}; uint8_t binder_key[PTLS_MAX_DIGEST_SIZE]; +#endif ptls_buffer_t encoded_ch_inner; int ret, is_second_flight = tls->key_schedule != NULL; @@ -2485,8 +2521,10 @@ static int send_client_hello(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_ Exit: ptls_buffer_dispose(&encoded_ch_inner); - ptls_clear_memory(binder_key, sizeof(binder_key)); + ptls_clear_memory(binder_key, PTLS_MAX_DIGEST_SIZE); return ret; +#undef resumption_secret +#undef resumption_ticket } ptls_cipher_suite_t *ptls_find_cipher_suite(ptls_cipher_suite_t **cipher_suites, uint16_t id) @@ -3102,16 +3140,42 @@ static int send_certificate_verify(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_buffer_t *sendbuf = emitter->buf; size_t algo_off = sendbuf->off; ptls_buffer_push16(sendbuf, 0); /* filled in later */ +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_push_block(sendbuf, 2, { + uint16_t algo; + uint8_t *data __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE); + assert(data); + size_t datalen = build_certificate_verify_signdata(data, tls->key_schedule, context_string); + if ((ret = tls->ctx->sign_certificate->cb( + tls->ctx->sign_certificate, tls, ptls_is_server(tls) ? &tls->server.async_job : NULL, &algo, sendbuf, + ptls_iovec_init(data, datalen), signature_algorithms != NULL ? signature_algorithms->list : NULL, + signature_algorithms != NULL ? signature_algorithms->count : 0)) != 0) { + if (ret == PTLS_ERROR_ASYNC_OPERATION) { + assert(ptls_is_server(tls) || !"async operation only supported on the server-side"); + assert(tls->server.async_job != NULL); + /* Reset the output to the end of the previous handshake message. CertificateVerify will be rebuilt when the + * async operation completes. */ + emitter->buf->off = start_off; + } else { + assert(tls->server.async_job == NULL); + } + goto Exit; + } + assert(tls->server.async_job == NULL); + sendbuf->base[algo_off] = (uint8_t)(algo >> 8); + sendbuf->base[algo_off + 1] = (uint8_t)algo; + }); +#else 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, context_string); if ((ret = tls->ctx->sign_certificate->cb( - tls->ctx->sign_certificate, tls, tls->is_server ? &tls->server.async_job : NULL, &algo, sendbuf, + tls->ctx->sign_certificate, tls, ptls_is_server(tls) ? &tls->server.async_job : NULL, &algo, sendbuf, ptls_iovec_init(data, datalen), signature_algorithms != NULL ? signature_algorithms->list : NULL, signature_algorithms != NULL ? signature_algorithms->count : 0)) != 0) { if (ret == PTLS_ERROR_ASYNC_OPERATION) { - assert(tls->is_server || !"async operation only supported on the server-side"); + assert(ptls_is_server(tls) || !"async operation only supported on the server-side"); assert(tls->server.async_job != NULL); /* Reset the output to the end of the previous handshake message. CertificateVerify will be rebuilt when the * async operation completes. */ @@ -3125,9 +3189,11 @@ static int send_certificate_verify(ptls_t *tls, ptls_message_emitter_t *emitter, sendbuf->base[algo_off] = (uint8_t)(algo >> 8); sendbuf->base[algo_off + 1] = (uint8_t)algo; }); +#endif }); Exit: return ret; +#undef data } static int client_handle_certificate_request(ptls_t *tls, ptls_iovec_t message, ptls_handshake_properties_t *properties) @@ -3152,7 +3218,11 @@ static int client_handle_certificate_request(ptls_t *tls, ptls_iovec_t message, static int handle_certificate(ptls_t *tls, const uint8_t *src, const uint8_t *end, int *got_certs) { +#ifdef PTLS_MINIMIZE_STACK + ptls_iovec_t certs[4]; +#else ptls_iovec_t certs[16]; +#endif size_t num_certs = 0; int ret = 0; @@ -3298,7 +3368,13 @@ static int handle_certificate_verify(ptls_t *tls, ptls_iovec_t message, const ch const uint8_t *src = message.base + PTLS_HANDSHAKE_HEADER_SIZE, *const end = message.base + message.len; uint16_t algo; ptls_iovec_t signature; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *signdata __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE); + if (signdata == NULL) + return PTLS_ERROR_NO_MEMORY; +#else uint8_t signdata[PTLS_MAX_CERTIFICATE_VERIFY_SIGNDATA_SIZE]; +#endif size_t signdata_size; int ret; @@ -3546,18 +3622,12 @@ static int decode_client_hello(ptls_context_t *ctx, struct st_ptls_client_hello_ /* decode and select from ciphersuites */ ptls_decode_open_block(src, end, 2, { + if ((end - src) % 2 != 0) { + ret = PTLS_ALERT_DECODE_ERROR; + goto Exit; + } ch->cipher_suites = ptls_iovec_init(src, end - src); - uint16_t *id = ch->client_ciphers.list; - do { - if ((ret = ptls_decode16(id, &src, end)) != 0) - goto Exit; - id++; - ch->client_ciphers.count++; - if (id >= ch->client_ciphers.list + MAX_CLIENT_CIPHERS) { - src = end; - break; - } - } while (src != end); + src = end; }); /* decode legacy_compression_methods */ @@ -3918,10 +3988,10 @@ static int rebuild_ch_inner(ptls_buffer_t *buf, const uint8_t *src, const uint8_ /* Wrapper function for invoking the on_client_hello callback, taking an exhaustive list of parameters as arguments. The intention * is to not miss setting them as we add new parameters to the struct. */ -static inline int call_on_client_hello_cb(ptls_t *tls, ptls_iovec_t server_name, ptls_iovec_t raw_message, ptls_iovec_t *alpns, - size_t num_alpns, const uint16_t *sig_algos, size_t num_sig_algos, - const uint16_t *cert_comp_algos, size_t num_cert_comp_algos, - const uint16_t *cipher_suites, size_t num_cipher_suites, const uint8_t *server_cert_types, +static inline int call_on_client_hello_cb(ptls_t *tls, ptls_iovec_t server_name, ptls_iovec_t raw_message, + ptls_iovec_t cipher_suites, ptls_iovec_t *alpns, size_t num_alpns, + const uint16_t *sig_algos, size_t num_sig_algos, const uint16_t *cert_comp_algos, + size_t num_cert_comp_algos, const uint8_t *server_cert_types, size_t num_server_cert_types, int incompatible_version) { if (tls->ctx->on_client_hello == NULL) @@ -3929,10 +3999,10 @@ static inline int call_on_client_hello_cb(ptls_t *tls, ptls_iovec_t server_name, ptls_on_client_hello_parameters_t params = {server_name, raw_message, + cipher_suites, {alpns, num_alpns}, {sig_algos, num_sig_algos}, {cert_comp_algos, num_cert_comp_algos}, - {cipher_suites, num_cipher_suites}, {server_cert_types, num_server_cert_types}, incompatible_version}; return tls->ctx->on_client_hello->cb(tls->ctx->on_client_hello, tls, ¶ms); @@ -3956,8 +4026,8 @@ static int check_client_hello_constraints(ptls_context_t *ctx, struct st_ptls_cl /* fail with PROTOCOL_VERSION alert, after providing the applications the raw CH and SNI to help them fallback */ if (!is_second_flight) { int ret; - if ((ret = call_on_client_hello_cb(tls_cbarg, ch->server_name, raw_message, ch->alpn.list, ch->alpn.count, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, 1)) != 0) + if ((ret = call_on_client_hello_cb(tls_cbarg, ch->server_name, raw_message, ch->cipher_suites, ch->alpn.list, + ch->alpn.count, NULL, 0, NULL, 0, NULL, 0, 1)) != 0) return ret; } return PTLS_ALERT_PROTOCOL_VERSION; @@ -4326,9 +4396,9 @@ static int server_handle_hello(ptls_t *tls, ptls_message_emitter_t *emitter, ptl ptls_iovec_t server_name = {NULL}; if (ch->server_name.base != NULL) server_name = ch->server_name; - if ((ret = call_on_client_hello_cb(tls, server_name, message, ch->alpn.list, ch->alpn.count, ch->signature_algorithms.list, - ch->signature_algorithms.count, ch->cert_compression_algos.list, - ch->cert_compression_algos.count, ch->client_ciphers.list, ch->client_ciphers.count, + if ((ret = call_on_client_hello_cb(tls, server_name, message, ch->cipher_suites, ch->alpn.list, ch->alpn.count, + ch->signature_algorithms.list, ch->signature_algorithms.count, + ch->cert_compression_algos.list, ch->cert_compression_algos.count, ch->server_certificate_types.list, ch->server_certificate_types.count, 0)) != 0) goto Exit; if (!certificate_type_exists(ch->server_certificate_types.list, ch->server_certificate_types.count, @@ -4933,7 +5003,9 @@ static ptls_t *new_instance(ptls_context_t *ctx, int is_server) update_open_count(ctx, 1); *tls = (ptls_t){ctx}; +#if defined(PICOTLS_CLIENT) == defined(PICOTLS_SERVER) tls->is_server = is_server; +#endif tls->send_change_cipher_spec = ctx->send_change_cipher_spec; tls->skip_tracing = ptls_default_skip_tracing; return tls; @@ -5050,8 +5122,7 @@ int ptls_export(ptls_t *tls, ptls_buffer_t *output) ptls_iovec_t negotiated_protocol = ptls_iovec_init(tls->negotiated_protocol, tls->negotiated_protocol != NULL ? strlen(tls->negotiated_protocol) : 0); - return export_tls12_params(output, tls->is_server, tls->is_psk_handshake, tls->cipher_suite, tls->client_random, - tls->server_name, negotiated_protocol, tls->traffic_protection.enc.secret, + return export_tls12_params(output, ptls_is_server(tls), tls->is_psk_handshake, tls->cipher_suite, tls->client_random, tls->server_name, negotiated_protocol, tls->traffic_protection.enc.secret, tls->traffic_protection.enc.secret + PTLS_MAX_SECRET_SIZE, tls->traffic_protection.enc.seq, tls->traffic_protection.enc.tls12_enc_record_iv, tls->traffic_protection.dec.secret, tls->traffic_protection.dec.secret + PTLS_MAX_SECRET_SIZE, tls->traffic_protection.dec.seq); @@ -5185,8 +5256,8 @@ void ptls_free(ptls_t *tls) ptls_aead_free(tls->traffic_protection.enc.aead); free(tls->server_name); free(tls->negotiated_protocol); - clear_ech(&tls->ech, tls->is_server); - if (tls->is_server) { + clear_ech(&tls->ech, ptls_is_server(tls)); + if (ptls_is_server(tls)) { if (tls->server.async_job != NULL) tls->server.async_job->destroy_(tls->server.async_job); } else { @@ -5604,7 +5675,7 @@ static int handle_input(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_buffe return ret; if ((ret = aead_decrypt(&tls->traffic_protection.dec, decryptbuf->base + decryptbuf->off, &decrypted_length, rec.fragment, rec.length)) != 0) { - if (tls->is_server && tls->server.early_data_skipped_bytes != UINT32_MAX) + if (ptls_is_server(tls) && tls->server.early_data_skipped_bytes != UINT32_MAX) goto ServerSkipEarlyData; return ret; } @@ -5617,13 +5688,13 @@ static int handle_input(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_buffe if (rec.length == 0) return PTLS_ALERT_UNEXPECTED_MESSAGE; rec.type = rec.fragment[--rec.length]; - } else if (rec.type == PTLS_CONTENT_TYPE_APPDATA && tls->is_server && tls->server.early_data_skipped_bytes != UINT32_MAX) { + } else if (rec.type == PTLS_CONTENT_TYPE_APPDATA && ptls_is_server(tls) && tls->server.early_data_skipped_bytes != UINT32_MAX) { goto ServerSkipEarlyData; } if (tls->recvbuf.mess.base != NULL || rec.type == PTLS_CONTENT_TYPE_HANDSHAKE) { /* handshake record */ - ret = handle_handshake_record(tls, tls->is_server ? handle_server_handshake_message : handle_client_handshake_message, + ret = handle_handshake_record(tls, ptls_is_server(tls) ? handle_server_handshake_message : handle_client_handshake_message, emitter, &rec, properties); } else { /* handling of an alert or an application record */ @@ -5915,8 +5986,16 @@ int ptls_send_alert(ptls_t *tls, ptls_buffer_t *sendbuf, uint8_t level, uint8_t 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; - 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]; + uint8_t *master_secret = is_early ? tls->exporter_master_secret.early : tls->exporter_master_secret.one_rtt; +#ifdef PTLS_MINIMIZE_STACK + uint8_t *tmp __attribute__((__cleanup__(ptls_cleanup_free))) = malloc(2 * PTLS_MAX_DIGEST_SIZE); + if (tmp == NULL) + return PTLS_ERROR_NO_MEMORY; +#define derived_secret (tmp) +#define context_value_hash (tmp + PTLS_MAX_DIGEST_SIZE) +#else + uint8_t derived_secret[PTLS_MAX_DIGEST_SIZE], context_value_hash[PTLS_MAX_DIGEST_SIZE]; +#endif int ret; if (master_secret == NULL) { @@ -5946,9 +6025,11 @@ int ptls_export_secret(ptls_t *tls, void *output, size_t outlen, const char *lab 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)); + ptls_clear_memory(derived_secret, PTLS_MAX_DIGEST_SIZE); + ptls_clear_memory(context_value_hash, PTLS_MAX_DIGEST_SIZE); return ret; +#undef derived_secret +#undef context_value_hash } struct st_picotls_hmac_context_t { @@ -6085,10 +6166,14 @@ int ptls_hkdf_expand_label(ptls_hash_algorithm_t *algo, void *output, size_t out ptls_iovec_t hash_value, const char *label_prefix) { ptls_buffer_t hkdf_label; - uint8_t hkdf_label_buf[80]; int ret; +#ifdef PTLS_MINIMIZE_STACK + ptls_buffer_init(&hkdf_label, "", 0); +#else + uint8_t hkdf_label_buf[80]; ptls_buffer_init(&hkdf_label, hkdf_label_buf, sizeof(hkdf_label_buf)); +#endif ptls_buffer_push16(&hkdf_label, (uint16_t)outlen); ptls_buffer_push_block(&hkdf_label, 1, { @@ -6264,10 +6349,12 @@ ptls_get_time_t ptls_get_time = {get_time}; PTLS_THREADLOCAL unsigned ptls_default_skip_tracing = 0; #endif +#if defined(PICOTLS_CLIENT) == defined(PICOTLS_SERVER) int ptls_is_server(ptls_t *tls) { return tls->is_server; } +#endif struct st_ptls_raw_message_emitter_t { ptls_message_emitter_t super; @@ -6337,14 +6424,14 @@ size_t ptls_get_read_epoch(ptls_t *tls) int ptls_handle_message(ptls_t *tls, ptls_buffer_t *sendbuf, size_t epoch_offsets[5], size_t in_epoch, const void *input, size_t inlen, ptls_handshake_properties_t *properties) { - return tls->is_server ? ptls_server_handle_message(tls, sendbuf, epoch_offsets, in_epoch, input, inlen, properties) - : ptls_client_handle_message(tls, sendbuf, epoch_offsets, in_epoch, input, inlen, properties); + return ptls_is_server(tls) ? ptls_server_handle_message(tls, sendbuf, epoch_offsets, in_epoch, input, inlen, properties) + : ptls_client_handle_message(tls, sendbuf, epoch_offsets, in_epoch, input, inlen, properties); } int ptls_client_handle_message(ptls_t *tls, ptls_buffer_t *sendbuf, size_t epoch_offsets[5], size_t in_epoch, const void *input, size_t inlen, ptls_handshake_properties_t *properties) { - assert(!tls->is_server); + assert(!ptls_is_server(tls)); struct st_ptls_raw_message_emitter_t emitter = { {sendbuf, &tls->traffic_protection.enc, 0, begin_raw_message, commit_raw_message}, SIZE_MAX, epoch_offsets}; @@ -6362,7 +6449,7 @@ int ptls_client_handle_message(ptls_t *tls, ptls_buffer_t *sendbuf, size_t epoch int ptls_server_handle_message(ptls_t *tls, ptls_buffer_t *sendbuf, size_t epoch_offsets[5], size_t in_epoch, const void *input, size_t inlen, ptls_handshake_properties_t *properties) { - assert(tls->is_server); + assert(ptls_is_server(tls)); struct st_ptls_raw_message_emitter_t emitter = { {sendbuf, &tls->traffic_protection.enc, 0, begin_raw_message, commit_raw_message}, SIZE_MAX, epoch_offsets}; @@ -6546,6 +6633,7 @@ int ptls_log__do_push_unsigned64(ptls_buffer_t *buf, uint64_t v) volatile ptls_log_t ptls_log = {}; +#ifndef PARTICLE static struct { int *fds; size_t num_fds; @@ -6580,11 +6668,13 @@ int ptls_log_add_fd(int fd) return ret; } +#endif #endif void ptls_log__do_write(const ptls_buffer_t *buf) { #if PTLS_HAVE_LOG +#ifndef PARTICLE pthread_mutex_lock(&logctx.mutex); for (size_t fd_index = 0; fd_index < logctx.num_fds;) { @@ -6609,5 +6699,8 @@ void ptls_log__do_write(const ptls_buffer_t *buf) } pthread_mutex_unlock(&logctx.mutex); +#else + LOG_WRITE(INFO, buf->base, buf->off); +#endif #endif } diff --git a/t/util.h b/t/util.h index 0ead3f724..6ae0f66a5 100644 --- a/t/util.h +++ b/t/util.h @@ -34,12 +34,23 @@ #include #include #include +#ifndef PARTICLE #include #include #include #include "picotls/pembase64.h" #include "picotls/openssl.h" +#else +#include "picotls/minicrypto.h" + +#define ptls_openssl_aes128gcm ptls_minicrypto_aes128gcm +#define ptls_openssl_sha256 ptls_minicrypto_sha256 +#define ptls_openssl_secp256r1 ptls_minicrypto_secp256r1 +#define ptls_openssl_cipher_suites ptls_minicrypto_cipher_suites + +#endif +#ifndef PARTICLE static inline void load_certificate_chain(ptls_context_t *ctx, const char *fn) { if (ptls_load_certificates(ctx, (char *)fn) != 0) { @@ -192,6 +203,7 @@ static inline void setup_log_event(ptls_context_t *ctx, const char *fn) ls.super.cb = log_event_cb; ctx->log_event = &ls.super; } +#endif /* single-entry session cache */ struct st_util_session_cache_t { @@ -251,6 +263,7 @@ static inline void setup_session_cache(ptls_context_t *ctx) ctx->encrypt_ticket = &sc.super; } +#ifndef PARTICLE static struct { ptls_iovec_t config_list; struct { @@ -393,6 +406,7 @@ static void ech_setup_key(ptls_context_t *ctx, const char *fn) static ptls_ech_create_opener_t opener = {.cb = ech_create_opener}; ctx->ech.server.create_opener = &opener; } +#endif static inline int resolve_address(struct sockaddr *sa, socklen_t *salen, const char *host, const char *port, int family, int type, int proto) @@ -406,8 +420,10 @@ static inline int resolve_address(struct sockaddr *sa, socklen_t *salen, const c hints.ai_protocol = proto; hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE; if ((err = getaddrinfo(host, port, &hints, &res)) != 0 || res == NULL) { +#ifndef PARTICLE fprintf(stderr, "failed to resolve address:%s:%s:%s\n", host, port, err != 0 ? gai_strerror(err) : "getaddrinfo returned NULL"); +#endif return -1; }