summaryrefslogtreecommitdiff
path: root/platform/src/ssl_sess_ticket.cpp
blob: 400baba986bb068336fa8dc262eb0fd9173c1719 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 *	SSL session ticket rotation implementation.
 *	Author: [email protected] (graduate student of 2019), [email protected]
 *	Create: 2019-5-24
 */

#include <time.h>
#include <tfe_utils.h>
#include <ssl_sess_ticket.h>
#include <openssl/ssl.h>
#include <pthread.h>


#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; i<STEK_WINDOW_SIZE; i++)
	{
		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;
		}
	}	
    pthread_rwlock_unlock(&(box->stek_rwlock));
	return ret;
}