Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypted SNI #155

Merged
merged 35 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
22349de
extend the key-exchange API
kazuho Jul 6, 2018
11250be
_XOPEN_SOURCE should only be set on linux (otherwise cannot build cod…
kazuho Jul 6, 2018
2065107
it works!
kazuho Jul 6, 2018
499a8ae
sscanf should use `SCN` not `PRI`
kazuho Jul 6, 2018
9a80f72
set `_GNU_SOURCE` on linux to use getaddrinfo and libresolv at the sa…
kazuho Jul 6, 2018
4f699f8
record if ESNI was used
kazuho Jul 6, 2018
49b9425
oops
kazuho Jul 6, 2018
21cdddd
base label should include "tls13 "
kazuho Jul 6, 2018
815eec9
hash the hello random
kazuho Jul 6, 2018
19d44df
Merge branch 'master' into kazuho/esni
kazuho Jul 7, 2018
d8881fb
use ptls_calc_hash
kazuho Jul 7, 2018
77ccfc7
Accept SNI and ESNI together
ekr Jul 14, 2018
9170f34
Merge pull request #157 from ekr/esni_fixes
kazuho Jul 14, 2018
e6caaa8
include SNI in EE only when SNI (not ESNI) is used
kazuho Jul 14, 2018
843bd4e
Merge branch 'master' into kazuho/esni
kazuho Dec 10, 2018
9763465
add ESNI nonce
kazuho Dec 10, 2018
5db7fd5
ESNI uses it's own key-exchange
kazuho Dec 10, 2018
c7330ed
version field
kazuho Dec 10, 2018
a414cec
PTLS_ESNI_NONCE_SIZE is part of ciphertext outside padded_length
kazuho Dec 10, 2018
cd1dbd6
directly calculate H(ESNIContents)
kazuho Dec 10, 2018
e60d913
retain ESNI-related per-connection values in `st_ptls_esni_secret_t` …
kazuho Dec 10, 2018
85e4742
report if esni was used in the on_client_hello callback
kazuho Dec 10, 2018
0df8eea
release ESNI data when done
kazuho Dec 10, 2018
965ad98
preliminary API that provides access to ESNI shared secret
kazuho Dec 10, 2018
68f2531
rename server-side context to "esni_context"
kazuho Dec 11, 2018
3caddbd
retain esni_keys as part of the context
kazuho Dec 11, 2018
aee1976
[refactor] retain ESNI private key outside of picotls
kazuho Dec 11, 2018
583b6e2
Merge branch 'master' into kazuho/esni
kazuho Dec 12, 2018
8e36e85
fix incorrect value
kazuho Dec 12, 2018
2486aa1
add x25519 support for ESNI
kazuho Dec 12, 2018
52b7552
`--help` fix
kazuho Dec 14, 2018
2841a21
add tests
kazuho Dec 17, 2018
8abdde2
use `#if` instead of `#ifdef` for feature check
kazuho Dec 17, 2018
3d91062
revert unrelated change
kazuho Dec 17, 2018
cbabf29
address memory leak (to help debugging)
kazuho Dec 17, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,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} ${CMAKE_DL_LIBS})
TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core ${OPENSSL_LIBRARIES} resolv ${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 @@ -46,6 +48,8 @@ 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 ()
53 changes: 48 additions & 5 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,15 @@ typedef struct st_ptls_buffer_t {
* key exchange context built by ptls_key_exchange_algorithm::create.
*/
typedef struct st_ptls_key_exchange_context_t {
const struct st_ptls_key_exchange_algorithm_t *algo;
/**
* 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.
* 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, ptls_iovec_t *secret, ptls_iovec_t peerkey);
int (*on_exchange)(struct st_ptls_key_exchange_context_t **keyex, int release, ptls_iovec_t *secret, ptls_iovec_t peerkey);
/**
* optional callback to serialize the private key
*/
int (*save)(struct st_ptls_key_exchange_context_t *keyex, ptls_buffer_t *outbuf);
} ptls_key_exchange_context_t;

/**
Expand All @@ -189,11 +193,21 @@ 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, ptls_iovec_t *pubkey);
/**
* 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);
/**
* optional callback for loading a serialized private key
*/
int (*load)(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx, ptls_iovec_t pubkey,
ptls_iovec_t privkey);
/**
* crypto-specific data
*/
intptr_t data;
} ptls_key_exchange_algorithm_t;

/**
Expand Down Expand Up @@ -333,6 +347,20 @@ typedef const struct st_ptls_cipher_suite_t {
ptls_hash_algorithm_t *hash;
} ptls_cipher_suite_t;

/**
* holds ESNIKeys and the private key (instantiated by ptlts_esni_parse, freed using ptls_esni_dispose)
*/
typedef struct st_ptls_esni_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_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 @@ -421,6 +449,10 @@ struct st_ptls_context_t {
ptls_iovec_t *list;
size_t count;
} certificates;
/**
* list of ESNI data terminated by NULL
*/
ptls_esni_t **esni;
/**
*
*/
Expand Down Expand Up @@ -515,6 +547,10 @@ typedef struct st_ptls_handshake_properties_t {
* pointer to store the maximum size of early-data that can be sent immediately (if NULL, early data is not used)
*/
size_t *max_early_data_size;
/**
* ESNIKeys (the value of the TXT record, after being base64-"decoded")
*/
ptls_iovec_t esni_keys;
/**
*
*/
Expand Down Expand Up @@ -554,6 +590,10 @@ typedef struct st_ptls_handshake_properties_t {
* if retry should be stateless (cookie.key MUST be set when this option is used)
*/
unsigned retry_uses_cookie : 1;
/**
* if esni was used
*/
unsigned esni : 1;
} server;
};
/**
Expand Down Expand Up @@ -980,6 +1020,9 @@ int ptls_load_certificates(ptls_context_t *ctx, char const *cert_pem_file);

extern ptls_get_time_t ptls_get_time;

void ptls_esni_dispose(ptls_esni_t *esni);
int ptls_esni_parse(ptls_context_t *ctx, ptls_esni_t *esni, ptls_iovec_t *esnikeys, const uint8_t *src, const uint8_t *end);

#define ptls_define_hash(name, ctx_type, init_func, update_func, final_func) \
\
struct name##_context_t { \
Expand Down
18 changes: 10 additions & 8 deletions lib/cifra.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,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 @@ -147,26 +145,30 @@ 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, 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};
ctx->super = (ptls_key_exchange_context_t){algo, 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