Fix for CVE-2014-0224
[openssl.git] / ssl / s3_clnt.c
index 7791b145088dc161b6add06453a183c8afdbc612..af2960027c36d6a891bd4002dd308d110a3c5219 100644 (file)
 
 static SSL_METHOD *ssl3_get_client_method(int ver);
 static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
-#ifndef OPENSSL_NO_TLSEXT
-static int ssl3_check_finished(SSL *s);
-#endif
 
 #ifndef OPENSSL_NO_ECDH
 static int curve_id2nid(int curve_id);
@@ -169,8 +166,7 @@ IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
 int ssl3_connect(SSL *s)
        {
        BUF_MEM *buf=NULL;
-       unsigned long Time=(unsigned long)time(NULL),l;
-       long num1;
+       unsigned long Time=(unsigned long)time(NULL);
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
        int ret= -1;
        int new_state,state,skip=0;
@@ -266,7 +262,16 @@ int ssl3_connect(SSL *s)
                        ret=ssl3_get_server_hello(s);
                        if (ret <= 0) goto end;
                        if (s->hit)
+                               {
                                s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+                               if (s->tlsext_ticket_expected)
+                                       {
+                                       /* receive renewed session ticket */
+                                       s->state=SSL3_ST_CR_SESSION_TICKET_A;
+                                       }
+#endif
+                               }
                        else
                                s->state=SSL3_ST_CR_CERT_A;
                        s->init_num=0;
@@ -364,7 +369,6 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CW_KEY_EXCH_B:
                        ret=ssl3_send_client_key_exchange(s);
                        if (ret <= 0) goto end;
-                       l=s->s3->tmp.new_cipher->algorithms;
                        /* EAY EAY EAY need to check for DH fix cert
                         * sent back */
                        /* For TLS, cert_req is set to 2, so a cert chain
@@ -487,6 +491,7 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CR_FINISHED_A:
                case SSL3_ST_CR_FINISHED_B:
 
+                       s->s3->flags |= SSL3_FLAGS_CCS_OK;
                        ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
                                SSL3_ST_CR_FINISHED_B);
                        if (ret <= 0) goto end;
@@ -499,16 +504,13 @@ int ssl3_connect(SSL *s)
                        break;
 
                case SSL3_ST_CW_FLUSH:
-                       /* number of bytes to be flushed */
-                       num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
-                       if (num1 > 0)
+                       s->rwstate=SSL_WRITING;
+                       if (BIO_flush(s->wbio) <= 0)
                                {
-                               s->rwstate=SSL_WRITING;
-                               num1=BIO_flush(s->wbio);
-                               if (num1 <= 0) { ret= -1; goto end; }
-                               s->rwstate=SSL_NOTHING;
+                               ret= -1;
+                               goto end;
                                }
-
+                       s->rwstate=SSL_NOTHING;
                        s->state=s->s3->tmp.next_state;
                        break;
 
@@ -594,9 +596,15 @@ int ssl3_client_hello(SSL *s)
        buf=(unsigned char *)s->init_buf->data;
        if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
                {
-               if ((s->session == NULL) ||
-                       (s->session->ssl_version != s->version) ||
-                       (s->session->not_resumable))
+               SSL_SESSION *sess = s->session;
+               if ((sess == NULL) ||
+                       (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+                       !sess->session_id_length ||
+#else
+                       (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+                       (sess->not_resumable))
                        {
                        if (!ssl_get_new_session(s,0))
                                goto err;
@@ -770,6 +778,7 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
                goto f_err;
                }
+           s->s3->flags |= SSL3_FLAGS_CCS_OK;
            s->hit=1;
            }
        else    /* a miss or crap from the other end */
@@ -816,8 +825,11 @@ int ssl3_get_server_hello(SSL *s)
                s->session->cipher_id = s->session->cipher->id;
        if (s->hit && (s->session->cipher_id != c->id))
                {
+/* Workaround is now obsolete */
+#if 0
                if (!(s->options &
                        SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
+#endif
                        {
                        al=SSL_AD_ILLEGAL_PARAMETER;
                        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
@@ -855,7 +867,7 @@ int ssl3_get_server_hello(SSL *s)
 #endif
 #ifndef OPENSSL_NO_TLSEXT
        /* TLS extensions*/
-       if (s->version > SSL3_VERSION)
+       if (s->version >= SSL3_VERSION)
                {
                if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
                        {
@@ -877,13 +889,15 @@ int ssl3_get_server_hello(SSL *s)
                /* wrong packet length */
                al=SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
-               goto err;
+               goto f_err;
                }
 
        return(1);
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
+#ifndef OPENSSL_NO_TLSEXT
 err:
+#endif
        return(-1);
        }
 
@@ -1378,6 +1392,7 @@ int ssl3_get_key_exchange(SSL *s)
                s->session->sess_cert->peer_ecdh_tmp=ecdh;
                ecdh=NULL;
                BN_CTX_free(bn_ctx);
+               bn_ctx = NULL;
                EC_POINT_free(srvr_ecpoint);
                srvr_ecpoint = NULL;
                }
@@ -1711,17 +1726,18 @@ int ssl3_get_new_session_ticket(SSL *s)
        if (n < 6)
                {
                /* need at least ticket_lifetime_hint + ticket length */
-               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               al = SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
+
        p=d=(unsigned char *)s->init_msg;
        n2l(p, s->session->tlsext_tick_lifetime_hint);
        n2s(p, ticklen);
        /* ticket_lifetime_hint + ticket_length + ticket */
        if (ticklen + 6 != n)
                {
-               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               al = SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
@@ -1738,7 +1754,28 @@ int ssl3_get_new_session_ticket(SSL *s)
                }
        memcpy(s->session->tlsext_tick, p, ticklen);
        s->session->tlsext_ticklen = ticklen;
-       
+       /* There are two ways to detect a resumed ticket sesion.
+        * One is to set an appropriate session ID and then the server
+        * must return a match in ServerHello. This allows the normal
+        * client session ID matching to work and we know much 
+        * earlier that the ticket has been accepted.
+        * 
+        * The other way is to set zero length session ID when the
+        * ticket is presented and rely on the handshake to determine
+        * session resumption.
+        *
+        * We choose the former approach because this fits in with
+        * assumptions elsewhere in OpenSSL. The session ID is set
+        * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
+        * ticket.
+        */ 
+       EVP_Digest(p, ticklen,
+                       s->session->session_id, &s->session->session_id_length,
+#ifndef OPENSSL_NO_SHA256
+                                                       EVP_sha256(), NULL);
+#else
+                                                       EVP_sha1(), NULL);
+#endif
        ret=1;
        return(ret);
 f_err:
@@ -2697,7 +2734,7 @@ static int curve_id2nid(int curve_id)
  */
 
 #ifndef OPENSSL_NO_TLSEXT
-static int ssl3_check_finished(SSL *s)
+int ssl3_check_finished(SSL *s)
        {
        int ok;
        long n;