blob: c6d5d31cad80a3bb3892006059244bfa361be8e5 [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
32struct shared_session {
33 struct ebmb_node key;
34 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +010035 unsigned char data[SHSESS_BLOCK_MIN_SIZE];
Emeric Brun3e541d12012-09-03 11:14:36 +020036};
37
Emeric Brunaf9619d2012-11-28 18:47:52 +010038struct shared_block {
39 union {
40 struct shared_session session;
41 unsigned char data[sizeof(struct shared_session)];
42 } data;
43 short int data_len;
44 struct shared_block *p;
45 struct shared_block *n;
46};
Emeric Brun3e541d12012-09-03 11:14:36 +020047
48struct shared_context {
Emeric Brun9faf0712012-09-25 11:11:16 +020049#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020050#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +020051 pthread_mutex_t mutex;
Emeric Bruncd1a5262014-05-07 23:11:42 +020052#else
53 unsigned int waiters;
Emeric Brun3e541d12012-09-03 11:14:36 +020054#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020055#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010056 struct shared_block active;
57 struct shared_block free;
Emeric Brun3e541d12012-09-03 11:14:36 +020058};
59
60/* Static shared context */
61static struct shared_context *shctx = NULL;
62
Emeric Brun3e541d12012-09-03 11:14:36 +020063/* Lock functions */
Emeric Bruncd1a5262014-05-07 23:11:42 +020064
65#if defined (USE_PRIVATE_CACHE)
66
Willy Tarreau338a4fc2012-10-18 15:11:52 +020067#define shared_context_lock()
68#define shared_context_unlock()
Emeric Brun9faf0712012-09-25 11:11:16 +020069
Emeric Bruncd1a5262014-05-07 23:11:42 +020070#elif defined (USE_PTHREAD_PSHARED)
71static int use_shared_mem = 0;
72
73#define shared_context_lock() if (use_shared_mem) pthread_mutex_lock(&shctx->mutex)
74#define shared_context_unlock() if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex)
75
Emeric Brun9faf0712012-09-25 11:11:16 +020076#else
Emeric Bruncd1a5262014-05-07 23:11:42 +020077static int use_shared_mem = 0;
78
Emeric Brun3e541d12012-09-03 11:14:36 +020079#ifdef USE_SYSCALL_FUTEX
Emeric Bruncd1a5262014-05-07 23:11:42 +020080static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
81{
82 syscall(SYS_futex, uaddr, FUTEX_WAIT, value, NULL, 0, 0);
83}
84
85static inline void _shared_context_awakelocker(unsigned int *uaddr)
86{
87 syscall(SYS_futex, uaddr, FUTEX_WAKE, 1, NULL, 0, 0);
88}
89
90#else /* internal spin lock */
91
92#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
93static inline void relax()
94{
95 __asm volatile("rep;nop\n" ::: "memory");
96}
97#else /* if no x86_64 or i586 arch: use less optimized but generic asm */
98static inline void relax()
99{
100 __asm volatile("" ::: "memory");
101}
102#endif
103
104static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
105{
106 int i;
107
108 for (i = 0; i < *count; i++) {
109 relax();
110 relax();
111 }
112 *count = *count << 1;
113}
114
115#define _shared_context_awakelocker(a)
116
117#endif
118
Emeric Brunce08baa2012-10-04 17:28:25 +0200119#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
Emeric Brun3e541d12012-09-03 11:14:36 +0200120static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
121{
122 __asm volatile("lock xchgl %0,%1"
123 : "=r" (x), "+m" (*ptr)
124 : "0" (x)
125 : "memory");
126 return x;
127}
128
129static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
130{
131 unsigned int ret;
132
133 __asm volatile("lock cmpxchgl %2,%1"
134 : "=a" (ret), "+m" (*ptr)
135 : "r" (new), "0" (old)
136 : "memory");
137 return ret;
138}
139
140static inline unsigned char atomic_dec(unsigned int *ptr)
141{
142 unsigned char ret;
143 __asm volatile("lock decl %0\n"
144 "setne %1\n"
145 : "+m" (*ptr), "=qm" (ret)
146 :
147 : "memory");
148 return ret;
149}
150
151#else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */
152static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
153{
154 return __sync_lock_test_and_set(ptr, x);
155}
156
157static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
158{
159 return __sync_val_compare_and_swap(ptr, old, new);
160}
161
162static inline unsigned char atomic_dec(unsigned int *ptr)
163{
164 return __sync_sub_and_fetch(ptr, 1) ? 1 : 0;
165}
166
167#endif
168
Emeric Brun4b3091e2012-09-24 15:48:52 +0200169static inline void _shared_context_lock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200170{
171 unsigned int x;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200172 unsigned int count = 4;
Emeric Brun3e541d12012-09-03 11:14:36 +0200173
174 x = cmpxchg(&shctx->waiters, 0, 1);
175 if (x) {
176 if (x != 2)
177 x = xchg(&shctx->waiters, 2);
178
179 while (x) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200180 _shared_context_wait4lock(&count, &shctx->waiters, 2);
Emeric Brun3e541d12012-09-03 11:14:36 +0200181 x = xchg(&shctx->waiters, 2);
182 }
183 }
184}
185
Emeric Brun4b3091e2012-09-24 15:48:52 +0200186static inline void _shared_context_unlock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200187{
188 if (atomic_dec(&shctx->waiters)) {
189 shctx->waiters = 0;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200190 _shared_context_awakelocker(&shctx->waiters);
Emeric Brun3e541d12012-09-03 11:14:36 +0200191 }
192}
193
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200194#define shared_context_lock() if (use_shared_mem) _shared_context_lock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200195
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200196#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200197
Emeric Brun9faf0712012-09-25 11:11:16 +0200198#endif
Emeric Brun3e541d12012-09-03 11:14:36 +0200199
200/* List Macros */
201
Emeric Brunaf9619d2012-11-28 18:47:52 +0100202#define shblock_unset(s) (s)->n->p = (s)->p; \
Emeric Brun3e541d12012-09-03 11:14:36 +0200203 (s)->p->n = (s)->n;
204
Emeric Brunaf9619d2012-11-28 18:47:52 +0100205#define shblock_set_free(s) shblock_unset(s) \
206 (s)->n = &shctx->free; \
207 (s)->p = shctx->free.p; \
208 shctx->free.p->n = s; \
209 shctx->free.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200210
211
Emeric Brunaf9619d2012-11-28 18:47:52 +0100212#define shblock_set_active(s) shblock_unset(s) \
213 (s)->n = &shctx->active; \
214 (s)->p = shctx->active.p; \
215 shctx->active.p->n = s; \
216 shctx->active.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200217
218
Emeric Brun3e541d12012-09-03 11:14:36 +0200219/* Tree Macros */
220
221#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
222
Emeric Brunaf9619d2012-11-28 18:47:52 +0100223#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200224 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
225
Emeric Brunaf9619d2012-11-28 18:47:52 +0100226#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200227 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
228
Emeric Brunaf9619d2012-11-28 18:47:52 +0100229/* shared session functions */
Emeric Brun3e541d12012-09-03 11:14:36 +0200230
Emeric Brunaf9619d2012-11-28 18:47:52 +0100231/* Free session blocks, returns number of freed blocks */
232static int shsess_free(struct shared_session *shsess)
233{
234 struct shared_block *block;
235 int ret = 1;
Emeric Brun3e541d12012-09-03 11:14:36 +0200236
Emeric Brunaf9619d2012-11-28 18:47:52 +0100237 if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
238 shblock_set_free((struct shared_block *)shsess);
239 return ret;
240 }
241 block = ((struct shared_block *)shsess)->n;
242 shblock_set_free((struct shared_block *)shsess);
243 while (1) {
244 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200245
Emeric Brunaf9619d2012-11-28 18:47:52 +0100246 if (block->data_len <= sizeof(block->data)) {
247 /* last block */
248 shblock_set_free(block);
249 ret++;
250 break;
251 }
252 next = block->n;
253 shblock_set_free(block);
254 ret++;
255 block = next;
256 }
257 return ret;
258}
Emeric Brun3e541d12012-09-03 11:14:36 +0200259
Emeric Brunaf9619d2012-11-28 18:47:52 +0100260/* This function frees enough blocks to store a new session of data_len.
261 * Returns a ptr on a free block if it succeeds, or NULL if there are not
262 * enough blocks to store that session.
263 */
264static struct shared_session *shsess_get_next(int data_len)
Emeric Brun3e541d12012-09-03 11:14:36 +0200265{
Emeric Brunaf9619d2012-11-28 18:47:52 +0100266 int head = 0;
267 struct shared_block *b;
268
269 b = shctx->free.n;
270 while (b != &shctx->free) {
271 if (!head) {
272 data_len -= sizeof(b->data.session.data);
273 head = 1;
274 }
275 else
276 data_len -= sizeof(b->data.data);
277 if (data_len <= 0)
278 return &shctx->free.n->data.session;
279 b = b->n;
280 }
281 b = shctx->active.n;
282 while (b != &shctx->active) {
283 int freed;
284
285 shsess_tree_delete(&b->data.session);
286 freed = shsess_free(&b->data.session);
287 if (!head)
288 data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
289 else
290 data_len -= freed*sizeof(b->data.data);
291 if (data_len <= 0)
292 return &shctx->free.n->data.session;
293 b = shctx->active.n;
294 }
295 return NULL;
296}
Emeric Brun3e541d12012-09-03 11:14:36 +0200297
Emeric Brunaf9619d2012-11-28 18:47:52 +0100298/* store a session into the cache
299 * s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
300 * data: asn1 encoded session
301 * data_len: asn1 encoded session length
302 * Returns 1 id session was stored (else 0)
303 */
304static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
305{
306 struct shared_session *shsess, *oldshsess;
307
308 shsess = shsess_get_next(data_len);
309 if (!shsess) {
310 /* Could not retrieve enough free blocks to store that session */
Emeric Brun3e541d12012-09-03 11:14:36 +0200311 return 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100312 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200313
Emeric Brunaf9619d2012-11-28 18:47:52 +0100314 /* prepare key */
315 memcpy(shsess->key_data, s_id, SSL_MAX_SSL_SESSION_ID_LENGTH);
Emeric Brun3e541d12012-09-03 11:14:36 +0200316
Emeric Brunaf9619d2012-11-28 18:47:52 +0100317 /* it returns the already existing node
318 or current node if none, never returns null */
319 oldshsess = shsess_tree_insert(shsess);
320 if (oldshsess != shsess) {
321 /* free all blocks used by old node */
322 shsess_free(oldshsess);
323 shsess = oldshsess;
324 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200325
Emeric Brunaf9619d2012-11-28 18:47:52 +0100326 ((struct shared_block *)shsess)->data_len = data_len;
327 if (data_len <= sizeof(shsess->data)) {
328 /* Store on a single block */
329 memcpy(shsess->data, data, data_len);
330 shblock_set_active((struct shared_block *)shsess);
331 }
332 else {
333 unsigned char *p;
334 /* Store on multiple blocks */
335 int cur_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200336
Emeric Brunaf9619d2012-11-28 18:47:52 +0100337 memcpy(shsess->data, data, sizeof(shsess->data));
338 p = data + sizeof(shsess->data);
339 cur_len = data_len - sizeof(shsess->data);
340 shblock_set_active((struct shared_block *)shsess);
341 while (1) {
342 /* Store next data on free block.
343 * shsess_get_next guarantees that there are enough
344 * free blocks in queue.
345 */
346 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200347
Emeric Brunaf9619d2012-11-28 18:47:52 +0100348 block = shctx->free.n;
349 if (cur_len <= sizeof(block->data)) {
350 /* This is the last block */
351 block->data_len = cur_len;
352 memcpy(block->data.data, p, cur_len);
353 shblock_set_active(block);
354 break;
355 }
356 /* Intermediate block */
357 block->data_len = cur_len;
358 memcpy(block->data.data, p, sizeof(block->data));
359 p += sizeof(block->data.data);
360 cur_len -= sizeof(block->data.data);
361 shblock_set_active(block);
362 }
363 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200364
Emeric Brunaf9619d2012-11-28 18:47:52 +0100365 return 1;
366}
Emeric Brun3e541d12012-09-03 11:14:36 +0200367
Emeric Brun3e541d12012-09-03 11:14:36 +0200368
Emeric Brunaf9619d2012-11-28 18:47:52 +0100369/* SSL context callbacks */
Emeric Brun3e541d12012-09-03 11:14:36 +0200370
Emeric Brunaf9619d2012-11-28 18:47:52 +0100371/* SSL callback used on new session creation */
372int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
373{
William Lallemand2a979662017-09-18 17:37:07 +0200374 unsigned char encsess[SHSESS_MAX_DATA_LEN]; /* encoded session */
375 unsigned char encid[SSL_MAX_SSL_SESSION_ID_LENGTH]; /* encoded id */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100376 unsigned char *p;
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200377 int data_len;
378 unsigned int sid_length, sid_ctx_length;
379 const unsigned char *sid_data;
380 const unsigned char *sid_ctx_data;
Emeric Brun3e541d12012-09-03 11:14:36 +0200381
Emeric Brunaf9619d2012-11-28 18:47:52 +0100382 /* Session id is already stored in to key and session id is known
383 * so we dont store it to keep size.
384 */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200385
386 sid_data = SSL_SESSION_get_id(sess, &sid_length);
387 sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
388 SSL_SESSION_set1_id(sess, sid_data, 0);
389 SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200390
Emeric Brunaf9619d2012-11-28 18:47:52 +0100391 /* check if buffer is large enough for the ASN1 encoded session */
392 data_len = i2d_SSL_SESSION(sess, NULL);
393 if (data_len > SHSESS_MAX_DATA_LEN)
394 goto err;
395
William Lallemand2a979662017-09-18 17:37:07 +0200396 p = encsess;
397
Emeric Brunaf9619d2012-11-28 18:47:52 +0100398 /* process ASN1 session encoding before the lock */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100399 i2d_SSL_SESSION(sess, &p);
400
William Lallemand2a979662017-09-18 17:37:07 +0200401 memcpy(encid, sid_data, sid_length);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100402 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
William Lallemand2a979662017-09-18 17:37:07 +0200403 memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100404
405 shared_context_lock();
406
407 /* store to cache */
William Lallemand2a979662017-09-18 17:37:07 +0200408 shsess_store(encid, encsess, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100409
410 shared_context_unlock();
411
412err:
413 /* reset original length values */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200414 SSL_SESSION_set1_id(sess, sid_data, sid_length);
415 SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
Emeric Brun3e541d12012-09-03 11:14:36 +0200416
417 return 0; /* do not increment session reference count */
418}
419
420/* SSL callback used on lookup an existing session cause none found in internal cache */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200421SSL_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 +0200422{
423 struct shared_session *shsess;
424 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
425 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +0100426 int data_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200427 SSL_SESSION *sess;
Emeric Brun3e541d12012-09-03 11:14:36 +0200428
Willy Tarreauce3f9132014-05-28 16:47:01 +0200429 global.shctx_lookups++;
430
Emeric Brun3e541d12012-09-03 11:14:36 +0200431 /* allow the session to be freed automatically by openssl */
432 *do_copy = 0;
433
434 /* tree key is zeros padded sessionid */
435 if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
436 memcpy(tmpkey, key, key_len);
437 memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
438 key = tmpkey;
439 }
440
441 /* lock cache */
442 shared_context_lock();
443
444 /* lookup for session */
445 shsess = shsess_tree_lookup(key);
446 if (!shsess) {
447 /* no session found: unlock cache and exit */
448 shared_context_unlock();
Willy Tarreauce3f9132014-05-28 16:47:01 +0200449 global.shctx_misses++;
Emeric Brun3e541d12012-09-03 11:14:36 +0200450 return NULL;
451 }
452
Emeric Brunaf9619d2012-11-28 18:47:52 +0100453 data_len = ((struct shared_block *)shsess)->data_len;
454 if (data_len <= sizeof(shsess->data)) {
455 /* Session stored on single block */
456 memcpy(data, shsess->data, data_len);
457 shblock_set_active((struct shared_block *)shsess);
458 }
459 else {
460 /* Session stored on multiple blocks */
461 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200462
Emeric Brunaf9619d2012-11-28 18:47:52 +0100463 memcpy(data, shsess->data, sizeof(shsess->data));
464 p = data + sizeof(shsess->data);
465 block = ((struct shared_block *)shsess)->n;
466 shblock_set_active((struct shared_block *)shsess);
467 while (1) {
468 /* Retrieve data from next block */
469 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200470
Emeric Brunaf9619d2012-11-28 18:47:52 +0100471 if (block->data_len <= sizeof(block->data.data)) {
472 /* This is the last block */
473 memcpy(p, block->data.data, block->data_len);
474 p += block->data_len;
475 shblock_set_active(block);
476 break;
477 }
478 /* Intermediate block */
479 memcpy(p, block->data.data, sizeof(block->data.data));
480 p += sizeof(block->data.data);
481 next = block->n;
482 shblock_set_active(block);
483 block = next;
484 }
485 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200486
487 shared_context_unlock();
488
489 /* decode ASN1 session */
490 p = data;
491 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100492 /* Reset session id and session id contenxt */
493 if (sess) {
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200494 SSL_SESSION_set1_id(sess, key, key_len);
495 SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
Emeric Brunaf9619d2012-11-28 18:47:52 +0100496 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200497
498 return sess;
499}
500
501/* SSL callback used to signal session is no more used in internal cache */
502void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
503{
504 struct shared_session *shsess;
505 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200506 unsigned int sid_length;
507 const unsigned char *sid_data;
Emeric Brun3e541d12012-09-03 11:14:36 +0200508 (void)ctx;
509
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200510 sid_data = SSL_SESSION_get_id(sess, &sid_length);
Emeric Brun3e541d12012-09-03 11:14:36 +0200511 /* tree key is zeros padded sessionid */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200512 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
513 memcpy(tmpkey, sid_data, sid_length);
514 memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
515 sid_data = tmpkey;
Emeric Brun3e541d12012-09-03 11:14:36 +0200516 }
517
518 shared_context_lock();
519
520 /* lookup for session */
Dirkjan Bussink1866d6d2016-08-29 13:26:37 +0200521 shsess = shsess_tree_lookup(sid_data);
Emeric Brun3e541d12012-09-03 11:14:36 +0200522 if (shsess) {
Emeric Brunaf9619d2012-11-28 18:47:52 +0100523 /* free session */
524 shsess_tree_delete(shsess);
525 shsess_free(shsess);
Emeric Brun3e541d12012-09-03 11:14:36 +0200526 }
527
528 /* unlock cache */
529 shared_context_unlock();
530}
531
Emeric Brun3e541d12012-09-03 11:14:36 +0200532/* Allocate shared memory context.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100533 * <size> is maximum cached sessions.
Emeric Brun22890a12012-12-28 14:41:32 +0100534 * If <size> is set to less or equal to 0, ssl cache is disabled.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100535 * Returns: -1 on alloc failure, <size> if it performs context alloc,
536 * and 0 if cache is already allocated.
537 */
Emeric Brun4b3091e2012-09-24 15:48:52 +0200538int shared_context_init(int size, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200539{
540 int i;
Emeric Brun9faf0712012-09-25 11:11:16 +0200541#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200542#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200543 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200544#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200545#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +0100546 struct shared_block *prev,*cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200547 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200548
549 if (shctx)
550 return 0;
551
552 if (size<=0)
Emeric Brun22890a12012-12-28 14:41:32 +0100553 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200554
Emeric Brunaf9619d2012-11-28 18:47:52 +0100555 /* Increate size by one to reserve one node for lookup */
556 size++;
Emeric Brun9faf0712012-09-25 11:11:16 +0200557#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200558 if (shared)
559 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200560#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200561
Emeric Brunaf9619d2012-11-28 18:47:52 +0100562 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_block)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200563 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200564 if (!shctx || shctx == MAP_FAILED) {
565 shctx = NULL;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200566 return SHCTX_E_ALLOC_CACHE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200567 }
568
Emeric Brun9faf0712012-09-25 11:11:16 +0200569#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200570 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200571#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200572 if (pthread_mutexattr_init(&attr)) {
573 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
574 shctx = NULL;
575 return SHCTX_E_INIT_LOCK;
576 }
577
578 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
579 pthread_mutexattr_destroy(&attr);
580 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
581 shctx = NULL;
582 return SHCTX_E_INIT_LOCK;
583 }
584
585 if (pthread_mutex_init(&shctx->mutex, &attr)) {
586 pthread_mutexattr_destroy(&attr);
587 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
588 shctx = NULL;
589 return SHCTX_E_INIT_LOCK;
590 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200591#else
592 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200593#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200594 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200595 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200596#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200597
Emeric Brunaf9619d2012-11-28 18:47:52 +0100598 memset(&shctx->active.data.session.key, 0, sizeof(struct ebmb_node));
599 memset(&shctx->free.data.session.key, 0, sizeof(struct ebmb_node));
Emeric Brun3e541d12012-09-03 11:14:36 +0200600
601 /* No duplicate authorized in tree: */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100602 shctx->active.data.session.key.node.branches = EB_ROOT_UNIQUE;
603
Emeric Brun3e541d12012-09-03 11:14:36 +0200604 cur = &shctx->active;
605 cur->n = cur->p = cur;
606
607 cur = &shctx->free;
608 for (i = 0 ; i < size ; i++) {
609 prev = cur;
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200610 cur++;
Emeric Brun3e541d12012-09-03 11:14:36 +0200611 prev->n = cur;
612 cur->p = prev;
613 }
614 cur->n = &shctx->free;
615 shctx->free.p = cur;
616
617 return size;
618}
619
620
621/* Set session cache mode to server and disable openssl internal cache.
622 * Set shared cache callbacks on an ssl context.
623 * Shared context MUST be firstly initialized */
624void shared_context_set_cache(SSL_CTX *ctx)
625{
Emeric Brun786991e2012-11-26 18:37:12 +0100626 SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
627
Emeric Brun22890a12012-12-28 14:41:32 +0100628 if (!shctx) {
629 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
Emeric Brun3e541d12012-09-03 11:14:36 +0200630 return;
Emeric Brun22890a12012-12-28 14:41:32 +0100631 }
632
633 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
634 SSL_SESS_CACHE_NO_INTERNAL |
635 SSL_SESS_CACHE_NO_AUTO_CLEAR);
Emeric Brun3e541d12012-09-03 11:14:36 +0200636
637 /* Set callbacks */
638 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
639 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
640 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
641}