0.9.8 version of PR#1931 fix.
[oweals/openssl.git] / ssl / d1_clnt.c
index 0f840f439d35f6c38b86328499f6b9451a60e008..a95705448f4ea687aaf93053df57cf8b147f299b 100644 (file)
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/md5.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
 
 static SSL_METHOD *dtls1_get_client_method(int ver);
 static int dtls1_get_hello_verify(SSL *s);
 
 static SSL_METHOD *dtls1_get_client_method(int ver)
        {
-       if (ver == DTLS1_VERSION)
+       if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
                return(DTLSv1_client_method());
        else
                return(NULL);
        }
 
-SSL_METHOD *DTLSv1_client_method(void)
-       {
-       static int init=1;
-       static SSL_METHOD DTLSv1_client_data;
-
-       if (init)
-               {
-               CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
-
-               if (init)
-                       {
-                       memcpy((char *)&DTLSv1_client_data,(char *)dtlsv1_base_method(),
-                               sizeof(SSL_METHOD));
-                       DTLSv1_client_data.ssl_connect=dtls1_connect;
-                       DTLSv1_client_data.get_ssl_method=dtls1_get_client_method;
-                       init=0;
-                       }
-               
-               CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
-               }
-       return(&DTLSv1_client_data);
-       }
+IMPLEMENT_dtls1_meth_func(DTLSv1_client_method,
+                       ssl_undefined_function,
+                       dtls1_connect,
+                       dtls1_get_client_method)
 
 int dtls1_connect(SSL *s)
        {
        BUF_MEM *buf=NULL;
-       unsigned long Time=time(NULL),l;
+       unsigned long Time=(unsigned long)time(NULL),l;
        long num1;
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
        int ret= -1;
@@ -196,7 +181,8 @@ int dtls1_connect(SSL *s)
                        s->server=0;
                        if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
 
-                       if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00))
+                       if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) &&
+                           (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00))
                                {
                                SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR);
                                ret = -1;
@@ -229,17 +215,22 @@ int dtls1_connect(SSL *s)
 
                        /* don't push the buffering BIO quite yet */
 
-                       ssl3_init_finished_mac(s);
-
                        s->state=SSL3_ST_CW_CLNT_HELLO_A;
                        s->ctx->stats.sess_connect++;
                        s->init_num=0;
+                       /* mark client_random uninitialized */
+                       memset(s->s3->client_random,0,sizeof(s->s3->client_random));
                        break;
 
                case SSL3_ST_CW_CLNT_HELLO_A:
                case SSL3_ST_CW_CLNT_HELLO_B:
 
                        s->shutdown=0;
+
+                       /* every DTLS ClientHello resets Finished MAC */
+                       ssl3_init_finished_mac(s);
+
+                       dtls1_start_timer(s);
                        ret=dtls1_client_hello(s);
                        if (ret <= 0) goto end;
 
@@ -265,6 +256,7 @@ int dtls1_connect(SSL *s)
                        if (ret <= 0) goto end;
                        else
                                {
+                               dtls1_stop_timer(s);
                                if (s->hit)
                                        s->state=SSL3_ST_CR_FINISHED_A;
                                else
@@ -279,6 +271,7 @@ int dtls1_connect(SSL *s)
                        ret = dtls1_get_hello_verify(s);
                        if ( ret <= 0)
                                goto end;
+                       dtls1_stop_timer(s);
                        if ( s->d1->send_cookie) /* start again, with a cookie */
                                s->state=SSL3_ST_CW_CLNT_HELLO_A;
                        else
@@ -340,6 +333,7 @@ int dtls1_connect(SSL *s)
                case SSL3_ST_CW_CERT_B:
                case SSL3_ST_CW_CERT_C:
                case SSL3_ST_CW_CERT_D:
+                       dtls1_start_timer(s);
                        ret=dtls1_send_client_certificate(s);
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_CW_KEY_EXCH_A;
@@ -348,6 +342,7 @@ int dtls1_connect(SSL *s)
 
                case SSL3_ST_CW_KEY_EXCH_A:
                case SSL3_ST_CW_KEY_EXCH_B:
+                       dtls1_start_timer(s);
                        ret=dtls1_send_client_key_exchange(s);
                        if (ret <= 0) goto end;
                        l=s->s3->tmp.new_cipher->algorithms;
@@ -370,6 +365,7 @@ int dtls1_connect(SSL *s)
 
                case SSL3_ST_CW_CERT_VRFY_A:
                case SSL3_ST_CW_CERT_VRFY_B:
+                       dtls1_start_timer(s);
                        ret=dtls1_send_client_verify(s);
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_CW_CHANGE_A;
@@ -379,6 +375,7 @@ int dtls1_connect(SSL *s)
 
                case SSL3_ST_CW_CHANGE_A:
                case SSL3_ST_CW_CHANGE_B:
+                       dtls1_start_timer(s);
                        ret=dtls1_send_change_cipher_spec(s,
                                SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
                        if (ret <= 0) goto end;
@@ -386,11 +383,15 @@ int dtls1_connect(SSL *s)
                        s->init_num=0;
 
                        s->session->cipher=s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+                       s->session->compress_meth=0;
+#else
                        if (s->s3->tmp.new_compression == NULL)
                                s->session->compress_meth=0;
                        else
                                s->session->compress_meth=
                                        s->s3->tmp.new_compression->id;
+#endif
                        if (!s->method->ssl3_enc->setup_key_block(s))
                                {
                                ret= -1;
@@ -409,6 +410,7 @@ int dtls1_connect(SSL *s)
 
                case SSL3_ST_CW_FINISHED_A:
                case SSL3_ST_CW_FINISHED_B:
+                       dtls1_start_timer(s);
                        ret=dtls1_send_finished(s,
                                SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
                                s->method->ssl3_enc->client_finished_label,
@@ -433,6 +435,7 @@ int dtls1_connect(SSL *s)
                                s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
                                }
                        s->init_num=0;
+
                        break;
 
                case SSL3_ST_CR_FINISHED_A:
@@ -441,6 +444,7 @@ int dtls1_connect(SSL *s)
                        ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
                                SSL3_ST_CR_FINISHED_B);
                        if (ret <= 0) goto end;
+                       dtls1_stop_timer(s);
 
                        if (s->hit)
                                s->state=SSL3_ST_CW_CHANGE_A;
@@ -496,6 +500,7 @@ int dtls1_connect(SSL *s)
 
                        /* done with handshaking */
                        s->d1->handshake_read_seq  = 0;
+                       s->d1->next_handshake_write_seq = 0;
                        goto end;
                        /* break; */
                        
@@ -538,7 +543,7 @@ int dtls1_client_hello(SSL *s)
        {
        unsigned char *buf;
        unsigned char *p,*d;
-       int i,j;
+       unsigned int i,j;
        unsigned long Time,l;
        SSL_COMP *comp;
 
@@ -555,9 +560,15 @@ int dtls1_client_hello(SSL *s)
                /* else use the pre-loaded session */
 
                p=s->s3->client_random;
-               Time=time(NULL);                        /* Time */
-               l2n(Time,p);
-               RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+               /* if client_random is initialized, reuse it, we are
+                * required to use same upon reply to HelloVerify */
+               for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) ;
+               if (i==sizeof(s->s3->client_random))
+                       {
+                       Time=(unsigned long)time(NULL); /* Time */
+                       l2n(Time,p);
+                       RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4);
+                       }
 
                /* Do the message type and length last */
                d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
@@ -743,7 +754,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                        s->session->master_key_length=sizeof tmp_buf;
 
                        q=p;
-                       /* Fix buf for TLS and beyond */
+                       /* Fix buf for TLS and [incidentally] DTLS */
                        if (s->version > SSL3_VERSION)
                                p+=2;
                        n=RSA_public_encrypt(sizeof tmp_buf,
@@ -758,7 +769,7 @@ int dtls1_send_client_key_exchange(SSL *s)
                                goto err;
                                }
 
-                       /* Fix buf for TLS and beyond */
+                       /* Fix buf for TLS and [incidentally] DTLS */
                        if (s->version > SSL3_VERSION)
                                {
                                s2n(n,q);
@@ -1093,8 +1104,7 @@ int dtls1_send_client_certificate(SSL *s)
                 * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
                 * We then get retied later */
                i=0;
-               if (s->ctx->client_cert_cb != NULL)
-                       i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
+               i = ssl_do_client_cert_cb(s, &x509, &pkey);
                if (i < 0)
                        {
                        s->rwstate=SSL_X509_LOOKUP;