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, ©, &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