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