2019-05-24 17:58:43 +08:00
|
|
|
/*
|
|
|
|
|
* SSL session ticket rotation implementation.
|
|
|
|
|
* Author: lijie2@iie.ac.cn (graduate student of 2019), zhengchao@iie.ac.cn
|
|
|
|
|
* Create: 2019-5-24
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <tfe_utils.h>
|
|
|
|
|
#include <ssl_sess_ticket.h>
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
|
|
|
2019-05-30 12:34:42 +08:00
|
|
|
#define STEK_WINDOW_SIZE 2
|
2019-05-24 17:58:43 +08:00
|
|
|
#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)
|
|
|
|
|
{
|
2019-05-30 12:34:42 +08:00
|
|
|
unsigned int i=0, j=0;
|
|
|
|
|
struct sess_ticket_box * ticket = (struct sess_ticket_box *) arg;
|
|
|
|
|
struct sess_ticket_key** steks=NULL;
|
2019-05-24 17:58:43 +08:00
|
|
|
set_stek_rand_seed(ticket->stek_rotation_seconds);
|
|
|
|
|
pthread_rwlock_wrlock(&(ticket->stek_rwlock));
|
2019-05-30 12:34:42 +08:00
|
|
|
steks=ticket->ticket_keys;
|
2019-05-24 17:58:43 +08:00
|
|
|
for(i = 0; i < ticket->ticket_group_num; i ++)
|
|
|
|
|
{
|
2019-05-30 12:34:42 +08:00
|
|
|
for(j=1; j<STEK_WINDOW_SIZE; j++)
|
|
|
|
|
{
|
|
|
|
|
steks[i][j]=steks[i][j-1];
|
|
|
|
|
}
|
2019-05-24 17:58:43 +08:00
|
|
|
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++)
|
|
|
|
|
{
|
2019-05-30 12:34:42 +08:00
|
|
|
ticket->ticket_keys[i] = ALLOC(struct sess_ticket_key, STEK_WINDOW_SIZE);
|
2019-05-24 17:58:43 +08:00
|
|
|
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);
|
2019-05-30 12:34:42 +08:00
|
|
|
int i=0;
|
|
|
|
|
for(i=0; i<STEK_WINDOW_SIZE; i++)
|
2019-05-24 17:58:43 +08:00
|
|
|
{
|
2019-05-30 12:34:42 +08:00
|
|
|
if (memcmp(key_name, steks[stek_index][i].name, 16) == 0)
|
|
|
|
|
{
|
|
|
|
|
*result=steks[stek_index][i];
|
|
|
|
|
ret=(i==0?STEK_FOUND_FRESH:STEK_FOUND_STALED);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-24 17:58:43 +08:00
|
|
|
pthread_rwlock_unlock(&(box->stek_rwlock));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|