On Sep 3, 2009, at 10:50 AM, Robin Seggelmann via RT wrote:

>
> On Sep 2, 2009, at 3:02 PM, Stephen Henson via RT wrote:
>
>> There appear to be several problems with this patch, see inline:
>>
>>> [seggelm...@fh-muenster.de - Mon Aug 31 17:04:19 2009]:
>>>
>>> This patch fixes several issues with DTLS cookies.
>>>
>> [snip]
>>>
>>
>> cookie_secret is defined:
>>
>>> +unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
>>> +int cookie_initialized=0;
>>>
>>
>> Then you call:
>>
>>> +           if (!RAND_bytes((unsigned char*) &cookie_secret,
>>> COOKIE_SECRET_LENGTH))
>>
>> Shouldn't that (and several other places too) be cookie_secret and  
>> not
>> &cookie_secret?
>
> Correct.
>
>>> --- crypto/bio/bio.h        24 Jul 2009 11:25:13 -0000      1.80
>>> +++ crypto/bio/bio.h        31 Aug 2009 13:24:35 -0000
>>> @@ -157,9 +157,10 @@
>>>                                           * previous write
>>>                                           * operation */
>>>
>>> -#define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the
>>> data */
>>> +#define BIO_CTRL_DGRAM_GET_PEER           44
>>> +#define BIO_CTRL_DGRAM_SET_PEER           45 /* Destination for the
>>> data */
>>>
>>> -#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   45 /* Next DTLS handshake
>>> timeout to
>>> +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   46 /* Next DTLS handshake
>>> timeout to
>>
>> The above changes the values of some ctrls which have appeared in a
>> released version of OpenSSL i.e. 0.9.8k. That is a definite no-no as
>> it
>> breaks binary compatibility.
>
> Ok. I have attached an updated version, which addresses these issues
> and fixes some other bugs. The order of the code in
> ssl3_get_client_hello() was correct, the problem was in function
> tls1_process_ticket() which didn't skip the cookie when trying to
> process extensions. Additionally, no memory at all is allocated now if
> cookies are required and the current ClientHello doesn't carry one.
> Previously a new session was generated for every ClientHello which
> could be used for denial of service attacks, which was the reason for
> adding the HelloVerifyRequest in the first place.

Another update...forgot to change two pointers in  
generate_cookie_callback() and removed the cookie secret  
initialization in verify_cookie_callback()...



--- apps/s_apps.h       22 Dec 2008 14:05:42 -0000      1.21
+++ apps/s_apps.h       3 Sep 2009 11:31:32 -0000
@@ -171,3 +171,6 @@
                                        unsigned char *data, int len,
                                        void *arg);
  #endif
+
+int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char  
*cookie, unsigned int *cookie_len);
+int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char  
*cookie, unsigned int cookie_len);

--- apps/s_cb.c 2 Sep 2009 12:45:19 -0000       1.27.2.2
+++ apps/s_cb.c 3 Sep 2009 11:31:32 -0000
@@ -121,9 +121,13 @@
  #include <openssl/ssl.h>
  #include "s_apps.h"

+#define        COOKIE_SECRET_LENGTH    16
+
  int verify_depth=0;
  int verify_error=X509_V_OK;
  int verify_return_error=0;
+unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
+int cookie_initialized=0;

  int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx)
        {
@@ -682,3 +686,86 @@
        BIO_dump(bio, (char *)data, len);
        (void)BIO_flush(bio);
        }
+
+int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char  
*cookie, unsigned int *cookie_len)
+       {
+       unsigned char *buffer, result[EVP_MAX_MD_SIZE];
+       unsigned int length, resultlength;
+       struct sockaddr_in peer;
+       
+       /* Initialize a random secret */
+       if (!cookie_initialized)
+               {
+               if (!RAND_bytes((unsigned char*) cookie_secret,  
COOKIE_SECRET_LENGTH))
+                       {
+                       BIO_printf(bio_err,"error setting random cookie 
secret\n");
+                       return 0;
+                       }
+               cookie_initialized = 1;
+               }
+
+       /* Read peer information */
+       BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
+
+       /* Create buffer with peer's address and port */
+       length = sizeof(peer.sin_addr);
+       length += sizeof(peer.sin_port);
+       buffer = OPENSSL_malloc(length);
+
+       if (buffer == NULL)
+               {
+               BIO_printf(bio_err,"out of memory\n");
+               return 0;
+               }
+       
+       memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
+       memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port,  
sizeof(peer.sin_port));
+
+       /* Calculate HMAC of buffer using the secret */
+       HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer,
+            length, (unsigned char*) result, &resultlength);
+       OPENSSL_free(buffer);
+
+       memcpy(cookie, result, resultlength);
+       *cookie_len = resultlength;
+
+       return 1;
+       }
+
+int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char  
*cookie, unsigned int cookie_len)
+       {
+       unsigned char *buffer, result[EVP_MAX_MD_SIZE];
+       unsigned int length, resultlength;
+       struct sockaddr_in peer;
+       
+       /* If secret isn't initialized yet, the cookie can't be valid */
+       if (!cookie_initialized)
+               return 0;
+
+       /* Read peer information */
+       BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
+
+       /* Create buffer with peer's address and port */
+       length = sizeof(peer.sin_addr);
+       length += sizeof(peer.sin_port);
+       buffer = OPENSSL_malloc(length);
+       
+       if (buffer == NULL)
+               {
+               BIO_printf(bio_err,"out of memory\n");
+               return 0;
+               }
+       
+       memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
+       memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port,  
sizeof(peer.sin_port));
+
+       /* Calculate HMAC of buffer using the secret */
+       HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer,
+            length, (unsigned char*) result, &resultlength);
+       OPENSSL_free(buffer);
+       
+       if (cookie_len == resultlength && memcmp(&result, cookie,  
resultlength) == 0)
+               return 1;
+
+       return 0;
+       }

--- apps/s_server.c     18 Aug 2009 11:14:12 -0000      1.136.2.7
+++ apps/s_server.c     3 Sep 2009 11:31:32 -0000
@@ -1654,6 +1654,10 @@
        SSL_CTX_set_session_id_context(ctx, 
(void*)&s_server_session_id_context,
                sizeof s_server_session_id_context);

+       /* Set DTLS cookie generation and verification callbacks */
+       SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback);
+       SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback);
+
  #ifndef OPENSSL_NO_TLSEXT
        if (ctx2)
                {

--- crypto/bio/bio.h    24 Jul 2009 11:24:45 -0000      1.76.2.4
+++ crypto/bio/bio.h    3 Sep 2009 11:31:32 -0000
@@ -157,6 +157,7 @@
                                              * previous write
                                              * operation */

+#define BIO_CTRL_DGRAM_GET_PEER           46
  #define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the  
data */

  #define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   45 /* Next DTLS handshake  
timeout to
@@ -538,6 +539,8 @@
           (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
  #define BIO_dgram_send_timedout(b) \
           (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
+#define BIO_dgram_get_peer(b,peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer)
  #define BIO_dgram_set_peer(b,peer) \
           (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)


--- crypto/bio/bss_dgram.c      26 Aug 2009 15:13:43 -0000      1.7.2.16
+++ crypto/bio/bss_dgram.c      3 Sep 2009 11:31:32 -0000
@@ -290,11 +290,11 @@
                ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen);
                dgram_reset_rcv_timeout(b);

-               if ( ! data->connected  && ret > 0)
-                       BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer);
+               if ( ! data->connected  && ret >= 0)
+                       BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);

                BIO_clear_retry_flags(b);
-               if (ret <= 0)
+               if (ret < 0)
                        {
                        if (BIO_dgram_should_retry(ret))
                                {
@@ -518,6 +518,12 @@
                        memset(&(data->peer), 0x00, sizeof(struct sockaddr));
                        }
                break;
+    case BIO_CTRL_DGRAM_GET_PEER:
+        to = (struct sockaddr *) ptr;
+
+        memcpy(to, &(data->peer), sizeof(struct sockaddr));
+               ret = sizeof(struct sockaddr);
+        break;
      case BIO_CTRL_DGRAM_SET_PEER:
          to = (struct sockaddr *) ptr;


--- ssl/d1_srvr.c       5 Jun 2009 14:46:49 -0000       1.20.2.6
+++ ssl/d1_srvr.c       3 Sep 2009 11:31:33 -0000
@@ -238,11 +238,6 @@
                                s->state=SSL3_ST_SW_HELLO_REQ_A;
                                }

-                       if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
-                               s->d1->send_cookie = 1;
-                       else
-                               s->d1->send_cookie = 0;
-                       
                        break;

                case SSL3_ST_SW_HELLO_REQ_A:
@@ -273,7 +268,7 @@
                        dtls1_stop_timer(s);
                        s->new_session = 2;

-                       if (s->d1->send_cookie)
+                       if (ret == 1 && (SSL_get_options(s) & 
SSL_OP_COOKIE_EXCHANGE))
                                s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
                        else
                                s->state = SSL3_ST_SW_SRVR_HELLO_A;
@@ -287,7 +282,6 @@
                        dtls1_start_timer(s);
                        ret = dtls1_send_hello_verify_request(s);
                        if ( ret <= 0) goto end;
-                       s->d1->send_cookie = 0;
                        s->state=SSL3_ST_SW_FLUSH;
                        s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;

@@ -670,15 +664,13 @@
                *(p++) = s->version >> 8;
                *(p++) = s->version & 0xFF;

-               if (s->ctx->app_gen_cookie_cb != NULL &&
-                   s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
-                       &(s->d1->cookie_len)) == 0)
+               if (s->ctx->app_gen_cookie_cb == NULL ||
+                    s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+                        &(s->d1->cookie_len)) == 0)
                        {
                        
SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
                        return 0;
                        }
-               /* else the cookie is assumed to have
-                * been initialized by the application */

                *(p++) = (unsigned char) s->d1->cookie_len;
                memcpy(p, s->d1->cookie, s->d1->cookie_len);

--- ssl/dtls1.h 25 Aug 2009 07:10:09 -0000      1.12.2.13
+++ ssl/dtls1.h 3 Sep 2009 11:31:33 -0000
@@ -88,7 +88,7 @@
  #endif

  /* lengths of messages */
-#define DTLS1_COOKIE_LENGTH                     32
+#define DTLS1_COOKIE_LENGTH                     256

  #define DTLS1_RT_HEADER_LENGTH                  13


--- ssl/s3_srvr.c       26 Jun 2009 15:04:22 -0000      1.171.2.7
+++ ssl/s3_srvr.c       3 Sep 2009 11:31:33 -0000
@@ -816,6 +816,21 @@
                goto f_err;
                }

+       /* If we require cookies and this ClientHello doesn't
+        * contain one, just return since we do not want to
+        * allocate any memory yet. So check cookie length...
+        */
+       if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
+               {
+               unsigned int session_length, cookie_length;
+               
+               session_length = *(p + SSL3_RANDOM_SIZE);
+               cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
+
+               if (cookie_len == 0)
+                       return 1;
+               }
+
        /* load the client random */
        memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
        p+=SSL3_RANDOM_SIZE;
@@ -855,23 +870,11 @@

        p+=j;

-       if (s->version == DTLS1_VERSION)
+       if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
                {
                /* cookie stuff */
                cookie_len = *(p++);

-               if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
-                       s->d1->send_cookie == 0)
-                       {
-                       /* HelloVerifyMessage has already been sent */
-                       if ( cookie_len != s->d1->cookie_len)
-                               {
-                               al = SSL_AD_HANDSHAKE_FAILURE;
-                               SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
SSL_R_COOKIE_MISMATCH);
-                               goto f_err;
-                               }
-                       }
-
                /*
                 * The ClientHello may contain a cookie even if the
                 * HelloVerify message has not been sent--make sure that it
@@ -886,7 +889,7 @@
                        }

                /* verify the cookie if appropriate option is set. */
-               if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+               if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
                        cookie_len > 0)
                        {
                        memcpy(s->d1->rcvd_cookie, p, cookie_len);
@@ -911,6 +914,8 @@
                                                SSL_R_COOKIE_MISMATCH);
                                        goto f_err;
                                }
+
+                       ret = 2;
                        }

                p += cookie_len;
@@ -1185,7 +1190,7 @@
         * s->tmp.new_cipher    - the new cipher to use.
         */

-       ret=1;
+       if (ret < 0) ret=1;
        if (0)
                {
  f_err:

--- ssl/t1_lib.c        28 Apr 2009 22:01:53 -0000      1.64.2.1
+++ ssl/t1_lib.c        3 Sep 2009 11:31:33 -0000
@@ -1444,6 +1444,14 @@
                return 1;
        if (p >= limit)
                return -1;
+       /* Skip past DTLS cookie */
+       if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+               {
+               i = *(p++);
+               p+= i;
+               if (p >= limit)
+                       return -1;
+               }
        /* Skip past cipher list */
        n2s(p, i);
        p+= i;







Attachment: dtls-cookie-management-bugs-0.9.8.patch
Description: Binary data

Attachment: dtls-cookie-management-bugs-1.0.0.patch
Description: Binary data

Reply via email to