Skip to content

Commit

Permalink
Merge pull request h2o#155 from h2o/kazuho/esni
Browse files Browse the repository at this point in the history
Encrypted SNI
  • Loading branch information
kazuho authored Dec 20, 2018
2 parents 6709251 + cbabf29 commit d240c4f
Show file tree
Hide file tree
Showing 15 changed files with 1,574 additions and 305 deletions.
8 changes: 6 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
ADD_LIBRARY(picotls-openssl lib/openssl.c)
ADD_EXECUTABLE(cli t/cli.c lib/pembase64.c)
TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core ${OPENSSL_LIBRARIES} ${CLI_EXTRA_LIBS} ${CMAKE_DL_LIBS})
TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core ${OPENSSL_LIBRARIES} resolv ${CLI_EXTRA_LIBS} ${CMAKE_DL_LIBS})
ADD_EXECUTABLE(picotls-esni src/esni.c)
TARGET_LINK_LIBRARIES(picotls-esni picotls-openssl picotls-core ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
ADD_EXECUTABLE(test-openssl.t ${MINICRYPTO_LIBRARY_FILES} lib/cifra.c lib/uecc.c lib/asn1.c lib/pembase64.c deps/picotest/picotest.c t/picotls.c 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})
Expand All @@ -60,7 +62,9 @@ ENDIF ()

ADD_CUSTOM_TARGET(check prove --exec '' -v ${CMAKE_CURRENT_BINARY_DIR}/*.t WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${TEST_EXES})

IF ("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
IF (CMAKE_SYSTEM_NAME STREQUAL "Linux")
SET(CMAKE_C_FLAGS "-D_GNU_SOURCE ${CMAKE_C_FLAGS}")
ELSEIF ("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
TARGET_LINK_LIBRARIES(cli "socket" "nsl")
ENDIF ()

Expand Down
64 changes: 59 additions & 5 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ extern "C" {
#define PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384 0x0805
#define PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512 0x0806

/* ESNI */
#define PTLS_ESNI_VERSION_DRAFT02 0xff01

/* error classes and macros */
#define PTLS_ERROR_CLASS_SELF_ALERT 0
#define PTLS_ERROR_CLASS_PEER_ALERT 0x100
Expand Down Expand Up @@ -189,10 +192,17 @@ typedef struct st_ptls_buffer_t {
*/
typedef struct st_ptls_key_exchange_context_t {
/**
* called once per created context. Callee must free resources allocated to the context and set *keyex to NULL. Secret and
* peerkey will be NULL in case the exchange never happened.
* the underlying algorithm
*/
const struct st_ptls_key_exchange_algorithm_t *algo;
/**
* the public key
*/
int (*on_exchange)(struct st_ptls_key_exchange_context_t **keyex, ptls_iovec_t *secret, ptls_iovec_t peerkey);
ptls_iovec_t pubkey;
/**
* If `release` is set, the callee frees resources allocated to the context and set *keyex to NULL
*/
int (*on_exchange)(struct st_ptls_key_exchange_context_t **keyex, int release, ptls_iovec_t *secret, ptls_iovec_t peerkey);
} ptls_key_exchange_context_t;

/**
Expand All @@ -207,11 +217,16 @@ typedef const struct st_ptls_key_exchange_algorithm_t {
* creates a context for asynchronous key exchange. The function is called when ClientHello is generated. The on_exchange
* callback of the created context is called when the client receives ServerHello.
*/
int (*create)(ptls_key_exchange_context_t **ctx, ptls_iovec_t *pubkey);
int (*create)(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx);
/**
* implements synchronous key exchange. Called when receiving a ServerHello.
*/
int (*exchange)(ptls_iovec_t *pubkey, ptls_iovec_t *secret, ptls_iovec_t peerkey);
int (*exchange)(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
ptls_iovec_t peerkey);
/**
* crypto-specific data
*/
intptr_t data;
} ptls_key_exchange_algorithm_t;

/**
Expand Down Expand Up @@ -361,6 +376,20 @@ typedef struct st_ptls_message_emitter_t {
int (*commit_message)(struct st_ptls_message_emitter_t *self);
} ptls_message_emitter_t;

/**
* holds ESNIKeys and the private key (instantiated by ptls_esni_parse, freed using ptls_esni_dispose)
*/
typedef struct st_ptls_esni_context_t {
ptls_key_exchange_context_t **key_exchanges;
struct {
ptls_cipher_suite_t *cipher_suite;
uint8_t record_digest[PTLS_MAX_DIGEST_SIZE];
} * cipher_suites;
uint16_t padded_length;
uint64_t not_before;
uint64_t not_after;
} ptls_esni_context_t;

#define PTLS_CALLBACK_TYPE0(ret, name) \
typedef struct st_ptls_##name##_t { \
ret (*cb)(struct st_ptls_##name##_t * self); \
Expand Down Expand Up @@ -394,6 +423,10 @@ typedef struct st_ptls_on_client_hello_parameters_t {
const uint16_t *list;
size_t count;
} certificate_compression_algorithms;
/**
* if ESNI was used
*/
uint8_t esni : 1;
} ptls_on_client_hello_parameters_t;

/**
Expand Down Expand Up @@ -460,6 +493,11 @@ typedef struct st_ptls_decompress_certificate_t {
int (*cb)(struct st_ptls_decompress_certificate_t *self, ptls_t *tls, uint16_t algorithm, ptls_iovec_t output,
ptls_iovec_t input);
} ptls_decompress_certificate_t;
/**
* provides access to the ESNI shared secret (Zx). API is subject to change.
*/
PTLS_CALLBACK_TYPE(int, update_esni_key, ptls_t *tls, ptls_iovec_t secret, ptls_hash_algorithm_t *hash,
const void *hashed_esni_contents);

/**
* the configuration
Expand Down Expand Up @@ -488,6 +526,10 @@ struct st_ptls_context_t {
ptls_iovec_t *list;
size_t count;
} certificates;
/**
* list of ESNI data terminated by NULL
*/
ptls_esni_context_t **esni;
/**
*
*/
Expand Down Expand Up @@ -562,6 +604,10 @@ struct st_ptls_context_t {
*
*/
ptls_decompress_certificate_t *decompress_certificate;
/**
*
*/
ptls_update_esni_key_t *update_esni_key;
};

typedef struct st_ptls_raw_extension_t {
Expand Down Expand Up @@ -606,6 +652,10 @@ typedef struct st_ptls_handshake_properties_t {
* negotiate the key exchange method before sending key_share
*/
unsigned negotiate_before_key_exchange : 1;
/**
* ESNIKeys (the value of the TXT record, after being base64-"decoded")
*/
ptls_iovec_t esni_keys;
} client;
struct {
/**
Expand Down Expand Up @@ -1119,6 +1169,10 @@ int ptls_load_certificates(ptls_context_t *ctx, char const *cert_pem_file);

extern ptls_get_time_t ptls_get_time;

int ptls_esni_init_context(ptls_context_t *ctx, ptls_esni_context_t *esni, ptls_iovec_t esni_keys,
ptls_key_exchange_context_t **key_exchanges);
void ptls_esni_dispose_context(ptls_esni_context_t *esni);

#define ptls_define_hash(name, ctx_type, init_func, update_func, final_func) \
\
struct name##_context_t { \
Expand Down
4 changes: 4 additions & 0 deletions include/picotls/openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ extern ptls_cipher_suite_t ptls_openssl_chacha20poly1305sha256;
#endif

void ptls_openssl_random_bytes(void *buf, size_t len);
/**
* constructs a key exchange context. pkey's reference count is incremented.
*/
int ptls_openssl_create_key_exchange(ptls_key_exchange_context_t **ctx, EVP_PKEY *pkey);

struct st_ptls_openssl_signature_scheme_t {
uint16_t scheme_id;
Expand Down
19 changes: 10 additions & 9 deletions lib/cifra.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,11 @@ static int x25519_derive_secret(ptls_iovec_t *secret, const uint8_t *clientpriv,
return 0;
}

static int x25519_on_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *secret, ptls_iovec_t peerkey)
static int x25519_on_exchange(ptls_key_exchange_context_t **_ctx, int release, 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;
Expand All @@ -177,26 +175,29 @@ static int x25519_on_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *
ret = x25519_derive_secret(secret, ctx->priv, ctx->pub, NULL, peerkey.base);

Exit:
ptls_clear_memory(ctx->priv, sizeof(ctx->priv));
free(ctx);
if (release) {
ptls_clear_memory(ctx->priv, sizeof(ctx->priv));
free(ctx);
*_ctx = NULL;
}
return ret;
}

static int x25519_create_key_exchange(ptls_key_exchange_context_t **_ctx, ptls_iovec_t *pubkey)
static int x25519_create_key_exchange(ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **_ctx)
{
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};
ctx->super = (ptls_key_exchange_context_t){algo, ptls_iovec_init(ctx->pub, sizeof(ctx->pub)), 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)
static int x25519_key_exchange(ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
ptls_iovec_t peerkey)
{
uint8_t priv[X25519_KEY_SIZE], *pub = NULL;
int ret;
Expand Down
Loading

0 comments on commit d240c4f

Please sign in to comment.