lsquic_tokgen.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <stddef.h> 4#include <stdlib.h> 5#include <string.h> 6#include <sys/queue.h> 7#include <time.h> 8 9#ifndef WIN32 10#include <netinet/in.h> 11#include <sys/socket.h> 12#endif 13 14#include <openssl/aead.h> 15#include <openssl/hkdf.h> 16#include <openssl/rand.h> 17#include <openssl/ssl.h> 18 19#include "lsquic.h" 20#include "lsquic_int_types.h" 21#include "lsquic_sizes.h" 22#include "lsquic_types.h" 23#include "lsquic_packet_common.h" 24#include "lsquic_packet_in.h" 25#include "lsquic_tokgen.h" 26#include "lsquic_trans_params.h" 27#include "lsquic_util.h" 28#include "lsquic_mm.h" 29#include "lsquic_engine_public.h" 30 31#define LSQUIC_LOGGER_MODULE LSQLM_TOKGEN 32#include "lsquic_logger.h" 33 34#define STRINGIFY(x) #x 35#define TOSTRING(x) STRINGIFY(x) 36 37#define TOKGEN_VERSION 2 38 39#define CRYPTER_KEY_SIZE 16 40#define SRST_MAX_PRK_SIZE EVP_MAX_MD_SIZE 41 42#define TOKGEN_SHM_KEY "TOKGEN" TOSTRING(TOKGEN_VERSION) 43#define TOKGEN_SHM_KEY_SIZE (sizeof(TOKGEN_SHM_KEY) - 1) 44 45#define TOKGEN_SHM_MAGIC_TOP "Feliz" 46#define TOKGEN_SHM_MAGIC_BOTTOM "Navidad" 47 48struct tokgen_shm_state 49{ 50 uint8_t tgss_version; 51 uint8_t tgss_magic_top[sizeof(TOKGEN_SHM_MAGIC_TOP) - 1]; 52 uint8_t tgss_padding[2 * CRYPTER_KEY_SIZE]; 53 uint8_t tgss_srst_prk_size; 54 uint8_t tgss_srst_prk[SRST_MAX_PRK_SIZE]; 55 uint8_t tgss_magic_bottom[sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1]; 56}; 57 58 59 60static const uint8_t srst_salt[8] = "\x28\x6e\x81\x02\x40\x5b\x2c\x2b"; 61 62struct crypter 63{ 64 EVP_AEAD_CTX ctx; 65 unsigned long nonce_counter; 66 size_t nonce_prk_sz; 67 uint8_t nonce_prk_buf[EVP_MAX_MD_SIZE]; 68}; 69 70 71 72 73struct token_generator 74{ 75 76 /* Stateless reset token is generated using HKDF with CID as the 77 * `info' parameter to HKDF-Expand. 78 */ 79 size_t tg_srst_prk_sz; 80 uint8_t tg_srst_prk_buf[SRST_MAX_PRK_SIZE]; 81}; 82 83 84 85 86static int 87get_or_generate_state (struct lsquic_engine_public *enpub, time_t now, 88 struct tokgen_shm_state *shm_state) 89{ 90 const struct lsquic_shared_hash_if *const shi = enpub->enp_shi; 91 void *const ctx = enpub->enp_shi_ctx; 92 void *data, *copy, *key_copy; 93 int s; 94 unsigned sz; 95 size_t bufsz; 96 struct { 97 time_t now; 98 unsigned char buf[24]; 99 } 100#if __GNUC__ 101 /* This is more of a documentation note: this struct should already 102 * have a multiple-of-eight size. 103 */ 104 __attribute__((packed)) 105#endif 106 srst_ikm; 107 108 data = shm_state; 109 sz = sizeof(*shm_state); 110 s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &data, &sz); 111 112 if (s == 1) 113 { 114 if (sz != sizeof(*shm_state)) 115 { 116 LSQ_WARN("found SHM data has non-matching size %u", sz); 117 return -1; 118 } 119 if (data != (void *) shm_state) 120 memcpy(shm_state, data, sizeof(*shm_state)); 121 if (shm_state->tgss_version != TOKGEN_VERSION) 122 { 123 LSQ_DEBUG("found SHM data has non-matching version %u", 124 shm_state->tgss_version); 125 return -1; 126 } 127 LSQ_DEBUG("found SHM data: size %u; version %u", sz, 128 shm_state->tgss_version); 129 return 0; 130 } 131 132 if (s != 0) 133 { 134 if (s != -1) 135 LSQ_WARN("SHM lookup returned unexpected value %d", s); 136 LSQ_DEBUG("SHM lookup returned an error: generate"); 137 goto generate; 138 } 139 140 assert(s == 0); 141 LSQ_DEBUG("%s does not exist: generate", TOKGEN_SHM_KEY); 142 generate: 143 now = time(NULL); 144 memset(shm_state, 0, sizeof(*shm_state)); 145 shm_state->tgss_version = TOKGEN_VERSION; 146 memcpy(shm_state->tgss_magic_top, TOKGEN_SHM_MAGIC_TOP, 147 sizeof(TOKGEN_SHM_MAGIC_TOP) - 1); 148 if (getenv("LSQUIC_NULL_TOKGEN")) 149 { 150 LSQ_NOTICE("using NULL tokgen"); 151 memset(&srst_ikm, 0, sizeof(srst_ikm)); 152 } 153 else 154 { 155 srst_ikm.now = now; 156 RAND_bytes(srst_ikm.buf, sizeof(srst_ikm.buf)); 157 } 158 if (!HKDF_extract(shm_state->tgss_srst_prk, &bufsz, 159 EVP_sha256(), (uint8_t *) &srst_ikm, sizeof(srst_ikm), 160 srst_salt, sizeof(srst_salt))) 161 { 162 LSQ_ERROR("HKDF_extract failed"); 163 return -1; 164 } 165 shm_state->tgss_srst_prk_size = (uint8_t) bufsz; 166 memcpy(shm_state->tgss_magic_bottom, TOKGEN_SHM_MAGIC_BOTTOM, 167 sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1); 168 169 data = malloc(sizeof(*shm_state)); 170 if (!data) 171 { 172 LSQ_ERROR("%s: malloc", __func__); 173 return -1; 174 } 175 memcpy(data, shm_state, sizeof(*shm_state)); 176 key_copy = malloc(TOKGEN_SHM_KEY_SIZE); 177 if (!key_copy) 178 { 179 LSQ_ERROR("%s: malloc", __func__); 180 free(data); 181 return -1; 182 } 183 memcpy(key_copy, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE); 184 s = shi->shi_insert(ctx, key_copy, TOKGEN_SHM_KEY_SIZE, data, 185 sizeof(*shm_state), 0); 186 if (s != 0) 187 { 188 LSQ_ERROR("cannot insert into SHM"); 189 free(data); 190 free(key_copy); 191 return -1; 192 } 193 sz = sizeof(*shm_state); 194 s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, ©, &sz); 195 if (s != 1 || sz != sizeof(*shm_state)) 196 { 197 LSQ_ERROR("cannot lookup after insert: s=%d; sz=%u", s, sz); 198 return -1; 199 } 200 if (copy != data) 201 memcpy(shm_state, copy, sizeof(*shm_state)); 202 LSQ_INFO("inserted %s of size %u", TOKGEN_SHM_KEY, sz); 203 return 0; 204} 205 206 207struct token_generator * 208lsquic_tg_new (struct lsquic_engine_public *enpub) 209{ 210 struct token_generator *tokgen; 211 time_t now; 212 struct tokgen_shm_state shm_state; 213 214 tokgen = calloc(1, sizeof(*tokgen)); 215 if (!tokgen) 216 goto err; 217 218 now = time(NULL); 219 if (0 != get_or_generate_state(enpub, now, &shm_state)) 220 goto err; 221 222 223 tokgen->tg_srst_prk_sz = shm_state.tgss_srst_prk_size; 224 if (tokgen->tg_srst_prk_sz > sizeof(tokgen->tg_srst_prk_buf)) 225 { 226 LSQ_WARN("bad stateless reset key size"); 227 goto err; 228 } 229 memcpy(tokgen->tg_srst_prk_buf, shm_state.tgss_srst_prk, 230 tokgen->tg_srst_prk_sz); 231 232 LSQ_DEBUG("initialized"); 233 return tokgen; 234 235 err: 236 LSQ_ERROR("error initializing"); 237 free(tokgen); 238 return NULL; 239} 240 241 242void 243lsquic_tg_destroy (struct token_generator *tokgen) 244{ 245 free(tokgen); 246 LSQ_DEBUG("destroyed"); 247} 248 249 250void 251lsquic_tg_generate_sreset (struct token_generator *tokgen, 252 const struct lsquic_cid *cid, unsigned char *reset_token) 253{ 254 char str[IQUIC_SRESET_TOKEN_SZ * 2 + 1]; 255 256 (void) HKDF_expand(reset_token, IQUIC_SRESET_TOKEN_SZ, EVP_sha256(), 257 tokgen->tg_srst_prk_buf, tokgen->tg_srst_prk_sz, cid->idbuf, cid->len); 258 LSQ_DEBUGC("generated stateless reset token %s for CID %"CID_FMT, 259 HEXSTR(reset_token, IQUIC_SRESET_TOKEN_SZ, str), CID_BITS(cid)); 260} 261