[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Feb 5 20:51:15 UTC 2016


The branch master has been updated
       via  a9052bed9e485a614dd44c6ae8f8c0e84c3205df (commit)
       via  ce0865d8dcf4ed088a9e9ae3aa2310b7bd8c295e (commit)
       via  4b1043ef1b54b0cf27d00cff9ff9a63f2c523e63 (commit)
       via  7d1d48a2d0a08567f5c8e14d50d89a9b47c02f1d (commit)
      from  0d4fb8439092ff8253af72ac6bc193e77ebbcf2f (commit)


- Log -----------------------------------------------------------------
commit a9052bed9e485a614dd44c6ae8f8c0e84c3205df
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Feb 5 20:17:10 2016 +0000

    Update DTLSv1_listen documentation
    
    Make it clear that if we are unable to get hold of the peer address then
    *peer is cleared and the family set to AF_UNSPEC.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

commit ce0865d8dcf4ed088a9e9ae3aa2310b7bd8c295e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 21 12:22:58 2016 +0000

    Add tests for DTLSv1_listen
    
    Adds a set of tests for the newly rewritten DTLSv1_listen function.
    The test pokes various packets at the function and then checks
    the return value and the data written out to ensure it is what we
    would have expected.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

commit 4b1043ef1b54b0cf27d00cff9ff9a63f2c523e63
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 4 13:53:57 2015 +0000

    Provide partial support for fragmented DTLS ClientHellos
    
    The recently rewriten DTLSv1_listen code does not support fragmented
    ClientHello messages because fragment reassembly requires server state
    which is against the whole point of DTLSv1_listen. This change adds some
    partial support for fragmented ClientHellos. It requires that the cookie
    must be within the initial fragment. That way any non-initial ClientHello
    fragments can be dropped and fragment reassembly is not required.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

commit 7d1d48a2d0a08567f5c8e14d50d89a9b47c02f1d
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Feb 5 19:40:44 2016 +0000

    Add a BIO_ADDR_clear function
    
    Adds a new function BIO_ADDR_clear to reset a BIO_ADDR back to an
    unitialised state, and to set the family to AF_UNSPEC.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 crypto/bio/b_addr.c                 |   7 +
 doc/crypto/BIO_ADDR.pod             |   9 +-
 doc/ssl/DTLSv1_listen.pod           |   8 +-
 include/openssl/bio.h               |   1 +
 ssl/d1_lib.c                        |  49 ++--
 test/Makefile.in                    |  11 +-
 test/dtlsv1listentest.c             | 478 ++++++++++++++++++++++++++++++++++++
 test/recipes/80-test_dtlsv1listen.t |   5 +
 8 files changed, 544 insertions(+), 24 deletions(-)
 create mode 100644 test/dtlsv1listentest.c
 create mode 100644 test/recipes/80-test_dtlsv1listen.t

diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c
index 20cb66d..f1ff5fe 100644
--- a/crypto/bio/b_addr.c
+++ b/crypto/bio/b_addr.c
@@ -76,6 +76,7 @@
 BIO_ADDR *BIO_ADDR_new(void)
 {
     BIO_ADDR *ret = (BIO_ADDR *)OPENSSL_zalloc(sizeof(BIO_ADDR));
+    ret->sa.sa_family = AF_UNSPEC;
     return ret;
 }
 
@@ -84,6 +85,12 @@ void BIO_ADDR_free(BIO_ADDR *ap)
     OPENSSL_free(ap);
 }
 
+void BIO_ADDR_clear(BIO_ADDR *ap)
+{
+    memset(ap, 0, sizeof(*ap));
+    ap->sa.sa_family = AF_UNSPEC;
+}
+
 /*
  * BIO_ADDR_make - non-public routine to fill a BIO_ADDR with the contents
  * of a struct sockaddr.
diff --git a/doc/crypto/BIO_ADDR.pod b/doc/crypto/BIO_ADDR.pod
index cec7ddd..a3c9b5c 100644
--- a/doc/crypto/BIO_ADDR.pod
+++ b/doc/crypto/BIO_ADDR.pod
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-BIO_ADDR, BIO_ADDR_new, BIO_ADDR_free, BIO_ADDR_rawmake,
+BIO_ADDR, BIO_ADDR_new, BIO_ADDR_clear, BIO_ADDR_free, BIO_ADDR_rawmake,
 BIO_ADDR_family, BIO_ADDR_rawaddress, BIO_ADDR_rawport,
 BIO_ADDR_hostname_string, BIO_ADDR_service_string,
 BIO_ADDR_path_string - BIO_ADDR routines
@@ -16,6 +16,7 @@ BIO_ADDR_path_string - BIO_ADDR routines
 
  BIO_ADDR *BIO_ADDR_new(void);
  void BIO_ADDR_free(BIO_ADDR *);
+ void BIO_ADDR_clear(BIO_ADDR *ap);
  int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
                       const void *where, size_t wherelen, unsigned short port);
  int BIO_ADDR_family(const BIO_ADDR *ap);
@@ -38,6 +39,9 @@ BIO_accept_ex().
 
 BIO_ADDR_free() frees a B<BIO_ADDR> created with BIO_ADDR_new().
 
+BIO_ADDR_clear() clears any data held within the provided B<BIO_ADDR> and sets
+it back to an uninitialised state.
+
 BIO_ADDR_rawmake() takes a protocol B<family>, an byte array of
 size B<wherelen> with an address in network byte order pointed at
 by B<where> and a port number in network byte order in B<port> (except
@@ -50,7 +54,8 @@ I<Read on about the addresses in L</RAW ADDRESSES> below>.
 
 BIO_ADDR_family() returns the protocol family of the given
 B<BIO_ADDR>.  The possible non-error results are one of the
-constants AF_INET, AF_INET6 and AF_UNIX.
+constants AF_INET, AF_INET6 and AF_UNIX. It will also return AF_UNSPEC if the
+BIO_ADDR has not been initialised.
 
 BIO_ADDR_rawaddress() will write the raw address of the given
 B<BIO_ADDR> in the area pointed at by B<p> if B<p> is non-NULL,
diff --git a/doc/ssl/DTLSv1_listen.pod b/doc/ssl/DTLSv1_listen.pod
index 62913de..7416693 100644
--- a/doc/ssl/DTLSv1_listen.pod
+++ b/doc/ssl/DTLSv1_listen.pod
@@ -44,9 +44,11 @@ When a ClientHello is received that contains a cookie that has been verified,
 then DTLSv1_listen() will return with the B<ssl> parameter updated into a state
 where the handshake can be continued by a call to (for example) SSL_accept().
 Additionally the B<BIO_ADDR> pointed to by B<peer> will be filled in with
-details of the peer that sent the ClientHello. Typically user code is expected
-to "connect" the underlying socket to the peer and continue the handshake in a
-connected state.
+details of the peer that sent the ClientHello. If the underlying BIO is unable
+to obtain the B<BIO_ADDR> of the peer (for example because the BIO does not
+support this), then B<*peer> will be cleared and the family set to AF_UNSPEC.
+Typically user code is expected to "connect" the underlying socket to the peer
+and continue the handshake in a connected state.
 
 Prior to calling DTLSv1_listen() user code must ensure that cookie generation
 and verification callbacks have been set up using
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 2989218..cfb7b0f 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -713,6 +713,7 @@ BIO_ADDR *BIO_ADDR_new(void);
 int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
                      const void *where, size_t wherelen, unsigned short port);
 void BIO_ADDR_free(BIO_ADDR *);
+void BIO_ADDR_clear(BIO_ADDR *ap);
 int BIO_ADDR_family(const BIO_ADDR *ap);
 int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l);
 unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap);
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index ae89a23..b1f6ed2 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -615,11 +615,14 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
         if (!PACKET_forward(&pkt, 1)
             /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
             || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
-            || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)
-            || PACKET_remaining(&pkt) != 0) {
+            || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) {
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
             goto end;
         }
+        /*
+         * We allow data remaining at the end of the packet because there could
+         * be a second record (but we ignore it)
+         */
 
         /* This is an initial ClientHello so the epoch has to be 0 */
         if (seq[0] != 0 || seq[1] != 0) {
@@ -636,7 +639,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
             || !PACKET_get_net_2(&msgpkt, &msgseq)
             || !PACKET_get_net_3(&msgpkt, &fragoff)
             || !PACKET_get_net_3(&msgpkt, &fraglen)
-            || !PACKET_get_sub_packet(&msgpkt, &msgpayload, msglen)
+            || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen)
             || PACKET_remaining(&msgpkt) != 0) {
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
             goto end;
@@ -653,15 +656,22 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
             goto end;
         }
 
-        /* We don't support a fragmented ClientHello whilst listening */
-        if (fragoff != 0 || fraglen != msglen) {
+        /*
+         * We don't support fragment reassembly for ClientHellos whilst
+         * listening because that would require server side state (which is
+         * against the whole point of the ClientHello/HelloVerifyRequest
+         * mechanism). Instead we only look at the first ClientHello fragment
+         * and require that the cookie must be contained within it.
+         */
+        if (fragoff != 0 || fraglen > msglen) {
+            /* Non initial ClientHello fragment (or bad fragment) */
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
             goto end;
         }
 
         if (s->msg_callback)
             s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
-                            msglen + DTLS1_HM_HEADER_LENGTH, s,
+                            fraglen + DTLS1_HM_HEADER_LENGTH, s,
                             s->msg_callback_arg);
 
         if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
@@ -681,6 +691,10 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
         if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
             || !PACKET_get_length_prefixed_1(&msgpayload, &session)
             || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
+            /*
+             * Could be malformed or the cookie does not fit within the initial
+             * ClientHello fragment. Either way we can't handle it.
+             */
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
             goto end;
         }
@@ -797,15 +811,19 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
                 s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
                                 DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
 
+
+            if ((tmpclient = BIO_ADDR_new()) == NULL) {
+                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
+                goto end;
+            }
+
             /*
              * This is unneccessary if rbio and wbio are one and the same - but
-             * maybe they're not.
+             * maybe they're not. We ignore errors here - some BIOs do not
+             * support this.
              */
-            if ((tmpclient = BIO_ADDR_new()) == NULL
-                || BIO_dgram_get_peer(rbio, tmpclient) <= 0
-                || BIO_dgram_set_peer(wbio, tmpclient) <= 0) {
-                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
-                goto end;
+            if(BIO_dgram_get_peer(rbio, tmpclient) > 0) {
+                (void)BIO_dgram_set_peer(wbio, tmpclient);
             }
             BIO_ADDR_free(tmpclient);
             tmpclient = NULL;
@@ -854,10 +872,9 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
      */
     ossl_statem_set_hello_verify_done(s);
 
-    if(BIO_dgram_get_peer(rbio, client) <= 0) {
-        SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
-        return -1;
-    }
+    /* Some BIOs may not support this. If we fail we clear the client address */
+    if (BIO_dgram_get_peer(rbio, client) <= 0)
+        BIO_ADDR_clear(client);
 
     ret = 1;
     clearpkt = 0;
diff --git a/test/Makefile.in b/test/Makefile.in
index cf6e816..96ee8f4 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -80,6 +80,7 @@ SSLEXTENSIONTEST=	sslextensiontest
 SSLSESSIONTICKTEST= 	sslsessionticktest
 SSLSKEWITH0PTEST=	sslskewith0ptest
 ASYNCTEST=	asynctest
+DTLSV1LISTENTEST = dtlsv1listentest
 
 TESTS=		alltests
 
@@ -100,7 +101,8 @@ EXE=	$(NPTEST)$(EXE_EXT) $(MEMLEAKTEST)$(EXE_EXT) \
 	$(SRPTEST)$(EXE_EXT) $(V3NAMETEST)$(EXE_EXT) \
 	$(HEARTBEATTEST)$(EXE_EXT) $(P5_CRPT2_TEST)$(EXE_EXT) \
 	$(CONSTTIMETEST)$(EXE_EXT) $(VERIFYEXTRATEST)$(EXE_EXT) \
-	$(CLIENTHELLOTEST)$(EXE_EXT) $(PACKETTEST)$(EXE_EXT) $(ASYNCTEST)$(EXE_EXT)
+	$(CLIENTHELLOTEST)$(EXE_EXT) $(PACKETTEST)$(EXE_EXT) $(ASYNCTEST)$(EXE_EXT) \
+	$(DTLSV1LISTENTEST)$(EXE_EXT)
 
 # $(METHTEST)$(EXE_EXT)
 
@@ -117,7 +119,7 @@ OBJ=	$(NPTEST).o $(MEMLEAKTEST).o \
 	$(EVPTEST).o $(EVPEXTRATEST).o $(IGETEST).o $(JPAKETEST).o $(V3NAMETEST).o \
 	$(HEARTBEATTEST).o $(P5_CRPT2_TEST).o \
 	$(CONSTTIMETEST).o $(VERIFYEXTRATEST).o $(CLIENTHELLOTEST).o \
-	$(PACKETTEST).o $(ASYNCTEST).o testutil.o
+	$(PACKETTEST).o $(ASYNCTEST).o $(DTLSV1LISTENTEST).o testutil.o
 
 SRC=	$(NPTEST).c $(MEMLEAKTEST).c \
 	$(BNTEST).c $(ECTEST).c \
@@ -131,7 +133,7 @@ SRC=	$(NPTEST).c $(MEMLEAKTEST).c \
 	$(EVPTEST).c $(EVPEXTRATEST).c $(IGETEST).c $(JPAKETEST).c $(V3NAMETEST).c \
 	$(HEARTBEATTEST).c $(P5_CRPT2_TEST).c \
 	$(CONSTTIMETEST).c $(VERIFYEXTRATEST).c $(CLIENTHELLOTEST).c \
-	$(PACKETTEST).c $(ASYNCTEST).c testutil.c
+	$(PACKETTEST).c $(ASYNCTEST).c $(DTLSV1LISTENTEST).c testutil.c
 
 HEADER=	testutil.h
 
@@ -363,6 +365,9 @@ $(PACKETTEST)$(EXE_EXT): $(PACKETTEST).o
 $(ASYNCTEST)$(EXE_EXT): $(ASYNCTEST).o
 	@target=$(ASYNCTEST) $(BUILD_CMD)
 
+$(DTLSV1LISTENTEST)$(EXE_EXT): $(DTLSV1LISTENTEST).o
+	@target=$(DTLSV1LISTENTEST) $(BUILD_CMD)
+
 #$(AESTEST).o: $(AESTEST).c
 #	$(CC) -c $(CFLAGS) -DINTERMEDIATE_VALUE_KAT -DTRACE_KAT_MCT $(AESTEST).c
 
diff --git a/test/dtlsv1listentest.c b/test/dtlsv1listentest.c
new file mode 100644
index 0000000..28b493e
--- /dev/null
+++ b/test/dtlsv1listentest.c
@@ -0,0 +1,478 @@
+/*
+ * Written by Matt Caswell for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 2016 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+#include <string.h>
+#include <sys/socket.h>
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include "e_os.h"
+
+/* Just a ClientHello without a cookie */
+const unsigned char clienthello_nocookie[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x3A, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x2E, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x2E, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x00, /* Cookie len */
+    0x00, 0x04, /* Ciphersuites len */
+    0x00, 0x2f, /* AES128-SHA */
+    0x00, 0xff, /* Empty reneg info SCSV */
+    0x01, /* Compression methods len */
+    0x00, /* Null compression */
+    0x00, 0x00 /* Extensions len */
+};
+
+/* First fragment of a ClientHello without a cookie */
+const unsigned char clienthello_nocookie_frag[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x30, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x2E, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x24, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x00 /* Cookie len */
+};
+
+/* First fragment of a ClientHello which is too short */
+const unsigned char clienthello_nocookie_short[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x2F, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x2E, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x23, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00 /* Session id len */
+};
+
+/* Second fragment of a ClientHello */
+const unsigned char clienthello_2ndfrag[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x38, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x2E, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x02, /* Fragment offset */
+    0x00, 0x00, 0x2C, /* Fragment length */
+    /* Version skipped - sent in first fragment */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x00, /* Cookie len */
+    0x00, 0x04, /* Ciphersuites len */
+    0x00, 0x2f, /* AES128-SHA */
+    0x00, 0xff, /* Empty reneg info SCSV */
+    0x01, /* Compression methods len */
+    0x00, /* Null compression */
+    0x00, 0x00 /* Extensions len */
+};
+
+/* A ClientHello with a good cookie */
+const unsigned char clienthello_cookie[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x4E, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x42, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x42, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x14, /* Cookie len */
+    0x00, 0x01, 0x02, 0x03, 0x04, 005, 0x06, 007, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, /* Cookie */
+    0x00, 0x04, /* Ciphersuites len */
+    0x00, 0x2f, /* AES128-SHA */
+    0x00, 0xff, /* Empty reneg info SCSV */
+    0x01, /* Compression methods len */
+    0x00, /* Null compression */
+    0x00, 0x00 /* Extensions len */
+};
+
+/* A fragmented ClientHello with a good cookie */
+const unsigned char clienthello_cookie_frag[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x44, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x42, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x38, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x14, /* Cookie len */
+    0x00, 0x01, 0x02, 0x03, 0x04, 005, 0x06, 007, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 /* Cookie */
+};
+
+
+/* A ClientHello with a bad cookie */
+const unsigned char clienthello_badcookie[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x4E, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x42, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x42, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x14, /* Cookie len */
+    0x01, 0x01, 0x02, 0x03, 0x04, 005, 0x06, 007, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, /* Cookie */
+    0x00, 0x04, /* Ciphersuites len */
+    0x00, 0x2f, /* AES128-SHA */
+    0x00, 0xff, /* Empty reneg info SCSV */
+    0x01, /* Compression methods len */
+    0x00, /* Null compression */
+    0x00, 0x00 /* Extensions len */
+};
+
+/* A fragmented ClientHello with the fragment boundary mid cookie */
+const unsigned char clienthello_cookie_short[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x43, /* Record Length */
+    0x01, /* ClientHello */
+    0x00, 0x00, 0x42, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x37, /* Fragment length */
+    0xFE, 0xFD, /* DTLSv1.2 */
+    0xCA, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
+    0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
+    0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, /* Random */
+    0x00, /* Session id len */
+    0x14, /* Cookie len */
+    0x00, 0x01, 0x02, 0x03, 0x04, 005, 0x06, 007, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12 /* Cookie */
+};
+
+/* Bad record - too short */
+const unsigned char record_short[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* Record sequence number */
+};
+
+const unsigned char verify[] = {
+    0x16, /* Handshake */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x00, 0x00, /* Epoch */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Record sequence number */
+    0x00, 0x23, /* Record Length */
+    0x03, /* HelloVerifyRequest */
+    0x00, 0x00, 0x17, /* Message length */
+    0x00, 0x00, /* Message sequence */
+    0x00, 0x00, 0x00, /* Fragment offset */
+    0x00, 0x00, 0x17, /* Fragment length */
+    0xFE, 0xFF, /* DTLSv1.0 */
+    0x14, /* Cookie len */
+    0x00, 0x01, 0x02, 0x03, 0x04, 005, 0x06, 007, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 /* Cookie */
+};
+
+struct {
+    const unsigned char *in;
+    unsigned int inlen;
+    /*
+     * GOOD == positive return value from DTLSv1_listen, no output yet
+     * VERIFY == 0 return value, HelloVerifyRequest sent
+     * DROP == 0 return value, no output
+     */
+    enum {GOOD, VERIFY, DROP} outtype;
+} testpackets[9] = {
+    {
+        clienthello_nocookie,
+        sizeof(clienthello_nocookie),
+        VERIFY
+    },
+    {
+        clienthello_nocookie_frag,
+        sizeof(clienthello_nocookie_frag),
+        VERIFY
+    },
+    {
+        clienthello_nocookie_short,
+        sizeof(clienthello_nocookie_short),
+        DROP
+    },
+    {
+        clienthello_2ndfrag,
+        sizeof(clienthello_2ndfrag),
+        DROP
+    },
+    {
+        clienthello_cookie,
+        sizeof(clienthello_cookie),
+        GOOD
+    },
+    {
+        clienthello_cookie_frag,
+        sizeof(clienthello_cookie_frag),
+        GOOD
+    },
+    {
+        clienthello_badcookie,
+        sizeof(clienthello_badcookie),
+        VERIFY
+    },
+    {
+        clienthello_cookie_short,
+        sizeof(clienthello_cookie_short),
+        DROP
+    },
+    {
+        record_short,
+        sizeof(record_short),
+        DROP
+    }
+};
+
+#define COOKIE_LEN  20
+
+static int cookie_gen(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
+{
+    unsigned int i;
+
+    for (i = 0; i < COOKIE_LEN; i++, cookie++) {
+        *cookie = i;
+    }
+    *cookie_len = COOKIE_LEN;
+
+    return 1;
+}
+
+static int cookie_verify(SSL *ssl, const unsigned char *cookie,
+                         unsigned int cookie_len)
+{
+    unsigned int i;
+
+    if (cookie_len != COOKIE_LEN)
+        return 0;
+
+    for (i = 0; i < COOKIE_LEN; i++, cookie++) {
+        if (*cookie != i)
+            return 0;
+    }
+
+    return 1;
+}
+
+int main(void)
+{
+    SSL_CTX *ctx = NULL;
+    SSL *ssl = NULL;
+    BIO *outbio = NULL;
+    BIO *inbio = NULL;
+    BIO_ADDR *peer = BIO_ADDR_new();
+    char *data;
+    long datalen;
+    int ret, success = 0;
+    size_t i;
+
+    /* Initialise libssl */
+    SSL_load_error_strings();
+    SSL_library_init();
+
+    ctx = SSL_CTX_new(DTLS_server_method());
+    if (ctx == NULL || peer == NULL)
+        goto err;
+
+    SSL_CTX_set_cookie_generate_cb(ctx, cookie_gen);
+    SSL_CTX_set_cookie_verify_cb(ctx, cookie_verify);
+
+    /* Create an SSL object for the connection */
+    ssl = SSL_new(ctx);
+    if (ssl == NULL)
+        goto err;
+
+    outbio = BIO_new(BIO_s_mem());
+    if (outbio == NULL)
+        goto err;
+    SSL_set_wbio(ssl, outbio);
+
+    success = 1;
+    for (i = 0; i < OSSL_NELEM(testpackets) && success; i++) {
+        inbio = BIO_new_mem_buf((char *)testpackets[i].in,
+                                testpackets[i].inlen);
+        if (inbio == NULL) {
+            success = 0;
+            goto err;
+        }
+        /* Set Non-blocking IO behaviour */
+        BIO_set_mem_eof_return(inbio, -1);
+
+        SSL_set_rbio(ssl, inbio);
+
+        /* Process the incoming packet */
+        ret = DTLSv1_listen(ssl, peer);
+        if (ret < 0) {
+            success = 0;
+            goto err;
+        }
+
+        datalen = BIO_get_mem_data(outbio, &data);
+
+        if (testpackets[i].outtype == VERIFY) {
+            if (ret == 0) {
+                if (datalen != sizeof(verify)
+                        || (memcmp(data, verify, sizeof(verify)) != 0)) {
+                    printf("Test %ld failure: incorrect HelloVerifyRequest\n", i);
+                    success = 0;
+                } else {
+                    printf("Test %ld success\n", i);
+                }
+            } else {
+                printf ("Test %ld failure: should not have succeeded\n", i);
+                success = 0;
+            }
+        } else if (datalen == 0) {
+            if ((ret == 0 && testpackets[i].outtype == DROP)
+                    || (ret == 1 && testpackets[i].outtype == GOOD)) {
+                printf("Test %ld success\n", i);
+            } else {
+                printf("Test %ld failure: wrong return value\n", i);
+                success = 0;
+            }
+        } else {
+            printf("Test %ld failure: Unexpected data output\n", i);
+            success = 0;
+        }
+        (void)BIO_reset(outbio);
+        inbio = NULL;
+        /* Frees up inbio */
+        SSL_set_rbio(ssl, NULL);
+    }
+
+ err:
+    if (!success)
+        ERR_print_errors_fp(stderr);
+    /* Also frees up outbio */
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+    BIO_free(inbio);
+    /* Unitialise libssl */
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE_cleanup();
+#endif
+    CONF_modules_unload(1);
+    CRYPTO_cleanup_all_ex_data();
+    EVP_cleanup();
+    ERR_remove_thread_state(NULL);
+    ERR_free_strings();
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    CRYPTO_mem_leaks_fp(stderr);
+#endif
+    return success ? 0 : 1;
+}
+
diff --git a/test/recipes/80-test_dtlsv1listen.t b/test/recipes/80-test_dtlsv1listen.t
new file mode 100644
index 0000000..e7371ca
--- /dev/null
+++ b/test/recipes/80-test_dtlsv1listen.t
@@ -0,0 +1,5 @@
+#! /usr/bin/perl
+
+use OpenSSL::Test::Simple;
+
+simple_test("test_dtlsv1listen", "dtlsv1listentest", "dh");


More information about the openssl-commits mailing list