For better forward-security support, add functions
[openssl.git] / ssl / s3_srvr.c
index 00fc2616b77a472a58373477a6d0482231648d0e..bc6ece47c1dc868248745d9c671aaa2054ef0026 100644 (file)
@@ -189,7 +189,6 @@ int ssl3_accept(SSL *s)
        BUF_MEM *buf;
        unsigned long alg_k,Time=(unsigned long)time(NULL);
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
-       long num1;
        int ret= -1;
        int new_state,state,skip=0;
 
@@ -219,7 +218,7 @@ int ssl3_accept(SSL *s)
                switch (s->state)
                        {
                case SSL_ST_RENEGOTIATE:
-                       s->new_session=1;
+                       s->renegotiate=1;
                        /* s->state=SSL_ST_ACCEPT; */
 
                case SSL_ST_BEFORE:
@@ -317,7 +316,7 @@ int ssl3_accept(SSL *s)
                        ret=ssl3_get_client_hello(s);
                        if (ret <= 0) goto end;
                        
-                       s->new_session = 2;
+                       s->renegotiate = 2;
                        s->state=SSL3_ST_SW_SRVR_HELLO_A;
                        s->init_num=0;
                        break;
@@ -483,15 +482,24 @@ int ssl3_accept(SSL *s)
                        break;
                
                case SSL3_ST_SW_FLUSH:
-                       /* number of bytes to be flushed */
-                       num1=BIO_ctrl(s->wbio,BIO_CTRL_WPENDING,0,NULL);
-                       if (num1 > 0)
+
+                       /* This code originally checked to see if
+                        * any data was pending using BIO_CTRL_INFO
+                        * and then flushed. This caused problems
+                        * as documented in PR#1939. The proposed
+                        * fix doesn't completely resolve this issue
+                        * as buggy implementations of BIO_CTRL_PENDING
+                        * still exist. So instead we just flush
+                        * unconditionally.
+                        */
+
+                       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;
@@ -530,7 +538,14 @@ int ssl3_accept(SSL *s)
                                 * the client uses its key from the certificate
                                 * for key exchange.
                                 */
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
                                s->state=SSL3_ST_SR_FINISHED_A;
+#else
+                               if (s->s3->next_proto_neg_seen)
+                                       s->state=SSL3_ST_SR_NEXT_PROTO_A;
+                               else
+                                       s->state=SSL3_ST_SR_FINISHED_A;
+#endif
                                s->init_num = 0;
                                }
                        else
@@ -573,10 +588,27 @@ int ssl3_accept(SSL *s)
                        ret=ssl3_get_cert_verify(s);
                        if (ret <= 0) goto end;
 
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
                        s->state=SSL3_ST_SR_FINISHED_A;
+#else
+                       if (s->s3->next_proto_neg_seen)
+                               s->state=SSL3_ST_SR_NEXT_PROTO_A;
+                       else
+                               s->state=SSL3_ST_SR_FINISHED_A;
+#endif
                        s->init_num=0;
                        break;
 
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+               case SSL3_ST_SR_NEXT_PROTO_A:
+               case SSL3_ST_SR_NEXT_PROTO_B:
+                       ret=ssl3_get_next_proto(s);
+                       if (ret <= 0) goto end;
+                       s->init_num = 0;
+                       s->state=SSL3_ST_SR_FINISHED_A;
+                       break;
+#endif
+
                case SSL3_ST_SR_FINISHED_A:
                case SSL3_ST_SR_FINISHED_B:
                        ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
@@ -647,7 +679,16 @@ int ssl3_accept(SSL *s)
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_SW_FLUSH;
                        if (s->hit)
+                               {
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
                                s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#else
+                               if (s->s3->next_proto_neg_seen)
+                                       s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
+                               else
+                                       s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#endif
+                               }
                        else
                                s->s3->tmp.next_state=SSL_ST_OK;
                        s->init_num=0;
@@ -665,11 +706,12 @@ int ssl3_accept(SSL *s)
 
                        s->init_num=0;
 
-                       if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
+                       if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
                                {
                                /* actually not necessarily a 'new' session unless
                                 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
                                
+                               s->renegotiate=0;
                                s->new_session=0;
                                
                                ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
@@ -1209,6 +1251,13 @@ int ssl3_get_client_hello(SSL *s)
                        goto f_err;
                        }
                s->s3->tmp.new_cipher=c;
+               /* check whether we should disable session resumption */
+               if (s->not_resumable_session_cb != NULL)
+                       s->session->not_resumable=s->not_resumable_session_cb(s,
+                               ((c->algorithm_mkey & (SSL_kEDH | SSL_kEECDH)) != 0));
+               if (s->session->not_resumable)
+                       /* do not send a session ticket */
+                       s->tlsext_ticket_expected = 0;
                }
        else
                {
@@ -1312,8 +1361,9 @@ int ssl3_send_server_hello(SSL *s)
                 * if session caching is disabled so existing functionality
                 * is unaffected.
                 */
-               if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
-                       && !s->hit)
+               if (s->session->not_resumable ||
+                       (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+                               && !s->hit))
                        s->session->session_id_length=0;
 
                sl=s->session->session_id_length;
@@ -2278,7 +2328,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                                SSL_R_DATA_LENGTH_TOO_LONG);
                        goto err;
                        }
-               if (!((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+               if (!((pms[0] == (s->client_version>>8)) && (pms[1] == (s->client_version & 0xff))))
                    {
                    /* The premaster secret must contain the same version number as the
                     * ClientHello to detect version rollback attacks (strangely, the
@@ -2288,8 +2338,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                     * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. 
                     * (Perhaps we should have a separate BUG value for the Kerberos cipher)
                     */
-                   if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
-                          (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+                   if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG))
                        {
                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                               SSL_AD_DECODE_ERROR);
@@ -3170,4 +3219,72 @@ int ssl3_send_cert_status(SSL *s)
        /* SSL3_ST_SW_CERT_STATUS_B */
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
+
+# ifndef OPENSSL_NO_NPN
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
+ * sets the next_proto member in s if found */
+int ssl3_get_next_proto(SSL *s)
+       {
+       int ok;
+       unsigned proto_len, padding_len;
+       long n;
+       const unsigned char *p;
+
+       /* Clients cannot send a NextProtocol message if we didn't see the
+        * extension in their ClientHello */
+       if (!s->s3->next_proto_neg_seen)
+               {
+               SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+               return -1;
+               }
+
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_SR_NEXT_PROTO_A,
+               SSL3_ST_SR_NEXT_PROTO_B,
+               SSL3_MT_NEXT_PROTO,
+               129,
+               &ok);
+
+       if (!ok)
+               return((int)n);
+
+       /* s->state doesn't reflect whether ChangeCipherSpec has been received
+        * in this handshake, but s->s3->change_cipher_spec does (will be reset
+        * by ssl3_get_finished). */
+       if (!s->s3->change_cipher_spec)
+               {
+               SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
+               return -1;
+               }
+
+       if (n < 2)
+               return 0;  /* The body must be > 1 bytes long */
+
+       p=(unsigned char *)s->init_msg;
+
+       /* The payload looks like:
+        *   uint8 proto_len;
+        *   uint8 proto[proto_len];
+        *   uint8 padding_len;
+        *   uint8 padding[padding_len];
+        */
+       proto_len = p[0];
+       if (proto_len + 2 > s->init_num)
+               return 0;
+       padding_len = p[proto_len + 1];
+       if (proto_len + padding_len + 2 != s->init_num)
+               return 0;
+
+       s->next_proto_negotiated = OPENSSL_malloc(proto_len);
+       if (!s->next_proto_negotiated)
+               {
+               SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       memcpy(s->next_proto_negotiated, p + 1, proto_len);
+       s->next_proto_negotiated_len = proto_len;
+
+       return 1;
+       }
+# endif
 #endif