lsquic_tokgen.c revision b55a5117
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 1 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 68struct token_generator 69{ 70 /* We encrypt different token types using different keys. */ 71 struct crypter tg_crypters[N_TOKEN_TYPES]; 72 73 /* Stateless reset token is generated using HKDF with CID as the 74 * `info' parameter to HKDF-Expand. 75 */ 76 size_t tg_srst_prk_sz; 77 uint8_t tg_srst_prk_buf[SRST_MAX_PRK_SIZE]; 78}; 79 80 81 82 83static int 84get_or_generate_state (struct lsquic_engine_public *enpub, time_t now, 85 struct tokgen_shm_state *shm_state) 86{ 87 const struct lsquic_shared_hash_if *const shi = enpub->enp_shi; 88 void *const ctx = enpub->enp_shi_ctx; 89 void *data, *copy, *key_copy; 90 int s; 91 unsigned sz; 92 size_t bufsz; 93 struct { 94 time_t now; 95 unsigned char buf[24]; 96 } 97#if __GNUC__ 98 /* This is more of a documentation note: this struct should already 99 * have a multiple-of-eight size. 100 */ 101 __attribute__((packed)) 102#endif 103 srst_ikm; 104 105 data = shm_state; 106 sz = sizeof(*shm_state); 107 s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, &data, &sz); 108 109 if (s == 1) 110 { 111 if (sz != sizeof(*shm_state)) 112 { 113 LSQ_WARN("found SHM data has non-matching size %u", sz); 114 return -1; 115 } 116 if (data != (void *) shm_state) 117 memcpy(shm_state, data, sizeof(*shm_state)); 118 if (shm_state->tgss_version != TOKGEN_VERSION) 119 { 120 LSQ_DEBUG("found SHM data has non-matching version %u", 121 shm_state->tgss_version); 122 return -1; 123 } 124 LSQ_DEBUG("found SHM data: size %u; version %u", sz, 125 shm_state->tgss_version); 126 return 0; 127 } 128 129 if (s != 0) 130 { 131 if (s != -1) 132 LSQ_WARN("SHM lookup returned unexpected value %d", s); 133 LSQ_DEBUG("SHM lookup returned an error: generate"); 134 goto generate; 135 } 136 137 assert(s == 0); 138 LSQ_DEBUG("%s does not exist: generate", TOKGEN_SHM_KEY); 139 generate: 140 now = time(NULL); 141 memset(shm_state, 0, sizeof(*shm_state)); 142 shm_state->tgss_version = TOKGEN_VERSION; 143 memcpy(shm_state->tgss_magic_top, TOKGEN_SHM_MAGIC_TOP, 144 sizeof(TOKGEN_SHM_MAGIC_TOP) - 1); 145 if (getenv("LSQUIC_NULL_TOKGEN")) 146 { 147 LSQ_NOTICE("using NULL tokgen"); 148 memset(&srst_ikm, 0, sizeof(srst_ikm)); 149 } 150 else 151 { 152 srst_ikm.now = now; 153 RAND_bytes(srst_ikm.buf, sizeof(srst_ikm.buf)); 154 } 155 if (!HKDF_extract(shm_state->tgss_srst_prk, &bufsz, 156 EVP_sha256(), (uint8_t *) &srst_ikm, sizeof(srst_ikm), 157 srst_salt, sizeof(srst_salt))) 158 { 159 LSQ_ERROR("HKDF_extract failed"); 160 return -1; 161 } 162 shm_state->tgss_srst_prk_size = (uint8_t) bufsz; 163 memcpy(shm_state->tgss_magic_bottom, TOKGEN_SHM_MAGIC_BOTTOM, 164 sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1); 165 166 data = malloc(sizeof(*shm_state)); 167 if (!data) 168 { 169 LSQ_ERROR("%s: malloc", __func__); 170 return -1; 171 } 172 memcpy(data, shm_state, sizeof(*shm_state)); 173 key_copy = malloc(TOKGEN_SHM_KEY_SIZE); 174 if (!key_copy) 175 { 176 LSQ_ERROR("%s: malloc", __func__); 177 free(data); 178 return -1; 179 } 180 memcpy(key_copy, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE); 181 s = shi->shi_insert(ctx, key_copy, TOKGEN_SHM_KEY_SIZE, data, 182 sizeof(*shm_state), 0); 183 if (s != 0) 184 { 185 LSQ_ERROR("cannot insert into SHM"); 186 free(data); 187 free(key_copy); 188 return -1; 189 } 190 sz = sizeof(*shm_state); 191 s = shi->shi_lookup(ctx, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE, ©, &sz); 192 if (s != 1 || sz != sizeof(*shm_state)) 193 { 194 LSQ_ERROR("cannot lookup after insert: s=%d; sz=%u", s, sz); 195 return -1; 196 } 197 if (copy != data) 198 memcpy(shm_state, copy, sizeof(*shm_state)); 199 LSQ_INFO("inserted %s of size %u", TOKGEN_SHM_KEY, sz); 200 return 0; 201} 202 203 204struct token_generator * 205lsquic_tg_new (struct lsquic_engine_public *enpub) 206{ 207 struct token_generator *tokgen; 208 time_t now; 209 struct tokgen_shm_state shm_state; 210 211 tokgen = calloc(1, sizeof(*tokgen)); 212 if (!tokgen) 213 goto err; 214 215 now = time(NULL); 216 if (0 != get_or_generate_state(enpub, now, &shm_state)) 217 goto err; 218 219 220 tokgen->tg_srst_prk_sz = shm_state.tgss_srst_prk_size; 221 if (tokgen->tg_srst_prk_sz > sizeof(tokgen->tg_srst_prk_buf)) 222 { 223 LSQ_WARN("bad stateless reset key size"); 224 goto err; 225 } 226 memcpy(tokgen->tg_srst_prk_buf, shm_state.tgss_srst_prk, 227 tokgen->tg_srst_prk_sz); 228 229 LSQ_DEBUG("initialized"); 230 return tokgen; 231 232 err: 233 LSQ_ERROR("error initializing"); 234 free(tokgen); 235 return NULL; 236} 237 238 239void 240lsquic_tg_destroy (struct token_generator *tokgen) 241{ 242 free(tokgen); 243 LSQ_DEBUG("destroyed"); 244} 245 246 247void 248lsquic_tg_generate_sreset (struct token_generator *tokgen, 249 const struct lsquic_cid *cid, unsigned char *reset_token) 250{ 251 char str[IQUIC_SRESET_TOKEN_SZ * 2 + 1]; 252 253 (void) HKDF_expand(reset_token, IQUIC_SRESET_TOKEN_SZ, EVP_sha256(), 254 tokgen->tg_srst_prk_buf, tokgen->tg_srst_prk_sz, cid->idbuf, cid->len); 255 LSQ_DEBUGC("generated stateless reset token %s for CID %"CID_FMT, 256 HEXSTR(reset_token, IQUIC_SRESET_TOKEN_SZ, str), CID_BITS(cid)); 257} 258