[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Aug 19 13:08:04 UTC 2016


The branch master has been updated
       via  7f35b7d9c5f41cac834c9fe20a16757adbd06535 (commit)
       via  52a03d2a5e28a379d94d38c629d05b2a3ab0ff19 (commit)
       via  1fb9fdc3027b27d8eb6a1e6a846435b070980770 (commit)
       via  ac9fc67a488427bc3e987f5a4c235e8fbeedf711 (commit)
       via  738ad946ddf7cbb839447981304df89f5f83b18b (commit)
       via  6fc1748ec65c94c195d02b59556434e36a5f7651 (commit)
       via  b4982125e63882cf9d77c704ef555105528a5dac (commit)
       via  d82dec40ba87408697357b04ba0d71a2be69c5fb (commit)
       via  d9a2e90bcede62cce36a845a677f99a22c419a9c (commit)
      from  15269e565427e9025c733c2a8b3d4b6d6c5a3bd3 (commit)


- Log -----------------------------------------------------------------
commit 7f35b7d9c5f41cac834c9fe20a16757adbd06535
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Aug 19 13:50:01 2016 +0100

    Update function error code
    
    A function error code needed updating due to merge issues.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 52a03d2a5e28a379d94d38c629d05b2a3ab0ff19
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jul 19 11:34:21 2016 +0100

    Fix some clang warnings
    
    Clang was complaining about some unused functions. Moving the stack
    declaration to the header seems to sort it. Also the certstatus variable
    in dtlstest needed to be declared static.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 1fb9fdc3027b27d8eb6a1e6a846435b070980770
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 1 15:20:33 2016 +0100

    Fix DTLS replay protection
    
    The DTLS implementation provides some protection against replay attacks
    in accordance with RFC6347 section 4.1.2.6.
    
    A sliding "window" of valid record sequence numbers is maintained with
    the "right" hand edge of the window set to the highest sequence number we
    have received so far. Records that arrive that are off the "left" hand
    edge of the window are rejected. Records within the window are checked
    against a list of records received so far. If we already received it then
    we also reject the new record.
    
    If we have not already received the record, or the sequence number is off
    the right hand edge of the window then we verify the MAC of the record.
    If MAC verification fails then we discard the record. Otherwise we mark
    the record as received. If the sequence number was off the right hand edge
    of the window, then we slide the window along so that the right hand edge
    is in line with the newly received sequence number.
    
    Records may arrive for future epochs, i.e. a record from after a CCS being
    sent, can arrive before the CCS does if the packets get re-ordered. As we
    have not yet received the CCS we are not yet in a position to decrypt or
    validate the MAC of those records. OpenSSL places those records on an
    unprocessed records queue. It additionally updates the window immediately,
    even though we have not yet verified the MAC. This will only occur if
    currently in a handshake/renegotiation.
    
    This could be exploited by an attacker by sending a record for the next
    epoch (which does not have to decrypt or have a valid MAC), with a very
    large sequence number. This means the right hand edge of the window is
    moved very far to the right, and all subsequent legitimate packets are
    dropped causing a denial of service.
    
    A similar effect can be achieved during the initial handshake. In this
    case there is no MAC key negotiated yet. Therefore an attacker can send a
    message for the current epoch with a very large sequence number. The code
    will process the record as normal. If the hanshake message sequence number
    (as opposed to the record sequence number that we have been talking about
    so far) is in the future then the injected message is bufferred to be
    handled later, but the window is still updated. Therefore all subsequent
    legitimate handshake records are dropped. This aspect is not considered a
    security issue because there are many ways for an attacker to disrupt the
    initial handshake and prevent it from completing successfully (e.g.
    injection of a handshake message will cause the Finished MAC to fail and
    the handshake to be aborted). This issue comes about as a result of trying
    to do replay protection, but having no integrity mechanism in place yet.
    Does it even make sense to have replay protection in epoch 0? That
    issue isn't addressed here though.
    
    This addressed an OCAP Audit issue.
    
    CVE-2016-2181
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ac9fc67a488427bc3e987f5a4c235e8fbeedf711
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jul 5 09:50:55 2016 +0100

    Add DTLS replay protection test
    
    Injects a record from epoch 1 during epoch 0 handshake, with a record
    sequence number in the future, to test that the record replay protection
    feature works as expected. This is described more fully in the next commit.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 738ad946ddf7cbb839447981304df89f5f83b18b
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jul 5 09:51:08 2016 +0100

    Fix DTLS unprocessed records bug
    
    During a DTLS handshake we may get records destined for the next epoch
    arrive before we have processed the CCS. In that case we can't decrypt or
    verify the record yet, so we buffer it for later use. When we do receive
    the CCS we work through the queue of unprocessed records and process them.
    
    Unfortunately the act of processing wipes out any existing packet data
    that we were still working through. This includes any records from the new
    epoch that were in the same packet as the CCS. We should only process the
    buffered records if we've not got any data left.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 6fc1748ec65c94c195d02b59556434e36a5f7651
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jul 4 14:59:06 2016 +0100

    Add a DTLS unprocesed records test
    
    Add a test to inject a record from the next epoch during the handshake and
    make sure it doesn't get processed immediately.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit b4982125e63882cf9d77c704ef555105528a5dac
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jul 4 14:55:50 2016 +0100

    Split create_ssl_connection()
    
    Split the create_ssl_connection() helper function into two steps: one to
    create the SSL objects, and one to actually create the connection. This
    provides the ability to make changes to the SSL object before the
    connection is actually made.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d82dec40ba87408697357b04ba0d71a2be69c5fb
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jul 4 14:53:28 2016 +0100

    Add a DTLS packet mem BIO
    
    This adds a BIO similar to a normal mem BIO but with datagram awareness.
    It also has the capability to inject additional packets at arbitrary
    locations into the BIO, for testing purposes.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d9a2e90bcede62cce36a845a677f99a22c419a9c
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jul 4 14:51:56 2016 +0100

    Add a (D)TLS dumper BIO
    
    Dump out the records passed over the BIO. Only works for DTLS at the
    moment but could easily be extended to TLS.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h                              |   1 +
 ssl/record/rec_layer_d1.c                          |  69 ++-
 ssl/record/record_locl.h                           |   2 +-
 ssl/record/ssl3_record.c                           |  20 +-
 ssl/ssl_err.c                                      |   2 +
 test/asynciotest.c                                 |   9 +-
 test/build.info                                    |   6 +-
 test/dtlstest.c                                    | 142 ++++++
 test/recipes/{70-test_asyncio.t => 80-test_dtls.t} |  11 +-
 test/sslapitest.c                                  |  32 +-
 test/ssltestlib.c                                  | 568 ++++++++++++++++++++-
 test/ssltestlib.h                                  |  23 +-
 12 files changed, 825 insertions(+), 60 deletions(-)
 create mode 100644 test/dtlstest.c
 copy test/recipes/{70-test_asyncio.t => 80-test_dtls.t} (59%)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index a7732ff..41cb36e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2066,6 +2066,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_DTLS1_CHECK_TIMEOUT_NUM                    318
 # define SSL_F_DTLS1_HEARTBEAT                            305
 # define SSL_F_DTLS1_PREPROCESS_FRAGMENT                  288
+# define SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS             424
 # define SSL_F_DTLS1_PROCESS_RECORD                       257
 # define SSL_F_DTLS1_READ_BYTES                           258
 # define SSL_F_DTLS1_READ_FAILED                          339
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index f9bf109..be6aac7 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -229,22 +229,70 @@ int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
 int dtls1_process_buffered_records(SSL *s)
 {
     pitem *item;
+    SSL3_BUFFER *rb;
+    SSL3_RECORD *rr;
+    DTLS1_BITMAP *bitmap;
+    unsigned int is_next_epoch;
+    int replayok = 1;
 
     item = pqueue_peek(s->rlayer.d->unprocessed_rcds.q);
     if (item) {
         /* Check if epoch is current. */
         if (s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch)
-            return (1);         /* Nothing to do. */
+            return 1;         /* Nothing to do. */
+
+        rr = RECORD_LAYER_get_rrec(&s->rlayer);
+
+        rb = RECORD_LAYER_get_rbuf(&s->rlayer);
+
+        if (SSL3_BUFFER_get_left(rb) > 0) {
+            /*
+             * We've still got data from the current packet to read. There could
+             * be a record from the new epoch in it - so don't overwrite it
+             * with the unprocessed records yet (we'll do it when we've
+             * finished reading the current packet).
+             */
+            return 1;
+        }
 
         /* Process all the records. */
         while (pqueue_peek(s->rlayer.d->unprocessed_rcds.q)) {
             dtls1_get_unprocessed_record(s);
-            if (!dtls1_process_record(s))
-                return (0);
+            bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+            if (bitmap == NULL) {
+                /*
+                 * Should not happen. This will only ever be NULL when the
+                 * current record is from a different epoch. But that cannot
+                 * be the case because we already checked the epoch above
+                 */
+                 SSLerr(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS,
+                        ERR_R_INTERNAL_ERROR);
+                 return 0;
+            }
+#ifndef OPENSSL_NO_SCTP
+            /* Only do replay check if no SCTP bio */
+            if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
+#endif
+            {
+                /*
+                 * Check whether this is a repeat, or aged record. We did this
+                 * check once already when we first received the record - but
+                 * we might have updated the window since then due to
+                 * records we subsequently processed.
+                 */
+                replayok = dtls1_record_replay_check(s, bitmap);
+            }
+
+            if (!replayok || !dtls1_process_record(s, bitmap)) {
+                /* dump this record */
+                rr->length = 0;
+                RECORD_LAYER_reset_packet_length(&s->rlayer);
+                continue;
+            }
+
             if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds),
-                                    SSL3_RECORD_get_seq_num(s->rlayer.rrec)) <
-                0)
-                return -1;
+                    SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0)
+                return 0;
         }
     }
 
@@ -255,7 +303,7 @@ int dtls1_process_buffered_records(SSL *s)
     s->rlayer.d->processed_rcds.epoch = s->rlayer.d->r_epoch;
     s->rlayer.d->unprocessed_rcds.epoch = s->rlayer.d->r_epoch + 1;
 
-    return (1);
+    return 1;
 }
 
 /*-
@@ -1115,8 +1163,13 @@ DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
     if (rr->epoch == s->rlayer.d->r_epoch)
         return &s->rlayer.d->bitmap;
 
-    /* Only HM and ALERT messages can be from the next epoch */
+    /*
+     * Only HM and ALERT messages can be from the next epoch and only if we
+     * have already processed all of the unprocessed records from the last
+     * epoch
+     */
     else if (rr->epoch == (unsigned long)(s->rlayer.d->r_epoch + 1) &&
+             s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch &&
              (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
         *is_next_epoch = 1;
         return &s->rlayer.d->next_bitmap;
diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index 3b9a700..52e59e4 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -110,5 +110,5 @@ __owur int ssl3_cbc_remove_padding(SSL3_RECORD *rec,
 __owur int tls1_cbc_remove_padding(const SSL *s,
                                    SSL3_RECORD *rec,
                                    unsigned block_size, unsigned mac_size);
-int dtls1_process_record(SSL *s);
+int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
 __owur int dtls1_get_record(SSL *s);
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 1782780..32a97af 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -1273,7 +1273,7 @@ void ssl3_cbc_copy_mac(unsigned char *out,
 #endif
 }
 
-int dtls1_process_record(SSL *s)
+int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
 {
     int i, al;
     int enc_err;
@@ -1429,6 +1429,10 @@ int dtls1_process_record(SSL *s)
 
     /* we have pulled in a full packet so zero things */
     RECORD_LAYER_reset_packet_length(&s->rlayer);
+
+    /* Mark receipt of record. */
+    dtls1_record_bitmap_update(s, bitmap);
+
     return (1);
 
  f_err:
@@ -1467,11 +1471,12 @@ int dtls1_get_record(SSL *s)
 
     rr = RECORD_LAYER_get_rrec(&s->rlayer);
 
+ again:
     /*
      * The epoch may have changed.  If so, process all the pending records.
      * This is a non-blocking operation.
      */
-    if (dtls1_process_buffered_records(s) < 0)
+    if (!dtls1_process_buffered_records(s))
         return -1;
 
     /* if we're renegotiating, then there may be buffered records */
@@ -1479,7 +1484,7 @@ int dtls1_get_record(SSL *s)
         return 1;
 
     /* get something from the wire */
- again:
+
     /* check if we have the header */
     if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
         (RECORD_LAYER_get_packet_length(&s->rlayer) < DTLS1_RT_HEADER_LENGTH)) {
@@ -1579,6 +1584,10 @@ int dtls1_get_record(SSL *s)
     if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) {
 #endif
         /* Check whether this is a repeat, or aged record. */
+        /*
+         * TODO: Does it make sense to have replay protection in epoch 0 where
+         * we have no integrity negotiated yet?
+         */
         if (!dtls1_record_replay_check(s, bitmap)) {
             rr->length = 0;
             RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
@@ -1603,20 +1612,17 @@ int dtls1_get_record(SSL *s)
                 (s, &(DTLS_RECORD_LAYER_get_unprocessed_rcds(&s->rlayer)),
                  rr->seq_num) < 0)
                 return -1;
-            /* Mark receipt of record. */
-            dtls1_record_bitmap_update(s, bitmap);
         }
         rr->length = 0;
         RECORD_LAYER_reset_packet_length(&s->rlayer);
         goto again;
     }
 
-    if (!dtls1_process_record(s)) {
+    if (!dtls1_process_record(s, bitmap)) {
         rr->length = 0;
         RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
         goto again;             /* get another record */
     }
-    dtls1_record_bitmap_update(s, bitmap); /* Mark receipt of record. */
 
     return (1);
 
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 9644fd2..1fddda6 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -32,6 +32,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_DTLS1_CHECK_TIMEOUT_NUM), "dtls1_check_timeout_num"},
     {ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "dtls1_heartbeat"},
     {ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "dtls1_preprocess_fragment"},
+    {ERR_FUNC(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS),
+     "dtls1_process_buffered_records"},
     {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "dtls1_process_record"},
     {ERR_FUNC(SSL_F_DTLS1_READ_BYTES), "dtls1_read_bytes"},
     {ERR_FUNC(SSL_F_DTLS1_READ_FAILED), "dtls1_read_failed"},
diff --git a/test/asynciotest.c b/test/asynciotest.c
index de67cce..720cc7c 100644
--- a/test/asynciotest.c
+++ b/test/asynciotest.c
@@ -276,8 +276,13 @@ int main(int argc, char *argv[])
         }
 
         /* BIOs get freed on error */
-        if (!create_ssl_connection(serverctx, clientctx, &serverssl, &clientssl,
-                                   s_to_c_fbio, c_to_s_fbio)) {
+        if (!create_ssl_objects(serverctx, clientctx, &serverssl, &clientssl,
+                                s_to_c_fbio, c_to_s_fbio)) {
+            printf("Test %d failed: Create SSL objects failed\n", test);
+            goto end;
+        }
+
+        if (!create_ssl_connection(serverssl, clientssl)) {
             printf("Test %d failed: Create SSL connection failed\n", test);
             goto end;
         }
diff --git a/test/build.info b/test/build.info
index 0c51d1e..ec450c2 100644
--- a/test/build.info
+++ b/test/build.info
@@ -16,7 +16,7 @@ IF[{- !$disabled{tests} -}]
           packettest asynctest secmemtest srptest memleaktest \
           dtlsv1listentest ct_test threadstest afalgtest d2i_test \
           ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \
-          bioprinttest sslapitest
+          bioprinttest sslapitest dtlstest
 
   SOURCE[aborttest]=aborttest.c
   INCLUDE[aborttest]=../include
@@ -266,6 +266,10 @@ IF[{- !$disabled{tests} -}]
   SOURCE[sslapitest]=sslapitest.c ssltestlib.c testutil.c
   INCLUDE[sslapitest]=../include
   DEPEND[sslapitest]=../libcrypto ../libssl
+
+  SOURCE[dtlstest]=dtlstest.c ssltestlib.c testutil.c
+  INCLUDE[dtlstest]=../include .
+  DEPEND[dtlstest]=../libcrypto ../libssl
 ENDIF
 
 {-
diff --git a/test/dtlstest.c b/test/dtlstest.c
new file mode 100644
index 0000000..4d497af
--- /dev/null
+++ b/test/dtlstest.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "ssltestlib.h"
+#include "testutil.h"
+
+static char *cert = NULL;
+static char *privkey = NULL;
+
+#define NUM_TESTS   2
+
+
+#define DUMMY_CERT_STATUS_LEN  12
+
+static unsigned char certstatus[] = {
+    SSL3_RT_HANDSHAKE, /* Content type */
+    0xfe, 0xfd, /* Record version */
+    0, 1, /* Epoch */
+    0, 0, 0, 0, 0, 0x0f, /* Record sequence number */
+    0, DTLS1_HM_HEADER_LENGTH + DUMMY_CERT_STATUS_LEN - 2,
+    SSL3_MT_CERTIFICATE_STATUS, /* Cert Status handshake message type */
+    0, 0, DUMMY_CERT_STATUS_LEN, /* Message len */
+    0, 5, /* Message sequence */
+    0, 0, 0, /* Fragment offset */
+    0, 0, DUMMY_CERT_STATUS_LEN - 2, /* Fragment len */
+    0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80 /* Dummy data */
+};
+
+#define RECORD_SEQUENCE 10
+
+static int test_dtls_unprocessed(int testidx)
+{
+    SSL_CTX *sctx = NULL, *cctx = NULL;
+    SSL *serverssl1 = NULL, *clientssl1 = NULL;
+    BIO *c_to_s_fbio, *c_to_s_mempacket;
+    int testresult = 0;
+
+    printf("Starting Test %d\n", testidx);
+
+    if (!create_ssl_ctx_pair(DTLS_server_method(), DTLS_client_method(), &sctx,
+                             &cctx, cert, privkey)) {
+        printf("Unable to create SSL_CTX pair\n");
+        return 0;
+    }
+
+    if (!SSL_CTX_set_cipher_list(cctx, "ECDHE-RSA-AES256-SHA384")) {
+        printf("Failed setting cipher list\n");
+    }
+
+    c_to_s_fbio = BIO_new(bio_f_tls_dump_filter());
+    if (c_to_s_fbio == NULL) {
+        printf("Failed to create filter BIO\n");
+        goto end;
+    }
+
+    /* BIO is freed by create_ssl_connection on error */
+    if (!create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL,
+                               c_to_s_fbio)) {
+        printf("Unable to create SSL objects\n");
+        ERR_print_errors_fp(stdout);
+        goto end;
+    }
+
+    if (testidx == 1)
+        certstatus[RECORD_SEQUENCE] = 0xff;
+
+    /*
+     * Inject a dummy record from the next epoch. In test 0, this should never
+     * get used because the message sequence number is too big. In test 1 we set
+     * the record sequence number to be way off in the future. This should not
+     * have an impact on the record replay protection because the record should
+     * be dropped before it is marked as arrived
+     */
+    c_to_s_mempacket = SSL_get_wbio(clientssl1);
+    c_to_s_mempacket = BIO_next(c_to_s_mempacket);
+    mempacket_test_inject(c_to_s_mempacket, (char *)certstatus,
+                          sizeof(certstatus), 1, INJECT_PACKET_IGNORE_REC_SEQ);
+
+    if (!create_ssl_connection(serverssl1, clientssl1)) {
+        printf("Unable to create SSL connection\n");
+        ERR_print_errors_fp(stdout);
+        goto end;
+    }
+
+    testresult = 1;
+ end:
+    SSL_free(serverssl1);
+    SSL_free(clientssl1);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
+int main(int argc, char *argv[])
+{
+    BIO *err = NULL;
+    int testresult = 1;
+
+    if (argc != 3) {
+        printf("Invalid argument count\n");
+        return 1;
+    }
+
+    cert = argv[1];
+    privkey = argv[2];
+
+    err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+
+    CRYPTO_set_mem_debug(1);
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+    ADD_ALL_TESTS(test_dtls_unprocessed, NUM_TESTS);
+
+    testresult = run_tests(argv[0]);
+
+    bio_f_tls_dump_filter_free();
+    bio_s_mempacket_test_free();
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (CRYPTO_mem_leaks(err) <= 0)
+        testresult = 1;
+#endif
+    BIO_free(err);
+
+    if (!testresult)
+        printf("PASS\n");
+
+    return testresult;
+}
diff --git a/test/recipes/70-test_asyncio.t b/test/recipes/80-test_dtls.t
similarity index 59%
copy from test/recipes/70-test_asyncio.t
copy to test/recipes/80-test_dtls.t
index c26f757..008c817 100644
--- a/test/recipes/70-test_asyncio.t
+++ b/test/recipes/80-test_dtls.t
@@ -6,17 +6,16 @@
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 
-
 use OpenSSL::Test;
 use OpenSSL::Test::Utils;
 use OpenSSL::Test qw/:DEFAULT srctop_file/;
 
-setup("test_asyncio");
+setup("test_dtls");
 
-plan skip_all => "No TLS/SSL protocols are supported by this OpenSSL build"
-    if alldisabled(grep { $_ ne "ssl3" } available_protocols("tls"));
+plan skip_all => "No DTLS protocols are supported by this OpenSSL build"
+    if alldisabled(available_protocols("dtls"));
 
 plan tests => 1;
 
-ok(run(test(["asynciotest", srctop_file("apps", "server.pem"),
-             srctop_file("apps", "server.pem")])), "running asynciotest");
+ok(run(test(["dtlstest", srctop_file("apps", "server.pem"),
+             srctop_file("apps", "server.pem")])), "running dtlstest");
diff --git a/test/sslapitest.c b/test/sslapitest.c
index cb86217..cc790a0 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -122,7 +122,9 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
     SSL_CTX *sctx = NULL, *cctx = NULL;
     SSL *serverssl1 = NULL, *clientssl1 = NULL;
     SSL *serverssl2 = NULL, *clientssl2 = NULL;
+#ifndef OPENSSL_NO_TLS1_1
     SSL *serverssl3 = NULL, *clientssl3 = NULL;
+#endif
     SSL_SESSION *sess1 = NULL, *sess2 = NULL;
     int testresult = 0;
 
@@ -151,8 +153,13 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
                                        | SSL_SESS_CACHE_NO_INTERNAL_STORE);
     }
 
-    if (!create_ssl_connection(sctx, cctx, &serverssl1, &clientssl1, NULL,
+    if (!create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, NULL,
                                NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl1, clientssl1)) {
         printf("Unable to create SSL connection\n");
         goto end;
     }
@@ -173,8 +180,12 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
         goto end;
     }
 
-    if (!create_ssl_connection(sctx, cctx, &serverssl2, &clientssl2, NULL,
-                               NULL)) {
+    if (!create_ssl_objects(sctx, cctx, &serverssl2, &clientssl2, NULL, NULL)) {
+        printf("Unable to create second SSL objects\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl2, clientssl2)) {
         printf("Unable to create second SSL connection\n");
         goto end;
     }
@@ -245,23 +256,24 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
 #if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_2)
     /* Force a connection failure */
     SSL_CTX_set_max_proto_version(sctx, TLS1_1_VERSION);
-    clientssl3 = SSL_new(cctx);
-    if (clientssl3 == NULL) {
-        printf("Malloc failure\n");
+
+    if (!create_ssl_objects(sctx, cctx, &serverssl3, &clientssl3, NULL, NULL)) {
+        printf("Unable to create third SSL objects\n");
         goto end;
     }
+
     if (!SSL_set_session(clientssl3, sess1)) {
         printf("Unable to set session for third connection\n");
         goto end;
     }
 
     /* This should fail because of the mismatched protocol versions */
-    if (create_ssl_connection(sctx, cctx, &serverssl3, &clientssl3, NULL,
-                               NULL)) {
-        printf("Unexpected success creating SSL connection\n");
+    if (create_ssl_connection(serverssl3, clientssl3)) {
+        printf("Unable to create third SSL connection\n");
         goto end;
     }
 
+
     /* We should have automatically removed the session from the cache */
     if (fix.use_ext_cache && (new_called != 2 || remove_called != 3)) {
         printf("Failed to call callback to remove session #2\n");
@@ -284,8 +296,10 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
     SSL_free(clientssl1);
     SSL_free(serverssl2);
     SSL_free(clientssl2);
+#ifndef OPENSSL_NO_TLS1_1
     SSL_free(serverssl3);
     SSL_free(clientssl3);
+#endif
     SSL_SESSION_free(sess1);
     SSL_SESSION_free(sess2);
     /*
diff --git a/test/ssltestlib.c b/test/ssltestlib.c
index 6d638a2..ff5cbed 100644
--- a/test/ssltestlib.c
+++ b/test/ssltestlib.c
@@ -7,8 +7,521 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h>
+
 #include "ssltestlib.h"
 
+static int tls_dump_new(BIO *bi);
+static int tls_dump_free(BIO *a);
+static int tls_dump_read(BIO *b, char *out, int outl);
+static int tls_dump_write(BIO *b, const char *in, int inl);
+static long tls_dump_ctrl(BIO *b, int cmd, long num, void *ptr);
+static int tls_dump_gets(BIO *bp, char *buf, int size);
+static int tls_dump_puts(BIO *bp, const char *str);
+
+/* Choose a sufficiently large type likely to be unused for this custom BIO */
+# define BIO_TYPE_TLS_DUMP_FILTER  (0x80 | BIO_TYPE_FILTER)
+
+# define BIO_TYPE_MEMPACKET_TEST      0x81
+
+static BIO_METHOD *method_tls_dump = NULL;
+static BIO_METHOD *method_mempacket_test = NULL;
+
+/* Note: Not thread safe! */
+const BIO_METHOD *bio_f_tls_dump_filter(void)
+{
+    if (method_tls_dump == NULL) {
+        method_tls_dump = BIO_meth_new(BIO_TYPE_TLS_DUMP_FILTER,
+                                        "TLS dump filter");
+        if (   method_tls_dump == NULL
+            || !BIO_meth_set_write(method_tls_dump, tls_dump_write)
+            || !BIO_meth_set_read(method_tls_dump, tls_dump_read)
+            || !BIO_meth_set_puts(method_tls_dump, tls_dump_puts)
+            || !BIO_meth_set_gets(method_tls_dump, tls_dump_gets)
+            || !BIO_meth_set_ctrl(method_tls_dump, tls_dump_ctrl)
+            || !BIO_meth_set_create(method_tls_dump, tls_dump_new)
+            || !BIO_meth_set_destroy(method_tls_dump, tls_dump_free))
+            return NULL;
+    }
+    return method_tls_dump;
+}
+
+void bio_f_tls_dump_filter_free(void)
+{
+    BIO_meth_free(method_tls_dump);
+}
+
+static int tls_dump_new(BIO *bio)
+{
+    BIO_set_init(bio, 1);
+    return 1;
+}
+
+static int tls_dump_free(BIO *bio)
+{
+    BIO_set_init(bio, 0);
+
+    return 1;
+}
+
+static void copy_flags(BIO *bio)
+{
+    int flags;
+    BIO *next = BIO_next(bio);
+
+    flags = BIO_test_flags(next, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
+    BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
+    BIO_set_flags(bio, flags);
+}
+
+#define RECORD_CONTENT_TYPE     0
+#define RECORD_VERSION_HI       1
+#define RECORD_VERSION_LO       2
+#define RECORD_EPOCH_HI         3
+#define RECORD_EPOCH_LO         4
+#define RECORD_SEQUENCE_START   5
+#define RECORD_SEQUENCE_END     10
+#define RECORD_LEN_HI           11
+#define RECORD_LEN_LO           12
+
+#define MSG_TYPE                0
+#define MSG_LEN_HI              1
+#define MSG_LEN_MID             2
+#define MSG_LEN_LO              3
+#define MSG_SEQ_HI              4
+#define MSG_SEQ_LO              5
+#define MSG_FRAG_OFF_HI         6
+#define MSG_FRAG_OFF_MID        7
+#define MSG_FRAG_OFF_LO         8
+#define MSG_FRAG_LEN_HI         9
+#define MSG_FRAG_LEN_MID        10
+#define MSG_FRAG_LEN_LO         11
+
+
+static void dump_data(const char *data, int len)
+{
+    int rem, i, content, reclen, msglen, fragoff, fraglen, epoch;
+    unsigned char *rec;
+
+    printf("---- START OF PACKET ----\n");
+
+    rem = len;
+    rec = (unsigned char *)data;
+
+    while (rem > 0) {
+        if (rem != len)
+            printf("*\n");
+        printf("*---- START OF RECORD ----\n");
+        if (rem < DTLS1_RT_HEADER_LENGTH) {
+            printf("*---- RECORD TRUNCATED ----\n");
+            break;
+        }
+        content = rec[RECORD_CONTENT_TYPE];
+        printf("** Record Content-type: %d\n", content);
+        printf("** Record Version: %02x%02x\n",
+               rec[RECORD_VERSION_HI], rec[RECORD_VERSION_LO]);
+        epoch = (rec[RECORD_EPOCH_HI] << 8) | rec[RECORD_EPOCH_LO];
+        printf("** Record Epoch: %d\n", epoch);
+        printf("** Record Sequence: ");
+        for (i = RECORD_SEQUENCE_START; i <= RECORD_SEQUENCE_END; i++)
+            printf("%02x", rec[i]);
+        reclen = (rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO];
+        printf("\n** Record Length: %d\n", reclen);
+
+        /* Now look at message */
+        rec += DTLS1_RT_HEADER_LENGTH;
+        rem -= DTLS1_RT_HEADER_LENGTH;
+        if (content == SSL3_RT_HANDSHAKE) {
+            printf("**---- START OF HANDSHAKE MESSAGE FRAGMENT ----\n");
+            if (epoch > 0) {
+                printf("**---- HANDSHAKE MESSAGE FRAGMENT ENCRYPTED ----\n");
+            } else if (rem < DTLS1_HM_HEADER_LENGTH
+                    || reclen < DTLS1_HM_HEADER_LENGTH) {
+                printf("**---- HANDSHAKE MESSAGE FRAGMENT TRUNCATED ----\n");
+            } else {
+                printf("*** Message Type: %d\n", rec[MSG_TYPE]);
+                msglen = (rec[MSG_LEN_HI] << 16) | (rec[MSG_LEN_MID] << 8)
+                         | rec[MSG_LEN_LO];
+                printf("*** Message Length: %d\n", msglen);
+                printf("*** Message sequence: %d\n",
+                       (rec[MSG_SEQ_HI] << 8) | rec[MSG_SEQ_LO]);
+                fragoff = (rec[MSG_FRAG_OFF_HI] << 16)
+                          | (rec[MSG_FRAG_OFF_MID] << 8)
+                          | rec[MSG_FRAG_OFF_LO];
+                printf("*** Message Fragment offset: %d\n", fragoff);
+                fraglen = (rec[MSG_FRAG_LEN_HI] << 16)
+                          | (rec[MSG_FRAG_LEN_MID] << 8)
+                          | rec[MSG_FRAG_LEN_LO];
+                printf("*** Message Fragment len: %d\n", fraglen);
+                if (fragoff + fraglen > msglen)
+                    printf("***---- HANDSHAKE MESSAGE FRAGMENT INVALID ----\n");
+                else if(reclen < fraglen)
+                    printf("**---- HANDSHAKE MESSAGE FRAGMENT TRUNCATED ----\n");
+                else
+                    printf("**---- END OF HANDSHAKE MESSAGE FRAGMENT ----\n");
+            }
+        }
+        if (rem < reclen) {
+            printf("*---- RECORD TRUNCATED ----\n");
+            rem = 0;
+        } else {
+            rec += reclen;
+            rem -= reclen;
+            printf("*---- END OF RECORD ----\n");
+        }
+    }
+    printf("---- END OF PACKET ----\n\n");
+    fflush(stdout);
+}
+
+static int tls_dump_read(BIO *bio, char *out, int outl)
+{
+    int ret;
+    BIO *next = BIO_next(bio);
+
+    ret = BIO_read(next, out, outl);
+    copy_flags(bio);
+
+    if (ret > 0) {
+        dump_data(out, ret);
+    }
+
+    return ret;
+}
+
+static int tls_dump_write(BIO *bio, const char *in, int inl)
+{
+    int ret;
+    BIO *next = BIO_next(bio);
+
+    ret = BIO_write(next, in, inl);
+    copy_flags(bio);
+
+    return ret;
+}
+
+static long tls_dump_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+    long ret;
+    BIO *next = BIO_next(bio);
+
+    if (next == NULL)
+        return 0;
+
+    switch (cmd) {
+    case BIO_CTRL_DUP:
+        ret = 0L;
+        break;
+    default:
+        ret = BIO_ctrl(next, cmd, num, ptr);
+        break;
+    }
+    return ret;
+}
+
+static int tls_dump_gets(BIO *bio, char *buf, int size)
+{
+    /* We don't support this - not needed anyway */
+    return -1;
+}
+
+static int tls_dump_puts(BIO *bio, const char *str)
+{
+    return tls_dump_write(bio, str, strlen(str));
+}
+
+
+typedef struct mempacket_st {
+    unsigned char *data;
+    int len;
+    unsigned int num;
+    unsigned int type;
+} MEMPACKET;
+
+static void mempacket_free(MEMPACKET *pkt)
+{
+    if (pkt->data != NULL)
+        OPENSSL_free(pkt->data);
+    OPENSSL_free(pkt);
+}
+
+typedef struct mempacket_test_ctx_st {
+    STACK_OF(MEMPACKET) *pkts;
+    unsigned int epoch;
+    unsigned int currrec;
+    unsigned int currpkt;
+    unsigned int lastpkt;
+    unsigned int noinject;
+} MEMPACKET_TEST_CTX;
+
+static int mempacket_test_new(BIO *bi);
+static int mempacket_test_free(BIO *a);
+static int mempacket_test_read(BIO *b, char *out, int outl);
+static int mempacket_test_write(BIO *b, const char *in, int inl);
+static long mempacket_test_ctrl(BIO *b, int cmd, long num, void *ptr);
+static int mempacket_test_gets(BIO *bp, char *buf, int size);
+static int mempacket_test_puts(BIO *bp, const char *str);
+
+const BIO_METHOD *bio_s_mempacket_test(void)
+{
+    if (method_mempacket_test == NULL) {
+        method_mempacket_test = BIO_meth_new(BIO_TYPE_MEMPACKET_TEST,
+                                             "Mem Packet Test");
+        if (   method_mempacket_test == NULL
+            || !BIO_meth_set_write(method_mempacket_test, mempacket_test_write)
+            || !BIO_meth_set_read(method_mempacket_test, mempacket_test_read)
+            || !BIO_meth_set_puts(method_mempacket_test, mempacket_test_puts)
+            || !BIO_meth_set_gets(method_mempacket_test, mempacket_test_gets)
+            || !BIO_meth_set_ctrl(method_mempacket_test, mempacket_test_ctrl)
+            || !BIO_meth_set_create(method_mempacket_test, mempacket_test_new)
+            || !BIO_meth_set_destroy(method_mempacket_test, mempacket_test_free))
+            return NULL;
+    }
+    return method_mempacket_test;
+}
+
+void bio_s_mempacket_test_free(void)
+{
+    BIO_meth_free(method_mempacket_test);
+}
+
+static int mempacket_test_new(BIO *bio)
+{
+    MEMPACKET_TEST_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL)
+        return 0;
+    ctx->pkts = sk_MEMPACKET_new_null();
+    if (ctx->pkts == NULL) {
+        OPENSSL_free(ctx);
+        return 0;
+    }
+    BIO_set_init(bio, 1);
+    BIO_set_data(bio, ctx);
+    return 1;
+}
+
+static int mempacket_test_free(BIO *bio)
+{
+    MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+
+    sk_MEMPACKET_pop_free(ctx->pkts, mempacket_free);
+    OPENSSL_free(ctx);
+    BIO_set_data(bio, NULL);
+    BIO_set_init(bio, 0);
+
+    return 1;
+}
+
+/* Record Header values */
+#define EPOCH_HI        4
+#define EPOCH_LO        5
+#define RECORD_SEQUENCE 10
+#define RECORD_LEN_HI   11
+#define RECORD_LEN_LO   12
+
+#define STANDARD_PACKET                 0
+
+static int mempacket_test_read(BIO *bio, char *out, int outl)
+{
+    MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+    MEMPACKET *thispkt;
+    unsigned char *rec;
+    int rem;
+    unsigned int seq, offset, len, epoch;
+
+    BIO_clear_retry_flags(bio);
+
+    thispkt = sk_MEMPACKET_value(ctx->pkts, 0);
+    if (thispkt == NULL || thispkt->num != ctx->currpkt) {
+        /* Probably run out of data */
+        BIO_set_retry_read(bio);
+        return -1;
+    }
+    sk_MEMPACKET_shift(ctx->pkts);
+    ctx->currpkt++;
+
+    if (outl > thispkt->len)
+        outl = thispkt->len;
+
+    if (thispkt->type != INJECT_PACKET_IGNORE_REC_SEQ) {
+        /*
+         * Overwrite the record sequence number. We strictly number them in
+         * the order received. Since we are actually a reliable transport
+         * we know that there won't be any re-ordering. We overwrite to deal
+         * with any packets that have been injected
+         */
+        rem = thispkt->len;
+        rec = thispkt->data;
+        while (rem > 0) {
+            if (rem < DTLS1_RT_HEADER_LENGTH) {
+                return -1;
+            }
+            epoch = (rec[EPOCH_HI] << 8) | rec[EPOCH_LO];
+            if (epoch != ctx->epoch) {
+                ctx->epoch = epoch;
+                ctx->currrec = 0;
+            }
+            seq = ctx->currrec;
+            offset = 0;
+            do {
+                rec[RECORD_SEQUENCE - offset] = seq & 0xFF;
+                seq >>= 8;
+                offset++;
+            } while (seq > 0);
+            ctx->currrec++;
+
+            len = ((rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO])
+                  + DTLS1_RT_HEADER_LENGTH;
+
+            rec += len;
+            rem -= len;
+        }
+    }
+
+    memcpy(out, thispkt->data, outl);
+
+    mempacket_free(thispkt);
+
+    return outl;
+}
+
+int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum,
+                          int type)
+{
+    MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+    MEMPACKET *thispkt, *looppkt, *nextpkt;
+    int i;
+
+    if (ctx == NULL)
+        return -1;
+
+    /* We only allow injection before we've started writing any data */
+    if (pktnum >= 0) {
+        if (ctx->noinject)
+            return -1;
+    } else {
+        ctx->noinject = 1;
+    }
+
+    thispkt = OPENSSL_malloc(sizeof(MEMPACKET));
+    if (thispkt == NULL)
+        return -1;
+
+    thispkt->data = OPENSSL_malloc(inl);
+    if (thispkt->data == NULL) {
+        mempacket_free(thispkt);
+        return -1;
+    }
+
+    memcpy(thispkt->data, in, inl);
+    thispkt->len = inl;
+    thispkt->num = (pktnum >= 0) ? (unsigned int)pktnum : ctx->lastpkt;
+    thispkt->type = type;
+
+    for(i = 0; (looppkt = sk_MEMPACKET_value(ctx->pkts, i)) != NULL; i++) {
+        /* Check if we found the right place to insert this packet */
+        if (looppkt->num > thispkt->num) {
+            if (sk_MEMPACKET_insert(ctx->pkts, thispkt, i) == 0) {
+                mempacket_free(thispkt);
+                return -1;
+            }
+            /* If we're doing up front injection then we're done */
+            if (pktnum >= 0)
+                return inl;
+            /*
+             * We need to do some accounting on lastpkt. We increment it first,
+             * but it might now equal the value of injected packets, so we need
+             * to skip over those
+             */
+            ctx->lastpkt++;
+            do {
+                i++;
+                nextpkt = sk_MEMPACKET_value(ctx->pkts, i);
+                if (nextpkt != NULL && nextpkt->num == ctx->lastpkt)
+                    ctx->lastpkt++;
+                else
+                    return inl;
+            } while(1);
+        } else if(looppkt->num == thispkt->num) {
+            if (!ctx->noinject) {
+                /* We injected two packets with the same packet number! */
+                return -1;
+            }
+            ctx->lastpkt++;
+            thispkt->num++;
+        }
+    }
+    /*
+     * We didn't find any packets with a packet number equal to or greater than
+     * this one, so we just add it onto the end
+     */
+    if (!sk_MEMPACKET_push(ctx->pkts, thispkt)) {
+        mempacket_free(thispkt);
+        return -1;
+    }
+
+    if (pktnum < 0)
+        ctx->lastpkt++;
+
+    return inl;
+}
+
+static int mempacket_test_write(BIO *bio, const char *in, int inl)
+{
+    return mempacket_test_inject(bio, in, inl, -1, STANDARD_PACKET);
+}
+
+static long mempacket_test_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+    long ret = 1;
+    MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+    MEMPACKET *thispkt;
+
+    switch (cmd) {
+    case BIO_CTRL_EOF:
+        ret = (long)(sk_MEMPACKET_num(ctx->pkts) == 0);
+        break;
+    case BIO_CTRL_GET_CLOSE:
+        ret = BIO_get_shutdown(bio);
+        break;
+    case BIO_CTRL_SET_CLOSE:
+        BIO_set_shutdown(bio, (int)num);
+        break;
+    case BIO_CTRL_WPENDING:
+        ret = 0L;
+        break;
+    case BIO_CTRL_PENDING:
+        thispkt = sk_MEMPACKET_value(ctx->pkts, 0);
+        if (thispkt == NULL)
+            ret = 0;
+        else
+            ret = thispkt->len;
+        break;
+    case BIO_CTRL_FLUSH:
+        ret = 1;
+        break;
+    case BIO_CTRL_RESET:
+    case BIO_CTRL_DUP:
+    case BIO_CTRL_PUSH:
+    case BIO_CTRL_POP:
+    default:
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+static int mempacket_test_gets(BIO *bio, char *buf, int size)
+{
+    /* We don't support this - not needed anyway */
+    return -1;
+}
+
+static int mempacket_test_puts(BIO *bio, const char *str)
+{
+    return mempacket_test_write(bio, str, strlen(str));
+}
+
 int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
                         SSL_CTX **sctx, SSL_CTX **cctx, char *certfile,
                         char *privkeyfile)
@@ -52,11 +565,9 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
 /*
  * NOTE: Transfers control of the BIOs - this function will free them on error
  */
-int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
+int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
                           SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio)
 {
-    int retc = -1, rets = -1, err, abortctr = 0;
-    int clienterr = 0, servererr = 0;
     SSL *serverssl, *clientssl;
     BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL;
 
@@ -74,8 +585,13 @@ int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
         goto error;
     }
 
-    s_to_c_bio = BIO_new(BIO_s_mem());
-    c_to_s_bio = BIO_new(BIO_s_mem());
+    if (SSL_is_dtls(clientssl)) {
+        s_to_c_bio = BIO_new(bio_s_mempacket_test());
+        c_to_s_bio = BIO_new(bio_s_mempacket_test());;
+    } else {
+        s_to_c_bio = BIO_new(BIO_s_mem());
+        c_to_s_bio = BIO_new(BIO_s_mem());
+    }
     if (s_to_c_bio == NULL || c_to_s_bio == NULL) {
         printf("Failed to create mem BIOs\n");
         goto error;
@@ -105,6 +621,27 @@ int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
     s_to_c_bio = c_to_s_bio = NULL;
     s_to_c_fbio = c_to_s_fbio = NULL;
 
+    *sssl = serverssl;
+    *cssl = clientssl;
+
+    return 1;
+
+ error:
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    BIO_free(s_to_c_bio);
+    BIO_free(c_to_s_bio);
+    BIO_free(s_to_c_fbio);
+    BIO_free(c_to_s_fbio);
+
+    return 0;
+}
+
+int create_ssl_connection(SSL *serverssl, SSL *clientssl)
+{
+    int retc = -1, rets = -1, err, abortctr = 0;
+    int clienterr = 0, servererr = 0;
+
     do {
         err = SSL_ERROR_WANT_WRITE;
         while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
@@ -130,29 +667,12 @@ int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
             servererr = 1;
         }
         if (clienterr && servererr)
-            goto error;
+            return 0;
         if (++abortctr == MAXLOOPS) {
             printf("No progress made\n");
-            goto error;
+            return 0;
         }
     } while (retc <=0 || rets <= 0);
 
-    *sssl = serverssl;
-    *cssl = clientssl;
-
     return 1;
-
- error:
-    if (*sssl == NULL) {
-        SSL_free(serverssl);
-        BIO_free(s_to_c_bio);
-        BIO_free(s_to_c_fbio);
-    }
-    if (*cssl == NULL) {
-        SSL_free(clientssl);
-        BIO_free(c_to_s_bio);
-        BIO_free(c_to_s_fbio);
-    }
-
-    return 0;
 }
diff --git a/test/ssltestlib.h b/test/ssltestlib.h
index f05878a..bd9272f 100644
--- a/test/ssltestlib.h
+++ b/test/ssltestlib.h
@@ -15,7 +15,26 @@
 int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
                         SSL_CTX **sctx, SSL_CTX **cctx, char *certfile,
                         char *privkeyfile);
-int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
-                          SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio);
+int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
+                       SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio);
+int create_ssl_connection(SSL *serverssl, SSL *clientssl);
+
+/* Note: Not thread safe! */
+const BIO_METHOD *bio_f_tls_dump_filter(void);
+void bio_f_tls_dump_filter_free(void);
+
+const BIO_METHOD *bio_s_mempacket_test(void);
+void bio_s_mempacket_test_free(void);
+
+/* Packet types - value 0 is reserved */
+#define INJECT_PACKET                   1
+#define INJECT_PACKET_IGNORE_REC_SEQ    2
+
+int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum,
+                          int type);
+
+typedef struct mempacket_st MEMPACKET;
+
+DEFINE_STACK_OF(MEMPACKET)
 
 #endif /* HEADER_SSLTESTLIB_H */


More information about the openssl-commits mailing list