[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Jul 29 13:12:12 UTC 2016


The branch master has been updated
       via  e040a42e44b40f09ce485f66c9198456a3f8a457 (commit)
       via  65e2d672548e7c4bcb28f1c5c835362830b1745b (commit)
       via  9a7169870e803bdd9767d75ca8f64802ca0e7f1c (commit)
       via  b46fe860fe18131f72e8bc059defe3acc8a20f5d (commit)
       via  eddef305897cd8e9facbc18ed93a4ec104ab1927 (commit)
       via  8e3854ac88836df0ba862b1aba851dcd963c4ad2 (commit)
       via  7fb4c82035d05ca8735303caa9941aeead165b78 (commit)
      from  0647719d809abdfe6b871949f4f75ce82da6616a (commit)


- Log -----------------------------------------------------------------
commit e040a42e44b40f09ce485f66c9198456a3f8a457
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 22 11:55:10 2016 +0100

    Update the SSL_set_bio()/SSL_set0_rbio()/SSL_set0_wbio() docs
    
    Update the documentation for the newly renamed and modified SSL_set0_rbio()
    and SSL_set0_wbio() functions. State that they should be preferred over
    SSL_set_bio(). Attempt to document the ownership rules for SSL_set_bio().
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 65e2d672548e7c4bcb28f1c5c835362830b1745b
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 12:17:29 2016 +0100

    Simplify and rename SSL_set_rbio() and SSL_set_wbio()
    
    SSL_set_rbio() and SSL_set_wbio() are new functions in 1.1.0 and really
    should be called SSL_set0_rbio() and SSL_set0_wbio(). The old
    implementation was not consistent with what "set0" means though as there
    were special cases around what happens if the rbio and wbio are the same.
    We were only ever taking one reference on the BIO, and checking everywhere
    whether the rbio and wbio are the same so as not to double free.
    
    A better approach is to rename the functions to SSL_set0_rbio() and
    SSL_set0_wbio(). If an existing BIO is present it is *always* freed
    regardless of whether the rbio and wbio are the same or not. It is
    therefore the callers responsibility to ensure that a reference is taken
    for *each* usage, i.e. one for the rbio and one for the wbio.
    
    The legacy function SSL_set_bio() takes both the rbio and wbio in one go
    and sets them both. We can wrap up the old behaviour in the implementation
    of that function, i.e. previously if the rbio and wbio are the same in the
    call to this function then the caller only needed to ensure one reference
    was passed. This behaviour is retained by internally upping the ref count.
    
    This commit was inspired by BoringSSL commit f715c423224.
    
    RT#4572
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 9a7169870e803bdd9767d75ca8f64802ca0e7f1c
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 11:02:22 2016 +0100

    Add some SSL BIO tests
    
    This adds some simple SSL BIO tests that check for pushing and popping of
    BIOs into the chain. These tests would have caught the bugs fixed in the
    previous three commits, if combined with a crypto-mdebug build.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b46fe860fe18131f72e8bc059defe3acc8a20f5d
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 10:55:31 2016 +0100

    Fix BIO_pop for SSL BIOs
    
    The BIO_pop implementation assumes that the rbio still equals the next BIO
    in the chain. While this would normally be the case, it is possible that it
    could have been changed directly by the application. It also does not
    properly cater for the scenario where the buffering BIO is still in place
    for the write BIO.
    
    Most of the existing BIO_pop code for SSL BIOs can be replaced by a single
    call to SSL_set_bio(). This is equivalent to the existing code but
    additionally handles the scenario where the rbio has been changed or the
    buffering BIO is still in place.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit eddef305897cd8e9facbc18ed93a4ec104ab1927
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 10:48:12 2016 +0100

    Fix BIO_push ref counting for SSL BIO
    
    When pushing a BIO onto an SSL BIO we set the rbio and wbio for the SSL
    object to be the BIO that has been pushed. Therefore we need to up the ref
    count for that BIO. The existing code was uping the ref count on the wrong
    BIO.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 8e3854ac88836df0ba862b1aba851dcd963c4ad2
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 10:28:24 2016 +0100

    Don't double free the write bio
    
    When setting the read bio we free up any old existing one. However this can
    lead to a double free if the existing one is the same as the write bio.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 7fb4c82035d05ca8735303caa9941aeead165b78
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 21 15:06:13 2016 +0100

    Add a test for SSL_set_bio()
    
    The SSL_set_bio() function has some complicated ownership rules. This adds a
    test to make sure it all works as expected.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 doc/ssl/SSL_set_bio.pod |  82 +++++++++++++---
 include/openssl/ssl.h   |   4 +-
 ssl/bio_ssl.c           |  18 ++--
 ssl/ssl_lib.c           |  65 ++++++++++---
 test/dtlsv1listentest.c |   6 +-
 test/sslapitest.c       | 246 +++++++++++++++++++++++++++++++++++++++++++++++-
 util/libssl.num         |   4 +-
 7 files changed, 375 insertions(+), 50 deletions(-)

diff --git a/doc/ssl/SSL_set_bio.pod b/doc/ssl/SSL_set_bio.pod
index 204c89e..e8e55f4 100644
--- a/doc/ssl/SSL_set_bio.pod
+++ b/doc/ssl/SSL_set_bio.pod
@@ -2,31 +2,85 @@
 
 =head1 NAME
 
-SSL_set_bio, SSL_set_rbio, SSL_set_wbio - connect the SSL object with a BIO
+SSL_set_bio, SSL_set0_rbio, SSL_set0_wbio - connect the SSL object with a BIO
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
  void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio);
- void SSL_set_rbio(SSL *s, BIO *rbio);
- void SSL_set_wbio(SSL *s, BIO *wbio);
+ void SSL_set0_rbio(SSL *s, BIO *rbio);
+ void SSL_set0_wbio(SSL *s, BIO *wbio);
 
 =head1 DESCRIPTION
 
-SSL_set_bio() connects the BIOs B<rbio> and B<wbio> for the read and write
-operations of the TLS/SSL (encrypted) side of B<ssl>.
+SSL_set0_rbio() connects the BIO B<rbio> for the read operations of the B<ssl>
+object. The SSL engine inherits the behaviour of B<rbio>. If the BIO is
+non-blocking then the B<ssl> object will also have non-blocking behaviour. This
+function transfers ownership of B<rbio> to B<ssl>. It will be automatically
+freed using L<BIO_free_all(3)> when the B<ssl> is freed. On calling this
+function, any existing B<rbio> that was previously set will also be freed via a
+call to L<BIO_free_all(3)> (this includes the case where the B<rbio> is set to
+the same value as previously).
 
-The SSL engine inherits the behaviour of B<rbio> and B<wbio>, respectively.
-If a BIO is non-blocking, the B<ssl> will also have non-blocking behaviour.
+SSL_set0_wbio() works in the same as SSL_set0_rbio() except that it connects
+the BIO B<wbio> for the write operations of the B<ssl> object. Note that if the
+rbio and wbio are the same then SSL_set0_rbio() and SSL_set0_wbio() each take
+ownership of one reference. Therefore it may be necessary to increment the
+number of references available using L<BIO_up_ref(3)> before calling the set0
+functions.
 
-If there was already a BIO connected to B<ssl>, BIO_free() will be called
-(for both the reading and writing side, if different).
+SSL_set_bio() does a similar job as SSL_set0_rbio() and SSL_set0_wbio() except
+that it connects both the B<rbio> and the B<wbio> at the same time. This
+function transfers the ownership of B<rbio> and B<wbio> to B<ssl> except that
+the rules for this are much more complex. For this reason this function is
+considered a legacy function and SSL_set0_rbio() and SSL_set0_wbio() should be
+used in preference. The ownership rules are as follows:
 
-SSL_set_rbio() does the same job as SSL_set_bio() except that it enables you
-to only connect the read bio, without touching the write bio. Similarly
-SSL_set_wbio() enables you to connect the write bio without touching the read
-bio.
+=over 4
+
+=item
+
+If neither the rbio or wbio have changed from their previous values then nothing
+is done.
+
+=item
+
+If the rbio and wbio parameters are different and both are different to their
+previously set values then one reference is consumed for the rbio and one
+reference is consumed for the wbio.
+
+=item
+
+If the rbio and wbio parameters are the same and the rbio is not the same as the
+previously set value then one reference is consumed.
+
+=item
+
+If the rbio and wbio parameters are the same and the rbio is the same as the
+previously set value, then no additional references are consumed.
+
+=item
+
+If the rbio and wbio parameters are different and the rbio is the same as the
+previously set value then one reference is consumbed for the wbio and no
+references are consumed for the rbio.
+
+=item
+
+If the rbio and wbio parameters are different and the wbio is the same as the
+previously set value and the old rbio and wbio values were the same as each
+other then one reference is consumed for the rbio and no references are consumed
+for the wbio.
+
+=item
+
+If the rbio and wbio parameters are different and the wbio is the same as the
+previously set value and the old rbio and wbio values were different to each
+other then one reference is consumed for the rbio and one reference is consumed
+for the wbio.
+
+=back
 
 =head1 RETURN VALUES
 
@@ -40,7 +94,7 @@ L<SSL_shutdown(3)>, L<ssl(3)>, L<bio(3)>
 
 =head1 HISTORY
 
-SSL_set_rbio() and SSL_set_wbio() were added in OpenSSL 1.1.0.
+SSL_set0_rbio() and SSL_set0_wbio() were added in OpenSSL 1.1.0.
 
 =head1 COPYRIGHT
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 3628cd5..2aca2f9 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1326,8 +1326,8 @@ __owur int SSL_set_fd(SSL *s, int fd);
 __owur int SSL_set_rfd(SSL *s, int fd);
 __owur int SSL_set_wfd(SSL *s, int fd);
 # endif
-void SSL_set_rbio(SSL *s, BIO *rbio);
-void SSL_set_wbio(SSL *s, BIO *wbio);
+void SSL_set0_rbio(SSL *s, BIO *rbio);
+void SSL_set0_wbio(SSL *s, BIO *wbio);
 void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio);
 __owur BIO *SSL_get_rbio(const SSL *s);
 __owur BIO *SSL_get_wbio(const SSL *s);
diff --git a/ssl/bio_ssl.c b/ssl/bio_ssl.c
index efe0df9..3dd09cf 100644
--- a/ssl/bio_ssl.c
+++ b/ssl/bio_ssl.c
@@ -327,23 +327,19 @@ static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr)
         break;
     case BIO_CTRL_PUSH:
         if ((next != NULL) && (next != ssl->rbio)) {
+            /*
+             * We are going to pass ownership of next to the SSL object...but
+             * we don't own a reference to pass yet - so up ref
+             */
+            BIO_up_ref(next);
             SSL_set_bio(ssl, next, next);
-            BIO_up_ref(b);
         }
         break;
     case BIO_CTRL_POP:
         /* Only detach if we are the BIO explicitly being popped */
         if (b == ptr) {
-            /*
-             * Shouldn't happen in practice because the rbio and wbio are the
-             * same when pushed.
-             */
-            if (ssl->rbio != ssl->wbio)
-                BIO_free_all(ssl->wbio);
-            if (next != NULL)
-                BIO_free(next);
-            ssl->wbio = NULL;
-            ssl->rbio = NULL;
+            /* This will clear the reference we obtained during push */
+            SSL_set_bio(ssl, NULL, NULL);
         }
         break;
     case BIO_C_DO_STATE_MACHINE:
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 4288c6f..df71f7b 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -979,8 +979,7 @@ void SSL_free(SSL *s)
 
     ssl_free_wbio_buffer(s);
 
-    if (s->wbio != s->rbio)
-        BIO_free_all(s->wbio);
+    BIO_free_all(s->wbio);
     BIO_free_all(s->rbio);
 
     BUF_MEM_free(s->init_buf);
@@ -1043,14 +1042,13 @@ void SSL_free(SSL *s)
     OPENSSL_free(s);
 }
 
-void SSL_set_rbio(SSL *s, BIO *rbio)
+void SSL_set0_rbio(SSL *s, BIO *rbio)
 {
-    if (s->rbio != rbio)
-        BIO_free_all(s->rbio);
+    BIO_free_all(s->rbio);
     s->rbio = rbio;
 }
 
-void SSL_set_wbio(SSL *s, BIO *wbio)
+void SSL_set0_wbio(SSL *s, BIO *wbio)
 {
     /*
      * If the output buffering BIO is still in place, remove it
@@ -1058,8 +1056,7 @@ void SSL_set_wbio(SSL *s, BIO *wbio)
     if (s->bbio != NULL)
         s->wbio = BIO_pop(s->wbio);
 
-    if (s->wbio != wbio && s->rbio != s->wbio)
-        BIO_free_all(s->wbio);
+    BIO_free_all(s->wbio);
     s->wbio = wbio;
 
     /* Re-attach |bbio| to the new |wbio|. */
@@ -1069,8 +1066,42 @@ void SSL_set_wbio(SSL *s, BIO *wbio)
 
 void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio)
 {
-    SSL_set_wbio(s, wbio);
-    SSL_set_rbio(s, rbio);
+    /*
+     * For historical reasons, this function has many different cases in
+     * ownership handling.
+     */
+
+    /* If nothing has changed, do nothing */
+    if (rbio == SSL_get_rbio(s) && wbio == SSL_get_wbio(s))
+        return;
+
+    /*
+     * If the two arguments are equal then one fewer reference is granted by the
+     * caller than we want to take
+     */
+    if (rbio != NULL && rbio == wbio)
+        BIO_up_ref(rbio);
+
+    /*
+     * If only the wbio is changed only adopt one reference.
+     */
+    if (rbio == SSL_get_rbio(s)) {
+        SSL_set0_wbio(s, wbio);
+        return;
+    }
+    /*
+     * There is an asymmetry here for historical reasons. If only the rbio is
+     * changed AND the rbio and wbio were originally different, then we only
+     * adopt one reference.
+     */
+    if (wbio == SSL_get_wbio(s) && SSL_get_rbio(s) != SSL_get_wbio(s)) {
+        SSL_set0_rbio(s, rbio);
+        return;
+    }
+
+    /* Otherwise, adopt both references. */
+    SSL_set0_rbio(s, rbio);
+    SSL_set0_wbio(s, wbio);
 }
 
 BIO *SSL_get_rbio(const SSL *s)
@@ -1151,9 +1182,10 @@ int SSL_set_wfd(SSL *s, int fd)
             return 0;
         }
         BIO_set_fd(bio, fd, BIO_NOCLOSE);
-        SSL_set_wbio(s, bio);
+        SSL_set0_wbio(s, bio);
     } else {
-        SSL_set_wbio(s, rbio);
+        BIO_up_ref(rbio);
+        SSL_set0_wbio(s, rbio);
     }
     return 1;
 }
@@ -1171,9 +1203,10 @@ int SSL_set_rfd(SSL *s, int fd)
             return 0;
         }
         BIO_set_fd(bio, fd, BIO_NOCLOSE);
-        SSL_set_rbio(s, bio);
+        SSL_set0_rbio(s, bio);
     } else {
-        SSL_set_rbio(s, wbio);
+        BIO_up_ref(wbio);
+        SSL_set0_rbio(s, wbio);
     }
 
     return 1;
@@ -3141,8 +3174,10 @@ SSL *SSL_dup(SSL *s)
         if (s->wbio != s->rbio) {
             if (!BIO_dup_state(s->wbio, (char *)&ret->wbio))
                 goto err;
-        } else
+        } else {
+            BIO_up_ref(ret->rbio);
             ret->wbio = ret->rbio;
+        }
     }
 
     ret->server = s->server;
diff --git a/test/dtlsv1listentest.c b/test/dtlsv1listentest.c
index cc7e5f7..91d78e1 100644
--- a/test/dtlsv1listentest.c
+++ b/test/dtlsv1listentest.c
@@ -352,7 +352,7 @@ int main(void)
     outbio = BIO_new(BIO_s_mem());
     if (outbio == NULL)
         goto err;
-    SSL_set_wbio(ssl, outbio);
+    SSL_set0_wbio(ssl, outbio);
 
     success = 1;
     for (i = 0; i < (long)OSSL_NELEM(testpackets) && success; i++) {
@@ -365,7 +365,7 @@ int main(void)
         /* Set Non-blocking IO behaviour */
         BIO_set_mem_eof_return(inbio, -1);
 
-        SSL_set_rbio(ssl, inbio);
+        SSL_set0_rbio(ssl, inbio);
 
         /* Process the incoming packet */
         ret = DTLSv1_listen(ssl, peer);
@@ -404,7 +404,7 @@ int main(void)
         (void)BIO_reset(outbio);
         inbio = NULL;
         /* Frees up inbio */
-        SSL_set_rbio(ssl, NULL);
+        SSL_set0_rbio(ssl, NULL);
     }
 
  err:
diff --git a/test/sslapitest.c b/test/sslapitest.c
index d36a792..5fc552d 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -301,7 +301,8 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
     return testresult;
 }
 
-static int test_session_with_only_int_cache(void) {
+static int test_session_with_only_int_cache(void)
+{
     SETUP_TEST_FIXTURE(SSL_SESSION_TEST_FIXTURE, ssl_session_set_up);
 
     fixture.use_ext_cache = 0;
@@ -309,7 +310,8 @@ static int test_session_with_only_int_cache(void) {
     EXECUTE_TEST(execute_test_session, ssl_session_tear_down);
 }
 
-static int test_session_with_only_ext_cache(void) {
+static int test_session_with_only_ext_cache(void)
+{
     SETUP_TEST_FIXTURE(SSL_SESSION_TEST_FIXTURE, ssl_session_set_up);
 
     fixture.use_int_cache = 0;
@@ -317,12 +319,245 @@ static int test_session_with_only_ext_cache(void) {
     EXECUTE_TEST(execute_test_session, ssl_session_tear_down);
 }
 
-static int test_session_with_both_cache(void) {
+static int test_session_with_both_cache(void)
+{
     SETUP_TEST_FIXTURE(SSL_SESSION_TEST_FIXTURE, ssl_session_set_up);
 
     EXECUTE_TEST(execute_test_session, ssl_session_tear_down);
 }
 
+#define USE_NULL    0
+#define USE_BIO_1   1
+#define USE_BIO_2   2
+
+#define TOTAL_SSL_SET_BIO_TESTS (3 * 3 * 3 * 3)
+
+static void setupbio(BIO **res, BIO *bio1, BIO *bio2, int type)
+{
+    switch (type) {
+    case USE_NULL:
+        *res = NULL;
+        break;
+    case USE_BIO_1:
+        *res = bio1;
+        break;
+    case USE_BIO_2:
+        *res = bio2;
+        break;
+    }
+}
+
+static int test_ssl_set_bio(int idx)
+{
+    SSL_CTX *ctx = SSL_CTX_new(TLS_method());
+    BIO *bio1 = NULL;
+    BIO *bio2 = NULL;
+    BIO *irbio, *iwbio, *nrbio, *nwbio;
+    SSL *ssl = NULL;
+    int initrbio, initwbio, newrbio, newwbio;
+    int testresult = 0;
+
+    if (ctx == NULL) {
+        printf("Failed to allocate SSL_CTX\n");
+        goto end;
+    }
+
+    ssl = SSL_new(ctx);
+    if (ssl == NULL) {
+        printf("Failed to allocate SSL object\n");
+        goto end;
+    }
+
+    initrbio = idx % 3;
+    idx /= 3;
+    initwbio = idx % 3;
+    idx /= 3;
+    newrbio = idx % 3;
+    idx /= 3;
+    newwbio = idx;
+    OPENSSL_assert(newwbio <= 2);
+
+    if (initrbio == USE_BIO_1 || initwbio == USE_BIO_1 || newrbio == USE_BIO_1
+            || newwbio == USE_BIO_1) {
+        bio1 = BIO_new(BIO_s_mem());
+        if (bio1 == NULL) {
+            printf("Failed to allocate bio1\n");
+            goto end;
+        }
+    }
+
+    if (initrbio == USE_BIO_2 || initwbio == USE_BIO_2 || newrbio == USE_BIO_2
+            || newwbio == USE_BIO_2) {
+        bio2 = BIO_new(BIO_s_mem());
+        if (bio2 == NULL) {
+            printf("Failed to allocate bio2\n");
+            goto end;
+        }
+    }
+
+    setupbio(&irbio, bio1, bio2, initrbio);
+    setupbio(&iwbio, bio1, bio2, initwbio);
+
+    /*
+     * We want to maintain our own refs to these BIO, so do an up ref for each
+     * BIO that will have ownersip transferred in the SSL_set_bio() call
+     */
+    if (irbio != NULL)
+        BIO_up_ref(irbio);
+    if (iwbio != NULL && iwbio != irbio)
+        BIO_up_ref(iwbio);
+
+    SSL_set_bio(ssl, irbio, iwbio);
+
+    setupbio(&nrbio, bio1, bio2, newrbio);
+    setupbio(&nwbio, bio1, bio2, newwbio);
+
+    /*
+     * We will (maybe) transfer ownership again so do more up refs.
+     * SSL_set_bio() has some really complicated ownership rules where BIOs have
+     * already been set!
+     */
+    if (nrbio != NULL && nrbio != irbio && (nwbio != iwbio || nrbio != nwbio))
+        BIO_up_ref(nrbio);
+    if (nwbio != NULL && nwbio != nrbio && (nwbio != iwbio || (nwbio == iwbio && irbio == iwbio)))
+        BIO_up_ref(nwbio);
+
+    SSL_set_bio(ssl, nrbio, nwbio);
+
+    testresult = 1;
+
+ end:
+    SSL_free(ssl);
+    BIO_free(bio1);
+    BIO_free(bio2);
+    /*
+     * This test is checking that the ref counting for SSL_set_bio is correct.
+     * If we get here and we did too many frees then we will fail in the above
+     * functions. If we haven't done enough then this will only be detected in
+     * a crypto-mdebug build
+     */
+    SSL_CTX_free(ctx);
+
+    return testresult;
+}
+
+typedef struct ssl_bio_test_fixture {
+    const char *test_case_name;
+    int pop_ssl;
+    enum { NO_BIO_CHANGE, CHANGE_RBIO, CHANGE_WBIO } change_bio;
+} SSL_BIO_TEST_FIXTURE;
+
+static SSL_BIO_TEST_FIXTURE ssl_bio_set_up(const char *const test_case_name)
+{
+    SSL_BIO_TEST_FIXTURE fixture;
+
+    fixture.test_case_name = test_case_name;
+    fixture.pop_ssl = 0;
+
+    return fixture;
+}
+
+static void ssl_bio_tear_down(SSL_BIO_TEST_FIXTURE fixture)
+{
+}
+
+static int execute_test_ssl_bio(SSL_BIO_TEST_FIXTURE fix)
+{
+    BIO *sslbio = NULL, *membio1 = NULL, *membio2 = NULL;
+    SSL_CTX *ctx = SSL_CTX_new(TLS_method());
+    SSL *ssl = NULL;
+    int testresult = 0;
+
+    if (ctx == NULL) {
+        printf("Failed to allocate SSL_CTX\n");
+        return 0;
+    }
+
+    ssl = SSL_new(ctx);
+    if (ssl == NULL) {
+        printf("Failed to allocate SSL object\n");
+        goto end;
+    }
+
+    sslbio = BIO_new(BIO_f_ssl());
+    membio1 = BIO_new(BIO_s_mem());
+
+    if (sslbio == NULL || membio1 == NULL) {
+        printf("Malloc failure creating BIOs\n");
+        goto end;
+    }
+
+    BIO_set_ssl(sslbio, ssl, BIO_CLOSE);
+
+    /*
+     * If anything goes wrong here then we could leak memory, so this will
+     * be caught in a crypto-mdebug build
+     */
+    BIO_push(sslbio, membio1);
+
+    /* Verify chaning the rbio/wbio directly does not cause leaks */
+    if (fix.change_bio != NO_BIO_CHANGE) {
+        membio2 = BIO_new(BIO_s_mem());
+        if (membio2 == NULL) {
+            printf("Malloc failure creating membio2\n");
+            goto end;
+        }
+        if (fix.change_bio == CHANGE_RBIO)
+            SSL_set0_rbio(ssl, membio2);
+        else
+            SSL_set0_wbio(ssl, membio2);
+    }
+    ssl = NULL;
+
+    if (fix.pop_ssl)
+        BIO_pop(sslbio);
+    else
+        BIO_pop(membio1);
+
+    testresult = 1;
+ end:
+    BIO_free(membio1);
+    BIO_free(sslbio);
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+
+    return testresult;
+}
+
+static int test_ssl_bio_pop_next_bio(void)
+{
+    SETUP_TEST_FIXTURE(SSL_BIO_TEST_FIXTURE, ssl_bio_set_up);
+
+    EXECUTE_TEST(execute_test_ssl_bio, ssl_bio_tear_down);
+}
+
+static int test_ssl_bio_pop_ssl_bio(void)
+{
+    SETUP_TEST_FIXTURE(SSL_BIO_TEST_FIXTURE, ssl_bio_set_up);
+
+    fixture.pop_ssl = 1;
+
+    EXECUTE_TEST(execute_test_ssl_bio, ssl_bio_tear_down);
+}
+
+static int test_ssl_bio_change_rbio(void)
+{
+    SETUP_TEST_FIXTURE(SSL_BIO_TEST_FIXTURE, ssl_bio_set_up);
+
+    fixture.change_bio = CHANGE_RBIO;
+
+    EXECUTE_TEST(execute_test_ssl_bio, ssl_bio_tear_down);
+}
+
+static int test_ssl_bio_change_wbio(void)
+{
+    SETUP_TEST_FIXTURE(SSL_BIO_TEST_FIXTURE, ssl_bio_set_up);
+
+    fixture.change_bio = CHANGE_WBIO;
+
+    EXECUTE_TEST(execute_test_ssl_bio, ssl_bio_tear_down);
+}
+
 int main(int argc, char *argv[])
 {
     BIO *err = NULL;
@@ -345,6 +580,11 @@ int main(int argc, char *argv[])
     ADD_TEST(test_session_with_only_int_cache);
     ADD_TEST(test_session_with_only_ext_cache);
     ADD_TEST(test_session_with_both_cache);
+    ADD_ALL_TESTS(test_ssl_set_bio, TOTAL_SSL_SET_BIO_TESTS);
+    ADD_TEST(test_ssl_bio_pop_next_bio);
+    ADD_TEST(test_ssl_bio_pop_ssl_bio);
+    ADD_TEST(test_ssl_bio_change_rbio);
+    ADD_TEST(test_ssl_bio_change_wbio);
 
     testresult = run_tests(argv[0]);
 
diff --git a/util/libssl.num b/util/libssl.num
index f19ee4c..1041d79 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -156,7 +156,7 @@ SSL_CTX_set_tmp_dh_callback             156	1_1_0	EXIST::FUNCTION:DH
 SSL_CTX_get_default_passwd_cb           157	1_1_0	EXIST::FUNCTION:
 TLSv1_server_method                     158	1_1_0	EXIST::FUNCTION:DEPRECATEDIN_1_1_0,TLS1_METHOD
 DTLS_server_method                      159	1_1_0	EXIST::FUNCTION:
-SSL_set_rbio                            160	1_1_0	EXIST::FUNCTION:
+SSL_set0_rbio                           160	1_1_0	EXIST::FUNCTION:
 SSL_CTX_set_options                     161	1_1_0	EXIST::FUNCTION:
 SSL_set_msg_callback                    162	1_1_0	EXIST::FUNCTION:
 SSL_CONF_CTX_free                       163	1_1_0	EXIST::FUNCTION:
@@ -236,7 +236,7 @@ DTLSv1_server_method                    236	1_1_0	EXIST::FUNCTION:DEPRECATEDIN_1
 SSL_set_fd                              237	1_1_0	EXIST::FUNCTION:SOCK
 SSL_use_certificate                     238	1_1_0	EXIST::FUNCTION:
 DTLSv1_method                           239	1_1_0	EXIST::FUNCTION:DEPRECATEDIN_1_1_0,DTLS1_METHOD
-SSL_set_wbio                            240	1_1_0	EXIST::FUNCTION:
+SSL_set0_wbio                           240	1_1_0	EXIST::FUNCTION:
 SSL_read                                241	1_1_0	EXIST::FUNCTION:
 SSL_CTX_get_options                     242	1_1_0	EXIST::FUNCTION:
 SSL_CTX_set_ssl_version                 243	1_1_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list