REORG: shctx: move ssl functions to ssl_sock.c
Move the ssl callback functions of the ssl shared session cache to
ssl_sock.c. The shctx functions still needs to be separated of the ssl
tree and data.
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 24e4f21..71bcbe3 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3718,6 +3718,191 @@
return cfgerr;
}
+/* SSL context callbacks */
+
+/* SSL callback used on new session creation */
+int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
+{
+ unsigned char encsess[SHSESS_MAX_DATA_LEN]; /* encoded session */
+ unsigned char encid[SSL_MAX_SSL_SESSION_ID_LENGTH]; /* encoded id */
+ unsigned char *p;
+ int data_len;
+ unsigned int sid_length, sid_ctx_length;
+ const unsigned char *sid_data;
+ const unsigned char *sid_ctx_data;
+
+ /* Session id is already stored in to key and session id is known
+ * so we dont store it to keep size.
+ */
+
+ sid_data = SSL_SESSION_get_id(sess, &sid_length);
+ sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
+ SSL_SESSION_set1_id(sess, sid_data, 0);
+ SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
+
+ /* check if buffer is large enough for the ASN1 encoded session */
+ data_len = i2d_SSL_SESSION(sess, NULL);
+ if (data_len > SHSESS_MAX_DATA_LEN)
+ goto err;
+
+ p = encsess;
+
+ /* process ASN1 session encoding before the lock */
+ i2d_SSL_SESSION(sess, &p);
+
+ memcpy(encid, sid_data, sid_length);
+ if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
+ memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
+
+ shared_context_lock(ssl_shctx);
+
+ /* store to cache */
+ shsess_store(ssl_shctx, encid, encsess, data_len);
+
+ shared_context_unlock(ssl_shctx);
+
+err:
+ /* reset original length values */
+ SSL_SESSION_set1_id(sess, sid_data, sid_length);
+ SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
+
+ return 0; /* do not increment session reference count */
+}
+
+/* SSL callback used on lookup an existing session cause none found in internal cache */
+SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, int key_len, int *do_copy)
+{
+ struct shared_session *shsess;
+ unsigned char data[SHSESS_MAX_DATA_LEN], *p;
+ unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
+ int data_len;
+ SSL_SESSION *sess;
+
+ global.shctx_lookups++;
+
+ /* allow the session to be freed automatically by openssl */
+ *do_copy = 0;
+
+ /* tree key is zeros padded sessionid */
+ if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ memcpy(tmpkey, key, key_len);
+ memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
+ key = tmpkey;
+ }
+
+ /* lock cache */
+ shared_context_lock(ssl_shctx);
+
+ /* lookup for session */
+ shsess = shsess_tree_lookup(ssl_shctx, key);
+ if (!shsess) {
+ /* no session found: unlock cache and exit */
+ shared_context_unlock(ssl_shctx);
+ global.shctx_misses++;
+ return NULL;
+ }
+
+ data_len = ((struct shared_block *)shsess)->data_len;
+ if (data_len <= sizeof(shsess->data)) {
+ /* Session stored on single block */
+ memcpy(data, shsess->data, data_len);
+ shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
+ }
+ else {
+ /* Session stored on multiple blocks */
+ struct shared_block *block;
+
+ memcpy(data, shsess->data, sizeof(shsess->data));
+ p = data + sizeof(shsess->data);
+ block = ((struct shared_block *)shsess)->n;
+ shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
+ while (1) {
+ /* Retrieve data from next block */
+ struct shared_block *next;
+
+ if (block->data_len <= sizeof(block->data.data)) {
+ /* This is the last block */
+ memcpy(p, block->data.data, block->data_len);
+ p += block->data_len;
+ shblock_set_active(ssl_shctx, block);
+ break;
+ }
+ /* Intermediate block */
+ memcpy(p, block->data.data, sizeof(block->data.data));
+ p += sizeof(block->data.data);
+ next = block->n;
+ shblock_set_active(ssl_shctx, block);
+ block = next;
+ }
+ }
+
+ shared_context_unlock(ssl_shctx);
+
+ /* decode ASN1 session */
+ p = data;
+ sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
+ /* Reset session id and session id contenxt */
+ if (sess) {
+ SSL_SESSION_set1_id(sess, key, key_len);
+ SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
+ }
+
+ return sess;
+}
+
+/* SSL callback used to signal session is no more used in internal cache */
+void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ struct shared_session *shsess;
+ unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
+ unsigned int sid_length;
+ const unsigned char *sid_data;
+ (void)ctx;
+
+ sid_data = SSL_SESSION_get_id(sess, &sid_length);
+ /* tree key is zeros padded sessionid */
+ if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ memcpy(tmpkey, sid_data, sid_length);
+ memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
+ sid_data = tmpkey;
+ }
+
+ shared_context_lock(ssl_shctx);
+
+ /* lookup for session */
+ shsess = shsess_tree_lookup(ssl_shctx, sid_data);
+ if (shsess) {
+ /* free session */
+ shsess_tree_delete(shsess);
+ shsess_free(ssl_shctx, shsess);
+ }
+
+ /* unlock cache */
+ shared_context_unlock(ssl_shctx);
+}
+
+/* Set session cache mode to server and disable openssl internal cache.
+ * Set shared cache callbacks on an ssl context.
+ * Shared context MUST be firstly initialized */
+void shared_context_set_cache(SSL_CTX *ctx)
+{
+ SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
+
+ if (!ssl_shctx) {
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+ return;
+ }
+
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
+ SSL_SESS_CACHE_NO_INTERNAL |
+ SSL_SESS_CACHE_NO_AUTO_CLEAR);
+
+ /* Set callbacks */
+ SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
+ SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
+ SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
+}
+
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf, SSL_CTX *ctx)
{
struct proxy *curproxy = bind_conf->frontend;