MINOR: SSL: Store the ASN1 representation of client sessions.
Instead of storing the SSL_SESSION pointer directly in the struct server,
store the ASN1 representation, otherwise, session resumption is broken with
TLS 1.3, when multiple outgoing connections want to use the same session.
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 25f3eca..c652d0a 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3855,19 +3855,35 @@
static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess)
{
struct connection *conn = SSL_get_app_data(ssl);
+ struct server *s;
- /* check if session was reused, if not store current session on server for reuse */
- if (objt_server(conn->target)->ssl_ctx.reused_sess[tid]) {
- SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess[tid]);
- objt_server(conn->target)->ssl_ctx.reused_sess[tid] = NULL;
- }
+ s = objt_server(conn->target);
- if (!(objt_server(conn->target)->ssl_ctx.options & SRV_SSL_O_NO_REUSE))
- objt_server(conn->target)->ssl_ctx.reused_sess[tid] = SSL_get1_session(conn->xprt_ctx);
+ if (!(s->ssl_ctx.options & SRV_SSL_O_NO_REUSE)) {
+ int len;
+ unsigned char *ptr;
- return 1;
+ len = i2d_SSL_SESSION(sess, NULL);
+ if (s->ssl_ctx.reused_sess[tid].ptr && s->ssl_ctx.reused_sess[tid].allocated_size >= len) {
+ ptr = s->ssl_ctx.reused_sess[tid].ptr;
+ } else {
+ free(s->ssl_ctx.reused_sess[tid].ptr);
+ ptr = s->ssl_ctx.reused_sess[tid].ptr = malloc(len);
+ s->ssl_ctx.reused_sess[tid].allocated_size = len;
+ }
+ if (s->ssl_ctx.reused_sess[tid].ptr) {
+ s->ssl_ctx.reused_sess[tid].size = i2d_SSL_SESSION(sess,
+ &ptr);
+ }
+ } else {
+ free(s->ssl_ctx.reused_sess[tid].ptr);
+ s->ssl_ctx.reused_sess[tid].ptr = NULL;
+ }
+
+ return 0;
}
+
/* SSL callback used on new session creation */
int sh_ssl_sess_new_cb(SSL *ssl, SSL_SESSION *sess)
{
@@ -4433,7 +4449,7 @@
/* Initiate SSL context for current server */
if (!srv->ssl_ctx.reused_sess) {
- if ((srv->ssl_ctx.reused_sess = calloc(1, global.nbthread*sizeof(SSL_SESSION*))) == NULL) {
+ if ((srv->ssl_ctx.reused_sess = calloc(1, global.nbthread*sizeof(*srv->ssl_ctx.reused_sess))) == NULL) {
Alert("Proxy '%s', server '%s' [%s:%d] out of memory.\n",
curproxy->id, srv->id,
srv->conf.file, srv->conf.line);
@@ -4922,10 +4938,15 @@
}
SSL_set_connect_state(conn->xprt_ctx);
- if (objt_server(conn->target)->ssl_ctx.reused_sess) {
- if(!SSL_set_session(conn->xprt_ctx, objt_server(conn->target)->ssl_ctx.reused_sess[tid])) {
- SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess[tid]);
- objt_server(conn->target)->ssl_ctx.reused_sess[tid] = NULL;
+ if (objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr) {
+ const unsigned char *ptr = objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr;
+ SSL_SESSION *sess = d2i_SSL_SESSION(NULL, &ptr, objt_server(conn->target)->ssl_ctx.reused_sess[tid].size);
+ if(sess && !SSL_set_session(conn->xprt_ctx, sess)) {
+ SSL_SESSION_free(sess);
+ free(objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr);
+ objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr = NULL;
+ } else if (sess) {
+ SSL_SESSION_free(sess);
}
}
@@ -5260,9 +5281,9 @@
ERR_clear_error();
/* free resumed session if exists */
- if (objt_server(conn->target) && objt_server(conn->target)->ssl_ctx.reused_sess[tid]) {
- SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess[tid]);
- objt_server(conn->target)->ssl_ctx.reused_sess[tid] = NULL;
+ if (objt_server(conn->target) && objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr) {
+ free(objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr);
+ objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr = NULL;
}
/* Fail on all other handshake errors */