diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2021-06-01 11:27:05 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska-skaware@skarnet.org> | 2021-06-01 11:27:05 +0000 |
| commit | a84b9b4e5d985a5d8a37268a76e1d35210fd31c5 (patch) | |
| tree | 64cf1b6e3f21e1ac96ea119358fda95091ee6e93 /src/sbearssl/sbearssl_sni_policy_vtable.c | |
| parent | e763c3ef1485404585b923365f93314aab4e8dd6 (diff) | |
| download | s6-networking-a84b9b4e5d985a5d8a37268a76e1d35210fd31c5.tar.gz | |
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.
Diffstat (limited to 'src/sbearssl/sbearssl_sni_policy_vtable.c')
| -rw-r--r-- | src/sbearssl/sbearssl_sni_policy_vtable.c | 204 |
1 files changed, 162 insertions, 42 deletions
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 <stdint.h> +#include <string.h> + #include <bearssl.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/avltree.h> + #include <s6-networking/sbearssl.h> +#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 } ; |
