/* ISC license. */ #include #include #include #include #include #include #include #include #include "sbearssl-internal.h" #define INSTANCE(c) ((sbearssl_sni_policy_context *)(c)) #define COPY(kt, x) do { k->data.kt.x##len = l->data.kt.x##len ; k->data.kt.x = (unsigned char *)s + m ; memcpy(s + m, t + l->data.kt.x, l->data.kt.x##len) ; m += l->data.kt.x##len ; } while (0) static inline size_t skey_copy (br_skey *k, sbearssl_skey const *l, char *s, char const *t) { size_t m = 0 ; k->type = l->type ; switch (l->type) { case BR_KEYTYPE_RSA : k->data.rsa.n_bitlen = l->data.rsa.n_bitlen ; COPY(rsa, p) ; COPY(rsa, q) ; COPY(rsa, dp) ; COPY(rsa, dq) ; COPY(rsa, iq) ; break ; case BR_KEYTYPE_EC : k->data.ec.curve = l->data.ec.curve ; COPY(ec, x) ; break ; } return m ; } static inline size_t cert_copy (br_x509_certificate *newc, sbearssl_cert const *oldc, char *s, char const *t) { memcpy(s, t + oldc->data, oldc->datalen) ; newc->data = (unsigned char *)s ; newc->data_len = oldc->datalen ; return oldc->datalen ; } 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) ; 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. If servername is foo.bar.baz, try: 1. foo.bar.baz 2. *.bar.baz (don't do this for TLDs, we don't want *.com) 3. empty string (i.e. default certificate) If no SNI, only try the empty string. */ { uint32_t n = avltree_totalsize(&pol->map) ; if (servername) { if (!avltree_search(&pol->map, servername, &n)) { char const *sub1 = strchr(servername, '.') ; if (sub1 && sub1[1]) { char const *sub2 = strchr(sub1 + 1, '.') ; if (sub2 && sub2[1]) { size_t len = strlen(sub1) ; char tmp[len + 2] ; tmp[0] = '*' ; memcpy(tmp + 1, sub1, len + 1) ; avltree_search(&pol->map, tmp, &n) ; } } } } if (n == avltree_totalsize(&pol->map) && !avltree_search(&pol->map, "", &n)) return 0 ; avltree_free(&pol->map) ; node = genalloc_s(sbearssl_sni_policy_node, &pol->mapga) + n ; } /* 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) ; /* 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 ; if (sbearssl_ec_issuer_keytype(&kt, &choices->chain[0])) 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_sign_asn1_get_default() ; pol->mhash = &sc->eng.mhash ; /* missing an abstraction function there */ break ; } default : return 0 ; } return 1 ; } 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 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 ; } } static inline 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) ; 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 inline 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_sni_policy_context *pol = INSTANCE(pctx) ; algo_id &= 0xff ; /* workaround for bearssl bug */ 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_ssl_server_policy_class const sbearssl_sni_policy_vtable = { .context_size = sizeof(sbearssl_sni_policy_context), .choose = &choose, .do_keyx = &do_keyx, .do_sign = &do_sign } ;