DTLS/SCTP Finished Auth Bug
[openssl.git] / ssl / ssl_sess.c
index a3ce6525ee6956b48d578a4fc7ce41cc3b74573e..73d87fd6c1a3c3088606370d04e04d1473b2fb62 100644 (file)
@@ -231,6 +231,11 @@ const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
        return s->session_id;
        }
 
+unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s)
+       {
+       return s->compress_meth;
+       }
+
 /* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1
  * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly
  * until we have no conflict is going to complete in one iteration pretty much
@@ -308,6 +313,11 @@ int ssl_get_new_session(SSL *s, int session)
                        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 == DTLS1_BAD_VER)
                        {
                        ss->ssl_version=DTLS1_BAD_VER;
@@ -318,6 +328,11 @@ int ssl_get_new_session(SSL *s, int session)
                        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);
@@ -383,32 +398,6 @@ int ssl_get_new_session(SSL *s, int session)
                                return 0;
                                }
                        }
-#ifndef OPENSSL_NO_EC
-               if (s->tlsext_ecpointformatlist)
-                       {
-                       if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
-                       if ((ss->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
-                               {
-                               SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE);
-                               SSL_SESSION_free(ss);
-                               return 0;
-                               }
-                       ss->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
-                       memcpy(ss->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
-                       }
-               if (s->tlsext_ellipticcurvelist)
-                       {
-                       if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
-                       if ((ss->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
-                               {
-                               SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE);
-                               SSL_SESSION_free(ss);
-                               return 0;
-                               }
-                       ss->tlsext_ellipticcurvelist_length = s->tlsext_ellipticcurvelist_length;
-                       memcpy(ss->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
-                       }
-#endif
 #endif
                }
        else
@@ -431,6 +420,25 @@ int ssl_get_new_session(SSL *s, int session)
        return(1);
        }
 
+/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
+ * connection. It is only called by servers.
+ *
+ *   session_id: points at the session ID in the ClientHello. This code will
+ *       read past the end of this in order to parse out the session ticket
+ *       extension, if any.
+ *   len: the length of the session ID.
+ *   limit: a pointer to the first byte after the ClientHello.
+ *
+ * Returns:
+ *   -1: error
+ *    0: a session may have been found.
+ *
+ * Side effects:
+ *   - If a session is found then s->session is pointed at it (after freeing an
+ *     existing session if need be) and s->verify_result is set from the session.
+ *   - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1
+ *     if the server should issue a new session ticket (to 0 otherwise).
+ */
 int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
                        const unsigned char *limit)
        {
@@ -438,27 +446,39 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
 
        SSL_SESSION *ret=NULL;
        int fatal = 0;
+       int try_session_cache = 1;
 #ifndef OPENSSL_NO_TLSEXT
        int r;
 #endif
 
        if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
                goto err;
+
+       if (len == 0)
+               try_session_cache = 0;
+
 #ifndef OPENSSL_NO_TLSEXT
-       r = tls1_process_ticket(s, session_id, len, limit, &ret);
-       if (r == -1)
+       r = tls1_process_ticket(s, session_id, len, limit, &ret); /* sets s->tlsext_ticket_expected */
+       switch (r)
                {
+       case -1: /* Error during processing */
                fatal = 1;
                goto err;
+       case 0: /* No ticket found */
+       case 1: /* Zero length ticket found */
+               break; /* Ok to carry on processing session id. */
+       case 2: /* Ticket found but not decrypted. */
+       case 3: /* Ticket decrypted, *ret has been set. */
+               try_session_cache = 0;
+               break;
+       default:
+               abort();
                }
-       else if (r == 0 || (!ret && !len))
-               goto err;
-       else if (!ret && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
-#else
-       if (len == 0)
-               goto err;
-       if (!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
 #endif
+
+       if (try_session_cache &&
+           ret == NULL &&
+           !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
                {
                SSL_SESSION data;
                data.ssl_version=s->version;
@@ -469,20 +489,22 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
                CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
                ret=lh_SSL_SESSION_retrieve(s->session_ctx->sessions,&data);
                if (ret != NULL)
-                   /* don't allow other threads to steal it: */
-                   CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
+                       {
+                       /* don't allow other threads to steal it: */
+                       CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
+                       }
                CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+               if (ret == NULL)
+                       s->session_ctx->stats.sess_miss++;
                }
 
-       if (ret == NULL)
+       if (try_session_cache &&
+           ret == NULL &&
+           s->session_ctx->get_session_cb != NULL)
                {
                int copy=1;
        
-               s->session_ctx->stats.sess_miss++;
-               ret=NULL;
-               if (s->session_ctx->get_session_cb != NULL
-                   && (ret=s->session_ctx->get_session_cb(s,session_id,len,&copy))
-                      != NULL)
+               if ((ret=s->session_ctx->get_session_cb(s,session_id,len,&copy)))
                        {
                        s->session_ctx->stats.sess_cb_hit++;
 
@@ -501,23 +523,18 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
                                 * things are very strange */
                                SSL_CTX_add_session(s->session_ctx,ret);
                        }
-               if (ret == NULL)
-                       goto err;
                }
 
-       /* Now ret is non-NULL, and we own one of its reference counts. */
+       if (ret == NULL)
+               goto err;
+
+       /* Now ret is non-NULL and we own one of its reference counts. */
 
        if (ret->sid_ctx_length != s->sid_ctx_length
            || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))
                {
-               /* We've found the session named by the client, but we don't
+               /* We have the session requested by the client, but we don't
                 * want to use it in this context. */
-
-#if 0 /* The client cannot always know when a session is not appropriate,
-       * so we shouldn't generate an error message. */
-
-               SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
-#endif
                goto err; /* treat like cache miss */
                }
        
@@ -554,39 +571,38 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
                        goto err;
                }
 
-
-#if 0 /* This is way too late. */
-
-       /* If a thread got the session, then 'swaped', and another got
-        * it and then due to a time-out decided to 'OPENSSL_free' it we could
-        * be in trouble.  So I'll increment it now, then double decrement
-        * later - am I speaking rubbish?. */
-       CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
-#endif
-
        if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */
                {
                s->session_ctx->stats.sess_timeout++;
-               /* remove it from the cache */
-               SSL_CTX_remove_session(s->session_ctx,ret);
+               if (try_session_cache)
+                       {
+                       /* session was from the cache, so remove it */
+                       SSL_CTX_remove_session(s->session_ctx,ret);
+                       }
                goto err;
                }
 
        s->session_ctx->stats.sess_hit++;
 
-       /* ret->time=time(NULL); */ /* rezero timeout? */
-       /* again, just leave the session 
-        * if it is the same session, we have just incremented and
-        * then decremented the reference count :-) */
        if (s->session != NULL)
                SSL_SESSION_free(s->session);
        s->session=ret;
        s->verify_result = s->session->verify_result;
-       return(1);
+       return 1;
 
  err:
        if (ret != NULL)
+               {
                SSL_SESSION_free(ret);
+#ifndef OPENSSL_NO_TLSEXT
+               if (!try_session_cache)
+                       {
+                       /* The session was from a ticket, so we should
+                        * issue a ticket for the new session */
+                       s->tlsext_ticket_expected = 1;
+                       }
+#endif
+               }
        if (fatal)
                return -1;
        else
@@ -765,10 +781,6 @@ int SSL_set_session(SSL *s, SSL_SESSION *session)
                        {
                        if (!SSL_set_ssl_method(s,meth))
                                return(0);
-                       if (s->ctx->session_timeout == 0)
-                               session->timeout=SSL_get_default_timeout(s);
-                       else
-                               session->timeout=s->ctx->session_timeout;
                        }
 
 #ifndef OPENSSL_NO_KRB5
@@ -836,6 +848,25 @@ long SSL_SESSION_set_time(SSL_SESSION *s, long t)
        return(t);
        }
 
+X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
+       {
+       return s->peer;
+       }
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
+                              unsigned int sid_ctx_len)
+       {
+       if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
+               {
+               SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+               return 0;
+               }
+       s->sid_ctx_length=sid_ctx_len;
+       memcpy(s->sid_ctx,sid_ctx,sid_ctx_len);
+
+       return 1;
+       }
+
 long SSL_CTX_set_timeout(SSL_CTX *s, long t)
        {
        long l;