give more meaningful error if presented with wrong certificate type by server
[openssl.git] / ssl / ssl_sess.c
index cbb7e7035210f1112e83445197c00ef51ee7e6e6..6cd17679bb34201a5c2783add22f54cf33bd9891 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
@@ -388,32 +393,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
@@ -436,6 +415,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)
        {
@@ -443,27 +441,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;
@@ -474,20 +484,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++;
 
@@ -506,23 +518,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 */
                }
        
@@ -559,39 +566,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
@@ -735,6 +741,8 @@ void SSL_SESSION_free(SSL_SESSION *ss)
        ss->tlsext_ellipticcurvelist_length = 0;
        if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
 #endif /* OPENSSL_NO_EC */
+       if (ss->audit_proof != NULL) OPENSSL_free(ss->audit_proof);
+       ss->audit_proof_length = 0;
 #endif
 #ifndef OPENSSL_NO_PSK
        if (ss->psk_identity_hint != NULL)
@@ -770,10 +778,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
@@ -841,16 +845,6 @@ long SSL_SESSION_set_time(SSL_SESSION *s, long t)
        return(t);
        }
 
-unsigned int SSL_SESSION_get_id_len(SSL_SESSION *s)
-       {
-       return s->session_id_length;
-       }
-
-const unsigned char *SSL_SESSION_get0_id(SSL_SESSION *s)
-       {
-       return s->session_id;
-       }
-
 X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
        {
        return s->peer;
@@ -858,17 +852,26 @@ X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
 
 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;
+       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;
        }
-    s->sid_ctx_length=sid_ctx_len;
-    memcpy(s->sid_ctx,sid_ctx,sid_ctx_len);
 
-    return 1;
-    }
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s, size_t *proof_length)
+       {
+       if (s->audit_proof != NULL)
+               *proof_length = s->audit_proof_length;
+       return s->audit_proof;
+       }
+#endif
 
 long SSL_CTX_set_timeout(SSL_CTX *s, long t)
        {