[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Thu Dec 8 17:26:02 UTC 2016


The branch master has been updated
       via  7d152a3c4f58bc2c4e94946e2a8dbf1a855a52f2 (commit)
       via  625b0d514e4f917c1eeaac621e66c6cba29aeae8 (commit)
       via  9615387408f355dc0620c1ab797a16ae7e72d722 (commit)
       via  1e566129ad8f7c7901b7beccd6128d37e063d2c7 (commit)
       via  7fe97c077b4571a71be3f6cb963c414216371a7c (commit)
       via  ecc2f938cf1cf7425be37156ecb216cdc6db257f (commit)
       via  cbb0954471b16a40e67639522b30009393983285 (commit)
       via  d270de322c7bfb9c1e7509fbc24e3bf6fde713e6 (commit)
       via  1266eefdb66db6c01e859ae672ccc19261e75bbf (commit)
       via  89247375efcf0869449a711fd248f160627de2a2 (commit)
       via  14d21b690a73e1598a97afa5ad9f642d53f63db7 (commit)
       via  22ab4b7dd34d01e23bc25e729541fefaa0f47502 (commit)
       via  1b0286a385aae88068af796d6d0f4fe907fe66eb (commit)
       via  7caf619f1a7c7901a63b8257ac7133dd1c584243 (commit)
       via  a1448c26d2bbec390db4c00bf3867c4369af7d15 (commit)
       via  bc349281880c3f1da784cbc76b28f34d8ab10601 (commit)
       via  60ea0034b8c5cb8b915ea025eb78970a1cb08f99 (commit)
       via  f50306c298390c701046126bd1f48f6fef3ec3ca (commit)
       via  6ca94f105814d284ff1eba7972197d24937aa419 (commit)
       via  2de94a3601863a74a52a07fa5743b0f85984e755 (commit)
       via  d70bde8805800473da0f25671902f1b4b07eecca (commit)
       via  0bfe166b8ffa1f0efe986e4d731e289c48437895 (commit)
       via  efab1586e041f4d4dde86cd786630e0d6af285a2 (commit)
       via  9ce3ed2a586032690bef6a1c4e58df8d1c18f344 (commit)
       via  3434f40b6f0b4eb782931d8f1fe2893c58c1a692 (commit)
       via  332eb3908883fcaac8483dcc895571b0a3c2813a (commit)
       via  70af3d8ed7e2497e8d0f34eb43a4404c493ba1cd (commit)
       via  24b8e4b2c835d6bf52c2768d4d4a78ed7d7e85bb (commit)
       via  02f0274e8c0596dcf7e2d104250232a42c650b96 (commit)
       via  805a2e9e1388f21bd381a8c55e66bae2e6325667 (commit)
       via  68db4ddab7d35f5a3df1beee9a95fe093682340b (commit)
       via  ab83e31414286ccdc35fbacf976f64a910a6c718 (commit)
       via  6dd083fd6804a3ee6ac3adc019f81910f1c63f21 (commit)
       via  e56c33b98bd8d72307da7911de27b5d38191d239 (commit)
       via  7da160b0f46d832dbf285cb0b48ae56d4a8b884d (commit)
       via  25670f3e87d3a9e7ea8ffb2b717a288e2b3024f5 (commit)
       via  4b299b8e174cd58f762f0f184ceac7955e4227c4 (commit)
       via  224135e96a16deaf9de787398d91c1b8212ab8ed (commit)
       via  6b473acabdfc72c99677a15f03295c12e4ff32fb (commit)
       via  fadd9a1e2d2ab1d63bd05c30a0d845e837deb9be (commit)
       via  91b60e2ab4e0ebeaf7690a2a329e88658a6ad30b (commit)
       via  ede6f762030467e492fabd49ad4c3fd20deb71d4 (commit)
       via  e46f23344462c33b9a9c25d5cfe09be7d1f039e3 (commit)
       via  71728dd8aa3acc0bc9d621f8c4a4032aa3325fe4 (commit)
      from  c901bccec6f747467e1af31473655c8290e32309 (commit)


- Log -----------------------------------------------------------------
commit 7d152a3c4f58bc2c4e94946e2a8dbf1a855a52f2
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 8 11:42:38 2016 +0000

    Fix the declaration of tls_parse_extension in statem_locl.h
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 625b0d514e4f917c1eeaac621e66c6cba29aeae8
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 8 09:48:29 2016 +0000

    Fix a travis failure
    
    Travis was indicating a bogus uninit var warning. This fixes it.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 9615387408f355dc0620c1ab797a16ae7e72d722
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 8 09:44:06 2016 +0000

    Fix various indentation
    
    The indentation was a bit off in some of the perl files following the
    extensions refactor.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 1e566129ad8f7c7901b7beccd6128d37e063d2c7
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 8 00:03:53 2016 +0000

    Move the checkhandshake.pm module into test/testlib
    
    Move this module into the same place as other test helper modules. It
    simplifies the code and keeps like things together.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7fe97c077b4571a71be3f6cb963c414216371a7c
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 23:50:55 2016 +0000

    Fix make update issues
    
    Various functions got renamed. We need to rename the error codes too.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ecc2f938cf1cf7425be37156ecb216cdc6db257f
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 23:19:45 2016 +0000

    Fix more style issues following extensions refactor feedback
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit cbb0954471b16a40e67639522b30009393983285
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 17:27:22 2016 +0000

    Introduce TLSEXT_STATUSTYPE_nothing constant
    
    The existing code used the magic number -1 to represent the absence of
    a status_type in the extension. This commit replaces it with a macro.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d270de322c7bfb9c1e7509fbc24e3bf6fde713e6
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 17:21:48 2016 +0000

    Change TLSEXT_IDX_* values into an enum
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 1266eefdb66db6c01e859ae672ccc19261e75bbf
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 17:04:46 2016 +0000

    Various style updates following extensions refactor
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 89247375efcf0869449a711fd248f160627de2a2
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Dec 7 12:30:52 2016 +0000

    Fix travis mixed declarations and code error
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 14d21b690a73e1598a97afa5ad9f642d53f63db7
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Dec 6 16:37:31 2016 +0000

    Suppress some BoringSSL test failures
    
    The external BoringSSL tests had some failures as a result of
    the extensions refactor. This was due to a deliberate relaxation
    of the duplicate extensions checking code. We now only check
    known extensions for duplicates. Unknown extensions are ignored.
    This is allowed behaviour, so we suppress those BoringSSL tests.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 22ab4b7dd34d01e23bc25e729541fefaa0f47502
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Dec 6 15:37:18 2016 +0000

    Correct imports for checkhandshake module
    
    Ensure the tests can find the checkhandshake module on all platforms
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 1b0286a385aae88068af796d6d0f4fe907fe66eb
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Dec 5 17:31:37 2016 +0000

    Fix a memory leak
    
    When we call tls_collect_extensions() we need to free up the raw
    extensions data later.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7caf619f1a7c7901a63b8257ac7133dd1c584243
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 1 12:54:44 2016 +0000

    Add some extra key_share tests
    
    Check that the extension framework properly handles extensions specific
    to a protocol version
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit a1448c26d2bbec390db4c00bf3867c4369af7d15
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 30 13:46:11 2016 +0000

    Remove some spurious whitespace
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit bc349281880c3f1da784cbc76b28f34d8ab10601
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 30 12:54:01 2016 +0000

    Add a renegotiation test
    
    Make sure we did not break the unsafe legacy reneg checks with the extension
    work.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 60ea0034b8c5cb8b915ea025eb78970a1cb08f99
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 30 12:04:34 2016 +0000

    Add more extension tests to test_sslmessages
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f50306c298390c701046126bd1f48f6fef3ec3ca
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 29 17:34:10 2016 +0000

    Merge common code between test_tls13messages and test_sslmessages
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 6ca94f105814d284ff1eba7972197d24937aa419
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 29 15:57:42 2016 +0000

    Add extension tests in test_sslmessages
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 2de94a3601863a74a52a07fa5743b0f85984e755
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 29 14:56:06 2016 +0000

    Enable status_request test in test_sslmessages
    
    The s_server option -status_file has been added so this test can be
    enabled.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d70bde8805800473da0f25671902f1b4b07eecca
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 22 16:16:23 2016 +0000

    Fix a bug in TLSProxy where zero length messages were not being recorded
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 0bfe166b8ffa1f0efe986e4d731e289c48437895
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 22 16:16:11 2016 +0000

    Add a test to check messsages sent are the ones we expect
    
    Repeat for various handshake types
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit efab1586e041f4d4dde86cd786630e0d6af285a2
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 22 13:43:50 2016 +0000

    Support renegotiation in TLSProxy
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 9ce3ed2a586032690bef6a1c4e58df8d1c18f344
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 28 22:39:23 2016 +0000

    Add tests for new extension code
    
    Extend test_tls13messages to additionally check the expected extensions
    under different options given to s_client/s_server.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 3434f40b6f0b4eb782931d8f1fe2893c58c1a692
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 28 16:45:52 2016 +0000

    Split ServerHello extensions
    
    In TLS1.3 some ServerHello extensions remain in the ServerHello, while
    others move to the EncryptedExtensions message. This commit performs that
    move.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 332eb3908883fcaac8483dcc895571b0a3c2813a
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 28 16:15:51 2016 +0000

    Move ServerHello extension parsing into the new extension framework
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 70af3d8ed7e2497e8d0f34eb43a4404c493ba1cd
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 28 09:31:59 2016 +0000

    Avoid repeatedly scanning the list of extensions
    
    Because extensions were keyed by type which is sparse, we were continually
    scanning the list to find the one we wanted. The way we stored them also
    had the side effect that we were running initialisers/finalisers in a
    different oder to the parsers. In this commit we change things so that we
    instead key on an index value for each extension.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 24b8e4b2c835d6bf52c2768d4d4a78ed7d7e85bb
Author: Matt Caswell <matt at openssl.org>
Date:   Sat Nov 26 11:45:02 2016 +0000

    Simplify ClientHello extension parsing
    
    Remove some functions that are no longer needed now that we have the new
    extension framework.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 02f0274e8c0596dcf7e2d104250232a42c650b96
Author: Matt Caswell <matt at openssl.org>
Date:   Sat Nov 26 11:22:50 2016 +0000

    Move ALPN processing into an extension finalisation function
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 805a2e9e1388f21bd381a8c55e66bae2e6325667
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 23:19:56 2016 +0000

    Provide server side extension init and finalisation functions
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 68db4ddab7d35f5a3df1beee9a95fe093682340b
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 17:52:35 2016 +0000

    Add an extension initilisation and finalisation capability
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ab83e31414286ccdc35fbacf976f64a910a6c718
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 16:28:02 2016 +0000

    Move client construction of ClientHello extensions into new framework
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 6dd083fd6804a3ee6ac3adc019f81910f1c63f21
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 12:34:29 2016 +0000

    Move client parsing of ServerHello extensions into new framework
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e56c33b98bd8d72307da7911de27b5d38191d239
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 10:34:35 2016 +0000

    Rename some functions
    
    The _clienthello_ in the extensions parsing functions is overly specific.
    Better to keep the convention to just _client_
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7da160b0f46d832dbf285cb0b48ae56d4a8b884d
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 25 10:22:02 2016 +0000

    Move ServerHello extension construction into the new extensions framework
    
    This lays the foundation for a later move to have the extensions built and
    placed into the correct message for TLSv1.3 (e.g. ServerHello or
    EncryptedExtensions).
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 25670f3e87d3a9e7ea8ffb2b717a288e2b3024f5
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 22:54:59 2016 +0000

    Split extensions code into core extensions and server extensions code
    
    Later we will have client extensions code too.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 4b299b8e174cd58f762f0f184ceac7955e4227c4
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 18:25:10 2016 +0000

    Add extensions construction support
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 224135e96a16deaf9de787398d91c1b8212ab8ed
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 18:02:12 2016 +0000

    Continue the extensions refactor
    
    Add support for construction of extensions
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 6b473acabdfc72c99677a15f03295c12e4ff32fb
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 16:59:48 2016 +0000

    Refactor ClientHello extension parsing
    
    This builds on the work started in 1ab3836b3 and extends is so that
    each extension has its own identified parsing functions, as well as an
    allowed context identifying which messages and protocols it is relevant for.
    Subsequent commits will do a similar job for the ServerHello extensions.
    This will enable us to have common functions for processing extension blocks
    no matter which of the multiple messages they are received from. In TLSv1.3
    a number of different messages have extension blocks, and some extensions
    have moved from one message to another when compared to TLSv1.2.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit fadd9a1e2d2ab1d63bd05c30a0d845e837deb9be
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 11:14:56 2016 +0000

    Verify that extensions are used in the correct context
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 91b60e2ab4e0ebeaf7690a2a329e88658a6ad30b
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 24 11:13:35 2016 +0000

    Add some missing extensions to SSL_extension_supported()
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ede6f762030467e492fabd49ad4c3fd20deb71d4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 23 17:38:31 2016 +0000

    Move tls_collect_extensions() into a separate file
    
    Subsequent commits will pull other extensions code into this file.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e46f23344462c33b9a9c25d5cfe09be7d1f039e3
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 23 15:20:22 2016 +0000

    Add EncryptedExtensions message
    
    At this stage the message is just empty. We need to fill it in with
    extension data.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 71728dd8aa3acc0bc9d621f8c4a4032aa3325fe4
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 7 13:50:43 2016 +0000

    Send and Receive a TLSv1.3 format ServerHello
    
    There are some minor differences in the format of a ServerHello in TLSv1.3.
    
    Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
    Salz
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h                              |   71 +-
 include/openssl/ssl3.h                             |    1 +
 ssl/build.info                                     |    5 +-
 ssl/d1_srtp.c                                      |  124 --
 ssl/ssl_err.c                                      |   83 +-
 ssl/ssl_lib.c                                      |    2 +-
 ssl/ssl_locl.h                                     |   61 +-
 ssl/statem/extensions.c                            |  908 ++++++++
 ssl/statem/extensions_clnt.c                       | 1042 ++++++++++
 ssl/statem/extensions_srvr.c                       |  934 +++++++++
 ssl/statem/statem_clnt.c                           |  139 +-
 ssl/statem/statem_lib.c                            |  113 +-
 ssl/statem/statem_locl.h                           |  143 +-
 ssl/statem/statem_srvr.c                           |  197 +-
 ssl/t1_ext.c                                       |    3 +
 ssl/t1_lib.c                                       | 2178 +-------------------
 ssl/t1_reneg.c                                     |  127 --
 ssl/t1_trce.c                                      |   41 +-
 test/ossl_shim/ossl_config.json                    |    6 +
 test/recipes/70-test_key_share.t                   |   26 +-
 ...est_sslcertstatus.t => 70-test_renegotiation.t} |   48 +-
 test/recipes/70-test_sslcertstatus.t               |    4 +-
 test/recipes/70-test_sslmessages.t                 |  352 ++++
 test/recipes/70-test_tls13messages.t               |  243 ++-
 test/ssl-tests/09-alpn.conf                        |    8 +
 test/ssl-tests/09-alpn.conf.in                     |   19 +-
 test/ssl-tests/12-ct.conf                          |    3 +
 test/ssl-tests/12-ct.conf.in                       |  113 +-
 test/ssl-tests/protocol_version.pm                 |   16 +
 test/sslapitest.c                                  |    6 +
 test/testlib/checkhandshake.pm                     |  128 ++
 util/TLSProxy/EncryptedExtensions.pm               |  115 ++
 util/TLSProxy/Message.pm                           |   32 +-
 util/TLSProxy/Proxy.pm                             |   49 +-
 util/TLSProxy/ServerHello.pm                       |   44 +-
 35 files changed, 4576 insertions(+), 2808 deletions(-)
 create mode 100644 ssl/statem/extensions.c
 create mode 100644 ssl/statem/extensions_clnt.c
 create mode 100644 ssl/statem/extensions_srvr.c
 delete mode 100644 ssl/t1_reneg.c
 copy test/recipes/{70-test_sslcertstatus.t => 70-test_renegotiation.t} (53%)
 create mode 100755 test/recipes/70-test_sslmessages.t
 create mode 100644 test/testlib/checkhandshake.pm
 create mode 100644 util/TLSProxy/EncryptedExtensions.pm

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 840eb6e..e746a81 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -883,7 +883,9 @@ typedef enum {
     TLS_ST_SW_SESSION_TICKET,
     TLS_ST_SW_CERT_STATUS,
     TLS_ST_SW_CHANGE,
-    TLS_ST_SW_FINISHED
+    TLS_ST_SW_FINISHED,
+    TLS_ST_SW_ENCRYPTED_EXTENSIONS,
+    TLS_ST_CR_ENCRYPTED_EXTENSIONS
 } OSSL_HANDSHAKE_STATE;
 
 /*
@@ -2101,6 +2103,9 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST        385
 # define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE               370
 # define SSL_F_DTLS_PROCESS_HELLO_VERIFY                  386
+# define SSL_F_FINAL_EC_PT_FORMATS                        485
+# define SSL_F_FINAL_EMS                                  486
+# define SSL_F_FINAL_RENEGOTIATE                          483
 # define SSL_F_OPENSSL_INIT_SSL                           342
 # define SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION       436
 # define SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE       430
@@ -2263,20 +2268,65 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE             407
 # define SSL_F_TLS_CONSTRUCT_CKE_RSA                      409
 # define SSL_F_TLS_CONSTRUCT_CKE_SRP                      410
-# define SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE           355
-# define SSL_F_TLS_CONSTRUCT_CLIENT_HELLO                 356
-# define SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE          357
-# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY                358
+# define SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE           484
+# define SSL_F_TLS_CONSTRUCT_CLIENT_HELLO                 487
+# define SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE          488
+# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY                489
+# define SSL_F_TLS_CONSTRUCT_CTOS_ALPN                    466
+# define SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE             355
+# define SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS           467
+# define SSL_F_TLS_CONSTRUCT_CTOS_EMS                     468
+# define SSL_F_TLS_CONSTRUCT_CTOS_ETM                     469
+# define SSL_F_TLS_CONSTRUCT_CTOS_HELLO                   356
+# define SSL_F_TLS_CONSTRUCT_CTOS_KEY_EXCHANGE            357
+# define SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE               470
+# define SSL_F_TLS_CONSTRUCT_CTOS_NPN                     471
+# define SSL_F_TLS_CONSTRUCT_CTOS_PADDING                 472
+# define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE             473
+# define SSL_F_TLS_CONSTRUCT_CTOS_SCT                     474
+# define SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME             475
+# define SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET          476
+# define SSL_F_TLS_CONSTRUCT_CTOS_SIG_ALGS                477
+# define SSL_F_TLS_CONSTRUCT_CTOS_SRP                     478
+# define SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST          479
+# define SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS        480
+# define SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS      481
+# define SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP                482
+# define SSL_F_TLS_CONSTRUCT_CTOS_VERIFY                  358
+# define SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS         443
+# define SSL_F_TLS_CONSTRUCT_EXTENSIONS                   447
 # define SSL_F_TLS_CONSTRUCT_FINISHED                     359
 # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST                373
 # define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET           428
 # define SSL_F_TLS_CONSTRUCT_NEXT_PROTO                   426
-# define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE           374
-# define SSL_F_TLS_CONSTRUCT_SERVER_DONE                  375
-# define SSL_F_TLS_CONSTRUCT_SERVER_HELLO                 376
-# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE          377
+# define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE           490
+# define SSL_F_TLS_CONSTRUCT_SERVER_HELLO                 491
+# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE          492
+# define SSL_F_TLS_CONSTRUCT_STOC_ALPN                    451
+# define SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE             374
+# define SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG           452
+# define SSL_F_TLS_CONSTRUCT_STOC_DONE                    375
+# define SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS           453
+# define SSL_F_TLS_CONSTRUCT_STOC_EMS                     454
+# define SSL_F_TLS_CONSTRUCT_STOC_ETM                     455
+# define SSL_F_TLS_CONSTRUCT_STOC_HELLO                   376
+# define SSL_F_TLS_CONSTRUCT_STOC_KEY_EXCHANGE            377
+# define SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE               456
+# define SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG          457
+# define SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE             458
+# define SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME             459
+# define SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET          460
+# define SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST          461
+# define SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP                462
 # define SSL_F_TLS_GET_MESSAGE_BODY                       351
 # define SSL_F_TLS_GET_MESSAGE_HEADER                     387
+# define SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT               449
+# define SSL_F_TLS_PARSE_CTOS_KEY_SHARE                   463
+# define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE                 464
+# define SSL_F_TLS_PARSE_CTOS_USE_SRTP                    465
+# define SSL_F_TLS_PARSE_STOC_KEY_SHARE                   445
+# define SSL_F_TLS_PARSE_STOC_RENEGOTIATE                 448
+# define SSL_F_TLS_PARSE_STOC_USE_SRTP                    446
 # define SSL_F_TLS_POST_PROCESS_CLIENT_HELLO              378
 # define SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE       384
 # define SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE             360
@@ -2293,6 +2343,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE             380
 # define SSL_F_TLS_PROCESS_CLIENT_HELLO                   381
 # define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE            382
+# define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
 # define SSL_F_TLS_PROCESS_FINISHED                       364
 # define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
 # define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
@@ -2305,6 +2356,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_SKE_ECDHE                      420
 # define SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE               421
 # define SSL_F_TLS_PROCESS_SKE_SRP                        422
+# define SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT                450
 # define SSL_F_USE_CERTIFICATE_CHAIN_FILE                 220
 
 /* Reason codes. */
@@ -2320,6 +2372,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_BAD_DIGEST_LENGTH                          111
 # define SSL_R_BAD_ECC_CERT                               304
 # define SSL_R_BAD_ECPOINT                                306
+# define SSL_R_BAD_EXTENSION                              110
 # define SSL_R_BAD_HANDSHAKE_LENGTH                       332
 # define SSL_R_BAD_HELLO_REQUEST                          105
 # define SSL_R_BAD_KEY_SHARE                              108
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 321a8dd..c005440 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -273,6 +273,7 @@ extern "C" {
 # define SSL3_MT_CLIENT_HELLO                    1
 # define SSL3_MT_SERVER_HELLO                    2
 # define SSL3_MT_NEWSESSION_TICKET               4
+# define SSL3_MT_ENCRYPTED_EXTENSIONS            8
 # define SSL3_MT_CERTIFICATE                     11
 # define SSL3_MT_SERVER_KEY_EXCHANGE             12
 # define SSL3_MT_CERTIFICATE_REQUEST             13
diff --git a/ssl/build.info b/ssl/build.info
index 23d33d3..f13c11f 100644
--- a/ssl/build.info
+++ b/ssl/build.info
@@ -2,13 +2,14 @@ LIBS=../libssl
 SOURCE[../libssl]=\
         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 \
+        statem/statem_lib.c statem/extensions.c statem/extensions_srvr.c \
+        statem/extensions_clnt.c s3_cbc.c s3_msg.c \
         methods.c   t1_lib.c  t1_enc.c tls13_enc.c t1_ext.c \
         d1_lib.c  record/rec_layer_d1.c d1_msg.c \
         statem/statem_dtls.c d1_srtp.c \
         ssl_lib.c ssl_cert.c ssl_sess.c \
         ssl_ciph.c ssl_stat.c ssl_rsa.c \
         ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c  ssl_mcnf.c \
-        bio_ssl.c ssl_err.c t1_reneg.c tls_srp.c t1_trce.c ssl_utst.c \
+        bio_ssl.c ssl_err.c tls_srp.c t1_trce.c ssl_utst.c \
         record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \
         statem/statem.c record/ssl3_record_tls13.c
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
index 718f417..ff8f0c5 100644
--- a/ssl/d1_srtp.c
+++ b/ssl/d1_srtp.c
@@ -136,128 +136,4 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s)
 {
     return s->srtp_profile;
 }
-
-int ssl_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al)
-{
-    SRTP_PROTECTION_PROFILE *sprof;
-    STACK_OF(SRTP_PROTECTION_PROFILE) *srvr;
-    unsigned int ct, mki_len, id;
-    int i, srtp_pref;
-    PACKET subpkt;
-
-    /* Pull off the length of the cipher suite list  and check it is even */
-    if (!PACKET_get_net_2(pkt, &ct)
-        || (ct & 1) != 0 || !PACKET_get_sub_packet(pkt, &subpkt, ct)) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT,
-               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
-        *al = SSL_AD_DECODE_ERROR;
-        return 1;
-    }
-
-    srvr = SSL_get_srtp_profiles(s);
-    s->srtp_profile = NULL;
-    /* Search all profiles for a match initially */
-    srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr);
-
-    while (PACKET_remaining(&subpkt)) {
-        if (!PACKET_get_net_2(&subpkt, &id)) {
-            SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT,
-                   SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
-            *al = SSL_AD_DECODE_ERROR;
-            return 1;
-        }
-
-        /*
-         * Only look for match in profiles of higher preference than
-         * current match.
-         * If no profiles have been have been configured then this
-         * does nothing.
-         */
-        for (i = 0; i < srtp_pref; i++) {
-            sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i);
-            if (sprof->id == id) {
-                s->srtp_profile = sprof;
-                srtp_pref = i;
-                break;
-            }
-        }
-    }
-
-    /*
-     * Now extract the MKI value as a sanity check, but discard it for now
-     */
-    if (!PACKET_get_1(pkt, &mki_len)) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT,
-               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
-        *al = SSL_AD_DECODE_ERROR;
-        return 1;
-    }
-
-    if (!PACKET_forward(pkt, mki_len)
-        || PACKET_remaining(pkt)) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT,
-               SSL_R_BAD_SRTP_MKI_VALUE);
-        *al = SSL_AD_DECODE_ERROR;
-        return 1;
-    }
-
-    return 0;
-}
-
-int ssl_parse_serverhello_use_srtp_ext(SSL *s, PACKET *pkt, int *al)
-{
-    unsigned int id, ct, mki;
-    int i;
-
-    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
-    SRTP_PROTECTION_PROFILE *prof;
-
-    if (!PACKET_get_net_2(pkt, &ct)
-        || ct != 2 || !PACKET_get_net_2(pkt, &id)
-        || !PACKET_get_1(pkt, &mki)
-        || PACKET_remaining(pkt) != 0) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT,
-               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
-        *al = SSL_AD_DECODE_ERROR;
-        return 1;
-    }
-
-    if (mki != 0) {
-        /* Must be no MKI, since we never offer one */
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT,
-               SSL_R_BAD_SRTP_MKI_VALUE);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return 1;
-    }
-
-    clnt = SSL_get_srtp_profiles(s);
-
-    /* Throw an error if the server gave us an unsolicited extension */
-    if (clnt == NULL) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT,
-               SSL_R_NO_SRTP_PROFILES);
-        *al = SSL_AD_DECODE_ERROR;
-        return 1;
-    }
-
-    /*
-     * Check to see if the server gave us something we support (and
-     * presumably offered)
-     */
-    for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) {
-        prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
-
-        if (prof->id == id) {
-            s->srtp_profile = prof;
-            *al = 0;
-            return 0;
-        }
-    }
-
-    SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT,
-           SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
-    *al = SSL_AD_DECODE_ERROR;
-    return 1;
-}
-
 #endif
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 5c8e9d4..1b3e409 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -49,6 +49,9 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE),
      "dtls_get_reassembled_message"},
     {ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
+    {ERR_FUNC(SSL_F_FINAL_EC_PT_FORMATS), "final_ec_pt_formats"},
+    {ERR_FUNC(SSL_F_FINAL_EMS), "final_ems"},
+    {ERR_FUNC(SSL_F_FINAL_RENEGOTIATE), "final_renegotiate"},
     {ERR_FUNC(SSL_F_OPENSSL_INIT_SSL), "OPENSSL_init_ssl"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION),
      "ossl_statem_client13_read_transition"},
@@ -273,6 +276,43 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_construct_client_key_exchange"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY),
      "tls_construct_client_verify"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_ALPN), "tls_construct_ctos_alpn"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE),
+     "TLS_CONSTRUCT_CTOS_CERTIFICATE"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS),
+     "tls_construct_ctos_ec_pt_formats"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EMS), "tls_construct_ctos_ems"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_ETM), "tls_construct_ctos_etm"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_HELLO), "TLS_CONSTRUCT_CTOS_HELLO"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_KEY_EXCHANGE),
+     "TLS_CONSTRUCT_CTOS_KEY_EXCHANGE"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE),
+     "tls_construct_ctos_key_share"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_NPN), "tls_construct_ctos_npn"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_PADDING),
+     "tls_construct_ctos_padding"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE),
+     "tls_construct_ctos_renegotiate"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SCT), "tls_construct_ctos_sct"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME),
+     "tls_construct_ctos_server_name"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET),
+     "tls_construct_ctos_session_ticket"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SIG_ALGS),
+     "tls_construct_ctos_sig_algs"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SRP), "tls_construct_ctos_srp"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST),
+     "tls_construct_ctos_status_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS),
+     "tls_construct_ctos_supported_groups"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS),
+     "tls_construct_ctos_supported_versions"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP),
+     "tls_construct_ctos_use_srtp"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_VERIFY), "TLS_CONSTRUCT_CTOS_VERIFY"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS),
+     "tls_construct_encrypted_extensions"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_EXTENSIONS), "tls_construct_extensions"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_FINISHED), "tls_construct_finished"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST),
      "tls_construct_hello_request"},
@@ -281,13 +321,49 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEXT_PROTO), "tls_construct_next_proto"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE),
      "tls_construct_server_certificate"},
-    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_DONE), "tls_construct_server_done"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_HELLO),
      "tls_construct_server_hello"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE),
      "tls_construct_server_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_ALPN), "tls_construct_stoc_alpn"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE),
+     "TLS_CONSTRUCT_STOC_CERTIFICATE"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG),
+     "tls_construct_stoc_cryptopro_bug"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_DONE), "TLS_CONSTRUCT_STOC_DONE"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS),
+     "tls_construct_stoc_ec_pt_formats"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EMS), "tls_construct_stoc_ems"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_ETM), "tls_construct_stoc_etm"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_HELLO), "TLS_CONSTRUCT_STOC_HELLO"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_KEY_EXCHANGE),
+     "TLS_CONSTRUCT_STOC_KEY_EXCHANGE"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE),
+     "tls_construct_stoc_key_share"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG),
+     "tls_construct_stoc_next_proto_neg"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE),
+     "tls_construct_stoc_renegotiate"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME),
+     "tls_construct_stoc_server_name"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET),
+     "tls_construct_stoc_session_ticket"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST),
+     "tls_construct_stoc_status_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP),
+     "tls_construct_stoc_use_srtp"},
     {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"},
     {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT),
+     "tls_parse_clienthello_tlsext"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_KEY_SHARE), "tls_parse_ctos_key_share"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE),
+     "tls_parse_ctos_renegotiate"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_USE_SRTP), "tls_parse_ctos_use_srtp"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_STOC_KEY_SHARE), "tls_parse_stoc_key_share"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_STOC_RENEGOTIATE),
+     "tls_parse_stoc_renegotiate"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_STOC_USE_SRTP), "tls_parse_stoc_use_srtp"},
     {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO),
      "tls_post_process_client_hello"},
     {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE),
@@ -312,6 +388,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_PROCESS_CLIENT_HELLO), "tls_process_client_hello"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE),
      "tls_process_client_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS),
+     "tls_process_encrypted_extensions"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
      "tls_process_initial_server_flight"},
@@ -328,6 +406,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE),
      "tls_process_ske_psk_preamble"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_SRP), "tls_process_ske_srp"},
+    {ERR_FUNC(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT),
+     "tls_scan_clienthello_tlsext"},
     {ERR_FUNC(SSL_F_USE_CERTIFICATE_CHAIN_FILE),
      "use_certificate_chain_file"},
     {0, NULL}
@@ -350,6 +430,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_BAD_DIGEST_LENGTH), "bad digest length"},
     {ERR_REASON(SSL_R_BAD_ECC_CERT), "bad ecc cert"},
     {ERR_REASON(SSL_R_BAD_ECPOINT), "bad ecpoint"},
+    {ERR_REASON(SSL_R_BAD_EXTENSION), "bad extension"},
     {ERR_REASON(SSL_R_BAD_HANDSHAKE_LENGTH), "bad handshake length"},
     {ERR_REASON(SSL_R_BAD_HELLO_REQUEST), "bad hello request"},
     {ERR_REASON(SSL_R_BAD_KEY_SHARE), "bad key share"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 4d41b17..65e3ba1 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2556,7 +2556,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
      */
     ret->options |= SSL_OP_NO_COMPRESSION;
 
-    ret->tlsext_status_type = -1;
+    ret->tlsext_status_type = TLSEXT_STATUSTYPE_nothing;
 
     return ret;
  err:
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index cb29b99..5671a6f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1636,10 +1636,47 @@ typedef struct ssl3_comp_st {
 # endif
 
 typedef struct raw_extension_st {
-    unsigned int type;
+    /* Raw packet data for the extension */
     PACKET data;
+    /* Set to 1 if the extension is present or 0 otherwise */
+    int present;
+    /* Set to 1 if we have already parsed the extension or 0 otherwise */
+    int parsed;
+    /* The type of this extension, i.e. a TLSEXT_TYPE_* value */
+    unsigned int type;
 } RAW_EXTENSION;
 
+/*
+ * Extension index values NOTE: Any updates to these defines should be mirrored
+ * with equivalent updates to ext_defs in extensions.c
+ */
+typedef enum tlsext_index_en {
+    TLSEXT_IDX_renegotiate,
+    TLSEXT_IDX_server_name,
+    TLSEXT_IDX_srp,
+    TLSEXT_IDX_ec_point_formats,
+    TLSEXT_IDX_supported_groups,
+    TLSEXT_IDX_session_ticket,
+    TLSEXT_IDX_signature_algorithms,
+    TLSEXT_IDX_status_request,
+    TLSEXT_IDX_next_proto_neg,
+    TLSEXT_IDX_application_layer_protocol_negotiation,
+    TLSEXT_IDX_use_srtp,
+    TLSEXT_IDX_encrypt_then_mac,
+    TLSEXT_IDX_signed_certificate_timestamp,
+    TLSEXT_IDX_extended_master_secret,
+    TLSEXT_IDX_supported_versions,
+    TLSEXT_IDX_key_share,
+    TLSEXT_IDX_cryptopro_bug,
+    TLSEXT_IDX_padding
+} TLSEXT_INDEX;
+
+/*
+ * Dummy status type for the status_type extension. Indicates no status type
+ * set
+ */
+#define TLSEXT_STATUSTYPE_nothing  -1
+
 #define MAX_COMPRESSIONS_SIZE   255
 
 typedef struct {
@@ -1654,7 +1691,6 @@ typedef struct {
     size_t compressions_len;
     unsigned char compressions[MAX_COMPRESSIONS_SIZE];
     PACKET extensions;
-    size_t num_extensions;
     RAW_EXTENSION *pre_proc_exts;
 } CLIENTHELLO_MSG;
 
@@ -2060,6 +2096,8 @@ __owur int tls1_set_groups(unsigned char **pext, size_t *pextlen,
                            int *curves, size_t ncurves);
 __owur int tls1_set_groups_list(unsigned char **pext, size_t *pextlen,
                                 const char *str);
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+                         size_t *num_formats);
 __owur int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
 __owur EVP_PKEY *ssl_generate_pkey_curve(int id);
 #  endif                        /* OPENSSL_NO_EC */
@@ -2067,21 +2105,18 @@ __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 int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al);
-__owur int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al);
-__owur int ssl_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello);
+__owur int tls_curve_allowed(SSL *s, const unsigned char *curve, int op);
+__owur  int tls1_get_curvelist(SSL *s, int sess, const unsigned char **pcurves,
+                               size_t *num_curves);
+
 void ssl_set_default_md(SSL *s);
 __owur int tls1_set_server_sigalgs(SSL *s);
-__owur int ssl_check_clienthello_tlsext_late(SSL *s, int *al);
-__owur int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt);
-__owur int ssl_prepare_clienthello_tlsext(SSL *s);
-__owur int ssl_prepare_serverhello_tlsext(SSL *s);
 __owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts,
                                                 size_t numexts,
                                                 unsigned int type);
 __owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
                                       SSL_SESSION **ret);
-__owur int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello);
+__owur int tls_use_ticket(SSL *s);
 
 __owur int tls12_get_sigandhash(WPACKET *pkt, const EVP_PKEY *pk,
                                 const EVP_MD *md);
@@ -2110,9 +2145,6 @@ __owur int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex,
 
 __owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md);
 void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
-__owur int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt);
-__owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al);
-__owur int ssl_parse_clienthello_renegotiate_ext(SSL *s, PACKET *pkt, int *al);
 __owur long ssl_get_algorithm2(SSL *s);
 __owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
                               const unsigned char *psig, size_t psiglen);
@@ -2124,9 +2156,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_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al);
-__owur int ssl_parse_serverhello_use_srtp_ext(SSL *s, PACKET *pkt, int *al);
-
 __owur int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
                                  size_t *hashlen);
 __owur const EVP_MD *ssl_md(int idx);
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
new file mode 100644
index 0000000..760b150
--- /dev/null
+++ b/ssl/statem/extensions.c
@@ -0,0 +1,908 @@
+/*
+ * 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 "../ssl_locl.h"
+#include "statem_locl.h"
+
+static int final_renegotiate(SSL *s, unsigned int context, int sent,
+                                     int *al);
+static int init_server_name(SSL *s, unsigned int context);
+static int final_server_name(SSL *s, unsigned int context, int sent,
+                                     int *al);
+#ifndef OPENSSL_NO_EC
+static int final_ec_pt_formats(SSL *s, unsigned int context, int sent,
+                                       int *al);
+#endif
+static int init_session_ticket(SSL *s, unsigned int context);
+static int init_status_request(SSL *s, unsigned int context);
+static int final_status_request(SSL *s, unsigned int context, int sent,
+                                        int *al);
+#ifndef OPENSSL_NO_NEXTPROTONEG
+static int init_npn(SSL *s, unsigned int context);
+#endif
+static int init_alpn(SSL *s, unsigned int context);
+static int final_alpn(SSL *s, unsigned int context, int sent, int *al);
+static int init_sig_algs(SSL *s, unsigned int context);
+#ifndef OPENSSL_NO_SRP
+static int init_srp(SSL *s, unsigned int context);
+#endif
+static int init_etm(SSL *s, unsigned int context);
+static int init_ems(SSL *s, unsigned int context);
+static int final_ems(SSL *s, unsigned int context, int sent, int *al);
+#ifndef OPENSSL_NO_SRTP
+static int init_srtp(SSL *s, unsigned int context);
+#endif
+
+/* Structure to define a built-in extension */
+typedef struct extensions_definition_st {
+    /* The defined type for the extension */
+    unsigned int type;
+    /*
+     * The context that this extension applies to, e.g. what messages and
+     * protocol versions
+     */
+    unsigned int context;
+    /*
+     * Initialise extension before parsing. Always called for relevant contexts
+     * even if extension not present
+     */
+    int (*init)(SSL *s, unsigned int context);
+    /* Parse extension sent from client to server */
+    int (*parse_ctos)(SSL *s, PACKET *pkt, int *al);
+    /* Parse extension send from server to client */
+    int (*parse_stoc)(SSL *s, PACKET *pkt, int *al);
+    /* Construct extension sent from server to client */
+    int (*construct_stoc)(SSL *s, WPACKET *pkt, int *al);
+    /* Construct extension sent from client to server */
+    int (*construct_ctos)(SSL *s, WPACKET *pkt, int *al);
+    /*
+     * Finalise extension after parsing. Always called where an extensions was
+     * initialised even if the extension was not present. |sent| is set to 1 if
+     * the extension was seen, or 0 otherwise.
+     */
+    int (*final)(SSL *s, unsigned int context, int sent, int *al);
+} EXTENSION_DEFINITION;
+
+/*
+ * Definitions of all built-in extensions. NOTE: Changes in the number or order
+ * of these extensions should be mirrored with equivalent changes to the indexes
+ * defined in statem_locl.h.
+ * Each extension has an initialiser, a client and
+ * server side parser and a finaliser. The initialiser is called (if the
+ * extension is relevant to the given context) even if we did not see the
+ * extension in the message that we received. The parser functions are only
+ * called if we see the extension in the message. The finalisers are always
+ * called if the initialiser was called.
+ * There are also server and client side constructor functions which are always
+ * called during message construction if the extension is relevant for the
+ * given context.
+ * The initialisation, parsing, finalisation and construction functions are
+ * always called in the order defined in this list. Some extensions may depend
+ * on others having been processed first, so the order of this list is
+ * significant.
+ * The extension context is defined by a series of flags which specify which
+ * messages the extension is relevant to. These flags also specify whether the
+ * extension is relevant to a paricular protocol or protocol version.
+ *
+ * TODO(TLS1.3): Make sure we have a test to check the consistency of these
+ */
+static const EXTENSION_DEFINITION ext_defs[] = {
+    {
+        TLSEXT_TYPE_renegotiate,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED
+        | EXT_TLS1_2_AND_BELOW_ONLY,
+        NULL, tls_parse_ctos_renegotiate, tls_parse_stoc_renegotiate,
+        tls_construct_stoc_renegotiate, tls_construct_ctos_renegotiate,
+        final_renegotiate
+    },
+    {
+        TLSEXT_TYPE_server_name,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
+        | EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        init_server_name,
+        tls_parse_ctos_server_name, tls_parse_stoc_server_name,
+        tls_construct_stoc_server_name, tls_construct_ctos_server_name,
+        final_server_name
+    },
+#ifndef OPENSSL_NO_SRP
+    {
+        TLSEXT_TYPE_srp,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        init_srp, tls_parse_ctos_srp, NULL, NULL, tls_construct_ctos_srp, NULL
+    },
+#endif
+#ifndef OPENSSL_NO_EC
+    {
+        TLSEXT_TYPE_ec_point_formats,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        NULL, tls_parse_ctos_ec_pt_formats, tls_parse_stoc_ec_pt_formats,
+        tls_construct_stoc_ec_pt_formats, tls_construct_ctos_ec_pt_formats,
+        final_ec_pt_formats
+    },
+    {
+        TLSEXT_TYPE_supported_groups,
+        EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        NULL, tls_parse_ctos_supported_groups, NULL,
+        NULL /* TODO(TLS1.3): Need to add this */,
+        tls_construct_ctos_supported_groups, NULL
+    },
+#endif
+    {
+        TLSEXT_TYPE_session_ticket,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        init_session_ticket, tls_parse_ctos_session_ticket,
+        tls_parse_stoc_session_ticket, tls_construct_stoc_session_ticket,
+        tls_construct_ctos_session_ticket, NULL
+    },
+    {
+        TLSEXT_TYPE_signature_algorithms,
+        EXT_CLIENT_HELLO,
+        init_sig_algs, tls_parse_ctos_sig_algs, NULL, NULL,
+        tls_construct_ctos_sig_algs, NULL
+    },
+#ifndef OPENSSL_NO_OCSP
+    {
+        TLSEXT_TYPE_status_request,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
+        | EXT_TLS1_3_CERTIFICATE,
+        init_status_request, tls_parse_ctos_status_request,
+        tls_parse_stoc_status_request, tls_construct_stoc_status_request,
+        tls_construct_ctos_status_request, final_status_request
+    },
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    {
+        TLSEXT_TYPE_next_proto_neg,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        init_npn, tls_parse_ctos_npn, tls_parse_stoc_npn,
+        tls_construct_stoc_next_proto_neg, tls_construct_ctos_npn, NULL
+    },
+#endif
+    {
+        /*
+         * Must appear in this list after server_name so that finalisation
+         * happens after server_name callbacks
+         */
+        TLSEXT_TYPE_application_layer_protocol_negotiation,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
+        | EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        init_alpn, tls_parse_ctos_alpn, tls_parse_stoc_alpn,
+        tls_construct_stoc_alpn, tls_construct_ctos_alpn, final_alpn
+    },
+#ifndef OPENSSL_NO_SRTP
+    {
+        TLSEXT_TYPE_use_srtp,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
+        | EXT_TLS1_3_ENCRYPTED_EXTENSIONS | EXT_DTLS_ONLY,
+        init_srtp, tls_parse_ctos_use_srtp, tls_parse_stoc_use_srtp,
+        tls_construct_stoc_use_srtp, tls_construct_ctos_use_srtp, NULL
+    },
+#endif
+    {
+        TLSEXT_TYPE_encrypt_then_mac,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        init_etm, tls_parse_ctos_etm, tls_parse_stoc_etm,
+        tls_construct_stoc_etm, tls_construct_ctos_etm, NULL
+    },
+#ifndef OPENSSL_NO_CT
+    {
+        TLSEXT_TYPE_signed_certificate_timestamp,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
+        | EXT_TLS1_3_CERTIFICATE,
+        NULL,
+        /*
+         * No server side support for this, but can be provided by a custom
+         * extension. This is an exception to the rule that custom extensions
+         * cannot override built in ones.
+         */
+        NULL, tls_parse_stoc_sct, NULL, tls_construct_ctos_sct,  NULL
+    },
+#endif
+    {
+        TLSEXT_TYPE_extended_master_secret,
+        EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        init_ems, tls_parse_ctos_ems, tls_parse_stoc_ems,
+        tls_construct_stoc_ems, tls_construct_ctos_ems, final_ems
+    },
+    {
+        TLSEXT_TYPE_supported_versions,
+        EXT_CLIENT_HELLO | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY,
+        NULL,
+        /* Processed inline as part of version selection */
+        NULL, NULL, NULL, tls_construct_ctos_supported_versions, NULL
+    },
+    {
+        /*
+         * Must be in this list after supported_groups. We need that to have
+         * been parsed before we do this one.
+         */
+        TLSEXT_TYPE_key_share,
+        EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO
+        | EXT_TLS1_3_HELLO_RETRY_REQUEST | EXT_TLS_IMPLEMENTATION_ONLY
+        | EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_key_share, tls_parse_stoc_key_share,
+        tls_construct_stoc_key_share, tls_construct_ctos_key_share, NULL
+    },
+    {
+        /*
+         * Special unsolicited ServerHello extension only used when
+         * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set
+         */
+        TLSEXT_TYPE_cryptopro_bug,
+        EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY,
+        NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
+    },
+    {
+        /* Last in the list because it must be added as the last extension */
+        TLSEXT_TYPE_padding,
+        EXT_CLIENT_HELLO,
+        NULL,
+        /* We send this, but don't read it */
+        NULL, NULL, NULL, tls_construct_ctos_padding, NULL
+    }
+};
+
+/*
+ * Verify whether we are allowed to use the extension |type| in the current
+ * |context|. Returns 1 to indicate the extension is allowed or unknown or 0 to
+ * indicate the extension is not allowed. If returning 1 then |*found| is set to
+ * 1 if we found a definition for the extension, and |*idx| is set to its index
+ */
+static int verify_extension(SSL *s, unsigned int context, unsigned int type,
+                            custom_ext_methods *meths, RAW_EXTENSION *rawexlist,
+                            RAW_EXTENSION **found)
+{
+    size_t i;
+    size_t builtin_num = OSSL_NELEM(ext_defs);
+    const EXTENSION_DEFINITION *thisext;
+
+    for (i = 0, thisext = ext_defs; i < builtin_num; i++, thisext++) {
+        if (type == thisext->type) {
+            /* Check we're allowed to use this extension in this context */
+            if ((context & thisext->context) == 0)
+                return 0;
+
+            if (SSL_IS_DTLS(s)) {
+                if ((thisext->context & EXT_TLS_ONLY) != 0)
+                    return 0;
+            } else if ((thisext->context & EXT_DTLS_ONLY) != 0) {
+                    return 0;
+            }
+
+            *found = &rawexlist[i];
+            return 1;
+        }
+    }
+
+    if ((context & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) == 0) {
+        /*
+         * Custom extensions only apply to <=TLS1.2. This extension is unknown
+         * in this context - we allow it
+         */
+        *found = NULL;
+        return 1;
+    }
+
+    /* Check the custom extensions */
+    if (meths != NULL) {
+        for (i = builtin_num; i < builtin_num + meths->meths_count; i++) {
+            if (meths->meths[i - builtin_num].ext_type == type) {
+                *found = &rawexlist[i];
+                return 1;
+            }
+        }
+    }
+
+    /* Unknown extension. We allow it */
+    *found = NULL;
+    return 1;
+}
+
+/*
+ * Check whether the context defined for an extension |extctx| means whether
+ * the extension is relevant for the current context |thisctx| or not. Returns
+ * 1 if the extension is relevant for this context, and 0 otherwise
+ */
+static int extension_is_relevant(SSL *s, unsigned int extctx,
+                                 unsigned int thisctx)
+{
+    if ((SSL_IS_DTLS(s)
+                && (extctx & EXT_TLS_IMPLEMENTATION_ONLY) != 0)
+            || (s->version == SSL3_VERSION
+                    && (extctx & EXT_SSL3_ALLOWED) == 0)
+            || (SSL_IS_TLS13(s)
+                && (extctx & EXT_TLS1_2_AND_BELOW_ONLY) != 0)
+            || (!SSL_IS_TLS13(s) && (extctx & EXT_TLS1_3_ONLY) != 0))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Gather a list of all the extensions from the data in |packet]. |context|
+ * tells us which message this extension is for. The raw extension data is
+ * stored in |*res| on success. In the event of an error the alert type to use
+ * is stored in |*al|. We don't actually process the content of the extensions
+ * yet, except to check their types. This function also runs the initialiser
+ * functions for all known extensions (whether we have collected them or not).
+ * If successful the caller is responsible for freeing the contents of |*res|.
+ *
+ * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
+ * more than one extension of the same type in a ClientHello or ServerHello.
+ * This function returns 1 if all extensions are unique and we have parsed their
+ * types, and 0 if the extensions contain duplicates, could not be successfully
+ * found, or an internal error occurred. We only check duplicates for
+ * extensions that we know about. We ignore others.
+ */
+int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
+                           RAW_EXTENSION **res, int *al)
+{
+    PACKET extensions = *packet;
+    size_t i = 0;
+    custom_ext_methods *exts = NULL;
+    RAW_EXTENSION *raw_extensions = NULL;
+    const EXTENSION_DEFINITION *thisexd;
+
+    *res = NULL;
+
+    /*
+     * Initialise server side custom extensions. Client side is done during
+     * construction of extensions for the ClientHello.
+     */
+    if ((context & EXT_CLIENT_HELLO) != 0) {
+        exts = &s->cert->srv_ext;
+        custom_ext_init(&s->cert->srv_ext);
+    } else if ((context & EXT_TLS1_2_SERVER_HELLO) != 0) {
+        exts = &s->cert->cli_ext;
+    }
+
+    raw_extensions = OPENSSL_zalloc((OSSL_NELEM(ext_defs)
+                                     + (exts != NULL ? exts->meths_count : 0))
+                                     * sizeof(*raw_extensions));
+    if (raw_extensions == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    while (PACKET_remaining(&extensions) > 0) {
+        unsigned int type;
+        PACKET extension;
+        RAW_EXTENSION *thisex;
+
+        if (!PACKET_get_net_2(&extensions, &type) ||
+            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
+            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
+            *al = SSL_AD_DECODE_ERROR;
+            goto err;
+        }
+        /*
+         * Verify this extension is allowed. We only check duplicates for
+         * extensions that we recognise.
+         */
+        if (!verify_extension(s, context, type, exts, raw_extensions, &thisex)
+                || (thisex != NULL && thisex->present == 1)) {
+            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
+            *al = SSL_AD_ILLEGAL_PARAMETER;
+            goto err;
+        }
+        if (thisex != NULL) {
+            thisex->data = extension;
+            thisex->present = 1;
+            thisex->type = type;
+        }
+    }
+
+    /*
+     * Initialise all known extensions relevant to this context, whether we have
+     * found them or not
+     */
+    for (thisexd = ext_defs, i = 0; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
+        if(thisexd->init != NULL && (thisexd->context & context) != 0
+                && extension_is_relevant(s, thisexd->context, context)
+                && !thisexd->init(s, context)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            goto err;
+        }
+    }
+
+    *res = raw_extensions;
+    return 1;
+
+ err:
+    OPENSSL_free(raw_extensions);
+    return 0;
+}
+
+/*
+ * Runs the parser for a given extension with index |idx|. |exts| contains the
+ * list of all parsed extensions previously collected by
+ * tls_collect_extensions(). The parser is only run if it is applicable for the
+ * given |context| and the parser has not already been run. Returns 1 on success
+ * or 0 on failure. In the event of a failure |*al| is populated with a suitable
+ * alert code. If an extension is not present this counted as success.
+ */
+int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
+                        RAW_EXTENSION *exts, int *al)
+{
+    RAW_EXTENSION *currext = &exts[idx];
+    int (*parser)(SSL *s, PACKET *pkt, int *al) = NULL;
+
+    /* Skip if the extension is not present */
+    if (!currext->present)
+        return 1;
+
+    if (s->tlsext_debug_cb)
+        s->tlsext_debug_cb(s, !s->server, currext->type,
+                           PACKET_data(&currext->data),
+                           PACKET_remaining(&currext->data),
+                           s->tlsext_debug_arg);
+
+    /* Skip if we've already parsed this extension */
+    if (currext->parsed)
+        return 1;
+
+    currext->parsed = 1;
+
+    if (idx < OSSL_NELEM(ext_defs)) {
+        /* We are handling a built-in extension */
+        const EXTENSION_DEFINITION *extdef = &ext_defs[idx];
+
+        /* Check if extension is defined for our protocol. If not, skip */
+        if (!extension_is_relevant(s, extdef->context, context))
+            return 1;
+
+        parser = s->server ? extdef->parse_ctos : extdef->parse_stoc;
+
+        if (parser != NULL)
+            return parser(s, &currext->data, al);
+
+        /*
+         * If the parser is NULL we fall through to the custom extension
+         * processing
+         */
+    }
+
+    /*
+     * This is a custom extension. We only allow this if it is a non
+     * resumed session on the server side.
+     *
+     * TODO(TLS1.3): We only allow old style <=TLS1.2 custom extensions.
+     * We're going to need a new mechanism for TLS1.3 to specify which
+     * messages to add the custom extensions to.
+     */
+    if ((!s->hit || !s->server)
+            && (context
+                & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) != 0
+            && custom_ext_parse(s, s->server, currext->type,
+                                PACKET_data(&currext->data),
+                                PACKET_remaining(&currext->data),
+                                al) <= 0)
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Parse all remaining extensions that have not yet been parsed. Also calls the
+ * finalisation for all extensions at the end, whether we collected them or not.
+ * Returns 1 for success or 0 for failure. On failure, |*al| is populated with a
+ * suitable alert code.
+ */
+int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, int *al)
+{
+    size_t i, numexts = OSSL_NELEM(ext_defs);
+    const EXTENSION_DEFINITION *thisexd;
+
+    /* Calculate the number of extensions in the extensions list */
+    if ((context & EXT_CLIENT_HELLO) != 0) {
+        numexts += s->cert->srv_ext.meths_count;
+    } else if ((context & EXT_TLS1_2_SERVER_HELLO) != 0) {
+        numexts += s->cert->cli_ext.meths_count;
+    }
+
+    /* Parse each extension in turn */
+    for (i = 0; i < numexts; i++) {
+        if (!tls_parse_extension(s, i, context, exts, al))
+            return 0;
+    }
+
+    /*
+     * Finalise all known extensions relevant to this context, whether we have
+     * found them or not
+     */
+    for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
+        if(thisexd->final != NULL
+                && (thisexd->context & context) != 0
+                && !thisexd->final(s, context, exts[i].present, al))
+            return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Construct all the extensions relevant to the current |context| and write
+ * them to |pkt|. Returns 1 on success or 0 on failure. If a failure occurs then
+ * |al| is populated with a suitable alert code. On a failure construction stops
+ * at the first extension to fail to construct.
+ */
+int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
+                             int *al)
+{
+    size_t i;
+    int addcustom = 0, min_version, max_version = 0, reason, tmpal;
+    const EXTENSION_DEFINITION *thisexd;
+
+    /*
+     * Normally if something goes wrong during construction it's an internal
+     * error. We can always override this later.
+     */
+    tmpal = SSL_AD_INTERNAL_ERROR;
+
+    if (!WPACKET_start_sub_packet_u16(pkt)
+               /*
+                * If extensions are of zero length then we don't even add the
+                * extensions length bytes to a ClientHello/ServerHello in SSLv3
+                */
+            || ((context & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) != 0
+               && s->version == SSL3_VERSION
+               && !WPACKET_set_flags(pkt,
+                                     WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if ((context & EXT_CLIENT_HELLO) != 0) {
+        reason = ssl_get_client_min_max_version(s, &min_version, &max_version);
+        if (reason != 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, reason);
+            goto err;
+        }
+    }
+
+    /* Add custom extensions first */
+    if ((context & EXT_CLIENT_HELLO) != 0) {
+        custom_ext_init(&s->cert->cli_ext);
+        addcustom = 1;
+    } else if ((context & EXT_TLS1_2_SERVER_HELLO) != 0) {
+        /*
+         * We already initialised the custom extensions during ClientHello
+         * parsing.
+         *
+         * TODO(TLS1.3): We're going to need a new custom extension mechanism
+         * for TLS1.3, so that custom extensions can specify which of the
+         * multiple message they wish to add themselves to.
+         */
+        addcustom = 1;
+    }
+
+    if (addcustom && !custom_ext_add(s, s->server, pkt, &tmpal)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
+        int (*construct)(SSL *s, WPACKET *pkt, int *al);
+
+        /* Skip if not relevant for our context */
+        if ((thisexd->context & context) == 0)
+            continue;
+
+        construct = s->server ? thisexd->construct_stoc
+                              : thisexd->construct_ctos;
+
+        /* Check if this extension is defined for our protocol. If not, skip */
+        if ((SSL_IS_DTLS(s)
+                    && (thisexd->context & EXT_TLS_IMPLEMENTATION_ONLY)
+                       != 0)
+                || (s->version == SSL3_VERSION
+                        && (thisexd->context & EXT_SSL3_ALLOWED) == 0)
+                || (SSL_IS_TLS13(s)
+                    && (thisexd->context & EXT_TLS1_2_AND_BELOW_ONLY)
+                       != 0)
+                || (!SSL_IS_TLS13(s)
+                    && (thisexd->context & EXT_TLS1_3_ONLY) != 0
+                    && (context & EXT_CLIENT_HELLO) == 0)
+                || ((thisexd->context & EXT_TLS1_3_ONLY) != 0
+                    && (context & EXT_CLIENT_HELLO) != 0
+                    && (SSL_IS_DTLS(s) || max_version < TLS1_3_VERSION))
+                || construct == NULL)
+            continue;
+
+        if (!construct(s, pkt, &tmpal))
+            goto err;
+    }
+
+    if (!WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return 1;
+
+ err:
+    *al = tmpal;
+    return 0;
+}
+
+/*
+ * Built in extension finalisation and initialisation functions. All initialise
+ * or finalise the associated extension type for the given |context|. For
+ * finalisers |sent| is set to 1 if we saw the extension during parsing, and 0
+ * otherwise. These functions return 1 on success or 0 on failure. In the event
+ * of a failure then |*al| is populated with a suitable error code.
+ */
+
+static int final_renegotiate(SSL *s, unsigned int context, int sent,
+                                     int *al)
+{
+    if (!s->server) {
+        /*
+         * Check if we can connect to a server that doesn't support safe
+         * renegotiation
+         */
+        if (!(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+                && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+                && !sent) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_FINAL_RENEGOTIATE,
+                   SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+            return 0;
+        }
+
+        return 1;
+    }
+
+    /* Need RI if renegotiating */
+    if (s->renegotiate
+            && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+            && !sent) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_FINAL_RENEGOTIATE,
+               SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+        return 0;
+    }
+
+
+    return 1;
+}
+
+static int init_server_name(SSL *s, unsigned int context)
+{
+    if (s->server)
+        s->servername_done = 0;
+
+    return 1;
+}
+
+static int final_server_name(SSL *s, unsigned int context, int sent,
+                                     int *al)
+{
+    int ret = SSL_TLSEXT_ERR_NOACK;
+    int altmp = SSL_AD_UNRECOGNIZED_NAME;
+
+    if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+        ret = s->ctx->tlsext_servername_callback(s, &altmp,
+                                                 s->ctx->tlsext_servername_arg);
+    else if (s->initial_ctx != NULL
+             && s->initial_ctx->tlsext_servername_callback != 0)
+        ret = s->initial_ctx->tlsext_servername_callback(s, &altmp,
+                                       s->initial_ctx->tlsext_servername_arg);
+
+    switch (ret) {
+    case SSL_TLSEXT_ERR_ALERT_FATAL:
+        *al = altmp;
+        return 0;
+
+    case SSL_TLSEXT_ERR_ALERT_WARNING:
+        *al = altmp;
+        return 1;
+
+    case SSL_TLSEXT_ERR_NOACK:
+        s->servername_done = 0;
+        return 1;
+
+    default:
+        return 1;
+    }
+}
+
+#ifndef OPENSSL_NO_EC
+static int final_ec_pt_formats(SSL *s, unsigned int context, int sent,
+                                       int *al)
+{
+    unsigned long alg_k, alg_a;
+
+    if (s->server)
+        return 1;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+    /*
+     * If we are client and using an elliptic curve cryptography cipher
+     * suite, then if server returns an EC point formats lists extension it
+     * must contain uncompressed.
+     */
+    if (s->tlsext_ecpointformatlist != NULL
+            && s->tlsext_ecpointformatlist_length > 0
+            && s->session->tlsext_ecpointformatlist != NULL
+            && s->session->tlsext_ecpointformatlist_length > 0
+            && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) {
+        /* we are using an ECC cipher */
+        size_t i;
+        unsigned char *list = s->session->tlsext_ecpointformatlist;
+
+        for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) {
+            if (*list++ == TLSEXT_ECPOINTFORMAT_uncompressed)
+                break;
+        }
+        if (i == s->session->tlsext_ecpointformatlist_length) {
+            SSLerr(SSL_F_FINAL_EC_PT_FORMATS,
+                   SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+static int init_session_ticket(SSL *s, unsigned int context)
+{
+    if (!s->server)
+        s->tlsext_ticket_expected = 0;
+
+    return 1;
+}
+
+static int init_status_request(SSL *s, unsigned int context)
+{
+    if (s->server)
+        s->tlsext_status_type = TLSEXT_STATUSTYPE_nothing;
+
+    return 1;
+}
+
+static int final_status_request(SSL *s, unsigned int context, int sent,
+                                        int *al)
+{
+    if (s->server)
+        return 1;
+
+    /*
+     * Ensure we get sensible values passed to tlsext_status_cb in the event
+     * that we don't receive a status message
+     */
+    OPENSSL_free(s->tlsext_ocsp_resp);
+    s->tlsext_ocsp_resp = NULL;
+    s->tlsext_ocsp_resplen = 0;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+static int init_npn(SSL *s, unsigned int context)
+{
+    s->s3->next_proto_neg_seen = 0;
+
+    return 1;
+}
+#endif
+
+static int init_alpn(SSL *s, unsigned int context)
+{
+    OPENSSL_free(s->s3->alpn_selected);
+    s->s3->alpn_selected = NULL;
+    if (s->server) {
+        s->s3->alpn_selected_len = 0;
+        OPENSSL_free(s->s3->alpn_proposed);
+        s->s3->alpn_proposed = NULL;
+        s->s3->alpn_proposed_len = 0;
+    }
+    return 1;
+}
+
+static int final_alpn(SSL *s, unsigned int context, int sent, int *al)
+{
+    const unsigned char *selected = NULL;
+    unsigned char selected_len = 0;
+
+    if (!s->server)
+        return 1;
+
+    if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+        int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
+                                       s->s3->alpn_proposed,
+                                       (unsigned int)s->s3->alpn_proposed_len,
+                                       s->ctx->alpn_select_cb_arg);
+
+        if (r == SSL_TLSEXT_ERR_OK) {
+            OPENSSL_free(s->s3->alpn_selected);
+            s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+            if (s->s3->alpn_selected == NULL) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                return 0;
+            }
+            s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+            /* ALPN takes precedence over NPN. */
+            s->s3->next_proto_neg_seen = 0;
+#endif
+        } else {
+            *al = SSL_AD_NO_APPLICATION_PROTOCOL;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static int init_sig_algs(SSL *s, unsigned int context)
+{
+    /* Clear any signature algorithms extension received */
+    OPENSSL_free(s->s3->tmp.peer_sigalgs);
+    s->s3->tmp.peer_sigalgs = NULL;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+static int init_srp(SSL *s, unsigned int context)
+{
+    OPENSSL_free(s->srp_ctx.login);
+    s->srp_ctx.login = NULL;
+
+    return 1;
+}
+#endif
+
+static int init_etm(SSL *s, unsigned int context)
+{
+    s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+
+    return 1;
+}
+
+static int init_ems(SSL *s, unsigned int context)
+{
+    if (!s->server)
+        s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
+
+    return 1;
+}
+
+static int final_ems(SSL *s, unsigned int context, int sent, int *al)
+{
+    if (!s->server && s->hit) {
+        /*
+         * Check extended master secret extension is consistent with
+         * original session.
+         */
+        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) !=
+            !(s->session->flags & SSL_SESS_FLAG_EXTMS)) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_FINAL_EMS, SSL_R_INCONSISTENT_EXTMS);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+static int init_srtp(SSL *s, unsigned int context)
+{
+    if (s->server)
+        s->srtp_profile = NULL;
+
+    return 1;
+}
+#endif
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
new file mode 100644
index 0000000..70d90e7
--- /dev/null
+++ b/ssl/statem/extensions_clnt.c
@@ -0,0 +1,1042 @@
+/*
+ * 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 <assert.h>
+#include <openssl/ocsp.h>
+#include "../ssl_locl.h"
+#include "statem_locl.h"
+
+int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, int *al)
+{
+    /* Add RI if renegotiating */
+    if (!s->renegotiate)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, s->s3->previous_client_finished,
+                               s->s3->previous_client_finished_len)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->tlsext_hostname == NULL)
+        return 1;
+
+    /* Add TLS extension servername to the Client Hello message */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
+               /* 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_u8(pkt, TLSEXT_NAMETYPE_host_name)
+            || !WPACKET_sub_memcpy_u16(pkt, s->tlsext_hostname,
+                                       strlen(s->tlsext_hostname))
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, int *al)
+{
+    /* Add SRP username if there is one */
+    if (s->srp_ctx.login == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_srp)
+               /* 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_TLS_CONSTRUCT_CTOS_SRP, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+static int use_ecc(SSL *s)
+{
+    int i, end;
+    unsigned long alg_k, alg_a;
+    STACK_OF(SSL_CIPHER) *cipher_stack = NULL;
+
+    /* See if we support any ECC ciphersuites */
+    if (s->version == SSL3_VERSION)
+        return 0;
+
+    cipher_stack = SSL_get_ciphers(s);
+    end = sk_SSL_CIPHER_num(cipher_stack);
+    for (i = 0; i < end; i++) {
+        const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+        alg_k = c->algorithm_mkey;
+        alg_a = c->algorithm_auth;
+        if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
+                || (alg_a & SSL_aECDSA)
+                || c->min_tls >= TLS1_3_VERSION)
+            break;
+    }
+
+    return i < end;
+}
+
+int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, int *al)
+{
+    const unsigned char *pformats;
+    size_t num_formats;
+
+    if (!use_ecc(s))
+        return 1;
+
+    /* Add TLS extension ECPointFormats to the ClientHello message */
+    tls1_get_formatlist(s, &pformats, &num_formats);
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
+               /* Sub-packet for formats extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, pformats, num_formats)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+
+int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, int *al)
+{
+    const unsigned char *pcurves = NULL, *pcurvestmp;
+    size_t num_curves = 0, i;
+
+    if (!use_ecc(s))
+        return 1;
+
+    /*
+     * Add TLS extension supported_groups to the ClientHello message
+     */
+    /* TODO(TLS1.3): Add support for DHE groups */
+    pcurves = s->tlsext_supportedgroupslist;
+    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    pcurvestmp = pcurves;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
+               /* Sub-packet for supported_groups extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    /* Copy curve ID if supported */
+    for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
+        if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
+            if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
+                || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
+                    SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+                           ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+        }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, int *al)
+{
+    size_t ticklen;
+
+    if (!tls_use_ticket(s))
+        return 1;
+
+    if (!s->new_session && s->session != NULL
+            && s->session->tlsext_tick != NULL) {
+        ticklen = s->session->tlsext_ticklen;
+    } else if (s->session && s->tlsext_session_ticket != NULL
+               && s->tlsext_session_ticket->data != NULL) {
+        ticklen = s->tlsext_session_ticket->length;
+        s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+        if (s->session->tlsext_tick == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET,
+                   ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        memcpy(s->session->tlsext_tick,
+               s->tlsext_session_ticket->data, ticklen);
+        s->session->tlsext_ticklen = ticklen;
+    } else {
+        ticklen = 0;
+    }
+
+    if (ticklen == 0 && s->tlsext_session_ticket != NULL &&
+            s->tlsext_session_ticket->data == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
+            || !WPACKET_sub_memcpy_u16(pkt, s->session->tlsext_tick, ticklen)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, int *al)
+{
+    size_t salglen;
+    const unsigned char *salg;
+
+    if (!SSL_CLIENT_USE_SIGALGS(s))
+        return 1;
+
+    salglen = tls12_get_psigalgs(s, &salg);
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signature_algorithms)
+               /* 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_TLS_CONSTRUCT_CTOS_SIG_ALGS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, int *al)
+{
+    int i;
+
+    if (s->tlsext_status_type != TLSEXT_STATUSTYPE_ocsp)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
+               /* Sub-packet for status request extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_STATUSTYPE_ocsp)
+               /* Sub-packet for the ids */
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
+        unsigned char *idbytes;
+        OCSP_RESPID *id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+        int idlen = i2d_OCSP_RESPID(id, NULL);
+
+        if (idlen <= 0
+                   /* Sub-packet for an individual id */
+                || !WPACKET_sub_allocate_bytes_u16(pkt, idlen, &idbytes)
+                || i2d_OCSP_RESPID(id, &idbytes) != idlen) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                   ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!WPACKET_close(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (s->tlsext_ocsp_exts) {
+        unsigned char *extbytes;
+        int extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+
+        if (extlen < 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                   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_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
+                   ERR_R_INTERNAL_ERROR);
+            return 0;
+       }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->ctx->next_proto_select_cb == NULL || s->s3->tmp.finish_md_len != 0)
+        return 1;
+
+    /*
+     * The client advertises an empty extension to indicate its support
+     * for Next Protocol Negotiation
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_NPN, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, int *al)
+{
+    s->s3->alpn_sent = 0;
+
+    /*
+     * finish_md_len is non-zero during a renegotiation, so
+     * this avoids sending ALPN during the renegotiation
+     */
+    if (s->alpn_client_proto_list == NULL || s->s3->tmp.finish_md_len != 0)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt,
+                TLSEXT_TYPE_application_layer_protocol_negotiation)
+               /* Sub-packet ALPN extension */
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u16(pkt, s->alpn_client_proto_list,
+                                       s->alpn_client_proto_list_len)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    s->s3->alpn_sent = 1;
+
+    return 1;
+}
+
+
+#ifndef OPENSSL_NO_SRTP
+int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, int *al)
+{
+    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
+    int i, end;
+
+    if (clnt == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
+               /* 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_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    end = sk_SRTP_PROTECTION_PROFILE_num(clnt);
+    for (i = 0; i < end; i++) {
+        const SRTP_PROTECTION_PROFILE *prof =
+            sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
+
+        if (prof == NULL || !WPACKET_put_bytes_u16(pkt, prof->id)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!WPACKET_close(pkt)
+               /* Add an empty use_mki value */
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ETM, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_CT
+int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->ct_validation_callback == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signed_certificate_timestamp)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SCT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, int *al)
+{
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EMS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, int *al)
+{
+    int currv, min_version, max_version, reason;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    reason = ssl_get_client_min_max_version(s, &min_version, &max_version);
+    if (reason != 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, reason);
+        return 0;
+    }
+
+    /*
+     * TODO(TLS1.3): There is some discussion on the TLS list as to wheter
+     * we should include versions <TLS1.2. For the moment we do. To be
+     * reviewed later.
+     */
+    for (currv = max_version; currv >= min_version; currv--) {
+        /* TODO(TLS1.3): Remove this first if clause prior to release!! */
+        if (currv == TLS1_3_VERSION) {
+            if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+                       ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        } else if (!WPACKET_put_bytes_u16(pkt, currv)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+                   ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+
+int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, int *al)
+{
+    size_t i, sharessent = 0, num_curves = 0;
+    const unsigned char *pcurves = NULL;
+
+    /* key_share extension */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+               /* Extension data sub-packet */
+            || !WPACKET_start_sub_packet_u16(pkt)
+               /* KeyShare list sub-packet */
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pcurves = s->tlsext_supportedgroupslist;
+    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*
+     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
+     * now, just send one
+     */
+    for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
+        unsigned char *encodedPoint = NULL;
+        unsigned int curve_id = 0;
+        EVP_PKEY *key_share_key = NULL;
+        size_t encodedlen;
+
+        if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
+            continue;
+
+        if (s->s3->tmp.pkey != NULL) {
+            /* Shouldn't happen! */
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        /* Generate a key for this key_share */
+        curve_id = (pcurves[0] << 8) | pcurves[1];
+        key_share_key = ssl_generate_pkey_curve(curve_id);
+        if (key_share_key == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
+            return 0;
+        }
+
+        /* Encode the public key. */
+        encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
+                                                    &encodedPoint);
+        if (encodedlen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB);
+            EVP_PKEY_free(key_share_key);
+            return 0;
+        }
+
+        /* Create KeyShareEntry */
+        if (!WPACKET_put_bytes_u16(pkt, curve_id)
+                || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+            EVP_PKEY_free(key_share_key);
+            OPENSSL_free(encodedPoint);
+            return 0;
+        }
+
+        /*
+         * TODO(TLS1.3): When changing to send more than one key_share we're
+         * going to need to be able to save more than one EVP_PKEY. For now
+         * we reuse the existing tmp.pkey
+         */
+        s->s3->group_id = curve_id;
+        s->s3->tmp.pkey = key_share_key;
+        sharessent++;
+        OPENSSL_free(encodedPoint);
+    }
+
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#define F5_WORKAROUND_MIN_MSG_LEN   0xff
+#define F5_WORKAROUND_MAX_MSG_LEN   0x200
+
+int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, int *al)
+{
+    unsigned char *padbytes;
+    size_t hlen;
+
+    if ((s->options & SSL_OP_TLSEXT_PADDING) == 0)
+        return 1;
+
+    /*
+     * Add padding to workaround bugs in F5 terminators. See
+     * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
+     * code calculates the length of all existing extensions it MUST always
+     * appear last.
+     */
+    if (!WPACKET_get_total_written(pkt, &hlen)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PADDING, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (hlen > F5_WORKAROUND_MIN_MSG_LEN && hlen < F5_WORKAROUND_MAX_MSG_LEN) {
+        /* Calculate the amond of padding we need to add */
+        hlen = F5_WORKAROUND_MAX_MSG_LEN - hlen;
+
+        /*
+         * Take off the size of extension header itself (2 bytes for type and
+         * 2 bytes for length bytes)
+         */
+        if (hlen >= 4)
+            hlen -= 4;
+        else
+            hlen = 0;
+
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_padding)
+                || !WPACKET_sub_allocate_bytes_u16(pkt, hlen, &padbytes)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PADDING, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        memset(padbytes, 0, hlen);
+    }
+
+    return 1;
+}
+
+/*
+ * Parse the server's renegotiation binding and abort if it's not right
+ */
+int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, int *al)
+{
+    size_t expected_len = s->s3->previous_client_finished_len
+        + s->s3->previous_server_finished_len;
+    size_t ilen;
+    const unsigned char *data;
+
+    /* Check for logic errors */
+    assert(expected_len == 0 || s->s3->previous_client_finished_len != 0);
+    assert(expected_len == 0 || s->s3->previous_server_finished_len != 0);
+
+    /* Parse the length byte */
+    if (!PACKET_get_1_len(pkt, &ilen)) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /* Consistency check */
+    if (PACKET_remaining(pkt) != ilen) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /* Check that the extension matches */
+    if (ilen != expected_len) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_MISMATCH);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+    }
+
+    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len)
+        || memcmp(data, s->s3->previous_client_finished,
+                  s->s3->previous_client_finished_len) != 0) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_MISMATCH);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+    }
+
+    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len)
+        || memcmp(data, s->s3->previous_server_finished,
+                  s->s3->previous_server_finished_len) != 0) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_MISMATCH);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+    s->s3->send_connection_binding = 1;
+
+    return 1;
+}
+
+int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, int *al)
+{
+    if (s->tlsext_hostname == NULL || PACKET_remaining(pkt) > 0) {
+        *al = SSL_AD_UNRECOGNIZED_NAME;
+        return 0;
+    }
+
+    if (!s->hit) {
+        if (s->session->tlsext_hostname != NULL) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+        s->session->tlsext_hostname = OPENSSL_strdup(s->tlsext_hostname);
+        if (s->session->tlsext_hostname == NULL) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int ecpointformatlist_length;
+    PACKET ecptformatlist;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &ecptformatlist)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+    if (!s->hit) {
+        ecpointformatlist_length = PACKET_remaining(&ecptformatlist);
+        s->session->tlsext_ecpointformatlist_length = 0;
+
+        OPENSSL_free(s->session->tlsext_ecpointformatlist);
+        s->session->tlsext_ecpointformatlist =
+             OPENSSL_malloc(ecpointformatlist_length);
+        if (s->session->tlsext_ecpointformatlist == NULL) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+
+        s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+
+        if (!PACKET_copy_bytes(&ecptformatlist,
+                               s->session->tlsext_ecpointformatlist,
+                               ecpointformatlist_length)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, int *al)
+{
+    if (s->tls_session_ticket_ext_cb != NULL &&
+        !s->tls_session_ticket_ext_cb(s, PACKET_data(pkt),
+                                      PACKET_remaining(pkt),
+                                      s->tls_session_ticket_ext_cb_arg)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    if (!tls_use_ticket(s) || PACKET_remaining(pkt) > 0) {
+        *al = SSL_AD_UNSUPPORTED_EXTENSION;
+        return 0;
+    }
+
+    s->tlsext_ticket_expected = 1;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, int *al)
+{
+    /*
+     * MUST be empty and only sent if we've requested a status
+     * request message.
+     */
+    if (s->tlsext_status_type == TLSEXT_STATUSTYPE_nothing
+            || PACKET_remaining(pkt) > 0) {
+        *al = SSL_AD_UNSUPPORTED_EXTENSION;
+        return 0;
+    }
+    /* Set flag to expect CertificateStatus message */
+    s->tlsext_status_expected = 1;
+
+    return 1;
+}
+#endif
+
+
+#ifndef OPENSSL_NO_CT
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, int *al)
+{
+    /*
+     * Only take it if we asked for it - i.e if there is no CT validation
+     * callback set, then a custom extension MAY be processing it, so we
+     * need to let control continue to flow to that.
+     */
+    if (s->ct_validation_callback != NULL) {
+        size_t size = PACKET_remaining(pkt);
+
+        /* Simply copy it off for later processing */
+        OPENSSL_free(s->tlsext_scts);
+        s->tlsext_scts = NULL;
+
+        s->tlsext_scts_len = size;
+        if (size > 0) {
+            s->tlsext_scts = OPENSSL_malloc(size);
+            if (s->tlsext_scts == NULL
+                    || !PACKET_copy_bytes(pkt, s->tlsext_scts, size)) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                return 0;
+            }
+        }
+    } else {
+        if (custom_ext_parse(s, 0, TLSEXT_TYPE_signed_certificate_timestamp,
+                             PACKET_data(pkt), PACKET_remaining(pkt), al) <= 0)
+            return 0;
+    }
+
+    return 1;
+}
+#endif
+
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * ssl_next_proto_validate validates a Next Protocol Negotiation block. No
+ * elements of zero length are allowed and the set of elements must exactly
+ * fill the length of the block. Returns 1 on success or 0 on failure.
+ */
+static int ssl_next_proto_validate(PACKET *pkt)
+{
+    PACKET tmp_protocol;
+
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_length_prefixed_1(pkt, &tmp_protocol)
+            || PACKET_remaining(&tmp_protocol) == 0)
+            return 0;
+    }
+
+    return 1;
+}
+
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned char *selected;
+    unsigned char selected_len;
+    PACKET tmppkt;
+
+    /* Check if we are in a renegotiation. If so ignore this extension */
+    if (s->s3->tmp.finish_md_len != 0)
+        return 1;
+
+    /* We must have requested it. */
+    if (s->ctx->next_proto_select_cb == NULL) {
+        *al = SSL_AD_UNSUPPORTED_EXTENSION;
+        return 0;
+    }
+
+    /* The data must be valid */
+    tmppkt = *pkt;
+    if (!ssl_next_proto_validate(&tmppkt)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+    if (s->ctx->next_proto_select_cb(s, &selected, &selected_len,
+                                     PACKET_data(pkt),
+                                     PACKET_remaining(pkt),
+                                     s->ctx->next_proto_select_cb_arg) !=
+             SSL_TLSEXT_ERR_OK) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    /*
+     * Could be non-NULL if server has sent multiple NPN extensions in
+     * a single Serverhello
+     */
+    OPENSSL_free(s->next_proto_negotiated);
+    s->next_proto_negotiated = OPENSSL_malloc(selected_len);
+    if (s->next_proto_negotiated == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    memcpy(s->next_proto_negotiated, selected, selected_len);
+    s->next_proto_negotiated_len = selected_len;
+    s->s3->next_proto_neg_seen = 1;
+
+    return 1;
+}
+#endif
+
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, int *al)
+{
+    size_t len;
+
+    /* We must have requested it. */
+    if (!s->s3->alpn_sent) {
+        *al = SSL_AD_UNSUPPORTED_EXTENSION;
+        return 0;
+    }
+    /*-
+     * The extension data consists of:
+     *   uint16 list_length
+     *   uint8 proto_length;
+     *   uint8 proto[proto_length];
+     */
+    if (!PACKET_get_net_2_len(pkt, &len)
+        || PACKET_remaining(pkt) != len || !PACKET_get_1_len(pkt, &len)
+        || PACKET_remaining(pkt) != len) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+    OPENSSL_free(s->s3->alpn_selected);
+    s->s3->alpn_selected = OPENSSL_malloc(len);
+    if (s->s3->alpn_selected == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
+    if (!PACKET_copy_bytes(pkt, s->s3->alpn_selected, len)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+    s->s3->alpn_selected_len = len;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int id, ct, mki;
+    int i;
+    STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
+    SRTP_PROTECTION_PROFILE *prof;
+
+    if (!PACKET_get_net_2(pkt, &ct) || ct != 2
+            || !PACKET_get_net_2(pkt, &id)
+            || !PACKET_get_1(pkt, &mki)
+            || PACKET_remaining(pkt) != 0) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_USE_SRTP,
+               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (mki != 0) {
+        /* Must be no MKI, since we never offer one */
+        SSLerr(SSL_F_TLS_PARSE_STOC_USE_SRTP, SSL_R_BAD_SRTP_MKI_VALUE);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /* Throw an error if the server gave us an unsolicited extension */
+    clnt = SSL_get_srtp_profiles(s);
+    if (clnt == NULL) {
+        SSLerr(SSL_F_TLS_PARSE_STOC_USE_SRTP, SSL_R_NO_SRTP_PROFILES);
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    /*
+     * Check to see if the server gave us something we support (and
+     * presumably offered)
+     */
+    for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) {
+        prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i);
+
+        if (prof->id == id) {
+            s->srtp_profile = prof;
+            *al = 0;
+            return 1;
+        }
+    }
+
+    SSLerr(SSL_F_TLS_PARSE_STOC_USE_SRTP,
+           SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+    *al = SSL_AD_DECODE_ERROR;
+    return 0;
+}
+#endif
+
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, int *al)
+{
+    /* Ignore if inappropriate ciphersuite */
+    if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
+            && s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
+            && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4)
+        s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+
+    return 1;
+}
+
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, int *al)
+{
+    s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
+    if (!s->hit)
+        s->session->flags |= SSL_SESS_FLAG_EXTMS;
+
+    return 1;
+}
+
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int group_id;
+    PACKET encoded_pt;
+    EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;
+
+    /* Sanity check */
+    if (ckey == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_get_net_2(pkt, &group_id)) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    if (group_id != s->s3->group_id) {
+        /*
+         * This isn't for the group that we sent in the original
+         * key_share!
+         */
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+        return 0;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt)
+            || PACKET_remaining(&encoded_pt) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    skey = ssl_generate_pkey(ckey);
+    if (skey == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
+                                        PACKET_remaining(&encoded_pt))) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_ECPOINT);
+        return 0;
+    }
+
+    if (ssl_derive(s, ckey, skey, 1) == 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+    EVP_PKEY_free(skey);
+
+    return 1;
+}
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
new file mode 100644
index 0000000..9876212
--- /dev/null
+++ b/ssl/statem/extensions_srvr.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/ocsp.h>
+#include "../ssl_locl.h"
+#include "statem_locl.h"
+
+/*
+ * Parse the client's renegotiation binding and abort if it's not right
+ */
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int ilen;
+    const unsigned char *data;
+
+    /* Parse the length byte */
+    if (!PACKET_get_1(pkt, &ilen)
+        || !PACKET_get_bytes(pkt, &data, ilen)) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+    }
+
+    /* Check that the extension matches */
+    if (ilen != s->s3->previous_client_finished_len) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_MISMATCH);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+    }
+
+    if (memcmp(data, s->s3->previous_client_finished,
+               s->s3->previous_client_finished_len)) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE,
+               SSL_R_RENEGOTIATION_MISMATCH);
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+    }
+
+    s->s3->send_connection_binding = 1;
+
+    return 1;
+}
+
+/*-
+ * The servername extension is treated as follows:
+ *
+ * - Only the hostname type is supported with a maximum length of 255.
+ * - The servername is rejected if too long or if it contains zeros,
+ *   in which case an fatal alert is generated.
+ * - The servername field is maintained together with the session cache.
+ * - When a session is resumed, the servername call back invoked in order
+ *   to allow the application to position itself to the right context.
+ * - The servername is acknowledged if it is new for a session or when
+ *   it is identical to a previously used for the same session.
+ *   Applications can control the behaviour.  They can at any time
+ *   set a 'desirable' servername for a new SSL object. This can be the
+ *   case for example with HTTPS when a Host: header field is received and
+ *   a renegotiation is requested. In this case, a possible servername
+ *   presented in the new client hello is only acknowledged if it matches
+ *   the value of the Host: field.
+ * - Applications must  use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ *   if they provide for changing an explicit servername context for the
+ *   session, i.e. when the session has been established with a servername
+ *   extension.
+ * - On session reconnect, the servername extension may be absent.
+ */
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int servname_type;
+    PACKET sni, hostname;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &sni)
+        /* ServerNameList must be at least 1 byte long. */
+        || PACKET_remaining(&sni) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    /*
+     * Although the server_name extension was intended to be
+     * extensible to new name types, RFC 4366 defined the
+     * syntax inextensibly and OpenSSL 1.0.x parses it as
+     * such.
+     * RFC 6066 corrected the mistake but adding new name types
+     * is nevertheless no longer feasible, so act as if no other
+     * SNI types can exist, to simplify parsing.
+     *
+     * Also note that the RFC permits only one SNI value per type,
+     * i.e., we can only have a single hostname.
+     */
+    if (!PACKET_get_1(&sni, &servname_type)
+        || servname_type != TLSEXT_NAMETYPE_host_name
+        || !PACKET_as_length_prefixed_2(&sni, &hostname)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (!s->hit) {
+        if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) {
+            *al = TLS1_AD_UNRECOGNIZED_NAME;
+            return 0;
+        }
+
+        if (PACKET_contains_zero_byte(&hostname)) {
+            *al = TLS1_AD_UNRECOGNIZED_NAME;
+            return 0;
+        }
+
+        if (!PACKET_strndup(&hostname, &s->session->tlsext_hostname)) {
+            *al = TLS1_AD_INTERNAL_ERROR;
+            return 0;
+        }
+
+        s->servername_done = 1;
+    } else {
+        /*
+         * TODO(openssl-team): if the SNI doesn't match, we MUST
+         * fall back to a full handshake.
+         */
+        s->servername_done = s->session->tlsext_hostname
+            && PACKET_equal(&hostname, s->session->tlsext_hostname,
+                            strlen(s->session->tlsext_hostname));
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRP
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET srp_I;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &srp_I)
+            || PACKET_contains_zero_byte(&srp_I)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    /*
+     * TODO(openssl-team): currently, we re-authenticate the user
+     * upon resumption. Instead, we MUST ignore the login.
+     */
+    if (!PACKET_strndup(&srp_I, &s->srp_ctx.login)) {
+        *al = TLS1_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET ec_point_format_list;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &ec_point_format_list)
+        || PACKET_remaining(&ec_point_format_list) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (!s->hit) {
+        if (!PACKET_memdup(&ec_point_format_list,
+                           &s->session->tlsext_ecpointformatlist,
+                           &s->session->tlsext_ecpointformatlist_length)) {
+            *al = TLS1_AD_INTERNAL_ERROR;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif                          /* OPENSSL_NO_EC */
+
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, int *al)
+{
+    if (s->tls_session_ticket_ext_cb &&
+            !s->tls_session_ticket_ext_cb(s, PACKET_data(pkt),
+                                          PACKET_remaining(pkt),
+                                          s->tls_session_ticket_ext_cb_arg)) {
+        *al = TLS1_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET supported_sig_algs;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs)
+            || (PACKET_remaining(&supported_sig_algs) % 2) != 0
+            || PACKET_remaining(&supported_sig_algs) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (!s->hit && !tls1_save_sigalgs(s, PACKET_data(&supported_sig_algs),
+                                      PACKET_remaining(&supported_sig_algs))) {
+        *al = TLS1_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET responder_id_list, exts;
+
+    if (!PACKET_get_1(pkt, (unsigned int *)&s->tlsext_status_type)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (s->tlsext_status_type != TLSEXT_STATUSTYPE_ocsp) {
+        /*
+         * We don't know what to do with any other type so ignore it.
+         */
+        s->tlsext_status_type = TLSEXT_STATUSTYPE_nothing;
+        return 1;
+    }
+
+    if (!PACKET_get_length_prefixed_2 (pkt, &responder_id_list)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    /*
+     * We remove any OCSP_RESPIDs from a previous handshake
+     * to prevent unbounded memory growth - CVE-2016-6304
+     */
+    sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+    if (PACKET_remaining(&responder_id_list) > 0) {
+        s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
+        if (s->tlsext_ocsp_ids == NULL) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+    } else {
+        s->tlsext_ocsp_ids = NULL;
+    }
+
+    while (PACKET_remaining(&responder_id_list) > 0) {
+        OCSP_RESPID *id;
+        PACKET responder_id;
+        const unsigned char *id_data;
+
+        if (!PACKET_get_length_prefixed_2(&responder_id_list, &responder_id)
+                || PACKET_remaining(&responder_id) == 0) {
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        id_data = PACKET_data(&responder_id);
+        /* TODO(size_t): Convert d2i_* to size_t */
+        id = d2i_OCSP_RESPID(NULL, &id_data,
+                             (int)PACKET_remaining(&responder_id));
+        if (id == NULL) {
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        if (id_data != PACKET_end(&responder_id)) {
+            OCSP_RESPID_free(id);
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) {
+            OCSP_RESPID_free(id);
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+    }
+
+    /* Read in request_extensions */
+    if (!PACKET_as_length_prefixed_2(pkt, &exts)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (PACKET_remaining(&exts) > 0) {
+        const unsigned char *ext_data = PACKET_data(&exts);
+
+        sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+                                   X509_EXTENSION_free);
+        s->tlsext_ocsp_exts =
+            d2i_X509_EXTENSIONS(NULL, &ext_data, (int)PACKET_remaining(&exts));
+        if (s->tlsext_ocsp_exts == NULL || ext_data != PACKET_end(&exts)) {
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, int *al)
+{
+    /*
+     * We shouldn't accept this extension on a
+     * renegotiation.
+     *
+     * s->new_session will be set on renegotiation, but we
+     * probably shouldn't rely that it couldn't be set on
+     * the initial renegotiation too in certain cases (when
+     * there's some other reason to disallow resuming an
+     * earlier session -- the current code won't be doing
+     * anything like that, but this might change).
+     *
+     * A valid sign that there's been a previous handshake
+     * in this connection is if s->s3->tmp.finish_md_len >
+     * 0.  (We are talking about a check that will happen
+     * in the Hello protocol round, well before a new
+     * Finished message could have been computed.)
+     */
+    if (s->s3->tmp.finish_md_len == 0)
+        s->s3->next_proto_neg_seen = 1;
+
+    return 1;
+}
+#endif
+
+/*
+ * Save the ALPN extension in a ClientHello.|pkt| holds the contents of the ALPN
+ * extension, not including type and length. |al| is a pointer to the alert
+ * value to send in the event of a failure. Returns: 1 on success, 0 on error.
+ */
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET protocol_list, save_protocol_list, protocol;
+
+    if (s->s3->tmp.finish_md_len != 0)
+        return 1;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &protocol_list)
+        || PACKET_remaining(&protocol_list) < 2) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    save_protocol_list = protocol_list;
+    do {
+        /* Protocol names can't be empty. */
+        if (!PACKET_get_length_prefixed_1(&protocol_list, &protocol)
+                || PACKET_remaining(&protocol) == 0) {
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+    } while (PACKET_remaining(&protocol_list) != 0);
+
+    if (!PACKET_memdup(&save_protocol_list,
+                       &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) {
+        *al = TLS1_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, int *al)
+{
+    STACK_OF(SRTP_PROTECTION_PROFILE) *srvr;
+    unsigned int ct, mki_len, id;
+    int i, srtp_pref;
+    PACKET subpkt;
+
+    /* Ignore this if we have no SRTP profiles */
+    if (SSL_get_srtp_profiles(s) == NULL)
+        return 1;
+
+    /* Pull off the length of the cipher suite list  and check it is even */
+    if (!PACKET_get_net_2(pkt, &ct) || (ct & 1) != 0
+            || !PACKET_get_sub_packet(pkt, &subpkt, ct)) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    srvr = SSL_get_srtp_profiles(s);
+    s->srtp_profile = NULL;
+    /* Search all profiles for a match initially */
+    srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr);
+
+    while (PACKET_remaining(&subpkt)) {
+        if (!PACKET_get_net_2(&subpkt, &id)) {
+            SSLerr(SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+                   SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        /*
+         * Only look for match in profiles of higher preference than
+         * current match.
+         * If no profiles have been have been configured then this
+         * does nothing.
+         */
+        for (i = 0; i < srtp_pref; i++) {
+            SRTP_PROTECTION_PROFILE *sprof =
+                sk_SRTP_PROTECTION_PROFILE_value(srvr, i);
+
+            if (sprof->id == id) {
+                s->srtp_profile = sprof;
+                srtp_pref = i;
+                break;
+            }
+        }
+    }
+
+    /* Now extract the MKI value as a sanity check, but discard it for now */
+    if (!PACKET_get_1(pkt, &mki_len)) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_USE_SRTP,
+               SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (!PACKET_forward(pkt, mki_len)
+        || PACKET_remaining(pkt)) {
+        SSLerr(SSL_F_TLS_PARSE_CTOS_USE_SRTP, SSL_R_BAD_SRTP_MKI_VALUE);
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, int *al)
+{
+    if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
+        s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+
+    return 1;
+}
+
+/*
+ * Checks a list of |groups| to determine if the |group_id| is in it. If it is
+ * and |checkallow| is 1 then additionally check if the group is allowed to be
+ * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
+ * 1) or 0 otherwise.
+ */
+static int check_in_list(SSL *s, unsigned int group_id,
+                         const unsigned char *groups, size_t num_groups,
+                         int checkallow)
+{
+    size_t i;
+
+    if (groups == NULL || num_groups == 0)
+        return 0;
+
+    for (i = 0; i < num_groups; i++, groups += 2) {
+        unsigned int share_id = (groups[0] << 8) | (groups[1]);
+
+        if (group_id == share_id
+                && (!checkallow
+                    || tls_curve_allowed(s, groups, SSL_SECOP_CURVE_CHECK))) {
+            break;
+        }
+    }
+
+    /* If i == num_groups then not in the list */
+    return i < num_groups;
+}
+
+/*
+ * Process a key_share extension received in the ClientHello. |pkt| contains
+ * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
+ * If a failure occurs then |*al| is set to an appropriate alert value.
+ */
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int group_id;
+    PACKET key_share_list, encoded_pt;
+    const unsigned char *clntcurves, *srvrcurves;
+    size_t clnt_num_curves, srvr_num_curves;
+    int group_nid, found = 0;
+    unsigned int curve_flags;
+
+    if (s->hit)
+        return 1;
+
+    /* Sanity check */
+    if (s->s3->peer_tmp != NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /* Get our list of supported curves */
+    if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /*
+     * Get the clients list of supported curves.
+     * TODO(TLS1.3): We should validate that we actually received
+     * supported_groups!
+     */
+    if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    while (PACKET_remaining(&key_share_list) > 0) {
+        if (!PACKET_get_net_2(&key_share_list, &group_id)
+                || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt)
+                || PACKET_remaining(&encoded_pt) == 0) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                   SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+
+        /*
+         * If we already found a suitable key_share we loop through the
+         * rest to verify the structure, but don't process them.
+         */
+        if (found)
+            continue;
+
+        /* Check if this share is in supported_groups sent from client */
+        if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Check if this share is for a group we can use */
+        if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) {
+            /* Share not suitable */
+            continue;
+        }
+
+        group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags);
+
+        if (group_nid == 0) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+            return 0;
+        }
+
+        if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
+            /* Can happen for some curves, e.g. X25519 */
+            EVP_PKEY *key = EVP_PKEY_new();
+
+            if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
+                EVP_PKEY_free(key);
+                return 0;
+            }
+            s->s3->peer_tmp = key;
+        } else {
+            /* Set up EVP_PKEY with named curve as parameters */
+            EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+
+            if (pctx == NULL
+                    || EVP_PKEY_paramgen_init(pctx) <= 0
+                    || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
+                                                              group_nid) <= 0
+                    || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
+                EVP_PKEY_CTX_free(pctx);
+                return 0;
+            }
+            EVP_PKEY_CTX_free(pctx);
+            pctx = NULL;
+        }
+        s->s3->group_id = group_id;
+
+        if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
+                PACKET_data(&encoded_pt),
+                PACKET_remaining(&encoded_pt))) {
+            *al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_ECPOINT);
+            return 0;
+        }
+
+        found = 1;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, int *al)
+{
+    PACKET supported_groups_list;
+
+    /* Each group is 2 bytes and we must have at least 1. */
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_groups_list)
+            || PACKET_remaining(&supported_groups_list) == 0
+            || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    if (!s->hit
+            && !PACKET_memdup(&supported_groups_list,
+                              &s->session->tlsext_supportedgroupslist,
+                              &s->session->tlsext_supportedgroupslist_length)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, int *al)
+{
+    /* The extension must always be empty */
+    if (PACKET_remaining(pkt) != 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
+
+    return 1;
+}
+
+/*
+ * Add the server's renegotiation binding
+ */
+int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, int *al)
+{
+    if (!s->s3->send_connection_binding)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+            || !WPACKET_memcpy(pkt, s->s3->previous_client_finished,
+                               s->s3->previous_client_finished_len)
+            || !WPACKET_memcpy(pkt, s->s3->previous_server_finished,
+                               s->s3->previous_server_finished_len)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->hit || s->servername_done != 1
+            || s->session->tlsext_hostname == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, int *al)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+    int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))
+                    && (s->session->tlsext_ecpointformatlist != NULL);
+    const unsigned char *plist;
+    size_t plistlen;
+
+    if (!using_ecc)
+        return 1;
+
+    tls1_get_formatlist(s, &plist, &plistlen);
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, int *al)
+{
+    if (!s->tlsext_ticket_expected || !tls_use_ticket(s)) {
+        s->tlsext_ticket_expected = 0;
+        return 1;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_OCSP
+int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, int *al)
+{
+    if (!s->tlsext_status_expected)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, int *al)
+{
+    const unsigned char *npa;
+    unsigned int npalen;
+    int ret;
+    int next_proto_neg_seen = s->s3->next_proto_neg_seen;
+
+    s->s3->next_proto_neg_seen = 0;
+    if (!next_proto_neg_seen || s->ctx->next_protos_advertised_cb == NULL)
+        return 1;
+
+    ret = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
+                                      s->ctx->next_protos_advertised_cb_arg);
+    if (ret == SSL_TLSEXT_ERR_OK) {
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
+                || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG,
+                   ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        s->s3->next_proto_neg_seen = 1;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->s3->alpn_selected == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt,
+                TLSEXT_TYPE_application_layer_protocol_negotiation)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
+                                      s->s3->alpn_selected_len)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_ALPN, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, int *al)
+{
+    if (s->srtp_profile == NULL)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, 2)
+            || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, int *al)
+{
+    if ((s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) == 0)
+        return 1;
+
+    /*
+     * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
+     * for other cases too.
+     */
+    if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
+        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12) {
+        s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+        return 1;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_ETM, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, int *al)
+{
+    if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
+            || !WPACKET_put_bytes_u16(pkt, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EMS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, int *al)
+{
+    unsigned char *encodedPoint;
+    size_t encoded_pt_len = 0;
+    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
+
+    if (s->hit)
+        return 1;
+
+    if (ckey == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    skey = ssl_generate_pkey(ckey);
+    if (skey == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /* Generate encoding of server key */
+    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
+    if (encoded_pt_len == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB);
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+
+    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_free(skey);
+        OPENSSL_free(encodedPoint);
+        return 0;
+    }
+    OPENSSL_free(encodedPoint);
+
+    /* This causes the crypto state to be updated based on the derived keys */
+    s->s3->tmp.pkey = skey;
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, int *al)
+{
+    const unsigned char cryptopro_ext[36] = {
+        0xfd, 0xe8,         /* 65000 */
+        0x00, 0x20,         /* 32 bytes length */
+        0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+        0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+        0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+        0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
+    };
+
+    if (((s->s3->tmp.new_cipher->id & 0xFFFF) != 0x80
+         && (s->s3->tmp.new_cipher->id & 0xFFFF) != 0x81)
+            || (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG) == 0)
+        return 1;
+
+    if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 287d8ab..35ca8de 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -59,6 +59,8 @@
 #include <openssl/bn.h>
 #include <openssl/engine.h>
 
+static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
+
 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);
@@ -135,6 +137,13 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
         break;
 
     case TLS_ST_CR_SRVR_HELLO:
+        if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
+            st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
         if (s->hit) {
             if (mt == SSL3_MT_FINISHED) {
                 st->hand_state = TLS_ST_CR_FINISHED;
@@ -759,6 +768,9 @@ size_t ossl_statem_client_max_message_size(SSL *s)
 
     case TLS_ST_CR_FINISHED:
         return FINISHED_MAX_LENGTH;
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return ENCRYPTED_EXTENSIONS_MAX_LENGTH;
     }
 }
 
@@ -803,6 +815,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
 
     case TLS_ST_CR_FINISHED:
         return tls_process_finished(s, pkt);
+
+    case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
+        return tls_process_encrypted_extensions(s, pkt);
     }
 }
 
@@ -996,18 +1011,7 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     }
 
     /* TLS extensions */
-    if (ssl_prepare_clienthello_tlsext(s) <= 0) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-        return 0;
-    }
-    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)) {
+    if (!tls_construct_extensions(s, pkt, EXT_CLIENT_HELLO, &al)) {
         ssl3_send_alert(s, SSL3_AL_FATAL, al);
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
         return 0;
@@ -1054,13 +1058,15 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
 {
     STACK_OF(SSL_CIPHER) *sk;
     const SSL_CIPHER *c;
-    PACKET session_id;
+    PACKET session_id, extpkt;
     size_t session_id_len;
     const unsigned char *cipherchars;
     int i, al = SSL_AD_INTERNAL_ERROR;
     unsigned int compression;
     unsigned int sversion;
+    unsigned int context;
     int protverr;
+    RAW_EXTENSION *extensions = NULL;
 #ifndef OPENSSL_NO_COMP
     SSL_COMP *comp;
 #endif
@@ -1089,17 +1095,23 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     s->hit = 0;
 
     /* Get the session-id. */
-    if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    session_id_len = PACKET_remaining(&session_id);
-    if (session_id_len > sizeof s->session->session_id
-        || session_id_len > SSL3_SESSION_ID_SIZE) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
-        goto f_err;
+    if (!SSL_IS_TLS13(s)) {
+        if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        session_id_len = PACKET_remaining(&session_id);
+        if (session_id_len > sizeof s->session->session_id
+            || session_id_len > SSL3_SESSION_ID_SIZE) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+                   SSL_R_SSL3_SESSION_ID_TOO_LONG);
+            goto f_err;
+        }
+    } else {
+        PACKET_null_init(&session_id);
+        session_id_len = 0;
     }
 
     if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
@@ -1120,8 +1132,8 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
      * we can resume, and later peek at the next handshake message to see if the
      * server wants to resume.
      */
-    if (s->version >= TLS1_VERSION && s->tls_session_secret_cb &&
-        s->session->tlsext_tick) {
+    if (s->version >= TLS1_VERSION && !SSL_IS_TLS13(s)
+            && s->tls_session_secret_cb != NULL && s->session->tlsext_tick) {
         const SSL_CIPHER *pref_cipher = NULL;
         /*
          * s->session->master_key_length is a size_t, but this is an int for
@@ -1235,11 +1247,16 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     s->s3->tmp.new_cipher = c;
     /* lets get the compression algorithm */
     /* COMPRESSION */
-    if (!PACKET_get_1(pkt, &compression)) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
+    if (!SSL_IS_TLS13(s)) {
+        if (!PACKET_get_1(pkt, &compression)) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+    } else {
+        compression = 0;
     }
+
 #ifdef OPENSSL_NO_COMP
     if (compression != 0) {
         al = SSL_AD_ILLEGAL_PARAMETER;
@@ -1283,17 +1300,20 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
 #endif
 
     /* TLS extensions */
-    if (!ssl_parse_serverhello_tlsext(s, pkt)) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
-        goto err;
-    }
-
-    if (PACKET_remaining(pkt) != 0) {
-        /* wrong packet length */
+    if (PACKET_remaining(pkt) == 0) {
+        PACKET_null_init(&extpkt);
+    } else if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_LENGTH);
         goto f_err;
     }
+
+    context = SSL_IS_TLS13(s) ? EXT_TLS1_3_SERVER_HELLO
+                              : EXT_TLS1_2_SERVER_HELLO;
+    if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al)
+            || !tls_parse_all_extensions(s, context, extensions, &al))
+        goto f_err;
+
 #ifndef OPENSSL_NO_SCTP
     if (SSL_IS_DTLS(s) && s->hit) {
         unsigned char sctpauthkey[64];
@@ -1333,11 +1353,12 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
+    OPENSSL_free(extensions);
     return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
     ossl_statem_set_error(s);
+    OPENSSL_free(extensions);
     return MSG_PROCESS_ERROR;
 }
 
@@ -2207,7 +2228,8 @@ int tls_process_initial_server_flight(SSL *s, int *al)
      * |tlsext_ocsp_resplen| values will be set if we actually received a status
      * message, or NULL and -1 otherwise
      */
-    if (s->tlsext_status_type != -1 && s->ctx->tlsext_status_cb != NULL) {
+    if (s->tlsext_status_type != TLSEXT_STATUSTYPE_nothing
+            && s->ctx->tlsext_status_cb != NULL) {
         int ret;
         ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
         if (ret == 0) {
@@ -3073,6 +3095,43 @@ int tls_construct_next_proto(SSL *s, WPACKET *pkt)
 }
 #endif
 
+static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
+{
+    int al = SSL_AD_INTERNAL_ERROR;
+    PACKET extensions;
+    RAW_EXTENSION *rawexts = NULL;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &extensions)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /*
+     * TODO(TLS1.3): For now we are processing Encrypted Extensions and
+     * Certificate extensions as part of this one message. Later we need to
+     * split out the Certificate extensions into the Certificate message
+     */
+    if (!tls_collect_extensions(s, &extensions,
+                                EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+                                    | EXT_TLS1_3_CERTIFICATE,
+                                &rawexts, &al)
+            || !tls_parse_all_extensions(s,
+                                         EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+                                            | EXT_TLS1_3_CERTIFICATE,
+                                         rawexts, &al))
+        goto err;
+
+    OPENSSL_free(rawexts);
+    return MSG_PROCESS_CONTINUE_READING;
+
+ err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    OPENSSL_free(rawexts);
+    return MSG_PROCESS_ERROR;
+}
+
 int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
 {
     int i = 0;
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index a736a09..742925f 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -152,111 +152,6 @@ static void ssl3_take_mac(SSL *s)
 }
 #endif
 
-/*
- * Comparison function used in a call to qsort (see tls_collect_extensions()
- * below.)
- * The two arguments |p1| and |p2| are expected to be pointers to RAW_EXTENSIONs
- *
- * Returns:
- *  1 if the type for p1 is greater than p2
- *  0 if the type for p1 and p2 are the same
- * -1 if the type for p1 is less than p2
- */
-static int compare_extensions(const void *p1, const void *p2)
-{
-    const RAW_EXTENSION *e1 = (const RAW_EXTENSION *)p1;
-    const RAW_EXTENSION *e2 = (const RAW_EXTENSION *)p2;
-
-    if (e1->type < e2->type)
-        return -1;
-    else if (e1->type > e2->type)
-        return 1;
-
-    return 0;
-}
-
-/*
- * Gather a list of all the extensions. We don't actually process the content
- * of the extensions yet, except to check their types.
- *
- * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
- * more than one extension of the same type in a ClientHello or ServerHello.
- * This function returns 1 if all extensions are unique and we have parsed their
- * types, and 0 if the extensions contain duplicates, could not be successfully
- * parsed, or an internal error occurred.
- */
-/*
- * TODO(TLS1.3): Refactor ServerHello extension parsing to use this and then
- * remove tls1_check_duplicate_extensions()
- */
-int tls_collect_extensions(PACKET *packet, RAW_EXTENSION **res,
-                             size_t *numfound, int *ad)
-{
-    PACKET extensions = *packet;
-    size_t num_extensions = 0, i = 0;
-    RAW_EXTENSION *raw_extensions = NULL;
-
-    /* First pass: count the extensions. */
-    while (PACKET_remaining(&extensions) > 0) {
-        unsigned int type;
-        PACKET extension;
-
-        if (!PACKET_get_net_2(&extensions, &type) ||
-            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
-            *ad = SSL_AD_DECODE_ERROR;
-            goto err;
-        }
-        num_extensions++;
-    }
-
-    if (num_extensions > 0) {
-        raw_extensions = OPENSSL_malloc(sizeof(*raw_extensions)
-                                        * num_extensions);
-        if (raw_extensions == NULL) {
-            *ad = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        /* Second pass: collect the extensions. */
-        for (i = 0; i < num_extensions; i++) {
-            if (!PACKET_get_net_2(packet, &raw_extensions[i].type) ||
-                !PACKET_get_length_prefixed_2(packet,
-                                              &raw_extensions[i].data)) {
-                /* This should not happen. */
-                *ad = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-        }
-
-        if (PACKET_remaining(packet) != 0) {
-            *ad = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
-        /* Sort the extensions and make sure there are no duplicates. */
-        qsort(raw_extensions, num_extensions, sizeof(*raw_extensions),
-              compare_extensions);
-        for (i = 1; i < num_extensions; i++) {
-            if (raw_extensions[i - 1].type == raw_extensions[i].type) {
-                *ad = SSL_AD_DECODE_ERROR;
-                goto err;
-            }
-        }
-    }
-
-    *res = raw_extensions;
-    *numfound = num_extensions;
-    return 1;
-
- err:
-    OPENSSL_free(raw_extensions);
-    return 0;
-}
-
-
-
 MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
 {
     int al;
@@ -1053,16 +948,16 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
         break;
     }
 
-    suppversions = tls_get_extension_by_type(hello->pre_proc_exts,
-                                             hello->num_extensions,
-                                             TLSEXT_TYPE_supported_versions);
+    suppversions = &hello->pre_proc_exts[TLSEXT_IDX_supported_versions];
 
-    if (suppversions != NULL && !SSL_IS_DTLS(s)) {
+    if (suppversions->present && !SSL_IS_DTLS(s)) {
         unsigned int candidate_vers = 0;
         unsigned int best_vers = 0;
         const SSL_METHOD *best_method = NULL;
         PACKET versionslist;
 
+        suppversions->parsed = 1;
+
         if (!PACKET_as_length_prefixed_1(&suppversions->data, &versionslist)) {
             /* Trailing or invalid data? */
             return SSL_R_LENGTH_MISMATCH;
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index f6c76ab..94e64b5 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -19,12 +19,35 @@
 /* The spec allows for a longer length than this, but we limit it */
 #define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
 #define SERVER_HELLO_MAX_LENGTH         20000
+#define ENCRYPTED_EXTENSIONS_MAX_LENGTH 20000
 #define SERVER_KEY_EXCH_MAX_LENGTH      102400
 #define SERVER_HELLO_DONE_MAX_LENGTH    0
 #define CCS_MAX_LENGTH                  1
 /* Max should actually be 36 but we are generous */
 #define FINISHED_MAX_LENGTH             64
 
+/* Extension context codes */
+/* This extension is only allowed in TLS */
+#define EXT_TLS_ONLY                        0x0001
+/* This extension is only allowed in DTLS */
+#define EXT_DTLS_ONLY                       0x0002
+/* Some extensions may be allowed in DTLS but we don't implement them for it */
+#define EXT_TLS_IMPLEMENTATION_ONLY         0x0004
+/* Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is */
+#define EXT_SSL3_ALLOWED                    0x0008
+/* Extension is only defined for TLS1.2 and above */
+#define EXT_TLS1_2_AND_BELOW_ONLY           0x0010
+/* Extension is only defined for TLS1.3 and above */
+#define EXT_TLS1_3_ONLY                     0x0020
+#define EXT_CLIENT_HELLO                    0x0040
+/* Really means TLS1.2 or below */
+#define EXT_TLS1_2_SERVER_HELLO             0x0080
+#define EXT_TLS1_3_SERVER_HELLO             0x0100
+#define EXT_TLS1_3_ENCRYPTED_EXTENSIONS     0x0200
+#define EXT_TLS1_3_HELLO_RETRY_REQUEST      0x0400
+#define EXT_TLS1_3_CERTIFICATE              0x0800
+#define EXT_TLS1_3_NEW_SESSION_TICKET       0x1000
+
 /* Message processing return codes */
 typedef enum {
     /* Something bad happened */
@@ -87,9 +110,6 @@ __owur int tls_construct_finished(SSL *s, WPACKET *pkt);
 __owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst);
 __owur WORK_STATE dtls_wait_for_dry(SSL *s);
 
-int tls_collect_extensions(PACKET *packet, RAW_EXTENSION **res,
-                             size_t *numfound, int *ad);
-
 /* some client-only functions */
 __owur int tls_construct_client_hello(SSL *s, WPACKET *pkt);
 __owur MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt);
@@ -129,3 +149,120 @@ __owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt);
 __owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt);
 #endif
 __owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt);
+
+
+/* Extension processing */
+
+__owur int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
+                                  RAW_EXTENSION **res, int *al);
+__owur int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
+                               RAW_EXTENSION *exts, int *al);
+__owur int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts,
+                                    int *al);
+__owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
+                                    int *al);
+
+/* Server Extension processing */
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, int *al);
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRP
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_EC
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, int *al);
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, int *al);
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, int *al);
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al);
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, int *al);
+
+int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_EC
+int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_OCSP
+int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRTP
+int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, int *al);
+/*
+ * Not in public headers as this is not an official extension. Only used when
+ * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
+ */
+#define TLSEXT_TYPE_cryptopro_bug      0xfde8
+int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, int *al);
+
+/* Client Extension processing */
+int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRP
+int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_EC
+int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_OCSP
+int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRTP
+int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, int *al);
+#ifndef OPENSSL_NO_CT
+int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, int *al);
+#endif
+int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, int *al);
+int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, int *al);
+int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_EC
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_OCSP
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_CT
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, int *al);
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, int *al);
+#ifndef OPENSSL_NO_SRTP
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, int *al);
+#endif
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, int *al);
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, int *al);
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, int *al);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 33808ed..56f3998 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -61,6 +61,7 @@
 #include <openssl/bn.h>
 #include <openssl/md5.h>
 
+static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt);
 static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
                                                       PACKET *cipher_suites,
                                                       STACK_OF(SSL_CIPHER)
@@ -408,6 +409,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_SW_SRVR_HELLO:
+        st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
         if (s->hit)
             st->hand_state = TLS_ST_SW_FINISHED;
         else if (send_certificate_request(s))
@@ -855,6 +860,11 @@ int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt,
         *confunc = tls_construct_finished;
         *mt = SSL3_MT_FINISHED;
         break;
+
+    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
+        *confunc = tls_construct_encrypted_extensions;
+        *mt = SSL3_MT_ENCRYPTED_EXTENSIONS;
+        break;
     }
 
     return 1;
@@ -1052,6 +1062,69 @@ int dtls_construct_hello_verify_request(SSL *s, WPACKET *pkt)
     return 1;
 }
 
+#ifndef OPENSSL_NO_EC
+/*-
+ * ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |hello|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ *   SNI,
+ *   elliptic_curves
+ *   ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
+{
+    static const unsigned char kSafariExtensionsBlock[] = {
+        0x00, 0x0a,             /* elliptic_curves extension */
+        0x00, 0x08,             /* 8 bytes */
+        0x00, 0x06,             /* 6 bytes of curve ids */
+        0x00, 0x17,             /* P-256 */
+        0x00, 0x18,             /* P-384 */
+        0x00, 0x19,             /* P-521 */
+
+        0x00, 0x0b,             /* ec_point_formats */
+        0x00, 0x02,             /* 2 bytes */
+        0x01,                   /* 1 point format */
+        0x00,                   /* uncompressed */
+        /* The following is only present in TLS 1.2 */
+        0x00, 0x0d,             /* signature_algorithms */
+        0x00, 0x0c,             /* 12 bytes */
+        0x00, 0x0a,             /* 10 bytes */
+        0x05, 0x01,             /* SHA-384/RSA */
+        0x04, 0x01,             /* SHA-256/RSA */
+        0x02, 0x01,             /* SHA-1/RSA */
+        0x04, 0x03,             /* SHA-256/ECDSA */
+        0x02, 0x03,             /* SHA-1/ECDSA */
+    };
+    /* Length of the common prefix (first two extensions). */
+    static const size_t kSafariCommonExtensionsLength = 18;
+    unsigned int type;
+    PACKET sni, tmppkt;
+    size_t ext_len;
+
+    tmppkt = hello->extensions;
+
+    if (!PACKET_forward(&tmppkt, 2)
+        || !PACKET_get_net_2(&tmppkt, &type)
+        || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) {
+        return;
+    }
+
+    if (type != TLSEXT_TYPE_server_name)
+        return;
+
+    ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ?
+        sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength;
+
+    s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock,
+                                             ext_len);
+}
+#endif                          /* !OPENSSL_NO_EC */
+
 MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
 {
     int i, al = SSL_AD_INTERNAL_ERROR;
@@ -1239,8 +1312,8 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
 
     /* Preserve the raw extensions PACKET for later use */
     extensions = clienthello.extensions;
-    if (!tls_collect_extensions(&extensions, &clienthello.pre_proc_exts,
-                                  &clienthello.num_extensions, &al)) {
+    if (!tls_collect_extensions(s, &extensions, EXT_CLIENT_HELLO,
+                                &clienthello.pre_proc_exts, &al)) {
         /* SSLerr already been called */
         goto f_err;
     }
@@ -1325,9 +1398,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     s->hit = 0;
 
     /* We need to do this before getting the session */
-    if (!tls_check_client_ems_support(s, &clienthello)) {
-        /* Only fails if the extension is malformed */
-        al = SSL_AD_DECODE_ERROR;
+    if (!tls_parse_extension(s, TLSEXT_IDX_extended_master_secret,
+                             EXT_CLIENT_HELLO,
+                             clienthello.pre_proc_exts, &al)) {
         SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
         goto f_err;
     }
@@ -1424,10 +1497,16 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
+#ifndef OPENSSL_NO_EC
+    if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+        ssl_check_for_safari(s, &clienthello);
+#endif                          /* !OPENSSL_NO_EC */
+
     /* TLS extensions */
-    if (!ssl_parse_clienthello_tlsext(s, &clienthello)) {
+    if (!tls_parse_all_extensions(s, EXT_CLIENT_HELLO,
+                                  clienthello.pre_proc_exts, &al)) {
         SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
-        goto err;
+        goto f_err;
     }
 
     /* Check we've got a key_share for TLSv1.3 */
@@ -1611,6 +1690,55 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
+/*
+ * Call the status request callback if needed. Upon success, returns 1.
+ * Upon failure, returns 0 and sets |*al| to the appropriate fatal alert.
+ */
+static int tls_handle_status_request(SSL *s, int *al)
+{
+    s->tlsext_status_expected = 0;
+
+    /*
+     * If status request then ask callback what to do. Note: this must be
+     * called after servername callbacks in case the certificate has changed,
+     * and must be called after the cipher has been chosen because this may
+     * influence which certificate is sent
+     */
+    if (s->tlsext_status_type != TLSEXT_STATUSTYPE_nothing && s->ctx != NULL
+            && s->ctx->tlsext_status_cb != NULL) {
+        int ret;
+        CERT_PKEY *certpkey = ssl_get_server_send_pkey(s);
+
+        /* If no certificate can't return certificate status */
+        if (certpkey != NULL) {
+            /*
+             * Set current certificate to one we will use so SSL_get_certificate
+             * et al can pick it up.
+             */
+            s->cert->key = certpkey;
+            ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+            switch (ret) {
+                /* We don't want to send a status request response */
+            case SSL_TLSEXT_ERR_NOACK:
+                s->tlsext_status_expected = 0;
+                break;
+                /* status request response should be sent */
+            case SSL_TLSEXT_ERR_OK:
+                if (s->tlsext_ocsp_resp)
+                    s->tlsext_status_expected = 1;
+                break;
+                /* something bad happened */
+            case SSL_TLSEXT_ERR_ALERT_FATAL:
+            default:
+                *al = SSL_AD_INTERNAL_ERROR;
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
 WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
 {
     int al = SSL_AD_HANDSHAKE_FAILURE;
@@ -1644,8 +1772,10 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
             s->s3->tmp.new_cipher = cipher;
             /* check whether we should disable session resumption */
             if (s->not_resumable_session_cb != NULL)
-                s->session->not_resumable = s->not_resumable_session_cb(s,
-                                                                        ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
+                s->session->not_resumable =
+                    s->not_resumable_session_cb(s, ((cipher->algorithm_mkey
+                                                    & (SSL_kDHE | SSL_kECDHE))
+                                                   != 0));
             if (s->session->not_resumable)
                 /* do not send a session ticket */
                 s->tlsext_ticket_expected = 0;
@@ -1673,13 +1803,14 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
          * s->s3->tmp.new_cipher- the new cipher to use.
          */
 
-        /* Handles TLS extensions that we couldn't check earlier */
-        if (s->version >= SSL3_VERSION) {
-            if (!ssl_check_clienthello_tlsext_late(s, &al)) {
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
-                       SSL_R_CLIENTHELLO_TLSEXT);
-                goto f_err;
-            }
+        /*
+         * Call status_request callback if needed. Has to be done after the
+         * certificate callbacks etc above.
+         */
+        if (!tls_handle_status_request(s, &al)) {
+            SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                   SSL_R_CLIENTHELLO_TLSEXT);
+            goto f_err;
         }
 
         wst = WORK_MORE_B;
@@ -1773,18 +1904,22 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt)
         compm = s->s3->tmp.new_compression->id;
 #endif
 
-    if (!WPACKET_sub_memcpy_u8(pkt, s->session->session_id, sl)
+    if ((!SSL_IS_TLS13(s)
+                && !WPACKET_sub_memcpy_u8(pkt, s->session->session_id, sl))
             || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len)
-            || !WPACKET_put_bytes_u8(pkt, compm)
-            || !ssl_prepare_serverhello_tlsext(s)
-            || !ssl_add_serverhello_tlsext(s, pkt, &al)) {
+            || (!SSL_IS_TLS13(s)
+                && !WPACKET_put_bytes_u8(pkt, compm))
+            || !tls_construct_extensions(s, pkt,
+                                         SSL_IS_TLS13(s)
+                                            ? EXT_TLS1_3_SERVER_HELLO
+                                            : EXT_TLS1_2_SERVER_HELLO, &al)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
     return 1;
  err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
     return 0;
 }
 
@@ -3352,6 +3487,26 @@ MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt)
 }
 #endif
 
+static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt)
+{
+    int al;
+
+    /*
+     * TODO(TLS1.3): For now we send certificate extensions in with the
+     * encrypted extensions. Later we need to move these to the certificate
+     * message.
+     */
+    if (!tls_construct_extensions(s, pkt, EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+                                          | EXT_TLS1_3_CERTIFICATE, &al)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        SSLerr(SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS, ERR_R_INTERNAL_ERROR);
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        return 0;
+    }
+
+    return 1;
+}
+
 #define SSLV2_CIPHER_LEN    3
 
 STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
diff --git a/ssl/t1_ext.c b/ssl/t1_ext.c
index ae6e978..1821647 100644
--- a/ssl/t1_ext.c
+++ b/ssl/t1_ext.c
@@ -258,6 +258,9 @@ int SSL_extension_supported(unsigned int ext_type)
 #ifdef TLSEXT_TYPE_encrypt_then_mac
     case TLSEXT_TYPE_encrypt_then_mac:
 #endif
+    case TLSEXT_TYPE_key_share:
+    case TLSEXT_TYPE_supported_versions:
+    case TLSEXT_TYPE_extended_master_secret:
         return 1;
     default:
         return 0;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 778f84e..f45ffcb 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -23,8 +23,6 @@
 static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, size_t ticklen,
                               const unsigned char *sess_id, size_t sesslen,
                               SSL_SESSION **psess);
-static int ssl_check_clienthello_tlsext_early(SSL *s);
-static int ssl_check_serverhello_tlsext(SSL *s);
 
 SSL3_ENC_METHOD const TLSv1_enc_data = {
     tls1_enc,
@@ -262,8 +260,8 @@ int tls1_ec_nid2curve_id(int nid)
  * parsed form instead. (However, this would affect binary compatibility
  * so cannot happen in the 1.0.x series.)
  */
-static int tls1_get_curvelist(SSL *s, int sess,
-                              const unsigned char **pcurves, size_t *num_curves)
+int tls1_get_curvelist(SSL *s, int sess, const unsigned char **pcurves,
+                       size_t *num_curves)
 {
     size_t pcurveslen = 0;
     if (sess) {
@@ -308,7 +306,7 @@ static int tls1_get_curvelist(SSL *s, int sess,
 }
 
 /* See if curve is allowed by security callback */
-static int tls_curve_allowed(SSL *s, const unsigned char *curve, int op)
+int tls_curve_allowed(SSL *s, const unsigned char *curve, int op)
 {
     const tls_curve_info *cinfo;
     if (curve[0])
@@ -597,8 +595,8 @@ static int tls1_check_ec_key(SSL *s,
     return 1;
 }
 
-static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
-                                size_t *num_formats)
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+                         size_t *num_formats)
 {
     /*
      * If we have a custom point format list use it otherwise use default
@@ -940,1982 +938,13 @@ int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op)
     return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
 }
 
-static int tls_use_ticket(SSL *s)
+int tls_use_ticket(SSL *s)
 {
     if ((s->options & SSL_OP_NO_TICKET) || SSL_IS_TLS13(s))
         return 0;
     return ssl_security(s, SSL_SECOP_TICKET, 0, 0, NULL);
 }
 
-static int compare_uint(const void *p1, const void *p2)
-{
-    unsigned int u1 = *((const unsigned int *)p1);
-    unsigned int u2 = *((const unsigned int *)p2);
-    if (u1 < u2)
-        return -1;
-    else if (u1 > u2)
-        return 1;
-    else
-        return 0;
-}
-
-/*
- * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
- * more than one extension of the same type in a ClientHello or ServerHello.
- * This function does an initial scan over the extensions block to filter those
- * out. It returns 1 if all extensions are unique, and 0 if the extensions
- * contain duplicates, could not be successfully parsed, or an internal error
- * occurred.
- */
-static int tls1_check_duplicate_extensions(const PACKET *packet)
-{
-    PACKET extensions = *packet;
-    size_t num_extensions = 0, i = 0;
-    unsigned int *extension_types = NULL;
-    int ret = 0;
-
-    /* First pass: count the extensions. */
-    while (PACKET_remaining(&extensions) > 0) {
-        unsigned int type;
-        PACKET extension;
-        if (!PACKET_get_net_2(&extensions, &type) ||
-            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
-            goto done;
-        }
-        num_extensions++;
-    }
-
-    if (num_extensions <= 1)
-        return 1;
-
-    extension_types = OPENSSL_malloc(sizeof(unsigned int) * num_extensions);
-    if (extension_types == NULL) {
-        SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_MALLOC_FAILURE);
-        goto done;
-    }
-
-    /* Second pass: gather the extension types. */
-    extensions = *packet;
-    for (i = 0; i < num_extensions; i++) {
-        PACKET extension;
-        if (!PACKET_get_net_2(&extensions, &extension_types[i]) ||
-            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
-            /* This should not happen. */
-            SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-            goto done;
-        }
-    }
-
-    if (PACKET_remaining(&extensions) != 0) {
-        SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-        goto done;
-    }
-    /* Sort the extensions and make sure there are no duplicates. */
-    qsort(extension_types, num_extensions, sizeof(unsigned int), compare_uint);
-    for (i = 1; i < num_extensions; i++) {
-        if (extension_types[i - 1] == extension_types[i])
-            goto done;
-    }
-    ret = 1;
- done:
-    OPENSSL_free(extension_types);
-    return ret;
-}
-
-int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
-{
-#ifndef OPENSSL_NO_EC
-    const unsigned char *pcurves = NULL;
-    size_t num_curves = 0;
-    int using_ecc = 0;
-    int min_version, max_version, reason;
-
-    /* See if we support any ECC ciphersuites */
-    if ((s->version >= TLS1_VERSION && s->version <= TLS1_3_VERSION)
-            || SSL_IS_DTLS(s)) {
-        int i;
-        unsigned long alg_k, alg_a;
-        STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
-        for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
-            const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
-            alg_k = c->algorithm_mkey;
-            alg_a = c->algorithm_auth;
-            if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
-                || (alg_a & SSL_aECDSA)
-                || c->min_tls >= TLS1_3_VERSION) {
-                using_ecc = 1;
-                break;
-            }
-        }
-    }
-#else
-    if (SSL_IS_TLS13(s)) {
-        /* Shouldn't happen! */
-        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-#endif
-
-    /* Add RI if renegotiating */
-    if (s->renegotiate) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_sub_memcpy_u8(pkt, s->s3->previous_client_finished,
-                                   s->s3->previous_client_finished_len)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-    /* Only add RI for SSLv3 */
-    if (s->client_version == SSL3_VERSION)
-        goto done;
-
-    if (s->tlsext_hostname != NULL) {
-        /* Add TLS extension servername to the Client Hello message */
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
-                   /* 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_u8(pkt, TLSEXT_NAMETYPE_host_name)
-                || !WPACKET_sub_memcpy_u16(pkt, s->tlsext_hostname,
-                                           strlen(s->tlsext_hostname))
-                || !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) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_srp)
-                   /* 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 0;
-        }
-    }
-#endif
-
-#ifndef OPENSSL_NO_EC
-    if (using_ecc) {
-        /*
-         * Add TLS extension ECPointFormats to the ClientHello message
-         */
-        const unsigned char *pformats, *pcurvestmp;
-        size_t num_formats;
-        size_t i;
-
-        tls1_get_formatlist(s, &pformats, &num_formats);
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
-                   /* Sub-packet for formats extension */
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_sub_memcpy_u8(pkt, pformats, num_formats)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-
-        /*
-         * Add TLS extension supported_groups to the ClientHello message
-         */
-        /* TODO(TLS1.3): Add support for DHE groups */
-        pcurves = s->tlsext_supportedgroupslist;
-        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-        pcurvestmp = pcurves;
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
-                   /* Sub-packet for supported_groups 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++, pcurvestmp += 2) {
-            if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
-                if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
-                    || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
-                        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;
-        }
-    }
-#endif                          /* OPENSSL_NO_EC */
-
-    if (tls_use_ticket(s)) {
-        size_t ticklen;
-        if (!s->new_session && s->session && s->session->tlsext_tick)
-            ticklen = s->session->tlsext_ticklen;
-        else if (s->session && s->tlsext_session_ticket &&
-                 s->tlsext_session_ticket->data) {
-            ticklen = s->tlsext_session_ticket->length;
-            s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-            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;
-        } else
-            ticklen = 0;
-        if (ticklen == 0 && s->tlsext_session_ticket &&
-            s->tlsext_session_ticket->data == NULL)
-            goto skip_ext;
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
-                || !WPACKET_sub_memcpy_u16(pkt, s->session->tlsext_tick,
-                                           ticklen)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
- skip_ext:
-
-    if (SSL_CLIENT_USE_SIGALGS(s)) {
-        size_t salglen;
-        const unsigned char *salg;
-
-        salglen = tls12_get_psigalgs(s, &salg);
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signature_algorithms)
-                   /* 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;
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
-                   /* Sub-packet for status request extension */
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_put_bytes_u8(pkt, TLSEXT_STATUSTYPE_ocsp)
-                   /* 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);
-            idlen = i2d_OCSP_RESPID(id, NULL);
-            if (idlen <= 0
-                       /* Sub-packet for an individual id */
-                    || !WPACKET_sub_allocate_bytes_u16(pkt, idlen, &idbytes)
-                    || i2d_OCSP_RESPID(id, &idbytes) != idlen) {
-                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) {
-            unsigned char *extbytes;
-            int extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
-
-            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;
-        }
-    }
-#endif
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) {
-        /*
-         * The client advertises an empty extension to indicate its support
-         * for Next Protocol Negotiation
-         */
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#endif
-
-    /*
-     * finish_md_len is non-zero during a renegotiation, so
-     * this avoids sending ALPN during the renegotiation
-     * (see longer comment below)
-     */
-    if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) {
-        if (!WPACKET_put_bytes_u16(pkt,
-                    TLSEXT_TYPE_application_layer_protocol_negotiation)
-                   /* Sub-packet ALPN extension */
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_sub_memcpy_u16(pkt, s->alpn_client_proto_list,
-                                           s->alpn_client_proto_list_len)
-                || !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)) {
-        STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
-        SRTP_PROTECTION_PROFILE *prof;
-        int i, ct;
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
-                   /* 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 0;
-        }
-        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_u16(pkt, prof->id)) {
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-        }
-        if (!WPACKET_close(pkt)
-                   /* Add an empty use_mki value */
-                || !WPACKET_put_bytes_u8(pkt, 0)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#endif
-    custom_ext_init(&s->cert->cli_ext);
-    /* Add custom TLS Extensions to ClientHello */
-    if (!custom_ext_add(s, 0, pkt, al)) {
-        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
-            || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-
-#ifndef OPENSSL_NO_CT
-    if (s->ct_validation_callback != NULL) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signed_certificate_timestamp)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#endif
-
-    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
-            || !WPACKET_put_bytes_u16(pkt, 0)) {
-        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    reason = ssl_get_client_min_max_version(s, &min_version, &max_version);
-    if (reason != 0) {
-        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, reason);
-        return 0;
-    }
-
-    /* TLS1.3 specific extensions */
-    if (!SSL_IS_DTLS(s) && max_version >= TLS1_3_VERSION) {
-        int currv;
-        size_t i, sharessent = 0;
-
-        /* TODO(TLS1.3): Should we add this extension for versions < TLS1.3? */
-        /* supported_versions extension */
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_start_sub_packet_u8(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-
-        /*
-         * TODO(TLS1.3): There is some discussion on the TLS list as to wheter
-         * we should include versions <TLS1.2. For the moment we do. To be
-         * reviewed later.
-         */
-        for (currv = max_version; currv >= min_version; currv--) {
-            /* TODO(TLS1.3): Remove this first if clause prior to release!! */
-            if (currv == TLS1_3_VERSION) {
-                if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) {
-                    SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
-                           ERR_R_INTERNAL_ERROR);
-                    return 0;
-                }
-            } else if (!WPACKET_put_bytes_u16(pkt, currv)) {
-                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;
-        }
-
-
-        /* key_share extension */
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
-                   /* Extension data sub-packet */
-                || !WPACKET_start_sub_packet_u16(pkt)
-                   /* KeyShare list sub-packet */
-                || !WPACKET_start_sub_packet_u16(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-
-        /*
-         * TODO(TLS1.3): Make the number of key_shares sent configurable. For
-         * now, just send one
-         */
-        for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
-            unsigned char *encodedPoint = NULL;
-            unsigned int curve_id = 0;
-            EVP_PKEY *key_share_key = NULL;
-            size_t encodedlen;
-
-            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
-                continue;
-
-            if (s->s3->tmp.pkey != NULL) {
-                /* Shouldn't happen! */
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
-                       ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-
-            /* Generate a key for this key_share */
-            curve_id = (pcurves[0] << 8) | pcurves[1];
-            key_share_key = ssl_generate_pkey_curve(curve_id);
-            if (key_share_key == NULL) {
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB);
-                return 0;
-            }
-
-            /* Encode the public key. */
-            encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
-                                                        &encodedPoint);
-            if (encodedlen == 0) {
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_EC_LIB);
-                EVP_PKEY_free(key_share_key);
-                return 0;
-            }
-
-            /* Create KeyShareEntry */
-            if (!WPACKET_put_bytes_u16(pkt, curve_id)
-                    || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
-                       ERR_R_INTERNAL_ERROR);
-                EVP_PKEY_free(key_share_key);
-                OPENSSL_free(encodedPoint);
-                return 0;
-            }
-
-            /*
-             * TODO(TLS1.3): When changing to send more than one key_share we're
-             * going to need to be able to save more than one EVP_PKEY. For now
-             * we reuse the existing tmp.pkey
-             */
-            s->s3->group_id = curve_id;
-            s->s3->tmp.pkey = key_share_key;
-            sharessent++;
-            OPENSSL_free(encodedPoint);
-        }
-        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-
-    /*
-     * Add padding to workaround bugs in F5 terminators. See
-     * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
-     * code works out the length of all existing extensions it MUST always
-     * appear last.
-     */
-    if (s->options & SSL_OP_TLSEXT_PADDING) {
-        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;
-            if (hlen >= 4)
-                hlen -= 4;
-            else
-                hlen = 0;
-
-            if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_padding)
-                    || !WPACKET_sub_allocate_bytes_u16(pkt, hlen, &padbytes)) {
-                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-            memset(padbytes, 0, hlen);
-        }
-    }
-
- done:
-    return 1;
-}
-
-/*
- * Add the key_share extension.
- *
- * Returns 1 on success or 0 on failure.
- */
-static int add_client_key_share_ext(SSL *s, WPACKET *pkt, int *al)
-{
-    unsigned char *encodedPoint;
-    size_t encoded_pt_len = 0;
-    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
-
-    if (ckey == NULL) {
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
-            || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    skey = ssl_generate_pkey(ckey);
-    if (skey == NULL) {
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
-
-    /* Generate encoding of server key */
-    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
-    if (encoded_pt_len == 0) {
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_EC_LIB);
-        EVP_PKEY_free(skey);
-        return 0;
-    }
-
-    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
-            || !WPACKET_close(pkt)) {
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
-        EVP_PKEY_free(skey);
-        OPENSSL_free(encodedPoint);
-        return 0;
-    }
-    OPENSSL_free(encodedPoint);
-
-    /* This causes the crypto state to be updated based on the derived keys */
-    s->s3->tmp.pkey = skey;
-    if (ssl_derive(s, skey, ckey, 1) == 0) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    return 1;
-}
-
-int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
-{
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    int next_proto_neg_seen;
-#endif
-#ifndef OPENSSL_NO_EC
-    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-    unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-    int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
-    using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-#endif
-
-    if (!WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)) {
-        SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    if (s->s3->send_connection_binding &&
-            !ssl_add_serverhello_renegotiate_ext(s, pkt)) {
-        SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    /* Only add RI for SSLv3 */
-    if (s->version == SSL3_VERSION)
-        goto done;
-
-    if (!s->hit && s->servername_done == 1
-            && s->session->tlsext_hostname != NULL) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#ifndef OPENSSL_NO_EC
-    if (using_ecc) {
-        const unsigned char *plist;
-        size_t plistlen;
-        /*
-         * Add TLS extension ECPointFormats to the ServerHello message
-         */
-        tls1_get_formatlist(s, &plist, &plistlen);
-
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-    /*
-     * Currently the server should not respond with a SupportedCurves
-     * extension
-     */
-#endif                          /* OPENSSL_NO_EC */
-
-    if (s->tlsext_ticket_expected && tls_use_ticket(s)) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    } else {
-        /*
-         * if we don't add the above TLSEXT, we can't add a session ticket
-         * later
-         */
-        s->tlsext_ticket_expected = 0;
-    }
-
-    if (s->tlsext_status_expected) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#ifndef OPENSSL_NO_SRTP
-    if (SSL_IS_DTLS(s) && s->srtp_profile) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_put_bytes_u16(pkt, 2)
-                || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
-                || !WPACKET_put_bytes_u8(pkt, 0)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-#endif
-
-    if (((s->s3->tmp.new_cipher->id & 0xFFFF) == 0x80
-         || (s->s3->tmp.new_cipher->id & 0xFFFF) == 0x81)
-        && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) {
-        const unsigned char cryptopro_ext[36] = {
-            0xfd, 0xe8,         /* 65000 */
-            0x00, 0x20,         /* 32 bytes length */
-            0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
-            0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
-            0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
-            0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
-        };
-        if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    next_proto_neg_seen = s->s3->next_proto_neg_seen;
-    s->s3->next_proto_neg_seen = 0;
-    if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) {
-        const unsigned char *npa;
-        unsigned int npalen;
-        int r;
-
-        r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
-                                              s->
-                                              ctx->next_protos_advertised_cb_arg);
-        if (r == SSL_TLSEXT_ERR_OK) {
-            if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
-                    || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
-                SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-            s->s3->next_proto_neg_seen = 1;
-        }
-    }
-#endif
-
-    if (SSL_IS_TLS13(s) && !s->hit && !add_client_key_share_ext(s, pkt, al))
-        return 0;
-
-    if (!custom_ext_add(s, 1, pkt, al)) {
-        SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
-        /*
-         * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
-         * for other cases too.
-         */
-        if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
-            || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
-            || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
-            || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12)
-            s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
-        else {
-            if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
-                    || !WPACKET_put_bytes_u16(pkt, 0)) {
-                SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-        }
-    }
-    if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
-        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
-                || !WPACKET_put_bytes_u16(pkt, 0)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-
-    if (s->s3->alpn_selected != NULL) {
-        if (!WPACKET_put_bytes_u16(pkt,
-                    TLSEXT_TYPE_application_layer_protocol_negotiation)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_start_sub_packet_u16(pkt)
-                || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
-                                          s->s3->alpn_selected_len)
-                || !WPACKET_close(pkt)
-                || !WPACKET_close(pkt)) {
-            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-    }
-
- done:
-    if (!WPACKET_close(pkt)) {
-        SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-    return 1;
-}
-
-/*
- * Save the ALPN extension in a ClientHello.
- * pkt: the contents of the ALPN extension, not including type and length.
- * al: a pointer to the  alert value to send in the event of a failure.
- * returns: 1 on success, 0 on error.
- */
-static int tls1_alpn_handle_client_hello(SSL *s, PACKET *pkt, int *al)
-{
-    PACKET protocol_list, save_protocol_list, protocol;
-
-    *al = SSL_AD_DECODE_ERROR;
-
-    if (!PACKET_as_length_prefixed_2(pkt, &protocol_list)
-        || PACKET_remaining(&protocol_list) < 2) {
-        return 0;
-    }
-
-    save_protocol_list = protocol_list;
-    do {
-        /* Protocol names can't be empty. */
-        if (!PACKET_get_length_prefixed_1(&protocol_list, &protocol)
-            || PACKET_remaining(&protocol) == 0) {
-            return 0;
-        }
-    } while (PACKET_remaining(&protocol_list) != 0);
-
-    if (!PACKET_memdup(&save_protocol_list,
-                       &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) {
-        *al = TLS1_AD_INTERNAL_ERROR;
-        return 0;
-    }
-
-    return 1;
-}
-
-/*
- * Process the ALPN extension in a ClientHello.
- * al: a pointer to the alert value to send in the event of a failure.
- * returns 1 on success, 0 on error.
- */
-static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
-{
-    const unsigned char *selected = NULL;
-    unsigned char selected_len = 0;
-
-    if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
-        int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
-                                       s->s3->alpn_proposed,
-                                       (unsigned int)s->s3->alpn_proposed_len,
-                                       s->ctx->alpn_select_cb_arg);
-
-        if (r == SSL_TLSEXT_ERR_OK) {
-            OPENSSL_free(s->s3->alpn_selected);
-            s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
-            if (s->s3->alpn_selected == NULL) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                return 0;
-            }
-            s->s3->alpn_selected_len = selected_len;
-#ifndef OPENSSL_NO_NEXTPROTONEG
-            /* ALPN takes precedence over NPN. */
-            s->s3->next_proto_neg_seen = 0;
-#endif
-        } else {
-            *al = SSL_AD_NO_APPLICATION_PROTOCOL;
-            return 0;
-        }
-    }
-
-    return 1;
-}
-
-#ifndef OPENSSL_NO_EC
-/*-
- * ssl_check_for_safari attempts to fingerprint Safari using OS X
- * SecureTransport using the TLS extension block in |hello|.
- * Safari, since 10.6, sends exactly these extensions, in this order:
- *   SNI,
- *   elliptic_curves
- *   ec_point_formats
- *
- * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
- * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
- * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
- * 10.8..10.8.3 (which don't work).
- */
-static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
-{
-    unsigned int type;
-    PACKET sni, tmppkt;
-    size_t ext_len;
-
-    static const unsigned char kSafariExtensionsBlock[] = {
-        0x00, 0x0a,             /* elliptic_curves extension */
-        0x00, 0x08,             /* 8 bytes */
-        0x00, 0x06,             /* 6 bytes of curve ids */
-        0x00, 0x17,             /* P-256 */
-        0x00, 0x18,             /* P-384 */
-        0x00, 0x19,             /* P-521 */
-
-        0x00, 0x0b,             /* ec_point_formats */
-        0x00, 0x02,             /* 2 bytes */
-        0x01,                   /* 1 point format */
-        0x00,                   /* uncompressed */
-        /* The following is only present in TLS 1.2 */
-        0x00, 0x0d,             /* signature_algorithms */
-        0x00, 0x0c,             /* 12 bytes */
-        0x00, 0x0a,             /* 10 bytes */
-        0x05, 0x01,             /* SHA-384/RSA */
-        0x04, 0x01,             /* SHA-256/RSA */
-        0x02, 0x01,             /* SHA-1/RSA */
-        0x04, 0x03,             /* SHA-256/ECDSA */
-        0x02, 0x03,             /* SHA-1/ECDSA */
-    };
-
-    /* Length of the common prefix (first two extensions). */
-    static const size_t kSafariCommonExtensionsLength = 18;
-
-    tmppkt = hello->extensions;
-
-    if (!PACKET_forward(&tmppkt, 2)
-        || !PACKET_get_net_2(&tmppkt, &type)
-        || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) {
-        return;
-    }
-
-    if (type != TLSEXT_TYPE_server_name)
-        return;
-
-    ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ?
-        sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength;
-
-    s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock,
-                                             ext_len);
-}
-#endif                          /* !OPENSSL_NO_EC */
-
-
-/*
- * Process the supported_groups extension if present. Returns success if the
- * extension is absent, or if it has been successfully processed.
- *
- * Returns 1 on success or 0 on failure
- */
-static int tls_process_supported_groups(SSL *s, CLIENTHELLO_MSG *hello)
-{
-#ifndef OPENSSL_NO_EC
-    PACKET supported_groups_list;
-    RAW_EXTENSION *suppgroups = tls_get_extension_by_type(hello->pre_proc_exts,
-                                    hello->num_extensions,
-                                    TLSEXT_TYPE_supported_groups);
-
-    if (suppgroups == NULL)
-        return 1;
-
-    /* Each group is 2 bytes and we must have at least 1. */
-    if (!PACKET_as_length_prefixed_2(&suppgroups->data,
-                                     &supported_groups_list)
-        || PACKET_remaining(&supported_groups_list) == 0
-        || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
-        return 0;
-    }
-
-    if (!s->hit
-            && !PACKET_memdup(&supported_groups_list,
-                              &s->session->tlsext_supportedgroupslist,
-                              &s->session->tlsext_supportedgroupslist_length)) {
-        return 0;
-    }
-#endif
-    return 1;
-}
-
-/*
- * Checks a list of |groups| to determine if the |group_id| is in it. If it is
- * and |checkallow| is 1 then additionally check if the group is allowed to be
- * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
- * 1) or 0 otherwise.
- */
-static int check_in_list(SSL *s, unsigned int group_id,
-                         const unsigned char *groups, size_t num_groups,
-                         int checkallow)
-{
-    size_t i;
-
-    if (groups == NULL || num_groups == 0)
-        return 0;
-
-    for (i = 0; i < num_groups; i++, groups += 2) {
-        unsigned int share_id = (groups[0] << 8) | (groups[1]);
-
-        if (group_id == share_id
-                && (!checkallow || tls_curve_allowed(s, groups,
-                                                     SSL_SECOP_CURVE_CHECK))) {
-            break;
-        }
-    }
-
-    /* If i == num_groups then not in the list */
-    return i < num_groups;
-}
-
-/*
- * Process a key_share extension received in the ClientHello. |pkt| contains
- * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
- * If a failure occurs then |*al| is set to an appropriate alert value.
- */
-static int process_key_share_ext(SSL *s, PACKET *pkt, int *al)
-{
-    unsigned int group_id;
-    PACKET key_share_list, encoded_pt;
-    const unsigned char *clntcurves, *srvrcurves;
-    size_t clnt_num_curves, srvr_num_curves;
-    int group_nid, found = 0;
-    unsigned int curve_flags;
-
-    /* Sanity check */
-    if (s->s3->peer_tmp != NULL) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) {
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-               SSL_R_LENGTH_MISMATCH);
-        return 0;
-    }
-
-    /* Get our list of supported curves */
-    if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-               ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    /* Get the clients list of supported curves */
-    if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-               ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    while (PACKET_remaining(&key_share_list) > 0) {
-        if (!PACKET_get_net_2(&key_share_list, &group_id)
-                || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt)
-                || PACKET_remaining(&encoded_pt) == 0) {
-            *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-                   SSL_R_LENGTH_MISMATCH);
-            return 0;
-        }
-
-        /*
-         * If we already found a suitable key_share we loop through the
-         * rest to verify the structure, but don't process them.
-         */
-        if (found)
-            continue;
-
-        /* Check if this share is in supported_groups sent from client */
-        if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) {
-            *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-                   SSL_R_BAD_KEY_SHARE);
-            return 0;
-        }
-
-        /* Check if this share is for a group we can use */
-        if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) {
-            /* Share not suitable */
-            continue;
-        }
-
-        group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags);
-
-        if (group_nid == 0) {
-            *al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
-                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
-            return 0;
-        }
-
-        if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
-            /* Can happen for some curves, e.g. X25519 */
-            EVP_PKEY *key = EVP_PKEY_new();
-
-            if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_EVP_LIB);
-                EVP_PKEY_free(key);
-                return 0;
-            }
-            s->s3->peer_tmp = key;
-        } else {
-            /* Set up EVP_PKEY with named curve as parameters */
-            EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
-            if (pctx == NULL
-                    || EVP_PKEY_paramgen_init(pctx) <= 0
-                    || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
-                                                              group_nid) <= 0
-                    || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_EVP_LIB);
-                EVP_PKEY_CTX_free(pctx);
-                return 0;
-            }
-            EVP_PKEY_CTX_free(pctx);
-            pctx = NULL;
-        }
-        s->s3->group_id = group_id;
-
-        if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
-                PACKET_data(&encoded_pt),
-                PACKET_remaining(&encoded_pt))) {
-            *al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, SSL_R_BAD_ECPOINT);
-            return 0;
-        }
-
-        found = 1;
-    }
-
-    return 1;
-}
-
-/*
- * Loop through all remaining ClientHello extensions that we collected earlier
- * and haven't already processed. For each one parse it and update the SSL
- * object as required.
- *
- * Behaviour upon resumption is extension-specific. If the extension has no
- * effect during resumption, it is parsed (to verify its format) but otherwise
- * ignored.
- *
- * Returns 1 on success and 0 on failure.
- * Upon failure, sets |al| to the appropriate alert.
- */
-static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
-{
-    size_t loop;
-    int renegotiate_seen = 0;
-
-    *al = SSL_AD_DECODE_ERROR;
-    s->servername_done = 0;
-    s->tlsext_status_type = -1;
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    s->s3->next_proto_neg_seen = 0;
-#endif
-
-    OPENSSL_free(s->s3->alpn_selected);
-    s->s3->alpn_selected = NULL;
-    s->s3->alpn_selected_len = 0;
-    OPENSSL_free(s->s3->alpn_proposed);
-    s->s3->alpn_proposed = NULL;
-    s->s3->alpn_proposed_len = 0;
-
-#ifndef OPENSSL_NO_EC
-    if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
-        ssl_check_for_safari(s, hello);
-#endif                          /* !OPENSSL_NO_EC */
-
-    /* Clear any signature algorithms extension received */
-    OPENSSL_free(s->s3->tmp.peer_sigalgs);
-    s->s3->tmp.peer_sigalgs = NULL;
-    s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
-
-#ifndef OPENSSL_NO_SRP
-    OPENSSL_free(s->srp_ctx.login);
-    s->srp_ctx.login = NULL;
-#endif
-
-    s->srtp_profile = NULL;
-
-    /*
-     * We process the supported_groups extension first so that is done before
-     * we get to key_share which needs to use the information in it.
-     */
-    if (!tls_process_supported_groups(s, hello)) {
-        *al = TLS1_AD_INTERNAL_ERROR;
-        return 0;
-    }
-
-    /*
-     * We parse all extensions to ensure the ClientHello is well-formed but,
-     * unless an extension specifies otherwise, we ignore extensions upon
-     * resumption.
-     */
-    for (loop = 0; loop < hello->num_extensions; loop++) {
-        RAW_EXTENSION *currext = &hello->pre_proc_exts[loop];
-
-        if (s->tlsext_debug_cb)
-            s->tlsext_debug_cb(s, 0, currext->type,
-                               PACKET_data(&currext->data),
-                               PACKET_remaining(&currext->data),
-                               s->tlsext_debug_arg);
-
-        if (currext->type == TLSEXT_TYPE_renegotiate) {
-            if (!ssl_parse_clienthello_renegotiate_ext(s,
-                    &currext->data, al))
-                return 0;
-            renegotiate_seen = 1;
-        } else if (s->version == SSL3_VERSION) {
-        }
-/*-
- * The servername extension is treated as follows:
- *
- * - Only the hostname type is supported with a maximum length of 255.
- * - The servername is rejected if too long or if it contains zeros,
- *   in which case an fatal alert is generated.
- * - The servername field is maintained together with the session cache.
- * - When a session is resumed, the servername call back invoked in order
- *   to allow the application to position itself to the right context.
- * - The servername is acknowledged if it is new for a session or when
- *   it is identical to a previously used for the same session.
- *   Applications can control the behaviour.  They can at any time
- *   set a 'desirable' servername for a new SSL object. This can be the
- *   case for example with HTTPS when a Host: header field is received and
- *   a renegotiation is requested. In this case, a possible servername
- *   presented in the new client hello is only acknowledged if it matches
- *   the value of the Host: field.
- * - Applications must  use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
- *   if they provide for changing an explicit servername context for the
- *   session, i.e. when the session has been established with a servername
- *   extension.
- * - On session reconnect, the servername extension may be absent.
- *
- */
-
-        else if (currext->type == TLSEXT_TYPE_server_name) {
-            unsigned int servname_type;
-            PACKET sni, hostname;
-
-            if (!PACKET_as_length_prefixed_2(&currext->data, &sni)
-                /* ServerNameList must be at least 1 byte long. */
-                || PACKET_remaining(&sni) == 0) {
-                return 0;
-            }
-
-            /*
-             * Although the server_name extension was intended to be
-             * extensible to new name types, RFC 4366 defined the
-             * syntax inextensibility and OpenSSL 1.0.x parses it as
-             * such.
-             * RFC 6066 corrected the mistake but adding new name types
-             * is nevertheless no longer feasible, so act as if no other
-             * SNI types can exist, to simplify parsing.
-             *
-             * Also note that the RFC permits only one SNI value per type,
-             * i.e., we can only have a single hostname.
-             */
-            if (!PACKET_get_1(&sni, &servname_type)
-                || servname_type != TLSEXT_NAMETYPE_host_name
-                || !PACKET_as_length_prefixed_2(&sni, &hostname)) {
-                return 0;
-            }
-
-            if (!s->hit) {
-                if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) {
-                    *al = TLS1_AD_UNRECOGNIZED_NAME;
-                    return 0;
-                }
-
-                if (PACKET_contains_zero_byte(&hostname)) {
-                    *al = TLS1_AD_UNRECOGNIZED_NAME;
-                    return 0;
-                }
-
-                if (!PACKET_strndup(&hostname, &s->session->tlsext_hostname)) {
-                    *al = TLS1_AD_INTERNAL_ERROR;
-                    return 0;
-                }
-
-                s->servername_done = 1;
-            } else {
-                /*
-                 * TODO(openssl-team): if the SNI doesn't match, we MUST
-                 * fall back to a full handshake.
-                 */
-                s->servername_done = s->session->tlsext_hostname
-                    && PACKET_equal(&hostname, s->session->tlsext_hostname,
-                                    strlen(s->session->tlsext_hostname));
-            }
-        }
-#ifndef OPENSSL_NO_SRP
-        else if (currext->type == TLSEXT_TYPE_srp) {
-            PACKET srp_I;
-
-            if (!PACKET_as_length_prefixed_1(&currext->data, &srp_I))
-                return 0;
-
-            if (PACKET_contains_zero_byte(&srp_I))
-                return 0;
-
-            /*
-             * TODO(openssl-team): currently, we re-authenticate the user
-             * upon resumption. Instead, we MUST ignore the login.
-             */
-            if (!PACKET_strndup(&srp_I, &s->srp_ctx.login)) {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-        }
-#endif
-
-#ifndef OPENSSL_NO_EC
-        else if (currext->type == TLSEXT_TYPE_ec_point_formats) {
-            PACKET ec_point_format_list;
-
-            if (!PACKET_as_length_prefixed_1(&currext->data,
-                                             &ec_point_format_list)
-                || PACKET_remaining(&ec_point_format_list) == 0) {
-                return 0;
-            }
-
-            if (!s->hit) {
-                if (!PACKET_memdup(&ec_point_format_list,
-                                   &s->session->tlsext_ecpointformatlist,
-                                   &s->
-                                   session->tlsext_ecpointformatlist_length)) {
-                    *al = TLS1_AD_INTERNAL_ERROR;
-                    return 0;
-                }
-            }
-        }
-#endif                          /* OPENSSL_NO_EC */
-        else if (currext->type == TLSEXT_TYPE_session_ticket
-                && !SSL_IS_TLS13(s)) {
-            if (s->tls_session_ticket_ext_cb &&
-                !s->tls_session_ticket_ext_cb(s,
-                    PACKET_data(&currext->data),
-                    PACKET_remaining(&currext->data),
-                    s->tls_session_ticket_ext_cb_arg)) {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-        } else if (currext->type == TLSEXT_TYPE_signature_algorithms) {
-            PACKET supported_sig_algs;
-
-            if (!PACKET_as_length_prefixed_2(&currext->data,
-                                             &supported_sig_algs)
-                || (PACKET_remaining(&supported_sig_algs) % 2) != 0
-                || PACKET_remaining(&supported_sig_algs) == 0) {
-                return 0;
-            }
-
-            if (!s->hit) {
-                if (!tls1_save_sigalgs(s, PACKET_data(&supported_sig_algs),
-                                       PACKET_remaining(&supported_sig_algs))) {
-                    return 0;
-                }
-            }
-        } else if (currext->type == TLSEXT_TYPE_status_request) {
-            if (!PACKET_get_1(&currext->data,
-                              (unsigned int *)&s->tlsext_status_type)) {
-                return 0;
-            }
-#ifndef OPENSSL_NO_OCSP
-            if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
-                const unsigned char *ext_data;
-                PACKET responder_id_list, exts;
-                if (!PACKET_get_length_prefixed_2
-                    (&currext->data, &responder_id_list))
-                    return 0;
-
-                /*
-                 * We remove any OCSP_RESPIDs from a previous handshake
-                 * to prevent unbounded memory growth - CVE-2016-6304
-                 */
-                sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids,
-                                        OCSP_RESPID_free);
-                if (PACKET_remaining(&responder_id_list) > 0) {
-                    s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
-                    if (s->tlsext_ocsp_ids == NULL) {
-                        *al = SSL_AD_INTERNAL_ERROR;
-                        return 0;
-                    }
-                } else {
-                    s->tlsext_ocsp_ids = NULL;
-                }
-
-                while (PACKET_remaining(&responder_id_list) > 0) {
-                    OCSP_RESPID *id;
-                    PACKET responder_id;
-                    const unsigned char *id_data;
-
-                    if (!PACKET_get_length_prefixed_2(&responder_id_list,
-                                                      &responder_id)
-                        || PACKET_remaining(&responder_id) == 0) {
-                        return 0;
-                    }
-
-                    id_data = PACKET_data(&responder_id);
-                    /* TODO(size_t): Convert d2i_* to size_t */
-                    id = d2i_OCSP_RESPID(NULL, &id_data,
-                                         (int)PACKET_remaining(&responder_id));
-                    if (id == NULL)
-                        return 0;
-
-                    if (id_data != PACKET_end(&responder_id)) {
-                        OCSP_RESPID_free(id);
-                        return 0;
-                    }
-
-                    if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) {
-                        OCSP_RESPID_free(id);
-                        *al = SSL_AD_INTERNAL_ERROR;
-                        return 0;
-                    }
-                }
-
-                /* Read in request_extensions */
-                if (!PACKET_as_length_prefixed_2(
-                        &currext->data, &exts))
-                    return 0;
-
-                if (PACKET_remaining(&exts) > 0) {
-                    ext_data = PACKET_data(&exts);
-                    sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
-                                               X509_EXTENSION_free);
-                    s->tlsext_ocsp_exts =
-                        d2i_X509_EXTENSIONS(NULL, &ext_data,
-                                            (int)PACKET_remaining(&exts));
-                    if (s->tlsext_ocsp_exts == NULL
-                        || ext_data != PACKET_end(&exts)) {
-                        return 0;
-                    }
-                }
-            } else
-#endif
-            {
-                /*
-                 * We don't know what to do with any other type so ignore it.
-                 */
-                s->tlsext_status_type = -1;
-            }
-        }
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        else if (currext->type == TLSEXT_TYPE_next_proto_neg
-                 && s->s3->tmp.finish_md_len == 0) {
-            /*-
-             * We shouldn't accept this extension on a
-             * renegotiation.
-             *
-             * s->new_session will be set on renegotiation, but we
-             * probably shouldn't rely that it couldn't be set on
-             * the initial renegotiation too in certain cases (when
-             * there's some other reason to disallow resuming an
-             * earlier session -- the current code won't be doing
-             * anything like that, but this might change).
-             *
-             * A valid sign that there's been a previous handshake
-             * in this connection is if s->s3->tmp.finish_md_len >
-             * 0.  (We are talking about a check that will happen
-             * in the Hello protocol round, well before a new
-             * Finished message could have been computed.)
-             */
-            s->s3->next_proto_neg_seen = 1;
-        }
-#endif
-
-        else if (currext->type
-                     == TLSEXT_TYPE_application_layer_protocol_negotiation
-                 && s->s3->tmp.finish_md_len == 0) {
-            if (!tls1_alpn_handle_client_hello(s,
-                    &currext->data, al))
-                return 0;
-        }
-
-        /* session ticket processed earlier */
-#ifndef OPENSSL_NO_SRTP
-        else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
-                 && currext->type == TLSEXT_TYPE_use_srtp) {
-            if (ssl_parse_clienthello_use_srtp_ext(s,
-                    &currext->data, al))
-                return 0;
-        }
-#endif
-        else if (currext->type == TLSEXT_TYPE_encrypt_then_mac
-                 && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) {
-            s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
-        } else if (currext->type == TLSEXT_TYPE_key_share
-                   && SSL_IS_TLS13(s) && !s->hit
-                   && !process_key_share_ext(s, &currext->data, al)) {
-            return 0;
-        }
-        /*
-         * Note: extended master secret extension handled in
-         * tls_check_client_ems_support()
-         */
-
-        /*
-         * If this ClientHello extension was unhandled and this is a
-         * nonresumed connection, check whether the extension is a custom
-         * TLS Extension (has a custom_srv_ext_record), and if so call the
-         * callback and record the extension number so that an appropriate
-         * ServerHello may be later returned.
-         */
-        else if (!s->hit) {
-            if (custom_ext_parse(s, 1, currext->type,
-                    PACKET_data(&currext->data),
-                    PACKET_remaining(&currext->data), al) <= 0)
-                return 0;
-        }
-    }
-
-    /* Need RI if renegotiating */
-
-    if (!renegotiate_seen && s->renegotiate &&
-        !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
-               SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-        return 0;
-    }
-
-    /*
-     * This function currently has no state to clean up, so it returns directly.
-     * If parsing fails at any point, the function returns early.
-     * The SSL object may be left with partial data from extensions, but it must
-     * then no longer be used, and clearing it up will free the leftovers.
-     */
-    return 1;
-}
-
-int ssl_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello)
-{
-    int al = -1;
-    custom_ext_init(&s->cert->srv_ext);
-    if (ssl_scan_clienthello_tlsext(s, hello, &al) <= 0) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        return 0;
-    }
-    if (ssl_check_clienthello_tlsext_early(s) <= 0) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_CLIENTHELLO_TLSEXT);
-        return 0;
-    }
-    return 1;
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/*
- * ssl_next_proto_validate validates a Next Protocol Negotiation block. No
- * elements of zero length are allowed and the set of elements must exactly
- * fill the length of the block.
- */
-static char ssl_next_proto_validate(PACKET *pkt)
-{
-    PACKET tmp_protocol;
-
-    while (PACKET_remaining(pkt)) {
-        if (!PACKET_get_length_prefixed_1(pkt, &tmp_protocol)
-            || PACKET_remaining(&tmp_protocol) == 0)
-            return 0;
-    }
-
-    return 1;
-}
-#endif
-
-static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
-{
-    unsigned int length, type, size;
-    int tlsext_servername = 0;
-    int renegotiate_seen = 0;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    s->s3->next_proto_neg_seen = 0;
-#endif
-    s->tlsext_ticket_expected = 0;
-
-    OPENSSL_free(s->s3->alpn_selected);
-    s->s3->alpn_selected = NULL;
-
-    s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
-
-    s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
-
-    if (!PACKET_get_net_2(pkt, &length))
-        goto ri_check;
-
-    if (PACKET_remaining(pkt) != length) {
-        *al = SSL_AD_DECODE_ERROR;
-        return 0;
-    }
-
-    if (!tls1_check_duplicate_extensions(pkt)) {
-        *al = SSL_AD_DECODE_ERROR;
-        return 0;
-    }
-
-    while (PACKET_get_net_2(pkt, &type) && PACKET_get_net_2(pkt, &size)) {
-        const unsigned char *data;
-        PACKET spkt;
-
-        if (!PACKET_get_sub_packet(pkt, &spkt, size)
-            || !PACKET_peek_bytes(&spkt, &data, size))
-            goto ri_check;
-
-        if (s->tlsext_debug_cb)
-            s->tlsext_debug_cb(s, 1, type, data, size, s->tlsext_debug_arg);
-
-        if (type == TLSEXT_TYPE_renegotiate) {
-            if (!ssl_parse_serverhello_renegotiate_ext(s, &spkt, al))
-                return 0;
-            renegotiate_seen = 1;
-        } else if (s->version == SSL3_VERSION) {
-        } else if (type == TLSEXT_TYPE_server_name) {
-            if (s->tlsext_hostname == NULL || size > 0) {
-                *al = TLS1_AD_UNRECOGNIZED_NAME;
-                return 0;
-            }
-            tlsext_servername = 1;
-        }
-#ifndef OPENSSL_NO_EC
-        else if (type == TLSEXT_TYPE_ec_point_formats) {
-            unsigned int ecpointformatlist_length;
-            if (!PACKET_get_1(&spkt, &ecpointformatlist_length)
-                || ecpointformatlist_length != size - 1) {
-                *al = TLS1_AD_DECODE_ERROR;
-                return 0;
-            }
-            if (!s->hit) {
-                s->session->tlsext_ecpointformatlist_length = 0;
-                OPENSSL_free(s->session->tlsext_ecpointformatlist);
-                if ((s->session->tlsext_ecpointformatlist =
-                     OPENSSL_malloc(ecpointformatlist_length)) == NULL) {
-                    *al = TLS1_AD_INTERNAL_ERROR;
-                    return 0;
-                }
-                s->session->tlsext_ecpointformatlist_length =
-                    ecpointformatlist_length;
-                if (!PACKET_copy_bytes(&spkt,
-                                       s->session->tlsext_ecpointformatlist,
-                                       ecpointformatlist_length)) {
-                    *al = TLS1_AD_DECODE_ERROR;
-                    return 0;
-                }
-
-            }
-        }
-#endif                          /* OPENSSL_NO_EC */
-
-        else if (type == TLSEXT_TYPE_session_ticket) {
-            if (s->tls_session_ticket_ext_cb &&
-                !s->tls_session_ticket_ext_cb(s, data, size,
-                                              s->tls_session_ticket_ext_cb_arg))
-            {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-            if (!tls_use_ticket(s) || (size > 0)) {
-                *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-                return 0;
-            }
-            s->tlsext_ticket_expected = 1;
-        } else if (type == TLSEXT_TYPE_status_request) {
-            /*
-             * MUST be empty and only sent if we've requested a status
-             * request message.
-             */
-            if ((s->tlsext_status_type == -1) || (size > 0)) {
-                *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-                return 0;
-            }
-            /* Set flag to expect CertificateStatus message */
-            s->tlsext_status_expected = 1;
-        }
-#ifndef OPENSSL_NO_CT
-        /*
-         * Only take it if we asked for it - i.e if there is no CT validation
-         * callback set, then a custom extension MAY be processing it, so we
-         * need to let control continue to flow to that.
-         */
-        else if (type == TLSEXT_TYPE_signed_certificate_timestamp &&
-                 s->ct_validation_callback != NULL) {
-            /* Simply copy it off for later processing */
-            if (s->tlsext_scts != NULL) {
-                OPENSSL_free(s->tlsext_scts);
-                s->tlsext_scts = NULL;
-            }
-            s->tlsext_scts_len = size;
-            if (size > 0) {
-                s->tlsext_scts = OPENSSL_malloc(size);
-                if (s->tlsext_scts == NULL) {
-                    *al = TLS1_AD_INTERNAL_ERROR;
-                    return 0;
-                }
-                memcpy(s->tlsext_scts, data, size);
-            }
-        }
-#endif
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        else if (type == TLSEXT_TYPE_next_proto_neg &&
-                 s->s3->tmp.finish_md_len == 0) {
-            unsigned char *selected;
-            unsigned char selected_len;
-            /* We must have requested it. */
-            if (s->ctx->next_proto_select_cb == NULL) {
-                *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-                return 0;
-            }
-            /* The data must be valid */
-            if (!ssl_next_proto_validate(&spkt)) {
-                *al = TLS1_AD_DECODE_ERROR;
-                return 0;
-            }
-            if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data,
-                                             size,
-                                             s->
-                                             ctx->next_proto_select_cb_arg) !=
-                SSL_TLSEXT_ERR_OK) {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-            /*
-             * Could be non-NULL if server has sent multiple NPN extensions in
-             * a single Serverhello
-             */
-            OPENSSL_free(s->next_proto_negotiated);
-            s->next_proto_negotiated = OPENSSL_malloc(selected_len);
-            if (s->next_proto_negotiated == NULL) {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-            memcpy(s->next_proto_negotiated, selected, selected_len);
-            s->next_proto_negotiated_len = selected_len;
-            s->s3->next_proto_neg_seen = 1;
-        }
-#endif
-
-        else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) {
-            unsigned len;
-            /* We must have requested it. */
-            if (!s->s3->alpn_sent) {
-                *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-                return 0;
-            }
-            /*-
-             * The extension data consists of:
-             *   uint16 list_length
-             *   uint8 proto_length;
-             *   uint8 proto[proto_length];
-             */
-            if (!PACKET_get_net_2(&spkt, &len)
-                || PACKET_remaining(&spkt) != len || !PACKET_get_1(&spkt, &len)
-                || PACKET_remaining(&spkt) != len) {
-                *al = TLS1_AD_DECODE_ERROR;
-                return 0;
-            }
-            OPENSSL_free(s->s3->alpn_selected);
-            s->s3->alpn_selected = OPENSSL_malloc(len);
-            if (s->s3->alpn_selected == NULL) {
-                *al = TLS1_AD_INTERNAL_ERROR;
-                return 0;
-            }
-            if (!PACKET_copy_bytes(&spkt, s->s3->alpn_selected, len)) {
-                *al = TLS1_AD_DECODE_ERROR;
-                return 0;
-            }
-            s->s3->alpn_selected_len = len;
-        }
-#ifndef OPENSSL_NO_SRTP
-        else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) {
-            if (ssl_parse_serverhello_use_srtp_ext(s, &spkt, al))
-                return 0;
-        }
-#endif
-        else if (type == TLSEXT_TYPE_encrypt_then_mac) {
-            /* Ignore if inappropriate ciphersuite */
-            if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC) &&
-                s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
-                && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4)
-                s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
-        } else if (type == TLSEXT_TYPE_extended_master_secret &&
-                (SSL_IS_DTLS(s) || !SSL_IS_TLS13(s))) {
-            s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
-            if (!s->hit)
-                s->session->flags |= SSL_SESS_FLAG_EXTMS;
-        } else if (type == TLSEXT_TYPE_key_share
-                && SSL_IS_TLS13(s)) {
-            unsigned int group_id;
-            PACKET encoded_pt;
-            EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;
-
-            /* Sanity check */
-            if (ckey == NULL) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                return 0;
-            }
-
-            if (!PACKET_get_net_2(&spkt, &group_id)) {
-                *al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
-                       SSL_R_LENGTH_MISMATCH);
-                return 0;
-            }
-
-            if (group_id != s->s3->group_id) {
-                /*
-                 * This isn't for the group that we sent in the original
-                 * key_share!
-                 */
-                *al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
-                       SSL_R_BAD_KEY_SHARE);
-                return 0;
-            }
-
-            if (!PACKET_as_length_prefixed_2(&spkt, &encoded_pt)
-                    || PACKET_remaining(&encoded_pt) == 0) {
-                *al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
-                       SSL_R_LENGTH_MISMATCH);
-                return 0;
-            }
-
-            skey = ssl_generate_pkey(ckey);
-            if (skey == NULL) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_MALLOC_FAILURE);
-                return 0;
-            }
-            if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
-                                                PACKET_remaining(&encoded_pt))) {
-                *al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_BAD_ECPOINT);
-                return 0;
-            }
-
-            if (ssl_derive(s, ckey, skey, 1) == 0) {
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
-                EVP_PKEY_free(skey);
-                return 0;
-            }
-            EVP_PKEY_free(skey);
-        /*
-         * If this extension type was not otherwise handled, but matches a
-         * custom_cli_ext_record, then send it to the c callback
-         */
-        } else if (custom_ext_parse(s, 0, type, data, size, al) <= 0)
-            return 0;
-    }
-
-    if (PACKET_remaining(pkt) != 0) {
-        *al = SSL_AD_DECODE_ERROR;
-        return 0;
-    }
-
-    if (!s->hit && tlsext_servername == 1) {
-        if (s->tlsext_hostname) {
-            if (s->session->tlsext_hostname == NULL) {
-                s->session->tlsext_hostname =
-                    OPENSSL_strdup(s->tlsext_hostname);
-                if (!s->session->tlsext_hostname) {
-                    *al = SSL_AD_UNRECOGNIZED_NAME;
-                    return 0;
-                }
-            } else {
-                *al = SSL_AD_DECODE_ERROR;
-                return 0;
-            }
-        }
-    }
-
- ri_check:
-
-    /*
-     * Determine if we need to see RI. Strictly speaking if we want to avoid
-     * an attack we should *always* see RI even on initial server hello
-     * because the client doesn't see any renegotiation during an attack.
-     * However this would mean we could not connect to any server which
-     * doesn't support RI so for the immediate future tolerate RI absence
-     */
-    if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
-        && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
-               SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-        return 0;
-    }
-
-    if (s->hit) {
-        /*
-         * Check extended master secret extension is consistent with
-         * original session.
-         */
-        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) !=
-            !(s->session->flags & SSL_SESS_FLAG_EXTMS)) {
-            *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_INCONSISTENT_EXTMS);
-            return 0;
-        }
-    }
-
-    return 1;
-}
-
-int ssl_prepare_clienthello_tlsext(SSL *s)
-{
-    s->s3->alpn_sent = 0;
-    return 1;
-}
-
-int ssl_prepare_serverhello_tlsext(SSL *s)
-{
-    return 1;
-}
-
-static int ssl_check_clienthello_tlsext_early(SSL *s)
-{
-    int ret = SSL_TLSEXT_ERR_NOACK;
-    int al = SSL_AD_UNRECOGNIZED_NAME;
-
-#ifndef OPENSSL_NO_EC
-    /*
-     * The handling of the ECPointFormats extension is done elsewhere, namely
-     * in ssl3_choose_cipher in s3_lib.c.
-     */
-    /*
-     * The handling of the EllipticCurves extension is done elsewhere, namely
-     * in ssl3_choose_cipher in s3_lib.c.
-     */
-#endif
-
-    if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
-        ret =
-            s->ctx->tlsext_servername_callback(s, &al,
-                                               s->ctx->tlsext_servername_arg);
-    else if (s->initial_ctx != NULL
-             && s->initial_ctx->tlsext_servername_callback != 0)
-        ret =
-            s->initial_ctx->tlsext_servername_callback(s, &al,
-                                                       s->
-                                                       initial_ctx->tlsext_servername_arg);
-
-    switch (ret) {
-    case SSL_TLSEXT_ERR_ALERT_FATAL:
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        return -1;
-
-    case SSL_TLSEXT_ERR_ALERT_WARNING:
-        ssl3_send_alert(s, SSL3_AL_WARNING, al);
-        return 1;
-
-    case SSL_TLSEXT_ERR_NOACK:
-        s->servername_done = 0;
-    default:
-        return 1;
-    }
-}
-
 /* Initialise digests to default values */
 void ssl_set_default_md(SSL *s)
 {
@@ -2979,148 +1008,6 @@ int tls1_set_server_sigalgs(SSL *s)
 }
 
 /*
- * Upon success, returns 1.
- * Upon failure, returns 0 and sets |al| to the appropriate fatal alert.
- */
-int ssl_check_clienthello_tlsext_late(SSL *s, int *al)
-{
-    s->tlsext_status_expected = 0;
-
-    /*
-     * If status request then ask callback what to do. Note: this must be
-     * called after servername callbacks in case the certificate has changed,
-     * and must be called after the cipher has been chosen because this may
-     * influence which certificate is sent
-     */
-    if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) {
-        int ret;
-        CERT_PKEY *certpkey;
-        certpkey = ssl_get_server_send_pkey(s);
-        /* If no certificate can't return certificate status */
-        if (certpkey != NULL) {
-            /*
-             * Set current certificate to one we will use so SSL_get_certificate
-             * et al can pick it up.
-             */
-            s->cert->key = certpkey;
-            ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-            switch (ret) {
-                /* We don't want to send a status request response */
-            case SSL_TLSEXT_ERR_NOACK:
-                s->tlsext_status_expected = 0;
-                break;
-                /* status request response should be sent */
-            case SSL_TLSEXT_ERR_OK:
-                if (s->tlsext_ocsp_resp)
-                    s->tlsext_status_expected = 1;
-                break;
-                /* something bad happened */
-            case SSL_TLSEXT_ERR_ALERT_FATAL:
-            default:
-                *al = SSL_AD_INTERNAL_ERROR;
-                return 0;
-            }
-        }
-    }
-
-    if (!tls1_alpn_handle_client_hello_late(s, al)) {
-        return 0;
-    }
-
-    return 1;
-}
-
-int ssl_check_serverhello_tlsext(SSL *s)
-{
-    int ret = SSL_TLSEXT_ERR_NOACK;
-    int al = SSL_AD_UNRECOGNIZED_NAME;
-
-#ifndef OPENSSL_NO_EC
-    /*
-     * If we are client and using an elliptic curve cryptography cipher
-     * suite, then if server returns an EC point formats lists extension it
-     * must contain uncompressed.
-     */
-    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-    unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-    if ((s->tlsext_ecpointformatlist != NULL)
-        && (s->tlsext_ecpointformatlist_length > 0)
-        && (s->session->tlsext_ecpointformatlist != NULL)
-        && (s->session->tlsext_ecpointformatlist_length > 0)
-        && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) {
-        /* we are using an ECC cipher */
-        size_t i;
-        unsigned char *list;
-        int found_uncompressed = 0;
-        list = s->session->tlsext_ecpointformatlist;
-        for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) {
-            if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed) {
-                found_uncompressed = 1;
-                break;
-            }
-        }
-        if (!found_uncompressed) {
-            SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,
-                   SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
-            return -1;
-        }
-    }
-    ret = SSL_TLSEXT_ERR_OK;
-#endif                          /* OPENSSL_NO_EC */
-
-    if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
-        ret =
-            s->ctx->tlsext_servername_callback(s, &al,
-                                               s->ctx->tlsext_servername_arg);
-    else if (s->initial_ctx != NULL
-             && s->initial_ctx->tlsext_servername_callback != 0)
-        ret =
-            s->initial_ctx->tlsext_servername_callback(s, &al,
-                                                       s->
-                                                       initial_ctx->tlsext_servername_arg);
-
-    /*
-     * Ensure we get sensible values passed to tlsext_status_cb in the event
-     * that we don't receive a status message
-     */
-    OPENSSL_free(s->tlsext_ocsp_resp);
-    s->tlsext_ocsp_resp = NULL;
-    s->tlsext_ocsp_resplen = 0;
-
-    switch (ret) {
-    case SSL_TLSEXT_ERR_ALERT_FATAL:
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        return -1;
-
-    case SSL_TLSEXT_ERR_ALERT_WARNING:
-        ssl3_send_alert(s, SSL3_AL_WARNING, al);
-        return 1;
-
-    case SSL_TLSEXT_ERR_NOACK:
-        s->servername_done = 0;
-    default:
-        return 1;
-    }
-}
-
-int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt)
-{
-    int al = -1;
-    if (s->version < SSL3_VERSION)
-        return 1;
-    if (ssl_scan_serverhello_tlsext(s, pkt, &al) <= 0) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        return 0;
-    }
-
-    if (ssl_check_serverhello_tlsext(s) <= 0) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_SERVERHELLO_TLSEXT);
-        return 0;
-    }
-    return 1;
-}
-
-/*
  * Given a list of extensions that we collected earlier, find one of a given
  * type and return it.
  *
@@ -3175,7 +1062,6 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
                                SSL_SESSION **ret)
 {
     int retv;
-    const unsigned char *etick;
     size_t size;
     RAW_EXTENSION *ticketext;
 
@@ -3190,10 +1076,8 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
     if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
         return 0;
 
-    ticketext = tls_get_extension_by_type(hello->pre_proc_exts,
-                                          hello->num_extensions,
-                                          TLSEXT_TYPE_session_ticket);
-    if (ticketext == NULL)
+    ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket];
+    if (!ticketext->present)
         return 0;
 
     size = PACKET_remaining(&ticketext->data);
@@ -3214,12 +1098,9 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
          */
         return 2;
     }
-    if (!PACKET_get_bytes(&ticketext->data, &etick, size)) {
-        /* Shouldn't ever happen */
-        return -1;
-    }
-    retv = tls_decrypt_ticket(s, etick, size, hello->session_id,
-                           hello->session_id_len, ret);
+
+    retv = tls_decrypt_ticket(s, PACKET_data(&ticketext->data), size,
+                              hello->session_id, hello->session_id_len, ret);
     switch (retv) {
     case 2:            /* ticket couldn't be decrypted */
         s->tlsext_ticket_expected = 1;
@@ -3237,43 +1118,6 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
     }
 }
 
-/*
- * Sets the extended master secret flag if the extension is present in the
- * ClientHello and we can support it
- * Returns:
- *  1 on success
- *  0 on error
- */
-int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
-{
-    RAW_EXTENSION *emsext;
-
-    s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
-
-    if (!SSL_IS_DTLS(s) && (s->version < TLS1_VERSION
-                            || s->version > TLS1_2_VERSION))
-        return 1;
-
-    emsext = tls_get_extension_by_type(hello->pre_proc_exts,
-                                       hello->num_extensions,
-                                       TLSEXT_TYPE_extended_master_secret);
-
-    /*
-     * No extensions is a success - we have successfully discovered that the
-     * client doesn't support EMS.
-     */
-    if (emsext == NULL)
-        return 1;
-
-    /* The extensions must always be empty */
-    if (PACKET_remaining(&emsext->data) != 0)
-        return 0;
-
-    s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
-
-    return 1;
-}
-
 /*-
  * tls_decrypt_ticket attempts to decrypt a session ticket.
  *
diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c
deleted file mode 100644
index 492386e..0000000
--- a/ssl/t1_reneg.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 1995-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 <stdio.h>
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-/*
- * Parse the client's renegotiation binding and abort if it's not right
- */
-int ssl_parse_clienthello_renegotiate_ext(SSL *s, PACKET *pkt, int *al)
-{
-    unsigned int ilen;
-    const unsigned char *d;
-
-    /* Parse the length byte */
-    if (!PACKET_get_1(pkt, &ilen)
-        || !PACKET_get_bytes(pkt, &d, ilen)) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_ENCODING_ERR);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return 0;
-    }
-
-    /* Check that the extension matches */
-    if (ilen != s->s3->previous_client_finished_len) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_MISMATCH);
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        return 0;
-    }
-
-    if (memcmp(d, s->s3->previous_client_finished,
-               s->s3->previous_client_finished_len)) {
-        SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_MISMATCH);
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        return 0;
-    }
-
-    s->s3->send_connection_binding = 1;
-
-    return 1;
-}
-
-/* Add the server's renegotiation binding */
-int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt)
-{
-    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
-            || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_start_sub_packet_u8(pkt)
-            || !WPACKET_memcpy(pkt, s->s3->previous_client_finished,
-                               s->s3->previous_client_finished_len)
-            || !WPACKET_memcpy(pkt, s->s3->previous_server_finished,
-                               s->s3->previous_server_finished_len)
-            || !WPACKET_close(pkt)
-            || !WPACKET_close(pkt))
-        return 0;
-
-    return 1;
-}
-
-/*
- * Parse the server's renegotiation binding and abort if it's not right
- */
-int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al)
-{
-    size_t expected_len = s->s3->previous_client_finished_len
-        + s->s3->previous_server_finished_len;
-    size_t ilen;
-    const unsigned char *data;
-
-    /* Check for logic errors */
-    OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len);
-    OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len);
-
-    /* Parse the length byte */
-    if (!PACKET_get_1_len(pkt, &ilen)) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_ENCODING_ERR);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return 0;
-    }
-
-    /* Consistency check */
-    if (PACKET_remaining(pkt) != ilen) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_ENCODING_ERR);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return 0;
-    }
-
-    /* Check that the extension matches */
-    if (ilen != expected_len) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_MISMATCH);
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        return 0;
-    }
-
-    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len)
-        || memcmp(data, s->s3->previous_client_finished,
-                  s->s3->previous_client_finished_len) != 0) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_MISMATCH);
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        return 0;
-    }
-
-    if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len)
-        || memcmp(data, s->s3->previous_server_finished,
-                  s->s3->previous_server_finished_len) != 0) {
-        SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
-               SSL_R_RENEGOTIATION_MISMATCH);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return 0;
-    }
-    s->s3->send_connection_binding = 1;
-
-    return 1;
-}
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 421d90d..796759e 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -92,6 +92,7 @@ static ssl_trace_tbl ssl_handshake_tbl[] = {
     {SSL3_MT_CERTIFICATE_VERIFY, "CertificateVerify"},
     {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"},
     {SSL3_MT_FINISHED, "Finished"},
+    {SSL3_MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions"},
     {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"}
 };
 
@@ -588,12 +589,18 @@ static int ssl_print_hexbuf(BIO *bio, int indent,
 }
 
 static int ssl_print_version(BIO *bio, int indent, const char *name,
-                             const unsigned char **pmsg, size_t *pmsglen)
+                             const unsigned char **pmsg, size_t *pmsglen,
+                             unsigned int *version)
 {
     int vers;
+
     if (*pmsglen < 2)
         return 0;
     vers = ((*pmsg)[0] << 8) | (*pmsg)[1];
+    if (version != NULL) {
+        /* TODO(TLS1.3): Remove the draft conditional here before release */
+        *version = (vers == TLS1_3_VERSION_DRAFT) ? TLS1_3_VERSION : vers;
+    }
     BIO_indent(bio, indent, 80);
     BIO_printf(bio, "%s=0x%x (%s)\n",
                name, vers, ssl_trace_str(vers, ssl_version_tbl));
@@ -796,7 +803,7 @@ static int ssl_print_client_hello(BIO *bio, SSL *ssl, int indent,
 {
     size_t len;
     unsigned int cs;
-    if (!ssl_print_version(bio, indent, "client_version", &msg, &msglen))
+    if (!ssl_print_version(bio, indent, "client_version", &msg, &msglen, NULL))
         return 0;
     if (!ssl_print_random(bio, indent, &msg, &msglen))
         return 0;
@@ -849,7 +856,7 @@ static int ssl_print_client_hello(BIO *bio, SSL *ssl, int indent,
 static int dtls_print_hello_vfyrequest(BIO *bio, int indent,
                                        const unsigned char *msg, size_t msglen)
 {
-    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen))
+    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, NULL))
         return 0;
     if (!ssl_print_hexbuf(bio, indent, "cookie", 1, &msg, &msglen))
         return 0;
@@ -860,11 +867,14 @@ static int ssl_print_server_hello(BIO *bio, int indent,
                                   const unsigned char *msg, size_t msglen)
 {
     unsigned int cs;
-    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen))
+    unsigned int vers;
+
+    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, &vers))
         return 0;
     if (!ssl_print_random(bio, indent, &msg, &msglen))
         return 0;
-    if (!ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen))
+    if (vers != TLS1_3_VERSION
+            && !ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen))
         return 0;
     if (msglen < 2)
         return 0;
@@ -874,13 +884,15 @@ static int ssl_print_server_hello(BIO *bio, int indent,
                msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl));
     msg += 2;
     msglen -= 2;
-    if (msglen < 1)
-        return 0;
-    BIO_indent(bio, indent, 80);
-    BIO_printf(bio, "compression_method: %s (0x%02X)\n",
-               ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]);
-    msg++;
-    msglen--;
+    if (vers != TLS1_3_VERSION) {
+        if (msglen < 1)
+            return 0;
+        BIO_indent(bio, indent, 80);
+        BIO_printf(bio, "compression_method: %s (0x%02X)\n",
+                   ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]);
+        msg++;
+        msglen--;
+    }
     if (!ssl_print_extensions(bio, indent, 1, msg, msglen))
         return 0;
     return 1;
@@ -1275,6 +1287,11 @@ static int ssl_print_handshake(BIO *bio, SSL *ssl,
             return 0;
         break;
 
+    case SSL3_MT_ENCRYPTED_EXTENSIONS:
+        if (!ssl_print_extensions(bio, indent + 2, 1, msg, msglen))
+            return 0;
+        break;
+
     default:
         BIO_indent(bio, indent + 2, 80);
         BIO_puts(bio, "Unsupported, hex dump follows:\n");
diff --git a/test/ossl_shim/ossl_config.json b/test/ossl_shim/ossl_config.json
index 690dc66..c4a4254 100644
--- a/test/ossl_shim/ossl_config.json
+++ b/test/ossl_shim/ossl_config.json
@@ -2,6 +2,12 @@
 {
     "DisabledTests" : {
             "*TLS13*":"No TLS1.3 support yet",
+            "DuplicateExtensionClient-TLS1":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
+            "DuplicateExtensionServer-TLS1":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
+            "DuplicateExtensionClient-TLS11":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
+            "DuplicateExtensionServer-TLS11":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
+            "DuplicateExtensionServer-TLS12":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
+            "DuplicateExtensionClient-TLS12":"OpenSSL, by design, only checks for duplicates of known extensions and ignores others",
             "UnauthenticatedECDH":"Test failure - reason unknown",
             "SkipServerKeyExchange":"Test failure - reason unknown",
             "FragmentAlert-DTLS":"Test failure - reason unknown",
diff --git a/test/recipes/70-test_key_share.t b/test/recipes/70-test_key_share.t
index 380b1a8..b0f8c09 100755
--- a/test/recipes/70-test_key_share.t
+++ b/test/recipes/70-test_key_share.t
@@ -74,7 +74,7 @@ $testtype = EMPTY_EXTENSION;
 $direction = CLIENT_TO_SERVER;
 $proxy->filter(\&modify_key_shares_filter);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 17;
+plan tests => 19;
 #TODO(TLS1.3): Actually this should succeed after a HelloRetryRequest - but
 #we've not implemented that yet, so for now we look for a fail
 ok(TLSProxy::Message->fail(), "Empty key_shares");
@@ -188,6 +188,26 @@ $testtype = TRAILING_DATA;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "key_share trailing data in ServerHello");
 
+#Test 18: key_share should not be sent if the client is not capable of
+#         negotiating TLSv1.3
+$proxy->clear();
+$proxy->filter(undef);
+$proxy->clientflags("-no_tls1_3");
+$proxy->start();
+my $clienthello = $proxy->message_list->[0];
+ok(TLSProxy::Message->success()
+   && !defined $clienthello->extension_data->{TLSProxy::Message::EXT_KEY_SHARE},
+   "No key_share for TLS<=1.2 client");
+$proxy->filter(\&modify_key_shares_filter);
+
+#Test 19: A server not capable of negotiating TLSv1.3 should not attempt to
+#         process a key_share
+$proxy->clear();
+$direction = CLIENT_TO_SERVER;
+$testtype = NO_ACCEPTABLE_KEY_SHARES;
+$proxy->serverflags("-no_tls1_3");
+$proxy->start();
+ok(TLSProxy::Message->success(), "Ignore key_share for TLS<=1.2 server");
 
 sub modify_key_shares_filter
 {
@@ -284,7 +304,7 @@ sub modify_key_shares_filter
                      && $direction == SERVER_TO_CLIENT) {
             my $ext;
             my $key_share =
-                ${$message->extension_data}{TLSProxy::Message::EXT_KEY_SHARE};
+                $message->extension_data->{TLSProxy::Message::EXT_KEY_SHARE};
             $selectedgroupid = unpack("n", $key_share);
 
             if ($testtype == LOOK_ONLY) {
@@ -316,7 +336,7 @@ sub modify_key_shares_filter
                     "EDF83495E80380089F831B94D14B1421", #key_exchange data
                     0x00; #Trailing garbage
             }
-            $message->set_extension( TLSProxy::Message::EXT_KEY_SHARE, $ext);
+            $message->set_extension(TLSProxy::Message::EXT_KEY_SHARE, $ext);
 
             $message->repack();
         }
diff --git a/test/recipes/70-test_sslcertstatus.t b/test/recipes/70-test_renegotiation.t
similarity index 53%
copy from test/recipes/70-test_sslcertstatus.t
copy to test/recipes/70-test_renegotiation.t
index f700f92..9bd9026 100755
--- a/test/recipes/70-test_sslcertstatus.t
+++ b/test/recipes/70-test_renegotiation.t
@@ -1,5 +1,5 @@
 #! /usr/bin/env perl
-# Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+# 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
@@ -11,7 +11,7 @@ use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
 use OpenSSL::Test::Utils;
 use TLSProxy::Proxy;
 
-my $test_name = "test_sslcertstatus";
+my $test_name = "test_renegotiation";
 setup($test_name);
 
 plan skip_all => "TLSProxy isn't usable on $^O"
@@ -23,43 +23,47 @@ plan skip_all => "$test_name needs the dynamic engine feature enabled"
 plan skip_all => "$test_name needs the sock feature enabled"
     if disabled("sock");
 
-plan skip_all => "$test_name needs the ocsp feature enabled"
-    if disabled("ocsp");
-
-plan skip_all => "$test_name needs TLS enabled"
-    if alldisabled(available_protocols("tls"));
+plan skip_all => "$test_name needs TLS <= 1.2 enabled"
+    if alldisabled(("ssl3", "tls1", "tls1_1", "tls1_2"));
 
 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
 my $proxy = TLSProxy::Proxy->new(
-    \&certstatus_filter,
+    undef,
     cmdstr(app(["openssl"]), display => 1),
     srctop_file("apps", "server.pem"),
     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
 );
 
-#Test 1: Sending a status_request extension in both ClientHello and
-#ServerHello but then omitting the CertificateStatus message is valid
-$proxy->clientflags("-status");
+#Test 1: A basic renegotiation test
+$proxy->clientflags("-no_tls1_3");
+$proxy->reneg(1);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 1;
-ok(TLSProxy::Message->success, "Missing CertificateStatus message");
+plan tests => 2;
+ok(TLSProxy::Message->success(), "Basic renegotiation");
+
+#Test 2: Client does not send the Reneg SCSV. Reneg should fail
+$proxy->clear();
+$proxy->filter(\&reneg_filter);
+$proxy->clientflags("-no_tls1_3");
+$proxy->reneg(1);
+$proxy->start();
+ok(TLSProxy::Message->fail(), "No client SCSV");
 
-sub certstatus_filter
+sub reneg_filter
 {
     my $proxy = shift;
 
-    # We're only interested in the initial ServerHello
-    if ($proxy->flight != 1) {
+    # We're only interested in the initial ClientHello message
+    if ($proxy->flight != 0) {
         return;
     }
 
     foreach my $message (@{$proxy->message_list}) {
-        if ($message->mt == TLSProxy::Message::MT_SERVER_HELLO) {
-            #Add the status_request to the ServerHello even though we are not
-            #going to send a CertificateStatus message
-            $message->set_extension(TLSProxy::Message::EXT_STATUS_REQUEST,
-                                    "");
-
+        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
+            #Remove any SCSV ciphersuites - just leave AES128-SHA (0x002f)
+            my @ciphersuite = (0x002f);
+            $message->ciphersuites(\@ciphersuite);
+            $message->ciphersuite_len(2);
             $message->repack();
         }
     }
diff --git a/test/recipes/70-test_sslcertstatus.t b/test/recipes/70-test_sslcertstatus.t
index f700f92..ed01855 100755
--- a/test/recipes/70-test_sslcertstatus.t
+++ b/test/recipes/70-test_sslcertstatus.t
@@ -39,7 +39,9 @@ my $proxy = TLSProxy::Proxy->new(
 
 #Test 1: Sending a status_request extension in both ClientHello and
 #ServerHello but then omitting the CertificateStatus message is valid
-$proxy->clientflags("-status");
+#TODO(TLS1.3): Temporarily disabling this test in TLS1.3 until we've completed
+#the move the status request extension to the Certificate message.
+$proxy->clientflags("-status -no_tls1_3");
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
 plan tests => 1;
 ok(TLSProxy::Message->success, "Missing CertificateStatus message");
diff --git a/test/recipes/70-test_sslmessages.t b/test/recipes/70-test_sslmessages.t
new file mode 100755
index 0000000..4e87e53
--- /dev/null
+++ b/test/recipes/70-test_sslmessages.t
@@ -0,0 +1,352 @@
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
+use OpenSSL::Test::Utils;
+use File::Temp qw(tempfile);
+use TLSProxy::Proxy;
+use checkhandshake qw(checkhandshake @handmessages @extensions);
+
+my $test_name = "test_sslmessages";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+    if $^O =~ /^(VMS|MSWin32)$/;
+
+plan skip_all => "$test_name needs the dynamic engine feature enabled"
+    if disabled("engine") || disabled("dynamic-engine");
+
+plan skip_all => "$test_name needs the sock feature enabled"
+    if disabled("sock");
+
+plan skip_all => "$test_name needs TLS enabled"
+    if alldisabled(available_protocols("tls"));
+
+$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+$ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
+
+my $proxy = TLSProxy::Proxy->new(
+    undef,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+ at handmessages = (
+    [TLSProxy::Message::MT_CLIENT_HELLO,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_SERVER_HELLO,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_CERTIFICATE,
+        checkhandshake::ALL_HANDSHAKES
+        & ~checkhandshake::RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE_STATUS,
+        checkhandshake::OCSP_HANDSHAKE],
+    #ServerKeyExchange handshakes not currently supported by TLSProxy
+    [TLSProxy::Message::MT_CERTIFICATE_REQUEST,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_SERVER_HELLO_DONE,
+        checkhandshake::ALL_HANDSHAKES
+        & ~checkhandshake::RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_CLIENT_KEY_EXCHANGE,
+        checkhandshake::ALL_HANDSHAKES
+        & ~checkhandshake::RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE_VERIFY,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_NEXT_PROTO,
+        checkhandshake::NPN_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_NEW_SESSION_TICKET,
+        checkhandshake::ALL_HANDSHAKES
+        & ~checkhandshake::RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_CLIENT_HELLO,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_SERVER_HELLO,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_SERVER_HELLO_DONE,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_CLIENT_KEY_EXCHANGE,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_NEW_SESSION_TICKET,
+        checkhandshake::RENEG_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::RENEG_HANDSHAKE],
+    [0, 0]
+);
+
+ at extensions = (
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
+        checkhandshake::SCT_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_RENEGOTIATE,
+        checkhandshake::RENEGOTIATE_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_NPN,
+        checkhandshake::NPN_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SRP,
+        checkhandshake::SRP_CLI_EXTENSION],
+
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_RENEGOTIATE,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SESSION_TICKET,
+        checkhandshake::SESSION_TICKET_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SCT,
+        checkhandshake::SCT_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_NPN,
+        checkhandshake::NPN_SRV_EXTENSION],
+    [0,0,0]
+);
+
+#Test 1: Check we get all the right messages for a default handshake
+(undef, my $session) = tempfile();
+$proxy->serverconnects(2);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 20;
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Default handshake test");
+
+#Test 2: Resumption handshake
+$proxy->clearClient();
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
+$proxy->clientstart();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               & ~checkhandshake::SESSION_TICKET_SRV_EXTENSION,
+               "Resumption handshake test");
+unlink $session;
+
+#Test 3: A status_request handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -status");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION,
+               "status_request handshake test (client)");
+
+#Test 4: A status_request handshake (server support only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "status_request handshake test (server)");
+
+#Test 5: A status_request handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -status");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::OCSP_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
+               "status_request handshake test");
+
+#Test 6: A client auth handshake
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -cert ".srctop_file("apps", "server.pem"));
+$proxy->serverflags("-Verify 5");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Client auth handshake test");
+
+#Test 7: A handshake with a renegotiation
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->reneg(1);
+$proxy->start();
+checkhandshake($proxy, checkhandshake::RENEG_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Rengotiation handshake test");
+
+#Test 8: Server name handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SERVER_NAME_CLI_EXTENSION,
+               "Server name handshake test (client)");
+
+#Test 9: Server name handshake (server support only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Server name handshake test (server)");
+
+#Test 10: Server name handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -servername testhost");
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SERVER_NAME_CLI_EXTENSION
+               | checkhandshake::SERVER_NAME_SRV_EXTENSION,
+               "Server name handshake test");
+
+#Test 11: ALPN handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::ALPN_CLI_EXTENSION,
+               "ALPN handshake test (client)");
+
+#Test 12: ALPN handshake (server support only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "ALPN handshake test (server)");
+
+#Test 13: ALPN handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -alpn test");
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::ALPN_CLI_EXTENSION
+               | checkhandshake::ALPN_SRV_EXTENSION,
+               "ALPN handshake test");
+
+#Test 14: SCT handshake (client request only)
+$proxy->clear();
+#Note: -ct also sends status_request
+$proxy->clientflags("-no_tls1_3 -ct");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::OCSP_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SCT_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
+               "SCT handshake test (client)");
+
+#Test 15: SCT handshake (server support only)
+$proxy->clear();
+#Note: -ct also sends status_request
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "SCT handshake test (server)");
+
+#Test 16: SCT handshake (client and server)
+#There is no built-in server side support for this so we are actually also
+#testing custom extensions here
+$proxy->clear();
+#Note: -ct also sends status_request
+$proxy->clientflags("-no_tls1_3 -ct");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der")
+                    ." -serverinfo ".srctop_file("test", "serverinfo.pem"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::OCSP_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SCT_CLI_EXTENSION
+               | checkhandshake::SCT_SRV_EXTENSION
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
+               "SCT handshake test");
+
+
+#Test 17: NPN handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -nextprotoneg test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::NPN_CLI_EXTENSION,
+              "NPN handshake test (client)");
+
+#Test 18: NPN handshake (server support only)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-nextprotoneg test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+              "NPN handshake test (server)");
+
+#Test 19: NPN handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -nextprotoneg test");
+$proxy->serverflags("-nextprotoneg test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::NPN_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::NPN_CLI_EXTENSION
+               | checkhandshake::NPN_SRV_EXTENSION,
+               "NPN handshake test");
+
+#Test 20: SRP extension
+#Note: We are not actually going to perform an SRP handshake (TLSProxy does not
+#support it). However it is sufficient for us to check that the SRP extension
+#gets added on the client side. There is no SRP extension generated on the
+#server side anyway.
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3 -srpuser user -srppass pass:pass");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SRP_CLI_EXTENSION,
+               "SRP extension test");
diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t
index 62c12c4..15dfa9f 100755
--- a/test/recipes/70-test_tls13messages.t
+++ b/test/recipes/70-test_tls13messages.t
@@ -7,10 +7,12 @@
 # https://www.openssl.org/source/license.html
 
 use strict;
-use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
 use OpenSSL::Test::Utils;
 use File::Temp qw(tempfile);
 use TLSProxy::Proxy;
+use checkhandshake qw(checkhandshake @handmessages @extensions);
+
 my $test_name = "test_tls13messages";
 setup($test_name);
 
@@ -27,28 +29,71 @@ plan skip_all => "$test_name needs TLSv1.3 enabled"
     if disabled("tls1_3");
 
 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
-
-use constant {
-    DEFAULT_HANDSHAKE => 1,
-    OCSP_HANDSHAKE => 2,
-    RESUME_HANDSHAKE => 4,
-    CLIENT_AUTH_HANDSHAKE => 8,
-    ALL_HANDSHAKES => 15
-};
-
-my @handmessages = (
-    [TLSProxy::Message::MT_CLIENT_HELLO, ALL_HANDSHAKES],
-    [TLSProxy::Message::MT_SERVER_HELLO, ALL_HANDSHAKES],
-    [TLSProxy::Message::MT_CERTIFICATE_REQUEST, CLIENT_AUTH_HANDSHAKE],
-    [TLSProxy::Message::MT_CERTIFICATE, ALL_HANDSHAKES & ~RESUME_HANDSHAKE],
-    [TLSProxy::Message::MT_CERTIFICATE_STATUS, OCSP_HANDSHAKE],
-    [TLSProxy::Message::MT_FINISHED, ALL_HANDSHAKES],
-    [TLSProxy::Message::MT_CERTIFICATE, CLIENT_AUTH_HANDSHAKE],
-    [TLSProxy::Message::MT_CERTIFICATE_VERIFY, CLIENT_AUTH_HANDSHAKE],
-    [TLSProxy::Message::MT_FINISHED, ALL_HANDSHAKES],
+$ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
+
+
+ at handmessages = (
+    [TLSProxy::Message::MT_CLIENT_HELLO,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_SERVER_HELLO,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_CERTIFICATE_REQUEST,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE,
+        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE_STATUS,
+        checkhandshake::OCSP_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_CERTIFICATE,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_CERTIFICATE_VERIFY,
+        checkhandshake::CLIENT_AUTH_HANDSHAKE],
+    [TLSProxy::Message::MT_FINISHED,
+        checkhandshake::ALL_HANDSHAKES],
     [0, 0]
 );
 
+ at extensions = (
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
+        checkhandshake::SCT_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::DEFAULT_EXTENSIONS],
+
+    [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_SRV_EXTENSION],
+    [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_SRV_EXTENSION],
+    [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_SRV_EXTENSION],
+    [0,0,0]
+);
+
 my $proxy = TLSProxy::Proxy->new(
     undef,
     cmdstr(app(["openssl"]), display => 1),
@@ -56,24 +101,43 @@ my $proxy = TLSProxy::Proxy->new(
     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
 );
 
-sub checkmessages($$);
-
 #Test 1: Check we get all the right messages for a default handshake
 (undef, my $session) = tempfile();
-$proxy->serverconnects(2);
+#$proxy->serverconnects(2);
 $proxy->clientflags("-sess_out ".$session);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 4;
-checkmessages(DEFAULT_HANDSHAKE, "Default handshake test");
+plan tests => 12;
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Default handshake test");
 
+#TODO(TLS1.3): Test temporarily disabled until we implement TLS1.3 resumption
 #Test 2: Resumption handshake
-$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
-$proxy->clientstart();
-checkmessages(RESUME_HANDSHAKE, "Resumption handshake test");
+#$proxy->clearClient();
+#$proxy->clientflags("-sess_in ".$session);
+#$proxy->clientstart();
+#checkmessages(RESUME_HANDSHAKE, "Resumption handshake test");
 unlink $session;
 
-#Test 3: A default handshake, but with a CertificateStatus message
+#Test 3: A status_request handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-status");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION,
+               "status_request handshake test (client)");
+
+#Test 4: A status_request handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "status_request handshake test (server)");
+
+#Test 5: A status_request handshake (client and server)
 #TODO(TLS1.3): TLS1.3 doesn't actually have CertificateStatus messages. This is
 #a temporary test until such time as we do proper TLS1.3 style certificate
 #status
@@ -82,42 +146,93 @@ $proxy->clientflags("-status");
 $proxy->serverflags("-status_file "
                     .srctop_file("test", "recipes", "ocsp-response.der"));
 $proxy->start();
-checkmessages(OCSP_HANDSHAKE, "OCSP handshake test");
+checkhandshake($proxy, checkhandshake::OCSP_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
+               "status_request handshake test");
 
-#Test 4: A client auth handshake
+#Test 6: A client auth handshake
 $proxy->clear();
 $proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
 $proxy->serverflags("-Verify 5");
 $proxy->start();
-checkmessages(CLIENT_AUTH_HANDSHAKE, "Client auth handshake test");
-
-sub checkmessages($$)
-{
-    my ($handtype, $testname) = @_;
-
-    subtest $testname => sub {
-        my $loop = 0;
-        my $numtests;
-
-        #First count the number of tests
-        for ($numtests = 1; $handmessages[$loop][1] != 0; $loop++) {
-            $numtests++ if (($handmessages[$loop][1] & $handtype) != 0);
-        }
-
-        plan tests => $numtests;
-
-        $loop = 0;
-        foreach my $message (@{$proxy->message_list}) {
-            for (; $handmessages[$loop][1] != 0
-                   && ($handmessages[$loop][1] & $handtype) == 0; $loop++) {
-                next;
-            }
-            ok($handmessages[$loop][1] != 0
-               && $message->mt == $handmessages[$loop][0],
-               "Message type check. Got ".$message->mt
-               .", expected ".$handmessages[$loop][0]);
-            $loop++;
-        }
-        ok($handmessages[$loop][1] == 0, "All expected messages processed");
-    }
-}
+checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Client auth handshake test");
+
+#Test 7: Server name handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SERVER_NAME_CLI_EXTENSION,
+               "Server name handshake test (client)");
+
+#Test 8: Server name handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "Server name handshake test (server)");
+
+#Test 9: Server name handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-servername testhost");
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SERVER_NAME_CLI_EXTENSION
+               | checkhandshake::SERVER_NAME_SRV_EXTENSION,
+               "Server name handshake test");
+
+#Test 10: ALPN handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::ALPN_CLI_EXTENSION,
+               "ALPN handshake test (client)");
+
+#Test 11: ALPN handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS,
+               "ALPN handshake test (server)");
+
+#Test 12: ALPN handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-alpn test");
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::ALPN_CLI_EXTENSION
+               | checkhandshake::ALPN_SRV_EXTENSION,
+               "ALPN handshake test");
+
+#Test 13: SCT handshake (client request only)
+#TODO(TLS1.3): This only checks that the client side extension appears. The
+#SCT extension is unusual in that we have no built-in server side implementation
+#The server side implementation can nomrally be added using the custom
+#extensions framework (e.g. by using the "-serverinfo" s_server option). However
+#currently we only support <= TLS1.2 for custom extensions because the existing
+#framework and API has no knowledge of the TLS1.3 messages
+$proxy->clear();
+#Note: -ct also sends status_request
+$proxy->clientflags("-ct");
+$proxy->serverflags("-status_file "
+                    .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkhandshake($proxy, checkhandshake::OCSP_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::SCT_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
+               | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
+               "SCT handshake test");
diff --git a/test/ssl-tests/09-alpn.conf b/test/ssl-tests/09-alpn.conf
index e7e6cb9..fc3c8da 100644
--- a/test/ssl-tests/09-alpn.conf
+++ b/test/ssl-tests/09-alpn.conf
@@ -383,6 +383,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [10-alpn-simple-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -425,6 +426,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [11-alpn-server-switch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -465,11 +467,13 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [12-alpn-client-switch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [12-alpn-client-switch-resumption-resume-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -515,6 +519,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [13-alpn-alert-on-mismatch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -560,6 +565,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [14-alpn-no-server-support-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -595,11 +601,13 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [15-alpn-no-client-support-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [15-alpn-no-client-support-resumption-resume-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
diff --git a/test/ssl-tests/09-alpn.conf.in b/test/ssl-tests/09-alpn.conf.in
index 18560e1..ff931a9 100644
--- a/test/ssl-tests/09-alpn.conf.in
+++ b/test/ssl-tests/09-alpn.conf.in
@@ -204,6 +204,8 @@ our @tests = (
             },
         },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
@@ -227,6 +229,8 @@ our @tests = (
             },
         },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo,bar,baz",
             },
@@ -245,11 +249,15 @@ our @tests = (
             },
         },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo,baz",
             },
         },
         resume_client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "bar,baz",
             },
@@ -273,6 +281,8 @@ our @tests = (
             },
         },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo,bar",
             },
@@ -292,6 +302,8 @@ our @tests = (
         },
         resume_server => { },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
@@ -310,11 +322,16 @@ our @tests = (
             },
         },
         client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
         },
-        resume_client => { },
+        resume_client => {
+            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
+            MaxProtocol => "TLSv1.2"
+        },
         test => {
             "HandshakeMode" => "Resume",
             "ResumptionExpected" => "Yes",
diff --git a/test/ssl-tests/12-ct.conf b/test/ssl-tests/12-ct.conf
index 22fa18d..14b8e93 100644
--- a/test/ssl-tests/12-ct.conf
+++ b/test/ssl-tests/12-ct.conf
@@ -79,6 +79,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [2-ct-permissive-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -111,11 +112,13 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [3-ct-strict-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [3-ct-strict-resumption-resume-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
diff --git a/test/ssl-tests/12-ct.conf.in b/test/ssl-tests/12-ct.conf.in
index 9964d01..e7fe1b9 100644
--- a/test/ssl-tests/12-ct.conf.in
+++ b/test/ssl-tests/12-ct.conf.in
@@ -18,63 +18,72 @@ package ssltests;
 our @tests = (
     # Currently only have tests for certs without SCTs.
     {
-	name => "ct-permissive",
-	server => { },
-	client => {
-     	    extra => {
-	        "CTValidation" => "Permissive",
-	    },
-	},
-	test => {
-	    "ExpectedResult" => "Success",
-	},
+        name => "ct-permissive",
+        server => { },
+        client => {
+            extra => {
+                "CTValidation" => "Permissive",
+            },
+        },
+        test => {
+            "ExpectedResult" => "Success",
+        },
     }, 
     {
-	name => "ct-strict",
-	server => { },
-	client => {
-     	    extra => {
-	        "CTValidation" => "Strict",
-	    },
-	},
-	test => {
-	    "ExpectedResult" => "ClientFail",
-	    "ExpectedClientAlert" => "HandshakeFailure",
-	},
+        name => "ct-strict",
+        server => { },
+        client => {
+            extra => {
+                "CTValidation" => "Strict",
+            },
+        },
+        test => {
+            "ExpectedResult" => "ClientFail",
+            "ExpectedClientAlert" => "HandshakeFailure",
+        },
     },
     {
-	name => "ct-permissive-resumption",
-	server => { },
-	client => {
-     	    extra => {
-	        "CTValidation" => "Permissive",
-	    },
-	},
-	test => {
-	    "HandshakeMode" => "Resume",
-	    "ResumptionExpected" => "Yes",
-	    "ExpectedResult" => "Success",
-	},
+        name => "ct-permissive-resumption",
+        server => { },
+        client => {
+            #TODO(TLS1.3): Temporarily set to TLSv1.2 until we implement TLS1.3
+            #              resumption
+            MaxProtocol => "TLSv1.2",
+            extra => {
+                "CTValidation" => "Permissive",
+            },
+        },
+        test => {
+            "HandshakeMode" => "Resume",
+            "ResumptionExpected" => "Yes",
+            "ExpectedResult" => "Success",
+        },
     }, 
     {
-	name => "ct-strict-resumption",
-	server => { },
-	client => {
-     	    extra => {
-	        "CTValidation" => "Permissive",
-	    },
-	},
-	# SCTs are not present during resumption, so the resumption
-	# should succeed.
-	resume_client => {
-     	    extra => {
-	        "CTValidation" => "Strict",
-	    },
-	},
-	test => {
-	    "HandshakeMode" => "Resume",
-	    "ResumptionExpected" => "Yes",
-	    "ExpectedResult" => "Success",
-	},
+        name => "ct-strict-resumption",
+        server => { },
+        client => {
+            #TODO(TLS1.3): Temporarily set to TLSv1.2 until we implement TLS1.3
+            #              resumption
+            MaxProtocol => "TLSv1.2",
+            extra => {
+                "CTValidation" => "Permissive",
+            },
+        },
+        # SCTs are not present during resumption, so the resumption
+        # should succeed.
+        resume_client => {
+            #TODO(TLS1.3): Temporarily set to TLSv1.2 until we implement TLS1.3
+            #              resumption
+            MaxProtocol => "TLSv1.2",
+            extra => {
+                "CTValidation" => "Strict",
+            },
+        },
+        test => {
+            "HandshakeMode" => "Resume",
+            "ResumptionExpected" => "Yes",
+            "ExpectedResult" => "Success",
+        },
     },
 );
diff --git a/test/ssl-tests/protocol_version.pm b/test/ssl-tests/protocol_version.pm
index cc39c75..a41ffc4 100644
--- a/test/ssl-tests/protocol_version.pm
+++ b/test/ssl-tests/protocol_version.pm
@@ -135,6 +135,22 @@ sub generate_resumption_tests {
     # Don't write the redundant "Method = TLS" into the configuration.
     undef $method if !$dtls;
 
+
+    #TODO(TLS1.3): This is temporary code while we do not have support for
+    #              TLS1.3 resumption. We recalculate min_tls_enabled and
+    #              max_tls_enabled, ignoring TLS1.3
+    foreach my $i (0..($#tls_protocols - 1)) {
+        if (!$is_tls_disabled[$i]) {
+            $min_tls_enabled = $i;
+            last;
+        }
+    }
+    foreach my $i (0..($#tls_protocols - 1)) {
+        if (!$is_tls_disabled[$i]) {
+            $max_tls_enabled = $i;
+        }
+    }
+
     my @protocols = $dtls ? @dtls_protocols : @tls_protocols;
     my $min_enabled  = $dtls ? $min_dtls_enabled : $min_tls_enabled;
     my $max_enabled = $dtls ? $max_dtls_enabled : $max_tls_enabled;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 1fa9a8d..add38cf 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -430,6 +430,12 @@ static int execute_test_session(SSL_SESSION_TEST_FIXTURE fix)
     SSL_CTX_set_min_proto_version(cctx, TLS1_2_VERSION);
 #endif
 
+    /*
+     * TODO(TLS1.3): Test temporarily disabled for TLS1.3 until we've
+     * implemented session resumption.
+     */
+    SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION);
+
     /* Set up session cache */
     if (fix.use_ext_cache) {
         SSL_CTX_sess_set_new_cb(cctx, new_session_cb);
diff --git a/test/testlib/checkhandshake.pm b/test/testlib/checkhandshake.pm
new file mode 100644
index 0000000..eb34fff
--- /dev/null
+++ b/test/testlib/checkhandshake.pm
@@ -0,0 +1,128 @@
+#! /usr/bin/env perl
+# 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
+
+package checkhandshake;
+
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+
+use Exporter;
+our @ISA = 'Exporter';
+our @EXPORT = qw(@handmessages @extensions checkhandshake);
+
+use constant {
+    DEFAULT_HANDSHAKE => 1,
+    OCSP_HANDSHAKE => 2,
+    RESUME_HANDSHAKE => 4,
+    CLIENT_AUTH_HANDSHAKE => 8,
+    RENEG_HANDSHAKE => 16,
+    NPN_HANDSHAKE => 32,
+
+    ALL_HANDSHAKES => 63
+};
+
+use constant {
+    #DEFAULT ALSO INCLUDES SESSION_TICKET_SRV_EXTENSION
+    DEFAULT_EXTENSIONS => 0x00000003,
+    SESSION_TICKET_SRV_EXTENSION => 0x00000002,
+    SERVER_NAME_CLI_EXTENSION => 0x00000004,
+    SERVER_NAME_SRV_EXTENSION => 0x00000008,
+    STATUS_REQUEST_CLI_EXTENSION => 0x00000010,
+    STATUS_REQUEST_SRV_EXTENSION => 0x00000020,
+    ALPN_CLI_EXTENSION => 0x00000040,
+    ALPN_SRV_EXTENSION => 0x00000080,
+    SCT_CLI_EXTENSION => 0x00000100,
+    SCT_SRV_EXTENSION => 0x00000200,
+    RENEGOTIATE_CLI_EXTENSION => 0x00000400,
+    NPN_CLI_EXTENSION => 0x00000800,
+    NPN_SRV_EXTENSION => 0x00001000,
+    SRP_CLI_EXTENSION => 0x00002000,
+};
+
+our @handmessages = ();
+our @extensions = ();
+
+sub checkhandshake($$$$)
+{
+    my ($proxy, $handtype, $exttype, $testname) = @_;
+
+    subtest $testname => sub {
+        my $loop = 0;
+        my $numtests;
+        my $extcount;
+        my $clienthelloseen = 0;
+
+        #First count the number of tests
+        for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
+            $numtests++ if (($handmessages[$loop][1] & $handtype) != 0);
+        }
+
+        #Add number of extensions we check plus 2 for the number of messages
+        #that contain extensions
+        $numtests += $#extensions + 2;
+        #In a renegotiation we will have double the number of extension tests
+        if (($handtype & RENEG_HANDSHAKE) != 0) {
+            $numtests += $#extensions + 2;
+        }
+        #In TLS1.3 there are 3 messages with extensions (and no renegotiations)
+        $numtests += 1 if ($proxy->is_tls13());
+
+        plan tests => $numtests;
+
+        my $nextmess = 0;
+        my $message = undef;
+        for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) {
+            next if (($handmessages[$loop][1] & $handtype) == 0);
+            if (scalar @{$proxy->message_list} > $nextmess) {
+                $message = ${$proxy->message_list}[$nextmess];
+                $nextmess++;
+            } else {
+                $message = undef;
+            }
+            if (!defined $message) {
+                fail("Message type check. Got nothing, expected "
+                     .$handmessages[$loop][0]);
+                next;
+            } else {
+                ok($message->mt == $handmessages[$loop][0],
+                   "Message type check. Got ".$message->mt
+                   .", expected ".$handmessages[$loop][0]);
+            }
+
+            next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+                    && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
+                    && $message->mt() !=
+                       TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS);
+
+            if ($message->mt() == TLSProxy::Message::MT_CLIENT_HELLO) {
+                #Add renegotiate extension we will expect if renegotiating
+                $exttype |= RENEGOTIATE_CLI_EXTENSION if ($clienthelloseen);
+                $clienthelloseen = 1;
+            }
+            #Now check that we saw the extensions we expected
+            my $msgexts = $message->extension_data();
+
+            for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0;
+                                $extloop++) {
+                next if ($message->mt() != $extensions[$extloop][0]);
+                ok (($extensions[$extloop][2] & $exttype) == 0
+                      || defined ($msgexts->{$extensions[$extloop][1]}),
+                    "Extension presence check (Message: ".$message->mt()
+                    ." Extension: ".($extensions[$extloop][2] & $exttype).", "
+                    .$extloop.")");
+                $extcount++ if (($extensions[$extloop][2] & $exttype) != 0);
+             }
+            ok($extcount == keys %$msgexts, "Extensions count mismatch ("
+                                            .$extcount.", ".(keys %$msgexts)
+                                            .")");
+        }
+    }
+}
+
+1;
diff --git a/util/TLSProxy/EncryptedExtensions.pm b/util/TLSProxy/EncryptedExtensions.pm
new file mode 100644
index 0000000..81242e2
--- /dev/null
+++ b/util/TLSProxy/EncryptedExtensions.pm
@@ -0,0 +1,115 @@
+# 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
+
+use strict;
+
+package TLSProxy::EncryptedExtensions;
+
+use vars '@ISA';
+push @ISA, 'TLSProxy::Message';
+
+sub new
+{
+    my $class = shift;
+    my ($server,
+        $data,
+        $records,
+        $startoffset,
+        $message_frag_lens) = @_;
+
+    my $self = $class->SUPER::new(
+        $server,
+        TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
+        $data,
+        $records,
+        $startoffset,
+        $message_frag_lens);
+
+    $self->{extension_data} = "";
+
+    return $self;
+}
+
+sub parse
+{
+    my $self = shift;
+
+    my $extensions_len = unpack('n', $self->data);
+    if (!defined $extensions_len) {
+        $extensions_len = 0;
+    }
+
+    my $extension_data;
+    if ($extensions_len != 0) {
+        $extension_data = substr($self->data, 2);
+
+        if (length($extension_data) != $extensions_len) {
+            die "Invalid extension length\n";
+        }
+    } else {
+        if (length($self->data) != 2) {
+            die "Invalid extension length\n";
+        }
+        $extension_data = "";
+    }
+    my %extensions = ();
+    while (length($extension_data) >= 4) {
+        my ($type, $size) = unpack("nn", $extension_data);
+        my $extdata = substr($extension_data, 4, $size);
+        $extension_data = substr($extension_data, 4 + $size);
+        $extensions{$type} = $extdata;
+    }
+
+    $self->extension_data(\%extensions);
+
+    print "    Extensions Len:".$extensions_len."\n";
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+    my $self = shift;
+    my $data;
+    my $extensions = "";
+
+    foreach my $key (keys %{$self->extension_data}) {
+        my $extdata = ${$self->extension_data}{$key};
+        $extensions .= pack("n", $key);
+        $extensions .= pack("n", length($extdata));
+        $extensions .= $extdata;
+        if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) {
+            $extensions .= pack("n", $key);
+            $extensions .= pack("n", length($extdata));
+            $extensions .= $extdata;
+        }
+    }
+
+    $data = pack('n', length($extensions));
+    $data .= $extensions;
+    $self->data($data);
+}
+
+#Read/write accessors
+sub extension_data
+{
+    my $self = shift;
+    if (@_) {
+        $self->{extension_data} = shift;
+    }
+    return $self->{extension_data};
+}
+sub set_extension
+{
+    my ($self, $ext_type, $ext_data) = @_;
+    $self->{extension_data}{$ext_type} = $ext_data;
+}
+sub delete_extension
+{
+    my ($self, $ext_type) = @_;
+    delete $self->{extension_data}{$ext_type};
+}
+1;
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index 3259edc..e5c42c8 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -17,6 +17,7 @@ use constant {
     MT_CLIENT_HELLO => 1,
     MT_SERVER_HELLO => 2,
     MT_NEW_SESSION_TICKET => 4,
+    MT_ENCRYPTED_EXTENSIONS => 8,
     MT_CERTIFICATE => 11,
     MT_SERVER_KEY_EXCHANGE => 12,
     MT_CERTIFICATE_REQUEST => 13,
@@ -46,6 +47,7 @@ my %message_type = (
     MT_CLIENT_HELLO, "ClientHello",
     MT_SERVER_HELLO, "ServerHello",
     MT_NEW_SESSION_TICKET, "NewSessionTicket",
+    MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions",
     MT_CERTIFICATE, "Certificate",
     MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
     MT_CERTIFICATE_REQUEST, "CertificateRequest",
@@ -58,16 +60,27 @@ my %message_type = (
 );
 
 use constant {
+    EXT_SERVER_NAME => 0,
     EXT_STATUS_REQUEST => 5,
     EXT_SUPPORTED_GROUPS => 10,
+    EXT_EC_POINT_FORMATS => 11,
+    EXT_SRP => 12,
+    EXT_SIG_ALGS => 13,
+    EXT_USE_SRTP => 14,
+    EXT_ALPN => 16,
+    EXT_SCT => 18,
+    EXT_PADDING => 21,
     EXT_ENCRYPT_THEN_MAC => 22,
     EXT_EXTENDED_MASTER_SECRET => 23,
     EXT_SESSION_TICKET => 35,
-    EXT_SUPPORTED_VERSIONS => 43,
     EXT_KEY_SHARE => 40,
-    # This extension does not exist and isn't recognised by OpenSSL.
-    # We use it to test handling of duplicate extensions.
-    EXT_DUPLICATE_EXTENSION => 1234
+    EXT_SUPPORTED_VERSIONS => 43,
+    EXT_RENEGOTIATE => 65281,
+    EXT_NPN => 13172,
+    # This extension is an unofficial extension only ever written by OpenSSL
+    # (i.e. not read), and even then only when enabled. We use it to test
+    # handling of duplicate extensions.
+    EXT_DUPLICATE_EXTENSION => 0xfde8
 };
 
 my $payload = "";
@@ -174,7 +187,7 @@ sub get_messages
                 $recoffset += 4;
                 $payload = "";
                 
-                if ($recoffset < $record->decrypt_len) {
+                if ($recoffset <= $record->decrypt_len) {
                     #Some payload data is present in this record
                     if ($record->decrypt_len - $recoffset >= $messlen) {
                         #We can complete the message with this record
@@ -242,6 +255,15 @@ sub create_message
             [@message_frag_lens]
         );
         $message->parse();
+    } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) {
+        $message = TLSProxy::EncryptedExtensions->new(
+            $server,
+            $data,
+            [@message_rec_list],
+            $startoffset,
+            [@message_frag_lens]
+        );
+        $message->parse();
     } elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
         $message = TLSProxy::ServerKeyExchange->new(
             $server,
diff --git a/util/TLSProxy/Proxy.pm b/util/TLSProxy/Proxy.pm
index ccfc5c9..6561589 100644
--- a/util/TLSProxy/Proxy.pm
+++ b/util/TLSProxy/Proxy.pm
@@ -17,6 +17,7 @@ use TLSProxy::Record;
 use TLSProxy::Message;
 use TLSProxy::ClientHello;
 use TLSProxy::ServerHello;
+use TLSProxy::EncryptedExtensions;
 use TLSProxy::ServerKeyExchange;
 use TLSProxy::NewSessionTicket;
 
@@ -44,6 +45,7 @@ sub new
         clientflags => "",
         serverconnects => 1,
         serverpid => 0,
+        reneg => 0,
 
         #Public read
         execute => $execute,
@@ -120,6 +122,7 @@ sub clear
     $self->{serverflags} = "";
     $self->{serverconnects} = 1;
     $self->{serverpid} = 0;
+    $self->{reneg} = 0;
 }
 
 sub restart
@@ -153,7 +156,8 @@ sub start
         my $execcmd = $self->execute
             ." s_server -no_comp -rev -engine ossltest -accept "
             .($self->server_port)
-            ." -cert ".$self->cert." -naccept ".$self->serverconnects;
+            ." -cert ".$self->cert." -cert2 ".$self->cert
+            ." -naccept ".$self->serverconnects;
         if ($self->ciphers ne "") {
             $execcmd .= " -cipher ".$self->ciphers;
         }
@@ -203,7 +207,13 @@ sub clientstart
                     or die "Failed to redirect stdout: $!";
                 open(STDERR, ">&STDOUT");
             }
-            my $execcmd = "echo test | ".$self->execute
+            my $echostr;
+            if ($self->reneg()) {
+                $echostr = "R";
+            } else {
+                $echostr = "test";
+            }
+            my $execcmd = "echo ".$echostr." | ".$self->execute
                  ." s_client -engine ossltest -connect "
                  .($self->proxy_addr).":".($self->proxy_port);
             if ($self->cipherc ne "") {
@@ -400,7 +410,7 @@ sub proxy_addr
 {
     my $self = shift;
     if (@_) {
-      $self->{proxy_addr} = shift;
+        $self->{proxy_addr} = shift;
     }
     return $self->{proxy_addr};
 }
@@ -408,7 +418,7 @@ sub proxy_port
 {
     my $self = shift;
     if (@_) {
-      $self->{proxy_port} = shift;
+        $self->{proxy_port} = shift;
     }
     return $self->{proxy_port};
 }
@@ -416,7 +426,7 @@ sub server_addr
 {
     my $self = shift;
     if (@_) {
-      $self->{server_addr} = shift;
+        $self->{server_addr} = shift;
     }
     return $self->{server_addr};
 }
@@ -424,7 +434,7 @@ sub server_port
 {
     my $self = shift;
     if (@_) {
-      $self->{server_port} = shift;
+        $self->{server_port} = shift;
     }
     return $self->{server_port};
 }
@@ -432,7 +442,7 @@ sub filter
 {
     my $self = shift;
     if (@_) {
-      $self->{filter} = shift;
+        $self->{filter} = shift;
     }
     return $self->{filter};
 }
@@ -440,7 +450,7 @@ sub cipherc
 {
     my $self = shift;
     if (@_) {
-      $self->{cipherc} = shift;
+        $self->{cipherc} = shift;
     }
     return $self->{cipherc};
 }
@@ -448,7 +458,7 @@ sub ciphers
 {
     my $self = shift;
     if (@_) {
-      $self->{ciphers} = shift;
+        $self->{ciphers} = shift;
     }
     return $self->{ciphers};
 }
@@ -456,7 +466,7 @@ sub serverflags
 {
     my $self = shift;
     if (@_) {
-      $self->{serverflags} = shift;
+        $self->{serverflags} = shift;
     }
     return $self->{serverflags};
 }
@@ -464,7 +474,7 @@ sub clientflags
 {
     my $self = shift;
     if (@_) {
-      $self->{clientflags} = shift;
+        $self->{clientflags} = shift;
     }
     return $self->{clientflags};
 }
@@ -472,7 +482,7 @@ sub serverconnects
 {
     my $self = shift;
     if (@_) {
-      $self->{serverconnects} = shift;
+        $self->{serverconnects} = shift;
     }
     return $self->{serverconnects};
 }
@@ -492,7 +502,7 @@ sub serverpid
 {
     my $self = shift;
     if (@_) {
-      $self->{serverpid} = shift;
+        $self->{serverpid} = shift;
     }
     return $self->{serverpid};
 }
@@ -506,12 +516,23 @@ sub fill_known_data
     }
     return $ret;
 }
+
 sub is_tls13
 {
     my $class = shift;
     if (@_) {
-      $is_tls13 = shift;
+        $is_tls13 = shift;
     }
     return $is_tls13;
 }
+
+sub reneg
+{
+    my $self = shift;
+    if (@_) {
+        $self->{reneg} = shift;
+    }
+    return $self->{reneg};
+}
+
 1;
diff --git a/util/TLSProxy/ServerHello.pm b/util/TLSProxy/ServerHello.pm
index a1bc7b3..5a038c9 100644
--- a/util/TLSProxy/ServerHello.pm
+++ b/util/TLSProxy/ServerHello.pm
@@ -45,16 +45,30 @@ sub parse
     my $self = shift;
     my $ptr = 2;
     my ($server_version) = unpack('n', $self->data);
+
+    # TODO(TLS1.3): Replace this reference to draft version before release
+    if ($server_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) {
+        $server_version = TLSProxy::Record::VERS_TLS_1_3;
+        TLSProxy::Proxy->is_tls13(1);
+    }
+
     my $random = substr($self->data, $ptr, 32);
     $ptr += 32;
-    my $session_id_len = unpack('C', substr($self->data, $ptr));
-    $ptr++;
-    my $session = substr($self->data, $ptr, $session_id_len);
-    $ptr += $session_id_len;
+    my $session_id_len = 0;
+    my $session = "";
+    if (!TLSProxy::Proxy->is_tls13()) {
+        $session_id_len = unpack('C', substr($self->data, $ptr));
+        $ptr++;
+        $session = substr($self->data, $ptr, $session_id_len);
+        $ptr += $session_id_len;
+    }
     my $ciphersuite = unpack('n', substr($self->data, $ptr));
     $ptr += 2;
-    my $comp_meth = unpack('C', substr($self->data, $ptr));
-    $ptr++;
+    my $comp_meth = 0;
+    if (!TLSProxy::Proxy->is_tls13()) {
+        $comp_meth = unpack('C', substr($self->data, $ptr));
+        $ptr++;
+    }
     my $extensions_len = unpack('n', substr($self->data, $ptr));
     if (!defined $extensions_len) {
         $extensions_len = 0;
@@ -94,11 +108,9 @@ sub parse
 
     $self->process_data();
 
-    # TODO(TLS1.3): Replace this reference to draft version before release
-    if ($server_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) {
+    if (TLSProxy::Proxy->is_tls13()) {
         TLSProxy::Record->server_encrypting(1);
         TLSProxy::Record->client_encrypting(1);
-        TLSProxy::Proxy->is_tls13(1);
     }
 
     print "    Server Version:".$server_version."\n";
@@ -125,10 +137,14 @@ sub set_message_contents
 
     $data = pack('n', $self->server_version);
     $data .= $self->random;
-    $data .= pack('C', $self->session_id_len);
-    $data .= $self->session;
+    if (!TLSProxy::Proxy->is_tls13()) {
+        $data .= pack('C', $self->session_id_len);
+        $data .= $self->session;
+    }
     $data .= pack('n', $self->ciphersuite);
-    $data .= pack('C', $self->comp_meth);
+    if (!TLSProxy::Proxy->is_tls13()) {
+        $data .= pack('C', $self->comp_meth);
+    }
 
     foreach my $key (keys %{$self->extension_data}) {
         my $extdata = ${$self->extension_data}{$key};
@@ -152,9 +168,9 @@ sub server_version
 {
     my $self = shift;
     if (@_) {
-      $self->{client_version} = shift;
+      $self->{server_version} = shift;
     }
-    return $self->{client_version};
+    return $self->{server_version};
 }
 sub random
 {


More information about the openssl-commits mailing list