1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 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]; 52b1a7c3f9SDmitri Tikhonov uint8_t tgss_padding[2 * 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 765392f7a3SLiteSpeed Tech /* Stateless reset token is generated using HKDF with CID as the 775392f7a3SLiteSpeed Tech * `info' parameter to HKDF-Expand. 785392f7a3SLiteSpeed Tech */ 795392f7a3SLiteSpeed Tech size_t tg_srst_prk_sz; 805392f7a3SLiteSpeed Tech uint8_t tg_srst_prk_buf[SRST_MAX_PRK_SIZE]; 815392f7a3SLiteSpeed Tech}; 825392f7a3SLiteSpeed Tech 835392f7a3SLiteSpeed Tech 845392f7a3SLiteSpeed Tech 855392f7a3SLiteSpeed Tech 865392f7a3SLiteSpeed Techstatic int 875392f7a3SLiteSpeed Techget_or_generate_state (struct lsquic_engine_public *enpub, time_t now, 885392f7a3SLiteSpeed Tech struct tokgen_shm_state *shm_state) 895392f7a3SLiteSpeed Tech{ 905392f7a3SLiteSpeed Tech const struct lsquic_shared_hash_if *const shi = enpub->enp_shi; 915392f7a3SLiteSpeed Tech void *const ctx = enpub->enp_shi_ctx; 925392f7a3SLiteSpeed Tech void *data, *copy, *key_copy; 935392f7a3SLiteSpeed Tech int s; 945392f7a3SLiteSpeed Tech unsigned sz; 955392f7a3SLiteSpeed Tech size_t bufsz; 965392f7a3SLiteSpeed Tech struct { 975392f7a3SLiteSpeed Tech time_t now; 98b55a5117SDmitri Tikhonov unsigned char buf[24]; 99b55a5117SDmitri Tikhonov } 100b55a5117SDmitri Tikhonov#if __GNUC__ 101b55a5117SDmitri Tikhonov /* This is more of a documentation note: this struct should already 102b55a5117SDmitri Tikhonov * have a multiple-of-eight size. 103b55a5117SDmitri Tikhonov */ 104b55a5117SDmitri Tikhonov __attribute__((packed)) 105b55a5117SDmitri Tikhonov#endif 106b55a5117SDmitri Tikhonov srst_ikm; 1075392f7a3SLiteSpeed Tech 1085392f7a3SLiteSpeed Tech data = shm_state; 109b55a5117SDmitri Tikhonov sz = sizeof(*shm_state); 1105392f7a3SLiteSpeed Tech s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &data, &sz); 1115392f7a3SLiteSpeed Tech 1125392f7a3SLiteSpeed Tech if (s == 1) 1135392f7a3SLiteSpeed Tech { 1145392f7a3SLiteSpeed Tech if (sz != sizeof(*shm_state)) 1155392f7a3SLiteSpeed Tech { 1165392f7a3SLiteSpeed Tech LSQ_WARN("found SHM data has non-matching size %u", sz); 1175392f7a3SLiteSpeed Tech return -1; 1185392f7a3SLiteSpeed Tech } 1195392f7a3SLiteSpeed Tech if (data != (void *) shm_state) 1205392f7a3SLiteSpeed Tech memcpy(shm_state, data, sizeof(*shm_state)); 1215392f7a3SLiteSpeed Tech if (shm_state->tgss_version != TOKGEN_VERSION) 1225392f7a3SLiteSpeed Tech { 1235392f7a3SLiteSpeed Tech LSQ_DEBUG("found SHM data has non-matching version %u", 1245392f7a3SLiteSpeed Tech shm_state->tgss_version); 1255392f7a3SLiteSpeed Tech return -1; 1265392f7a3SLiteSpeed Tech } 1275392f7a3SLiteSpeed Tech LSQ_DEBUG("found SHM data: size %u; version %u", sz, 1285392f7a3SLiteSpeed Tech shm_state->tgss_version); 1295392f7a3SLiteSpeed Tech return 0; 1305392f7a3SLiteSpeed Tech } 1315392f7a3SLiteSpeed Tech 1325392f7a3SLiteSpeed Tech if (s != 0) 1335392f7a3SLiteSpeed Tech { 1345392f7a3SLiteSpeed Tech if (s != -1) 1355392f7a3SLiteSpeed Tech LSQ_WARN("SHM lookup returned unexpected value %d", s); 1365392f7a3SLiteSpeed Tech LSQ_DEBUG("SHM lookup returned an error: generate"); 1375392f7a3SLiteSpeed Tech goto generate; 1385392f7a3SLiteSpeed Tech } 1395392f7a3SLiteSpeed Tech 1405392f7a3SLiteSpeed Tech assert(s == 0); 1415392f7a3SLiteSpeed Tech LSQ_DEBUG("%s does not exist: generate", TOKGEN_SHM_KEY); 1425392f7a3SLiteSpeed Tech generate: 1435392f7a3SLiteSpeed Tech now = time(NULL); 1445392f7a3SLiteSpeed Tech memset(shm_state, 0, sizeof(*shm_state)); 1455392f7a3SLiteSpeed Tech shm_state->tgss_version = TOKGEN_VERSION; 1465392f7a3SLiteSpeed Tech memcpy(shm_state->tgss_magic_top, TOKGEN_SHM_MAGIC_TOP, 1475392f7a3SLiteSpeed Tech sizeof(TOKGEN_SHM_MAGIC_TOP) - 1); 1485392f7a3SLiteSpeed Tech if (getenv("LSQUIC_NULL_TOKGEN")) 1495392f7a3SLiteSpeed Tech { 1505392f7a3SLiteSpeed Tech LSQ_NOTICE("using NULL tokgen"); 1519fc12041SDmitri Tikhonov memset(&srst_ikm, 0, sizeof(srst_ikm)); 1525392f7a3SLiteSpeed Tech } 1535392f7a3SLiteSpeed Tech else 1545392f7a3SLiteSpeed Tech { 1555392f7a3SLiteSpeed Tech srst_ikm.now = now; 1565392f7a3SLiteSpeed Tech RAND_bytes(srst_ikm.buf, sizeof(srst_ikm.buf)); 1575392f7a3SLiteSpeed Tech } 1585392f7a3SLiteSpeed Tech if (!HKDF_extract(shm_state->tgss_srst_prk, &bufsz, 1595392f7a3SLiteSpeed Tech EVP_sha256(), (uint8_t *) &srst_ikm, sizeof(srst_ikm), 1605392f7a3SLiteSpeed Tech srst_salt, sizeof(srst_salt))) 1615392f7a3SLiteSpeed Tech { 1625392f7a3SLiteSpeed Tech LSQ_ERROR("HKDF_extract failed"); 1635392f7a3SLiteSpeed Tech return -1; 1645392f7a3SLiteSpeed Tech } 1655392f7a3SLiteSpeed Tech shm_state->tgss_srst_prk_size = (uint8_t) bufsz; 1665392f7a3SLiteSpeed Tech memcpy(shm_state->tgss_magic_bottom, TOKGEN_SHM_MAGIC_BOTTOM, 1675392f7a3SLiteSpeed Tech sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1); 1685392f7a3SLiteSpeed Tech 1695392f7a3SLiteSpeed Tech data = malloc(sizeof(*shm_state)); 1705392f7a3SLiteSpeed Tech if (!data) 1715392f7a3SLiteSpeed Tech { 1725392f7a3SLiteSpeed Tech LSQ_ERROR("%s: malloc", __func__); 1735392f7a3SLiteSpeed Tech return -1; 1745392f7a3SLiteSpeed Tech } 1755392f7a3SLiteSpeed Tech memcpy(data, shm_state, sizeof(*shm_state)); 1765392f7a3SLiteSpeed Tech key_copy = malloc(TOKGEN_SHM_KEY_SIZE); 1775392f7a3SLiteSpeed Tech if (!key_copy) 1785392f7a3SLiteSpeed Tech { 1795392f7a3SLiteSpeed Tech LSQ_ERROR("%s: malloc", __func__); 1805392f7a3SLiteSpeed Tech free(data); 1815392f7a3SLiteSpeed Tech return -1; 1825392f7a3SLiteSpeed Tech } 1835392f7a3SLiteSpeed Tech memcpy(key_copy, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE); 1845392f7a3SLiteSpeed Tech s = shi->shi_insert(ctx, key_copy, TOKGEN_SHM_KEY_SIZE, data, 1855392f7a3SLiteSpeed Tech sizeof(*shm_state), 0); 1865392f7a3SLiteSpeed Tech if (s != 0) 1875392f7a3SLiteSpeed Tech { 1885392f7a3SLiteSpeed Tech LSQ_ERROR("cannot insert into SHM"); 1895392f7a3SLiteSpeed Tech free(data); 1905392f7a3SLiteSpeed Tech free(key_copy); 1915392f7a3SLiteSpeed Tech return -1; 1925392f7a3SLiteSpeed Tech } 1935392f7a3SLiteSpeed Tech sz = sizeof(*shm_state); 1945392f7a3SLiteSpeed Tech s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, ©, &sz); 1955392f7a3SLiteSpeed Tech if (s != 1 || sz != sizeof(*shm_state)) 1965392f7a3SLiteSpeed Tech { 1975392f7a3SLiteSpeed Tech LSQ_ERROR("cannot lookup after insert: s=%d; sz=%u", s, sz); 1985392f7a3SLiteSpeed Tech return -1; 1995392f7a3SLiteSpeed Tech } 2005392f7a3SLiteSpeed Tech if (copy != data) 2015392f7a3SLiteSpeed Tech memcpy(shm_state, copy, sizeof(*shm_state)); 2025392f7a3SLiteSpeed Tech LSQ_INFO("inserted %s of size %u", TOKGEN_SHM_KEY, sz); 2035392f7a3SLiteSpeed Tech return 0; 2045392f7a3SLiteSpeed Tech} 2055392f7a3SLiteSpeed Tech 2065392f7a3SLiteSpeed Tech 2075392f7a3SLiteSpeed Techstruct token_generator * 2085392f7a3SLiteSpeed Techlsquic_tg_new (struct lsquic_engine_public *enpub) 2095392f7a3SLiteSpeed Tech{ 2105392f7a3SLiteSpeed Tech struct token_generator *tokgen; 2115392f7a3SLiteSpeed Tech time_t now; 2125392f7a3SLiteSpeed Tech struct tokgen_shm_state shm_state; 2135392f7a3SLiteSpeed Tech 2145392f7a3SLiteSpeed Tech tokgen = calloc(1, sizeof(*tokgen)); 2155392f7a3SLiteSpeed Tech if (!tokgen) 2165392f7a3SLiteSpeed Tech goto err; 2175392f7a3SLiteSpeed Tech 2185392f7a3SLiteSpeed Tech now = time(NULL); 2195392f7a3SLiteSpeed Tech if (0 != get_or_generate_state(enpub, now, &shm_state)) 2205392f7a3SLiteSpeed Tech goto err; 2215392f7a3SLiteSpeed Tech 2225392f7a3SLiteSpeed Tech 2235392f7a3SLiteSpeed Tech tokgen->tg_srst_prk_sz = shm_state.tgss_srst_prk_size; 2245392f7a3SLiteSpeed Tech if (tokgen->tg_srst_prk_sz > sizeof(tokgen->tg_srst_prk_buf)) 2255392f7a3SLiteSpeed Tech { 2265392f7a3SLiteSpeed Tech LSQ_WARN("bad stateless reset key size"); 2275392f7a3SLiteSpeed Tech goto err; 2285392f7a3SLiteSpeed Tech } 2295392f7a3SLiteSpeed Tech memcpy(tokgen->tg_srst_prk_buf, shm_state.tgss_srst_prk, 2305392f7a3SLiteSpeed Tech tokgen->tg_srst_prk_sz); 2315392f7a3SLiteSpeed Tech 2325392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized"); 2335392f7a3SLiteSpeed Tech return tokgen; 2345392f7a3SLiteSpeed Tech 2355392f7a3SLiteSpeed Tech err: 2365392f7a3SLiteSpeed Tech LSQ_ERROR("error initializing"); 2375392f7a3SLiteSpeed Tech free(tokgen); 2385392f7a3SLiteSpeed Tech return NULL; 2395392f7a3SLiteSpeed Tech} 2405392f7a3SLiteSpeed Tech 2415392f7a3SLiteSpeed Tech 2425392f7a3SLiteSpeed Techvoid 2435392f7a3SLiteSpeed Techlsquic_tg_destroy (struct token_generator *tokgen) 2445392f7a3SLiteSpeed Tech{ 2455392f7a3SLiteSpeed Tech free(tokgen); 2465392f7a3SLiteSpeed Tech LSQ_DEBUG("destroyed"); 2475392f7a3SLiteSpeed Tech} 2485392f7a3SLiteSpeed Tech 2495392f7a3SLiteSpeed Tech 2505392f7a3SLiteSpeed Techvoid 2515392f7a3SLiteSpeed Techlsquic_tg_generate_sreset (struct token_generator *tokgen, 2525392f7a3SLiteSpeed Tech const struct lsquic_cid *cid, unsigned char *reset_token) 2535392f7a3SLiteSpeed Tech{ 2545392f7a3SLiteSpeed Tech char str[IQUIC_SRESET_TOKEN_SZ * 2 + 1]; 2555392f7a3SLiteSpeed Tech 2565392f7a3SLiteSpeed Tech (void) HKDF_expand(reset_token, IQUIC_SRESET_TOKEN_SZ, EVP_sha256(), 2575392f7a3SLiteSpeed Tech tokgen->tg_srst_prk_buf, tokgen->tg_srst_prk_sz, cid->idbuf, cid->len); 2585392f7a3SLiteSpeed Tech LSQ_DEBUGC("generated stateless reset token %s for CID %"CID_FMT, 2595392f7a3SLiteSpeed Tech HEXSTR(reset_token, IQUIC_SRESET_TOKEN_SZ, str), CID_BITS(cid)); 2605392f7a3SLiteSpeed Tech} 261