Don't do version neg on an HRR
[openssl.git] / ssl / ssl_sess.c
index a1d20131878a9a5dc77303927a24dd344ddbb521..8e37025e438abae9957fe716532243bc67af2fca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright 2005 Nokia. All rights reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
@@ -9,9 +9,9 @@
  */
 
 #include <stdio.h>
-#include <openssl/lhash.h>
 #include <openssl/rand.h>
 #include <openssl/engine.h>
+#include "internal/refcount.h"
 #include "ssl_locl.h"
 #include "statem/statem_locl.h"
 
@@ -93,6 +93,11 @@ SSL_SESSION *SSL_SESSION_new(void)
     return ss;
 }
 
+SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *src)
+{
+    return ssl_session_dup(src, 1);
+}
+
 /*
  * Create a new SSL_SESSION and duplicate the contents of |src| into it. If
  * ticket == 0 then no ticket information is duplicated, otherwise it is.
@@ -277,12 +282,12 @@ unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s)
  */
 
 #define MAX_SESS_ID_ATTEMPTS 10
-static int def_generate_session_id(const SSL *ssl, unsigned char *id,
+static int def_generate_session_id(SSL *ssl, unsigned char *id,
                                    unsigned int *id_len)
 {
     unsigned int retry = 0;
     do
-        if (RAND_bytes(id, *id_len) <= 0)
+        if (ssl_randbytes(ssl, id, *id_len) <= 0)
             return 0;
     while (SSL_has_matching_session_id(ssl, id, *id_len) &&
            (++retry < MAX_SESS_ID_ATTEMPTS)) ;
@@ -300,16 +305,94 @@ static int def_generate_session_id(const 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)
@@ -321,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);
-            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);
+        if (!ssl_generate_session_id(s, ss)) {
             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) {
@@ -438,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;
 }
 
 /*-
@@ -486,7 +484,8 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello, int *al)
             goto err;
         case TICKET_NONE:
         case TICKET_EMPTY:
-            try_session_cache = 1;
+            if (hello->session_id_len > 0)
+                try_session_cache = 1;
             break;
         case TICKET_NO_DECRYPT:
         case TICKET_SUCCESS:
@@ -545,11 +544,11 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello, int *al)
                 (s->session_ctx->session_cache_mode &
                  SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
                 /*
-                 * The following should not return 1, otherwise, things are
-                 * very strange
+                 * Either return value of SSL_CTX_add_session should not
+                 * interrupt the session resumption process. The return
+                 * value is intentionally ignored.
                  */
-                if (SSL_CTX_add_session(s->session_ctx, ret))
-                    goto err;
+                SSL_CTX_add_session(s->session_ctx, ret);
             }
         }
     }
@@ -847,7 +846,7 @@ long SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
     if (s == NULL)
         return (0);
     s->timeout = t;
-    return (1);
+    return 1;
 }
 
 long SSL_SESSION_get_timeout(const SSL_SESSION *s)
@@ -899,6 +898,18 @@ const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s)
     return s->ext.hostname;
 }
 
+int SSL_SESSION_set1_hostname(SSL_SESSION *s, const char *hostname)
+{
+    OPENSSL_free(s->ext.hostname);
+    if (hostname == NULL) {
+        s->ext.hostname = NULL;
+        return 1;
+    }
+    s->ext.hostname = OPENSSL_strdup(hostname);
+
+    return s->ext.hostname != NULL;
+}
+
 int SSL_SESSION_has_ticket(const SSL_SESSION *s)
 {
     return (s->ext.ticklen > 0) ? 1 : 0;
@@ -922,6 +933,40 @@ uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s)
     return s->ext.max_early_data;
 }
 
+int SSL_SESSION_set_max_early_data(SSL_SESSION *s, uint32_t max_early_data)
+{
+    s->ext.max_early_data = max_early_data;
+
+    return 1;
+}
+
+void SSL_SESSION_get0_alpn_selected(const SSL_SESSION *s,
+                                    const unsigned char **alpn,
+                                    size_t *len)
+{
+    *alpn = s->ext.alpn_selected;
+    *len = s->ext.alpn_selected_len;
+}
+
+int SSL_SESSION_set1_alpn_selected(SSL_SESSION *s, const unsigned char *alpn,
+                                   size_t len)
+{
+    OPENSSL_free(s->ext.alpn_selected);
+    if (alpn == NULL || len == 0) {
+        s->ext.alpn_selected = NULL;
+        s->ext.alpn_selected_len = 0;
+        return 1;
+    }
+    s->ext.alpn_selected = OPENSSL_memdup(alpn, len);
+    if (s->ext.alpn_selected == NULL) {
+        s->ext.alpn_selected_len = 0;
+        return 0;
+    }
+    s->ext.alpn_selected_len = len;
+
+    return 1;
+}
+
 X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
 {
     return s->peer;
@@ -977,7 +1022,7 @@ int SSL_set_session_secret_cb(SSL *s,
         return (0);
     s->ext.session_secret_cb = tls_session_secret_cb;
     s->ext.session_secret_cb_arg = arg;
-    return (1);
+    return 1;
 }
 
 int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
@@ -987,7 +1032,7 @@ int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
         return (0);
     s->ext.session_ticket_cb = cb;
     s->ext.session_ticket_cb_arg = arg;
-    return (1);
+    return 1;
 }
 
 int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
@@ -1065,7 +1110,7 @@ int ssl_clear_bad_session(SSL *s)
         !(s->shutdown & SSL_SENT_SHUTDOWN) &&
         !(SSL_in_init(s) || SSL_in_before(s))) {
         SSL_CTX_remove_session(s->session_ctx, s->session);
-        return (1);
+        return 1;
     } else
         return (0);
 }