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