Skip to content

Commit

Permalink
Merge pull request #481 from h2o/kazuho/psk2
Browse files Browse the repository at this point in the history
external PSK mode
  • Loading branch information
kazuho committed Apr 8, 2024
2 parents 703553c + 2af3d24 commit 8b52beb
Show file tree
Hide file tree
Showing 9 changed files with 504 additions and 179 deletions.
2 changes: 1 addition & 1 deletion deps/picotest
Submodule picotest updated 2 files
+29 −23 picotest.c
+24 −3 picotest.h
23 changes: 23 additions & 0 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ extern "C" {
#define PTLS_ALERT_MISSING_EXTENSION 109
#define PTLS_ALERT_UNSUPPORTED_EXTENSION 110
#define PTLS_ALERT_UNRECOGNIZED_NAME 112
#define PTLS_ALERT_UNKNOWN_PSK_IDENTITY 115
#define PTLS_ALERT_CERTIFICATE_REQUIRED 116
#define PTLS_ALERT_NO_APPLICATION_PROTOCOL 120
#define PTLS_ALERT_ECH_REQUIRED 121
Expand Down Expand Up @@ -671,6 +672,12 @@ typedef const struct st_ptls_hpke_cipher_suite_t {
ret (*cb)(struct st_ptls_##name##_t * self, __VA_ARGS__); \
} ptls_##name##_t

typedef struct st_ptls_client_hello_psk_identity_t {
ptls_iovec_t identity;
uint32_t obfuscated_ticket_age;
ptls_iovec_t binder;
} ptls_client_hello_psk_identity_t;

/**
* arguments passsed to the on_client_hello callback
*/
Expand Down Expand Up @@ -706,6 +713,10 @@ typedef struct st_ptls_on_client_hello_parameters_t {
const uint8_t *list;
size_t count;
} server_certificate_types;
struct {
const ptls_client_hello_psk_identity_t *list;
size_t count;
} psk_identities;
/**
* set to 1 if ClientHello is too old (or too new) to be handled by picotls
*/
Expand Down Expand Up @@ -849,6 +860,18 @@ struct st_ptls_context_t {
ptls_iovec_t *list;
size_t count;
} certificates;
/**
* External pre-shared key used for mutual authentication. Unless when using PSK, all the fields must be set to NULL / 0.
*/
struct {
ptls_iovec_t identity;
ptls_iovec_t secret;
/**
* (mandatory) hash algorithm associated to the PSK; cipher-suites not sharing the same `ptls_hash_algorithm_t` will be
* ignored
*/
ptls_hash_algorithm_t *hash;
} pre_shared_key;
/**
* ECH
*/
Expand Down
292 changes: 198 additions & 94 deletions lib/picotls.c

Large diffs are not rendered by default.

78 changes: 53 additions & 25 deletions t/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,9 @@ static void usage(const char *cmd)
" -K key-file ECH private key for each ECH config provided by -E\n"
" -l log-file file to log events (incl. traffic secrets)\n"
" -n negotiates the key exchange method (i.e. wait for HRR)\n"
" -N named-group named group to be used (default: secp256r1)\n"
" -N named-group named group to be used (default: secp256r1); if \"null\"\n"
" is specified alongside `-p`, external PSK handshake with\n"
" no ECDHE is performed\n"
" -s session-file file to read/write the session ticket\n"
" -S require public key exchange when resuming a session\n"
" -E echconfiglist file that contains ECHConfigList or an empty file to\n"
Expand All @@ -383,6 +385,9 @@ static void usage(const char *cmd)
" client, the argument specifies the public keys that the\n"
" server is expected to use. When running as a server, the\n"
" argument is ignored.\n"
" -p psk-identity name of the PSK key; if set, -c and -C specify the\n"
" pre-shared secret\n"
" -P psk-hash hash function associated to the PSK (default: sha256)\n"
" -u update the traffic key when handshake is complete\n"
" -v verify peer using the default certificates\n"
" -V CA-root-file verify peer using the CA Root File\n"
Expand Down Expand Up @@ -444,14 +449,14 @@ int main(int argc, char **argv)
.ech = {.client = {ptls_openssl_hpke_cipher_suites, ptls_openssl_hpke_kems}, .server = {NULL /* activated by -K option */}},
};
ptls_handshake_properties_t hsprop = {{{{NULL}}}};
const char *host, *port, *input_file = NULL;
const char *host, *port, *input_file = NULL, *psk_hash = "sha256";
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;
const char *raw_pub_key_file = NULL, *cert_location = NULL;

while ((ch = getopt(argc, argv, "46abBC:c:i:Ij:k:nN:es:Sr:E:K:l:y:vV:h")) != -1) {
while ((ch = getopt(argc, argv, "46abBC:c:i:Ij:k:nN:es:Sr:p:P:E:K:l:y:vV:h")) != -1) {
switch (ch) {
case '4':
family = AF_INET;
Expand Down Expand Up @@ -503,6 +508,12 @@ int main(int argc, char **argv)
case 'r':
raw_pub_key_file = optarg;
break;
case 'p':
ctx.pre_shared_key.identity = ptls_iovec_init(optarg, strlen(optarg));
break;
case 'P':
psk_hash = optarg;
break;
case 's':
setup_session_file(&ctx, &hsprop, optarg);
break;
Expand All @@ -524,31 +535,36 @@ int main(int argc, char **argv)
case 'V':
setup_verify_certificate(&ctx, optarg);
break;
case 'N': {
ptls_key_exchange_algorithm_t *algo = NULL;
case 'N':
if (strcasecmp(optarg, "null") == 0) {
/* disable use of key exchanges entirely */
ctx.key_exchanges = NULL;
} else {
ptls_key_exchange_algorithm_t *algo = NULL;
#define MATCH(name) \
if (algo == NULL && strcasecmp(optarg, #name) == 0) \
algo = (&ptls_openssl_##name)
MATCH(secp256r1);
MATCH(secp256r1);
#if PTLS_OPENSSL_HAVE_SECP384R1
MATCH(secp384r1);
MATCH(secp384r1);
#endif
#if PTLS_OPENSSL_HAVE_SECP521R1
MATCH(secp521r1);
MATCH(secp521r1);
#endif
#if PTLS_OPENSSL_HAVE_X25519
MATCH(x25519);
MATCH(x25519);
#endif
#undef MATCH
if (algo == NULL) {
fprintf(stderr, "could not find key exchange: %s\n", optarg);
return 1;
if (algo == NULL) {
fprintf(stderr, "could not find key exchange: %s\n", optarg);
return 1;
}
size_t i;
for (i = 0; key_exchanges[i] != NULL; ++i)
;
key_exchanges[i++] = algo;
}
size_t i;
for (i = 0; key_exchanges[i] != NULL; ++i)
;
key_exchanges[i++] = algo;
} break;
break;
case 'u':
request_key_update = 1;
break;
Expand Down Expand Up @@ -604,8 +620,14 @@ int main(int argc, char **argv)
EVP_PKEY_free(pubkey);
}
ctx.use_raw_public_keys = 1;
} else if (ctx.pre_shared_key.identity.base != NULL) {
if (cert_location == NULL) {
fprintf(stderr, "-p must be used with -C or -c\n");
return 1;
}
ctx.pre_shared_key.secret = load_file(cert_location);
} else {
if (cert_location)
if (cert_location != NULL)
load_certificate_chain(&ctx, cert_location);
}

Expand All @@ -615,12 +637,8 @@ int main(int argc, char **argv)
}

if (is_server) {
if (ctx.certificates.count == 0) {
fprintf(stderr, "-c and -k options must be set\n");
return 1;
}
#if PICOTLS_USE_BROTLI
if (ctx.decompress_certificate != NULL) {
if (ctx.certificates.count != 0 && ctx.decompress_certificate != NULL) {
static ptls_emit_compressed_certificate_t ecc;
if (ptls_init_compressed_certificate(&ecc, ctx.certificates.list, ctx.certificates.count, ptls_iovec_init(NULL, 0)) !=
0) {
Expand All @@ -644,10 +662,20 @@ int main(int argc, char **argv)
if (key_exchanges[0] == NULL)
key_exchanges[0] = &ptls_openssl_secp256r1;
if (cipher_suites[0] == NULL) {
size_t i;
for (i = 0; ptls_openssl_cipher_suites[i] != NULL; ++i)
for (size_t i = 0; ptls_openssl_cipher_suites[i] != NULL; ++i)
cipher_suites[i] = ptls_openssl_cipher_suites[i];
}
if (ctx.pre_shared_key.identity.base != NULL) {
size_t i;
for (i = 0; cipher_suites[i] != NULL; ++i)
if (strcmp(cipher_suites[i]->hash->name, psk_hash) == 0)
break;
if (cipher_suites[i] == NULL) {
fprintf(stderr, "no compatible cipher-suite for psk hash: %s\n", psk_hash);
exit(1);
}
ctx.pre_shared_key.hash = cipher_suites[i]->hash;
}
if (argc != 2) {
fprintf(stderr, "missing host and port\n");
return 1;
Expand Down
30 changes: 12 additions & 18 deletions t/mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,30 +112,24 @@ int main(int argc, char **argv)
ptls_minicrypto_secp256r1sha256_sign_certificate_t minicrypto_sign_certificate;
ptls_minicrypto_init_secp256r1sha256_sign_certificate(
&minicrypto_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
ptls_context_t minicrypto_ctx = {ptls_minicrypto_random_bytes,
&ptls_get_time,
ptls_minicrypto_key_exchanges,
ptls_minicrypto_cipher_suites,
{&secp256r1_certificate, 1},
{{NULL}},
NULL,
NULL,
&minicrypto_sign_certificate.super};
ptls_context_t minicrypto_ctx = {.random_bytes = ptls_minicrypto_random_bytes,
.get_time = &ptls_get_time,
.key_exchanges = ptls_minicrypto_key_exchanges,
.cipher_suites = ptls_minicrypto_cipher_suites,
.certificates = {&secp256r1_certificate, 1},
.sign_certificate = &minicrypto_sign_certificate.super};

/* context using mbedtls as backend; minicrypto is used for signing certificate as the mbedtls backend does not (yet) have the
* capability */
ptls_minicrypto_secp256r1sha256_sign_certificate_t mbedtls_sign_certificate;
ptls_minicrypto_init_secp256r1sha256_sign_certificate(
&mbedtls_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
ptls_context_t mbedtls_ctx = {ptls_mbedtls_random_bytes,
&ptls_get_time,
ptls_mbedtls_key_exchanges,
ptls_mbedtls_cipher_suites,
{&secp256r1_certificate, 1},
{{NULL}},
NULL,
NULL,
&mbedtls_sign_certificate.super};
ptls_context_t mbedtls_ctx = {.random_bytes = ptls_mbedtls_random_bytes,
.get_time = &ptls_get_time,
.key_exchanges = ptls_mbedtls_key_exchanges,
.cipher_suites = ptls_mbedtls_cipher_suites,
.certificates = {&secp256r1_certificate, 1},
.sign_certificate = &mbedtls_sign_certificate.super};

ctx = &mbedtls_ctx;
ctx_peer = &mbedtls_ctx;
Expand Down
15 changes: 6 additions & 9 deletions t/minicrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,12 @@ int main(int argc, char **argv)
ptls_minicrypto_init_secp256r1sha256_sign_certificate(&sign_certificate,
ptls_iovec_init(SECP256R1_PRIVATE_KEY, SECP256R1_PRIVATE_KEY_SIZE));

ptls_context_t ctxbuf = {ptls_minicrypto_random_bytes,
&ptls_get_time,
ptls_minicrypto_key_exchanges,
ptls_minicrypto_cipher_suites_all,
{&cert, 1},
{{NULL}},
NULL,
NULL,
&sign_certificate.super};
ptls_context_t ctxbuf = {.random_bytes = ptls_minicrypto_random_bytes,
.get_time = &ptls_get_time,
.key_exchanges = ptls_minicrypto_key_exchanges,
.cipher_suites = ptls_minicrypto_cipher_suites_all,
.certificates = {&cert, 1},
.sign_certificate = &sign_certificate.super};
ctx = ctx_peer = &ctxbuf;
ADD_FFX_AES128_ALGORITHMS(minicrypto);
ADD_FFX_CHACHA20_ALGORITHMS(minicrypto);
Expand Down
15 changes: 6 additions & 9 deletions t/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,15 +599,12 @@ int main(int argc, char **argv)
ptls_iovec_t minicrypto_certificate = ptls_iovec_init(SECP256R1_CERTIFICATE, sizeof(SECP256R1_CERTIFICATE) - 1);
ptls_minicrypto_init_secp256r1sha256_sign_certificate(
&minicrypto_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
ptls_context_t minicrypto_ctx = {ptls_minicrypto_random_bytes,
&ptls_get_time,
ptls_minicrypto_key_exchanges,
ptls_minicrypto_cipher_suites,
{&minicrypto_certificate, 1},
{{NULL}},
NULL,
NULL,
&minicrypto_sign_certificate.super};
ptls_context_t minicrypto_ctx = {.random_bytes = ptls_minicrypto_random_bytes,
.get_time = &ptls_get_time,
.key_exchanges = ptls_minicrypto_key_exchanges,
.cipher_suites = ptls_minicrypto_cipher_suites,
.certificates = {&minicrypto_certificate, 1},
.sign_certificate = &minicrypto_sign_certificate.super};
ctx = &openssl_ctx;
ctx_peer = &minicrypto_ctx;
subtest("vs. minicrypto", test_picotls);
Expand Down
Loading

0 comments on commit 8b52beb

Please sign in to comment.