[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Mon Jan 30 10:22:41 UTC 2017


The branch master has been updated
       via  1f04f23ef42564c5e9c186ec290a7a17bcf56b0f (commit)
       via  1b8bacff8cbab3d3bf4d2566be240a35c2f65b88 (commit)
       via  40f805ad924e228d5e77c8f87bd4413b5767ac65 (commit)
       via  61c3264970c41b3c6b8a09e58ea38fbf2ec68041 (commit)
       via  fed60a781c3da1e91aa90df68f062bf577a2b24a (commit)
       via  34f7245ba0a5381867e1ea0b7520106218e5bbb1 (commit)
       via  3ae6b5f800a88a8dac109aeb3ea758469ab1cbb8 (commit)
       via  1a9f457c6656a0905102c8850ca586eda1e3ba91 (commit)
       via  1a3392c878e8421c2e5730fde5accd4ab77c2875 (commit)
       via  342543426d19ad948e3e7a37209baa78d0032d86 (commit)
       via  e463cb39d32d3621183e9a1d487daae13ff716e3 (commit)
       via  2c0980d2fad0ed7d87f32a28f0d4f4527b32b9d9 (commit)
       via  ddf6ec006963d49e8b0dce55fe22fb8e844c3fbf (commit)
       via  1f5b44e943d911c3d0bf1445a6dab60798a66408 (commit)
       via  6df55cac1a2c4441a70d15875ab22530251509ce (commit)
       via  9ac6244b575486dcdbd600c36da78776fde32e11 (commit)
       via  79495812fbf7804609157510657fae4a11fec0b7 (commit)
       via  a23bb15abe873dc1ba6c7e5b49dfb8286eab1490 (commit)
       via  1c361b4a39d0db647e8e91a6215976544f4dfc53 (commit)
       via  93fa7e8dbed49ff6007f49c7ed36a87cd1df693e (commit)
       via  dd1e75bd8e2297bdf3da49dc199ef0fd0e94e998 (commit)
       via  b05e4ce6e14c78f15f40b73ba6696283d0e4589f (commit)
       via  59db06f160e1572a633ca3325fa4dc0dba80f2f1 (commit)
       via  4b7ffd8bbeb1c64261e10ef2050312bd183abeed (commit)
       via  534a43ffeaec03e50768ccf84d431f96f11256e3 (commit)
       via  4086b42b2d58773bee8463f69eee4bf8c299b589 (commit)
       via  081912943f951a49420b1f7d89288bab47f67500 (commit)
       via  128ae2769270f467982601b743964fb840aa2926 (commit)
       via  b3ad72ce1de399322c4362acc2d4d792f7f14893 (commit)
       via  0247086d9a0713e18a0f16949039a40fdb63ff7e (commit)
       via  1053a6e2281d81cd5d04d2d90da2c4905c9c3561 (commit)
       via  71c94d3c6115ab853bbdc2e0e1e26da2c8aba76a (commit)
       via  f4bbb37c4c95ea8cdb4b3470098a1b5d7d1977ed (commit)
       via  4ff65f77b62df12ad75ec232b38627c5fe131041 (commit)
       via  fc24f0bf45085c0f6272af8bb3ff03602face505 (commit)
       via  ec15acb6bc554b8f87a519c3519f5bf4d367ded9 (commit)
       via  a2b7e65526d92123f143cc7f248b4ac017372faf (commit)
       via  be62b22b527e89061f88c0b9eaefb0410982f41e (commit)
       via  f05bcf0f4581664f429154cdb689faef242cf843 (commit)
       via  e7a28df70bcf8677df6c5270eff8bbe8858b8fe9 (commit)
       via  de1df7e9f2d03d2eb368093b0268de333f6f1b18 (commit)
       via  30f05b19d3bad0fb0b223f6b0c5c68bb667c3a5a (commit)
       via  b2f7e8c0fe2f4e8d3d14fa30805211daa5456ffa (commit)
       via  cc2455bfa8cb4d62792dee533e9262f470e78e72 (commit)
       via  cda6b99867e5f353c9c9da7127a92c4bf902a2f4 (commit)
       via  c7f47786a5e5f68dc33091ffb2a42e51a73de3a1 (commit)
       via  0386aad1ab472a4059da85131cceca15aab5ebae (commit)
       via  97997489748c79466bc18789e1f44d742887a32d (commit)
      from  26967dc3e710a69515e477055893a2691f010162 (commit)


- Log -----------------------------------------------------------------
commit 1f04f23ef42564c5e9c186ec290a7a17bcf56b0f
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 15:23:25 2017 +0000

    Expand comment in tls_process_hello_req()
    
    Following review feedback.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1b8bacff8cbab3d3bf4d2566be240a35c2f65b88
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 15:18:51 2017 +0000

    Add a TODO around validating the ticket age
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 40f805ad924e228d5e77c8f87bd4413b5767ac65
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 15:17:51 2017 +0000

    Various style fixes following review feedback
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 61c3264970c41b3c6b8a09e58ea38fbf2ec68041
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 12:11:23 2017 +0000

    Remove unneccessary comments
    
    Now we're using an enum the values themselves are self explanatory
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit fed60a781c3da1e91aa90df68f062bf577a2b24a
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 12:05:52 2017 +0000

    Use for loop in WPACKET_fill_lengths instead of do...while
    
    Based on review feedback
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 34f7245ba0a5381867e1ea0b7520106218e5bbb1
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 27 11:58:04 2017 +0000

    Move the SSL3_CK_CIPHERSUITE_FLAG out of public header
    
    The newly added SSL3_CK_CIPHERSUITE_FLAG shouldn't be in a public header
    file
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 3ae6b5f800a88a8dac109aeb3ea758469ab1cbb8
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 25 10:44:46 2017 +0000

    Add a test for the PSK kex modes extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1a9f457c6656a0905102c8850ca586eda1e3ba91
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 25 11:56:23 2017 +0000

    If we have no suitable PSK kex modes then don't attempt to resume
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1a3392c878e8421c2e5730fde5accd4ab77c2875
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 23 16:59:35 2017 +0000

    Fix <= TLS1.2 break
    
    Changing the value of SSL_MAX_MASTER_KEY_LENGTH had some unexpected
    side effects in the <=TLS1.2 code which apparently relies on this being
    48 for interoperability. Therefore create a new define for the TLSv1.3
    resumption master secret which can be up to 64 bytes.
    
    Found through the boring test suite.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 342543426d19ad948e3e7a37209baa78d0032d86
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 23 15:09:25 2017 +0000

    Add a test for WPACKET_fill_lengths()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit e463cb39d32d3621183e9a1d487daae13ff716e3
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 23 14:53:44 2017 +0000

    Enable wpacket test on shared builds
    
    Now that we support internal tests properly, we can test wpacket even in
    shared builds.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 2c0980d2fad0ed7d87f32a28f0d4f4527b32b9d9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 17:00:03 2017 +0000

    Make calls to SSL_renegotiate() error out for TLSv1.3
    
    When we have support for KeyUpdate we might consider doing that instead.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit ddf6ec006963d49e8b0dce55fe22fb8e844c3fbf
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 16:01:27 2017 +0000

    Make the "ticket" function return codes clearer
    
    Remove "magic" return values and use an enum instead.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1f5b44e943d911c3d0bf1445a6dab60798a66408
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 16:02:07 2017 +0000

    Miscellaneous style tweaks based on feedback received
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 6df55cac1a2c4441a70d15875ab22530251509ce
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 13:53:38 2017 +0000

    Ensure the al variable is properly ininitialised in all code paths
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 9ac6244b575486dcdbd600c36da78776fde32e11
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 13:50:47 2017 +0000

    Ensure the age_add variable is properly initialised
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 79495812fbf7804609157510657fae4a11fec0b7
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 13:48:41 2017 +0000

    Re-enable resumption for TLS1.3 CT tests
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit a23bb15abe873dc1ba6c7e5b49dfb8286eab1490
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 12:11:49 2017 +0000

    Add testing of TLSv1.3 resumption in test_tls13messages
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1c361b4a39d0db647e8e91a6215976544f4dfc53
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 20 12:08:51 2017 +0000

    Add a capability for TLSProxy to wait for a session before killing s_client
    
    TLSProxy normally fires off s_client, which creates a connection to the
    server. TLSProxy also pipes some data to send to the process and s_client
    automatically exits when the pipe hits eof. Unfortunately this means that
    it sends the data and closes before it has processed the NewSessionTicket
    returned from the server in TLSv1.3. This commits adds an option for
    s_client to stay loaded until the sesion has been processed. A side effect
    of this is that s_client never sends a close_notify in this mode, so we
    count success as seeing that data has been transferred.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 93fa7e8dbed49ff6007f49c7ed36a87cd1df693e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 16:49:57 2017 +0000

    Re-enable test_ssl_new resumption tests for TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit dd1e75bd8e2297bdf3da49dc199ef0fd0e94e998
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 16:44:25 2017 +0000

    Remove a TLS1.3 TODO that is now completed
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit b05e4ce6e14c78f15f40b73ba6696283d0e4589f
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 16:02:27 2017 +0000

    Re-enable TLSv1.3 session resumption related tests in sslapitest
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 59db06f160e1572a633ca3325fa4dc0dba80f2f1
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 16:00:19 2017 +0000

    Update create_ssl_connection() to make sure its gets a session
    
    In TLSv1.3 the connection will be created before the session is
    established. In OpenSSL we send the NewSessionTicket message immediately
    after the client finished has been received. Therefore we change
    create_ssl_connection() to attempt a read of application data after the
    handshake has completed. We expect this to fail but it will force the
    reading of the NewSessionTicket and the session to be set up.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 4b7ffd8bbeb1c64261e10ef2050312bd183abeed
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 15:02:16 2017 +0000

    Re-enable ALPN resumption tests where we are using TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 534a43ffeaec03e50768ccf84d431f96f11256e3
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 15:01:55 2017 +0000

    Always ensure that session->cipher is set
    
    If we have deserialized the SSL_SESSION then in some circumstances the
    session->cipher value is NULL. We were patching up in some places but not
    in others. We should just do it as part of loading the SSL_SESSION.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 4086b42b2d58773bee8463f69eee4bf8c299b589
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 12:12:35 2017 +0000

    Tweak a comment
    
    psk_kex_mode stores the available modes - not the one which we selected.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 081912943f951a49420b1f7d89288bab47f67500
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 11:23:06 2017 +0000

    Use the correct session resumption mechanism
    
    Don't attempt to add a TLS1.3 session to a TLS1.2 ClientHello session
    ticket extensions. Similarly don't add a TLS1.2 session to a TLS1.3
    psk extension.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 128ae2769270f467982601b743964fb840aa2926
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 10:46:53 2017 +0000

    Move session version consistency check
    
    Make sure the session version consistency check is inside
    ssl_get_prev_session(). Also fixes a bug where an inconsistent version can
    cause a seg fault in TLSv1.3.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit b3ad72ce1de399322c4362acc2d4d792f7f14893
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 19 10:07:50 2017 +0000

    Set the kex modes on the client too.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 0247086d9a0713e18a0f16949039a40fdb63ff7e
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 18 17:22:18 2017 +0000

    Implement server side of PSK extension construction
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 1053a6e2281d81cd5d04d2d90da2c4905c9c3561
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 18 16:28:23 2017 +0000

    Implement Server side of PSK extension parsing
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 71c94d3c6115ab853bbdc2e0e1e26da2c8aba76a
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 18 11:52:50 2017 +0000

    Make sure we also cleanse the finished key
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit f4bbb37c4c95ea8cdb4b3470098a1b5d7d1977ed
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 18 11:31:37 2017 +0000

    Provide a key_share extension finaliser
    
    This mops up various edge cases with key_shares and makes sure we still
    generate the handshake secret if we haven't been provided with one but we
    have a PSK.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 4ff65f77b62df12ad75ec232b38627c5fe131041
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 18 09:38:53 2017 +0000

    Add support for client side parsing of the PSK extension
    
    Requires a refactor of the ServerHello parsing, so that we parse first and
    then subsequently process. This is because the resumption information is
    held in the extensions block which is parsed last - but we need to know that
    information earlier.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit fc24f0bf45085c0f6272af8bb3ff03602face505
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jan 17 10:43:37 2017 +0000

    Add support for the age_add field
    
    Update SSL_SESSION to store the age_add and use it where needed.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit ec15acb6bc554b8f87a519c3519f5bf4d367ded9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 17:00:49 2017 +0000

    Construct the client side psk extension for TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit a2b7e65526d92123f143cc7f248b4ac017372faf
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 16:59:18 2017 +0000

    Provide a new WPACKET function for filling in all the lengths
    
    For the psk extension we need to fill in all the lengths of the message so
    far, even though we haven't closed the WPACKET yet. This provides a function
    to do that.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit be62b22b527e89061f88c0b9eaefb0410982f41e
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 14:25:15 2017 +0000

    Update the s_client -sess_out feature to work for TLSv1.3
    
    Previously "-sess_out" wrote out the session as soon as the handshake
    finished. In TLSv1.3 this won't work because the NewSessionTicket message
    arrives post-handshake. Instead we use the session callback mechanism to
    do this.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit f05bcf0f4581664f429154cdb689faef242cf843
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 13:49:44 2017 +0000

    Never send a session id in TLS1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit e7a28df70bcf8677df6c5270eff8bbe8858b8fe9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 13:34:49 2017 +0000

    Add a TODO around handling of SSL_get_session() and SSL_get1_session()
    
    These functions are problematic in TLSv1.3 because the server sends the
    NewSessionTicket message after the handshake has finished.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit de1df7e9f2d03d2eb368093b0268de333f6f1b18
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 13:32:11 2017 +0000

    Process incoming NewSessionTicket messages on the client side
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 30f05b19d3bad0fb0b223f6b0c5c68bb667c3a5a
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 13 09:19:10 2017 +0000

    Create the NewSessionTicket message in TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit b2f7e8c0fe2f4e8d3d14fa30805211daa5456ffa
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jan 12 15:28:48 2017 +0000

    Add support for the psk_key_exchange_modes extension
    
    This is required for the later addition of resumption support.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit cc2455bfa8cb4d62792dee533e9262f470e78e72
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 11 17:18:19 2017 +0000

    Move TLSv1.3 Session Ticket processing into the state machine
    
    We still ignore it for now, but at least its in the right place.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit cda6b99867e5f353c9c9da7127a92c4bf902a2f4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jan 11 16:29:38 2017 +0000

    Disable requests for renegotiation in TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit c7f47786a5e5f68dc33091ffb2a42e51a73de3a1
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jan 10 23:02:28 2017 +0000

    Move state machine knowledge out of the record layer
    
    The record layer was making decisions that should really be left to the
    state machine around unexpected handshake messages that are received after
    the initial handshake (i.e. renegotiation related messages). This commit
    removes that code from the record layer and updates the state machine
    accordingly. This simplifies the state machine and paves the way for
    handling other messages post-handshake such as the NewSessionTicket in
    TLSv1.3.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 0386aad1ab472a4059da85131cceca15aab5ebae
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jan 10 14:58:17 2017 +0000

    Remove use of the SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS flag
    
    This flag is never set by anything so remove it.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

commit 97997489748c79466bc18789e1f44d742887a32d
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 6 16:22:23 2017 +0000

    ChangeCipherSpec is not allowed in TLSv1.3
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2259)

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

Summary of changes:
 apps/s_client.c                      |  41 ++++--
 include/openssl/ssl.h                |  16 ++-
 include/openssl/ssl3.h               |   1 +
 include/openssl/tls1.h               |   2 +
 ssl/packet.c                         |  39 +++--
 ssl/packet_locl.h                    |   9 ++
 ssl/record/rec_layer_d1.c            |  86 +++--------
 ssl/record/rec_layer_s3.c            | 103 +++----------
 ssl/s3_lib.c                         |  58 +++++---
 ssl/ssl_asn1.c                       |  12 +-
 ssl/ssl_err.c                        |  11 ++
 ssl/ssl_lib.c                        |  16 ++-
 ssl/ssl_locl.h                       |  89 ++++++++++--
 ssl/ssl_sess.c                       | 121 ++++++++--------
 ssl/statem/extensions.c              | 161 ++++++++++++++++++++-
 ssl/statem/extensions_clnt.c         | 177 +++++++++++++++++++++--
 ssl/statem/extensions_srvr.c         | 182 +++++++++++++++++++----
 ssl/statem/statem.c                  |  66 ++-------
 ssl/statem/statem.h                  |   9 +-
 ssl/statem/statem_clnt.c             | 270 ++++++++++++++++++++++++++---------
 ssl/statem/statem_dtls.c             |   6 +-
 ssl/statem/statem_lib.c              |  92 +++++++++---
 ssl/statem/statem_locl.h             |  19 ++-
 ssl/statem/statem_srvr.c             | 104 +++++++++-----
 ssl/t1_lib.c                         |  76 +++++-----
 ssl/t1_trce.c                        |  15 ++
 ssl/tls13_enc.c                      | 113 +++++++--------
 test/build.info                      |  12 +-
 test/recipes/70-test_tls13kexmodes.t | 243 +++++++++++++++++++++++++++++++
 test/recipes/70-test_tls13messages.t |  24 +++-
 test/recipes/70-test_wpacket.t       |   4 +-
 test/ssl-tests/06-sni-ticket.conf.in |   1 -
 test/ssl-tests/09-alpn.conf          |   8 --
 test/ssl-tests/09-alpn.conf.in       |  16 ---
 test/ssl-tests/12-ct.conf            |   3 -
 test/ssl-tests/12-ct.conf.in         |   9 --
 test/ssl-tests/protocol_version.pm   |  16 ---
 test/sslapitest.c                    |   6 -
 test/ssltestlib.c                    |  17 +++
 test/testlib/checkhandshake.pm       |   8 ++
 test/tls13secretstest.c              |  10 +-
 test/wpackettest.c                   |  21 +++
 util/TLSProxy/Message.pm             |  18 ++-
 util/TLSProxy/Proxy.pm               |  31 ++++
 44 files changed, 1680 insertions(+), 661 deletions(-)
 create mode 100755 test/recipes/70-test_tls13kexmodes.t

diff --git a/apps/s_client.c b/apps/s_client.c
index d2f10a6..99770b9 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -90,6 +90,7 @@ static char *keymatexportlabel = NULL;
 static int keymatexportlen = 20;
 static BIO *bio_c_out = NULL;
 static int c_quiet = 0;
+static char *sess_out = NULL;
 
 static void print_stuff(BIO *berr, SSL *con, int full);
 #ifndef OPENSSL_NO_OCSP
@@ -779,6 +780,24 @@ static void freeandcopy(char **dest, const char *source)
         *dest = OPENSSL_strdup(source);
 }
 
+static int new_session_cb(SSL *S, SSL_SESSION *sess)
+{
+    BIO *stmp = BIO_new_file(sess_out, "w");
+
+    if (stmp == NULL) {
+        BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
+    } else {
+        PEM_write_bio_SSL_SESSION(stmp, sess);
+        BIO_free(stmp);
+    }
+
+    /*
+     * We always return a "fail" response so that the session gets freed again
+     * because we haven't used the reference.
+     */
+    return 0;
+}
+
 int s_client_main(int argc, char **argv)
 {
     BIO *sbio;
@@ -804,7 +823,7 @@ int s_client_main(int argc, char **argv)
     char *port = OPENSSL_strdup(PORT);
     char *inrand = NULL;
     char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL;
-    char *sess_in = NULL, *sess_out = NULL, *crl_file = NULL, *p;
+    char *sess_in = NULL, *crl_file = NULL, *p;
     char *xmpphost = NULL;
     const char *ehlo = "mail.example.com";
     struct timeval timeout, *timeoutp;
@@ -1674,6 +1693,17 @@ int s_client_main(int argc, char **argv)
         }
     }
 
+    /*
+     * In TLSv1.3 NewSessionTicket messages arrive after the handshake and can
+     * come at any time. Therefore we use a callback to write out the session
+     * when we know about it. This approach works for < TLSv1.3 as well.
+     */
+    if (sess_out) {
+        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT
+                                            | SSL_SESS_CACHE_NO_INTERNAL_STORE);
+        SSL_CTX_sess_set_new_cb(ctx, new_session_cb);
+    }
+
     con = SSL_new(ctx);
     if (sess_in) {
         SSL_SESSION *sess;
@@ -2168,15 +2198,6 @@ int s_client_main(int argc, char **argv)
                                tlsextcbp.ack ? "" : "not ");
                 }
 
-                if (sess_out) {
-                    BIO *stmp = BIO_new_file(sess_out, "w");
-                    if (stmp) {
-                        PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
-                        BIO_free(stmp);
-                    } else
-                        BIO_printf(bio_err, "Error writing session file %s\n",
-                                   sess_out);
-                }
                 if (c_brief) {
                     BIO_puts(bio_err, "CONNECTION ESTABLISHED\n");
                     print_ssl_summary(con);
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 86ffcb9..9d9e193 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -77,6 +77,7 @@ extern "C" {
 # define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES     (512/8)
 # define SSL_MAX_KEY_ARG_LENGTH                  8
 # define SSL_MAX_MASTER_KEY_LENGTH               48
+# define TLS13_MAX_RESUMPTION_MASTER_LENGTH      64
 
 /* The maximum number of encrypt/decrypt pipelines we can support */
 # define SSL_MAX_PIPELINES  32
@@ -878,7 +879,8 @@ typedef enum {
     TLS_ST_SW_ENCRYPTED_EXTENSIONS,
     TLS_ST_CR_ENCRYPTED_EXTENSIONS,
     TLS_ST_CR_CERT_VRFY,
-    TLS_ST_SW_CERT_VRFY
+    TLS_ST_SW_CERT_VRFY,
+    TLS_ST_CR_HELLO_REQ
 } OSSL_HANDSHAKE_STATE;
 
 /*
@@ -1647,7 +1649,7 @@ __owur STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s);
 
 __owur int SSL_do_handshake(SSL *s);
 int SSL_renegotiate(SSL *s);
-__owur int SSL_renegotiate_abbreviated(SSL *s);
+int SSL_renegotiate_abbreviated(SSL *s);
 __owur int SSL_renegotiate_pending(SSL *s);
 int SSL_shutdown(SSL *s);
 
@@ -2096,6 +2098,7 @@ int ERR_load_SSL_strings(void);
 # 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_KEY_SHARE                            503
 # define SSL_F_FINAL_RENEGOTIATE                          483
 # define SSL_F_FINAL_SIG_ALGS                             497
 # define SSL_F_NSS_KEYLOG_INT                             500
@@ -2280,6 +2283,8 @@ int ERR_load_SSL_strings(void);
 # 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_PSK_KEX_MODES           509
+# define SSL_F_TLS_CONSTRUCT_CTOS_PSK                     501
 # 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
@@ -2311,6 +2316,7 @@ int ERR_load_SSL_strings(void);
 # 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_PSK                     504
 # 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
@@ -2320,9 +2326,11 @@ int ERR_load_SSL_strings(void);
 # 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_PSK                         505
 # 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_PSK                         502
 # 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
@@ -2344,6 +2352,7 @@ int ERR_load_SSL_strings(void);
 # 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_HELLO_REQ                      507
 # define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
 # define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
 # define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
@@ -2355,7 +2364,9 @@ 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_PSK_DO_BINDER                          506
 # define SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT                450
+# define SSL_F_TLS_SETUP_HANDSHAKE                        508
 # define SSL_F_USE_CERTIFICATE_CHAIN_FILE                 220
 
 /* Reason codes. */
@@ -2378,6 +2389,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_BAD_LENGTH                                 271
 # define SSL_R_BAD_PACKET_LENGTH                          115
 # define SSL_R_BAD_PROTOCOL_VERSION_NUMBER                116
+# define SSL_R_BAD_PSK_IDENTITY                           114
 # define SSL_R_BAD_RECORD_TYPE                            443
 # define SSL_R_BAD_RSA_ENCRYPT                            119
 # define SSL_R_BAD_SIGNATURE                              123
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index c005440..8d146be 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -256,6 +256,7 @@ extern "C" {
  */
 # define SSL3_CT_NUMBER                  9
 
+/* No longer used as of OpenSSL 1.1.1 */
 # define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS       0x0001
 
 /* Removed from OpenSSL 1.1.0 */
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 707fb96..328b266 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -177,7 +177,9 @@ extern "C" {
 
 /* As defined for TLS1.3 */
 # define TLSEXT_TYPE_key_share                   40
+# define TLSEXT_TYPE_psk                         41
 # define TLSEXT_TYPE_supported_versions          43
+# define TLSEXT_TYPE_psk_kex_modes               45
 
 /* Temporary extension type */
 # define TLSEXT_TYPE_renegotiate                 0xff01
diff --git a/ssl/packet.c b/ssl/packet.c
index 12321e7..3479f1f 100644
--- a/ssl/packet.c
+++ b/ssl/packet.c
@@ -180,12 +180,13 @@ static int put_value(unsigned char *data, size_t value, size_t len)
 
 
 /*
- * Internal helper function used by WPACKET_close() and WPACKET_finish() to
- * close a sub-packet and write out its length if necessary.
+ * Internal helper function used by WPACKET_close(), WPACKET_finish() and
+ * WPACKET_fill_lengths() to close a sub-packet and write out its length if
+ * necessary. If |doclose| is 0 then it goes through the motions of closing
+ * (i.e. it fills in all the lengths), but doesn't actually close anything.
  */
-static int wpacket_intern_close(WPACKET *pkt)
+static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose)
 {
-    WPACKET_SUB *sub = pkt->subs;
     size_t packlen = pkt->written - sub->pwritten;
 
     if (packlen == 0
@@ -194,6 +195,10 @@ static int wpacket_intern_close(WPACKET *pkt)
 
     if (packlen == 0
             && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
+        /* We can't handle this case. Return an error */
+        if (!doclose)
+            return 0;
+
         /* Deallocate any bytes allocated for the length of the WPACKET */
         if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
             pkt->written -= sub->lenbytes;
@@ -211,8 +216,26 @@ static int wpacket_intern_close(WPACKET *pkt)
                               sub->lenbytes))
             return 0;
 
-    pkt->subs = sub->parent;
-    OPENSSL_free(sub);
+    if (doclose) {
+        pkt->subs = sub->parent;
+        OPENSSL_free(sub);
+    }
+
+    return 1;
+}
+
+int WPACKET_fill_lengths(WPACKET *pkt)
+{
+    WPACKET_SUB *sub;
+
+    assert(pkt->subs != NULL);
+    if (pkt->subs == NULL)
+        return 0;
+
+    for (sub = pkt->subs; sub != NULL; sub = sub->parent) {
+        if (!wpacket_intern_close(pkt, sub, 0))
+            return 0;
+    }
 
     return 1;
 }
@@ -226,7 +249,7 @@ int WPACKET_close(WPACKET *pkt)
     if (pkt->subs == NULL || pkt->subs->parent == NULL)
         return 0;
 
-    return wpacket_intern_close(pkt);
+    return wpacket_intern_close(pkt, pkt->subs, 1);
 }
 
 int WPACKET_finish(WPACKET *pkt)
@@ -240,7 +263,7 @@ int WPACKET_finish(WPACKET *pkt)
     if (pkt->subs == NULL || pkt->subs->parent != NULL)
         return 0;
 
-    ret = wpacket_intern_close(pkt);
+    ret = wpacket_intern_close(pkt, pkt->subs, 1);
     if (ret) {
         OPENSSL_free(pkt->subs);
         pkt->subs = NULL;
diff --git a/ssl/packet_locl.h b/ssl/packet_locl.h
index 61233d9..67b4999 100644
--- a/ssl/packet_locl.h
+++ b/ssl/packet_locl.h
@@ -700,6 +700,15 @@ int WPACKET_close(WPACKET *pkt);
 int WPACKET_finish(WPACKET *pkt);
 
 /*
+ * Iterate through all the sub-packets and write out their lengths as if they
+ * were being closed. The lengths will be overwritten with the final lengths
+ * when the sub-packets are eventually closed (which may be different if more
+ * data is added to the WPACKET). This function fails if a sub-packet is of 0
+ * length and WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH is set.
+ */
+int WPACKET_fill_lengths(WPACKET *pkt);
+
+/*
  * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
  * at the start of the sub-packet to store its length once we know it. Don't
  * call this directly. Use the convenience macros below instead.
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index 5d971fb..67846bd 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -14,6 +14,7 @@
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
 #include "record_locl.h"
+#include <assert.h>
 
 int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl)
 {
@@ -632,71 +633,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
      */
 
-    /* If we are a client, check for an incoming 'Hello Request': */
-    if ((!s->server) &&
-        (s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
-        (s->rlayer.d->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
-        (s->session != NULL) && (s->session->cipher != NULL)) {
-        s->rlayer.d->handshake_fragment_len = 0;
-
-        if ((s->rlayer.d->handshake_fragment[1] != 0) ||
-            (s->rlayer.d->handshake_fragment[2] != 0) ||
-            (s->rlayer.d->handshake_fragment[3] != 0)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
-            goto f_err;
-        }
-
-        /*
-         * no need to check sequence number on HELLO REQUEST messages
-         */
-
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                            s->rlayer.d->handshake_fragment, 4, s,
-                            s->msg_callback_arg);
-
-        if (SSL_is_init_finished(s) &&
-            !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
-            !s->s3->renegotiate) {
-            s->d1->handshake_read_seq++;
-            s->new_session = 1;
-            ssl3_renegotiate(s);
-            if (ssl3_renegotiate_check(s)) {
-                i = s->handshake_func(s);
-                if (i < 0)
-                    return i;
-                if (i == 0) {
-                    SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
-                    return -1;
-                }
-
-                if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
-                    if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
-                        /* no read-ahead left? */
-                        BIO *bio;
-                        /*
-                         * In the case where we try to read application data,
-                         * but we trigger an SSL handshake, we return -1 with
-                         * the retry option set.  Otherwise renegotiation may
-                         * cause nasty problems in the blocking world
-                         */
-                        s->rwstate = SSL_READING;
-                        bio = SSL_get_rbio(s);
-                        BIO_clear_retry_flags(bio);
-                        BIO_set_retry_read(bio);
-                        return -1;
-                    }
-                }
-            }
-        }
-        /*
-         * we either finished a handshake or ignored the request, now try
-         * again to obtain the (application) data we were asked for
-         */
-        goto start;
-    }
-
     if (s->rlayer.d->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) {
         int alert_level = s->rlayer.d->alert_fragment[0];
         int alert_descr = s->rlayer.d->alert_fragment[1];
@@ -838,12 +774,22 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
             goto start;
         }
 
-        if (SSL_is_init_finished(s) &&
-            !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) {
-            ossl_statem_set_in_init(s, 1);
-            s->renegotiate = 1;
-            s->new_session = 1;
+        /*
+         * To get here we must be trying to read app data but found handshake
+         * data. But if we're trying to read app data, and we're not in init
+         * (which is tested for at the top of this function) then init must be
+         * finished
+         */
+        assert(SSL_is_init_finished(s));
+        if (!SSL_is_init_finished(s)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
+            goto f_err;
         }
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
         i = s->handshake_func(s);
         if (i < 0)
             return i;
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index f0ac4a4..58a4716 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -8,6 +8,7 @@
  */
 
 #include <stdio.h>
+#include <assert.h>
 #include <limits.h>
 #include <errno.h>
 #define USE_SOCKETS
@@ -1223,7 +1224,8 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
 
     if (type == SSL3_RECORD_get_type(rr)
         || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
-            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) {
+            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL
+            && !SSL_IS_TLS13(s))) {
         /*
          * SSL3_RT_APPLICATION_DATA or
          * SSL3_RT_HANDSHAKE or
@@ -1370,85 +1372,12 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         }
     }
 
-    /*
-     * TODO(TLS1.3): Temporarily we will just ignore NewSessionTicket messages.
-     * Later we will want to process them.
-     */
-    if (!s->server && SSL_IS_TLS13(s) && s->rlayer.handshake_fragment_len >= 4
-            && s->rlayer.handshake_fragment[0] == SSL3_MT_NEWSESSION_TICKET) {
-        SSL3_RECORD_set_read(rr);
-        goto start;
-    }
-
     /*-
      * s->rlayer.handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
      * s->rlayer.alert_fragment_len == 2      iff  rr->type == SSL3_RT_ALERT.
      * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
      */
 
-    /* If we are a client, check for an incoming 'Hello Request': */
-    if ((!s->server) &&
-        (s->rlayer.handshake_fragment_len >= 4) &&
-        (s->rlayer.handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
-        (s->session != NULL) && (s->session->cipher != NULL)) {
-        s->rlayer.handshake_fragment_len = 0;
-
-        if ((s->rlayer.handshake_fragment[1] != 0) ||
-            (s->rlayer.handshake_fragment[2] != 0) ||
-            (s->rlayer.handshake_fragment[3] != 0)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
-            goto f_err;
-        }
-
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                            s->rlayer.handshake_fragment, 4, s,
-                            s->msg_callback_arg);
-
-        if (SSL_is_init_finished(s) &&
-            !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
-            !s->s3->renegotiate) {
-            ssl3_renegotiate(s);
-            if (ssl3_renegotiate_check(s)) {
-                i = s->handshake_func(s);
-                if (i < 0)
-                    return i;
-                if (i == 0) {
-                    SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
-                    return -1;
-                }
-
-                if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
-                    if (SSL3_BUFFER_get_left(rbuf) == 0) {
-                        /* no read-ahead left? */
-                        BIO *bio;
-                        /*
-                         * In the case where we try to read application data,
-                         * but we trigger an SSL handshake, we return -1 with
-                         * the retry option set.  Otherwise renegotiation may
-                         * cause nasty problems in the blocking world
-                         */
-                        s->rwstate = SSL_READING;
-                        bio = SSL_get_rbio(s);
-                        BIO_clear_retry_flags(bio);
-                        BIO_set_retry_read(bio);
-                        return -1;
-                    }
-                }
-            } else {
-                SSL3_RECORD_set_read(rr);
-            }
-        } else {
-            /* Does this ever happen? */
-            SSL3_RECORD_set_read(rr);
-        }
-        /*
-         * we either finished a handshake or ignored the request, now try
-         * again to obtain the (application) data we were asked for
-         */
-        goto start;
-    }
     /*
      * If we are a server and get a client hello when renegotiation isn't
      * allowed send back a no renegotiation alert and carry on. WARNING:
@@ -1458,6 +1387,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         SSL_is_init_finished(s) &&
         !s->s3->send_connection_binding &&
         (s->version > SSL3_VERSION) &&
+        !SSL_IS_TLS13(s) &&
         (s->rlayer.handshake_fragment_len >= 4) &&
         (s->rlayer.handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
         (s->session != NULL) && (s->session->cipher != NULL) &&
@@ -1556,16 +1486,27 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     }
 
     /*
-     * Unexpected handshake message (Client Hello, or protocol violation)
+     * Unexpected handshake message (ClientHello, NewSessionTicket (TLS1.3) or
+     * protocol violation)
      */
     if ((s->rlayer.handshake_fragment_len >= 4)
-        && !ossl_statem_get_in_handshake(s)) {
-        if (SSL_is_init_finished(s) &&
-            !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) {
-            ossl_statem_set_in_init(s, 1);
-            s->renegotiate = 1;
-            s->new_session = 1;
+            && !ossl_statem_get_in_handshake(s)) {
+        /*
+         * To get here we must be trying to read app data but found handshake
+         * data. But if we're trying to read app data, and we're not in init
+         * (which is tested for at the top of this function) then init must be
+         * finished
+         */
+        assert(SSL_is_init_finished(s));
+        if (!SSL_is_init_finished(s)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
+            goto f_err;
         }
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
         i = s->handshake_func(s);
         if (i < 0)
             return i;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 4010985..c4d4352 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3545,25 +3545,28 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
     return (1);
 }
 
+const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id)
+{
+    SSL_CIPHER c;
+
+    c.id = id;
+    return OBJ_bsearch_ssl_cipher_id(&c, ssl3_ciphers, SSL3_NUM_CIPHERS);
+}
+
 /*
  * This function needs to check if the ciphers required are actually
  * available
  */
 const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p)
 {
-    SSL_CIPHER c;
-    const SSL_CIPHER *cp;
-    uint32_t id;
-
-    id = 0x03000000 | ((uint32_t)p[0] << 8L) | (uint32_t)p[1];
-    c.id = id;
-    cp = OBJ_bsearch_ssl_cipher_id(&c, ssl3_ciphers, SSL3_NUM_CIPHERS);
-    return cp;
+    return ssl3_get_cipher_by_id(SSL3_CK_CIPHERSUITE_FLAG
+                                 | ((uint32_t)p[0] << 8L)
+                                 | (uint32_t)p[1]);
 }
 
 int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt, size_t *len)
 {
-    if ((c->id & 0xff000000) != 0x03000000) {
+    if ((c->id & 0xff000000) != SSL3_CK_CIPHERSUITE_FLAG) {
         *len = 0;
         return 1;
     }
@@ -3822,7 +3825,7 @@ int ssl3_write(SSL *s, const void *buf, size_t len, size_t *written)
 {
     clear_sys_error();
     if (s->s3->renegotiate)
-        ssl3_renegotiate_check(s);
+        ssl3_renegotiate_check(s, 0);
 
     return s->method->ssl_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len,
                                       written);
@@ -3835,7 +3838,7 @@ static int ssl3_read_internal(SSL *s, void *buf, size_t len, int peek,
 
     clear_sys_error();
     if (s->s3->renegotiate)
-        ssl3_renegotiate_check(s);
+        ssl3_renegotiate_check(s, 0);
     s->s3->in_read_app_data = 1;
     ret =
         s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
@@ -3874,21 +3877,26 @@ int ssl3_renegotiate(SSL *s)
     if (s->handshake_func == NULL)
         return (1);
 
-    if (s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
-        return (0);
-
     s->s3->renegotiate = 1;
     return (1);
 }
 
-int ssl3_renegotiate_check(SSL *s)
+/*
+ * Check if we are waiting to do a renegotiation and if so whether now is a
+ * good time to do it. If |initok| is true then we are being called from inside
+ * the state machine so ignore the result of SSL_in_init(s). Otherwise we
+ * should not do a renegotiation if SSL_in_init(s) is true. Returns 1 if we
+ * should do a renegotiation now and sets up the state machine for it. Otherwise
+ * returns 0.
+ */
+int ssl3_renegotiate_check(SSL *s, int initok)
 {
     int ret = 0;
 
     if (s->s3->renegotiate) {
         if (!RECORD_LAYER_read_pending(&s->rlayer)
             && !RECORD_LAYER_write_pending(&s->rlayer)
-            && !SSL_in_init(s)) {
+            && (initok || !SSL_in_init(s))) {
             /*
              * if we are the server, and we have sent a 'RENEGOTIATE'
              * message, we need to set the state machine into the renegotiate
@@ -3901,7 +3909,7 @@ int ssl3_renegotiate_check(SSL *s)
             ret = 1;
         }
     }
-    return (ret);
+    return ret;
 }
 
 /*
@@ -4098,13 +4106,17 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret)
     if (gensecret) {
         if (SSL_IS_TLS13(s)) {
             /*
-             * TODO(TLS1.3): For now we just use the default early_secret, this
-             * will need to change later when other early_secrets will be
-             * possible.
+             * If we are resuming then we already generated the early secret
+             * when we created the ClientHello, so don't recreate it.
              */
-            rv = tls13_generate_early_secret(s, NULL, 0)
-                 && tls13_generate_handshake_secret(s, pms, pmslen);
-            OPENSSL_free(pms);
+            if (!s->hit)
+                rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL,
+                                           0,
+                                           (unsigned char *)&s->early_secret);
+            else
+                rv = 1;
+
+            rv = rv && tls13_generate_handshake_secret(s, pms, pmslen);
         } else {
             /* Generate master secret and discard premaster */
             rv = ssl_generate_master_secret(s, pms, pmslen, 1);
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 401aeb5..73ba78d 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -55,6 +55,7 @@ typedef struct {
     long verify_result;
     ASN1_OCTET_STRING *tlsext_hostname;
     long tlsext_tick_lifetime_hint;
+    long tlsext_tick_age_add;
     ASN1_OCTET_STRING *tlsext_tick;
 #ifndef OPENSSL_NO_PSK
     ASN1_OCTET_STRING *psk_identity_hint;
@@ -89,7 +90,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
 #ifndef OPENSSL_NO_SRP
     ASN1_EXP_OPT(SSL_SESSION_ASN1, srp_username, ASN1_OCTET_STRING, 12),
 #endif
-    ASN1_EXP_OPT(SSL_SESSION_ASN1, flags, ZLONG, 13)
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, flags, ZLONG, 13),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick_age_add, ZLONG, 14)
 } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
 
 IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
@@ -190,6 +192,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
     }
     if (in->ext.tick_lifetime_hint > 0)
         as.tlsext_tick_lifetime_hint = in->ext.tick_lifetime_hint;
+    as.tlsext_tick_age_add = in->ext.tick_age_add;
 #ifndef OPENSSL_NO_PSK
     ssl_session_sinit(&as.psk_identity_hint, &psk_identity_hint,
                       in->psk_identity_hint);
@@ -281,15 +284,17 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
     p = as->cipher->data;
     id = 0x03000000L | ((unsigned long)p[0] << 8L) | (unsigned long)p[1];
 
-    ret->cipher = NULL;
     ret->cipher_id = id;
+    ret->cipher = ssl3_get_cipher_by_id(id);
+    if (ret->cipher == NULL)
+        goto err;
 
     if (!ssl_session_memcpy(ret->session_id, &ret->session_id_length,
                             as->session_id, SSL3_MAX_SSL_SESSION_ID_LENGTH))
         goto err;
 
     if (!ssl_session_memcpy(ret->master_key, &tmpl,
-                            as->master_key, SSL_MAX_MASTER_KEY_LENGTH))
+                            as->master_key, TLS13_MAX_RESUMPTION_MASTER_LENGTH))
         goto err;
 
     ret->master_key_length = tmpl;
@@ -326,6 +331,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 #endif
 
     ret->ext.tick_lifetime_hint = as->tlsext_tick_lifetime_hint;
+    ret->ext.tick_age_add = as->tlsext_tick_age_add;
     if (as->tlsext_tick) {
         ret->ext.tick = as->tlsext_tick->data;
         ret->ext.ticklen = as->tlsext_tick->length;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index d380c86..589cfa2 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -51,6 +51,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {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_KEY_SHARE), "final_key_share"},
     {ERR_FUNC(SSL_F_FINAL_RENEGOTIATE), "final_renegotiate"},
     {ERR_FUNC(SSL_F_FINAL_SIG_ALGS), "final_sig_algs"},
     {ERR_FUNC(SSL_F_NSS_KEYLOG_INT), "nss_keylog_int"},
@@ -300,6 +301,9 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {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_PSK), "tls_construct_ctos_psk"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES),
+     "tls_construct_ctos_psk_kex_modes"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE),
      "tls_construct_ctos_renegotiate"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_SCT), "tls_construct_ctos_sct"},
@@ -351,6 +355,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "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_PSK), "tls_construct_stoc_psk"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE),
      "tls_construct_stoc_renegotiate"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME),
@@ -366,10 +371,12 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {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_PSK), "tls_parse_ctos_psk"},
     {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_PSK), "tls_parse_stoc_psk"},
     {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"},
@@ -402,6 +409,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {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_HELLO_REQ), "tls_process_hello_req"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
      "tls_process_initial_server_flight"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
@@ -417,8 +425,10 @@ 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_PSK_DO_BINDER), "tls_psk_do_binder"},
     {ERR_FUNC(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT),
      "tls_scan_clienthello_tlsext"},
+    {ERR_FUNC(SSL_F_TLS_SETUP_HANDSHAKE), "tls_setup_handshake"},
     {ERR_FUNC(SSL_F_USE_CERTIFICATE_CHAIN_FILE),
      "use_certificate_chain_file"},
     {0, NULL}
@@ -449,6 +459,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
     {ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
      "bad protocol version number"},
+    {ERR_REASON(SSL_R_BAD_PSK_IDENTITY), "bad psk identity"},
     {ERR_REASON(SSL_R_BAD_RECORD_TYPE), "bad record type"},
     {ERR_REASON(SSL_R_BAD_RSA_ENCRYPT), "bad rsa encrypt"},
     {ERR_REASON(SSL_R_BAD_SIGNATURE), "bad signature"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 8ca1a3c..49c504d 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1716,6 +1716,13 @@ int SSL_shutdown(SSL *s)
 
 int SSL_renegotiate(SSL *s)
 {
+    /*
+     * TODO(TLS1.3): Return an error for now. Perhaps we should do a KeyUpdate
+     * instead when we support that?
+     */
+    if (SSL_IS_TLS13(s))
+        return 0;
+
     if (s->renegotiate == 0)
         s->renegotiate = 1;
 
@@ -1726,6 +1733,13 @@ int SSL_renegotiate(SSL *s)
 
 int SSL_renegotiate_abbreviated(SSL *s)
 {
+    /*
+     * TODO(TLS1.3): Return an error for now. Perhaps we should do a KeyUpdate
+     * instead when we support that?
+     */
+    if (SSL_IS_TLS13(s))
+        return 0;
+
     if (s->renegotiate == 0)
         s->renegotiate = 1;
 
@@ -3087,7 +3101,7 @@ int SSL_do_handshake(SSL *s)
         return -1;
     }
 
-    s->method->ssl_renegotiate_check(s);
+    s->method->ssl_renegotiate_check(s, 0);
 
     if (SSL_in_init(s) || SSL_in_before(s)) {
         if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 39e27ea..c7bfa22 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -348,6 +348,9 @@
 
 /* we have used 0000003f - 26 bits left to go */
 
+/* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */
+# define SSL3_CK_CIPHERSUITE_FLAG                0x03000000
+
 /* Check if an SSL structure is using DTLS */
 # define SSL_IS_DTLS(s)  (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
 
@@ -356,6 +359,8 @@
                           && (s)->method->version >= TLS1_3_VERSION \
                           && (s)->method->version != TLS_ANY_VERSION)
 
+# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0)
+
 /* See if we need explicit IV */
 # define SSL_USE_EXPLICIT_IV(s)  \
                 (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
@@ -456,7 +461,7 @@ struct ssl_method_st {
     int (*ssl_write) (SSL *s, const void *buf, size_t len, size_t *written);
     int (*ssl_shutdown) (SSL *s);
     int (*ssl_renegotiate) (SSL *s);
-    int (*ssl_renegotiate_check) (SSL *s);
+    int (*ssl_renegotiate_check) (SSL *s, int);
     int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
                            unsigned char *buf, size_t len, int peek,
                            size_t *readbytes);
@@ -508,7 +513,12 @@ struct ssl_session_st {
     int ssl_version;            /* what ssl version session info is being kept
                                  * in here? */
     size_t master_key_length;
-    unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+
+    /*
+     * For <=TLS1.2 this is the master_key. For TLS1.3 this is the resumption
+     * master secret
+     */
+    unsigned char master_key[TLS13_MAX_RESUMPTION_MASTER_LENGTH];
     /* session_id - valid? */
     size_t session_id_length;
     unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
@@ -567,6 +577,8 @@ struct ssl_session_st {
         size_t ticklen;      /* Session ticket length */
         /* Session lifetime hint in seconds */
         unsigned long tick_lifetime_hint;
+        uint32_t tick_age_add;
+        int tick_identity;
     } ext;
 # ifndef OPENSSL_NO_SRP
     char *srp_username;
@@ -954,11 +966,12 @@ struct ssl_st {
      */
     uint32_t mac_flags;
     /*
-     * The TLS1.3 early_secret and handshake_secret. The master_secret is stored
-     * in the session.
+     * The TLS1.3 secrets. The resumption master secret is stored in the
+     * session.
      */
     unsigned char early_secret[EVP_MAX_MD_SIZE];
     unsigned char handshake_secret[EVP_MAX_MD_SIZE];
+    unsigned char master_secret[EVP_MAX_MD_SIZE];
     unsigned char client_finished_secret[EVP_MAX_MD_SIZE];
     unsigned char server_finished_secret[EVP_MAX_MD_SIZE];
     unsigned char server_finished_hash[EVP_MAX_MD_SIZE];
@@ -1103,6 +1116,9 @@ struct ssl_st {
          */
         unsigned char *npn;
         size_t npn_len;
+
+        /* The available PSK key exchange modes */
+        int psk_kex_mode;
     } ext;
 
     /*-
@@ -1678,9 +1694,11 @@ typedef enum tlsext_index_en {
     TLSEXT_IDX_signed_certificate_timestamp,
     TLSEXT_IDX_extended_master_secret,
     TLSEXT_IDX_supported_versions,
+    TLSEXT_IDX_psk_kex_modes,
     TLSEXT_IDX_key_share,
     TLSEXT_IDX_cryptopro_bug,
-    TLSEXT_IDX_padding
+    TLSEXT_IDX_padding,
+    TLSEXT_IDX_psk
 } TLSEXT_INDEX;
 
 /*
@@ -1709,6 +1727,20 @@ typedef enum tlsext_index_en {
 #define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0xefef
 #define TLSEXT_SIGALG_gostr34102001_gostr3411                   0xeded
 
+/* Known PSK key exchange modes */
+#define TLSEXT_KEX_MODE_KE                                      0x00
+#define TLSEXT_KEX_MODE_KE_DHE                                  0x01
+
+/*
+ * Internal representations of key exchange modes
+ */
+#define TLSEXT_KEX_MODE_FLAG_NONE                               0
+#define TLSEXT_KEX_MODE_FLAG_KE                                 1
+#define TLSEXT_KEX_MODE_FLAG_KE_DHE                             2
+
+/* An invalid index into the TLSv1.3 PSK identities */
+#define TLSEXT_PSK_BAD_IDENTITY                                 -1
+
 #define SIGID_IS_PSS(sigid) ((sigid) == TLSEXT_SIGALG_rsa_pss_sha256 \
                              || (sigid) == TLSEXT_SIGALG_rsa_pss_sha384 \
                              || (sigid) == TLSEXT_SIGALG_rsa_pss_sha512)
@@ -1904,7 +1936,7 @@ __owur CERT *ssl_cert_dup(CERT *cert);
 void ssl_cert_clear_certs(CERT *c);
 void ssl_cert_free(CERT *c);
 __owur int ssl_get_new_session(SSL *s, int session);
-__owur int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello);
+__owur int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello, int *al);
 __owur SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket);
 __owur int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b);
 DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
@@ -1969,6 +2001,7 @@ __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey,
                       int genmaster);
 __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
 
+__owur const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id);
 __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
 __owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt,
                                    size_t *len);
@@ -1985,7 +2018,7 @@ __owur int ssl3_get_req_cert_type(SSL *s, WPACKET *pkt);
 __owur int ssl3_num_ciphers(void);
 __owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
 int ssl3_renegotiate(SSL *ssl);
-int ssl3_renegotiate_check(SSL *ssl);
+int ssl3_renegotiate_check(SSL *ssl, int initok);
 __owur int ssl3_dispatch_alert(SSL *s);
 __owur size_t ssl3_final_finish_mac(SSL *s, const char *sender, size_t slen,
                                     unsigned char *p);
@@ -2014,6 +2047,7 @@ __owur long ssl3_default_timeout(void);
 
 __owur int ssl3_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
 __owur int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
+__owur int tls_setup_handshake(SSL *s);
 __owur int dtls1_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
 __owur int dtls1_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
 __owur int ssl3_handshake_write(SSL *s);
@@ -2092,7 +2126,8 @@ __owur int tls13_setup_key_block(SSL *s);
 __owur size_t tls13_final_finish_mac(SSL *s, const char *str, size_t slen,
                                      unsigned char *p);
 __owur int tls13_change_cipher_state(SSL *s, int which);
-__owur int tls13_hkdf_expand(SSL *s, const unsigned char *secret,
+__owur int tls13_hkdf_expand(SSL *s, const EVP_MD *md,
+                             const unsigned char *secret,
                              const unsigned char *label, size_t labellen,
                              const unsigned char *hash,
                              unsigned char *out, size_t outlen);
@@ -2100,8 +2135,14 @@ __owur int tls13_derive_key(SSL *s, const unsigned char *secret,
                             unsigned char *key, size_t keylen);
 __owur int tls13_derive_iv(SSL *s, const unsigned char *secret,
                            unsigned char *iv, size_t ivlen);
-__owur int tls13_generate_early_secret(SSL *s, const unsigned char *insecret,
-                                       size_t insecretlen);
+__owur int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
+                                    const unsigned char *secret,
+                                    unsigned char *fin, size_t finlen);
+int tls13_generate_secret(SSL *s, const EVP_MD *md,
+                          const unsigned char *prevsecret,
+                          const unsigned char *insecret,
+                          size_t insecretlen,
+                          unsigned char *outsecret);
 __owur int tls13_generate_handshake_secret(SSL *s,
                                            const unsigned char *insecret,
                                            size_t insecretlen);
@@ -2153,8 +2194,32 @@ __owur  int tls1_get_curvelist(SSL *s, int sess, const unsigned char **pcurves,
 
 void ssl_set_default_md(SSL *s);
 __owur int tls1_set_server_sigalgs(SSL *s);
-__owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
-                                      SSL_SESSION **ret);
+
+/* Return codes for tls_get_ticket_from_client() and tls_decrypt_ticket() */
+typedef enum ticket_en {
+    /* fatal error, malloc failure */
+    TICKET_FATAL_ERR_MALLOC,
+    /* fatal error, either from parsing or decrypting the ticket */
+    TICKET_FATAL_ERR_OTHER,
+    /* No ticket present */
+    TICKET_NONE,
+    /* Empty ticket present */
+    TICKET_EMPTY,
+    /* the ticket couldn't be decrypted */
+    TICKET_NO_DECRYPT,
+    /* a ticket was successfully decrypted */
+    TICKET_SUCCESS,
+    /* same as above but the ticket needs to be reneewed */
+    TICKET_SUCCESS_RENEW
+} TICKET_RETURN;
+
+__owur TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
+                                                SSL_SESSION **ret);
+__owur TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick,
+                                        size_t eticklen,
+                                        const unsigned char *sess_id,
+                                        size_t sesslen, SSL_SESSION **psess);
+
 __owur int tls_use_ticket(SSL *s);
 
 __owur int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk,
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index c6d5c12..ddd949d 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -39,11 +39,21 @@
 #include <openssl/rand.h>
 #include <openssl/engine.h>
 #include "ssl_locl.h"
+#include "statem/statem_locl.h"
 
 static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
 static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
 static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
 
+/*
+ * TODO(TLS1.3): SSL_get_session() and SSL_get1_session() are problematic in
+ * TLS1.3 because, unlike in earlier protocol versions, the session ticket
+ * may not have been sent yet even though a handshake has finished. The session
+ * ticket data could come in sometime later...or even change if multiple session
+ * ticket messages are sent from the server. We need to work out how to deal
+ * with this.
+ */
+
 SSL_SESSION *SSL_get_session(const SSL *ssl)
 /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
 {
@@ -81,6 +91,9 @@ SSL_SESSION *SSL_SESSION_new(void)
 {
     SSL_SESSION *ss;
 
+    if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
+        return NULL;
+
     ss = OPENSSL_zalloc(sizeof(*ss));
     if (ss == NULL) {
         SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE);
@@ -435,8 +448,9 @@ int ssl_get_new_session(SSL *s, int session)
  *   hello: The parsed ClientHello data
  *
  * Returns:
- *   -1: error
- *    0: a session may have been found.
+ *   -1: fatal error
+ *    0: no session found
+ *    1: a session may have been found.
  *
  * Side effects:
  *   - If a session is found then s->session is pointed at it (after freeing an
@@ -444,33 +458,40 @@ int ssl_get_new_session(SSL *s, int session)
  *   - Both for new and resumed sessions, s->ext.ticket_expected is set to 1
  *     if the server should issue a new session ticket (to 0 otherwise).
  */
-int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
+int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello, int *al)
 {
     /* This is used only by servers. */
 
     SSL_SESSION *ret = NULL;
     int fatal = 0;
-    int try_session_cache = 1;
-    int r;
+    int try_session_cache = 0;
+    TICKET_RETURN r;
 
-    if (hello->session_id_len == 0)
-        try_session_cache = 0;
+    if (SSL_IS_TLS13(s)) {
+        if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes, EXT_CLIENT_HELLO,
+                                 hello->pre_proc_exts, NULL, 0, al)
+                || !tls_parse_extension(s, TLSEXT_IDX_psk, EXT_CLIENT_HELLO,
+                                        hello->pre_proc_exts, NULL, 0, al))
+            return -1;
 
-    /* sets s->ext.ticket_expected */
-    r = tls_get_ticket_from_client(s, hello, &ret);
-    switch (r) {
-    case -1:                   /* Error during processing */
-        fatal = 1;
-        goto err;
-    case 0:                    /* No ticket found */
-    case 1:                    /* Zero length ticket found */
-        break;                  /* Ok to carry on processing session id. */
-    case 2:                    /* Ticket found but not decrypted. */
-    case 3:                    /* Ticket decrypted, *ret has been set. */
-        try_session_cache = 0;
-        break;
-    default:
-        abort();
+        ret = s->session;
+    } else {
+        /* sets s->ext.ticket_expected */
+        r = tls_get_ticket_from_client(s, hello, &ret);
+        switch (r) {
+        case TICKET_FATAL_ERR_MALLOC:
+        case TICKET_FATAL_ERR_OTHER:
+            fatal = 1;
+            goto err;
+        case TICKET_NONE:
+        case TICKET_EMPTY:
+            try_session_cache = 1;
+            break;
+        case TICKET_NO_DECRYPT:
+        case TICKET_SUCCESS:
+        case TICKET_SUCCESS_RENEW:
+            break;
+        }
     }
 
     if (try_session_cache &&
@@ -538,6 +559,10 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
 
     /* Now ret is non-NULL and we own one of its reference counts. */
 
+    /* Check TLS version consistency */
+    if (ret->ssl_version != s->version)
+        goto err;
+
     if (ret->sid_ctx_length != s->sid_ctx_length
         || memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) {
         /*
@@ -564,21 +589,6 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
         goto err;
     }
 
-    if (ret->cipher == NULL) {
-        unsigned char buf[5], *p;
-        unsigned long l;
-
-        p = buf;
-        l = ret->cipher_id;
-        l2n(l, p);
-        if ((ret->ssl_version >> 8) >= SSL3_VERSION_MAJOR)
-            ret->cipher = ssl_get_cipher_by_char(s, &(buf[2]));
-        else
-            ret->cipher = ssl_get_cipher_by_char(s, &(buf[1]));
-        if (ret->cipher == NULL)
-            goto err;
-    }
-
     if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */
         s->session_ctx->stats.sess_timeout++;
         if (try_session_cache) {
@@ -588,23 +598,6 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
         goto err;
     }
 
-    /*
-     * TODO(TLS1.3): This is temporary, because TLSv1.3 resumption is completely
-     * different. For now though we're still using the old resumption logic, so
-     * to avoid test failures we need this. Remove this code!
-     * 
-     * Check TLS version consistency. We can't resume <=TLSv1.2 session if we
-     * have negotiated TLSv1.3, and vice versa.
-     */
-    if (!SSL_IS_DTLS(s)
-            && ((ret->ssl_version <= TLS1_2_VERSION
-                 && s->version >=TLS1_3_VERSION)
-                || (ret->ssl_version >= TLS1_3_VERSION
-                    && s->version <= TLS1_2_VERSION))) {
-        /* Continue but do not resume */
-        goto err;
-    }
-
     /* Check extended master secret extension consistency */
     if (ret->flags & SSL_SESS_FLAG_EXTMS) {
         /* If old session includes extms, but new does not: abort handshake */
@@ -619,16 +612,22 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
         goto err;
     }
 
-    s->session_ctx->stats.sess_hit++;
+    if (!SSL_IS_TLS13(s)) {
+        /* We already did this for TLS1.3 */
+        SSL_SESSION_free(s->session);
+        s->session = ret;
+    }
 
-    SSL_SESSION_free(s->session);
-    s->session = ret;
+    s->session_ctx->stats.sess_hit++;
     s->verify_result = s->session->verify_result;
     return 1;
 
  err:
     if (ret != NULL) {
         SSL_SESSION_free(ret);
+        /* In TLSv1.3 s->session was already set to ret, so we NULL it out */
+        if (SSL_IS_TLS13(s))
+            s->session = NULL;
 
         if (!try_session_cache) {
             /*
@@ -638,10 +637,12 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
             s->ext.ticket_expected = 1;
         }
     }
-    if (fatal)
+    if (fatal) {
+        *al = SSL_AD_INTERNAL_ERROR;
         return -1;
-    else
-        return 0;
+    }
+
+    return 0;
 }
 
 int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index ee5b0d7..526318f 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -35,6 +35,8 @@ static int init_srp(SSL *s, unsigned int context);
 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);
+static int init_psk_kex_modes(SSL *s, unsigned int context);
+static int final_key_share(SSL *s, unsigned int context, int sent, int *al);
 #ifndef OPENSSL_NO_SRTP
 static int init_srtp(SSL *s, unsigned int context);
 #endif
@@ -235,6 +237,12 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         NULL, NULL, NULL, tls_construct_ctos_supported_versions, NULL
     },
     {
+        TLSEXT_TYPE_psk_kex_modes,
+        EXT_CLIENT_HELLO | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY,
+        init_psk_kex_modes, tls_parse_ctos_psk_kex_modes, NULL, NULL,
+        tls_construct_ctos_psk_kex_modes, NULL
+    },
+    {
         /*
          * Must be in this list after supported_groups. We need that to have
          * been parsed before we do this one.
@@ -244,7 +252,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         | 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
+        tls_construct_stoc_key_share, tls_construct_ctos_key_share,
+        final_key_share
     },
     {
         /*
@@ -256,12 +265,21 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
     },
     {
-        /* Last in the list because it must be added as the last extension */
+        /* Must be immediately before pre_shared_key */
+        /* TODO(TLS1.3): Fix me */
         TLSEXT_TYPE_padding,
         EXT_CLIENT_HELLO,
         NULL,
         /* We send this, but don't read it */
         NULL, NULL, NULL, tls_construct_ctos_padding, NULL
+    },
+    {
+        /* Required by the TLSv1.3 spec to always be the last extension */
+        TLSEXT_TYPE_psk,
+        EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO | EXT_TLS_IMPLEMENTATION_ONLY
+        | EXT_TLS1_3_ONLY,
+        NULL, tls_parse_ctos_psk, tls_parse_stoc_psk, tls_construct_stoc_psk,
+        tls_construct_ctos_psk, NULL
     }
 };
 
@@ -938,3 +956,142 @@ static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al)
 
     return 1;
 }
+
+
+static int final_key_share(SSL *s, unsigned int context, int sent, int *al)
+{
+    if (!SSL_IS_TLS13(s))
+        return 1;
+
+    /*
+     * If
+     *     we have no key_share
+     *     AND
+     *     (we are not resuming
+     *      OR the kex_mode doesn't allow non key_share resumes)
+     * THEN
+     *     fail
+     */
+    if (((s->server && s->s3->peer_tmp == NULL) || (!s->server && !sent))
+            && (!s->hit
+                || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
+        /* No suitable share */
+        /* TODO(TLS1.3): Send a HelloRetryRequest */
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+        return 0;
+    }
+
+    /*
+     * For a client side resumption with no key_share we need to generate
+     * the handshake secret (otherwise this is done during key_share
+     * processing).
+     */
+    if (!sent && !s->server && !tls13_generate_handshake_secret(s, NULL, 0)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_FINAL_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int init_psk_kex_modes(SSL *s, unsigned int context)
+{
+    s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_NONE;
+    return 1;
+}
+
+int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
+                      size_t binderoffset, const unsigned char *binderin,
+                      unsigned char *binderout,
+                      SSL_SESSION *sess, int sign)
+{
+    EVP_PKEY *mackey = NULL;
+    EVP_MD_CTX *mctx = NULL;
+    unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
+    unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
+    const char resumption_label[] = "resumption psk binder key";
+    size_t bindersize, hashsize = EVP_MD_size(md);
+    int ret = -1;
+
+    /* Generate the early_secret */
+    if (!tls13_generate_secret(s, md, NULL, sess->master_key,
+                               sess->master_key_length,
+                               (unsigned char *)&s->early_secret)) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * Create the handshake hash for the binder key...the messages so far are
+     * empty!
+     */
+    mctx = EVP_MD_CTX_new();
+    if (mctx == NULL
+            || EVP_DigestInit_ex(mctx, md, NULL) <= 0
+            || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Generate the binder key */
+    if (!tls13_hkdf_expand(s, md, s->early_secret,
+                           (unsigned char *)resumption_label,
+                           sizeof(resumption_label) - 1, hash, binderkey,
+                           hashsize)) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* Generate the finished key */
+    if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * Get a hash of the ClientHello up to the start of the binders.
+     * TODO(TLS1.3): This will need to be tweaked when we implement
+     * HelloRetryRequest to include the digest of the previous messages here.
+     */
+    if (EVP_DigestInit_ex(mctx, md, NULL) <= 0
+            || EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
+            || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    mackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, finishedkey, hashsize);
+    if (mackey == NULL) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!sign)
+        binderout = tmpbinder;
+
+    bindersize = hashsize;
+    if (EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
+            || EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
+            || EVP_DigestSignFinal(mctx, binderout, &bindersize) <= 0
+            || bindersize != hashsize) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (sign) {
+        ret = 1;
+    } else {
+        /* HMAC keys can't do EVP_DigestVerify* - use CRYPTO_memcmp instead */
+        ret = (CRYPTO_memcmp(binderin, binderout, hashsize) == 0);
+    }
+
+ err:
+    OPENSSL_cleanse(binderkey, sizeof(binderkey));
+    OPENSSL_cleanse(finishedkey, sizeof(finishedkey));
+    EVP_PKEY_free(mackey);
+    EVP_MD_CTX_free(mctx);
+
+    return ret;
+}
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index fe00749..ceae77f 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -191,7 +191,8 @@ int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
         return 1;
 
     if (!s->new_session && s->session != NULL
-            && s->session->ext.tick != NULL) {
+            && s->session->ext.tick != NULL
+            && s->session->ssl_version != TLS1_3_VERSION) {
         ticklen = s->session->ext.ticklen;
     } else if (s->session && s->ext.session_ticket != NULL
                && s->ext.session_ticket->data != NULL) {
@@ -318,7 +319,7 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, X509 *x,
 int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
                            int *al)
 {
-    if (s->ctx->ext.npn_select_cb == NULL || s->s3->tmp.finish_md_len != 0)
+    if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     /*
@@ -340,11 +341,7 @@ int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 {
     s->s3->alpn_sent = 0;
 
-    /*
-     * finish_md_len is non-zero during a renegotiation, so
-     * this avoids sending ALPN during the renegotiation
-     */
-    if (s->ext.alpn == NULL || s->s3->tmp.finish_md_len != 0)
+    if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     if (!WPACKET_put_bytes_u16(pkt,
@@ -498,6 +495,35 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
+/*
+ * Construct a psk_kex_modes extension. We only have two modes we know about
+ * at this stage, so we send both.
+ */
+int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
+                                     size_t chainidx, int *al)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    /*
+     * TODO(TLS1.3): Do we want this list to be configurable? For now we always
+     * just send both supported modes
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk_kex_modes)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE_DHE)
+            || !WPACKET_put_bytes_u8(pkt, TLSEXT_KEX_MODE_KE)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_KE | TLSEXT_KEX_MODE_FLAG_KE_DHE;
+#endif
+
+    return 1;
+}
+
 int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
                                  int *al)
 {
@@ -634,6 +660,118 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 
 /*
+ * Construct the pre_shared_key extension
+ */
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+                           int *al)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    uint32_t now, agesec, agems;
+    size_t hashsize, binderoffset, msglen;
+    unsigned char *binder = NULL, *msgstart = NULL;
+    const EVP_MD *md;
+    int ret = 0;
+
+    s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
+
+    /*
+     * If this is an incompatible or new session then we have nothing to resume
+     * so don't add this extension.
+     */
+    if (s->session->ssl_version != TLS1_3_VERSION
+            || s->session->ext.ticklen == 0)
+        return 1;
+
+    if (s->session->cipher == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    md = ssl_md(s->session->cipher->algorithm2);
+    if (md == NULL) {
+        /* Don't recognise this cipher so we can't use the session. Ignore it */
+        return 1;
+    }
+
+    /*
+     * Technically the C standard just says time() returns a time_t and says
+     * nothing about the encoding of that type. In practice most implementations
+     * follow POSIX which holds it as an integral type in seconds since epoch.
+     * We've already made the assumption that we can do this in multiple places
+     * in the code, so portability shouldn't be an issue.
+     */
+    now = (uint32_t)time(NULL);
+    agesec = now - (uint32_t)s->session->time;
+
+    if (s->session->ext.tick_lifetime_hint < agesec) {
+        /* Ticket is too old. Ignore it. */
+        return 1;
+    }
+
+    /*
+     * Calculate age in ms. We're just doing it to nearest second. Should be
+     * good enough.
+     */
+    agems = agesec * (uint32_t)1000;
+
+    if (agesec != 0 && agems / (uint32_t)1000 != agesec) {
+        /*
+         * Overflow. Shouldn't happen unless this is a *really* old session. If
+         * so we just ignore it.
+         */
+        return 1;
+    }
+
+    /*
+     * Obfuscate the age. Overflow here is fine, this addition is supposed to
+     * be mod 2^32.
+     */
+    agems += s->session->ext.tick_age_add;
+
+    hashsize = EVP_MD_size(md);
+
+    /* Create the extension, but skip over the binder for now */
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick,
+                                       s->session->ext.ticklen)
+            || !WPACKET_put_bytes_u32(pkt, agems)
+            || !WPACKET_close(pkt)
+            || !WPACKET_get_total_written(pkt, &binderoffset)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_allocate_bytes_u8(pkt, hashsize, &binder)
+            || !WPACKET_close(pkt)
+            || !WPACKET_close(pkt)
+            || !WPACKET_get_total_written(pkt, &msglen)
+               /*
+                * We need to fill in all the sub-packet lengths now so we can
+                * calculate the HMAC of the message up to the binders
+                */
+            || !WPACKET_fill_lengths(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    msgstart = WPACKET_get_curr(pkt) - msglen;
+
+    if (tls_psk_do_binder(s, md, msgstart, binderoffset, NULL, binder,
+                          s->session, 1) != 1) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->session->ext.tick_identity = 0;
+
+    ret = 1;
+ err:
+    return ret;
+#else
+    return 1;
+#endif
+}
+
+/*
  * Parse the server's renegotiation binding and abort if it's not right
  */
 int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
@@ -866,7 +1004,7 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     PACKET tmppkt;
 
     /* Check if we are in a renegotiation. If so ignore this extension */
-    if (s->s3->tmp.finish_md_len != 0)
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     /* We must have requested it. */
@@ -1083,3 +1221,26 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 
     return 1;
 }
+
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    unsigned int identity;
+
+    if (!PACKET_get_net_2(pkt, &identity) || PACKET_remaining(pkt) != 0) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PARSE_STOC_PSK, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    if (s->session->ext.tick_identity != (int)identity) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PARSE_STOC_PSK, SSL_R_BAD_PSK_IDENTITY);
+        return 0;
+    }
+
+    s->hit = 1;
+#endif
+
+    return 1;
+}
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index d58eedd..df1e6c2 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -322,21 +322,8 @@ int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, 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)
+    if (SSL_IS_FIRST_HANDSHAKE(s))
         s->s3->npn_seen = 1;
 
     return 1;
@@ -352,7 +339,7 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 {
     PACKET protocol_list, save_protocol_list, protocol;
 
-    if (s->s3->tmp.finish_md_len != 0)
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     if (!PACKET_as_length_prefixed_2(pkt, &protocol_list)
@@ -492,6 +479,35 @@ static int check_in_list(SSL *s, unsigned int group_id,
 #endif
 
 /*
+ * Process a psk_kex_modes 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_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
+                                 int *al)
+{
+#ifndef OPENSSL_NO_TLS1_3
+    PACKET psk_kex_modes;
+    unsigned int mode;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &psk_kex_modes)
+            || PACKET_remaining(&psk_kex_modes) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    while (PACKET_get_1(&psk_kex_modes, &mode)) {
+        if (mode == TLSEXT_KEX_MODE_KE_DHE)
+            s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE_DHE;
+        else if (mode == TLSEXT_KEX_MODE_KE)
+            s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE;
+    }
+#endif
+
+    return 1;
+}
+
+/*
  * 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.
@@ -507,7 +523,7 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
     int group_nid, found = 0;
     unsigned int curve_flags;
 
-    if (s->hit)
+    if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0)
         return 1;
 
     /* Sanity check */
@@ -639,10 +655,9 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
         return 0;
     }
 
-    if (!s->hit
-            && !PACKET_memdup(&supported_groups_list,
-                              &s->session->ext.supportedgroups,
-                              &s->session->ext.supportedgroups_len)) {
+    if (!PACKET_memdup(&supported_groups_list,
+                       &s->session->ext.supportedgroups,
+                       &s->session->ext.supportedgroups_len)) {
         *al = SSL_AD_DECODE_ERROR;
         return 0;
     }
@@ -664,6 +679,104 @@ int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     return 1;
 }
 
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+{
+    PACKET identities, binders, binder;
+    size_t binderoffset, hashsize;
+    SSL_SESSION *sess = NULL;
+    unsigned int id, i;
+    const EVP_MD *md = NULL;
+
+    /*
+     * If we have no PSK kex mode that we recognise then we can't resume so
+     * ignore this extension
+     */
+    if ((s->ext.psk_kex_mode
+            & (TLSEXT_KEX_MODE_FLAG_KE | TLSEXT_KEX_MODE_FLAG_KE_DHE)) == 0)
+        return 1;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &identities)) {
+        *al = SSL_AD_DECODE_ERROR;
+        return 0;
+    }
+
+    for (id = 0; PACKET_remaining(&identities) != 0; id++) {
+        PACKET identity;
+        unsigned long ticket_age;
+        int ret;
+
+        if (!PACKET_get_length_prefixed_2(&identities, &identity)
+                || !PACKET_get_net_4(&identities, &ticket_age)) {
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        /* TODO(TLS1.3): Should we validate the ticket age? */
+
+        ret = tls_decrypt_ticket(s, PACKET_data(&identity),
+                                 PACKET_remaining(&identity), NULL, 0, &sess);
+        if (ret == TICKET_FATAL_ERR_MALLOC || ret == TICKET_FATAL_ERR_OTHER) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            return 0;
+        }
+        if (ret == TICKET_NO_DECRYPT)
+            continue;
+
+        md = ssl_md(sess->cipher->algorithm2);
+        if (md == NULL) {
+            /*
+             * Don't recognise this cipher so we can't use the session.
+             * Ignore it
+             */
+            SSL_SESSION_free(sess);
+            sess = NULL;
+            continue;
+        }
+
+        /*
+         * TODO(TLS1.3): Somehow we need to handle the case of a ticket renewal.
+         * Ignored for now
+         */
+
+        break;
+    }
+
+    if (sess == NULL)
+        return 1;
+
+    binderoffset = PACKET_data(pkt) - (const unsigned char *)s->init_buf->data;
+    hashsize = EVP_MD_size(md);
+
+    if (!PACKET_get_length_prefixed_2(pkt, &binders)) {
+        *al = SSL_AD_DECODE_ERROR;
+        goto err;
+    }
+
+    for (i = 0; i <= id; i++) {
+        if (!PACKET_get_length_prefixed_1(&binders, &binder)) {
+            *al = SSL_AD_DECODE_ERROR;
+            goto err;
+        }
+    }
+
+    if (PACKET_remaining(&binder) != hashsize
+            || tls_psk_do_binder(s, md,
+                                 (const unsigned char *)s->init_buf->data,
+                                 binderoffset, PACKET_data(&binder), NULL,
+                                 sess, 0) != 1) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    sess->ext.tick_identity = id;
+    SSL_SESSION_free(s->session);
+    s->session = sess;
+    return 1;
+err:
+    return 0;
+}
+
 /*
  * Add the server's renegotiation binding
  */
@@ -901,12 +1014,14 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     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;
+        /* No key_share received from client; must be resuming. */
+        if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        return 1;
     }
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
@@ -974,3 +1089,20 @@ int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, X509 *x,
 
     return 1;
 }
+
+int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+                           int *al)
+{
+    if (!s->hit)
+        return 1;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u16(pkt, s->session->ext.tick_identity)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_PSK, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index 51a9266..bd7d89a 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -105,8 +105,8 @@ void ossl_statem_clear(SSL *s)
  */
 void ossl_statem_set_renegotiate(SSL *s)
 {
-    s->statem.state = MSG_FLOW_RENEGOTIATE;
     s->statem.in_init = 1;
+    s->statem.request_state = TLS_ST_SW_HELLO_REQ;
 }
 
 /*
@@ -189,10 +189,10 @@ static info_cb get_callback(SSL *s)
 
 /*
  * The main message flow state machine. We start in the MSG_FLOW_UNINITED or
- * MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
+ * MSG_FLOW_FINISHED state and finish in MSG_FLOW_FINISHED. Valid states and
  * transitions are as follows:
  *
- * MSG_FLOW_UNINITED     MSG_FLOW_RENEGOTIATE
+ * MSG_FLOW_UNINITED     MSG_FLOW_FINISHED
  *        |                       |
  *        +-----------------------+
  *        v
@@ -252,16 +252,11 @@ static int state_machine(SSL *s, int server)
 #endif
 
     /* Initialise state machine */
-
-    if (st->state == MSG_FLOW_RENEGOTIATE) {
-        s->renegotiate = 1;
-        if (!server)
-            s->ctx->stats.sess_connect_renegotiate++;
-    }
-
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) {
+    if (st->state == MSG_FLOW_UNINITED
+            || st->state == MSG_FLOW_FINISHED) {
         if (st->state == MSG_FLOW_UNINITED) {
             st->hand_state = TLS_ST_BEFORE;
+            st->request_state = TLS_ST_BEFORE;
         }
 
         s->server = server;
@@ -318,54 +313,18 @@ static int state_machine(SSL *s, int server)
                 goto end;
             }
 
-        if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
-            if (!ssl3_init_finished_mac(s)) {
+        if (SSL_IS_FIRST_HANDSHAKE(s) || s->renegotiate) {
+            if (!tls_setup_handshake(s)) {
                 ossl_statem_set_error(s);
                 goto end;
             }
-        }
 
-        if (server) {
-            if (st->state != MSG_FLOW_RENEGOTIATE) {
-                s->ctx->stats.sess_accept++;
-            } else if (!s->s3->send_connection_binding &&
-                       !(s->options &
-                         SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
-                /*
-                 * Server attempting to renegotiate with client that doesn't
-                 * support secure renegotiation.
-                 */
-                SSLerr(SSL_F_STATE_MACHINE,
-                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-                ossl_statem_set_error(s);
-                goto end;
-            } else {
-                /*
-                 * st->state == MSG_FLOW_RENEGOTIATE, we will just send a
-                 * HelloRequest
-                 */
-                s->ctx->stats.sess_accept_renegotiate++;
-            }
-
-            s->s3->tmp.cert_request = 0;
-        } else {
-            s->ctx->stats.sess_connect++;
-
-            /* mark client_random uninitialized */
-            memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
-            s->hit = 0;
-
-            s->s3->tmp.cert_req = 0;
-
-            if (SSL_IS_DTLS(s)) {
-                st->use_timer = 1;
-            }
+            if (SSL_IS_FIRST_HANDSHAKE(s))
+                st->read_state_first_init = 1;
         }
 
         st->state = MSG_FLOW_WRITING;
         init_write_state_machine(s);
-        st->read_state_first_init = 1;
     }
 
     while (st->state != MSG_FLOW_FINISHED) {
@@ -396,7 +355,6 @@ static int state_machine(SSL *s, int server)
         }
     }
 
-    st->state = MSG_FLOW_UNINITED;
     ret = 1;
 
  end:
@@ -820,7 +778,7 @@ int statem_flush(SSL *s)
 
 /*
  * Called by the record layer to determine whether application data is
- * allowed to be sent in the current handshake state or not.
+ * allowed to be received in the current handshake state or not.
  *
  * Return values are:
  *   1: Yes (application data allowed)
@@ -830,7 +788,7 @@ int ossl_statem_app_data_allowed(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
+    if (st->state == MSG_FLOW_UNINITED)
         return 0;
 
     if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
index 2fca39b..021d2d0 100644
--- a/ssl/statem/statem.h
+++ b/ssl/statem/statem.h
@@ -46,8 +46,6 @@ typedef enum {
     MSG_FLOW_UNINITED,
     /* A permanent error with this connection */
     MSG_FLOW_ERROR,
-    /* We are about to renegotiate */
-    MSG_FLOW_RENEGOTIATE,
     /* We are reading messages */
     MSG_FLOW_READING,
     /* We are writing messages */
@@ -86,10 +84,17 @@ struct ossl_statem_st {
     READ_STATE read_state;
     WORK_STATE read_state_work;
     OSSL_HANDSHAKE_STATE hand_state;
+    /* The handshake state requested by an API call (e.g. HelloRequest) */
+    OSSL_HANDSHAKE_STATE request_state;
     int in_init;
     int read_state_first_init;
     /* true when we are actually in SSL_accept() or SSL_connect() */
     int in_handshake;
+    /*
+     * True when are processing a "real" handshake that needs cleaning up (not
+     * just a HelloRequest or similar).
+     */
+    int cleanuphand;
     /* Should we skip the CertificateVerify message? */
     unsigned int no_cert_verify;
     int use_timer;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 90e4df6..9ce4ff6 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -48,6 +48,7 @@
  */
 
 #include <stdio.h>
+#include <time.h>
 #include "../ssl_locl.h"
 #include "statem_locl.h"
 #include <openssl/buffer.h>
@@ -181,6 +182,13 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
             return 1;
         }
         break;
+
+    case TLS_ST_OK:
+        if (mt == SSL3_MT_NEWSESSION_TICKET) {
+            st->hand_state = TLS_ST_CR_SESSION_TICKET;
+            return 1;
+        }
+        break;
     }
 
     /* No valid transition found */
@@ -351,6 +359,13 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
             return 1;
         }
         break;
+
+    case TLS_ST_OK:
+        if (mt == SSL3_MT_HELLO_REQUEST) {
+            st->hand_state = TLS_ST_CR_HELLO_REQ;
+            return 1;
+        }
+        break;
     }
 
  err:
@@ -399,10 +414,15 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         st->hand_state = TLS_ST_CW_FINISHED;
         return WRITE_TRAN_CONTINUE;
 
+    case TLS_ST_CR_SESSION_TICKET:
     case TLS_ST_CW_FINISHED:
         st->hand_state = TLS_ST_OK;
         ossl_statem_set_in_init(s, 0);
         return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_OK:
+        /* Just go straight to trying to read from the server */
+        return WRITE_TRAN_FINISHED;
     }
 }
 
@@ -428,6 +448,13 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
         return WRITE_TRAN_ERROR;
 
     case TLS_ST_OK:
+        if (!s->renegotiate) {
+            /*
+             * We haven't requested a renegotiation ourselves so we must have
+             * received a message from the server. Better read it.
+             */
+            return WRITE_TRAN_FINISHED;
+        }
         /* Renegotiation - fall through */
     case TLS_ST_BEFORE:
         st->hand_state = TLS_ST_CW_CLNT_HELLO;
@@ -515,6 +542,23 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
             ossl_statem_set_in_init(s, 0);
             return WRITE_TRAN_CONTINUE;
         }
+
+    case TLS_ST_CR_HELLO_REQ:
+        /*
+         * If we can renegotiate now then do so, otherwise wait for a more
+         * convenient time.
+         */
+        if (ssl3_renegotiate_check(s, 1)) {
+            if (!tls_setup_handshake(s)) {
+                ossl_statem_set_error(s);
+                return WRITE_TRAN_ERROR;
+            }
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
+        }
+        st->hand_state = TLS_ST_OK;
+        ossl_statem_set_in_init(s, 0);
+        return WRITE_TRAN_CONTINUE;
     }
 }
 
@@ -559,7 +603,7 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
         break;
 
     case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
+        return tls_finish_handshake(s, wst, 1);
     }
 
     return WORK_FINISHED_CONTINUE;
@@ -819,6 +863,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_HELLO_REQ:
+        return tls_process_hello_req(s, pkt);
+
     case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
         return tls_process_encrypted_extensions(s, pkt);
     }
@@ -893,6 +940,9 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     }
     /* else use the pre-loaded session */
 
+    /* This is a real handshake so make sure we clean it up at the end */
+    s->statem.cleanuphand = 1;
+
     p = s->s3->client_random;
 
     /*
@@ -954,7 +1004,7 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     }
 
     /* Session ID */
-    if (s->new_session)
+    if (s->new_session || s->session->ssl_version == TLS1_3_VERSION)
         sess_id_len = 0;
     else
         sess_id_len = s->session->session_id_length;
@@ -1080,6 +1130,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
+    /* We do this immediately so we know what format the ServerHello is in */
     protverr = ssl_choose_client_version(s, sversion);
     if (protverr != 0) {
         al = SSL_AD_PROTOCOL_VERSION;
@@ -1095,8 +1146,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    s->hit = 0;
-
     /* Get the session-id. */
     if (!SSL_IS_TLS13(s)) {
         if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
@@ -1123,63 +1172,103 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    /*
-     * Check if we can resume the session based on external pre-shared secret.
-     * EAP-FAST (RFC 4851) supports two types of session resumption.
-     * Resumption based on server-side state works with session IDs.
-     * Resumption based on pre-shared Protected Access Credentials (PACs)
-     * works by overriding the SessionTicket extension at the application
-     * layer, and does not send a session ID. (We do not know whether EAP-FAST
-     * servers would honour the session ID.) Therefore, the session ID alone
-     * is not a reliable indicator of session resumption, so we first check if
-     * we can resume, and later peek at the next handshake message to see if the
-     * server wants to resume.
-     */
-    if (s->version >= TLS1_VERSION && !SSL_IS_TLS13(s)
-            && s->ext.session_secret_cb != NULL && s->session->ext.tick) {
-        const SSL_CIPHER *pref_cipher = NULL;
+    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;
+    }
+
+    /* TLS extensions */
+    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_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))
+        goto f_err;
+
+    s->hit = 0;
+
+    if (SSL_IS_TLS13(s)) {
+        /* This will set s->hit if we are resuming */
+        if (!tls_parse_extension(s, TLSEXT_IDX_psk,
+                                 EXT_TLS1_3_SERVER_HELLO,
+                                 extensions, NULL, 0, &al))
+            goto f_err;
+    } else {
         /*
-         * s->session->master_key_length is a size_t, but this is an int for
-         * backwards compat reasons
+         * Check if we can resume the session based on external pre-shared
+         * secret. EAP-FAST (RFC 4851) supports two types of session resumption.
+         * Resumption based on server-side state works with session IDs.
+         * Resumption based on pre-shared Protected Access Credentials (PACs)
+         * works by overriding the SessionTicket extension at the application
+         * layer, and does not send a session ID. (We do not know whether
+         * EAP-FAST servers would honour the session ID.) Therefore, the session
+         * ID alone is not a reliable indicator of session resumption, so we
+         * first check if we can resume, and later peek at the next handshake
+         * message to see if the server wants to resume.
          */
-        int master_key_length;
-        master_key_length = sizeof(s->session->master_key);
-        if (s->ext.session_secret_cb(s, s->session->master_key,
-                                     &master_key_length,
-                                     NULL, &pref_cipher,
-                                     s->ext.session_secret_cb_arg)
-                 && master_key_length > 0) {
-            s->session->master_key_length = master_key_length;
-            s->session->cipher = pref_cipher ?
-                pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
-        } else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
+        if (s->version >= TLS1_VERSION
+                && s->ext.session_secret_cb != NULL && s->session->ext.tick) {
+            const SSL_CIPHER *pref_cipher = NULL;
+            /*
+             * s->session->master_key_length is a size_t, but this is an int for
+             * backwards compat reasons
+             */
+            int master_key_length;
+            master_key_length = sizeof(s->session->master_key);
+            if (s->ext.session_secret_cb(s, s->session->master_key,
+                                         &master_key_length,
+                                         NULL, &pref_cipher,
+                                         s->ext.session_secret_cb_arg)
+                     && master_key_length > 0) {
+                s->session->master_key_length = master_key_length;
+                s->session->cipher = pref_cipher ?
+                    pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
+            } else {
+                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+                al = SSL_AD_INTERNAL_ERROR;
+                goto f_err;
+            }
         }
+
+        if (session_id_len != 0
+                && session_id_len == s->session->session_id_length
+                && memcmp(PACKET_data(&session_id), s->session->session_id,
+                          session_id_len) == 0)
+            s->hit = 1;
     }
 
-    if (session_id_len != 0 && session_id_len == s->session->session_id_length
-        && memcmp(PACKET_data(&session_id), s->session->session_id,
-                  session_id_len) == 0) {
+    if (s->hit) {
         if (s->sid_ctx_length != s->session->sid_ctx_length
-            || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
+                || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
             /* actually a client application bug */
             al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                    SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
             goto f_err;
         }
-        s->hit = 1;
     } else {
         /*
          * If we were trying for session-id reuse but the server
-         * didn't echo the ID, make a new SSL_SESSION.
+         * didn't resume, make a new SSL_SESSION.
          * In the case of EAP-FAST and PAC, we do not send a session ID,
          * so the PAC-based session secret is always preserved. It'll be
          * overwritten if the server refuses resumption.
          */
-        if (s->session->session_id_length > 0) {
+        if (s->session->session_id_length > 0
+                || (SSL_IS_TLS13(s)
+                    && s->session->ext.tick_identity
+                       != TLSEXT_PSK_BAD_IDENTITY)) {
             s->ctx->stats.sess_miss++;
             if (!ssl_get_new_session(s, 0)) {
                 goto f_err;
@@ -1249,17 +1338,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
     s->s3->tmp.new_cipher = c;
-    /* lets get the compression algorithm */
-    /* COMPRESSION */
-    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) {
@@ -1303,19 +1381,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     }
 #endif
 
-    /* TLS extensions */
-    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_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, NULL, 0, &al))
+    if (!tls_parse_all_extensions(s, context, extensions, NULL, 0, &al))
         goto f_err;
 
 #ifndef OPENSSL_NO_SCTP
@@ -2144,23 +2210,31 @@ static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
 
 MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
 {
-    int al;
+    int al = SSL_AD_DECODE_ERROR;
     unsigned int ticklen;
-    unsigned long ticket_lifetime_hint;
+    unsigned long ticket_lifetime_hint, age_add = 0;
     unsigned int sess_len;
+    RAW_EXTENSION *exts = NULL;
 
     if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+        || (SSL_IS_TLS13(s) && !PACKET_get_net_4(pkt, &age_add))
         || !PACKET_get_net_2(pkt, &ticklen)
-        || PACKET_remaining(pkt) != ticklen) {
-        al = SSL_AD_DECODE_ERROR;
+        || (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) != ticklen)
+        || (SSL_IS_TLS13(s)
+            && (ticklen == 0 || PACKET_remaining(pkt) < ticklen))) {
         SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
 
-    /* Server is allowed to change its mind and send an empty ticket. */
+    /*
+     * Server is allowed to change its mind (in <=TLSv1.2) and send an empty
+     * ticket. We already checked this TLSv1.3 case above, so it should never
+     * be 0 here in that instance
+     */
     if (ticklen == 0)
         return MSG_PROCESS_CONTINUE_READING;
 
+    /* TODO(TLS1.3): Is this a suitable test for TLS1.3? */
     if (s->session->session_id_length > 0) {
         int i = s->session_ctx->session_cache_mode;
         SSL_SESSION *new_sess;
@@ -2185,6 +2259,12 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
         s->session = new_sess;
     }
 
+    /*
+     * Technically the cast to long here is not guaranteed by the C standard -
+     * but we use it elsewhere, so this should be ok.
+     */
+    s->session->time = (long)time(NULL);
+
     OPENSSL_free(s->session->ext.tick);
     s->session->ext.tick = NULL;
     s->session->ext.ticklen = 0;
@@ -2201,7 +2281,23 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
     }
 
     s->session->ext.tick_lifetime_hint = ticket_lifetime_hint;
+    s->session->ext.tick_age_add = age_add;
     s->session->ext.ticklen = ticklen;
+
+    if (SSL_IS_TLS13(s)) {
+        PACKET extpkt;
+
+        if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
+                || !tls_collect_extensions(s, &extpkt,
+                                           EXT_TLS1_3_NEW_SESSION_TICKET,
+                                           &exts, &al)
+                || !tls_parse_all_extensions(s, EXT_TLS1_3_NEW_SESSION_TICKET,
+                                             exts, NULL, 0, &al)) {
+            SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+            goto f_err;
+        }
+    }
+
     /*
      * There are two ways to detect a resumed ticket session. One is to set
      * an appropriate session ID and then the server must return a match in
@@ -2224,6 +2320,13 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
         goto err;
     }
     s->session->session_id_length = sess_len;
+
+    /* This is a standalone message in TLSv1.3, so there is no more to read */
+    if (SSL_IS_TLS13(s)) {
+        ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+        return MSG_PROCESS_FINISHED_READING;
+    }
+
     return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -3112,6 +3215,31 @@ int tls_construct_next_proto(SSL *s, WPACKET *pkt)
 }
 #endif
 
+MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) > 0) {
+        /* should contain no data */
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_REQ, SSL_R_LENGTH_MISMATCH);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        ossl_statem_set_error(s);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * This is a historical discrepancy (not in the RFC) maintained for
+     * compatibility reasons. If a TLS client receives a HelloRequest it will
+     * attempt an abbreviated handshake. However if a DTLS client receives a
+     * HelloRequest it will do a full handshake. Either behaviour is reasonable
+     * but doing one for TLS and another for DTLS is odd.
+     */
+    if (SSL_IS_DTLS(s))
+        SSL_renegotiate(s);
+    else
+        SSL_renegotiate_abbreviated(s);
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
 static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
 {
     int al = SSL_AD_INTERNAL_ERROR;
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c
index 1c1758b..34964db 100644
--- a/ssl/statem/statem_dtls.c
+++ b/ssl/statem/statem_dtls.c
@@ -788,8 +788,10 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len)
         return 0;
     }
 
-    if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
-        wire[0] == SSL3_MT_HELLO_REQUEST) {
+    if (!s->server
+            && s->d1->r_msg_hdr.frag_off == 0
+            && s->statem.hand_state != TLS_ST_OK
+            && wire[0] == SSL3_MT_HELLO_REQUEST) {
         /*
          * The server may always send 'Hello Request' messages -- we are
          * doing a handshake anyway now, so ignore them if their format is
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 905a2cc..c8b1469 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -72,6 +72,49 @@ int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype)
     return 1;
 }
 
+int tls_setup_handshake(SSL *s)
+{
+    if (!ssl3_init_finished_mac(s))
+        return 0;
+
+    if (s->server) {
+        if (SSL_IS_FIRST_HANDSHAKE(s)) {
+            s->ctx->stats.sess_accept++;
+        } else if (!s->s3->send_connection_binding &&
+                   !(s->options &
+                     SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
+            /*
+             * Server attempting to renegotiate with client that doesn't
+             * support secure renegotiation.
+             */
+            SSLerr(SSL_F_TLS_SETUP_HANDSHAKE,
+                   SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+            return 0;
+        } else {
+            s->ctx->stats.sess_accept_renegotiate++;
+
+            s->s3->tmp.cert_request = 0;
+        }
+    } else {
+        if (SSL_IS_FIRST_HANDSHAKE(s))
+            s->ctx->stats.sess_connect++;
+        else
+            s->ctx->stats.sess_connect_renegotiate++;
+
+        /* mark client_random uninitialized */
+        memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
+        s->hit = 0;
+
+        s->s3->tmp.cert_req = 0;
+
+        if (SSL_IS_DTLS(s))
+            s->statem.use_timer = 1;
+    }
+
+    return 1;
+}
+
 /*
  * Size of the to-be-signed TLS13 data, without the hash size itself:
  * 64 bytes of value 32, 33 context bytes, 1 byte separator
@@ -607,7 +650,7 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
             }
         } else {
             if (!s->method->ssl3_enc->generate_master_secret(s,
-                    s->session->master_key, s->handshake_secret, 0,
+                    s->master_secret, s->handshake_secret, 0,
                     &s->session->master_key_length)) {
                 SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
                 goto f_err;
@@ -778,7 +821,12 @@ unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk,
     return 1;
 }
 
-WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst)
+/*
+ * Tidy up after the end of a handshake. In the case of SCTP this may result
+ * in NBIO events. If |clearbufs| is set then init_buf and the wbio buffer is
+ * freed up as well.
+ */
+WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
 {
     void (*cb) (const SSL *ssl, int type, int val) = NULL;
 
@@ -791,26 +839,26 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst)
     }
 #endif
 
-    /* clean a few things up */
-    ssl3_cleanup_key_block(s);
-
-    if (!SSL_IS_DTLS(s)) {
-        /*
-         * We don't do this in DTLS because we may still need the init_buf
-         * in case there are any unexpected retransmits
-         */
-        BUF_MEM_free(s->init_buf);
-        s->init_buf = NULL;
+    if (clearbufs) {
+        if (!SSL_IS_DTLS(s)) {
+            /*
+             * We don't do this in DTLS because we may still need the init_buf
+             * in case there are any unexpected retransmits
+             */
+            BUF_MEM_free(s->init_buf);
+            s->init_buf = NULL;
+        }
+        ssl_free_wbio_buffer(s);
+        s->init_num = 0;
     }
 
-    ssl_free_wbio_buffer(s);
-
-    s->init_num = 0;
-
-    if (!s->server || s->renegotiate == 2) {
+    if (s->statem.cleanuphand) {
         /* skipped if we just sent a HelloRequest */
         s->renegotiate = 0;
         s->new_session = 0;
+        s->statem.cleanuphand = 0;
+
+        ssl3_cleanup_key_block(s);
 
         if (s->server) {
             ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
@@ -843,6 +891,13 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst)
         }
     }
 
+    /*
+     * If we've not cleared the buffers its because we've got more work to do,
+     * so continue.
+     */
+    if (!clearbufs)
+        return WORK_FINISHED_CONTINUE;
+
     return WORK_FINISHED_STOP;
 }
 
@@ -891,7 +946,8 @@ int tls_get_message_header(SSL *s, int *mt)
 
         skip_message = 0;
         if (!s->server)
-            if (p[0] == SSL3_MT_HELLO_REQUEST)
+            if (s->statem.hand_state != TLS_ST_OK
+                    && p[0] == SSL3_MT_HELLO_REQUEST)
                 /*
                  * The server may always send 'Hello Request' messages --
                  * we are doing a handshake anyway now, so ignore them if
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index b52de70..cb6457f 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -107,7 +107,7 @@ __owur int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt);
 __owur int dtls_construct_change_cipher_spec(SSL *s, WPACKET *pkt);
 
 __owur int tls_construct_finished(SSL *s, WPACKET *pkt);
-__owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst);
+__owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs);
 __owur WORK_STATE dtls_wait_for_dry(SSL *s);
 
 /* some client-only functions */
@@ -132,6 +132,7 @@ __owur int ssl3_check_cert_and_algorithm(SSL *s);
 #ifndef OPENSSL_NO_NEXTPROTONEG
 __owur int tls_construct_next_proto(SSL *s, WPACKET *pkt);
 #endif
+__owur MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt);
 __owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt);
 
 /* some server-only functions */
@@ -165,6 +166,12 @@ __owur int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts,
 __owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
                                     X509 *x, size_t chainidx, int *al);
 
+__owur int tls_psk_do_binder(SSL *s, const EVP_MD *md,
+                             const unsigned char *msgstart,
+                             size_t binderoffset, const unsigned char *binderin,
+                             unsigned char *binderout,
+                             SSL_SESSION *sess, int sign);
+
 /* Server Extension processing */
 int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
                                int *al);
@@ -199,6 +206,9 @@ int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
 int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
                              int *al);
 int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
+                                 int *al);
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
 
 int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
                                    size_t chainidx, int *al);
@@ -237,6 +247,8 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 #define TLSEXT_TYPE_cryptopro_bug      0xfde8
 int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, X509 *x,
                                      size_t chainidx, int *al);
+int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+                           int *al);
 
 /* Client Extension processing */
 int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
@@ -283,8 +295,12 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x,
                                           size_t chainidx, int *al);
 int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
                                  int *al);
+int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
+                                     size_t chainidx, int *al);
 int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
                                int *al);
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+                           int *al);
 int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
                                int *al);
 int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
@@ -314,3 +330,4 @@ int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
                              int *al);
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 2e76b80..023f1ac 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -162,6 +162,7 @@ int ossl_statem_server_read_transition(SSL *s, int mt)
         break;
 
     case TLS_ST_BEFORE:
+    case TLS_ST_OK:
     case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
         if (mt == SSL3_MT_CLIENT_HELLO) {
             st->hand_state = TLS_ST_SR_CLNT_HELLO;
@@ -438,6 +439,18 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
         return WRITE_TRAN_FINISHED;
 
     case TLS_ST_SR_FINISHED:
+        /*
+         * Technically we have finished the handshake at this point, but we're
+         * going to remain "in_init" for now and write out the session ticket
+         * immediately.
+         * TODO(TLS1.3): Perhaps we need to be able to control this behaviour
+         * and give the application the opportunity to delay sending the
+         * session ticket?
+         */
+        st->hand_state = TLS_ST_SW_SESSION_TICKET;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
         st->hand_state = TLS_ST_OK;
         ossl_statem_set_in_init(s, 0);
         return WRITE_TRAN_CONTINUE;
@@ -465,15 +478,24 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
         /* Shouldn't happen */
         return WRITE_TRAN_ERROR;
 
+    case TLS_ST_OK:
+        if (st->request_state == TLS_ST_SW_HELLO_REQ) {
+            /* We must be trying to renegotiate */
+            st->hand_state = TLS_ST_SW_HELLO_REQ;
+            st->request_state = TLS_ST_BEFORE;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Must be an incoming ClientHello */
+        if (!tls_setup_handshake(s)) {
+            ossl_statem_set_error(s);
+            return WRITE_TRAN_ERROR;
+        }
+        /* Fall through */
+
     case TLS_ST_BEFORE:
         /* Just go straight to trying to read from the client */
         return WRITE_TRAN_FINISHED;
 
-    case TLS_ST_OK:
-        /* We must be trying to renegotiate */
-        st->hand_state = TLS_ST_SW_HELLO_REQ;
-        return WRITE_TRAN_CONTINUE;
-
     case TLS_ST_SW_HELLO_REQ:
         st->hand_state = TLS_ST_OK;
         ossl_statem_set_in_init(s, 0);
@@ -616,7 +638,14 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
         return WORK_FINISHED_CONTINUE;
 
     case TLS_ST_SW_SESSION_TICKET:
-        if (SSL_IS_DTLS(s)) {
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * Actually this is the end of the handshake, but we're going
+             * straight into writing the session ticket out. So we finish off
+             * the handshake, but keep the various buffers active.
+             */
+            return tls_finish_handshake(s, wst, 0);
+        } if (SSL_IS_DTLS(s)) {
             /*
              * We're into the last flight. We don't retransmit the last flight
              * unless we need to, so we don't use the timer
@@ -643,7 +672,7 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
         return WORK_FINISHED_CONTINUE;
 
     case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
+        return tls_finish_handshake(s, wst, 1);
     }
 
     return WORK_FINISHED_CONTINUE;
@@ -771,13 +800,18 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
 #endif
         if (SSL_IS_TLS13(s)) {
             if (!s->method->ssl3_enc->generate_master_secret(s,
-                        s->session->master_key, s->handshake_secret, 0,
+                        s->master_secret, s->handshake_secret, 0,
                         &s->session->master_key_length)
                 || !s->method->ssl3_enc->change_cipher_state(s,
                         SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE))
             return WORK_ERROR;
         }
         break;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        if (SSL_IS_TLS13(s) && statem_flush(s) != 1)
+            return WORK_MORE_A;
+        break;
     }
 
     return WORK_FINISHED_CONTINUE;
@@ -1147,6 +1181,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     static const unsigned char null_compression = 0;
     CLIENTHELLO_MSG clienthello;
 
+    /* Check if this is actually an unexpected renegotiation ClientHello */
+    if (s->renegotiate == 0 && !SSL_IS_FIRST_HANDSHAKE(s)) {
+        s->renegotiate = 1;
+        s->new_session = 1;
+    }
+
+    /* This is a real handshake so make sure we clean it up at the end */
+    s->statem.cleanuphand = 1;
+
     /*
      * First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
      */
@@ -1432,21 +1475,12 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         if (!ssl_get_new_session(s, 1))
             goto err;
     } else {
-        i = ssl_get_prev_session(s, &clienthello);
-        /*
-         * Only resume if the session's version matches the negotiated
-         * version.
-         * RFC 5246 does not provide much useful advice on resumption
-         * with a different protocol version. It doesn't forbid it but
-         * the sanity of such behaviour would be questionable.
-         * In practice, clients do not accept a version mismatch and
-         * will abort the handshake with an error.
-         */
-        if (i == 1 && s->version == s->session->ssl_version) {
+        i = ssl_get_prev_session(s, &clienthello, &al);
+        if (i == 1) {
             /* previous session */
             s->hit = 1;
         } else if (i == -1) {
-            goto err;
+            goto f_err;
         } else {
             /* i == 0 */
             if (!ssl_get_new_session(s, 1))
@@ -1514,15 +1548,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    /* Check we've got a key_share for TLSv1.3 */
-    if (SSL_IS_TLS13(s) && s->s3->peer_tmp == NULL && !s->hit) {
-        /* No suitable share */
-        /* TODO(TLS1.3): Send a HelloRetryRequest */
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SUITABLE_KEY_SHARE);
-        goto f_err;
-    }
-
     /*
      * Check if we want to use external pre-shared secret for this handshake
      * for not reused session only. We need to generate server_random before
@@ -1845,7 +1870,6 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
         }
     }
 #endif
-    s->renegotiate = 2;
 
     return WORK_FINISHED_STOP;
  f_err:
@@ -3201,8 +3225,18 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
     SSL_CTX *tctx = s->initial_ctx;
     unsigned char iv[EVP_MAX_IV_LENGTH];
     unsigned char key_name[TLSEXT_KEYNAME_LENGTH];
-    int iv_len;
+    int iv_len, al = SSL_AD_INTERNAL_ERROR;
     size_t macoffset, macendoffset;
+    union {
+        unsigned char age_add_c[sizeof(uint32_t)];
+        uint32_t age_add;
+    } age_add_u;
+
+    if (SSL_IS_TLS13(s)) {
+        if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0)
+            goto err;
+        s->session->ext.tick_age_add = age_add_u.age_add;
+    }
 
     /* get session encoding length */
     slen_full = i2d_SSL_SESSION(s->session, NULL);
@@ -3301,6 +3335,8 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
      * new sessions will live as long as their sessions.
      */
     if (!WPACKET_put_bytes_u32(pkt, s->hit ? 0 : s->session->timeout)
+            || (SSL_IS_TLS13(s)
+                && !WPACKET_put_bytes_u32(pkt, age_add_u.age_add))
                /* Now the actual ticket data */
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_get_total_written(pkt, &macoffset)
@@ -3327,7 +3363,11 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
             || hlen > EVP_MAX_MD_SIZE
             || !WPACKET_allocate_bytes(pkt, hlen, &macdata2)
             || macdata1 != macdata2
-            || !WPACKET_close(pkt)) {
+            || !WPACKET_close(pkt)
+            || (SSL_IS_TLS13(s)
+                && !tls_construct_extensions(s, pkt,
+                                             EXT_TLS1_3_NEW_SESSION_TICKET,
+                                             NULL, 0, &al))) {
         SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
         goto err;
     }
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b05d148..a7239c7 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -20,10 +20,6 @@
 #include "ssl_locl.h"
 #include <openssl/ct.h>
 
-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);
-
 SSL3_ENC_METHOD const TLSv1_enc_data = {
     tls1_enc,
     tls1_mac,
@@ -958,7 +954,7 @@ int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op)
 
 int tls_use_ticket(SSL *s)
 {
-    if ((s->options & SSL_OP_NO_TICKET) || SSL_IS_TLS13(s))
+    if ((s->options & SSL_OP_NO_TICKET))
         return 0;
     return ssl_security(s, SSL_SECOP_TICKET, 0, 0, NULL);
 }
@@ -1053,8 +1049,8 @@ int tls1_set_server_sigalgs(SSL *s)
  *   s->ctx->ext.ticket_key_cb asked to renew the client's ticket.
  *   Otherwise, s->ext.ticket_expected is set to 0.
  */
-int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
-                               SSL_SESSION **ret)
+TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
+                                         SSL_SESSION **ret)
 {
     int retv;
     size_t size;
@@ -1069,11 +1065,11 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
      * resumption.
      */
     if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
-        return 0;
+        return TICKET_NONE;
 
     ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket];
     if (!ticketext->present)
-        return 0;
+        return TICKET_NONE;
 
     size = PACKET_remaining(&ticketext->data);
     if (size == 0) {
@@ -1082,7 +1078,7 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
          * one.
          */
         s->ext.ticket_expected = 1;
-        return 1;
+        return TICKET_EMPTY;
     }
     if (s->ext.session_secret_cb) {
         /*
@@ -1091,25 +1087,25 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
          * abbreviated handshake based on external mechanism to
          * calculate the master secret later.
          */
-        return 2;
+        return TICKET_NO_DECRYPT;
     }
 
     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 */
+    case TICKET_NO_DECRYPT:
         s->ext.ticket_expected = 1;
-        return 2;
+        return TICKET_NO_DECRYPT;
 
-    case 3:            /* ticket was decrypted */
-        return 3;
+    case TICKET_SUCCESS:
+        return TICKET_SUCCESS;
 
-    case 4:            /* ticket decrypted but need to renew */
+    case TICKET_SUCCESS_RENEW:
         s->ext.ticket_expected = 1;
-        return 3;
+        return TICKET_SUCCESS;
 
-    default:           /* fatal error */
-        return -1;
+    default:
+        return TICKET_FATAL_ERR_OTHER;
     }
 }
 
@@ -1122,22 +1118,16 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
  *   sesslen: the length of the session ID.
  *   psess: (output) on return, if a ticket was decrypted, then this is set to
  *       point to the resulting session.
- *
- * Returns:
- *   -2: fatal error, malloc failure.
- *   -1: fatal error, either from parsing or decrypting the ticket.
- *    2: the ticket couldn't be decrypted.
- *    3: a ticket was successfully decrypted and *psess was set.
- *    4: same as 3, but the ticket needs to be renewed.
  */
-static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
-                              size_t eticklen, const unsigned char *sess_id,
-                              size_t sesslen, SSL_SESSION **psess)
+TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick,
+                                 size_t eticklen, const unsigned char *sess_id,
+                                 size_t sesslen, SSL_SESSION **psess)
 {
     SSL_SESSION *sess;
     unsigned char *sdec;
     const unsigned char *p;
-    int slen, renew_ticket = 0, ret = -1, declen;
+    int slen, renew_ticket = 0, declen;
+    TICKET_RETURN ret = TICKET_FATAL_ERR_OTHER;
     size_t mlen;
     unsigned char tick_hmac[EVP_MAX_MD_SIZE];
     HMAC_CTX *hctx = NULL;
@@ -1147,10 +1137,10 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
     /* Initialize session ticket encryption and HMAC contexts */
     hctx = HMAC_CTX_new();
     if (hctx == NULL)
-        return -2;
+        return TICKET_FATAL_ERR_MALLOC;
     ctx = EVP_CIPHER_CTX_new();
     if (ctx == NULL) {
-        ret = -2;
+        ret = TICKET_FATAL_ERR_MALLOC;
         goto err;
     }
     if (tctx->ext.ticket_key_cb) {
@@ -1160,7 +1150,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
         if (rv < 0)
             goto err;
         if (rv == 0) {
-            ret = 2;
+            ret = TICKET_NO_DECRYPT;
             goto err;
         }
         if (rv == 2)
@@ -1169,7 +1159,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
         /* Check key name matches */
         if (memcmp(etick, tctx->ext.tick_key_name,
                    sizeof(tctx->ext.tick_key_name)) != 0) {
-            ret = 2;
+            ret = TICKET_NO_DECRYPT;
             goto err;
         }
         if (HMAC_Init_ex(hctx, tctx->ext.tick_hmac_key,
@@ -1177,8 +1167,8 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
                          EVP_sha256(), NULL) <= 0
             || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
                                   tctx->ext.tick_aes_key,
-                                  etick + sizeof(tctx->ext.tick_key_name)) <=
-            0) {
+                                  etick
+                                  + sizeof(tctx->ext.tick_key_name)) <= 0) {
             goto err;
         }
     }
@@ -1193,7 +1183,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
     /* Sanity check ticket length: must exceed keyname + IV + HMAC */
     if (eticklen <=
         TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx) + mlen) {
-        ret = 2;
+        ret = TICKET_NO_DECRYPT;
         goto err;
     }
     eticklen -= mlen;
@@ -1205,7 +1195,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
     HMAC_CTX_free(hctx);
     if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) {
         EVP_CIPHER_CTX_free(ctx);
-        return 2;
+        return TICKET_NO_DECRYPT;
     }
     /* Attempt to decrypt session data */
     /* Move p after IV to start of encrypted ticket, update length */
@@ -1216,12 +1206,12 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
                                           (int)eticklen) <= 0) {
         EVP_CIPHER_CTX_free(ctx);
         OPENSSL_free(sdec);
-        return -1;
+        return TICKET_FATAL_ERR_OTHER;
     }
     if (EVP_DecryptFinal(ctx, sdec + slen, &declen) <= 0) {
         EVP_CIPHER_CTX_free(ctx);
         OPENSSL_free(sdec);
-        return 2;
+        return TICKET_NO_DECRYPT;
     }
     slen += declen;
     EVP_CIPHER_CTX_free(ctx);
@@ -1242,15 +1232,15 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
         sess->session_id_length = sesslen;
         *psess = sess;
         if (renew_ticket)
-            return 4;
+            return TICKET_SUCCESS_RENEW;
         else
-            return 3;
+            return TICKET_SUCCESS;
     }
     ERR_clear_error();
     /*
      * For session parse failure, indicate that we need to send a new ticket.
      */
-    return 2;
+    return TICKET_NO_DECRYPT;
  err:
     EVP_CIPHER_CTX_free(ctx);
     HMAC_CTX_free(hctx);
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index b3b6e18..9da8f75 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -449,6 +449,7 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_server_authz, "server_authz"},
     {TLSEXT_TYPE_cert_type, "cert_type"},
     {TLSEXT_TYPE_key_share, "key_share"},
+    {TLSEXT_TYPE_psk_kex_modes, "psk_key_exchange_modes"},
     {TLSEXT_TYPE_supported_groups, "supported_groups"},
     {TLSEXT_TYPE_ec_point_formats, "ec_point_formats"},
     {TLSEXT_TYPE_srp, "srp"},
@@ -540,6 +541,11 @@ static ssl_trace_tbl ssl_ctype_tbl[] = {
     {66, "ecdsa_fixed_ecdh"}
 };
 
+static ssl_trace_tbl ssl_psk_kex_modes_tbl[] = {
+    {TLSEXT_KEX_MODE_KE, "psk_ke"},
+    {TLSEXT_KEX_MODE_KE_DHE, "psk_dhe_ke"}
+};
+
 static ssl_trace_tbl ssl_crypto_tbl[] = {
     {TLS1_RT_CRYPTO_PREMASTER, "Premaster Secret"},
     {TLS1_RT_CRYPTO_CLIENT_RANDOM, "Client Random"},
@@ -760,6 +766,15 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
         return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 2,
                               ssl_version_tbl);
 
+    case TLSEXT_TYPE_psk_kex_modes:
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1,
+                              ssl_psk_kex_modes_tbl);
+
     default:
         BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2);
     }
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index 449e6f9..7c217c1 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -23,13 +23,12 @@ static const unsigned char default_zeros[EVP_MAX_MD_SIZE];
  * the location pointed to be |out|. The |hash| value may be NULL. Returns 1 on
  * success  0 on failure.
  */
-int tls13_hkdf_expand(SSL *s, const unsigned char *secret,
+int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret,
                              const unsigned char *label, size_t labellen,
                              const unsigned char *hash,
                              unsigned char *out, size_t outlen)
 {
     const unsigned char label_prefix[] = "TLS 1.3, ";
-    const EVP_MD *md = ssl_handshake_md(s);
     EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
     int ret;
     size_t hkdflabellen;
@@ -83,8 +82,8 @@ int tls13_derive_key(SSL *s, const unsigned char *secret, unsigned char *key,
 {
     static const unsigned char keylabel[] = "key";
 
-    return tls13_hkdf_expand(s, secret, keylabel, sizeof(keylabel) - 1, NULL,
-                             key, keylen);
+    return tls13_hkdf_expand(s, ssl_handshake_md(s), secret, keylabel,
+                             sizeof(keylabel) - 1, NULL, key, keylen);
 }
 
 /*
@@ -96,16 +95,17 @@ int tls13_derive_iv(SSL *s, const unsigned char *secret, unsigned char *iv,
 {
     static const unsigned char ivlabel[] = "iv";
 
-    return tls13_hkdf_expand(s, secret, ivlabel, sizeof(ivlabel) - 1, NULL,
-                             iv, ivlen);
+    return tls13_hkdf_expand(s, ssl_handshake_md(s), secret, ivlabel,
+                             sizeof(ivlabel) - 1, NULL, iv, ivlen);
 }
 
-static int tls13_derive_finishedkey(SSL *s, const unsigned char *secret,
-                                 unsigned char *fin, size_t finlen)
+int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
+                             const unsigned char *secret,
+                             unsigned char *fin, size_t finlen)
 {
     static const unsigned char finishedlabel[] = "finished";
 
-    return tls13_hkdf_expand(s, secret, finishedlabel,
+    return tls13_hkdf_expand(s, md, secret, finishedlabel,
                              sizeof(finishedlabel) - 1, NULL, fin, finlen);
 }
 
@@ -114,12 +114,12 @@ static int tls13_derive_finishedkey(SSL *s, const unsigned char *secret,
  * length |insecretlen|, generate a new secret and store it in the location
  * pointed to by |outsecret|. Returns 1 on success  0 on failure.
  */
-static int tls13_generate_secret(SSL *s, const unsigned char *prevsecret,
-                                 const unsigned char *insecret,
-                                 size_t insecretlen,
-                                 unsigned char *outsecret)
+int tls13_generate_secret(SSL *s, const EVP_MD *md,
+                          const unsigned char *prevsecret,
+                          const unsigned char *insecret,
+                          size_t insecretlen,
+                          unsigned char *outsecret)
 {
-    const EVP_MD *md = ssl_handshake_md(s);
     size_t mdlen, prevsecretlen;
     int ret;
     EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
@@ -155,17 +155,6 @@ static int tls13_generate_secret(SSL *s, const unsigned char *prevsecret,
 }
 
 /*
- * Given an input secret |insecret| of length |insecretlen| generate the early
- * secret. Returns 1 on success  0 on failure.
- */
-int tls13_generate_early_secret(SSL *s, const unsigned char *insecret,
-                                size_t insecretlen)
-{
-    return tls13_generate_secret(s, NULL, insecret, insecretlen,
-                                 (unsigned char *)&s->early_secret);
-}
-
-/*
  * Given an input secret |insecret| of length |insecretlen| generate the
  * handshake secret. This requires the early secret to already have been
  * generated. Returns 1 on success  0 on failure.
@@ -173,7 +162,8 @@ int tls13_generate_early_secret(SSL *s, const unsigned char *insecret,
 int tls13_generate_handshake_secret(SSL *s, const unsigned char *insecret,
                                 size_t insecretlen)
 {
-    return tls13_generate_secret(s, s->early_secret, insecret, insecretlen,
+    return tls13_generate_secret(s, ssl_handshake_md(s), s->early_secret,
+                                 insecret, insecretlen,
                                  (unsigned char *)&s->handshake_secret);
 }
 
@@ -186,8 +176,10 @@ int tls13_generate_master_secret(SSL *s, unsigned char *out,
                                  unsigned char *prev, size_t prevlen,
                                  size_t *secret_size)
 {
-    *secret_size = EVP_MD_size(ssl_handshake_md(s));
-    return tls13_generate_secret(s, prev, NULL, 0, out);
+    const EVP_MD *md = ssl_handshake_md(s);
+
+    *secret_size = EVP_MD_size(md);
+    return tls13_generate_secret(s, md, prev, NULL, 0, out);
 }
 
 /*
@@ -260,6 +252,8 @@ int tls13_change_cipher_state(SSL *s, int which)
         "server handshake traffic secret";
     static const unsigned char server_application_traffic[] =
         "server application traffic secret";
+    static const unsigned char resumption_master_secret[] =
+        "resumption master secret";
     unsigned char key[EVP_MAX_KEY_LENGTH];
     unsigned char *iv;
     unsigned char secret[EVP_MAX_MD_SIZE];
@@ -313,9 +307,7 @@ int tls13_change_cipher_state(SSL *s, int which)
             label = client_handshake_traffic;
             labellen = sizeof(client_handshake_traffic) - 1;
         } else {
-            int hashleni;
-
-            insecret = s->session->master_key;
+            insecret = s->master_secret;
             label = client_application_traffic;
             labellen = sizeof(client_application_traffic) - 1;
             /*
@@ -325,12 +317,6 @@ int tls13_change_cipher_state(SSL *s, int which)
              * previously saved value.
              */
             hash = s->server_finished_hash;
-            hashleni = EVP_MD_CTX_size(s->s3->handshake_dgst);
-            if (hashleni < 0) {
-                SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            hashlen = (size_t)hashleni;
         }
     } else {
         if (which & SSL3_CC_HANDSHAKE) {
@@ -340,42 +326,57 @@ int tls13_change_cipher_state(SSL *s, int which)
             label = server_handshake_traffic;
             labellen = sizeof(server_handshake_traffic) - 1;
         } else {
-            insecret = s->session->master_key;
+            insecret = s->master_secret;
             label = server_application_traffic;
             labellen = sizeof(server_application_traffic) - 1;
         }
     }
 
-    if (label != client_application_traffic) {
-        if (!ssl3_digest_cached_records(s, 1)
-                || !ssl_handshake_hash(s, hash, sizeof(hashval), &hashlen)) {
-            SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        /*
-         * Save the hash of handshakes up to now for use when we calculate the
-         * client application traffic secret
-         */
-        if (label == server_application_traffic)
-            memcpy(s->server_finished_hash, hash, hashlen);
+    if (!ssl3_digest_cached_records(s, 1)
+            || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
+        SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+        goto err;
     }
 
-    if (!tls13_hkdf_expand(s, insecret, label, labellen, hash, secret,
-                           hashlen)) {
+    /*
+     * Save the hash of handshakes up to now for use when we calculate the
+     * client application traffic secret
+     */
+    if (label == server_application_traffic)
+        memcpy(s->server_finished_hash, hashval, hashlen);
+
+    if (!tls13_hkdf_expand(s, ssl_handshake_md(s), insecret, label, labellen,
+                           hash, secret, hashlen)) {
         SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
+    if (label == client_application_traffic) {
+        /*
+         * We also create the resumption master secret, but this time use the
+         * hash for the whole handshake including the Client Finished
+         */
+        if (!tls13_hkdf_expand(s, ssl_handshake_md(s), insecret,
+                               resumption_master_secret,
+                               sizeof(resumption_master_secret) - 1,
+                               hashval, s->session->master_key, hashlen)) {
+            SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        s->session->master_key_length = hashlen;
+    }
+
     /* TODO(size_t): convert me */
     keylen = EVP_CIPHER_key_length(ciph);
     ivlen = EVP_CIPHER_iv_length(ciph);
 
     if (!tls13_derive_key(s, secret, key, keylen)
             || !tls13_derive_iv(s, secret, iv, ivlen)
-            || (finsecret != NULL && !tls13_derive_finishedkey(s, secret,
-                                                               finsecret,
-                                                               finsecretlen))) {
+            || (finsecret != NULL && !tls13_derive_finishedkey(s,
+                                                           ssl_handshake_md(s),
+                                                           secret,
+                                                           finsecret,
+                                                           finsecretlen))) {
         SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
         goto err;
     }
diff --git a/test/build.info b/test/build.info
index c116238..a6a5c7c 100644
--- a/test/build.info
+++ b/test/build.info
@@ -309,11 +309,7 @@ IF[{- !$disabled{tests} -}]
   ENDIF
 
   IF[{- $disabled{shared} -}]
-    PROGRAMS_NO_INST=wpackettest cipher_overhead_test
-    SOURCE[wpackettest]=wpackettest.c testutil.c test_main_custom.c
-    INCLUDE[wpackettest]=../include
-    DEPEND[wpackettest]=../libcrypto ../libssl
-
+    PROGRAMS_NO_INST=cipher_overhead_test
     SOURCE[cipher_overhead_test]=cipher_overhead_test.c
     INCLUDE[cipher_overhead_test]=.. ../include
     DEPEND[cipher_overhead_test]=../libcrypto ../libssl
@@ -334,7 +330,7 @@ IF[{- !$disabled{tests} -}]
   # names with the DLL import libraries.
   IF[{- $disabled{shared} || $target{build_scheme}->[1] ne 'windows' -}]
     PROGRAMS_NO_INST=asn1_internal_test modes_internal_test x509_internal_test \
-                     tls13encryptiontest
+                     tls13encryptiontest wpackettest
     IF[{- !$disabled{poly1305} -}]
       PROGRAMS_NO_INST=poly1305_internal_test
     ENDIF
@@ -358,6 +354,10 @@ IF[{- !$disabled{tests} -}]
     SOURCE[tls13encryptiontest]=tls13encryptiontest.c testutil.c test_main.c
     INCLUDE[tls13encryptiontest]=.. ../include
     DEPEND[tls13encryptiontest]=../libcrypto ../libssl.a
+
+    SOURCE[wpackettest]=wpackettest.c testutil.c test_main_custom.c
+    INCLUDE[wpackettest]=../include
+    DEPEND[wpackettest]=../libcrypto ../libssl.a
   ENDIF
 
   IF[{- !$disabled{mdc2} -}]
diff --git a/test/recipes/70-test_tls13kexmodes.t b/test/recipes/70-test_tls13kexmodes.t
new file mode 100755
index 0000000..9383519
--- /dev/null
+++ b/test/recipes/70-test_tls13kexmodes.t
@@ -0,0 +1,243 @@
+#! /usr/bin/env perl
+# Copyright 2017 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_tls13kexmodes";
+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 TLSv1.3 enabled"
+    if disabled("tls1_3");
+
+$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+$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_VERIFY,
+        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_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_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
+        checkhandshake::PSK_KEX_MODES_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_CLI_EXTENSION],
+
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::KEY_SHARE_SRV_EXTENSION],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_SRV_EXTENSION],
+
+    [TLSProxy::Message::MT_CERTIFICATE, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_SRV_EXTENSION],
+    [0,0,0]
+);
+
+use constant {
+    DELETE_EXTENSION => 0,
+    EMPTY_EXTENSION => 1,
+    NON_DHE_KEX_MODE_ONLY => 2,
+    DHE_KEX_MODE_ONLY => 3,
+    UNKNONW_KEX_MODES => 4,
+    BOTH_KEX_MODES => 5
+};
+
+my $proxy = TLSProxy::Proxy->new(
+    undef,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+#Test 1: First get a session
+(undef, my $session) = tempfile();
+$proxy->clientflags("-sess_out ".$session);
+$proxy->sessionfile($session);
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 7;
+ok(TLSProxy::Message->success(), "Initial connection");
+
+#Test 2: Attempt a resume with no kex modes extension. Should not resume
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+my $testtype = DELETE_EXTENSION;
+$proxy->filter(\&modify_kex_modes_filter);
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION,
+               "Resume with no kex modes");
+
+#Test 3: Attempt a resume with empty kex modes extension. Should fail (empty
+#        extension is invalid)
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$testtype = EMPTY_EXTENSION;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Resume with empty kex modes");
+
+#Test 4: Attempt a resume with non-dhe kex mode only. Should resume without a
+#        key_share
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$testtype = NON_DHE_KEX_MODE_ONLY;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with non-dhe kex mode");
+
+#Test 5: Attempt a resume with dhe kex mode only. Should resume with a key_share
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$testtype = DHE_KEX_MODE_ONLY;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with non-dhe kex mode");
+
+#Test 6: Attempt a resume with only unrecognised kex modes. Should not resume
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$testtype = UNKNONW_KEX_MODES;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION,
+               "Resume with empty kex modes");
+
+#Test 7: Attempt a resume with both non-dhe and dhe kex mode. Should resume with
+#        a key_share
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$testtype = BOTH_KEX_MODES;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with non-dhe kex mode");
+
+unlink $session;
+
+sub modify_kex_modes_filter
+{
+    my $proxy = shift;
+
+    # We're only interested in the initial ClientHello
+    return if ($proxy->flight != 0);
+
+    foreach my $message (@{$proxy->message_list}) {
+        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
+            my $ext;
+
+            if ($testtype == EMPTY_EXTENSION) {
+                $ext = pack "C",
+                    0x00;       #List length
+            } elsif ($testtype == NON_DHE_KEX_MODE_ONLY) {
+                $ext = pack "C2",
+                    0x01,       #List length
+                    0x00;       #psk_ke
+            } elsif ($testtype == DHE_KEX_MODE_ONLY) {
+                $ext = pack "C2",
+                    0x01,       #List length
+                    0x01;       #psk_dhe_ke
+            } elsif ($testtype == UNKNONW_KEX_MODES) {
+                $ext = pack "C3",
+                    0x02,       #List length
+                    0xfe,       #unknown
+                    0xff;       #unknown
+            } elsif ($testtype == BOTH_KEX_MODES) {
+                #We deliberately list psk_ke first...should still use psk_dhe_ke
+                $ext = pack "C3",
+                    0x02,       #List length
+                    0x00,       #psk_ke
+                    0x01;       #psk_dhe_ke
+            }
+
+            if ($testtype == DELETE_EXTENSION) {
+                $message->delete_extension(
+                    TLSProxy::Message::EXT_PSK_KEX_MODES);
+            } else {
+                $message->set_extension(
+                    TLSProxy::Message::EXT_PSK_KEX_MODES, $ext);
+            }
+
+            $message->repack();
+        }
+    }
+}
diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t
index d6512b5..609a4f4 100755
--- a/test/recipes/70-test_tls13messages.t
+++ b/test/recipes/70-test_tls13messages.t
@@ -81,9 +81,15 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
         checkhandshake::DEFAULT_EXTENSIONS],
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
         checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_CLI_EXTENSION],
 
     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
         checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_SRV_EXTENSION],
 
     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SERVER_NAME,
         checkhandshake::SERVER_NAME_SRV_EXTENSION],
@@ -105,20 +111,24 @@ my $proxy = TLSProxy::Proxy->new(
 
 #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->sessionfile($session);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 12;
+plan tests => 13;
 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();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resumption handshake test");
 unlink $session;
 
 #Test 3: A status_request handshake (client request only)
diff --git a/test/recipes/70-test_wpacket.t b/test/recipes/70-test_wpacket.t
index 9170122..6d50b9f 100644
--- a/test/recipes/70-test_wpacket.t
+++ b/test/recipes/70-test_wpacket.t
@@ -12,8 +12,8 @@ use OpenSSL::Test::Utils;
 
 setup("test_wpacket");
 
-plan skip_all => "Only supported in no-shared builds"
-    if !disabled("shared");
+plan skip_all => "Test disabled in this configuration"
+    if $^O eq 'MSWin32' && !disabled("shared");
 
 plan tests => 1;
 
diff --git a/test/ssl-tests/06-sni-ticket.conf.in b/test/ssl-tests/06-sni-ticket.conf.in
index 9c5266f..8725960 100644
--- a/test/ssl-tests/06-sni-ticket.conf.in
+++ b/test/ssl-tests/06-sni-ticket.conf.in
@@ -19,7 +19,6 @@ our @tests = ();
 
 #Note: MaxProtocol is set to TLSv1.2 as session tickets work differently in
 #TLSv1.3.
-#TODO(TLS1.3): Implement TLSv1.3 style session tickets
 sub generate_tests() {
     foreach my $c ("SessionTicket", "-SessionTicket") {
         foreach my $s1 ("SessionTicket", "-SessionTicket") {
diff --git a/test/ssl-tests/09-alpn.conf b/test/ssl-tests/09-alpn.conf
index fc3c8da..e7e6cb9 100644
--- a/test/ssl-tests/09-alpn.conf
+++ b/test/ssl-tests/09-alpn.conf
@@ -383,7 +383,6 @@ 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
 
@@ -426,7 +425,6 @@ 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
 
@@ -467,13 +465,11 @@ 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
 
@@ -519,7 +515,6 @@ 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
 
@@ -565,7 +560,6 @@ 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
 
@@ -601,13 +595,11 @@ 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 ff931a9..6e86375 100644
--- a/test/ssl-tests/09-alpn.conf.in
+++ b/test/ssl-tests/09-alpn.conf.in
@@ -204,8 +204,6 @@ our @tests = (
             },
         },
         client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
@@ -229,8 +227,6 @@ our @tests = (
             },
         },
         client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo,bar,baz",
             },
@@ -249,15 +245,11 @@ 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",
             },
@@ -281,8 +273,6 @@ our @tests = (
             },
         },
         client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo,bar",
             },
@@ -302,8 +292,6 @@ our @tests = (
         },
         resume_server => { },
         client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
@@ -322,15 +310,11 @@ our @tests = (
             },
         },
         client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2",
             extra => {
                 "ALPNProtocols" => "foo",
             },
         },
         resume_client => {
-            #TODO(TLS1.3): Temporary until we support TLSv1.3 resumption
-            MaxProtocol => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
diff --git a/test/ssl-tests/12-ct.conf b/test/ssl-tests/12-ct.conf
index 14b8e93..22fa18d 100644
--- a/test/ssl-tests/12-ct.conf
+++ b/test/ssl-tests/12-ct.conf
@@ -79,7 +79,6 @@ 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
 
@@ -112,13 +111,11 @@ 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 e7fe1b9..c27e091 100644
--- a/test/ssl-tests/12-ct.conf.in
+++ b/test/ssl-tests/12-ct.conf.in
@@ -46,9 +46,6 @@ our @tests = (
         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",
             },
@@ -63,9 +60,6 @@ our @tests = (
         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",
             },
@@ -73,9 +67,6 @@ our @tests = (
         # 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",
             },
diff --git a/test/ssl-tests/protocol_version.pm b/test/ssl-tests/protocol_version.pm
index a41ffc4..cc39c75 100644
--- a/test/ssl-tests/protocol_version.pm
+++ b/test/ssl-tests/protocol_version.pm
@@ -135,22 +135,6 @@ 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 1bd7878..d76357a 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -789,12 +789,6 @@ 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/ssltestlib.c b/test/ssltestlib.c
index 57039e7..1981cb5 100644
--- a/test/ssltestlib.c
+++ b/test/ssltestlib.c
@@ -645,6 +645,8 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl)
 {
     int retc = -1, rets = -1, err, abortctr = 0;
     int clienterr = 0, servererr = 0;
+    unsigned char buf;
+    size_t readbytes;
 
     do {
         err = SSL_ERROR_WANT_WRITE;
@@ -678,5 +680,20 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl)
         }
     } while (retc <=0 || rets <= 0);
 
+    /*
+     * We attempt to read some data on the client side which we expect to fail.
+     * This will ensure we have received the NewSessionTicket in TLSv1.3 where
+     * appropriate.
+     */
+    if (SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes) > 0) {
+        if (readbytes != 0) {
+            printf("Unexpected success reading data %"OSSLzu"\n", readbytes);
+            return 0;
+        }
+    } else if (SSL_get_error(clientssl, 0) != SSL_ERROR_WANT_READ) {
+        printf("SSL_read_ex() failed\n");
+        return 0;
+    }
+
     return 1;
 }
diff --git a/test/testlib/checkhandshake.pm b/test/testlib/checkhandshake.pm
index 0c3df6f..44f7b1a 100644
--- a/test/testlib/checkhandshake.pm
+++ b/test/testlib/checkhandshake.pm
@@ -46,6 +46,10 @@ use constant {
     SRP_CLI_EXTENSION => 0x00002000,
     #Client side for ec point formats is a default extension
     EC_POINT_FORMAT_SRV_EXTENSION => 0x00004000,
+    PSK_CLI_EXTENSION => 0x00008000,
+    PSK_SRV_EXTENSION => 0x00010000,
+    KEY_SHARE_SRV_EXTENSION => 0x00020000,
+    PSK_KEX_MODES_EXTENSION => 0x00040000
 };
 
 our @handmessages = ();
@@ -81,6 +85,10 @@ sub checkhandshake($$$$)
         #one extension gets checked twice (once in each Certificate message)
         $numtests += 2 if ($proxy->is_tls13()
                           && ($handtype & CLIENT_AUTH_HANDSHAKE) != 0);
+        #And in a resumption handshake we don't get Certificate at all and the
+        #Certificate extension doesn't get checked at all
+        $numtests -= 2 if ($proxy->is_tls13()
+                          && ($handtype & RESUME_HANDSHAKE) != 0);
 
         plan tests => $numtests;
 
diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
index 68ebb9b..69b85b8 100644
--- a/test/tls13secretstest.c
+++ b/test/tls13secretstest.c
@@ -196,13 +196,14 @@ static int test_secret(SSL *s, unsigned char *prk,
     unsigned char hash[EVP_MAX_MD_SIZE];
     unsigned char key[KEYLEN];
     unsigned char iv[IVLEN];
+    const EVP_MD *md = ssl_handshake_md(s);
 
     if (!ssl_handshake_hash(s, hash, sizeof(hash), &hashsize)) {
         fprintf(stderr, "Failed to get hash\n");
         return 0;
     }
 
-    if (!tls13_hkdf_expand(s, prk, label, labellen, hash, gensecret,
+    if (!tls13_hkdf_expand(s, md, prk, label, labellen, hash, gensecret,
                            hashsize)) {
         fprintf(stderr, "Secret generation failed\n");
         return 0;
@@ -253,7 +254,12 @@ static int test_handshake_secrets(void)
     if (s == NULL)
         goto err;
 
-    if (!tls13_generate_early_secret(s, NULL, 0)) {
+    s->session = SSL_SESSION_new();
+    if (s->session == NULL)
+        goto err;
+
+    if (!tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL, 0,
+                               (unsigned char *)&s->early_secret)) {
         fprintf(stderr, "Early secret generation failed\n");
         goto err;
     }
diff --git a/test/wpackettest.c b/test/wpackettest.c
index 52c9827..3ab293e 100644
--- a/test/wpackettest.c
+++ b/test/wpackettest.c
@@ -254,6 +254,27 @@ static int test_WPACKET_start_sub_packet(void)
         return 0;
     }
 
+    /* Nested sub-packets with lengths filled before finish */
+    if (!WPACKET_init(&pkt, buf)
+            || !WPACKET_start_sub_packet_u8(&pkt)
+            || !WPACKET_put_bytes_u8(&pkt, 0xff)
+            || !WPACKET_start_sub_packet_u8(&pkt)
+            || !WPACKET_put_bytes_u8(&pkt, 0xff)
+            || !WPACKET_get_length(&pkt, &len)
+            || len != 1
+            || !WPACKET_close(&pkt)
+            || !WPACKET_get_length(&pkt, &len)
+            || len != 3
+            || !WPACKET_close(&pkt)
+            || !WPACKET_fill_lengths(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(nestedsub)
+            ||  memcmp(buf->data, &nestedsub, written) != 0
+            || !WPACKET_finish(&pkt)) {
+        testfail("test_WPACKET_start_sub_packet():5 failed\n", &pkt);
+        return 0;
+    }
+
     return 1;
 }
 
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index 7cb7b28..ab90586 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -74,7 +74,9 @@ use constant {
     EXT_EXTENDED_MASTER_SECRET => 23,
     EXT_SESSION_TICKET => 35,
     EXT_KEY_SHARE => 40,
+    EXT_PSK => 41,
     EXT_SUPPORTED_VERSIONS => 43,
+    EXT_PSK_KEX_MODES => 45,
     EXT_RENEGOTIATE => 65281,
     EXT_NPN => 13172,
     # This extension is an unofficial extension only ever written by OpenSSL
@@ -98,6 +100,7 @@ my $end = 0;
 my @message_rec_list = ();
 my @message_frag_lens = ();
 my $ciphersuite = 0;
+my $successondata = 0;
 
 sub clear
 {
@@ -107,6 +110,7 @@ sub clear
     $server = 0;
     $success = 0;
     $end = 0;
+    $successondata = 0;
     @message_rec_list = ();
     @message_frag_lens = ();
 }
@@ -218,6 +222,11 @@ sub get_messages
     } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) {
         print "  [ENCRYPTED APPLICATION DATA]\n";
         print "  [".$record->decrypt_data."]\n";
+
+        if ($successondata) {
+            $success = 1;
+            $end = 1;
+        }
     } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) {
         my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data);
         #A CloseNotify from the client indicates we have finished successfully
@@ -506,5 +515,12 @@ sub encoded_length
     my $self = shift;
     return TLS_MESSAGE_HEADER_LENGTH + length($self->data);
 }
-
+sub successondata
+{
+    my $class = shift;
+    if (@_) {
+        $successondata = shift;
+    }
+    return $successondata;
+}
 1;
diff --git a/util/TLSProxy/Proxy.pm b/util/TLSProxy/Proxy.pm
index 2e90ab0..cee3bc5 100644
--- a/util/TLSProxy/Proxy.pm
+++ b/util/TLSProxy/Proxy.pm
@@ -49,6 +49,7 @@ sub new
         serverconnects => 1,
         serverpid => 0,
         reneg => 0,
+        sessionfile => undef,
 
         #Public read
         execute => $execute,
@@ -110,6 +111,7 @@ sub clearClient
     $self->{record_list} = [];
     $self->{message_list} = [];
     $self->{clientflags} = "";
+    $self->{sessionfile} = undef;
     $is_tls13 = 0;
     $ciphersuite = undef;
 
@@ -226,6 +228,9 @@ sub clientstart
             if ($self->clientflags ne "") {
                 $execcmd .= " ".$self->clientflags;
             }
+            if (defined $self->sessionfile) {
+                $execcmd .= " -ign_eof";
+            }
             exec($execcmd);
         }
     }
@@ -295,6 +300,16 @@ sub clientstart
         }
     }
 
+    for (my $ctr = 0;
+         defined $self->sessionfile()
+            && (!(-f $self->sessionfile()) || $ctr == 3);
+         $ctr++) {
+        sleep 1;
+    }
+
+    die "Session file not created"
+        if (defined $self->sessionfile() && !(-f $self->sessionfile()));
+
     END:
     print "Connection closed\n";
     if($server_sock) {
@@ -540,6 +555,22 @@ sub reneg
     return $self->{reneg};
 }
 
+#Setting a sessionfile means that the client will not close until the given
+#file exists. This is useful in TLSv1.3 where otherwise s_client will close
+#immediately at the end of the handshake, but before the session has been
+#received from the server. A side effect of this is that s_client never sends
+#a close_notify, so instead we consider success to be when it sends application
+#data over the connection.
+sub sessionfile
+{
+    my $self = shift;
+    if (@_) {
+        $self->{sessionfile} = shift;
+        TLSProxy::Message->successondata(1);
+    }
+    return $self->{sessionfile};
+}
+
 sub ciphersuite
 {
     my $class = shift;


More information about the openssl-commits mailing list