]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: SSL: Store the ASN1 representation of client sessions.
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 16 Nov 2017 16:42:52 +0000 (17:42 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 16 Nov 2017 18:03:32 +0000 (19:03 +0100)
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.

include/types/server.h
src/ssl_sock.c

index adedca43cd460a1bead9881ae9dd3eaba8d8160c..d22f05ac626cc8ddc282e3290ff92268f2d40fb3 100644 (file)
@@ -274,7 +274,11 @@ struct server {
        char *sni_expr;             /* Temporary variable to store a sample expression for SNI */
        struct {
                SSL_CTX *ctx;
-               SSL_SESSION **reused_sess;
+               struct {
+                       unsigned char *ptr;
+                       int size;
+                       int allocated_size;
+               } * reused_sess;
                char *ciphers;                  /* cipher suite to use if non-null */
                int options;                    /* ssl options */
                struct tls_version_filter methods;      /* ssl methods */
index 25f3ecaaffecd68ed2d163272859cfcfa8bf9dac..c652d0adbb806c5274ceb4607a4c88eb7b193a9e 100644 (file)
@@ -3855,19 +3855,35 @@ static int sh_ssl_sess_store(unsigned char *s_id, unsigned char *data, int data_
 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 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
 
        /* 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 @@ static int ssl_sock_init(struct connection *conn)
                }
 
                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 @@ reneg_ok:
        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 */