lsquic_tokgen.c revision b55a5117
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech#include <assert.h>
35392f7a3SLiteSpeed Tech#include <netinet/in.h>
45392f7a3SLiteSpeed Tech#include <stddef.h>
55392f7a3SLiteSpeed Tech#include <stdlib.h>
65392f7a3SLiteSpeed Tech#include <string.h>
75392f7a3SLiteSpeed Tech#include <sys/queue.h>
85392f7a3SLiteSpeed Tech#include <sys/socket.h>
95392f7a3SLiteSpeed Tech#include <time.h>
105392f7a3SLiteSpeed Tech
115392f7a3SLiteSpeed Tech#include <openssl/aead.h>
125392f7a3SLiteSpeed Tech#include <openssl/hkdf.h>
135392f7a3SLiteSpeed Tech#include <openssl/rand.h>
145392f7a3SLiteSpeed Tech#include <openssl/ssl.h>
155392f7a3SLiteSpeed Tech
165392f7a3SLiteSpeed Tech#include "lsquic.h"
175392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
185392f7a3SLiteSpeed Tech#include "lsquic_sizes.h"
195392f7a3SLiteSpeed Tech#include "lsquic_types.h"
205392f7a3SLiteSpeed Tech#include "lsquic_packet_common.h"
215392f7a3SLiteSpeed Tech#include "lsquic_packet_in.h"
225392f7a3SLiteSpeed Tech#include "lsquic_tokgen.h"
235392f7a3SLiteSpeed Tech#include "lsquic_trans_params.h"
245392f7a3SLiteSpeed Tech#include "lsquic_util.h"
255392f7a3SLiteSpeed Tech#include "lsquic_mm.h"
265392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h"
275392f7a3SLiteSpeed Tech
285392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_TOKGEN
295392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
305392f7a3SLiteSpeed Tech
315392f7a3SLiteSpeed Tech#define STRINGIFY(x) #x
325392f7a3SLiteSpeed Tech#define TOSTRING(x) STRINGIFY(x)
335392f7a3SLiteSpeed Tech
345392f7a3SLiteSpeed Tech#define TOKGEN_VERSION 1
355392f7a3SLiteSpeed Tech
365392f7a3SLiteSpeed Tech#define CRYPTER_KEY_SIZE        16
375392f7a3SLiteSpeed Tech#define SRST_MAX_PRK_SIZE       EVP_MAX_MD_SIZE
385392f7a3SLiteSpeed Tech
395392f7a3SLiteSpeed Tech#define TOKGEN_SHM_KEY "TOKGEN" TOSTRING(TOKGEN_VERSION)
405392f7a3SLiteSpeed Tech#define TOKGEN_SHM_KEY_SIZE (sizeof(TOKGEN_SHM_KEY) - 1)
415392f7a3SLiteSpeed Tech
425392f7a3SLiteSpeed Tech#define TOKGEN_SHM_MAGIC_TOP "Feliz"
435392f7a3SLiteSpeed Tech#define TOKGEN_SHM_MAGIC_BOTTOM "Navidad"
445392f7a3SLiteSpeed Tech
455392f7a3SLiteSpeed Techstruct tokgen_shm_state
465392f7a3SLiteSpeed Tech{
475392f7a3SLiteSpeed Tech    uint8_t     tgss_version;
485392f7a3SLiteSpeed Tech    uint8_t     tgss_magic_top[sizeof(TOKGEN_SHM_MAGIC_TOP) - 1];
495392f7a3SLiteSpeed Tech    uint8_t     tgss_crypter_key[N_TOKEN_TYPES][CRYPTER_KEY_SIZE];
505392f7a3SLiteSpeed Tech    uint8_t     tgss_srst_prk_size;
515392f7a3SLiteSpeed Tech    uint8_t     tgss_srst_prk[SRST_MAX_PRK_SIZE];
525392f7a3SLiteSpeed Tech    uint8_t     tgss_magic_bottom[sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1];
535392f7a3SLiteSpeed Tech};
545392f7a3SLiteSpeed Tech
555392f7a3SLiteSpeed Tech
565392f7a3SLiteSpeed Tech
575392f7a3SLiteSpeed Techstatic const uint8_t srst_salt[8] = "\x28\x6e\x81\x02\x40\x5b\x2c\x2b";
585392f7a3SLiteSpeed Tech
595392f7a3SLiteSpeed Techstruct crypter
605392f7a3SLiteSpeed Tech{
615392f7a3SLiteSpeed Tech    EVP_AEAD_CTX    ctx;
625392f7a3SLiteSpeed Tech    unsigned long   nonce_counter;
635392f7a3SLiteSpeed Tech    size_t          nonce_prk_sz;
645392f7a3SLiteSpeed Tech    uint8_t         nonce_prk_buf[EVP_MAX_MD_SIZE];
655392f7a3SLiteSpeed Tech};
665392f7a3SLiteSpeed Tech
675392f7a3SLiteSpeed Tech
685392f7a3SLiteSpeed Techstruct token_generator
695392f7a3SLiteSpeed Tech{
705392f7a3SLiteSpeed Tech    /* We encrypt different token types using different keys. */
715392f7a3SLiteSpeed Tech    struct crypter  tg_crypters[N_TOKEN_TYPES];
725392f7a3SLiteSpeed Tech
735392f7a3SLiteSpeed Tech    /* Stateless reset token is generated using HKDF with CID as the
745392f7a3SLiteSpeed Tech     * `info' parameter to HKDF-Expand.
755392f7a3SLiteSpeed Tech     */
765392f7a3SLiteSpeed Tech    size_t          tg_srst_prk_sz;
775392f7a3SLiteSpeed Tech    uint8_t         tg_srst_prk_buf[SRST_MAX_PRK_SIZE];
785392f7a3SLiteSpeed Tech};
795392f7a3SLiteSpeed Tech
805392f7a3SLiteSpeed Tech
815392f7a3SLiteSpeed Tech
825392f7a3SLiteSpeed Tech
835392f7a3SLiteSpeed Techstatic int
845392f7a3SLiteSpeed Techget_or_generate_state (struct lsquic_engine_public *enpub, time_t now,
855392f7a3SLiteSpeed Tech                                        struct tokgen_shm_state *shm_state)
865392f7a3SLiteSpeed Tech{
875392f7a3SLiteSpeed Tech    const struct lsquic_shared_hash_if *const shi = enpub->enp_shi;
885392f7a3SLiteSpeed Tech    void *const ctx = enpub->enp_shi_ctx;
895392f7a3SLiteSpeed Tech    void *data, *copy, *key_copy;
905392f7a3SLiteSpeed Tech    int s;
915392f7a3SLiteSpeed Tech    unsigned sz;
925392f7a3SLiteSpeed Tech    size_t bufsz;
935392f7a3SLiteSpeed Tech    struct {
945392f7a3SLiteSpeed Tech        time_t        now;
95b55a5117SDmitri Tikhonov        unsigned char buf[24];
96b55a5117SDmitri Tikhonov    }
97b55a5117SDmitri Tikhonov#if __GNUC__
98b55a5117SDmitri Tikhonov    /* This is more of a documentation note: this struct should already
99b55a5117SDmitri Tikhonov     * have a multiple-of-eight size.
100b55a5117SDmitri Tikhonov     */
101b55a5117SDmitri Tikhonov    __attribute__((packed))
102b55a5117SDmitri Tikhonov#endif
103b55a5117SDmitri Tikhonov    srst_ikm;
1045392f7a3SLiteSpeed Tech
1055392f7a3SLiteSpeed Tech    data = shm_state;
106b55a5117SDmitri Tikhonov    sz = sizeof(*shm_state);
1075392f7a3SLiteSpeed Tech    s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &data, &sz);
1085392f7a3SLiteSpeed Tech
1095392f7a3SLiteSpeed Tech    if (s == 1)
1105392f7a3SLiteSpeed Tech    {
1115392f7a3SLiteSpeed Tech        if (sz != sizeof(*shm_state))
1125392f7a3SLiteSpeed Tech        {
1135392f7a3SLiteSpeed Tech            LSQ_WARN("found SHM data has non-matching size %u", sz);
1145392f7a3SLiteSpeed Tech            return -1;
1155392f7a3SLiteSpeed Tech        }
1165392f7a3SLiteSpeed Tech        if (data != (void *) shm_state)
1175392f7a3SLiteSpeed Tech            memcpy(shm_state, data, sizeof(*shm_state));
1185392f7a3SLiteSpeed Tech        if (shm_state->tgss_version != TOKGEN_VERSION)
1195392f7a3SLiteSpeed Tech        {
1205392f7a3SLiteSpeed Tech            LSQ_DEBUG("found SHM data has non-matching version %u",
1215392f7a3SLiteSpeed Tech                                                        shm_state->tgss_version);
1225392f7a3SLiteSpeed Tech            return -1;
1235392f7a3SLiteSpeed Tech        }
1245392f7a3SLiteSpeed Tech        LSQ_DEBUG("found SHM data: size %u; version %u", sz,
1255392f7a3SLiteSpeed Tech                                                        shm_state->tgss_version);
1265392f7a3SLiteSpeed Tech        return 0;
1275392f7a3SLiteSpeed Tech    }
1285392f7a3SLiteSpeed Tech
1295392f7a3SLiteSpeed Tech    if (s != 0)
1305392f7a3SLiteSpeed Tech    {
1315392f7a3SLiteSpeed Tech        if (s != -1)
1325392f7a3SLiteSpeed Tech            LSQ_WARN("SHM lookup returned unexpected value %d", s);
1335392f7a3SLiteSpeed Tech        LSQ_DEBUG("SHM lookup returned an error: generate");
1345392f7a3SLiteSpeed Tech        goto generate;
1355392f7a3SLiteSpeed Tech    }
1365392f7a3SLiteSpeed Tech
1375392f7a3SLiteSpeed Tech    assert(s == 0);
1385392f7a3SLiteSpeed Tech    LSQ_DEBUG("%s does not exist: generate", TOKGEN_SHM_KEY);
1395392f7a3SLiteSpeed Tech  generate:
1405392f7a3SLiteSpeed Tech    now = time(NULL);
1415392f7a3SLiteSpeed Tech    memset(shm_state, 0, sizeof(*shm_state));
1425392f7a3SLiteSpeed Tech    shm_state->tgss_version = TOKGEN_VERSION;
1435392f7a3SLiteSpeed Tech    memcpy(shm_state->tgss_magic_top, TOKGEN_SHM_MAGIC_TOP,
1445392f7a3SLiteSpeed Tech                                        sizeof(TOKGEN_SHM_MAGIC_TOP) - 1);
1455392f7a3SLiteSpeed Tech    if (getenv("LSQUIC_NULL_TOKGEN"))
1465392f7a3SLiteSpeed Tech    {
1475392f7a3SLiteSpeed Tech        LSQ_NOTICE("using NULL tokgen");
1489fc12041SDmitri Tikhonov        memset(&srst_ikm, 0, sizeof(srst_ikm));
1495392f7a3SLiteSpeed Tech    }
1505392f7a3SLiteSpeed Tech    else
1515392f7a3SLiteSpeed Tech    {
1525392f7a3SLiteSpeed Tech        srst_ikm.now = now;
1535392f7a3SLiteSpeed Tech        RAND_bytes(srst_ikm.buf, sizeof(srst_ikm.buf));
1545392f7a3SLiteSpeed Tech    }
1555392f7a3SLiteSpeed Tech    if (!HKDF_extract(shm_state->tgss_srst_prk, &bufsz,
1565392f7a3SLiteSpeed Tech                     EVP_sha256(), (uint8_t *) &srst_ikm, sizeof(srst_ikm),
1575392f7a3SLiteSpeed Tech                     srst_salt, sizeof(srst_salt)))
1585392f7a3SLiteSpeed Tech    {
1595392f7a3SLiteSpeed Tech        LSQ_ERROR("HKDF_extract failed");
1605392f7a3SLiteSpeed Tech        return -1;
1615392f7a3SLiteSpeed Tech    }
1625392f7a3SLiteSpeed Tech    shm_state->tgss_srst_prk_size = (uint8_t) bufsz;
1635392f7a3SLiteSpeed Tech    memcpy(shm_state->tgss_magic_bottom, TOKGEN_SHM_MAGIC_BOTTOM,
1645392f7a3SLiteSpeed Tech                                        sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1);
1655392f7a3SLiteSpeed Tech
1665392f7a3SLiteSpeed Tech    data = malloc(sizeof(*shm_state));
1675392f7a3SLiteSpeed Tech    if (!data)
1685392f7a3SLiteSpeed Tech    {
1695392f7a3SLiteSpeed Tech        LSQ_ERROR("%s: malloc", __func__);
1705392f7a3SLiteSpeed Tech        return -1;
1715392f7a3SLiteSpeed Tech    }
1725392f7a3SLiteSpeed Tech    memcpy(data, shm_state, sizeof(*shm_state));
1735392f7a3SLiteSpeed Tech    key_copy = malloc(TOKGEN_SHM_KEY_SIZE);
1745392f7a3SLiteSpeed Tech    if (!key_copy)
1755392f7a3SLiteSpeed Tech    {
1765392f7a3SLiteSpeed Tech        LSQ_ERROR("%s: malloc", __func__);
1775392f7a3SLiteSpeed Tech        free(data);
1785392f7a3SLiteSpeed Tech        return -1;
1795392f7a3SLiteSpeed Tech    }
1805392f7a3SLiteSpeed Tech    memcpy(key_copy, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE);
1815392f7a3SLiteSpeed Tech    s = shi->shi_insert(ctx, key_copy, TOKGEN_SHM_KEY_SIZE, data,
1825392f7a3SLiteSpeed Tech                                                    sizeof(*shm_state), 0);
1835392f7a3SLiteSpeed Tech    if (s != 0)
1845392f7a3SLiteSpeed Tech    {
1855392f7a3SLiteSpeed Tech        LSQ_ERROR("cannot insert into SHM");
1865392f7a3SLiteSpeed Tech        free(data);
1875392f7a3SLiteSpeed Tech        free(key_copy);
1885392f7a3SLiteSpeed Tech        return -1;
1895392f7a3SLiteSpeed Tech    }
1905392f7a3SLiteSpeed Tech    sz = sizeof(*shm_state);
1915392f7a3SLiteSpeed Tech    s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &copy, &sz);
1925392f7a3SLiteSpeed Tech    if (s != 1 || sz != sizeof(*shm_state))
1935392f7a3SLiteSpeed Tech    {
1945392f7a3SLiteSpeed Tech        LSQ_ERROR("cannot lookup after insert: s=%d; sz=%u", s, sz);
1955392f7a3SLiteSpeed Tech        return -1;
1965392f7a3SLiteSpeed Tech    }
1975392f7a3SLiteSpeed Tech    if (copy != data)
1985392f7a3SLiteSpeed Tech        memcpy(shm_state, copy, sizeof(*shm_state));
1995392f7a3SLiteSpeed Tech    LSQ_INFO("inserted %s of size %u", TOKGEN_SHM_KEY, sz);
2005392f7a3SLiteSpeed Tech    return 0;
2015392f7a3SLiteSpeed Tech}
2025392f7a3SLiteSpeed Tech
2035392f7a3SLiteSpeed Tech
2045392f7a3SLiteSpeed Techstruct token_generator *
2055392f7a3SLiteSpeed Techlsquic_tg_new (struct lsquic_engine_public *enpub)
2065392f7a3SLiteSpeed Tech{
2075392f7a3SLiteSpeed Tech    struct token_generator *tokgen;
2085392f7a3SLiteSpeed Tech    time_t now;
2095392f7a3SLiteSpeed Tech    struct tokgen_shm_state shm_state;
2105392f7a3SLiteSpeed Tech
2115392f7a3SLiteSpeed Tech    tokgen = calloc(1, sizeof(*tokgen));
2125392f7a3SLiteSpeed Tech    if (!tokgen)
2135392f7a3SLiteSpeed Tech        goto err;
2145392f7a3SLiteSpeed Tech
2155392f7a3SLiteSpeed Tech    now = time(NULL);
2165392f7a3SLiteSpeed Tech    if (0 != get_or_generate_state(enpub, now, &shm_state))
2175392f7a3SLiteSpeed Tech        goto err;
2185392f7a3SLiteSpeed Tech
2195392f7a3SLiteSpeed Tech
2205392f7a3SLiteSpeed Tech    tokgen->tg_srst_prk_sz = shm_state.tgss_srst_prk_size;
2215392f7a3SLiteSpeed Tech    if (tokgen->tg_srst_prk_sz > sizeof(tokgen->tg_srst_prk_buf))
2225392f7a3SLiteSpeed Tech    {
2235392f7a3SLiteSpeed Tech        LSQ_WARN("bad stateless reset key size");
2245392f7a3SLiteSpeed Tech        goto err;
2255392f7a3SLiteSpeed Tech    }
2265392f7a3SLiteSpeed Tech    memcpy(tokgen->tg_srst_prk_buf, shm_state.tgss_srst_prk,
2275392f7a3SLiteSpeed Tech                                                    tokgen->tg_srst_prk_sz);
2285392f7a3SLiteSpeed Tech
2295392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
2305392f7a3SLiteSpeed Tech    return tokgen;
2315392f7a3SLiteSpeed Tech
2325392f7a3SLiteSpeed Tech  err:
2335392f7a3SLiteSpeed Tech    LSQ_ERROR("error initializing");
2345392f7a3SLiteSpeed Tech    free(tokgen);
2355392f7a3SLiteSpeed Tech    return NULL;
2365392f7a3SLiteSpeed Tech}
2375392f7a3SLiteSpeed Tech
2385392f7a3SLiteSpeed Tech
2395392f7a3SLiteSpeed Techvoid
2405392f7a3SLiteSpeed Techlsquic_tg_destroy (struct token_generator *tokgen)
2415392f7a3SLiteSpeed Tech{
2425392f7a3SLiteSpeed Tech    free(tokgen);
2435392f7a3SLiteSpeed Tech    LSQ_DEBUG("destroyed");
2445392f7a3SLiteSpeed Tech}
2455392f7a3SLiteSpeed Tech
2465392f7a3SLiteSpeed Tech
2475392f7a3SLiteSpeed Techvoid
2485392f7a3SLiteSpeed Techlsquic_tg_generate_sreset (struct token_generator *tokgen,
2495392f7a3SLiteSpeed Tech        const struct lsquic_cid *cid, unsigned char *reset_token)
2505392f7a3SLiteSpeed Tech{
2515392f7a3SLiteSpeed Tech    char str[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
2525392f7a3SLiteSpeed Tech
2535392f7a3SLiteSpeed Tech    (void) HKDF_expand(reset_token, IQUIC_SRESET_TOKEN_SZ, EVP_sha256(),
2545392f7a3SLiteSpeed Tech        tokgen->tg_srst_prk_buf, tokgen->tg_srst_prk_sz, cid->idbuf, cid->len);
2555392f7a3SLiteSpeed Tech    LSQ_DEBUGC("generated stateless reset token %s for CID %"CID_FMT,
2565392f7a3SLiteSpeed Tech        HEXSTR(reset_token, IQUIC_SRESET_TOKEN_SZ, str), CID_BITS(cid));
2575392f7a3SLiteSpeed Tech}
258