blob: a22730a48b488d7d42c036fc91c7bcb9687f5456 [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"
30
Emeric Brunaf9619d2012-11-28 18:47:52 +010031struct shsess_packet_hdr {
32 unsigned int eol;
33 unsigned char final:1;
34 unsigned char seq:7;
35 unsigned char id[SSL_MAX_SSL_SESSION_ID_LENGTH];
36};
37
38struct shsess_packet {
39 unsigned char version;
40 unsigned char sig[SHA_DIGEST_LENGTH];
41 struct shsess_packet_hdr hdr;
42 unsigned char data[0];
43};
44
Emeric Brun3e541d12012-09-03 11:14:36 +020045struct shared_session {
46 struct ebmb_node key;
47 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +010048 unsigned char data[SHSESS_BLOCK_MIN_SIZE];
Emeric Brun3e541d12012-09-03 11:14:36 +020049};
50
Emeric Brunaf9619d2012-11-28 18:47:52 +010051struct shared_block {
52 union {
53 struct shared_session session;
54 unsigned char data[sizeof(struct shared_session)];
55 } data;
56 short int data_len;
57 struct shared_block *p;
58 struct shared_block *n;
59};
Emeric Brun3e541d12012-09-03 11:14:36 +020060
61struct shared_context {
Emeric Brun9faf0712012-09-25 11:11:16 +020062#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020063#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +020064 pthread_mutex_t mutex;
Emeric Bruncd1a5262014-05-07 23:11:42 +020065#else
66 unsigned int waiters;
Emeric Brun3e541d12012-09-03 11:14:36 +020067#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020068#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010069 struct shsess_packet_hdr upd;
70 unsigned char data[SHSESS_MAX_DATA_LEN];
71 short int data_len;
72 struct shared_block active;
73 struct shared_block free;
Emeric Brun3e541d12012-09-03 11:14:36 +020074};
75
76/* Static shared context */
77static struct shared_context *shctx = NULL;
78
Emeric Brun3e541d12012-09-03 11:14:36 +020079/* Lock functions */
Emeric Bruncd1a5262014-05-07 23:11:42 +020080
81#if defined (USE_PRIVATE_CACHE)
82
Willy Tarreau338a4fc2012-10-18 15:11:52 +020083#define shared_context_lock()
84#define shared_context_unlock()
Emeric Brun9faf0712012-09-25 11:11:16 +020085
Emeric Bruncd1a5262014-05-07 23:11:42 +020086#elif defined (USE_PTHREAD_PSHARED)
87static int use_shared_mem = 0;
88
89#define shared_context_lock() if (use_shared_mem) pthread_mutex_lock(&shctx->mutex)
90#define shared_context_unlock() if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex)
91
Emeric Brun9faf0712012-09-25 11:11:16 +020092#else
Emeric Bruncd1a5262014-05-07 23:11:42 +020093static int use_shared_mem = 0;
94
Emeric Brun3e541d12012-09-03 11:14:36 +020095#ifdef USE_SYSCALL_FUTEX
Emeric Bruncd1a5262014-05-07 23:11:42 +020096static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
97{
98 syscall(SYS_futex, uaddr, FUTEX_WAIT, value, NULL, 0, 0);
99}
100
101static inline void _shared_context_awakelocker(unsigned int *uaddr)
102{
103 syscall(SYS_futex, uaddr, FUTEX_WAKE, 1, NULL, 0, 0);
104}
105
106#else /* internal spin lock */
107
108#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
109static inline void relax()
110{
111 __asm volatile("rep;nop\n" ::: "memory");
112}
113#else /* if no x86_64 or i586 arch: use less optimized but generic asm */
114static inline void relax()
115{
116 __asm volatile("" ::: "memory");
117}
118#endif
119
120static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
121{
122 int i;
123
124 for (i = 0; i < *count; i++) {
125 relax();
126 relax();
127 }
128 *count = *count << 1;
129}
130
131#define _shared_context_awakelocker(a)
132
133#endif
134
Emeric Brunce08baa2012-10-04 17:28:25 +0200135#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
Emeric Brun3e541d12012-09-03 11:14:36 +0200136static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
137{
138 __asm volatile("lock xchgl %0,%1"
139 : "=r" (x), "+m" (*ptr)
140 : "0" (x)
141 : "memory");
142 return x;
143}
144
145static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
146{
147 unsigned int ret;
148
149 __asm volatile("lock cmpxchgl %2,%1"
150 : "=a" (ret), "+m" (*ptr)
151 : "r" (new), "0" (old)
152 : "memory");
153 return ret;
154}
155
156static inline unsigned char atomic_dec(unsigned int *ptr)
157{
158 unsigned char ret;
159 __asm volatile("lock decl %0\n"
160 "setne %1\n"
161 : "+m" (*ptr), "=qm" (ret)
162 :
163 : "memory");
164 return ret;
165}
166
167#else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */
168static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
169{
170 return __sync_lock_test_and_set(ptr, x);
171}
172
173static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
174{
175 return __sync_val_compare_and_swap(ptr, old, new);
176}
177
178static inline unsigned char atomic_dec(unsigned int *ptr)
179{
180 return __sync_sub_and_fetch(ptr, 1) ? 1 : 0;
181}
182
183#endif
184
Emeric Brun4b3091e2012-09-24 15:48:52 +0200185static inline void _shared_context_lock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200186{
187 unsigned int x;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200188 unsigned int count = 4;
Emeric Brun3e541d12012-09-03 11:14:36 +0200189
190 x = cmpxchg(&shctx->waiters, 0, 1);
191 if (x) {
192 if (x != 2)
193 x = xchg(&shctx->waiters, 2);
194
195 while (x) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200196 _shared_context_wait4lock(&count, &shctx->waiters, 2);
Emeric Brun3e541d12012-09-03 11:14:36 +0200197 x = xchg(&shctx->waiters, 2);
198 }
199 }
200}
201
Emeric Brun4b3091e2012-09-24 15:48:52 +0200202static inline void _shared_context_unlock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200203{
204 if (atomic_dec(&shctx->waiters)) {
205 shctx->waiters = 0;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200206 _shared_context_awakelocker(&shctx->waiters);
Emeric Brun3e541d12012-09-03 11:14:36 +0200207 }
208}
209
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200210#define shared_context_lock() if (use_shared_mem) _shared_context_lock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200211
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200212#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200213
Emeric Brun9faf0712012-09-25 11:11:16 +0200214#endif
Emeric Brun3e541d12012-09-03 11:14:36 +0200215
216/* List Macros */
217
Emeric Brunaf9619d2012-11-28 18:47:52 +0100218#define shblock_unset(s) (s)->n->p = (s)->p; \
Emeric Brun3e541d12012-09-03 11:14:36 +0200219 (s)->p->n = (s)->n;
220
Emeric Brunaf9619d2012-11-28 18:47:52 +0100221#define shblock_set_free(s) shblock_unset(s) \
222 (s)->n = &shctx->free; \
223 (s)->p = shctx->free.p; \
224 shctx->free.p->n = s; \
225 shctx->free.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200226
227
Emeric Brunaf9619d2012-11-28 18:47:52 +0100228#define shblock_set_active(s) shblock_unset(s) \
229 (s)->n = &shctx->active; \
230 (s)->p = shctx->active.p; \
231 shctx->active.p->n = s; \
232 shctx->active.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200233
234
Emeric Brun3e541d12012-09-03 11:14:36 +0200235/* Tree Macros */
236
237#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
238
Emeric Brunaf9619d2012-11-28 18:47:52 +0100239#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200240 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
241
Emeric Brunaf9619d2012-11-28 18:47:52 +0100242#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200243 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
244
Emeric Brunaf9619d2012-11-28 18:47:52 +0100245/* shared session functions */
Emeric Brun3e541d12012-09-03 11:14:36 +0200246
Emeric Brunaf9619d2012-11-28 18:47:52 +0100247/* Free session blocks, returns number of freed blocks */
248static int shsess_free(struct shared_session *shsess)
249{
250 struct shared_block *block;
251 int ret = 1;
Emeric Brun3e541d12012-09-03 11:14:36 +0200252
Emeric Brunaf9619d2012-11-28 18:47:52 +0100253 if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
254 shblock_set_free((struct shared_block *)shsess);
255 return ret;
256 }
257 block = ((struct shared_block *)shsess)->n;
258 shblock_set_free((struct shared_block *)shsess);
259 while (1) {
260 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200261
Emeric Brunaf9619d2012-11-28 18:47:52 +0100262 if (block->data_len <= sizeof(block->data)) {
263 /* last block */
264 shblock_set_free(block);
265 ret++;
266 break;
267 }
268 next = block->n;
269 shblock_set_free(block);
270 ret++;
271 block = next;
272 }
273 return ret;
274}
Emeric Brun3e541d12012-09-03 11:14:36 +0200275
Emeric Brunaf9619d2012-11-28 18:47:52 +0100276/* This function frees enough blocks to store a new session of data_len.
277 * Returns a ptr on a free block if it succeeds, or NULL if there are not
278 * enough blocks to store that session.
279 */
280static struct shared_session *shsess_get_next(int data_len)
Emeric Brun3e541d12012-09-03 11:14:36 +0200281{
Emeric Brunaf9619d2012-11-28 18:47:52 +0100282 int head = 0;
283 struct shared_block *b;
284
285 b = shctx->free.n;
286 while (b != &shctx->free) {
287 if (!head) {
288 data_len -= sizeof(b->data.session.data);
289 head = 1;
290 }
291 else
292 data_len -= sizeof(b->data.data);
293 if (data_len <= 0)
294 return &shctx->free.n->data.session;
295 b = b->n;
296 }
297 b = shctx->active.n;
298 while (b != &shctx->active) {
299 int freed;
300
301 shsess_tree_delete(&b->data.session);
302 freed = shsess_free(&b->data.session);
303 if (!head)
304 data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
305 else
306 data_len -= freed*sizeof(b->data.data);
307 if (data_len <= 0)
308 return &shctx->free.n->data.session;
309 b = shctx->active.n;
310 }
311 return NULL;
312}
Emeric Brun3e541d12012-09-03 11:14:36 +0200313
Emeric Brunaf9619d2012-11-28 18:47:52 +0100314/* store a session into the cache
315 * s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
316 * data: asn1 encoded session
317 * data_len: asn1 encoded session length
318 * Returns 1 id session was stored (else 0)
319 */
320static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
321{
322 struct shared_session *shsess, *oldshsess;
323
324 shsess = shsess_get_next(data_len);
325 if (!shsess) {
326 /* Could not retrieve enough free blocks to store that session */
Emeric Brun3e541d12012-09-03 11:14:36 +0200327 return 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100328 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200329
Emeric Brunaf9619d2012-11-28 18:47:52 +0100330 /* prepare key */
331 memcpy(shsess->key_data, s_id, SSL_MAX_SSL_SESSION_ID_LENGTH);
Emeric Brun3e541d12012-09-03 11:14:36 +0200332
Emeric Brunaf9619d2012-11-28 18:47:52 +0100333 /* it returns the already existing node
334 or current node if none, never returns null */
335 oldshsess = shsess_tree_insert(shsess);
336 if (oldshsess != shsess) {
337 /* free all blocks used by old node */
338 shsess_free(oldshsess);
339 shsess = oldshsess;
340 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200341
Emeric Brunaf9619d2012-11-28 18:47:52 +0100342 ((struct shared_block *)shsess)->data_len = data_len;
343 if (data_len <= sizeof(shsess->data)) {
344 /* Store on a single block */
345 memcpy(shsess->data, data, data_len);
346 shblock_set_active((struct shared_block *)shsess);
347 }
348 else {
349 unsigned char *p;
350 /* Store on multiple blocks */
351 int cur_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200352
Emeric Brunaf9619d2012-11-28 18:47:52 +0100353 memcpy(shsess->data, data, sizeof(shsess->data));
354 p = data + sizeof(shsess->data);
355 cur_len = data_len - sizeof(shsess->data);
356 shblock_set_active((struct shared_block *)shsess);
357 while (1) {
358 /* Store next data on free block.
359 * shsess_get_next guarantees that there are enough
360 * free blocks in queue.
361 */
362 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200363
Emeric Brunaf9619d2012-11-28 18:47:52 +0100364 block = shctx->free.n;
365 if (cur_len <= sizeof(block->data)) {
366 /* This is the last block */
367 block->data_len = cur_len;
368 memcpy(block->data.data, p, cur_len);
369 shblock_set_active(block);
370 break;
371 }
372 /* Intermediate block */
373 block->data_len = cur_len;
374 memcpy(block->data.data, p, sizeof(block->data));
375 p += sizeof(block->data.data);
376 cur_len -= sizeof(block->data.data);
377 shblock_set_active(block);
378 }
379 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200380
Emeric Brunaf9619d2012-11-28 18:47:52 +0100381 return 1;
382}
Emeric Brun3e541d12012-09-03 11:14:36 +0200383
Emeric Brun3e541d12012-09-03 11:14:36 +0200384
Emeric Brunaf9619d2012-11-28 18:47:52 +0100385/* SSL context callbacks */
Emeric Brun3e541d12012-09-03 11:14:36 +0200386
Emeric Brunaf9619d2012-11-28 18:47:52 +0100387/* SSL callback used on new session creation */
388int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
389{
390 unsigned char encsess[sizeof(struct shsess_packet)+SHSESS_MAX_DATA_LEN];
391 struct shsess_packet *packet = (struct shsess_packet *)encsess;
392 unsigned char *p;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200393 int data_len, sid_length, sid_ctx_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200394
Emeric Brun3e541d12012-09-03 11:14:36 +0200395
Emeric Brunaf9619d2012-11-28 18:47:52 +0100396 /* Session id is already stored in to key and session id is known
397 * so we dont store it to keep size.
398 */
399 sid_length = sess->session_id_length;
400 sess->session_id_length = 0;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200401 sid_ctx_length = sess->sid_ctx_length;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100402 sess->sid_ctx_length = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200403
Emeric Brunaf9619d2012-11-28 18:47:52 +0100404 /* check if buffer is large enough for the ASN1 encoded session */
405 data_len = i2d_SSL_SESSION(sess, NULL);
406 if (data_len > SHSESS_MAX_DATA_LEN)
407 goto err;
408
409 /* process ASN1 session encoding before the lock */
410 p = packet->data;
411 i2d_SSL_SESSION(sess, &p);
412
413 memcpy(packet->hdr.id, sess->session_id, sid_length);
414 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
415 memset(&packet->hdr.id[sid_length], 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
416
417 shared_context_lock();
418
419 /* store to cache */
420 shsess_store(packet->hdr.id, packet->data, data_len);
421
422 shared_context_unlock();
423
424err:
425 /* reset original length values */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100426 sess->session_id_length = sid_length;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200427 sess->sid_ctx_length = sid_ctx_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200428
429 return 0; /* do not increment session reference count */
430}
431
432/* SSL callback used on lookup an existing session cause none found in internal cache */
433SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy)
434{
435 struct shared_session *shsess;
436 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
437 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +0100438 int data_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200439 SSL_SESSION *sess;
Emeric Brun3e541d12012-09-03 11:14:36 +0200440
Willy Tarreauce3f9132014-05-28 16:47:01 +0200441 global.shctx_lookups++;
442
Emeric Brun3e541d12012-09-03 11:14:36 +0200443 /* allow the session to be freed automatically by openssl */
444 *do_copy = 0;
445
446 /* tree key is zeros padded sessionid */
447 if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
448 memcpy(tmpkey, key, key_len);
449 memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
450 key = tmpkey;
451 }
452
453 /* lock cache */
454 shared_context_lock();
455
456 /* lookup for session */
457 shsess = shsess_tree_lookup(key);
458 if (!shsess) {
459 /* no session found: unlock cache and exit */
460 shared_context_unlock();
Willy Tarreauce3f9132014-05-28 16:47:01 +0200461 global.shctx_misses++;
Emeric Brun3e541d12012-09-03 11:14:36 +0200462 return NULL;
463 }
464
Emeric Brunaf9619d2012-11-28 18:47:52 +0100465 data_len = ((struct shared_block *)shsess)->data_len;
466 if (data_len <= sizeof(shsess->data)) {
467 /* Session stored on single block */
468 memcpy(data, shsess->data, data_len);
469 shblock_set_active((struct shared_block *)shsess);
470 }
471 else {
472 /* Session stored on multiple blocks */
473 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200474
Emeric Brunaf9619d2012-11-28 18:47:52 +0100475 memcpy(data, shsess->data, sizeof(shsess->data));
476 p = data + sizeof(shsess->data);
477 block = ((struct shared_block *)shsess)->n;
478 shblock_set_active((struct shared_block *)shsess);
479 while (1) {
480 /* Retrieve data from next block */
481 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200482
Emeric Brunaf9619d2012-11-28 18:47:52 +0100483 if (block->data_len <= sizeof(block->data.data)) {
484 /* This is the last block */
485 memcpy(p, block->data.data, block->data_len);
486 p += block->data_len;
487 shblock_set_active(block);
488 break;
489 }
490 /* Intermediate block */
491 memcpy(p, block->data.data, sizeof(block->data.data));
492 p += sizeof(block->data.data);
493 next = block->n;
494 shblock_set_active(block);
495 block = next;
496 }
497 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200498
499 shared_context_unlock();
500
501 /* decode ASN1 session */
502 p = data;
503 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100504 /* Reset session id and session id contenxt */
505 if (sess) {
506 memcpy(sess->session_id, key, key_len);
507 sess->session_id_length = key_len;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200508 memcpy(sess->sid_ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
Emeric Brunaf9619d2012-11-28 18:47:52 +0100509 sess->sid_ctx_length = ssl->sid_ctx_length;
510 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200511
512 return sess;
513}
514
515/* SSL callback used to signal session is no more used in internal cache */
516void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
517{
518 struct shared_session *shsess;
519 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
520 unsigned char *key = sess->session_id;
521 (void)ctx;
522
523 /* tree key is zeros padded sessionid */
524 if (sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
525 memcpy(tmpkey, sess->session_id, sess->session_id_length);
526 memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sess->session_id_length);
527 key = tmpkey;
528 }
529
530 shared_context_lock();
531
532 /* lookup for session */
533 shsess = shsess_tree_lookup(key);
534 if (shsess) {
Emeric Brunaf9619d2012-11-28 18:47:52 +0100535 /* free session */
536 shsess_tree_delete(shsess);
537 shsess_free(shsess);
Emeric Brun3e541d12012-09-03 11:14:36 +0200538 }
539
540 /* unlock cache */
541 shared_context_unlock();
542}
543
Emeric Brun3e541d12012-09-03 11:14:36 +0200544/* Allocate shared memory context.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100545 * <size> is maximum cached sessions.
Emeric Brun22890a12012-12-28 14:41:32 +0100546 * If <size> is set to less or equal to 0, ssl cache is disabled.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100547 * Returns: -1 on alloc failure, <size> if it performs context alloc,
548 * and 0 if cache is already allocated.
549 */
Emeric Brun4b3091e2012-09-24 15:48:52 +0200550int shared_context_init(int size, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200551{
552 int i;
Emeric Brun9faf0712012-09-25 11:11:16 +0200553#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200554#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200555 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200556#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200557#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +0100558 struct shared_block *prev,*cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200559 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200560
561 if (shctx)
562 return 0;
563
564 if (size<=0)
Emeric Brun22890a12012-12-28 14:41:32 +0100565 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200566
Emeric Brunaf9619d2012-11-28 18:47:52 +0100567 /* Increate size by one to reserve one node for lookup */
568 size++;
Emeric Brun9faf0712012-09-25 11:11:16 +0200569#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200570 if (shared)
571 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200572#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200573
Emeric Brunaf9619d2012-11-28 18:47:52 +0100574 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_block)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200575 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200576 if (!shctx || shctx == MAP_FAILED) {
577 shctx = NULL;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200578 return SHCTX_E_ALLOC_CACHE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200579 }
580
Emeric Brun9faf0712012-09-25 11:11:16 +0200581#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200582 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200583#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200584 if (pthread_mutexattr_init(&attr)) {
585 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
586 shctx = NULL;
587 return SHCTX_E_INIT_LOCK;
588 }
589
590 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
591 pthread_mutexattr_destroy(&attr);
592 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
593 shctx = NULL;
594 return SHCTX_E_INIT_LOCK;
595 }
596
597 if (pthread_mutex_init(&shctx->mutex, &attr)) {
598 pthread_mutexattr_destroy(&attr);
599 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
600 shctx = NULL;
601 return SHCTX_E_INIT_LOCK;
602 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200603#else
604 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200605#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200606 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200607 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200608#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200609
Emeric Brunaf9619d2012-11-28 18:47:52 +0100610 memset(&shctx->active.data.session.key, 0, sizeof(struct ebmb_node));
611 memset(&shctx->free.data.session.key, 0, sizeof(struct ebmb_node));
Emeric Brun3e541d12012-09-03 11:14:36 +0200612
613 /* No duplicate authorized in tree: */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100614 shctx->active.data.session.key.node.branches = EB_ROOT_UNIQUE;
615
616 /* Init remote update cache */
617 shctx->upd.eol = 0;
618 shctx->upd.seq = 0;
619 shctx->data_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200620
621 cur = &shctx->active;
622 cur->n = cur->p = cur;
623
624 cur = &shctx->free;
625 for (i = 0 ; i < size ; i++) {
626 prev = cur;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100627 cur = (struct shared_block *)((char *)prev + sizeof(struct shared_block));
Emeric Brun3e541d12012-09-03 11:14:36 +0200628 prev->n = cur;
629 cur->p = prev;
630 }
631 cur->n = &shctx->free;
632 shctx->free.p = cur;
633
634 return size;
635}
636
637
638/* Set session cache mode to server and disable openssl internal cache.
639 * Set shared cache callbacks on an ssl context.
640 * Shared context MUST be firstly initialized */
641void shared_context_set_cache(SSL_CTX *ctx)
642{
Emeric Brun786991e2012-11-26 18:37:12 +0100643 SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
644
Emeric Brun22890a12012-12-28 14:41:32 +0100645 if (!shctx) {
646 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
Emeric Brun3e541d12012-09-03 11:14:36 +0200647 return;
Emeric Brun22890a12012-12-28 14:41:32 +0100648 }
649
650 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
651 SSL_SESS_CACHE_NO_INTERNAL |
652 SSL_SESS_CACHE_NO_AUTO_CLEAR);
Emeric Brun3e541d12012-09-03 11:14:36 +0200653
654 /* Set callbacks */
655 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
656 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
657 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
658}