[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Oct 28 08:51:27 UTC 2016


The branch master has been updated
       via  f7970f303f849f0d0c8eb1717efd35b559c47964 (commit)
       via  d62bf89cbba8df21c317fbf3fbefadeb0ca5a7f4 (commit)
       via  7bf79e33c94545eb3d67f142ce2dcc974c4dc79b (commit)
       via  fbba62f6c9671b151df648f06afdf6af14518ab4 (commit)
       via  42c6046064d2ee45d59baec53bedde4ea434294f (commit)
       via  f42fd819d60c5ebbcfd7bff6173b89664ab2fde1 (commit)
       via  bb5310bed5ab14747cad1f6a57aa3b075ca4af65 (commit)
       via  7f5f01cf538a01879805d22cb9a92047d1d97b19 (commit)
       via  ac0edec108804c383e1f7c48dd2fe72deecf6f9c (commit)
       via  47263ace13c47a3e2c4c9c4439884cf1ff8e6866 (commit)
       via  b055fceb9bd8f613f39dab9df4d77b2a95231755 (commit)
       via  98e553d2ce31e2179be68d6a60b5bec765cd9768 (commit)
       via  3befffa39dbaf2688d823fcf2bdfc07d2487be48 (commit)
       via  d07aee2c7a33e77d97d8e13811af3637e3849cb2 (commit)
      from  229bd12487f8576fc088dc4f641950ac33c62033 (commit)


- Log -----------------------------------------------------------------
commit f7970f303f849f0d0c8eb1717efd35b559c47964
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 27 12:59:26 2016 +0100

    Fix stdio build following BIO size_t work
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d62bf89cbba8df21c317fbf3fbefadeb0ca5a7f4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Oct 26 00:05:25 2016 +0100

    Fix more shadowed variable warnings
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7bf79e33c94545eb3d67f142ce2dcc974c4dc79b
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 25 13:19:59 2016 +0100

    Fix some feedback issues for BIO size_t-ify
    
    Rename some parameters; add some error codes; fix a comment; etc
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit fbba62f6c9671b151df648f06afdf6af14518ab4
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 15:21:55 2016 +0100

    Add some sanity checks for BIO_read* and BIO_gets
    
    Make sure the return value isn't bigger than the buffer len
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 42c6046064d2ee45d59baec53bedde4ea434294f
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 15:15:51 2016 +0100

    More parameter naming of BIO_read*/BIO_write* related functions
    
    Based on feedback received.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f42fd819d60c5ebbcfd7bff6173b89664ab2fde1
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 14:35:26 2016 +0100

    Tweaks based on review feedback of BIO size_t work
    
    Rename some parameters.
    Also change handling of buffer sizes >INT_MAX in length.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit bb5310bed5ab14747cad1f6a57aa3b075ca4af65
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 13:07:06 2016 +0100

    Ensure that BIO_read_ex() and BIO_write_ex() only return 0 or 1
    
    They should return 0 for a failure (retryable or not), and 1 for a success.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7f5f01cf538a01879805d22cb9a92047d1d97b19
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 00:09:02 2016 +0100

    Read up to INT_MAX when calling legacy BIO_read() implementations
    
    In converting a new style BIO_read() call into an old one, read
    as much data as we can (INT_MAX), if the size of the buffer is
    >INT_MAX.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ac0edec108804c383e1f7c48dd2fe72deecf6f9c
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 00:00:40 2016 +0100

    Fix a shadowed variable declaration warning
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 47263ace13c47a3e2c4c9c4439884cf1ff8e6866
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 00:00:19 2016 +0100

    Fix some bogus uninit variable warnings
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit b055fceb9bd8f613f39dab9df4d77b2a95231755
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 20 09:56:18 2016 +0100

    Document the new BIO functions introduced as part of the size_t work
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 98e553d2ce31e2179be68d6a60b5bec765cd9768
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 20 13:48:31 2016 +0100

    Ensure all BIO functions call the new style callback
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 3befffa39dbaf2688d823fcf2bdfc07d2487be48
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 20 15:18:39 2016 +0100

    Create BIO_write_ex() which handles size_t arguments
    
    Also extend BIO_METHOD to be able to supply an implementation for the new
    BIO_write_ex function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d07aee2c7a33e77d97d8e13811af3637e3849cb2
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 5 17:26:58 2016 +0100

    Create BIO_read_ex() which handles size_t arguments
    
    Also extend BIO_METHOD to be able to supply an implementation for the new
    BIO_read function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 crypto/asn1/bio_asn1.c        |   4 +
 crypto/bio/bf_buff.c          |   4 +
 crypto/bio/bf_lbuf.c          |   4 +
 crypto/bio/bf_nbio.c          |   4 +
 crypto/bio/bf_null.c          |   4 +
 crypto/bio/bio_err.c          |   5 +
 crypto/bio/bio_lcl.h          |   3 +-
 crypto/bio/bio_lib.c          | 368 +++++++++++++++++++++++++++++++-----------
 crypto/bio/bio_meth.c         |  69 ++++++++
 crypto/bio/bss_acpt.c         |   4 +
 crypto/bio/bss_bio.c          |   4 +
 crypto/bio/bss_conn.c         |   4 +
 crypto/bio/bss_dgram.c        |   4 +
 crypto/bio/bss_fd.c           |   4 +
 crypto/bio/bss_file.c         |   8 +
 crypto/bio/bss_log.c          |   3 +
 crypto/bio/bss_mem.c          |   8 +
 crypto/bio/bss_null.c         |   4 +
 crypto/bio/bss_sock.c         |   4 +
 crypto/evp/bio_b64.c          |   4 +
 crypto/evp/bio_enc.c          |   4 +
 crypto/evp/bio_md.c           |   4 +
 crypto/evp/bio_ok.c           |   4 +
 doc/man3/BIO_ctrl.pod         |   2 +-
 doc/man3/BIO_f_buffer.pod     |   2 +-
 doc/man3/BIO_f_md.pod         |   4 +-
 doc/man3/BIO_f_ssl.pod        |   2 +-
 doc/man3/BIO_meth_new.pod     |  48 ++++--
 doc/man3/BIO_read.pod         |  26 ++-
 doc/man3/BIO_s_bio.pod        |  24 +--
 doc/man3/BIO_s_fd.pod         |  10 +-
 doc/man3/BIO_s_file.pod       |   6 +-
 doc/man3/BIO_s_socket.pod     |   2 +-
 doc/man3/BIO_set_callback.pod | 135 +++++++++++++---
 doc/man3/BIO_should_retry.pod |   4 +-
 doc/man7/bio.pod              |   2 +-
 include/internal/bio.h        |  11 +-
 include/openssl/bio.h         |  25 ++-
 ssl/bio_ssl.c                 |  44 +++--
 util/libcrypto.num            |   8 +
 40 files changed, 699 insertions(+), 184 deletions(-)

diff --git a/crypto/asn1/bio_asn1.c b/crypto/asn1/bio_asn1.c
index d3cc108..3d3f8e4 100644
--- a/crypto/asn1/bio_asn1.c
+++ b/crypto/asn1/bio_asn1.c
@@ -78,7 +78,11 @@ static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
 static const BIO_METHOD methods_asn1 = {
     BIO_TYPE_ASN1,
     "asn1",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     asn1_bio_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     asn1_bio_read,
     asn1_bio_puts,
     asn1_bio_gets,
diff --git a/crypto/bio/bf_buff.c b/crypto/bio/bf_buff.c
index b2a387b..7a73095 100644
--- a/crypto/bio/bf_buff.c
+++ b/crypto/bio/bf_buff.c
@@ -25,7 +25,11 @@ static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
 static const BIO_METHOD methods_buffer = {
     BIO_TYPE_BUFFER,
     "buffer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     buffer_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     buffer_read,
     buffer_puts,
     buffer_gets,
diff --git a/crypto/bio/bf_lbuf.c b/crypto/bio/bf_lbuf.c
index b3c2b5e..0cee526 100644
--- a/crypto/bio/bf_lbuf.c
+++ b/crypto/bio/bf_lbuf.c
@@ -30,7 +30,11 @@ static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
 static const BIO_METHOD methods_linebuffer = {
     BIO_TYPE_LINEBUFFER,
     "linebuffer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     linebuffer_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     linebuffer_read,
     linebuffer_puts,
     linebuffer_gets,
diff --git a/crypto/bio/bf_nbio.c b/crypto/bio/bf_nbio.c
index 364d9fb..1d98a94 100644
--- a/crypto/bio/bf_nbio.c
+++ b/crypto/bio/bf_nbio.c
@@ -34,7 +34,11 @@ typedef struct nbio_test_st {
 static const BIO_METHOD methods_nbiof = {
     BIO_TYPE_NBIO_TEST,
     "non-blocking IO test filter",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     nbiof_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     nbiof_read,
     nbiof_puts,
     nbiof_gets,
diff --git a/crypto/bio/bf_null.c b/crypto/bio/bf_null.c
index 0736b3f..ff2a04c 100644
--- a/crypto/bio/bf_null.c
+++ b/crypto/bio/bf_null.c
@@ -27,7 +27,11 @@ static long nullf_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
 static const BIO_METHOD methods_nullf = {
     BIO_TYPE_NULL_FILTER,
     "NULL filter",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     nullf_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     nullf_read,
     nullf_puts,
     nullf_gets,
diff --git a/crypto/bio/bio_err.c b/crypto/bio/bio_err.c
index 98c90d6..b8cb1eb 100644
--- a/crypto/bio/bio_err.c
+++ b/crypto/bio/bio_err.c
@@ -44,11 +44,15 @@ static ERR_STRING_DATA BIO_str_functs[] = {
     {ERR_FUNC(BIO_F_BIO_PARSE_HOSTSERV), "BIO_parse_hostserv"},
     {ERR_FUNC(BIO_F_BIO_PUTS), "BIO_puts"},
     {ERR_FUNC(BIO_F_BIO_READ), "BIO_read"},
+    {ERR_FUNC(BIO_F_BIO_READ_EX), "BIO_read_ex"},
+    {ERR_FUNC(BIO_F_BIO_READ_INTERN), "bio_read_intern"},
     {ERR_FUNC(BIO_F_BIO_SOCKET), "BIO_socket"},
     {ERR_FUNC(BIO_F_BIO_SOCKET_NBIO), "BIO_socket_nbio"},
     {ERR_FUNC(BIO_F_BIO_SOCK_INFO), "BIO_sock_info"},
     {ERR_FUNC(BIO_F_BIO_SOCK_INIT), "BIO_sock_init"},
     {ERR_FUNC(BIO_F_BIO_WRITE), "BIO_write"},
+    {ERR_FUNC(BIO_F_BIO_WRITE_EX), "BIO_write_ex"},
+    {ERR_FUNC(BIO_F_BIO_WRITE_INTERN), "bio_write_intern"},
     {ERR_FUNC(BIO_F_BUFFER_CTRL), "buffer_ctrl"},
     {ERR_FUNC(BIO_F_CONN_CTRL), "conn_ctrl"},
     {ERR_FUNC(BIO_F_CONN_STATE), "conn_state"},
@@ -80,6 +84,7 @@ static ERR_STRING_DATA BIO_str_reasons[] = {
     {ERR_REASON(BIO_R_INVALID_ARGUMENT), "invalid argument"},
     {ERR_REASON(BIO_R_INVALID_SOCKET), "invalid socket"},
     {ERR_REASON(BIO_R_IN_USE), "in use"},
+    {ERR_REASON(BIO_R_LENGTH_TOO_LONG), "length too long"},
     {ERR_REASON(BIO_R_LISTEN_V6_ONLY), "listen v6 only"},
     {ERR_REASON(BIO_R_LOOKUP_RETURNED_NOTHING), "lookup returned nothing"},
     {ERR_REASON(BIO_R_MALFORMED_HOST_OR_SERVICE),
diff --git a/crypto/bio/bio_lcl.h b/crypto/bio/bio_lcl.h
index 39178cf..d46f4e7 100644
--- a/crypto/bio/bio_lcl.h
+++ b/crypto/bio/bio_lcl.h
@@ -114,7 +114,8 @@ typedef struct bio_f_buffer_ctx_struct {
 struct bio_st {
     const BIO_METHOD *method;
     /* bio, mode, argp, argi, argl, ret */
-    long (*callback) (struct bio_st *, int, const char *, int, long, long);
+    BIO_callback_fn callback;
+    BIO_callback_fn_ex callback_ex;
     char *cb_arg;               /* first argument for the callback */
     int init;
     int shutdown;
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index 62392c3..2bd337c 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -13,6 +13,62 @@
 #include "bio_lcl.h"
 #include "internal/cryptlib.h"
 
+
+/*
+ * Helper macro for the callback to determine whether an operator expects a
+ * len parameter or not
+ */
+#define HAS_LEN_OPER(o)        ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \
+                                (o) == BIO_CB_GETS)
+
+/*
+ * Helper function to work out whether to call the new style callback or the old
+ * one, and translate between the two.
+ *
+ * This has a long return type for consistency with the old callback. Similarly
+ * for the "long" used for "inret"
+ */
+static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len,
+                              int argi, long argl, long inret, size_t *processed)
+{
+    long ret;
+    int bareoper;
+
+    if (b->callback_ex != NULL) {
+        return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed);
+    }
+
+    /* Strip off any BIO_CB_RETURN flag */
+    bareoper = oper & ~BIO_CB_RETURN;
+
+    /*
+     * We have an old style callback, so we will have to do nasty casts and
+     * check for overflows.
+     */
+    if (HAS_LEN_OPER(bareoper)) {
+        /* In this case |len| is set, and should be used instead of |argi| */
+        if (len > INT_MAX)
+            return -1;
+
+        argi = (int)len;
+
+        if (inret && (oper & BIO_CB_RETURN)) {
+            if (*processed > INT_MAX)
+                return -1;
+            inret = *processed;
+        }
+    }
+
+    ret = b->callback(b, oper, argp, argi, argl, inret);
+
+    if (ret >= 0 && (HAS_LEN_OPER(bareoper) || bareoper == BIO_CB_PUTS)) {
+        *processed = (size_t)ret;
+        ret = 1;
+    }
+
+    return ret;
+}
+
 BIO *BIO_new(const BIO_METHOD *method)
 {
     BIO *bio = OPENSSL_zalloc(sizeof(*bio));
@@ -52,21 +108,24 @@ err:
 
 int BIO_free(BIO *a)
 {
-    int i;
+    int ret;
 
     if (a == NULL)
         return 0;
 
-    if (CRYPTO_atomic_add(&a->references, -1, &i, a->lock) <= 0)
+    if (CRYPTO_atomic_add(&a->references, -1, &ret, a->lock) <= 0)
         return 0;
 
     REF_PRINT_COUNT("BIO", a);
-    if (i > 0)
+    if (ret > 0)
         return 1;
-    REF_ASSERT_ISNT(i < 0);
-    if ((a->callback != NULL) &&
-        ((i = (int)a->callback(a, BIO_CB_FREE, NULL, 0, 0L, 1L)) <= 0))
-        return i;
+    REF_ASSERT_ISNT(ret < 0);
+
+    if (a->callback != NULL || a->callback_ex != NULL) {
+        ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL);
+        if (ret <= 0)
+            return ret;
+    }
 
     if ((a->method != NULL) && (a->method->destroy != NULL))
         a->method->destroy(a);
@@ -142,18 +201,26 @@ void BIO_set_flags(BIO *b, int flags)
     b->flags |= flags;
 }
 
-long (*BIO_get_callback(const BIO *b)) (struct bio_st *, int, const char *,
-                                        int, long, long) {
+BIO_callback_fn BIO_get_callback(const BIO *b)
+{
     return b->callback;
 }
 
-void BIO_set_callback(BIO *b,
-                      long (*cb) (struct bio_st *, int, const char *, int,
-                                  long, long))
+void BIO_set_callback(BIO *b, BIO_callback_fn cb)
 {
     b->callback = cb;
 }
 
+BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b)
+{
+    return b->callback_ex;
+}
+
+void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb)
+{
+    b->callback_ex = cb;
+}
+
 void BIO_set_callback_arg(BIO *b, char *arg)
 {
     b->cb_arg = arg;
@@ -174,124 +241,239 @@ int BIO_method_type(const BIO *b)
     return b->method->type;
 }
 
-int BIO_read(BIO *b, void *out, int outl)
+/*
+ * This is essentially the same as BIO_read_ex() except that it allows
+ * 0 or a negative value to indicate failure (retryable or not) in the return.
+ * This is for compatibility with the old style BIO_read(), where existing code
+ * may make assumptions about the return value that it might get.
+ */
+static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes)
 {
-    int i;
-    long (*cb) (BIO *, int, const char *, int, long, long);
+    int ret;
 
     if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) {
-        BIOerr(BIO_F_BIO_READ, BIO_R_UNSUPPORTED_METHOD);
-        return (-2);
+        BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD);
+        return -2;
     }
 
-    cb = b->callback;
-    if ((cb != NULL) &&
-        ((i = (int)cb(b, BIO_CB_READ, out, outl, 0L, 1L)) <= 0))
-        return (i);
+    if ((b->callback != NULL || b->callback_ex != NULL) &&
+        ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L,
+                                       readbytes)) <= 0))
+        return ret;
 
     if (!b->init) {
-        BIOerr(BIO_F_BIO_READ, BIO_R_UNINITIALIZED);
-        return (-2);
+        BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED);
+        return -2;
     }
 
-    i = b->method->bread(b, out, outl);
+    ret = b->method->bread(b, data, dlen, readbytes);
+
+    if (ret > 0)
+        b->num_read += (uint64_t)*read;
 
-    if (i > 0)
-        b->num_read += (uint64_t)i;
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data,
+                                     dlen, 0, 0L, ret, readbytes);
 
-    if (cb != NULL)
-        i = (int)cb(b, BIO_CB_READ | BIO_CB_RETURN, out, outl, 0L, (long)i);
-    return (i);
+    /* Shouldn't happen */
+    if (ret > 0 && *readbytes > dlen) {
+        BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    return ret;
 }
 
-int BIO_write(BIO *b, const void *in, int inl)
+int BIO_read(BIO *b, void *data, int dlen)
 {
-    int i;
-    long (*cb) (BIO *, int, const char *, int, long, long);
+    size_t readbytes;
+    int ret;
+
+    if (dlen < 0)
+        return 0;
+
+    ret = bio_read_intern(b, data, (size_t)dlen, &readbytes);
+
+    if (ret > 0) {
+        /* *readbytes should always be <= outl */
+        ret = (int)readbytes;
+    }
+
+    return ret;
+}
+
+int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes)
+{
+    int ret;
+
+    ret = bio_read_intern(b, data, dlen, readbytes);
+
+    if (ret > 0)
+        ret = 1;
+    else
+        ret = 0;
+
+    return ret;
+}
+
+static int bio_write_intern(BIO *b, const void *data, size_t dlen,
+                            size_t *written)
+{
+    int ret;
 
     if (b == NULL)
-        return (0);
+        return 0;
 
-    cb = b->callback;
     if ((b->method == NULL) || (b->method->bwrite == NULL)) {
-        BIOerr(BIO_F_BIO_WRITE, BIO_R_UNSUPPORTED_METHOD);
-        return (-2);
+        BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD);
+        return -2;
     }
 
-    if ((cb != NULL) &&
-        ((i = (int)cb(b, BIO_CB_WRITE, in, inl, 0L, 1L)) <= 0))
-        return (i);
+    if ((b->callback != NULL || b->callback_ex != NULL) &&
+        ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L,
+                                       written)) <= 0))
+        return ret;
 
     if (!b->init) {
-        BIOerr(BIO_F_BIO_WRITE, BIO_R_UNINITIALIZED);
-        return (-2);
+        BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED);
+        return -2;
+    }
+
+    ret = b->method->bwrite(b, data, dlen, written);
+
+    if (ret > 0)
+        b->num_write += (uint64_t)*written;
+
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data,
+                                     dlen, 0, 0L, ret, written);
+
+    return ret;
+}
+
+int BIO_write(BIO *b, const void *data, int dlen)
+{
+    size_t written;
+    int ret;
+
+    if (dlen < 0)
+        return 0;
+
+    ret = bio_write_intern(b, data, (size_t)dlen, &written);
+
+    if (ret > 0) {
+        /* *written should always be <= inl */
+        ret = (int)written;
     }
 
-    i = b->method->bwrite(b, in, inl);
+    return ret;
+}
+
+int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written)
+{
+    int ret;
+
+    ret = bio_write_intern(b, data, dlen, written);
 
-    if (i > 0)
-        b->num_write += (uint64_t)i;
+    if (ret > 0)
+        ret = 1;
+    else
+        ret = 0;
 
-    if (cb != NULL)
-        i = (int)cb(b, BIO_CB_WRITE | BIO_CB_RETURN, in, inl, 0L, (long)i);
-    return (i);
+    return ret;
 }
 
 int BIO_puts(BIO *b, const char *in)
 {
-    int i;
-    long (*cb) (BIO *, int, const char *, int, long, long);
+    int ret;
+    size_t written = 0;
 
     if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) {
         BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD);
-        return (-2);
+        return -2;
     }
 
-    cb = b->callback;
-
-    if ((cb != NULL) && ((i = (int)cb(b, BIO_CB_PUTS, in, 0, 0L, 1L)) <= 0))
-        return (i);
+    if (b->callback != NULL || b->callback_ex != NULL) {
+        ret = (int)bio_call_callback(b, BIO_CB_PUTS, in, 0, 0, 0L, 1L, NULL);
+        if (ret <= 0)
+            return ret;
+    }
 
     if (!b->init) {
         BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED);
-        return (-2);
+        return -2;
+    }
+
+    ret = b->method->bputs(b, in);
+
+    if (ret > 0) {
+        b->num_write += (uint64_t)ret;
+        written = ret;
+        ret = 1;
     }
 
-    i = b->method->bputs(b, in);
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, in, 0, 0,
+                                     0L, ret, &written);
 
-    if (i > 0)
-        b->num_write += (uint64_t)i;
+    if (ret > 0) {
+        if (written > INT_MAX) {
+            BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG);
+            ret = -1;
+        } else {
+            ret = (int)written;
+        }
+    }
 
-    if (cb != NULL)
-        i = (int)cb(b, BIO_CB_PUTS | BIO_CB_RETURN, in, 0, 0L, (long)i);
-    return (i);
+    return ret;
 }
 
-int BIO_gets(BIO *b, char *in, int inl)
+int BIO_gets(BIO *b, char *out, int outl)
 {
-    int i;
-    long (*cb) (BIO *, int, const char *, int, long, long);
+    int ret;
+    size_t readbytes = 0;
 
     if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) {
         BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD);
         return (-2);
     }
 
-    cb = b->callback;
+    if (outl < 0) {
+        BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT);
+        return 0;
+    }
 
-    if ((cb != NULL) && ((i = (int)cb(b, BIO_CB_GETS, in, inl, 0L, 1L)) <= 0))
-        return (i);
+    if (b->callback != NULL || b->callback_ex != NULL) {
+        ret = (int)bio_call_callback(b, BIO_CB_GETS, out, outl, 0, 0L, 1, NULL);
+        if (ret <= 0)
+            return ret;
+    }
 
     if (!b->init) {
         BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED);
         return (-2);
     }
 
-    i = b->method->bgets(b, in, inl);
+    ret = b->method->bgets(b, out, outl);
+
+    if (ret > 0) {
+        readbytes = ret;
+        ret = 1;
+    }
+
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, out, outl,
+                                     0, 0L, ret, &readbytes);
 
-    if (cb != NULL)
-        i = (int)cb(b, BIO_CB_GETS | BIO_CB_RETURN, in, inl, 0L, (long)i);
-    return (i);
+    if (ret > 0) {
+        /* Shouldn't happen */
+        if (readbytes > (size_t)outl)
+            ret = -1;
+        else
+            ret = (int)readbytes;
+    }
+
+    return ret;
 }
 
 int BIO_indent(BIO *b, int indent, int max)
@@ -327,27 +509,28 @@ void *BIO_ptr_ctrl(BIO *b, int cmd, long larg)
 long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
 {
     long ret;
-    long (*cb) (BIO *, int, const char *, int, long, long);
 
     if (b == NULL)
-        return (0);
+        return 0;
 
     if ((b->method == NULL) || (b->method->ctrl == NULL)) {
         BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD);
-        return (-2);
+        return -2;
     }
 
-    cb = b->callback;
-
-    if ((cb != NULL) &&
-        ((ret = cb(b, BIO_CB_CTRL, parg, cmd, larg, 1L)) <= 0))
-        return (ret);
+    if (b->callback != NULL || b->callback_ex != NULL) {
+        ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL);
+        if (ret <= 0)
+            return ret;
+    }
 
     ret = b->method->ctrl(b, cmd, larg, parg);
 
-    if (cb != NULL)
-        ret = cb(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
-    return (ret);
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd,
+                                larg, ret, NULL);
+
+    return ret;
 }
 
 long BIO_callback_ctrl(BIO *b, int cmd,
@@ -355,7 +538,6 @@ long BIO_callback_ctrl(BIO *b, int cmd,
                                    long, long))
 {
     long ret;
-    long (*cb) (BIO *, int, const char *, int, long, long);
 
     if (b == NULL)
         return (0);
@@ -365,17 +547,20 @@ long BIO_callback_ctrl(BIO *b, int cmd,
         return (-2);
     }
 
-    cb = b->callback;
-
-    if ((cb != NULL) &&
-        ((ret = cb(b, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L)) <= 0))
-        return (ret);
+    if (b->callback != NULL || b->callback_ex != NULL) {
+        ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L,
+                                NULL);
+        if (ret <= 0)
+            return ret;
+    }
 
     ret = b->method->callback_ctrl(b, cmd, fp);
 
-    if (cb != NULL)
-        ret = cb(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
-    return (ret);
+    if (b->callback != NULL || b->callback_ex != NULL)
+        ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0,
+                                cmd, 0, ret, NULL);
+
+    return ret;
 }
 
 /*
@@ -518,6 +703,7 @@ BIO *BIO_dup_chain(BIO *in)
         if ((new_bio = BIO_new(bio->method)) == NULL)
             goto err;
         new_bio->callback = bio->callback;
+        new_bio->callback_ex = bio->callback_ex;
         new_bio->cb_arg = bio->cb_arg;
         new_bio->init = bio->init;
         new_bio->shutdown = bio->shutdown;
diff --git a/crypto/bio/bio_meth.c b/crypto/bio/bio_meth.c
index c5f9f7e..588c517 100644
--- a/crypto/bio/bio_meth.c
+++ b/crypto/bio/bio_meth.c
@@ -51,24 +51,93 @@ void BIO_meth_free(BIO_METHOD *biom)
 
 int (*BIO_meth_get_write(BIO_METHOD *biom)) (BIO *, const char *, int)
 {
+    return biom->bwrite_old;
+}
+
+int (*BIO_meth_get_write_ex(BIO_METHOD *biom)) (BIO *, const char *, size_t,
+                                                size_t *)
+{
     return biom->bwrite;
 }
 
+/* Conversion for old style bwrite to new style */
+int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written)
+{
+    int ret;
+
+    if (datal > INT_MAX)
+        datal = INT_MAX;
+
+    ret = bio->method->bwrite_old(bio, data, (int)datal);
+
+    if (ret <= 0) {
+        *written = 0;
+        return ret;
+    }
+
+    *written = (size_t)ret;
+
+    return 1;
+}
+
 int BIO_meth_set_write(BIO_METHOD *biom,
                        int (*bwrite) (BIO *, const char *, int))
 {
+    biom->bwrite_old = bwrite;
+    biom->bwrite = bwrite_conv;
+    return 1;
+}
+
+int BIO_meth_set_write_ex(BIO_METHOD *biom,
+                       int (*bwrite) (BIO *, const char *, size_t, size_t *))
+{
+    biom->bwrite_old = NULL;
     biom->bwrite = bwrite;
     return 1;
 }
 
 int (*BIO_meth_get_read(BIO_METHOD *biom)) (BIO *, char *, int)
 {
+    return biom->bread_old;
+}
+
+int (*BIO_meth_get_read_ex(BIO_METHOD *biom)) (BIO *, char *, size_t, size_t *)
+{
     return biom->bread;
 }
 
+/* Conversion for old style bread to new style */
+int bread_conv(BIO *bio, char *data, size_t datal, size_t *readbytes)
+{
+    int ret;
+
+    if (datal > INT_MAX)
+        datal = INT_MAX;
+
+    ret = bio->method->bread_old(bio, data, (int)datal);
+
+    if (ret <= 0) {
+        *readbytes = 0;
+        return ret;
+    }
+
+    *readbytes = (size_t)ret;
+
+    return 1;
+}
+
 int BIO_meth_set_read(BIO_METHOD *biom,
                       int (*bread) (BIO *, char *, int))
 {
+    biom->bread_old = bread;
+    biom->bread = bread_conv;
+    return 1;
+}
+
+int BIO_meth_set_read_ex(BIO_METHOD *biom,
+                         int (*bread) (BIO *, char *, size_t, size_t *))
+{
+    biom->bread_old = NULL;
     biom->bread = bread;
     return 1;
 }
diff --git a/crypto/bio/bss_acpt.c b/crypto/bio/bss_acpt.c
index 6fb971a..e490fcd 100644
--- a/crypto/bio/bss_acpt.c
+++ b/crypto/bio/bss_acpt.c
@@ -54,7 +54,11 @@ static void BIO_ACCEPT_free(BIO_ACCEPT *a);
 static const BIO_METHOD methods_acceptp = {
     BIO_TYPE_ACCEPT,
     "socket accept",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     acpt_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     acpt_read,
     acpt_puts,
     NULL,                       /* connect_gets, */
diff --git a/crypto/bio/bss_bio.c b/crypto/bio/bss_bio.c
index de34f6b..9fa4760 100644
--- a/crypto/bio/bss_bio.c
+++ b/crypto/bio/bss_bio.c
@@ -39,7 +39,11 @@ static void bio_destroy_pair(BIO *bio);
 static const BIO_METHOD methods_biop = {
     BIO_TYPE_BIO,
     "BIO pair",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     bio_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     bio_read,
     bio_puts,
     NULL /* no bio_gets */ ,
diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c
index dfd0988..ddbc896 100644
--- a/crypto/bio/bss_conn.c
+++ b/crypto/bio/bss_conn.c
@@ -58,7 +58,11 @@ void BIO_CONNECT_free(BIO_CONNECT *a);
 static const BIO_METHOD methods_connectp = {
     BIO_TYPE_CONNECT,
     "socket connect",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     conn_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     conn_read,
     conn_puts,
     NULL,                       /* connect_gets, */
diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c
index 6dfcc9b..89936ff 100644
--- a/crypto/bio/bss_dgram.c
+++ b/crypto/bio/bss_dgram.c
@@ -73,7 +73,11 @@ static void get_current_time(struct timeval *t);
 static const BIO_METHOD methods_dgramp = {
     BIO_TYPE_DGRAM,
     "datagram socket",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     dgram_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     dgram_read,
     dgram_puts,
     NULL,                       /* dgram_gets, */
diff --git a/crypto/bio/bss_fd.c b/crypto/bio/bss_fd.c
index 1e56cb6..0f003cd 100644
--- a/crypto/bio/bss_fd.c
+++ b/crypto/bio/bss_fd.c
@@ -59,7 +59,11 @@ int BIO_fd_should_retry(int s);
 
 static const BIO_METHOD methods_fdp = {
     BIO_TYPE_FD, "file descriptor",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     fd_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     fd_read,
     fd_puts,
     fd_gets,
diff --git a/crypto/bio/bss_file.c b/crypto/bio/bss_file.c
index 6af2d9c..adf935f 100644
--- a/crypto/bio/bss_file.c
+++ b/crypto/bio/bss_file.c
@@ -51,7 +51,11 @@ static int file_free(BIO *data);
 static const BIO_METHOD methods_filep = {
     BIO_TYPE_FILE,
     "FILE pointer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     file_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     file_read,
     file_puts,
     file_gets,
@@ -394,7 +398,11 @@ static int file_free(BIO *a)
 static const BIO_METHOD methods_filep = {
     BIO_TYPE_FILE,
     "FILE pointer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     file_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     file_read,
     file_puts,
     file_gets,
diff --git a/crypto/bio/bss_log.c b/crypto/bio/bss_log.c
index 6cbde4d..963371e 100644
--- a/crypto/bio/bss_log.c
+++ b/crypto/bio/bss_log.c
@@ -86,8 +86,11 @@ static void xcloselog(BIO *bp);
 
 static const BIO_METHOD methods_slg = {
     BIO_TYPE_MEM, "syslog",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     slg_write,
     NULL,
+    NULL,
     slg_puts,
     NULL,
     slg_ctrl,
diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c
index 6dc075d..38ffb10 100644
--- a/crypto/bio/bss_mem.c
+++ b/crypto/bio/bss_mem.c
@@ -26,7 +26,11 @@ static int mem_buf_sync(BIO *h);
 static const BIO_METHOD mem_method = {
     BIO_TYPE_MEM,
     "memory buffer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     mem_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     mem_read,
     mem_puts,
     mem_gets,
@@ -39,7 +43,11 @@ static const BIO_METHOD mem_method = {
 static const BIO_METHOD secmem_method = {
     BIO_TYPE_MEM,
     "secure memory buffer",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     mem_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     mem_read,
     mem_puts,
     mem_gets,
diff --git a/crypto/bio/bss_null.c b/crypto/bio/bss_null.c
index e5c4adc..d197a60 100644
--- a/crypto/bio/bss_null.c
+++ b/crypto/bio/bss_null.c
@@ -22,7 +22,11 @@ static int null_free(BIO *data);
 static const BIO_METHOD null_method = {
     BIO_TYPE_NULL,
     "NULL",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     null_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     null_read,
     null_puts,
     null_gets,
diff --git a/crypto/bio/bss_sock.c b/crypto/bio/bss_sock.c
index 570e898..c47b160 100644
--- a/crypto/bio/bss_sock.c
+++ b/crypto/bio/bss_sock.c
@@ -38,7 +38,11 @@ int BIO_sock_should_retry(int s);
 static const BIO_METHOD methods_sockp = {
     BIO_TYPE_SOCKET,
     "socket",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     sock_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     sock_read,
     sock_puts,
     NULL,                       /* sock_gets, */
diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c
index 32a884a..4f0e19e 100644
--- a/crypto/evp/bio_b64.c
+++ b/crypto/evp/bio_b64.c
@@ -48,7 +48,11 @@ typedef struct b64_struct {
 
 static const BIO_METHOD methods_b64 = {
     BIO_TYPE_BASE64, "base64 encoding",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     b64_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     b64_read,
     b64_puts,
     NULL,                       /* b64_gets, */
diff --git a/crypto/evp/bio_enc.c b/crypto/evp/bio_enc.c
index 5a3beef..7d596e0 100644
--- a/crypto/evp/bio_enc.c
+++ b/crypto/evp/bio_enc.c
@@ -47,7 +47,11 @@ typedef struct enc_struct {
 
 static const BIO_METHOD methods_enc = {
     BIO_TYPE_CIPHER, "cipher",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     enc_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     enc_read,
     NULL,                       /* enc_puts, */
     NULL,                       /* enc_gets, */
diff --git a/crypto/evp/bio_md.c b/crypto/evp/bio_md.c
index cd968ec..c9e3858 100644
--- a/crypto/evp/bio_md.c
+++ b/crypto/evp/bio_md.c
@@ -33,7 +33,11 @@ static long md_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
 
 static const BIO_METHOD methods_md = {
     BIO_TYPE_MD, "message digest",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     md_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     md_read,
     NULL,                       /* md_puts, */
     md_gets,
diff --git a/crypto/evp/bio_ok.c b/crypto/evp/bio_ok.c
index 7974b96..4722846 100644
--- a/crypto/evp/bio_ok.c
+++ b/crypto/evp/bio_ok.c
@@ -109,7 +109,11 @@ typedef struct ok_struct {
 
 static const BIO_METHOD methods_ok = {
     BIO_TYPE_CIPHER, "reliable",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     ok_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     ok_read,
     NULL,                       /* ok_puts, */
     NULL,                       /* ok_gets, */
diff --git a/doc/man3/BIO_ctrl.pod b/doc/man3/BIO_ctrl.pod
index 17dc6ed..934d07b 100644
--- a/doc/man3/BIO_ctrl.pod
+++ b/doc/man3/BIO_ctrl.pod
@@ -94,7 +94,7 @@ return the amount of pending data.
 =head1 NOTES
 
 BIO_flush(), because it can write data may return 0 or -1 indicating
-that the call should be retried later in a similar manner to BIO_write().
+that the call should be retried later in a similar manner to BIO_write_ex().
 The BIO_should_retry() call should be used and appropriate action taken
 is the call fails.
 
diff --git a/doc/man3/BIO_f_buffer.pod b/doc/man3/BIO_f_buffer.pod
index 3224710..9c178ce 100644
--- a/doc/man3/BIO_f_buffer.pod
+++ b/doc/man3/BIO_f_buffer.pod
@@ -49,7 +49,7 @@ is expanded.
 
 These functions, other than BIO_f_buffer(), are implemented as macros.
 
-Buffering BIOs implement BIO_gets() by using BIO_read() operations on the
+Buffering BIOs implement BIO_gets() by using BIO_read_ex() operations on the
 next BIO in the chain. By prepending a buffering BIO to a chain it is therefore
 possible to provide BIO_gets() functionality if the following BIOs do not
 support it (for example SSL BIOs).
diff --git a/doc/man3/BIO_f_md.pod b/doc/man3/BIO_f_md.pod
index 32f0046..d7ad04d 100644
--- a/doc/man3/BIO_f_md.pod
+++ b/doc/man3/BIO_f_md.pod
@@ -23,8 +23,8 @@ BIO that digests any data passed through it, it is a BIO wrapper
 for the digest routines EVP_DigestInit(), EVP_DigestUpdate()
 and EVP_DigestFinal().
 
-Any data written or read through a digest BIO using BIO_read() and
-BIO_write() is digested.
+Any data written or read through a digest BIO using BIO_read_ex() and
+BIO_write_ex() is digested.
 
 BIO_gets(), if its B<size> parameter is large enough finishes the
 digest calculation and returns the digest value. BIO_puts() is
diff --git a/doc/man3/BIO_f_ssl.pod b/doc/man3/BIO_f_ssl.pod
index 3f9635e..48bc150 100644
--- a/doc/man3/BIO_f_ssl.pod
+++ b/doc/man3/BIO_f_ssl.pod
@@ -108,7 +108,7 @@ already been established this call has no effect.
 SSL BIOs are exceptional in that if the underlying transport
 is non blocking they can still request a retry in exceptional
 circumstances. Specifically this will happen if a session
-renegotiation takes place during a BIO_read() operation, one
+renegotiation takes place during a BIO_read_ex() operation, one
 case where this happens is when step up occurs.
 
 The SSL flag SSL_AUTO_RETRY can be
diff --git a/doc/man3/BIO_meth_new.pod b/doc/man3/BIO_meth_new.pod
index bf33161..b1deb2a 100644
--- a/doc/man3/BIO_meth_new.pod
+++ b/doc/man3/BIO_meth_new.pod
@@ -3,11 +3,12 @@
 =head1 NAME
 
 BIO_get_new_index,
-BIO_meth_new, BIO_meth_free, BIO_meth_get_write, BIO_meth_set_write,
-BIO_meth_get_read, BIO_meth_set_read, BIO_meth_get_puts, BIO_meth_set_puts,
-BIO_meth_get_gets, BIO_meth_set_gets, BIO_meth_get_ctrl, BIO_meth_set_ctrl,
-BIO_meth_get_create, BIO_meth_set_create, BIO_meth_get_destroy,
-BIO_meth_set_destroy, BIO_meth_get_callback_ctrl,
+BIO_meth_new, BIO_meth_free, BIO_meth_get_read_ex, BIO_meth_set_read_ex,
+BIO_meth_get_write_ex, BIO_meth_set_write_ex, BIO_meth_get_write,
+BIO_meth_set_write, BIO_meth_get_read, BIO_meth_set_read, BIO_meth_get_puts,
+BIO_meth_set_puts, BIO_meth_get_gets, BIO_meth_set_gets, BIO_meth_get_ctrl,
+BIO_meth_set_ctrl, BIO_meth_get_create, BIO_meth_set_create,
+BIO_meth_get_destroy, BIO_meth_set_destroy, BIO_meth_get_callback_ctrl,
 BIO_meth_set_callback_ctrl  - Routines to build up BIO methods
 
 =head1 SYNOPSIS
@@ -17,10 +18,19 @@ BIO_meth_set_callback_ctrl  - Routines to build up BIO methods
  int BIO_get_new_index(void);
  BIO_METHOD *BIO_meth_new(int type, const char *name);
  void BIO_meth_free(BIO_METHOD *biom);
+ int (*BIO_meth_get_write_ex(BIO_METHOD *biom)) (BIO *, const char *, size_t,
+                                                 size_t *);
  int (*BIO_meth_get_write(BIO_METHOD *biom)) (BIO *, const char *, int);
+ int BIO_meth_set_write_ex(BIO_METHOD *biom,
+                           int (*bwrite) (BIO *, const char *, size_t,
+                                          size_t *));
  int BIO_meth_set_write(BIO_METHOD *biom,
                         int (*write) (BIO *, const char *, int));
+ int (*BIO_meth_get_read_ex(BIO_METHOD *biom)) (BIO *, char *, size_t,
+                                                size_t *);
  int (*BIO_meth_get_read(BIO_METHOD *biom)) (BIO *, char *, int);
+ int BIO_meth_set_read_ex(BIO_METHOD *biom,
+                          int (*bread) (BIO *, char *, size_t, size_t *));
  int BIO_meth_set_read(BIO_METHOD *biom,
                        int (*read) (BIO *, char *, int));
  int (*BIO_meth_get_puts(BIO_METHOD *biom)) (BIO *, const char *);
@@ -64,15 +74,23 @@ more information.
 BIO_meth_free() destroys a B<BIO_METHOD> structure and frees up any memory
 associated with it.
 
-BIO_meth_get_write() and BIO_meth_set_write() get and set the function used for
-writing arbitrary length data to the BIO respectively. This function will be
-called in response to the application calling BIO_write(). The parameters for
-the function have the same meaning as for BIO_write().
-
-BIO_meth_get_read() and BIO_meth_set_read() get and set the function used for
-reading arbitrary length data from the BIO respectively. This function will be
-called in response to the application calling BIO_read(). The parameters for the
-function have the same meaning as for BIO_read().
+BIO_meth_get_write_ex() and BIO_meth_set_write_ex() get and set the function
+used for writing arbitrary length data to the BIO respectively. This function
+will be called in response to the application calling BIO_write_ex() or
+BIO_write(). The parameters for the function have the same meaning as for
+BIO_write_ex(). Older code may call BIO_meth_get_write() and
+BIO_meth_set_write() instead. Applications should not call both
+BIO_meth_set_write_ex() and BIO_meth_set_write() or call BIO_meth_get_write()
+when the function was set with BIO_meth_set_write_ex().
+
+BIO_meth_get_read_ex() and BIO_meth_set_read_ex() get and set the function used
+for reading arbitrary length data from the BIO respectively. This function will
+be called in response to the application calling BIO_read_ex() or BIO_read().
+The parameters for the function have the same meaning as for BIO_read_ex().
+Older code may call BIO_meth_get_read() and BIO_meth_set_read() instead.
+Applications should not call both BIO_meth_set_read_ex() and BIO_meth_set_read()
+or call BIO_meth_get_read() when the function was set with
+BIO_meth_set_read_ex().
 
 BIO_meth_get_puts() and BIO_meth_set_puts() get and set the function used for
 writing a NULL terminated string to the BIO respectively. This function will be
@@ -113,7 +131,7 @@ the function have the same meaning as for BIO_callback_ctrl().
 
 =head1 SEE ALSO
 
-L<bio>, L<BIO_find_type>, L<BIO_ctrl>, L<BIO_read>, L<BIO_new>
+L<bio>, L<BIO_find_type>, L<BIO_ctrl>, L<BIO_read_ex>, L<BIO_new>
 
 =head1 HISTORY
 
diff --git a/doc/man3/BIO_read.pod b/doc/man3/BIO_read.pod
index 45871c1..6baa075 100644
--- a/doc/man3/BIO_read.pod
+++ b/doc/man3/BIO_read.pod
@@ -2,19 +2,30 @@
 
 =head1 NAME
 
-BIO_read, BIO_write, BIO_gets, BIO_puts - BIO I/O functions
+BIO_read_ex, BIO_write_ex, BIO_read, BIO_write, BIO_gets, BIO_puts
+- BIO I/O functions
 
 =head1 SYNOPSIS
 
  #include <openssl/bio.h>
 
- int    BIO_read(BIO *b, void *buf, int len);
- int    BIO_gets(BIO *b, char *buf, int size);
- int    BIO_write(BIO *b, const void *buf, int len);
- int    BIO_puts(BIO *b, const char *buf);
+ int BIO_read_ex(BIO *b, void *out, size_t outl, size_t *read);
+ int BIO_write_ex(BIO *b, const void *in, size_t inl, size_t *written);
+
+ int BIO_read(BIO *b, void *buf, int len);
+ int BIO_gets(BIO *b, char *buf, int size);
+ int BIO_write(BIO *b, const void *buf, int len);
+ int BIO_puts(BIO *b, const char *buf);
 
 =head1 DESCRIPTION
 
+BIO_read_ex() attempts to read B<outl> bytes from BIO B<b> and places the data
+in B<out>. If any bytes were successfully read then the number of bytes read is
+stored in B<*read>.
+
+BIO_write_ex() attempts to write B<inl> bytes from B<in> to BIO B<b>. If
+successful then the number of bytes written is stored in B<*written>.
+
 BIO_read() attempts to read B<len> bytes from BIO B<b> and places
 the data in B<buf>.
 
@@ -31,7 +42,10 @@ BIO_puts() attempts to write a NUL-terminated string B<buf> to BIO B<b>.
 
 =head1 RETURN VALUES
 
-All these functions return either the amount of data successfully read or
+BIO_read_ex() and BIO_write_ex() return 1 if data was successfully read or
+written, and 0 otherwise.
+
+All other functions return either the amount of data successfully read or
 written (if the return value is positive) or that no data was successfully
 read or written if the result is 0 or -1. If the return value is -2 then
 the operation is not implemented in the specific BIO type.  The trailing
diff --git a/doc/man3/BIO_s_bio.pod b/doc/man3/BIO_s_bio.pod
index cb46546..48c67fe 100644
--- a/doc/man3/BIO_s_bio.pod
+++ b/doc/man3/BIO_s_bio.pod
@@ -44,10 +44,10 @@ One typical use of BIO pairs is to place TLS/SSL I/O under application control,
 can be used when the application wishes to use a non standard transport for
 TLS/SSL or the normal socket routines are inappropriate.
 
-Calls to BIO_read() will read data from the buffer or request a retry if no
+Calls to BIO_read_ex() will read data from the buffer or request a retry if no
 data is available.
 
-Calls to BIO_write() will place data in the buffer or request a retry if the
+Calls to BIO_write_ex() will place data in the buffer or request a retry if the
 buffer is full.
 
 The standard calls BIO_ctrl_pending() and BIO_ctrl_wpending() can be used to
@@ -80,9 +80,9 @@ BIO_free() is not called.
 
 BIO_get_write_guarantee() and BIO_ctrl_get_write_guarantee() return the maximum
 length of data that can be currently written to the BIO. Writes larger than this
-value will return a value from BIO_write() less than the amount requested or if the
-buffer is full request a retry. BIO_ctrl_get_write_guarantee() is a function
-whereas BIO_get_write_guarantee() is a macro.
+value will return a value from BIO_write_ex() less than the amount requested or
+if the buffer is full request a retry. BIO_ctrl_get_write_guarantee() is a
+function whereas BIO_get_write_guarantee() is a macro.
 
 BIO_get_read_request() and BIO_ctrl_get_read_request() return the
 amount of data requested, or the buffer size if it is less, if the
@@ -111,12 +111,12 @@ it to the underlying transport. This must be done before any normal processing
 (such as calling select() ) due to a request and BIO_should_read() being true.
 
 To see why this is important consider a case where a request is sent using
-BIO_write() and a response read with BIO_read(), this can occur during an
-TLS/SSL handshake for example. BIO_write() will succeed and place data in the write
-buffer. BIO_read() will initially fail and BIO_should_read() will be true. If
-the application then waits for data to be available on the underlying transport
-before flushing the write buffer it will never succeed because the request was
-never sent!
+BIO_write_ex() and a response read with BIO_read_ex(), this can occur during an
+TLS/SSL handshake for example. BIO_write_ex() will succeed and place data in the
+write buffer. BIO_read_ex() will initially fail and BIO_should_read() will be
+true. If the application then waits for data to be available on the underlying
+transport before flushing the write buffer it will never succeed because the
+request was never sent!
 
 BIO_eof() is true if no data is in the peer BIO and the peer BIO has been
 shutdown.
@@ -187,7 +187,7 @@ the peer might be waiting for the data before being able to continue.
 =head1 SEE ALSO
 
 L<SSL_set_bio(3)>, L<ssl(3)>, L<bio(3)>,
-L<BIO_should_retry(3)>, L<BIO_read(3)>
+L<BIO_should_retry(3)>, L<BIO_read_ex(3)>
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/BIO_s_fd.pod b/doc/man3/BIO_s_fd.pod
index 79c4a59..8ebf563 100644
--- a/doc/man3/BIO_s_fd.pod
+++ b/doc/man3/BIO_s_fd.pod
@@ -20,7 +20,7 @@ BIO_s_fd, BIO_set_fd, BIO_get_fd, BIO_new_fd - file descriptor BIO
 BIO_s_fd() returns the file descriptor BIO method. This is a wrapper
 round the platforms file descriptor routines such as read() and write().
 
-BIO_read() and BIO_write() read or write the underlying descriptor.
+BIO_read_ex() and BIO_write_ex() read or write the underlying descriptor.
 BIO_puts() is supported but BIO_gets() is not.
 
 If the close flag is set then close() is called on the underlying
@@ -45,10 +45,10 @@ BIO_new_fd() returns a file descriptor BIO using B<fd> and B<close_flag>.
 
 =head1 NOTES
 
-The behaviour of BIO_read() and BIO_write() depends on the behavior of the
+The behaviour of BIO_read_ex() and BIO_write_ex() depends on the behavior of the
 platforms read() and write() calls on the descriptor. If the underlying
 file descriptor is in a non blocking mode then the BIO will behave in the
-manner described in the L<BIO_read(3)> and L<BIO_should_retry(3)>
+manner described in the L<BIO_read_ex(3)> and L<BIO_should_retry(3)>
 manual pages.
 
 File descriptor BIOs should not be used for socket I/O. Use socket BIOs
@@ -81,8 +81,8 @@ This is a file descriptor BIO version of "Hello World":
 =head1 SEE ALSO
 
 L<BIO_seek(3)>, L<BIO_tell(3)>,
-L<BIO_reset(3)>, L<BIO_read(3)>,
-L<BIO_write(3)>, L<BIO_puts(3)>,
+L<BIO_reset(3)>, L<BIO_read_ex(3)>,
+L<BIO_write_ex(3)>, L<BIO_puts(3)>,
 L<BIO_gets(3)>, L<BIO_printf(3)>,
 L<BIO_set_close(3)>, L<BIO_get_close(3)>
 
diff --git a/doc/man3/BIO_s_file.pod b/doc/man3/BIO_s_file.pod
index e19d824..abbcdb0 100644
--- a/doc/man3/BIO_s_file.pod
+++ b/doc/man3/BIO_s_file.pod
@@ -28,7 +28,7 @@ BIO_s_file() returns the BIO file method. As its name implies it
 is a wrapper round the stdio FILE structure and it is a
 source/sink BIO.
 
-Calls to BIO_read() and BIO_write() read and write data to the
+Calls to BIO_read_ex() and BIO_write_ex() read and write data to the
 underlying stream. BIO_gets() and BIO_puts() are supported on file BIOs.
 
 BIO_flush() on a file BIO calls the fflush() function on the wrapped
@@ -142,8 +142,8 @@ occurred this differs from other types of BIO which will typically return
 
 L<BIO_seek(3)>, L<BIO_tell(3)>,
 L<BIO_reset(3)>, L<BIO_flush(3)>,
-L<BIO_read(3)>,
-L<BIO_write(3)>, L<BIO_puts(3)>,
+L<BIO_read_ex(3)>,
+L<BIO_write_ex(3)>, L<BIO_puts(3)>,
 L<BIO_gets(3)>, L<BIO_printf(3)>,
 L<BIO_set_close(3)>, L<BIO_get_close(3)>
 
diff --git a/doc/man3/BIO_s_socket.pod b/doc/man3/BIO_s_socket.pod
index ad0574a..781ff24 100644
--- a/doc/man3/BIO_s_socket.pod
+++ b/doc/man3/BIO_s_socket.pod
@@ -17,7 +17,7 @@ BIO_s_socket, BIO_new_socket - socket BIO
 BIO_s_socket() returns the socket BIO method. This is a wrapper
 round the platform's socket routines.
 
-BIO_read() and BIO_write() read or write the underlying socket.
+BIO_read_ex() and BIO_write_ex() read or write the underlying socket.
 BIO_puts() is supported but BIO_gets() is not.
 
 If the close flag is set then the socket is shut down and closed
diff --git a/doc/man3/BIO_set_callback.pod b/doc/man3/BIO_set_callback.pod
index 113b416..6e5656f 100644
--- a/doc/man3/BIO_set_callback.pod
+++ b/doc/man3/BIO_set_callback.pod
@@ -2,17 +2,23 @@
 
 =head1 NAME
 
-BIO_set_callback, BIO_get_callback, BIO_set_callback_arg, BIO_get_callback_arg,
-BIO_debug_callback - BIO callback functions
+BIO_set_callback_ex, BIO_get_callback_ex, BIO_set_callback, BIO_get_callback,
+BIO_set_callback_arg, BIO_get_callback_arg, BIO_debug_callback
+- BIO callback functions
 
 =head1 SYNOPSIS
 
  #include <openssl/bio.h>
 
-
+ typedef long (*BIO_callback_fn_ex)(BIO *b, int oper, const char *argp,
+                                    size_t len, int argi,
+                                    long argl, int ret, size_t *processed);
  typedef long (*BIO_callback_fn)(BIO *b, int oper, const char *argp, int argi,
                                  long argl, long ret);
 
+ void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex callback);
+ BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b);
+
  void BIO_set_callback(BIO *b, BIO_callack_fn cb);
  BIO_callack_fn BIO_get_callback(BIO *b);
  void BIO_set_callback_arg(BIO *b, char *arg);
@@ -23,10 +29,15 @@ BIO_debug_callback - BIO callback functions
 
 =head1 DESCRIPTION
 
-BIO_set_callback() and BIO_get_callback() set and retrieve the BIO callback,
-they are both macros. The callback is called during most high level BIO
-operations. It can be used for debugging purposes to trace operations on
-a BIO or to modify its operation.
+BIO_set_callback_ex() and BIO_get_callback_ex() set and retrieve the BIO
+callback. The callback is called during most high level BIO operations. It can
+be used for debugging purposes to trace operations on a BIO or to modify its
+operation.
+
+BIO_set_callback() and BIO_get_callback() set and retrieve the old format BIO
+callback. New code should not use these functions, but they are retained for
+backwards compatbility. Any callback set via BIO_set_callback_ex() will get
+called in preference to any set by BIO_set_callback().
 
 BIO_set_callback_arg() and BIO_get_callback_arg() are macros which can be
 used to set and retrieve an argument for use in the callback.
@@ -36,8 +47,9 @@ out information relating to each BIO operation. If the callback
 argument is set it is interpreted as a BIO to send the information
 to, otherwise stderr is used.
 
-BIO_callback_fn() is the type of the callback function. The meaning of each
-argument is described below:
+BIO_callback_fn_ex() is the type of the callback function and BIO_callback_fn()
+is the type of the old format callback function. The meaning of each argument
+is described below:
 
 =over
 
@@ -51,11 +63,22 @@ B<oper> is set to the operation being performed. For some operations
 the callback is called twice, once before and once after the actual
 operation, the latter case has B<oper> or'ed with BIO_CB_RETURN.
 
+=item B<len>
+
+The length of the data requested to be read or written. This is only useful if
+B<oper> is BIO_CB_READ, BIO_CB_WRITE or BIO_CB_GETS.
+
 =item B<argp> B<argi> B<argl>
 
 The meaning of the arguments B<argp>, B<argi> and B<argl> depends on
 the value of B<oper>, that is the operation being performed.
 
+=item B<processed>
+
+B<processed> is a pointer to a location which will be updated with the amount of
+data that was actually read or written. Only used for BIO_CB_READ, BIO_CB_WRITE, 
+BIO_CB_GETS and BIO_CB_PUTS.
+
 =item B<ret>
 
 B<ret> is the return value that would be returned to the
@@ -80,37 +103,103 @@ function that is called.
 
 =item B<BIO_free(b)>
 
-callback(b, BIO_CB_FREE, NULL, 0L, 0L, 1L) is called before the
-free operation.
+ callback_ex(b, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL)
+
+or
+
+ callback(b, BIO_CB_FREE, NULL, 0L, 0L, 1L)
+
+is called before the free operation.
+
+=item B<BIO_read_ex(b, out, outl, read)>
 
-=item B<BIO_read(b, out, outl)>
+ callback_ex(b, BIO_CB_READ, out, outl, 0, 0L, 1L, read)
+
+or
+
+ callback(b, BIO_CB_READ, out, outl, 0L, 1L)
+ 
+is called before the read and
+
+ callback_ex(b, BIO_CB_READ | BIO_CB_RETURN, out, outl, 0, 0L, retvalue, read)
+
+or
+
+ callback(b, BIO_CB_READ|BIO_CB_RETURN, out, outl, 0L, retvalue)
 
-callback(b, BIO_CB_READ, out, outl, 0L, 1L) is called before
-the read and callback(b, BIO_CB_READ|BIO_CB_RETURN, out, outl, 0L, retvalue)
 after.
 
-=item B<BIO_write(b, in, inl)>
+=item B<BIO_write(b, in, inl, written)>
+
+ callback_ex(b, BIO_CB_WRITE, in, inl, 0, 0L, 1L, written)
+
+or
+
+ callback(b, BIO_CB_WRITE, in, inl, 0L, 1L)
+
+is called before the write and
+
+ callback_ex(b, BIO_CB_WRITE | BIO_CB_RETURN, in, inl, 0, 0L, retvalue, written)
+
+or
+
+ callback(b, BIO_CB_WRITE|BIO_CB_RETURN, in, inl, 0L, retvalue)
 
-callback(b, BIO_CB_WRITE, in, inl, 0L, 1L) is called before
-the write and callback(b, BIO_CB_WRITE|BIO_CB_RETURN, in, inl, 0L, retvalue)
 after.
 
 =item B<BIO_gets(b, out, outl)>
 
-callback(b, BIO_CB_GETS, out, outl, 0L, 1L) is called before
-the operation and callback(b, BIO_CB_GETS|BIO_CB_RETURN, out, outl, 0L, retvalue)
+ callback_ex(b, BIO_CB_GETS, out, outl, 0, 0L, 1, NULL, NULL)
+
+or
+
+ callback(b, BIO_CB_GETS, out, outl, 0L, 1L)
+
+is called before the operation and
+
+ callback_ex(b, BIO_CB_GETS | BIO_CB_RETURN, out, outl, 0, 0L, retvalue, read)
+
+or
+
+ callback(b, BIO_CB_GETS|BIO_CB_RETURN, out, outl, 0L, retvalue)
+
 after.
 
 =item B<BIO_puts(b, in)>
 
-callback(b, BIO_CB_WRITE, in, 0, 0L, 1L) is called before
-the operation and callback(b, BIO_CB_WRITE|BIO_CB_RETURN, in, 0, 0L, retvalue)
+ callback_ex(b, BIO_CB_PUTS, in, 0, 0, 0L, 1L, NULL);
+
+or
+
+ callback(b, BIO_CB_PUTS, in, 0, 0L, 1L)
+
+is called before the operation and
+
+ callback_ex(b, BIO_CB_PUTS | BIO_CB_RETURN, in, 0, 0, 0L, retvalue, written)
+
+or
+
+ callback(b, BIO_CB_WRITE|BIO_CB_RETURN, in, 0, 0L, retvalue)
+
 after.
 
 =item B<BIO_ctrl(BIO *b, int cmd, long larg, void *parg)>
 
-callback(b, BIO_CB_CTRL, parg, cmd, larg, 1L) is called before the call and
-callback(b, BIO_CB_CTRL|BIO_CB_RETURN, parg, cmd, larg, ret) after.
+ callback_ex(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL)
+
+or
+
+ callback(b, BIO_CB_CTRL, parg, cmd, larg, 1L)
+
+is called before the call and
+
+ callback_ex(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, larg, ret, NULL)
+
+or
+
+ callback(b, BIO_CB_CTRL|BIO_CB_RETURN, parg, cmd, larg, ret)
+ 
+after.
 
 =back
 
diff --git a/doc/man3/BIO_should_retry.pod b/doc/man3/BIO_should_retry.pod
index d6ddf48..d145bf4 100644
--- a/doc/man3/BIO_should_retry.pod
+++ b/doc/man3/BIO_should_retry.pod
@@ -24,7 +24,7 @@ functions
 =head1 DESCRIPTION
 
 These functions determine why a BIO is not able to read or write data.
-They will typically be called after a failed BIO_read() or BIO_write()
+They will typically be called after a failed BIO_read_ex() or BIO_write_ex()
 call.
 
 BIO_should_retry() is true if the call that produced this condition
@@ -65,7 +65,7 @@ BIO_retry_type(), and BIO_should_retry(), are implemented as macros.
 
 If BIO_should_retry() returns false then the precise "error condition"
 depends on the BIO type that caused it and the return code of the BIO
-operation. For example if a call to BIO_read() on a socket BIO returns
+operation. For example if a call to BIO_read_ex() on a socket BIO returns
 0 and BIO_should_retry() is false then the cause will be that the
 connection closed. A similar condition on a file BIO will mean that it
 has reached EOF. Some BIO types may place additional information on
diff --git a/doc/man7/bio.pod b/doc/man7/bio.pod
index ec0d2df..7ad8bf4 100644
--- a/doc/man7/bio.pod
+++ b/doc/man7/bio.pod
@@ -66,7 +66,7 @@ L<BIO_f_cipher(3)>, L<BIO_f_md(3)>,
 L<BIO_f_null(3)>, L<BIO_f_ssl(3)>,
 L<BIO_find_type(3)>, L<BIO_new(3)>,
 L<BIO_new_bio_pair(3)>,
-L<BIO_push(3)>, L<BIO_read(3)>,
+L<BIO_push(3)>, L<BIO_read_ex(3)>,
 L<BIO_s_accept(3)>, L<BIO_s_bio(3)>,
 L<BIO_s_connect(3)>, L<BIO_s_fd(3)>,
 L<BIO_s_file(3)>, L<BIO_s_mem(3)>,
diff --git a/include/internal/bio.h b/include/internal/bio.h
index 3b6a6ac..f02d741 100644
--- a/include/internal/bio.h
+++ b/include/internal/bio.h
@@ -12,8 +12,10 @@
 struct bio_method_st {
     int type;
     const char *name;
-    int (*bwrite) (BIO *, const char *, int);
-    int (*bread) (BIO *, char *, int);
+    int (*bwrite) (BIO *, const char *, size_t, size_t *);
+    int (*bwrite_old) (BIO *, const char *, int);
+    int (*bread) (BIO *, char *, size_t, size_t *);
+    int (*bread_old) (BIO *, char *, int);
     int (*bputs) (BIO *, const char *);
     int (*bgets) (BIO *, char *, int);
     long (*ctrl) (BIO *, int, long, void *);
@@ -24,3 +26,8 @@ struct bio_method_st {
 
 void bio_free_ex_data(BIO *bio);
 void bio_cleanup(void);
+
+
+/* Old style to new style BIO_METHOD conversion functions */
+int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written);
+int bread_conv(BIO *bio, char *data, size_t datal, size_t *read);
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 9bc941b..4b80719 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -239,8 +239,15 @@ void BIO_clear_flags(BIO *b, int flags);
 
 typedef long (*BIO_callback_fn)(BIO *b, int oper, const char *argp, int argi,
                                 long argl, long ret);
+typedef long (*BIO_callback_fn_ex)(BIO *b, int oper, const char *argp,
+                                   size_t len, int argi,
+                                   long argl, int ret, size_t *processed);
 BIO_callback_fn BIO_get_callback(const BIO *b);
 void BIO_set_callback(BIO *b, BIO_callback_fn callback);
+
+BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b);
+void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex callback);
+
 char *BIO_get_callback_arg(const BIO *b);
 void BIO_set_callback_arg(BIO *b, char *arg);
 
@@ -544,9 +551,11 @@ void BIO_set_shutdown(BIO *a, int shut);
 int BIO_get_shutdown(BIO *a);
 void BIO_vfree(BIO *a);
 int BIO_up_ref(BIO *a);
-int BIO_read(BIO *b, void *data, int len);
+int BIO_read(BIO *b, void *data, int dlen);
+int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *read);
 int BIO_gets(BIO *bp, char *buf, int size);
-int BIO_write(BIO *b, const void *data, int len);
+int BIO_write(BIO *b, const void *data, int dlen);
+int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written);
 int BIO_puts(BIO *bp, const char *buf);
 int BIO_indent(BIO *b, int indent, int max);
 long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);
@@ -734,11 +743,18 @@ __bio_h__attr__((__format__(__printf__, 3, 0)));
 BIO_METHOD *BIO_meth_new(int type, const char *name);
 void BIO_meth_free(BIO_METHOD *biom);
 int (*BIO_meth_get_write(BIO_METHOD *biom)) (BIO *, const char *, int);
+int (*BIO_meth_get_write_ex(BIO_METHOD *biom)) (BIO *, const char *, size_t,
+                                                size_t *);
 int BIO_meth_set_write(BIO_METHOD *biom,
                        int (*write) (BIO *, const char *, int));
+int BIO_meth_set_write_ex(BIO_METHOD *biom,
+                       int (*bwrite) (BIO *, const char *, size_t, size_t *));
 int (*BIO_meth_get_read(BIO_METHOD *biom)) (BIO *, char *, int);
+int (*BIO_meth_get_read_ex(BIO_METHOD *biom)) (BIO *, char *, size_t, size_t *);
 int BIO_meth_set_read(BIO_METHOD *biom,
                       int (*read) (BIO *, char *, int));
+int BIO_meth_set_read_ex(BIO_METHOD *biom,
+                         int (*bread) (BIO *, char *, size_t, size_t *));
 int (*BIO_meth_get_puts(BIO_METHOD *biom)) (BIO *, const char *);
 int BIO_meth_set_puts(BIO_METHOD *biom,
                       int (*puts) (BIO *, const char *));
@@ -794,11 +810,15 @@ int ERR_load_BIO_strings(void);
 # define BIO_F_BIO_PARSE_HOSTSERV                         136
 # define BIO_F_BIO_PUTS                                   110
 # define BIO_F_BIO_READ                                   111
+# define BIO_F_BIO_READ_EX                                105
+# define BIO_F_BIO_READ_INTERN                            120
 # define BIO_F_BIO_SOCKET                                 140
 # define BIO_F_BIO_SOCKET_NBIO                            142
 # define BIO_F_BIO_SOCK_INFO                              141
 # define BIO_F_BIO_SOCK_INIT                              112
 # define BIO_F_BIO_WRITE                                  113
+# define BIO_F_BIO_WRITE_EX                               119
+# define BIO_F_BIO_WRITE_INTERN                           128
 # define BIO_F_BUFFER_CTRL                                114
 # define BIO_F_CONN_CTRL                                  127
 # define BIO_F_CONN_STATE                                 115
@@ -824,6 +844,7 @@ int ERR_load_BIO_strings(void);
 # define BIO_R_INVALID_ARGUMENT                           125
 # define BIO_R_INVALID_SOCKET                             135
 # define BIO_R_IN_USE                                     123
+# define BIO_R_LENGTH_TOO_LONG                            102
 # define BIO_R_LISTEN_V6_ONLY                             136
 # define BIO_R_LOOKUP_RETURNED_NOTHING                    142
 # define BIO_R_MALFORMED_HOST_OR_SERVICE                  130
diff --git a/ssl/bio_ssl.c b/ssl/bio_ssl.c
index 3dd09cf..d64451c 100644
--- a/ssl/bio_ssl.c
+++ b/ssl/bio_ssl.c
@@ -16,8 +16,8 @@
 #include <openssl/err.h>
 #include "ssl_locl.h"
 
-static int ssl_write(BIO *h, const char *buf, int num);
-static int ssl_read(BIO *h, char *buf, int size);
+static int ssl_write(BIO *h, const char *buf, size_t size, size_t *written);
+static int ssl_read(BIO *b, char *buf, size_t size, size_t *readbytes);
 static int ssl_puts(BIO *h, const char *str);
 static long ssl_ctrl(BIO *h, int cmd, long arg1, void *arg2);
 static int ssl_new(BIO *h);
@@ -36,7 +36,9 @@ typedef struct bio_ssl_st {
 static const BIO_METHOD methods_sslp = {
     BIO_TYPE_SSL, "ssl",
     ssl_write,
+    NULL,
     ssl_read,
+    NULL,
     ssl_puts,
     NULL,                       /* ssl_gets, */
     ssl_ctrl,
@@ -86,7 +88,7 @@ static int ssl_free(BIO *a)
     return 1;
 }
 
-static int ssl_read(BIO *b, char *out, int outl)
+static int ssl_read(BIO *b, char *buf, size_t size, size_t *readbytes)
 {
     int ret = 1;
     BIO_SSL *sb;
@@ -94,21 +96,26 @@ static int ssl_read(BIO *b, char *out, int outl)
     int retry_reason = 0;
     int r = 0;
 
-    if (out == NULL)
-        return (0);
+    if (buf == NULL)
+        return 0;
     sb = BIO_get_data(b);
     ssl = sb->ssl;
 
     BIO_clear_retry_flags(b);
 
-    ret = SSL_read(ssl, out, outl);
+    if (size > INT_MAX)
+        size = INT_MAX;
+
+    ret = SSL_read(ssl, buf, size);
+    if (ret > 0)
+        *readbytes = ret;
 
     switch (SSL_get_error(ssl, ret)) {
     case SSL_ERROR_NONE:
         if (ret <= 0)
             break;
         if (sb->renegotiate_count > 0) {
-            sb->byte_count += ret;
+            sb->byte_count += *readbytes;
             if (sb->byte_count > sb->renegotiate_count) {
                 sb->byte_count = 0;
                 sb->num_renegotiates++;
@@ -154,27 +161,28 @@ static int ssl_read(BIO *b, char *out, int outl)
     }
 
     BIO_set_retry_reason(b, retry_reason);
-    return (ret);
+
+    return ret;
 }
 
-static int ssl_write(BIO *b, const char *out, int outl)
+static int ssl_write(BIO *b, const char *buf, size_t size, size_t *written)
 {
     int ret, r = 0;
     int retry_reason = 0;
     SSL *ssl;
     BIO_SSL *bs;
 
-    if (out == NULL)
-        return (0);
+    if (buf == NULL)
+        return 0;
     bs = BIO_get_data(b);
     ssl = bs->ssl;
 
     BIO_clear_retry_flags(b);
 
-    /*
-     * ret=SSL_do_handshake(ssl); if (ret > 0)
-     */
-    ret = SSL_write(ssl, out, outl);
+    if (size > INT_MAX)
+        size = INT_MAX;
+
+    ret = SSL_write(ssl, buf, size);
 
     switch (SSL_get_error(ssl, ret)) {
     case SSL_ERROR_NONE:
@@ -220,6 +228,12 @@ static int ssl_write(BIO *b, const char *out, int outl)
     }
 
     BIO_set_retry_reason(b, retry_reason);
+
+    if (ret > 0) {
+        *written = ret;
+        ret = 1;
+    }
+
     return ret;
 }
 
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 21d46d2..e04580c 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4208,3 +4208,11 @@ OCSP_RESPID_set_by_key                  4158	1_1_0a	EXIST::FUNCTION:OCSP
 OCSP_RESPID_match                       4159	1_1_0a	EXIST::FUNCTION:OCSP
 ASN1_ITEM_lookup                        4160	1_1_1	EXIST::FUNCTION:
 ASN1_ITEM_get                           4161	1_1_1	EXIST::FUNCTION:
+BIO_read_ex                             4162	1_1_1	EXIST::FUNCTION:
+BIO_set_callback_ex                     4163	1_1_1	EXIST::FUNCTION:
+BIO_get_callback_ex                     4164	1_1_1	EXIST::FUNCTION:
+BIO_meth_set_read_ex                    4165	1_1_1	EXIST::FUNCTION:
+BIO_meth_get_read_ex                    4166	1_1_1	EXIST::FUNCTION:
+BIO_write_ex                            4167	1_1_1	EXIST::FUNCTION:
+BIO_meth_get_write_ex                   4168	1_1_1	EXIST::FUNCTION:
+BIO_meth_set_write_ex                   4169	1_1_1	EXIST::FUNCTION:


More information about the openssl-commits mailing list