Merge pull request #47 from h2o/master
Align October 7, 2019
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 85ee333..874b9be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,9 +4,22 @@
PROJECT(picotls)
FIND_PACKAGE(PkgConfig REQUIRED)
+INCLUDE(cmake/dtrace-utils.cmake)
+
+CHECK_DTRACE(${CMAKE_SOURCE_DIR}/picotls-probes.d)
+OPTION(WITH_DTRACE "use USDT (userspace Dtrace probes)" ${HAVE_DTRACE})
+IF (WITH_DTRACE)
+ MESSAGE(STATUS "Enabling USDT support")
+ENDIF ()
SET(CMAKE_C_FLAGS "-std=c99 -Wall -O2 -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}")
-INCLUDE_DIRECTORIES(deps/cifra/src/ext deps/cifra/src deps/micro-ecc deps/picotest include)
+INCLUDE_DIRECTORIES(
+ deps/cifra/src/ext
+ deps/cifra/src
+ deps/micro-ecc
+ deps/picotest
+ include
+ ${CMAKE_CURRENT_BINARY_DIR})
SET(MINICRYPTO_LIBRARY_FILES
deps/micro-ecc/uECC.c
deps/cifra/src/aes.c
@@ -25,6 +38,18 @@
SET(CORE_FILES
lib/picotls.c
lib/pembase64.c)
+SET(CORE_TEST_FILES
+ t/picotls.c)
+IF (WITH_DTRACE)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPICOTLS_USE_DTRACE=1")
+ DEFINE_DTRACE_DEPENDENCIES(${CMAKE_SOURCE_DIR}/picotls-probes.d picotls)
+ LIST(APPEND CORE_FILES ${CMAKE_CURRENT_BINARY_DIR}/picotls-probes.h)
+ LIST(APPEND CORE_TEST_FILES ${CMAKE_CURRENT_BINARY_DIR}/picotls-probes.h)
+ IF (DTRACE_USES_OBJFILE)
+ LIST(APPEND CORE_FILES ${CMAKE_CURRENT_BINARY_DIR}/picotls-probes.o)
+ LIST(APPEND CORE_TEST_FILES ${CMAKE_CURRENT_BINARY_DIR}/picotls-probes.o)
+ ENDIF ()
+ENDIF ()
PKG_CHECK_MODULES(BROTLI_DEC libbrotlidec)
PKG_CHECK_MODULES(BROTLI_ENC libbrotlienc)
@@ -55,7 +80,7 @@
ADD_EXECUTABLE(test-minicrypto.t
${MINICRYPTO_LIBRARY_FILES}
deps/picotest/picotest.c
- t/picotls.c
+ ${CORE_TEST_FILES}
t/minicrypto.c
lib/asn1.c
lib/pembase64.c
@@ -70,7 +95,7 @@
FIND_PACKAGE(OpenSSL)
IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
- MESSAGE(WARNING "Enabling OpenSSL support")
+ MESSAGE(STATUS " Enabling OpenSSL support")
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
ADD_LIBRARY(picotls-openssl lib/openssl.c)
TARGET_LINK_LIBRARIES(picotls-openssl ${OPENSSL_LIBRARIES} picotls-core ${CMAKE_DL_LIBS})
@@ -92,7 +117,7 @@
lib/pembase64.c
lib/ffx.c
deps/picotest/picotest.c
- t/picotls.c
+ ${CORE_TEST_FILES}
t/openssl.c)
SET_TARGET_PROPERTIES(test-openssl.t PROPERTIES COMPILE_FLAGS "-DPTLS_MEMORY_DEBUG=1")
TARGET_LINK_LIBRARIES(test-openssl.t ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
diff --git a/cmake/dtrace-utils.cmake b/cmake/dtrace-utils.cmake
new file mode 100644
index 0000000..da56646
--- /dev/null
+++ b/cmake/dtrace-utils.cmake
@@ -0,0 +1,36 @@
+FUNCTION (CHECK_DTRACE d_file)
+ MESSAGE(STATUS "Detecting USDT support")
+ SET(HAVE_DTRACE "OFF" PARENT_SCOPE)
+ SET(DTRACE_USES_OBJFILE "OFF" PARENT_SCOPE)
+ IF ((CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
+ # USDT is not (yet) supported on platforms (e.g., FreeBSD, Solaris) that require pre-link modification of .o files
+ EXECUTE_PROCESS(
+ COMMAND dtrace -o .tmp.dprobes.h -s ${d_file} -h
+ RESULT_VARIABLE DTRACE_RESULT)
+ FILE(REMOVE .tmp.dprobes.h)
+ IF (DTRACE_RESULT EQUAL 0)
+ MESSAGE(STATUS "Detecting USDT support - found")
+ SET(HAVE_DTRACE "ON" PARENT_SCOPE)
+ IF (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ SET(DTRACE_USES_OBJFILE "ON" PARENT_SCOPE)
+ ENDIF ()
+ ELSE ()
+ MESSAGE(STATUS "Detecting USDT support - not found")
+ ENDIF ()
+ ELSE ()
+ MESSAGE(STATUS "Detecting USDT support - disabled on this platform")
+ ENDIF ()
+ENDFUNCTION ()
+
+FUNCTION (DEFINE_DTRACE_DEPENDENCIES d_file prefix)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${prefix}-probes.h
+ COMMAND dtrace -o ${CMAKE_CURRENT_BINARY_DIR}/${prefix}-probes.h -s ${d_file} -h
+ DEPENDS ${d_file})
+ IF (DTRACE_USES_OBJFILE)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${prefix}-probes.o
+ COMMAND dtrace -o ${CMAKE_CURRENT_BINARY_DIR}/${prefix}-probes.o -s ${d_file} -G
+ DEPENDS ${d_file})
+ ENDIF ()
+ENDFUNCTION ()
diff --git a/fuzz/fuzz-asn1.c b/fuzz/fuzz-asn1.c
index 001f72d..dc8b070 100644
--- a/fuzz/fuzz-asn1.c
+++ b/fuzz/fuzz-asn1.c
@@ -97,7 +97,6 @@
}
} else {
ptls_minicrypto_load_private_key(&ctx, fname);
- free(ctx.pkey_buf.base);
}
out2:
close(fd);
diff --git a/include/picotls.h b/include/picotls.h
index 0fdc7c6..4181714 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -34,7 +34,19 @@
#include <inttypes.h>
#include <sys/types.h>
+#if __GNUC__ >= 3
+#define PTLS_LIKELY(x) __builtin_expect(!!(x), 1)
+#define PTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define PTLS_LIKELY(x) (x)
+#define PTLS_UNLIKELY(x) (x)
+#endif
+#ifdef _WINDOWS
+#define PTLS_THREADLOCAL __declspec(thread)
+#else
+#define PTLS_THREADLOCAL __thread
+#endif
#ifndef PTLS_FUZZ_HANDSHAKE
#define PTLS_FUZZ_HANDSHAKE 0
@@ -142,6 +154,7 @@
#define PTLS_ERROR_NOT_AVAILABLE (PTLS_ERROR_CLASS_INTERNAL + 7)
#define PTLS_ERROR_COMPRESSION_FAILURE (PTLS_ERROR_CLASS_INTERNAL + 8)
#define PTLS_ERROR_ESNI_RETRY (PTLS_ERROR_CLASS_INTERNAL + 8)
+#define PTLS_ERROR_REJECT_EARLY_DATA (PTLS_ERROR_CLASS_INTERNAL + 9)
#define PTLS_ERROR_INCORRECT_BASE64 (PTLS_ERROR_CLASS_INTERNAL + 50)
#define PTLS_ERROR_PEM_LABEL_NOT_FOUND (PTLS_ERROR_CLASS_INTERNAL + 51)
@@ -426,15 +439,13 @@
ptls_iovec_t secret;
uint8_t nonce[PTLS_ESNI_NONCE_SIZE];
uint8_t esni_contents_hash[PTLS_MAX_DIGEST_SIZE];
- union {
- struct {
- ptls_key_exchange_algorithm_t *key_share;
- ptls_cipher_suite_t *cipher;
- ptls_iovec_t pubkey;
- uint8_t record_digest[PTLS_MAX_DIGEST_SIZE];
- uint16_t padded_length;
- } client;
- };
+ struct {
+ ptls_key_exchange_algorithm_t *key_share;
+ ptls_cipher_suite_t *cipher;
+ ptls_iovec_t pubkey;
+ uint8_t record_digest[PTLS_MAX_DIGEST_SIZE];
+ uint16_t padded_length;
+ } client;
uint16_t version;
} ptls_esni_secret_t;
@@ -457,6 +468,10 @@
*/
ptls_iovec_t server_name;
/**
+ * Raw value of the client_hello message.
+ */
+ ptls_iovec_t raw_message;
+ /**
*
*/
struct {
@@ -478,7 +493,7 @@
/**
* if ESNI was used
*/
- uint8_t esni : 1;
+ unsigned esni : 1;
} ptls_on_client_hello_parameters_t;
/**
@@ -511,7 +526,10 @@
int (**verify_sign)(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t sign), void **verify_data,
ptls_iovec_t *certs, size_t num_certs);
/**
- * encrypt-and-signs (or verify-and-decrypts) a ticket (server-only)
+ * Encrypt-and-signs (or verify-and-decrypts) a ticket (server-only).
+ * When used for encryption (i.e., is_encrypt being set), the function should return 0 if successful, or else a non-zero value.
+ * When used for decryption, the function should return 0 (successful), PTLS_ERROR_REJECT_EARLY_DATA (successful, but 0-RTT is
+ * forbidden), or any other value to indicate failure.
*/
PTLS_CALLBACK_TYPE(int, encrypt_ticket, ptls_t *tls, int is_encrypt, ptls_buffer_t *dst, ptls_iovec_t src);
/**
@@ -670,10 +688,6 @@
/**
*
*/
- ptls_iovec_t pkey_buf;
- /**
- *
- */
ptls_on_extension_t *on_extension;
};
@@ -1010,6 +1024,14 @@
*/
void **ptls_get_data_ptr(ptls_t *tls);
/**
+ *
+ */
+int ptls_skip_tracing(ptls_t *tls);
+/**
+ *
+ */
+void ptls_set_skip_tracing(ptls_t *tls, int skip_tracing);
+/**
* proceeds with the handshake, optionally taking some input from peer. The function returns zero in case the handshake completed
* successfully. PTLS_ERROR_IN_PROGRESS is returned in case the handshake is incomplete. Otherwise, an error value is returned. The
* contents of sendbuf should be sent to the client, regardless of whether if an error is returned. inlen is an argument used for
@@ -1188,20 +1210,26 @@
*
*/
void ptls_esni_dispose_context(ptls_esni_context_t *esni);
-
/**
* Obtain the ESNI secrets negotiated during the handshake.
*/
ptls_esni_secret_t *ptls_get_esni_secret(ptls_t *ctx);
-
/**
*
*/
-void ptls_hexdump(char *dst, const void *src, size_t len);
+char *ptls_hexdump(char *dst, const void *src, size_t len);
/**
* the default get_time callback
*/
extern ptls_get_time_t ptls_get_time;
+#if PICOTLS_USE_DTRACE
+/**
+ *
+ */
+extern PTLS_THREADLOCAL unsigned ptls_default_skip_tracing;
+#else
+#define ptls_default_skip_tracing 0
+#endif
/* inline functions */
diff --git a/lib/cifra/random.c b/lib/cifra/random.c
index 4dc3a55..9d26634 100644
--- a/lib/cifra/random.c
+++ b/lib/cifra/random.c
@@ -111,11 +111,7 @@
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
+ static PTLS_THREADLOCAL cf_hash_drbg_sha256 ctx;
if (cf_hash_drbg_sha256_needs_reseed(&ctx)) {
uint8_t entropy[256];
diff --git a/lib/minicrypto-pem.c b/lib/minicrypto-pem.c
index 7c52b20..9d6c499 100644
--- a/lib/minicrypto-pem.c
+++ b/lib/minicrypto-pem.c
@@ -211,7 +211,6 @@
uint8_t *ecdsa_key_data = NULL;
uint32_t ecdsa_key_data_length = 0;
size_t ecdsa_key_data_last = 0;
- ctx->pkey_buf = pkey->vec;
/* We expect the parameters to include just the curve ID */
@@ -335,15 +334,17 @@
* In theory, we could add support for RSA keys at some point.
*/
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)
+ memcmp(pkey.vec.base + pkey.algorithm_index, ptls_asn1_algorithm_ecdsa, sizeof(ptls_asn1_algorithm_ecdsa)) != 0) {
+ ret = -1;
goto err;
+ }
- return ptls_set_ecdsa_private_key(ctx, &pkey, NULL);
+ ret = ptls_set_ecdsa_private_key(ctx, &pkey, NULL);
err:
if (pkey.vec.base) {
ptls_clear_memory(pkey.vec.base, pkey.vec.len);
free(pkey.vec.base);
}
- return -1;
+ return ret;
}
diff --git a/lib/picotls.c b/lib/picotls.c
index d79d96c..5b4e060 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -31,6 +31,9 @@
#include <sys/time.h>
#endif
#include "picotls.h"
+#if PICOTLS_USE_DTRACE
+#include "picotls-probes.h"
+#endif
#define PTLS_MAX_PLAINTEXT_RECORD_SIZE 16384
#define PTLS_MAX_ENCRYPTED_RECORD_SIZE (16384 + 256)
@@ -89,6 +92,25 @@
#define PTLS_MEMORY_DEBUG 0
#endif
+#if PICOTLS_USE_DTRACE
+#define PTLS_SHOULD_PROBE(LABEL, tls) (PTLS_UNLIKELY(PICOTLS_##LABEL##_ENABLED()) && !(tls)->skip_tracing)
+#define PTLS_PROBE0(LABEL, tls) \
+ do { \
+ ptls_t *_tls = (tls); \
+ if (PTLS_SHOULD_PROBE(LABEL, _tls)) \
+ PICOTLS_##LABEL(_tls); \
+ } while (0)
+#define PTLS_PROBE(LABEL, tls, ...) \
+ do { \
+ ptls_t *_tls = (tls); \
+ if (PTLS_SHOULD_PROBE(LABEL, _tls)) \
+ PICOTLS_##LABEL(_tls, __VA_ARGS__); \
+ } while (0)
+#else
+#define PTLS_PROBE0(LABEL, tls)
+#define PTLS_PROBE(LABEL, tls, ...)
+#endif
+
/**
* list of supported versions in the preferred order
*/
@@ -208,6 +230,7 @@
unsigned send_change_cipher_spec : 1;
unsigned needs_key_update : 1;
unsigned key_update_send_request : 1;
+ unsigned skip_tracing : 1;
/**
* misc.
*/
@@ -775,11 +798,12 @@
static void log_secret(ptls_t *tls, const char *type, ptls_iovec_t secret)
{
- if (tls->ctx->log_event != NULL) {
- char hexbuf[PTLS_MAX_DIGEST_SIZE * 2 + 1];
- ptls_hexdump(hexbuf, secret.base, secret.len);
- tls->ctx->log_event->cb(tls->ctx->log_event, tls, type, "%s", hexbuf);
- }
+ char hexbuf[PTLS_MAX_DIGEST_SIZE * 2 + 1];
+
+ PTLS_PROBE(NEW_SECRET, tls, type, ptls_hexdump(hexbuf, secret.base, secret.len));
+
+ if (tls->ctx->log_event != NULL)
+ tls->ctx->log_event->cb(tls->ctx->log_event, tls, type, "%s", ptls_hexdump(hexbuf, secret.base, secret.len));
}
static void key_schedule_free(ptls_key_schedule_t *sched)
@@ -1170,6 +1194,12 @@
return setup_traffic_protection(tls, is_enc, NULL, 2, 1);
}
+static inline void log_client_random(ptls_t *tls)
+{
+ PTLS_PROBE(CLIENT_RANDOM, tls,
+ ptls_hexdump(alloca(sizeof(tls->client_random) * 2 + 1), tls->client_random, sizeof(tls->client_random)));
+}
+
#define SESSION_IDENTIFIER_MAGIC "ptls0001" /* the number should be changed upon incompatible format change */
#define SESSION_IDENTIFIER_MAGIC_SIZE (sizeof(SESSION_IDENTIFIER_MAGIC) - 1)
@@ -3368,9 +3398,17 @@
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 */
+ int can_accept_early_data = 1;
decbuf.off = 0;
- if ((tls->ctx->encrypt_ticket->cb(tls->ctx->encrypt_ticket, tls, 0, &decbuf, identity->identity)) != 0)
+ switch (tls->ctx->encrypt_ticket->cb(tls->ctx->encrypt_ticket, tls, 0, &decbuf, identity->identity)) {
+ case 0: /* decrypted */
+ break;
+ case PTLS_ERROR_REJECT_EARLY_DATA: /* decrypted, but early data is rejected */
+ can_accept_early_data = 0;
+ break;
+ default: /* decryption failure */
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;
@@ -3380,7 +3418,7 @@
if (now - issue_at > (uint64_t)tls->ctx->ticket_lifetime * 1000)
continue;
*accept_early_data = 0;
- if (ch->psk.early_data_indication) {
+ if (ch->psk.early_data_indication && can_accept_early_data) {
/* accept early-data if abs(diff) between the reported age and the actual age is within += 10 seconds */
int64_t delta = (now - issue_at) - (identity->obfuscated_ticket_age - age_add);
if (delta < 0)
@@ -3553,6 +3591,7 @@
/* handle client_random, SNI, ESNI */
if (!is_second_flight) {
memcpy(tls->client_random, ch.random_bytes, sizeof(tls->client_random));
+ log_client_random(tls);
ptls_iovec_t server_name = {NULL};
int is_esni = 0;
if (ch.esni.cipher != NULL && tls->ctx->esni != NULL) {
@@ -3568,7 +3607,7 @@
server_name = ch.server_name;
}
if (tls->ctx->on_client_hello != NULL) {
- ptls_on_client_hello_parameters_t params = {server_name,
+ ptls_on_client_hello_parameters_t params = {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},
@@ -4105,20 +4144,24 @@
*tls = (ptls_t){ctx};
tls->is_server = is_server;
tls->send_change_cipher_spec = ctx->send_change_cipher_spec;
+ tls->skip_tracing = ptls_default_skip_tracing;
if (!is_server) {
tls->state = PTLS_STATE_CLIENT_HANDSHAKE_START;
tls->ctx->random_bytes(tls->client_random, sizeof(tls->client_random));
+ log_client_random(tls);
tls->ctx->random_bytes(tls->client.legacy_session_id, sizeof(tls->client.legacy_session_id));
} else {
tls->state = PTLS_STATE_SERVER_EXPECT_CLIENT_HELLO;
tls->server.early_data_skipped_bytes = UINT32_MAX;
}
+ PTLS_PROBE(NEW, tls, is_server);
return tls;
}
void ptls_free(ptls_t *tls)
{
+ PTLS_PROBE0(FREE, tls);
ptls_buffer_dispose(&tls->recvbuf.rec);
ptls_buffer_dispose(&tls->recvbuf.mess);
free_exporter_master_secret(tls, 1);
@@ -4238,6 +4281,16 @@
return &tls->data_ptr;
}
+int ptls_skip_tracing(ptls_t *tls)
+{
+ return tls->skip_tracing;
+}
+
+void ptls_set_skip_tracing(ptls_t *tls, int skip_tracing)
+{
+ tls->skip_tracing = skip_tracing;
+}
+
static int handle_handshake_message(ptls_t *tls, ptls_message_emitter_t *emitter, ptls_iovec_t message, int is_end_of_record,
ptls_handshake_properties_t *properties)
{
@@ -4358,6 +4411,9 @@
break;
}
+ PTLS_PROBE(RECEIVE_MESSAGE, tls, message.base[0], message.base + PTLS_HANDSHAKE_HEADER_SIZE,
+ message.len - PTLS_HANDSHAKE_HEADER_SIZE, ret);
+
return ret;
}
@@ -5015,6 +5071,9 @@
}
ptls_get_time_t ptls_get_time = {get_time};
+#if PICOTLS_USE_DTRACE
+PTLS_THREADLOCAL unsigned ptls_default_skip_tracing = 0;
+#endif
int ptls_is_server(ptls_t *tls)
{
@@ -5247,8 +5306,9 @@
return 0;
}
-void ptls_hexdump(char *dst, const void *_src, size_t len)
+char *ptls_hexdump(char *buf, const void *_src, size_t len)
{
+ char *dst = buf;
const uint8_t *src = _src;
size_t i;
@@ -5257,4 +5317,5 @@
*dst++ = "0123456789abcdef"[src[i] & 0xf];
}
*dst++ = '\0';
+ return buf;
}
diff --git a/misc/dtrace/bpftrace.d b/misc/dtrace/bpftrace.d
new file mode 100644
index 0000000..84ea53a
--- /dev/null
+++ b/misc/dtrace/bpftrace.d
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Fastly, 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.
+ *
+ * Below is an example bpftrace script that logs the events in JSON-logging
+ * format. The script can be invoked like:
+ *
+ * % sudo bpftrace -p $(pidof cli) /mydev/picotls/misc/dtrace/bpftrace.d
+ */
+
+usdt::picotls_new {
+ printf("{\"addr\": \"%p\", \"event\": \"new\", \"is_server\": %d}\n", arg0, arg1);
+}
+usdt::picotls_free {
+ printf("{\"addr\": \"%p\", \"event\": \"free\"}\n", arg0);
+}
+usdt::picotls_client_random {
+ printf("{\"addr\": \"%p\", \"event\": \"client_random\"", arg0);
+ printf(", \"bytes\": \"%s\"}\n", str(arg1));
+}
+usdt::picotls_new_secret {
+ printf("\"addr\": \"%p\", \"event\": \"new_secret\"", arg0);
+ printf(", \"label\": \"%s\", \"secret\": \"%s\"}\n", str(arg1), str(arg2));
+}
diff --git a/misc/dtrace/dtrace.d b/misc/dtrace/dtrace.d
new file mode 100644
index 0000000..de34d38
--- /dev/null
+++ b/misc/dtrace/dtrace.d
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Fastly, 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.
+ *
+ * Below is an example bpftrace script that logs the events in JSON-logging
+ * format. The script can be invoked like:
+ *
+ * % sudo dtrace -c './cli 127.0.0.1 4433' -s misc/dtrace/dtrace.d
+ */
+
+picotls$target:::picotls_new {
+ printf("\n{\"addr\": \"0x%p\", \"event\": \"new\", \"is_server\": %d}", arg0, arg1);
+}
+picotls$target:::picotls_free {
+ printf("\n{\"addr\": \"0x%p\", \"event\": \"free\"}", arg0);
+}
+picotls$target:::picotls_client_random {
+ printf("\n{\"addr\": \"0x%p\", \"event\": \"client_random\", \"bytes\": \"%s\"}", arg0, copyinstr(arg1));
+}
+picotls$target:::picotls_new_secret {
+ printf("\n{\"addr\": \"0x%p\", \"event\": \"new_secret\", \"label\": \"%s\", \"secret\": \"%s\"}", arg0, copyinstr(arg1), copyinstr(arg2));
+}
+picotls$target:::picotls_receive_message {
+ printf("\n{\"addr\": \"0x%p\", \"event\": \"receive_message\", \"type\": %d, \"ret\": %d}\n", arg0, arg1, arg4);
+ tracemem(copyin(arg2, arg3), 65535, arg3);
+}
diff --git a/picotls-probes.d b/picotls-probes.d
new file mode 100644
index 0000000..614a571
--- /dev/null
+++ b/picotls-probes.d
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Fastly, 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.
+ */
+
+provider picotls {
+ probe new(struct st_ptls_t *tls, int is_server);
+ probe free(struct st_ptls_t *tls);
+ probe client_random(struct st_ptls_t *tls, const void *bytes);
+ probe receive_message(struct st_ptls_t *tls, uint8_t message, const void *bytes, size_t len, int result);
+ probe new_secret(struct st_ptls_t *tls, const char *label, const char *secret_hex);
+};
diff --git a/picotls.xcodeproj/project.pbxproj b/picotls.xcodeproj/project.pbxproj
index 921682e..519a807 100644
--- a/picotls.xcodeproj/project.pbxproj
+++ b/picotls.xcodeproj/project.pbxproj
@@ -91,6 +91,7 @@
10EACB131DCEAF0F00CA0341 /* curve25519.h in Headers */ = {isa = PBXBuildFile; fileRef = 105900361DC8D44E00FB4085 /* curve25519.h */; };
10EACB1A1DCEC2A300CA0341 /* libpicotls-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 106530DA1D9B3E6F005B2C60 /* libpicotls-core.a */; };
E949EF282073629300511ECA /* minicrypto-pem.c in Sources */ = {isa = PBXBuildFile; fileRef = E949EF272073629300511ECA /* minicrypto-pem.c */; };
+ E95E95382290456B00215ACD /* picotls-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = E95EBCC0227B71170022C32D /* picotls-probes.d */; };
E97577012212405300D1EF74 /* ffx.h in Headers */ = {isa = PBXBuildFile; fileRef = E97577002212405300D1EF74 /* ffx.h */; };
E97577032212405D00D1EF74 /* ffx.c in Sources */ = {isa = PBXBuildFile; fileRef = E97577022212405D00D1EF74 /* ffx.c */; };
E97577042212407900D1EF74 /* ffx.c in Sources */ = {isa = PBXBuildFile; fileRef = E97577022212405D00D1EF74 /* ffx.c */; };
@@ -249,6 +250,11 @@
106530FE1DAD8A3C005B2C60 /* cli.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cli.c; sourceTree = "<group>"; };
10EACB171DCEAF0F00CA0341 /* libpicotls-minicrypto.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpicotls-minicrypto.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E949EF272073629300511ECA /* minicrypto-pem.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "minicrypto-pem.c"; sourceTree = "<group>"; };
+ E95EBCC0227B71170022C32D /* picotls-probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = "picotls-probes.d"; sourceTree = "<group>"; };
+ E95EBCC3227E82E00022C32D /* dump-github-repository.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "dump-github-repository.pl"; sourceTree = "<group>"; };
+ E95EBCC5227E82FF0022C32D /* bpftrace.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = bpftrace.d; sourceTree = "<group>"; };
+ E95EBCC6227E82FF0022C32D /* dtrace.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = dtrace.d; sourceTree = "<group>"; };
+ E95EBCCA227EA0180022C32D /* dtrace-utils.cmake */ = {isa = PBXFileReference; lastKnownFileType = text; path = "dtrace-utils.cmake"; sourceTree = "<group>"; };
E97577002212405300D1EF74 /* ffx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffx.h; sourceTree = "<group>"; };
E97577022212405D00D1EF74 /* ffx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffx.c; sourceTree = "<group>"; };
E97577072213148800D1EF74 /* e2e.t */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = e2e.t; sourceTree = "<group>"; };
@@ -380,10 +386,13 @@
106530A91D9985E0005B2C60 = {
isa = PBXGroup;
children = (
+ E95EBCC9227E9FF30022C32D /* cmake */,
E9E4B12C2181927900514B47 /* CMakeLists.txt */,
106530E11D9B4000005B2C60 /* deps */,
106530BC1D998616005B2C60 /* include */,
106530BD1D998624005B2C60 /* lib */,
+ E95EBCC2227E82BA0022C32D /* misc */,
+ E95EBCC0227B71170022C32D /* picotls-probes.d */,
E992F79920E99A080008154D /* src */,
106530C41D9B1A0E005B2C60 /* t */,
106530B31D9985E0005B2C60 /* Products */,
@@ -474,6 +483,32 @@
path = picotls;
sourceTree = "<group>";
};
+ E95EBCC2227E82BA0022C32D /* misc */ = {
+ isa = PBXGroup;
+ children = (
+ E95EBCC4227E82F20022C32D /* dtrace */,
+ E95EBCC3227E82E00022C32D /* dump-github-repository.pl */,
+ );
+ path = misc;
+ sourceTree = "<group>";
+ };
+ E95EBCC4227E82F20022C32D /* dtrace */ = {
+ isa = PBXGroup;
+ children = (
+ E95EBCC5227E82FF0022C32D /* bpftrace.d */,
+ E95EBCC6227E82FF0022C32D /* dtrace.d */,
+ );
+ path = dtrace;
+ sourceTree = "<group>";
+ };
+ E95EBCC9227E9FF30022C32D /* cmake */ = {
+ isa = PBXGroup;
+ children = (
+ E95EBCCA227EA0180022C32D /* dtrace-utils.cmake */,
+ );
+ path = cmake;
+ sourceTree = "<group>";
+ };
E992F79920E99A080008154D /* src */ = {
isa = PBXGroup;
children = (
@@ -800,6 +835,7 @@
files = (
E99B75E01F5CDDB500CF503E /* asn1.c in Sources */,
E99B75E11F5CDDB500CF503E /* pembase64.c in Sources */,
+ E95E95382290456B00215ACD /* picotls-probes.d in Sources */,
E97577032212405D00D1EF74 /* ffx.c in Sources */,
106530EB1D9B7C5C005B2C60 /* picotls.c in Sources */,
E9E4B12B2180530400514B47 /* certificate_compression.c in Sources */,
@@ -880,7 +916,7 @@
105900491DC8D57000FB4085 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -889,7 +925,7 @@
1059004A1DC8D57000FB4085 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -899,6 +935,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
@@ -912,6 +949,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
@@ -952,6 +990,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
+ "PICOTLS_USE_DTRACE=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -999,6 +1038,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "PICOTLS_USE_DTRACE=1";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1019,7 +1059,7 @@
106530D11D9B3D45005B2C60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
@@ -1033,7 +1073,7 @@
106530D21D9B3D45005B2C60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
@@ -1048,7 +1088,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -1057,7 +1097,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -1065,7 +1105,10 @@
106530FA1DAD8985005B2C60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "PICOTLS_USE_BROTLI=1";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "PICOTLS_USE_BROTLI=1",
+ "$(inherited)",
+ );
HEADER_SEARCH_PATHS = (
include,
"/usr/local/openssl-1.1.0/include",
@@ -1088,7 +1131,10 @@
106530FB1DAD8985005B2C60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = "PICOTLS_USE_BROTLI=1";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "PICOTLS_USE_BROTLI=1",
+ "$(inherited)",
+ );
HEADER_SEARCH_PATHS = (
include,
"/usr/local/openssl-1.1.0/include",
@@ -1112,7 +1158,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -1121,7 +1167,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
- GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -1129,6 +1175,7 @@
E992F7A720E99A7C0008154D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
@@ -1142,6 +1189,7 @@
E992F7A820E99A7C0008154D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"/usr/local/openssl-1.1.0/include",
include,
diff --git a/t/cli.c b/t/cli.c
index e502d14..0a90dca 100644
--- a/t/cli.c
+++ b/t/cli.c
@@ -64,7 +64,7 @@
}
static int handle_connection(int sockfd, ptls_context_t *ctx, const char *server_name, const char *input_file,
- ptls_handshake_properties_t *hsprop, int request_key_update)
+ ptls_handshake_properties_t *hsprop, int request_key_update, int keep_sender_open)
{
ptls_t *tls = ptls_new(ctx, server_name == NULL);
ptls_buffer_t rbuf, encbuf, ptbuf;
@@ -224,18 +224,19 @@
/* close the sender side when necessary */
if (state == IN_1RTT && inputfd == -1) {
- ptls_buffer_t wbuf;
- uint8_t wbuf_small[32];
- ptls_buffer_init(&wbuf, wbuf_small, sizeof(wbuf_small));
- if ((ret = ptls_send_alert(tls, &wbuf,
- PTLS_ALERT_LEVEL_WARNING, PTLS_ALERT_CLOSE_NOTIFY)) != 0) {
- fprintf(stderr, "ptls_send_alert:%d\n", ret);
+ if (!keep_sender_open) {
+ ptls_buffer_t wbuf;
+ uint8_t wbuf_small[32];
+ ptls_buffer_init(&wbuf, wbuf_small, sizeof(wbuf_small));
+ if ((ret = ptls_send_alert(tls, &wbuf,
+ PTLS_ALERT_LEVEL_WARNING, PTLS_ALERT_CLOSE_NOTIFY)) != 0) {
+ fprintf(stderr, "ptls_send_alert:%d\n", ret);
+ }
+ if (wbuf.off != 0)
+ (void)write(sockfd, wbuf.base, wbuf.off);
+ ptls_buffer_dispose(&wbuf);
+ shutdown(sockfd, SHUT_WR);
}
- if (wbuf.off != 0) {
- (void)write(sockfd, wbuf.base, wbuf.off);
- }
- ptls_buffer_dispose(&wbuf);
- shutdown(sockfd, SHUT_WR);
state = IN_SHUTDOWN;
}
}
@@ -278,14 +279,14 @@
while (1) {
fprintf(stderr, "waiting for connections\n");
if ((conn_fd = accept(listen_fd, NULL, 0)) != -1)
- handle_connection(conn_fd, ctx, NULL, input_file, hsprop, request_key_update);
+ handle_connection(conn_fd, ctx, NULL, input_file, hsprop, request_key_update, 0);
}
return 0;
}
static int run_client(struct sockaddr *sa, socklen_t salen, ptls_context_t *ctx, const char *server_name, const char *input_file,
- ptls_handshake_properties_t *hsprop, int request_key_update)
+ ptls_handshake_properties_t *hsprop, int request_key_update, int keep_sender_open)
{
int fd;
@@ -300,7 +301,7 @@
return 1;
}
- int ret = handle_connection(fd, ctx, server_name, input_file, hsprop, request_key_update);
+ int ret = handle_connection(fd, ctx, server_name, input_file, hsprop, request_key_update, keep_sender_open);
free(hsprop->client.esni_keys.base);
return ret;
}
@@ -317,6 +318,7 @@
" -C certificate-file certificate chain used for client authentication\n"
" -c certificate-file certificate chain used for server authentication\n"
" -i file a file to read from and send to the peer (default: stdin)\n"
+ " -I keep send side open after sending all data (client-only)\n"
" -k key-file specifies the credentials for signing the certificate\n"
" -l log-file file to log events (incl. traffic secrets)\n"
" -n negotiates the key exchange method (i.e. wait for HRR)\n"
@@ -365,12 +367,12 @@
ptls_key_exchange_context_t *elements[16];
size_t count;
} esni_key_exchanges;
- int is_server = 0, use_early_data = 0, request_key_update = 0, ch;
+ int is_server = 0, use_early_data = 0, request_key_update = 0, keep_sender_open = 0, ch;
struct sockaddr_storage sa;
socklen_t salen;
int family = 0;
- while ((ch = getopt(argc, argv, "46abC:c:i:k:nN:es:SE:K:l:vh")) != -1) {
+ while ((ch = getopt(argc, argv, "46abC:c:i:Ik:nN:es:SE:K:l:vh")) != -1) {
switch (ch) {
case '4':
family = AF_INET;
@@ -401,6 +403,9 @@
case 'i':
file = optarg;
break;
+ case 'I':
+ keep_sender_open = 1;
+ break;
case 'k':
load_private_key(&ctx, optarg);
break;
@@ -531,6 +536,6 @@
if (is_server) {
return run_server((struct sockaddr *)&sa, salen, &ctx, file, &hsprop, request_key_update);
} else {
- return run_client((struct sockaddr *)&sa, salen, &ctx, host, file, &hsprop, request_key_update);
+ return run_client((struct sockaddr *)&sa, salen, &ctx, host, file, &hsprop, request_key_update, keep_sender_open);
}
}