[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Tue Sep 13 08:47:03 UTC 2016


The branch master has been updated
       via  c0f9e23c6b8d1076796987d5a84557d410682d85 (commit)
       via  df065a2b3b325fb55f085f95afbc3896b49e8f05 (commit)
       via  826573559df6c74a6773475a1b7a2a2ba13cec28 (commit)
       via  c39609aa6a575c9645d87711e3db439eb832ca70 (commit)
       via  de451856f08364ad6c6659b6eacbe820edc2aab9 (commit)
       via  6ae4f5e087d204e02a5dc88ea905cca9d144a30d (commit)
       via  9bf85bf9c52359813b5f9f6709b381497671d625 (commit)
       via  d6c4cc293974e622b387458d2293e29f8f14fbbb (commit)
       via  796a627e0a816ffbd79f53fa7d349e4edb624573 (commit)
       via  871bc59bc190d24ddd7b29aeb5fb2493b48e9cf5 (commit)
       via  fb790f1673884f4a9db9118e93714650f92eed66 (commit)
       via  0217dd19c00657b8bfd2bce1090785eb32abb235 (commit)
       via  ae2f7b37da3640f4cfa5df0e5bad2aa2ca5f1ba3 (commit)
       via  2c7b4dbc1af9cfae4e4afd7c4a07db95a1133a6a (commit)
       via  b7273855acd7ec2d1e7a4ba626ed538808fc7517 (commit)
      from  cdbbf9900253e8006868eba948248b1092a057de (commit)


- Log -----------------------------------------------------------------
commit c0f9e23c6b8d1076796987d5a84557d410682d85
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 13 09:40:38 2016 +0100

    Fix a few style nits in the wpacket code
    
    Addressing more feedback comments.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit df065a2b3b325fb55f085f95afbc3896b49e8f05
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 12 09:41:01 2016 +0100

    Remove else after a return in packet code
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 826573559df6c74a6773475a1b7a2a2ba13cec28
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 12 09:39:10 2016 +0100

    Pull out some common packet code into a function
    
    Two locations had the same loop for writing out a value. Pull it out into
    a function.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit c39609aa6a575c9645d87711e3db439eb832ca70
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 9 09:49:16 2016 +0100

    Add some soft asserts where applicable
    
    This is an internal API. Some of the tests were for programmer erorr and
    "should not happen" situations, so a soft assert is reasonable.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit de451856f08364ad6c6659b6eacbe820edc2aab9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 9 00:13:41 2016 +0100

    Address WPACKET review comments
    
    A few style tweaks here and there. The main change is that curr and
    packet_len are now offsets into the buffer to account for the fact that
    the pointers can change if the buffer grows. Also dropped support for the
    WPACKET_set_packet_len() function. I thought that was going to be needed
    but so far it hasn't been. It doesn't really work any more due to the
    offsets change.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 6ae4f5e087d204e02a5dc88ea905cca9d144a30d
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 8 23:08:53 2016 +0100

    Simplify the overflow checks in WPACKET_allocate_bytes()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 9bf85bf9c52359813b5f9f6709b381497671d625
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 8 11:44:25 2016 +0100

    Move the WPACKET documentation comments to packet_locl.h
    
    The PACKET documentation is already in packet_locl.h so it makes sense to
    have the WPACKET documentation there as well.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d6c4cc293974e622b387458d2293e29f8f14fbbb
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 8 10:01:24 2016 +0100

    Add tests for the WPACKET implementation
    
    The tests will only work in no-shared builds because WPACKET is an
    internal only API that does not get exported by the shared library.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 796a627e0a816ffbd79f53fa7d349e4edb624573
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 8 10:00:56 2016 +0100

    Ensure the WPACKET gets cleaned up in the event of an error
    
    Otherwise a mem leak can occur.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 871bc59bc190d24ddd7b29aeb5fb2493b48e9cf5
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 8 09:58:29 2016 +0100

    Various bug fixes and tweaks to WPACKET implementation
    
    Also added the WPACKET_cleanup() function to cleanup a WPACKET if we hit
    an error.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit fb790f1673884f4a9db9118e93714650f92eed66
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 6 15:19:32 2016 +0100

    Add WPACKET_sub_memcpy() function
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 0217dd19c00657b8bfd2bce1090785eb32abb235
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 6 15:09:51 2016 +0100

    Move from explicit sub-packets to implicit ones
    
    No need to declare an explicit sub-packet. Just start one.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit ae2f7b37da3640f4cfa5df0e5bad2aa2ca5f1ba3
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 5 17:34:04 2016 +0100

    Rename PACKETW to WPACKET
    
    To avoid confusion with the read PACKET structure.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 2c7b4dbc1af9cfae4e4afd7c4a07db95a1133a6a
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Aug 3 20:57:52 2016 +0100

    Convert tls_construct_client_hello() to use PACKETW
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b7273855acd7ec2d1e7a4ba626ed538808fc7517
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Aug 3 17:06:39 2016 +0100

    First pass at writing a writeable packets API
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h                              |   3 +-
 ssl/build.info                                     |   2 +-
 ssl/d1_lib.c                                       |   4 +
 ssl/d1_srtp.c                                      |  43 --
 ssl/packet.c                                       | 325 ++++++++++++++
 ssl/packet_locl.h                                  | 162 +++++++
 ssl/s3_lib.c                                       |  40 +-
 ssl/ssl_err.c                                      |   4 +-
 ssl/ssl_locl.h                                     |  37 +-
 ssl/statem/statem_clnt.c                           | 195 +++++----
 ssl/statem/statem_dtls.c                           |  43 ++
 ssl/statem/statem_lib.c                            |  14 +
 ssl/statem/statem_srvr.c                           |   4 +-
 ssl/t1_ext.c                                       |  69 ++-
 ssl/t1_lib.c                                       | 465 +++++++++++----------
 ssl/t1_reneg.c                                     |  24 --
 test/build.info                                    |   7 +
 .../{70-test_bad_dtls.t => 70-test_wpacket.t}      |   8 +-
 test/wpackettest.c                                 | 396 ++++++++++++++++++
 19 files changed, 1450 insertions(+), 395 deletions(-)
 create mode 100644 ssl/packet.c
 copy test/recipes/{70-test_bad_dtls.t => 70-test_wpacket.t} (69%)
 create mode 100644 test/wpackettest.c

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 41cb36e..af6d9b5 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2120,6 +2120,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_CHECK_PRIVATE_KEY                      163
 # define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT               280
 # define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG            279
+# define SSL_F_SSL_CIPHER_LIST_TO_BYTES                   425
 # define SSL_F_SSL_CIPHER_PROCESS_RULESTR                 230
 # define SSL_F_SSL_CIPHER_STRENGTH_SORT                   231
 # define SSL_F_SSL_CLEAR                                  164
@@ -2456,9 +2457,9 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_SSL_SECTION_NOT_FOUND                      136
 # define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED             301
 # define SSL_R_SSL_SESSION_ID_CONFLICT                    302
-# define SSL_R_SSL_SESSION_ID_TOO_LONG                    408
 # define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG            273
 # define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH              303
+# define SSL_R_SSL_SESSION_ID_TOO_LONG                    408
 # define SSL_R_SSL_SESSION_VERSION_MISMATCH               210
 # define SSL_R_TLSV1_ALERT_ACCESS_DENIED                  1049
 # define SSL_R_TLSV1_ALERT_DECODE_ERROR                   1050
diff --git a/ssl/build.info b/ssl/build.info
index 6977246..c7d4574 100644
--- a/ssl/build.info
+++ b/ssl/build.info
@@ -1,6 +1,6 @@
 LIBS=../libssl
 SOURCE[../libssl]=\
-        pqueue.c \
+        pqueue.c packet.c \
         statem/statem_srvr.c statem/statem_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
         statem/statem_lib.c s3_cbc.c s3_msg.c \
         methods.c   t1_lib.c  t1_enc.c t1_ext.c \
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 0ada7ed..043057f 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -44,6 +44,8 @@ const SSL3_ENC_METHOD DTLSv1_enc_data = {
     SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV,
     DTLS1_HM_HEADER_LENGTH,
     dtls1_set_handshake_header,
+    dtls1_set_handshake_header2,
+    dtls1_close_construct_packet,
     dtls1_handshake_write
 };
 
@@ -63,6 +65,8 @@ const SSL3_ENC_METHOD DTLSv1_2_enc_data = {
         | SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS,
     DTLS1_HM_HEADER_LENGTH,
     dtls1_set_handshake_header,
+    dtls1_set_handshake_header2,
+    dtls1_close_construct_packet,
     dtls1_handshake_write
 };
 
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
index 7e88f17..b5e5ef3 100644
--- a/ssl/d1_srtp.c
+++ b/ssl/d1_srtp.c
@@ -136,49 +136,6 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s)
     return s->srtp_profile;
 }
 
-/*
- * Note: this function returns 0 length if there are no profiles specified
- */
-int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
-                                     int maxlen)
-{
-    int ct = 0;
-    int i;
-    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0;
-    SRTP_PROTECTION_PROFILE *prof;
-
-    clnt = SSL_get_srtp_profiles(s);
-    ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */
-
-    if (p) {
-        if (ct == 0) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT,
-                   SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
-            return 1;
-        }
-
-        if ((2 + ct * 2 + 1) > maxlen) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT,
-                   SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
-            return 1;
-        }
-
-        /* Add the length */
-        s2n(ct * 2, p);
-        for (i = 0; i < ct; i++) {
-            prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
-            s2n(prof->id, p);
-        }
-
-        /* Add an empty use_mki value */
-        *p++ = 0;
-    }
-
-    *len = 2 + ct * 2 + 1;
-
-    return 0;
-}
-
 int ssl_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al)
 {
     SRTP_PROTECTION_PROFILE *sprof;
diff --git a/ssl/packet.c b/ssl/packet.c
new file mode 100644
index 0000000..b7084b0
--- /dev/null
+++ b/ssl/packet.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <assert.h>
+#include "packet_locl.h"
+
+#define DEFAULT_BUF_SIZE    256
+
+int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
+{
+    /* Internal API, so should not fail */
+    assert(pkt->subs != NULL && len != 0);
+    if (pkt->subs == NULL || len == 0)
+        return 0;
+
+    if (pkt->maxsize - pkt->written < len)
+        return 0;
+
+    if (pkt->buf->length - pkt->written < len) {
+        size_t newlen;
+
+        if (pkt->buf->length > SIZE_MAX / 2) {
+            newlen = SIZE_MAX;
+        } else {
+            newlen = (pkt->buf->length == 0) ? DEFAULT_BUF_SIZE
+                                             : pkt->buf->length * 2;
+        }
+        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
+            return 0;
+    }
+    *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
+    pkt->written += len;
+    pkt->curr += len;
+
+    return 1;
+}
+
+static size_t maxmaxsize(size_t lenbytes)
+{
+    if (lenbytes >= sizeof(size_t) || lenbytes == 0)
+        return SIZE_MAX;
+
+    return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
+}
+
+int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
+{
+    unsigned char *lenchars;
+
+    /* Internal API, so should not fail */
+    assert(buf != NULL);
+    if (buf == NULL)
+        return 0;
+
+    pkt->buf = buf;
+    pkt->curr = 0;
+    pkt->written = 0;
+    pkt->maxsize = maxmaxsize(lenbytes);
+
+    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
+    if (pkt->subs == NULL)
+        return 0;
+
+    if (lenbytes == 0)
+        return 1;
+
+    pkt->subs->pwritten = lenbytes;
+    pkt->subs->lenbytes = lenbytes;
+
+    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
+        OPENSSL_free(pkt->subs);
+        pkt->subs = NULL;
+        return 0;
+    }
+    pkt->subs->packet_len = lenchars - (unsigned char *)pkt->buf->data;
+
+    return 1;
+}
+
+int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
+{
+    return WPACKET_init_len(pkt, buf, 0);
+}
+
+int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
+{
+    /* Internal API, so should not fail */
+    assert(pkt->subs != NULL);
+    if (pkt->subs == NULL)
+        return 0;
+
+    pkt->subs->flags = flags;
+
+    return 1;
+}
+
+/* Store the |value| of length |len| at location |data| */
+static int put_value(unsigned char *data, size_t value, size_t len)
+{
+    for (data += len - 1; len > 0; len--) {
+        *data = (unsigned char)(value & 0xff);
+        data--;
+        value >>= 8;
+    }
+
+    /* Check whether we could fit the value in the assigned number of bytes */
+    if (value > 0)
+        return 0;
+
+    return 1;
+}
+
+
+/*
+ * Internal helper function used by WPACKET_close() and WPACKET_finish() to
+ * close a sub-packet and write out its length if necessary.
+ */
+static int wpacket_intern_close(WPACKET *pkt)
+{
+    WPACKET_SUB *sub = pkt->subs;
+    size_t packlen = pkt->written - sub->pwritten;
+
+    if (packlen == 0
+            && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0)
+        return 0;
+
+    if (packlen == 0
+            && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
+        /* Deallocate any bytes allocated for the length of the WPACKET */
+        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
+            pkt->written -= sub->lenbytes;
+            pkt->curr -= sub->lenbytes;
+        }
+
+        /* Don't write out the packet length */
+        sub->packet_len = 0;
+        sub->lenbytes = 0;
+    }
+
+    /* Write out the WPACKET length if needed */
+    if (sub->lenbytes > 0 
+                && !put_value((unsigned char *)&pkt->buf->data[sub->packet_len],
+                              packlen, sub->lenbytes))
+            return 0;
+
+    pkt->subs = sub->parent;
+    OPENSSL_free(sub);
+
+    return 1;
+}
+
+int WPACKET_close(WPACKET *pkt)
+{
+    /*
+     * Internal API, so should not fail - but we do negative testing of this
+     * so no assert (otherwise the tests fail)
+     */
+    if (pkt->subs == NULL || pkt->subs->parent == NULL)
+        return 0;
+
+    return wpacket_intern_close(pkt);
+}
+
+int WPACKET_finish(WPACKET *pkt)
+{
+    int ret;
+
+    /*
+     * Internal API, so should not fail - but we do negative testing of this
+     * so no assert (otherwise the tests fail)
+     */
+    if (pkt->subs == NULL || pkt->subs->parent != NULL)
+        return 0;
+
+    ret = wpacket_intern_close(pkt);
+    if (ret) {
+        OPENSSL_free(pkt->subs);
+        pkt->subs = NULL;
+    }
+
+    return ret;
+}
+
+int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
+{
+    WPACKET_SUB *sub;
+    unsigned char *lenchars;
+
+    /* Internal API, so should not fail */
+    assert(pkt->subs != NULL);
+    if (pkt->subs == NULL)
+        return 0;
+
+    sub = OPENSSL_zalloc(sizeof(*sub));
+    if (sub == NULL)
+        return 0;
+
+    sub->parent = pkt->subs;
+    pkt->subs = sub;
+    sub->pwritten = pkt->written + lenbytes;
+    sub->lenbytes = lenbytes;
+
+    if (lenbytes == 0) {
+        sub->packet_len = 0;
+        return 1;
+    }
+
+    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
+        return 0;
+    sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
+
+    return 1;
+}
+
+int WPACKET_start_sub_packet(WPACKET *pkt)
+{
+    return WPACKET_start_sub_packet_len(pkt, 0);
+}
+
+int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t size)
+{
+    unsigned char *data;
+
+    /* Internal API, so should not fail */
+    assert(size <= sizeof(unsigned int));
+
+    if (size > sizeof(unsigned int)
+            || !WPACKET_allocate_bytes(pkt, size, &data)
+            || !put_value(data, val, size))
+        return 0;
+
+    return 1;
+}
+
+int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
+{
+    WPACKET_SUB *sub;
+    size_t lenbytes;
+
+    /* Internal API, so should not fail */
+    assert(pkt->subs != NULL);
+    if (pkt->subs == NULL)
+        return 0;
+
+    /* Find the WPACKET_SUB for the top level */
+    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
+        continue;
+
+    lenbytes = sub->lenbytes;
+    if (lenbytes == 0)
+        lenbytes = sizeof(pkt->maxsize);
+
+    if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
+        return 0;
+
+    pkt->maxsize = maxsize;
+
+    return 1;
+}
+
+int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
+{
+    unsigned char *dest;
+
+    if (len == 0)
+        return 1;
+
+    if (!WPACKET_allocate_bytes(pkt, len, &dest))
+        return 0;
+
+    memcpy(dest, src, len);
+
+    return 1;
+}
+
+int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len, size_t lenbytes)
+{
+    if (!WPACKET_start_sub_packet_len(pkt, lenbytes)
+            || !WPACKET_memcpy(pkt, src, len)
+            || !WPACKET_close(pkt))
+        return 0;
+
+    return 1;
+}
+
+int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
+{
+    /* Internal API, so should not fail */
+    assert(written != NULL);
+    if (written == NULL)
+        return 0;
+
+    *written = pkt->written;
+
+    return 1;
+}
+
+int WPACKET_get_length(WPACKET *pkt, size_t *len)
+{
+    /* Internal API, so should not fail */
+    assert(pkt->subs != NULL && len != NULL);
+    if (pkt->subs == NULL || len == NULL)
+        return 0;
+
+    *len = pkt->written - pkt->subs->pwritten;
+
+    return 1;
+}
+
+void WPACKET_cleanup(WPACKET *pkt)
+{
+    WPACKET_SUB *sub, *parent;
+
+    for (sub = pkt->subs; sub != NULL; sub = parent) {
+        parent = sub->parent;
+        OPENSSL_free(sub);
+    }
+    pkt->subs = NULL;
+}
diff --git a/ssl/packet_locl.h b/ssl/packet_locl.h
index d34034d..daef69e 100644
--- a/ssl/packet_locl.h
+++ b/ssl/packet_locl.h
@@ -548,6 +548,168 @@ __owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt,
 
     return 1;
 }
+
+/* Writeable packets */
+
+typedef struct wpacket_sub WPACKET_SUB;
+struct wpacket_sub {
+    /* The parent WPACKET_SUB if we have one or NULL otherwise */
+    WPACKET_SUB *parent;
+
+    /*
+     * Offset into the buffer where the length of this WPACKET goes. We use an
+     * offset in case the buffer grows and gets reallocated.
+     */
+    size_t packet_len;
+
+    /* Number of bytes in the packet_len or 0 if we don't write the length */
+    size_t lenbytes;
+
+    /* Number of bytes written to the buf prior to this packet starting */
+    size_t pwritten;
+
+    /* Flags for this sub-packet */
+    unsigned int flags;
+};
+
+typedef struct wpacket_st WPACKET;
+struct wpacket_st {
+    /* The buffer where we store the output data */
+    BUF_MEM *buf;
+
+    /*
+     * Offset into the buffer where we are currently writing. We use an offset
+     * in case the buffer grows and gets reallocated.
+     */
+    size_t curr;
+
+    /* Number of bytes written so far */
+    size_t written;
+
+    /* Maximum number of bytes we will allow to be written to this WPACKET */
+    size_t maxsize;
+
+    /* Our sub-packets (always at least one if not finished) */
+    WPACKET_SUB *subs;
+};
+
+/* Flags */
+
+/* Default */
+#define WPACKET_FLAGS_NONE                      0
+
+/* Error on WPACKET_close() if no data written to the WPACKET */
+#define WPACKET_FLAGS_NON_ZERO_LENGTH           1
+
+/*
+ * Abandon all changes on WPACKET_close() if no data written to the WPACKET,
+ * i.e. this does not write out a zero packet length
+ */
+#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH    2
+
+
+/*
+ * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
+ * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
+ * data is preallocated at the start of the buffer to store the length of the
+ * WPACKET once we know it.
+ */
+int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes);
+
+/*
+ * Same as WPACKET_init_len except there is no preallocation of the WPACKET
+ * length.
+ */
+int WPACKET_init(WPACKET *pkt, BUF_MEM *buf);
+
+/*
+ * Set the flags to be applied to the current sub-packet
+ */
+int WPACKET_set_flags(WPACKET *pkt, unsigned int flags);
+
+/*
+ * Closes the most recent sub-packet. It also writes out the length of the
+ * packet to the required location (normally the start of the WPACKET) if
+ * appropriate. The top level WPACKET should be closed using WPACKET_finish()
+ * instead of this function.
+ */
+int WPACKET_close(WPACKET *pkt);
+
+/*
+ * The same as WPACKET_close() but only for the top most WPACKET. Additionally
+ * frees memory resources for this WPACKET.
+ */
+int WPACKET_finish(WPACKET *pkt);
+
+/*
+ * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
+ * at the start of the sub-packet to store its length once we know it.
+ */
+int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes);
+
+/*
+ * Convenience macros for calling WPACKET_start_sub_packet_len with different
+ * lengths
+ */
+#define WPACKET_start_sub_packet_u8(pkt) \
+    WPACKET_start_sub_packet_len((pkt), 1)
+#define WPACKET_start_sub_packet_u16(pkt) \
+    WPACKET_start_sub_packet_len((pkt), 2)
+#define WPACKET_start_sub_packet_u24(pkt) \
+    WPACKET_start_sub_packet_len((pkt), 3)
+#define WPACKET_start_sub_packet_u32(pkt) \
+    WPACKET_start_sub_packet_len((pkt), 4)
+
+/*
+ * Same as WPACKET_start_sub_packet_len() except no bytes are pre-allocated for
+ * the sub-packet length.
+ */
+int WPACKET_start_sub_packet(WPACKET *pkt);
+
+/*
+ * Allocate bytes in the WPACKET for the output. This reserves the bytes
+ * and counts them as "written", but doesn't actually do the writing. A pointer
+ * to the allocated bytes is stored in |*allocbytes|.
+ */
+int WPACKET_allocate_bytes(WPACKET *pkt, size_t bytes,
+                           unsigned char **allocbytes);
+
+/*
+ * Write the value stored in |val| into the WPACKET. The value will consume
+ * |bytes| amount of storage. An error will occur if |val| cannot be
+ * accommodated in |bytes| storage, e.g. attempting to write the value 256 into
+ * 1 byte will fail.
+ */
+int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes);
+
+/* Set a maximum size that we will not allow the WPACKET to grow beyond */
+int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize);
+
+/* Copy |len| bytes of data from |*src| into the WPACKET. */
+int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len);
+
+/*
+ * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its
+ * length (consuming |lenbytes| of data for the length)
+ */
+int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len,
+                       size_t lenbytes);
+
+/*
+ * Return the total number of bytes written so far to the underlying buffer
+ * including any storage allocated for length bytes
+ */
+int WPACKET_get_total_written(WPACKET *pkt, size_t *written);
+
+/*
+ * Returns the length of the current sub-packet. This excludes any bytes
+ * allocated for the length itself.
+ */
+int WPACKET_get_length(WPACKET *pkt, size_t *len);
+
+/* Release resources in a WPACKET if a failure has occurred. */
+void WPACKET_cleanup(WPACKET *pkt);
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index e94ee83..3749b2c 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2751,6 +2751,8 @@ const SSL3_ENC_METHOD SSLv3_enc_data = {
     0,
     SSL3_HM_HEADER_LENGTH,
     ssl3_set_handshake_header,
+    ssl3_set_handshake_header2,
+    tls_close_construct_packet,
     ssl3_handshake_write
 };
 
@@ -2787,6 +2789,22 @@ int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len)
     return 1;
 }
 
+/*
+ * Temporary name. To be renamed ssl3_set_handshake_header() once all WPACKET
+ * conversion is complete. The old ssl3_set_handshake_heder() can be deleted
+ * at that point.
+ * TODO - RENAME ME
+ */
+int ssl3_set_handshake_header2(SSL *s, WPACKET *pkt, int htype)
+{
+    /* Set the content type and 3 bytes for the message len */
+    if (!WPACKET_put_bytes(pkt, htype, 1)
+            || !WPACKET_start_sub_packet_u24(pkt))
+        return 0;
+
+    return 1;
+}
+
 int ssl3_handshake_write(SSL *s)
 {
     return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
@@ -3553,7 +3571,13 @@ const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p)
     return cp;
 }
 
-int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p)
+/*
+ * Old version of the ssl3_put_cipher_by_char function used by code that has not
+ * yet been converted to WPACKET yet. It will be deleted once WPACKET conversion
+ * is complete.
+ * TODO - DELETE ME
+ */
+int ssl3_put_cipher_by_char_old(const SSL_CIPHER *c, unsigned char *p)
 {
     long l;
 
@@ -3567,6 +3591,20 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p)
     return (2);
 }
 
+int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt, size_t *len)
+{
+    if ((c->id & 0xff000000) != 0x03000000) {
+        *len = 0;
+        return 1;
+    }
+
+    if (!WPACKET_put_bytes(pkt, c->id & 0xffff, 2))
+        return 0;
+
+    *len = 2;
+    return 1;
+}
+
 /*
  * ssl3_choose_cipher - choose a cipher from those offered by the client
  * @s: SSL connection
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 1fddda6..f776f61 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -107,6 +107,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "ssl_check_serverhello_tlsext"},
     {ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG),
      "ssl_check_srvr_ecc_cert_and_alg"},
+    {ERR_FUNC(SSL_F_SSL_CIPHER_LIST_TO_BYTES), "ssl_cipher_list_to_bytes"},
     {ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR),
      "ssl_cipher_process_rulestr"},
     {ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT), "ssl_cipher_strength_sort"},
@@ -567,10 +568,9 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_SSL_SESSION_ID_CONFLICT), "ssl session id conflict"},
     {ERR_REASON(SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG),
      "ssl session id context too long"},
-    {ERR_REASON(SSL_R_SSL_SESSION_ID_TOO_LONG),
-     "ssl session id too long"},
     {ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),
      "ssl session id has bad length"},
+    {ERR_REASON(SSL_R_SSL_SESSION_ID_TOO_LONG), "ssl session id too long"},
     {ERR_REASON(SSL_R_SSL_SESSION_VERSION_MISMATCH),
      "ssl session version mismatch"},
     {ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 4079b31..26485f6 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -457,7 +457,8 @@ struct ssl_method_st {
     long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg);
     long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg);
     const SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr);
-    int (*put_cipher_by_char) (const SSL_CIPHER *cipher, unsigned char *ptr);
+    int (*put_cipher_by_char) (const SSL_CIPHER *cipher, WPACKET *pkt,
+                               size_t *len);
     int (*ssl_pending) (const SSL *s);
     int (*num_ciphers) (void);
     const SSL_CIPHER *(*get_cipher) (unsigned ncipher);
@@ -1584,6 +1585,10 @@ typedef struct ssl3_enc_method {
     unsigned int hhlen;
     /* Set the handshake header */
     int (*set_handshake_header) (SSL *s, int type, unsigned long len);
+    /* Set the handshake header */
+    int (*set_handshake_header2) (SSL *s, WPACKET *pkt, int type);
+    /* Close construction of the handshake message */
+    int (*close_construct_packet) (SSL *s, WPACKET *pkt);
     /* Write out handshake message */
     int (*do_write) (SSL *s);
 } SSL3_ENC_METHOD;
@@ -1593,6 +1598,10 @@ typedef struct ssl3_enc_method {
         (((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen)
 # define ssl_set_handshake_header(s, htype, len) \
         s->method->ssl3_enc->set_handshake_header(s, htype, len)
+# define ssl_set_handshake_header2(s, pkt, htype) \
+        s->method->ssl3_enc->set_handshake_header2((s), (pkt), (htype))
+# define ssl_close_construct_packet(s, pkt) \
+        s->method->ssl3_enc->close_construct_packet((s), (pkt))
 # define ssl_do_write(s)  s->method->ssl3_enc->do_write(s)
 
 /* Values for enc_flags */
@@ -1854,7 +1863,9 @@ __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey);
 __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
 
 __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
-__owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p);
+__owur int ssl3_put_cipher_by_char_old(const SSL_CIPHER *c, unsigned char *p);
+__owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt,
+                                   size_t *len);
 int ssl3_init_finished_mac(SSL *s);
 __owur int ssl3_setup_key_block(SSL *s);
 __owur int ssl3_change_cipher_state(SSL *s, int which);
@@ -1894,6 +1905,10 @@ __owur int ssl3_do_change_cipher_spec(SSL *ssl);
 __owur long ssl3_default_timeout(void);
 
 __owur int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
+__owur int ssl3_set_handshake_header2(SSL *s, WPACKET *pkt, int htype);
+__owur int tls_close_construct_packet(SSL *s, WPACKET *pkt);
+__owur int dtls1_set_handshake_header2(SSL *s, WPACKET *pkt, int htype);
+__owur int dtls1_close_construct_packet(SSL *s, WPACKET *pkt);
 __owur int ssl3_handshake_write(SSL *s);
 
 __owur int ssl_allow_compression(SSL *s);
@@ -2002,8 +2017,7 @@ __owur EVP_PKEY *ssl_generate_pkey_curve(int id);
 __owur int tls1_shared_list(SSL *s,
                             const unsigned char *l1, size_t l1len,
                             const unsigned char *l2, size_t l2len, int nmatch);
-__owur unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
-                                                 unsigned char *limit, int *al);
+__owur int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al);
 __owur unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
                                                  unsigned char *limit, int *al);
 __owur int ssl_parse_clienthello_tlsext(SSL *s, PACKET *pkt);
@@ -2054,12 +2068,12 @@ void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
 __owur int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p,
                                                int *len, int maxlen);
 __owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al);
-__owur int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p,
-                                               int *len, int maxlen);
 __owur int ssl_parse_clienthello_renegotiate_ext(SSL *s, PACKET *pkt, int *al);
 __owur long ssl_get_algorithm2(SSL *s);
-__owur size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
-                                 const unsigned char *psig, size_t psiglen);
+__owur size_t tls12_copy_sigalgs_old(SSL *s, unsigned char *out,
+                                     const unsigned char *psig, size_t psiglen);
+__owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
+                              const unsigned char *psig, size_t psiglen);
 __owur int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize);
 __owur int tls1_process_sigalgs(SSL *s);
 __owur size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs);
@@ -2068,8 +2082,6 @@ __owur int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
 void ssl_set_client_disabled(SSL *s);
 __owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op);
 
-__owur int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
-                                            int maxlen);
 __owur int ssl_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al);
 __owur int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
                                             int maxlen);
@@ -2108,8 +2120,9 @@ __owur int custom_ext_parse(SSL *s, int server,
                             unsigned int ext_type,
                             const unsigned char *ext_data, size_t ext_size,
                             int *al);
-__owur int custom_ext_add(SSL *s, int server, unsigned char **pret,
-                          unsigned char *limit, int *al);
+__owur int custom_ext_add_old(SSL *s, int server, unsigned char **pret,
+                              unsigned char *limit, int *al);
+__owur int custom_ext_add(SSL *s, int server, WPACKET *pkt, int *al);
 
 __owur int custom_exts_copy(custom_ext_methods *dst,
                             const custom_ext_methods *src);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index ff42858..59d21df 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -63,7 +63,7 @@ static ossl_inline int cert_req_allowed(SSL *s);
 static int key_exchange_expected(SSL *s);
 static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
 static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
-                                    unsigned char *p);
+                                    WPACKET *pkt);
 
 /*
  * Is a CertificateRequest message allowed at the moment or not?
@@ -689,19 +689,22 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
 
 int tls_construct_client_hello(SSL *s)
 {
-    unsigned char *buf;
-    unsigned char *p, *d;
+    unsigned char *p;
     int i;
     int protverr;
-    unsigned long l;
-    int al = 0;
+    int al = SSL_AD_HANDSHAKE_FAILURE;
 #ifndef OPENSSL_NO_COMP
-    int j;
     SSL_COMP *comp;
 #endif
     SSL_SESSION *sess = s->session;
+    WPACKET pkt;
 
-    buf = (unsigned char *)s->init_buf->data;
+    if (!WPACKET_init(&pkt, s->init_buf)
+            || !WPACKET_set_max_size(&pkt, SSL3_RT_MAX_PLAIN_LENGTH)) {
+        /* Should not happen */
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
     /* Work out what SSL/TLS/DTLS version to use */
     protverr = ssl_set_client_hello_version(s);
@@ -743,8 +746,11 @@ int tls_construct_client_hello(SSL *s)
     if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)) <= 0)
         goto err;
 
-    /* Do the message type and length last */
-    d = p = ssl_handshake_start(s);
+    if (!ssl_set_handshake_header2(s, &pkt, SSL3_MT_CLIENT_HELLO)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
     /*-
      * version indicates the negotiated version: for example from
@@ -776,90 +782,90 @@ int tls_construct_client_hello(SSL *s)
      * client_version in client hello and not resetting it to
      * the negotiated version.
      */
-    *(p++) = s->client_version >> 8;
-    *(p++) = s->client_version & 0xff;
-
-    /* Random stuff */
-    memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
-    p += SSL3_RANDOM_SIZE;
+    if (!WPACKET_put_bytes(&pkt, s->client_version, 2)
+            || !WPACKET_memcpy(&pkt, s->s3->client_random, SSL3_RANDOM_SIZE)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
     /* Session ID */
     if (s->new_session)
         i = 0;
     else
         i = s->session->session_id_length;
-    *(p++) = i;
-    if (i != 0) {
-        if (i > (int)sizeof(s->session->session_id)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        memcpy(p, s->session->session_id, i);
-        p += i;
+    if (i > (int)sizeof(s->session->session_id)
+            || !WPACKET_start_sub_packet_u8(&pkt)
+            || (i != 0 && !WPACKET_memcpy(&pkt, s->session->session_id, i))
+            || !WPACKET_close(&pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
     }
 
     /* cookie stuff for DTLS */
     if (SSL_IS_DTLS(s)) {
-        if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
+        if (s->d1->cookie_len > sizeof(s->d1->cookie)
+                || !WPACKET_sub_memcpy(&pkt, s->d1->cookie, s->d1->cookie_len,
+                                       1)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-        *(p++) = s->d1->cookie_len;
-        memcpy(p, s->d1->cookie, s->d1->cookie_len);
-        p += s->d1->cookie_len;
     }
 
     /* Ciphers supported */
-    i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]));
-    if (i == 0) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE);
+    if (!WPACKET_start_sub_packet_u16(&pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    /* ssl_cipher_list_to_bytes() raises SSLerr if appropriate */
+    if (!ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &pkt))
+        goto err;
+    if (!WPACKET_close(&pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
         goto err;
     }
-#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
-    /*
-     * Some servers hang if client hello > 256 bytes as hack workaround
-     * chop number of supported ciphers to keep it well below this if we
-     * use TLS v1.2
-     */
-    if (TLS1_get_version(s) >= TLS1_2_VERSION
-        && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
-        i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
-#endif
-    s2n(i, p);
-    p += i;
 
     /* COMPRESSION */
-#ifdef OPENSSL_NO_COMP
-    *(p++) = 1;
-#else
-
-    if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
-        j = 0;
-    else
-        j = sk_SSL_COMP_num(s->ctx->comp_methods);
-    *(p++) = 1 + j;
-    for (i = 0; i < j; i++) {
-        comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
-        *(p++) = comp->id;
+    if (!WPACKET_start_sub_packet_u8(&pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+#ifndef OPENSSL_NO_COMP
+    if (ssl_allow_compression(s) && s->ctx->comp_methods) {
+        int compnum = sk_SSL_COMP_num(s->ctx->comp_methods);
+        for (i = 0; i < compnum; i++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
+            if (!WPACKET_put_bytes(&pkt, comp->id, 1)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
     }
 #endif
-    *(p++) = 0;                 /* Add the NULL method */
+    /* Add the NULL method */
+    if (!WPACKET_put_bytes(&pkt, 0, 1) || !WPACKET_close(&pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
     /* TLS extensions */
     if (ssl_prepare_clienthello_tlsext(s) <= 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
         goto err;
     }
-    if ((p =
-         ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
-                                    &al)) == NULL) {
+    if (!WPACKET_start_sub_packet_u16(&pkt)
+               /*
+                * If extensions are of zero length then we don't even add the
+                * extensions length bytes
+                */
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
+            || !ssl_add_clienthello_tlsext(s, &pkt, &al)
+            || !WPACKET_close(&pkt)) {
         ssl3_send_alert(s, SSL3_AL_FATAL, al);
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
-    l = p - d;
-    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
+    if (!WPACKET_close(&pkt) || !ssl_close_construct_packet(s, &pkt)) {
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
         goto err;
@@ -868,6 +874,7 @@ int tls_construct_client_hello(SSL *s)
     return 1;
  err:
     ossl_statem_set_error(s);
+    WPACKET_cleanup(&pkt);
     return 0;
 }
 
@@ -2909,47 +2916,79 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
     return i;
 }
 
-int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p)
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, WPACKET *pkt)
 {
-    int i, j = 0;
-    const SSL_CIPHER *c;
-    unsigned char *q;
+    int i;
+    size_t totlen = 0, len, maxlen;
     int empty_reneg_info_scsv = !s->renegotiate;
     /* Set disabled masks for this session */
     ssl_set_client_disabled(s);
 
     if (sk == NULL)
         return (0);
-    q = p;
 
-    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+# if OPENSSL_MAX_TLS1_2_CIPHER_LENGTH < 6
+#  error Max cipher length too short
+# endif
+    /*
+     * Some servers hang if client hello > 256 bytes as hack workaround
+     * chop number of supported ciphers to keep it well below this if we
+     * use TLS v1.2
+     */
+    if (TLS1_get_version(s) >= TLS1_2_VERSION)
+        maxlen = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+    else
+#endif
+        /* Maximum length that can be stored in 2 bytes. Length must be even */
+        maxlen = 0xfffe;
+
+    if (empty_reneg_info_scsv)
+        maxlen -= 2;
+    if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV)
+        maxlen -= 2;
+
+    for (i = 0; i < sk_SSL_CIPHER_num(sk) && totlen < maxlen; i++) {
+        const SSL_CIPHER *c;
+
         c = sk_SSL_CIPHER_value(sk, i);
         /* Skip disabled ciphers */
         if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
             continue;
-        j = s->method->put_cipher_by_char(c, p);
-        p += j;
+
+        if (!s->method->put_cipher_by_char(c, pkt, &len)) {
+            SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        totlen += len;
     }
-    /*
-     * If p == q, no ciphers; caller indicates an error. Otherwise, add
-     * applicable SCSVs.
-     */
-    if (p != q) {
+
+    if (totlen == 0) {
+        SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, SSL_R_NO_CIPHERS_AVAILABLE);
+        return 0;
+    }
+
+    if (totlen != 0) {
         if (empty_reneg_info_scsv) {
             static SSL_CIPHER scsv = {
                 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
             };
-            j = s->method->put_cipher_by_char(&scsv, p);
-            p += j;
+            if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) {
+                SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
         }
         if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
             static SSL_CIPHER scsv = {
                 0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
             };
-            j = s->method->put_cipher_by_char(&scsv, p);
-            p += j;
+            if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) {
+                SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
         }
     }
 
-    return (p - q);
+    return 1;
 }
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c
index de2de09..25c4575 100644
--- a/ssl/statem/statem_dtls.c
+++ b/ssl/statem/statem_dtls.c
@@ -1190,3 +1190,46 @@ void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
     n2l3(data, msg_hdr->frag_off);
     n2l3(data, msg_hdr->frag_len);
 }
+
+/*
+ * Temporary name. To be renamed dtls1_set_handshake_header() once all WPACKET
+ * conversion is complete. The old dtls1_set_handshake_heder() can be deleted
+ * at that point.
+ * TODO - RENAME ME
+ */
+int dtls1_set_handshake_header2(SSL *s, WPACKET *pkt, int htype)
+{
+    unsigned char *header;
+
+    dtls1_set_message_header(s, htype, 0, 0, 0);
+
+    /*
+     * We allocate space at the start for the message header. This gets filled
+     * in later
+     */
+    if (!WPACKET_allocate_bytes(pkt, DTLS1_HM_HEADER_LENGTH, &header)
+            || !WPACKET_start_sub_packet(pkt))
+        return 0;
+
+    return 1;
+}
+
+int dtls1_close_construct_packet(SSL *s, WPACKET *pkt)
+{
+    size_t msglen;
+
+    if (!WPACKET_get_length(pkt, &msglen)
+            || msglen > INT_MAX
+            || !WPACKET_finish(pkt))
+        return 0;
+    s->d1->w_msg_hdr.msg_len = msglen - DTLS1_HM_HEADER_LENGTH;
+    s->d1->w_msg_hdr.frag_len = msglen - DTLS1_HM_HEADER_LENGTH;
+    s->init_num = (int)msglen;
+    s->init_off = 0;
+
+    /* Buffer the message to handle re-xmits */
+    if (!dtls1_buffer_message(s, 0))
+        return 0;
+
+    return 1;
+}
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 19b75a7..7ad3899 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -57,6 +57,20 @@ int ssl3_do_write(SSL *s, int type)
     return (0);
 }
 
+int tls_close_construct_packet(SSL *s, WPACKET *pkt)
+{
+    size_t msglen;
+
+    if (!WPACKET_get_length(pkt, &msglen)
+            || msglen > INT_MAX
+            || !WPACKET_finish(pkt))
+        return 0;
+    s->init_num = (int)msglen;
+    s->init_off = 0;
+
+    return 1;
+}
+
 int tls_construct_finished(SSL *s, const char *sender, int slen)
 {
     unsigned char *p;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index a6b8a87..818f48d 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1551,7 +1551,7 @@ int tls_construct_server_hello(SSL *s)
     p += sl;
 
     /* put the cipher */
-    i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p);
+    i = ssl3_put_cipher_by_char_old(s->s3->tmp.new_cipher, p);
     p += i;
 
     /* put the compression method */
@@ -2002,7 +2002,7 @@ int tls_construct_certificate_request(SSL *s)
         nl = tls12_get_psigalgs(s, &psigs);
         /* Skip over length for now */
         p += 2;
-        nl = tls12_copy_sigalgs(s, p, psigs, nl);
+        nl = tls12_copy_sigalgs_old(s, p, psigs, nl);
         /* Now fill in length */
         s2n(nl, etmp);
         p += nl;
diff --git a/ssl/t1_ext.c b/ssl/t1_ext.c
index a8e9f9a..664906c 100644
--- a/ssl/t1_ext.c
+++ b/ssl/t1_ext.c
@@ -72,10 +72,13 @@ int custom_ext_parse(SSL *s, int server,
 
 /*
  * Request custom extension data from the application and add to the return
- * buffer.
+ * buffer. This is the old style function signature prior to WPACKET. This is
+ * here temporarily until the conversion to WPACKET is completed, i.e. it is
+ * used by code that hasn't been converted yet.
+ * TODO - REMOVE THIS FUNCTION
  */
-int custom_ext_add(SSL *s, int server,
-                   unsigned char **pret, unsigned char *limit, int *al)
+int custom_ext_add_old(SSL *s, int server,
+                       unsigned char **pret, unsigned char *limit, int *al)
 {
     custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
     custom_ext_method *meth;
@@ -131,6 +134,66 @@ int custom_ext_add(SSL *s, int server,
     return 1;
 }
 
+
+/*
+ * Request custom extension data from the application and add to the return
+ * buffer.
+ */
+int custom_ext_add(SSL *s, int server, WPACKET *pkt, int *al)
+{
+    custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
+    custom_ext_method *meth;
+    size_t i;
+
+    for (i = 0; i < exts->meths_count; i++) {
+        const unsigned char *out = NULL;
+        size_t outlen = 0;
+
+        meth = exts->meths + i;
+
+        if (server) {
+            /*
+             * For ServerHello only send extensions present in ClientHello.
+             */
+            if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
+                continue;
+            /* If callback absent for server skip it */
+            if (!meth->add_cb)
+                continue;
+        }
+        if (meth->add_cb) {
+            int cb_retval = 0;
+            cb_retval = meth->add_cb(s, meth->ext_type,
+                                     &out, &outlen, al, meth->add_arg);
+            if (cb_retval < 0)
+                return 0;       /* error */
+            if (cb_retval == 0)
+                continue;       /* skip this extension */
+        }
+
+        if (!WPACKET_put_bytes(pkt, meth->ext_type, 2)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || (outlen > 0 && !WPACKET_memcpy(pkt, out, outlen))
+                || !WPACKET_close(pkt)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+        /*
+         * We can't send duplicates: code logic should prevent this.
+         */
+        OPENSSL_assert(!(meth->ext_flags & SSL_EXT_FLAG_SENT));
+        /*
+         * Indicate extension has been sent: this is both a sanity check to
+         * ensure we don't send duplicate extensions and indicates that it is
+         * not an error if the extension is present in ServerHello.
+         */
+        meth->ext_flags |= SSL_EXT_FLAG_SENT;
+        if (meth->free_cb)
+            meth->free_cb(s, meth->ext_type, out, meth->add_arg);
+    }
+    return 1;
+}
+
 /* Copy table of custom extensions */
 int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
 {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b8f8fd2..50083a9 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -41,6 +41,8 @@ SSL3_ENC_METHOD const TLSv1_enc_data = {
     0,
     SSL3_HM_HEADER_LENGTH,
     ssl3_set_handshake_header,
+    ssl3_set_handshake_header2,
+    tls_close_construct_packet,
     ssl3_handshake_write
 };
 
@@ -59,6 +61,8 @@ SSL3_ENC_METHOD const TLSv1_1_enc_data = {
     SSL_ENC_FLAG_EXPLICIT_IV,
     SSL3_HM_HEADER_LENGTH,
     ssl3_set_handshake_header,
+    ssl3_set_handshake_header2,
+    tls_close_construct_packet,
     ssl3_handshake_write
 };
 
@@ -78,6 +82,8 @@ SSL3_ENC_METHOD const TLSv1_2_enc_data = {
         | SSL_ENC_FLAG_TLS1_2_CIPHERS,
     SSL3_HM_HEADER_LENGTH,
     ssl3_set_handshake_header,
+    ssl3_set_handshake_header2,
+    tls_close_construct_packet,
     ssl3_handshake_write
 };
 
@@ -1007,12 +1013,8 @@ static int tls1_check_duplicate_extensions(const PACKET *packet)
     return ret;
 }
 
-unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
-                                          unsigned char *limit, int *al)
+int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
 {
-    int extdatalen = 0;
-    unsigned char *orig = buf;
-    unsigned char *ret = buf;
 #ifndef OPENSSL_NO_EC
     /* See if we support any ECC ciphersuites */
     int using_ecc = 0;
@@ -1035,32 +1037,14 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
     }
 #endif
 
-    ret += 2;
-
-    if (ret >= limit)
-        return NULL;            /* this really never occurs, but ... */
-
     /* Add RI if renegotiating */
     if (s->renegotiate) {
-        int el;
-
-        if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
-        }
-
-        if ((limit - ret - 4 - el) < 0)
-            return NULL;
-
-        s2n(TLSEXT_TYPE_renegotiate, ret);
-        s2n(el, ret);
-
-        if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) {
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_renegotiate, 2)
+                || !WPACKET_sub_memcpy(pkt, s->s3->previous_client_finished,
+                                   s->s3->previous_client_finished_len, 2)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
-
-        ret += el;
     }
     /* Only add RI for SSLv3 */
     if (s->client_version == SSL3_VERSION)
@@ -1068,61 +1052,36 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
 
     if (s->tlsext_hostname != NULL) {
         /* Add TLS extension servername to the Client Hello message */
-        unsigned long size_str;
-        long lenmax;
-
-        /*-
-         * check for enough space.
-         * 4 for the servername type and extension length
-         * 2 for servernamelist length
-         * 1 for the hostname type
-         * 2 for hostname length
-         * + hostname length
-         */
-
-        if ((lenmax = limit - ret - 9) < 0
-            || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax)
-            return NULL;
-
-        /* extension type and length */
-        s2n(TLSEXT_TYPE_server_name, ret);
-        s2n(size_str + 5, ret);
-
-        /* length of servername list */
-        s2n(size_str + 3, ret);
-
-        /* hostname type, length and hostname */
-        *(ret++) = (unsigned char)TLSEXT_NAMETYPE_host_name;
-        s2n(size_str, ret);
-        memcpy(ret, s->tlsext_hostname, size_str);
-        ret += size_str;
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_server_name, 2)
+                   /* Sub-packet for server_name extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                   /* Sub-packet for servername list (always 1 hostname)*/
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes(pkt, TLSEXT_NAMETYPE_host_name, 1)
+                || !WPACKET_sub_memcpy(pkt, s->tlsext_hostname,
+                                       strlen(s->tlsext_hostname), 2)
+                || !WPACKET_close(pkt)
+                || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #ifndef OPENSSL_NO_SRP
     /* Add SRP username if there is one */
-    if (s->srp_ctx.login != NULL) { /* Add TLS extension SRP username to the
-                                     * Client Hello message */
-
-        int login_len = strlen(s->srp_ctx.login);
-        if (login_len > 255 || login_len == 0) {
+    if (s->srp_ctx.login != NULL) {
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_srp, 2)
+                   /* Sub-packet for SRP extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_start_sub_packet_u8(pkt)
+                   /* login must not be zero...internal error if so */
+                || !WPACKET_set_flags(pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)
+                || !WPACKET_memcpy(pkt, s->srp_ctx.login,
+                                   strlen(s->srp_ctx.login))
+                || !WPACKET_close(pkt)
+                || !WPACKET_close(pkt)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
-
-        /*-
-         * check for enough space.
-         * 4 for the srp type type and extension length
-         * 1 for the srp user identity
-         * + srp user identity length
-         */
-        if ((limit - ret - 5 - login_len) < 0)
-            return NULL;
-
-        /* fill in the extension */
-        s2n(TLSEXT_TYPE_srp, ret);
-        s2n(login_len + 1, ret);
-        (*ret++) = (unsigned char)login_len;
-        memcpy(ret, s->srp_ctx.login, login_len);
-        ret += login_len;
     }
 #endif
 
@@ -1131,61 +1090,52 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
         /*
          * Add TLS extension ECPointFormats to the ClientHello message
          */
-        long lenmax;
         const unsigned char *pcurves, *pformats;
-        size_t num_curves, num_formats, curves_list_len;
+        size_t num_curves, num_formats;
         size_t i;
-        unsigned char *etmp;
 
         tls1_get_formatlist(s, &pformats, &num_formats);
 
-        if ((lenmax = limit - ret - 5) < 0)
-            return NULL;
-        if (num_formats > (size_t)lenmax)
-            return NULL;
-        if (num_formats > 255) {
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_ec_point_formats, 2)
+                   /* Sub-packet for formats extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_sub_memcpy(pkt, pformats, num_formats, 1)
+                || !WPACKET_close(pkt)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
 
-        s2n(TLSEXT_TYPE_ec_point_formats, ret);
-        /* The point format list has 1-byte length. */
-        s2n(num_formats + 1, ret);
-        *(ret++) = (unsigned char)num_formats;
-        memcpy(ret, pformats, num_formats);
-        ret += num_formats;
-
         /*
          * Add TLS extension EllipticCurves to the ClientHello message
          */
         pcurves = s->tlsext_ellipticcurvelist;
-        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves))
-            return NULL;
-
-        if ((lenmax = limit - ret - 6) < 0)
-            return NULL;
-        if (num_curves > (size_t)lenmax / 2)
-            return NULL;
-        if (num_curves > 65532 / 2) {
+        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
 
-        s2n(TLSEXT_TYPE_elliptic_curves, ret);
-        etmp = ret + 4;
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_elliptic_curves, 2)
+                   /* Sub-packet for curves extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_start_sub_packet_u16(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
         /* Copy curve ID if supported */
         for (i = 0; i < num_curves; i++, pcurves += 2) {
             if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
-                *etmp++ = pcurves[0];
-                *etmp++ = pcurves[1];
+                if (!WPACKET_put_bytes(pkt, pcurves[0], 1)
+                    || !WPACKET_put_bytes(pkt, pcurves[1], 1)) {
+                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
+                               ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
             }
         }
-
-        curves_list_len = etmp - ret - 4;
-
-        s2n(curves_list_len + 2, ret);
-        s2n(curves_list_len, ret);
-        ret += curves_list_len;
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #endif                          /* OPENSSL_NO_EC */
 
@@ -1197,8 +1147,10 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
                  s->tlsext_session_ticket->data) {
             ticklen = s->tlsext_session_ticket->length;
             s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-            if (s->session->tlsext_tick == NULL)
-                return NULL;
+            if (s->session->tlsext_tick == NULL) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
             memcpy(s->session->tlsext_tick,
                    s->tlsext_session_ticket->data, ticklen);
             s->session->tlsext_ticklen = ticklen;
@@ -1207,17 +1159,12 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
         if (ticklen == 0 && s->tlsext_session_ticket &&
             s->tlsext_session_ticket->data == NULL)
             goto skip_ext;
-        /*
-         * Check for enough room 2 for extension type, 2 for len rest for
-         * ticket
-         */
-        if ((long)(limit - ret - 4 - ticklen) < 0)
-            return NULL;
-        s2n(TLSEXT_TYPE_session_ticket, ret);
-        s2n(ticklen, ret);
-        if (ticklen) {
-            memcpy(ret, s->session->tlsext_tick, ticklen);
-            ret += ticklen;
+
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_session_ticket, 2)
+                || !WPACKET_sub_memcpy(pkt, s->session->tlsext_tick, ticklen,
+                                       2)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
         }
     }
  skip_ext:
@@ -1225,81 +1172,99 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
     if (SSL_CLIENT_USE_SIGALGS(s)) {
         size_t salglen;
         const unsigned char *salg;
-        unsigned char *etmp;
+
         salglen = tls12_get_psigalgs(s, &salg);
-        if ((size_t)(limit - ret) < salglen + 6)
-            return NULL;
-        s2n(TLSEXT_TYPE_signature_algorithms, ret);
-        etmp = ret;
-        /* Skip over lengths for now */
-        ret += 4;
-        salglen = tls12_copy_sigalgs(s, ret, salg, salglen);
-        /* Fill in lengths */
-        s2n(salglen + 2, etmp);
-        s2n(salglen, etmp);
-        ret += salglen;
+
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_signature_algorithms, 2)
+                   /* Sub-packet for sig-algs extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                   /* Sub-packet for the actual list */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !tls12_copy_sigalgs(s, pkt, salg, salglen)
+                || !WPACKET_close(pkt)
+                || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #ifndef OPENSSL_NO_OCSP
     if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
         int i;
-        long extlen, idlen, itmp;
-        OCSP_RESPID *id;
 
-        idlen = 0;
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_status_request, 2)
+                   /* Sub-packet for status request extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes(pkt, TLSEXT_STATUSTYPE_ocsp, 1)
+                   /* Sub-packet for the ids */
+                || !WPACKET_start_sub_packet_u16(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
         for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
+            unsigned char *idbytes;
+            int idlen;
+            OCSP_RESPID *id;
+
             id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
-            itmp = i2d_OCSP_RESPID(id, NULL);
-            if (itmp <= 0)
-                return NULL;
-            idlen += itmp + 2;
+            idlen = i2d_OCSP_RESPID(id, NULL);
+            if (idlen <= 0
+                       /* Sub-packet for an individual id */
+                    || !WPACKET_start_sub_packet_u8(pkt)
+                    || !WPACKET_allocate_bytes(pkt, idlen, &idbytes)
+                    || i2d_OCSP_RESPID(id, &idbytes) != idlen
+                    || !WPACKET_close(pkt)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+        if (!WPACKET_close(pkt)
+                || !WPACKET_start_sub_packet_u16(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
         }
-
         if (s->tlsext_ocsp_exts) {
-            extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
-            if (extlen < 0)
-                return NULL;
-        } else
-            extlen = 0;
+            unsigned char *extbytes;
+            int extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
 
-        if ((long)(limit - ret - 7 - extlen - idlen) < 0)
-            return NULL;
-        s2n(TLSEXT_TYPE_status_request, ret);
-        if (extlen + idlen > 0xFFF0)
-            return NULL;
-        s2n(extlen + idlen + 5, ret);
-        *(ret++) = TLSEXT_STATUSTYPE_ocsp;
-        s2n(idlen, ret);
-        for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
-            /* save position of id len */
-            unsigned char *q = ret;
-            id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
-            /* skip over id len */
-            ret += 2;
-            itmp = i2d_OCSP_RESPID(id, &ret);
-            /* write id len */
-            s2n(itmp, q);
+            if (extlen < 0) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            if (!WPACKET_allocate_bytes(pkt, extlen, &extbytes)
+                    || i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &extbytes)
+                       != extlen) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+           }
+        }
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
         }
-        s2n(extlen, ret);
-        if (extlen > 0)
-            i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
     }
 #endif
 #ifndef OPENSSL_NO_HEARTBEATS
     if (SSL_IS_DTLS(s)) {
-        /* Add Heartbeat extension */
-        if ((limit - ret - 4 - 1) < 0)
-            return NULL;
-        s2n(TLSEXT_TYPE_heartbeat, ret);
-        s2n(1, ret);
+        unsigned int mode;
+
         /*-
          * Set mode:
          * 1: peer may send requests
          * 2: peer not allowed to send requests
          */
         if (s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_RECV_REQUESTS)
-            *(ret++) = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
+            mode = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS;
         else
-            *(ret++) = SSL_DTLSEXT_HB_ENABLED;
+            mode = SSL_DTLSEXT_HB_ENABLED;
+
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_heartbeat, 2)
+                   /* Sub-packet for Hearbeat extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes(pkt, mode, 1)
+                || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #endif
 
@@ -1309,10 +1274,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
          * The client advertises an empty extension to indicate its support
          * for Next Protocol Negotiation
          */
-        if (limit - ret - 4 < 0)
-            return NULL;
-        s2n(TLSEXT_TYPE_next_proto_neg, ret);
-        s2n(0, ret);
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_next_proto_neg, 2)
+                || !WPACKET_put_bytes(pkt, 0, 2)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #endif
 
@@ -1322,52 +1288,74 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
      * (see longer comment below)
      */
     if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) {
-        if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
-            return NULL;
-        s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
-        s2n(2 + s->alpn_client_proto_list_len, ret);
-        s2n(s->alpn_client_proto_list_len, ret);
-        memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len);
-        ret += s->alpn_client_proto_list_len;
+        if (!WPACKET_put_bytes(pkt,
+                    TLSEXT_TYPE_application_layer_protocol_negotiation, 2)
+                   /* Sub-packet ALPN extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_sub_memcpy(pkt, s->alpn_client_proto_list,
+                                       s->alpn_client_proto_list_len, 2)
+                || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
         s->s3->alpn_sent = 1;
     }
 #ifndef OPENSSL_NO_SRTP
     if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) {
-        int el;
-
-        /* Returns 0 on success!! */
-        if (ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0)) {
+        STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0;
+        SRTP_PROTECTION_PROFILE *prof;
+        int i, ct;
+
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_use_srtp, 2)
+                   /* Sub-packet for SRTP extension */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                   /* Sub-packet for the protection profile list */
+                || !WPACKET_start_sub_packet_u16(pkt)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
-
-        if ((limit - ret - 4 - el) < 0)
-            return NULL;
-
-        s2n(TLSEXT_TYPE_use_srtp, ret);
-        s2n(el, ret);
-
-        if (ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) {
+        ct = sk_SRTP_PROTECTION_PROFILE_num(clnt);
+        for (i = 0; i < ct; i++) {
+            prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
+            if (prof == NULL || !WPACKET_put_bytes(pkt, prof->id, 2)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            return 0;
         }
-        ret += el;
     }
 #endif
     custom_ext_init(&s->cert->cli_ext);
     /* Add custom TLS Extensions to ClientHello */
-    if (!custom_ext_add(s, 0, &ret, limit, al))
-        return NULL;
-    s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
-    s2n(0, ret);
+    if (!custom_ext_add(s, 0, pkt, al)) {
+        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_encrypt_then_mac, 2)
+            || !WPACKET_put_bytes(pkt, 0, 2)) {
+        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
 #ifndef OPENSSL_NO_CT
     if (s->ct_validation_callback != NULL) {
-        s2n(TLSEXT_TYPE_signed_certificate_timestamp, ret);
-        s2n(0, ret);
+        if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_signed_certificate_timestamp, 2)
+                || !WPACKET_put_bytes(pkt, 0, 2)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 #endif
-    s2n(TLSEXT_TYPE_extended_master_secret, ret);
-    s2n(0, ret);
+
+    if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_extended_master_secret, 2)
+            || !WPACKET_put_bytes(pkt, 0, 2)) {
+        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
 
     /*
      * Add padding to workaround bugs in F5 terminators. See
@@ -1376,7 +1364,13 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
      * appear last.
      */
     if (s->options & SSL_OP_TLSEXT_PADDING) {
-        int hlen = ret - (unsigned char *)s->init_buf->data;
+        unsigned char *padbytes;
+        size_t hlen;
+
+        if (!WPACKET_get_total_written(pkt, &hlen)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
 
         if (hlen > 0xff && hlen < 0x200) {
             hlen = 0x200 - hlen;
@@ -1385,20 +1379,22 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
             else
                 hlen = 0;
 
-            s2n(TLSEXT_TYPE_padding, ret);
-            s2n(hlen, ret);
-            memset(ret, 0, hlen);
-            ret += hlen;
+            if (!WPACKET_put_bytes(pkt, TLSEXT_TYPE_padding, 2)
+                    || !WPACKET_start_sub_packet_u16(pkt)
+                    || !WPACKET_allocate_bytes(pkt, hlen, &padbytes)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            memset(padbytes, 0, hlen);
+            if (!WPACKET_close(pkt)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
         }
     }
 
  done:
-
-    if ((extdatalen = ret - orig - 2) == 0)
-        return orig;
-
-    s2n(extdatalen, orig);
-    return ret;
+    return 1;
 }
 
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
@@ -1589,7 +1585,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
         }
     }
 #endif
-    if (!custom_ext_add(s, 1, &ret, limit, al))
+    if (!custom_ext_add_old(s, 1, &ret, limit, al))
         return NULL;
     if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
         /*
@@ -3311,7 +3307,13 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
         *pmask_a |= SSL_aECDSA;
 }
 
-size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
+/*
+ * Old version of the tls12_copy_sigalgs function used by code that has not
+ * yet been converted to WPACKET yet. It will be deleted once WPACKET conversion
+ * is complete.
+ * TODO - DELETE ME
+ */
+size_t tls12_copy_sigalgs_old(SSL *s, unsigned char *out,
                           const unsigned char *psig, size_t psiglen)
 {
     unsigned char *tmpout = out;
@@ -3325,6 +3327,21 @@ size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
     return tmpout - out;
 }
 
+int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
+                       const unsigned char *psig, size_t psiglen)
+{
+    size_t i;
+
+    for (i = 0; i < psiglen; i += 2, psig += 2) {
+        if (tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, psig)) {
+            if (!WPACKET_put_bytes(pkt, psig[0], 1)
+                    || !WPACKET_put_bytes(pkt, psig[1], 1))
+                return 0;
+        }
+    }
+    return 1;
+}
+
 /* Given preference and allowed sigalgs set shared sigalgs */
 static int tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
                                 const unsigned char *pref, size_t preflen,
diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c
index 01dc403..f5136e2 100644
--- a/ssl/t1_reneg.c
+++ b/ssl/t1_reneg.c
@@ -11,30 +11,6 @@
 #include <openssl/objects.h>
 #include "ssl_locl.h"
 
-/* Add the client's renegotiation binding */
-int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
-                                        int maxlen)
-{
-    if (p) {
-        if ((s->s3->previous_client_finished_len + 1) > maxlen) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,
-                   SSL_R_RENEGOTIATE_EXT_TOO_LONG);
-            return 0;
-        }
-
-        /* Length byte */
-        *p = s->s3->previous_client_finished_len;
-        p++;
-
-        memcpy(p, s->s3->previous_client_finished,
-               s->s3->previous_client_finished_len);
-    }
-
-    *len = s->s3->previous_client_finished_len + 1;
-
-    return 1;
-}
-
 /*
  * Parse the client's renegotiation binding and abort if it's not right
  */
diff --git a/test/build.info b/test/build.info
index b8fc431..013a0c6 100644
--- a/test/build.info
+++ b/test/build.info
@@ -274,6 +274,13 @@ IF[{- !$disabled{tests} -}]
   SOURCE[bio_enc_test]=bio_enc_test.c
   INCLUDE[bio_enc_test]=../include
   DEPEND[bio_enc_test]=../libcrypto
+
+  IF[{- $disabled{shared} -}]
+    PROGRAMS_NO_INST=wpackettest
+    SOURCE[wpackettest]=wpackettest.c testutil.c
+    INCLUDE[wpackettest]=../include
+    DEPEND[wpackettest]=../libcrypto ../libssl
+  ENDIF
 ENDIF
 
 {-
diff --git a/test/recipes/70-test_bad_dtls.t b/test/recipes/70-test_wpacket.t
similarity index 69%
copy from test/recipes/70-test_bad_dtls.t
copy to test/recipes/70-test_wpacket.t
index a20db77..9170122 100644
--- a/test/recipes/70-test_bad_dtls.t
+++ b/test/recipes/70-test_wpacket.t
@@ -10,11 +10,11 @@
 use OpenSSL::Test;
 use OpenSSL::Test::Utils;
 
-setup("test_bad_dtls");
+setup("test_wpacket");
 
-plan skip_all => "DTLSv1 is not supported by this OpenSSL build"
-    if disabled("dtls1");
+plan skip_all => "Only supported in no-shared builds"
+    if !disabled("shared");
 
 plan tests => 1;
 
-ok(run(test(["bad_dtls_test"])), "running bad_dtls_test");
+ok(run(test(["wpackettest"])));
diff --git a/test/wpackettest.c b/test/wpackettest.c
new file mode 100644
index 0000000..ca2a1a7
--- /dev/null
+++ b/test/wpackettest.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/buffer.h>
+#include "../ssl/packet_locl.h"
+#include "testutil.h"
+
+const static unsigned char simple1 = 0xff;
+const static unsigned char simple2[] = { 0x01, 0xff };
+const static unsigned char simple3[] = { 0x00, 0x00, 0x00, 0x01, 0xff };
+const static unsigned char nestedsub[] = { 0x03, 0xff, 0x01, 0xff };
+const static unsigned char seqsub[] = { 0x01, 0xff, 0x01, 0xff };
+const static unsigned char empty = 0x00;
+const static unsigned char alloc[] = { 0x02, 0xfe, 0xff };
+const static unsigned char submem[] = { 0x03, 0x02, 0xfe, 0xff };
+
+static BUF_MEM *buf;
+
+static void testfail(const char *msg, WPACKET *pkt)
+{
+    fprintf(stderr, "%s", msg);
+    WPACKET_cleanup(pkt);
+}
+
+static int test_WPACKET_init(void)
+{
+    WPACKET pkt;
+    int i;
+    size_t written;
+
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+                /* Closing a top level WPACKET should fail */
+            ||  WPACKET_close(&pkt)
+                /* Finishing a top level WPACKET should succeed */
+            || !WPACKET_finish(&pkt)
+                /*
+                 * Can't call close or finish on a WPACKET that's already
+                 * finished.
+                 */
+            ||  WPACKET_close(&pkt)
+            ||  WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple1)
+            ||  memcmp(buf->data, &simple1, written) != 0) {
+        testfail("test_WPACKET_init():1 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Now try with a one byte length prefix */
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple2)
+            ||  memcmp(buf->data, &simple2, written) != 0) {
+        testfail("test_WPACKET_init():2 failed\n", &pkt);
+        return 0;
+    }
+
+    /* And a longer length prefix */
+    if (       !WPACKET_init_len(&pkt, buf, 4)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple3)
+            ||  memcmp(buf->data, &simple3, written) != 0) {
+        testfail("test_WPACKET_init():3 failed\n", &pkt);
+        return 0;
+    }
+
+    if (!WPACKET_init_len(&pkt, buf, 1)) {
+        testfail("test_WPACKET_init():4 failed\n", &pkt);
+        return 0;
+    }
+    for (i = 1; i < 257; i++) {
+        /*
+         * Putting more bytes in than fit for the size of the length prefix
+         * should fail
+         */
+        if ((!WPACKET_put_bytes(&pkt, 0xff, 1)) == (i != 256)) {
+            testfail("test_WPACKET_init():4 failed\n", &pkt);
+            return 0;
+        }
+    }
+    if (!WPACKET_finish(&pkt)) {
+        testfail("test_WPACKET_init():4 failed\n", &pkt);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int test_WPACKET_set_max_size(void)
+{
+    WPACKET pkt;
+    size_t written;
+
+    if (       !WPACKET_init(&pkt, buf)
+                /*
+                 * No previous lenbytes set so we should be ok to set the max
+                 * possible max size
+                 */
+            || !WPACKET_set_max_size(&pkt, SIZE_MAX)
+                /* We should be able to set it smaller too */
+            || !WPACKET_set_max_size(&pkt, SIZE_MAX -1)
+                /* And setting it bigger again should be ok */
+            || !WPACKET_set_max_size(&pkt, SIZE_MAX)
+            || !WPACKET_finish(&pkt)) {
+        testfail("test_WPACKET_set_max_size():1 failed\n", &pkt);
+        return 0; 
+    }
+
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+                /*
+                 * Should fail because we already consumed 1 byte with the
+                 * length
+                 */
+            ||  WPACKET_set_max_size(&pkt, 0)
+                /*
+                 * Max size can't be bigger than biggest that will fit in
+                 * lenbytes
+                 */
+            ||  WPACKET_set_max_size(&pkt, 0x0101)
+                /* It can be the same as the maximum possible size */
+            || !WPACKET_set_max_size(&pkt, 0x0100)
+                /* Or it can be less */
+            || !WPACKET_set_max_size(&pkt, 0x01)
+                /*
+                 * Should fail because packet is already filled
+                 */
+            ||  WPACKET_put_bytes(&pkt, 0xff, 1)
+                /*
+                 * You can't put in more bytes than max size
+                 */
+            || !WPACKET_set_max_size(&pkt, 0x02)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            ||  WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple2)
+            ||  memcmp(buf->data, &simple2, written) != 0) {
+        testfail("test_WPACKET_set_max_size():2 failed\n", &pkt);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int test_WPACKET_start_sub_packet(void)
+{
+    WPACKET pkt;
+    size_t written;
+    size_t len;
+
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet(&pkt)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+                /* Can't finish because we have a sub packet */
+            ||  WPACKET_finish(&pkt)
+            || !WPACKET_close(&pkt)
+                /* Sub packet is closed so can't close again */
+            ||  WPACKET_close(&pkt)
+                /* Now a top level so finish should succeed */
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple1)
+            ||  memcmp(buf->data, &simple1, written) != 0) {
+        testfail("test_WPACKET_start_sub_packet():1 failed\n", &pkt);
+        return 0;
+    }
+
+   /* Single sub-packet with length prefix */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple2)
+            ||  memcmp(buf->data, &simple2, written) != 0) {
+        testfail("test_WPACKET_start_sub_packet():2 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Nested sub-packets with length prefixes */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_get_length(&pkt, &len)
+            || len != 1
+            || !WPACKET_close(&pkt)
+            || !WPACKET_get_length(&pkt, &len)
+            || len != 3
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(nestedsub)
+            ||  memcmp(buf->data, &nestedsub, written) != 0) {
+        testfail("test_WPACKET_start_sub_packet():3 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Sequential sub-packets with length prefixes */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(seqsub)
+            ||  memcmp(buf->data, &seqsub, written) != 0) {
+        testfail("test_WPACKET_start_sub_packet():4 failed\n", &pkt);
+        return 0;
+    }
+
+    return 1;
+}
+
+
+static int test_WPACKET_set_flags(void)
+{
+    WPACKET pkt;
+    size_t written;
+
+    /* Set packet to be non-zero length */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)
+                /* Should fail because of zero length */
+            ||  WPACKET_finish(&pkt)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple1)
+            ||  memcmp(buf->data, &simple1, written) != 0) {
+        testfail("test_WPACKET_set_flags():1 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Repeat above test in a sub-packet */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet(&pkt)
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)
+                /* Should fail because of zero length */
+            ||  WPACKET_close(&pkt)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple1)
+            ||  memcmp(buf->data, &simple1, written) != 0) {
+        testfail("test_WPACKET_set_flags():2 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Set packet to abandon non-zero length */
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != 0) {
+        testfail("test_WPACKET_set_flags():3 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Repeat above test but only abandon a sub-packet */
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(empty)
+            ||  memcmp(buf->data, &empty, written) != 0) {
+        testfail("test_WPACKET_set_flags():4 failed\n", &pkt);
+        return 0;
+    }
+
+    /* And repeat with a non empty sub-packet */
+    if (       !WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet_len(&pkt, 1)
+            || !WPACKET_set_flags(&pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
+            || !WPACKET_put_bytes(&pkt, 0xff, 1)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(simple2)
+            ||  memcmp(buf->data, &simple2, written) != 0) {
+        testfail("test_WPACKET_set_flags():5 failed\n", &pkt);
+        return 0;
+    }
+    return 1;
+}
+
+static int test_WPACKET_allocate_bytes(void)
+{
+    WPACKET pkt;
+    size_t written;
+    unsigned char *bytes;
+
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_allocate_bytes(&pkt, 2, &bytes)) {
+        testfail("test_WPACKET_allocate_bytes():1 failed\n", &pkt);
+        return 0;
+    }
+    bytes[0] = 0xfe;
+    bytes[1] = 0xff;
+    if (       !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(alloc)
+            ||  memcmp(buf->data, &alloc, written) != 0) {
+        testfail("test_WPACKET_allocate_bytes():2 failed\n", &pkt);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int test_WPACKET_memcpy(void)
+{
+    WPACKET pkt;
+    size_t written;
+    const unsigned char bytes[] = { 0xfe, 0xff };
+
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_memcpy(&pkt, bytes, sizeof(bytes))
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(alloc)
+            ||  memcmp(buf->data, &alloc, written) != 0) {
+        testfail("test_WPACKET_memcpy():1 failed\n", &pkt);
+        return 0;
+    }
+
+    /* Repeat with WPACKET_sub_memcpy() */
+    if (       !WPACKET_init_len(&pkt, buf, 1)
+            || !WPACKET_sub_memcpy(&pkt, bytes, sizeof(bytes), 1)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(submem)
+            ||  memcmp(buf->data, &submem, written) != 0) {
+        testfail("test_WPACKET_memcpy():2 failed\n", &pkt);
+        return 0;
+    }
+
+    return 1;
+}
+
+int main(int argc, char *argv[])
+{
+    BIO *err = NULL;
+    int testresult = 0;
+
+    err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+
+    CRYPTO_set_mem_debug(1);
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+    buf = BUF_MEM_new();
+    if (buf != NULL) {
+        ADD_TEST(test_WPACKET_init);
+        ADD_TEST(test_WPACKET_set_max_size);
+        ADD_TEST(test_WPACKET_start_sub_packet);
+        ADD_TEST(test_WPACKET_set_flags);
+        ADD_TEST(test_WPACKET_allocate_bytes);
+        ADD_TEST(test_WPACKET_memcpy);
+
+        testresult = run_tests(argv[0]);
+
+        BUF_MEM_free(buf);
+    }
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (CRYPTO_mem_leaks(err) <= 0)
+        testresult = 1;
+#endif
+    BIO_free(err);
+
+    if (!testresult)
+        printf("PASS\n");
+
+    return testresult;
+}
+


More information about the openssl-commits mailing list