From e763c3ef1485404585b923365f93314aab4e8dd6 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Sun, 30 May 2021 09:19:26 +0000 Subject: Start work on bearssl server-side sni --- src/include/s6-networking/sbearssl.h | 32 ++++++++ src/sbearssl/deps-lib/sbearssl | 3 + src/sbearssl/sbearssl-internal.h | 9 +++ src/sbearssl/sbearssl_sctx_init_full_generic.c | 87 ++++++++++++++++++++++ src/sbearssl/sbearssl_sctx_set_policy_sni.c | 11 +++ src/sbearssl/sbearssl_skey_storagelen.c | 16 ++++ src/sbearssl/sbearssl_skey_wipe.c | 26 +++++++ .../sbearssl_sni_policy_add_keypair_file.c | 42 +++++++++++ src/sbearssl/sbearssl_sni_policy_init.c | 75 +++++++++++++++++++ src/sbearssl/sbearssl_sni_policy_vtable.c | 71 ++++++++++++++++++ 10 files changed, 372 insertions(+) create mode 100644 src/sbearssl/sbearssl_sctx_init_full_generic.c create mode 100644 src/sbearssl/sbearssl_sctx_set_policy_sni.c create mode 100644 src/sbearssl/sbearssl_skey_storagelen.c create mode 100644 src/sbearssl/sbearssl_skey_wipe.c create mode 100644 src/sbearssl/sbearssl_sni_policy_add_keypair_file.c create mode 100644 src/sbearssl/sbearssl_sni_policy_init.c create mode 100644 src/sbearssl/sbearssl_sni_policy_vtable.c (limited to 'src') diff --git a/src/include/s6-networking/sbearssl.h b/src/include/s6-networking/sbearssl.h index 8de12ab..83bc376 100644 --- a/src/include/s6-networking/sbearssl.h +++ b/src/include/s6-networking/sbearssl.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * Support library for bearssl. @@ -153,6 +154,7 @@ extern int sbearssl_skey_from (sbearssl_skey *, br_skey const *, stralloc *) ; extern int sbearssl_skey_to (sbearssl_skey const *, br_skey *, char *) ; extern int sbearssl_skey_readfile (char const *, sbearssl_skey *, stralloc *) ; +extern void sbearssl_skey_wipe (sbearssl_skey, char *) ; /* Public keys */ @@ -262,6 +264,36 @@ extern int sbearssl_send_environment (br_ssl_engine_context *, sbearssl_handshak extern void sbearssl_run (br_ssl_engine_context *, int *, tain_t const *, uint32_t, unsigned int, sbearssl_handshake_cbfunc_ref, sbearssl_handshake_cbarg *) gccattr_noreturn ; + /* Generic server policy class and server-side SNI implementation */ + +typedef struct sbearssl_sni_map_s sbearssl_sni_map, *sbearssl_sni_map_ref ; +struct sbearssl_sni_map_s +{ + char const *servername ; + sbearssl_skey skey ; + size_t chainindex ; + size_t chainlen ; +} ; + +typedef struct sbearssl_sni_policy_context_s sbearssl_sni_policy_context, *sbearssl_sni_policy_context_ref ; +struct sbearssl_sni_policy_context_s +{ + br_ssl_server_policy_class const *vtable ; + br_skey skey ; + avltree map ; + genalloc mapga ; + genalloc certga ; + stralloc storage ; +} + +extern br_ssl_server_policy_class const sbearssl_sni_policy_vtable ; +extern int sbearssl_sni_policy_init (sbearssl_sni_policy_context *) ; +extern int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *, char const *, char const *, char const *) ; + +extern void sbearssl_sctx_init_full_generic (br_ssl_server_context *) ; +extern void sbearssl_sctx_set_policy_sni (br_ssl_server_context *, sbearssl_sni_policy_context *) ; + + /* s6-tlsc-io and s6-tlsd-io implementations */ extern void sbearssl_client_init_and_run (int *, tain_t const *, uint32_t, uint32_t, unsigned int, char const *, sbearssl_handshake_cbfunc_ref, sbearssl_handshake_cbarg *) gccattr_noreturn ; diff --git a/src/sbearssl/deps-lib/sbearssl b/src/sbearssl/deps-lib/sbearssl index 68b3ce1..c0d4507 100644 --- a/src/sbearssl/deps-lib/sbearssl +++ b/src/sbearssl/deps-lib/sbearssl @@ -24,8 +24,11 @@ sbearssl_rsa_pkey_to.o sbearssl_rsa_skey_from.o sbearssl_rsa_skey_to.o sbearssl_run.o +sbearssl_sctx_init_full_generic.o +sbearssl_sctx_set_policy_sni.o sbearssl_send_environment.o sbearssl_server_init_and_run.o +sbearssl_sni_policy_vtable.o sbearssl_skey_from.o sbearssl_skey_readfile.o sbearssl_skey_to.o diff --git a/src/sbearssl/sbearssl-internal.h b/src/sbearssl/sbearssl-internal.h index 21a28d7..d8e0c57 100644 --- a/src/sbearssl/sbearssl-internal.h +++ b/src/sbearssl/sbearssl-internal.h @@ -75,4 +75,13 @@ extern int sbearssl_pem_push (br_pem_decoder_context *, char const *, size_t, sb extern sbearssl_suiteinfo const *const sbearssl_suite_list ; extern size_t const sbearssl_suite_list_len ; +typedef struct sbearssl_sni_policy_node_s sbearssl_sni_policy_node, *sbearssl_policy_node_ref ; +struct sbearssl_sni_policy_node_s +{ + size_t servername ; + sbearssl_skey skey ; + size_t chainindex ; + size_t chainlen ; +} ; + #endif diff --git a/src/sbearssl/sbearssl_sctx_init_full_generic.c b/src/sbearssl/sbearssl_sctx_init_full_generic.c new file mode 100644 index 0000000..2c930c8 --- /dev/null +++ b/src/sbearssl/sbearssl_sctx_init_full_generic.c @@ -0,0 +1,87 @@ +/* ISC license. */ + +#include + +#include + +#include + +static uint16_t const suites[] = +{ + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* ec cipher */ + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* rsa cipher */ + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_RSA_WITH_AES_256_CCM_8, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA +} ; + +static br_hash_class const *hashes[] = +{ + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable +} ; + +void sbearssl_sctx_init_full_generic (br_ssl_server_context *sc) +{ + br_ssl_server_zero(sc) ; + br_ssl_engine_set_versions(&sc->eng, BR_TLS10, BR_TLS12) ; + br_ssl_engine_set_suites(&sc->eng, suites, sizeof(suites) / sizeof(suites[0])) ; + br_ssl_engine_set_default_ec(&sc->eng) ; + + for (unsigned int i = br_md5_ID ; i <= br_sha512_ID ; i++) + br_ssl_engine_set_hash(&sc->eng, i, hashes[i-1]) ; + + br_ssl_engine_set_prf10(&sc->eng, &br_tls10_prf) ; + br_ssl_engine_set_prf_sha256(&sc->eng, &br_tls12_sha256_prf) ; + br_ssl_engine_set_prf_sha384(&sc->eng, &br_tls12_sha384_prf) ; + + br_ssl_engine_set_default_aes_cbc(&sc->eng) ; + br_ssl_engine_set_default_aes_ccm(&sc->eng) ; + br_ssl_engine_set_default_aes_gcm(&sc->eng) ; + br_ssl_engine_set_default_des_cbc(&sc->eng) ; + br_ssl_engine_set_default_chapol(&sc->eng) ; +} diff --git a/src/sbearssl/sbearssl_sctx_set_policy_sni.c b/src/sbearssl/sbearssl_sctx_set_policy_sni.c new file mode 100644 index 0000000..166cd97 --- /dev/null +++ b/src/sbearssl/sbearssl_sctx_set_policy_sni.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include + +#include + +void sbearssl_sctx_set_policy_sni (br_ssl_server_context *sc, sbearssl_sni_policy_context *pol) +{ + sc->chain_handler.vtable = pol->vtable ; + sc->policy_vtable = &sc->chain_handler.vtable ; +} diff --git a/src/sbearssl/sbearssl_skey_storagelen.c b/src/sbearssl/sbearssl_skey_storagelen.c new file mode 100644 index 0000000..706b5f6 --- /dev/null +++ b/src/sbearssl/sbearssl_skey_storagelen.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include + +size_t sbearssl_skey_storagelen (sbearssl_skey const *l) +{ + switch (l->type) + { + case BR_KEYTYPE_RSA : + return l->data.rsa.plen + l->data.rsa.qlen + l->data.rsa.dplen + l->data.rsa.dqlen + l->data.rsa.iqlen ; + case BR_KEYTYPE_EC : + return l->data.ec.xlen ; + default : + return 0 ; + } +} diff --git a/src/sbearssl/sbearssl_skey_wipe.c b/src/sbearssl/sbearssl_skey_wipe.c new file mode 100644 index 0000000..208f89f --- /dev/null +++ b/src/sbearssl/sbearssl_skey_wipe.c @@ -0,0 +1,26 @@ +/* ISC license. */ + +#include + +#include + +#include + +void sbearssl_skey_wipe (sbearssl_skey *key, char *s) +{ + switch (key->type) + { + case BR_KEYTYPE_RSA : + byte_zzero(s + key->rsa.p, key->rsa.plen) ; + byte_zzero(s + key->rsa.q, key->rsa.qlen) ; + byte_zzero(s + key->rsa.dp, key->rsa.dplen) ; + byte_zzero(s + key->rsa.dq, key->rsa.dqlen) ; + byte_zzero(s + key->rsa.iq, key->rsa.iqlen) ; + break ; + case BR_KEYTYPE_EC : + byte_zzero(s + key->ec.x, key->ec.xlen) ; + break ; + default : break ; + } + byte_zzero(key, sizeof(sbearssl_skey)) ; +} diff --git a/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c new file mode 100644 index 0000000..e6cc974 --- /dev/null +++ b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c @@ -0,0 +1,42 @@ +/* ISC license. */ + +#include +#include + +#include + +#include +#include +#include + +#include +#include "sbearssl-internal.h" + +int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *pol, char const *servername, char const *certfile, char const *keyfile) +{ + size_t sabase = pol->storage.len ; + size_t gabase = genalloc_len(sbearssl_cert, &pol->certga) ; + size_t mbase = genalloc_len(sbearssl_sni_policy_node, &pol->mapga) ; + sbearssl_sni_policy_node node = { .servername = sabase, .chainindex = gabase } ; + + if (!stralloc_catb(&pol->storage, servername, strlen(servername) + 1)) return 0 ; + if (!sbearssl_cert_readbigpem(certfile, &pol->certga, &pol->storage)) goto err0 ; + node.chainlen = genalloc_len(sbearssl_cert, &pol->certga) - node.chainindex ; + if (!sbearssl_skey_readfile(keyfile, &node.skey, &pol->storage)) goto err1 ; + if (!genalloc_catb(sbearssl_sni_policy_node, &pol->mapga, &node, 1)) goto err2 ; + if (!avltree_insert(&pol->map, mbase)) goto err3 ; + return 1 ; + + err3: + if (mbase) genalloc_setlen(sbearssl_sni_policy_node, &pol->mapga, mbase) ; + else genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; + err2: + sbearssl_skey_wipe(&pol->skey, pol->storage.s) ; + err1: + if (gabase) genalloc_setlen(sbearssl_cert, &pol->certga, gabase) ; + else genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; + err0: + if (sabase) pol->storage.len = sabase ; + else stralloc_free(pol->storage) ; + return 0 ; +} diff --git a/src/sbearssl/sbearssl_sni_policy_init.c b/src/sbearssl/sbearssl_sni_policy_init.c new file mode 100644 index 0000000..fd0e946 --- /dev/null +++ b/src/sbearssl/sbearssl_sni_policy_init.c @@ -0,0 +1,75 @@ +/* ISC license. */ + +#include + +#include + +#include +#include +#include + +#include + +#define INSTANCE(c) ((sbearssl_sni_policy_context *)(c)) + +static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_context const *sc, br_ssl_server_choices *choices) +{ + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + uint32_t n ; + char const *servername = br_ssl_engine_get_server_name(&sc->eng) ; + if (!avltree_search(&pol->map, servername, &n) + && (!servername[0] || !avltree_search(&pol->map, "", &n))) + return 0 ; + avltree_free(&pol->map) ; + copy_and_free(pol, n) ; +} + +static uint32_t do_keyx (br_ssl_server_policy_class const **pctx, unsigned char *data, size_t *len) +{ + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + switch (pol->skey.type) + { + case BR_KEYTYPE_RSA : return kx_rsa(pol, data, len) ; + case BR_KEYTYPE_EC : return kx_ec(pol, data, len) ; + default : return 0 ; + } +} + +static size_t do_sign (br_ssl_server_policy_class const **pctx, unsigned int algo_id, unsigned char *data, size_t hv_len, size_t len) +{ + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + switch (pol->skey.type) + { + case BR_KEYTYPE_RSA : return sign_rsa(pol, algo_id, data, hv_len, len) ; + case BR_KEYTYPE_EC : return sign_ec(pol, algo_id, data, hv_len, len) ; + default : return 0 ; + } +} + +static br_ssl_server_policy_class const vtable = +{ + .context_size = sizeof(sbearssl_sni_policy_context), + .choose = &choose, + .do_keyx = &do_keyx, + .do_sign = &do_sign +} ; + +static void *sbearssl_sni_policy_node_dtok (uint32_t d, void *data) +{ + return ((sbearssl_sni_policy_context *)data)->storage.s + d ; +} + +static int sbearssl_sni_policy_node_cmp (void const *a, void const *b, void *data) +{ + (void)data ; + return strcmp((char const *)a, (char const *)b) ; +} + +void sbearssl_sni_policy_init (sbearssl_sni_policy_context *pol) +{ + pol->vtable = &vtable ; + pol->map = avltree_zero ; + pol->mapga = genalloc_zero ; + pol->certga = genalloc_zero ; + pol->storage = GENALLOC_ZERO ; +} diff --git a/src/sbearssl/sbearssl_sni_policy_vtable.c b/src/sbearssl/sbearssl_sni_policy_vtable.c new file mode 100644 index 0000000..3b39055 --- /dev/null +++ b/src/sbearssl/sbearssl_sni_policy_vtable.c @@ -0,0 +1,71 @@ +/* ISC license. */ + +#include + +#include + +#define INSTANCE(c) ((sbearssl_x509_small_context *)(c)) + +static void start_chain (br_x509_class const **c, char const *server_name) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + ctx->minimal.vtable->start_chain(&ctx->minimal.vtable, server_name) ; + + ctx->i = 0 ; +} + +static void start_cert (br_x509_class const **c, uint32_t len) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + ctx->minimal.vtable->start_cert(&ctx->minimal.vtable, len) ; + + if (!ctx->i) br_sha256_init(&ctx->hashctx) ; +} + +static void append (br_x509_class const **c, unsigned char const *s, size_t len) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + ctx->minimal.vtable->append(&ctx->minimal.vtable, s, len) ; + + if (!ctx->i) br_sha256_update(&ctx->hashctx, s, len) ; +} + +static void end_cert (br_x509_class const **c) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + ctx->minimal.vtable->end_cert(&ctx->minimal.vtable) ; + + if (!ctx->i) br_sha256_out(&ctx->hashctx, ctx->eehash) ; + ctx->i++ ; +} + +static unsigned int end_chain (br_x509_class const **c) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + unsigned int r = ctx->minimal.vtable->end_chain(&ctx->minimal.vtable) ; + if (!r) + { + uint8_t mask = 1 ; + for (unsigned int i = 0 ; i < 6 ; i++, mask <<= 1) + if (ctx->elts[i].status) + *ctx->eltstatus |= ctx->elts[i].status < 0 ? 128 : mask ; + } + return r ; +} + +static br_x509_pkey const *get_pkey(br_x509_class const *const *c, unsigned int *usages) +{ + sbearssl_x509_small_context *ctx = INSTANCE(c) ; + return ctx->minimal.vtable->get_pkey(&ctx->minimal.vtable, usages) ; +} + +br_x509_class const sbearssl_x509_small_vtable = +{ + .context_size = sizeof(sbearssl_x509_small_context), + .start_chain = &start_chain, + .start_cert = &start_cert, + .append = &append, + .end_cert = &end_cert, + .end_chain = &end_chain, + .get_pkey = &get_pkey, +} ; -- cgit v1.2.3 From a84b9b4e5d985a5d8a37268a76e1d35210fd31c5 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 1 Jun 2021 11:27:05 +0000 Subject: Add all the missing pieces for sni_policy sbearssl_server_init_and_run is yet unchanged, the next step is to rewrite it using the new primitives. --- src/include/s6-networking/sbearssl.h | 13 +- src/sbearssl/deps-lib/sbearssl | 11 +- src/sbearssl/sbearssl-internal.h | 4 +- src/sbearssl/sbearssl_cert_readbigpem.c | 4 +- src/sbearssl/sbearssl_cert_readfile.c | 4 +- src/sbearssl/sbearssl_choose_algos_ec.c | 44 +++++ src/sbearssl/sbearssl_choose_algos_rsa.c | 43 +++++ src/sbearssl/sbearssl_choose_hash.c | 20 ++ src/sbearssl/sbearssl_ec_issuer_keytype.c | 3 + src/sbearssl/sbearssl_pkey_from.c | 3 +- src/sbearssl/sbearssl_pkey_to.c | 3 +- src/sbearssl/sbearssl_skey_from.c | 3 +- src/sbearssl/sbearssl_skey_readfile.c | 3 + src/sbearssl/sbearssl_skey_to.c | 3 +- src/sbearssl/sbearssl_skey_wipe.c | 14 +- .../sbearssl_sni_policy_add_keypair_file.c | 11 +- src/sbearssl/sbearssl_sni_policy_init.c | 55 +----- src/sbearssl/sbearssl_sni_policy_vtable.c | 204 ++++++++++++++++----- src/sbearssl/sbearssl_ta_readfile.c | 3 +- 19 files changed, 326 insertions(+), 122 deletions(-) create mode 100644 src/sbearssl/sbearssl_choose_algos_ec.c create mode 100644 src/sbearssl/sbearssl_choose_algos_rsa.c create mode 100644 src/sbearssl/sbearssl_choose_hash.c (limited to 'src') diff --git a/src/include/s6-networking/sbearssl.h b/src/include/s6-networking/sbearssl.h index 83bc376..f7f721d 100644 --- a/src/include/s6-networking/sbearssl.h +++ b/src/include/s6-networking/sbearssl.h @@ -154,7 +154,8 @@ extern int sbearssl_skey_from (sbearssl_skey *, br_skey const *, stralloc *) ; extern int sbearssl_skey_to (sbearssl_skey const *, br_skey *, char *) ; extern int sbearssl_skey_readfile (char const *, sbearssl_skey *, stralloc *) ; -extern void sbearssl_skey_wipe (sbearssl_skey, char *) ; +extern size_t sbearssl_skey_storagelen (sbearssl_skey const *) ; +extern void sbearssl_skey_wipe (sbearssl_skey *, char *) ; /* Public keys */ @@ -266,6 +267,9 @@ extern void sbearssl_run (br_ssl_engine_context *, int *, tain_t const *, uint32 /* Generic server policy class and server-side SNI implementation */ +extern int sbearssl_choose_algos_rsa (br_ssl_server_context const *, br_ssl_server_choices *, unsigned int) ; +extern int sbearssl_choose_algos_ec (br_ssl_server_context const *, br_ssl_server_choices *, unsigned int, int) ; + typedef struct sbearssl_sni_map_s sbearssl_sni_map, *sbearssl_sni_map_ref ; struct sbearssl_sni_map_s { @@ -284,10 +288,13 @@ struct sbearssl_sni_policy_context_s genalloc mapga ; genalloc certga ; stralloc storage ; -} + union { br_rsa_private rsa ; br_ec_impl const *ec ; } keyx ; + union { br_rsa_pkcs1_sign rsa ; br_ecdsa_sign ec ; } sign ; + br_multihash_context const *mhash ; +} ; extern br_ssl_server_policy_class const sbearssl_sni_policy_vtable ; -extern int sbearssl_sni_policy_init (sbearssl_sni_policy_context *) ; +extern void sbearssl_sni_policy_init (sbearssl_sni_policy_context *) ; extern int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *, char const *, char const *, char const *) ; extern void sbearssl_sctx_init_full_generic (br_ssl_server_context *) ; diff --git a/src/sbearssl/deps-lib/sbearssl b/src/sbearssl/deps-lib/sbearssl index c0d4507..4b6ea70 100644 --- a/src/sbearssl/deps-lib/sbearssl +++ b/src/sbearssl/deps-lib/sbearssl @@ -3,6 +3,9 @@ sbearssl_cert_from.o sbearssl_cert_readbigpem.o sbearssl_cert_readfile.o sbearssl_cert_to.o +sbearssl_choose_algos_ec.o +sbearssl_choose_algos_rsa.o +sbearssl_choose_hash.o sbearssl_client_init_and_run.o sbearssl_drop.o sbearssl_ec_issuer_keytype.o @@ -28,10 +31,14 @@ sbearssl_sctx_init_full_generic.o sbearssl_sctx_set_policy_sni.o sbearssl_send_environment.o sbearssl_server_init_and_run.o -sbearssl_sni_policy_vtable.o sbearssl_skey_from.o sbearssl_skey_readfile.o +sbearssl_skey_storagelen.o sbearssl_skey_to.o +sbearssl_skey_wipe.o +sbearssl_sni_policy_add_keypair_file.o +sbearssl_sni_policy_init.o +sbearssl_sni_policy_vtable.o sbearssl_suite_bits.o sbearssl_suite_list.o sbearssl_suite_name.o @@ -41,8 +48,8 @@ sbearssl_ta_from.o sbearssl_ta_readdir.o sbearssl_ta_readfile.o sbearssl_ta_to.o -sbearssl_x500_name_len.o sbearssl_x500_from_ta.o +sbearssl_x500_name_len.o sbearssl_x509_minimal_set_tai.o sbearssl_x509_small_init_full.o sbearssl_x509_small_vtable.o diff --git a/src/sbearssl/sbearssl-internal.h b/src/sbearssl/sbearssl-internal.h index d8e0c57..8c8839b 100644 --- a/src/sbearssl/sbearssl-internal.h +++ b/src/sbearssl/sbearssl-internal.h @@ -78,10 +78,12 @@ extern size_t const sbearssl_suite_list_len ; typedef struct sbearssl_sni_policy_node_s sbearssl_sni_policy_node, *sbearssl_policy_node_ref ; struct sbearssl_sni_policy_node_s { - size_t servername ; + char const *servername ; sbearssl_skey skey ; size_t chainindex ; size_t chainlen ; } ; +extern unsigned int sbearssl_choose_hash (unsigned int) ; + #endif diff --git a/src/sbearssl/sbearssl_cert_readbigpem.c b/src/sbearssl/sbearssl_cert_readbigpem.c index 64ce139..9e6339a 100644 --- a/src/sbearssl/sbearssl_cert_readbigpem.c +++ b/src/sbearssl/sbearssl_cert_readbigpem.c @@ -1,12 +1,14 @@ /* ISC license. */ #include -#include + #include + #include #include #include #include + #include int sbearssl_cert_readbigpem (char const *fn, genalloc *certs, stralloc *sa) diff --git a/src/sbearssl/sbearssl_cert_readfile.c b/src/sbearssl/sbearssl_cert_readfile.c index 746c2e8..b00a35a 100644 --- a/src/sbearssl/sbearssl_cert_readfile.c +++ b/src/sbearssl/sbearssl_cert_readfile.c @@ -1,12 +1,14 @@ /* ISC license. */ #include -#include + #include + #include #include #include #include + #include int sbearssl_cert_readfile (char const *fn, genalloc *certs, stralloc *sa) diff --git a/src/sbearssl/sbearssl_choose_algos_ec.c b/src/sbearssl/sbearssl_choose_algos_ec.c new file mode 100644 index 0000000..8f02868 --- /dev/null +++ b/src/sbearssl/sbearssl_choose_algos_ec.c @@ -0,0 +1,44 @@ +/* ISC license. */ + +#include + +#include +#include "sbearssl-internal.h" + +int sbearssl_choose_algos_ec (br_ssl_server_context const *sc, br_ssl_server_choices *choices, unsigned int usages, int kt) +{ + size_t n ; + br_suite_translated const *st = br_ssl_server_get_client_suites(sc, &n) ; + unsigned int hash_id = sbearssl_choose_hash(br_ssl_server_get_client_hashes(sc) >> 8) ; + if (sc->eng.session.version < BR_TLS12) hash_id = br_sha1_ID ; + for (size_t i = 0 ; i < n ; i++) + { + unsigned int tt = st[i][1] ; + switch (tt >> 12) + { + case BR_SSLKEYX_ECDH_RSA : + if ((usages & BR_KEYTYPE_KEYX) && kt == BR_KEYTYPE_RSA) + { + choices->cipher_suite = st[i][0] ; + return 1 ; + } + break ; + case BR_SSLKEYX_ECDH_ECDSA : + if ((usages & BR_KEYTYPE_KEYX) && kt == BR_KEYTYPE_EC) + { + choices->cipher_suite = st[i][0] ; + return 1 ; + } + break ; + case BR_SSLKEYX_ECDHE_ECDSA : + if ((usages & BR_KEYTYPE_SIGN) && hash_id) + { + choices->cipher_suite = st[i][0] ; + choices->algo_id = hash_id + 0xff00 ; + return 1 ; + } + break ; + } + } + return 0 ; +} diff --git a/src/sbearssl/sbearssl_choose_algos_rsa.c b/src/sbearssl/sbearssl_choose_algos_rsa.c new file mode 100644 index 0000000..d1f7e19 --- /dev/null +++ b/src/sbearssl/sbearssl_choose_algos_rsa.c @@ -0,0 +1,43 @@ +/* ISC license. */ + +#include + +#include +#include "sbearssl-internal.h" + +int sbearssl_choose_algos_rsa (br_ssl_server_context const *sc, br_ssl_server_choices *choices, unsigned int usages) +{ + size_t n ; + unsigned int hash_id = 0 ; + int fh ; + br_suite_translated const *st = br_ssl_server_get_client_suites(sc, &n) ; + if (sc->eng.session.version < BR_TLS12) fh = 1 ; + else + { + hash_id = sbearssl_choose_hash(br_ssl_server_get_client_hashes(sc)) ; + fh = !!hash_id ; + } + for (size_t i = 0 ; i < n ; i++) + { + unsigned int tt = st[i][1] ; + switch (tt >> 12) + { + case BR_SSLKEYX_RSA : + if (usages & BR_KEYTYPE_KEYX) + { + choices->cipher_suite = st[i][0] ; + return 1 ; + } + break ; + case BR_SSLKEYX_ECDHE_RSA : + if ((usages & BR_KEYTYPE_SIGN) && fh) + { + choices->cipher_suite = st[i][0] ; + choices->algo_id = hash_id + 0xff00 ; + return 1 ; + } + break ; + } + } + return 0 ; +} diff --git a/src/sbearssl/sbearssl_choose_hash.c b/src/sbearssl/sbearssl_choose_hash.c new file mode 100644 index 0000000..1228081 --- /dev/null +++ b/src/sbearssl/sbearssl_choose_hash.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include + +#include "sbearssl-internal.h" + +unsigned int sbearssl_choose_hash (unsigned int bf) +{ + static unsigned char const pref[5] = + { + br_sha256_ID, + br_sha384_ID, + br_sha512_ID, + br_sha224_ID, + br_sha1_ID + } ; + for (unsigned int i = 0 ; i < 5 ; i++) + if ((bf >> pref[i]) & 1) return pref[i] ; + return 0 ; +} diff --git a/src/sbearssl/sbearssl_ec_issuer_keytype.c b/src/sbearssl/sbearssl_ec_issuer_keytype.c index c59da37..aa9365e 100644 --- a/src/sbearssl/sbearssl_ec_issuer_keytype.c +++ b/src/sbearssl/sbearssl_ec_issuer_keytype.c @@ -1,8 +1,11 @@ /* ISC license. */ #include + #include + #include + #include #include "sbearssl-internal.h" diff --git a/src/sbearssl/sbearssl_pkey_from.c b/src/sbearssl/sbearssl_pkey_from.c index c7bc707..e60907e 100644 --- a/src/sbearssl/sbearssl_pkey_from.c +++ b/src/sbearssl/sbearssl_pkey_from.c @@ -1,6 +1,5 @@ /* ISC license. */ -#include #include #include @@ -15,7 +14,7 @@ int sbearssl_pkey_from (sbearssl_pkey *l, br_x509_pkey const *k, stralloc *sa) if (!sbearssl_ec_pkey_from(&l->data.ec, &k->key.ec, sa)) return 0 ; break ; default : - return (errno = EINVAL, 0) ; + return 0 ; } l->type = k->key_type ; return 1 ; diff --git a/src/sbearssl/sbearssl_pkey_to.c b/src/sbearssl/sbearssl_pkey_to.c index 54570aa..158280a 100644 --- a/src/sbearssl/sbearssl_pkey_to.c +++ b/src/sbearssl/sbearssl_pkey_to.c @@ -1,6 +1,5 @@ /* ISC license. */ -#include #include #include @@ -15,7 +14,7 @@ int sbearssl_pkey_to (sbearssl_pkey const *l, br_x509_pkey *k, char *s) sbearssl_ec_pkey_to(&l->data.ec, &k->key.ec, s) ; break ; default : - return (errno = EINVAL, 0) ; + return 0 ; } k->key_type = l->type ; return 1 ; diff --git a/src/sbearssl/sbearssl_skey_from.c b/src/sbearssl/sbearssl_skey_from.c index ac16969..798b6ed 100644 --- a/src/sbearssl/sbearssl_skey_from.c +++ b/src/sbearssl/sbearssl_skey_from.c @@ -1,6 +1,5 @@ /* ISC license. */ -#include #include #include @@ -15,7 +14,7 @@ int sbearssl_skey_from (sbearssl_skey *l, br_skey const *k, stralloc *sa) if (!sbearssl_ec_skey_from(&l->data.ec, &k->data.ec, sa)) return 0 ; break ; default : - return (errno = EINVAL, 0) ; + return 0 ; } l->type = k->type ; return 1 ; diff --git a/src/sbearssl/sbearssl_skey_readfile.c b/src/sbearssl/sbearssl_skey_readfile.c index 7e7df51..0a92842 100644 --- a/src/sbearssl/sbearssl_skey_readfile.c +++ b/src/sbearssl/sbearssl_skey_readfile.c @@ -2,10 +2,13 @@ #include #include + #include + #include #include #include + #include static int decode_key (sbearssl_skey *key, char const *s, size_t len, stralloc *sa) diff --git a/src/sbearssl/sbearssl_skey_to.c b/src/sbearssl/sbearssl_skey_to.c index b588578..5f3b220 100644 --- a/src/sbearssl/sbearssl_skey_to.c +++ b/src/sbearssl/sbearssl_skey_to.c @@ -1,6 +1,5 @@ /* ISC license. */ -#include #include #include @@ -15,7 +14,7 @@ int sbearssl_skey_to (sbearssl_skey const *l, br_skey *k, char *s) sbearssl_ec_skey_to(&l->data.ec, &k->data.ec, s) ; break ; default : - return (errno = EINVAL, 0) ; + return 0 ; } k->type = l->type ; return 1 ; diff --git a/src/sbearssl/sbearssl_skey_wipe.c b/src/sbearssl/sbearssl_skey_wipe.c index 208f89f..8fbcd36 100644 --- a/src/sbearssl/sbearssl_skey_wipe.c +++ b/src/sbearssl/sbearssl_skey_wipe.c @@ -11,16 +11,16 @@ void sbearssl_skey_wipe (sbearssl_skey *key, char *s) switch (key->type) { case BR_KEYTYPE_RSA : - byte_zzero(s + key->rsa.p, key->rsa.plen) ; - byte_zzero(s + key->rsa.q, key->rsa.qlen) ; - byte_zzero(s + key->rsa.dp, key->rsa.dplen) ; - byte_zzero(s + key->rsa.dq, key->rsa.dqlen) ; - byte_zzero(s + key->rsa.iq, key->rsa.iqlen) ; + byte_zzero(s + key->data.rsa.p, key->data.rsa.plen) ; + byte_zzero(s + key->data.rsa.q, key->data.rsa.qlen) ; + byte_zzero(s + key->data.rsa.dp, key->data.rsa.dplen) ; + byte_zzero(s + key->data.rsa.dq, key->data.rsa.dqlen) ; + byte_zzero(s + key->data.rsa.iq, key->data.rsa.iqlen) ; break ; case BR_KEYTYPE_EC : - byte_zzero(s + key->ec.x, key->ec.xlen) ; + byte_zzero(s + key->data.ec.x, key->data.ec.xlen) ; break ; default : break ; } - byte_zzero(key, sizeof(sbearssl_skey)) ; + byte_zzero((char *)key, sizeof(sbearssl_skey)) ; } diff --git a/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c index e6cc974..f77b1d8 100644 --- a/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c +++ b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c @@ -1,7 +1,6 @@ /* ISC license. */ #include -#include #include @@ -17,10 +16,9 @@ int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *pol, char size_t sabase = pol->storage.len ; size_t gabase = genalloc_len(sbearssl_cert, &pol->certga) ; size_t mbase = genalloc_len(sbearssl_sni_policy_node, &pol->mapga) ; - sbearssl_sni_policy_node node = { .servername = sabase, .chainindex = gabase } ; + sbearssl_sni_policy_node node = { .servername = servername, .chainindex = gabase } ; - if (!stralloc_catb(&pol->storage, servername, strlen(servername) + 1)) return 0 ; - if (!sbearssl_cert_readbigpem(certfile, &pol->certga, &pol->storage)) goto err0 ; + if (!sbearssl_cert_readbigpem(certfile, &pol->certga, &pol->storage)) return 0 ; ; node.chainlen = genalloc_len(sbearssl_cert, &pol->certga) - node.chainindex ; if (!sbearssl_skey_readfile(keyfile, &node.skey, &pol->storage)) goto err1 ; if (!genalloc_catb(sbearssl_sni_policy_node, &pol->mapga, &node, 1)) goto err2 ; @@ -31,12 +29,11 @@ int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *pol, char if (mbase) genalloc_setlen(sbearssl_sni_policy_node, &pol->mapga, mbase) ; else genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; err2: - sbearssl_skey_wipe(&pol->skey, pol->storage.s) ; + sbearssl_skey_wipe(&node.skey, pol->storage.s) ; err1: if (gabase) genalloc_setlen(sbearssl_cert, &pol->certga, gabase) ; else genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; - err0: if (sabase) pol->storage.len = sabase ; - else stralloc_free(pol->storage) ; + else stralloc_free(&pol->storage) ; return 0 ; } diff --git a/src/sbearssl/sbearssl_sni_policy_init.c b/src/sbearssl/sbearssl_sni_policy_init.c index fd0e946..150250f 100644 --- a/src/sbearssl/sbearssl_sni_policy_init.c +++ b/src/sbearssl/sbearssl_sni_policy_init.c @@ -1,6 +1,6 @@ /* ISC license. */ -#include +#include #include @@ -9,54 +9,11 @@ #include #include - -#define INSTANCE(c) ((sbearssl_sni_policy_context *)(c)) - -static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_context const *sc, br_ssl_server_choices *choices) -{ - sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; - uint32_t n ; - char const *servername = br_ssl_engine_get_server_name(&sc->eng) ; - if (!avltree_search(&pol->map, servername, &n) - && (!servername[0] || !avltree_search(&pol->map, "", &n))) - return 0 ; - avltree_free(&pol->map) ; - copy_and_free(pol, n) ; -} - -static uint32_t do_keyx (br_ssl_server_policy_class const **pctx, unsigned char *data, size_t *len) -{ - sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; - switch (pol->skey.type) - { - case BR_KEYTYPE_RSA : return kx_rsa(pol, data, len) ; - case BR_KEYTYPE_EC : return kx_ec(pol, data, len) ; - default : return 0 ; - } -} - -static size_t do_sign (br_ssl_server_policy_class const **pctx, unsigned int algo_id, unsigned char *data, size_t hv_len, size_t len) -{ - sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; - switch (pol->skey.type) - { - case BR_KEYTYPE_RSA : return sign_rsa(pol, algo_id, data, hv_len, len) ; - case BR_KEYTYPE_EC : return sign_ec(pol, algo_id, data, hv_len, len) ; - default : return 0 ; - } -} - -static br_ssl_server_policy_class const vtable = -{ - .context_size = sizeof(sbearssl_sni_policy_context), - .choose = &choose, - .do_keyx = &do_keyx, - .do_sign = &do_sign -} ; +#include "sbearssl-internal.h" static void *sbearssl_sni_policy_node_dtok (uint32_t d, void *data) { - return ((sbearssl_sni_policy_context *)data)->storage.s + d ; + return (void *)genalloc_s(sbearssl_sni_map, &((sbearssl_sni_policy_context *)data)->mapga)[d].servername ; } static int sbearssl_sni_policy_node_cmp (void const *a, void const *b, void *data) @@ -67,9 +24,9 @@ static int sbearssl_sni_policy_node_cmp (void const *a, void const *b, void *dat void sbearssl_sni_policy_init (sbearssl_sni_policy_context *pol) { - pol->vtable = &vtable ; - pol->map = avltree_zero ; + avltree_init(&pol->map, 3, 3, 8, &sbearssl_sni_policy_node_dtok, &sbearssl_sni_policy_node_cmp, pol) ; pol->mapga = genalloc_zero ; pol->certga = genalloc_zero ; - pol->storage = GENALLOC_ZERO ; + pol->storage = stralloc_zero ; + pol->vtable = &sbearssl_sni_policy_vtable ; } diff --git a/src/sbearssl/sbearssl_sni_policy_vtable.c b/src/sbearssl/sbearssl_sni_policy_vtable.c index 3b39055..eca198a 100644 --- a/src/sbearssl/sbearssl_sni_policy_vtable.c +++ b/src/sbearssl/sbearssl_sni_policy_vtable.c @@ -1,71 +1,191 @@ /* ISC license. */ +#include +#include + #include +#include +#include +#include +#include +#include + #include +#include "sbearssl-internal.h" -#define INSTANCE(c) ((sbearssl_x509_small_context *)(c)) +#define INSTANCE(c) ((sbearssl_sni_policy_context *)(c)) -static void start_chain (br_x509_class const **c, char const *server_name) -{ - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - ctx->minimal.vtable->start_chain(&ctx->minimal.vtable, server_name) ; +#define COPY(x) do { k.data.rsa.x = m ; memcpy(s + m, t + k.data.rsa.x, k.data.rsa.x##len) ; m += k.data.rsa.x##len ; } while (0) - ctx->i = 0 ; +static inline size_t skey_copy (br_skey *key, sbearssl_skey const *l, char *s, char const *t) +{ + sbearssl_skey k = *l ; + size_t m = 0 ; + switch (k.type) + { + case BR_KEYTYPE_RSA : + { + COPY(p) ; COPY(q) ; COPY(dp) ; COPY(dq) ; COPY(iq) ; + break ; + } + case BR_KEYTYPE_EC : + k.data.ec.x = m ; memcpy(s + m, t + k.data.ec.x, k.data.ec.xlen) ; m += k.data.ec.xlen ; + break ; + } + sbearssl_skey_to(&k, key, s) ; + return m ; } -static void start_cert (br_x509_class const **c, uint32_t len) +static size_t cert_copy (br_x509_certificate *newc, sbearssl_cert const *oldc, char *s, char const *t) { - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - ctx->minimal.vtable->start_cert(&ctx->minimal.vtable, len) ; - - if (!ctx->i) br_sha256_init(&ctx->hashctx) ; + memcpy(s, t + oldc->data, oldc->datalen) ; + newc->data = (unsigned char *)s ; + newc->data_len = oldc->datalen ; + return oldc->datalen ; } -static void append (br_x509_class const **c, unsigned char const *s, size_t len) +static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_context const *sc, br_ssl_server_choices *choices) { - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - ctx->minimal.vtable->append(&ctx->minimal.vtable, s, len) ; + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + sbearssl_sni_policy_node *node ; + char const *servername = br_ssl_engine_get_server_name(&sc->eng) ; - if (!ctx->i) br_sha256_update(&ctx->hashctx, s, len) ; -} + /* Get the node corresponding to the ServerName sent by the client */ + { + uint32_t n ; + if (!avltree_search(&pol->map, servername, &n) + && (!servername[0] || !avltree_search(&pol->map, "", &n))) + return 0 ; + avltree_free(&pol->map) ; + node = genalloc_s(sbearssl_sni_policy_node, &pol->mapga) + n ; + } -static void end_cert (br_x509_class const **c) -{ - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - ctx->minimal.vtable->end_cert(&ctx->minimal.vtable) ; + /* Replace certga and storage with the chosen chain and its data, free all the rest */ + { + stralloc storage = STRALLOC_ZERO ; + genalloc certga = GENALLOC_ZERO ; + size_t clen = 0 ; + size_t m = 0 ; + sbearssl_cert const *certstart = genalloc_s(sbearssl_cert, &pol->certga) + node->chainindex ; + for (size_t i = 0 ; i < node->chainlen ; i++) clen += certstart[i].datalen ; + if (!stralloc_ready_tuned(&storage, sbearssl_skey_storagelen(&node->skey) + clen, 0, 0, 1)) return 0 ; + if (!genalloc_ready_tuned(br_x509_certificate, &certga, node->chainlen, 0, 0, 1)) + { + stralloc_free(&storage) ; + return 0 ; + } + m += skey_copy(&pol->skey, &node->skey, storage.s + m, pol->storage.s) ; + for (size_t i = 0 ; i < node->chainlen ; i++) + m += cert_copy(genalloc_s(br_x509_certificate, &certga) + i, certstart + i, storage.s + m, pol->storage.s) ; + genalloc_setlen(br_x509_certificate, &certga, node->chainlen) ; + genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; + genalloc_free(sbearssl_cert, &pol->certga) ; + byte_zzero(pol->storage.s, pol->storage.len) ; /* contains skeys, so we wipe it */ + stralloc_free(&pol->storage) ; + pol->certga = certga ; + pol->storage = storage ; + } + + /* We got our choice of cert chain */ + choices->chain = genalloc_s(br_x509_certificate, &pol->certga) ; + choices->chain_len = genalloc_len(br_x509_certificate, &pol->certga) ; - if (!ctx->i) br_sha256_out(&ctx->hashctx, ctx->eehash) ; - ctx->i++ ; + /* Now fill up the rest of the choices structure and gather info for later keyx/sign */ + switch (pol->skey.type) + { + case BR_KEYTYPE_RSA : + if (!sbearssl_choose_algos_rsa(sc, choices, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN)) return 0 ; + pol->keyx.rsa = br_rsa_private_get_default() ; + pol->sign.rsa = br_rsa_pkcs1_sign_get_default() ; + break ; + case BR_KEYTYPE_EC : + { + int kt ; + int r = sbearssl_ec_issuer_keytype(&kt, &choices->chain[0]) ; + switch (r) + { + case -2 : strerr_warnw3x("certificate issuer key type not recognized", servername[0] ? " for name " : "", servername[0] ? servername : "") ; return 0 ; + case -1 : strerr_warnwu3sys("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "") ; return 0 ; + case 0 : break ; + default : strerr_warnwu5x("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "", ": ", sbearssl_error_str(r)) ; return 0 ; + } + if (!sbearssl_choose_algos_ec(sc, choices, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, kt)) return 0 ; + pol->keyx.ec = sc->eng.iec ; /* the br_ssl_engine_get_ec() abstraction lacks a const */ + pol->sign.ec = br_ecdsa_i31_sign_asn1 ; /* have to hardcode, no access to BR_LOMUL */ + pol->mhash = &sc->eng.mhash ; /* missing an abstraction function there */ + break ; + } + default : return 0 ; + } + return 1 ; } -static unsigned int end_chain (br_x509_class const **c) +static uint32_t do_keyx (br_ssl_server_policy_class const **pctx, unsigned char *data, size_t *len) { - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - unsigned int r = ctx->minimal.vtable->end_chain(&ctx->minimal.vtable) ; - if (!r) + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + switch (pol->skey.type) { - uint8_t mask = 1 ; - for (unsigned int i = 0 ; i < 6 ; i++, mask <<= 1) - if (ctx->elts[i].status) - *ctx->eltstatus |= ctx->elts[i].status < 0 ? 128 : mask ; + case BR_KEYTYPE_RSA : + return br_rsa_ssl_decrypt(pol->keyx.rsa, &pol->skey.data.rsa, data, *len) ; + case BR_KEYTYPE_EC : + { + size_t xlen ; + uint32_t r = pol->keyx.ec->mul(data, *len, pol->skey.data.ec.x, pol->skey.data.ec.xlen, pol->skey.data.ec.curve) ; + size_t xoff = pol->keyx.ec->xoff(pol->skey.data.ec.curve, &xlen) ; + memmove(data, data + xoff, xlen) ; + *len = xlen ; + return r ; + } + default : return 0 ; } - return r ; } -static br_x509_pkey const *get_pkey(br_x509_class const *const *c, unsigned int *usages) +static size_t sign_rsa (sbearssl_sni_policy_context *pol, unsigned int algo_id, unsigned char *data, size_t hv_len, size_t len) +{ + static unsigned char const HASH_OID_SHA1[] = { 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A } ; + static unsigned char const HASH_OID_SHA224[] = { 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 } ; + static unsigned char const HASH_OID_SHA256[] = { 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 } ; + static unsigned char const HASH_OID_SHA384[] = { 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 } ; + static unsigned char const HASH_OID_SHA512[] = { 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 } ; + static unsigned char const *HASH_OID[] = { HASH_OID_SHA1, HASH_OID_SHA224, HASH_OID_SHA256, HASH_OID_SHA384, HASH_OID_SHA512 } ; + unsigned char const *hash_oid = 0 ; + size_t sig_len ; + unsigned char hv[64] ; + memcpy(hv, data, hv_len) ; + algo_id &= 0xff ; + if (algo_id >= 2 && algo_id <= 6) hash_oid = HASH_OID[algo_id - 2] ; + else if (algo_id) return 0 ; + sig_len = (pol->skey.data.rsa.n_bitlen + 7) >> 3 ; + if (len < sig_len) return 0 ; + return pol->sign.rsa(hash_oid, hv, hv_len, &pol->skey.data.rsa, data) ? sig_len : 0 ; +} + +static size_t sign_ec (sbearssl_sni_policy_context *pol, unsigned int algo_id, unsigned char *data, size_t hv_len, size_t len) +{ + unsigned char hv[64] ; + br_hash_class const *hc = br_multihash_getimpl(pol->mhash, algo_id) ; + if (!hc) return 0 ; + memcpy(hv, data, hv_len) ; + if (len < 139) return 0 ; + return pol->sign.ec(pol->keyx.ec, hc, hv, &pol->skey.data.ec, data) ; +} + +static size_t do_sign (br_ssl_server_policy_class const **pctx, unsigned int algo_id, unsigned char *data, size_t hv_len, size_t len) { - sbearssl_x509_small_context *ctx = INSTANCE(c) ; - return ctx->minimal.vtable->get_pkey(&ctx->minimal.vtable, usages) ; + sbearssl_sni_policy_context *pol = INSTANCE(pctx) ; + switch (pol->skey.type) + { + case BR_KEYTYPE_RSA : return sign_rsa(pol, algo_id, data, hv_len, len) ; + case BR_KEYTYPE_EC : return sign_ec(pol, algo_id, data, hv_len, len) ; + default : return 0 ; + } } -br_x509_class const sbearssl_x509_small_vtable = +br_ssl_server_policy_class const sbearssl_sni_policy_vtable = { - .context_size = sizeof(sbearssl_x509_small_context), - .start_chain = &start_chain, - .start_cert = &start_cert, - .append = &append, - .end_cert = &end_cert, - .end_chain = &end_chain, - .get_pkey = &get_pkey, + .context_size = sizeof(sbearssl_sni_policy_context), + .choose = &choose, + .do_keyx = &do_keyx, + .do_sign = &do_sign } ; diff --git a/src/sbearssl/sbearssl_ta_readfile.c b/src/sbearssl/sbearssl_ta_readfile.c index 9411347..bb51887 100644 --- a/src/sbearssl/sbearssl_ta_readfile.c +++ b/src/sbearssl/sbearssl_ta_readfile.c @@ -2,8 +2,10 @@ #include #include + #include #include + #include int sbearssl_ta_readfile (char const *file, genalloc *taga, stralloc *tasa) @@ -35,5 +37,4 @@ int sbearssl_ta_readfile (char const *file, genalloc *taga, stralloc *tasa) errno = e ; } return r ; - } -- cgit v1.2.3 From e36fd79f212a4fbcb69ef6fa6add4d06e52956b5 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 1 Jun 2021 20:35:49 +0000 Subject: Make stuff build Still not working: we need to add servername to the storage --- src/sbearssl/sbearssl_server_init_and_run.c | 104 +++++++++++++++------------- src/sbearssl/sbearssl_sni_policy_vtable.c | 22 ++++-- src/stls/stls_server_init_and_handshake.c | 4 +- 3 files changed, 76 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/sbearssl/sbearssl_server_init_and_run.c b/src/sbearssl/sbearssl_server_init_and_run.c index 467041a..cdd2804 100644 --- a/src/sbearssl/sbearssl_server_init_and_run.c +++ b/src/sbearssl/sbearssl_server_init_and_run.c @@ -5,6 +5,8 @@ #include +#include +#include #include #include #include @@ -15,56 +17,64 @@ void sbearssl_server_init_and_run (int *fds, tain_t const *tto, uint32_t preoptions, uint32_t options, unsigned int verbosity, sbearssl_handshake_cbfunc_ref cb, sbearssl_handshake_cbarg *cbarg) { - sbearssl_skey skey ; - genalloc certs = GENALLOC_ZERO ; /* sbearssl_cert */ - genalloc tas = GENALLOC_ZERO ; /* sbearssl_ta */ - stralloc storage = STRALLOC_ZERO ; - size_t chainlen = sbearssl_get_keycert(&skey, &certs, &storage) ; - size_t n = preoptions & 1 ? sbearssl_get_tas(&tas, &storage) : 0 ; - - sbearssl_drop() ; - stralloc_shrink(&storage) ; + sbearssl_sni_policy_context pol ; + sbearssl_sni_policy_init(&pol) ; + if (!(preoptions & 8)) /* snilevel < 2 : add default keypair */ { - union br_skey_u key ; - br_ssl_server_context sc ; - sbearssl_x509_small_context xc ; - br_x509_certificate chain[chainlen] ; - br_x509_trust_anchor btas[n ? n : 1] ; - unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; - - for (size_t i = 0 ; i < chainlen ; i++) - sbearssl_cert_to(genalloc_s(sbearssl_cert, &certs) + i, chain + i, storage.s) ; - genalloc_free(sbearssl_cert, &certs) ; - - for (size_t i = 0 ; i < n ; i++) - sbearssl_ta_to(genalloc_s(sbearssl_ta, &tas) + i, btas + i, storage.s) ; - genalloc_free(sbearssl_ta, &tas) ; + char const *keyfile ; + char const *certfile = getenv("CERTFILE") ; + if (!certfile) strerr_dienotset(100, "CERTFILE") ; + keyfile = getenv("KEYFILE") ; + if (!keyfile) strerr_dienotset(100, "KEYFILE") ; + if (!sbearssl_sni_policy_add_keypair_file(&pol, "", certfile, keyfile)) + strerr_diefu1sys(96, "add default keypair to policy context") ; + } - switch (skey.type) + if (preoptions & 4) /* snilevel > 0 : add additional keypairs */ + { + char const *const *envp = (char const *const *)environ ; + for (; *envp ; envp++) { - case BR_KEYTYPE_RSA : - sbearssl_rsa_skey_to(&skey.data.rsa, &key.rsa, storage.s) ; - br_ssl_server_init_full_rsa(&sc, chain, chainlen, &key.rsa) ; - break ; - case BR_KEYTYPE_EC : + if (str_start(*envp, "KEYFILE:")) { - int kt, r ; - sbearssl_ec_skey_to(&skey.data.ec, &key.ec, storage.s) ; - r = sbearssl_ec_issuer_keytype(&kt, &chain[0]) ; - switch (r) + size_t len = strlen(*envp) ; + size_t kequal = byte_chr(*envp, len, '=') ; + if (kequal == len) strerr_dief1x(100, "invalid environment") ; + if (kequal != 8) { - case -2 : strerr_dief1x(96, "certificate issuer key type not recognized") ; - case -1 : strerr_diefu1sys(111, "get certificate issuer key type") ; - case 0 : break ; - default : strerr_diefu3x(96, "get certificate issuer key type", ": ", sbearssl_error_str(r)) ; + char const *x ; + char certvar[len - kequal + 10] ; + memcpy(certvar, "CERTFILE:", 9) ; + memcpy(certvar + 9, *envp + 8, kequal - 8) ; + certvar[kequal + 1] = 0 ; + x = getenv(certvar) ; + if (!x) + strerr_dief3x(96, "environment variable KEYFILE:", certvar + 9, " not paired with the corresponding CERTFILE") ; + else if (!sbearssl_sni_policy_add_keypair_file(&pol, certvar + 9, x, *envp + kequal + 1)) + strerr_diefu1sys(96, "sbearssl_sni_policy_add_keypair_file") ; } - br_ssl_server_init_full_ec(&sc, chain, chainlen, kt, &key.ec) ; - break ; } - default : - strerr_dief1x(96, "unsupported private key type") ; } + } + + sbearssl_drop() ; + + { + br_ssl_server_context sc ; + sbearssl_x509_small_context xc ; + stralloc tastorage = STRALLOC_ZERO ; + genalloc tas = GENALLOC_ZERO ; /* sbearssl_ta */ + size_t n = preoptions & 1 ? sbearssl_get_tas(&tas, &tastorage) : 0 ; + unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; + br_x509_trust_anchor btas[n ? n : 1] ; + + sbearssl_sctx_init_full_generic(&sc) ; + sbearssl_sctx_set_policy_sni(&sc, &pol) ; + random_string((char *)buf, 32) ; + random_finish() ; + br_ssl_engine_inject_entropy(&sc.eng, buf, 32) ; + br_ssl_engine_set_buffer(&sc.eng, buf, sizeof(buf), 1) ; { uint32_t flags = BR_OPT_ENFORCE_SERVER_PREFERENCES | BR_OPT_NO_RENEGOTIATION ; @@ -72,25 +82,23 @@ void sbearssl_server_init_and_run (int *fds, tain_t const *tto, uint32_t preopti br_ssl_engine_add_flags(&sc.eng, flags) ; } - if (n) + if (n) /* Set up client cert verification */ { + for (size_t i = 0 ; i < n ; i++) + sbearssl_ta_to(genalloc_s(sbearssl_ta, &tas) + i, btas + i, tastorage.s) ; + genalloc_free(sbearssl_ta, &tas) ; sbearssl_x509_small_init_full(&xc, btas, n, &cbarg->eedn, &cbarg->eltstatus, cbarg->eehash) ; if (!sbearssl_x509_small_set_tain(&xc, &STAMP)) strerr_diefu1sys(111, "initialize validation time") ; - br_ssl_engine_set_x509(&sc.eng, &xc.vtable) ; br_ssl_engine_set_default_rsavrfy(&sc.eng) ; br_ssl_engine_set_default_ecdsa(&sc.eng) ; + br_ssl_engine_set_x509(&sc.eng, &xc.vtable) ; br_ssl_server_set_trust_anchor_names_alt(&sc, btas, n) ; cbarg->exportmask |= 3 ; } - random_string((char *)buf, 32) ; - random_finish() ; - br_ssl_engine_inject_entropy(&sc.eng, buf, 32) ; - br_ssl_engine_set_buffer(&sc.eng, buf, sizeof(buf), 1) ; if (!br_ssl_server_reset(&sc)) strerr_diefu2x(97, "reset server context: ", sbearssl_error_str(br_ssl_engine_last_error(&sc.eng))) ; - sbearssl_run(&sc.eng, fds, tto, options, verbosity, cb, cbarg) ; } } diff --git a/src/sbearssl/sbearssl_sni_policy_vtable.c b/src/sbearssl/sbearssl_sni_policy_vtable.c index eca198a..dc18805 100644 --- a/src/sbearssl/sbearssl_sni_policy_vtable.c +++ b/src/sbearssl/sbearssl_sni_policy_vtable.c @@ -6,7 +6,9 @@ #include #include -#include +#ifdef DEBUG +# include +#endif #include #include #include @@ -105,10 +107,22 @@ static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_contex int r = sbearssl_ec_issuer_keytype(&kt, &choices->chain[0]) ; switch (r) { - case -2 : strerr_warnw3x("certificate issuer key type not recognized", servername[0] ? " for name " : "", servername[0] ? servername : "") ; return 0 ; - case -1 : strerr_warnwu3sys("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "") ; return 0 ; + case -2 : +#ifdef DEBUG + strerr_warnw3x("certificate issuer key type not recognized", servername[0] ? " for name " : "", servername[0] ? servername : "") ; +#endif + return 0 ; + case -1 : +#ifdef DEBUG + strerr_warnwu3sys("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "") ; +#endif + return 0 ; case 0 : break ; - default : strerr_warnwu5x("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "", ": ", sbearssl_error_str(r)) ; return 0 ; + default : +#ifdef DEBUG + strerr_warnwu5x("get certificate issuer key type", servername[0] ? " for name " : "", servername[0] ? servername : "", ": ", sbearssl_error_str(r)) ; +#endif + return 0 ; } if (!sbearssl_choose_algos_ec(sc, choices, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, kt)) return 0 ; pol->keyx.ec = sc->eng.iec ; /* the br_ssl_engine_get_ec() abstraction lacks a const */ diff --git a/src/stls/stls_server_init_and_handshake.c b/src/stls/stls_server_init_and_handshake.c index 2cc9585..2a8c235 100644 --- a/src/stls/stls_server_init_and_handshake.c +++ b/src/stls/stls_server_init_and_handshake.c @@ -47,12 +47,12 @@ struct tls *stls_server_init_and_handshake (int const *fds, tain_t const *tto, u if (kequal != 8) { char certvar[len - kequal + 10] ; - memcpy(certvar, "CERTFILE:", 9 ; + memcpy(certvar, "CERTFILE:", 9) ; memcpy(certvar + 9, *envp + 8, kequal - 8) ; certvar[kequal + 1] = 0 ; x = getenv(certvar) ; if (!x) - strerr_dief3x("environment variable KEYFILE:", certvar + 9, " not paired with the corresponding CERTFILE") ; + strerr_dief3x(96, "environment variable KEYFILE:", certvar + 9, " not paired with the corresponding CERTFILE") ; else if (tls_config_add_keypair_file(cfg, x, *envp + kequal + 1) < 0) diecfg(cfg, "tls_config_add_keypair_file") ; } -- cgit v1.2.3 From 1191557c30af6326fc5fae7f02167375043bb293 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 1 Jun 2021 21:28:12 +0000 Subject: Add servername to storage --- src/include/s6-networking/sbearssl.h | 20 +++++++------------- src/sbearssl/sbearssl-internal.h | 2 +- src/sbearssl/sbearssl_sni_policy_add_keypair_file.c | 6 ++++-- src/sbearssl/sbearssl_sni_policy_init.c | 3 ++- src/sbearssl/sbearssl_sni_policy_vtable.c | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/include/s6-networking/sbearssl.h b/src/include/s6-networking/sbearssl.h index f7f721d..7ed4e5b 100644 --- a/src/include/s6-networking/sbearssl.h +++ b/src/include/s6-networking/sbearssl.h @@ -270,27 +270,21 @@ extern void sbearssl_run (br_ssl_engine_context *, int *, tain_t const *, uint32 extern int sbearssl_choose_algos_rsa (br_ssl_server_context const *, br_ssl_server_choices *, unsigned int) ; extern int sbearssl_choose_algos_ec (br_ssl_server_context const *, br_ssl_server_choices *, unsigned int, int) ; -typedef struct sbearssl_sni_map_s sbearssl_sni_map, *sbearssl_sni_map_ref ; -struct sbearssl_sni_map_s -{ - char const *servername ; - sbearssl_skey skey ; - size_t chainindex ; - size_t chainlen ; -} ; - typedef struct sbearssl_sni_policy_context_s sbearssl_sni_policy_context, *sbearssl_sni_policy_context_ref ; struct sbearssl_sni_policy_context_s { + /* generic fields that any br_ssl_server_policy_class instance should have */ br_ssl_server_policy_class const *vtable ; br_skey skey ; - avltree map ; - genalloc mapga ; - genalloc certga ; - stralloc storage ; union { br_rsa_private rsa ; br_ec_impl const *ec ; } keyx ; union { br_rsa_pkcs1_sign rsa ; br_ecdsa_sign ec ; } sign ; br_multihash_context const *mhash ; + + /* specific fields to sni_policy: keypairs and servername->keypair dict */ + stralloc storage ; + genalloc certga ; + genalloc mapga ; + avltree map ; } ; extern br_ssl_server_policy_class const sbearssl_sni_policy_vtable ; diff --git a/src/sbearssl/sbearssl-internal.h b/src/sbearssl/sbearssl-internal.h index 8c8839b..0677caf 100644 --- a/src/sbearssl/sbearssl-internal.h +++ b/src/sbearssl/sbearssl-internal.h @@ -78,7 +78,7 @@ extern size_t const sbearssl_suite_list_len ; typedef struct sbearssl_sni_policy_node_s sbearssl_sni_policy_node, *sbearssl_policy_node_ref ; struct sbearssl_sni_policy_node_s { - char const *servername ; + size_t servername ; sbearssl_skey skey ; size_t chainindex ; size_t chainlen ; diff --git a/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c index f77b1d8..2462645 100644 --- a/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c +++ b/src/sbearssl/sbearssl_sni_policy_add_keypair_file.c @@ -16,9 +16,10 @@ int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *pol, char size_t sabase = pol->storage.len ; size_t gabase = genalloc_len(sbearssl_cert, &pol->certga) ; size_t mbase = genalloc_len(sbearssl_sni_policy_node, &pol->mapga) ; - sbearssl_sni_policy_node node = { .servername = servername, .chainindex = gabase } ; + sbearssl_sni_policy_node node = { .servername = sabase, .chainindex = gabase } ; - if (!sbearssl_cert_readbigpem(certfile, &pol->certga, &pol->storage)) return 0 ; ; + if (!stralloc_catb(&pol->storage, servername, strlen(servername) + 1)) return 0 ; + if (!sbearssl_cert_readbigpem(certfile, &pol->certga, &pol->storage)) goto err0 ; node.chainlen = genalloc_len(sbearssl_cert, &pol->certga) - node.chainindex ; if (!sbearssl_skey_readfile(keyfile, &node.skey, &pol->storage)) goto err1 ; if (!genalloc_catb(sbearssl_sni_policy_node, &pol->mapga, &node, 1)) goto err2 ; @@ -33,6 +34,7 @@ int sbearssl_sni_policy_add_keypair_file (sbearssl_sni_policy_context *pol, char err1: if (gabase) genalloc_setlen(sbearssl_cert, &pol->certga, gabase) ; else genalloc_free(sbearssl_sni_policy_node, &pol->mapga) ; + err0: if (sabase) pol->storage.len = sabase ; else stralloc_free(&pol->storage) ; return 0 ; diff --git a/src/sbearssl/sbearssl_sni_policy_init.c b/src/sbearssl/sbearssl_sni_policy_init.c index 150250f..3446f35 100644 --- a/src/sbearssl/sbearssl_sni_policy_init.c +++ b/src/sbearssl/sbearssl_sni_policy_init.c @@ -13,7 +13,8 @@ static void *sbearssl_sni_policy_node_dtok (uint32_t d, void *data) { - return (void *)genalloc_s(sbearssl_sni_map, &((sbearssl_sni_policy_context *)data)->mapga)[d].servername ; + sbearssl_sni_policy_context *pol = data ; + return pol->storage.s + genalloc_s(sbearssl_sni_policy_node, &pol->mapga)[d].servername ; } static int sbearssl_sni_policy_node_cmp (void const *a, void const *b, void *data) diff --git a/src/sbearssl/sbearssl_sni_policy_vtable.c b/src/sbearssl/sbearssl_sni_policy_vtable.c index dc18805..6d6bcc3 100644 --- a/src/sbearssl/sbearssl_sni_policy_vtable.c +++ b/src/sbearssl/sbearssl_sni_policy_vtable.c @@ -53,7 +53,7 @@ static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_contex sbearssl_sni_policy_node *node ; char const *servername = br_ssl_engine_get_server_name(&sc->eng) ; - /* Get the node corresponding to the ServerName sent by the client */ + /* Get the node corresponding to the ServerName sent by the client. "" for no SNI. */ { uint32_t n ; if (!avltree_search(&pol->map, servername, &n) -- cgit v1.2.3