blob: 988832fe33bc5fac0db3019a7d8d39c3ce01bdf8 [file] [log] [blame]
Emeric Brun3e541d12012-09-03 11:14:36 +02001/*
2 * shctx.c - shared context management functions for SSL
3 *
4 * Copyright (C) 2011-2012 EXCELIANCE
5 *
6 * Author: Emeric Brun - emeric@exceliance.fr
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <sys/mman.h>
Emeric Brun9faf0712012-09-25 11:11:16 +020015#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020016#ifdef USE_PTHREAD_PSHARED
17#include <pthread.h>
18#else
Emeric Brun3e541d12012-09-03 11:14:36 +020019#ifdef USE_SYSCALL_FUTEX
20#include <unistd.h>
Emeric Brun3e541d12012-09-03 11:14:36 +020021#include <linux/futex.h>
22#include <sys/syscall.h>
Emeric Bruncd1a5262014-05-07 23:11:42 +020023#endif
24#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020025#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010026#include <arpa/inet.h>
Willy Tarreauce3f9132014-05-28 16:47:01 +020027#include <ebmbtree.h>
28#include <types/global.h>
Emeric Brun3e541d12012-09-03 11:14:36 +020029#include "proto/shctx.h"
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +020030#include <proto/openssl-compat.h>
Emeric Brun3e541d12012-09-03 11:14:36 +020031
Emeric Brunaf9619d2012-11-28 18:47:52 +010032struct shsess_packet_hdr {
33 unsigned int eol;
34 unsigned char final:1;
35 unsigned char seq:7;
36 unsigned char id[SSL_MAX_SSL_SESSION_ID_LENGTH];
37};
38
39struct shsess_packet {
40 unsigned char version;
41 unsigned char sig[SHA_DIGEST_LENGTH];
42 struct shsess_packet_hdr hdr;
43 unsigned char data[0];
44};
45
Emeric Brun3e541d12012-09-03 11:14:36 +020046struct shared_session {
47 struct ebmb_node key;
48 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +010049 unsigned char data[SHSESS_BLOCK_MIN_SIZE];
Emeric Brun3e541d12012-09-03 11:14:36 +020050};
51
Emeric Brunaf9619d2012-11-28 18:47:52 +010052struct shared_block {
53 union {
54 struct shared_session session;
55 unsigned char data[sizeof(struct shared_session)];
56 } data;
57 short int data_len;
58 struct shared_block *p;
59 struct shared_block *n;
60};
Emeric Brun3e541d12012-09-03 11:14:36 +020061
62struct shared_context {
Emeric Brun9faf0712012-09-25 11:11:16 +020063#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020064#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +020065 pthread_mutex_t mutex;
Emeric Bruncd1a5262014-05-07 23:11:42 +020066#else
67 unsigned int waiters;
Emeric Brun3e541d12012-09-03 11:14:36 +020068#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020069#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010070 struct shsess_packet_hdr upd;
71 unsigned char data[SHSESS_MAX_DATA_LEN];
72 short int data_len;
73 struct shared_block active;
74 struct shared_block free;
Emeric Brun3e541d12012-09-03 11:14:36 +020075};
76
77/* Static shared context */
78static struct shared_context *shctx = NULL;
79
Emeric Brun3e541d12012-09-03 11:14:36 +020080/* Lock functions */
Emeric Bruncd1a5262014-05-07 23:11:42 +020081
82#if defined (USE_PRIVATE_CACHE)
83
Willy Tarreau338a4fc2012-10-18 15:11:52 +020084#define shared_context_lock()
85#define shared_context_unlock()
Emeric Brun9faf0712012-09-25 11:11:16 +020086
Emeric Bruncd1a5262014-05-07 23:11:42 +020087#elif defined (USE_PTHREAD_PSHARED)
88static int use_shared_mem = 0;
89
90#define shared_context_lock() if (use_shared_mem) pthread_mutex_lock(&shctx->mutex)
91#define shared_context_unlock() if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex)
92
Emeric Brun9faf0712012-09-25 11:11:16 +020093#else
Emeric Bruncd1a5262014-05-07 23:11:42 +020094static int use_shared_mem = 0;
95
Emeric Brun3e541d12012-09-03 11:14:36 +020096#ifdef USE_SYSCALL_FUTEX
Emeric Bruncd1a5262014-05-07 23:11:42 +020097static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
98{
99 syscall(SYS_futex, uaddr, FUTEX_WAIT, value, NULL, 0, 0);
100}
101
102static inline void _shared_context_awakelocker(unsigned int *uaddr)
103{
104 syscall(SYS_futex, uaddr, FUTEX_WAKE, 1, NULL, 0, 0);
105}
106
107#else /* internal spin lock */
108
109#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
110static inline void relax()
111{
112 __asm volatile("rep;nop\n" ::: "memory");
113}
114#else /* if no x86_64 or i586 arch: use less optimized but generic asm */
115static inline void relax()
116{
117 __asm volatile("" ::: "memory");
118}
119#endif
120
121static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
122{
123 int i;
124
125 for (i = 0; i < *count; i++) {
126 relax();
127 relax();
128 }
129 *count = *count << 1;
130}
131
132#define _shared_context_awakelocker(a)
133
134#endif
135
Emeric Brunce08baa2012-10-04 17:28:25 +0200136#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
Emeric Brun3e541d12012-09-03 11:14:36 +0200137static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
138{
139 __asm volatile("lock xchgl %0,%1"
140 : "=r" (x), "+m" (*ptr)
141 : "0" (x)
142 : "memory");
143 return x;
144}
145
146static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
147{
148 unsigned int ret;
149
150 __asm volatile("lock cmpxchgl %2,%1"
151 : "=a" (ret), "+m" (*ptr)
152 : "r" (new), "0" (old)
153 : "memory");
154 return ret;
155}
156
157static inline unsigned char atomic_dec(unsigned int *ptr)
158{
159 unsigned char ret;
160 __asm volatile("lock decl %0\n"
161 "setne %1\n"
162 : "+m" (*ptr), "=qm" (ret)
163 :
164 : "memory");
165 return ret;
166}
167
168#else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */
169static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
170{
171 return __sync_lock_test_and_set(ptr, x);
172}
173
174static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
175{
176 return __sync_val_compare_and_swap(ptr, old, new);
177}
178
179static inline unsigned char atomic_dec(unsigned int *ptr)
180{
181 return __sync_sub_and_fetch(ptr, 1) ? 1 : 0;
182}
183
184#endif
185
Emeric Brun4b3091e2012-09-24 15:48:52 +0200186static inline void _shared_context_lock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200187{
188 unsigned int x;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200189 unsigned int count = 4;
Emeric Brun3e541d12012-09-03 11:14:36 +0200190
191 x = cmpxchg(&shctx->waiters, 0, 1);
192 if (x) {
193 if (x != 2)
194 x = xchg(&shctx->waiters, 2);
195
196 while (x) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200197 _shared_context_wait4lock(&count, &shctx->waiters, 2);
Emeric Brun3e541d12012-09-03 11:14:36 +0200198 x = xchg(&shctx->waiters, 2);
199 }
200 }
201}
202
Emeric Brun4b3091e2012-09-24 15:48:52 +0200203static inline void _shared_context_unlock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200204{
205 if (atomic_dec(&shctx->waiters)) {
206 shctx->waiters = 0;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200207 _shared_context_awakelocker(&shctx->waiters);
Emeric Brun3e541d12012-09-03 11:14:36 +0200208 }
209}
210
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200211#define shared_context_lock() if (use_shared_mem) _shared_context_lock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200212
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200213#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200214
Emeric Brun9faf0712012-09-25 11:11:16 +0200215#endif
Emeric Brun3e541d12012-09-03 11:14:36 +0200216
217/* List Macros */
218
Emeric Brunaf9619d2012-11-28 18:47:52 +0100219#define shblock_unset(s) (s)->n->p = (s)->p; \
Emeric Brun3e541d12012-09-03 11:14:36 +0200220 (s)->p->n = (s)->n;
221
Emeric Brunaf9619d2012-11-28 18:47:52 +0100222#define shblock_set_free(s) shblock_unset(s) \
223 (s)->n = &shctx->free; \
224 (s)->p = shctx->free.p; \
225 shctx->free.p->n = s; \
226 shctx->free.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200227
228
Emeric Brunaf9619d2012-11-28 18:47:52 +0100229#define shblock_set_active(s) shblock_unset(s) \
230 (s)->n = &shctx->active; \
231 (s)->p = shctx->active.p; \
232 shctx->active.p->n = s; \
233 shctx->active.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200234
235
Emeric Brun3e541d12012-09-03 11:14:36 +0200236/* Tree Macros */
237
238#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
239
Emeric Brunaf9619d2012-11-28 18:47:52 +0100240#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200241 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
242
Emeric Brunaf9619d2012-11-28 18:47:52 +0100243#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200244 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
245
Emeric Brunaf9619d2012-11-28 18:47:52 +0100246/* shared session functions */
Emeric Brun3e541d12012-09-03 11:14:36 +0200247
Emeric Brunaf9619d2012-11-28 18:47:52 +0100248/* Free session blocks, returns number of freed blocks */
249static int shsess_free(struct shared_session *shsess)
250{
251 struct shared_block *block;
252 int ret = 1;
Emeric Brun3e541d12012-09-03 11:14:36 +0200253
Emeric Brunaf9619d2012-11-28 18:47:52 +0100254 if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
255 shblock_set_free((struct shared_block *)shsess);
256 return ret;
257 }
258 block = ((struct shared_block *)shsess)->n;
259 shblock_set_free((struct shared_block *)shsess);
260 while (1) {
261 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200262
Emeric Brunaf9619d2012-11-28 18:47:52 +0100263 if (block->data_len <= sizeof(block->data)) {
264 /* last block */
265 shblock_set_free(block);
266 ret++;
267 break;
268 }
269 next = block->n;
270 shblock_set_free(block);
271 ret++;
272 block = next;
273 }
274 return ret;
275}
Emeric Brun3e541d12012-09-03 11:14:36 +0200276
Emeric Brunaf9619d2012-11-28 18:47:52 +0100277/* This function frees enough blocks to store a new session of data_len.
278 * Returns a ptr on a free block if it succeeds, or NULL if there are not
279 * enough blocks to store that session.
280 */
281static struct shared_session *shsess_get_next(int data_len)
Emeric Brun3e541d12012-09-03 11:14:36 +0200282{
Emeric Brunaf9619d2012-11-28 18:47:52 +0100283 int head = 0;
284 struct shared_block *b;
285
286 b = shctx->free.n;
287 while (b != &shctx->free) {
288 if (!head) {
289 data_len -= sizeof(b->data.session.data);
290 head = 1;
291 }
292 else
293 data_len -= sizeof(b->data.data);
294 if (data_len <= 0)
295 return &shctx->free.n->data.session;
296 b = b->n;
297 }
298 b = shctx->active.n;
299 while (b != &shctx->active) {
300 int freed;
301
302 shsess_tree_delete(&b->data.session);
303 freed = shsess_free(&b->data.session);
304 if (!head)
305 data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
306 else
307 data_len -= freed*sizeof(b->data.data);
308 if (data_len <= 0)
309 return &shctx->free.n->data.session;
310 b = shctx->active.n;
311 }
312 return NULL;
313}
Emeric Brun3e541d12012-09-03 11:14:36 +0200314
Emeric Brunaf9619d2012-11-28 18:47:52 +0100315/* store a session into the cache
316 * s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
317 * data: asn1 encoded session
318 * data_len: asn1 encoded session length
319 * Returns 1 id session was stored (else 0)
320 */
321static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
322{
323 struct shared_session *shsess, *oldshsess;
324
325 shsess = shsess_get_next(data_len);
326 if (!shsess) {
327 /* Could not retrieve enough free blocks to store that session */
Emeric Brun3e541d12012-09-03 11:14:36 +0200328 return 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100329 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200330
Emeric Brunaf9619d2012-11-28 18:47:52 +0100331 /* prepare key */
332 memcpy(shsess->key_data, s_id, SSL_MAX_SSL_SESSION_ID_LENGTH);
Emeric Brun3e541d12012-09-03 11:14:36 +0200333
Emeric Brunaf9619d2012-11-28 18:47:52 +0100334 /* it returns the already existing node
335 or current node if none, never returns null */
336 oldshsess = shsess_tree_insert(shsess);
337 if (oldshsess != shsess) {
338 /* free all blocks used by old node */
339 shsess_free(oldshsess);
340 shsess = oldshsess;
341 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200342
Emeric Brunaf9619d2012-11-28 18:47:52 +0100343 ((struct shared_block *)shsess)->data_len = data_len;
344 if (data_len <= sizeof(shsess->data)) {
345 /* Store on a single block */
346 memcpy(shsess->data, data, data_len);
347 shblock_set_active((struct shared_block *)shsess);
348 }
349 else {
350 unsigned char *p;
351 /* Store on multiple blocks */
352 int cur_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200353
Emeric Brunaf9619d2012-11-28 18:47:52 +0100354 memcpy(shsess->data, data, sizeof(shsess->data));
355 p = data + sizeof(shsess->data);
356 cur_len = data_len - sizeof(shsess->data);
357 shblock_set_active((struct shared_block *)shsess);
358 while (1) {
359 /* Store next data on free block.
360 * shsess_get_next guarantees that there are enough
361 * free blocks in queue.
362 */
363 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200364
Emeric Brunaf9619d2012-11-28 18:47:52 +0100365 block = shctx->free.n;
366 if (cur_len <= sizeof(block->data)) {
367 /* This is the last block */
368 block->data_len = cur_len;
369 memcpy(block->data.data, p, cur_len);
370 shblock_set_active(block);
371 break;
372 }
373 /* Intermediate block */
374 block->data_len = cur_len;
375 memcpy(block->data.data, p, sizeof(block->data));
376 p += sizeof(block->data.data);
377 cur_len -= sizeof(block->data.data);
378 shblock_set_active(block);
379 }
380 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200381
Emeric Brunaf9619d2012-11-28 18:47:52 +0100382 return 1;
383}
Emeric Brun3e541d12012-09-03 11:14:36 +0200384
Emeric Brun3e541d12012-09-03 11:14:36 +0200385
Emeric Brunaf9619d2012-11-28 18:47:52 +0100386/* SSL context callbacks */
Emeric Brun3e541d12012-09-03 11:14:36 +0200387
Emeric Brunaf9619d2012-11-28 18:47:52 +0100388/* SSL callback used on new session creation */
389int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
390{
391 unsigned char encsess[sizeof(struct shsess_packet)+SHSESS_MAX_DATA_LEN];
392 struct shsess_packet *packet = (struct shsess_packet *)encsess;
393 unsigned char *p;
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200394 int data_len;
395 unsigned int sid_length, sid_ctx_length;
396 const unsigned char *sid_data;
397 const unsigned char *sid_ctx_data;
Emeric Brun3e541d12012-09-03 11:14:36 +0200398
Emeric Brunaf9619d2012-11-28 18:47:52 +0100399 /* Session id is already stored in to key and session id is known
400 * so we dont store it to keep size.
401 */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200402
403 sid_data = SSL_SESSION_get_id(sess, &sid_length);
404 sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
405 SSL_SESSION_set1_id(sess, sid_data, 0);
406 SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200407
Emeric Brunaf9619d2012-11-28 18:47:52 +0100408 /* check if buffer is large enough for the ASN1 encoded session */
409 data_len = i2d_SSL_SESSION(sess, NULL);
410 if (data_len > SHSESS_MAX_DATA_LEN)
411 goto err;
412
413 /* process ASN1 session encoding before the lock */
414 p = packet->data;
415 i2d_SSL_SESSION(sess, &p);
416
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200417 memcpy(packet->hdr.id, sid_data, sid_length);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100418 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
419 memset(&packet->hdr.id[sid_length], 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
420
421 shared_context_lock();
422
423 /* store to cache */
424 shsess_store(packet->hdr.id, packet->data, data_len);
425
426 shared_context_unlock();
427
428err:
429 /* reset original length values */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200430 SSL_SESSION_set1_id(sess, sid_data, sid_length);
431 SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
Emeric Brun3e541d12012-09-03 11:14:36 +0200432
433 return 0; /* do not increment session reference count */
434}
435
436/* SSL callback used on lookup an existing session cause none found in internal cache */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200437SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, int key_len, int *do_copy)
Emeric Brun3e541d12012-09-03 11:14:36 +0200438{
439 struct shared_session *shsess;
440 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
441 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +0100442 int data_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200443 SSL_SESSION *sess;
Emeric Brun3e541d12012-09-03 11:14:36 +0200444
Willy Tarreauce3f9132014-05-28 16:47:01 +0200445 global.shctx_lookups++;
446
Emeric Brun3e541d12012-09-03 11:14:36 +0200447 /* allow the session to be freed automatically by openssl */
448 *do_copy = 0;
449
450 /* tree key is zeros padded sessionid */
451 if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
452 memcpy(tmpkey, key, key_len);
453 memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
454 key = tmpkey;
455 }
456
457 /* lock cache */
458 shared_context_lock();
459
460 /* lookup for session */
461 shsess = shsess_tree_lookup(key);
462 if (!shsess) {
463 /* no session found: unlock cache and exit */
464 shared_context_unlock();
Willy Tarreauce3f9132014-05-28 16:47:01 +0200465 global.shctx_misses++;
Emeric Brun3e541d12012-09-03 11:14:36 +0200466 return NULL;
467 }
468
Emeric Brunaf9619d2012-11-28 18:47:52 +0100469 data_len = ((struct shared_block *)shsess)->data_len;
470 if (data_len <= sizeof(shsess->data)) {
471 /* Session stored on single block */
472 memcpy(data, shsess->data, data_len);
473 shblock_set_active((struct shared_block *)shsess);
474 }
475 else {
476 /* Session stored on multiple blocks */
477 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200478
Emeric Brunaf9619d2012-11-28 18:47:52 +0100479 memcpy(data, shsess->data, sizeof(shsess->data));
480 p = data + sizeof(shsess->data);
481 block = ((struct shared_block *)shsess)->n;
482 shblock_set_active((struct shared_block *)shsess);
483 while (1) {
484 /* Retrieve data from next block */
485 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200486
Emeric Brunaf9619d2012-11-28 18:47:52 +0100487 if (block->data_len <= sizeof(block->data.data)) {
488 /* This is the last block */
489 memcpy(p, block->data.data, block->data_len);
490 p += block->data_len;
491 shblock_set_active(block);
492 break;
493 }
494 /* Intermediate block */
495 memcpy(p, block->data.data, sizeof(block->data.data));
496 p += sizeof(block->data.data);
497 next = block->n;
498 shblock_set_active(block);
499 block = next;
500 }
501 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200502
503 shared_context_unlock();
504
505 /* decode ASN1 session */
506 p = data;
507 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100508 /* Reset session id and session id contenxt */
509 if (sess) {
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200510 SSL_SESSION_set1_id(sess, key, key_len);
511 SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
Emeric Brunaf9619d2012-11-28 18:47:52 +0100512 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200513
514 return sess;
515}
516
517/* SSL callback used to signal session is no more used in internal cache */
518void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
519{
520 struct shared_session *shsess;
521 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200522 unsigned int sid_length;
523 const unsigned char *sid_data;
Emeric Brun3e541d12012-09-03 11:14:36 +0200524 (void)ctx;
525
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200526 sid_data = SSL_SESSION_get_id(sess, &sid_length);
Emeric Brun3e541d12012-09-03 11:14:36 +0200527 /* tree key is zeros padded sessionid */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200528 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
529 memcpy(tmpkey, sid_data, sid_length);
530 memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
531 sid_data = tmpkey;
Emeric Brun3e541d12012-09-03 11:14:36 +0200532 }
533
534 shared_context_lock();
535
536 /* lookup for session */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200537 shsess = shsess_tree_lookup(sid_data);
Emeric Brun3e541d12012-09-03 11:14:36 +0200538 if (shsess) {
Emeric Brunaf9619d2012-11-28 18:47:52 +0100539 /* free session */
540 shsess_tree_delete(shsess);
541 shsess_free(shsess);
Emeric Brun3e541d12012-09-03 11:14:36 +0200542 }
543
544 /* unlock cache */
545 shared_context_unlock();
546}
547
Emeric Brun3e541d12012-09-03 11:14:36 +0200548/* Allocate shared memory context.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100549 * <size> is maximum cached sessions.
Emeric Brun22890a12012-12-28 14:41:32 +0100550 * If <size> is set to less or equal to 0, ssl cache is disabled.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100551 * Returns: -1 on alloc failure, <size> if it performs context alloc,
552 * and 0 if cache is already allocated.
553 */
Emeric Brun4b3091e2012-09-24 15:48:52 +0200554int shared_context_init(int size, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200555{
556 int i;
Emeric Brun9faf0712012-09-25 11:11:16 +0200557#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200558#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200559 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200560#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200561#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +0100562 struct shared_block *prev,*cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200563 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200564
565 if (shctx)
566 return 0;
567
568 if (size<=0)
Emeric Brun22890a12012-12-28 14:41:32 +0100569 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200570
Emeric Brunaf9619d2012-11-28 18:47:52 +0100571 /* Increate size by one to reserve one node for lookup */
572 size++;
Emeric Brun9faf0712012-09-25 11:11:16 +0200573#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200574 if (shared)
575 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200576#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200577
Emeric Brunaf9619d2012-11-28 18:47:52 +0100578 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_block)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200579 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200580 if (!shctx || shctx == MAP_FAILED) {
581 shctx = NULL;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200582 return SHCTX_E_ALLOC_CACHE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200583 }
584
Emeric Brun9faf0712012-09-25 11:11:16 +0200585#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200586 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200587#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200588 if (pthread_mutexattr_init(&attr)) {
589 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
590 shctx = NULL;
591 return SHCTX_E_INIT_LOCK;
592 }
593
594 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
595 pthread_mutexattr_destroy(&attr);
596 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
597 shctx = NULL;
598 return SHCTX_E_INIT_LOCK;
599 }
600
601 if (pthread_mutex_init(&shctx->mutex, &attr)) {
602 pthread_mutexattr_destroy(&attr);
603 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
604 shctx = NULL;
605 return SHCTX_E_INIT_LOCK;
606 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200607#else
608 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200609#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200610 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200611 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200612#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200613
Emeric Brunaf9619d2012-11-28 18:47:52 +0100614 memset(&shctx->active.data.session.key, 0, sizeof(struct ebmb_node));
615 memset(&shctx->free.data.session.key, 0, sizeof(struct ebmb_node));
Emeric Brun3e541d12012-09-03 11:14:36 +0200616
617 /* No duplicate authorized in tree: */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100618 shctx->active.data.session.key.node.branches = EB_ROOT_UNIQUE;
619
620 /* Init remote update cache */
621 shctx->upd.eol = 0;
622 shctx->upd.seq = 0;
623 shctx->data_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200624
625 cur = &shctx->active;
626 cur->n = cur->p = cur;
627
628 cur = &shctx->free;
629 for (i = 0 ; i < size ; i++) {
630 prev = cur;
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200631 cur++;
Emeric Brun3e541d12012-09-03 11:14:36 +0200632 prev->n = cur;
633 cur->p = prev;
634 }
635 cur->n = &shctx->free;
636 shctx->free.p = cur;
637
638 return size;
639}
640
641
642/* Set session cache mode to server and disable openssl internal cache.
643 * Set shared cache callbacks on an ssl context.
644 * Shared context MUST be firstly initialized */
645void shared_context_set_cache(SSL_CTX *ctx)
646{
Emeric Brun786991e2012-11-26 18:37:12 +0100647 SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
648
Emeric Brun22890a12012-12-28 14:41:32 +0100649 if (!shctx) {
650 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
Emeric Brun3e541d12012-09-03 11:14:36 +0200651 return;
Emeric Brun22890a12012-12-28 14:41:32 +0100652 }
653
654 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
655 SSL_SESS_CACHE_NO_INTERNAL |
656 SSL_SESS_CACHE_NO_AUTO_CLEAR);
Emeric Brun3e541d12012-09-03 11:14:36 +0200657
658 /* Set callbacks */
659 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
660 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
661 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
662}