[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Oct 30 09:06:18 UTC 2015


The branch master has been updated
       via  b7fa1f989d0059ad7b992c11797f37f095d61204 (commit)
       via  bb3e20cf8c5e733c16fe68ce41f67eea5a2a520e (commit)
       via  956de7b2873e0dde61b287049cd0eb35756b6207 (commit)
       via  fed1767436f626bc43140182442567340bd8bd34 (commit)
       via  141eb8c679a316278651d1e50b2259a989e030c9 (commit)
       via  8481f583d3aebd7383ba5824bfbe854242231e1b (commit)
       via  be3583fa40a2658cbbcf73320f75e9d674bb39f4 (commit)
       via  3616bb63586df04b22de00f49bc92d92dff1b8b6 (commit)
       via  006207d1bc39335b9cb474e6c9a4ca96a33bae46 (commit)
       via  c9de4a20fa21101208cf311c5437d9c358ba1f07 (commit)
       via  d13dd4beb4674689c7a46450dbb8bae9af24d510 (commit)
       via  9b67c0d810a4842096cb73702c59a1320805f912 (commit)
       via  f0659bdb0014afda3585a837607331133b7bc6b1 (commit)
       via  024f543c15e70acb57a80067c3b32227f87bfe5f (commit)
       via  20dbe585772a18952b730b71cd6722ce62dfe88b (commit)
       via  31fd10e60d12ae2e955de8651fa84aff016d719a (commit)
       via  91eac8d567c2717ef7bfd7a5997f8e73057ce780 (commit)
       via  f3ae986218ad2269758f4994ffe137b8233dc0b8 (commit)
       via  d78052cf4f3b8def0ebbd89d3ecc0098190ee20f (commit)
       via  d6f1a6e931beccd75b4e77c8ea99ca6699d052b4 (commit)
       via  5998e2903589e7b19e102ebff06521f2dcb60409 (commit)
       via  a71a4966a31b31df72db42c130544462fd6ad624 (commit)
       via  c874def60a756df57d1069f48852632a0690f856 (commit)
       via  fe3a329117dbb04a17ca2cb9fc9e3493dc7f03ab (commit)
       via  7c8b53571698f32219a912e05bc71df4017094c1 (commit)
       via  35bf6e05371de3aebd83dc630125a108ec4a5e70 (commit)
       via  a455d0f6fff7bdac2b991715e7bf5b000e2274af (commit)
       via  f3b9257f8239e06cc30cea47558d37fc540853ee (commit)
       via  264ab6b1cd3dae59d98cbead70fd76677a409592 (commit)
       via  075c8795857de6746ee662e50ebe44055a494f51 (commit)
       via  e0a51488c335e0c61e929e71828fab1252335062 (commit)
       via  9d671ad1cf6d48c3249c73e2e0ad5aa0f3768a86 (commit)
       via  f0de39595013e4b3af2fd8c76740e52c1a87c2cf (commit)
       via  82c1aa93c955736e21746593c3e434ae046641ae (commit)
       via  61ae935a9831d2b132e50508ccc37f879c17a5c4 (commit)
       via  8ba708e5166b02ab61f2762d36b3e7b7455e9c06 (commit)
       via  1aeaa7ec06ccd4c819a3ca94139c3ab79463fada (commit)
       via  73999b62a27d9ac7c10ff27d79fd2bab97f97670 (commit)
       via  0131df49ee1f98918e958c05b0d4f56b7d441f83 (commit)
       via  23a635c0ec895f9876d4d7633e7e2923b5bbfc17 (commit)
       via  5e41ba031edd91bfbac6a614664f83b22fb48207 (commit)
       via  c64359db8af1bf759f4496a01c93bac658decc7e (commit)
       via  49ae742398aecd81551d59f421e4116a5b8a4ea9 (commit)
       via  c130dd8ea4d09cb708aac9e41bd25c2f5fa7ea38 (commit)
       via  94836de2aeab65869caf2aa9a260114a309aaf0a (commit)
       via  e27f234a4147a7bd621d2a439c2cc2cc9a6a8382 (commit)
       via  4e3458a565da5bccf30fe598e87ad7da1ee9daa7 (commit)
       via  473483d42db5d176946323ac390fcd3c80ea40e6 (commit)
       via  76af303761670cd54a93f1b196bcd7b2eaf7c29c (commit)
       via  f6a2f2da58d6ba0042a9e94cf7281e5db23e9333 (commit)
       via  8723588e1b9a13511ffd7b806c73293120bc1f44 (commit)
       via  b9908bf9b8d6d609736b537f4ecda720ff5dc078 (commit)
       via  f8e0a5573820bd7318782d4954c6643ff7e58102 (commit)
       via  9ab930b27d51a13362e6647074f13589a8ac004d (commit)
      from  94b3664a528258df5ebcaae213d19bf6568cc47d (commit)


- Log -----------------------------------------------------------------
commit b7fa1f989d0059ad7b992c11797f37f095d61204
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 23:11:44 2015 +0000

    Add SRP and PSK to disallowed CertificateRequest ciphersuites
    
    There was a discrepancy between what ciphersuites we allowed to send a
    CertificateRequest, and what ciphersuites we allowed to receive one. So
    add PSK and SRP to the disallowed ones.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit bb3e20cf8c5e733c16fe68ce41f67eea5a2a520e
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 14:08:22 2015 +0000

    Remove the inline keyword
    
    Some functions were marked as inline in statem_srvr.c where they probably
    didn't need to be, so remove it.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 956de7b2873e0dde61b287049cd0eb35756b6207
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 14:05:43 2015 +0000

    Remove superfluous check
    
    |tls_process_finished| was checking that |peer_finish_md_len| was
    non-negative. However neither |tls1_final_finish_mac| or
    |ssl3_final_finish_mac| can ever return a negative value, so the check is
    superfluous.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit fed1767436f626bc43140182442567340bd8bd34
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 12:21:40 2015 +0000

    Change SSL_state_string return strings to start with a T
    
    Due the rest of the state machine changes it makes sense to change the
    SSL_state_string return strings from 3* to T*. They are not SSL3 specific
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 141eb8c679a316278651d1e50b2259a989e030c9
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 12:00:00 2015 +0000

    Change snprintf to memcpy
    
    There was a few uses of snprintf in the DTLS SCTP code which made more
    sense to be a memcpy.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 8481f583d3aebd7383ba5824bfbe854242231e1b
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 11:54:17 2015 +0000

    Add ossl_statem prefix to various functions
    
    Add the ossl_statem prefix to various funtions to avoid name clashes.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit be3583fa40a2658cbbcf73320f75e9d674bb39f4
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 11:46:33 2015 +0000

    Convert enums to typedefs
    
    Various enums were introduced as part of the state machine rewrite. As a
    matter of style it is preferred for these to be typedefs.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 3616bb63586df04b22de00f49bc92d92dff1b8b6
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 26 11:13:56 2015 +0000

    Make dtls1_link_min_mtu static
    
    The function dtls1_link_min_mtu() was only used within d1_lib.c so make
    it static.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 006207d1bc39335b9cb474e6c9a4ca96a33bae46
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 15:13:20 2015 +0100

    Fix a bogus clang warning
    
    Clang with --strict-warnings was complaining about an uninitalised
    variable. In reality it will never be used uninitialised but clang can't
    figure out the logic, so just init it anyway to silence the warning.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit c9de4a20fa21101208cf311c5437d9c358ba1f07
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 15:02:14 2015 +0100

    Fix empty NewSessionTicket processing
    
    Rebasing the state machine code introduced a problem with empty
    NewSessionTicket processing. The return value from the
    tls_process_new_session_ticket() is supposed to be an enum, but a bare
    integer was being used. Unfortunately this is valid C so the compiler
    doesn't pick it up.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d13dd4beb4674689c7a46450dbb8bae9af24d510
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 14:34:33 2015 +0100

    Fix uninitialised variable
    
    Fix another instance of |al| being unitialised in certain error scenarios.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 9b67c0d810a4842096cb73702c59a1320805f912
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 14:13:40 2015 +0100

    make update
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f0659bdb0014afda3585a837607331133b7bc6b1
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 14:02:46 2015 +0100

    Fix various error codes
    
    A number of error codes were wrong due to a rebase of the state machine
    code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 024f543c15e70acb57a80067c3b32227f87bfe5f
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 13:57:18 2015 +0100

    Move in_handshake into STATEM
    
    The SSL variable |in_handshake| seems misplaced. It would be better to have
    it in the STATEM structure.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 20dbe585772a18952b730b71cd6722ce62dfe88b
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 13:31:20 2015 +0100

    Fix unitialised variable problem
    
    tls_process_client_hello() failed to initialise the |al| variable in some
    (error) scenarios. This could cause issues with creating the alert.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 31fd10e60d12ae2e955de8651fa84aff016d719a
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 12:18:45 2015 +0100

    Fix DTLSv1_listen following state machine changes
    
    Adding the new state machine broke the DTLSv1_listen code because
    calling SSL_in_before() was erroneously returning true after DTLSv1_listen
    had successfully completed. This change ensures that SSL_in_before returns
    false.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 91eac8d567c2717ef7bfd7a5997f8e73057ce780
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 11:28:51 2015 +0100

    Add a function to get the info_callback
    
    Remove repeated blocks of checking SSL and then SSL_CTX for the
    info_callback.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f3ae986218ad2269758f4994ffe137b8233dc0b8
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 11:17:08 2015 +0100

    Remove the old state defines
    
    Remove all the defines for the old state machines states. Mapping old to new
    is probably going to cause more problems than it solves so it is probably
    better to just remove them.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d78052cf4f3b8def0ebbd89d3ecc0098190ee20f
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 11:03:27 2015 +0100

    Change SUB_STATE_RETURN into a typedef
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit d6f1a6e931beccd75b4e77c8ea99ca6699d052b4
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:58:52 2015 +0100

    Rename STATEM to OSSL_STATEM
    
    Add an OSSL_ prefix onto STATEM
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 5998e2903589e7b19e102ebff06521f2dcb60409
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:49:15 2015 +0100

    Remove SSL_state and SSL_set_state
    
    SSL_state has been replaced by SSL_get_state and SSL_set_state is no longer
    supported.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit a71a4966a31b31df72db42c130544462fd6ad624
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:44:41 2015 +0100

    Move |no_cert_verify| into state machine
    
    The |no_cert_verify| should be in the state machine structure not in SSL
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit c874def60a756df57d1069f48852632a0690f856
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:41:13 2015 +0100

    Remove extraneous parens
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit fe3a329117dbb04a17ca2cb9fc9e3493dc7f03ab
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:39:54 2015 +0100

    Change statem prefix to ossl_statem
    
    Change various state machine functions to use the prefix ossl_statem
    instead.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7c8b53571698f32219a912e05bc71df4017094c1
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:21:11 2015 +0100

    Don't depend on SSL structure internals
    
    The macros SSL_in_connect_init() and SSL_in_accept_init() inadvertently
    depended on SSL structure internals. This fixes it to use public API calls
    instead.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 35bf6e05371de3aebd83dc630125a108ec4a5e70
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 5 10:18:06 2015 +0100

    Change HANDSHAKE_STATE to OSSL_HANDSHAKE_STATE
    
    Rename the enum HANDSHAKE_STATE to OSSL_HANDSHAKE_STATE to ensure there are
    no namespace clashes, and convert it into a typedef.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit a455d0f6fff7bdac2b991715e7bf5b000e2274af
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 14 15:06:37 2015 +0100

    Fix some client side transition logic
    
    Fixed some issues in the logic for determining whether an SKE should be
    expected or not. In particular only allow an SKE for RSA if its export and
    the key size is not allowed. Also fix the ephemeral ciphersuite checks and
    add in a missing call to ssl3_check_cert_and_algorithm().
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f3b9257f8239e06cc30cea47558d37fc540853ee
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 13:39:04 2015 +0100

    Minor documentation tweak
    
    Update the return type for SSL_state in the documentation.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 264ab6b1cd3dae59d98cbead70fd76677a409592
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 13:36:42 2015 +0100

    Update CHANGES
    
    Update the CHANGES file for the state machine rewrite
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 075c8795857de6746ee662e50ebe44055a494f51
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 13:11:37 2015 +0100

    Remove a call to SSL_set_state from s_server
    
    s_server was (ab)using SSL_set_state to force a renegotiation. This is a
    bad way to do things and does not work with the new state machine code, so
    we need to do it a different way.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e0a51488c335e0c61e929e71828fab1252335062
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 12:11:39 2015 +0100

    Fix a comment
    
    Fix an out of date reference to old state machine code in a comment
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 9d671ad1cf6d48c3249c73e2e0ad5aa0f3768a86
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 11:56:48 2015 +0100

    Remove some unused variables
    
    The next_state variable is no longer needed in the new state machine.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f0de39595013e4b3af2fd8c76740e52c1a87c2cf
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 11:51:20 2015 +0100

    Add a state machine README
    
    Add some documentation on the thinking behind the state machine.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 82c1aa93c955736e21746593c3e434ae046641ae
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 11:28:24 2015 +0100

    make update
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 61ae935a9831d2b132e50508ccc37f879c17a5c4
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 11:23:20 2015 +0100

    More state machine reorg
    
    Move some function definitions around within the state machine to make sure
    they are in the correct files. Also create a statem_locl.h header for stuff
    entirely local to the state machine code and move various definitions into
    it.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 8ba708e5166b02ab61f2762d36b3e7b7455e9c06
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 11 10:48:59 2015 +0100

    Reorganise state machine files
    
    Pull out the state machine into a separate sub directory. Also moved some
    functions which were nothing to do with the state machine but were in state
    machine files. Pulled all the SSL_METHOD definitions into one place...most
    of those files had very little left in them any more.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 1aeaa7ec06ccd4c819a3ca94139c3ab79463fada
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 10 10:43:22 2015 +0100

    Remove ssl_get_message from ssl_method_st
    
    ssl_get_message is no longer used so it should be removed from
    ssl_method_st
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 73999b62a27d9ac7c10ff27d79fd2bab97f97670
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 10 10:22:30 2015 +0100

    Move PACKET creation into the state machine
    
    Previously each message specific process function would create its own
    PACKET structure. Rather than duplicate all of this code lots of times we
    should create it in the state machine itself.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 0131df49ee1f98918e958c05b0d4f56b7d441f83
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 10 09:23:34 2015 +0100

    Remove the SSL state variable
    
    The SSL structure contained a "state" variable that kept track of the state
    machine in the old code. The new state machine does not use this so it can
    be removed.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 23a635c0ec895f9876d4d7633e7e2923b5bbfc17
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 10 09:19:53 2015 +0100

    Remove the type variable
    
    The SSL structure contained a "type" variable that was set to either
    SSL_ST_ACCEPT or SSL_ST_CONNECT depending on whether we are the server or
    the client. This duplicates the capability of the "server" variable and was
    actually rarely used.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 5e41ba031edd91bfbac6a614664f83b22fb48207
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 22 10:45:29 2015 +0100

    Convert DTLSv1_listen to use new state machine code
    
    The DTLSv1_listen code set the state value explicitly to move into init.
    Change to use state_set_in_init() instead.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit c64359db8af1bf759f4496a01c93bac658decc7e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 10 09:11:41 2015 +0100

    Redefine old state values
    
    ssl.h and ssl3.h have a number of defines for the various states in the old
    state machine code. Since this is public API it is not desirable to just
    remove them. Instead redefine them to the closest equivalent state in the
    new state machine code. If an application calls SSL_state then the return
    value can still be compared against these old values if necessary. However
    not all values have an equivalent state in the new code, so these are just
    redefined to a dummy value.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 49ae742398aecd81551d59f421e4116a5b8a4ea9
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 8 09:13:50 2015 +0100

    Remove redundant code
    
    Clean up and remove lots of code that is now no longer needed due to the
    move to the new state machine.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit c130dd8ea4d09cb708aac9e41bd25c2f5fa7ea38
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Sep 4 13:51:49 2015 +0100

    Move server side DTLS to new state machine
    
    Implement all of the necessary changes to make DTLS on the server work
    with the new state machine code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 94836de2aeab65869caf2aa9a260114a309aaf0a
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 8 09:19:22 2015 +0100

    Move server side TLS to new state machine
    
    Implement all of the necessary changes for moving TLS server side
    processing into the new state machine code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e27f234a4147a7bd621d2a439c2cc2cc9a6a8382
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 8 09:38:08 2015 +0100

    Split TLS server functions
    
    Split the TLS server ssl3_get_* and ssl3_send_* functions into two ready
    for the migration to the new state machine code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 4e3458a565da5bccf30fe598e87ad7da1ee9daa7
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Aug 12 19:58:29 2015 +0100

    Delete unused functions
    
    Remove all the functions and dead code that is now no longer required as
    a result of the DTLS client move into the new state machine code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 473483d42db5d176946323ac390fcd3c80ea40e6
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 7 22:00:36 2015 +0100

    Implement DTLS client move to new state machine
    
    Move all DTLS client side processing into the new state machine code. A
    subsequent commit will clean up the old dead code.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 76af303761670cd54a93f1b196bcd7b2eaf7c29c
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Aug 11 11:41:03 2015 +0100

    dtls_get_message changes for state machine move
    
    Create a dtls_get_message function similar to the old dtls1_get_message but
    in the format required for the new state machine code. The old function will
    eventually be deleted in later commits.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f6a2f2da58d6ba0042a9e94cf7281e5db23e9333
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jul 30 13:45:50 2015 +0100

    Client TLS state machine rewrite cleanup
    
    Remove redundant code following moving client side TLS handling to the new
    state machine implementation.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 8723588e1b9a13511ffd7b806c73293120bc1f44
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 7 16:36:53 2015 +0100

    Implement Client TLS state machine
    
    This swaps the implementation of the client TLS state machine to use the
    new state machine code instead.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit b9908bf9b8d6d609736b537f4ecda720ff5dc078
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jul 29 14:08:49 2015 +0100

    Split client message reading and writing functions
    
    The new state machine code will split up the reading and writing of
    hanshake messages into discrete phases. In order to facilitate that the
    existing "get" type functions will be split into two halves: one to get
    the message and one to process it. The "send" type functions will also have
    all work relating to constructing the message split out into a separate
    function just for that. For some functions there will also be separate
    pre and post "work" phases to prepare or update state.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit f8e0a5573820bd7318782d4954c6643ff7e58102
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jul 29 14:23:56 2015 +0100

    Add initial state machine rewrite code
    
    This is the first drop of the new state machine code.
    
    The rewrite has the following objectives:
    - Remove duplication of state code between client and server
    - Remove duplication of state code between TLS and DTLS
    - Simplify transitions and bring the logic together in a single location
      so that it is easier to validate
    - Remove duplication of code between each of the message handling functions
    - Receive a message first and then work out whether that is a valid
      transition - not the other way around (the other way causes lots of issues
      where we are expecting one type of message next but actually get something
      else)
    - Separate message flow state from handshake state (in order to better
      understand each)
      - message flow state = when to flush buffers; handling restarts in the
        event of NBIO events; handling the common flow of steps for reading a
        message and the common flow of steps for writing a message etc
      - handshake state = what handshake message are we working on now
    - Control complexity: only the state machine can change state: keep all
      the state changes local to a file
    
    This builds on previous state machine related work:
    - Surface CCS processing in the state machine
    - Version negotiation rewrite
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 9ab930b27d51a13362e6647074f13589a8ac004d
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jul 29 14:20:05 2015 +0100

    Split ssl3_get_message
    
    The function ssl3_get_message gets a whole message from the underlying bio
    and returns it to the state machine code. The new state machine code will
    split this into two discrete steps: get the message header and get the
    message body. This commit splits the existing function into these two
    sub steps to facilitate the state machine implementation.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 CHANGES                                 |   11 +
 apps/s_server.c                         |   28 +-
 crypto/ct/Makefile                      |    3 +-
 doc/ssl/ssl.pod                         |    4 +-
 include/openssl/ssl.h                   |  121 +-
 include/openssl/ssl3.h                  |  107 -
 ssl/Makefile                            |  460 ++--
 ssl/d1_clnt.c                           |  830 -------
 ssl/d1_lib.c                            |  248 ++-
 ssl/d1_meth.c                           |   88 -
 ssl/d1_msg.c                            |    7 +-
 ssl/d1_srvr.c                           |  914 --------
 ssl/methods.c                           |  351 +++
 ssl/record/rec_layer_d1.c               |   37 +-
 ssl/record/rec_layer_s3.c               |   28 +-
 ssl/record/ssl3_record.c                |    2 +-
 ssl/s3_lib.c                            |   12 +-
 ssl/s3_msg.c                            |    4 +-
 ssl/s3_srvr.c                           | 3534 ------------------------------
 ssl/ssl_cert.c                          |    2 +-
 ssl/ssl_err.c                           |   58 +
 ssl/ssl_lib.c                           |   28 +-
 ssl/ssl_locl.h                          |   81 +-
 ssl/ssl_stat.c                          |  479 ++--
 ssl/statem/README                       |   63 +
 ssl/statem/statem.c                     |  891 ++++++++
 ssl/statem/statem.h                     |  176 ++
 ssl/{s3_clnt.c => statem/statem_clnt.c} | 3213 +++++++++++++--------------
 ssl/{d1_both.c => statem/statem_dtls.c} |  482 +---
 ssl/{s3_both.c => statem/statem_lib.c}  |  476 ++--
 ssl/statem/statem_locl.h                |  171 ++
 ssl/statem/statem_srvr.c                | 3652 +++++++++++++++++++++++++++++++
 ssl/t1_clnt.c                           |  107 -
 ssl/t1_lib.c                            |    2 +-
 ssl/t1_meth.c                           |  100 -
 ssl/t1_srvr.c                           |  109 -
 test/Makefile                           |    5 +-
 util/ssleay.num                         |    8 +-
 38 files changed, 8109 insertions(+), 8783 deletions(-)
 delete mode 100644 ssl/d1_clnt.c
 delete mode 100644 ssl/d1_meth.c
 delete mode 100644 ssl/d1_srvr.c
 create mode 100644 ssl/methods.c
 delete mode 100644 ssl/s3_srvr.c
 create mode 100644 ssl/statem/README
 create mode 100644 ssl/statem/statem.c
 create mode 100644 ssl/statem/statem.h
 rename ssl/{s3_clnt.c => statem/statem_clnt.c} (50%)
 rename ssl/{d1_both.c => statem/statem_dtls.c} (76%)
 rename ssl/{s3_both.c => statem/statem_lib.c} (64%)
 create mode 100644 ssl/statem/statem_locl.h
 create mode 100644 ssl/statem/statem_srvr.c
 delete mode 100644 ssl/t1_clnt.c
 delete mode 100644 ssl/t1_meth.c
 delete mode 100644 ssl/t1_srvr.c

diff --git a/CHANGES b/CHANGES
index 7f33901..a8629d8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 1.0.2 and 1.1.0  [xx XXX xxxx]
 
+  *) State machine rewrite. The state machine code has been significantly
+     refactored in order to remove much duplication of code and solve issues
+     with the old code (see ssl/statem/README for further details). This change
+     does have some associated API changes. Notably the SSL_state() function
+     has been removed and replaced by SSL_get_state which now returns an
+     "OSSL_HANDSHAKE_STATE" instead of an int. SSL_set_state() has been removed
+     altogether. The previous handshake states defined in ssl.h and ssl3.h have
+     also been removed.
+     [Matt Caswell]
+
   *) The demo files in crypto/threads were moved to demo/threads.
      [Rich Salz]
 
@@ -47,6 +57,7 @@
   *) Fix no-stdio build.
     [ David Woodhouse <David.Woodhouse at intel.com> and also
       Ivan Nestlerode <ivan.nestlerode at sonos.com> ]
+
   *) New testing framework
      The testing framework has been largely rewritten and is now using
      perl and the perl modules Test::Harness and an extended variant of
diff --git a/apps/s_server.c b/apps/s_server.c
index bfc8b1f..aa01d43 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -2428,7 +2428,7 @@ static int init_ssl_connection(SSL *con)
 #ifdef CERT_CB_TEST_RETRY
     {
         while (i <= 0 && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP
-               && SSL_state(con) == SSL3_ST_SR_CLNT_HELLO_C) {
+               && SSL_get_state(con) == TLS_ST_SR_CLNT_HELLO) {
             BIO_printf(bio_err,
                        "LOOKUP from certificate callback during accept\n");
             i = SSL_accept(con);
@@ -2567,6 +2567,11 @@ static int www_body(char *hostname, int s, int stype, unsigned char *context)
 #ifdef RENEG
     int total_bytes = 0;
 #endif
+    int width;
+    fd_set readfds;
+
+    /* Set width for a select call if needed */
+    width = s + 1;
 
     buf = app_malloc(bufsize, "server www buffer");
     io = BIO_new(BIO_f_buffer());
@@ -2684,6 +2689,7 @@ static int www_body(char *hostname, int s, int stype, unsigned char *context)
                                    NULL);
                 i = SSL_renegotiate(con);
                 BIO_printf(bio_s_out, "SSL_renegotiate -> %d\n", i);
+                /* Send the HelloRequest */
                 i = SSL_do_handshake(con);
                 if (i <= 0) {
                     BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n",
@@ -2691,16 +2697,22 @@ static int www_body(char *hostname, int s, int stype, unsigned char *context)
                     ERR_print_errors(bio_err);
                     goto err;
                 }
-                /* EVIL HACK! */
-                SSL_set_state(con, SSL_ST_ACCEPT);
-                i = SSL_do_handshake(con);
-                BIO_printf(bio_s_out, "SSL_do_handshake -> %d\n", i);
-                if (i <= 0) {
-                    BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n",
-                               SSL_get_error(con, i));
+                /* Wait for a ClientHello to come back */
+                FD_ZERO(&readfds);
+                openssl_fdset(s, &readfds);
+                i = select(width, (void *)&readfds, NULL, NULL, NULL);
+                if (i <= 0 || !FD_ISSET(s, &readfds)) {
+                    BIO_printf(bio_s_out, "Error waiting for client response\n");
                     ERR_print_errors(bio_err);
                     goto err;
                 }
+                /*
+                 * We're not acutally expecting any data here and we ignore
+                 * any that is sent. This is just to force the handshake that
+                 * we're expecting to come from the client. If they haven't
+                 * sent one there's not much we can do.
+                 */
+                BIO_gets(io, buf, bufsize - 1);
             }
 
             BIO_puts(io,
diff --git a/crypto/ct/Makefile b/crypto/ct/Makefile
index 2f55a2d..dfb0839 100644
--- a/crypto/ct/Makefile
+++ b/crypto/ct/Makefile
@@ -90,4 +90,5 @@ ct_lib.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
 ct_lib.o: ../../include/openssl/tls1.h ../../include/openssl/x509.h
 ct_lib.o: ../../include/openssl/x509_vfy.h ../../ssl/packet_locl.h
 ct_lib.o: ../../ssl/record/record.h ../../ssl/ssl_locl.h
-ct_lib.o: ../include/internal/cryptlib.h ../include/internal/ct_int.h ct_lib.c
+ct_lib.o: ../../ssl/statem/statem.h ../include/internal/cryptlib.h
+ct_lib.o: ../include/internal/ct_int.h ct_lib.c
diff --git a/doc/ssl/ssl.pod b/doc/ssl/ssl.pod
index 37046c1..9413907 100644
--- a/doc/ssl/ssl.pod
+++ b/doc/ssl/ssl.pod
@@ -624,7 +624,9 @@ success or 0 on failure.
 
 =item int B<SSL_shutdown>(SSL *ssl);
 
-=item int B<SSL_state>(const SSL *ssl);
+=item OSSL_HANDSHAKE_STATE B<SSL_get_state>(const SSL *ssl);
+
+Returns the current handshake state.
 
 =item char *B<SSL_state_string>(const SSL *ssl);
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 25ceca8..2e899cd 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -920,22 +920,71 @@ extern "C" {
 # define SSL_CTX_get_app_data(ctx)       (SSL_CTX_get_ex_data(ctx,0))
 # define SSL_CTX_set_app_data(ctx,arg)   (SSL_CTX_set_ex_data(ctx,0,(char *)arg))
 
+
+/*
+ * The valid handshake states (one for each type message sent and one for each
+ * type of message received). There are also two "special" states:
+ * TLS = TLS or DTLS state
+ * DTLS = DTLS specific state
+ * CR/SR = Client Read/Server Read
+ * CW/SW = Client Write/Server Write
+ *
+ * The "special" states are:
+ * TLS_ST_BEFORE = No handshake has been initiated yet
+ * TLS_ST_OK = A handshake has been successfully completed
+ */
+typedef enum {
+    TLS_ST_BEFORE,
+    TLS_ST_OK,
+    DTLS_ST_CR_HELLO_VERIFY_REQUEST,
+    TLS_ST_CR_SRVR_HELLO,
+    TLS_ST_CR_CERT,
+    TLS_ST_CR_CERT_STATUS,
+    TLS_ST_CR_KEY_EXCH,
+    TLS_ST_CR_CERT_REQ,
+    TLS_ST_CR_SRVR_DONE,
+    TLS_ST_CR_SESSION_TICKET,
+    TLS_ST_CR_CHANGE,
+    TLS_ST_CR_FINISHED,
+    TLS_ST_CW_CLNT_HELLO,
+    TLS_ST_CW_CERT,
+    TLS_ST_CW_KEY_EXCH,
+    TLS_ST_CW_CERT_VRFY,
+    TLS_ST_CW_CHANGE,
+    TLS_ST_CW_NEXT_PROTO,
+    TLS_ST_CW_FINISHED,
+    TLS_ST_SW_HELLO_REQ,
+    TLS_ST_SR_CLNT_HELLO,
+    DTLS_ST_SW_HELLO_VERIFY_REQUEST,
+    TLS_ST_SW_SRVR_HELLO,
+    TLS_ST_SW_CERT,
+    TLS_ST_SW_KEY_EXCH,
+    TLS_ST_SW_CERT_REQ,
+    TLS_ST_SW_SRVR_DONE,
+    TLS_ST_SR_CERT,
+    TLS_ST_SR_KEY_EXCH,
+    TLS_ST_SR_CERT_VRFY,
+    TLS_ST_SR_NEXT_PROTO,
+    TLS_ST_SR_CHANGE,
+    TLS_ST_SR_FINISHED,
+    TLS_ST_SW_SESSION_TICKET,
+    TLS_ST_SW_CERT_STATUS,
+    TLS_ST_SW_CHANGE,
+    TLS_ST_SW_FINISHED
+} OSSL_HANDSHAKE_STATE;
+
 /*
- * The following are the possible values for ssl->state are are used to
- * indicate where we are up to in the SSL connection establishment. The
- * macros that follow are about the only things you should need to use and
- * even then, only when using non-blocking IO. It can also be useful to work
- * out where you were when the connection failed
+ * Most of the following state values are no longer used and are defined to be
+ * the closest equivalent value in the current state machine code. Not all
+ * defines have an equivalent and are set to a dummy value (-1). SSL_ST_CONNECT
+ * and SSL_ST_ACCEPT are still in use in the definition of SSL_CB_ACCEPT_LOOP,
+ * SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP and SSL_CB_CONNECT_EXIT.
  */
 
 # define SSL_ST_CONNECT                  0x1000
 # define SSL_ST_ACCEPT                   0x2000
+
 # define SSL_ST_MASK                     0x0FFF
-# define SSL_ST_INIT                     (SSL_ST_CONNECT|SSL_ST_ACCEPT)
-# define SSL_ST_BEFORE                   0x4000
-# define SSL_ST_OK                       0x03
-# define SSL_ST_RENEGOTIATE              (0x04|SSL_ST_INIT)
-# define SSL_ST_ERR                      0x05
 
 # define SSL_CB_LOOP                     0x01
 # define SSL_CB_EXIT                     0x02
@@ -952,12 +1001,11 @@ extern "C" {
 # define SSL_CB_HANDSHAKE_DONE           0x20
 
 /* Is the SSL_connection established? */
-# define SSL_get_state(a)                SSL_state(a)
-# define SSL_is_init_finished(a)         (SSL_state(a) == SSL_ST_OK)
-# define SSL_in_init(a)                  (SSL_state(a)&SSL_ST_INIT)
-# define SSL_in_before(a)                (SSL_state(a)&SSL_ST_BEFORE)
-# define SSL_in_connect_init(a)          (SSL_state(a)&SSL_ST_CONNECT)
-# define SSL_in_accept_init(a)           (SSL_state(a)&SSL_ST_ACCEPT)
+# define SSL_in_connect_init(a)          (SSL_in_init(a) && !SSL_is_server(a))
+# define SSL_in_accept_init(a)           (SSL_in_init(a) && SSL_is_server(a))
+int SSL_in_init(SSL *s);
+int SSL_in_before(SSL *s);
+int SSL_is_init_finished(SSL *s);
 
 /*
  * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you
@@ -1646,8 +1694,7 @@ void SSL_set_info_callback(SSL *ssl,
                            void (*cb) (const SSL *ssl, int type, int val));
 void (*SSL_get_info_callback(const SSL *ssl)) (const SSL *ssl, int type,
                                                int val);
-__owur int SSL_state(const SSL *ssl);
-void SSL_set_state(SSL *ssl, int state);
+__owur OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl);
 
 void SSL_set_verify_result(SSL *ssl, long v);
 __owur long SSL_get_verify_result(const SSL *ssl);
@@ -1928,6 +1975,11 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_DTLS1_SEND_SERVER_HELLO                    266
 # define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE             267
 # define SSL_F_DTLS1_WRITE_APP_DATA_BYTES                 268
+# define SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC          371
+# define SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST        385
+# define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE               370
+# define SSL_F_DTLS_PROCESS_HELLO_VERIFY                  386
+# define SSL_F_READ_STATE_MACHINE                         352
 # define SSL_F_SSL3_ACCEPT                                128
 # define SSL_F_SSL3_ADD_CERT_TO_BUF                       296
 # define SSL_F_SSL3_CALLBACK_CTRL                         233
@@ -2085,6 +2137,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE                 206
 # define SSL_F_SSL_VERIFY_CERT_CHAIN                      207
 # define SSL_F_SSL_WRITE                                  208
+# define SSL_F_STATE_MACHINE                              353
 # define SSL_F_TLS12_CHECK_PEER_SIGALG                    333
 # define SSL_F_TLS1_CERT_VERIFY_MAC                       286
 # define SSL_F_TLS1_CHANGE_CIPHER_STATE                   209
@@ -2099,6 +2152,37 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_TLS1_PROCESS_HEARTBEAT                     341
 # define SSL_F_TLS1_SETUP_KEY_BLOCK                       211
 # define SSL_F_TLS1_SET_SERVER_SIGALGS                    335
+# define SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK          354
+# define SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST          372
+# define SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE           355
+# define SSL_F_TLS_CONSTRUCT_CLIENT_HELLO                 356
+# define SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE          357
+# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY                358
+# define SSL_F_TLS_CONSTRUCT_FINISHED                     359
+# define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST                373
+# define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE           374
+# define SSL_F_TLS_CONSTRUCT_SERVER_DONE                  375
+# define SSL_F_TLS_CONSTRUCT_SERVER_HELLO                 376
+# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE          377
+# define SSL_F_TLS_GET_MESSAGE_BODY                       351
+# define SSL_F_TLS_GET_MESSAGE_HEADER                     387
+# define SSL_F_TLS_POST_PROCESS_CLIENT_HELLO              378
+# define SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE       384
+# define SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE             360
+# define SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST            361
+# define SSL_F_TLS_PROCESS_CERT_STATUS                    362
+# define SSL_F_TLS_PROCESS_CERT_VERIFY                    379
+# define SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC             363
+# define SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE             380
+# define SSL_F_TLS_PROCESS_CLIENT_HELLO                   381
+# define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE            382
+# define SSL_F_TLS_PROCESS_FINISHED                       364
+# define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
+# define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
+# define SSL_F_TLS_PROCESS_NEXT_PROTO                     383
+# define SSL_F_TLS_PROCESS_SERVER_CERTIFICATE             367
+# define SSL_F_TLS_PROCESS_SERVER_DONE                    368
+# define SSL_F_TLS_PROCESS_SERVER_HELLO                   369
 # define SSL_F_USE_CERTIFICATE_CHAIN_FILE                 220
 
 /* Reason codes. */
@@ -2211,6 +2295,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_INVALID_TRUST                              279
 # define SSL_R_LENGTH_MISMATCH                            159
 # define SSL_R_LENGTH_TOO_SHORT                           160
+# define SSL_R_LENGTH_TOO_LONG                            404
 # define SSL_R_LIBRARY_BUG                                274
 # define SSL_R_LIBRARY_HAS_NO_CIPHERS                     161
 # define SSL_R_MISSING_DH_DSA_CERT                        162
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index ec339de..ef93c08 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -370,113 +370,6 @@ extern "C" {
 # define TLS1_FLAGS_ENCRYPT_THEN_MAC             0x0100
 
 
-/* SSLv3 */
-/*
- * client
- */
-/* extra state */
-# define SSL3_ST_CW_FLUSH                (0x100|SSL_ST_CONNECT)
-# ifndef OPENSSL_NO_SCTP
-#  define DTLS1_SCTP_ST_CW_WRITE_SOCK                     (0x310|SSL_ST_CONNECT)
-#  define DTLS1_SCTP_ST_CR_READ_SOCK                      (0x320|SSL_ST_CONNECT)
-# endif
-/* write to server */
-# define SSL3_ST_CW_CLNT_HELLO_A         (0x110|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CLNT_HELLO_B         (0x111|SSL_ST_CONNECT)
-/* read from server */
-# define SSL3_ST_CR_SRVR_HELLO_A         (0x120|SSL_ST_CONNECT)
-# define SSL3_ST_CR_SRVR_HELLO_B         (0x121|SSL_ST_CONNECT)
-# define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
-# define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_A               (0x130|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_B               (0x131|SSL_ST_CONNECT)
-# define SSL3_ST_CR_KEY_EXCH_A           (0x140|SSL_ST_CONNECT)
-# define SSL3_ST_CR_KEY_EXCH_B           (0x141|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_REQ_A           (0x150|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_REQ_B           (0x151|SSL_ST_CONNECT)
-# define SSL3_ST_CR_SRVR_DONE_A          (0x160|SSL_ST_CONNECT)
-# define SSL3_ST_CR_SRVR_DONE_B          (0x161|SSL_ST_CONNECT)
-/* write to server */
-# define SSL3_ST_CW_CERT_A               (0x170|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CERT_B               (0x171|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CERT_C               (0x172|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CERT_D               (0x173|SSL_ST_CONNECT)
-# define SSL3_ST_CW_KEY_EXCH_A           (0x180|SSL_ST_CONNECT)
-# define SSL3_ST_CW_KEY_EXCH_B           (0x181|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CERT_VRFY_A          (0x190|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CERT_VRFY_B          (0x191|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CHANGE_A             (0x1A0|SSL_ST_CONNECT)
-# define SSL3_ST_CW_CHANGE_B             (0x1A1|SSL_ST_CONNECT)
-# ifndef OPENSSL_NO_NEXTPROTONEG
-#  define SSL3_ST_CW_NEXT_PROTO_A         (0x200|SSL_ST_CONNECT)
-#  define SSL3_ST_CW_NEXT_PROTO_B         (0x201|SSL_ST_CONNECT)
-# endif
-# define SSL3_ST_CW_FINISHED_A           (0x1B0|SSL_ST_CONNECT)
-# define SSL3_ST_CW_FINISHED_B           (0x1B1|SSL_ST_CONNECT)
-/* read from server */
-# define SSL3_ST_CR_CHANGE_A             (0x1C0|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CHANGE_B             (0x1C1|SSL_ST_CONNECT)
-# define SSL3_ST_CR_FINISHED_A           (0x1D0|SSL_ST_CONNECT)
-# define SSL3_ST_CR_FINISHED_B           (0x1D1|SSL_ST_CONNECT)
-# define SSL3_ST_CR_SESSION_TICKET_A     (0x1E0|SSL_ST_CONNECT)
-# define SSL3_ST_CR_SESSION_TICKET_B     (0x1E1|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_STATUS_A        (0x1F0|SSL_ST_CONNECT)
-# define SSL3_ST_CR_CERT_STATUS_B        (0x1F1|SSL_ST_CONNECT)
-
-/* server */
-/* extra state */
-# define SSL3_ST_SW_FLUSH                (0x100|SSL_ST_ACCEPT)
-# ifndef OPENSSL_NO_SCTP
-#  define DTLS1_SCTP_ST_SW_WRITE_SOCK                     (0x310|SSL_ST_ACCEPT)
-#  define DTLS1_SCTP_ST_SR_READ_SOCK                      (0x320|SSL_ST_ACCEPT)
-# endif
-/* read from client */
-/* Do not change the number values, they do matter */
-# define SSL3_ST_SR_CLNT_HELLO_A         (0x110|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CLNT_HELLO_B         (0x111|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CLNT_HELLO_C         (0x112|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CLNT_HELLO_D         (0x115|SSL_ST_ACCEPT)
-/* write to client */
-# define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
-# define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_HELLO_REQ_A          (0x120|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_HELLO_REQ_B          (0x121|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_HELLO_REQ_C          (0x122|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SRVR_HELLO_A         (0x130|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SRVR_HELLO_B         (0x131|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_A               (0x140|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_B               (0x141|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_KEY_EXCH_A           (0x150|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_KEY_EXCH_B           (0x151|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_REQ_A           (0x160|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_REQ_B           (0x161|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SRVR_DONE_A          (0x170|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SRVR_DONE_B          (0x171|SSL_ST_ACCEPT)
-/* read from client */
-# define SSL3_ST_SR_CERT_A               (0x180|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CERT_B               (0x181|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_KEY_EXCH_A           (0x190|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_KEY_EXCH_B           (0x191|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CERT_VRFY_A          (0x1A0|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CERT_VRFY_B          (0x1A1|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CHANGE_A             (0x1B0|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_CHANGE_B             (0x1B1|SSL_ST_ACCEPT)
-# ifndef OPENSSL_NO_NEXTPROTONEG
-#  define SSL3_ST_SR_NEXT_PROTO_A         (0x210|SSL_ST_ACCEPT)
-#  define SSL3_ST_SR_NEXT_PROTO_B         (0x211|SSL_ST_ACCEPT)
-# endif
-# define SSL3_ST_SR_FINISHED_A           (0x1C0|SSL_ST_ACCEPT)
-# define SSL3_ST_SR_FINISHED_B           (0x1C1|SSL_ST_ACCEPT)
-/* write to client */
-# define SSL3_ST_SW_CHANGE_A             (0x1D0|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CHANGE_B             (0x1D1|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_FINISHED_A           (0x1E0|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_FINISHED_B           (0x1E1|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SESSION_TICKET_A     (0x1F0|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_SESSION_TICKET_B     (0x1F1|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_STATUS_A        (0x200|SSL_ST_ACCEPT)
-# define SSL3_ST_SW_CERT_STATUS_B        (0x201|SSL_ST_ACCEPT)
-
 # define SSL3_MT_HELLO_REQUEST                   0
 # define SSL3_MT_CLIENT_HELLO                    1
 # define SSL3_MT_SERVER_HELLO                    2
diff --git a/ssl/Makefile b/ssl/Makefile
index 7953da4..0865631 100644
--- a/ssl/Makefile
+++ b/ssl/Makefile
@@ -17,31 +17,33 @@ GENERAL=Makefile README ssl-lib.com install.com
 LIB=$(TOP)/libssl.a
 SHARED_LIB= libssl$(SHLIB_EXT)
 LIBSRC=	\
-	s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
-	s3_both.c s3_cbc.c s3_msg.c \
-	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c t1_ext.c \
-	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  record/rec_layer_d1.c d1_msg.c \
-	d1_both.c d1_srtp.c \
+	statem/statem_srvr.c statem/statem_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
+	statem/statem_lib.c s3_cbc.c s3_msg.c \
+	methods.c   t1_lib.c  t1_enc.c t1_ext.c \
+	d1_lib.c  record/rec_layer_d1.c d1_msg.c \
+	statem/statem_dtls.c d1_srtp.c \
 	ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
 	ssl_ciph.c ssl_stat.c ssl_rsa.c \
 	ssl_asn1.c ssl_txt.c ssl_algs.c ssl_conf.c \
 	bio_ssl.c ssl_err.c t1_reneg.c tls_srp.c t1_trce.c ssl_utst.c \
-	record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c
+	record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \
+	statem/statem.c
 LIBOBJ= \
-	s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o record/rec_layer_s3.o \
-	s3_both.o s3_cbc.o s3_msg.o \
-	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o t1_ext.o \
-	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  record/rec_layer_d1.o d1_msg.o \
-	d1_both.o d1_srtp.o\
+	statem/statem_srvr.o  statem/statem_clnt.o  s3_lib.o  s3_enc.o record/rec_layer_s3.o \
+	statem/statem_lib.o s3_cbc.o s3_msg.o \
+	methods.o   t1_lib.o  t1_enc.o t1_ext.o \
+	d1_lib.o  record/rec_layer_d1.o d1_msg.o \
+	statem/statem_dtls.o d1_srtp.o\
 	ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
 	ssl_ciph.o ssl_stat.o ssl_rsa.o \
 	ssl_asn1.o ssl_txt.o ssl_algs.o ssl_conf.o \
 	bio_ssl.o ssl_err.o t1_reneg.o tls_srp.o t1_trce.o ssl_utst.o \
-	record/ssl3_buffer.o record/ssl3_record.o record/dtls1_bitmap.o
+	record/ssl3_buffer.o record/ssl3_record.o record/dtls1_bitmap.o \
+	statem/statem.o
 
 SRC= $(LIBSRC)
 
-HEADER=	ssl_locl.h record/record_locl.h record/record.h
+HEADER=	ssl_locl.h record/record_locl.h record/record.h statem/statem.h
 
 ALL=	$(GENERAL) $(SRC) $(HEADER)
 
@@ -91,7 +93,9 @@ clean:
 	rm -f $(LIBOBJ) *.obj lib tags core .pure .nfs* *.old *.bak fluff
 	rm -f record/*.obj record/lib record/retags record/core \
 	record/.pure record/.nfs* record/*.old record/*.bak record/fluff
-
+	rm -f statem/*.obj statem/lib statem/retags statem/core \
+	statem/.pure statem/.nfs* statem/*.old statem/*.bak statem/fluff
+	
 # DO NOT DELETE THIS LINE -- make depend depends on it.
 
 bio_ssl.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
@@ -113,48 +117,7 @@ bio_ssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 bio_ssl.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 bio_ssl.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 bio_ssl.o: ../include/openssl/x509_vfy.h bio_ssl.c packet_locl.h
-bio_ssl.o: record/record.h ssl_locl.h
-d1_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_both.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_both.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_both.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-d1_both.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-d1_both.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-d1_both.o: ../include/openssl/err.h ../include/openssl/evp.h
-d1_both.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-d1_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_both.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_both.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_both.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_both.c
-d1_both.o: packet_locl.h record/record.h ssl_locl.h
-d1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-d1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_clnt.c
-d1_clnt.o: packet_locl.h record/record.h ssl_locl.h
+bio_ssl.o: record/record.h ssl_locl.h statem/statem.h
 d1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_lib.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -167,34 +130,14 @@ d1_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
 d1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
 d1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
 d1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-d1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_lib.o: ../include/openssl/x509_vfy.h d1_lib.c packet_locl.h record/record.h
-d1_lib.o: ssl_locl.h
-d1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_meth.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_meth.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_meth.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-d1_meth.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-d1_meth.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-d1_meth.o: ../include/openssl/err.h ../include/openssl/evp.h
-d1_meth.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-d1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-d1_meth.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_meth.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_meth.o: ../include/openssl/x509_vfy.h d1_meth.c packet_locl.h
-d1_meth.o: record/record.h ssl_locl.h
+d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+d1_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+d1_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+d1_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+d1_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+d1_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+d1_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_lib.c
+d1_lib.o: packet_locl.h record/record.h ssl_locl.h statem/statem.h
 d1_msg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_msg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_msg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -214,7 +157,7 @@ d1_msg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 d1_msg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 d1_msg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 d1_msg.o: ../include/openssl/x509_vfy.h d1_msg.c packet_locl.h record/record.h
-d1_msg.o: ssl_locl.h
+d1_msg.o: ssl_locl.h statem/statem.h
 d1_srtp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_srtp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_srtp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -234,28 +177,27 @@ d1_srtp.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 d1_srtp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 d1_srtp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 d1_srtp.o: ../include/openssl/x509_vfy.h d1_srtp.c packet_locl.h
-d1_srtp.o: record/record.h ssl_locl.h
-d1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-d1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srvr.c
-d1_srvr.o: packet_locl.h record/record.h ssl_locl.h
+d1_srtp.o: record/record.h ssl_locl.h statem/statem.h
+methods.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
+methods.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+methods.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+methods.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+methods.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+methods.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+methods.o: ../include/openssl/err.h ../include/openssl/evp.h
+methods.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
+methods.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+methods.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+methods.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+methods.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+methods.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
+methods.o: ../include/openssl/safestack.h ../include/openssl/sha.h
+methods.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
+methods.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
+methods.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+methods.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+methods.o: ../include/openssl/x509_vfy.h methods.c packet_locl.h
+methods.o: record/record.h ssl_locl.h statem/statem.h
 record/dtls1_bitmap.o: ../e_os.h ../include/openssl/asn1.h
 record/dtls1_bitmap.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/dtls1_bitmap.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -278,7 +220,8 @@ record/dtls1_bitmap.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 record/dtls1_bitmap.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 record/dtls1_bitmap.o: ../include/openssl/x509_vfy.h record/../packet_locl.h
 record/dtls1_bitmap.o: record/../record/record.h record/../ssl_locl.h
-record/dtls1_bitmap.o: record/dtls1_bitmap.c record/record_locl.h
+record/dtls1_bitmap.o: record/../statem/statem.h record/dtls1_bitmap.c
+record/dtls1_bitmap.o: record/record_locl.h
 record/rec_layer_d1.o: ../e_os.h ../include/openssl/asn1.h
 record/rec_layer_d1.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/rec_layer_d1.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -301,8 +244,8 @@ record/rec_layer_d1.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/rec_layer_d1.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/rec_layer_d1.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/rec_layer_d1.o: record/../packet_locl.h record/../record/record.h
-record/rec_layer_d1.o: record/../ssl_locl.h record/rec_layer_d1.c
-record/rec_layer_d1.o: record/record_locl.h
+record/rec_layer_d1.o: record/../ssl_locl.h record/../statem/statem.h
+record/rec_layer_d1.o: record/rec_layer_d1.c record/record_locl.h
 record/rec_layer_s3.o: ../e_os.h ../include/openssl/asn1.h
 record/rec_layer_s3.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/rec_layer_s3.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -325,8 +268,8 @@ record/rec_layer_s3.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/rec_layer_s3.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/rec_layer_s3.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/rec_layer_s3.o: record/../packet_locl.h record/../record/record.h
-record/rec_layer_s3.o: record/../ssl_locl.h record/rec_layer_s3.c
-record/rec_layer_s3.o: record/record_locl.h
+record/rec_layer_s3.o: record/../ssl_locl.h record/../statem/statem.h
+record/rec_layer_s3.o: record/rec_layer_s3.c record/record_locl.h
 record/ssl3_buffer.o: ../e_os.h ../include/openssl/asn1.h
 record/ssl3_buffer.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/ssl3_buffer.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -349,7 +292,8 @@ record/ssl3_buffer.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 record/ssl3_buffer.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 record/ssl3_buffer.o: ../include/openssl/x509_vfy.h record/../packet_locl.h
 record/ssl3_buffer.o: record/../record/record.h record/../ssl_locl.h
-record/ssl3_buffer.o: record/record_locl.h record/ssl3_buffer.c
+record/ssl3_buffer.o: record/../statem/statem.h record/record_locl.h
+record/ssl3_buffer.o: record/ssl3_buffer.c
 record/ssl3_record.o: ../e_os.h ../include/internal/constant_time_locl.h
 record/ssl3_record.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 record/ssl3_record.o: ../include/openssl/bn.h ../include/openssl/buffer.h
@@ -372,28 +316,8 @@ record/ssl3_record.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/ssl3_record.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/ssl3_record.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/ssl3_record.o: record/../packet_locl.h record/../record/record.h
-record/ssl3_record.o: record/../ssl_locl.h record/record_locl.h
-record/ssl3_record.o: record/ssl3_record.c
-s3_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_both.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_both.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_both.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-s3_both.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-s3_both.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-s3_both.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_both.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-s3_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_both.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_both.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_both.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-s3_both.o: packet_locl.h record/record.h s3_both.c ssl_locl.h
+record/ssl3_record.o: record/../ssl_locl.h record/../statem/statem.h
+record/ssl3_record.o: record/record_locl.h record/ssl3_record.c
 s3_cbc.o: ../e_os.h ../include/internal/constant_time_locl.h
 s3_cbc.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_cbc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
@@ -414,29 +338,7 @@ s3_cbc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_cbc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_cbc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_cbc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_cbc.o: record/record.h s3_cbc.c ssl_locl.h
-s3_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-s3_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_clnt.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-s3_clnt.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_clnt.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_clnt.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_clnt.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_clnt.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_clnt.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-s3_clnt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_clnt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_clnt.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-s3_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_clnt.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-s3_clnt.o: s3_clnt.c ssl_locl.h
+s3_cbc.o: record/record.h s3_cbc.c ssl_locl.h statem/statem.h
 s3_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_enc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_enc.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -456,7 +358,7 @@ s3_enc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_enc.o: record/record.h s3_enc.c ssl_locl.h
+s3_enc.o: record/record.h s3_enc.c ssl_locl.h statem/statem.h
 s3_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_lib.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -477,7 +379,7 @@ s3_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_lib.o: record/record.h s3_lib.c ssl_locl.h
+s3_lib.o: record/record.h s3_lib.c ssl_locl.h statem/statem.h
 s3_msg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_msg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_msg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -497,29 +399,7 @@ s3_msg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 s3_msg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 s3_msg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 s3_msg.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h s3_msg.c
-s3_msg.o: ssl_locl.h
-s3_srvr.o: ../e_os.h ../include/internal/constant_time_locl.h
-s3_srvr.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-s3_srvr.o: packet_locl.h record/record.h s3_srvr.c ssl_locl.h
+s3_msg.o: ssl_locl.h statem/statem.h
 ssl_algs.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_algs.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_algs.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -539,7 +419,7 @@ ssl_algs.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_algs.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_algs.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_algs.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_algs.o: ssl_algs.c ssl_locl.h
+ssl_algs.o: ssl_algs.c ssl_locl.h statem/statem.h
 ssl_asn1.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/asn1t.h
 ssl_asn1.o: ../include/openssl/bio.h ../include/openssl/bn.h
 ssl_asn1.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -559,7 +439,7 @@ ssl_asn1.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 ssl_asn1.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_asn1.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_asn1.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_asn1.o: packet_locl.h record/record.h ssl_asn1.c ssl_locl.h
+ssl_asn1.o: packet_locl.h record/record.h ssl_asn1.c ssl_locl.h statem/statem.h
 ssl_cert.o: ../e_os.h ../include/internal/o_dir.h ../include/openssl/asn1.h
 ssl_cert.o: ../include/openssl/bio.h ../include/openssl/bn.h
 ssl_cert.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -581,7 +461,7 @@ ssl_cert.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_cert.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_cert.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssl_cert.o: ../include/openssl/x509v3.h packet_locl.h record/record.h
-ssl_cert.o: ssl_cert.c ssl_locl.h
+ssl_cert.o: ssl_cert.c ssl_locl.h statem/statem.h
 ssl_ciph.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_ciph.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_ciph.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -601,7 +481,7 @@ ssl_ciph.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 ssl_ciph.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_ciph.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_ciph.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_ciph.o: packet_locl.h record/record.h ssl_ciph.c ssl_locl.h
+ssl_ciph.o: packet_locl.h record/record.h ssl_ciph.c ssl_locl.h statem/statem.h
 ssl_conf.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_conf.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_conf.o: ../include/openssl/comp.h ../include/openssl/conf.h
@@ -622,7 +502,7 @@ ssl_conf.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_conf.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_conf.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_conf.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_conf.o: ssl_conf.c ssl_locl.h
+ssl_conf.o: ssl_conf.c ssl_locl.h statem/statem.h
 ssl_err.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_err.o: ../include/openssl/buffer.h ../include/openssl/comp.h
 ssl_err.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
@@ -679,7 +559,7 @@ ssl_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssl_lib.o: ../include/openssl/x509v3.h packet_locl.h record/record.h ssl_lib.c
-ssl_lib.o: ssl_locl.h
+ssl_lib.o: ssl_locl.h statem/statem.h
 ssl_rsa.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_rsa.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_rsa.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -699,7 +579,7 @@ ssl_rsa.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_rsa.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_rsa.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_rsa.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_rsa.o: ssl_locl.h ssl_rsa.c
+ssl_rsa.o: ssl_locl.h ssl_rsa.c statem/statem.h
 ssl_sess.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_sess.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_sess.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -720,7 +600,7 @@ ssl_sess.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_sess.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_sess.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_sess.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_sess.o: ssl_locl.h ssl_sess.c
+ssl_sess.o: ssl_locl.h ssl_sess.c statem/statem.h
 ssl_stat.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_stat.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_stat.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -740,7 +620,7 @@ ssl_stat.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_stat.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_stat.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_stat.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_stat.o: ssl_locl.h ssl_stat.c
+ssl_stat.o: ssl_locl.h ssl_stat.c statem/statem.h
 ssl_txt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_txt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_txt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -760,7 +640,7 @@ ssl_txt.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_txt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_txt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_txt.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_txt.o: ssl_locl.h ssl_txt.c
+ssl_txt.o: ssl_locl.h ssl_txt.c statem/statem.h
 ssl_utst.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_utst.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_utst.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -780,27 +660,127 @@ ssl_utst.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_utst.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_utst.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_utst.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_utst.o: ssl_locl.h ssl_utst.c
-t1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-t1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-t1_clnt.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_clnt.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_clnt.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_clnt.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-t1_clnt.o: packet_locl.h record/record.h ssl_locl.h t1_clnt.c
+ssl_utst.o: ssl_locl.h ssl_utst.c statem/statem.h
+statem/statem.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
+statem/statem.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+statem/statem.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+statem/statem.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+statem/statem.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+statem/statem.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+statem/statem.o: ../include/openssl/err.h ../include/openssl/evp.h
+statem/statem.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
+statem/statem.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+statem/statem.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem.o: statem/../ssl_locl.h statem/../statem/statem.h statem/statem.c
+statem/statem.o: statem/statem_locl.h
+statem/statem_clnt.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_clnt.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_clnt.o: ../include/openssl/crypto.h ../include/openssl/dh.h
+statem/statem_clnt.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+statem/statem_clnt.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+statem/statem_clnt.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+statem/statem_clnt.o: ../include/openssl/engine.h ../include/openssl/err.h
+statem/statem_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
+statem/statem_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem_clnt.o: ../include/openssl/opensslconf.h
+statem/statem_clnt.o: ../include/openssl/opensslv.h
+statem/statem_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_clnt.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_clnt.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_clnt.o: statem/statem_clnt.c statem/statem_locl.h
+statem/statem_dtls.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_dtls.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_dtls.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_dtls.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
+statem/statem_dtls.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_dtls.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_dtls.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_dtls.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_dtls.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+statem/statem_dtls.o: ../include/openssl/objects.h
+statem/statem_dtls.o: ../include/openssl/opensslconf.h
+statem/statem_dtls.o: ../include/openssl/opensslv.h
+statem/statem_dtls.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_dtls.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_dtls.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_dtls.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_dtls.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_dtls.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_dtls.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_dtls.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_dtls.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_dtls.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_dtls.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_dtls.o: statem/statem_dtls.c statem/statem_locl.h
+statem/statem_lib.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_lib.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
+statem/statem_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+statem/statem_lib.o: ../include/openssl/objects.h
+statem/statem_lib.o: ../include/openssl/opensslconf.h
+statem/statem_lib.o: ../include/openssl/opensslv.h
+statem/statem_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_lib.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_lib.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_lib.o: statem/statem_lib.c statem/statem_locl.h
+statem/statem_srvr.o: ../e_os.h ../include/internal/constant_time_locl.h
+statem/statem_srvr.o: ../include/openssl/asn1.h ../include/openssl/bio.h
+statem/statem_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+statem/statem_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+statem/statem_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
+statem/statem_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
+statem/statem_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem_srvr.o: ../include/openssl/opensslconf.h
+statem/statem_srvr.o: ../include/openssl/opensslv.h
+statem/statem_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_srvr.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_srvr.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_srvr.o: statem/statem_locl.h statem/statem_srvr.c
 t1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_enc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_enc.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -821,7 +801,7 @@ t1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_enc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_enc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_enc.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_enc.o: ssl_locl.h t1_enc.c
+t1_enc.o: ssl_locl.h statem/statem.h t1_enc.c
 t1_ext.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_ext.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_ext.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -841,7 +821,7 @@ t1_ext.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_ext.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_ext.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_ext.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_ext.o: ssl_locl.h t1_ext.c
+t1_ext.o: ssl_locl.h statem/statem.h t1_ext.c
 t1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_lib.o: ../include/openssl/comp.h ../include/openssl/conf.h
@@ -863,27 +843,7 @@ t1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h
-t1_lib.o: packet_locl.h record/record.h ssl_locl.h t1_lib.c
-t1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_meth.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-t1_meth.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-t1_meth.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_meth.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_meth.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_meth.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_meth.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-t1_meth.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_meth.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_meth.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_meth.o: ssl_locl.h t1_meth.c
+t1_lib.o: packet_locl.h record/record.h ssl_locl.h statem/statem.h t1_lib.c
 t1_reneg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_reneg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_reneg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -903,27 +863,7 @@ t1_reneg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_reneg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_reneg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_reneg.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_reneg.o: ssl_locl.h t1_reneg.c
-t1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-t1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-t1_srvr.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_srvr.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_srvr.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_srvr.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_srvr.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-t1_srvr.o: packet_locl.h record/record.h ssl_locl.h t1_srvr.c
+t1_reneg.o: ssl_locl.h statem/statem.h t1_reneg.c
 t1_trce.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_trce.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_trce.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -943,7 +883,7 @@ t1_trce.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_trce.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_trce.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_trce.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_trce.o: ssl_locl.h t1_trce.c
+t1_trce.o: ssl_locl.h statem/statem.h t1_trce.c
 tls_srp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 tls_srp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 tls_srp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -964,4 +904,4 @@ tls_srp.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 tls_srp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 tls_srp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 tls_srp.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-tls_srp.o: ssl_locl.h tls_srp.c
+tls_srp.o: ssl_locl.h statem/statem.h tls_srp.c
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
deleted file mode 100644
index 083333e..0000000
--- a/ssl/d1_clnt.c
+++ /dev/null
@@ -1,830 +0,0 @@
-/* ssl/d1_clnt.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra at cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core at OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay at cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh at cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-
-static const SSL_METHOD *dtls1_get_client_method(int ver);
-static int dtls1_get_hello_verify(SSL *s);
-
-static const SSL_METHOD *dtls1_get_client_method(int ver)
-{
-    if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
-        return (DTLSv1_client_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_client_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
-
-int dtls1_connect(SSL *s)
-{
-    BUF_MEM *buf = NULL;
-    unsigned long Time = (unsigned long)time(NULL);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    int ret = -1;
-    int new_state, state, skip = 0;
-#ifndef OPENSSL_NO_SCTP
-    unsigned char sctpauthkey[64];
-    char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-#endif
-
-    RAND_add(&Time, sizeof(Time), 0);
-    ERR_clear_error();
-    clear_sys_error();
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    s->in_handshake++;
-    if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
-            return -1;
-    }
-
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Notify SCTP BIO socket to enter handshake mode and prevent stream
-     * identifier other than 0. Will be ignored if no SCTP is used.
-     */
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-             s->in_handshake, NULL);
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
-    /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
-     */
-    if (s->tlsext_hb_pending) {
-        dtls1_stop_timer(s);
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
-    }
-#endif
-
-    for (;;) {
-        state = s->state;
-
-        switch (s->state) {
-        case SSL_ST_RENEGOTIATE:
-            s->renegotiate = 1;
-            s->state = SSL_ST_CONNECT;
-            s->ctx->stats.sess_connect_renegotiate++;
-            /* break */
-        case SSL_ST_BEFORE:
-        case SSL_ST_CONNECT:
-        case SSL_ST_BEFORE | SSL_ST_CONNECT:
-        case SSL_ST_OK | SSL_ST_CONNECT:
-
-            s->server = 0;
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_START, 1);
-
-            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
-                (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00)) {
-                SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR);
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            /* s->version=SSL3_VERSION; */
-            s->type = SSL_ST_CONNECT;
-
-            if (s->init_buf == NULL) {
-                if ((buf = BUF_MEM_new()) == NULL) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                s->init_buf = buf;
-                buf = NULL;
-            }
-
-            if (!ssl3_setup_buffers(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            /* setup buffing BIO */
-            if (!ssl_init_wbio_buffer(s, 0)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            /* don't push the buffering BIO quite yet */
-
-            s->state = SSL3_ST_CW_CLNT_HELLO_A;
-            s->ctx->stats.sess_connect++;
-            s->init_num = 0;
-            /* mark client_random uninitialized */
-            memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
-            s->d1->send_cookie = 0;
-            s->hit = 0;
-            /*
-             * Should have been reset by ssl3_get_finished, too.
-             */
-            s->s3->change_cipher_spec = 0;
-            break;
-
-#ifndef OPENSSL_NO_SCTP
-        case DTLS1_SCTP_ST_CR_READ_SOCK:
-
-            if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-                s->s3->in_read_app_data = 2;
-                s->rwstate = SSL_READING;
-                BIO_clear_retry_flags(SSL_get_rbio(s));
-                BIO_set_retry_read(SSL_get_rbio(s));
-                ret = -1;
-                goto end;
-            }
-
-            s->state = s->s3->tmp.next_state;
-            break;
-
-        case DTLS1_SCTP_ST_CW_WRITE_SOCK:
-            /* read app data until dry event */
-
-            ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
-            if (ret < 0)
-                goto end;
-
-            if (ret == 0) {
-                s->s3->in_read_app_data = 2;
-                s->rwstate = SSL_READING;
-                BIO_clear_retry_flags(SSL_get_rbio(s));
-                BIO_set_retry_read(SSL_get_rbio(s));
-                ret = -1;
-                goto end;
-            }
-
-            s->state = s->d1->next_state;
-            break;
-#endif
-
-        case SSL3_ST_CW_CLNT_HELLO_A:
-        case SSL3_ST_CW_CLNT_HELLO_B:
-
-            s->shutdown = 0;
-
-            /* every DTLS ClientHello resets Finished MAC */
-            ssl3_init_finished_mac(s);
-
-            dtls1_start_timer(s);
-            ret = ssl3_client_hello(s);
-            if (ret <= 0)
-                goto end;
-
-            if (s->d1->send_cookie) {
-                s->state = SSL3_ST_CW_FLUSH;
-                s->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
-            } else
-                s->state = SSL3_ST_CR_SRVR_HELLO_A;
-
-            s->init_num = 0;
-
-#ifndef OPENSSL_NO_SCTP
-            /* Disable buffering for SCTP */
-            if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-#endif
-                /*
-                 * turn on buffering for the next lot of output
-                 */
-                if (s->bbio != s->wbio)
-                    s->wbio = BIO_push(s->bbio, s->wbio);
-#ifndef OPENSSL_NO_SCTP
-            }
-#endif
-
-            break;
-
-        case SSL3_ST_CR_SRVR_HELLO_A:
-        case SSL3_ST_CR_SRVR_HELLO_B:
-            ret = ssl3_get_server_hello(s);
-            if (ret <= 0)
-                goto end;
-            else {
-                if (s->hit) {
-#ifndef OPENSSL_NO_SCTP
-                    /*
-                     * Add new shared key for SCTP-Auth, will be ignored if
-                     * no SCTP used.
-                     */
-                    snprintf((char *)labelbuffer,
-                             sizeof(DTLS1_SCTP_AUTH_LABEL),
-                             DTLS1_SCTP_AUTH_LABEL);
-
-                    if (SSL_export_keying_material(s, sctpauthkey,
-                                               sizeof(sctpauthkey),
-                                               labelbuffer,
-                                               sizeof(labelbuffer), NULL, 0,
-                                               0) <= 0) {
-                        ret = -1;
-                        s->state = SSL_ST_ERR;
-                        goto end;
-                    }
-
-                    BIO_ctrl(SSL_get_wbio(s),
-                             BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                             sizeof(sctpauthkey), sctpauthkey);
-#endif
-
-                    s->state = SSL3_ST_CR_CHANGE_A;
-                    if (s->tlsext_ticket_expected) {
-                        /* receive renewed session ticket */
-                        s->state = SSL3_ST_CR_SESSION_TICKET_A;
-                    }
-                } else
-                    s->state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
-            }
-            s->init_num = 0;
-            break;
-
-        case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
-        case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
-
-            ret = dtls1_get_hello_verify(s);
-            if (ret <= 0)
-                goto end;
-            dtls1_stop_timer(s);
-            if (s->d1->send_cookie) /* start again, with a cookie */
-                s->state = SSL3_ST_CW_CLNT_HELLO_A;
-            else
-                s->state = SSL3_ST_CR_CERT_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_CERT_A:
-        case SSL3_ST_CR_CERT_B:
-            /* Check if it is anon DH or PSK */
-            if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
-                !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
-                ret = ssl3_get_server_certificate(s);
-                if (ret <= 0)
-                    goto end;
-
-                if (s->tlsext_status_expected)
-                    s->state = SSL3_ST_CR_CERT_STATUS_A;
-                else
-                    s->state = SSL3_ST_CR_KEY_EXCH_A;
-            } else {
-                skip = 1;
-                s->state = SSL3_ST_CR_KEY_EXCH_A;
-            }
-
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_KEY_EXCH_A:
-        case SSL3_ST_CR_KEY_EXCH_B:
-            ret = ssl3_get_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_CERT_REQ_A;
-            s->init_num = 0;
-
-            /*
-             * at this point we check that we have the required stuff from
-             * the server
-             */
-            if (!ssl3_check_cert_and_algorithm(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-            break;
-
-        case SSL3_ST_CR_CERT_REQ_A:
-        case SSL3_ST_CR_CERT_REQ_B:
-            ret = ssl3_get_certificate_request(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_SRVR_DONE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_SRVR_DONE_A:
-        case SSL3_ST_CR_SRVR_DONE_B:
-            ret = ssl3_get_server_done(s);
-            if (ret <= 0)
-                goto end;
-            dtls1_stop_timer(s);
-            if (s->s3->tmp.cert_req)
-                s->s3->tmp.next_state = SSL3_ST_CW_CERT_A;
-            else
-                s->s3->tmp.next_state = SSL3_ST_CW_KEY_EXCH_A;
-            s->init_num = 0;
-
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
-                state == SSL_ST_RENEGOTIATE)
-                s->state = DTLS1_SCTP_ST_CR_READ_SOCK;
-            else
-#endif
-                s->state = s->s3->tmp.next_state;
-            break;
-
-        case SSL3_ST_CW_CERT_A:
-        case SSL3_ST_CW_CERT_B:
-        case SSL3_ST_CW_CERT_C:
-        case SSL3_ST_CW_CERT_D:
-            dtls1_start_timer(s);
-            ret = ssl3_send_client_certificate(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_KEY_EXCH_A:
-        case SSL3_ST_CW_KEY_EXCH_B:
-            dtls1_start_timer(s);
-            ret = ssl3_send_client_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-
-#ifndef OPENSSL_NO_SCTP
-            /*
-             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
-             * used.
-             */
-            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                     DTLS1_SCTP_AUTH_LABEL);
-
-            if (SSL_export_keying_material(s, sctpauthkey,
-                                       sizeof(sctpauthkey), labelbuffer,
-                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                     sizeof(sctpauthkey), sctpauthkey);
-#endif
-
-            /*
-             * EAY EAY EAY need to check for DH fix cert sent back
-             */
-            /*
-             * For TLS, cert_req is set to 2, so a cert chain of nothing is
-             * sent, but no verify packet is sent
-             */
-            if (s->s3->tmp.cert_req == 1) {
-                s->state = SSL3_ST_CW_CERT_VRFY_A;
-            } else {
-#ifndef OPENSSL_NO_SCTP
-                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                    s->d1->next_state = SSL3_ST_CW_CHANGE_A;
-                    s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK;
-                } else
-#endif
-                    s->state = SSL3_ST_CW_CHANGE_A;
-            }
-
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_CERT_VRFY_A:
-        case SSL3_ST_CW_CERT_VRFY_B:
-            dtls1_start_timer(s);
-            ret = ssl3_send_client_verify(s);
-            if (ret <= 0)
-                goto end;
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                s->d1->next_state = SSL3_ST_CW_CHANGE_A;
-                s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK;
-            } else
-#endif
-                s->state = SSL3_ST_CW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_CHANGE_A:
-        case SSL3_ST_CW_CHANGE_B:
-            if (!s->hit)
-                dtls1_start_timer(s);
-            ret = dtls1_send_change_cipher_spec(s,
-                                                SSL3_ST_CW_CHANGE_A,
-                                                SSL3_ST_CW_CHANGE_B);
-            if (ret <= 0)
-                goto end;
-
-            s->state = SSL3_ST_CW_FINISHED_A;
-            s->init_num = 0;
-
-            s->session->cipher = s->s3->tmp.new_cipher;
-#ifdef OPENSSL_NO_COMP
-            s->session->compress_meth = 0;
-#else
-            if (s->s3->tmp.new_compression == NULL)
-                s->session->compress_meth = 0;
-            else
-                s->session->compress_meth = s->s3->tmp.new_compression->id;
-#endif
-            if (!s->method->ssl3_enc->setup_key_block(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                          SSL3_CHANGE_CIPHER_CLIENT_WRITE))
-            {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-#ifndef OPENSSL_NO_SCTP
-            if (s->hit) {
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-            }
-#endif
-
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-            break;
-
-        case SSL3_ST_CW_FINISHED_A:
-        case SSL3_ST_CW_FINISHED_B:
-            if (!s->hit)
-                dtls1_start_timer(s);
-            ret = ssl3_send_finished(s,
-                                     SSL3_ST_CW_FINISHED_A,
-                                     SSL3_ST_CW_FINISHED_B,
-                                     s->method->
-                                     ssl3_enc->client_finished_label,
-                                     s->method->
-                                     ssl3_enc->client_finished_label_len);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_FLUSH;
-
-            if (s->hit) {
-                s->s3->tmp.next_state = SSL_ST_OK;
-#ifndef OPENSSL_NO_SCTP
-                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                    s->d1->next_state = s->s3->tmp.next_state;
-                    s->s3->tmp.next_state = DTLS1_SCTP_ST_CW_WRITE_SOCK;
-                }
-#endif
-            } else {
-#ifndef OPENSSL_NO_SCTP
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-#endif
-
-                /*
-                 * Allow NewSessionTicket if ticket expected
-                 */
-                if (s->tlsext_ticket_expected)
-                    s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A;
-                else
-                    s->s3->tmp.next_state = SSL3_ST_CR_CHANGE_A;
-            }
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_SESSION_TICKET_A:
-        case SSL3_ST_CR_SESSION_TICKET_B:
-            ret = ssl3_get_new_session_ticket(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_CERT_STATUS_A:
-        case SSL3_ST_CR_CERT_STATUS_B:
-            ret = ssl3_get_cert_status(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_CHANGE_A:
-        case SSL3_ST_CR_CHANGE_B:
-            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_CR_CHANGE_A,
-                                              SSL3_ST_CR_CHANGE_B);
-            if (ret <= 0)
-                goto end;
-
-            s->state = SSL3_ST_CR_FINISHED_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CR_FINISHED_A:
-        case SSL3_ST_CR_FINISHED_B:
-            ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
-                                    SSL3_ST_CR_FINISHED_B);
-            if (ret <= 0)
-                goto end;
-            dtls1_stop_timer(s);
-
-            if (s->hit)
-                s->state = SSL3_ST_CW_CHANGE_A;
-            else
-                s->state = SSL_ST_OK;
-
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
-                state == SSL_ST_RENEGOTIATE) {
-                s->d1->next_state = s->state;
-                s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK;
-            }
-#endif
-
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_FLUSH:
-            s->rwstate = SSL_WRITING;
-            if (BIO_flush(s->wbio) <= 0) {
-                /*
-                 * If the write error was fatal, stop trying
-                 */
-                if (!BIO_should_retry(s->wbio)) {
-                    s->rwstate = SSL_NOTHING;
-                    s->state = s->s3->tmp.next_state;
-                }
-
-                ret = -1;
-                goto end;
-            }
-            s->rwstate = SSL_NOTHING;
-            s->state = s->s3->tmp.next_state;
-            break;
-
-        case SSL_ST_OK:
-            /* clean a few things up */
-            ssl3_cleanup_key_block(s);
-
-            /* Remove the buffering */
-            ssl_free_wbio_buffer(s);
-
-            s->init_num = 0;
-            s->renegotiate = 0;
-            s->new_session = 0;
-
-            ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
-            if (s->hit)
-                s->ctx->stats.sess_hit++;
-
-            ret = 1;
-            /* s->server=0; */
-            s->handshake_func = dtls1_connect;
-            s->ctx->stats.sess_connect_good++;
-
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_DONE, 1);
-
-            /* done with handshaking */
-            s->d1->handshake_read_seq = 0;
-            s->d1->next_handshake_write_seq = 0;
-            goto end;
-            /* break; */
-
-        case SSL_ST_ERR:
-        default:
-            SSLerr(SSL_F_DTLS1_CONNECT, SSL_R_UNKNOWN_STATE);
-            ret = -1;
-            goto end;
-            /* break; */
-        }
-
-        /* did we do anything */
-        if (!s->s3->tmp.reuse_message && !skip) {
-            if (s->debug) {
-                if ((ret = BIO_flush(s->wbio)) <= 0)
-                    goto end;
-            }
-
-            if ((cb != NULL) && (s->state != state)) {
-                new_state = s->state;
-                s->state = state;
-                cb(s, SSL_CB_CONNECT_LOOP, 1);
-                s->state = new_state;
-            }
-        }
-        skip = 0;
-    }
- end:
-    s->in_handshake--;
-
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Notify SCTP BIO socket to leave handshake mode and allow stream
-     * identifier other than 0. Will be ignored if no SCTP is used.
-     */
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-             s->in_handshake, NULL);
-#endif
-
-    BUF_MEM_free(buf);
-    if (cb != NULL)
-        cb(s, SSL_CB_CONNECT_EXIT, ret);
-    return (ret);
-}
-
-static int dtls1_get_hello_verify(SSL *s)
-{
-    int n, al, ok = 0;
-    unsigned char *data;
-    unsigned int cookie_len;
-
-    s->first_packet = 1;
-    n = s->method->ssl_get_message(s,
-                                   DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A,
-                                   DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B,
-                                   -1, s->max_cert_list, &ok);
-    s->first_packet = 0;
-
-    if (!ok)
-        return ((int)n);
-
-    if (s->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
-        s->d1->send_cookie = 0;
-        s->s3->tmp.reuse_message = 1;
-        return (1);
-    }
-
-    data = (unsigned char *)s->init_msg;
-    data += 2;
-
-    cookie_len = *(data++);
-    if (cookie_len > sizeof(s->d1->cookie)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        goto f_err;
-    }
-
-    memcpy(s->d1->cookie, data, cookie_len);
-    s->d1->cookie_len = cookie_len;
-
-    s->d1->send_cookie = 1;
-    return 1;
-
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    s->state = SSL_ST_ERR;
-    return -1;
-}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 3a0a4cf..733973b 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -60,6 +60,7 @@
 #include <stdio.h>
 #define USE_SOCKETS
 #include <openssl/objects.h>
+#include <openssl/rand.h>
 #include "ssl_locl.h"
 
 #if defined(OPENSSL_SYS_VMS)
@@ -76,6 +77,10 @@ static void get_current_time(struct timeval *t);
 static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
 static int dtls1_handshake_write(SSL *s);
 int dtls1_listen(SSL *s, struct sockaddr *client);
+static unsigned int dtls1_link_min_mtu(void);
+
+/* XDTLS:  figure out the right values */
+static const unsigned int g_probable_mtu[] = { 1500, 512, 256 };
 
 const SSL3_ENC_METHOD DTLSv1_enc_data = {
     tls1_enc,
@@ -762,8 +767,8 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
             }
 
             p = &buf[DTLS1_RT_HEADER_LENGTH];
-            msglen = dtls1_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
-                                                    cookie, cookielen);
+            msglen = dtls_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
+                                                   cookie, cookielen);
 
             *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;
 
@@ -869,10 +874,10 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
     SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
 
     /*
-     * Put us into the "init" state so that dtls1_accept doesn't clear our
-     * state
+     * Tell the state machine that we've done the initial hello verify
+     * exchange
      */
-    s->state = SSL_ST_ACCEPT;
+    ossl_statem_set_hello_verify_done(s);
 
     if(BIO_dgram_get_peer(rbio, client) <= 0) {
         SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
@@ -908,3 +913,236 @@ static int dtls1_handshake_write(SSL *s)
 {
     return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
 }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int dtls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
+{
+    unsigned char *pl;
+    unsigned short hbtype;
+    unsigned int payload;
+    unsigned int padding = 16;  /* Use minimum padding */
+
+    if (s->msg_callback)
+        s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+                        p, length, s, s->msg_callback_arg);
+
+    /* Read type and payload length first */
+    if (1 + 2 + 16 > length)
+        return 0;               /* silently discard */
+    if (length > SSL3_RT_MAX_PLAIN_LENGTH)
+        return 0;               /* silently discard per RFC 6520 sec. 4 */
+
+    hbtype = *p++;
+    n2s(p, payload);
+    if (1 + 2 + payload + 16 > length)
+        return 0;               /* silently discard per RFC 6520 sec. 4 */
+    pl = p;
+
+    if (hbtype == TLS1_HB_REQUEST) {
+        unsigned char *buffer, *bp;
+        unsigned int write_length = 1 /* heartbeat type */  +
+            2 /* heartbeat length */  +
+            payload + padding;
+        int r;
+
+        if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+            return 0;
+
+        /*
+         * Allocate memory for the response, size is 1 byte message type,
+         * plus 2 bytes payload length, plus payload, plus padding
+         */
+        buffer = OPENSSL_malloc(write_length);
+        if (buffer == NULL)
+            return -1;
+        bp = buffer;
+
+        /* Enter response type, length and copy payload */
+        *bp++ = TLS1_HB_RESPONSE;
+        s2n(payload, bp);
+        memcpy(bp, pl, payload);
+        bp += payload;
+        /* Random padding */
+        if (RAND_bytes(bp, padding) <= 0) {
+            OPENSSL_free(buffer);
+            return -1;
+        }
+
+        r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
+
+        if (r >= 0 && s->msg_callback)
+            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                            buffer, write_length, s, s->msg_callback_arg);
+
+        OPENSSL_free(buffer);
+
+        if (r < 0)
+            return r;
+    } else if (hbtype == TLS1_HB_RESPONSE) {
+        unsigned int seq;
+
+        /*
+         * We only send sequence numbers (2 bytes unsigned int), and 16
+         * random bytes, so we just try to read the sequence number
+         */
+        n2s(pl, seq);
+
+        if (payload == 18 && seq == s->tlsext_hb_seq) {
+            dtls1_stop_timer(s);
+            s->tlsext_hb_seq++;
+            s->tlsext_hb_pending = 0;
+        }
+    }
+
+    return 0;
+}
+
+int dtls1_heartbeat(SSL *s)
+{
+    unsigned char *buf, *p;
+    int ret = -1;
+    unsigned int payload = 18;  /* Sequence number + random bytes */
+    unsigned int padding = 16;  /* Use minimum padding */
+
+    /* Only send if peer supports and accepts HB requests... */
+    if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+        s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+        return -1;
+    }
+
+    /* ...and there is none in flight yet... */
+    if (s->tlsext_hb_pending) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
+        return -1;
+    }
+
+    /* ...and no handshake in progress. */
+    if (SSL_in_init(s) || ossl_statem_get_in_handshake(s)) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
+        return -1;
+    }
+
+    /*
+     * Check if padding is too long, payload and padding must not exceed 2^14
+     * - 3 = 16381 bytes in total.
+     */
+    OPENSSL_assert(payload + padding <= 16381);
+
+    /*-
+     * Create HeartBeat message, we just use a sequence number
+     * as payload to distuingish different messages and add
+     * some random stuff.
+     *  - Message Type, 1 byte
+     *  - Payload Length, 2 bytes (unsigned int)
+     *  - Payload, the sequence number (2 bytes uint)
+     *  - Payload, random bytes (16 bytes uint)
+     *  - Padding
+     */
+    buf = OPENSSL_malloc(1 + 2 + payload + padding);
+    if (buf == NULL) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    p = buf;
+    /* Message Type */
+    *p++ = TLS1_HB_REQUEST;
+    /* Payload length (18 bytes here) */
+    s2n(payload, p);
+    /* Sequence number */
+    s2n(s->tlsext_hb_seq, p);
+    /* 16 random bytes */
+    if (RAND_bytes(p, 16) <= 0) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    p += 16;
+    /* Random padding */
+    if (RAND_bytes(p, padding) <= 0) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+    if (ret >= 0) {
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                            buf, 3 + payload + padding,
+                            s, s->msg_callback_arg);
+
+        dtls1_start_timer(s);
+        s->tlsext_hb_pending = 1;
+    }
+
+ err:
+    OPENSSL_free(buf);
+
+    return ret;
+}
+#endif
+
+int dtls1_shutdown(SSL *s)
+{
+    int ret;
+#ifndef OPENSSL_NO_SCTP
+    BIO *wbio;
+
+    wbio = SSL_get_wbio(s);
+    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
+        !(s->shutdown & SSL_SENT_SHUTDOWN)) {
+        ret = BIO_dgram_sctp_wait_for_dry(wbio);
+        if (ret < 0)
+            return -1;
+
+        if (ret == 0)
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
+                     NULL);
+    }
+#endif
+    ret = ssl3_shutdown(s);
+#ifndef OPENSSL_NO_SCTP
+    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
+#endif
+    return ret;
+}
+
+int dtls1_query_mtu(SSL *s)
+{
+    if (s->d1->link_mtu) {
+        s->d1->mtu =
+            s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+        s->d1->link_mtu = 0;
+    }
+
+    /* AHA!  Figure out the MTU, and stick to the right size */
+    if (s->d1->mtu < dtls1_min_mtu(s)) {
+        if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+            s->d1->mtu =
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+
+            /*
+             * I've seen the kernel return bogus numbers when it doesn't know
+             * (initial write), so just make sure we have a reasonable number
+             */
+            if (s->d1->mtu < dtls1_min_mtu(s)) {
+                /* Set to min mtu */
+                s->d1->mtu = dtls1_min_mtu(s);
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
+                         s->d1->mtu, NULL);
+            }
+        } else
+            return 0;
+    }
+    return 1;
+}
+
+static unsigned int dtls1_link_min_mtu(void)
+{
+    return (g_probable_mtu[(sizeof(g_probable_mtu) /
+                            sizeof(g_probable_mtu[0])) - 1]);
+}
+
+unsigned int dtls1_min_mtu(SSL *s)
+{
+    return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+}
diff --git a/ssl/d1_meth.c b/ssl/d1_meth.c
deleted file mode 100644
index 7340774..0000000
--- a/ssl/d1_meth.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ssl/d1_meth.h */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra at cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core at OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay at cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh at cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-static const SSL_METHOD *dtls1_get_method(int ver);
-static const SSL_METHOD *dtls1_get_method(int ver)
-{
-    if (ver == DTLS1_VERSION)
-        return (DTLSv1_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data)
diff --git a/ssl/d1_msg.c b/ssl/d1_msg.c
index 13bda46..4a2f0dc 100644
--- a/ssl/d1_msg.c
+++ b/ssl/d1_msg.c
@@ -125,12 +125,11 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
      * Check if we have to continue an interrupted handshake for reading
      * belated app data with SCTP.
      */
-    if ((SSL_in_init(s) && !s->in_handshake) ||
+    if ((SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) ||
         (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
-         (s->state == DTLS1_SCTP_ST_SR_READ_SOCK
-          || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
+         ossl_statem_in_sctp_read_sock(s)))
 #else
-    if (SSL_in_init(s) && !s->in_handshake)
+    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s))
 #endif
     {
         i = s->handshake_func(s);
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
deleted file mode 100644
index e32c4c1..0000000
--- a/ssl/d1_srvr.c
+++ /dev/null
@@ -1,914 +0,0 @@
-/* ssl/d1_srvr.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra at cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core at OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay at cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh at cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <openssl/md5.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-
-static const SSL_METHOD *dtls1_get_server_method(int ver);
-static int dtls1_send_hello_verify_request(SSL *s);
-
-static const SSL_METHOD *dtls1_get_server_method(int ver)
-{
-    if (ver == DTLS1_VERSION)
-        return (DTLSv1_server_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_server_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
-
-int dtls1_accept(SSL *s)
-{
-    BUF_MEM *buf;
-    unsigned long Time = (unsigned long)time(NULL);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    unsigned long alg_k;
-    int ret = -1;
-    int new_state, state, skip = 0;
-#ifndef OPENSSL_NO_SCTP
-    unsigned char sctpauthkey[64];
-    char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-#endif
-
-    RAND_add(&Time, sizeof(Time), 0);
-    ERR_clear_error();
-    clear_sys_error();
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    /* init things to blank */
-    s->in_handshake++;
-    if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
-            return -1;
-    }
-
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Notify SCTP BIO socket to enter handshake mode and prevent stream
-     * identifier other than 0. Will be ignored if no SCTP is used.
-     */
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-             s->in_handshake, NULL);
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
-    /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
-     */
-    if (s->tlsext_hb_pending) {
-        dtls1_stop_timer(s);
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
-    }
-#endif
-
-    for (;;) {
-        state = s->state;
-
-        switch (s->state) {
-        case SSL_ST_RENEGOTIATE:
-            s->renegotiate = 1;
-            /* s->state=SSL_ST_ACCEPT; */
-
-        case SSL_ST_BEFORE:
-        case SSL_ST_ACCEPT:
-        case SSL_ST_BEFORE | SSL_ST_ACCEPT:
-        case SSL_ST_OK | SSL_ST_ACCEPT:
-
-            s->server = 1;
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_START, 1);
-
-            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
-                SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
-                return -1;
-            }
-            s->type = SSL_ST_ACCEPT;
-
-            if (s->init_buf == NULL) {
-                if ((buf = BUF_MEM_new()) == NULL) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-                    BUF_MEM_free(buf);
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                s->init_buf = buf;
-            }
-
-            if (!ssl3_setup_buffers(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            s->init_num = 0;
-            /*
-             * Should have been reset by ssl3_get_finished, too.
-             */
-            s->s3->change_cipher_spec = 0;
-
-            if (s->state != SSL_ST_RENEGOTIATE) {
-                /*
-                 * Ok, we now need to push on a buffering BIO so that the
-                 * output is sent in a way that TCP likes :-) ...but not with
-                 * SCTP :-)
-                 */
-#ifndef OPENSSL_NO_SCTP
-                if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
-#endif
-                    if (!ssl_init_wbio_buffer(s, 1)) {
-                        ret = -1;
-                        s->state = SSL_ST_ERR;
-                        goto end;
-                    }
-
-                ssl3_init_finished_mac(s);
-                s->state = SSL3_ST_SR_CLNT_HELLO_A;
-                s->ctx->stats.sess_accept++;
-            } else {
-                /*
-                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
-                 * HelloRequest
-                 */
-                s->ctx->stats.sess_accept_renegotiate++;
-                s->state = SSL3_ST_SW_HELLO_REQ_A;
-            }
-
-            break;
-
-        case SSL3_ST_SW_HELLO_REQ_A:
-        case SSL3_ST_SW_HELLO_REQ_B:
-
-            s->shutdown = 0;
-            dtls1_clear_record_buffer(s);
-            dtls1_start_timer(s);
-            ret = ssl3_send_hello_request(s);
-            if (ret <= 0)
-                goto end;
-            s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;
-            s->state = SSL3_ST_SW_FLUSH;
-            s->init_num = 0;
-
-            ssl3_init_finished_mac(s);
-            break;
-
-        case SSL3_ST_SW_HELLO_REQ_C:
-            s->state = SSL_ST_OK;
-            break;
-
-        case SSL3_ST_SR_CLNT_HELLO_A:
-        case SSL3_ST_SR_CLNT_HELLO_B:
-        case SSL3_ST_SR_CLNT_HELLO_C:
-
-            s->shutdown = 0;
-            ret = ssl3_get_client_hello(s);
-            if (ret <= 0)
-                goto end;
-            dtls1_stop_timer(s);
-
-            if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
-                s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
-            else
-                s->state = SSL3_ST_SW_SRVR_HELLO_A;
-
-            s->init_num = 0;
-            break;
-
-        case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
-        case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
-
-            ret = dtls1_send_hello_verify_request(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_FLUSH;
-            s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A;
-
-            /* HelloVerifyRequest resets Finished MAC */
-            if (s->version != DTLS1_BAD_VER)
-                ssl3_init_finished_mac(s);
-            break;
-
-#ifndef OPENSSL_NO_SCTP
-        case DTLS1_SCTP_ST_SR_READ_SOCK:
-
-            if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-                s->s3->in_read_app_data = 2;
-                s->rwstate = SSL_READING;
-                BIO_clear_retry_flags(SSL_get_rbio(s));
-                BIO_set_retry_read(SSL_get_rbio(s));
-                ret = -1;
-                goto end;
-            }
-
-            s->state = SSL3_ST_SR_CHANGE_A;
-            break;
-
-        case DTLS1_SCTP_ST_SW_WRITE_SOCK:
-            ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
-            if (ret < 0)
-                goto end;
-
-            if (ret == 0) {
-                if (s->d1->next_state != SSL_ST_OK) {
-                    s->s3->in_read_app_data = 2;
-                    s->rwstate = SSL_READING;
-                    BIO_clear_retry_flags(SSL_get_rbio(s));
-                    BIO_set_retry_read(SSL_get_rbio(s));
-                    ret = -1;
-                    goto end;
-                }
-            }
-
-            s->state = s->d1->next_state;
-            break;
-#endif
-
-        case SSL3_ST_SW_SRVR_HELLO_A:
-        case SSL3_ST_SW_SRVR_HELLO_B:
-            s->renegotiate = 2;
-            dtls1_start_timer(s);
-            ret = ssl3_send_server_hello(s);
-            if (ret <= 0)
-                goto end;
-
-            if (s->hit) {
-#ifndef OPENSSL_NO_SCTP
-                /*
-                 * Add new shared key for SCTP-Auth, will be ignored if no
-                 * SCTP used.
-                 */
-                snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                         DTLS1_SCTP_AUTH_LABEL);
-
-                if (SSL_export_keying_material(s, sctpauthkey,
-                        sizeof(sctpauthkey), labelbuffer,
-                        sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                         sizeof(sctpauthkey), sctpauthkey);
-#endif
-                if (s->tlsext_ticket_expected)
-                    s->state = SSL3_ST_SW_SESSION_TICKET_A;
-                else
-                    s->state = SSL3_ST_SW_CHANGE_A;
-            } else
-                s->state = SSL3_ST_SW_CERT_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_A:
-        case SSL3_ST_SW_CERT_B:
-            /* Check if it is anon DH or normal PSK */
-            if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
-                && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
-                dtls1_start_timer(s);
-                ret = ssl3_send_server_certificate(s);
-                if (ret <= 0)
-                    goto end;
-
-                if (s->tlsext_status_expected)
-                    s->state = SSL3_ST_SW_CERT_STATUS_A;
-                else
-                    s->state = SSL3_ST_SW_KEY_EXCH_A;
-            } else {
-                skip = 1;
-                s->state = SSL3_ST_SW_KEY_EXCH_A;
-            }
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_KEY_EXCH_A:
-        case SSL3_ST_SW_KEY_EXCH_B:
-            alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-            /*
-             * clear this, it may get reset by
-             * send_server_key_exchange
-             */
-            s->s3->tmp.use_rsa_tmp = 0;
-
-            /*
-             * only send if a DH key exchange or RSA but we have a sign only
-             * certificate
-             */
-            if (0
-                /*
-                 * PSK: send ServerKeyExchange if PSK identity hint if
-                 * provided
-                 */
-#ifndef OPENSSL_NO_PSK
-                || ((alg_k & SSL_kPSK) && s->cert->psk_identity_hint)
-#endif
-                || (alg_k & SSL_kDHE)
-                || (alg_k & SSL_kECDHE)
-                || ((alg_k & SSL_kRSA)
-                    && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
-                        || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
-                            && EVP_PKEY_size(s->cert->pkeys
-                                             [SSL_PKEY_RSA_ENC].privatekey) *
-                            8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
-                        )
-                    )
-                )
-                ) {
-                dtls1_start_timer(s);
-                ret = ssl3_send_server_key_exchange(s);
-                if (ret <= 0)
-                    goto end;
-            } else
-                skip = 1;
-
-            s->state = SSL3_ST_SW_CERT_REQ_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_REQ_A:
-        case SSL3_ST_SW_CERT_REQ_B:
-            if (                /* don't request cert unless asked for it: */
-                   !(s->verify_mode & SSL_VERIFY_PEER) ||
-                   /*
-                    * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
-                    * during re-negotiation:
-                    */
-                   ((s->session->peer != NULL) &&
-                    (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
-                   /*
-                    * never request cert in anonymous ciphersuites (see
-                    * section "Certificate request" in SSL 3 drafts and in
-                    * RFC 2246):
-                    */
-                   ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
-                   /*
-                    * ... except when the application insists on
-                    * verification (against the specs, but s3_clnt.c accepts
-                    * this for SSL 3)
-                    */
-                   !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
-                   /*
-                    * With normal PSK Certificates and Certificate Requests
-                    * are omitted
-                    */
-                   || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
-                /* no cert request */
-                skip = 1;
-                s->s3->tmp.cert_request = 0;
-                s->state = SSL3_ST_SW_SRVR_DONE_A;
-#ifndef OPENSSL_NO_SCTP
-                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                    s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
-                    s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
-                }
-#endif
-            } else {
-                s->s3->tmp.cert_request = 1;
-                dtls1_start_timer(s);
-                ret = ssl3_send_certificate_request(s);
-                if (ret <= 0)
-                    goto end;
-                s->state = SSL3_ST_SW_SRVR_DONE_A;
-# ifndef OPENSSL_NO_SCTP
-                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                    s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
-                    s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
-                }
-# endif
-                s->init_num = 0;
-            }
-            break;
-
-        case SSL3_ST_SW_SRVR_DONE_A:
-        case SSL3_ST_SW_SRVR_DONE_B:
-            dtls1_start_timer(s);
-            ret = ssl3_send_server_done(s);
-            if (ret <= 0)
-                goto end;
-            s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
-            s->state = SSL3_ST_SW_FLUSH;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_FLUSH:
-            s->rwstate = SSL_WRITING;
-            if (BIO_flush(s->wbio) <= 0) {
-                /*
-                 * If the write error was fatal, stop trying
-                 */
-                if (!BIO_should_retry(s->wbio)) {
-                    s->rwstate = SSL_NOTHING;
-                    s->state = s->s3->tmp.next_state;
-                }
-
-                ret = -1;
-                goto end;
-            }
-            s->rwstate = SSL_NOTHING;
-            s->state = s->s3->tmp.next_state;
-            break;
-
-        case SSL3_ST_SR_CERT_A:
-        case SSL3_ST_SR_CERT_B:
-            if (s->s3->tmp.cert_request) {
-                ret = ssl3_get_client_certificate(s);
-                if (ret <= 0)
-                    goto end;
-            }
-            s->init_num = 0;
-            s->state = SSL3_ST_SR_KEY_EXCH_A;
-            break;
-
-        case SSL3_ST_SR_KEY_EXCH_A:
-        case SSL3_ST_SR_KEY_EXCH_B:
-            ret = ssl3_get_client_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-#ifndef OPENSSL_NO_SCTP
-            /*
-             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
-             * used.
-             */
-            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                     DTLS1_SCTP_AUTH_LABEL);
-
-            if (SSL_export_keying_material(s, sctpauthkey,
-                                       sizeof(sctpauthkey), labelbuffer,
-                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                     sizeof(sctpauthkey), sctpauthkey);
-#endif
-
-            s->state = SSL3_ST_SR_CERT_VRFY_A;
-            s->init_num = 0;
-
-            if (ret == 2) {
-                /*
-                 * For the ECDH ciphersuites when the client sends its ECDH
-                 * pub key in a certificate, the CertificateVerify message is
-                 * not sent.
-                 */
-                s->state = SSL3_ST_SR_CHANGE_A;
-                s->init_num = 0;
-            } else if (SSL_USE_SIGALGS(s)) {
-                s->state = SSL3_ST_SR_CERT_VRFY_A;
-                s->init_num = 0;
-                if (!s->session->peer)
-                    break;
-                if (!s->s3->handshake_buffer) {
-                    SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR);
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-                /*
-                 * For sigalgs freeze the handshake buffer. If we support
-                 * extms we've done this already.
-                 */
-                if (!ssl3_digest_cached_records(s, 1)) {
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-            } else {
-                s->state = SSL3_ST_SR_CERT_VRFY_A;
-                s->init_num = 0;
-
-                /*
-                 * We need to get hashes here so if there is a client cert,
-                 * it can be verified
-                 */
-                s->method->ssl3_enc->cert_verify_mac(s,
-                                                     NID_md5,
-                                                     &(s->s3->
-                                                       tmp.cert_verify_md
-                                                       [0]));
-                s->method->ssl3_enc->cert_verify_mac(s, NID_sha1,
-                                                     &(s->s3->
-                                                       tmp.cert_verify_md
-                                                       [MD5_DIGEST_LENGTH]));
-            }
-            break;
-
-        case SSL3_ST_SR_CERT_VRFY_A:
-        case SSL3_ST_SR_CERT_VRFY_B:
-            ret = ssl3_get_cert_verify(s);
-            if (ret <= 0)
-                goto end;
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
-                state == SSL_ST_RENEGOTIATE)
-                s->state = DTLS1_SCTP_ST_SR_READ_SOCK;
-            else
-#endif
-                s->state = SSL3_ST_SR_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SR_CHANGE_A:
-        case SSL3_ST_SR_CHANGE_B:
-            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_SR_CHANGE_A,
-                                              SSL3_ST_SR_CHANGE_B);
-            if (ret <= 0)
-                goto end;
-
-            s->state = SSL3_ST_SR_FINISHED_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SR_FINISHED_A:
-        case SSL3_ST_SR_FINISHED_B:
-            ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
-                                    SSL3_ST_SR_FINISHED_B);
-            if (ret <= 0)
-                goto end;
-            dtls1_stop_timer(s);
-            if (s->hit)
-                s->state = SSL_ST_OK;
-            else if (s->tlsext_ticket_expected)
-                s->state = SSL3_ST_SW_SESSION_TICKET_A;
-            else
-                s->state = SSL3_ST_SW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_SESSION_TICKET_A:
-        case SSL3_ST_SW_SESSION_TICKET_B:
-            ret = ssl3_send_newsession_ticket(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_STATUS_A:
-        case SSL3_ST_SW_CERT_STATUS_B:
-            ret = ssl3_send_cert_status(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CHANGE_A:
-        case SSL3_ST_SW_CHANGE_B:
-
-            s->session->cipher = s->s3->tmp.new_cipher;
-            if (!s->method->ssl3_enc->setup_key_block(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            ret = dtls1_send_change_cipher_spec(s,
-                                                SSL3_ST_SW_CHANGE_A,
-                                                SSL3_ST_SW_CHANGE_B);
-
-            if (ret <= 0)
-                goto end;
-
-#ifndef OPENSSL_NO_SCTP
-            if (!s->hit) {
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-            }
-#endif
-
-            s->state = SSL3_ST_SW_FINISHED_A;
-            s->init_num = 0;
-
-            if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                          SSL3_CHANGE_CIPHER_SERVER_WRITE))
-            {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-            break;
-
-        case SSL3_ST_SW_FINISHED_A:
-        case SSL3_ST_SW_FINISHED_B:
-            ret = ssl3_send_finished(s,
-                                     SSL3_ST_SW_FINISHED_A,
-                                     SSL3_ST_SW_FINISHED_B,
-                                     s->method->
-                                     ssl3_enc->server_finished_label,
-                                     s->method->
-                                     ssl3_enc->server_finished_label_len);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_FLUSH;
-            if (s->hit) {
-                s->s3->tmp.next_state = SSL3_ST_SR_CHANGE_A;
-
-#ifndef OPENSSL_NO_SCTP
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-#endif
-            } else {
-                s->s3->tmp.next_state = SSL_ST_OK;
-#ifndef OPENSSL_NO_SCTP
-                if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-                    s->d1->next_state = s->s3->tmp.next_state;
-                    s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
-                }
-#endif
-            }
-            s->init_num = 0;
-            break;
-
-        case SSL_ST_OK:
-            /* clean a few things up */
-            ssl3_cleanup_key_block(s);
-
-            /* remove buffering on output */
-            ssl_free_wbio_buffer(s);
-
-            s->init_num = 0;
-
-            if (s->renegotiate == 2) { /* skipped if we just sent a
-                                        * HelloRequest */
-                s->renegotiate = 0;
-                s->new_session = 0;
-
-                ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
-
-                s->ctx->stats.sess_accept_good++;
-                /* s->server=1; */
-                s->handshake_func = dtls1_accept;
-
-                if (cb != NULL)
-                    cb(s, SSL_CB_HANDSHAKE_DONE, 1);
-            }
-
-            ret = 1;
-
-            /* done handshaking, next message is client hello */
-            s->d1->handshake_read_seq = 0;
-            /* next message is server hello */
-            s->d1->handshake_write_seq = 0;
-            s->d1->next_handshake_write_seq = 0;
-            goto end;
-            /* break; */
-
-        case SSL_ST_ERR:
-        default:
-            SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_UNKNOWN_STATE);
-            ret = -1;
-            goto end;
-            /* break; */
-        }
-
-        if (!s->s3->tmp.reuse_message && !skip) {
-            if (s->debug) {
-                if ((ret = BIO_flush(s->wbio)) <= 0)
-                    goto end;
-            }
-
-            if ((cb != NULL) && (s->state != state)) {
-                new_state = s->state;
-                s->state = state;
-                cb(s, SSL_CB_ACCEPT_LOOP, 1);
-                s->state = new_state;
-            }
-        }
-        skip = 0;
-    }
- end:
-    /* BIO_flush(s->wbio); */
-
-    s->in_handshake--;
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Notify SCTP BIO socket to leave handshake mode and prevent stream
-     * identifier other than 0. Will be ignored if no SCTP is used.
-     */
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-             s->in_handshake, NULL);
-#endif
-
-    if (cb != NULL)
-        cb(s, SSL_CB_ACCEPT_EXIT, ret);
-    return (ret);
-}
-
-unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
-                                            unsigned char *cookie,
-                                            unsigned char cookie_len)
-{
-    unsigned int msg_len;
-    unsigned char *p;
-
-    p = buf;
-    /* Always use DTLS 1.0 version: see RFC 6347 */
-    *(p++) = DTLS1_VERSION >> 8;
-    *(p++) = DTLS1_VERSION & 0xFF;
-
-    *(p++) = (unsigned char)cookie_len;
-    memcpy(p, cookie, cookie_len);
-    p += cookie_len;
-    msg_len = p - buf;
-
-    return msg_len;
-}
-
-
-int dtls1_send_hello_verify_request(SSL *s)
-{
-    unsigned int len;
-    unsigned char *buf;
-
-    if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) {
-        buf = (unsigned char *)s->init_buf->data;
-
-        if (s->ctx->app_gen_cookie_cb == NULL ||
-            s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
-                                      &(s->d1->cookie_len)) == 0 ||
-            s->d1->cookie_len > 255) {
-            SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
-                   SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
-            s->state = SSL_ST_ERR;
-            return 0;
-        }
-
-        len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
-                                             s->d1->cookie, s->d1->cookie_len);
-
-        dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
-                                 len);
-        len += DTLS1_HM_HEADER_LENGTH;
-
-        s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
-        /* number of bytes to write */
-        s->init_num = len;
-        s->init_off = 0;
-    }
-
-    /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
-    return (dtls1_do_write(s, SSL3_RT_HANDSHAKE));
-}
diff --git a/ssl/methods.c b/ssl/methods.c
new file mode 100644
index 0000000..3319119
--- /dev/null
+++ b/ssl/methods.c
@@ -0,0 +1,351 @@
+/* ssl/t1_meth.c */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+ 
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+/*
+ * TLS/SSLv3 methods
+ */
+
+static const SSL_METHOD *tls1_get_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_method());
+    else
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, tls1_get_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, tls1_get_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_method, ossl_statem_accept, ossl_statem_connect,
+                         tls1_get_method)
+#endif
+
+
+/*
+ * TLS/SSLv3 server methods
+ */
+
+static const SSL_METHOD *tls1_get_server_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_server_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_server_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_server_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_server_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_server_method());
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+                         ossl_statem_accept,
+                         ssl_undefined_function, tls1_get_server_method)
+#endif
+
+
+/*
+ * TLS/SSLv3 client methods
+ */
+
+static const SSL_METHOD *tls1_get_client_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_client_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_client_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_client_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_client_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_client_method());
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect,
+                        tls1_get_client_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect,
+                        tls1_get_client_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect,
+                        tls1_get_client_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect,
+                        tls1_get_client_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
+                         ssl_undefined_function,
+                         ossl_statem_connect, tls1_get_client_method)
+#endif
+
+
+/*
+ * DTLS methods
+ */
+static const SSL_METHOD *dtls1_get_method(int ver)
+{
+    if (ver == DTLS1_VERSION)
+        return (DTLSv1_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect,
+                          dtls1_get_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect,
+                          dtls1_get_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_method,
+                          ossl_statem_accept,
+                          ossl_statem_connect,
+                          dtls1_get_method, DTLSv1_2_enc_data)
+
+
+/*
+ * DTLS server methods
+ */
+
+static const SSL_METHOD *dtls1_get_server_method(int ver)
+{
+    if (ver == DTLS1_VERSION)
+        return (DTLSv1_server_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_server_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_server_method,
+                          ossl_statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_2_enc_data)
+
+
+/*
+ * DTLS client methods
+ */
+
+static const SSL_METHOD *dtls1_get_client_method(int ver)
+{
+    if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
+        return (DTLSv1_client_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_client_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect,
+                          dtls1_get_client_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect,
+                          dtls1_get_client_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_client_method,
+                          ssl_undefined_function,
+                          ossl_statem_connect,
+                          dtls1_get_client_method, DTLSv1_2_enc_data)
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index d7d0093..0133ae3 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -283,8 +283,8 @@ int dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
 #ifndef OPENSSL_NO_SCTP
     /* Store bio_dgram_sctp_rcvinfo struct */
     if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
-        (s->state == SSL3_ST_SR_FINISHED_A
-         || s->state == SSL3_ST_CR_FINISHED_A)) {
+        (SSL_get_state(s) == TLS_ST_SR_FINISHED
+         || SSL_get_state(s) == TLS_ST_CR_FINISHED)) {
         BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO,
                  sizeof(rdata->recordinfo), &rdata->recordinfo);
     }
@@ -439,13 +439,12 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * Continue handshake if it had to be interrupted to read app data with
      * SCTP.
      */
-    if ((!s->in_handshake && SSL_in_init(s)) ||
-        (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
-         (s->state == DTLS1_SCTP_ST_SR_READ_SOCK
-          || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)
+    if ((!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) ||
+        (BIO_dgram_is_sctp(SSL_get_rbio(s))
+         && ossl_statem_in_sctp_read_sock(s)
          && s->s3->in_read_app_data != 2))
 #else
-    if (!s->in_handshake && SSL_in_init(s))
+    if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s))
 #endif
     {
         /* type == SSL3_RT_APPLICATION_DATA */
@@ -473,7 +472,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * We are not handshaking and have no data yet, so process data buffered
      * during the last handshake in advance, if any.
      */
-    if (s->state == SSL_ST_OK && SSL3_RECORD_get_length(rr) == 0) {
+    if (SSL_is_init_finished(s) && SSL3_RECORD_get_length(rr) == 0) {
         pitem *item;
         item = pqueue_pop(s->rlayer.d->buffered_app_data.q);
         if (item) {
@@ -586,8 +585,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
          */
         if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
             SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA &&
-            (s->state == DTLS1_SCTP_ST_SR_READ_SOCK
-             || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)) {
+            ossl_statem_in_sctp_read_sock(s)) {
             s->rwstate = SSL_READING;
             BIO_clear_retry_flags(SSL_get_rbio(s));
             BIO_set_retry_read(SSL_get_rbio(s));
@@ -880,7 +878,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * Unexpected handshake message (Client Hello, or protocol violation)
      */
     if ((s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
-        !s->in_handshake) {
+        !ossl_statem_get_in_handshake(s)) {
         struct hm_header_st msg_hdr;
 
         /* this may just be a stale retransmit */
@@ -903,9 +901,9 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
             goto start;
         }
 
-        if (((s->state & SSL_ST_MASK) == SSL_ST_OK) &&
+        if (SSL_is_init_finished(s) &&
             !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) {
-            s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+            ossl_statem_set_in_init(s, 1);
             s->renegotiate = 1;
             s->new_session = 1;
         }
@@ -952,8 +950,8 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     case SSL3_RT_HANDSHAKE:
         /*
          * we already handled all of these, with the possible exception of
-         * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not
-         * happen when type != rr->type
+         * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
+         * that should not happen when type != rr->type
          */
         al = SSL_AD_UNEXPECTED_MESSAGE;
         SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
@@ -968,14 +966,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
          */
         if (s->s3->in_read_app_data &&
             (s->s3->total_renegotiations != 0) &&
-            (((s->state & SSL_ST_CONNECT) &&
-              (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
-              (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
-             ) || ((s->state & SSL_ST_ACCEPT) &&
-                   (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
-                   (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
-             )
-            )) {
+            ossl_statem_app_data_allowed(s)) {
             s->s3->in_read_app_data = 2;
             return (-1);
         } else {
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index f5dd27a..e59c203 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -459,7 +459,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
     tot = s->rlayer.wnum;
     s->rlayer.wnum = 0;
 
-    if (SSL_in_init(s) && !s->in_handshake) {
+    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {
         i = s->handshake_func(s);
         if (i < 0)
             return (i);
@@ -779,7 +779,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
      * Some servers hang if iniatial client hello is larger than 256 bytes
      * and record version number > TLS 1.0
      */
-    if (s->state == SSL3_ST_CW_CLNT_HELLO_B
+    if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
         && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
         *(p++) = 0x1;
     else
@@ -1025,7 +1025,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * Now s->rlayer.handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE.
      */
 
-    if (!s->in_handshake && SSL_in_init(s)) {
+    if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) {
         /* type == SSL3_RT_APPLICATION_DATA */
         i = s->handshake_func(s);
         if (i < 0)
@@ -1383,10 +1383,11 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     /*
      * Unexpected handshake message (Client Hello, or protocol violation)
      */
-    if ((s->rlayer.handshake_fragment_len >= 4) && !s->in_handshake) {
-        if (((s->state & SSL_ST_MASK) == SSL_ST_OK) &&
+    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)) {
-            s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+            ossl_statem_set_in_init(s, 1);
             s->renegotiate = 1;
             s->new_session = 1;
         }
@@ -1436,8 +1437,8 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     case SSL3_RT_HANDSHAKE:
         /*
          * we already handled all of these, with the possible exception of
-         * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not
-         * happen when type != rr->type
+         * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
+         * that should not happen when type != rr->type
          */
         al = SSL_AD_UNEXPECTED_MESSAGE;
         SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
@@ -1450,16 +1451,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
          * application data at this point (session renegotiation not yet
          * started), we will indulge it.
          */
-        if (s->s3->in_read_app_data &&
-            (s->s3->total_renegotiations != 0) &&
-            (((s->state & SSL_ST_CONNECT) &&
-              (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
-              (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
-             ) || ((s->state & SSL_ST_ACCEPT) &&
-                   (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
-                   (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
-             )
-            )) {
+        if (ossl_statem_app_data_allowed(s)) {
             s->s3->in_read_app_data = 2;
             return (-1);
         } else {
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 7383f13..86aaf4f 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -1528,7 +1528,7 @@ int dtls1_get_record(SSL *s)
      * processed at this time.
      */
     if (is_next_epoch) {
-        if ((SSL_in_init(s) || s->in_handshake)) {
+        if ((SSL_in_init(s) || ossl_statem_get_in_handshake(s))) {
             if (dtls1_buffer_record
                 (s, &(DTLS_RECORD_LAYER_get_unprocessed_rcds(&s->rlayer)),
                 rr->seq_num) < 0)
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 5e7b618..39d08a0 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -5014,7 +5014,7 @@ int ssl3_shutdown(SSL *s)
      * Don't do anything much if we have not done the handshake or we don't
      * want to send messages :-)
      */
-    if ((s->quiet_shutdown) || (s->state == SSL_ST_BEFORE)) {
+    if (s->quiet_shutdown || SSL_in_before(s)) {
         s->shutdown = (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
         return (1);
     }
@@ -5085,11 +5085,11 @@ static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
          * makes sense here; so disable handshake processing and try to read
          * application data again.
          */
-        s->in_handshake++;
+        ossl_statem_set_in_handshake(s, 1);
         ret =
             s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf,
                                       len, peek);
-        s->in_handshake--;
+        ossl_statem_set_in_handshake(s, 0);
     } else
         s->s3->in_read_app_data = 0;
 
@@ -5128,10 +5128,10 @@ int ssl3_renegotiate_check(SSL *s)
             && !SSL_in_init(s)) {
             /*
              * if we are the server, and we have sent a 'RENEGOTIATE'
-             * message, we need to go to SSL_ST_ACCEPT.
+             * message, we need to set the state machine into the renegotiate
+             * state.
              */
-            /* SSL_ST_ACCEPT */
-            s->state = SSL_ST_RENEGOTIATE;
+            ossl_statem_set_renegotiate(s);
             s->s3->renegotiate = 0;
             s->s3->num_renegotiations++;
             s->s3->total_renegotiations++;
diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c
index fcf4744..8d7f042 100644
--- a/ssl/s3_msg.c
+++ b/ssl/s3_msg.c
@@ -118,7 +118,7 @@ int ssl3_do_change_cipher_spec(SSL *s)
     const char *sender;
     int slen;
 
-    if (s->state & SSL_ST_ACCEPT)
+    if (s->server)
         i = SSL3_CHANGE_CIPHER_SERVER_READ;
     else
         i = SSL3_CHANGE_CIPHER_CLIENT_READ;
@@ -143,7 +143,7 @@ int ssl3_do_change_cipher_spec(SSL *s)
      * we have to record the message digest at this point so we can get it
      * before we read the finished message
      */
-    if (s->state & SSL_ST_CONNECT) {
+    if (!s->server) {
         sender = s->method->ssl3_enc->server_finished_label;
         slen = s->method->ssl3_enc->server_finished_label_len;
     } else {
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
deleted file mode 100644
index 376ab71..0000000
--- a/ssl/s3_srvr.c
+++ /dev/null
@@ -1,3534 +0,0 @@
-/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core at openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay at cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh at cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include "internal/constant_time_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/x509.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#include <openssl/md5.h>
-
-static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
-                                                      PACKET *cipher_suites,
-                                                      STACK_OF(SSL_CIPHER) **skp,
-                                                      int sslv2format, int *al);
-
-
-#ifndef OPENSSL_NO_SRP
-static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
-{
-    int ret = SSL_ERROR_NONE;
-
-    *al = SSL_AD_UNRECOGNIZED_NAME;
-
-    if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
-        (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) {
-        if (s->srp_ctx.login == NULL) {
-            /*
-             * RFC 5054 says SHOULD reject, we do so if There is no srp
-             * login name
-             */
-            ret = SSL3_AL_FATAL;
-            *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
-        } else {
-            ret = SSL_srp_server_param_with_username(s, al);
-        }
-    }
-    return ret;
-}
-#endif
-
-int ssl3_accept(SSL *s)
-{
-    BUF_MEM *buf;
-    unsigned long alg_k, Time = (unsigned long)time(NULL);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    int ret = -1;
-    int new_state, state, skip = 0;
-
-    RAND_add(&Time, sizeof(Time), 0);
-    ERR_clear_error();
-    clear_sys_error();
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    /* init things to blank */
-    s->in_handshake++;
-    if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
-            return -1;
-    }
-
-#ifndef OPENSSL_NO_HEARTBEATS
-    /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
-     */
-    if (s->tlsext_hb_pending) {
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
-    }
-#endif
-
-    for (;;) {
-        state = s->state;
-
-        switch (s->state) {
-        case SSL_ST_RENEGOTIATE:
-            s->renegotiate = 1;
-            /* s->state=SSL_ST_ACCEPT; */
-
-        case SSL_ST_BEFORE:
-        case SSL_ST_ACCEPT:
-        case SSL_ST_BEFORE | SSL_ST_ACCEPT:
-        case SSL_ST_OK | SSL_ST_ACCEPT:
-
-            s->server = 1;
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_START, 1);
-
-            if ((s->version >> 8 != 3) && s->version != TLS_ANY_VERSION) {
-                SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
-                s->state = SSL_ST_ERR;
-                return -1;
-            }
-
-            if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-                SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_VERSION_TOO_LOW);
-                return -1;
-            }
-
-            s->type = SSL_ST_ACCEPT;
-
-            if (s->init_buf == NULL) {
-                if ((buf = BUF_MEM_new()) == NULL) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-                    BUF_MEM_free(buf);
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-                s->init_buf = buf;
-            }
-
-            if (!ssl3_setup_buffers(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            s->init_num = 0;
-            s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
-            /*
-             * Should have been reset by ssl3_get_finished, too.
-             */
-            s->s3->change_cipher_spec = 0;
-
-            if (s->state != SSL_ST_RENEGOTIATE) {
-                /*
-                 * Ok, we now need to push on a buffering BIO so that the
-                 * output is sent in a way that TCP likes :-)
-                 */
-                if (!ssl_init_wbio_buffer(s, 1)) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-
-                ssl3_init_finished_mac(s);
-                s->state = SSL3_ST_SR_CLNT_HELLO_A;
-                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_SSL3_ACCEPT,
-                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            } else {
-                /*
-                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
-                 * HelloRequest
-                 */
-                s->ctx->stats.sess_accept_renegotiate++;
-                s->state = SSL3_ST_SW_HELLO_REQ_A;
-            }
-            break;
-
-        case SSL3_ST_SW_HELLO_REQ_A:
-        case SSL3_ST_SW_HELLO_REQ_B:
-
-            s->shutdown = 0;
-            ret = ssl3_send_hello_request(s);
-            if (ret <= 0)
-                goto end;
-            s->s3->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C;
-            s->state = SSL3_ST_SW_FLUSH;
-            s->init_num = 0;
-
-            ssl3_init_finished_mac(s);
-            break;
-
-        case SSL3_ST_SW_HELLO_REQ_C:
-            s->state = SSL_ST_OK;
-            break;
-
-        case SSL3_ST_SR_CLNT_HELLO_A:
-        case SSL3_ST_SR_CLNT_HELLO_B:
-        case SSL3_ST_SR_CLNT_HELLO_C:
-
-            ret = ssl3_get_client_hello(s);
-            if (ret <= 0)
-                goto end;
-#ifndef OPENSSL_NO_SRP
-            s->state = SSL3_ST_SR_CLNT_HELLO_D;
-        case SSL3_ST_SR_CLNT_HELLO_D:
-            {
-                int al;
-                if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) {
-                    /*
-                     * callback indicates firther work to be done
-                     */
-                    s->rwstate = SSL_X509_LOOKUP;
-                    goto end;
-                }
-                if (ret != SSL_ERROR_NONE) {
-                    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-                    /*
-                     * This is not really an error but the only means to for
-                     * a client to detect whether srp is supported.
-                     */
-                    if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
-                        SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_CLIENTHELLO_TLSEXT);
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-            }
-#endif
-
-            s->renegotiate = 2;
-            s->state = SSL3_ST_SW_SRVR_HELLO_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_SRVR_HELLO_A:
-        case SSL3_ST_SW_SRVR_HELLO_B:
-            ret = ssl3_send_server_hello(s);
-            if (ret <= 0)
-                goto end;
-
-            if (s->hit) {
-                if (s->tlsext_ticket_expected)
-                    s->state = SSL3_ST_SW_SESSION_TICKET_A;
-                else
-                    s->state = SSL3_ST_SW_CHANGE_A;
-            } else {
-                s->state = SSL3_ST_SW_CERT_A;
-            }
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_A:
-        case SSL3_ST_SW_CERT_B:
-            /* Check if it is anon DH or anon ECDH, */
-            /* normal PSK or SRP */
-            if (!(s->s3->tmp.new_cipher->algorithm_auth &
-                 (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                ret = ssl3_send_server_certificate(s);
-                if (ret <= 0)
-                    goto end;
-
-                if (s->tlsext_status_expected)
-                    s->state = SSL3_ST_SW_CERT_STATUS_A;
-                else
-                    s->state = SSL3_ST_SW_KEY_EXCH_A;
-            } else {
-                skip = 1;
-                s->state = SSL3_ST_SW_KEY_EXCH_A;
-            }
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_KEY_EXCH_A:
-        case SSL3_ST_SW_KEY_EXCH_B:
-            alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-            /*
-             * clear this, it may get reset by
-             * send_server_key_exchange
-             */
-            s->s3->tmp.use_rsa_tmp = 0;
-
-            /*
-             * only send if a DH key exchange, fortezza or RSA but we have a
-             * sign only certificate PSK: may send PSK identity hints For
-             * ECC ciphersuites, we send a serverKeyExchange message only if
-             * the cipher suite is either ECDH-anon or ECDHE. In other cases,
-             * the server certificate contains the server's public key for
-             * key exchange.
-             */
-            if (0
-                /*
-                 * PSK: send ServerKeyExchange if PSK identity hint if
-                 * provided
-                 */
-#ifndef OPENSSL_NO_PSK
-                /* Only send SKE if we have identity hint for plain PSK */
-                || ((alg_k & (SSL_kPSK | SSL_kRSAPSK)) && s->cert->psk_identity_hint)
-                /* For other PSK always send SKE */
-                || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
-#endif
-#ifndef OPENSSL_NO_SRP
-                /* SRP: send ServerKeyExchange */
-                || (alg_k & SSL_kSRP)
-#endif
-                || (alg_k & SSL_kDHE)
-                || (alg_k & SSL_kECDHE)
-                || ((alg_k & SSL_kRSA)
-                    && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
-                        || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
-                            && EVP_PKEY_size(s->cert->pkeys
-                                             [SSL_PKEY_RSA_ENC].privatekey) *
-                            8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
-                        )
-                    )
-                )
-                ) {
-                ret = ssl3_send_server_key_exchange(s);
-                if (ret <= 0)
-                    goto end;
-            } else
-                skip = 1;
-
-            s->state = SSL3_ST_SW_CERT_REQ_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_REQ_A:
-        case SSL3_ST_SW_CERT_REQ_B:
-            if (                /* don't request cert unless asked for it: */
-                   !(s->verify_mode & SSL_VERIFY_PEER) ||
-                   /*
-                    * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
-                    * during re-negotiation:
-                    */
-                   ((s->session->peer != NULL) &&
-                    (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
-                   /*
-                    * never request cert in anonymous ciphersuites (see
-                    * section "Certificate request" in SSL 3 drafts and in
-                    * RFC 2246):
-                    */
-                   ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
-                   /*
-                    * ... except when the application insists on
-                    * verification (against the specs, but s3_clnt.c accepts
-                    * this for SSL 3)
-                    */
-                   !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
-                   /* don't request certificate for SRP auth */
-                   (s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
-                   /*
-                    * With normal PSK Certificates and Certificate Requests
-                    * are omitted
-                    */
-                   || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-                /* no cert request */
-                skip = 1;
-                s->s3->tmp.cert_request = 0;
-                s->state = SSL3_ST_SW_SRVR_DONE_A;
-                if (!ssl3_digest_cached_records(s, 0)) {
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-            } else {
-                s->s3->tmp.cert_request = 1;
-                ret = ssl3_send_certificate_request(s);
-                if (ret <= 0)
-                    goto end;
-                s->state = SSL3_ST_SW_SRVR_DONE_A;
-                s->init_num = 0;
-            }
-            break;
-
-        case SSL3_ST_SW_SRVR_DONE_A:
-        case SSL3_ST_SW_SRVR_DONE_B:
-            ret = ssl3_send_server_done(s);
-            if (ret <= 0)
-                goto end;
-            s->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
-            s->state = SSL3_ST_SW_FLUSH;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_FLUSH:
-
-            /*
-             * This code originally checked to see if any data was pending
-             * using BIO_CTRL_INFO and then flushed. This caused problems as
-             * documented in PR#1939. The proposed fix doesn't completely
-             * resolve this issue as buggy implementations of
-             * BIO_CTRL_PENDING still exist. So instead we just flush
-             * unconditionally.
-             */
-
-            s->rwstate = SSL_WRITING;
-            if (BIO_flush(s->wbio) <= 0) {
-                ret = -1;
-                goto end;
-            }
-            s->rwstate = SSL_NOTHING;
-
-            s->state = s->s3->tmp.next_state;
-            break;
-
-        case SSL3_ST_SR_CERT_A:
-        case SSL3_ST_SR_CERT_B:
-            if (s->s3->tmp.cert_request) {
-                ret = ssl3_get_client_certificate(s);
-                if (ret <= 0)
-                    goto end;
-            }
-            s->init_num = 0;
-            s->state = SSL3_ST_SR_KEY_EXCH_A;
-            break;
-
-        case SSL3_ST_SR_KEY_EXCH_A:
-        case SSL3_ST_SR_KEY_EXCH_B:
-            ret = ssl3_get_client_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-            if (ret == 2) {
-                /*
-                 * For the ECDH ciphersuites when the client sends its ECDH
-                 * pub key in a certificate, the CertificateVerify message is
-                 * not sent. Also for GOST ciphersuites when the client uses
-                 * its key from the certificate for key exchange.
-                 */
-                s->state = SSL3_ST_SR_CHANGE_A;
-                s->init_num = 0;
-            } else if (SSL_USE_SIGALGS(s)) {
-                s->state = SSL3_ST_SR_CERT_VRFY_A;
-                s->init_num = 0;
-                if (!s->session->peer)
-                    break;
-                if (!s->s3->handshake_buffer) {
-                    SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-                /*
-                 * For sigalgs freeze the handshake buffer. If we support
-                 * extms we've done this already so this is a no-op
-                 */
-                if (!ssl3_digest_cached_records(s, 1)) {
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-            } else {
-                int offset = 0;
-                int dgst_num;
-
-                s->state = SSL3_ST_SR_CERT_VRFY_A;
-                s->init_num = 0;
-
-                /*
-                 * We need to get hashes here so if there is a client cert,
-                 * it can be verified FIXME - digest processing for
-                 * CertificateVerify should be generalized. But it is next
-                 * step
-                 */
-                if (!ssl3_digest_cached_records(s, 0)) {
-                    s->state = SSL_ST_ERR;
-                    return -1;
-                }
-                for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++)
-                    if (s->s3->handshake_dgst[dgst_num]) {
-                        int dgst_size;
-
-                        s->method->ssl3_enc->cert_verify_mac(s,
-                                                             EVP_MD_CTX_type
-                                                             (s->
-                                                              s3->handshake_dgst
-                                                              [dgst_num]),
-                                                             &(s->s3->
-                                                               tmp.cert_verify_md
-                                                               [offset]));
-                        dgst_size =
-                            EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
-                        if (dgst_size < 0) {
-                            s->state = SSL_ST_ERR;
-                            ret = -1;
-                            goto end;
-                        }
-                        offset += dgst_size;
-                    }
-            }
-            break;
-
-        case SSL3_ST_SR_CERT_VRFY_A:
-        case SSL3_ST_SR_CERT_VRFY_B:
-            ret = ssl3_get_cert_verify(s);
-            if (ret <= 0)
-                goto end;
-
-            s->state = SSL3_ST_SR_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-        case SSL3_ST_SR_NEXT_PROTO_A:
-        case SSL3_ST_SR_NEXT_PROTO_B:
-            ret = ssl3_get_next_proto(s);
-            if (ret <= 0)
-                goto end;
-            s->init_num = 0;
-            s->state = SSL3_ST_SR_FINISHED_A;
-            break;
-#endif
-
-
-        case SSL3_ST_SR_CHANGE_A:
-        case SSL3_ST_SR_CHANGE_B:
-            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_SR_CHANGE_A,
-                                              SSL3_ST_SR_CHANGE_B);
-            if (ret <= 0)
-                goto end;
-
-#if defined(OPENSSL_NO_NEXTPROTONEG)
-            s->state = SSL3_ST_SR_FINISHED_A;
-#else
-            if (s->s3->next_proto_neg_seen)
-                s->state = SSL3_ST_SR_NEXT_PROTO_A;
-            else
-                s->state = SSL3_ST_SR_FINISHED_A;
-#endif
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SR_FINISHED_A:
-        case SSL3_ST_SR_FINISHED_B:
-            ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
-                                    SSL3_ST_SR_FINISHED_B);
-            if (ret <= 0)
-                goto end;
-            if (s->hit)
-                s->state = SSL_ST_OK;
-            else if (s->tlsext_ticket_expected)
-                s->state = SSL3_ST_SW_SESSION_TICKET_A;
-            else
-                s->state = SSL3_ST_SW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_SESSION_TICKET_A:
-        case SSL3_ST_SW_SESSION_TICKET_B:
-            ret = ssl3_send_newsession_ticket(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CERT_STATUS_A:
-        case SSL3_ST_SW_CERT_STATUS_B:
-            ret = ssl3_send_cert_status(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_SW_CHANGE_A:
-        case SSL3_ST_SW_CHANGE_B:
-
-            s->session->cipher = s->s3->tmp.new_cipher;
-            if (!s->method->ssl3_enc->setup_key_block(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            ret = ssl3_send_change_cipher_spec(s,
-                                               SSL3_ST_SW_CHANGE_A,
-                                               SSL3_ST_SW_CHANGE_B);
-
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_FINISHED_A;
-            s->init_num = 0;
-
-            if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                          SSL3_CHANGE_CIPHER_SERVER_WRITE))
-            {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-
-            break;
-
-        case SSL3_ST_SW_FINISHED_A:
-        case SSL3_ST_SW_FINISHED_B:
-            ret = ssl3_send_finished(s,
-                                     SSL3_ST_SW_FINISHED_A,
-                                     SSL3_ST_SW_FINISHED_B,
-                                     s->method->
-                                     ssl3_enc->server_finished_label,
-                                     s->method->
-                                     ssl3_enc->server_finished_label_len);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_SW_FLUSH;
-            if (s->hit) {
-                s->s3->tmp.next_state = SSL3_ST_SR_CHANGE_A;
-            } else
-                s->s3->tmp.next_state = SSL_ST_OK;
-            s->init_num = 0;
-            break;
-
-        case SSL_ST_OK:
-            /* clean a few things up */
-            ssl3_cleanup_key_block(s);
-
-            BUF_MEM_free(s->init_buf);
-            s->init_buf = NULL;
-
-            /* remove buffering on output */
-            ssl_free_wbio_buffer(s);
-
-            s->init_num = 0;
-
-            if (s->renegotiate == 2) { /* skipped if we just sent a
-                                        * HelloRequest */
-                s->renegotiate = 0;
-                s->new_session = 0;
-
-                ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
-
-                s->ctx->stats.sess_accept_good++;
-                /* s->server=1; */
-                s->handshake_func = ssl3_accept;
-
-                if (cb != NULL)
-                    cb(s, SSL_CB_HANDSHAKE_DONE, 1);
-            }
-
-            ret = 1;
-            goto end;
-            /* break; */
-
-        case SSL_ST_ERR:
-        default:
-            SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNKNOWN_STATE);
-            ret = -1;
-            goto end;
-            /* break; */
-        }
-
-        if (!s->s3->tmp.reuse_message && !skip) {
-            if (s->debug) {
-                if ((ret = BIO_flush(s->wbio)) <= 0)
-                    goto end;
-            }
-
-            if ((cb != NULL) && (s->state != state)) {
-                new_state = s->state;
-                s->state = state;
-                cb(s, SSL_CB_ACCEPT_LOOP, 1);
-                s->state = new_state;
-            }
-        }
-        skip = 0;
-    }
- end:
-    /* BIO_flush(s->wbio); */
-
-    s->in_handshake--;
-    if (cb != NULL)
-        cb(s, SSL_CB_ACCEPT_EXIT, ret);
-    return (ret);
-}
-
-int ssl3_send_hello_request(SSL *s)
-{
-
-    if (s->state == SSL3_ST_SW_HELLO_REQ_A) {
-        if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) {
-            SSLerr(SSL_F_SSL3_SEND_HELLO_REQUEST, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        s->state = SSL3_ST_SW_HELLO_REQ_B;
-    }
-
-    /* SSL3_ST_SW_HELLO_REQ_B */
-    return ssl_do_write(s);
-}
-
-int ssl3_get_client_hello(SSL *s)
-{
-    int i, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
-    unsigned int j, complen = 0;
-    long n;
-    unsigned long id;
-    SSL_CIPHER *c;
-#ifndef OPENSSL_NO_COMP
-    SSL_COMP *comp = NULL;
-#endif
-    STACK_OF(SSL_CIPHER) *ciphers = NULL;
-    int protverr = 1;
-    /* |cookie| will only be initialized for DTLS. */
-    PACKET pkt, session_id, cipher_suites, compression, extensions, cookie;
-    int is_v2_record;
-
-    if (s->state == SSL3_ST_SR_CLNT_HELLO_C && !s->first_packet)
-        goto retry_cert;
-
-    /*
-     * We do this so that we will respond with our native type. If we are
-     * TLSv1 and we get SSLv3, we will respond with TLSv1, This down
-     * switching should be handled by a different method. If we are SSLv3, we
-     * will respond with SSLv3, even if prompted with TLSv1.
-     */
-    if (s->state == SSL3_ST_SR_CLNT_HELLO_A) {
-        s->state = SSL3_ST_SR_CLNT_HELLO_B;
-    }
-    s->first_packet = 1;
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_SR_CLNT_HELLO_B,
-                                   SSL3_ST_SR_CLNT_HELLO_C,
-                                   SSL3_MT_CLIENT_HELLO,
-                                   SSL3_RT_MAX_PLAIN_LENGTH, &ok);
-
-    if (!ok)
-        return ((int)n);
-    s->first_packet = 0;
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-        al = SSL_AD_INTERNAL_ERROR;
-        goto f_err;
-    }
-
-    is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer);
-
-    PACKET_null_init(&cookie);
-    /* First lets get s->client_version set correctly */
-    if (is_v2_record) {
-        unsigned int version;
-        unsigned int mt;
-        /*-
-         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
-         * header is sent directly on the wire, not wrapped as a TLS
-         * record. Our record layer just processes the message length and passes
-         * the rest right through. Its format is:
-         * Byte  Content
-         * 0-1   msg_length - decoded by the record layer
-         * 2     msg_type - s->init_msg points here
-         * 3-4   version
-         * 5-6   cipher_spec_length
-         * 7-8   session_id_length
-         * 9-10  challenge_length
-         * ...   ...
-         */
-
-        if (!PACKET_get_1(&pkt, &mt)
-                || mt != SSL2_MT_CLIENT_HELLO) {
-            /*
-             * Should never happen. We should have tested this in the record
-             * layer in order to have determined that this is a SSLv2 record
-             * in the first place
-             */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (!PACKET_get_net_2(&pkt, &version)) {
-            /* No protocol version supplied! */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        }
-        if (version == 0x0002) {
-            /* This is real SSLv2. We don't support it. */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) {
-            /* SSLv3/TLS */
-            s->client_version = version;
-        } else {
-            /* No idea what protocol this is */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        }
-    } else {
-        /*
-         * use version from inside client hello, not from record header (may
-         * differ: see RFC 2246, Appendix E, second paragraph)
-         */
-        if(!PACKET_get_net_2(&pkt, (unsigned int *)&s->client_version)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-    }
-
-    /* Do SSL/TLS version negotiation if applicable */
-    if (!SSL_IS_DTLS(s)) {
-        if (s->version != TLS_ANY_VERSION) {
-            if (s->client_version >= s->version) {
-                protverr = 0;
-            }
-        } else if (s->client_version >= SSL3_VERSION) {
-            switch(s->client_version) {
-            default:
-            case TLS1_2_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_2)) {
-                    s->version = TLS1_2_VERSION;
-                    s->method = TLSv1_2_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_1)) {
-                    s->version = TLS1_1_VERSION;
-                    s->method = TLSv1_1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1)) {
-                    s->version = TLS1_VERSION;
-                    s->method = TLSv1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case SSL3_VERSION:
-#ifndef OPENSSL_NO_SSL3
-                if(!(s->options & SSL_OP_NO_SSLv3)) {
-                    s->version = SSL3_VERSION;
-                    s->method = SSLv3_server_method();
-                    protverr = 0;
-                    break;
-                }
-#else
-                break;
-#endif
-            }
-        }
-    } else if (s->client_version <= s->version
-                || s->method->version == DTLS_ANY_VERSION) {
-        /*
-         * For DTLS we just check versions are potentially compatible. Version
-         * negotiation comes later.
-         */
-        protverr = 0;
-    }
-
-    if (protverr) {
-        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-        if ((!s->enc_write_ctx && !s->write_hash)) {
-            /*
-             * similar to ssl3_get_record, send alert using remote version
-             * number
-             */
-            s->version = s->client_version;
-        }
-        al = SSL_AD_PROTOCOL_VERSION;
-        goto f_err;
-    }
-
-    /* Parse the message and load client random. */
-    if (is_v2_record) {
-        /*
-         * Handle an SSLv2 backwards compatible ClientHello
-         * Note, this is only for SSLv3+ using the backward compatible format.
-         * Real SSLv2 is not supported, and is rejected above.
-         */
-        unsigned int cipher_len, session_id_len, challenge_len;
-        PACKET challenge;
-
-        if (!PACKET_get_net_2(&pkt, &cipher_len)
-                || !PACKET_get_net_2(&pkt, &session_id_len)
-                || !PACKET_get_net_2(&pkt, &challenge_len)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-
-        if (!PACKET_get_sub_packet(&pkt, &cipher_suites, cipher_len)
-            || !PACKET_get_sub_packet(&pkt, &session_id, session_id_len)
-            || !PACKET_get_sub_packet(&pkt, &challenge, challenge_len)
-            /* No extensions. */
-            || PACKET_remaining(&pkt) != 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-
-        /* Load the client random */
-        challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE :
-            challenge_len;
-        memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE);
-        if (!PACKET_copy_bytes(&challenge,
-                               s->s3->client_random + SSL3_RANDOM_SIZE -
-                               challenge_len, challenge_len)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        PACKET_null_init(&compression);
-        PACKET_null_init(&extensions);
-    } else {
-        /* Regular ClientHello. */
-        if (!PACKET_copy_bytes(&pkt, s->s3->client_random, SSL3_RANDOM_SIZE)
-            || !PACKET_get_length_prefixed_1(&pkt, &session_id)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if (SSL_IS_DTLS(s)) {
-            if (!PACKET_get_length_prefixed_1(&pkt, &cookie)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-                goto f_err;
-            }
-            /*
-             * If we require cookies and this ClientHello doesn't contain one,
-             * just return since we do not want to allocate any memory yet.
-             * So check cookie length...
-             */
-            if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
-                if (PACKET_remaining(&cookie) == 0)
-                return 1;
-            }
-        }
-
-        if (!PACKET_get_length_prefixed_2(&pkt, &cipher_suites)
-            || !PACKET_get_length_prefixed_1(&pkt, &compression)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-                goto f_err;
-        }
-        /* Could be empty. */
-        extensions = pkt;
-    }
-
-    s->hit = 0;
-
-    /*
-     * We don't allow resumption in a backwards compatible ClientHello.
-     * TODO(openssl-team): in TLS1.1+, session_id MUST be empty.
-     *
-     * Versions before 0.9.7 always allow clients to resume sessions in
-     * renegotiation. 0.9.7 and later allow this by default, but optionally
-     * ignore resumption requests with flag
-     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
-     * than a change to default behavior so that applications relying on
-     * this for security won't even compile against older library versions).
-     * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to
-     * request renegotiation but not a new session (s->new_session remains
-     * unset): for servers, this essentially just means that the
-     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
-     * ignored.
-     */
-    if (is_v2_record ||
-        (s->new_session &&
-         (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
-        if (!ssl_get_new_session(s, 1))
-            goto err;
-    } else {
-        i = ssl_get_prev_session(s, &extensions, &session_id);
-        /*
-         * 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) {
-            /* previous session */
-            s->hit = 1;
-        } else if (i == -1) {
-            goto err;
-        } else {
-            /* i == 0 */
-            if (!ssl_get_new_session(s, 1))
-                goto err;
-        }
-    }
-
-    if (SSL_IS_DTLS(s)) {
-	/* Empty cookie was already handled above by returning early. */
-        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
-            if (s->ctx->app_verify_cookie_cb != NULL) {
-                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
-                                                 PACKET_remaining(&cookie)) == 0) {
-                    al = SSL_AD_HANDSHAKE_FAILURE;
-                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                           SSL_R_COOKIE_MISMATCH);
-                    goto f_err;
-                    /* else cookie verification succeeded */
-                }
-            /* default verification */
-            } else if (!PACKET_equal(&cookie, s->d1->cookie,
-                                     s->d1->cookie_len)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
-                goto f_err;
-            }
-            /* Set to -2 so if successful we return 2 */
-            ret = -2;
-        }
-        if (s->method->version == DTLS_ANY_VERSION) {
-            /* Select version to use */
-            if (s->client_version <= DTLS1_2_VERSION &&
-                !(s->options & SSL_OP_NO_DTLSv1_2)) {
-                s->version = DTLS1_2_VERSION;
-                s->method = DTLSv1_2_server_method();
-            } else if (tls1_suiteb(s)) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            } else if (s->client_version <= DTLS1_VERSION &&
-                       !(s->options & SSL_OP_NO_DTLSv1)) {
-                s->version = DTLS1_VERSION;
-                s->method = DTLSv1_server_method();
-            } else {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                       SSL_R_WRONG_VERSION_NUMBER);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->session->ssl_version = s->version;
-        }
-    }
-
-    if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers),
-                                 is_v2_record, &al) == NULL) {
-        goto f_err;
-    }
-
-    /* If it is a hit, check that the cipher is in the list */
-    if (s->hit) {
-        j = 0;
-        id = s->session->cipher->id;
-
-#ifdef CIPHER_DEBUG
-        fprintf(stderr, "client sent %d ciphers\n",
-                sk_SSL_CIPHER_num(ciphers));
-#endif
-        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
-            c = sk_SSL_CIPHER_value(ciphers, i);
-#ifdef CIPHER_DEBUG
-            fprintf(stderr, "client [%2d of %2d]:%s\n",
-                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
-#endif
-            if (c->id == id) {
-                j = 1;
-                break;
-            }
-        }
-        if (j == 0) {
-            /*
-             * we need to have the cipher in the cipher list if we are asked
-             * to reuse it
-             */
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                   SSL_R_REQUIRED_CIPHER_MISSING);
-            goto f_err;
-        }
-    }
-
-    complen = PACKET_remaining(&compression);
-    for (j = 0; j < complen; j++) {
-        if (PACKET_data(&compression)[j] == 0)
-            break;
-    }
-
-    if (j >= complen) {
-        /* no compress */
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED);
-        goto f_err;
-    }
-    
-    /* TLS extensions */
-    if (s->version >= SSL3_VERSION) {
-        if (!ssl_parse_clienthello_tlsext(s, &extensions)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
-            goto 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
-     * calling tls_session_secret_cb in order to allow SessionTicket
-     * processing to use it in key derivation.
-     */
-    {
-        unsigned char *pos;
-        pos = s->s3->server_random;
-        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
-            goto f_err;
-        }
-    }
-
-    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-        SSL_CIPHER *pref_cipher = NULL;
-
-        s->session->master_key_length = sizeof(s->session->master_key);
-        if (s->tls_session_secret_cb(s, s->session->master_key,
-                                     &s->session->master_key_length, ciphers,
-                                     &pref_cipher,
-                                     s->tls_session_secret_cb_arg)) {
-            s->hit = 1;
-            s->session->ciphers = ciphers;
-            s->session->verify_result = X509_V_OK;
-
-            ciphers = NULL;
-
-            /* check if some cipher was preferred by call back */
-            pref_cipher =
-                pref_cipher ? pref_cipher : ssl3_choose_cipher(s,
-                                                               s->
-                                                               session->ciphers,
-                                                               SSL_get_ciphers
-                                                               (s));
-            if (pref_cipher == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-                goto f_err;
-            }
-
-            s->session->cipher = pref_cipher;
-            sk_SSL_CIPHER_free(s->cipher_list);
-            s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-            sk_SSL_CIPHER_free(s->cipher_list_by_id);
-            s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-        }
-    }
-
-    /*
-     * Worst case, we will use the NULL compression, but if we have other
-     * options, we will now look for them.  We have complen-1 compression
-     * algorithms from the client, starting at q.
-     */
-    s->s3->tmp.new_compression = NULL;
-#ifndef OPENSSL_NO_COMP
-    /* This only happens if we have a cache hit */
-    if (s->session->compress_meth != 0) {
-        int m, comp_id = s->session->compress_meth;
-        unsigned int k;
-        /* Perform sanity checks on resumed compression algorithm */
-        /* Can't disable compression */
-        if (!ssl_allow_compression(s)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                   SSL_R_INCONSISTENT_COMPRESSION);
-            goto f_err;
-        }
-        /* Look for resumed compression method */
-        for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) {
-            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
-            if (comp_id == comp->id) {
-                s->s3->tmp.new_compression = comp;
-                break;
-            }
-        }
-        if (s->s3->tmp.new_compression == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                   SSL_R_INVALID_COMPRESSION_ALGORITHM);
-            goto f_err;
-        }
-        /* Look for resumed method in compression list */
-        for (k = 0; k < complen; k++) {
-            if (PACKET_data(&compression)[k] == comp_id)
-                break;
-        }
-        if (k >= complen) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                   SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
-            goto f_err;
-        }
-    } else if (s->hit)
-        comp = NULL;
-    else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
-        /* See if we have a match */
-        int m, nn, v, done = 0;
-        unsigned int o;
-
-        nn = sk_SSL_COMP_num(s->ctx->comp_methods);
-        for (m = 0; m < nn; m++) {
-            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
-            v = comp->id;
-            for (o = 0; o < complen; o++) {
-                if (v == PACKET_data(&compression)[o]) {
-                    done = 1;
-                    break;
-                }
-            }
-            if (done)
-                break;
-        }
-        if (done)
-            s->s3->tmp.new_compression = comp;
-        else
-            comp = NULL;
-    }
-#else
-    /*
-     * If compression is disabled we'd better not try to resume a session
-     * using compression.
-     */
-    if (s->session->compress_meth != 0) {
-        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
-        goto f_err;
-    }
-#endif
-
-    /*
-     * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
-     */
-
-    if (!s->hit) {
-#ifdef OPENSSL_NO_COMP
-        s->session->compress_meth = 0;
-#else
-        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
-#endif
-        sk_SSL_CIPHER_free(s->session->ciphers);
-        s->session->ciphers = ciphers;
-        if (ciphers == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        ciphers = NULL;
-        if (!tls1_set_server_sigalgs(s)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-            goto err;
-        }
-        /* Let cert callback update server certificates if required */
- retry_cert:
-        if (s->cert->cert_cb) {
-            int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
-            if (rv == 0) {
-                al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CERT_CB_ERROR);
-                goto f_err;
-            }
-            if (rv < 0) {
-                s->rwstate = SSL_X509_LOOKUP;
-                return -1;
-            }
-            s->rwstate = SSL_NOTHING;
-        }
-        c = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-
-        if (c == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-            goto f_err;
-        }
-        s->s3->tmp.new_cipher = c;
-        /* check whether we should disable session resumption */
-        if (s->not_resumable_session_cb != NULL)
-            s->session->not_resumable = s->not_resumable_session_cb(s,
-                                                                    ((c->algorithm_mkey & (SSL_kDHE | SSL_kECDHE))
-                                                                     != 0));
-        if (s->session->not_resumable)
-            /* do not send a session ticket */
-            s->tlsext_ticket_expected = 0;
-    } else {
-        /* Session-id reuse */
-        s->s3->tmp.new_cipher = s->session->cipher;
-    }
-
-    if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
-        if (!ssl3_digest_cached_records(s, 0))
-            goto f_err;
-    }
-
-    /*-
-     * we now have the following setup.
-     * client_random
-     * cipher_list          - our prefered list of ciphers
-     * ciphers              - the clients prefered list of ciphers
-     * compression          - basically ignored right now
-     * ssl version is set   - sslv3
-     * s->session           - The ssl session has been setup.
-     * s->hit               - session reuse flag
-     * s->s3->tmp.new_cipher- the new cipher to use.
-     */
-
-    /* Handles TLS extensions that we couldn't check earlier */
-    if (s->version >= SSL3_VERSION) {
-        if (ssl_check_clienthello_tlsext_late(s) <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-            goto err;
-        }
-    }
-
-    if (ret < 0)
-        ret = -ret;
-    if (0) {
- f_err:
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-        s->state = SSL_ST_ERR;
-    }
-
-    sk_SSL_CIPHER_free(ciphers);
-    return ret < 0 ? -1 : ret;
-}
-
-int ssl3_send_server_hello(SSL *s)
-{
-    unsigned char *buf;
-    unsigned char *p, *d;
-    int i, sl;
-    int al = 0;
-    unsigned long l;
-
-    if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
-        buf = (unsigned char *)s->init_buf->data;
-
-        /* Do the message type and length last */
-        d = p = ssl_handshake_start(s);
-
-        *(p++) = s->version >> 8;
-        *(p++) = s->version & 0xff;
-
-        /*
-         * Random stuff. Filling of the server_random takes place in
-         * ssl3_get_client_hello()
-         */
-        memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
-        p += SSL3_RANDOM_SIZE;
-
-        /*-
-         * There are several cases for the session ID to send
-         * back in the server hello:
-         * - For session reuse from the session cache,
-         *   we send back the old session ID.
-         * - If stateless session reuse (using a session ticket)
-         *   is successful, we send back the client's "session ID"
-         *   (which doesn't actually identify the session).
-         * - If it is a new session, we send back the new
-         *   session ID.
-         * - However, if we want the new session to be single-use,
-         *   we send back a 0-length session ID.
-         * s->hit is non-zero in either case of session reuse,
-         * so the following won't overwrite an ID that we're supposed
-         * to send back.
-         */
-        if (s->session->not_resumable ||
-            (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
-             && !s->hit))
-            s->session->session_id_length = 0;
-
-        sl = s->session->session_id_length;
-        if (sl > (int)sizeof(s->session->session_id)) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-        *(p++) = sl;
-        memcpy(p, s->session->session_id, sl);
-        p += sl;
-
-        /* put the cipher */
-        i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p);
-        p += i;
-
-        /* put the compression method */
-#ifdef OPENSSL_NO_COMP
-        *(p++) = 0;
-#else
-        if (s->s3->tmp.new_compression == NULL)
-            *(p++) = 0;
-        else
-            *(p++) = s->s3->tmp.new_compression->id;
-#endif
-
-        if (ssl_prepare_serverhello_tlsext(s) <= 0) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-        if ((p =
-             ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
-                                        &al)) == NULL) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, al);
-            SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-
-        /* do the header */
-        l = (p - d);
-        if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        s->state = SSL3_ST_SW_SRVR_HELLO_B;
-    }
-
-    /* SSL3_ST_SW_SRVR_HELLO_B */
-    return ssl_do_write(s);
-}
-
-int ssl3_send_server_done(SSL *s)
-{
-
-    if (s->state == SSL3_ST_SW_SRVR_DONE_A) {
-        if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_DONE, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        s->state = SSL3_ST_SW_SRVR_DONE_B;
-    }
-
-    /* SSL3_ST_SW_SRVR_DONE_B */
-    return ssl_do_write(s);
-}
-
-int ssl3_send_server_key_exchange(SSL *s)
-{
-#ifndef OPENSSL_NO_RSA
-    unsigned char *q;
-    int j, num;
-    RSA *rsa;
-    unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
-    unsigned int u;
-#endif
-#ifndef OPENSSL_NO_DH
-    DH *dh = NULL, *dhp;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *ecdh = NULL, *ecdhp;
-    unsigned char *encodedPoint = NULL;
-    int encodedlen = 0;
-    int curve_id = 0;
-    BN_CTX *bn_ctx = NULL;
-#endif
-    EVP_PKEY *pkey;
-    const EVP_MD *md = NULL;
-    unsigned char *p, *d;
-    int al, i;
-    unsigned long type;
-    int n;
-    CERT *cert;
-    BIGNUM *r[4];
-    int nr[4], kn;
-    BUF_MEM *buf;
-    EVP_MD_CTX md_ctx;
-
-    EVP_MD_CTX_init(&md_ctx);
-    if (s->state == SSL3_ST_SW_KEY_EXCH_A) {
-        type = s->s3->tmp.new_cipher->algorithm_mkey;
-        cert = s->cert;
-
-        buf = s->init_buf;
-
-        r[0] = r[1] = r[2] = r[3] = NULL;
-        n = 0;
-#ifndef OPENSSL_NO_PSK
-        if (type & SSL_PSK) {
-            /*
-             * reserve size for record length and PSK identity hint
-             */
-            n += 2;
-            if (s->cert->psk_identity_hint)
-                n += strlen(s->cert->psk_identity_hint);
-        }
-        /* Plain PSK or RSAPSK nothing to do */
-        if (type & (SSL_kPSK | SSL_kRSAPSK)) {
-        } else
-#endif                          /* !OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_RSA
-        if (type & SSL_kRSA) {
-            rsa = cert->rsa_tmp;
-            if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) {
-                rsa = s->cert->rsa_tmp_cb(s,
-                                          SSL_C_IS_EXPORT(s->s3->
-                                                          tmp.new_cipher),
-                                          SSL_C_EXPORT_PKEYLENGTH(s->s3->
-                                                                  tmp.new_cipher));
-                if (rsa == NULL) {
-                    al = SSL_AD_HANDSHAKE_FAILURE;
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                           SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
-                    goto f_err;
-                }
-                RSA_up_ref(rsa);
-                cert->rsa_tmp = rsa;
-            }
-            if (rsa == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_RSA_KEY);
-                goto f_err;
-            }
-            r[0] = rsa->n;
-            r[1] = rsa->e;
-            s->s3->tmp.use_rsa_tmp = 1;
-        } else
-#endif
-#ifndef OPENSSL_NO_DH
-        if (type & (SSL_kDHE | SSL_kDHEPSK)) {
-            if (s->cert->dh_tmp_auto) {
-                dhp = ssl_get_auto_dh(s);
-                if (dhp == NULL) {
-                    al = SSL_AD_INTERNAL_ERROR;
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto f_err;
-                }
-            } else
-                dhp = cert->dh_tmp;
-            if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
-                dhp = s->cert->dh_tmp_cb(s,
-                                         SSL_C_IS_EXPORT(s->s3->
-                                                         tmp.new_cipher),
-                                         SSL_C_EXPORT_PKEYLENGTH(s->s3->
-                                                                 tmp.new_cipher));
-            if (dhp == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_DH_KEY);
-                goto f_err;
-            }
-            if (!ssl_security(s, SSL_SECOP_TMP_DH,
-                              DH_security_bits(dhp), 0, dhp)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_DH_KEY_TOO_SMALL);
-                goto f_err;
-            }
-            if (s->s3->tmp.dh != NULL) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-
-            if (s->cert->dh_tmp_auto)
-                dh = dhp;
-            else if ((dh = DHparams_dup(dhp)) == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                goto err;
-            }
-
-            s->s3->tmp.dh = dh;
-            if ((dhp->pub_key == NULL ||
-                 dhp->priv_key == NULL ||
-                 (s->options & SSL_OP_SINGLE_DH_USE))) {
-                if (!DH_generate_key(dh)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    goto err;
-                }
-            } else {
-                dh->pub_key = BN_dup(dhp->pub_key);
-                dh->priv_key = BN_dup(dhp->priv_key);
-                if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    goto err;
-                }
-            }
-            r[0] = dh->p;
-            r[1] = dh->g;
-            r[2] = dh->pub_key;
-        } else
-#endif
-#ifndef OPENSSL_NO_EC
-        if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
-            const EC_GROUP *group;
-
-            ecdhp = cert->ecdh_tmp;
-            if (s->cert->ecdh_tmp_auto) {
-                /* Get NID of appropriate shared curve */
-                int nid = tls1_shared_curve(s, -2);
-                if (nid != NID_undef)
-                    ecdhp = EC_KEY_new_by_curve_name(nid);
-            } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) {
-                ecdhp = s->cert->ecdh_tmp_cb(s,
-                                             SSL_C_IS_EXPORT(s->s3->
-                                                             tmp.new_cipher),
-                                             SSL_C_EXPORT_PKEYLENGTH(s->
-                                                                     s3->tmp.new_cipher));
-            }
-            if (ecdhp == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_ECDH_KEY);
-                goto f_err;
-            }
-
-            if (s->s3->tmp.ecdh != NULL) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-
-            /* Duplicate the ECDH structure. */
-            if (ecdhp == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-                goto err;
-            }
-            if (s->cert->ecdh_tmp_auto)
-                ecdh = ecdhp;
-            else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-                goto err;
-            }
-
-            s->s3->tmp.ecdh = ecdh;
-            if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
-                (EC_KEY_get0_private_key(ecdh) == NULL) ||
-                (s->options & SSL_OP_SINGLE_ECDH_USE)) {
-                if (!EC_KEY_generate_key(ecdh)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                           ERR_R_ECDH_LIB);
-                    goto err;
-                }
-            }
-
-            if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
-                (EC_KEY_get0_public_key(ecdh) == NULL) ||
-                (EC_KEY_get0_private_key(ecdh) == NULL)) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-                goto err;
-            }
-
-            if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
-                (EC_GROUP_get_degree(group) > 163)) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
-                goto err;
-            }
-
-            /*
-             * XXX: For now, we only support ephemeral ECDH keys over named
-             * (not generic) curves. For supported named curves, curve_id is
-             * non-zero.
-             */
-            if ((curve_id =
-                 tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
-                == 0) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
-                goto err;
-            }
-
-            /*
-             * Encode the public key. First check the size of encoding and
-             * allocate memory accordingly.
-             */
-            encodedlen = EC_POINT_point2oct(group,
-                                            EC_KEY_get0_public_key(ecdh),
-                                            POINT_CONVERSION_UNCOMPRESSED,
-                                            NULL, 0, NULL);
-
-            encodedPoint = (unsigned char *)
-                OPENSSL_malloc(encodedlen * sizeof(unsigned char));
-            bn_ctx = BN_CTX_new();
-            if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-
-            encodedlen = EC_POINT_point2oct(group,
-                                            EC_KEY_get0_public_key(ecdh),
-                                            POINT_CONVERSION_UNCOMPRESSED,
-                                            encodedPoint, encodedlen, bn_ctx);
-
-            if (encodedlen == 0) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-                goto err;
-            }
-
-            BN_CTX_free(bn_ctx);
-            bn_ctx = NULL;
-
-            /*
-             * XXX: For now, we only support named (not generic) curves in
-             * ECDH ephemeral key exchanges. In this situation, we need four
-             * additional bytes to encode the entire ServerECDHParams
-             * structure.
-             */
-            n += 4 + encodedlen;
-
-            /*
-             * We'll generate the serverKeyExchange message explicitly so we
-             * can set these to NULLs
-             */
-            r[0] = NULL;
-            r[1] = NULL;
-            r[2] = NULL;
-            r[3] = NULL;
-        } else
-#endif                          /* !OPENSSL_NO_EC */
-#ifndef OPENSSL_NO_SRP
-        if (type & SSL_kSRP) {
-            if ((s->srp_ctx.N == NULL) ||
-                (s->srp_ctx.g == NULL) ||
-                (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) {
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_MISSING_SRP_PARAM);
-                goto err;
-            }
-            r[0] = s->srp_ctx.N;
-            r[1] = s->srp_ctx.g;
-            r[2] = s->srp_ctx.s;
-            r[3] = s->srp_ctx.B;
-        } else
-#endif
-        {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                   SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
-            goto f_err;
-        }
-        for (i = 0; i < 4 && r[i] != NULL; i++) {
-            nr[i] = BN_num_bytes(r[i]);
-#ifndef OPENSSL_NO_SRP
-            if ((i == 2) && (type & SSL_kSRP))
-                n += 1 + nr[i];
-            else
-#endif
-                n += 2 + nr[i];
-        }
-
-        if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP))
-            && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-            if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
-                == NULL) {
-                al = SSL_AD_DECODE_ERROR;
-                goto f_err;
-            }
-            kn = EVP_PKEY_size(pkey);
-        } else {
-            pkey = NULL;
-            kn = 0;
-        }
-
-        if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_BUF);
-            goto err;
-        }
-        d = p = ssl_handshake_start(s);
-
-#ifndef OPENSSL_NO_PSK
-        if (type & SSL_PSK) {
-            /* copy PSK identity hint */
-            if (s->cert->psk_identity_hint) {
-                s2n(strlen(s->cert->psk_identity_hint), p);
-                strncpy((char *)p, s->cert->psk_identity_hint,
-                        strlen(s->cert->psk_identity_hint));
-                p += strlen(s->cert->psk_identity_hint);
-            } else {
-                s2n(0, p);
-            }
-        }
-#endif
-
-        for (i = 0; i < 4 && r[i] != NULL; i++) {
-#ifndef OPENSSL_NO_SRP
-            if ((i == 2) && (type & SSL_kSRP)) {
-                *p = nr[i];
-                p++;
-            } else
-#endif
-                s2n(nr[i], p);
-            BN_bn2bin(r[i], p);
-            p += nr[i];
-        }
-
-#ifndef OPENSSL_NO_EC
-        if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
-            /*
-             * XXX: For now, we only support named (not generic) curves. In
-             * this situation, the serverKeyExchange message has: [1 byte
-             * CurveType], [2 byte CurveName] [1 byte length of encoded
-             * point], followed by the actual encoded point itself
-             */
-            *p = NAMED_CURVE_TYPE;
-            p += 1;
-            *p = 0;
-            p += 1;
-            *p = curve_id;
-            p += 1;
-            *p = encodedlen;
-            p += 1;
-            memcpy(p, encodedPoint, encodedlen);
-            OPENSSL_free(encodedPoint);
-            encodedPoint = NULL;
-            p += encodedlen;
-        }
-#endif
-
-        /* not anonymous */
-        if (pkey != NULL) {
-            /*
-             * n is the length of the params, they start at &(d[4]) and p
-             * points to the space at the end.
-             */
-#ifndef OPENSSL_NO_RSA
-            if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
-                q = md_buf;
-                j = 0;
-                for (num = 2; num > 0; num--) {
-                    EVP_MD_CTX_set_flags(&md_ctx,
-                                         EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                    EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                      ? s->ctx->md5 : s->ctx->sha1, NULL);
-                    EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                     SSL3_RANDOM_SIZE);
-                    EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                     SSL3_RANDOM_SIZE);
-                    EVP_DigestUpdate(&md_ctx, d, n);
-                    EVP_DigestFinal_ex(&md_ctx, q, (unsigned int *)&i);
-                    q += i;
-                    j += i;
-                }
-                if (RSA_sign(NID_md5_sha1, md_buf, j,
-                             &(p[2]), &u, pkey->pkey.rsa) <= 0) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_RSA);
-                    goto err;
-                }
-                s2n(u, p);
-                n += u + 2;
-            } else
-#endif
-            if (md) {
-                /* send signature algorithm */
-                if (SSL_USE_SIGALGS(s)) {
-                    if (!tls12_get_sigandhash(p, pkey, md)) {
-                        /* Should never happen */
-                        al = SSL_AD_INTERNAL_ERROR;
-                        SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                               ERR_R_INTERNAL_ERROR);
-                        goto f_err;
-                    }
-                    p += 2;
-                }
-#ifdef SSL_DEBUG
-                fprintf(stderr, "Using hash %s\n", EVP_MD_name(md));
-#endif
-                EVP_SignInit_ex(&md_ctx, md, NULL);
-                EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
-                               SSL3_RANDOM_SIZE);
-                EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
-                               SSL3_RANDOM_SIZE);
-                EVP_SignUpdate(&md_ctx, d, n);
-                if (!EVP_SignFinal(&md_ctx, &(p[2]),
-                                   (unsigned int *)&i, pkey)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_EVP);
-                    goto err;
-                }
-                s2n(i, p);
-                n += i + 2;
-                if (SSL_USE_SIGALGS(s))
-                    n += 2;
-            } else {
-                /* Is this error check actually needed? */
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
-                       SSL_R_UNKNOWN_PKEY_TYPE);
-                goto f_err;
-            }
-        }
-
-        if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-    }
-
-    s->state = SSL3_ST_SW_KEY_EXCH_B;
-    EVP_MD_CTX_cleanup(&md_ctx);
-    return ssl_do_write(s);
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-#ifndef OPENSSL_NO_EC
-    OPENSSL_free(encodedPoint);
-    BN_CTX_free(bn_ctx);
-#endif
-    EVP_MD_CTX_cleanup(&md_ctx);
-    s->state = SSL_ST_ERR;
-    return (-1);
-}
-
-int ssl3_send_certificate_request(SSL *s)
-{
-    unsigned char *p, *d;
-    int i, j, nl, off, n;
-    STACK_OF(X509_NAME) *sk = NULL;
-    X509_NAME *name;
-    BUF_MEM *buf;
-
-    if (s->state == SSL3_ST_SW_CERT_REQ_A) {
-        buf = s->init_buf;
-
-        d = p = ssl_handshake_start(s);
-
-        /* get the list of acceptable cert types */
-        p++;
-        n = ssl3_get_req_cert_type(s, p);
-        d[0] = n;
-        p += n;
-        n++;
-
-        if (SSL_USE_SIGALGS(s)) {
-            const unsigned char *psigs;
-            unsigned char *etmp = p;
-            nl = tls12_get_psigalgs(s, &psigs);
-            /* Skip over length for now */
-            p += 2;
-            nl = tls12_copy_sigalgs(s, p, psigs, nl);
-            /* Now fill in length */
-            s2n(nl, etmp);
-            p += nl;
-            n += nl + 2;
-        }
-
-        off = n;
-        p += 2;
-        n += 2;
-
-        sk = SSL_get_client_CA_list(s);
-        nl = 0;
-        if (sk != NULL) {
-            for (i = 0; i < sk_X509_NAME_num(sk); i++) {
-                name = sk_X509_NAME_value(sk, i);
-                j = i2d_X509_NAME(name, NULL);
-                if (!BUF_MEM_grow_clean
-                    (buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) {
-                    SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,
-                           ERR_R_BUF_LIB);
-                    goto err;
-                }
-                p = ssl_handshake_start(s) + n;
-                s2n(j, p);
-                i2d_X509_NAME(name, &p);
-                n += 2 + j;
-                nl += 2 + j;
-            }
-        }
-        /* else no CA names */
-        p = ssl_handshake_start(s) + off;
-        s2n(nl, p);
-
-        if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) {
-            SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-
-        s->state = SSL3_ST_SW_CERT_REQ_B;
-    }
-
-    /* SSL3_ST_SW_CERT_REQ_B */
-    return ssl_do_write(s);
- err:
-    s->state = SSL_ST_ERR;
-    return (-1);
-}
-
-int ssl3_get_client_key_exchange(SSL *s)
-{
-    unsigned int i;
-    int al, ok;
-    long n;
-    unsigned long alg_k;
-#ifndef OPENSSL_NO_RSA
-    RSA *rsa = NULL;
-    EVP_PKEY *pkey = NULL;
-#endif
-#ifndef OPENSSL_NO_DH
-    BIGNUM *pub = NULL;
-    DH *dh_srvr, *dh_clnt = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *srvr_ecdh = NULL;
-    EVP_PKEY *clnt_pub_pkey = NULL;
-    EC_POINT *clnt_ecpoint = NULL;
-    BN_CTX *bn_ctx = NULL;
-#endif
-    PACKET pkt, enc_premaster;
-    unsigned char *data, *rsa_decrypt = NULL;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_SR_KEY_EXCH_A,
-                                   SSL3_ST_SR_KEY_EXCH_B,
-                                   SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, &ok);
-
-    if (!ok)
-        return ((int)n);
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
-
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-#ifndef OPENSSL_NO_PSK
-    /* For PSK parse and retrieve identity, obtain PSK key */
-    if (alg_k & SSL_PSK) {
-        unsigned char psk[PSK_MAX_PSK_LEN];
-        size_t psklen;
-	PACKET psk_identity;
-
-        if (!PACKET_get_length_prefixed_2(&pkt, &psk_identity)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DATA_LENGTH_TOO_LONG);
-            goto f_err;
-        }
-        if (s->psk_server_callback == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_NO_SERVER_CB);
-            goto f_err;
-        }
-
-        if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        psklen = s->psk_server_callback(s, s->session->psk_identity,
-                                         psk, sizeof(psk));
-
-        if (psklen > PSK_MAX_PSK_LEN) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        } else if (psklen == 0) {
-            /*
-             * PSK related to the given identity not found
-             */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_IDENTITY_NOT_FOUND);
-            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
-            goto f_err;
-        }
-
-        OPENSSL_free(s->s3->tmp.psk);
-        s->s3->tmp.psk = BUF_memdup(psk, psklen);
-        OPENSSL_cleanse(psk, psklen);
-
-        if (s->s3->tmp.psk == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-
-        s->s3->tmp.psklen = psklen;
-    }
-    if (alg_k & SSL_kPSK) {
-        /* Identity extracted earlier: should be nothing left */
-        if (PACKET_remaining(&pkt) != 0) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        /* PSK handled by ssl_generate_master_secret */
-        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_RSA
-    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-        unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
-        int decrypt_len;
-        unsigned char decrypt_good, version_good;
-        size_t j;
-
-        /* FIX THIS UP EAY EAY EAY EAY */
-        if (s->s3->tmp.use_rsa_tmp) {
-            if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
-                rsa = s->cert->rsa_tmp;
-            /*
-             * Don't do a callback because rsa_tmp should be sent already
-             */
-            if (rsa == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_RSA_PKEY);
-                goto f_err;
-
-            }
-        } else {
-            pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
-            if ((pkey == NULL) ||
-                (pkey->type != EVP_PKEY_RSA) || (pkey->pkey.rsa == NULL)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_RSA_CERTIFICATE);
-                goto f_err;
-            }
-            rsa = pkey->pkey.rsa;
-        }
-
-        /* SSLv3 and pre-standard DTLS omit the length bytes. */
-        if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) {
-            enc_premaster = pkt;
-        } else {
-            PACKET orig = pkt;
-            if (!PACKET_get_length_prefixed_2(&pkt, &enc_premaster)
-                || PACKET_remaining(&pkt) != 0) {
-                /* Try SSLv3 behaviour for TLS. */
-                if (s->options & SSL_OP_TLS_D5_BUG) {
-                    enc_premaster = orig;
-                } else {
-                    al = SSL_AD_DECODE_ERROR;
-                    SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-                    goto f_err;
-                }
-            }
-        }
-
-        /*
-         * We want to be sure that the plaintext buffer size makes it safe to
-         * iterate over the entire size of a premaster secret
-         * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
-         * their ciphertext cannot accommodate a premaster secret anyway.
-         */
-        if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   RSA_R_KEY_SIZE_TOO_SMALL);
-            goto f_err;
-        }
-
-        rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
-        if (rsa_decrypt == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-
-        /*
-         * We must not leak whether a decryption failure occurs because of
-         * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
-         * section 7.4.7.1). The code follows that advice of the TLS RFC and
-         * generates a random premaster secret for the case that the decrypt
-         * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
-         */
-
-        if (RAND_bytes(rand_premaster_secret,
-                       sizeof(rand_premaster_secret)) <= 0) {
-            goto err;
-        }
-
-        decrypt_len = RSA_private_decrypt(PACKET_remaining(&enc_premaster),
-                                          PACKET_data(&enc_premaster),
-                                          rsa_decrypt, rsa, RSA_PKCS1_PADDING);
-        ERR_clear_error();
-
-        /*
-         * decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH. decrypt_good will
-         * be 0xff if so and zero otherwise.
-         */
-        decrypt_good =
-            constant_time_eq_int_8(decrypt_len, SSL_MAX_MASTER_KEY_LENGTH);
-
-        /*
-         * If the version in the decrypted pre-master secret is correct then
-         * version_good will be 0xff, otherwise it'll be zero. The
-         * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
-         * (http://eprint.iacr.org/2003/052/) exploits the version number
-         * check as a "bad version oracle". Thus version checks are done in
-         * constant time and are treated like any other decryption error.
-         */
-        version_good =
-            constant_time_eq_8(rsa_decrypt[0],
-                               (unsigned)(s->client_version >> 8));
-        version_good &=
-            constant_time_eq_8(rsa_decrypt[1],
-                               (unsigned)(s->client_version & 0xff));
-
-        /*
-         * The premaster secret must contain the same version number as the
-         * ClientHello to detect version rollback attacks (strangely, the
-         * protocol does not offer such protection for DH ciphersuites).
-         * However, buggy clients exist that send the negotiated protocol
-         * version instead if the server does not support the requested
-         * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
-         * clients.
-         */
-        if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
-            unsigned char workaround_good;
-            workaround_good =
-                constant_time_eq_8(rsa_decrypt[0], (unsigned)(s->version >> 8));
-            workaround_good &=
-                constant_time_eq_8(rsa_decrypt[1],
-                                   (unsigned)(s->version & 0xff));
-            version_good |= workaround_good;
-        }
-
-        /*
-         * Both decryption and version must be good for decrypt_good to
-         * remain non-zero (0xff).
-         */
-        decrypt_good &= version_good;
-
-        /*
-         * Now copy rand_premaster_secret over from p using
-         * decrypt_good_mask. If decryption failed, then p does not
-         * contain valid plaintext, however, a check above guarantees
-         * it is still sufficiently large to read from.
-         */
-        for (j = 0; j < sizeof(rand_premaster_secret); j++) {
-            rsa_decrypt[j] =
-                constant_time_select_8(decrypt_good, rsa_decrypt[j],
-                                       rand_premaster_secret[j]);
-        }
-
-        if (!ssl_generate_master_secret(s, rsa_decrypt,
-                                        sizeof(rand_premaster_secret), 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        OPENSSL_free(rsa_decrypt);
-        rsa_decrypt = NULL;
-    } else
-#endif
-#ifndef OPENSSL_NO_DH
-    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
-        int idx = -1;
-        EVP_PKEY *skey = NULL;
-        PACKET bookmark = pkt;
-        unsigned char shared[(OPENSSL_DH_MAX_MODULUS_BITS + 7) / 8];
-
-        if (!PACKET_get_net_2(&pkt, &i)) {
-            if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
-                goto f_err;
-            }
-            i = 0;
-        }
-        if (PACKET_remaining(&pkt) != i) {
-            if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
-                goto err;
-            } else {
-                pkt = bookmark;
-                i = PACKET_remaining(&pkt);
-            }
-        }
-        if (alg_k & SSL_kDHr)
-            idx = SSL_PKEY_DH_RSA;
-        else if (alg_k & SSL_kDHd)
-            idx = SSL_PKEY_DH_DSA;
-        if (idx >= 0) {
-            skey = s->cert->pkeys[idx].privatekey;
-            if ((skey == NULL) ||
-                (skey->type != EVP_PKEY_DH) || (skey->pkey.dh == NULL)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_RSA_CERTIFICATE);
-                goto f_err;
-            }
-            dh_srvr = skey->pkey.dh;
-        } else if (s->s3->tmp.dh == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_DH_KEY);
-            goto f_err;
-        } else
-            dh_srvr = s->s3->tmp.dh;
-
-        if (n == 0L) {
-            /* Get pubkey from cert */
-            EVP_PKEY *clkey = X509_get_pubkey(s->session->peer);
-            if (clkey) {
-                if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
-                    dh_clnt = EVP_PKEY_get1_DH(clkey);
-            }
-            if (dh_clnt == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_DH_KEY);
-                goto f_err;
-            }
-            EVP_PKEY_free(clkey);
-            pub = dh_clnt->pub_key;
-        } else {
-            if (!PACKET_get_bytes(&pkt, &data, i)) {
-                /* We already checked we have enough data */
-                al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto f_err;
-            }
-            pub = BN_bin2bn(data, i, NULL);
-        }
-        if (pub == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
-            goto err;
-        }
-
-        i = DH_compute_key(shared, pub, dh_srvr);
-
-        if (i <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-            BN_clear_free(pub);
-            goto err;
-        }
-
-        DH_free(s->s3->tmp.dh);
-        s->s3->tmp.dh = NULL;
-        if (dh_clnt)
-            DH_free(dh_clnt);
-        else
-            BN_clear_free(pub);
-        pub = NULL;
-        if (!ssl_generate_master_secret(s, shared, i, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        if (dh_clnt)
-            return 2;
-    } else
-#endif
-
-#ifndef OPENSSL_NO_EC
-    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-        int ret = 1;
-        int field_size = 0;
-        const EC_KEY *tkey;
-        const EC_GROUP *group;
-        const BIGNUM *priv_key;
-        unsigned char *shared;
-
-        /* initialize structures for server's ECDH key pair */
-        if ((srvr_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        /* Let's get server private key and group information */
-        if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
-            /* use the certificate */
-            tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
-        } else {
-            /*
-             * use the ephermeral values we saved when generating the
-             * ServerKeyExchange msg.
-             */
-            tkey = s->s3->tmp.ecdh;
-        }
-
-        group = EC_KEY_get0_group(tkey);
-        priv_key = EC_KEY_get0_private_key(tkey);
-
-        if (!EC_KEY_set_group(srvr_ecdh, group) ||
-            !EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-
-        /* Let's get client's public key */
-        if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (n == 0L) {
-            /* Client Publickey was in Client Certificate */
-
-            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_ECDH_KEY);
-                goto f_err;
-            }
-            if (((clnt_pub_pkey = X509_get_pubkey(s->session->peer))
-                 == NULL) || (clnt_pub_pkey->type != EVP_PKEY_EC)) {
-                /*
-                 * XXX: For now, we do not support client authentication
-                 * using ECDH certificates so this branch (n == 0L) of the
-                 * code is never executed. When that support is added, we
-                 * ought to ensure the key received in the certificate is
-                 * authorized for key agreement. ECDH_compute_key implicitly
-                 * checks that the two ECDH shares are for the same group.
-                 */
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
-                goto f_err;
-            }
-
-            if (EC_POINT_copy(clnt_ecpoint,
-                              EC_KEY_get0_public_key(clnt_pub_pkey->
-                                                     pkey.ec)) == 0) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            ret = 2;            /* Skip certificate verify processing */
-        } else {
-            /*
-             * Get client's public key from encoded point in the
-             * ClientKeyExchange message.
-             */
-            if ((bn_ctx = BN_CTX_new()) == NULL) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-
-            /* Get encoded point length */
-            if (!PACKET_get_1(&pkt, &i)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                       SSL_R_LENGTH_MISMATCH);
-                goto f_err;
-            }
-            if (!PACKET_get_bytes(&pkt, &data, i)
-                    || PACKET_remaining(&pkt) != 0) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-        }
-
-        /* Compute the shared pre-master secret */
-        field_size = EC_GROUP_get_degree(group);
-        if (field_size <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        shared = OPENSSL_malloc((field_size + 7) / 8);
-        if (shared == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
-                             srvr_ecdh, NULL);
-        if (i <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            OPENSSL_free(shared);
-            goto err;
-        }
-
-        EVP_PKEY_free(clnt_pub_pkey);
-        EC_POINT_free(clnt_ecpoint);
-        EC_KEY_free(srvr_ecdh);
-        BN_CTX_free(bn_ctx);
-        EC_KEY_free(s->s3->tmp.ecdh);
-        s->s3->tmp.ecdh = NULL;
-
-        if (!ssl_generate_master_secret(s, shared, i, 1)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        return (ret);
-    } else
-#endif
-#ifndef OPENSSL_NO_SRP
-    if (alg_k & SSL_kSRP) {
-        if (!PACKET_get_net_2(&pkt, &i)
-                || !PACKET_get_bytes(&pkt, &data, i)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_SRP_A_LENGTH);
-            goto f_err;
-        }
-        if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
-        if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0
-            || BN_is_zero(s->srp_ctx.A)) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_BAD_SRP_PARAMETERS);
-            goto f_err;
-        }
-        OPENSSL_free(s->session->srp_username);
-        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
-        if (s->session->srp_username == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (!srp_generate_server_master_secret(s)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-    } else
-#endif                          /* OPENSSL_NO_SRP */
-    if (alg_k & SSL_kGOST) {
-        int ret = 0;
-        EVP_PKEY_CTX *pkey_ctx;
-        EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
-        unsigned char premaster_secret[32], *start;
-        size_t outlen = 32, inlen;
-        unsigned long alg_a;
-        int Ttag, Tclass;
-        long Tlen;
-
-        /* Get our certificate private key */
-        alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-        if (alg_a & SSL_aGOST01)
-            pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
-
-        pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
-        EVP_PKEY_decrypt_init(pkey_ctx);
-        /*
-         * If client certificate is present and is of the same type, maybe
-         * use it for key exchange.  Don't mind errors from
-         * EVP_PKEY_derive_set_peer, because it is completely valid to use a
-         * client certificate for authorization only.
-         */
-        client_pub_pkey = X509_get_pubkey(s->session->peer);
-        if (client_pub_pkey) {
-            if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
-                ERR_clear_error();
-        }
-        /* Decrypt session key */
-        if (!PACKET_get_bytes(&pkt, &data, n)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        if (ASN1_get_object
-            ((const unsigned char **)&data, &Tlen, &Ttag, &Tclass,
-             n) != V_ASN1_CONSTRUCTED || Ttag != V_ASN1_SEQUENCE
-            || Tclass != V_ASN1_UNIVERSAL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DECRYPTION_FAILED);
-            goto gerr;
-        }
-        start = data;
-        inlen = Tlen;
-        if (EVP_PKEY_decrypt
-            (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DECRYPTION_FAILED);
-            goto gerr;
-        }
-        /* Generate master secret */
-        if (!ssl_generate_master_secret(s, premaster_secret,
-                                        sizeof(premaster_secret), 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        /* Check if pubkey from client certificate was used */
-        if (EVP_PKEY_CTX_ctrl
-            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
-            ret = 2;
-        else
-            ret = 1;
- gerr:
-        EVP_PKEY_free(client_pub_pkey);
-        EVP_PKEY_CTX_free(pkey_ctx);
-        if (ret)
-            return ret;
-        goto err;
-    } else {
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_UNKNOWN_CIPHER_TYPE);
-        goto f_err;
-    }
-
-    return (1);
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_SRP)
- err:
-#endif
-#ifndef OPENSSL_NO_EC
-    EVP_PKEY_free(clnt_pub_pkey);
-    EC_POINT_free(clnt_ecpoint);
-    EC_KEY_free(srvr_ecdh);
-    BN_CTX_free(bn_ctx);
-    OPENSSL_free(rsa_decrypt);
-#endif
-#ifndef OPENSSL_NO_PSK
-    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
-    s->s3->tmp.psk = NULL;
-#endif
-    s->state = SSL_ST_ERR;
-    return (-1);
-}
-
-int ssl3_get_cert_verify(SSL *s)
-{
-    EVP_PKEY *pkey = NULL;
-    unsigned char *sig, *data;
-    int al, ok, ret = 0;
-    long n;
-    int type = 0, i, j;
-    unsigned int len;
-    X509 *peer;
-    const EVP_MD *md = NULL;
-    EVP_MD_CTX mctx;
-    PACKET pkt;
-    EVP_MD_CTX_init(&mctx);
-
-    /*
-     * We should only process a CertificateVerify message if we have received
-     * a Certificate from the client. If so then |s->session->peer| will be non
-     * NULL. In some instances a CertificateVerify message is not required even
-     * if the peer has sent a Certificate (e.g. such as in the case of static
-     * DH). In that case the ClientKeyExchange processing will skip the
-     * CertificateVerify state so we should not arrive here.
-     */
-    if (s->session->peer == NULL) {
-        ret = 1;
-        goto end;
-    }
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_SR_CERT_VRFY_A,
-                                   SSL3_ST_SR_CERT_VRFY_B,
-                                   SSL3_MT_CERTIFICATE_VERIFY,
-                                   SSL3_RT_MAX_PLAIN_LENGTH, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    peer = s->session->peer;
-    pkey = X509_get_pubkey(peer);
-    type = X509_certificate_type(peer, pkey);
-
-    if (!(type & EVP_PKT_SIGN)) {
-        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
-               SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        goto f_err;
-    }
-
-    /* we now have a signature that we need to verify */
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
-        al = SSL_AD_INTERNAL_ERROR;
-        goto f_err;
-    }
-    /* Check for broken implementations of GOST ciphersuites */
-    /*
-     * If key is GOST and n is exactly 64, it is bare signature without
-     * length field
-     */
-    if (n == 64 && pkey->type == NID_id_GostR3410_2001) {
-        len = 64;
-    } else {
-        if (SSL_USE_SIGALGS(s)) {
-            int rv;
-
-            if (!PACKET_get_bytes(&pkt, &sig, 2)) {
-                al = SSL_AD_DECODE_ERROR;
-                goto f_err;
-            }
-            rv = tls12_check_peer_sigalg(&md, s, sig, pkey);
-            if (rv == -1) {
-                al = SSL_AD_INTERNAL_ERROR;
-                goto f_err;
-            } else if (rv == 0) {
-                al = SSL_AD_DECODE_ERROR;
-                goto f_err;
-            }
-#ifdef SSL_DEBUG
-            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
-#endif
-        }
-        if (!PACKET_get_net_2(&pkt, &len)) {
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-    }
-    j = EVP_PKEY_size(pkey);
-    if (((int)len > j) || ((int)PACKET_remaining(&pkt) > j) || (n <= 0)) {
-        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-    if (!PACKET_get_bytes(&pkt, &data, len)) {
-        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-
-    if (SSL_USE_SIGALGS(s)) {
-        long hdatalen = 0;
-        void *hdata;
-        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
-        if (hdatalen <= 0) {
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-#ifdef SSL_DEBUG
-        fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
-                EVP_MD_name(md));
-#endif
-        if (!EVP_VerifyInit_ex(&mctx, md, NULL)
-            || !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) {
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#ifndef OPENSSL_NO_RSA
-    if (pkey->type == EVP_PKEY_RSA) {
-        i = RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, data, len,
-                       pkey->pkey.rsa);
-        if (i < 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_RSA_DECRYPT);
-            goto f_err;
-        }
-        if (i == 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_RSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_DSA
-    if (pkey->type == EVP_PKEY_DSA) {
-        j = DSA_verify(pkey->save_type,
-                       &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                       SHA_DIGEST_LENGTH, data, len, pkey->pkey.dsa);
-        if (j <= 0) {
-            /* bad signature */
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_DSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_EC
-    if (pkey->type == EVP_PKEY_EC) {
-        j = ECDSA_verify(pkey->save_type,
-                         &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                         SHA_DIGEST_LENGTH, data, len, pkey->pkey.ec);
-        if (j <= 0) {
-            /* bad signature */
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-    if (pkey->type == NID_id_GostR3410_2001) {
-        unsigned char signature[64];
-        int idx;
-        EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_verify_init(pctx);
-        if (len != 64) {
-            fprintf(stderr, "GOST signature length is %d", len);
-        }
-        for (idx = 0; idx < 64; idx++) {
-            signature[63 - idx] = data[idx];
-        }
-        j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
-                            32);
-        EVP_PKEY_CTX_free(pctx);
-        if (j <= 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
-            goto f_err;
-        }
-    } else {
-        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
-        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
-        goto f_err;
-    }
-
-    ret = 1;
-    if (0) {
- f_err:
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        s->state = SSL_ST_ERR;
-    }
- end:
-    BIO_free(s->s3->handshake_buffer);
-    s->s3->handshake_buffer = NULL;
-    EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_free(pkey);
-    return (ret);
-}
-
-int ssl3_get_client_certificate(SSL *s)
-{
-    int i, ok, al, ret = -1;
-    X509 *x = NULL;
-    unsigned long l, llen, n;
-    const unsigned char *certstart;
-    unsigned char *certbytes;
-    STACK_OF(X509) *sk = NULL;
-    PACKET pkt, spkt;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_SR_CERT_A,
-                                   SSL3_ST_SR_CERT_B,
-                                   -1, s->max_cert_list, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    if (s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
-        if ((s->verify_mode & SSL_VERIFY_PEER) &&
-            (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            goto f_err;
-        }
-        /*
-         * If tls asked for a client cert, the client must return a 0 list
-         */
-        if ((s->version > SSL3_VERSION) && s->s3->tmp.cert_request) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            goto f_err;
-        }
-        s->s3->tmp.reuse_message = 1;
-        return (1);
-    }
-
-    if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, SSL_R_WRONG_MESSAGE_TYPE);
-        goto f_err;
-    }
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
-
-    if ((sk = sk_X509_new_null()) == NULL) {
-        SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-        goto done;
-    }
-
-    if (!PACKET_get_net_3(&pkt, &llen)
-            || !PACKET_get_sub_packet(&pkt, &spkt, llen)
-            || PACKET_remaining(&pkt) != 0) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    while (PACKET_remaining(&spkt) > 0) {
-        if (!PACKET_get_net_3(&spkt, &l)
-                || !PACKET_get_bytes(&spkt, &certbytes, l)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        certstart = certbytes;
-        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
-        if (x == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
-            goto done;
-        }
-        if (certbytes != (certstart + l)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (!sk_X509_push(sk, x)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-            goto done;
-        }
-        x = NULL;
-    }
-
-    if (sk_X509_num(sk) <= 0) {
-        /* TLS does not mind 0 certs returned */
-        if (s->version == SSL3_VERSION) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_NO_CERTIFICATES_RETURNED);
-            goto f_err;
-        }
-        /* Fail for TLS only if we required a certificate */
-        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
-                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            goto f_err;
-        }
-        /* No client certificate so digest cached records */
-        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-    } else {
-        EVP_PKEY *pkey;
-        i = ssl_verify_cert_chain(s, sk);
-        if (i <= 0) {
-            al = ssl_verify_alarm_type(s->verify_result);
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_CERTIFICATE_VERIFY_FAILED);
-            goto f_err;
-        }
-        if (i > 1) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, i);
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            goto f_err;
-        }
-        pkey = X509_get_pubkey(sk_X509_value(sk, 0));
-        if (pkey == NULL) {
-            al = SSL3_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
-                   SSL_R_UNKNOWN_CERTIFICATE_TYPE);
-            goto f_err;
-        }
-        EVP_PKEY_free(pkey);
-    }
-
-    X509_free(s->session->peer);
-    s->session->peer = sk_X509_shift(sk);
-    s->session->verify_result = s->verify_result;
-
-    sk_X509_pop_free(s->session->peer_chain, X509_free);
-    s->session->peer_chain = sk;
-    /*
-     * Inconsistency alert: cert_chain does *not* include the peer's own
-     * certificate, while we do include it in s3_clnt.c
-     */
-    sk = NULL;
-    ret = 1;
-    goto done;
-
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- done:
-    s->state = SSL_ST_ERR;
-    X509_free(x);
-    sk_X509_pop_free(sk, X509_free);
-    return (ret);
-}
-
-int ssl3_send_server_certificate(SSL *s)
-{
-    CERT_PKEY *cpk;
-
-    if (s->state == SSL3_ST_SW_CERT_A) {
-        cpk = ssl_get_server_send_pkey(s);
-        if (cpk == NULL) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-            s->state = SSL_ST_ERR;
-            return (0);
-        }
-
-        if (!ssl3_output_cert_chain(s, cpk)) {
-            SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-            s->state = SSL_ST_ERR;
-            return (0);
-        }
-        s->state = SSL3_ST_SW_CERT_B;
-    }
-
-    /* SSL3_ST_SW_CERT_B */
-    return ssl_do_write(s);
-}
-
-/* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_newsession_ticket(SSL *s)
-{
-    unsigned char *senc = NULL;
-    EVP_CIPHER_CTX ctx;
-    HMAC_CTX hctx;
-
-    if (s->state == SSL3_ST_SW_SESSION_TICKET_A) {
-        unsigned char *p, *macstart;
-        const unsigned char *const_p;
-        int len, slen_full, slen;
-        SSL_SESSION *sess;
-        unsigned int hlen;
-        SSL_CTX *tctx = s->initial_ctx;
-        unsigned char iv[EVP_MAX_IV_LENGTH];
-        unsigned char key_name[16];
-
-        /* get session encoding length */
-        slen_full = i2d_SSL_SESSION(s->session, NULL);
-        /*
-         * Some length values are 16 bits, so forget it if session is too
-         * long
-         */
-        if (slen_full == 0 || slen_full > 0xFF00) {
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-        senc = OPENSSL_malloc(slen_full);
-        if (!senc) {
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-
-        EVP_CIPHER_CTX_init(&ctx);
-        HMAC_CTX_init(&hctx);
-
-        p = senc;
-        if (!i2d_SSL_SESSION(s->session, &p))
-            goto err;
-
-        /*
-         * create a fresh copy (not shared with other threads) to clean up
-         */
-        const_p = senc;
-        sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
-        if (sess == NULL)
-            goto err;
-        sess->session_id_length = 0; /* ID is irrelevant for the ticket */
-
-        slen = i2d_SSL_SESSION(sess, NULL);
-        if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */
-            SSL_SESSION_free(sess);
-            goto err;
-        }
-        p = senc;
-        if (!i2d_SSL_SESSION(sess, &p)) {
-            SSL_SESSION_free(sess);
-            goto err;
-        }
-        SSL_SESSION_free(sess);
-
-        /*-
-         * Grow buffer if need be: the length calculation is as
-         * follows handshake_header_length +
-         * 4 (ticket lifetime hint) + 2 (ticket length) +
-         * 16 (key name) + max_iv_len (iv length) +
-         * session_length + max_enc_block_size (max encrypted session
-         * length) + max_md_size (HMAC).
-         */
-        if (!BUF_MEM_grow(s->init_buf,
-                          SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
-                          EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
-            goto err;
-
-        p = ssl_handshake_start(s);
-        /*
-         * Initialize HMAC and cipher contexts. If callback present it does
-         * all the work otherwise use generated values from parent ctx.
-         */
-        if (tctx->tlsext_ticket_key_cb) {
-            if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
-                                           &hctx, 1) < 0)
-                goto err;
-        } else {
-            if (RAND_bytes(iv, 16) <= 0)
-                goto err;
-            if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
-                                    tctx->tlsext_tick_aes_key, iv))
-                goto err;
-            if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
-                              EVP_sha256(), NULL))
-                goto err;
-            memcpy(key_name, tctx->tlsext_tick_key_name, 16);
-        }
-
-        /*
-         * Ticket lifetime hint (advisory only): We leave this unspecified
-         * for resumed session (for simplicity), and guess that tickets for
-         * new sessions will live as long as their sessions.
-         */
-        l2n(s->hit ? 0 : s->session->timeout, p);
-
-        /* Skip ticket length for now */
-        p += 2;
-        /* Output key name */
-        macstart = p;
-        memcpy(p, key_name, 16);
-        p += 16;
-        /* output IV */
-        memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
-        p += EVP_CIPHER_CTX_iv_length(&ctx);
-        /* Encrypt session data */
-        if (!EVP_EncryptUpdate(&ctx, p, &len, senc, slen))
-            goto err;
-        p += len;
-        if (!EVP_EncryptFinal(&ctx, p, &len))
-            goto err;
-        p += len;
-
-        if (!HMAC_Update(&hctx, macstart, p - macstart))
-            goto err;
-        if (!HMAC_Final(&hctx, p, &hlen))
-            goto err;
-
-        EVP_CIPHER_CTX_cleanup(&ctx);
-        HMAC_CTX_cleanup(&hctx);
-
-        p += hlen;
-        /* Now write out lengths: p points to end of data written */
-        /* Total length */
-        len = p - ssl_handshake_start(s);
-        /* Skip ticket lifetime hint */
-        p = ssl_handshake_start(s) + 4;
-        s2n(len - 6, p);
-        if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len))
-            goto err;
-        s->state = SSL3_ST_SW_SESSION_TICKET_B;
-        OPENSSL_free(senc);
-    }
-
-    /* SSL3_ST_SW_SESSION_TICKET_B */
-    return ssl_do_write(s);
- err:
-    OPENSSL_free(senc);
-    EVP_CIPHER_CTX_cleanup(&ctx);
-    HMAC_CTX_cleanup(&hctx);
-    s->state = SSL_ST_ERR;
-    return -1;
-}
-
-int ssl3_send_cert_status(SSL *s)
-{
-    if (s->state == SSL3_ST_SW_CERT_STATUS_A) {
-        unsigned char *p;
-        /*-
-         * Grow buffer if need be: the length calculation is as
-         * follows 1 (message type) + 3 (message length) +
-         * 1 (ocsp response type) + 3 (ocsp response length)
-         * + (ocsp response)
-         */
-        if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) {
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-
-        p = (unsigned char *)s->init_buf->data;
-
-        /* do the header */
-        *(p++) = SSL3_MT_CERTIFICATE_STATUS;
-        /* message length */
-        l2n3(s->tlsext_ocsp_resplen + 4, p);
-        /* status type */
-        *(p++) = s->tlsext_status_type;
-        /* length of OCSP response */
-        l2n3(s->tlsext_ocsp_resplen, p);
-        /* actual response */
-        memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
-        /* number of bytes to write */
-        s->init_num = 8 + s->tlsext_ocsp_resplen;
-        s->state = SSL3_ST_SW_CERT_STATUS_B;
-        s->init_off = 0;
-    }
-
-    /* SSL3_ST_SW_CERT_STATUS_B */
-    return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/*
- * ssl3_get_next_proto reads a Next Protocol Negotiation handshake message.
- * It sets the next_proto member in s if found
- */
-int ssl3_get_next_proto(SSL *s)
-{
-    int ok;
-    long n;
-    PACKET pkt, next_proto, padding;
-    size_t next_proto_len;
-
-    /*
-     * Clients cannot send a NextProtocol message if we didn't see the
-     * extension in their ClientHello
-     */
-    if (!s->s3->next_proto_neg_seen) {
-        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,
-               SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
-        s->state = SSL_ST_ERR;
-        return -1;
-    }
-
-    /* See the payload format below */
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_SR_NEXT_PROTO_A,
-                                   SSL3_ST_SR_NEXT_PROTO_B,
-                                   SSL3_MT_NEXT_PROTO, 514, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    /*
-     * s->state doesn't reflect whether ChangeCipherSpec has been received in
-     * this handshake, but s->s3->change_cipher_spec does (will be reset by
-     * ssl3_get_finished).
-     */
-    if (!s->s3->change_cipher_spec) {
-        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
-        s->state = SSL_ST_ERR;
-        return -1;
-    }
-
-    if (n < 2) {
-        goto err;               /* The body must be > 1 bytes long */
-    }
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    /*-
-     * The payload looks like:
-     *   uint8 proto_len;
-     *   uint8 proto[proto_len];
-     *   uint8 padding_len;
-     *   uint8 padding[padding_len];
-     */
-    if (!PACKET_get_length_prefixed_1(&pkt, &next_proto)
-        || !PACKET_get_length_prefixed_1(&pkt, &padding)
-        || PACKET_remaining(&pkt) > 0) {
-        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, SSL_R_LENGTH_MISMATCH);
-        goto err;
-    }
-
-    if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated,
-                       &next_proto_len)) {
-        s->next_proto_negotiated_len = 0;
-        goto err;
-    }
-
-    s->next_proto_negotiated_len = (unsigned char)next_proto_len;
-
-    return 1;
-err:
-    s->state = SSL_ST_ERR;
-    return 0;
-}
-#endif
-
-#define SSLV2_CIPHER_LEN    3
-
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
-                                               PACKET *cipher_suites,
-                                               STACK_OF(SSL_CIPHER) **skp,
-                                               int sslv2format, int *al
-                                               )
-{
-    const SSL_CIPHER *c;
-    STACK_OF(SSL_CIPHER) *sk;
-    int n;
-    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
-    unsigned char cipher[SSLV2_CIPHER_LEN];
-
-    s->s3->send_connection_binding = 0;
-
-    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
-
-    if (PACKET_remaining(cipher_suites) == 0) {
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return NULL;
-    }
-
-    if (PACKET_remaining(cipher_suites) % n != 0) {
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-               SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
-        *al = SSL_AD_DECODE_ERROR;
-        return NULL;
-    }
-
-    if ((skp == NULL) || (*skp == NULL)) {
-        sk = sk_SSL_CIPHER_new_null(); /* change perhaps later */
-        if(sk == NULL) {
-            SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
-            *al = SSL_AD_INTERNAL_ERROR;
-            return NULL;
-        }
-    } else {
-        sk = *skp;
-        sk_SSL_CIPHER_zero(sk);
-    }
-
-    if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
-                       &s->s3->tmp.ciphers_rawlen)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        goto err;
-    }
-
-    while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
-        /*
-         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
-         * first byte set to zero, while true SSLv2 ciphers have a non-zero
-         * first byte. We don't support any true SSLv2 ciphers, so skip them.
-         */
-        if (sslv2format && cipher[0] != '\0')
-                continue;
-
-        /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
-        if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
-            (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) {
-            /* SCSV fatal if renegotiating */
-            if (s->renegotiate) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-                       SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
-                *al = SSL_AD_HANDSHAKE_FAILURE;
-                goto err;
-            }
-            s->s3->send_connection_binding = 1;
-#ifdef OPENSSL_RI_DEBUG
-            fprintf(stderr, "SCSV received by server\n");
-#endif
-            continue;
-        }
-
-        /* Check for TLS_FALLBACK_SCSV */
-        if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) &&
-            (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) {
-            /*
-             * The SCSV indicates that the client previously tried a higher
-             * version. Fail if the current version is an unexpected
-             * downgrade.
-             */
-            if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-                       SSL_R_INAPPROPRIATE_FALLBACK);
-                *al = SSL_AD_INAPPROPRIATE_FALLBACK;
-                goto err;
-            }
-            continue;
-        }
-
-        /* For SSLv2-compat, ignore leading 0-byte. */
-        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher);
-        if (c != NULL) {
-            if (!sk_SSL_CIPHER_push(sk, c)) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
-                *al = SSL_AD_INTERNAL_ERROR;
-                goto err;
-            }
-        }
-    }
-    if (PACKET_remaining(cipher_suites) > 0) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    if (skp != NULL)
-        *skp = sk;
-    return (sk);
- err:
-    if ((skp == NULL) || (*skp == NULL))
-        sk_SSL_CIPHER_free(sk);
-    return NULL;
-}
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 1caa3c8..3304a1d 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -625,7 +625,7 @@ STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
 
 STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s)
 {
-    if (s->type == SSL_ST_CONNECT) { /* we are in the client */
+    if (!s->server) { /* we are in the client */
         if (((s->version >> 8) == SSL3_VERSION_MAJOR) && (s->s3 != NULL))
             return (s->s3->tmp.ca_names);
         else
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 0b93db9..cbc4f59 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -112,6 +112,14 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE),
      "dtls1_send_server_key_exchange"},
     {ERR_FUNC(SSL_F_DTLS1_WRITE_APP_DATA_BYTES), "dtls1_write_app_data_bytes"},
+    {ERR_FUNC(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC),
+     "dtls_construct_change_cipher_spec"},
+    {ERR_FUNC(SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST),
+     "dtls_construct_hello_verify_request"},
+    {ERR_FUNC(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE),
+     "DTLS_GET_REASSEMBLED_MESSAGE"},
+    {ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
+    {ERR_FUNC(SSL_F_READ_STATE_MACHINE), "READ_STATE_MACHINE"},
     {ERR_FUNC(SSL_F_SSL3_ACCEPT), "ssl3_accept"},
     {ERR_FUNC(SSL_F_SSL3_ADD_CERT_TO_BUF), "SSL3_ADD_CERT_TO_BUF"},
     {ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "ssl3_callback_ctrl"},
@@ -313,6 +321,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
     {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "ssl_verify_cert_chain"},
     {ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
+    {ERR_FUNC(SSL_F_STATE_MACHINE), "STATE_MACHINE"},
     {ERR_FUNC(SSL_F_TLS12_CHECK_PEER_SIGALG), "tls12_check_peer_sigalg"},
     {ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"},
     {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "tls1_change_cipher_state"},
@@ -331,6 +340,54 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS1_PROCESS_HEARTBEAT), "tls1_process_heartbeat"},
     {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "tls1_setup_key_block"},
     {ERR_FUNC(SSL_F_TLS1_SET_SERVER_SIGALGS), "tls1_set_server_sigalgs"},
+    {ERR_FUNC(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK),
+     "tls_client_key_exchange_post_work"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST),
+     "tls_construct_certificate_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE),
+     "tls_construct_client_certificate"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO), "tls_construct_client_hello"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE),
+     "tls_construct_client_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY),
+     "tls_construct_client_verify"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_FINISHED), "tls_construct_finished"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST),
+     "tls_construct_hello_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE),
+     "tls_construct_server_certificate"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_DONE), "tls_construct_server_done"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_HELLO), "tls_construct_server_hello"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE),
+     "tls_construct_server_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"},
+    {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"},
+    {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO),
+     "tls_post_process_client_hello"},
+    {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE),
+     "tls_post_process_client_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE),
+     "tls_prepare_client_certificate"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST),
+     "tls_process_certificate_request"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CERT_STATUS), "tls_process_cert_status"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CERT_VERIFY), "tls_process_cert_verify"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC),
+     "tls_process_change_cipher_spec"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE),
+     "tls_process_client_certificate"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CLIENT_HELLO), "tls_process_client_hello"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE),
+     "tls_process_client_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET),
+     "tls_process_new_session_ticket"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_NEXT_PROTO), "tls_process_next_proto"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE),
+     "tls_process_server_certificate"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SERVER_DONE), "tls_process_server_done"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SERVER_HELLO), "tls_process_server_hello"},
     {ERR_FUNC(SSL_F_USE_CERTIFICATE_CHAIN_FILE), "use_certificate_chain_file"},
     {0, NULL}
 };
@@ -468,6 +525,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
      "invalid ticket keys length"},
     {ERR_REASON(SSL_R_INVALID_TRUST), "invalid trust"},
     {ERR_REASON(SSL_R_LENGTH_MISMATCH), "length mismatch"},
+    {ERR_REASON(SSL_R_LENGTH_TOO_LONG), "length too long"},
     {ERR_REASON(SSL_R_LENGTH_TOO_SHORT), "length too short"},
     {ERR_REASON(SSL_R_LIBRARY_BUG), "library bug"},
     {ERR_REASON(SSL_R_LIBRARY_HAS_NO_CIPHERS), "library has no ciphers"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index e80d5f1..7e30aba 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -215,9 +215,7 @@ int SSL_clear(SSL *s)
         return 0;
     }
 
-    s->type = 0;
-
-    s->state = SSL_ST_BEFORE | ((s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT);
+    ossl_statem_clear(s);
 
     s->version = s->method->version;
     s->client_version = s->version;
@@ -232,7 +230,7 @@ int SSL_clear(SSL *s)
      * Check to see if we were changed into a different method, if so, revert
      * back if we are not doing session-id reuse.
      */
-    if (!s->in_handshake && (s->session == NULL)
+    if (!ossl_statem_get_in_handshake(s) && (s->session == NULL)
         && (s->method != s->ctx->method)) {
         s->method->ssl_free(s);
         s->method = s->ctx->method;
@@ -1082,7 +1080,7 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
             return TLS_CIPHER_LEN;
         }
     case SSL_CTRL_GET_EXTMS_SUPPORT:
-        if (!s->session || SSL_in_init(s) || s->in_handshake)
+        if (!s->session || SSL_in_init(s) || ossl_statem_get_in_handshake(s))
 		return -1;
 	if (s->session->flags & SSL_SESS_FLAG_EXTMS)
             return 1;
@@ -2397,7 +2395,7 @@ void SSL_set_accept_state(SSL *s)
 {
     s->server = 1;
     s->shutdown = 0;
-    s->state = SSL_ST_ACCEPT | SSL_ST_BEFORE;
+    ossl_statem_clear(s);
     s->handshake_func = s->method->ssl_accept;
     clear_ciphers(s);
 }
@@ -2406,7 +2404,7 @@ void SSL_set_connect_state(SSL *s)
 {
     s->server = 0;
     s->shutdown = 0;
-    s->state = SSL_ST_CONNECT | SSL_ST_BEFORE;
+    ossl_statem_clear(s);
     s->handshake_func = s->method->ssl_connect;
     clear_ciphers(s);
 }
@@ -2468,7 +2466,6 @@ SSL *SSL_dup(SSL *s)
         return (NULL);
 
     ret->version = s->version;
-    ret->type = s->type;
     ret->method = s->method;
 
     if (s->session != NULL) {
@@ -2529,15 +2526,14 @@ SSL *SSL_dup(SSL *s)
             ret->wbio = ret->rbio;
     }
     ret->rwstate = s->rwstate;
-    ret->in_handshake = s->in_handshake;
     ret->handshake_func = s->handshake_func;
     ret->server = s->server;
     ret->renegotiate = s->renegotiate;
     ret->new_session = s->new_session;
     ret->quiet_shutdown = s->quiet_shutdown;
     ret->shutdown = s->shutdown;
-    ret->state = s->state;      /* SSL_dup does not really work at any state,
-                                 * though */
+    ret->statem = s->statem;      /* SSL_dup does not really work at any state,
+                                   * though */
     RECORD_LAYER_dup(&ret->rlayer, &s->rlayer);
     ret->init_num = 0;          /* would have to copy ret->init_buf,
                                  * ret->init_msg, ret->init_num,
@@ -2839,16 +2835,6 @@ void (*SSL_get_info_callback(const SSL *ssl)) (const SSL * /* ssl */ ,
     return ssl->info_callback;
 }
 
-int SSL_state(const SSL *ssl)
-{
-    return (ssl->state);
-}
-
-void SSL_set_state(SSL *ssl, int state)
-{
-    ssl->state = state;
-}
-
 void SSL_set_verify_result(SSL *ssl, long arg)
 {
     ssl->verify_result = arg;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index ad6ae0e..56ec70f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -166,6 +166,7 @@
 # include <openssl/symhacks.h>
 
 #include "record/record.h"
+#include "statem/statem.h"
 #include "packet_locl.h"
 
 # ifdef OPENSSL_BUILD_SHLIBSSL
@@ -568,8 +569,6 @@ struct ssl_method_st {
     int (*ssl_shutdown) (SSL *s);
     int (*ssl_renegotiate) (SSL *s);
     int (*ssl_renegotiate_check) (SSL *s);
-    long (*ssl_get_message) (SSL *s, int st1, int stn, int mt, long
-                             max, int *ok);
     int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
                            unsigned char *buf, int len, int peek);
     int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, int len);
@@ -717,6 +716,7 @@ struct ssl_comp_st {
 DECLARE_STACK_OF(SSL_COMP)
 DECLARE_LHASH_OF(SSL_SESSION);
 
+
 struct ssl_ctx_st {
     const SSL_METHOD *method;
     STACK_OF(SSL_CIPHER) *cipher_list;
@@ -967,8 +967,7 @@ struct ssl_st {
      * DTLS1_VERSION)
      */
     int version;
-    /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
-    int type;
+
     /* SSLv3 */
     const SSL_METHOD *method;
     /*
@@ -987,8 +986,7 @@ struct ssl_st {
      * request needs re-doing when in SSL_accept or SSL_connect
      */
     int rwstate;
-    /* true when we are actually in SSL_accept() or SSL_connect() */
-    int in_handshake;
+
     int (*handshake_func) (SSL *);
     /*
      * Imagine that here's a boolean member "init" that is switched as soon
@@ -997,7 +995,7 @@ struct ssl_st {
      * handshake_func is == 0 until then, we use this test instead of an
      * "init" member.
      */
-    /* are we the server side? - mostly used by SSL_clear */
+    /* are we the server side? */
     int server;
     /*
      * Generate a new session or reuse an old one.
@@ -1011,7 +1009,8 @@ struct ssl_st {
     /* we have shut things down, 0x01 sent, 0x02 for received */
     int shutdown;
     /* where we are */
-    int state;
+    OSSL_STATEM statem;
+
     BUF_MEM *init_buf;          /* buffer used during init */
     void *init_msg;             /* pointer to handshake message body, set by
                                  * ssl3_get_message() */
@@ -1257,9 +1256,6 @@ typedef struct ssl3_state_st {
 #  ifndef OPENSSL_NO_EC
         EC_KEY *ecdh;           /* holds short lived ECDH key */
 #  endif
-        /* used when SSL_ST_FLUSH_DATA is entered */
-        int next_state;
-        int reuse_message;
         /* used for certificate requests */
         int cert_req;
         int ctype_num;
@@ -1419,9 +1415,9 @@ typedef struct hm_fragment_st {
 } hm_fragment;
 
 typedef struct dtls1_state_st {
-    unsigned int send_cookie;
     unsigned char cookie[DTLS1_COOKIE_LENGTH];
     unsigned int cookie_len;
+    unsigned int cookie_verified;
 
     /* handshake message numbers */
     unsigned short handshake_write_seq;
@@ -1447,8 +1443,6 @@ typedef struct dtls1_state_st {
 
     unsigned int retransmitting;
 #  ifndef OPENSSL_NO_SCTP
-    /* used when SSL_ST_XX_FLUSH is entered */
-    int next_state;
     int shutdown_received;
 #  endif
 } DTLS1_STATE;
@@ -1746,7 +1740,6 @@ const SSL_METHOD *func_name(void)  \
                 ssl3_shutdown, \
                 ssl3_renegotiate, \
                 ssl3_renegotiate_check, \
-                ssl3_get_message, \
                 ssl3_read_bytes, \
                 ssl3_write_bytes, \
                 ssl3_dispatch_alert, \
@@ -1783,7 +1776,6 @@ const SSL_METHOD *func_name(void)  \
                 ssl3_shutdown, \
                 ssl3_renegotiate, \
                 ssl3_renegotiate_check, \
-                ssl3_get_message, \
                 ssl3_read_bytes, \
                 ssl3_write_bytes, \
                 ssl3_dispatch_alert, \
@@ -1821,7 +1813,6 @@ const SSL_METHOD *func_name(void)  \
                 dtls1_shutdown, \
                 ssl3_renegotiate, \
                 ssl3_renegotiate_check, \
-                dtls1_get_message, \
                 dtls1_read_bytes, \
                 dtls1_write_app_data_bytes, \
                 dtls1_dispatch_alert, \
@@ -1915,13 +1906,7 @@ __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
 __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
 __owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p);
 void ssl3_init_finished_mac(SSL *s);
-__owur int ssl3_send_server_certificate(SSL *s);
-__owur int ssl3_send_newsession_ticket(SSL *s);
-__owur int ssl3_send_cert_status(SSL *s);
-__owur int ssl3_get_change_cipher_spec(SSL *s, int a, int b);
-__owur int ssl3_get_finished(SSL *s, int state_a, int state_b);
 __owur int ssl3_setup_key_block(SSL *s);
-__owur int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b);
 __owur int ssl3_change_cipher_state(SSL *s, int which);
 void ssl3_cleanup_key_block(SSL *s);
 __owur int ssl3_do_write(SSL *s, int type);
@@ -1929,8 +1914,6 @@ int ssl3_send_alert(SSL *s, int level, int desc);
 __owur int ssl3_generate_master_secret(SSL *s, unsigned char *out,
                                 unsigned char *p, int len);
 __owur int ssl3_get_req_cert_type(SSL *s, unsigned char *p);
-__owur long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
-__owur int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen);
 __owur int ssl3_num_ciphers(void);
 __owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
 int ssl3_renegotiate(SSL *ssl);
@@ -1947,8 +1930,6 @@ __owur SSL_CIPHER *ssl3_choose_cipher(SSL *ssl, STACK_OF(SSL_CIPHER) *clnt,
 __owur int ssl3_digest_cached_records(SSL *s, int keep);
 __owur int ssl3_new(SSL *s);
 void ssl3_free(SSL *s);
-__owur int ssl3_accept(SSL *s);
-__owur int ssl3_connect(SSL *s);
 __owur int ssl3_read(SSL *s, void *buf, int len);
 __owur int ssl3_peek(SSL *s, void *buf, int len);
 __owur int ssl3_write(SSL *s, const void *buf, int len);
@@ -1977,7 +1958,6 @@ void dtls1_set_message_header(SSL *s,
 
 __owur int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len);
 
-__owur int dtls1_send_change_cipher_spec(SSL *s, int a, int b);
 __owur int dtls1_read_failed(SSL *s, int code);
 __owur int dtls1_buffer_message(SSL *s, int ccs);
 __owur int dtls1_retransmit_message(SSL *s, unsigned short seq,
@@ -1996,47 +1976,13 @@ void dtls1_start_timer(SSL *s);
 void dtls1_stop_timer(SSL *s);
 __owur int dtls1_is_timer_expired(SSL *s);
 void dtls1_double_timeout(SSL *s);
-__owur unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
-                                                   unsigned char *cookie,
-                                                   unsigned char cookie_len);
+__owur unsigned int dtls_raw_hello_verify_request(unsigned char *buf,
+                                                  unsigned char *cookie,
+                                                  unsigned char cookie_len);
 __owur int dtls1_send_newsession_ticket(SSL *s);
 __owur unsigned int dtls1_min_mtu(SSL *s);
-__owur unsigned int dtls1_link_min_mtu(void);
 void dtls1_hm_fragment_free(hm_fragment *frag);
-
-/* some client-only functions */
-__owur int ssl3_client_hello(SSL *s);
-__owur int ssl3_get_server_hello(SSL *s);
-__owur int ssl3_get_certificate_request(SSL *s);
-__owur int ssl3_get_new_session_ticket(SSL *s);
-__owur int ssl3_get_cert_status(SSL *s);
-__owur int ssl3_get_server_done(SSL *s);
-__owur int ssl3_send_client_verify(SSL *s);
-__owur int ssl3_send_client_certificate(SSL *s);
-__owur int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
-__owur int ssl3_send_client_key_exchange(SSL *s);
-__owur int ssl3_get_key_exchange(SSL *s);
-__owur int ssl3_get_server_certificate(SSL *s);
-__owur int ssl3_check_cert_and_algorithm(SSL *s);
-#  ifndef OPENSSL_NO_NEXTPROTONEG
-__owur int ssl3_send_next_proto(SSL *s);
-#  endif
-
-int dtls1_client_hello(SSL *s);
-
-/* some server-only functions */
-__owur int ssl3_get_client_hello(SSL *s);
-__owur int ssl3_send_server_hello(SSL *s);
-__owur int ssl3_send_hello_request(SSL *s);
-__owur int ssl3_send_server_key_exchange(SSL *s);
-__owur int ssl3_send_certificate_request(SSL *s);
-__owur int ssl3_send_server_done(SSL *s);
-__owur int ssl3_get_client_certificate(SSL *s);
-__owur int ssl3_get_client_key_exchange(SSL *s);
-__owur int ssl3_get_cert_verify(SSL *s);
-#  ifndef OPENSSL_NO_NEXTPROTONEG
-__owur int ssl3_get_next_proto(SSL *s);
-#  endif
+__owur int dtls1_query_mtu(SSL *s);
 
 __owur int tls1_new(SSL *s);
 void tls1_free(SSL *s);
@@ -2045,14 +1991,11 @@ long tls1_ctrl(SSL *s, int cmd, long larg, void *parg);
 long tls1_callback_ctrl(SSL *s, int cmd, void (*fp) (void));
 
 __owur int dtls1_new(SSL *s);
-__owur int dtls1_accept(SSL *s);
-__owur int dtls1_connect(SSL *s);
 void dtls1_free(SSL *s);
 void dtls1_clear(SSL *s);
 long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg);
 __owur int dtls1_shutdown(SSL *s);
 
-__owur long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
 __owur int dtls1_dispatch_alert(SSL *s);
 
 __owur int ssl_init_wbio_buffer(SSL *s, int push);
diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c
index f59553b..3bd7843 100644
--- a/ssl/ssl_stat.c
+++ b/ssl/ssl_stat.c
@@ -89,231 +89,107 @@ const char *SSL_state_string_long(const SSL *s)
 {
     const char *str;
 
-    switch (s->state) {
-    case SSL_ST_BEFORE:
+    if (ossl_statem_in_error(s)) {
+        return "error";
+    }
+
+    switch (SSL_get_state(s)) {
+    case TLS_ST_BEFORE:
         str = "before SSL initialization";
         break;
-    case SSL_ST_ACCEPT:
-        str = "before accept initialization";
-        break;
-    case SSL_ST_CONNECT:
-        str = "before connect initialization";
-        break;
-    case SSL_ST_OK:
+    case TLS_ST_OK:
         str = "SSL negotiation finished successfully";
         break;
-    case SSL_ST_RENEGOTIATE:
-        str = "SSL renegotiate ciphers";
-        break;
-    case SSL_ST_BEFORE | SSL_ST_CONNECT:
-        str = "before/connect initialization";
-        break;
-    case SSL_ST_OK | SSL_ST_CONNECT:
-        str = "ok/connect SSL initialization";
-        break;
-    case SSL_ST_BEFORE | SSL_ST_ACCEPT:
-        str = "before/accept initialization";
-        break;
-    case SSL_ST_OK | SSL_ST_ACCEPT:
-        str = "ok/accept SSL initialization";
-        break;
-    case SSL_ST_ERR:
-        str = "error";
-        break;
 
-#ifndef OPENSSL_NO_SSL3
 /* SSLv3 additions */
-    case SSL3_ST_CW_CLNT_HELLO_A:
-        str = "SSLv3 write client hello A";
-        break;
-    case SSL3_ST_CW_CLNT_HELLO_B:
-        str = "SSLv3 write client hello B";
-        break;
-    case SSL3_ST_CR_SRVR_HELLO_A:
-        str = "SSLv3 read server hello A";
-        break;
-    case SSL3_ST_CR_SRVR_HELLO_B:
-        str = "SSLv3 read server hello B";
-        break;
-    case SSL3_ST_CR_CERT_A:
-        str = "SSLv3 read server certificate A";
-        break;
-    case SSL3_ST_CR_CERT_B:
-        str = "SSLv3 read server certificate B";
-        break;
-    case SSL3_ST_CR_KEY_EXCH_A:
-        str = "SSLv3 read server key exchange A";
-        break;
-    case SSL3_ST_CR_KEY_EXCH_B:
-        str = "SSLv3 read server key exchange B";
-        break;
-    case SSL3_ST_CR_CERT_REQ_A:
-        str = "SSLv3 read server certificate request A";
-        break;
-    case SSL3_ST_CR_CERT_REQ_B:
-        str = "SSLv3 read server certificate request B";
-        break;
-    case SSL3_ST_CR_SESSION_TICKET_A:
-        str = "SSLv3 read server session ticket A";
+    case TLS_ST_CW_CLNT_HELLO:
+        str = "SSLv3/TLS write client hello";
         break;
-    case SSL3_ST_CR_SESSION_TICKET_B:
-        str = "SSLv3 read server session ticket B";
+    case TLS_ST_CR_SRVR_HELLO:
+        str = "SSLv3/TLS read server hello";
         break;
-    case SSL3_ST_CR_SRVR_DONE_A:
-        str = "SSLv3 read server done A";
+    case TLS_ST_CR_CERT:
+        str = "SSLv3/TLS read server certificate";
         break;
-    case SSL3_ST_CR_SRVR_DONE_B:
-        str = "SSLv3 read server done B";
+    case TLS_ST_CR_KEY_EXCH:
+        str = "SSLv3/TLS read server key exchange";
         break;
-    case SSL3_ST_CW_CERT_A:
-        str = "SSLv3 write client certificate A";
+    case TLS_ST_CR_CERT_REQ:
+        str = "SSLv3/TLS read server certificate request";
         break;
-    case SSL3_ST_CW_CERT_B:
-        str = "SSLv3 write client certificate B";
+    case TLS_ST_CR_SESSION_TICKET:
+        str = "SSLv3/TLS read server session ticket";
         break;
-    case SSL3_ST_CW_CERT_C:
-        str = "SSLv3 write client certificate C";
+    case TLS_ST_CR_SRVR_DONE:
+        str = "SSLv3/TLS read server done";
         break;
-    case SSL3_ST_CW_CERT_D:
-        str = "SSLv3 write client certificate D";
+    case TLS_ST_CW_CERT:
+        str = "SSLv3/TLS write client certificate";
         break;
-    case SSL3_ST_CW_KEY_EXCH_A:
-        str = "SSLv3 write client key exchange A";
+    case TLS_ST_CW_KEY_EXCH:
+        str = "SSLv3/TLS write client key exchange";
         break;
-    case SSL3_ST_CW_KEY_EXCH_B:
-        str = "SSLv3 write client key exchange B";
-        break;
-    case SSL3_ST_CW_CERT_VRFY_A:
-        str = "SSLv3 write certificate verify A";
-        break;
-    case SSL3_ST_CW_CERT_VRFY_B:
-        str = "SSLv3 write certificate verify B";
+    case TLS_ST_CW_CERT_VRFY:
+        str = "SSLv3/TLS write certificate verify";
         break;
 
-    case SSL3_ST_CW_CHANGE_A:
-    case SSL3_ST_SW_CHANGE_A:
-        str = "SSLv3 write change cipher spec A";
-        break;
-    case SSL3_ST_CW_CHANGE_B:
-    case SSL3_ST_SW_CHANGE_B:
-        str = "SSLv3 write change cipher spec B";
-        break;
-    case SSL3_ST_CW_FINISHED_A:
-    case SSL3_ST_SW_FINISHED_A:
-        str = "SSLv3 write finished A";
-        break;
-    case SSL3_ST_CW_FINISHED_B:
-    case SSL3_ST_SW_FINISHED_B:
-        str = "SSLv3 write finished B";
+    case TLS_ST_CW_CHANGE:
+    case TLS_ST_SW_CHANGE:
+        str = "SSLv3/TLS write change cipher spec";
         break;
-    case SSL3_ST_CR_CHANGE_A:
-    case SSL3_ST_SR_CHANGE_A:
-        str = "SSLv3 read change cipher spec A";
+    case TLS_ST_CW_FINISHED:
+    case TLS_ST_SW_FINISHED:
+        str = "SSLv3/TLS write finished";
         break;
-    case SSL3_ST_CR_CHANGE_B:
-    case SSL3_ST_SR_CHANGE_B:
-        str = "SSLv3 read change cipher spec B";
+    case TLS_ST_CR_CHANGE:
+    case TLS_ST_SR_CHANGE:
+        str = "SSLv3/TLS read change cipher spec";
         break;
-    case SSL3_ST_CR_FINISHED_A:
-    case SSL3_ST_SR_FINISHED_A:
-        str = "SSLv3 read finished A";
-        break;
-    case SSL3_ST_CR_FINISHED_B:
-    case SSL3_ST_SR_FINISHED_B:
-        str = "SSLv3 read finished B";
-        break;
-
-    case SSL3_ST_CW_FLUSH:
-    case SSL3_ST_SW_FLUSH:
-        str = "SSLv3 flush data";
+    case TLS_ST_CR_FINISHED:
+    case TLS_ST_SR_FINISHED:
+        str = "SSLv3/TLS read finished";
         break;
 
-    case SSL3_ST_SR_CLNT_HELLO_A:
-        str = "SSLv3 read client hello A";
-        break;
-    case SSL3_ST_SR_CLNT_HELLO_B:
-        str = "SSLv3 read client hello B";
-        break;
-    case SSL3_ST_SR_CLNT_HELLO_C:
-        str = "SSLv3 read client hello C";
-        break;
-    case SSL3_ST_SW_HELLO_REQ_A:
-        str = "SSLv3 write hello request A";
-        break;
-    case SSL3_ST_SW_HELLO_REQ_B:
-        str = "SSLv3 write hello request B";
-        break;
-    case SSL3_ST_SW_HELLO_REQ_C:
-        str = "SSLv3 write hello request C";
-        break;
-    case SSL3_ST_SW_SRVR_HELLO_A:
-        str = "SSLv3 write server hello A";
-        break;
-    case SSL3_ST_SW_SRVR_HELLO_B:
-        str = "SSLv3 write server hello B";
-        break;
-    case SSL3_ST_SW_CERT_A:
-        str = "SSLv3 write certificate A";
-        break;
-    case SSL3_ST_SW_CERT_B:
-        str = "SSLv3 write certificate B";
-        break;
-    case SSL3_ST_SW_KEY_EXCH_A:
-        str = "SSLv3 write key exchange A";
-        break;
-    case SSL3_ST_SW_KEY_EXCH_B:
-        str = "SSLv3 write key exchange B";
-        break;
-    case SSL3_ST_SW_CERT_REQ_A:
-        str = "SSLv3 write certificate request A";
+    case TLS_ST_SR_CLNT_HELLO:
+        str = "SSLv3/TLS read client hello";
         break;
-    case SSL3_ST_SW_CERT_REQ_B:
-        str = "SSLv3 write certificate request B";
+    case TLS_ST_SW_HELLO_REQ:
+        str = "SSLv3/TLS write hello request";
         break;
-    case SSL3_ST_SW_SESSION_TICKET_A:
-        str = "SSLv3 write session ticket A";
+    case TLS_ST_SW_SRVR_HELLO:
+        str = "SSLv3/TLS write server hello";
         break;
-    case SSL3_ST_SW_SESSION_TICKET_B:
-        str = "SSLv3 write session ticket B";
+    case TLS_ST_SW_CERT:
+        str = "SSLv3/TLS write certificate";
         break;
-    case SSL3_ST_SW_SRVR_DONE_A:
-        str = "SSLv3 write server done A";
+    case TLS_ST_SW_KEY_EXCH:
+        str = "SSLv3/TLS write key exchange";
         break;
-    case SSL3_ST_SW_SRVR_DONE_B:
-        str = "SSLv3 write server done B";
+    case TLS_ST_SW_CERT_REQ:
+        str = "SSLv3/TLS write certificate request";
         break;
-    case SSL3_ST_SR_CERT_A:
-        str = "SSLv3 read client certificate A";
+    case TLS_ST_SW_SESSION_TICKET:
+        str = "SSLv3/TLS write session ticket";
         break;
-    case SSL3_ST_SR_CERT_B:
-        str = "SSLv3 read client certificate B";
+    case TLS_ST_SW_SRVR_DONE:
+        str = "SSLv3/TLS write server done";
         break;
-    case SSL3_ST_SR_KEY_EXCH_A:
-        str = "SSLv3 read client key exchange A";
+    case TLS_ST_SR_CERT:
+        str = "SSLv3/TLS read client certificate";
         break;
-    case SSL3_ST_SR_KEY_EXCH_B:
-        str = "SSLv3 read client key exchange B";
+    case TLS_ST_SR_KEY_EXCH:
+        str = "SSLv3/TLS read client key exchange";
         break;
-    case SSL3_ST_SR_CERT_VRFY_A:
-        str = "SSLv3 read certificate verify A";
+    case TLS_ST_SR_CERT_VRFY:
+        str = "SSLv3/TLS read certificate verify";
         break;
-    case SSL3_ST_SR_CERT_VRFY_B:
-        str = "SSLv3 read certificate verify B";
-        break;
-#endif
 
 /* DTLS */
-    case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
-        str = "DTLS1 read hello verify request A";
-        break;
-    case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
-        str = "DTLS1 read hello verify request B";
-        break;
-    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
-        str = "DTLS1 write hello verify request A";
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        str = "DTLS1 read hello verify request";
         break;
-    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
-        str = "DTLS1 write hello verify request B";
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        str = "DTLS1 write hello verify request";
         break;
 
     default:
@@ -328,203 +204,100 @@ const char *SSL_state_string(const SSL *s)
 {
     const char *str;
 
-    switch (s->state) {
-    case SSL_ST_BEFORE:
+    if (ossl_statem_in_error(s)) {
+        return "SSLERR";
+    }
+
+    switch (SSL_get_state(s)) {
+    case TLS_ST_BEFORE:
         str = "PINIT ";
         break;
-    case SSL_ST_ACCEPT:
-        str = "AINIT ";
-        break;
-    case SSL_ST_CONNECT:
-        str = "CINIT ";
-        break;
-    case SSL_ST_OK:
+    case TLS_ST_OK:
         str = "SSLOK ";
         break;
-    case SSL_ST_ERR:
-        str = "SSLERR";
-        break;
 
-#ifndef OPENSSL_NO_SSL3
-/* SSLv3 additions */
-    case SSL3_ST_SW_FLUSH:
-    case SSL3_ST_CW_FLUSH:
-        str = "3FLUSH";
-        break;
-    case SSL3_ST_CW_CLNT_HELLO_A:
-        str = "3WCH_A";
-        break;
-    case SSL3_ST_CW_CLNT_HELLO_B:
-        str = "3WCH_B";
-        break;
-    case SSL3_ST_CR_SRVR_HELLO_A:
-        str = "3RSH_A";
-        break;
-    case SSL3_ST_CR_SRVR_HELLO_B:
-        str = "3RSH_B";
-        break;
-    case SSL3_ST_CR_CERT_A:
-        str = "3RSC_A";
-        break;
-    case SSL3_ST_CR_CERT_B:
-        str = "3RSC_B";
-        break;
-    case SSL3_ST_CR_KEY_EXCH_A:
-        str = "3RSKEA";
-        break;
-    case SSL3_ST_CR_KEY_EXCH_B:
-        str = "3RSKEB";
-        break;
-    case SSL3_ST_CR_CERT_REQ_A:
-        str = "3RCR_A";
-        break;
-    case SSL3_ST_CR_CERT_REQ_B:
-        str = "3RCR_B";
-        break;
-    case SSL3_ST_CR_SRVR_DONE_A:
-        str = "3RSD_A";
+    case TLS_ST_CW_CLNT_HELLO:
+        str = "TWCH";
         break;
-    case SSL3_ST_CR_SRVR_DONE_B:
-        str = "3RSD_B";
+    case TLS_ST_CR_SRVR_HELLO:
+        str = "TRSH";
         break;
-    case SSL3_ST_CW_CERT_A:
-        str = "3WCC_A";
+    case TLS_ST_CR_CERT:
+        str = "TRSC";
         break;
-    case SSL3_ST_CW_CERT_B:
-        str = "3WCC_B";
+    case TLS_ST_CR_KEY_EXCH:
+        str = "TRSKE";
         break;
-    case SSL3_ST_CW_CERT_C:
-        str = "3WCC_C";
+    case TLS_ST_CR_CERT_REQ:
+        str = "TRCR";
         break;
-    case SSL3_ST_CW_CERT_D:
-        str = "3WCC_D";
+    case TLS_ST_CR_SRVR_DONE:
+        str = "TRSD";
         break;
-    case SSL3_ST_CW_KEY_EXCH_A:
-        str = "3WCKEA";
+    case TLS_ST_CW_CERT:
+        str = "TWCC";
         break;
-    case SSL3_ST_CW_KEY_EXCH_B:
-        str = "3WCKEB";
+    case TLS_ST_CW_KEY_EXCH:
+        str = "TWCKE";
         break;
-    case SSL3_ST_CW_CERT_VRFY_A:
-        str = "3WCV_A";
-        break;
-    case SSL3_ST_CW_CERT_VRFY_B:
-        str = "3WCV_B";
+    case TLS_ST_CW_CERT_VRFY:
+        str = "TWCV";
         break;
 
-    case SSL3_ST_SW_CHANGE_A:
-    case SSL3_ST_CW_CHANGE_A:
-        str = "3WCCSA";
-        break;
-    case SSL3_ST_SW_CHANGE_B:
-    case SSL3_ST_CW_CHANGE_B:
-        str = "3WCCSB";
-        break;
-    case SSL3_ST_SW_FINISHED_A:
-    case SSL3_ST_CW_FINISHED_A:
-        str = "3WFINA";
-        break;
-    case SSL3_ST_SW_FINISHED_B:
-    case SSL3_ST_CW_FINISHED_B:
-        str = "3WFINB";
-        break;
-    case SSL3_ST_SR_CHANGE_A:
-    case SSL3_ST_CR_CHANGE_A:
-        str = "3RCCSA";
+    case TLS_ST_SW_CHANGE:
+    case TLS_ST_CW_CHANGE:
+        str = "TWCCS";
         break;
-    case SSL3_ST_SR_CHANGE_B:
-    case SSL3_ST_CR_CHANGE_B:
-        str = "3RCCSB";
+    case TLS_ST_SW_FINISHED:
+    case TLS_ST_CW_FINISHED:
+        str = "TWFIN";
         break;
-    case SSL3_ST_SR_FINISHED_A:
-    case SSL3_ST_CR_FINISHED_A:
-        str = "3RFINA";
+    case TLS_ST_SR_CHANGE:
+    case TLS_ST_CR_CHANGE:
+        str = "TRCCS";
         break;
-    case SSL3_ST_SR_FINISHED_B:
-    case SSL3_ST_CR_FINISHED_B:
-        str = "3RFINB";
+    case TLS_ST_SR_FINISHED:
+    case TLS_ST_CR_FINISHED:
+        str = "TRFIN";
         break;
 
-    case SSL3_ST_SW_HELLO_REQ_A:
-        str = "3WHR_A";
-        break;
-    case SSL3_ST_SW_HELLO_REQ_B:
-        str = "3WHR_B";
-        break;
-    case SSL3_ST_SW_HELLO_REQ_C:
-        str = "3WHR_C";
-        break;
-    case SSL3_ST_SR_CLNT_HELLO_A:
-        str = "3RCH_A";
-        break;
-    case SSL3_ST_SR_CLNT_HELLO_B:
-        str = "3RCH_B";
-        break;
-    case SSL3_ST_SR_CLNT_HELLO_C:
-        str = "3RCH_C";
+    case TLS_ST_SW_HELLO_REQ:
+        str = "TWHR";
         break;
-    case SSL3_ST_SW_SRVR_HELLO_A:
-        str = "3WSH_A";
+    case TLS_ST_SR_CLNT_HELLO:
+        str = "TRCH";
         break;
-    case SSL3_ST_SW_SRVR_HELLO_B:
-        str = "3WSH_B";
+    case TLS_ST_SW_SRVR_HELLO:
+        str = "TWSH";
         break;
-    case SSL3_ST_SW_CERT_A:
-        str = "3WSC_A";
+    case TLS_ST_SW_CERT:
+        str = "TWSC";
         break;
-    case SSL3_ST_SW_CERT_B:
-        str = "3WSC_B";
+    case TLS_ST_SW_KEY_EXCH:
+        str = "TWSKE";
         break;
-    case SSL3_ST_SW_KEY_EXCH_A:
-        str = "3WSKEA";
+    case TLS_ST_SW_CERT_REQ:
+        str = "TWCR";
         break;
-    case SSL3_ST_SW_KEY_EXCH_B:
-        str = "3WSKEB";
+    case TLS_ST_SW_SRVR_DONE:
+        str = "TWSD";
         break;
-    case SSL3_ST_SW_CERT_REQ_A:
-        str = "3WCR_A";
+    case TLS_ST_SR_CERT:
+        str = "TRCC";
         break;
-    case SSL3_ST_SW_CERT_REQ_B:
-        str = "3WCR_B";
+    case TLS_ST_SR_KEY_EXCH:
+        str = "TRCKE";
         break;
-    case SSL3_ST_SW_SRVR_DONE_A:
-        str = "3WSD_A";
+    case TLS_ST_SR_CERT_VRFY:
+        str = "TRCV";
         break;
-    case SSL3_ST_SW_SRVR_DONE_B:
-        str = "3WSD_B";
-        break;
-    case SSL3_ST_SR_CERT_A:
-        str = "3RCC_A";
-        break;
-    case SSL3_ST_SR_CERT_B:
-        str = "3RCC_B";
-        break;
-    case SSL3_ST_SR_KEY_EXCH_A:
-        str = "3RCKEA";
-        break;
-    case SSL3_ST_SR_KEY_EXCH_B:
-        str = "3RCKEB";
-        break;
-    case SSL3_ST_SR_CERT_VRFY_A:
-        str = "3RCV_A";
-        break;
-    case SSL3_ST_SR_CERT_VRFY_B:
-        str = "3RCV_B";
-        break;
-#endif
 
 /* DTLS */
-    case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
-        str = "DRCHVA";
-        break;
-    case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
-        str = "DRCHVB";
-        break;
-    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
-        str = "DWCHVA";
+    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        str = "DRCHV";
         break;
-    case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
-        str = "DWCHVB";
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        str = "DWCHV";
         break;
 
     default:
diff --git a/ssl/statem/README b/ssl/statem/README
new file mode 100644
index 0000000..145c69d
--- /dev/null
+++ b/ssl/statem/README
@@ -0,0 +1,63 @@
+State Machine Design
+====================
+
+This file provides some guidance on the thinking behind the design of the
+state machine code to aid future maintenance.
+
+The state machine code replaces an older state machine present in OpenSSL
+versions 1.0.2 and below. The new state machine has the following objectives:
+    - Remove duplication of state code between client and server
+    - Remove duplication of state code between TLS and DTLS
+    - Simplify transitions and bring the logic together in a single location
+      so that it is easier to validate
+    - Remove duplication of code between each of the message handling functions
+    - Receive a message first and then work out whether that is a valid
+      transition - not the other way around (the other way causes lots of issues
+      where we are expecting one type of message next but actually get something
+      else)
+    - Separate message flow state from handshake state (in order to better
+      understand each)
+      - message flow state = when to flush buffers; handling restarts in the
+        event of NBIO events; handling the common flow of steps for reading a
+        message and the common flow of steps for writing a message etc
+      - handshake state = what handshake message are we working on now
+    - Control complexity: only the state machine can change state: keep all
+      the state changes local to the state machine component
+
+The message flow state machine is divided into a reading sub-state machine and a
+writing sub-state machine. See the source comments in statem.c for a more
+detailed description of the various states and transitions possible.
+
+Conceptually the state machine component is designed as follows:
+
+                        libssl
+                           |
+---------------------------|-----statem.h--------------------------------------
+                           |
+                    _______V____________________
+                   |                            |
+                   |    statem.c                |
+                   |                            |
+                   |    Core state machine code |
+                   |____________________________|
+        statem_locl.h     ^          ^
+                 _________|          |_______
+                |                            |
+   _____________|____________   _____________|____________
+  |                          | |                          |
+  | statem_clnt.c            | | statem_srvr.c            |
+  |                          | |                          |
+  | TLS/DTLS client specific | | TLS/DTLS server specific |
+  | state machine code       | | state machine code       |
+  |__________________________| |__________________________|
+               |        |_______________|__       |
+               |        ________________|  |      |
+               |       |                   |      |
+   ____________V_______V________   ________V______V_______________
+  |                             | |                               |
+  | statem_both.c               | | statem_dtls.c                 |
+  |                             | |                               |
+  | Non core functions common   | | Non core functions common to  |
+  | to both servers and clients | | both DTLS servers and clients |
+  |_____________________________| |_______________________________|
+
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
new file mode 100644
index 0000000..3a44846
--- /dev/null
+++ b/ssl/statem/statem.c
@@ -0,0 +1,891 @@
+/* ssl/statem/statem.c */
+/*
+ * Written by Matt Caswell for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+#include <openssl/rand.h>
+#include "../ssl_locl.h"
+#include "statem_locl.h"
+
+/*
+ * This file implements the SSL/TLS/DTLS state machines.
+ *
+ * There are two primary state machines:
+ *
+ * 1) Message flow state machine
+ * 2) Handshake state machine
+ *
+ * The Message flow state machine controls the reading and sending of messages
+ * including handling of non-blocking IO events, flushing of the underlying
+ * write BIO, handling unexpected messages, etc. It is itself broken into two
+ * separate sub-state machines which control reading and writing respectively.
+ *
+ * The Handshake state machine keeps track of the current SSL/TLS handshake
+ * state. Transitions of the handshake state are the result of events that
+ * occur within the Message flow state machine.
+ *
+ * Overall it looks like this:
+ *
+ * ---------------------------------------------            -------------------
+ * |                                           |            |                 |
+ * | Message flow state machine                |            |                 |
+ * |                                           |            |                 |
+ * | -------------------- -------------------- | Transition | Handshake state |
+ * | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event      | machine         |
+ * | | sub-state        | | sub-state        | |----------->|                 |
+ * | | machine for      | | machine for      | |            |                 |
+ * | | reading messages | | writing messages | |            |                 |
+ * | -------------------- -------------------- |            |                 |
+ * |                                           |            |                 |
+ * ---------------------------------------------            -------------------
+ *
+ */
+
+/* Sub state machine return values */
+typedef enum  {
+    /* Something bad happened or NBIO */
+    SUB_STATE_ERROR,
+    /* Sub state finished go to the next sub state */
+    SUB_STATE_FINISHED,
+    /* Sub state finished and handshake was completed */
+    SUB_STATE_END_HANDSHAKE
+} SUB_STATE_RETURN;
+
+static int state_machine(SSL *s, int server);
+static void init_read_state_machine(SSL *s);
+static SUB_STATE_RETURN read_state_machine(SSL *s);
+static void init_write_state_machine(SSL *s);
+static SUB_STATE_RETURN write_state_machine(SSL *s);
+
+OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl)
+{
+    return ssl->statem.hand_state;
+}
+
+int SSL_in_init(SSL *s)
+{
+    return s->statem.in_init;
+}
+
+int SSL_is_init_finished(SSL *s)
+{
+    return !(s->statem.in_init) && (s->statem.hand_state == TLS_ST_OK);
+}
+
+int SSL_in_before(SSL *s)
+{
+    /*
+     * Historically being "in before" meant before anything had happened. In the
+     * current code though we remain in the "before" state for a while after we
+     * have started the handshake process (e.g. as a server waiting for the
+     * first message to arrive). There "in before" is taken to mean "in before"
+     * and not started any handshake process yet.
+     */
+    return (s->statem.hand_state == TLS_ST_BEFORE)
+        && (s->statem.state == MSG_FLOW_UNINITED);
+}
+
+/*
+ * Clear the state machine state and reset back to MSG_FLOW_UNINITED
+ */
+void ossl_statem_clear(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.hand_state = TLS_ST_BEFORE;
+    s->statem.in_init = 1;
+    s->statem.no_cert_verify = 0;
+}
+
+/*
+ * Set the state machine up ready for a renegotiation handshake
+ */
+void ossl_statem_set_renegotiate(SSL *s)
+{
+    s->statem.state = MSG_FLOW_RENEGOTIATE;
+    s->statem.in_init = 1;
+}
+
+/*
+ * Put the state machine into an error state. This is a permanent error for
+ * the current connection.
+ */
+void ossl_statem_set_error(SSL *s)
+{
+    s->statem.state = MSG_FLOW_ERROR;
+}
+
+/*
+ * Discover whether the current connection is in the error state.
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+int ossl_statem_in_error(const SSL *s)
+{
+    if (s->statem.state == MSG_FLOW_ERROR)
+        return 1;
+
+    return 0;
+}
+
+void ossl_statem_set_in_init(SSL *s, int init)
+{
+    s->statem.in_init = init;
+}
+
+int ossl_statem_get_in_handshake(SSL *s)
+{
+    return s->statem.in_handshake;
+}
+
+void ossl_statem_set_in_handshake(SSL *s, int inhand)
+{
+    if (inhand)
+        s->statem.in_handshake++;
+    else
+        s->statem.in_handshake--;
+}
+
+void ossl_statem_set_hello_verify_done(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.in_init = 1;
+    /*
+     * This will get reset (briefly) back to TLS_ST_BEFORE when we enter
+     * state_machine() because |state| is MSG_FLOW_UNINITED, but until then any
+     * calls to SSL_in_before() will return false. Also calls to
+     * SSL_state_string() and SSL_state_string_long() will return something
+     * sensible.
+     */
+    s->statem.hand_state = TLS_ST_SR_CLNT_HELLO;
+}
+
+int ossl_statem_connect(SSL *s) {
+    return state_machine(s, 0);
+}
+
+int ossl_statem_accept(SSL *s)
+{
+    return state_machine(s, 1);
+}
+
+static void (*get_callback(SSL *s))(const SSL *, int, int)
+{
+    if (s->info_callback != NULL)
+        return s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        return s->ctx->info_callback;
+
+    return NULL;
+}
+
+/*
+ * 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
+ * transitions are as follows:
+ *
+ * MSG_FLOW_UNINITED     MSG_FLOW_RENEGOTIATE
+ *        |                       |
+ *        +-----------------------+
+ *        v
+ * MSG_FLOW_WRITING <---> MSG_FLOW_READING
+ *        |
+ *        V
+ * MSG_FLOW_FINISHED
+ *        |
+ *        V
+ *    [SUCCESS]
+ *
+ * We may exit at any point due to an error or NBIO event. If an NBIO event
+ * occurs then we restart at the point we left off when we are recalled.
+ * MSG_FLOW_WRITING and MSG_FLOW_READING have sub-state machines associated with them.
+ *
+ * In addition to the above there is also the MSG_FLOW_ERROR state. We can move
+ * into that state at any point in the event that an irrecoverable error occurs.
+ *
+ * Valid return values are:
+ *   1: Success
+ * <=0: NBIO or error
+ */
+static int state_machine(SSL *s, int server) {
+    BUF_MEM *buf = NULL;
+    unsigned long Time = (unsigned long)time(NULL);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    OSSL_STATEM *st = &s->statem;
+    int ret = -1;
+    int ssret;
+
+    if (st->state == MSG_FLOW_ERROR) {
+        /* Shouldn't have been called if we're already in the error state */
+        return -1;
+    }
+
+    RAND_add(&Time, sizeof(Time), 0);
+    ERR_clear_error();
+    clear_sys_error();
+
+    cb = get_callback(s);
+
+    st->in_handshake++;
+    if (!SSL_in_init(s) || SSL_in_before(s)) {
+        if (!SSL_clear(s))
+            return -1;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        /*
+         * Notify SCTP BIO socket to enter handshake mode and prevent stream
+         * identifier other than 0. Will be ignored if no SCTP is used.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 st->in_handshake, NULL);
+    }
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+    /*
+     * If we're awaiting a HeartbeatResponse, pretend we already got and
+     * don't await it anymore, because Heartbeats don't make sense during
+     * handshakes anyway.
+     */
+    if (s->tlsext_hb_pending) {
+        if (SSL_IS_DTLS(s))
+            dtls1_stop_timer(s);
+        s->tlsext_hb_pending = 0;
+        s->tlsext_hb_seq++;
+    }
+#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->hand_state = TLS_ST_BEFORE;
+        }
+
+        s->server = server;
+        if (cb != NULL)
+            cb(s, SSL_CB_HANDSHAKE_START, 1);
+
+        if (SSL_IS_DTLS(s)) {
+            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
+                    (server
+                    || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
+                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        } else {
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR
+                    && s->version != TLS_ANY_VERSION) {
+                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        }
+
+        if (!SSL_IS_DTLS(s)) {
+            if (s->version != TLS_ANY_VERSION &&
+                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+                SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
+                goto end;
+            }
+        }
+
+        if (s->init_buf == NULL) {
+            if ((buf = BUF_MEM_new()) == NULL) {
+                goto end;
+            }
+            if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+                goto end;
+            }
+            s->init_buf = buf;
+            buf = NULL;
+        }
+
+        if (!ssl3_setup_buffers(s)) {
+            goto end;
+        }
+        s->init_num = 0;
+
+        /*
+         * Should have been reset by tls_process_finished, too.
+         */
+        s->s3->change_cipher_spec = 0;
+
+        if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
+                /*
+                 * Ok, we now need to push on a buffering BIO ...but not with
+                 * SCTP
+                 */
+#ifndef OPENSSL_NO_SCTP
+                if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
+#endif
+                    if (!ssl_init_wbio_buffer(s, server ? 1 : 0)) {
+                        goto end;
+                    }
+
+            ssl3_init_finished_mac(s);
+        }
+
+        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++;
+            }
+        } 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_request = 0;
+
+            if (SSL_IS_DTLS(s)) {
+                st->use_timer = 1;
+            }
+        }
+
+        st->state = MSG_FLOW_WRITING;
+        init_write_state_machine(s);
+        st->read_state_first_init = 1;
+    }
+
+    while(st->state != MSG_FLOW_FINISHED) {
+        if(st->state == MSG_FLOW_READING) {
+            ssret = read_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_WRITING;
+                init_write_state_machine(s);
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else if (st->state == MSG_FLOW_WRITING) {
+            ssret = write_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_READING;
+                init_read_state_machine(s);
+            } else if (ssret == SUB_STATE_END_HANDSHAKE) {
+                st->state = MSG_FLOW_FINISHED;
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else {
+            /* Error */
+            ossl_statem_set_error(s);
+            goto end;
+        }
+    }
+
+    st->state = MSG_FLOW_UNINITED;
+    ret = 1;
+
+ end:
+    st->in_handshake--;
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        /*
+         * Notify SCTP BIO socket to leave handshake mode and allow stream
+         * identifier other than 0. Will be ignored if no SCTP is used.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 st->in_handshake, NULL);
+    }
+#endif
+
+    BUF_MEM_free(buf);
+    if (cb != NULL) {
+        if (server)
+            cb(s, SSL_CB_ACCEPT_EXIT, ret);
+        else
+            cb(s, SSL_CB_CONNECT_EXIT, ret);
+    }
+    return ret;
+}
+
+/*
+ * Initialise the MSG_FLOW_READING sub-state machine
+ */
+static void init_read_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    st->read_state = READ_STATE_HEADER;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_READING. The valid sub-states and transitions are:
+ *
+ * READ_STATE_HEADER <--+<-------------+
+ *        |             |              |
+ *        v             |              |
+ * READ_STATE_BODY -----+-->READ_STATE_POST_PROCESS
+ *        |                            |
+ *        +----------------------------+
+ *        v
+ * [SUB_STATE_FINISHED]
+ *
+ * READ_STATE_HEADER has the responsibility for reading in the message header
+ * and transitioning the state of the handshake state machine.
+ *
+ * READ_STATE_BODY reads in the rest of the message and then subsequently
+ * processes it.
+ *
+ * READ_STATE_POST_PROCESS is an optional step that may occur if some post
+ * processing activity performed on the message may block.
+ *
+ * Any of the above states could result in an NBIO event occuring in which case
+ * control returns to the calling application. When this function is recalled we
+ * will resume in the same state where we left off.
+ */
+static SUB_STATE_RETURN read_state_machine(SSL *s) {
+    OSSL_STATEM *st = &s->statem;
+    int ret, mt;
+    unsigned long len = 0;
+    int (*transition)(SSL *s, int mt);
+    PACKET pkt;
+    MSG_PROCESS_RETURN (*process_message)(SSL *s, PACKET *pkt);
+    WORK_STATE (*post_process_message)(SSL *s, WORK_STATE wst);
+    unsigned long (*max_message_size)(SSL *s);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+    cb = get_callback(s);
+
+    if(s->server) {
+        transition = ossl_statem_server_read_transition;
+        process_message = ossl_statem_server_process_message;
+        max_message_size = ossl_statem_server_max_message_size;
+        post_process_message = ossl_statem_server_post_process_message;
+    } else {
+        transition = ossl_statem_client_read_transition;
+        process_message = ossl_statem_client_process_message;
+        max_message_size = ossl_statem_client_max_message_size;
+        post_process_message = ossl_statem_client_post_process_message;
+    }
+
+    if (st->read_state_first_init) {
+        s->first_packet = 1;
+        st->read_state_first_init = 0;
+    }
+
+    while(1) {
+        switch(st->read_state) {
+        case READ_STATE_HEADER:
+            s->init_num = 0;
+            /* Get the state the peer wants to move to */
+            if (SSL_IS_DTLS(s)) {
+                /*
+                 * In DTLS we get the whole message in one go - header and body
+                 */
+                ret = dtls_get_message(s, &mt, &len);
+            } else {
+                ret = tls_get_message_header(s, &mt);
+            }
+
+            if (ret == 0) {
+                /* Could be non-blocking IO */
+                return SUB_STATE_ERROR;
+            }
+
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            /*
+             * Validate that we are allowed to move to the new state and move
+             * to that state if so
+             */
+            if(!transition(s, mt)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_UNEXPECTED_MESSAGE);
+                return SUB_STATE_ERROR;
+            }
+
+            if (s->s3->tmp.message_size > max_message_size(s)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+                return SUB_STATE_ERROR;
+            }
+
+            st->read_state = READ_STATE_BODY;
+            /* Fall through */
+
+        case READ_STATE_BODY:
+            if (!SSL_IS_DTLS(s)) {
+                /* We already got this above for DTLS */
+                ret = tls_get_message_body(s, &len);
+                if (ret == 0) {
+                    /* Could be non-blocking IO */
+                    return SUB_STATE_ERROR;
+                }
+            }
+
+            s->first_packet = 0;
+            if (!PACKET_buf_init(&pkt, s->init_msg, len)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+                SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+            ret = process_message(s, &pkt);
+            if (ret == MSG_PROCESS_ERROR) {
+                return SUB_STATE_ERROR;
+            }
+
+            if (ret == MSG_PROCESS_FINISHED_READING) {
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+            }
+
+            if (ret == MSG_PROCESS_CONTINUE_PROCESSING) {
+                st->read_state = READ_STATE_POST_PROCESS;
+                st->read_state_work = WORK_MORE_A;
+            } else {
+                st->read_state = READ_STATE_HEADER;
+            }
+            break;
+
+        case READ_STATE_POST_PROCESS:
+            st->read_state_work = post_process_message(s, st->read_state_work);
+            switch(st->read_state_work) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->read_state = READ_STATE_HEADER;
+                break;
+
+            case WORK_FINISHED_STOP:
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+            }
+            break;
+
+        default:
+            /* Shouldn't happen */
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+            ossl_statem_set_error(s);
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Send a previously constructed message to the peer.
+ */
+static int statem_do_write(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    if (st->hand_state == TLS_ST_CW_CHANGE
+            || st->hand_state == TLS_ST_SW_CHANGE) {
+        if (SSL_IS_DTLS(s))
+            return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+        else
+            return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+    } else {
+        return ssl_do_write(s);
+    }
+}
+
+/*
+ * Initialise the MSG_FLOW_WRITING sub-state machine
+ */
+static void init_write_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    st->write_state = WRITE_STATE_TRANSITION;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_WRITING. The valid sub-states and transitions are:
+ *
+ * +-> WRITE_STATE_TRANSITION ------> [SUB_STATE_FINISHED]
+ * |             |
+ * |             v
+ * |      WRITE_STATE_PRE_WORK -----> [SUB_STATE_END_HANDSHAKE]
+ * |             |
+ * |             v
+ * |       WRITE_STATE_SEND
+ * |             |
+ * |             v
+ * |     WRITE_STATE_POST_WORK
+ * |             |
+ * +-------------+
+ *
+ * WRITE_STATE_TRANSITION transitions the state of the handshake state machine
+
+ * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later
+ * sending of the message. This could result in an NBIO event occuring in
+ * which case control returns to the calling application. When this function
+ * is recalled we will resume in the same state where we left off.
+ *
+ * WRITE_STATE_SEND sends the message and performs any work to be done after
+ * sending.
+ *
+ * WRITE_STATE_POST_WORK performs any work necessary after the sending of the
+ * message has been completed. As for WRITE_STATE_PRE_WORK this could also
+ * result in an NBIO event.
+ */
+static SUB_STATE_RETURN write_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+    int ret;
+    WRITE_TRAN (*transition)(SSL *s);
+    WORK_STATE (*pre_work)(SSL *s, WORK_STATE wst);
+    WORK_STATE (*post_work)(SSL *s, WORK_STATE wst);
+    int (*construct_message)(SSL *s);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+    cb = get_callback(s);
+
+    if(s->server) {
+        transition = ossl_statem_server_write_transition;
+        pre_work = ossl_statem_server_pre_work;
+        post_work = ossl_statem_server_post_work;
+        construct_message = ossl_statem_server_construct_message;
+    } else {
+        transition = ossl_statem_client_write_transition;
+        pre_work = ossl_statem_client_pre_work;
+        post_work = ossl_statem_client_post_work;
+        construct_message = ossl_statem_client_construct_message;
+    }
+
+    while(1) {
+        switch(st->write_state) {
+        case WRITE_STATE_TRANSITION:
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            switch(transition(s)) {
+            case WRITE_TRAN_CONTINUE:
+                st->write_state = WRITE_STATE_PRE_WORK;
+                st->write_state_work = WORK_MORE_A;
+                break;
+
+            case WRITE_TRAN_FINISHED:
+                return SUB_STATE_FINISHED;
+                break;
+
+            default:
+                return SUB_STATE_ERROR;
+            }
+            break;
+
+        case WRITE_STATE_PRE_WORK:
+            switch(st->write_state_work = pre_work(s, st->write_state_work)) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_SEND;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            if(construct_message(s) == 0)
+                return SUB_STATE_ERROR;
+
+            /* Fall through */
+
+        case WRITE_STATE_SEND:
+            if (SSL_IS_DTLS(s) && st->use_timer) {
+                dtls1_start_timer(s);
+            }
+            ret = statem_do_write(s);
+            if (ret <= 0) {
+                return SUB_STATE_ERROR;
+            }
+            st->write_state = WRITE_STATE_POST_WORK;
+            st->write_state_work = WORK_MORE_A;
+            /* Fall through */
+
+        case WRITE_STATE_POST_WORK:
+            switch(st->write_state_work = post_work(s, st->write_state_work)) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_TRANSITION;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            break;
+
+        default:
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Flush the write BIO
+ */
+int statem_flush(SSL *s)
+{
+    s->rwstate = SSL_WRITING;
+    if (BIO_flush(s->wbio) <= 0) {
+        return 0;
+    }
+    s->rwstate = SSL_NOTHING;
+
+    return 1;
+}
+
+/*
+ * Called by the record layer to determine whether application data is
+ * allowed to be sent in the current handshake state or not.
+ *
+ * Return values are:
+ *   1: Yes (application data allowed)
+ *   0: No (application data not allowed)
+ */
+int ossl_statem_app_data_allowed(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
+        return 0;
+
+    if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
+        return 0;
+
+    if (s->server) {
+        /*
+         * If we're a server and we haven't got as far as writing our
+         * ServerHello yet then we allow app data
+         */
+        if (st->hand_state == TLS_ST_BEFORE
+                || st->hand_state == TLS_ST_SR_CLNT_HELLO)
+            return 1;
+    } else {
+        /*
+         * If we're a client and we haven't read the ServerHello yet then we
+         * allow app data
+         */
+        if (st->hand_state == TLS_ST_CW_CLNT_HELLO)
+            return 1;
+    }
+
+    return 0;
+}
+
+#ifndef OPENSSL_NO_SCTP
+/*
+ * Set flag used by SCTP to determine whether we are in the read sock state
+ */
+void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock)
+{
+    s->statem.in_sctp_read_sock = read_sock;
+}
+
+/*
+ * Called by the record layer to determine whether we are in the read sock
+ * state or not.
+ *
+ * Return values are:
+ *   1: Yes (we are in the read sock state)
+ *   0: No (we are not in the read sock state)
+ */
+int statem_in_sctp_read_sock(SSL *s)
+{
+    return s->statem.in_sctp_read_sock;
+}
+#endif
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
new file mode 100644
index 0000000..1350967
--- /dev/null
+++ b/ssl/statem/statem.h
@@ -0,0 +1,176 @@
+/* ssl/statem/statem.h */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * These emums should be considered PRIVATE to the state machine. No         *
+ * non-state machine code should need to use these                           *
+ *                                                                           *
+ *****************************************************************************/
+/*
+ * Valid return codes used for functions performing work prior to or after
+ * sending or receiving a message
+ */
+typedef enum {
+    /* Something went wrong */
+    WORK_ERROR,
+    /* We're done working and there shouldn't be anything else to do after */
+    WORK_FINISHED_STOP,
+    /* We're done working move onto the next thing */
+    WORK_FINISHED_CONTINUE,
+    /* We're working on phase A */
+    WORK_MORE_A,
+    /* We're working on phase B */
+    WORK_MORE_B
+} WORK_STATE;
+
+/* Write transition return codes */
+typedef enum {
+    /* Something went wrong */
+    WRITE_TRAN_ERROR,
+    /* A transition was successfully completed and we should continue */
+    WRITE_TRAN_CONTINUE,
+    /* There is no more write work to be done */
+    WRITE_TRAN_FINISHED
+} WRITE_TRAN;
+
+/* Message flow states */
+typedef enum {
+    /* No handshake in progress */
+    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 */
+    MSG_FLOW_WRITING,
+    /* Handshake has finished */
+    MSG_FLOW_FINISHED
+} MSG_FLOW_STATE;
+
+/* Read states */
+typedef enum {
+    READ_STATE_HEADER,
+    READ_STATE_BODY,
+    READ_STATE_POST_PROCESS
+} READ_STATE;
+
+/* Write states */
+typedef enum {
+    WRITE_STATE_TRANSITION,
+    WRITE_STATE_PRE_WORK,
+    WRITE_STATE_SEND,
+    WRITE_STATE_POST_WORK
+} WRITE_STATE;
+
+
+/*****************************************************************************
+ *                                                                           *
+ * This structure should be considered "opaque" to anything outside of the   *
+ * state machine. No non-state machine code should be accessing the members  *
+ * of this structure.                                                        *
+ *                                                                           *
+ *****************************************************************************/
+
+struct ossl_statem_st {
+    MSG_FLOW_STATE state;
+    WRITE_STATE write_state;
+    WORK_STATE write_state_work;
+    READ_STATE read_state;
+    WORK_STATE read_state_work;
+    OSSL_HANDSHAKE_STATE hand_state;
+    int in_init;
+    int read_state_first_init;
+
+    /* true when we are actually in SSL_accept() or SSL_connect() */
+    int in_handshake;
+
+    /* Should we skip the CertificateVerify message? */
+    unsigned int no_cert_verify;
+
+    int use_timer;
+#ifndef OPENSSL_NO_SCTP
+    int in_sctp_read_sock;
+#endif
+};
+typedef struct ossl_statem_st OSSL_STATEM;
+
+
+/*****************************************************************************
+ *                                                                           *
+ * The following macros/functions represent the libssl internal API to the   *
+ * state machine. Any libssl code may call these functions/macros            *
+ *                                                                           *
+ *****************************************************************************/
+
+__owur int ossl_statem_accept(SSL *s);
+__owur int ossl_statem_connect(SSL *s);
+void ossl_statem_clear(SSL *s);
+void ossl_statem_set_renegotiate(SSL *s);
+void ossl_statem_set_error(SSL *s);
+int ossl_statem_in_error(const SSL *s);
+void ossl_statem_set_in_init(SSL *s, int init);
+int ossl_statem_get_in_handshake(SSL *s);
+void ossl_statem_set_in_handshake(SSL *s, int inhand);
+void ossl_statem_set_hello_verify_done(SSL *s);
+__owur int ossl_statem_app_data_allowed(SSL *s);
+#ifndef OPENSSL_NO_SCTP
+void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock);
+__owur int ossl_statem_in_sctp_read_sock(SSL *s);
+#endif
+
+
diff --git a/ssl/s3_clnt.c b/ssl/statem/statem_clnt.c
similarity index 50%
rename from ssl/s3_clnt.c
rename to ssl/statem/statem_clnt.c
index 8a89b42..c9d760f 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1,4 +1,4 @@
-/* ssl/s3_clnt.c */
+/* ssl/statem/statem_clnt.c */
 /* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
  * All rights reserved.
  *
@@ -149,7 +149,8 @@
  */
 
 #include <stdio.h>
-#include "ssl_locl.h"
+#include "../ssl_locl.h"
+#include "statem_locl.h"
 #include <openssl/buffer.h>
 #include <openssl/rand.h>
 #include <openssl/objects.h>
@@ -163,259 +164,268 @@
 # include <openssl/engine.h>
 #endif
 
+static inline int cert_req_allowed(SSL *s);
+static int key_exchange_expected(SSL *s);
 static int ssl_set_version(SSL *s);
 static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
-static int ssl3_check_change(SSL *s);
 static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
                                     unsigned char *p);
 
 
-int ssl3_connect(SSL *s)
+/*
+ * Is a CertificateRequest message allowed at the moment or not?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ */
+static inline int cert_req_allowed(SSL *s)
 {
-    BUF_MEM *buf = NULL;
-    unsigned long Time = (unsigned long)time(NULL);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    int ret = -1;
-    int new_state, state, skip = 0;
-
-    RAND_add(&Time, sizeof(Time), 0);
-    ERR_clear_error();
-    clear_sys_error();
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    s->in_handshake++;
-    if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
-            return -1;
+    /* TLS does not like anon-DH with client cert */
+    if ((s->version > SSL3_VERSION
+                && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+            || (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aSRP | SSL_aPSK)))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Should we expect the ServerKeyExchange message or not?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ * -1: Error
+ */
+static int key_exchange_expected(SSL *s)
+{
+    long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * Can't skip server key exchange if this is an ephemeral
+     * ciphersuite or for SRP
+     */
+    if (alg_k & (SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK
+                 | SSL_kSRP)) {
+        return 1;
     }
 
-#ifndef OPENSSL_NO_HEARTBEATS
     /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
+     * Export ciphersuites may have temporary RSA keys if the public key in the
+     * server certificate is longer than the maximum export strength
      */
-    if (s->tlsext_hb_pending) {
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
-    }
-#endif
-
-    for (;;) {
-        state = s->state;
-
-        switch (s->state) {
-        case SSL_ST_RENEGOTIATE:
-            s->renegotiate = 1;
-            s->state = SSL_ST_CONNECT;
-            s->ctx->stats.sess_connect_renegotiate++;
-            /* break */
-        case SSL_ST_BEFORE:
-        case SSL_ST_CONNECT:
-        case SSL_ST_BEFORE | SSL_ST_CONNECT:
-        case SSL_ST_OK | SSL_ST_CONNECT:
-
-            s->server = 0;
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_START, 1);
-
-            if ((s->version >> 8) != SSL3_VERSION_MAJOR
-                    && s->version != TLS_ANY_VERSION) {
-                SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
-                s->state = SSL_ST_ERR;
-                ret = -1;
-                goto end;
-            }
+    if ((alg_k & SSL_kRSA) && SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
+        EVP_PKEY *pkey;
 
-            if (s->version != TLS_ANY_VERSION &&
-                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-                SSLerr(SSL_F_SSL3_CONNECT, SSL_R_VERSION_TOO_LOW);
-                return -1;
-            }
+        pkey = X509_get_pubkey(s->session->peer);
+        if (pkey == NULL)
+            return -1;
+
+        /*
+         * If the public key in the certificate is shorter than or equal to the
+         * maximum export strength then a temporary RSA key is not allowed
+         */
+        if (EVP_PKEY_bits(pkey)
+                <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
+            return 0;
+
+        EVP_PKEY_free(pkey);
+
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ *  Return values are:
+ *  1: Success (transition allowed)
+ *  0: Error (transition not allowed)
+ */
+int ossl_statem_client_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+    int ske_expected;
 
-            /* s->version=SSL3_VERSION; */
-            s->type = SSL_ST_CONNECT;
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            }
+        }
+        break;
 
-            if (s->init_buf == NULL) {
-                if ((buf = BUF_MEM_new()) == NULL) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
+    case TLS_ST_CR_SRVR_HELLO:
+        if (s->hit) {
+            if (s->tlsext_ticket_expected) {
+                if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                    return 1;
                 }
-                if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-                    ret = -1;
-                    s->state = SSL_ST_ERR;
-                    goto end;
+            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_CR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            } else if (!(s->s3->tmp.new_cipher->algorithm_auth
+                        & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                if (mt == SSL3_MT_CERTIFICATE) {
+                    st->hand_state = TLS_ST_CR_CERT;
+                    return 1;
+                }
+            } else {
+                ske_expected = key_exchange_expected(s);
+                if (ske_expected < 0)
+                    return 0;
+                /* SKE is optional for some PSK ciphersuites */
+                if (ske_expected
+                        || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)
+                            && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) {
+                    if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                        st->hand_state = TLS_ST_CR_KEY_EXCH;
+                        return 1;
+                    }
+                } else if (mt == SSL3_MT_CERTIFICATE_REQUEST
+                            && cert_req_allowed(s)) {
+                        st->hand_state = TLS_ST_CR_CERT_REQ;
+                        return 1;
+                } else if (mt == SSL3_MT_SERVER_DONE) {
+                        st->hand_state = TLS_ST_CR_SRVR_DONE;
+                        return 1;
                 }
-                s->init_buf = buf;
-                buf = NULL;
             }
+        }
+        break;
 
-            if (!ssl3_setup_buffers(s)) {
-                ret = -1;
-                goto end;
+    case TLS_ST_CR_CERT:
+        if (s->tlsext_status_expected) {
+            if (mt == SSL3_MT_CERTIFICATE_STATUS) {
+                st->hand_state = TLS_ST_CR_CERT_STATUS;
+                return 1;
             }
+            return 0;
+        }
+        /* Fall through */
 
-            /* setup buffing BIO */
-            if (!ssl_init_wbio_buffer(s, 0)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
+    case TLS_ST_CR_CERT_STATUS:
+        ske_expected = key_exchange_expected(s);
+        if (ske_expected < 0)
+            return 0;
+        /* SKE is optional for some PSK ciphersuites */
+        if (ske_expected
+                || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)
+                    && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) {
+            if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                st->hand_state = TLS_ST_CR_KEY_EXCH;
+                return 1;
             }
+            return 0;
+        }
+        /* Fall through */
 
-            /* don't push the buffering BIO quite yet */
-
-            ssl3_init_finished_mac(s);
-
-            s->state = SSL3_ST_CW_CLNT_HELLO_A;
-            s->ctx->stats.sess_connect++;
-            s->init_num = 0;
-            /*
-             * Should have been reset by ssl3_get_finished, too.
-             */
-            s->s3->change_cipher_spec = 0;
-            break;
-
-        case SSL3_ST_CW_CLNT_HELLO_A:
-        case SSL3_ST_CW_CLNT_HELLO_B:
+    case TLS_ST_CR_KEY_EXCH:
+        if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+            if (cert_req_allowed(s)) {
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            }
+            return 0;
+        }
+        /* Fall through */
 
-            s->shutdown = 0;
-            ret = ssl3_client_hello(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_SRVR_HELLO_A;
-            s->init_num = 0;
+    case TLS_ST_CR_CERT_REQ:
+        if (mt == SSL3_MT_SERVER_DONE) {
+            st->hand_state = TLS_ST_CR_SRVR_DONE;
+            return 1;
+        }
+        break;
 
-            /* turn on buffering for the next lot of output */
-            if (s->bbio != s->wbio)
-                s->wbio = BIO_push(s->bbio, s->wbio);
+    case TLS_ST_CW_FINISHED:
+        if (mt == SSL3_MT_NEWSESSION_TICKET && s->tlsext_ticket_expected) {
+            st->hand_state = TLS_ST_CR_SESSION_TICKET;
+            return 1;
+        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
 
-            break;
+    case TLS_ST_CR_SESSION_TICKET:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
 
-        case SSL3_ST_CR_SRVR_HELLO_A:
-        case SSL3_ST_CR_SRVR_HELLO_B:
-            ret = ssl3_get_server_hello(s);
-            if (ret <= 0)
-                goto end;
+    case TLS_ST_CR_CHANGE:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_CR_FINISHED;
+            return 1;
+        }
+        break;
 
-            if (s->hit) {
-                s->state = SSL3_ST_CR_CHANGE_A;
-                if (s->tlsext_ticket_expected) {
-                    /* receive renewed session ticket */
-                    s->state = SSL3_ST_CR_SESSION_TICKET_A;
-                }
-            } else {
-                s->state = SSL3_ST_CR_CERT_A;
-            }
-            s->init_num = 0;
-            break;
-        case SSL3_ST_CR_CERT_A:
-        case SSL3_ST_CR_CERT_B:
-            /* Noop (ret = 0) for everything but EAP-FAST. */
-            ret = ssl3_check_change(s);
-            if (ret < 0)
-                goto end;
-            if (ret == 1) {
-                s->hit = 1;
-                s->state = SSL3_ST_CR_CHANGE_A;
-                s->init_num = 0;
-                break;
-            }
+    default:
+        break;
+    }
 
-            /* Check if it is anon DH/ECDH, SRP auth */
-            /* or PSK */
-            if (!(s->s3->tmp.new_cipher->algorithm_auth &
-                    (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                ret = ssl3_get_server_certificate(s);
-                if (ret <= 0)
-                    goto end;
-
-                if (s->tlsext_status_expected)
-                    s->state = SSL3_ST_CR_CERT_STATUS_A;
-                else
-                    s->state = SSL3_ST_CR_KEY_EXCH_A;
-            } else {
-                skip = 1;
-                s->state = SSL3_ST_CR_KEY_EXCH_A;
-            }
+    /* No valid transition found */
+    return 0;
+}
 
-            s->init_num = 0;
-            break;
+/*
+ * client_write_transition() works out what handshake state to move to next
+ * when the client is writing messages to be sent to the server.
+ */
+WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
 
-        case SSL3_ST_CR_KEY_EXCH_A:
-        case SSL3_ST_CR_KEY_EXCH_B:
-            ret = ssl3_get_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_CERT_REQ_A;
-            s->init_num = 0;
+    switch(st->hand_state) {
+        case TLS_ST_OK:
+            /* Renegotiation - fall through */
+        case TLS_ST_BEFORE:
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
 
+        case TLS_ST_CW_CLNT_HELLO:
             /*
-             * at this point we check that we have the required stuff from
-             * the server
+             * No transition at the end of writing because we don't know what
+             * we will be sent
              */
-            if (!ssl3_check_cert_and_algorithm(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
-            }
-            break;
+            return WRITE_TRAN_FINISHED;
 
-        case SSL3_ST_CR_CERT_REQ_A:
-        case SSL3_ST_CR_CERT_REQ_B:
-            ret = ssl3_get_certificate_request(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_SRVR_DONE_A;
-            s->init_num = 0;
-            break;
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
 
-        case SSL3_ST_CR_SRVR_DONE_A:
-        case SSL3_ST_CR_SRVR_DONE_B:
-            ret = ssl3_get_server_done(s);
-            if (ret <= 0)
-                goto end;
-#ifndef OPENSSL_NO_SRP
-            if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
-                if ((ret = SRP_Calc_A_param(s)) <= 0) {
-                    SSLerr(SSL_F_SSL3_CONNECT, SSL_R_SRP_A_CALC);
-                    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                    s->state = SSL_ST_ERR;
-                    goto end;
-                }
-            }
-#endif
+        case TLS_ST_CR_SRVR_DONE:
             if (s->s3->tmp.cert_req)
-                s->state = SSL3_ST_CW_CERT_A;
+                st->hand_state = TLS_ST_CW_CERT;
             else
-                s->state = SSL3_ST_CW_KEY_EXCH_A;
-            s->init_num = 0;
+                st->hand_state = TLS_ST_CW_KEY_EXCH;
+            return WRITE_TRAN_CONTINUE;
 
-            break;
-
-        case SSL3_ST_CW_CERT_A:
-        case SSL3_ST_CW_CERT_B:
-        case SSL3_ST_CW_CERT_C:
-        case SSL3_ST_CW_CERT_D:
-            ret = ssl3_send_client_certificate(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
+        case TLS_ST_CW_CERT:
+            st->hand_state = TLS_ST_CW_KEY_EXCH;
+            return WRITE_TRAN_CONTINUE;
 
-        case SSL3_ST_CW_KEY_EXCH_A:
-        case SSL3_ST_CW_KEY_EXCH_B:
-            ret = ssl3_send_client_key_exchange(s);
-            if (ret <= 0)
-                goto end;
-            /*
-             * EAY EAY EAY need to check for DH fix cert sent back
-             */
+        case TLS_ST_CW_KEY_EXCH:
             /*
              * For TLS, cert_req is set to 2, so a cert chain of nothing is
              * sent, but no verify packet is sent
@@ -427,217 +437,381 @@ int ssl3_connect(SSL *s)
              * ECDH public key is sent inside the client certificate.
              */
             if (s->s3->tmp.cert_req == 1) {
-                s->state = SSL3_ST_CW_CERT_VRFY_A;
+                st->hand_state = TLS_ST_CW_CERT_VRFY;
             } else {
-                s->state = SSL3_ST_CW_CHANGE_A;
+                st->hand_state = TLS_ST_CW_CHANGE;
             }
             if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
-                s->state = SSL3_ST_CW_CHANGE_A;
+                st->hand_state = TLS_ST_CW_CHANGE;
             }
+            return WRITE_TRAN_CONTINUE;
 
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_CERT_VRFY_A:
-        case SSL3_ST_CW_CERT_VRFY_B:
-            ret = ssl3_send_client_verify(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_CHANGE_A;
-            s->init_num = 0;
-            break;
-
-        case SSL3_ST_CW_CHANGE_A:
-        case SSL3_ST_CW_CHANGE_B:
-            ret = ssl3_send_change_cipher_spec(s,
-                                               SSL3_ST_CW_CHANGE_A,
-                                               SSL3_ST_CW_CHANGE_B);
-            if (ret <= 0)
-                goto end;
+        case TLS_ST_CW_CERT_VRFY:
+            st->hand_state = TLS_ST_CW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
 
+        case TLS_ST_CW_CHANGE:
 #if defined(OPENSSL_NO_NEXTPROTONEG)
-            s->state = SSL3_ST_CW_FINISHED_A;
+            st->hand_state = TLS_ST_CW_FINISHED;
 #else
-            if (s->s3->next_proto_neg_seen)
-                s->state = SSL3_ST_CW_NEXT_PROTO_A;
+            if (!SSL_IS_DTLS(s) && s->s3->next_proto_neg_seen)
+                st->hand_state = TLS_ST_CW_NEXT_PROTO;
             else
-                s->state = SSL3_ST_CW_FINISHED_A;
+                st->hand_state = TLS_ST_CW_FINISHED;
 #endif
-            s->init_num = 0;
+            return WRITE_TRAN_CONTINUE;
 
-            s->session->cipher = s->s3->tmp.new_cipher;
-#ifdef OPENSSL_NO_COMP
-            s->session->compress_meth = 0;
-#else
-            if (s->s3->tmp.new_compression == NULL)
-                s->session->compress_meth = 0;
-            else
-                s->session->compress_meth = s->s3->tmp.new_compression->id;
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+        case TLS_ST_CW_NEXT_PROTO:
+            st->hand_state = TLS_ST_CW_FINISHED;
+            return WRITE_TRAN_CONTINUE;
 #endif
-            if (!s->method->ssl3_enc->setup_key_block(s)) {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
+
+        case TLS_ST_CW_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_OK;
+                ossl_statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
+            } else {
+                return WRITE_TRAN_FINISHED;
             }
 
-            if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                          SSL3_CHANGE_CIPHER_CLIENT_WRITE))
-            {
-                ret = -1;
-                s->state = SSL_ST_ERR;
-                goto end;
+        case TLS_ST_CR_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_CW_CHANGE;
+                return WRITE_TRAN_CONTINUE;
+            } else {
+                st->hand_state = TLS_ST_OK;
+                ossl_statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
             }
 
-            break;
+        default:
+            /* Shouldn't happen */
+            return WRITE_TRAN_ERROR;
+    }
+}
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-        case SSL3_ST_CW_NEXT_PROTO_A:
-        case SSL3_ST_CW_NEXT_PROTO_B:
-            ret = ssl3_send_next_proto(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_FINISHED_A;
-            break;
-#endif
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the client to the server.
+ */
+WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            /* every DTLS ClientHello resets Finished MAC */
+            ssl3_init_finished_mac(s);
+        }
+        break;
 
-        case SSL3_ST_CW_FINISHED_A:
-        case SSL3_ST_CW_FINISHED_B:
-            ret = ssl3_send_finished(s,
-                                     SSL3_ST_CW_FINISHED_A,
-                                     SSL3_ST_CW_FINISHED_B,
-                                     s->method->
-                                     ssl3_enc->client_finished_label,
-                                     s->method->
-                                     ssl3_enc->client_finished_label_len);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CW_FLUSH;
+    case TLS_ST_CW_CERT:
+        return tls_prepare_client_certificate(s, wst);
 
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s)) {
             if (s->hit) {
-                s->s3->tmp.next_state = SSL_ST_OK;
-            } else {
                 /*
-                 * Allow NewSessionTicket if ticket expected
+                 * We're into the last flight so we don't retransmit these
+                 * messages unless we need to.
                  */
-                if (s->tlsext_ticket_expected)
-                    s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A;
-                else
-                    s->s3->tmp.next_state = SSL3_ST_CR_CHANGE_A;
+                st->use_timer = 0;
             }
-            s->init_num = 0;
-            break;
+#ifndef OPENSSL_NO_SCTP
+            if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+                return dtls_wait_for_dry(s);
+#endif
+        }
+        return WORK_FINISHED_CONTINUE;
 
-        case SSL3_ST_CR_SESSION_TICKET_A:
-        case SSL3_ST_CR_SESSION_TICKET_B:
-            ret = ssl3_get_new_session_ticket(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_CHANGE_A;
-            s->init_num = 0;
-            break;
+    case TLS_ST_OK:
+        return tls_finish_handshake(s, wst);
 
-        case SSL3_ST_CR_CERT_STATUS_A:
-        case SSL3_ST_CR_CERT_STATUS_B:
-            ret = ssl3_get_cert_status(s);
-            if (ret <= 0)
-                goto end;
-            s->state = SSL3_ST_CR_KEY_EXCH_A;
-            s->init_num = 0;
-            break;
+    default:
+        /* No pre work to be done */
+        break;
+    }
 
-        case SSL3_ST_CR_CHANGE_A:
-        case SSL3_ST_CR_CHANGE_B:
-            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_CR_CHANGE_A,
-                                              SSL3_ST_CR_CHANGE_B);
-            if (ret <= 0)
-                goto end;
+    return WORK_FINISHED_CONTINUE;
+}
 
-            s->state = SSL3_ST_CR_FINISHED_A;
-            s->init_num = 0;
-            break;
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * client to the server.
+ */
+WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
 
-        case SSL3_ST_CR_FINISHED_A:
-        case SSL3_ST_CR_FINISHED_B:
-            ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
-                                    SSL3_ST_CR_FINISHED_B);
-            if (ret <= 0)
-                goto end;
+    s->init_num = 0;
 
-            if (s->hit)
-                s->state = SSL3_ST_CW_CHANGE_A;
-            else
-                s->state = SSL_ST_OK;
-            s->init_num = 0;
-            break;
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        if (SSL_IS_DTLS(s) && s->d1->cookie_len > 0 && statem_flush(s) != 1)
+            return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+        /* Disable buffering for SCTP */
+        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+#endif
+            /*
+             * turn on buffering for the next lot of output
+             */
+            if (s->bbio != s->wbio)
+                s->wbio = BIO_push(s->bbio, s->wbio);
+#ifndef OPENSSL_NO_SCTP
+            }
+#endif
+        if (SSL_IS_DTLS(s)) {
+            /* Treat the next message as the first packet */
+            s->first_packet = 1;
+        }
+        break;
+
+    case TLS_ST_CW_KEY_EXCH:
+        if (tls_client_key_exchange_post_work(s) == 0)
+            return WORK_ERROR;
+        break;
+
+    case TLS_ST_CW_CHANGE:
+        s->session->cipher = s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        if (s->s3->tmp.new_compression == NULL)
+            s->session->compress_meth = 0;
+        else
+            s->session->compress_meth = s->s3->tmp.new_compression->id;
+#endif
+        if (!s->method->ssl3_enc->setup_key_block(s))
+            return WORK_ERROR;
 
-        case SSL3_ST_CW_FLUSH:
-            s->rwstate = SSL_WRITING;
-            if (BIO_flush(s->wbio) <= 0) {
-                ret = -1;
-                goto end;
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                                                      SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+            return WORK_ERROR;
+
+        if (SSL_IS_DTLS(s)) {
+#ifndef OPENSSL_NO_SCTP
+            if (s->hit) {
+                /*
+                 * Change to new shared key of SCTP-Auth, will be ignored if
+                 * no SCTP used.
+                 */
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                         0, NULL);
             }
-            s->rwstate = SSL_NOTHING;
-            s->state = s->s3->tmp.next_state;
+#endif
+
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+#ifndef OPENSSL_NO_SCTP
+        if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (statem_flush(s) != 1)
+            return WORK_MORE_B;
+
+        if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
+                return WORK_ERROR;
+        break;
+
+    default:
+        /* No post work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Construct a message to be sent from the client to the server.
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+int ossl_statem_client_construct_message(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        return tls_construct_client_hello(s);
+
+    case TLS_ST_CW_CERT:
+        return tls_construct_client_certificate(s);
+
+    case TLS_ST_CW_KEY_EXCH:
+        return tls_construct_client_key_exchange(s);
+
+    case TLS_ST_CW_CERT_VRFY:
+        return tls_construct_client_verify(s);
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            return dtls_construct_change_cipher_spec(s);
+        else
+            return tls_construct_change_cipher_spec(s);
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    case TLS_ST_CW_NEXT_PROTO:
+        return tls_construct_next_proto(s);
+#endif
+    case TLS_ST_CW_FINISHED:
+        return tls_construct_finished(s,
+                                      s->method->
+                                      ssl3_enc->client_finished_label,
+                                      s->method->
+                                      ssl3_enc->client_finished_label_len);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+unsigned long ossl_statem_client_max_message_size(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        case TLS_ST_CR_SRVR_HELLO:
+            return SERVER_HELLO_MAX_LENGTH;
+
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            return HELLO_VERIFY_REQUEST_MAX_LENGTH;
+
+        case TLS_ST_CR_CERT:
+            return s->max_cert_list;
+
+        case TLS_ST_CR_CERT_STATUS:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_KEY_EXCH:
+            return SERVER_KEY_EXCH_MAX_LENGTH;
+
+        case TLS_ST_CR_CERT_REQ:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_SRVR_DONE:
+            return SERVER_HELLO_DONE_MAX_LENGTH;
+
+        case TLS_ST_CR_CHANGE:
+            return CCS_MAX_LENGTH;
+
+        case TLS_ST_CR_SESSION_TICKET:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_FINISHED:
+            return FINISHED_MAX_LENGTH;
+
+        default:
+            /* Shouldn't happen */
             break;
+    }
+
+    return 0;
+}
+
+/*
+ * Process a message that the client has been received from the server.
+ */
+MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
+{
+    OSSL_STATEM *st = &s->statem;
 
-        case SSL_ST_OK:
-            /* clean a few things up */
-            ssl3_cleanup_key_block(s);
-            BUF_MEM_free(s->init_buf);
-            s->init_buf = NULL;
+    switch(st->hand_state) {
+        case TLS_ST_CR_SRVR_HELLO:
+            return tls_process_server_hello(s, pkt);
 
-            /* remove the buffering */
-            ssl_free_wbio_buffer(s);
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            return dtls_process_hello_verify(s, pkt);
 
-            s->init_num = 0;
-            s->renegotiate = 0;
-            s->new_session = 0;
+        case TLS_ST_CR_CERT:
+            return tls_process_server_certificate(s, pkt);
 
-            ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
-            if (s->hit)
-                s->ctx->stats.sess_hit++;
+        case TLS_ST_CR_CERT_STATUS:
+            return tls_process_cert_status(s, pkt);
 
-            ret = 1;
-            /* s->server=0; */
-            s->handshake_func = ssl3_connect;
-            s->ctx->stats.sess_connect_good++;
+        case TLS_ST_CR_KEY_EXCH:
+            return tls_process_key_exchange(s, pkt);
 
-            if (cb != NULL)
-                cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+        case TLS_ST_CR_CERT_REQ:
+            return tls_process_certificate_request(s, pkt);
 
-            goto end;
-            /* break; */
+        case TLS_ST_CR_SRVR_DONE:
+            return tls_process_server_done(s, pkt);
+
+        case TLS_ST_CR_CHANGE:
+            return tls_process_change_cipher_spec(s, pkt);
+
+        case TLS_ST_CR_SESSION_TICKET:
+            return tls_process_new_session_ticket(s, pkt);
+
+        case TLS_ST_CR_FINISHED:
+            return tls_process_finished(s, pkt);
 
-        case SSL_ST_ERR:
         default:
-            SSLerr(SSL_F_SSL3_CONNECT, SSL_R_UNKNOWN_STATE);
-            ret = -1;
-            goto end;
-            /* break; */
-        }
+            /* Shouldn't happen */
+            break;
+    }
 
-        /* did we do anything */
-        if (!s->s3->tmp.reuse_message && !skip) {
-            if (s->debug) {
-                if ((ret = BIO_flush(s->wbio)) <= 0)
-                    goto end;
-            }
+    return MSG_PROCESS_ERROR;
+}
 
-            if ((cb != NULL) && (s->state != state)) {
-                new_state = s->state;
-                s->state = state;
-                cb(s, SSL_CB_CONNECT_LOOP, 1);
-                s->state = new_state;
-            }
-        }
-        skip = 0;
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the server
+ */
+WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+#ifndef OPENSSL_NO_SCTP
+    case TLS_ST_CR_SRVR_DONE:
+        /* We only get here if we are using SCTP and we are renegotiating */
+        if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+            s->s3->in_read_app_data = 2;
+            s->rwstate = SSL_READING;
+            BIO_clear_retry_flags(SSL_get_rbio(s));
+            BIO_set_retry_read(SSL_get_rbio(s));
+            ossl_statem_set_sctp_read_sock(s, 1);
+            return WORK_MORE_A;
+        }
+        ossl_statem_set_sctp_read_sock(s, 0);
+        return WORK_FINISHED_STOP;
+#endif
+
+    case TLS_ST_CR_FINISHED:
+        if (!s->hit)
+            return tls_finish_handshake(s, wst);
+        else
+            return WORK_FINISHED_STOP;
+    default:
+        break;
     }
- end:
-    s->in_handshake--;
-    BUF_MEM_free(buf);
-    if (cb != NULL)
-        cb(s, SSL_CB_CONNECT_EXIT, ret);
-    return (ret);
+
+    /* Shouldn't happen */
+    return WORK_ERROR;
 }
 
 /*
@@ -739,7 +913,7 @@ static int ssl_set_version(SSL *s)
     return 1;
 }
 
-int ssl3_client_hello(SSL *s)
+int tls_construct_client_hello(SSL *s)
 {
     unsigned char *buf;
     unsigned char *p, *d;
@@ -750,239 +924,229 @@ int ssl3_client_hello(SSL *s)
     int j;
     SSL_COMP *comp;
 #endif
+    SSL_SESSION *sess = s->session;
 
     buf = (unsigned char *)s->init_buf->data;
-    if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
-        SSL_SESSION *sess = s->session;
-
-        /* Work out what SSL/TLS/DTLS version to use */
-        if (ssl_set_version(s) == 0)
-            goto err;
-
-        if ((sess == NULL) || (sess->ssl_version != s->version) ||
-            /*
-             * In the case of EAP-FAST, we can have a pre-shared
-             * "ticket" without a session ID.
-             */
-            (!sess->session_id_length && !sess->tlsext_tick) ||
-            (sess->not_resumable)) {
-            if (!ssl_get_new_session(s, 0))
-                goto err;
-        }
-        /* else use the pre-loaded session */
 
-        p = s->s3->client_random;
+    /* Work out what SSL/TLS/DTLS version to use */
+    if (ssl_set_version(s) == 0)
+        goto err;
 
+    if ((sess == NULL) || (sess->ssl_version != s->version) ||
         /*
-         * for DTLS if client_random is initialized, reuse it, we are
-         * required to use same upon reply to HelloVerify
+         * In the case of EAP-FAST, we can have a pre-shared
+         * "ticket" without a session ID.
          */
-        if (SSL_IS_DTLS(s)) {
-            size_t idx;
-            i = 1;
-            for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
-                if (p[idx]) {
-                    i = 0;
-                    break;
-                }
-            }
-        } else
-            i = 1;
-
-        if (i && ssl_fill_hello_random(s, 0, p,
-                                       sizeof(s->s3->client_random)) <= 0)
+        (!sess->session_id_length && !sess->tlsext_tick) ||
+        (sess->not_resumable)) {
+        if (!ssl_get_new_session(s, 0))
             goto err;
+    }
+    /* else use the pre-loaded session */
 
-        /* Do the message type and length last */
-        d = p = ssl_handshake_start(s);
-
-        /*-
-         * version indicates the negotiated version: for example from
-         * an SSLv2/v3 compatible client hello). The client_version
-         * field is the maximum version we permit and it is also
-         * used in RSA encrypted premaster secrets. Some servers can
-         * choke if we initially report a higher version then
-         * renegotiate to a lower one in the premaster secret. This
-         * didn't happen with TLS 1.0 as most servers supported it
-         * but it can with TLS 1.1 or later if the server only supports
-         * 1.0.
-         *
-         * Possible scenario with previous logic:
-         *      1. Client hello indicates TLS 1.2
-         *      2. Server hello says TLS 1.0
-         *      3. RSA encrypted premaster secret uses 1.2.
-         *      4. Handhaked proceeds using TLS 1.0.
-         *      5. Server sends hello request to renegotiate.
-         *      6. Client hello indicates TLS v1.0 as we now
-         *         know that is maximum server supports.
-         *      7. Server chokes on RSA encrypted premaster secret
-         *         containing version 1.0.
-         *
-         * For interoperability it should be OK to always use the
-         * maximum version we support in client hello and then rely
-         * on the checking of version to ensure the servers isn't
-         * being inconsistent: for example initially negotiating with
-         * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
-         * client_version in client hello and not resetting it to
-         * the negotiated version.
-         */
-        *(p++) = s->client_version >> 8;
-        *(p++) = s->client_version & 0xff;
-
-        /* Random stuff */
-        memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
-        p += SSL3_RANDOM_SIZE;
+    p = s->s3->client_random;
 
-        /* Session ID */
-        if (s->new_session)
-            i = 0;
-        else
-            i = s->session->session_id_length;
-        *(p++) = i;
-        if (i != 0) {
-            if (i > (int)sizeof(s->session->session_id)) {
-                SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-                goto err;
+    /*
+     * for DTLS if client_random is initialized, reuse it, we are
+     * required to use same upon reply to HelloVerify
+     */
+    if (SSL_IS_DTLS(s)) {
+        size_t idx;
+        i = 1;
+        for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
+            if (p[idx]) {
+                i = 0;
+                break;
             }
-            memcpy(p, s->session->session_id, i);
-            p += i;
         }
+    } else
+        i = 1;
 
-        /* cookie stuff for DTLS */
-        if (SSL_IS_DTLS(s)) {
-            if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
-                SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            *(p++) = s->d1->cookie_len;
-            memcpy(p, s->d1->cookie, s->d1->cookie_len);
-            p += s->d1->cookie_len;
+    if (i && ssl_fill_hello_random(s, 0, p,
+                                   sizeof(s->s3->client_random)) <= 0)
+        goto err;
+
+    /* Do the message type and length last */
+    d = p = ssl_handshake_start(s);
+
+    /*-
+     * version indicates the negotiated version: for example from
+     * an SSLv2/v3 compatible client hello). The client_version
+     * field is the maximum version we permit and it is also
+     * used in RSA encrypted premaster secrets. Some servers can
+     * choke if we initially report a higher version then
+     * renegotiate to a lower one in the premaster secret. This
+     * didn't happen with TLS 1.0 as most servers supported it
+     * but it can with TLS 1.1 or later if the server only supports
+     * 1.0.
+     *
+     * Possible scenario with previous logic:
+     *      1. Client hello indicates TLS 1.2
+     *      2. Server hello says TLS 1.0
+     *      3. RSA encrypted premaster secret uses 1.2.
+     *      4. Handhaked proceeds using TLS 1.0.
+     *      5. Server sends hello request to renegotiate.
+     *      6. Client hello indicates TLS v1.0 as we now
+     *         know that is maximum server supports.
+     *      7. Server chokes on RSA encrypted premaster secret
+     *         containing version 1.0.
+     *
+     * For interoperability it should be OK to always use the
+     * maximum version we support in client hello and then rely
+     * on the checking of version to ensure the servers isn't
+     * being inconsistent: for example initially negotiating with
+     * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+     * client_version in client hello and not resetting it to
+     * the negotiated version.
+     */
+    *(p++) = s->client_version >> 8;
+    *(p++) = s->client_version & 0xff;
+
+    /* Random stuff */
+    memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+    p += SSL3_RANDOM_SIZE;
+
+    /* Session ID */
+    if (s->new_session)
+        i = 0;
+    else
+        i = s->session->session_id_length;
+    *(p++) = i;
+    if (i != 0) {
+        if (i > (int)sizeof(s->session->session_id)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto err;
         }
+        memcpy(p, s->session->session_id, i);
+        p += i;
+    }
 
-        /* Ciphers supported */
-        i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]));
-        if (i == 0) {
-            SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE);
+    /* cookie stuff for DTLS */
+    if (SSL_IS_DTLS(s)) {
+        if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
             goto err;
         }
+        *(p++) = s->d1->cookie_len;
+        memcpy(p, s->d1->cookie, s->d1->cookie_len);
+        p += s->d1->cookie_len;
+    }
+
+    /* Ciphers supported */
+    i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]));
+    if (i == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE);
+        goto err;
+    }
 #ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
-        /*
-         * Some servers hang if client hello > 256 bytes as hack workaround
-         * chop number of supported ciphers to keep it well below this if we
-         * use TLS v1.2
-         */
-        if (TLS1_get_version(s) >= TLS1_2_VERSION
-            && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
-            i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+    /*
+     * Some servers hang if client hello > 256 bytes as hack workaround
+     * chop number of supported ciphers to keep it well below this if we
+     * use TLS v1.2
+     */
+    if (TLS1_get_version(s) >= TLS1_2_VERSION
+        && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+        i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
 #endif
-        s2n(i, p);
-        p += i;
+    s2n(i, p);
+    p += i;
 
-        /* COMPRESSION */
+    /* COMPRESSION */
 #ifdef OPENSSL_NO_COMP
-        *(p++) = 1;
+    *(p++) = 1;
 #else
 
-        if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
-            j = 0;
-        else
-            j = sk_SSL_COMP_num(s->ctx->comp_methods);
-        *(p++) = 1 + j;
-        for (i = 0; i < j; i++) {
-            comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
-            *(p++) = comp->id;
-        }
+    if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
+        j = 0;
+    else
+        j = sk_SSL_COMP_num(s->ctx->comp_methods);
+    *(p++) = 1 + j;
+    for (i = 0; i < j; i++) {
+        comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
+        *(p++) = comp->id;
+    }
 #endif
-        *(p++) = 0;             /* Add the NULL method */
+    *(p++) = 0;             /* Add the NULL method */
 
-        /* TLS extensions */
-        if (ssl_prepare_clienthello_tlsext(s) <= 0) {
-            SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-            goto err;
-        }
-        if ((p =
-             ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
-                                        &al)) == NULL) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, al);
-            SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
+    /* TLS extensions */
+    if (ssl_prepare_clienthello_tlsext(s) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+        goto err;
+    }
+    if ((p =
+         ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
+                                    &al)) == NULL) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
-        l = p - d;
-        if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-            SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        s->state = SSL3_ST_CW_CLNT_HELLO_B;
+    l = p - d;
+    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
     }
 
-    /* SSL3_ST_CW_CLNT_HELLO_B */
-    return ssl_do_write(s);
+    return 1;
  err:
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return 0;
 }
 
-int ssl3_get_server_hello(SSL *s)
+MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
 {
-    STACK_OF(SSL_CIPHER) *sk;
-    const SSL_CIPHER *c;
-    PACKET pkt, session_id;
-    size_t session_id_len;
-    unsigned char *cipherchars;
-    int i, al = SSL_AD_INTERNAL_ERROR, ok;
-    unsigned int compression;
-    long n;
-#ifndef OPENSSL_NO_COMP
-    SSL_COMP *comp;
-#endif
-    /*
-     * Hello verify request and/or server hello version may not match so set
-     * first packet if we're negotiating version.
-     */
-    s->first_packet = 1;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_SRVR_HELLO_A,
-                                   SSL3_ST_CR_SRVR_HELLO_B, -1, 20000, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    s->first_packet = 0;
-    if (SSL_IS_DTLS(s)) {
-        if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) {
-            if (s->d1->send_cookie == 0) {
-                s->s3->tmp.reuse_message = 1;
-                return 1;
-            } else {            /* already sent a cookie */
+    int al;
+    unsigned int cookie_len;
+    PACKET cookiepkt;
 
-                al = SSL_AD_UNEXPECTED_MESSAGE;
-                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_MESSAGE_TYPE);
-                goto f_err;
-            }
-        }
+    if (!PACKET_forward(pkt, 2)
+            || !PACKET_get_length_prefixed_1(pkt, &cookiepkt)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
     }
 
-    if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_MESSAGE_TYPE);
+    cookie_len = PACKET_remaining(&cookiepkt);
+    if (cookie_len > sizeof(s->d1->cookie)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_TOO_LONG);
         goto f_err;
     }
 
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+    if (!PACKET_copy_bytes(&cookiepkt, s->d1->cookie, cookie_len)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
+    s->d1->cookie_len = cookie_len;
+
+    return MSG_PROCESS_FINISHED_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+    const SSL_CIPHER *c;
+    PACKET session_id;
+    size_t session_id_len;
+    unsigned char *cipherchars;
+    int i, al = SSL_AD_INTERNAL_ERROR;
+    unsigned int compression;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp;
+#endif
 
     if (s->method->version == TLS_ANY_VERSION) {
         unsigned int sversion;
 
-        if (!PACKET_get_net_2(&pkt, &sversion)) {
+        if (!PACKET_get_net_2(pkt, &sversion)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
@@ -992,7 +1156,7 @@ int ssl3_get_server_hello(SSL *s)
 #ifndef OPENSSL_NO_SSL3
         if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
             if (FIPS_mode()) {
-                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                        SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
                 al = SSL_AD_PROTOCOL_VERSION;
                 goto f_err;
@@ -1009,14 +1173,14 @@ int ssl3_get_server_hello(SSL *s)
                    !(s->options & SSL_OP_NO_TLSv1_2)) {
             s->method = TLSv1_2_client_method();
         } else {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
             al = SSL_AD_PROTOCOL_VERSION;
             goto f_err;
         }
         s->session->ssl_version = s->version = s->method->version;
 
         if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
             al = SSL_AD_PROTOCOL_VERSION;
             goto f_err;
         }
@@ -1025,9 +1189,9 @@ int ssl3_get_server_hello(SSL *s)
         unsigned int hversion;
         int options;
 
-        if (!PACKET_get_net_2(&pkt, &hversion)) {
+        if (!PACKET_get_net_2(pkt, &hversion)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
@@ -1035,7 +1199,7 @@ int ssl3_get_server_hello(SSL *s)
         if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
             s->method = DTLSv1_2_client_method();
         else if (tls1_suiteb(s)) {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                    SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
             s->version = hversion;
             al = SSL_AD_PROTOCOL_VERSION;
@@ -1043,7 +1207,7 @@ int ssl3_get_server_hello(SSL *s)
         } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
             s->method = DTLSv1_client_method();
         else {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
             s->version = hversion;
             al = SSL_AD_PROTOCOL_VERSION;
             goto f_err;
@@ -1052,14 +1216,14 @@ int ssl3_get_server_hello(SSL *s)
     } else {
         unsigned char *vers;
 
-        if (!PACKET_get_bytes(&pkt, &vers, 2)) {
+        if (!PACKET_get_bytes(pkt, &vers, 2)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
         if ((vers[0] != (s->version >> 8))
                 || (vers[1] != (s->version & 0xff))) {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
             s->version = (s->version & 0xff00) | vers[1];
             al = SSL_AD_PROTOCOL_VERSION;
             goto f_err;
@@ -1068,30 +1232,30 @@ int ssl3_get_server_hello(SSL *s)
 
     /* load the server hello data */
     /* load the server random */
-    if (!PACKET_copy_bytes(&pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+    if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
 
     s->hit = 0;
 
     /* Get the session-id. */
-    if (!PACKET_get_length_prefixed_1(&pkt, &session_id)) {
+    if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
     session_id_len = PACKET_remaining(&session_id);
     if (session_id_len > sizeof s->session->session_id
         || session_id_len > SSL3_SESSION_ID_SIZE) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
         goto f_err;
     }
 
-    if (!PACKET_get_bytes(&pkt, &cipherchars, TLS_CIPHER_LEN)) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
         al = SSL_AD_DECODE_ERROR;
         goto f_err;
     }
@@ -1119,7 +1283,7 @@ int ssl3_get_server_hello(SSL *s)
             s->session->cipher = pref_cipher ?
                 pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
         } else {
-            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
             al = SSL_AD_INTERNAL_ERROR;
             goto f_err;
         }
@@ -1132,7 +1296,7 @@ int ssl3_get_server_hello(SSL *s)
             || 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_SSL3_GET_SERVER_HELLO,
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                    SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
             goto f_err;
         }
@@ -1161,7 +1325,7 @@ int ssl3_get_server_hello(SSL *s)
     if (c == NULL) {
         /* unknown cipher */
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
         goto f_err;
     }
     /* Set version disabled mask now we know version */
@@ -1175,7 +1339,7 @@ int ssl3_get_server_hello(SSL *s)
      */
     if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
         goto f_err;
     }
 
@@ -1184,7 +1348,7 @@ int ssl3_get_server_hello(SSL *s)
     if (i < 0) {
         /* we did not say we would use this cipher */
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
         goto f_err;
     }
 
@@ -1197,7 +1361,7 @@ int ssl3_get_server_hello(SSL *s)
         s->session->cipher_id = s->session->cipher->id;
     if (s->hit && (s->session->cipher_id != c->id)) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
         goto f_err;
     }
@@ -1210,15 +1374,15 @@ int ssl3_get_server_hello(SSL *s)
         goto f_err;
     /* lets get the compression algorithm */
     /* COMPRESSION */
-    if (!PACKET_get_1(&pkt, &compression)) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+    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;
     }
 #ifdef OPENSSL_NO_COMP
     if (compression != 0) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
         goto f_err;
     }
@@ -1227,13 +1391,13 @@ int ssl3_get_server_hello(SSL *s)
      * using compression.
      */
     if (s->session->compress_meth != 0) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
         goto f_err;
     }
 #else
     if (s->hit && compression != s->session->compress_meth) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
         goto f_err;
     }
@@ -1241,7 +1405,7 @@ int ssl3_get_server_hello(SSL *s)
         comp = NULL;
     else if (!ssl_allow_compression(s)) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED);
         goto f_err;
     } else {
         comp = ssl3_comp_find(s->ctx->comp_methods, compression);
@@ -1249,7 +1413,7 @@ int ssl3_get_server_hello(SSL *s)
 
     if (compression != 0 && comp == NULL) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
                SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
         goto f_err;
     } else {
@@ -1258,77 +1422,76 @@ int ssl3_get_server_hello(SSL *s)
 #endif
 
     /* TLS extensions */
-    if (!ssl_parse_serverhello_tlsext(s, &pkt)) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
+    if (!ssl_parse_serverhello_tlsext(s, pkt)) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
         goto err;
     }
 
-    if (PACKET_remaining(&pkt) != 0) {
+    if (PACKET_remaining(pkt) != 0) {
         /* wrong packet length */
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
         goto f_err;
     }
 
-    return (1);
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && s->hit) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if
+         * no SCTP used.
+         */
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                   sizeof(sctpauthkey),
+                                   labelbuffer,
+                                   sizeof(labelbuffer), NULL, 0,
+                                   0) <= 0)
+            goto err;
+
+        BIO_ctrl(SSL_get_wbio(s),
+                 BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-int ssl3_get_server_certificate(SSL *s)
+MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
 {
-    int al, i, ok, ret = -1, exp_idx;
-    unsigned long n, cert_list_len, cert_len;
+    int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
+    unsigned long cert_list_len, cert_len;
     X509 *x = NULL;
     unsigned char *certstart, *certbytes;
     STACK_OF(X509) *sk = NULL;
     EVP_PKEY *pkey = NULL;
-    PACKET pkt;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_CERT_A,
-                                   SSL3_ST_CR_CERT_B,
-                                   -1, s->max_cert_list, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    if (s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) {
-        s->s3->tmp.reuse_message = 1;
-        return (1);
-    }
-
-    if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_BAD_MESSAGE_TYPE);
-        goto f_err;
-    }
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
 
     if ((sk = sk_X509_new_null()) == NULL) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
-    if (!PACKET_get_net_3(&pkt, &cert_list_len)
-            || PACKET_remaining(&pkt) != cert_list_len) {
+    if (!PACKET_get_net_3(pkt, &cert_list_len)
+            || PACKET_remaining(pkt) != cert_list_len) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
-    while (PACKET_remaining(&pkt)) {
-        if (!PACKET_get_net_3(&pkt, &cert_len)
-                || !PACKET_get_bytes(&pkt, &certbytes, cert_len)) {
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_net_3(pkt, &cert_len)
+                || !PACKET_get_bytes(pkt, &certbytes, cert_len)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                    SSL_R_CERT_LENGTH_MISMATCH);
             goto f_err;
         }
@@ -1337,17 +1500,17 @@ int ssl3_get_server_certificate(SSL *s)
         x = d2i_X509(NULL, (const unsigned char **)&certbytes, cert_len);
         if (x == NULL) {
             al = SSL_AD_BAD_CERTIFICATE;
-            SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_ASN1_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_ASN1_LIB);
             goto f_err;
         }
         if (certbytes != (certstart + cert_len)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                    SSL_R_CERT_LENGTH_MISMATCH);
             goto f_err;
         }
         if (!sk_X509_push(sk, x)) {
-            SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
             goto err;
         }
         x = NULL;
@@ -1356,13 +1519,13 @@ int ssl3_get_server_certificate(SSL *s)
     i = ssl_verify_cert_chain(s, sk);
     if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) {
         al = ssl_verify_alarm_type(s->verify_result);
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                SSL_R_CERTIFICATE_VERIFY_FAILED);
         goto f_err;
     }
     ERR_clear_error();          /* but we keep s->verify_result */
     if (i > 1) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, i);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, i);
         al = SSL_AD_HANDSHAKE_FAILURE;
         goto f_err;
     }
@@ -1383,7 +1546,7 @@ int ssl3_get_server_certificate(SSL *s)
     if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) {
         x = NULL;
         al = SSL3_AL_FATAL;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
         goto f_err;
     }
@@ -1392,7 +1555,7 @@ int ssl3_get_server_certificate(SSL *s)
     if (i < 0) {
         x = NULL;
         al = SSL3_AL_FATAL;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                SSL_R_UNKNOWN_CERTIFICATE_TYPE);
         goto f_err;
     }
@@ -1401,7 +1564,7 @@ int ssl3_get_server_certificate(SSL *s)
     if (exp_idx >= 0 && i != exp_idx) {
         x = NULL;
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
                SSL_R_WRONG_CERTIFICATE_TYPE);
         goto f_err;
     }
@@ -1413,28 +1576,28 @@ int ssl3_get_server_certificate(SSL *s)
     s->session->verify_result = s->verify_result;
 
     x = NULL;
-    ret = 1;
+    ret = MSG_PROCESS_CONTINUE_READING;
     goto done;
 
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
-    s->state = SSL_ST_ERR;
+    ossl_statem_set_error(s);
  done:
     EVP_PKEY_free(pkey);
     X509_free(x);
     sk_X509_pop_free(sk, X509_free);
-    return (ret);
+    return ret;
 }
 
-int ssl3_get_key_exchange(SSL *s)
+MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 {
 #ifndef OPENSSL_NO_RSA
     unsigned char *q, md_buf[EVP_MAX_MD_SIZE * 2];
 #endif
     EVP_MD_CTX md_ctx;
-    int al, j, verify_ret, ok;
-    long n, alg_k, alg_a;
+    int al, j, verify_ret;
+    long alg_k, alg_a;
     EVP_PKEY *pkey = NULL;
     const EVP_MD *md = NULL;
 #ifndef OPENSSL_NO_RSA
@@ -1449,44 +1612,13 @@ int ssl3_get_key_exchange(SSL *s)
     EC_POINT *srvr_ecpoint = NULL;
     int curve_nid = 0;
 #endif
-    PACKET pkt, save_param_start, signature;
+    PACKET save_param_start, signature;
 
     EVP_MD_CTX_init(&md_ctx);
 
-    /*
-     * use same message size as in ssl3_get_certificate_request() as
-     * ServerKeyExchange message may be skipped
-     */
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_KEY_EXCH_A,
-                                   SSL3_ST_CR_KEY_EXCH_B,
-                                   -1, s->max_cert_list, &ok);
-    if (!ok)
-        return ((int)n);
-
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
-    if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) {
-        /*
-         * Can't skip server key exchange if this is an ephemeral
-         * ciphersuite.
-         */
-        if (alg_k & (SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            goto f_err;
-        }
-
-        s->s3->tmp.reuse_message = 1;
-        return (1);
-    }
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-    }
-    save_param_start = pkt;
+    save_param_start = *pkt;
 
 #ifndef OPENSSL_NO_RSA
     RSA_free(s->s3->peer_rsa_tmp);
@@ -1509,8 +1641,8 @@ int ssl3_get_key_exchange(SSL *s)
     /* PSK ciphersuites are preceded by an identity hint */
     if (alg_k & SSL_PSK) {
         PACKET psk_identity_hint;
-        if (!PACKET_get_length_prefixed_2(&pkt, &psk_identity_hint)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
@@ -1522,7 +1654,7 @@ int ssl3_get_key_exchange(SSL *s)
          */
         if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
             al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
             goto f_err;
         }
 
@@ -1540,11 +1672,11 @@ int ssl3_get_key_exchange(SSL *s)
 #ifndef OPENSSL_NO_SRP
     if (alg_k & SSL_kSRP) {
         PACKET prime, generator, salt, server_pub;
-        if (!PACKET_get_length_prefixed_2(&pkt, &prime)
-            || !PACKET_get_length_prefixed_2(&pkt, &generator)
-            || !PACKET_get_length_prefixed_1(&pkt, &salt)
-            || !PACKET_get_length_prefixed_2(&pkt, &server_pub)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_2(pkt, &prime)
+            || !PACKET_get_length_prefixed_2(pkt, &generator)
+            || !PACKET_get_length_prefixed_1(pkt, &salt)
+            || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
@@ -1560,12 +1692,12 @@ int ssl3_get_key_exchange(SSL *s)
             || (s->srp_ctx.B =
                 BN_bin2bn(PACKET_data(&server_pub),
                           PACKET_remaining(&server_pub), NULL)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
             goto err;
         }
 
         if (!srp_verify_server_param(s, &al)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS);
             goto f_err;
         }
 
@@ -1580,18 +1712,18 @@ int ssl3_get_key_exchange(SSL *s)
         /* Temporary RSA keys only allowed in export ciphersuites */
         if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
             al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
             goto f_err;
         }
 
-        if (!PACKET_get_length_prefixed_2(&pkt, &mod)
-            || !PACKET_get_length_prefixed_2(&pkt, &exp)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_2(pkt, &mod)
+            || !PACKET_get_length_prefixed_2(pkt, &exp)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
         if ((rsa = RSA_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto err;
         }
 
@@ -1599,7 +1731,7 @@ int ssl3_get_key_exchange(SSL *s)
                                 rsa->n)) == NULL
             || (rsa->e = BN_bin2bn(PACKET_data(&exp), PACKET_remaining(&exp),
                                    rsa->e)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
             goto err;
         }
 
@@ -1607,16 +1739,10 @@ int ssl3_get_key_exchange(SSL *s)
         if (alg_a & SSL_aRSA)
             pkey = X509_get_pubkey(s->session->peer);
         else {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto err;
         }
 
-        if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-        }
-
         s->s3->peer_rsa_tmp = rsa;
         rsa = NULL;
     }
@@ -1627,15 +1753,15 @@ int ssl3_get_key_exchange(SSL *s)
     else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
         PACKET prime, generator, pub_key;
 
-        if (!PACKET_get_length_prefixed_2(&pkt, &prime)
-            || !PACKET_get_length_prefixed_2(&pkt, &generator)
-            || !PACKET_get_length_prefixed_2(&pkt, &pub_key)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_2(pkt, &prime)
+            || !PACKET_get_length_prefixed_2(pkt, &generator)
+            || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
         if ((dh = DH_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_DH_LIB);
             goto err;
         }
 
@@ -1646,18 +1772,18 @@ int ssl3_get_key_exchange(SSL *s)
             || (dh->pub_key =
                 BN_bin2bn(PACKET_data(&pub_key),
                           PACKET_remaining(&pub_key), NULL)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
             goto err;
         }
 
         if (BN_is_zero(dh->p) || BN_is_zero(dh->g) || BN_is_zero(dh->pub_key)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
             goto f_err;
         }
 
         if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
             al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
             goto f_err;
         }
         if (alg_a & (SSL_aRSA|SSL_aDSS))
@@ -1677,7 +1803,7 @@ int ssl3_get_key_exchange(SSL *s)
         unsigned char *ecparams;
 
         if ((ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto err;
         }
 
@@ -1686,8 +1812,8 @@ int ssl3_get_key_exchange(SSL *s)
          * public key. For now we only support named (not generic) curves and
          * ECParameters in this case is just three bytes.
          */
-        if (!PACKET_get_bytes(&pkt, &ecparams, 3)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
+        if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
         }
         /*
@@ -1695,24 +1821,24 @@ int ssl3_get_key_exchange(SSL *s)
          * invalid curve. ECParameters is 3 bytes.
          */
         if (!tls1_check_curve(s, ecparams, 3)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
             goto f_err;
         }
 
         if ((curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2))) == 0) {
             al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
                    SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
             goto f_err;
         }
 
         ngroup = EC_GROUP_new_by_curve_name(curve_nid);
         if (ngroup == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
         }
         if (EC_KEY_set_group(ecdh, ngroup) == 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
         }
         EC_GROUP_free(ngroup);
@@ -1722,7 +1848,7 @@ int ssl3_get_key_exchange(SSL *s)
         if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
             (EC_GROUP_get_degree(group) > 163)) {
             al = SSL_AD_EXPORT_RESTRICTION;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
                    SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
             goto f_err;
         }
@@ -1730,18 +1856,18 @@ int ssl3_get_key_exchange(SSL *s)
         /* Next, get the encoded ECPoint */
         if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
             ((bn_ctx = BN_CTX_new()) == NULL)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto err;
         }
 
-        if (!PACKET_get_length_prefixed_1(&pkt, &encoded_pt)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
         if (EC_POINT_oct2point(group, srvr_ecpoint, PACKET_data(&encoded_pt),
                                PACKET_remaining(&encoded_pt), bn_ctx) == 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
             goto f_err;
         }
 
@@ -1769,7 +1895,7 @@ int ssl3_get_key_exchange(SSL *s)
         srvr_ecpoint = NULL;
     } else if (alg_k) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+        SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
         goto f_err;
     }
 #endif                          /* !OPENSSL_NO_EC */
@@ -1783,17 +1909,17 @@ int ssl3_get_key_exchange(SSL *s)
          */
         if (!PACKET_get_sub_packet(&save_param_start, &params,
                                    PACKET_remaining(&save_param_start) -
-                                   PACKET_remaining(&pkt))) {
+                                   PACKET_remaining(pkt))) {
             al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
         }
 
         if (SSL_USE_SIGALGS(s)) {
             unsigned char *sigalgs;
             int rv;
-            if (!PACKET_get_bytes(&pkt, &sigalgs, 2)) {
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
+            if (!PACKET_get_bytes(pkt, &sigalgs, 2)) {
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
                 goto f_err;
             }
             rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey);
@@ -1809,14 +1935,14 @@ int ssl3_get_key_exchange(SSL *s)
             md = EVP_sha1();
         }
 
-        if (!PACKET_get_length_prefixed_2(&pkt, &signature)
-            || PACKET_remaining(&pkt) != 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+        if (!PACKET_get_length_prefixed_2(pkt, &signature)
+            || PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
         j = EVP_PKEY_size(pkey);
         if (j < 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
         }
 
@@ -1825,7 +1951,7 @@ int ssl3_get_key_exchange(SSL *s)
          */
         if (PACKET_remaining(&signature) > (size_t)j) {
             /* wrong packet length */
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
             goto f_err;
         }
 #ifndef OPENSSL_NO_RSA
@@ -1854,13 +1980,13 @@ int ssl3_get_key_exchange(SSL *s)
                            PACKET_remaining(&signature), pkey->pkey.rsa);
             if (verify_ret < 0) {
                 al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_RSA_DECRYPT);
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_RSA_DECRYPT);
                 goto f_err;
             }
             if (verify_ret == 0) {
                 /* bad signature */
                 al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
                 goto f_err;
             }
         } else
@@ -1877,7 +2003,7 @@ int ssl3_get_key_exchange(SSL *s)
                                 PACKET_remaining(&signature), pkey) <= 0) {
                 /* bad signature */
                 al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
                 goto f_err;
             }
         }
@@ -1887,18 +2013,18 @@ int ssl3_get_key_exchange(SSL *s)
             /* Might be wrong key type, check it */
             if (ssl3_check_cert_and_algorithm(s))
                 /* Otherwise this shouldn't happen */
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto err;
         }
         /* still data left over */
-        if (PACKET_remaining(&pkt) != 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE);
+        if (PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE);
             goto f_err;
         }
     }
     EVP_PKEY_free(pkey);
     EVP_MD_CTX_cleanup(&md_ctx);
-    return (1);
+    return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
@@ -1915,74 +2041,29 @@ int ssl3_get_key_exchange(SSL *s)
     EC_KEY_free(ecdh);
 #endif
     EVP_MD_CTX_cleanup(&md_ctx);
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-int ssl3_get_certificate_request(SSL *s)
+MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
 {
-    int ok, ret = 0;
-    unsigned long n;
+    int ret = MSG_PROCESS_ERROR;
     unsigned int list_len, ctype_num, i, name_len;
     X509_NAME *xn = NULL;
     unsigned char *data;
     unsigned char *namestart, *namebytes;
     STACK_OF(X509_NAME) *ca_sk = NULL;
-    PACKET pkt;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_CERT_REQ_A,
-                                   SSL3_ST_CR_CERT_REQ_B,
-                                   -1, s->max_cert_list, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    s->s3->tmp.cert_req = 0;
-
-    if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE) {
-        s->s3->tmp.reuse_message = 1;
-        /*
-         * If we get here we don't need any cached handshake records as we
-         * wont be doing client auth.
-         */
-        if (!ssl3_digest_cached_records(s, 0))
-            goto err;
-        return (1);
-    }
-
-    if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
-        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_WRONG_MESSAGE_TYPE);
-        goto err;
-    }
-
-    /* TLS does not like anon-DH with client cert */
-    if (s->version > SSL3_VERSION) {
-        if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,
-                   SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER);
-            goto err;
-        }
-    }
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
 
     if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) {
-        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
     /* get the certificate types */
-    if (!PACKET_get_1(&pkt, &ctype_num)
-            || !PACKET_get_bytes(&pkt, &data, ctype_num)) {
+    if (!PACKET_get_1(pkt, &ctype_num)
+            || !PACKET_get_bytes(pkt, &data, ctype_num)) {
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
         goto err;
     }
     OPENSSL_free(s->cert->ctypes);
@@ -1991,7 +2072,7 @@ int ssl3_get_certificate_request(SSL *s)
         /* If we exceed static buffer copy all to cert structure */
         s->cert->ctypes = OPENSSL_malloc(ctype_num);
         if (s->cert->ctypes == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
             goto err;
         }
         memcpy(s->cert->ctypes, data, ctype_num);
@@ -2002,10 +2083,11 @@ int ssl3_get_certificate_request(SSL *s)
         s->s3->tmp.ctype[i] = data[i];
 
     if (SSL_USE_SIGALGS(s)) {
-        if (!PACKET_get_net_2(&pkt, &list_len)
-                || !PACKET_get_bytes(&pkt, &data, list_len)) {
+        if (!PACKET_get_net_2(pkt, &list_len)
+                || !PACKET_get_bytes(pkt, &data, list_len)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_LENGTH_MISMATCH);
             goto err;
         }
 
@@ -2016,30 +2098,31 @@ int ssl3_get_certificate_request(SSL *s)
         }
         if ((list_len & 1) || !tls1_save_sigalgs(s, data, list_len)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
                    SSL_R_SIGNATURE_ALGORITHMS_ERROR);
             goto err;
         }
         if (!tls1_process_sigalgs(s)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
             goto err;
         }
     }
 
     /* get the CA RDNs */
-    if (!PACKET_get_net_2(&pkt, &list_len)
-            || PACKET_remaining(&pkt) != list_len) {
+    if (!PACKET_get_net_2(pkt, &list_len)
+            || PACKET_remaining(pkt) != list_len) {
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
         goto err;
     }
 
-    while (PACKET_remaining(&pkt)) {
-        if (!PACKET_get_net_2(&pkt, &name_len)
-                || !PACKET_get_bytes(&pkt, &namebytes, name_len)) {
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_net_2(pkt, &name_len)
+                || !PACKET_get_bytes(pkt, &namebytes, name_len)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_LENGTH_MISMATCH);
             goto err;
         }
 
@@ -2048,18 +2131,18 @@ int ssl3_get_certificate_request(SSL *s)
         if ((xn = d2i_X509_NAME(NULL, (const unsigned char **)&namebytes,
                                 name_len)) == NULL) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
             goto err;
         }
 
         if (namebytes != (namestart + name_len)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
                    SSL_R_CA_DN_LENGTH_MISMATCH);
             goto err;
         }
         if (!sk_X509_NAME_push(ca_sk, xn)) {
-            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
             goto err;
         }
     }
@@ -2071,13 +2154,13 @@ int ssl3_get_certificate_request(SSL *s)
     s->s3->tmp.ca_names = ca_sk;
     ca_sk = NULL;
 
-    ret = 1;
+    ret = MSG_PROCESS_CONTINUE_READING;
     goto done;
  err:
-    s->state = SSL_ST_ERR;
+    ossl_statem_set_error(s);
  done:
     sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
-    return (ret);
+    return ret;
 }
 
 static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
@@ -2085,39 +2168,23 @@ static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
     return (X509_NAME_cmp(*a, *b));
 }
 
-int ssl3_get_new_session_ticket(SSL *s)
+MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
 {
-    int ok, al, ret = 0;
+    int al;
     unsigned int ticklen;
     unsigned long ticket_lifetime_hint;
-    long n;
-    PACKET pkt;
-
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_SESSION_TICKET_A,
-                                   SSL3_ST_CR_SESSION_TICKET_B,
-                                   SSL3_MT_NEWSESSION_TICKET, 16384, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
 
-    if (!PACKET_get_net_4(&pkt, &ticket_lifetime_hint)
-            || !PACKET_get_net_2(&pkt, &ticklen)
-            || PACKET_remaining(&pkt) != ticklen) {
+    if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+            || !PACKET_get_net_2(pkt, &ticklen)
+            || PACKET_remaining(pkt) != ticklen) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
+        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. */
     if (ticklen == 0)
-        return 1;
+        return MSG_PROCESS_CONTINUE_READING;
 
     if (s->session->session_id_length > 0) {
         int i = s->session_ctx->session_cache_mode;
@@ -2142,7 +2209,7 @@ int ssl3_get_new_session_ticket(SSL *s)
 
         if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
             al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
             goto f_err;
         }
 
@@ -2155,12 +2222,12 @@ int ssl3_get_new_session_ticket(SSL *s)
 
     s->session->tlsext_tick = OPENSSL_malloc(ticklen);
     if (!s->session->tlsext_tick) {
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
         goto err;
     }
-    if (!PACKET_copy_bytes(&pkt, s->session->tlsext_tick, ticklen)) {
+    if (!PACKET_copy_bytes(pkt, s->session->tlsext_tick, ticklen)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
 
@@ -2180,57 +2247,42 @@ int ssl3_get_new_session_ticket(SSL *s)
     EVP_Digest(s->session->tlsext_tick, ticklen,
                s->session->session_id, &s->session->session_id_length,
                EVP_sha256(), NULL);
-    ret = 1;
-    return (ret);
+    return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-int ssl3_get_cert_status(SSL *s)
+MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
 {
-    int ok, al;
-    unsigned long resplen, n;
+    int al;
+    unsigned long resplen;
     unsigned int type;
-    PACKET pkt;
 
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_CERT_STATUS_A,
-                                   SSL3_ST_CR_CERT_STATUS_B,
-                                   SSL3_MT_CERTIFICATE_STATUS, 16384, &ok);
-
-    if (!ok)
-        return ((int)n);
-
-    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
-    if (!PACKET_get_1(&pkt, &type)
+    if (!PACKET_get_1(pkt, &type)
             || type != TLSEXT_STATUSTYPE_ocsp) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
         goto f_err;
     }
-    if (!PACKET_get_net_3(&pkt, &resplen)
-            || PACKET_remaining(&pkt) != resplen) {
+    if (!PACKET_get_net_3(pkt, &resplen)
+            || PACKET_remaining(pkt) != resplen) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
     OPENSSL_free(s->tlsext_ocsp_resp);
     s->tlsext_ocsp_resp = OPENSSL_malloc(resplen);
     if (!s->tlsext_ocsp_resp) {
         al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_MALLOC_FAILURE);
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
         goto f_err;
     }
-    if (!PACKET_copy_bytes(&pkt, s->tlsext_ocsp_resp, resplen)) {
+    if (!PACKET_copy_bytes(pkt, s->tlsext_ocsp_resp, resplen)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
     s->tlsext_ocsp_resplen = resplen;
@@ -2239,47 +2291,64 @@ int ssl3_get_cert_status(SSL *s)
         ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
         if (ret == 0) {
             al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
-            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_INVALID_STATUS_RESPONSE);
+            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_INVALID_STATUS_RESPONSE);
             goto f_err;
         }
         if (ret < 0) {
             al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_MALLOC_FAILURE);
+            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
             goto f_err;
         }
     }
-    return 1;
+    return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-int ssl3_get_server_done(SSL *s)
+MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
 {
-    int ok, ret = 0;
-    long n;
-
-    /* Second to last param should be very small, like 0 :-) */
-    n = s->method->ssl_get_message(s,
-                                   SSL3_ST_CR_SRVR_DONE_A,
-                                   SSL3_ST_CR_SRVR_DONE_B,
-                                   SSL3_MT_SERVER_DONE, 30, &ok);
-
-    if (!ok)
-        return ((int)n);
-    if (n > 0) {
+    if (PACKET_remaining(pkt) > 0) {
         /* should contain no data */
         ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_SSL3_GET_SERVER_DONE, SSL_R_LENGTH_MISMATCH);
-        s->state = SSL_ST_ERR;
-        return -1;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_LENGTH_MISMATCH);
+        ossl_statem_set_error(s);
+        return MSG_PROCESS_ERROR;
+    }
+
+#ifndef OPENSSL_NO_SRP
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (SRP_Calc_A_param(s) <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_SRP_A_CALC);
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            ossl_statem_set_error(s);
+            return MSG_PROCESS_ERROR;
+        }
+    }
+#endif
+
+    /*
+     * at this point we check that we have the required stuff from
+     * the server
+     */
+    if (!ssl3_check_cert_and_algorithm(s)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        ossl_statem_set_error(s);
+        return MSG_PROCESS_ERROR;
     }
-    ret = 1;
-    return (ret);
+
+#ifndef OPENSSL_NO_SCTP
+    /* Only applies to renegotiation */
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))
+            && s->renegotiate != 0)
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+    else
+#endif
+        return MSG_PROCESS_FINISHED_READING;
 }
 
-int ssl3_send_client_key_exchange(SSL *s)
+int tls_construct_client_key_exchange(SSL *s)
 {
     unsigned char *p;
     int n;
@@ -2303,580 +2372,540 @@ int ssl3_send_client_key_exchange(SSL *s)
     size_t pmslen = 0;
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
-    if (s->state == SSL3_ST_CW_KEY_EXCH_A) {
-        p = ssl_handshake_start(s);
+    p = ssl_handshake_start(s);
 
 
 #ifndef OPENSSL_NO_PSK
-        if (alg_k & SSL_PSK) {
-            int psk_err = 1;
-            /*
-             * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
-             * \0-terminated identity. The last byte is for us for simulating
-             * strnlen.
-             */
-            char identity[PSK_MAX_IDENTITY_LEN + 1];
-            size_t identitylen;
-            unsigned char psk[PSK_MAX_PSK_LEN];
-            size_t psklen;
-
-            if (s->psk_client_callback == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_PSK_NO_CLIENT_CB);
-                goto err;
-            }
-
-            memset(identity, 0, sizeof(identity));
+    if (alg_k & SSL_PSK) {
+        int psk_err = 1;
+        /*
+         * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
+         * \0-terminated identity. The last byte is for us for simulating
+         * strnlen.
+         */
+        char identity[PSK_MAX_IDENTITY_LEN + 1];
+        size_t identitylen;
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen;
+
+        if (s->psk_client_callback == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_NO_CLIENT_CB);
+            goto err;
+        }
 
-            psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
-                                            identity, sizeof(identity) - 1,
-                                            psk, sizeof(psk));
+        memset(identity, 0, sizeof(identity));
 
-            if (psklen > PSK_MAX_PSK_LEN) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto psk_err;
-            } else if (psklen == 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_PSK_IDENTITY_NOT_FOUND);
-                goto psk_err;
-            }
+        psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
+                                        identity, sizeof(identity) - 1,
+                                        psk, sizeof(psk));
 
-            OPENSSL_free(s->s3->tmp.psk);
-            s->s3->tmp.psk = BUF_memdup(psk, psklen);
-            OPENSSL_cleanse(psk, psklen);
+        if (psklen > PSK_MAX_PSK_LEN) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto psk_err;
+        } else if (psklen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_IDENTITY_NOT_FOUND);
+            goto psk_err;
+        }
 
-            if (s->s3->tmp.psk == NULL) {
-                OPENSSL_cleanse(identity, sizeof(identity));
-                goto memerr;
-            }
+        OPENSSL_free(s->s3->tmp.psk);
+        s->s3->tmp.psk = BUF_memdup(psk, psklen);
+        OPENSSL_cleanse(psk, psklen);
 
-            s->s3->tmp.psklen = psklen;
+        if (s->s3->tmp.psk == NULL) {
+            OPENSSL_cleanse(identity, sizeof(identity));
+            goto memerr;
+        }
 
-            identitylen = strlen(identity);
-            if (identitylen > PSK_MAX_IDENTITY_LEN) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto psk_err;
-            }
-            OPENSSL_free(s->session->psk_identity);
-            s->session->psk_identity = BUF_strdup(identity);
-            if (s->session->psk_identity == NULL) {
-                OPENSSL_cleanse(identity, sizeof(identity));
-                goto memerr;
-            }
+        s->s3->tmp.psklen = psklen;
 
-            s2n(identitylen, p);
-            memcpy(p, identity, identitylen);
-            pskhdrlen = 2 + identitylen;
-            p += identitylen;
-            psk_err = 0;
- psk_err:
+        identitylen = strlen(identity);
+        if (identitylen > PSK_MAX_IDENTITY_LEN) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto psk_err;
+        }
+        OPENSSL_free(s->session->psk_identity);
+        s->session->psk_identity = BUF_strdup(identity);
+        if (s->session->psk_identity == NULL) {
             OPENSSL_cleanse(identity, sizeof(identity));
-            if (psk_err != 0) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-                goto err;
-            }
+            goto memerr;
         }
-        if (alg_k & SSL_kPSK) {
-            n = 0;
-        } else
-#endif
 
-        /* Fool emacs indentation */
-        if (0) {
+        s2n(identitylen, p);
+        memcpy(p, identity, identitylen);
+        pskhdrlen = 2 + identitylen;
+        p += identitylen;
+        psk_err = 0;
+psk_err:
+        OPENSSL_cleanse(identity, sizeof(identity));
+        if (psk_err != 0) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+            goto err;
         }
+    }
+    if (alg_k & SSL_kPSK) {
+        n = 0;
+    } else
+#endif
+
+    /* Fool emacs indentation */
+    if (0) {
+    }
 #ifndef OPENSSL_NO_RSA
-        else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-            RSA *rsa;
-            pmslen = SSL_MAX_MASTER_KEY_LENGTH;
-            pms = OPENSSL_malloc(pmslen);
-            if (!pms)
-                goto memerr;
-
-            if (s->session->peer == NULL) {
-                /*
-                 * We should always have a server certificate with SSL_kRSA.
-                 */
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
+    else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        RSA *rsa;
+        pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+
+        if (s->session->peer == NULL) {
+            /*
+             * We should always have a server certificate with SSL_kRSA.
+             */
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
-            if (s->s3->peer_rsa_tmp != NULL)
-                rsa = s->s3->peer_rsa_tmp;
-            else {
-                pkey = X509_get_pubkey(s->session->peer);
-                if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA)
-                    || (pkey->pkey.rsa == NULL)) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    EVP_PKEY_free(pkey);
-                    goto err;
-                }
-                rsa = pkey->pkey.rsa;
+        if (s->s3->peer_rsa_tmp != NULL)
+            rsa = s->s3->peer_rsa_tmp;
+        else {
+            pkey = X509_get_pubkey(s->session->peer);
+            if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA)
+                || (pkey->pkey.rsa == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
                 EVP_PKEY_free(pkey);
+                goto err;
             }
+            rsa = pkey->pkey.rsa;
+            EVP_PKEY_free(pkey);
+        }
 
-            pms[0] = s->client_version >> 8;
-            pms[1] = s->client_version & 0xff;
-            if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
-                goto err;
+        pms[0] = s->client_version >> 8;
+        pms[1] = s->client_version & 0xff;
+        if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
+            goto err;
 
-            q = p;
-            /* Fix buf for TLS and beyond */
-            if (s->version > SSL3_VERSION)
-                p += 2;
-            n = RSA_public_encrypt(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
+        q = p;
+        /* Fix buf for TLS and beyond */
+        if (s->version > SSL3_VERSION)
+            p += 2;
+        n = RSA_public_encrypt(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
 # ifdef PKCS1_CHECK
-            if (s->options & SSL_OP_PKCS1_CHECK_1)
-                p[1]++;
-            if (s->options & SSL_OP_PKCS1_CHECK_2)
-                tmp_buf[0] = 0x70;
+        if (s->options & SSL_OP_PKCS1_CHECK_1)
+            p[1]++;
+        if (s->options & SSL_OP_PKCS1_CHECK_2)
+            tmp_buf[0] = 0x70;
 # endif
-            if (n <= 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_BAD_RSA_ENCRYPT);
-                goto err;
-            }
+        if (n <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_BAD_RSA_ENCRYPT);
+            goto err;
+        }
 
-            /* Fix buf for TLS and beyond */
-            if (s->version > SSL3_VERSION) {
-                s2n(n, q);
-                n += 2;
-            }
+        /* Fix buf for TLS and beyond */
+        if (s->version > SSL3_VERSION) {
+            s2n(n, q);
+            n += 2;
         }
+    }
 #endif
 #ifndef OPENSSL_NO_DH
-        else if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
-            DH *dh_srvr, *dh_clnt;
-            if (s->s3->peer_dh_tmp != NULL)
-                dh_srvr = s->s3->peer_dh_tmp;
-            else {
-                /* we get them from the cert */
-                EVP_PKEY *spkey = NULL;
-                dh_srvr = NULL;
-                spkey = X509_get_pubkey(s->session->peer);
-                if (spkey) {
-                    dh_srvr = EVP_PKEY_get1_DH(spkey);
-                    EVP_PKEY_free(spkey);
-                }
-                if (dh_srvr == NULL) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto err;
-                }
-            }
-            if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
-                /* Use client certificate key */
-                EVP_PKEY *clkey = s->cert->key->privatekey;
-                dh_clnt = NULL;
-                if (clkey)
-                    dh_clnt = EVP_PKEY_get1_DH(clkey);
-                if (dh_clnt == NULL) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto err;
-                }
-            } else {
-                /* generate a new random key */
-                if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    goto err;
-                }
-                if (!DH_generate_key(dh_clnt)) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    DH_free(dh_clnt);
-                    goto err;
-                }
+    else if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
+        DH *dh_srvr, *dh_clnt;
+        if (s->s3->peer_dh_tmp != NULL)
+            dh_srvr = s->s3->peer_dh_tmp;
+        else {
+            /* we get them from the cert */
+            EVP_PKEY *spkey = NULL;
+            dh_srvr = NULL;
+            spkey = X509_get_pubkey(s->session->peer);
+            if (spkey) {
+                dh_srvr = EVP_PKEY_get1_DH(spkey);
+                EVP_PKEY_free(spkey);
             }
-
-            pmslen = DH_size(dh_clnt);
-            pms = OPENSSL_malloc(pmslen);
-            if (!pms)
-                goto memerr;
-
-            /*
-             * use the 'p' output buffer for the DH key, but make sure to
-             * clear it out afterwards
-             */
-
-            n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
-            if (s->s3->peer_dh_tmp == NULL)
-                DH_free(dh_srvr);
-
-            if (n <= 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-                DH_free(dh_clnt);
+            if (dh_srvr == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
                 goto err;
             }
-            pmslen = n;
-
-            if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
-                n = 0;
-            else {
-                /* send off the data */
-                n = BN_num_bytes(dh_clnt->pub_key);
-                s2n(n, p);
-                BN_bn2bin(dh_clnt->pub_key, p);
-                n += 2;
-            }
-
-            DH_free(dh_clnt);
         }
-#endif
-
-#ifndef OPENSSL_NO_EC
-        else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-            const EC_GROUP *srvr_group = NULL;
-            EC_KEY *tkey;
-            int ecdh_clnt_cert = 0;
-            int field_size = 0;
-            /*
-             * Did we send out the client's ECDH share for use in premaster
-             * computation as part of client certificate? If so, set
-             * ecdh_clnt_cert to 1.
-             */
-            if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) {
-                /*-
-                 * XXX: For now, we do not support client
-                 * authentication using ECDH certificates.
-                 * To add such support, one needs to add
-                 * code that checks for appropriate
-                 * conditions and sets ecdh_clnt_cert to 1.
-                 * For example, the cert have an ECC
-                 * key on the same curve as the server's
-                 * and the key should be authorized for
-                 * key agreement.
-                 *
-                 * One also needs to add code in ssl3_connect
-                 * to skip sending the certificate verify
-                 * message.
-                 *
-                 * if ((s->cert->key->privatekey != NULL) &&
-                 *     (s->cert->key->privatekey->type ==
-                 *      EVP_PKEY_EC) && ...)
-                 * ecdh_clnt_cert = 1;
-                 */
-            }
-
-            if (s->s3->peer_ecdh_tmp != NULL) {
-                tkey = s->s3->peer_ecdh_tmp;
-            } else {
-                /* Get the Server Public Key from Cert */
-                srvr_pub_pkey = X509_get_pubkey(s->session->peer);
-                if ((srvr_pub_pkey == NULL)
-                    || (srvr_pub_pkey->type != EVP_PKEY_EC)
-                    || (srvr_pub_pkey->pkey.ec == NULL)) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto err;
-                }
-
-                tkey = srvr_pub_pkey->pkey.ec;
-            }
-
-            srvr_group = EC_KEY_get0_group(tkey);
-            srvr_ecpoint = EC_KEY_get0_public_key(tkey);
-
-            if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
+            /* Use client certificate key */
+            EVP_PKEY *clkey = s->cert->key->privatekey;
+            dh_clnt = NULL;
+            if (clkey)
+                dh_clnt = EVP_PKEY_get1_DH(clkey);
+            if (dh_clnt == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                        ERR_R_INTERNAL_ERROR);
                 goto err;
             }
-
-            if ((clnt_ecdh = EC_KEY_new()) == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-
-            if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            if (ecdh_clnt_cert) {
-                /*
-                 * Reuse key info from our certificate We only need our
-                 * private key to perform the ECDH computation.
-                 */
-                const BIGNUM *priv_key;
-                tkey = s->cert->key->privatekey->pkey.ec;
-                priv_key = EC_KEY_get0_private_key(tkey);
-                if (priv_key == NULL) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_MALLOC_FAILURE);
-                    goto err;
-                }
-                if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                    goto err;
-                }
-            } else {
-                /* Generate a new ECDH key pair */
-                if (!(EC_KEY_generate_key(clnt_ecdh))) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_ECDH_LIB);
-                    goto err;
-                }
-            }
-
-            /*
-             * use the 'p' output buffer for the ECDH key, but make sure to
-             * clear it out afterwards
-             */
-
-            field_size = EC_GROUP_get_degree(srvr_group);
-            if (field_size <= 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+        } else {
+            /* generate a new random key */
+            if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
                 goto err;
             }
-            pmslen = (field_size + 7) / 8;
-            pms = OPENSSL_malloc(pmslen);
-            if (!pms)
-                goto memerr;
-            n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
-            if (n <= 0 || pmslen != (size_t)n) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            if (!DH_generate_key(dh_clnt)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+                DH_free(dh_clnt);
                 goto err;
             }
+        }
 
-            if (ecdh_clnt_cert) {
-                /* Send empty client key exch message */
-                n = 0;
-            } else {
-                /*
-                 * First check the size of encoding and allocate memory
-                 * accordingly.
-                 */
-                encoded_pt_len =
-                    EC_POINT_point2oct(srvr_group,
-                                       EC_KEY_get0_public_key(clnt_ecdh),
-                                       POINT_CONVERSION_UNCOMPRESSED,
-                                       NULL, 0, NULL);
-
-                encodedPoint = (unsigned char *)
-                    OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char));
-                bn_ctx = BN_CTX_new();
-                if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-                    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                           ERR_R_MALLOC_FAILURE);
-                    goto err;
-                }
+        pmslen = DH_size(dh_clnt);
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
 
-                /* Encode the public key */
-                n = EC_POINT_point2oct(srvr_group,
-                                       EC_KEY_get0_public_key(clnt_ecdh),
-                                       POINT_CONVERSION_UNCOMPRESSED,
-                                       encodedPoint, encoded_pt_len, bn_ctx);
-
-                *p = n;         /* length of encoded point */
-                /* Encoded point will be copied here */
-                p += 1;
-                /* copy the point */
-                memcpy(p, encodedPoint, n);
-                /* increment n to account for length field */
-                n += 1;
-            }
+        /*
+         * use the 'p' output buffer for the DH key, but make sure to
+         * clear it out afterwards
+         */
 
-            /* Free allocated memory */
-            BN_CTX_free(bn_ctx);
-            OPENSSL_free(encodedPoint);
-            EC_KEY_free(clnt_ecdh);
-            EVP_PKEY_free(srvr_pub_pkey);
+        n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
+        if (s->s3->peer_dh_tmp == NULL)
+            DH_free(dh_srvr);
+
+        if (n <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+            DH_free(dh_clnt);
+            goto err;
         }
-#endif                          /* !OPENSSL_NO_EC */
-        else if (alg_k & SSL_kGOST) {
-            /* GOST key exchange message creation */
-            EVP_PKEY_CTX *pkey_ctx;
-            X509 *peer_cert;
-            size_t msglen;
-            unsigned int md_len;
-            unsigned char shared_ukm[32], tmp[256];
-            EVP_MD_CTX *ukm_hash;
-            EVP_PKEY *pub_key;
-
-            pmslen = 32;
-            pms = OPENSSL_malloc(pmslen);
-            if (!pms)
-                goto memerr;
+        pmslen = n;
 
-            /*
-             * Get server sertificate PKEY and create ctx from it
-             */
-            peer_cert = s->session->peer;
-            if (!peer_cert) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
-                goto err;
-            }
+        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+            n = 0;
+        else {
+            /* send off the data */
+            n = BN_num_bytes(dh_clnt->pub_key);
+            s2n(n, p);
+            BN_bn2bin(dh_clnt->pub_key, p);
+            n += 2;
+        }
 
-            pkey_ctx = EVP_PKEY_CTX_new(pub_key =
-                                        X509_get_pubkey(peer_cert), NULL);
-            /*
-             * If we have send a certificate, and certificate key
+        DH_free(dh_clnt);
+    }
+#endif
+
+#ifndef OPENSSL_NO_EC
+    else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
+        const EC_GROUP *srvr_group = NULL;
+        EC_KEY *tkey;
+        int ecdh_clnt_cert = 0;
+        int field_size = 0;
+        /*
+         * Did we send out the client's ECDH share for use in premaster
+         * computation as part of client certificate? If so, set
+         * ecdh_clnt_cert to 1.
+         */
+        if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) {
+            /*-
+             * XXX: For now, we do not support client
+             * authentication using ECDH certificates.
+             * To add such support, one needs to add
+             * code that checks for appropriate
+             * conditions and sets ecdh_clnt_cert to 1.
+             * For example, the cert have an ECC
+             * key on the same curve as the server's
+             * and the key should be authorized for
+             * key agreement.
              *
-             * * parameters match those of server certificate, use
-             * certificate key for key exchange
+             * One also needs to add code in ssl3_connect
+             * to skip sending the certificate verify
+             * message.
+             *
+             * if ((s->cert->key->privatekey != NULL) &&
+             *     (s->cert->key->privatekey->type ==
+             *      EVP_PKEY_EC) && ...)
+             * ecdh_clnt_cert = 1;
              */
+        }
 
-            /* Otherwise, generate ephemeral key pair */
-
-            EVP_PKEY_encrypt_init(pkey_ctx);
-            /* Generate session key */
-            if (RAND_bytes(pms, pmslen) <= 0) {
-                EVP_PKEY_CTX_free(pkey_ctx);
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+        if (s->s3->peer_ecdh_tmp != NULL) {
+            tkey = s->s3->peer_ecdh_tmp;
+        } else {
+            /* Get the Server Public Key from Cert */
+            srvr_pub_pkey = X509_get_pubkey(s->session->peer);
+            if ((srvr_pub_pkey == NULL)
+                || (srvr_pub_pkey->type != EVP_PKEY_EC)
+                || (srvr_pub_pkey->pkey.ec == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                        ERR_R_INTERNAL_ERROR);
                 goto err;
-            };
-            /*
-             * If we have client certificate, use its secret as peer key
-             */
-            if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
-                if (EVP_PKEY_derive_set_peer
-                    (pkey_ctx, s->cert->key->privatekey) <= 0) {
-                    /*
-                     * If there was an error - just ignore it. Ephemeral key
-                     * * would be used
-                     */
-                    ERR_clear_error();
-                }
             }
+
+            tkey = srvr_pub_pkey->pkey.ec;
+        }
+
+        srvr_group = EC_KEY_get0_group(tkey);
+        srvr_ecpoint = EC_KEY_get0_public_key(tkey);
+
+        if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if ((clnt_ecdh = EC_KEY_new()) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+        if (ecdh_clnt_cert) {
             /*
-             * Compute shared IV and store it in algorithm-specific context
-             * data
+             * Reuse key info from our certificate We only need our
+             * private key to perform the ECDH computation.
              */
-            ukm_hash = EVP_MD_CTX_create();
-            EVP_DigestInit(ukm_hash,
-                           EVP_get_digestbynid(NID_id_GostR3411_94));
-            EVP_DigestUpdate(ukm_hash, s->s3->client_random,
-                             SSL3_RANDOM_SIZE);
-            EVP_DigestUpdate(ukm_hash, s->s3->server_random,
-                             SSL3_RANDOM_SIZE);
-            EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
-            EVP_MD_CTX_destroy(ukm_hash);
-            if (EVP_PKEY_CTX_ctrl
-                (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
-                 shared_ukm) < 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_LIBRARY_BUG);
+            const BIGNUM *priv_key;
+            tkey = s->cert->key->privatekey->pkey.ec;
+            priv_key = EC_KEY_get0_private_key(tkey);
+            if (priv_key == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
                 goto err;
             }
-            /* Make GOST keytransport blob message */
-            /*
-             * Encapsulate it into sequence
-             */
-            *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
-            msglen = 255;
-            if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       SSL_R_LIBRARY_BUG);
+            if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
                 goto err;
             }
-            if (msglen >= 0x80) {
-                *(p++) = 0x81;
-                *(p++) = msglen & 0xff;
-                n = msglen + 3;
-            } else {
-                *(p++) = msglen & 0xff;
-                n = msglen + 2;
-            }
-            memcpy(p, tmp, msglen);
-            /* Check if pubkey from client certificate was used */
-            if (EVP_PKEY_CTX_ctrl
-                (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) {
-                /* Set flag "skip certificate verify" */
-                s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+        } else {
+            /* Generate a new ECDH key pair */
+            if (!(EC_KEY_generate_key(clnt_ecdh))) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_ECDH_LIB);
+                goto err;
             }
-            EVP_PKEY_CTX_free(pkey_ctx);
-            EVP_PKEY_free(pub_key);
+        }
+
+        /*
+         * use the 'p' output buffer for the ECDH key, but make sure to
+         * clear it out afterwards
+         */
 
+        field_size = EC_GROUP_get_degree(srvr_group);
+        if (field_size <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
         }
-#ifndef OPENSSL_NO_SRP
-        else if (alg_k & SSL_kSRP) {
-            if (s->srp_ctx.A != NULL) {
-                /* send off the data */
-                n = BN_num_bytes(s->srp_ctx.A);
-                s2n(n, p);
-                BN_bn2bin(s->srp_ctx.A, p);
-                n += 2;
-            } else {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            OPENSSL_free(s->session->srp_username);
-            s->session->srp_username = BUF_strdup(s->srp_ctx.login);
-            if (s->session->srp_username == NULL) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+        pmslen = (field_size + 7) / 8;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+        n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
+        if (n <= 0 || pmslen != (size_t)n) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        if (ecdh_clnt_cert) {
+            /* Send empty client key exch message */
+            n = 0;
+        } else {
+            /*
+             * First check the size of encoding and allocate memory
+             * accordingly.
+             */
+            encoded_pt_len =
+                EC_POINT_point2oct(srvr_group,
+                                   EC_KEY_get0_public_key(clnt_ecdh),
+                                   POINT_CONVERSION_UNCOMPRESSED,
+                                   NULL, 0, NULL);
+
+            encodedPoint = (unsigned char *)
+                OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char));
+            bn_ctx = BN_CTX_new();
+            if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                        ERR_R_MALLOC_FAILURE);
                 goto err;
             }
-        }
-#endif
-        else {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto err;
+
+            /* Encode the public key */
+            n = EC_POINT_point2oct(srvr_group,
+                                   EC_KEY_get0_public_key(clnt_ecdh),
+                                   POINT_CONVERSION_UNCOMPRESSED,
+                                   encodedPoint, encoded_pt_len, bn_ctx);
+
+            *p = n;         /* length of encoded point */
+            /* Encoded point will be copied here */
+            p += 1;
+            /* copy the point */
+            memcpy(p, encodedPoint, n);
+            /* increment n to account for length field */
+            n += 1;
         }
 
-#ifndef OPENSSL_NO_PSK
-        n += pskhdrlen;
-#endif
+        /* Free allocated memory */
+        BN_CTX_free(bn_ctx);
+        OPENSSL_free(encodedPoint);
+        EC_KEY_free(clnt_ecdh);
+        EVP_PKEY_free(srvr_pub_pkey);
+    }
+#endif                          /* !OPENSSL_NO_EC */
+    else if (alg_k & SSL_kGOST) {
+        /* GOST key exchange message creation */
+        EVP_PKEY_CTX *pkey_ctx;
+        X509 *peer_cert;
+        size_t msglen;
+        unsigned int md_len;
+        unsigned char shared_ukm[32], tmp[256];
+        EVP_MD_CTX *ukm_hash;
+        EVP_PKEY *pub_key;
+
+        pmslen = 32;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
 
-        if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        /*
+         * Get server sertificate PKEY and create ctx from it
+         */
+        peer_cert = s->session->peer;
+        if (!peer_cert) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
             goto err;
         }
 
-        s->state = SSL3_ST_CW_KEY_EXCH_B;
-    }
+        pkey_ctx = EVP_PKEY_CTX_new(pub_key =
+                                    X509_get_pubkey(peer_cert), NULL);
+        /*
+         * If we have send a certificate, and certificate key
+         *
+         * * parameters match those of server certificate, use
+         * certificate key for key exchange
+         */
 
-    /* SSL3_ST_CW_KEY_EXCH_B */
-    n = ssl_do_write(s);
-#ifndef OPENSSL_NO_SRP
-    /* Check for SRP */
-    if (alg_k & SSL_kSRP) {
+        /* Otherwise, generate ephemeral key pair */
+
+        EVP_PKEY_encrypt_init(pkey_ctx);
+        /* Generate session key */
+        if (RAND_bytes(pms, pmslen) <= 0) {
+            EVP_PKEY_CTX_free(pkey_ctx);
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        };
         /*
-         * If everything written generate master key: no need to save PMS as
-         * srp_generate_client_master_secret generates it internally.
+         * If we have client certificate, use its secret as peer key
          */
-        if (n > 0) {
-            if (!srp_generate_client_master_secret(s)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
+        if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+            if (EVP_PKEY_derive_set_peer
+                (pkey_ctx, s->cert->key->privatekey) <= 0) {
+                /*
+                 * If there was an error - just ignore it. Ephemeral key
+                 * * would be used
+                 */
+                ERR_clear_error();
             }
         }
-    } else
-#endif
-        /* If we haven't written everything save PMS */
-    if (n <= 0) {
-        s->s3->tmp.pms = pms;
-        s->s3->tmp.pmslen = pmslen;
-    } else {
-        /* If we don't have a PMS restore */
-        if (pms == NULL) {
-            pms = s->s3->tmp.pms;
-            pmslen = s->s3->tmp.pmslen;
+        /*
+         * Compute shared IV and store it in algorithm-specific context
+         * data
+         */
+        ukm_hash = EVP_MD_CTX_create();
+        EVP_DigestInit(ukm_hash,
+                       EVP_get_digestbynid(NID_id_GostR3411_94));
+        EVP_DigestUpdate(ukm_hash, s->s3->client_random,
+                         SSL3_RANDOM_SIZE);
+        EVP_DigestUpdate(ukm_hash, s->s3->server_random,
+                         SSL3_RANDOM_SIZE);
+        EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+        EVP_MD_CTX_destroy(ukm_hash);
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
+             shared_ukm) < 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_LIBRARY_BUG);
+            goto err;
         }
-        if (pms == NULL && !(alg_k & SSL_kPSK)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+        /* Make GOST keytransport blob message */
+        /*
+         * Encapsulate it into sequence
+         */
+        *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+        msglen = 255;
+        if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_LIBRARY_BUG);
             goto err;
         }
-        if (!ssl_generate_master_secret(s, pms, pmslen, 1)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        if (msglen >= 0x80) {
+            *(p++) = 0x81;
+            *(p++) = msglen & 0xff;
+            n = msglen + 3;
+        } else {
+            *(p++) = msglen & 0xff;
+            n = msglen + 2;
+        }
+        memcpy(p, tmp, msglen);
+        /* Check if pubkey from client certificate was used */
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) {
+            /* Set flag "skip certificate verify" */
+            s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+        }
+        EVP_PKEY_CTX_free(pkey_ctx);
+        EVP_PKEY_free(pub_key);
+
+    }
+#ifndef OPENSSL_NO_SRP
+    else if (alg_k & SSL_kSRP) {
+        if (s->srp_ctx.A != NULL) {
+            /* send off the data */
+            n = BN_num_bytes(s->srp_ctx.A);
+            s2n(n, p);
+            BN_bn2bin(s->srp_ctx.A, p);
+            n += 2;
+        } else {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        OPENSSL_free(s->session->srp_username);
+        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+        if (s->session->srp_username == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
             goto err;
         }
     }
-    return n;
+#endif
+    else {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_PSK
+    n += pskhdrlen;
+#endif
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
  memerr:
     ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-    SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+    SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
  err:
     OPENSSL_clear_free(pms, pmslen);
     s->s3->tmp.pms = NULL;
@@ -2890,11 +2919,70 @@ int ssl3_send_client_key_exchange(SSL *s)
     OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
     s->s3->tmp.psk = NULL;
 #endif
-    s->state = SSL_ST_ERR;
-    return (-1);
+    ossl_statem_set_error(s);
+    return 0;
+}
+
+int tls_client_key_exchange_post_work(SSL *s)
+{
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+#ifndef OPENSSL_NO_SRP
+    /* Check for SRP */
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (!srp_generate_client_master_secret(s)) {
+            SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        return 1;
+    }
+#endif
+    pms = s->s3->tmp.pms;
+    pmslen = s->s3->tmp.pmslen;
+
+    if (pms == NULL && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!ssl_generate_master_secret(s, pms, pmslen, 1)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+         * used.
+         */
+        memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+               sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                   sizeof(sctpauthkey), labelbuffer,
+                                   sizeof(labelbuffer), NULL, 0, 0) <= 0)
+            goto err;
+
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    return 1;
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    s->s3->tmp.pms = NULL;
+    return 0;
 }
 
-int ssl3_send_client_verify(SSL *s)
+int tls_construct_client_verify(SSL *s)
 {
     unsigned char *p;
     unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
@@ -2907,123 +2995,120 @@ int ssl3_send_client_verify(SSL *s)
 
     EVP_MD_CTX_init(&mctx);
 
-    if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
-        p = ssl_handshake_start(s);
-        pkey = s->cert->key->privatekey;
+    p = ssl_handshake_start(s);
+    pkey = s->cert->key->privatekey;
 /* Create context from key and test if sha1 is allowed as digest */
-        pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_sign_init(pctx);
-        if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
-            if (!SSL_USE_SIGALGS(s))
-                s->method->ssl3_enc->cert_verify_mac(s,
-                                                     NID_sha1,
-                                                     &(data
-                                                       [MD5_DIGEST_LENGTH]));
-        } else {
-            ERR_clear_error();
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    EVP_PKEY_sign_init(pctx);
+    if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
+        if (!SSL_USE_SIGALGS(s))
+            s->method->ssl3_enc->cert_verify_mac(s,
+                                                 NID_sha1,
+                                                 &(data
+                                                   [MD5_DIGEST_LENGTH]));
+    } else {
+        ERR_clear_error();
+    }
+    /*
+     * For TLS v1.2 send signature algorithm and signature using agreed
+     * digest and cached handshake records.
+     */
+    if (SSL_USE_SIGALGS(s)) {
+        long hdatalen = 0;
+        void *hdata;
+        const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+            goto err;
         }
-        /*
-         * For TLS v1.2 send signature algorithm and signature using agreed
-         * digest and cached handshake records.
-         */
-        if (SSL_USE_SIGALGS(s)) {
-            long hdatalen = 0;
-            void *hdata;
-            const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
-            hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
-            if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            p += 2;
+        p += 2;
 #ifdef SSL_DEBUG
-            fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
-                    EVP_MD_name(md));
+        fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
+                EVP_MD_name(md));
 #endif
-            if (!EVP_SignInit_ex(&mctx, md, NULL)
-                || !EVP_SignUpdate(&mctx, hdata, hdatalen)
-                || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_EVP_LIB);
-                goto err;
-            }
-            s2n(u, p);
-            n = u + 4;
-            /* Digest cached records and discard handshake buffer */
-            if (!ssl3_digest_cached_records(s, 0))
-                goto err;
-        } else
+        if (!EVP_SignInit_ex(&mctx, md, NULL)
+            || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+            || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
+            goto err;
+        }
+        s2n(u, p);
+        n = u + 4;
+        /* Digest cached records and discard handshake buffer */
+        if (!ssl3_digest_cached_records(s, 0))
+            goto err;
+    } else
 #ifndef OPENSSL_NO_RSA
-        if (pkey->type == EVP_PKEY_RSA) {
-            s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(data[0]));
-            if (RSA_sign(NID_md5_sha1, data,
-                         MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
-                         &(p[2]), &u, pkey->pkey.rsa) <= 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_RSA_LIB);
-                goto err;
-            }
-            s2n(u, p);
-            n = u + 2;
-        } else
+    if (pkey->type == EVP_PKEY_RSA) {
+        s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(data[0]));
+        if (RSA_sign(NID_md5_sha1, data,
+                     MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
+                     &(p[2]), &u, pkey->pkey.rsa) <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_RSA_LIB);
+            goto err;
+        }
+        s2n(u, p);
+        n = u + 2;
+    } else
 #endif
 #ifndef OPENSSL_NO_DSA
-        if (pkey->type == EVP_PKEY_DSA) {
-            if (!DSA_sign(pkey->save_type,
-                          &(data[MD5_DIGEST_LENGTH]),
-                          SHA_DIGEST_LENGTH, &(p[2]),
-                          (unsigned int *)&j, pkey->pkey.dsa)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_DSA_LIB);
-                goto err;
-            }
-            s2n(j, p);
-            n = j + 2;
-        } else
+    if (pkey->type == EVP_PKEY_DSA) {
+        if (!DSA_sign(pkey->save_type,
+                      &(data[MD5_DIGEST_LENGTH]),
+                      SHA_DIGEST_LENGTH, &(p[2]),
+                      (unsigned int *)&j, pkey->pkey.dsa)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_DSA_LIB);
+            goto err;
+        }
+        s2n(j, p);
+        n = j + 2;
+    } else
 #endif
 #ifndef OPENSSL_NO_EC
-        if (pkey->type == EVP_PKEY_EC) {
-            if (!ECDSA_sign(pkey->save_type,
-                            &(data[MD5_DIGEST_LENGTH]),
-                            SHA_DIGEST_LENGTH, &(p[2]),
-                            (unsigned int *)&j, pkey->pkey.ec)) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_ECDSA_LIB);
-                goto err;
-            }
-            s2n(j, p);
-            n = j + 2;
-        } else
-#endif
-        if (pkey->type == NID_id_GostR3410_2001) {
-            unsigned char signbuf[64];
-            int i;
-            size_t sigsize = 64;
-            s->method->ssl3_enc->cert_verify_mac(s,
-                                                 NID_id_GostR3411_94, data);
-            if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
-                SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            for (i = 63, j = 0; i >= 0; j++, i--) {
-                p[2 + j] = signbuf[i];
-            }
-            s2n(j, p);
-            n = j + 2;
-        } else {
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+    if (pkey->type == EVP_PKEY_EC) {
+        if (!ECDSA_sign(pkey->save_type,
+                        &(data[MD5_DIGEST_LENGTH]),
+                        SHA_DIGEST_LENGTH, &(p[2]),
+                        (unsigned int *)&j, pkey->pkey.ec)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_ECDSA_LIB);
             goto err;
         }
-        if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        s2n(j, p);
+        n = j + 2;
+    } else
+#endif
+    if (pkey->type == NID_id_GostR3410_2001) {
+        unsigned char signbuf[64];
+        int i;
+        size_t sigsize = 64;
+        s->method->ssl3_enc->cert_verify_mac(s,
+                                             NID_id_GostR3411_94, data);
+        if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-        s->state = SSL3_ST_CW_CERT_VRFY_B;
+        for (i = 63, j = 0; i >= 0; j++, i--) {
+            p[2 + j] = signbuf[i];
+        }
+        s2n(j, p);
+        n = j + 2;
+    } else {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        goto err;
     }
+
     EVP_MD_CTX_cleanup(&mctx);
     EVP_PKEY_CTX_free(pctx);
-    return ssl_do_write(s);
+    return 1;
  err:
     EVP_MD_CTX_cleanup(&mctx);
     EVP_PKEY_CTX_free(pctx);
-    s->state = SSL_ST_ERR;
-    return (-1);
+    return 0;
 }
 
 /*
@@ -3069,35 +3154,36 @@ static int ssl3_check_client_certificate(SSL *s)
     return 1;
 }
 
-int ssl3_send_client_certificate(SSL *s)
+WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
 {
     X509 *x509 = NULL;
     EVP_PKEY *pkey = NULL;
     int i;
 
-    if (s->state == SSL3_ST_CW_CERT_A) {
+    if (wst == WORK_MORE_A) {
         /* Let cert callback update client certificates if required */
         if (s->cert->cert_cb) {
             i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
             if (i < 0) {
                 s->rwstate = SSL_X509_LOOKUP;
-                return -1;
+                return WORK_MORE_A;
             }
             if (i == 0) {
                 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                s->state = SSL_ST_ERR;
+                ossl_statem_set_error(s);
                 return 0;
             }
             s->rwstate = SSL_NOTHING;
         }
         if (ssl3_check_client_certificate(s))
-            s->state = SSL3_ST_CW_CERT_C;
-        else
-            s->state = SSL3_ST_CW_CERT_B;
+            return WORK_FINISHED_CONTINUE;
+
+        /* Fall through to WORK_MORE_B */
+        wst = WORK_MORE_B;
     }
 
     /* We need to get a client cert */
-    if (s->state == SSL3_ST_CW_CERT_B) {
+    if (wst == WORK_MORE_B) {
         /*
          * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP;
          * return(-1); We then get retied later
@@ -3105,16 +3191,15 @@ int ssl3_send_client_certificate(SSL *s)
         i = ssl_do_client_cert_cb(s, &x509, &pkey);
         if (i < 0) {
             s->rwstate = SSL_X509_LOOKUP;
-            return (-1);
+            return WORK_MORE_B;
         }
         s->rwstate = SSL_NOTHING;
         if ((i == 1) && (pkey != NULL) && (x509 != NULL)) {
-            s->state = SSL3_ST_CW_CERT_B;
             if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey))
                 i = 0;
         } else if (i == 1) {
             i = 0;
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE,
+            SSLerr(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
                    SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
         }
 
@@ -3126,34 +3211,36 @@ int ssl3_send_client_certificate(SSL *s)
             if (s->version == SSL3_VERSION) {
                 s->s3->tmp.cert_req = 0;
                 ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
-                return (1);
+                return WORK_FINISHED_CONTINUE;
             } else {
                 s->s3->tmp.cert_req = 2;
                 if (!ssl3_digest_cached_records(s, 0)) {
                     ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                    s->state = SSL_ST_ERR;
+                    ossl_statem_set_error(s);
                     return 0;
                 }
             }
         }
 
-        /* Ok, we have a cert */
-        s->state = SSL3_ST_CW_CERT_C;
+        return WORK_FINISHED_CONTINUE;
     }
 
-    if (s->state == SSL3_ST_CW_CERT_C) {
-        s->state = SSL3_ST_CW_CERT_D;
-        if (!ssl3_output_cert_chain(s,
-                                    (s->s3->tmp.cert_req ==
-                                     2) ? NULL : s->cert->key)) {
-            SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            s->state = SSL_ST_ERR;
-            return 0;
-        }
+    /* Shouldn't ever get here */
+    return WORK_ERROR;
+}
+
+int tls_construct_client_certificate(SSL *s)
+{
+    if (!ssl3_output_cert_chain(s,
+                                (s->s3->tmp.cert_req ==
+                                 2) ? NULL : s->cert->key)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
     }
-    /* SSL3_ST_CW_CERT_D */
-    return ssl_do_write(s);
+
+    return 1;
 }
 
 #define has_bits(i,m)   (((i)&(m)) == (m))
@@ -3317,67 +3404,25 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     return (0);
 }
 
-/*
- * Normally, we can tell if the server is resuming the session from
- * the session ID. EAP-FAST (RFC 4851), however, relies on the next server
- * message after the ServerHello to determine if the server is resuming.
- * Therefore, we allow EAP-FAST to peek ahead.
- * ssl3_check_change returns 1 if we are resuming from an external
- * pre-shared secret, we have a "ticket" and the next server message
- * is CCS; and 0 otherwise. It returns -1 upon an error.
- */
-static int ssl3_check_change(SSL *s)
-{
-    int ok = 0;
-
-    if (s->version < TLS1_VERSION || !s->tls_session_secret_cb ||
-        !s->session->tlsext_tick)
-        return 0;
-
-    /*
-     * This function is called when we might get a Certificate message instead,
-     * so permit appropriate message length.
-     * We ignore the return value as we're only interested in the message type
-     * and not its length.
-     */
-    s->method->ssl_get_message(s,
-                               SSL3_ST_CR_CERT_A,
-                               SSL3_ST_CR_CERT_B,
-                               -1, s->max_cert_list, &ok);
-
-    if (!ok)
-        return -1;
-
-    s->s3->tmp.reuse_message = 1;
-
-    if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC)
-        return 1;
-
-    return 0;
-}
-
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int ssl3_send_next_proto(SSL *s)
+int tls_construct_next_proto(SSL *s)
 {
     unsigned int len, padding_len;
     unsigned char *d;
 
-    if (s->state == SSL3_ST_CW_NEXT_PROTO_A) {
-        len = s->next_proto_negotiated_len;
-        padding_len = 32 - ((len + 2) % 32);
-        d = (unsigned char *)s->init_buf->data;
-        d[4] = len;
-        memcpy(d + 5, s->next_proto_negotiated, len);
-        d[5 + len] = padding_len;
-        memset(d + 6 + len, 0, padding_len);
-        *(d++) = SSL3_MT_NEXT_PROTO;
-        l2n3(2 + len + padding_len, d);
-        s->state = SSL3_ST_CW_NEXT_PROTO_B;
-        s->init_num = 4 + 2 + len + padding_len;
-        s->init_off = 0;
-    }
-
-    return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+    len = s->next_proto_negotiated_len;
+    padding_len = 32 - ((len + 2) % 32);
+    d = (unsigned char *)s->init_buf->data;
+    d[4] = len;
+    memcpy(d + 5, s->next_proto_negotiated, len);
+    d[5 + len] = padding_len;
+    memset(d + 6 + len, 0, padding_len);
+    *(d++) = SSL3_MT_NEXT_PROTO;
+    l2n3(2 + len + padding_len, d);
+    s->init_num = 4 + 2 + len + padding_len;
+    s->init_off = 0;
+
+    return 1;
 }
 #endif
 
diff --git a/ssl/d1_both.c b/ssl/statem/statem_dtls.c
similarity index 76%
rename from ssl/d1_both.c
rename to ssl/statem/statem_dtls.c
index 02a464e..58a0959 100644
--- a/ssl/d1_both.c
+++ b/ssl/statem/statem_dtls.c
@@ -1,4 +1,4 @@
-/* ssl/d1_both.c */
+/* ssl/statem/statem_dtls.c */
 /*
  * DTLS implementation written by Nagendra Modadugu
  * (nagendra at cs.stanford.edu) for the OpenSSL project 2005.
@@ -116,7 +116,8 @@
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
-#include "ssl_locl.h"
+#include "../ssl_locl.h"
+#include "statem_locl.h"
 #include <openssl/buffer.h>
 #include <openssl/rand.h>
 #include <openssl/objects.h>
@@ -149,9 +150,6 @@ static unsigned char bitmask_start_values[] =
 static unsigned char bitmask_end_values[] =
     { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
 
-/* XDTLS:  figure out the right values */
-static const unsigned int g_probable_mtu[] = { 1500, 512, 256 };
-
 static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
                                      unsigned long frag_len);
 static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p);
@@ -160,8 +158,7 @@ static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
                                          unsigned short seq_num,
                                          unsigned long frag_off,
                                          unsigned long frag_len);
-static long dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt,
-                                       long max, int *ok);
+static int dtls_get_reassembled_message(SSL *s, long *len);
 
 static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len,
                                           int reassembly)
@@ -215,36 +212,6 @@ void dtls1_hm_fragment_free(hm_fragment *frag)
     OPENSSL_free(frag);
 }
 
-static int dtls1_query_mtu(SSL *s)
-{
-    if (s->d1->link_mtu) {
-        s->d1->mtu =
-            s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
-        s->d1->link_mtu = 0;
-    }
-
-    /* AHA!  Figure out the MTU, and stick to the right size */
-    if (s->d1->mtu < dtls1_min_mtu(s)) {
-        if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
-            s->d1->mtu =
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
-
-            /*
-             * I've seen the kernel return bogus numbers when it doesn't know
-             * (initial write), so just make sure we have a reasonable number
-             */
-            if (s->d1->mtu < dtls1_min_mtu(s)) {
-                /* Set to min mtu */
-                s->d1->mtu = dtls1_min_mtu(s);
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
-                         s->d1->mtu, NULL);
-            }
-        } else
-            return 0;
-    }
-    return 1;
-}
-
 /*
  * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
  * SSL3_RT_CHANGE_CIPHER_SPEC)
@@ -437,77 +404,41 @@ int dtls1_do_write(SSL *s, int type)
     return (0);
 }
 
-/*
- * Obtain handshake message of message type 'mt' (any if mt == -1), maximum
- * acceptable body length 'max'. Read an entire handshake message.  Handshake
- * messages arrive in fragments.
- */
-long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
+int dtls_get_message(SSL *s, int *mt, unsigned long *len)
 {
-    int i, al;
     struct hm_header_st *msg_hdr;
     unsigned char *p;
     unsigned long msg_len;
-
-    /*
-     * s3->tmp is used to store messages that are unexpected, caused by the
-     * absence of an optional handshake message
-     */
-    if (s->s3->tmp.reuse_message) {
-        if ((mt >= 0) && (s->s3->tmp.message_type != mt)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-        }
-        *ok = 1;
-
-
-        /*
-         * Messages reused from dtls1_listen also have the record header in
-         * the buffer which we need to skip over.
-         */
-        if (s->s3->tmp.reuse_message == DTLS1_SKIP_RECORD_HEADER) {
-            s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH
-                          + DTLS1_RT_HEADER_LENGTH;
-        } else {
-            s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-        }
-        s->init_num = (int)s->s3->tmp.message_size;
-        s->s3->tmp.reuse_message = 0;
-        return s->init_num;
-    }
+    int ok;
+    long tmplen;
 
     msg_hdr = &s->d1->r_msg_hdr;
     memset(msg_hdr, 0, sizeof(*msg_hdr));
 
  again:
-    i = dtls1_get_message_fragment(s, st1, stn, mt, max, ok);
-    if (i == DTLS1_HM_BAD_FRAGMENT || i == DTLS1_HM_FRAGMENT_RETRY) {
+    ok = dtls_get_reassembled_message(s, &tmplen);
+    if (tmplen == DTLS1_HM_BAD_FRAGMENT
+        || tmplen == DTLS1_HM_FRAGMENT_RETRY) {
         /* bad fragment received */
         goto again;
-    } else if (i <= 0 && !*ok) {
-        return i;
+    } else if (tmplen <= 0 && !ok) {
+        return 0;
     }
 
-    if (mt >= 0 && s->s3->tmp.message_type != mt) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
-        goto f_err;
-    }
+    *mt = s->s3->tmp.message_type;
 
     p = (unsigned char *)s->init_buf->data;
 
-    if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
         if (s->msg_callback) {
             s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
                             p, 1, s, s->msg_callback_arg);
         }
         /*
          * This isn't a real handshake message so skip the processing below.
-         * dtls1_get_message_fragment() will never return a CCS if mt == -1,
-         * so we are ok to continue in that case.
          */
-        return i;
+        *len = (unsigned long)tmplen;
+        return 1;
     }
 
     msg_len = msg_hdr->msg_len;
@@ -534,16 +465,12 @@ long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
 
 
     s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-    return s->init_num;
+    *len = s->init_num;
 
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    *ok = 0;
-    return -1;
+    return 1;
 }
 
-static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr,
-                                     int max)
+static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
 {
     size_t frag_off, frag_len, msg_len;
 
@@ -557,11 +484,6 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr,
         return SSL_AD_ILLEGAL_PARAMETER;
     }
 
-    if ((frag_off + frag_len) > (unsigned long)max) {
-        SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        return SSL_AD_ILLEGAL_PARAMETER;
-    }
-
     if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
         /*
          * msg_len is limited to 2^24, but is effectively checked against max
@@ -590,7 +512,7 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr,
     return 0;                   /* no error */
 }
 
-static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok)
 {
     /*-
      * (0) check whether the desired fragment is available
@@ -617,7 +539,7 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
         unsigned long frag_len = frag->msg_header.frag_len;
         pqueue_pop(s->d1->buffered_messages);
 
-        al = dtls1_preprocess_fragment(s, &frag->msg_header, max);
+        al = dtls1_preprocess_fragment(s, &frag->msg_header);
 
         if (al == 0) {          /* no alert */
             unsigned char *p =
@@ -858,20 +780,21 @@ dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr,
     return i;
 }
 
-static long
-dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
+static int dtls_get_reassembled_message(SSL *s, long *len)
 {
     unsigned char wire[DTLS1_HM_HEADER_LENGTH];
-    unsigned long len, frag_off, frag_len;
+    unsigned long mlen, frag_off, frag_len;
     int i, al, recvd_type;
     struct hm_header_st msg_hdr;
+    int ok;
 
  redo:
     /* see if we have the required fragment already */
-    if ((frag_len = dtls1_retrieve_buffered_fragment(s, max, ok)) || *ok) {
-        if (*ok)
+    if ((frag_len = dtls1_retrieve_buffered_fragment(s, &ok)) || ok) {
+        if (ok)
             s->init_num = frag_len;
-        return frag_len;
+        *len = frag_len;
+        return ok;
     }
 
     /* read handshake message header */
@@ -879,53 +802,37 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
                                   DTLS1_HM_HEADER_LENGTH, 0);
     if (i <= 0) {               /* nbio, or an error */
         s->rwstate = SSL_READING;
-        *ok = 0;
-        return i;
+        *len = i;
+        return 0;
     }
     if(recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
-        /* This isn't a real handshake message - its a CCS.
-         * There is no message sequence number in a CCS to give us confidence
-         * that this was really intended to be at this point in the handshake
-         * sequence. Therefore we only allow this if we were explicitly looking
-         * for it (i.e. if |mt| is -1 we still don't allow it).
-         */
-        if(mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            if (wire[0] != SSL3_MT_CCS) {
-                al = SSL_AD_UNEXPECTED_MESSAGE;
-                SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_BAD_CHANGE_CIPHER_SPEC);
-                goto f_err;
-            }
-
-            memcpy(s->init_buf->data, wire, i);
-            s->init_num = i - 1;
-            s->init_msg = s->init_buf->data + 1;
-            s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
-            s->s3->tmp.message_size = i - 1;
-            s->state = stn;
-            *ok = 1;
-            return i-1;
-        } else {
-            /*
-             * We weren't expecting a CCS yet. Probably something got
-             * re-ordered or this is a retransmit. We should drop this and try
-             * again.
-             */
-            s->init_num = 0;
-            goto redo;
+        if (wire[0] != SSL3_MT_CCS) {
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            goto f_err;
         }
+
+        memcpy(s->init_buf->data, wire, i);
+        s->init_num = i - 1;
+        s->init_msg = s->init_buf->data + 1;
+        s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
+        s->s3->tmp.message_size = i - 1;
+        *len = i - 1;
+        return 1;
     }
 
     /* Handshake fails if message header is incomplete */
     if (i != DTLS1_HM_HEADER_LENGTH) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_UNEXPECTED_MESSAGE);
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
         goto f_err;
     }
 
     /* parse the message fragment header */
     dtls1_get_message_header(wire, &msg_hdr);
 
-    len = msg_hdr.msg_len;
+    mlen = msg_hdr.msg_len;
     frag_off = msg_hdr.frag_off;
     frag_len = msg_hdr.frag_len;
 
@@ -935,7 +842,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
      */
     if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) {
         al = SSL3_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_BAD_LENGTH);
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
         goto f_err;
     }
 
@@ -945,11 +852,15 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
      * While listening, we accept seq 1 (ClientHello with cookie)
      * although we're still expecting seq 0 (ClientHello)
      */
-    if (msg_hdr.seq != s->d1->handshake_read_seq)
-        return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
+    if (msg_hdr.seq != s->d1->handshake_read_seq) {
+        *len = dtls1_process_out_of_seq_message(s, &msg_hdr, &ok);
+        return ok;
+    }
 
-    if (frag_len && frag_len < len)
-        return dtls1_reassemble_fragment(s, &msg_hdr, ok);
+    if (frag_len && frag_len < mlen) {
+        *len = dtls1_reassemble_fragment(s, &msg_hdr, &ok);
+        return ok;
+    }
 
     if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
         wire[0] == SSL3_MT_HELLO_REQUEST) {
@@ -969,13 +880,13 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
         } else {                /* Incorrectly formated Hello request */
 
             al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,
+            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
                    SSL_R_UNEXPECTED_MESSAGE);
             goto f_err;
         }
     }
 
-    if ((al = dtls1_preprocess_fragment(s, &msg_hdr, max)))
+    if ((al = dtls1_preprocess_fragment(s, &msg_hdr)))
         goto f_err;
 
     if (frag_len > 0) {
@@ -991,8 +902,8 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
          */
         if (i <= 0) {
             s->rwstate = SSL_READING;
-            *ok = 0;
-            return i;
+            *len = i;
+            return 0;
         }
     } else
         i = 0;
@@ -1003,28 +914,24 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
      */
     if (i != (int)frag_len) {
         al = SSL3_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL3_AD_ILLEGAL_PARAMETER);
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL3_AD_ILLEGAL_PARAMETER);
         goto f_err;
     }
 
-    *ok = 1;
-    s->state = stn;
-
     /*
      * Note that s->init_num is *not* used as current offset in
      * s->init_buf->data, but as a counter summing up fragments' lengths: as
      * soon as they sum up to handshake packet length, we assume we have got
      * all the fragments.
      */
-    s->init_num = frag_len;
-    return frag_len;
+    *len = s->init_num = frag_len;
+    return 1;
 
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
     s->init_num = 0;
-
-    *ok = 0;
-    return (-1);
+    *len = -1;
+    return 0;
 }
 
 /*-
@@ -1036,40 +943,56 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
  * ssl->session->read_compression       assign
  * ssl->session->read_hash              assign
  */
-int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
+int dtls_construct_change_cipher_spec(SSL *s)
 {
     unsigned char *p;
 
-    if (s->state == a) {
-        p = (unsigned char *)s->init_buf->data;
-        *p++ = SSL3_MT_CCS;
-        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
-        s->init_num = DTLS1_CCS_HEADER_LENGTH;
+    p = (unsigned char *)s->init_buf->data;
+    *p++ = SSL3_MT_CCS;
+    s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+    s->init_num = DTLS1_CCS_HEADER_LENGTH;
 
-        if (s->version == DTLS1_BAD_VER) {
-            s->d1->next_handshake_write_seq++;
-            s2n(s->d1->handshake_write_seq, p);
-            s->init_num += 2;
-        }
+    if (s->version == DTLS1_BAD_VER) {
+        s->d1->next_handshake_write_seq++;
+        s2n(s->d1->handshake_write_seq, p);
+        s->init_num += 2;
+    }
 
-        s->init_off = 0;
+    s->init_off = 0;
 
-        dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
-                                     s->d1->handshake_write_seq, 0, 0);
+    dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+                                 s->d1->handshake_write_seq, 0, 0);
 
-        /* buffer the message to handle re-xmits */
-        if (!dtls1_buffer_message(s, 1)) {
-            SSLerr(SSL_F_DTLS1_SEND_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-
-        s->state = b;
+    /* buffer the message to handle re-xmits */
+    if (!dtls1_buffer_message(s, 1)) {
+        SSLerr(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 
-    /* SSL3_ST_CW_CHANGE_B */
-    return (dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC));
+    return 1;
 }
 
+#ifndef OPENSSL_NO_SCTP
+WORK_STATE dtls_wait_for_dry(SSL *s)
+{
+    int ret;
+
+    /* read app data until dry event */
+    ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+    if (ret < 0)
+        return WORK_ERROR;
+
+    if (ret == 0) {
+        s->s3->in_read_app_data = 2;
+        s->rwstate = SSL_READING;
+        BIO_clear_retry_flags(SSL_get_rbio(s));
+        BIO_set_retry_read(SSL_get_rbio(s));
+        return WORK_MORE_A;
+    }
+    return WORK_FINISHED_CONTINUE;
+}
+#endif
+
 int dtls1_read_failed(SSL *s, int code)
 {
     if (code > 0) {
@@ -1346,17 +1269,6 @@ static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p)
     return p;
 }
 
-unsigned int dtls1_link_min_mtu(void)
-{
-    return (g_probable_mtu[(sizeof(g_probable_mtu) /
-                            sizeof(g_probable_mtu[0])) - 1]);
-}
-
-unsigned int dtls1_min_mtu(SSL *s)
-{
-    return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
-}
-
 void
 dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
 {
@@ -1369,194 +1281,4 @@ dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
     n2l3(data, msg_hdr->frag_len);
 }
 
-int dtls1_shutdown(SSL *s)
-{
-    int ret;
-#ifndef OPENSSL_NO_SCTP
-    BIO *wbio;
-
-    wbio = SSL_get_wbio(s);
-    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
-        !(s->shutdown & SSL_SENT_SHUTDOWN)) {
-        ret = BIO_dgram_sctp_wait_for_dry(wbio);
-        if (ret < 0)
-            return -1;
-
-        if (ret == 0)
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
-                     NULL);
-    }
-#endif
-    ret = ssl3_shutdown(s);
-#ifndef OPENSSL_NO_SCTP
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
-#endif
-    return ret;
-}
-
-#ifndef OPENSSL_NO_HEARTBEATS
-int dtls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
-{
-    unsigned char *pl;
-    unsigned short hbtype;
-    unsigned int payload;
-    unsigned int padding = 16;  /* Use minimum padding */
-
-    if (s->msg_callback)
-        s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
-                        p, length, s, s->msg_callback_arg);
-
-    /* Read type and payload length first */
-    if (1 + 2 + 16 > length)
-        return 0;               /* silently discard */
-    if (length > SSL3_RT_MAX_PLAIN_LENGTH)
-        return 0;               /* silently discard per RFC 6520 sec. 4 */
-
-    hbtype = *p++;
-    n2s(p, payload);
-    if (1 + 2 + payload + 16 > length)
-        return 0;               /* silently discard per RFC 6520 sec. 4 */
-    pl = p;
-
-    if (hbtype == TLS1_HB_REQUEST) {
-        unsigned char *buffer, *bp;
-        unsigned int write_length = 1 /* heartbeat type */  +
-            2 /* heartbeat length */  +
-            payload + padding;
-        int r;
-
-        if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
-            return 0;
-
-        /*
-         * Allocate memory for the response, size is 1 byte message type,
-         * plus 2 bytes payload length, plus payload, plus padding
-         */
-        buffer = OPENSSL_malloc(write_length);
-        if (buffer == NULL)
-            return -1;
-        bp = buffer;
-
-        /* Enter response type, length and copy payload */
-        *bp++ = TLS1_HB_RESPONSE;
-        s2n(payload, bp);
-        memcpy(bp, pl, payload);
-        bp += payload;
-        /* Random padding */
-        if (RAND_bytes(bp, padding) <= 0) {
-            OPENSSL_free(buffer);
-            return -1;
-        }
-
-        r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
-
-        if (r >= 0 && s->msg_callback)
-            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                            buffer, write_length, s, s->msg_callback_arg);
-
-        OPENSSL_free(buffer);
-
-        if (r < 0)
-            return r;
-    } else if (hbtype == TLS1_HB_RESPONSE) {
-        unsigned int seq;
-
-        /*
-         * We only send sequence numbers (2 bytes unsigned int), and 16
-         * random bytes, so we just try to read the sequence number
-         */
-        n2s(pl, seq);
-
-        if (payload == 18 && seq == s->tlsext_hb_seq) {
-            dtls1_stop_timer(s);
-            s->tlsext_hb_seq++;
-            s->tlsext_hb_pending = 0;
-        }
-    }
-
-    return 0;
-}
-
-int dtls1_heartbeat(SSL *s)
-{
-    unsigned char *buf, *p;
-    int ret = -1;
-    unsigned int payload = 18;  /* Sequence number + random bytes */
-    unsigned int padding = 16;  /* Use minimum padding */
-
-    /* Only send if peer supports and accepts HB requests... */
-    if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
-        s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
-        return -1;
-    }
-
-    /* ...and there is none in flight yet... */
-    if (s->tlsext_hb_pending) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
-        return -1;
-    }
 
-    /* ...and no handshake in progress. */
-    if (SSL_in_init(s) || s->in_handshake) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
-        return -1;
-    }
-
-    /*
-     * Check if padding is too long, payload and padding must not exceed 2^14
-     * - 3 = 16381 bytes in total.
-     */
-    OPENSSL_assert(payload + padding <= 16381);
-
-    /*-
-     * Create HeartBeat message, we just use a sequence number
-     * as payload to distuingish different messages and add
-     * some random stuff.
-     *  - Message Type, 1 byte
-     *  - Payload Length, 2 bytes (unsigned int)
-     *  - Payload, the sequence number (2 bytes uint)
-     *  - Payload, random bytes (16 bytes uint)
-     *  - Padding
-     */
-    buf = OPENSSL_malloc(1 + 2 + payload + padding);
-    if (buf == NULL) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
-        return -1;
-    }
-    p = buf;
-    /* Message Type */
-    *p++ = TLS1_HB_REQUEST;
-    /* Payload length (18 bytes here) */
-    s2n(payload, p);
-    /* Sequence number */
-    s2n(s->tlsext_hb_seq, p);
-    /* 16 random bytes */
-    if (RAND_bytes(p, 16) <= 0) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-    p += 16;
-    /* Random padding */
-    if (RAND_bytes(p, padding) <= 0) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
-    if (ret >= 0) {
-        if (s->msg_callback)
-            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                            buf, 3 + payload + padding,
-                            s, s->msg_callback_arg);
-
-        dtls1_start_timer(s);
-        s->tlsext_hb_pending = 1;
-    }
-
- err:
-    OPENSSL_free(buf);
-
-    return ret;
-}
-#endif
diff --git a/ssl/s3_both.c b/ssl/statem/statem_lib.c
similarity index 64%
rename from ssl/s3_both.c
rename to ssl/statem/statem_lib.c
index 4d69c2a..2c100dc 100644
--- a/ssl/s3_both.c
+++ b/ssl/statem/statem_lib.c
@@ -1,4 +1,4 @@
-/* ssl/s3_both.c */
+/* ssl/statem/statem_lib.c */
 /* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
  * All rights reserved.
  *
@@ -117,7 +117,8 @@
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
-#include "ssl_locl.h"
+#include "../ssl_locl.h"
+#include "statem_locl.h"
 #include <openssl/buffer.h>
 #include <openssl/rand.h>
 #include <openssl/objects.h>
@@ -156,46 +157,42 @@ int ssl3_do_write(SSL *s, int type)
     return (0);
 }
 
-int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
+int tls_construct_finished(SSL *s, const char *sender, int slen)
 {
     unsigned char *p;
     int i;
     unsigned long l;
 
-    if (s->state == a) {
-        p = ssl_handshake_start(s);
+    p = ssl_handshake_start(s);
 
-        i = s->method->ssl3_enc->final_finish_mac(s,
-                                                  sender, slen,
-                                                  s->s3->tmp.finish_md);
-        if (i <= 0)
-            return 0;
-        s->s3->tmp.finish_md_len = i;
-        memcpy(p, s->s3->tmp.finish_md, i);
-        l = i;
+    i = s->method->ssl3_enc->final_finish_mac(s,
+                                              sender, slen,
+                                              s->s3->tmp.finish_md);
+    if (i <= 0)
+        return 0;
+    s->s3->tmp.finish_md_len = i;
+    memcpy(p, s->s3->tmp.finish_md, i);
+    l = i;
 
-        /*
-         * Copy the finished so we can use it for renegotiation checks
-         */
-        if (s->type == SSL_ST_CONNECT) {
-            OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
-            memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i);
-            s->s3->previous_client_finished_len = i;
-        } else {
-            OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
-            memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i);
-            s->s3->previous_server_finished_len = i;
-        }
+    /*
+     * Copy the finished so we can use it for renegotiation checks
+     */
+    if (!s->server) {
+        OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+        memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i);
+        s->s3->previous_client_finished_len = i;
+    } else {
+        OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+        memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i);
+        s->s3->previous_server_finished_len = i;
+    }
 
-        if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, l)) {
-            SSLerr(SSL_F_SSL3_SEND_FINISHED, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        s->state = b;
+    if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, l)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 
-    /* SSL3_ST_SEND_xxxxxx_HELLO_B */
-    return ssl_do_write(s);
+    return 1;
 }
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
@@ -213,7 +210,7 @@ static void ssl3_take_mac(SSL *s)
      */
     if (s->s3->tmp.new_cipher == NULL)
         return;
-    if (s->state & SSL_ST_CONNECT) {
+    if (!s->server) {
         sender = s->method->ssl3_enc->server_finished_label;
         slen = s->method->ssl3_enc->server_finished_label_len;
     } else {
@@ -228,33 +225,32 @@ static void ssl3_take_mac(SSL *s)
 }
 #endif
 
-int ssl3_get_change_cipher_spec(SSL *s, int a, int b)
+MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
 {
-    int ok, al;
-    long n;
-
-    n = s->method->ssl_get_message(s, a, b, SSL3_MT_CHANGE_CIPHER_SPEC, 1, &ok);
-
-    if (!ok)
-        return ((int)n);
-
+    int al;
+    long remain;
+    
+    remain = PACKET_remaining(pkt);
     /*
      * 'Change Cipher Spec' is just a single byte, which should already have
      * been consumed by ssl_get_message() so there should be no bytes left,
      * unless we're using DTLS1_BAD_VER, which has an extra 2 bytes
      */
     if (SSL_IS_DTLS(s)) {
-        if ((s->version == DTLS1_BAD_VER && n != DTLS1_CCS_HEADER_LENGTH + 1)
+        if ((s->version == DTLS1_BAD_VER
+                        && remain != DTLS1_CCS_HEADER_LENGTH + 1)
                     || (s->version != DTLS1_BAD_VER
-                        && n != DTLS1_CCS_HEADER_LENGTH - 1)) {
+                        && remain != DTLS1_CCS_HEADER_LENGTH - 1)) {
                 al = SSL_AD_ILLEGAL_PARAMETER;
-                SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+                SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                       SSL_R_BAD_CHANGE_CIPHER_SPEC);
                 goto f_err;
         }
     } else {
-        if (n != 0) {
+        if (remain != 0) {
             al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
             goto f_err;
         }
     }
@@ -262,14 +258,14 @@ int ssl3_get_change_cipher_spec(SSL *s, int a, int b)
     /* Check we have a cipher to change to */
     if (s->s3->tmp.new_cipher == NULL) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
+        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
         goto f_err;
     }
 
     s->s3->change_cipher_spec = 1;
     if (!ssl3_do_change_cipher_spec(s)) {
         al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
         goto f_err;
     }
 
@@ -289,59 +285,43 @@ int ssl3_get_change_cipher_spec(SSL *s, int a, int b)
 #endif
     }
 
-    return 1;
+    return MSG_PROCESS_CONTINUE_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    return 0;
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-
-int ssl3_get_finished(SSL *s, int a, int b)
+MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
 {
-    int al, i, ok;
-    long n;
-    unsigned char *p;
-
-#ifdef OPENSSL_NO_NEXTPROTONEG
-    /*
-     * the mac has already been generated when we received the change cipher
-     * spec message and is in s->s3->tmp.peer_finish_md
-     */
-#endif
-
-    /* 64 argument should actually be 36+4 :-) */
-    n = s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, &ok);
-
-    if (!ok)
-        return ((int)n);
+    int al, i;
 
     /* If this occurs, we have missed a message */
     if (!s->s3->change_cipher_spec) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
         goto f_err;
     }
     s->s3->change_cipher_spec = 0;
 
-    p = (unsigned char *)s->init_msg;
     i = s->s3->tmp.peer_finish_md_len;
 
-    if (i != n) {
+    if ((unsigned long)i != PACKET_remaining(pkt)) {
         al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH);
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_BAD_DIGEST_LENGTH);
         goto f_err;
     }
 
-    if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0) {
+    if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md, i) != 0) {
         al = SSL_AD_DECRYPT_ERROR;
-        SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED);
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_DIGEST_CHECK_FAILED);
         goto f_err;
     }
 
     /*
      * Copy the finished so we can use it for renegotiation checks
      */
-    if (s->type == SSL_ST_ACCEPT) {
+    if (s->server) {
         OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
         memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i);
         s->s3->previous_client_finished_len = i;
@@ -351,36 +331,23 @@ int ssl3_get_finished(SSL *s, int a, int b)
         s->s3->previous_server_finished_len = i;
     }
 
-    return (1);
+    return MSG_PROCESS_CONTINUE_PROCESSING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    return (0);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
 
-/*-
- * for these 2 messages, we need to
- * ssl->enc_read_ctx                    re-init
- * ssl->rlayer.read_sequence            zero
- * ssl->s3->read_mac_secret             re-init
- * ssl->session->read_sym_enc           assign
- * ssl->session->read_compression       assign
- * ssl->session->read_hash              assign
- */
-int ssl3_send_change_cipher_spec(SSL *s, int a, int b)
+int tls_construct_change_cipher_spec(SSL *s)
 {
     unsigned char *p;
 
-    if (s->state == a) {
-        p = (unsigned char *)s->init_buf->data;
-        *p = SSL3_MT_CCS;
-        s->init_num = 1;
-        s->init_off = 0;
-
-        s->state = b;
-    }
+    p = (unsigned char *)s->init_buf->data;
+    *p = SSL3_MT_CCS;
+    s->init_num = 1;
+    s->init_off = 0;
 
-    /* SSL3_ST_CW_CHANGE_B */
-    return (ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC));
+    return 1;
 }
 
 unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
@@ -403,151 +370,187 @@ unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
     return l + SSL_HM_HEADER_LENGTH(s);
 }
 
-/*
- * Obtain handshake message of message type 'mt' (any if mt == -1), maximum
- * acceptable body length 'max'. The first four bytes (msg_type and length)
- * are read in state 'st1', the body is read in state 'stn'.
- */
-long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
+WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst)
 {
-    unsigned char *p;
-    unsigned long l;
-    long n;
-    int i, al, recvd_type;
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
 
-    if (s->s3->tmp.reuse_message) {
-        s->s3->tmp.reuse_message = 0;
-        if ((mt >= 0) && (s->s3->tmp.message_type != mt)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+        WORK_STATE ret;
+        ret = dtls_wait_for_dry(s);
+        if (ret != WORK_FINISHED_CONTINUE)
+            return ret;
+    }
+#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;
+    }
+
+    ssl_free_wbio_buffer(s);
+
+    s->init_num = 0;
+
+    if (!s->server || s->renegotiate == 2) {
+        /* skipped if we just sent a HelloRequest */
+        s->renegotiate = 0;
+        s->new_session = 0;
+
+        if (s->server) {
+            s->renegotiate = 0;
+            s->new_session = 0;
+
+            ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
+
+            s->ctx->stats.sess_accept_good++;
+            s->handshake_func = ossl_statem_accept;
+        } else {
+            ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+            if (s->hit)
+                s->ctx->stats.sess_hit++;
+
+            s->handshake_func = ossl_statem_connect;
+            s->ctx->stats.sess_connect_good++;
+        }
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL)
+            cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+
+        if (SSL_IS_DTLS(s)) {
+            /* done with handshaking */
+            s->d1->handshake_read_seq = 0;
+            s->d1->handshake_write_seq = 0;
+            s->d1->next_handshake_write_seq = 0;
         }
-        *ok = 1;
-        s->state = stn;
-        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
-        s->init_num = (int)s->s3->tmp.message_size;
-        return s->init_num;
     }
 
+    return WORK_FINISHED_STOP;
+}
+
+int tls_get_message_header(SSL *s, int *mt)
+{
+    /* s->init_num < SSL3_HM_HEADER_LENGTH */
+    int skip_message, i, recvd_type, al;
+    unsigned char *p;
+    unsigned long l;
+
     p = (unsigned char *)s->init_buf->data;
 
-    if (s->state == st1) {
-        /* s->init_num < SSL3_HM_HEADER_LENGTH */
-        int skip_message;
-
-        do {
-            while (s->init_num < SSL3_HM_HEADER_LENGTH) {
-                i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
-                    &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
-                if (i <= 0) {
-                    s->rwstate = SSL_READING;
-                    *ok = 0;
-                    return i;
-                }
-                if (s->init_num == 0
-                        && recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC
-                        && (mt < 0 || mt == SSL3_MT_CHANGE_CIPHER_SPEC)) {
-                    if (*p != SSL3_MT_CCS) {
-                        al = SSL_AD_UNEXPECTED_MESSAGE;
-                        SSLerr(SSL_F_SSL3_GET_MESSAGE,
-                               SSL_R_UNEXPECTED_MESSAGE);
-                        goto f_err;
-                    }
-                    s->init_num = i - 1;
-                    s->init_msg = p + 1;
-                    s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
-                    s->s3->tmp.message_size = i - 1;
-                    s->state = stn;
-                    *ok = 1;
+    do {
+        while (s->init_num < SSL3_HM_HEADER_LENGTH) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
+                &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
+            if (i <= 0) {
+                s->rwstate = SSL_READING;
+                return 0;
+            }
+            if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+                s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
+                s->init_num = i - 1;
+                s->s3->tmp.message_size = i;
+                return 1;
+            } else if (recvd_type != SSL3_RT_HANDSHAKE) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_CCS_RECEIVED_EARLY);
+                goto f_err;
+            }
+            s->init_num += i;
+        }
+
+        skip_message = 0;
+        if (!s->server)
+            if (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
+                 * their format is correct. Does not count for 'Finished'
+                 * MAC.
+                 */
+                if (p[1] == 0 && p[2] == 0 && p[3] == 0) {
+                    s->init_num = 0;
+                    skip_message = 1;
+
                     if (s->msg_callback)
-                        s->msg_callback(0, s->version,
-                                        SSL3_RT_CHANGE_CIPHER_SPEC, p, 1, s,
+                        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                                        p, SSL3_HM_HEADER_LENGTH, s,
                                         s->msg_callback_arg);
-                    return i - 1;
-                } else if (recvd_type != SSL3_RT_HANDSHAKE) {
-                    al = SSL_AD_UNEXPECTED_MESSAGE;
-                    SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_CCS_RECEIVED_EARLY);
-                    goto f_err;
                 }
-                s->init_num += i;
-            }
+    } while (skip_message);
+    /* s->init_num == SSL3_HM_HEADER_LENGTH */
 
-            skip_message = 0;
-            if (!s->server)
-                if (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
-                     * their format is correct. Does not count for 'Finished'
-                     * MAC.
-                     */
-                    if (p[1] == 0 && p[2] == 0 && p[3] == 0) {
-                        s->init_num = 0;
-                        skip_message = 1;
-
-                        if (s->msg_callback)
-                            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                                            p, SSL3_HM_HEADER_LENGTH, s,
-                                            s->msg_callback_arg);
-                    }
-        } while (skip_message);
-        /* s->init_num == SSL3_HM_HEADER_LENGTH */
-
-        if ((mt >= 0) && (*p != mt)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
+    *mt = *p;
+    s->s3->tmp.message_type = *(p++);
+
+    if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        /*
+         * Only happens with SSLv3+ in an SSLv2 backward compatible
+         * ClientHello
+         */
+         /*
+          * Total message size is the remaining record bytes to read
+          * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
+          */
+        l = RECORD_LAYER_get_rrec_length(&s->rlayer)
+            + SSL3_HM_HEADER_LENGTH;
+        if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l)) {
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
+            goto err;
+        }
+        s->s3->tmp.message_size = l;
+
+        s->init_msg = s->init_buf->data;
+        s->init_num = SSL3_HM_HEADER_LENGTH;
+    } else {
+        n2l3(p, l);
+        /* BUF_MEM_grow takes an 'int' parameter */
+        if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_EXCESSIVE_MESSAGE_SIZE);
             goto f_err;
         }
+        if (l && !BUF_MEM_grow_clean(s->init_buf,
+                                    (int)l + SSL3_HM_HEADER_LENGTH)) {
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
+            goto err;
+        }
+        s->s3->tmp.message_size = l;
 
-        s->s3->tmp.message_type = *(p++);
-
-        if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
-            /*
-             * Only happens with SSLv3+ in an SSLv2 backward compatible
-             * ClientHello
-             */
-             /*
-              * Total message size is the remaining record bytes to read
-              * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
-              */
-            l = RECORD_LAYER_get_rrec_length(&s->rlayer)
-                + SSL3_HM_HEADER_LENGTH;
-            if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l)) {
-                SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB);
-                goto err;
-            }
-            s->s3->tmp.message_size = l;
-            s->state = stn;
+        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+        s->init_num = 0;
+    }
 
-            s->init_msg = s->init_buf->data;
-            s->init_num = SSL3_HM_HEADER_LENGTH;
-        } else {
-            n2l3(p, l);
-            if (l > (unsigned long)max) {
-                al = SSL_AD_ILLEGAL_PARAMETER;
-                SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-                goto f_err;
-            }
-            /* BUF_MEM_grow takes an 'int' parameter */
-            if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
-                al = SSL_AD_ILLEGAL_PARAMETER;
-                SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-                goto f_err;
-            }
-            if (l && !BUF_MEM_grow_clean(s->init_buf,
-                                        (int)l + SSL3_HM_HEADER_LENGTH)) {
-                SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB);
-                goto err;
-            }
-            s->s3->tmp.message_size = l;
-            s->state = stn;
+    return 1;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    return 0;
+}
 
-            s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
-            s->init_num = 0;
-        }
+int tls_get_message_body(SSL *s, unsigned long *len)
+{
+    long n;
+    unsigned char *p;
+    int i;
+
+    if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        /* We've already read everything in */
+        *len = (unsigned long)s->init_num;
+        return 1;
     }
 
-    /* next state (stn) */
     p = s->init_msg;
     n = s->s3->tmp.message_size - s->init_num;
     while (n > 0) {
@@ -555,8 +558,8 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
                                       &p[s->init_num], n, 0);
         if (i <= 0) {
             s->rwstate = SSL_READING;
-            *ok = 0;
-            return i;
+            *len = 0;
+            return 0;
         }
         s->init_num += i;
         n -= i;
@@ -586,13 +589,18 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
                             s->msg_callback_arg);
     }
 
-    *ok = 1;
-    return s->init_num;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    *ok = 0;
-    return (-1);
+    /*
+     * init_num should never be negative...should probably be declared
+     * unsigned
+     */
+    if (s->init_num < 0) {
+        SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_INTERNAL_ERROR);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        *len = 0;
+        return 0;
+    }
+    *len = (unsigned long)s->init_num;
+    return 1;
 }
 
 int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
new file mode 100644
index 0000000..4c3d797
--- /dev/null
+++ b/ssl/statem/statem_locl.h
@@ -0,0 +1,171 @@
+/* ssl/statem/statem_locl.h */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * The following definitions are PRIVATE to the state machine. They should   *
+ * NOT be used outside of the state machine.                                 *
+ *                                                                           *
+ *****************************************************************************/
+
+/* Max message length definitions */
+
+/* The spec allows for a longer length than this, but we limit it */
+#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
+#define SERVER_HELLO_MAX_LENGTH         20000
+#define SERVER_KEY_EXCH_MAX_LENGTH      102400
+#define SERVER_HELLO_DONE_MAX_LENGTH    0
+#define CCS_MAX_LENGTH                  1
+/* Max should actually be 36 but we are generous */
+#define FINISHED_MAX_LENGTH             64
+
+/* Message processing return codes */
+typedef enum {
+    /* Something bad happened */
+    MSG_PROCESS_ERROR,
+    /* We've finished reading - swap to writing */
+    MSG_PROCESS_FINISHED_READING,
+    /*
+     * We've completed the main processing of this message but there is some
+     * post processing to be done.
+     */
+    MSG_PROCESS_CONTINUE_PROCESSING,
+    /* We've finished this message - read the next message */
+    MSG_PROCESS_CONTINUE_READING
+} MSG_PROCESS_RETURN;
+
+/* Flush the write BIO */
+int statem_flush(SSL *s);
+
+/*
+ * TLS/DTLS client state machine functions
+ */
+int ossl_statem_client_read_transition(SSL *s, int mt);
+WRITE_TRAN ossl_statem_client_write_transition(SSL *s);
+WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst);
+WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst);
+int ossl_statem_client_construct_message(SSL *s);
+unsigned long ossl_statem_client_max_message_size(SSL *s);
+MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt);
+WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst);
+
+/*
+ * TLS/DTLS server state machine functions
+ */
+int ossl_statem_server_read_transition(SSL *s, int mt);
+WRITE_TRAN ossl_statem_server_write_transition(SSL *s);
+WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst);
+WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst);
+int ossl_statem_server_construct_message(SSL *s);
+unsigned long ossl_statem_server_max_message_size(SSL *s);
+MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt);
+WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst);
+
+/* Functions for getting new message data */
+__owur int tls_get_message_header(SSL *s, int *mt);
+__owur int tls_get_message_body(SSL *s, unsigned long *len);
+__owur int dtls_get_message(SSL *s, int *mt, unsigned long *len);
+
+/* Message construction and processing functions */
+__owur MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt);
+__owur int tls_construct_change_cipher_spec(SSL *s);
+__owur int dtls_construct_change_cipher_spec(SSL *s);
+
+__owur int tls_construct_finished(SSL *s, const char *sender, int slen);
+__owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst);
+__owur WORK_STATE dtls_wait_for_dry(SSL *s);
+
+/* some client-only functions */
+__owur int tls_construct_client_hello(SSL *s);
+__owur MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt);
+__owur int tls_construct_client_verify(SSL *s);
+__owur WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst);
+__owur int tls_construct_client_certificate(SSL *s);
+__owur int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
+__owur int tls_construct_client_key_exchange(SSL *s);
+__owur int tls_client_key_exchange_post_work(SSL *s);
+__owur int tls_construct_cert_status(SSL *s);
+__owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s,
+                                                        PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt);
+__owur int ssl3_check_cert_and_algorithm(SSL *s);
+#  ifndef OPENSSL_NO_NEXTPROTONEG
+__owur int tls_construct_next_proto(SSL *s);
+#  endif
+__owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt);
+
+/* some server-only functions */
+__owur MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt);
+__owur WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst);
+__owur int tls_construct_server_hello(SSL *s);
+__owur int tls_construct_hello_request(SSL *s);
+__owur int dtls_construct_hello_verify_request(SSL *s);
+__owur int tls_construct_server_certificate(SSL *s);
+__owur int tls_construct_server_key_exchange(SSL *s);
+__owur int tls_construct_certificate_request(SSL *s);
+__owur int tls_construct_server_done(SSL *s);
+__owur MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt);
+__owur WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst);
+__owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt);
+#  ifndef OPENSSL_NO_NEXTPROTONEG
+__owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt);
+#  endif
+__owur int tls_construct_new_session_ticket(SSL *s);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
new file mode 100644
index 0000000..6f51d5d
--- /dev/null
+++ b/ssl/statem/statem_srvr.c
@@ -0,0 +1,3652 @@
+/* ssl/statem/statem_srvr.c -*- mode:C; c-file-style: "eay" -*- */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+
+#include <stdio.h>
+#include "../ssl_locl.h"
+#include "statem_locl.h"
+#include "internal/constant_time_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/x509.h>
+#ifndef OPENSSL_NO_DH
+# include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+
+static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
+                                                      PACKET *cipher_suites,
+                                                      STACK_OF(SSL_CIPHER) **skp,
+                                                      int sslv2format, int *al);
+
+/*
+ * server_read_transition() encapsulates the logic for the allowed handshake
+ * state transitions when the server is reading messages from the client. The
+ * message type that the client has sent is provided in |mt|. The current state
+ * is in |s->statem.hand_state|.
+ *
+ *  Valid return values are:
+ *  1: Success (transition allowed)
+ *  0: Error (transition not allowed)
+ */
+int ossl_statem_server_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_BEFORE:
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (mt == SSL3_MT_CLIENT_HELLO) {
+            st->hand_state = TLS_ST_SR_CLNT_HELLO;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        /*
+         * If we get a CKE message after a ServerDone then either
+         * 1) We didn't request a Certificate
+         * OR
+         * 2) If we did request one then
+         *      a) We allow no Certificate to be returned
+         *      AND
+         *      b) We are running SSL3 (in TLS1.0+ the client must return a 0
+         *         list if we requested a certificate)
+         */
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE
+                && (!s->s3->tmp.cert_request
+                    || (!((s->verify_mode & SSL_VERIFY_PEER) &&
+                          (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+                        && (s->version == SSL3_VERSION)))) {
+            st->hand_state = TLS_ST_SR_KEY_EXCH;
+            return 1;
+        } else if (s->s3->tmp.cert_request) {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_SR_CERT;
+                return 1;
+            } 
+        }
+        break;
+
+    case TLS_ST_SR_CERT:
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+            st->hand_state = TLS_ST_SR_KEY_EXCH;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_KEY_EXCH:
+        /*
+         * We should only process a CertificateVerify message if we have
+         * received a Certificate from the client. If so then |s->session->peer|
+         * will be non NULL. In some instances a CertificateVerify message is
+         * not required even if the peer has sent a Certificate (e.g. such as in
+         * the case of static DH). In that case |st->no_cert_verify| should be
+         * set.
+         */
+        if (s->session->peer == NULL || st->no_cert_verify) {
+            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                /*
+                 * For the ECDH ciphersuites when the client sends its ECDH
+                 * pub key in a certificate, the CertificateVerify message is
+                 * not sent. Also for GOST ciphersuites when the client uses
+                 * its key from the certificate for key exchange.
+                 */
+                st->hand_state = TLS_ST_SR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+                st->hand_state = TLS_ST_SR_CERT_VRFY;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT_VRFY:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_CHANGE:
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        if (s->s3->next_proto_neg_seen) {
+            if (mt == SSL3_MT_NEXT_PROTO) {
+                st->hand_state = TLS_ST_SR_NEXT_PROTO;
+                return 1;
+            }
+        } else {
+#endif
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_SR_FINISHED;
+                return 1;
+            }
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        }
+#endif
+        break;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_SR_FINISHED;
+            return 1;
+        }
+        break;
+#endif
+
+    case TLS_ST_SW_FINISHED:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    /* No valid transition found */
+    return 0;
+}
+
+/*
+ * Should we send a ServerKeyExchange message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+static int send_server_key_exchange(SSL *s)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
+     * sign only certificate PSK: may send PSK identity hints For
+     * ECC ciphersuites, we send a serverKeyExchange message only if
+     * the cipher suite is either ECDH-anon or ECDHE. In other cases,
+     * the server certificate contains the server's public key for
+     * key exchange.
+     */
+    if (   (alg_k & SSL_kDHE)
+        || (alg_k & SSL_kECDHE)
+        || ((alg_k & SSL_kRSA)
+            && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+                || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+                    && EVP_PKEY_size(s->cert->pkeys
+                                     [SSL_PKEY_RSA_ENC].privatekey) *
+                    8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+                   )
+               )
+           )
+        /*
+         * PSK: send ServerKeyExchange if PSK identity hint if
+         * provided
+         */
+#ifndef OPENSSL_NO_PSK
+        /* Only send SKE if we have identity hint for plain PSK */
+        || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
+            && s->cert->psk_identity_hint)
+        /* For other PSK always send SKE */
+        || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
+#endif
+#ifndef OPENSSL_NO_SRP
+        /* SRP: send ServerKeyExchange */
+        || (alg_k & SSL_kSRP)
+#endif
+       ) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Should we send a CertificateRequest message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+static int send_certificate_request(SSL *s)
+{
+    if (
+           /* don't request cert unless asked for it: */
+           s->verify_mode & SSL_VERIFY_PEER
+           /*
+            * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
+            * during re-negotiation:
+            */
+           && ((s->session->peer == NULL) ||
+               !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
+           /*
+            * never request cert in anonymous ciphersuites (see
+            * section "Certificate request" in SSL 3 drafts and in
+            * RFC 2246):
+            */
+           && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+           /*
+            * ... except when the application insists on
+            * verification (against the specs, but s3_clnt.c accepts
+            * this for SSL 3)
+            */
+               || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+           /* don't request certificate for SRP auth */
+           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
+           /*
+            * With normal PSK Certificates and Certificate Requests
+            * are omitted
+            */
+           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * server_write_transition() works out what handshake state to move to next
+ * when the server is writing messages to be sent to the client.
+ */
+WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        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);
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SR_CLNT_HELLO:
+            if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
+                    && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
+                st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
+            else
+                st->hand_state = TLS_ST_SW_SRVR_HELLO;
+            return WRITE_TRAN_CONTINUE;
+
+        case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+            return WRITE_TRAN_FINISHED;
+
+        case TLS_ST_SW_SRVR_HELLO:
+            if (s->hit) {
+                if (s->tlsext_ticket_expected)
+                    st->hand_state = TLS_ST_SW_SESSION_TICKET;
+                else
+                    st->hand_state = TLS_ST_SW_CHANGE;
+            } else {
+                /* Check if it is anon DH or anon ECDH, */
+                /* normal PSK or SRP */
+                if (!(s->s3->tmp.new_cipher->algorithm_auth &
+                     (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                    st->hand_state = TLS_ST_SW_CERT;
+                } else if (send_server_key_exchange(s)) {
+                    st->hand_state = TLS_ST_SW_KEY_EXCH;
+                } else if (send_certificate_request(s)) {
+                    st->hand_state = TLS_ST_SW_CERT_REQ;
+                } else {
+                    st->hand_state = TLS_ST_SW_SRVR_DONE;
+                }
+            }
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_CERT:
+            if (s->tlsext_status_expected) {
+                st->hand_state = TLS_ST_SW_CERT_STATUS;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_CERT_STATUS:
+            if (send_server_key_exchange(s)) {
+                st->hand_state = TLS_ST_SW_KEY_EXCH;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_KEY_EXCH:
+            if (send_certificate_request(s)) {
+                st->hand_state = TLS_ST_SW_CERT_REQ;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_CERT_REQ:
+            st->hand_state = TLS_ST_SW_SRVR_DONE;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_SRVR_DONE:
+            return WRITE_TRAN_FINISHED;
+
+        case TLS_ST_SR_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_OK;
+                ossl_statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
+            } else if (s->tlsext_ticket_expected) {
+                st->hand_state = TLS_ST_SW_SESSION_TICKET;
+            } else {
+                st->hand_state = TLS_ST_SW_CHANGE;
+            }
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_SESSION_TICKET:
+            st->hand_state = TLS_ST_SW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_CHANGE:
+            st->hand_state = TLS_ST_SW_FINISHED;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_FINISHED:
+            if (s->hit) {
+                return WRITE_TRAN_FINISHED;
+            }
+            st->hand_state = TLS_ST_OK;
+            ossl_statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+
+        default:
+            /* Shouldn't happen */
+            return WRITE_TRAN_ERROR;
+    }
+}
+
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the server to the client.
+ */
+WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SW_HELLO_REQ:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s))
+            dtls1_clear_record_buffer(s);
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            dtls1_clear_record_buffer(s);
+            /* We don't buffer this message so don't use the timer */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * Messages we write from now on should be bufferred and
+             * retransmitted if necessary, so we need to use the timer now
+             */
+            st->use_timer = 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s)))
+            return dtls_wait_for_dry(s);
+#endif
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        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
+             */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_CHANGE:
+        s->session->cipher = s->s3->tmp.new_cipher;
+        if (!s->method->ssl3_enc->setup_key_block(s)) {
+            ossl_statem_set_error(s);
+            return WORK_ERROR;
+        }
+        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. This might have
+             * already been set to 0 if we sent a NewSessionTicket message,
+             * but we'll set it again here in case we didn't.
+             */
+            st->use_timer = 0;
+        }
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_OK:
+        return tls_finish_handshake(s, wst);
+
+    default:
+        /* No pre work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * server to the client.
+ */
+WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    s->init_num = 0;
+
+    switch(st->hand_state) {
+    case TLS_ST_SW_HELLO_REQ:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        ssl3_init_finished_mac(s);
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        /* HelloVerifyRequest resets Finished MAC */
+        if (s->version != DTLS1_BAD_VER)
+            ssl3_init_finished_mac(s);
+        /*
+         * The next message should be another ClientHello which we need to
+         * treat like it was the first packet
+         */
+        s->first_packet = 1;
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no
+             * SCTP used.
+             */
+            memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+                   sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                    sizeof(sctpauthkey), labelbuffer,
+                    sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                ossl_statem_set_error(s);
+                return WORK_ERROR;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+#endif
+        break;
+
+    case TLS_ST_SW_CHANGE:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && !s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+            ossl_statem_set_error(s);
+            return WORK_ERROR;
+        }
+
+        if (SSL_IS_DTLS(s))
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        break;
+
+    case TLS_ST_SW_FINISHED:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        break;
+
+    default:
+        /* No post work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Construct a message to be sent from the server to the client.
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+int ossl_statem_server_construct_message(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        return dtls_construct_hello_verify_request(s);
+
+    case TLS_ST_SW_HELLO_REQ:
+        return tls_construct_hello_request(s);
+
+    case TLS_ST_SW_SRVR_HELLO:
+        return tls_construct_server_hello(s);
+
+    case TLS_ST_SW_CERT:
+        return tls_construct_server_certificate(s);
+
+    case TLS_ST_SW_KEY_EXCH:
+        return tls_construct_server_key_exchange(s);
+
+    case TLS_ST_SW_CERT_REQ:
+        return tls_construct_certificate_request(s);
+
+    case TLS_ST_SW_SRVR_DONE:
+        return tls_construct_server_done(s);
+
+    case TLS_ST_SW_SESSION_TICKET:
+        return tls_construct_new_session_ticket(s);
+
+    case TLS_ST_SW_CERT_STATUS:
+        return tls_construct_cert_status(s);
+
+    case TLS_ST_SW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            return dtls_construct_change_cipher_spec(s);
+        else
+            return tls_construct_change_cipher_spec(s);
+
+    case TLS_ST_SW_FINISHED:
+        return tls_construct_finished(s,
+                                      s->method->
+                                      ssl3_enc->server_finished_label,
+                                      s->method->
+                                      ssl3_enc->server_finished_label_len);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+#define CLIENT_KEY_EXCH_MAX_LENGTH      2048
+#define NEXT_PROTO_MAX_LENGTH           514
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+unsigned long ossl_statem_server_max_message_size(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+    case TLS_ST_SR_CERT:
+        return s->max_cert_list;
+
+    case TLS_ST_SR_KEY_EXCH:
+        return CLIENT_KEY_EXCH_MAX_LENGTH;
+
+    case TLS_ST_SR_CERT_VRFY:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return NEXT_PROTO_MAX_LENGTH;
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return CCS_MAX_LENGTH;
+
+    case TLS_ST_SR_FINISHED:
+        return FINISHED_MAX_LENGTH;
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+/*
+ * Process a message that the server has received from the client.
+ */
+MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_process_client_hello(s, pkt);
+
+    case TLS_ST_SR_CERT:
+        return tls_process_client_certificate(s, pkt);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_process_client_key_exchange(s, pkt);
+
+    case TLS_ST_SR_CERT_VRFY:
+        return tls_process_cert_verify(s, pkt);
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return tls_process_next_proto(s, pkt);
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return tls_process_change_cipher_spec(s, pkt);
+
+    case TLS_ST_SR_FINISHED:
+        return tls_process_finished(s, pkt);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return MSG_PROCESS_ERROR;
+}
+
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the client
+ */
+WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_post_process_client_hello(s, wst);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_post_process_client_key_exchange(s, wst);
+
+    case TLS_ST_SR_CERT_VRFY:
+#ifndef OPENSSL_NO_SCTP
+        if (    /* Is this SCTP? */
+                BIO_dgram_is_sctp(SSL_get_wbio(s))
+                /* Are we renegotiating? */
+                && s->renegotiate
+                && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+            s->s3->in_read_app_data = 2;
+            s->rwstate = SSL_READING;
+            BIO_clear_retry_flags(SSL_get_rbio(s));
+            BIO_set_retry_read(SSL_get_rbio(s));
+            statem_set_sctp_read_sock(s, 1);
+            return WORK_MORE_A;
+        } else {
+            ossl_ossl_statem_set_sctp_read_sock(s, 0);
+        }
+#endif
+        return WORK_FINISHED_CONTINUE;
+
+
+    case TLS_ST_SR_FINISHED:
+        if (s->hit)
+            return tls_finish_handshake(s, wst);
+        else
+            return WORK_FINISHED_STOP;
+    default:
+        break;
+    }
+
+    /* Shouldn't happen */
+    return WORK_ERROR;
+}
+
+#ifndef OPENSSL_NO_SRP
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
+{
+    int ret = SSL_ERROR_NONE;
+
+    *al = SSL_AD_UNRECOGNIZED_NAME;
+
+    if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
+        (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) {
+        if (s->srp_ctx.login == NULL) {
+            /*
+             * RFC 5054 says SHOULD reject, we do so if There is no srp
+             * login name
+             */
+            ret = SSL3_AL_FATAL;
+            *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+        } else {
+            ret = SSL_srp_server_param_with_username(s, al);
+        }
+    }
+    return ret;
+}
+#endif
+
+int tls_construct_hello_request(SSL *s)
+{
+    if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+unsigned int dtls_raw_hello_verify_request(unsigned char *buf,
+                                            unsigned char *cookie,
+                                            unsigned char cookie_len)
+{
+    unsigned int msg_len;
+    unsigned char *p;
+
+    p = buf;
+    /* Always use DTLS 1.0 version: see RFC 6347 */
+    *(p++) = DTLS1_VERSION >> 8;
+    *(p++) = DTLS1_VERSION & 0xFF;
+
+    *(p++) = (unsigned char)cookie_len;
+    memcpy(p, cookie, cookie_len);
+    p += cookie_len;
+    msg_len = p - buf;
+
+    return msg_len;
+}
+
+int dtls_construct_hello_verify_request(SSL *s)
+{
+    unsigned int len;
+    unsigned char *buf;
+
+    buf = (unsigned char *)s->init_buf->data;
+
+    if (s->ctx->app_gen_cookie_cb == NULL ||
+        s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+                                  &(s->d1->cookie_len)) == 0 ||
+        s->d1->cookie_len > 255) {
+        SSLerr(SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST,
+               SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    len = dtls_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
+                                         s->d1->cookie, s->d1->cookie_len);
+
+    dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
+                             len);
+    len += DTLS1_HM_HEADER_LENGTH;
+
+    /* number of bytes to write */
+    s->init_num = len;
+    s->init_off = 0;
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
+{
+    int i, al = SSL_AD_INTERNAL_ERROR;
+    unsigned int j, complen = 0;
+    unsigned long id;
+    SSL_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp = NULL;
+#endif
+    STACK_OF(SSL_CIPHER) *ciphers = NULL;
+    int protverr = 1;
+    /* |cookie| will only be initialized for DTLS. */
+    PACKET session_id, cipher_suites, compression, extensions, cookie;
+    int is_v2_record;
+
+    is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer);
+
+    PACKET_null_init(&cookie);
+    /* First lets get s->client_version set correctly */
+    if (is_v2_record) {
+        unsigned int version;
+        unsigned int mt;
+        /*-
+         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
+         * header is sent directly on the wire, not wrapped as a TLS
+         * record. Our record layer just processes the message length and passes
+         * the rest right through. Its format is:
+         * Byte  Content
+         * 0-1   msg_length - decoded by the record layer
+         * 2     msg_type - s->init_msg points here
+         * 3-4   version
+         * 5-6   cipher_spec_length
+         * 7-8   session_id_length
+         * 9-10  challenge_length
+         * ...   ...
+         */
+
+        if (!PACKET_get_1(pkt, &mt)
+                || mt != SSL2_MT_CLIENT_HELLO) {
+            /*
+             * Should never happen. We should have tested this in the record
+             * layer in order to have determined that this is a SSLv2 record
+             * in the first place
+             */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (!PACKET_get_net_2(pkt, &version)) {
+            /* No protocol version supplied! */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+        if (version == 0x0002) {
+            /* This is real SSLv2. We don't support it. */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) {
+            /* SSLv3/TLS */
+            s->client_version = version;
+        } else {
+            /* No idea what protocol this is */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+    } else {
+        /*
+         * use version from inside client hello, not from record header (may
+         * differ: see RFC 2246, Appendix E, second paragraph)
+         */
+        if(!PACKET_get_net_2(pkt, (unsigned int *)&s->client_version)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
+            goto f_err;
+        }
+    }
+
+    /* Do SSL/TLS version negotiation if applicable */
+    if (!SSL_IS_DTLS(s)) {
+        if (s->version != TLS_ANY_VERSION) {
+            if (s->client_version >= s->version) {
+                protverr = 0;
+            }
+        } else if (s->client_version >= SSL3_VERSION) {
+            switch(s->client_version) {
+            default:
+            case TLS1_2_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1_2)) {
+                    s->version = TLS1_2_VERSION;
+                    s->method = TLSv1_2_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case TLS1_1_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1_1)) {
+                    s->version = TLS1_1_VERSION;
+                    s->method = TLSv1_1_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case TLS1_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1)) {
+                    s->version = TLS1_VERSION;
+                    s->method = TLSv1_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case SSL3_VERSION:
+#ifndef OPENSSL_NO_SSL3
+                if(!(s->options & SSL_OP_NO_SSLv3)) {
+                    s->version = SSL3_VERSION;
+                    s->method = SSLv3_server_method();
+                    protverr = 0;
+                    break;
+                }
+#else
+                break;
+#endif
+            }
+        }
+    } else if (s->client_version <= s->version
+                || s->method->version == DTLS_ANY_VERSION) {
+        /*
+         * For DTLS we just check versions are potentially compatible. Version
+         * negotiation comes later.
+         */
+        protverr = 0;
+    }
+
+    if (protverr) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+        if ((!s->enc_write_ctx && !s->write_hash)) {
+            /*
+             * similar to ssl3_get_record, send alert using remote version
+             * number
+             */
+            s->version = s->client_version;
+        }
+        al = SSL_AD_PROTOCOL_VERSION;
+        goto f_err;
+    }
+
+    /* Parse the message and load client random. */
+    if (is_v2_record) {
+        /*
+         * Handle an SSLv2 backwards compatible ClientHello
+         * Note, this is only for SSLv3+ using the backward compatible format.
+         * Real SSLv2 is not supported, and is rejected above.
+         */
+        unsigned int cipher_len, session_id_len, challenge_len;
+        PACKET challenge;
+
+        if (!PACKET_get_net_2(pkt, &cipher_len)
+                || !PACKET_get_net_2(pkt, &session_id_len)
+                || !PACKET_get_net_2(pkt, &challenge_len)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+
+        if (!PACKET_get_sub_packet(pkt, &cipher_suites, cipher_len)
+            || !PACKET_get_sub_packet(pkt, &session_id, session_id_len)
+            || !PACKET_get_sub_packet(pkt, &challenge, challenge_len)
+            /* No extensions. */
+            || PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+
+        /* Load the client random */
+        challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE :
+            challenge_len;
+        memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE);
+        if (!PACKET_copy_bytes(&challenge,
+                               s->s3->client_random + SSL3_RANDOM_SIZE -
+                               challenge_len, challenge_len)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        PACKET_null_init(&compression);
+        PACKET_null_init(&extensions);
+    } else {
+        /* Regular ClientHello. */
+        if (!PACKET_copy_bytes(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)
+            || !PACKET_get_length_prefixed_1(pkt, &session_id)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+            }
+            /*
+             * If we require cookies and this ClientHello doesn't contain one,
+             * just return since we do not want to allocate any memory yet.
+             * So check cookie length...
+             */
+            if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+                if (PACKET_remaining(&cookie) == 0)
+                return 1;
+            }
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &cipher_suites)
+            || !PACKET_get_length_prefixed_1(pkt, &compression)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+        }
+        /* Could be empty. */
+        extensions = *pkt;
+    }
+
+    s->hit = 0;
+
+    /*
+     * We don't allow resumption in a backwards compatible ClientHello.
+     * TODO(openssl-team): in TLS1.1+, session_id MUST be empty.
+     *
+     * Versions before 0.9.7 always allow clients to resume sessions in
+     * renegotiation. 0.9.7 and later allow this by default, but optionally
+     * ignore resumption requests with flag
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
+     * than a change to default behavior so that applications relying on
+     * this for security won't even compile against older library versions).
+     * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to
+     * request renegotiation but not a new session (s->new_session remains
+     * unset): for servers, this essentially just means that the
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
+     * ignored.
+     */
+    if (is_v2_record ||
+        (s->new_session &&
+         (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
+        if (!ssl_get_new_session(s, 1))
+            goto err;
+    } else {
+        i = ssl_get_prev_session(s, &extensions, &session_id);
+        /*
+         * 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) {
+            /* previous session */
+            s->hit = 1;
+        } else if (i == -1) {
+            goto err;
+        } else {
+            /* i == 0 */
+            if (!ssl_get_new_session(s, 1))
+                goto err;
+        }
+    }
+
+    if (SSL_IS_DTLS(s)) {
+        /* Empty cookie was already handled above by returning early. */
+        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+            if (s->ctx->app_verify_cookie_cb != NULL) {
+                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
+                                                 PACKET_remaining(&cookie)) == 0) {
+                    al = SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                           SSL_R_COOKIE_MISMATCH);
+                    goto f_err;
+                    /* else cookie verification succeeded */
+                }
+            /* default verification */
+            } else if (!PACKET_equal(&cookie, s->d1->cookie,
+                                     s->d1->cookie_len)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+                goto f_err;
+            }
+            s->d1->cookie_verified = 1;
+        }
+        if (s->method->version == DTLS_ANY_VERSION) {
+            /* Select version to use */
+            if (s->client_version <= DTLS1_2_VERSION &&
+                !(s->options & SSL_OP_NO_DTLSv1_2)) {
+                s->version = DTLS1_2_VERSION;
+                s->method = DTLSv1_2_server_method();
+            } else if (tls1_suiteb(s)) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                s->version = s->client_version;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            } else if (s->client_version <= DTLS1_VERSION &&
+                       !(s->options & SSL_OP_NO_DTLSv1)) {
+                s->version = DTLS1_VERSION;
+                s->method = DTLSv1_server_method();
+            } else {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                       SSL_R_WRONG_VERSION_NUMBER);
+                s->version = s->client_version;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            }
+            s->session->ssl_version = s->version;
+        }
+    }
+
+    if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers),
+                                 is_v2_record, &al) == NULL) {
+        goto f_err;
+    }
+
+    /* If it is a hit, check that the cipher is in the list */
+    if (s->hit) {
+        j = 0;
+        id = s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+        fprintf(stderr, "client sent %d ciphers\n",
+                sk_SSL_CIPHER_num(ciphers));
+#endif
+        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+            c = sk_SSL_CIPHER_value(ciphers, i);
+#ifdef CIPHER_DEBUG
+            fprintf(stderr, "client [%2d of %2d]:%s\n",
+                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
+#endif
+            if (c->id == id) {
+                j = 1;
+                break;
+            }
+        }
+        if (j == 0) {
+            /*
+             * we need to have the cipher in the cipher list if we are asked
+             * to reuse it
+             */
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_REQUIRED_CIPHER_MISSING);
+            goto f_err;
+        }
+    }
+
+    complen = PACKET_remaining(&compression);
+    for (j = 0; j < complen; j++) {
+        if (PACKET_data(&compression)[j] == 0)
+            break;
+    }
+
+    if (j >= complen) {
+        /* no compress */
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED);
+        goto f_err;
+    }
+    
+    /* TLS extensions */
+    if (s->version >= SSL3_VERSION) {
+        if (!ssl_parse_clienthello_tlsext(s, &extensions)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
+            goto 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
+     * calling tls_session_secret_cb in order to allow SessionTicket
+     * processing to use it in key derivation.
+     */
+    {
+        unsigned char *pos;
+        pos = s->s3->server_random;
+        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
+            goto f_err;
+        }
+    }
+
+    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
+        SSL_CIPHER *pref_cipher = NULL;
+
+        s->session->master_key_length = sizeof(s->session->master_key);
+        if (s->tls_session_secret_cb(s, s->session->master_key,
+                                     &s->session->master_key_length, ciphers,
+                                     &pref_cipher,
+                                     s->tls_session_secret_cb_arg)) {
+            s->hit = 1;
+            s->session->ciphers = ciphers;
+            s->session->verify_result = X509_V_OK;
+
+            ciphers = NULL;
+
+            /* check if some cipher was preferred by call back */
+            pref_cipher =
+                pref_cipher ? pref_cipher : ssl3_choose_cipher(s,
+                                                               s->
+                                                               session->ciphers,
+                                                               SSL_get_ciphers
+                                                               (s));
+            if (pref_cipher == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
+                goto f_err;
+            }
+
+            s->session->cipher = pref_cipher;
+            sk_SSL_CIPHER_free(s->cipher_list);
+            s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+            sk_SSL_CIPHER_free(s->cipher_list_by_id);
+            s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+        }
+    }
+
+    /*
+     * Worst case, we will use the NULL compression, but if we have other
+     * options, we will now look for them.  We have complen-1 compression
+     * algorithms from the client, starting at q.
+     */
+    s->s3->tmp.new_compression = NULL;
+#ifndef OPENSSL_NO_COMP
+    /* This only happens if we have a cache hit */
+    if (s->session->compress_meth != 0) {
+        int m, comp_id = s->session->compress_meth;
+        unsigned int k;
+        /* Perform sanity checks on resumed compression algorithm */
+        /* Can't disable compression */
+        if (!ssl_allow_compression(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_INCONSISTENT_COMPRESSION);
+            goto f_err;
+        }
+        /* Look for resumed compression method */
+        for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            if (comp_id == comp->id) {
+                s->s3->tmp.new_compression = comp;
+                break;
+            }
+        }
+        if (s->s3->tmp.new_compression == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_INVALID_COMPRESSION_ALGORITHM);
+            goto f_err;
+        }
+        /* Look for resumed method in compression list */
+        for (k = 0; k < complen; k++) {
+            if (PACKET_data(&compression)[k] == comp_id)
+                break;
+        }
+        if (k >= complen) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
+            goto f_err;
+        }
+    } else if (s->hit)
+        comp = NULL;
+    else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
+        /* See if we have a match */
+        int m, nn, v, done = 0;
+        unsigned int o;
+
+        nn = sk_SSL_COMP_num(s->ctx->comp_methods);
+        for (m = 0; m < nn; m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            v = comp->id;
+            for (o = 0; o < complen; o++) {
+                if (v == PACKET_data(&compression)[o]) {
+                    done = 1;
+                    break;
+                }
+            }
+            if (done)
+                break;
+        }
+        if (done)
+            s->s3->tmp.new_compression = comp;
+        else
+            comp = NULL;
+    }
+#else
+    /*
+     * If compression is disabled we'd better not try to resume a session
+     * using compression.
+     */
+    if (s->session->compress_meth != 0) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
+        goto f_err;
+    }
+#endif
+
+    /*
+     * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
+     */
+
+    if (!s->hit) {
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
+#endif
+        sk_SSL_CIPHER_free(s->session->ciphers);
+        s->session->ciphers = ciphers;
+        if (ciphers == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        ciphers = NULL;
+        if (!tls1_set_server_sigalgs(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+            goto err;
+        }
+    }
+
+    sk_SSL_CIPHER_free(ciphers);
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    ossl_statem_set_error(s);
+
+    sk_SSL_CIPHER_free(ciphers);
+    return MSG_PROCESS_ERROR;
+
+}
+
+WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
+{
+    int al = SSL_AD_HANDSHAKE_FAILURE;
+    SSL_CIPHER *cipher;
+
+    if (wst == WORK_MORE_A) {
+        if (!s->hit) {
+            /* Let cert callback update server certificates if required */
+            if (s->cert->cert_cb) {
+                int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+                if (rv == 0) {
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CERT_CB_ERROR);
+                    goto f_err;
+                }
+                if (rv < 0) {
+                    s->rwstate = SSL_X509_LOOKUP;
+                    return WORK_MORE_A;
+                }
+                s->rwstate = SSL_NOTHING;
+            }
+            cipher = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+
+            if (cipher == NULL) {
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
+                goto f_err;
+            }
+            s->s3->tmp.new_cipher = cipher;
+            /* check whether we should disable session resumption */
+            if (s->not_resumable_session_cb != NULL)
+                s->session->not_resumable = s->not_resumable_session_cb(s,
+                    ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
+            if (s->session->not_resumable)
+                /* do not send a session ticket */
+                s->tlsext_ticket_expected = 0;
+        } else {
+            /* Session-id reuse */
+            s->s3->tmp.new_cipher = s->session->cipher;
+        }
+
+        if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
+            if (!ssl3_digest_cached_records(s, 0)) {
+                al = SSL_AD_INTERNAL_ERROR;
+                goto f_err;
+            }
+        }
+
+        /*-
+         * we now have the following setup.
+         * client_random
+         * cipher_list          - our prefered list of ciphers
+         * ciphers              - the clients prefered list of ciphers
+         * compression          - basically ignored right now
+         * ssl version is set   - sslv3
+         * s->session           - The ssl session has been setup.
+         * s->hit               - session reuse flag
+         * s->s3->tmp.new_cipher- the new cipher to use.
+         */
+
+        /* Handles TLS extensions that we couldn't check earlier */
+        if (s->version >= SSL3_VERSION) {
+            if (ssl_check_clienthello_tlsext_late(s) <= 0) {
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                       SSL_R_CLIENTHELLO_TLSEXT);
+                goto f_err;
+            }
+        }
+
+        wst = WORK_MORE_B;
+    }
+#ifndef OPENSSL_NO_SRP
+    if (wst == WORK_MORE_B) {
+        int ret;
+        if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) {
+            /*
+             * callback indicates further work to be done
+             */
+            s->rwstate = SSL_X509_LOOKUP;
+            return WORK_MORE_B;
+        }
+        if (ret != SSL_ERROR_NONE) {
+            /*
+             * This is not really an error but the only means to for
+             * a client to detect whether srp is supported.
+             */
+            if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                           SSL_R_CLIENTHELLO_TLSEXT);
+            goto f_err;
+        }
+    }
+#endif
+    s->renegotiate = 2;
+
+    return WORK_FINISHED_STOP;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    return WORK_ERROR;
+}
+
+int tls_construct_server_hello(SSL *s)
+{
+    unsigned char *buf;
+    unsigned char *p, *d;
+    int i, sl;
+    int al = 0;
+    unsigned long l;
+
+    buf = (unsigned char *)s->init_buf->data;
+
+    /* Do the message type and length last */
+    d = p = ssl_handshake_start(s);
+
+    *(p++) = s->version >> 8;
+    *(p++) = s->version & 0xff;
+
+    /*
+     * Random stuff. Filling of the server_random takes place in
+     * tls_process_client_hello()
+     */
+    memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
+    p += SSL3_RANDOM_SIZE;
+
+    /*-
+     * There are several cases for the session ID to send
+     * back in the server hello:
+     * - For session reuse from the session cache,
+     *   we send back the old session ID.
+     * - If stateless session reuse (using a session ticket)
+     *   is successful, we send back the client's "session ID"
+     *   (which doesn't actually identify the session).
+     * - If it is a new session, we send back the new
+     *   session ID.
+     * - However, if we want the new session to be single-use,
+     *   we send back a 0-length session ID.
+     * s->hit is non-zero in either case of session reuse,
+     * so the following won't overwrite an ID that we're supposed
+     * to send back.
+     */
+    if (s->session->not_resumable ||
+        (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+         && !s->hit))
+        s->session->session_id_length = 0;
+
+    sl = s->session->session_id_length;
+    if (sl > (int)sizeof(s->session->session_id)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+    *(p++) = sl;
+    memcpy(p, s->session->session_id, sl);
+    p += sl;
+
+    /* put the cipher */
+    i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p);
+    p += i;
+
+    /* put the compression method */
+#ifdef OPENSSL_NO_COMP
+    *(p++) = 0;
+#else
+    if (s->s3->tmp.new_compression == NULL)
+        *(p++) = 0;
+    else
+        *(p++) = s->s3->tmp.new_compression->id;
+#endif
+
+    if (ssl_prepare_serverhello_tlsext(s) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+    if ((p =
+         ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
+                                    &al)) == NULL) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    /* do the header */
+    l = (p - d);
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_server_done(SSL *s)
+{
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_DONE, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    if (!s->s3->tmp.cert_request) {
+        if (!ssl3_digest_cached_records(s, 0)) {
+            ossl_statem_set_error(s);
+        }
+    }
+
+    return 1;
+}
+
+int tls_construct_server_key_exchange(SSL *s)
+{
+#ifndef OPENSSL_NO_RSA
+    unsigned char *q;
+    int j, num;
+    RSA *rsa;
+    unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+    unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+    DH *dh = NULL, *dhp;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *ecdh = NULL, *ecdhp;
+    unsigned char *encodedPoint = NULL;
+    int encodedlen = 0;
+    int curve_id = 0;
+    BN_CTX *bn_ctx = NULL;
+#endif
+    EVP_PKEY *pkey;
+    const EVP_MD *md = NULL;
+    unsigned char *p, *d;
+    int al, i;
+    unsigned long type;
+    int n;
+    CERT *cert;
+    BIGNUM *r[4];
+    int nr[4], kn;
+    BUF_MEM *buf;
+    EVP_MD_CTX md_ctx;
+
+    EVP_MD_CTX_init(&md_ctx);
+
+    type = s->s3->tmp.new_cipher->algorithm_mkey;
+    cert = s->cert;
+
+    buf = s->init_buf;
+
+    r[0] = r[1] = r[2] = r[3] = NULL;
+    n = 0;
+#ifndef OPENSSL_NO_PSK
+    if (type & SSL_PSK) {
+        /*
+         * reserve size for record length and PSK identity hint
+         */
+        n += 2;
+        if (s->cert->psk_identity_hint)
+            n += strlen(s->cert->psk_identity_hint);
+    }
+    /* Plain PSK or RSAPSK nothing to do */
+    if (type & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else
+#endif                          /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_RSA
+    if (type & SSL_kRSA) {
+        rsa = cert->rsa_tmp;
+        if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) {
+            rsa = s->cert->rsa_tmp_cb(s,
+                                      SSL_C_IS_EXPORT(s->s3->
+                                                      tmp.new_cipher),
+                                      SSL_C_EXPORT_PKEYLENGTH(s->s3->
+                                                              tmp.new_cipher));
+            if (rsa == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+                goto f_err;
+            }
+            RSA_up_ref(rsa);
+            cert->rsa_tmp = rsa;
+        }
+        if (rsa == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_RSA_KEY);
+            goto f_err;
+        }
+        r[0] = rsa->n;
+        r[1] = rsa->e;
+        s->s3->tmp.use_rsa_tmp = 1;
+    } else
+#endif
+#ifndef OPENSSL_NO_DH
+    if (type & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (s->cert->dh_tmp_auto) {
+            dhp = ssl_get_auto_dh(s);
+            if (dhp == NULL) {
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+        } else
+            dhp = cert->dh_tmp;
+        if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+            dhp = s->cert->dh_tmp_cb(s,
+                                     SSL_C_IS_EXPORT(s->s3->
+                                                     tmp.new_cipher),
+                                     SSL_C_EXPORT_PKEYLENGTH(s->s3->
+                                                             tmp.new_cipher));
+        if (dhp == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_DH_KEY);
+            goto f_err;
+        }
+        if (!ssl_security(s, SSL_SECOP_TMP_DH,
+                          DH_security_bits(dhp), 0, dhp)) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_DH_KEY_TOO_SMALL);
+            goto f_err;
+        }
+        if (s->s3->tmp.dh != NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (s->cert->dh_tmp_auto)
+            dh = dhp;
+        else if ((dh = DHparams_dup(dhp)) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+            goto err;
+        }
+
+        s->s3->tmp.dh = dh;
+        if ((dhp->pub_key == NULL ||
+             dhp->priv_key == NULL ||
+             (s->options & SSL_OP_SINGLE_DH_USE))) {
+            if (!DH_generate_key(dh)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
+            }
+        } else {
+            dh->pub_key = BN_dup(dhp->pub_key);
+            dh->priv_key = BN_dup(dhp->priv_key);
+            if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
+            }
+        }
+        r[0] = dh->p;
+        r[1] = dh->g;
+        r[2] = dh->pub_key;
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        const EC_GROUP *group;
+
+        ecdhp = cert->ecdh_tmp;
+        if (s->cert->ecdh_tmp_auto) {
+            /* Get NID of appropriate shared curve */
+            int nid = tls1_shared_curve(s, -2);
+            if (nid != NID_undef)
+                ecdhp = EC_KEY_new_by_curve_name(nid);
+        } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) {
+            ecdhp = s->cert->ecdh_tmp_cb(s,
+                                         SSL_C_IS_EXPORT(s->s3->
+                                                         tmp.new_cipher),
+                                         SSL_C_EXPORT_PKEYLENGTH(s->
+                                                                 s3->tmp.new_cipher));
+        }
+        if (ecdhp == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_ECDH_KEY);
+            goto f_err;
+        }
+
+        if (s->s3->tmp.ecdh != NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* Duplicate the ECDH structure. */
+        if (ecdhp == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+        if (s->cert->ecdh_tmp_auto)
+            ecdh = ecdhp;
+        else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        s->s3->tmp.ecdh = ecdh;
+        if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+            (EC_KEY_get0_private_key(ecdh) == NULL) ||
+            (s->options & SSL_OP_SINGLE_ECDH_USE)) {
+            if (!EC_KEY_generate_key(ecdh)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       ERR_R_ECDH_LIB);
+                goto err;
+            }
+        }
+
+        if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+            (EC_KEY_get0_public_key(ecdh) == NULL) ||
+            (EC_KEY_get0_private_key(ecdh) == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+            (EC_GROUP_get_degree(group) > 163)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+            goto err;
+        }
+
+        /*
+         * XXX: For now, we only support ephemeral ECDH keys over named
+         * (not generic) curves. For supported named curves, curve_id is
+         * non-zero.
+         */
+        if ((curve_id =
+             tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
+            == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+            goto err;
+        }
+
+        /*
+         * Encode the public key. First check the size of encoding and
+         * allocate memory accordingly.
+         */
+        encodedlen = EC_POINT_point2oct(group,
+                                        EC_KEY_get0_public_key(ecdh),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        NULL, 0, NULL);
+
+        encodedPoint = (unsigned char *)
+            OPENSSL_malloc(encodedlen * sizeof(unsigned char));
+        bn_ctx = BN_CTX_new();
+        if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        encodedlen = EC_POINT_point2oct(group,
+                                        EC_KEY_get0_public_key(ecdh),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        encodedPoint, encodedlen, bn_ctx);
+
+        if (encodedlen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        BN_CTX_free(bn_ctx);
+        bn_ctx = NULL;
+
+        /*
+         * XXX: For now, we only support named (not generic) curves in
+         * ECDH ephemeral key exchanges. In this situation, we need four
+         * additional bytes to encode the entire ServerECDHParams
+         * structure.
+         */
+        n += 4 + encodedlen;
+
+        /*
+         * We'll generate the serverKeyExchange message explicitly so we
+         * can set these to NULLs
+         */
+        r[0] = NULL;
+        r[1] = NULL;
+        r[2] = NULL;
+        r[3] = NULL;
+    } else
+#endif                          /* !OPENSSL_NO_EC */
+#ifndef OPENSSL_NO_SRP
+    if (type & SSL_kSRP) {
+        if ((s->srp_ctx.N == NULL) ||
+            (s->srp_ctx.g == NULL) ||
+            (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_SRP_PARAM);
+            goto err;
+        }
+        r[0] = s->srp_ctx.N;
+        r[1] = s->srp_ctx.g;
+        r[2] = s->srp_ctx.s;
+        r[3] = s->srp_ctx.B;
+    } else
+#endif
+    {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+               SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+        goto f_err;
+    }
+    for (i = 0; i < 4 && r[i] != NULL; i++) {
+        nr[i] = BN_num_bytes(r[i]);
+#ifndef OPENSSL_NO_SRP
+        if ((i == 2) && (type & SSL_kSRP))
+            n += 1 + nr[i];
+        else
+#endif
+            n += 2 + nr[i];
+    }
+
+    if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP))
+        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
+        if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
+            == NULL) {
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+        kn = EVP_PKEY_size(pkey);
+    } else {
+        pkey = NULL;
+        kn = 0;
+    }
+
+    if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_BUF);
+        goto err;
+    }
+    d = p = ssl_handshake_start(s);
+
+#ifndef OPENSSL_NO_PSK
+    if (type & SSL_PSK) {
+        /* copy PSK identity hint */
+        if (s->cert->psk_identity_hint) {
+            s2n(strlen(s->cert->psk_identity_hint), p);
+            strncpy((char *)p, s->cert->psk_identity_hint,
+                    strlen(s->cert->psk_identity_hint));
+            p += strlen(s->cert->psk_identity_hint);
+        } else {
+            s2n(0, p);
+        }
+    }
+#endif
+
+    for (i = 0; i < 4 && r[i] != NULL; i++) {
+#ifndef OPENSSL_NO_SRP
+        if ((i == 2) && (type & SSL_kSRP)) {
+            *p = nr[i];
+            p++;
+        } else
+#endif
+            s2n(nr[i], p);
+        BN_bn2bin(r[i], p);
+        p += nr[i];
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        /*
+         * XXX: For now, we only support named (not generic) curves. In
+         * this situation, the serverKeyExchange message has: [1 byte
+         * CurveType], [2 byte CurveName] [1 byte length of encoded
+         * point], followed by the actual encoded point itself
+         */
+        *p = NAMED_CURVE_TYPE;
+        p += 1;
+        *p = 0;
+        p += 1;
+        *p = curve_id;
+        p += 1;
+        *p = encodedlen;
+        p += 1;
+        memcpy(p, encodedPoint, encodedlen);
+        OPENSSL_free(encodedPoint);
+        encodedPoint = NULL;
+        p += encodedlen;
+    }
+#endif
+
+    /* not anonymous */
+    if (pkey != NULL) {
+        /*
+         * n is the length of the params, they start at &(d[4]) and p
+         * points to the space at the end.
+         */
+#ifndef OPENSSL_NO_RSA
+        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
+            q = md_buf;
+            j = 0;
+            for (num = 2; num > 0; num--) {
+                EVP_MD_CTX_set_flags(&md_ctx,
+                                     EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+                EVP_DigestInit_ex(&md_ctx, (num == 2)
+                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, d, n);
+                EVP_DigestFinal_ex(&md_ctx, q, (unsigned int *)&i);
+                q += i;
+                j += i;
+            }
+            if (RSA_sign(NID_md5_sha1, md_buf, j,
+                         &(p[2]), &u, pkey->pkey.rsa) <= 0) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_RSA);
+                goto err;
+            }
+            s2n(u, p);
+            n += u + 2;
+        } else
+#endif
+        if (md) {
+            /* send signature algorithm */
+            if (SSL_USE_SIGALGS(s)) {
+                if (!tls12_get_sigandhash(p, pkey, md)) {
+                    /* Should never happen */
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                           ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+                p += 2;
+            }
+#ifdef SSL_DEBUG
+            fprintf(stderr, "Using hash %s\n", EVP_MD_name(md));
+#endif
+            EVP_SignInit_ex(&md_ctx, md, NULL);
+            EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
+                           SSL3_RANDOM_SIZE);
+            EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
+                           SSL3_RANDOM_SIZE);
+            EVP_SignUpdate(&md_ctx, d, n);
+            if (!EVP_SignFinal(&md_ctx, &(p[2]),
+                               (unsigned int *)&i, pkey)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_EVP);
+                goto err;
+            }
+            s2n(i, p);
+            n += i + 2;
+            if (SSL_USE_SIGALGS(s))
+                n += 2;
+        } else {
+            /* Is this error check actually needed? */
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_UNKNOWN_PKEY_TYPE);
+            goto f_err;
+        }
+    }
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
+
+    EVP_MD_CTX_cleanup(&md_ctx);
+    return 1;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+#ifndef OPENSSL_NO_EC
+    OPENSSL_free(encodedPoint);
+    BN_CTX_free(bn_ctx);
+#endif
+    EVP_MD_CTX_cleanup(&md_ctx);
+    ossl_statem_set_error(s);
+    return 0;
+}
+
+int tls_construct_certificate_request(SSL *s)
+{
+    unsigned char *p, *d;
+    int i, j, nl, off, n;
+    STACK_OF(X509_NAME) *sk = NULL;
+    X509_NAME *name;
+    BUF_MEM *buf;
+
+    buf = s->init_buf;
+
+    d = p = ssl_handshake_start(s);
+
+    /* get the list of acceptable cert types */
+    p++;
+    n = ssl3_get_req_cert_type(s, p);
+    d[0] = n;
+    p += n;
+    n++;
+
+    if (SSL_USE_SIGALGS(s)) {
+        const unsigned char *psigs;
+        unsigned char *etmp = p;
+        nl = tls12_get_psigalgs(s, &psigs);
+        /* Skip over length for now */
+        p += 2;
+        nl = tls12_copy_sigalgs(s, p, psigs, nl);
+        /* Now fill in length */
+        s2n(nl, etmp);
+        p += nl;
+        n += nl + 2;
+    }
+
+    off = n;
+    p += 2;
+    n += 2;
+
+    sk = SSL_get_client_CA_list(s);
+    nl = 0;
+    if (sk != NULL) {
+        for (i = 0; i < sk_X509_NAME_num(sk); i++) {
+            name = sk_X509_NAME_value(sk, i);
+            j = i2d_X509_NAME(name, NULL);
+            if (!BUF_MEM_grow_clean
+                (buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                       ERR_R_BUF_LIB);
+                goto err;
+            }
+            p = ssl_handshake_start(s) + n;
+            s2n(j, p);
+            i2d_X509_NAME(name, &p);
+            n += 2 + j;
+            nl += 2 + j;
+        }
+    }
+    /* else no CA names */
+    p = ssl_handshake_start(s) + off;
+    s2n(nl, p);
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->s3->tmp.cert_request = 1;
+
+    return 1;
+ err:
+    ossl_statem_set_error(s);
+    return 0;
+}
+
+MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
+{
+    int al;
+    unsigned int i;
+    unsigned long alg_k;
+#ifndef OPENSSL_NO_RSA
+    RSA *rsa = NULL;
+    EVP_PKEY *pkey = NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+    BIGNUM *pub = NULL;
+    DH *dh_srvr, *dh_clnt = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *srvr_ecdh = NULL;
+    EVP_PKEY *clnt_pub_pkey = NULL;
+    EC_POINT *clnt_ecpoint = NULL;
+    BN_CTX *bn_ctx = NULL;
+#endif
+    PACKET enc_premaster;
+    unsigned char *data, *rsa_decrypt = NULL;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_PSK
+    /* For PSK parse and retrieve identity, obtain PSK key */
+    if (alg_k & SSL_PSK) {
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen;
+        PACKET psk_identity;
+
+        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DATA_LENGTH_TOO_LONG);
+            goto f_err;
+        }
+        if (s->psk_server_callback == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_NO_SERVER_CB);
+            goto f_err;
+        }
+
+        if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        psklen = s->psk_server_callback(s, s->session->psk_identity,
+                                         psk, sizeof(psk));
+
+        if (psklen > PSK_MAX_PSK_LEN) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        } else if (psklen == 0) {
+            /*
+             * PSK related to the given identity not found
+             */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_IDENTITY_NOT_FOUND);
+            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+            goto f_err;
+        }
+
+        OPENSSL_free(s->s3->tmp.psk);
+        s->s3->tmp.psk = BUF_memdup(psk, psklen);
+        OPENSSL_cleanse(psk, psklen);
+
+        if (s->s3->tmp.psk == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        s->s3->tmp.psklen = psklen;
+    }
+    if (alg_k & SSL_kPSK) {
+        /* Identity extracted earlier: should be nothing left */
+        if (PACKET_remaining(pkt) != 0) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        /* PSK handled by ssl_generate_master_secret */
+        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_RSA
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+        int decrypt_len;
+        unsigned char decrypt_good, version_good;
+        size_t j;
+
+        /* FIX THIS UP EAY EAY EAY EAY */
+        if (s->s3->tmp.use_rsa_tmp) {
+            if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
+                rsa = s->cert->rsa_tmp;
+            /*
+             * Don't do a callback because rsa_tmp should be sent already
+             */
+            if (rsa == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_RSA_PKEY);
+                goto f_err;
+
+            }
+        } else {
+            pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+            if ((pkey == NULL) ||
+                (pkey->type != EVP_PKEY_RSA) || (pkey->pkey.rsa == NULL)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_RSA_CERTIFICATE);
+                goto f_err;
+            }
+            rsa = pkey->pkey.rsa;
+        }
+
+        /* SSLv3 and pre-standard DTLS omit the length bytes. */
+        if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) {
+            enc_premaster = *pkt;
+        } else {
+            PACKET orig = *pkt;
+            if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster)
+                || PACKET_remaining(pkt) != 0) {
+                /* Try SSLv3 behaviour for TLS. */
+                if (s->options & SSL_OP_TLS_D5_BUG) {
+                    enc_premaster = orig;
+                } else {
+                    al = SSL_AD_DECODE_ERROR;
+                    SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                           SSL_R_LENGTH_MISMATCH);
+                    goto f_err;
+                }
+            }
+        }
+
+        /*
+         * We want to be sure that the plaintext buffer size makes it safe to
+         * iterate over the entire size of a premaster secret
+         * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
+         * their ciphertext cannot accommodate a premaster secret anyway.
+         */
+        if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   RSA_R_KEY_SIZE_TOO_SMALL);
+            goto f_err;
+        }
+
+        rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
+        if (rsa_decrypt == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        /*
+         * We must not leak whether a decryption failure occurs because of
+         * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
+         * section 7.4.7.1). The code follows that advice of the TLS RFC and
+         * generates a random premaster secret for the case that the decrypt
+         * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
+         */
+
+        if (RAND_bytes(rand_premaster_secret,
+                       sizeof(rand_premaster_secret)) <= 0) {
+            goto err;
+        }
+
+        decrypt_len = RSA_private_decrypt(PACKET_remaining(&enc_premaster),
+                                          PACKET_data(&enc_premaster),
+                                          rsa_decrypt, rsa, RSA_PKCS1_PADDING);
+        ERR_clear_error();
+
+        /*
+         * decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH. decrypt_good will
+         * be 0xff if so and zero otherwise.
+         */
+        decrypt_good =
+            constant_time_eq_int_8(decrypt_len, SSL_MAX_MASTER_KEY_LENGTH);
+
+        /*
+         * If the version in the decrypted pre-master secret is correct then
+         * version_good will be 0xff, otherwise it'll be zero. The
+         * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+         * (http://eprint.iacr.org/2003/052/) exploits the version number
+         * check as a "bad version oracle". Thus version checks are done in
+         * constant time and are treated like any other decryption error.
+         */
+        version_good =
+            constant_time_eq_8(rsa_decrypt[0],
+                               (unsigned)(s->client_version >> 8));
+        version_good &=
+            constant_time_eq_8(rsa_decrypt[1],
+                               (unsigned)(s->client_version & 0xff));
+
+        /*
+         * The premaster secret must contain the same version number as the
+         * ClientHello to detect version rollback attacks (strangely, the
+         * protocol does not offer such protection for DH ciphersuites).
+         * However, buggy clients exist that send the negotiated protocol
+         * version instead if the server does not support the requested
+         * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
+         * clients.
+         */
+        if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
+            unsigned char workaround_good;
+            workaround_good =
+                constant_time_eq_8(rsa_decrypt[0], (unsigned)(s->version >> 8));
+            workaround_good &=
+                constant_time_eq_8(rsa_decrypt[1],
+                                   (unsigned)(s->version & 0xff));
+            version_good |= workaround_good;
+        }
+
+        /*
+         * Both decryption and version must be good for decrypt_good to
+         * remain non-zero (0xff).
+         */
+        decrypt_good &= version_good;
+
+        /*
+         * Now copy rand_premaster_secret over from p using
+         * decrypt_good_mask. If decryption failed, then p does not
+         * contain valid plaintext, however, a check above guarantees
+         * it is still sufficiently large to read from.
+         */
+        for (j = 0; j < sizeof(rand_premaster_secret); j++) {
+            rsa_decrypt[j] =
+                constant_time_select_8(decrypt_good, rsa_decrypt[j],
+                                       rand_premaster_secret[j]);
+        }
+
+        if (!ssl_generate_master_secret(s, rsa_decrypt,
+                                        sizeof(rand_premaster_secret), 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        OPENSSL_free(rsa_decrypt);
+        rsa_decrypt = NULL;
+    } else
+#endif
+#ifndef OPENSSL_NO_DH
+    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
+        int idx = -1;
+        EVP_PKEY *skey = NULL;
+        PACKET bookmark = *pkt;
+        unsigned char shared[(OPENSSL_DH_MAX_MODULUS_BITS + 7) / 8];
+
+        if (!PACKET_get_net_2(pkt, &i)) {
+            if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+                goto f_err;
+            }
+            i = 0;
+        }
+        if (PACKET_remaining(pkt) != i) {
+            if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+                goto err;
+            } else {
+                *pkt = bookmark;
+                i = PACKET_remaining(pkt);
+            }
+        }
+        if (alg_k & SSL_kDHr)
+            idx = SSL_PKEY_DH_RSA;
+        else if (alg_k & SSL_kDHd)
+            idx = SSL_PKEY_DH_DSA;
+        if (idx >= 0) {
+            skey = s->cert->pkeys[idx].privatekey;
+            if ((skey == NULL) ||
+                (skey->type != EVP_PKEY_DH) || (skey->pkey.dh == NULL)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_RSA_CERTIFICATE);
+                goto f_err;
+            }
+            dh_srvr = skey->pkey.dh;
+        } else if (s->s3->tmp.dh == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_DH_KEY);
+            goto f_err;
+        } else
+            dh_srvr = s->s3->tmp.dh;
+
+        if (PACKET_remaining(pkt) == 0L) {
+            /* Get pubkey from cert */
+            EVP_PKEY *clkey = X509_get_pubkey(s->session->peer);
+            if (clkey) {
+                if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
+                    dh_clnt = EVP_PKEY_get1_DH(clkey);
+            }
+            if (dh_clnt == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_DH_KEY);
+                goto f_err;
+            }
+            EVP_PKEY_free(clkey);
+            pub = dh_clnt->pub_key;
+        } else {
+            if (!PACKET_get_bytes(pkt, &data, i)) {
+                /* We already checked we have enough data */
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+            pub = BN_bin2bn(data, i, NULL);
+        }
+        if (pub == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
+            goto err;
+        }
+
+        i = DH_compute_key(shared, pub, dh_srvr);
+
+        if (i <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+            BN_clear_free(pub);
+            goto err;
+        }
+
+        DH_free(s->s3->tmp.dh);
+        s->s3->tmp.dh = NULL;
+        if (dh_clnt)
+            DH_free(dh_clnt);
+        else
+            BN_clear_free(pub);
+        pub = NULL;
+        if (!ssl_generate_master_secret(s, shared, i, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        if (dh_clnt) {
+            s->statem.no_cert_verify = 1;
+            return MSG_PROCESS_CONTINUE_PROCESSING;
+        }
+    } else
+#endif
+
+#ifndef OPENSSL_NO_EC
+    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
+        int field_size = 0;
+        const EC_KEY *tkey;
+        const EC_GROUP *group;
+        const BIGNUM *priv_key;
+        unsigned char *shared;
+
+        /* initialize structures for server's ECDH key pair */
+        if ((srvr_ecdh = EC_KEY_new()) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        /* Let's get server private key and group information */
+        if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
+            /* use the certificate */
+            tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+        } else {
+            /*
+             * use the ephermeral values we saved when generating the
+             * ServerKeyExchange msg.
+             */
+            tkey = s->s3->tmp.ecdh;
+        }
+
+        group = EC_KEY_get0_group(tkey);
+        priv_key = EC_KEY_get0_private_key(tkey);
+
+        if (!EC_KEY_set_group(srvr_ecdh, group) ||
+            !EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+
+        /* Let's get client's public key */
+        if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (PACKET_remaining(pkt) == 0L) {
+            /* Client Publickey was in Client Certificate */
+
+            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_ECDH_KEY);
+                goto f_err;
+            }
+            if (((clnt_pub_pkey = X509_get_pubkey(s->session->peer))
+                 == NULL) || (clnt_pub_pkey->type != EVP_PKEY_EC)) {
+                /*
+                 * XXX: For now, we do not support client authentication
+                 * using ECDH certificates so this branch (n == 0L) of the
+                 * code is never executed. When that support is added, we
+                 * ought to ensure the key received in the certificate is
+                 * authorized for key agreement. ECDH_compute_key implicitly
+                 * checks that the two ECDH shares are for the same group.
+                 */
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+                goto f_err;
+            }
+
+            if (EC_POINT_copy(clnt_ecpoint,
+                              EC_KEY_get0_public_key(clnt_pub_pkey->
+                                                     pkey.ec)) == 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+            s->statem.no_cert_verify = 1;
+        } else {
+            /*
+             * Get client's public key from encoded point in the
+             * ClientKeyExchange message.
+             */
+            if ((bn_ctx = BN_CTX_new()) == NULL) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+
+            /* Get encoded point length */
+            if (!PACKET_get_1(pkt, &i)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+            }
+            if (!PACKET_get_bytes(pkt, &data, i)
+                    || PACKET_remaining(pkt) != 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+        }
+
+        /* Compute the shared pre-master secret */
+        field_size = EC_GROUP_get_degree(group);
+        if (field_size <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+        shared = OPENSSL_malloc((field_size + 7) / 8);
+        if (shared == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
+                             srvr_ecdh, NULL);
+        if (i <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            OPENSSL_free(shared);
+            goto err;
+        }
+
+        EVP_PKEY_free(clnt_pub_pkey);
+        EC_POINT_free(clnt_ecpoint);
+        EC_KEY_free(srvr_ecdh);
+        BN_CTX_free(bn_ctx);
+        EC_KEY_free(s->s3->tmp.ecdh);
+        s->s3->tmp.ecdh = NULL;
+
+        if (!ssl_generate_master_secret(s, shared, i, 1)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+    } else
+#endif
+#ifndef OPENSSL_NO_SRP
+    if (alg_k & SSL_kSRP) {
+        if (!PACKET_get_net_2(pkt, &i)
+                || !PACKET_get_bytes(pkt, &data, i)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BAD_SRP_A_LENGTH);
+            goto f_err;
+        }
+        if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB);
+            goto err;
+        }
+        if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0
+            || BN_is_zero(s->srp_ctx.A)) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_BAD_SRP_PARAMETERS);
+            goto f_err;
+        }
+        OPENSSL_free(s->session->srp_username);
+        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+        if (s->session->srp_username == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (!srp_generate_server_master_secret(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else
+#endif                          /* OPENSSL_NO_SRP */
+    if (alg_k & SSL_kGOST) {
+        EVP_PKEY_CTX *pkey_ctx;
+        EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+        unsigned char premaster_secret[32], *start;
+        size_t outlen = 32, inlen;
+        unsigned long alg_a;
+        int Ttag, Tclass;
+        long Tlen;
+        long sess_key_len;
+
+        /* Get our certificate private key */
+        alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+        if (alg_a & SSL_aGOST01)
+            pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+
+        pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
+        EVP_PKEY_decrypt_init(pkey_ctx);
+        /*
+         * If client certificate is present and is of the same type, maybe
+         * use it for key exchange.  Don't mind errors from
+         * EVP_PKEY_derive_set_peer, because it is completely valid to use a
+         * client certificate for authorization only.
+         */
+        client_pub_pkey = X509_get_pubkey(s->session->peer);
+        if (client_pub_pkey) {
+            if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+                ERR_clear_error();
+        }
+        /* Decrypt session key */
+        sess_key_len = PACKET_remaining(pkt);
+        if (!PACKET_get_bytes(pkt, &data, sess_key_len)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        if (ASN1_get_object ((const unsigned char **)&data, &Tlen, &Ttag,
+                             &Tclass, sess_key_len) != V_ASN1_CONSTRUCTED
+            || Ttag != V_ASN1_SEQUENCE
+            || Tclass != V_ASN1_UNIVERSAL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DECRYPTION_FAILED);
+            goto gerr;
+        }
+        start = data;
+        inlen = Tlen;
+        if (EVP_PKEY_decrypt
+            (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DECRYPTION_FAILED);
+            goto gerr;
+        }
+        /* Generate master secret */
+        if (!ssl_generate_master_secret(s, premaster_secret,
+                                        sizeof(premaster_secret), 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        /* Check if pubkey from client certificate was used */
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+            s->statem.no_cert_verify = 1;
+
+        EVP_PKEY_free(client_pub_pkey);
+        EVP_PKEY_CTX_free(pkey_ctx);
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+ gerr:
+        EVP_PKEY_free(client_pub_pkey);
+        EVP_PKEY_CTX_free(pkey_ctx);
+        goto err;
+    } else {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_UNKNOWN_CIPHER_TYPE);
+        goto f_err;
+    }
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_SRP)
+ err:
+#endif
+#ifndef OPENSSL_NO_EC
+    EVP_PKEY_free(clnt_pub_pkey);
+    EC_POINT_free(clnt_ecpoint);
+    EC_KEY_free(srvr_ecdh);
+    BN_CTX_free(bn_ctx);
+    OPENSSL_free(rsa_decrypt);
+#endif
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
+#endif
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst)
+{
+#ifndef OPENSSL_NO_SCTP
+    if (wst == WORK_MORE_A) {
+        if (SSL_IS_DTLS(s)) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+             * used.
+             */
+            memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL,
+                   sizeof(DTLS1_SCTP_AUTH_LABEL));
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                                       sizeof(sctpauthkey), labelbuffer,
+                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                ossl_statem_set_error(s);
+                return WORK_ERROR;;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+        wst = WORK_MORE_B;
+    }
+
+    if ((wst == WORK_MORE_B)
+            /* Is this SCTP? */
+            && BIO_dgram_is_sctp(SSL_get_wbio(s))
+            /* Are we renegotiating? */
+            && s->renegotiate
+            /* Are we going to skip the CertificateVerify? */
+            && (s->session->peer == NULL || s->statem.no_cert_verify)
+            && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+        s->s3->in_read_app_data = 2;
+        s->rwstate = SSL_READING;
+        BIO_clear_retry_flags(SSL_get_rbio(s));
+        BIO_set_retry_read(SSL_get_rbio(s));
+        statem_set_sctp_read_sock(s, 1);
+        return WORK_MORE_B;
+    } else {
+        ossl_statem_set_sctp_read_sock(s, 0);
+    }
+#endif
+
+    if (s->statem.no_cert_verify) {
+        /* No certificate verify so we no longer need the handshake_buffer */
+        BIO_free(s->s3->handshake_buffer);
+        return WORK_FINISHED_CONTINUE;
+    } else if (SSL_USE_SIGALGS(s)) {
+        if (!s->session->peer) {
+            /* No peer certificate so we no longer need the handshake_buffer */
+            BIO_free(s->s3->handshake_buffer);
+            return WORK_FINISHED_CONTINUE;
+        }
+        if (!s->s3->handshake_buffer) {
+            SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            ossl_statem_set_error(s);
+            return WORK_ERROR;
+        }
+        /*
+         * For sigalgs freeze the handshake buffer. If we support
+         * extms we've done this already so this is a no-op
+         */
+        if (!ssl3_digest_cached_records(s, 1)) {
+            ossl_statem_set_error(s);
+            return WORK_ERROR;
+        }
+    } else {
+        int offset = 0;
+        int dgst_num;
+
+        /*
+         * We need to get hashes here so if there is a client cert,
+         * it can be verified FIXME - digest processing for
+         * CertificateVerify should be generalized. But it is next
+         * step
+         */
+        if (!ssl3_digest_cached_records(s, 0)) {
+            ossl_statem_set_error(s);
+            return WORK_ERROR;
+        }
+        for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++) {
+            if (s->s3->handshake_dgst[dgst_num]) {
+                int dgst_size;
+
+                s->method->ssl3_enc->cert_verify_mac(s,
+                                                     EVP_MD_CTX_type
+                                                     (s->
+                                                      s3->handshake_dgst
+                                                      [dgst_num]),
+                                                     &(s->s3->
+                                                       tmp.cert_verify_md
+                                                       [offset]));
+                dgst_size =
+                    EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
+                if (dgst_size < 0) {
+                    ossl_statem_set_error(s);
+                return WORK_ERROR;
+                }
+                offset += dgst_size;
+            }
+        }
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
+{
+    EVP_PKEY *pkey = NULL;
+    unsigned char *sig, *data;
+    int al, ret = MSG_PROCESS_ERROR;
+    int type = 0, i, j;
+    unsigned int len;
+    X509 *peer;
+    const EVP_MD *md = NULL;
+    EVP_MD_CTX mctx;
+    EVP_MD_CTX_init(&mctx);
+
+    peer = s->session->peer;
+    pkey = X509_get_pubkey(peer);
+    type = X509_certificate_type(peer, pkey);
+
+    if (!(type & EVP_PKT_SIGN)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY,
+               SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        goto f_err;
+    }
+
+    /* Check for broken implementations of GOST ciphersuites */
+    /*
+     * If key is GOST and n is exactly 64, it is bare signature without
+     * length field
+     */
+    if (PACKET_remaining(pkt) == 64 && pkey->type == NID_id_GostR3410_2001) {
+        len = 64;
+    } else {
+        if (SSL_USE_SIGALGS(s)) {
+            int rv;
+
+            if (!PACKET_get_bytes(pkt, &sig, 2)) {
+                al = SSL_AD_DECODE_ERROR;
+                goto f_err;
+            }
+            rv = tls12_check_peer_sigalg(&md, s, sig, pkey);
+            if (rv == -1) {
+                al = SSL_AD_INTERNAL_ERROR;
+                goto f_err;
+            } else if (rv == 0) {
+                al = SSL_AD_DECODE_ERROR;
+                goto f_err;
+            }
+#ifdef SSL_DEBUG
+            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+        }
+        if (!PACKET_get_net_2(pkt, &len)) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+    }
+    j = EVP_PKEY_size(pkey);
+    if (((int)len > j) || ((int)PACKET_remaining(pkt) > j)
+            || (PACKET_remaining(pkt) == 0)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+    if (!PACKET_get_bytes(pkt, &data, len)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+
+    if (SSL_USE_SIGALGS(s)) {
+        long hdatalen = 0;
+        void *hdata;
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+#ifdef SSL_DEBUG
+        fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+                EVP_MD_name(md));
+#endif
+        if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+            || !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#ifndef OPENSSL_NO_RSA
+    if (pkey->type == EVP_PKEY_RSA) {
+        i = RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
+                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, data, len,
+                       pkey->pkey.rsa);
+        if (i < 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_DECRYPT);
+            goto f_err;
+        }
+        if (i == 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_DSA
+    if (pkey->type == EVP_PKEY_DSA) {
+        j = DSA_verify(pkey->save_type,
+                       &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+                       SHA_DIGEST_LENGTH, data, len, pkey->pkey.dsa);
+        if (j <= 0) {
+            /* bad signature */
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_DSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (pkey->type == EVP_PKEY_EC) {
+        j = ECDSA_verify(pkey->save_type,
+                         &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+                         SHA_DIGEST_LENGTH, data, len, pkey->pkey.ec);
+        if (j <= 0) {
+            /* bad signature */
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+    if (pkey->type == NID_id_GostR3410_2001) {
+        unsigned char signature[64];
+        int idx;
+        EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
+        EVP_PKEY_verify_init(pctx);
+        if (len != 64) {
+            fprintf(stderr, "GOST signature length is %d", len);
+        }
+        for (idx = 0; idx < 64; idx++) {
+            signature[63 - idx] = data[idx];
+        }
+        j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
+                            32);
+        EVP_PKEY_CTX_free(pctx);
+        if (j <= 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
+            goto f_err;
+        }
+    } else {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+        goto f_err;
+    }
+
+    ret = MSG_PROCESS_CONTINUE_PROCESSING;
+    if (0) {
+ f_err:
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        ossl_statem_set_error(s);
+    }
+    BIO_free(s->s3->handshake_buffer);
+    s->s3->handshake_buffer = NULL;
+    EVP_MD_CTX_cleanup(&mctx);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
+{
+    int i, al = SSL_AD_INTERNAL_ERROR, ret = MSG_PROCESS_ERROR;
+    X509 *x = NULL;
+    unsigned long l, llen;
+    const unsigned char *certstart;
+    unsigned char *certbytes;
+    STACK_OF(X509) *sk = NULL;
+    PACKET spkt;
+
+    if ((sk = sk_X509_new_null()) == NULL) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+        goto f_err;
+    }
+
+    if (!PACKET_get_net_3(pkt, &llen)
+            || !PACKET_get_sub_packet(pkt, &spkt, llen)
+            || PACKET_remaining(pkt) != 0) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    while (PACKET_remaining(&spkt) > 0) {
+        if (!PACKET_get_net_3(&spkt, &l)
+                || !PACKET_get_bytes(&spkt, &certbytes, l)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
+        if (x == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
+            goto f_err;
+        }
+        if (certbytes != (certstart + l)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (!sk_X509_push(sk, x)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        x = NULL;
+    }
+
+    if (sk_X509_num(sk) <= 0) {
+        /* TLS does not mind 0 certs returned */
+        if (s->version == SSL3_VERSION) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_NO_CERTIFICATES_RETURNED);
+            goto f_err;
+        }
+        /* Fail for TLS only if we required a certificate */
+        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            goto f_err;
+        }
+        /* No client certificate so digest cached records */
+        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
+            goto f_err;
+        }
+    } else {
+        EVP_PKEY *pkey;
+        i = ssl_verify_cert_chain(s, sk);
+        if (i <= 0) {
+            al = ssl_verify_alarm_type(s->verify_result);
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERTIFICATE_VERIFY_FAILED);
+            goto f_err;
+        }
+        if (i > 1) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i);
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            goto f_err;
+        }
+        pkey = X509_get_pubkey(sk_X509_value(sk, 0));
+        if (pkey == NULL) {
+            al = SSL3_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+            goto f_err;
+        }
+        EVP_PKEY_free(pkey);
+    }
+
+    X509_free(s->session->peer);
+    s->session->peer = sk_X509_shift(sk);
+    s->session->verify_result = s->verify_result;
+
+    sk_X509_pop_free(s->session->peer_chain, X509_free);
+    s->session->peer_chain = sk;
+    /*
+     * Inconsistency alert: cert_chain does *not* include the peer's own
+     * certificate, while we do include it in s3_clnt.c
+     */
+    sk = NULL;
+    ret = MSG_PROCESS_CONTINUE_READING;
+    goto done;
+
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+ done:
+    X509_free(x);
+    sk_X509_pop_free(sk, X509_free);
+    return ret;
+}
+
+int tls_construct_server_certificate(SSL *s)
+{
+    CERT_PKEY *cpk;
+
+    cpk = ssl_get_server_send_pkey(s);
+    if (cpk == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    if (!ssl3_output_cert_chain(s, cpk)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_new_session_ticket(SSL *s)
+{
+    unsigned char *senc = NULL;
+    EVP_CIPHER_CTX ctx;
+    HMAC_CTX hctx;
+    unsigned char *p, *macstart;
+    const unsigned char *const_p;
+    int len, slen_full, slen;
+    SSL_SESSION *sess;
+    unsigned int hlen;
+    SSL_CTX *tctx = s->initial_ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+    unsigned char key_name[16];
+
+    /* get session encoding length */
+    slen_full = i2d_SSL_SESSION(s->session, NULL);
+    /*
+     * Some length values are 16 bits, so forget it if session is too
+     * long
+     */
+    if (slen_full == 0 || slen_full > 0xFF00) {
+        ossl_statem_set_error(s);
+        return 0;
+    }
+    senc = OPENSSL_malloc(slen_full);
+    if (!senc) {
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    EVP_CIPHER_CTX_init(&ctx);
+    HMAC_CTX_init(&hctx);
+
+    p = senc;
+    if (!i2d_SSL_SESSION(s->session, &p))
+        goto err;
+
+    /*
+     * create a fresh copy (not shared with other threads) to clean up
+     */
+    const_p = senc;
+    sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+    if (sess == NULL)
+        goto err;
+    sess->session_id_length = 0; /* ID is irrelevant for the ticket */
+
+    slen = i2d_SSL_SESSION(sess, NULL);
+    if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    p = senc;
+    if (!i2d_SSL_SESSION(sess, &p)) {
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    SSL_SESSION_free(sess);
+
+    /*-
+     * Grow buffer if need be: the length calculation is as
+     * follows handshake_header_length +
+     * 4 (ticket lifetime hint) + 2 (ticket length) +
+     * 16 (key name) + max_iv_len (iv length) +
+     * session_length + max_enc_block_size (max encrypted session
+     * length) + max_md_size (HMAC).
+     */
+    if (!BUF_MEM_grow(s->init_buf,
+                      SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
+                      EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+        goto err;
+
+    p = ssl_handshake_start(s);
+    /*
+     * Initialize HMAC and cipher contexts. If callback present it does
+     * all the work otherwise use generated values from parent ctx.
+     */
+    if (tctx->tlsext_ticket_key_cb) {
+        if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
+                                       &hctx, 1) < 0)
+            goto err;
+    } else {
+        if (RAND_bytes(iv, 16) <= 0)
+            goto err;
+        if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+                                tctx->tlsext_tick_aes_key, iv))
+            goto err;
+        if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+                          EVP_sha256(), NULL))
+            goto err;
+        memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+    }
+
+    /*
+     * Ticket lifetime hint (advisory only): We leave this unspecified
+     * for resumed session (for simplicity), and guess that tickets for
+     * new sessions will live as long as their sessions.
+     */
+    l2n(s->hit ? 0 : s->session->timeout, p);
+
+    /* Skip ticket length for now */
+    p += 2;
+    /* Output key name */
+    macstart = p;
+    memcpy(p, key_name, 16);
+    p += 16;
+    /* output IV */
+    memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
+    p += EVP_CIPHER_CTX_iv_length(&ctx);
+    /* Encrypt session data */
+    if (!EVP_EncryptUpdate(&ctx, p, &len, senc, slen))
+        goto err;
+    p += len;
+    if (!EVP_EncryptFinal(&ctx, p, &len))
+        goto err;
+    p += len;
+
+    if (!HMAC_Update(&hctx, macstart, p - macstart))
+        goto err;
+    if (!HMAC_Final(&hctx, p, &hlen))
+        goto err;
+
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    HMAC_CTX_cleanup(&hctx);
+
+    p += hlen;
+    /* Now write out lengths: p points to end of data written */
+    /* Total length */
+    len = p - ssl_handshake_start(s);
+    /* Skip ticket lifetime hint */
+    p = ssl_handshake_start(s) + 4;
+    s2n(len - 6, p);
+    if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len))
+        goto err;
+    OPENSSL_free(senc);
+
+    return 1;
+ err:
+    OPENSSL_free(senc);
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    HMAC_CTX_cleanup(&hctx);
+    ossl_statem_set_error(s);
+    return 0;
+}
+
+int tls_construct_cert_status(SSL *s)
+{
+    unsigned char *p;
+    /*-
+     * Grow buffer if need be: the length calculation is as
+     * follows 1 (message type) + 3 (message length) +
+     * 1 (ocsp response type) + 3 (ocsp response length)
+     * + (ocsp response)
+     */
+    if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) {
+        ossl_statem_set_error(s);
+        return 0;
+    }
+
+    p = (unsigned char *)s->init_buf->data;
+
+    /* do the header */
+    *(p++) = SSL3_MT_CERTIFICATE_STATUS;
+    /* message length */
+    l2n3(s->tlsext_ocsp_resplen + 4, p);
+    /* status type */
+    *(p++) = s->tlsext_status_type;
+    /* length of OCSP response */
+    l2n3(s->tlsext_ocsp_resplen, p);
+    /* actual response */
+    memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+    /* number of bytes to write */
+    s->init_num = 8 + s->tlsext_ocsp_resplen;
+    s->init_off = 0;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * tls_process_next_proto reads a Next Protocol Negotiation handshake message.
+ * It sets the next_proto member in s if found
+ */
+MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt)
+{
+    PACKET next_proto, padding;
+    size_t next_proto_len;
+
+    /*-
+     * The payload looks like:
+     *   uint8 proto_len;
+     *   uint8 proto[proto_len];
+     *   uint8 padding_len;
+     *   uint8 padding[padding_len];
+     */
+    if (!PACKET_get_length_prefixed_1(pkt, &next_proto)
+        || !PACKET_get_length_prefixed_1(pkt, &padding)
+        || PACKET_remaining(pkt) > 0) {
+        SSLerr(SSL_F_TLS_PROCESS_NEXT_PROTO, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated,
+                       &next_proto_len)) {
+        s->next_proto_negotiated_len = 0;
+        goto err;
+    }
+
+    s->next_proto_negotiated_len = (unsigned char)next_proto_len;
+
+    return MSG_PROCESS_CONTINUE_READING;
+err:
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+#endif
+
+#define SSLV2_CIPHER_LEN    3
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
+                                               PACKET *cipher_suites,
+                                               STACK_OF(SSL_CIPHER) **skp,
+                                               int sslv2format, int *al
+                                               )
+{
+    const SSL_CIPHER *c;
+    STACK_OF(SSL_CIPHER) *sk;
+    int n;
+    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
+    unsigned char cipher[SSLV2_CIPHER_LEN];
+
+    s->s3->send_connection_binding = 0;
+
+    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
+
+    if (PACKET_remaining(cipher_suites) == 0) {
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return NULL;
+    }
+
+    if (PACKET_remaining(cipher_suites) % n != 0) {
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+               SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+        *al = SSL_AD_DECODE_ERROR;
+        return NULL;
+    }
+
+    if ((skp == NULL) || (*skp == NULL)) {
+        sk = sk_SSL_CIPHER_new_null(); /* change perhaps later */
+        if(sk == NULL) {
+            SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+            *al = SSL_AD_INTERNAL_ERROR;
+            return NULL;
+        }
+    } else {
+        sk = *skp;
+        sk_SSL_CIPHER_zero(sk);
+    }
+
+    if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
+                       &s->s3->tmp.ciphers_rawlen)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        goto err;
+    }
+
+    while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
+        /*
+         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
+         * first byte set to zero, while true SSLv2 ciphers have a non-zero
+         * first byte. We don't support any true SSLv2 ciphers, so skip them.
+         */
+        if (sslv2format && cipher[0] != '\0')
+                continue;
+
+        /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
+        if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+            (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) {
+            /* SCSV fatal if renegotiating */
+            if (s->renegotiate) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+                       SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+                *al = SSL_AD_HANDSHAKE_FAILURE;
+                goto err;
+            }
+            s->s3->send_connection_binding = 1;
+#ifdef OPENSSL_RI_DEBUG
+            fprintf(stderr, "SCSV received by server\n");
+#endif
+            continue;
+        }
+
+        /* Check for TLS_FALLBACK_SCSV */
+        if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) &&
+            (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) {
+            /*
+             * The SCSV indicates that the client previously tried a higher
+             * version. Fail if the current version is an unexpected
+             * downgrade.
+             */
+            if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+                       SSL_R_INAPPROPRIATE_FALLBACK);
+                *al = SSL_AD_INAPPROPRIATE_FALLBACK;
+                goto err;
+            }
+            continue;
+        }
+
+        /* For SSLv2-compat, ignore leading 0-byte. */
+        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher);
+        if (c != NULL) {
+            if (!sk_SSL_CIPHER_push(sk, c)) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+                *al = SSL_AD_INTERNAL_ERROR;
+                goto err;
+            }
+        }
+    }
+    if (PACKET_remaining(cipher_suites) > 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (skp != NULL)
+        *skp = sk;
+    return (sk);
+ err:
+    if ((skp == NULL) || (*skp == NULL))
+        sk_SSL_CIPHER_free(sk);
+    return NULL;
+}
diff --git a/ssl/t1_clnt.c b/ssl/t1_clnt.c
deleted file mode 100644
index 9e117e9..0000000
--- a/ssl/t1_clnt.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ssl/t1_clnt.c */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-
-static const SSL_METHOD *tls1_get_client_method(int ver);
-static const SSL_METHOD *tls1_get_client_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_client_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_client_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_client_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_client_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_client_method());
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect, tls1_get_client_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
-                         ssl_undefined_function,
-                         ssl3_connect, tls1_get_client_method)
-#endif
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 6446623..f42fb64 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -3680,7 +3680,7 @@ int tls1_heartbeat(SSL *s)
     }
 
     /* ...and no handshake in progress. */
-    if (SSL_in_init(s) || s->in_handshake) {
+    if (SSL_in_init(s) || ossl_statem_get_in_handshake(s)) {
         SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
         return -1;
     }
diff --git a/ssl/t1_meth.c b/ssl/t1_meth.c
deleted file mode 100644
index aa16d3f..0000000
--- a/ssl/t1_meth.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ssl/t1_meth.c */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-static const SSL_METHOD *tls1_get_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_method());
-    else
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_method,
-                         ssl3_accept, ssl3_connect, tls1_get_method)
-#endif
diff --git a/ssl/t1_srvr.c b/ssl/t1_srvr.c
deleted file mode 100644
index 6e54b51..0000000
--- a/ssl/t1_srvr.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ssl/t1_srvr.c */
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-static const SSL_METHOD *tls1_get_server_method(int ver);
-static const SSL_METHOD *tls1_get_server_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_server_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_server_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_server_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_server_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_server_method());
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
-                         ssl3_accept,
-                         ssl_undefined_function, tls1_get_server_method)
-#endif
diff --git a/test/Makefile b/test/Makefile
index 6f32758..ffeba40 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -559,7 +559,7 @@ heartbeat_test.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 heartbeat_test.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 heartbeat_test.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 heartbeat_test.o: ../ssl/packet_locl.h ../ssl/record/record.h ../ssl/ssl_locl.h
-heartbeat_test.o: heartbeat_test.c testutil.h
+heartbeat_test.o: ../ssl/statem/statem.h heartbeat_test.c testutil.h
 hmactest.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 hmactest.o: ../include/openssl/crypto.h ../include/openssl/e_os2.h
 hmactest.o: ../include/openssl/evp.h ../include/openssl/hmac.h
@@ -681,7 +681,8 @@ ssltest.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssltest.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssltest.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssltest.o: ../include/openssl/x509v3.h ../ssl/packet_locl.h
-ssltest.o: ../ssl/record/record.h ../ssl/ssl_locl.h ssltest.c
+ssltest.o: ../ssl/record/record.h ../ssl/ssl_locl.h ../ssl/statem/statem.h
+ssltest.o: ssltest.c
 testutil.o: ../e_os.h ../include/openssl/e_os2.h
 testutil.o: ../include/openssl/opensslconf.h testutil.c testutil.h
 v3nametest.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
diff --git a/util/ssleay.num b/util/ssleay.num
index 4c8a783..b3f6324 100755
--- a/util/ssleay.num
+++ b/util/ssleay.num
@@ -145,7 +145,7 @@ SSL_set_shutdown                        162	EXIST::FUNCTION:
 SSL_set_verify_result                   163	EXIST::FUNCTION:
 SSL_version                             164	EXIST::FUNCTION:
 SSL_get_info_callback                   165	EXIST::FUNCTION:
-SSL_state                               166	EXIST::FUNCTION:
+SSL_state                               166	NOEXIST::FUNCTION:
 SSL_CTX_get_ex_new_index                167	EXIST::FUNCTION:
 SSL_SESSION_get_ex_new_index            168	EXIST::FUNCTION:
 SSL_get_ex_new_index                    169	EXIST::FUNCTION:
@@ -304,7 +304,7 @@ SSL_cache_hit                           344	EXIST::FUNCTION:
 SSL_get0_kssl_ctx                       345	NOEXIST::FUNCTION:
 SSL_set0_kssl_ctx                       346	NOEXIST::FUNCTION:
 SSL_SESSION_get0_id                     347	NOEXIST::FUNCTION:
-SSL_set_state                           348	EXIST::FUNCTION:
+SSL_set_state                           348	NOEXIST::FUNCTION:
 SSL_CIPHER_get_id                       349	EXIST::FUNCTION:
 TLSv1_2_method                          350	EXIST::FUNCTION:
 SSL_SESSION_get_id_len                  351	NOEXIST::FUNCTION:
@@ -405,3 +405,7 @@ SSL_get_client_random                   439	EXIST::FUNCTION:
 SSL_SESSION_get_master_key              440	EXIST::FUNCTION:
 SSL_CTX_set_default_verify_dir          441	EXIST::FUNCTION:
 SSL_CTX_set_default_verify_file         442	EXIST::FUNCTION:
+SSL_in_init                             443	EXIST::FUNCTION:
+SSL_in_before                           444	EXIST::FUNCTION:
+SSL_is_init_finished                    445	EXIST::FUNCTION:
+SSL_get_state                           446	EXIST::FUNCTION:


More information about the openssl-commits mailing list