/* * SSL session ticket rotation implementation. * Author: lijie2@iie.ac.cn (graduate student of 2019), zhengchao@iie.ac.cn * Create: 2019-5-24 */ #include #include #include #include #include #define STEK_WINDOW_SIZE 2 #define STEK_SIZE 80 #define SEED_MAX_LEN 100 #define RAND_MAX_VALUE 256 static unsigned int murmurhash2(const void * key, int len, const unsigned int seed) { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. const unsigned int m = 0x5bd1e995; const int r = 24; // Initialize the hash to a 'random' value unsigned int h = seed ^ len; // Mix 4 bytes at a time into the hash const unsigned char * data = (const unsigned char *)key; while(len >= 4) { unsigned int k = *(unsigned int *)data; k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } // Handle the last few bytes of the input array switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; // Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. h ^= h >> 13; h *= m; h ^= h >> 15; return h; } struct sess_ticket_box { unsigned int ticket_group_num; // Number of STEK group used simultaneously unsigned int stek_rotation_seconds; struct sess_ticket_key **ticket_keys; pthread_rwlock_t stek_rwlock; struct event * stek_rotation_cb; struct event_base * ref_ev_base; }; static void set_stek_rand_seed(unsigned int stek_rotation_time) { time_t seed; time(&seed); seed = (seed/stek_rotation_time); srand(seed); } static void stek_key_reset(struct sess_ticket_key * stek) { int i = 0; unsigned char buf[STEK_SIZE]; memset(buf,0,sizeof(buf)); for(i = 0;i < STEK_SIZE; i++) { buf[i]=rand()%RAND_MAX_VALUE; } stek->size = STEK_SIZE; memcpy(stek->name, buf, 16); memcpy(stek->hmac_key, buf+16, 32); memcpy(stek->aes_key, buf+48, 32); } static void ssl_stek_rotation_cb(evutil_socket_t fd, short what, void * arg) { unsigned int i=0, j=0; struct sess_ticket_box * ticket = (struct sess_ticket_box *) arg; struct sess_ticket_key** steks=NULL; set_stek_rand_seed(ticket->stek_rotation_seconds); pthread_rwlock_wrlock(&(ticket->stek_rwlock)); steks=ticket->ticket_keys; for(i = 0; i < ticket->ticket_group_num; i ++) { for (j = STEK_WINDOW_SIZE - 1; j > 0; j--) { steks[i][j] = steks[i][j - 1]; } stek_key_reset(&(ticket->ticket_keys[i][0])); } pthread_rwlock_unlock(&(ticket->stek_rwlock)); //update the stek rotation time struct timeval stek_time = {ticket->stek_rotation_seconds, 0}; evtimer_add(ticket->stek_rotation_cb, &stek_time); } struct sess_ticket_box * sess_ticket_box_create(struct event_base * ev_base, unsigned int stek_group_num, unsigned int round_time, void * logger) { UNUSED int ret = 0; unsigned int i = 0; struct sess_ticket_box *ticket = ALLOC(struct sess_ticket_box,1); if(pthread_rwlock_init(&(ticket->stek_rwlock),NULL) != 0) { return NULL; } ticket->ticket_group_num = stek_group_num ; ticket->stek_rotation_seconds = round_time; ticket->ticket_keys = ALLOC(struct sess_ticket_key*,stek_group_num); set_stek_rand_seed(round_time); pthread_rwlock_wrlock(&(ticket->stek_rwlock)); for(i = 0; i < stek_group_num; i++) { ticket->ticket_keys[i] = ALLOC(struct sess_ticket_key, STEK_WINDOW_SIZE); stek_key_reset(&(ticket->ticket_keys[i][0])); } pthread_rwlock_unlock(&(ticket->stek_rwlock)); time_t now; time(&now); unsigned int till_first_rotation = round_time - now%round_time; struct timeval stek_first_rotate_time = {till_first_rotation, 0}; ticket->stek_rotation_cb = event_new(ev_base, -1, 0, ssl_stek_rotation_cb, ticket); evtimer_add(ticket->stek_rotation_cb, &stek_first_rotate_time); return ticket; } static int stek_get_idx_by_sni(const char* sni, int group_num) { unsigned int stek_index = 0; if(sni != NULL) { stek_index = murmurhash2(sni, strlen(sni), 1021); stek_index = stek_index % group_num; } return stek_index; } void sess_ticket_box_get_key_for_enc(struct sess_ticket_box * box, const char* sni, struct sess_ticket_key *result) { unsigned int stek_index = 0; pthread_rwlock_rdlock(&(box->stek_rwlock)); stek_index=stek_get_idx_by_sni(sni, box->ticket_group_num); *result=box->ticket_keys[stek_index][0]; pthread_rwlock_unlock(&(box->stek_rwlock)); return; } enum STEK_GET_RET sess_ticket_box_get_key_for_dec(struct sess_ticket_box * box, const char* sni, const unsigned char* key_name, struct sess_ticket_key *result) { unsigned int stek_index = 0; enum STEK_GET_RET ret=STEK_NOT_FOUND; struct sess_ticket_key** steks=NULL; pthread_rwlock_rdlock(&(box->stek_rwlock)); steks=box->ticket_keys; stek_index=stek_get_idx_by_sni(sni, box->ticket_group_num); int i=0; for(i=0; istek_rwlock)); return ret; }