Add tests for DTLSv1_listen
authorMatt Caswell <matt@openssl.org>
Thu, 21 Jan 2016 12:22:58 +0000 (12:22 +0000)
committerMatt Caswell <matt@openssl.org>
Fri, 5 Feb 2016 20:47:36 +0000 (20:47 +0000)
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@openssl.org>
ssl/d1_lib.c
test/Makefile.in
test/dtlsv1listentest.c [new file with mode: 0644]
test/recipes/80-test_dtlsv1listen.t [new file with mode: 0644]

index 4aea13cc8c37a3dbf94941823d36a9deea7249d4..b1f6ed207d0188a3efb97bf04e4f9b628905cfba 100644 (file)
@@ -811,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;
@@ -868,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;
index cf6e8163a009985cf6f23d89cbdb2979e33ed212..96ee8f46fbed73ed958830d074d4bd64ab769783 100644 (file)
@@ -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 (file)
index 0000000..28b493e
--- /dev/null
@@ -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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@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 (file)
index 0000000..e7371ca
--- /dev/null
@@ -0,0 +1,5 @@
+#! /usr/bin/perl
+
+use OpenSSL::Test::Simple;
+
+simple_test("test_dtlsv1listen", "dtlsv1listentest", "dh");