Session resume broken switching contexts
[openssl.git] / ssl / ssl_sess.c
index dcdf4f6..98d6106 100644 (file)
@@ -305,16 +305,94 @@ static int def_generate_session_id(SSL *ssl, unsigned char *id,
     return 0;
 }
 
+int ssl_generate_session_id(SSL *s, SSL_SESSION *ss)
+{
+    unsigned int tmp;
+    GEN_SESSION_CB cb = def_generate_session_id;
+
+    switch (s->version) {
+    case SSL3_VERSION:
+    case TLS1_VERSION:
+    case TLS1_1_VERSION:
+    case TLS1_2_VERSION:
+    case TLS1_3_VERSION:
+    case DTLS1_BAD_VER:
+    case DTLS1_VERSION:
+    case DTLS1_2_VERSION:
+        ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+        break;
+    default:
+        SSLerr(SSL_F_SSL_GENERATE_SESSION_ID, SSL_R_UNSUPPORTED_SSL_VERSION);
+        return 0;
+    }
+
+    /*-
+     * If RFC5077 ticket, use empty session ID (as server).
+     * Note that:
+     * (a) ssl_get_prev_session() does lookahead into the
+     *     ClientHello extensions to find the session ticket.
+     *     When ssl_get_prev_session() fails, statem_srvr.c calls
+     *     ssl_get_new_session() in tls_process_client_hello().
+     *     At that point, it has not yet parsed the extensions,
+     *     however, because of the lookahead, it already knows
+     *     whether a ticket is expected or not.
+     *
+     * (b) statem_clnt.c calls ssl_get_new_session() before parsing
+     *     ServerHello extensions, and before recording the session
+     *     ID received from the server, so this block is a noop.
+     */
+    if (s->ext.ticket_expected) {
+        ss->session_id_length = 0;
+        return 1;
+    }
+
+    /* Choose which callback will set the session ID */
+    CRYPTO_THREAD_read_lock(s->lock);
+    CRYPTO_THREAD_read_lock(s->session_ctx->lock);
+    if (s->generate_session_id)
+        cb = s->generate_session_id;
+    else if (s->session_ctx->generate_session_id)
+        cb = s->session_ctx->generate_session_id;
+    CRYPTO_THREAD_unlock(s->session_ctx->lock);
+    CRYPTO_THREAD_unlock(s->lock);
+    /* Choose a session ID */
+    memset(ss->session_id, 0, ss->session_id_length);
+    tmp = (int)ss->session_id_length;
+    if (!cb(s, ss->session_id, &tmp)) {
+        /* The callback failed */
+        SSLerr(SSL_F_SSL_GENERATE_SESSION_ID,
+               SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
+        return 0;
+    }
+    /*
+     * Don't allow the callback to set the session length to zero. nor
+     * set it higher than it was.
+     */
+    if (tmp == 0 || tmp > ss->session_id_length) {
+        /* The callback set an illegal length */
+        SSLerr(SSL_F_SSL_GENERATE_SESSION_ID,
+               SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
+        return 0;
+    }
+    ss->session_id_length = tmp;
+    /* Finally, check for a conflict */
+    if (SSL_has_matching_session_id(s, ss->session_id,
+                                    (unsigned int)ss->session_id_length)) {
+        SSLerr(SSL_F_SSL_GENERATE_SESSION_ID, SSL_R_SSL_SESSION_ID_CONFLICT);
+        return 0;
+    }
+
+    return 1;
+}
+
 int ssl_get_new_session(SSL *s, int session)
 {
     /* This gets used by clients and servers. */
 
-    unsigned int tmp;
     SSL_SESSION *ss = NULL;
-    GEN_SESSION_CB cb = def_generate_session_id;
 
     if ((ss = SSL_SESSION_new()) == NULL)
-        return (0);
+        return 0;
 
     /* If the context has a default timeout, use it */
     if (s->session_ctx->session_timeout == 0)
@@ -326,96 +404,11 @@ int ssl_get_new_session(SSL *s, int session)
     s->session = NULL;
 
     if (session) {
-        if (s->version == SSL3_VERSION) {
-            ss->ssl_version = SSL3_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == TLS1_VERSION) {
-            ss->ssl_version = TLS1_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == TLS1_1_VERSION) {
-            ss->ssl_version = TLS1_1_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == TLS1_2_VERSION) {
-            ss->ssl_version = TLS1_2_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == TLS1_3_VERSION) {
-            ss->ssl_version = TLS1_3_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == DTLS1_BAD_VER) {
-            ss->ssl_version = DTLS1_BAD_VER;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == DTLS1_VERSION) {
-            ss->ssl_version = DTLS1_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else if (s->version == DTLS1_2_VERSION) {
-            ss->ssl_version = DTLS1_2_VERSION;
-            ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
-        } else {
-            SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION);
+        if (!ssl_generate_session_id(s, ss)) {
             SSL_SESSION_free(ss);
-            return (0);
-        }
-
-        /*-
-         * If RFC5077 ticket, use empty session ID (as server).
-         * Note that:
-         * (a) ssl_get_prev_session() does lookahead into the
-         *     ClientHello extensions to find the session ticket.
-         *     When ssl_get_prev_session() fails, statem_srvr.c calls
-         *     ssl_get_new_session() in tls_process_client_hello().
-         *     At that point, it has not yet parsed the extensions,
-         *     however, because of the lookahead, it already knows
-         *     whether a ticket is expected or not.
-         *
-         * (b) statem_clnt.c calls ssl_get_new_session() before parsing
-         *     ServerHello extensions, and before recording the session
-         *     ID received from the server, so this block is a noop.
-         */
-        if (s->ext.ticket_expected) {
-            ss->session_id_length = 0;
-            goto sess_id_done;
-        }
-
-        /* Choose which callback will set the session ID */
-        CRYPTO_THREAD_read_lock(s->lock);
-        CRYPTO_THREAD_read_lock(s->session_ctx->lock);
-        if (s->generate_session_id)
-            cb = s->generate_session_id;
-        else if (s->session_ctx->generate_session_id)
-            cb = s->session_ctx->generate_session_id;
-        CRYPTO_THREAD_unlock(s->session_ctx->lock);
-        CRYPTO_THREAD_unlock(s->lock);
-        /* Choose a session ID */
-        memset(ss->session_id, 0, ss->session_id_length);
-        tmp = (int)ss->session_id_length;
-        if (!cb(s, ss->session_id, &tmp)) {
-            /* The callback failed */
-            SSLerr(SSL_F_SSL_GET_NEW_SESSION,
-                   SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
-            SSL_SESSION_free(ss);
-            return (0);
-        }
-        /*
-         * Don't allow the callback to set the session length to zero. nor
-         * set it higher than it was.
-         */
-        if (tmp == 0 || tmp > ss->session_id_length) {
-            /* The callback set an illegal length */
-            SSLerr(SSL_F_SSL_GET_NEW_SESSION,
-                   SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
-            SSL_SESSION_free(ss);
-            return (0);
-        }
-        ss->session_id_length = tmp;
-        /* Finally, check for a conflict */
-        if (SSL_has_matching_session_id(s, ss->session_id,
-                                        (unsigned int)ss->session_id_length)) {
-            SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_SSL_SESSION_ID_CONFLICT);
-            SSL_SESSION_free(ss);
-            return (0);
+            return 0;
         }
 
- sess_id_done:
         if (s->ext.hostname) {
             ss->ext.hostname = OPENSSL_strdup(s->ext.hostname);
             if (ss->ext.hostname == NULL) {
@@ -443,7 +436,7 @@ int ssl_get_new_session(SSL *s, int session)
     if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS)
         ss->flags |= SSL_SESS_FLAG_EXTMS;
 
-    return (1);
+    return 1;
 }
 
 /*-