tls: add 2nd cipher_id, TLS_RSA_WITH_AES_128_CBC_SHA, so far it doesn't work
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 24 Jan 2017 15:00:54 +0000 (16:00 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 24 Jan 2017 15:00:54 +0000 (16:00 +0100)
Good news that TLS_RSA_WITH_AES_256_CBC_SHA256 still works with new code ;)

This change adds inevitable extension to have different sized hashes and AES key sizes.
In libbb, md5_end() and shaX_end() are extended to return result size instead of void -
this helps *a lot* in tls (the cost is ~5 bytes per _end() function).

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/md5_sha1_sum.c
include/libbb.h
libbb/hash_md5_sha.c
libbb/hash_md5prime.c
libbb/pw_encrypt_sha.c
networking/tls.c

index 76788554c3529c5a2b7bb419a8d59ee958157a00..50111bd267a9cfb06b90ee66e86fe167d3dec033 100644 (file)
@@ -166,7 +166,7 @@ static uint8_t *hash_file(const char *filename, unsigned sha3_width)
        } context;
        uint8_t *hash_value;
        void FAST_FUNC (*update)(void*, const void*, size_t);
-       void FAST_FUNC (*final)(void*, void*);
+       unsigned FAST_FUNC (*final)(void*, void*);
        char hash_algo;
 
        src_fd = open_or_warn_stdin(filename);
index ba3b1479e5a86e9add7e954dc1fa1a5ec01a673c..b1ceb32786eceeedc8a4945c9b8617062f502143 100644 (file)
@@ -713,18 +713,19 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC;
 // Also mount.c and inetd.c are using gethostbyname(),
 // + inet_common.c has additional IPv4-only stuff
 
-#define SHA256_INSIZE  64
-#define SHA256_OUTSIZE 32
-#define AES_BLOCKSIZE  16
-#define AES128_KEYSIZE 16
-#define AES256_KEYSIZE 32
+
+#define TLS_MAX_MAC_SIZE 32
+#define TLS_MAX_KEY_SIZE 32
 struct tls_handshake_data; /* opaque */
 typedef struct tls_state {
-       int     ofd;
-       int     ifd;
+       int ofd;
+       int ifd;
 
-       int     min_encrypted_len_on_read;
-       uint8_t encrypt_on_write;
+       int      min_encrypted_len_on_read;
+       uint16_t cipher_id;
+       uint8_t  encrypt_on_write;
+       unsigned MAC_size;
+       unsigned key_size;
 
        uint8_t *outbuf;
        int     outbuf_size;
@@ -746,10 +747,12 @@ typedef struct tls_state {
        /*uint64_t read_seq64_be;*/
        uint64_t write_seq64_be;
 
-       uint8_t client_write_MAC_key[SHA256_OUTSIZE];
-       uint8_t server_write_MAC_key[SHA256_OUTSIZE];
-       uint8_t client_write_key[AES256_KEYSIZE];
-       uint8_t server_write_key[AES256_KEYSIZE];
+       uint8_t *client_write_key;
+       uint8_t *server_write_key;
+       uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE];
+       uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE];
+       uint8_t client_write_k__[TLS_MAX_KEY_SIZE];
+       uint8_t server_write_k__[TLS_MAX_KEY_SIZE];
 } tls_state_t;
 
 static inline tls_state_t *new_tls_state(void)
@@ -760,6 +763,7 @@ static inline tls_state_t *new_tls_state(void)
 void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC;
 void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC;
 
+
 void socket_want_pktinfo(int fd) FAST_FUNC;
 ssize_t send_to_from(int fd, void *buf, size_t len, int flags,
                const struct sockaddr *to,
@@ -1799,19 +1803,23 @@ typedef struct sha3_ctx_t {
 } sha3_ctx_t;
 void md5_begin(md5_ctx_t *ctx) FAST_FUNC;
 void md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
-void md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC;
+unsigned md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC;
 void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC;
 #define sha1_hash md5_hash
-void sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC;
+unsigned sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC;
 void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC;
 #define sha256_hash md5_hash
 #define sha256_end  sha1_end
 void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC;
 void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
-void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
+unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
 void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC;
 void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
-void sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC;
+unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC;
+/* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */
+typedef struct md5_ctx_t md5sha_ctx_t;
+#define md5sha_hash md5_hash
+#define sha_end sha1_end
 
 extern uint32_t *global_crc32_table;
 uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
index d325584d7e05c3d8e113749ff6bc2777b1227b1c..2a7247430cc30feb492203fc625bc4c177eb45b3 100644 (file)
@@ -458,7 +458,7 @@ void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
  * endian byte order, so that a byte-wise output yields to the wanted
  * ASCII representation of the message digest.
  */
-void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
+unsigned FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
 {
        /* MD5 stores total in LE, need to swap on BE arches: */
        common64_end(ctx, /*swap_needed:*/ BB_BIG_ENDIAN);
@@ -472,6 +472,7 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
        }
 
        memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * 4);
+       return sizeof(ctx->hash[0]) * 4;
 }
 
 
@@ -865,7 +866,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len)
 #endif /* NEED_SHA512 */
 
 /* Used also for sha256 */
-void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
+unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
 {
        unsigned hash_size;
 
@@ -879,11 +880,13 @@ void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
                for (i = 0; i < hash_size; ++i)
                        ctx->hash[i] = SWAP_BE32(ctx->hash[i]);
        }
-       memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size);
+       hash_size *= sizeof(ctx->hash[0]);
+       memcpy(resbuf, ctx->hash, hash_size);
+       return hash_size;
 }
 
 #if NEED_SHA512
-void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
+unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
 {
        unsigned bufpos = ctx->total64[0] & 127;
 
@@ -915,6 +918,7 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
                        ctx->hash[i] = SWAP_BE64(ctx->hash[i]);
        }
        memcpy(resbuf, ctx->hash, sizeof(ctx->hash));
+       return sizeof(ctx->hash);
 }
 #endif /* NEED_SHA512 */
 
@@ -1450,7 +1454,7 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
 #endif
 }
 
-void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
+unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
 {
        /* Padding */
        uint8_t *buf = (uint8_t*)ctx->state;
@@ -1475,4 +1479,5 @@ void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
 
        /* Output */
        memcpy(resbuf, ctx->state, 64);
+       return 64;
 }
index e089a15f5ab555e58c264af454dde5c7646eaf44..4b58d37ffbcc36245c2b8f4016145ca9d5501891 100644 (file)
@@ -437,7 +437,7 @@ void FAST_FUNC md5_hash(const void *buffer, size_t inputLen, md5_ctx_t *context)
  * MD5 finalization. Ends an MD5 message-digest operation,
  * writing the message digest.
  */
-void FAST_FUNC md5_end(void *digest, md5_ctx_t *context)
+unsigned FAST_FUNC md5_end(void *digest, md5_ctx_t *context)
 {
        unsigned idx, padLen;
        unsigned char bits[8];
@@ -457,4 +457,5 @@ void FAST_FUNC md5_end(void *digest, md5_ctx_t *context)
 
        /* Store state in digest */
        memcpy32_cpu2le(digest, context->state, 16);
+       return 16;
 }
index 72e37e485033c78d14b65b03523a101fcedf5d42..5457d7ab6a8a37613e46fcf49e58002cfeaba48a 100644 (file)
@@ -18,9 +18,10 @@ static char *
 NOINLINE
 sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
 {
+#undef sha_end
        void (*sha_begin)(void *ctx) FAST_FUNC;
        void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
-       void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC;
+       unsigned (*sha_end)(void *ctx, void *resbuf) FAST_FUNC;
        int _32or64;
 
        char *result, *resptr;
index 8549a21da6ec519e864e875fc3c8df83b13e0c37..a65da4ad4625784ad7100222c56a23e8f877aa9f 100644 (file)
 
 #include "tls.h"
 
-#define TLS_DEBUG      0
-#define TLS_DEBUG_HASH 0
-#define TLS_DEBUG_DER  0
-#define TLS_DEBUG_FIXED_SECRETS 0
+//Tested against kernel.org:
+//TLS 1.2
+#define TLS_MAJ 3
+#define TLS_MIN 3
+//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box
+//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
+//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE
+//^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck, server refuses it)
+//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE
+//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
+//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // ok, recvs SERVER_KEY_EXCHANGE
+//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
+//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
+//#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE
+//#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this?
+
+// works against "openssl s_server -cipher NULL"
+// and against wolfssl-3.9.10-stable/examples/server/server.c:
+//#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting)
+
+// works against wolfssl-3.9.10-stable/examples/server/server.c
+// works for kernel.org
+// does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page)
+//  getting alert 40 "handshake failure" at once
+//  with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher
+//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256
+//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384
+//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256
+//  ok:   openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256
+//  ok:   openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA
+//        (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported)
+#define CIPHER_ID1  TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer
+// Does not work yet:
+//#define CIPHER_ID2  TLS_RSA_WITH_AES_128_CBC_SHA
+#define CIPHER_ID2  0
+
+
+#define TLS_DEBUG      1
+#define TLS_DEBUG_HASH 1
+#define TLS_DEBUG_DER  1
+#define TLS_DEBUG_FIXED_SECRETS 1
 #if 0
 # define dump_raw_out(...) dump_hex(__VA_ARGS__)
 #else
 #define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256    0xC031  /* 49201 */
 #define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384    0xC032  /* 49202 */
 
-//Tested against kernel.org:
-//TLS 1.2
-#define TLS_MAJ 3
-#define TLS_MIN 3
-//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box
-//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
-//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE
-//^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck, server refuses it)
-//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE
-//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
-//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // ok, recvs SERVER_KEY_EXCHANGE
-//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
-//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
-//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
-//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE
-//#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE
-//#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this?
+/* Might go to libbb.h */
+#define TLS_MAX_CRYPTBLOCK_SIZE 16
+#define TLS_MAX_OUTBUF          (1 << 14)
 
-// works against "openssl s_server -cipher NULL"
-// and against wolfssl-3.9.10-stable/examples/server/server.c:
-//#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting)
+enum {
+       SHA_INSIZE     = 64,
+       SHA1_OUTSIZE   = 20,
+       SHA256_OUTSIZE = 32,
 
-// works against wolfssl-3.9.10-stable/examples/server/server.c
-// works for kernel.org
-// does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page)
-//  getting alert 40 "handshake failure" at once
-//  with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher
-//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256
-//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384
-//  fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256
-//  ok:   openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256
-//  ok:   openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA
-//        (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported)
-#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer
+       AES_BLOCKSIZE  = 16,
+       AES128_KEYSIZE = 16,
+       AES256_KEYSIZE = 32,
 
-enum {
        RSA_PREMASTER_SIZE = 48,
 
        RECHDR_LEN = 5,
 
-       MAX_TLS_RECORD = (1 << 14),
        /* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */
        OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
-       OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
-       MAX_OUTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX,
+       OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */
 
        // RFC 5246
        // | 6.2.1. Fragmentation
@@ -205,7 +219,7 @@ enum {
        // |  length
        // |    The length (in bytes) of the following TLSCiphertext.fragment.
        // |    The length MUST NOT exceed 2^14 + 2048.
-       MAX_INBUF = (1 << 14) + 2048,
+       MAX_INBUF = RECHDR_LEN + (1 << 14) + 2048,
 };
 
 struct record_hdr {
@@ -215,12 +229,17 @@ struct record_hdr {
 };
 
 struct tls_handshake_data {
-       sha256_ctx_t handshake_sha256_ctx;
+       /* In bbox, md5/sha1/sha256 ctx's are the same structure */
+       md5sha_ctx_t handshake_hash_ctx;
+
        uint8_t client_and_server_rand32[2 * 32];
        uint8_t master_secret[48];
 //TODO: store just the DER key here, parse/use/delete it when sending client key
 //this way it will stay key type agnostic here.
        psRsaKey_t server_rsa_pub_key;
+
+       unsigned saved_client_hello_size;
+       uint8_t saved_client_hello[1];
 };
 
 
@@ -275,37 +294,41 @@ void tls_get_random(void *buf, unsigned len)
                xfunc_die();
 }
 
-//TODO rename this to sha256_hash, and sha256_hash -> sha256_update
-static void hash_sha256(uint8_t out[SHA256_OUTSIZE], const void *data, unsigned size)
+/* Nondestructively see the current hash value */
+static unsigned sha_peek(md5sha_ctx_t *ctx, void *buffer)
 {
-       sha256_ctx_t ctx;
-       sha256_begin(&ctx);
-       sha256_hash(&ctx, data, size);
-       sha256_end(&ctx, out);
+       md5sha_ctx_t ctx_copy = *ctx; /* struct copy */
+       return sha_end(&ctx_copy, buffer);
 }
 
-/* Nondestructively see the current hash value */
-static void sha256_peek(sha256_ctx_t *ctx, void *buffer)
+static ALWAYS_INLINE unsigned get_handshake_hash(tls_state_t *tls, void *buffer)
 {
-       sha256_ctx_t ctx_copy = *ctx;
-        sha256_end(&ctx_copy, buffer);
+       return sha_peek(&tls->hsd->handshake_hash_ctx, buffer);
 }
 
-#if TLS_DEBUG_HASH
-static void sha256_hash_dbg(const char *fmt, sha256_ctx_t *ctx, const void *buffer, size_t len)
+#if !TLS_DEBUG_HASH
+# define hash_handshake(tls, fmt, buffer, len) \
+         hash_handshake(tls, buffer, len)
+#endif
+static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer, unsigned len)
 {
-        uint8_t h[SHA256_OUTSIZE];
-
-       sha256_hash(ctx, buffer, len);
-       dump_hex(fmt, buffer, len);
-       dbg(" (%u) ", (int)len);
-       sha256_peek(ctx, h);
-       dump_hex("%s\n", h, SHA256_OUTSIZE);
-}
-#else
-# define sha256_hash_dbg(fmt, ctx, buffer, len) \
-         sha256_hash(ctx, buffer, len)
+       md5sha_hash(&tls->hsd->handshake_hash_ctx, buffer, len);
+#if TLS_DEBUG_HASH
+       {
+               uint8_t h[TLS_MAX_MAC_SIZE];
+               dump_hex(fmt, buffer, len);
+               dbg(" (%u bytes) ", (int)len);
+               len = sha_peek(&tls->hsd->handshake_hash_ctx, h);
+               if (len == SHA1_OUTSIZE)
+                       dump_hex("sha1:%s\n", h, len);
+               else
+               if (len == SHA256_OUTSIZE)
+                       dump_hex("sha256:%s\n", h, len);
+               else
+                       dump_hex("sha???:%s\n", h, len);
+       }
 #endif
+}
 
 // RFC 2104
 // HMAC(key, text) based on a hash H (say, sha256) is:
@@ -317,12 +340,13 @@ static void sha256_hash_dbg(const char *fmt, sha256_ctx_t *ctx, const void *buff
 // if we often need HMAC hmac with the same key.
 //
 // text is often given in disjoint pieces.
-static void hmac_sha256_precomputed_v(uint8_t out[SHA256_OUTSIZE],
-               sha256_ctx_t *hashed_key_xor_ipad,
-               sha256_ctx_t *hashed_key_xor_opad,
+static unsigned hmac_sha_precomputed_v(uint8_t *out,
+               md5sha_ctx_t *hashed_key_xor_ipad,
+               md5sha_ctx_t *hashed_key_xor_opad,
                va_list va)
 {
        uint8_t *text;
+       unsigned len;
 
        /* hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
        /* hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
@@ -330,24 +354,24 @@ static void hmac_sha256_precomputed_v(uint8_t out[SHA256_OUTSIZE],
        /* calculate out = H((key XOR ipad) + text) */
        while ((text = va_arg(va, uint8_t*)) != NULL) {
                unsigned text_size = va_arg(va, unsigned);
-               sha256_hash(hashed_key_xor_ipad, text, text_size);
+               md5sha_hash(hashed_key_xor_ipad, text, text_size);
        }
-       sha256_end(hashed_key_xor_ipad, out);
+       len = sha_end(hashed_key_xor_ipad, out);
 
        /* out = H((key XOR opad) + out) */
-       sha256_hash(hashed_key_xor_opad, out, SHA256_OUTSIZE);
-       sha256_end(hashed_key_xor_opad, out);
+       md5sha_hash(hashed_key_xor_opad, out, len);
+       return sha_end(hashed_key_xor_opad, out);
 }
 
-static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_size, ...)
+static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...)
 {
-       sha256_ctx_t hashed_key_xor_ipad;
-       sha256_ctx_t hashed_key_xor_opad;
-       uint8_t key_xor_ipad[SHA256_INSIZE];
-       uint8_t key_xor_opad[SHA256_INSIZE];
+       md5sha_ctx_t hashed_key_xor_ipad;
+       md5sha_ctx_t hashed_key_xor_opad;
+       uint8_t key_xor_ipad[SHA_INSIZE];
+       uint8_t key_xor_opad[SHA_INSIZE];
        uint8_t tempkey[SHA256_OUTSIZE];
        va_list va;
-       int i;
+       unsigned i;
 
        va_start(va, key_size);
 
@@ -355,27 +379,38 @@ static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_
        // block length of the hash function.  Applications that use keys longer
        // than INSIZE bytes will first hash the key using H and then use the
        // resultant OUTSIZE byte string as the actual key to HMAC."
-       if (key_size > SHA256_INSIZE) {
-               hash_sha256(tempkey, key, key_size);
-               key = tempkey;
-               key_size = SHA256_OUTSIZE;
+       if (key_size > SHA_INSIZE) {
+               md5sha_ctx_t ctx;
+               if (tls->MAC_size == SHA256_OUTSIZE)
+                       sha256_begin(&ctx);
+               else
+                       sha1_begin(&ctx);
+               md5sha_hash(&ctx, key, key_size);
+               key_size = sha_end(&ctx, tempkey);
        }
 
        for (i = 0; i < key_size; i++) {
                key_xor_ipad[i] = key[i] ^ 0x36;
                key_xor_opad[i] = key[i] ^ 0x5c;
        }
-       for (; i < SHA256_INSIZE; i++) {
+       for (; i < SHA_INSIZE; i++) {
                key_xor_ipad[i] = 0x36;
                key_xor_opad[i] = 0x5c;
        }
-       sha256_begin(&hashed_key_xor_ipad);
-       sha256_hash(&hashed_key_xor_ipad, key_xor_ipad, SHA256_INSIZE);
-       sha256_begin(&hashed_key_xor_opad);
-       sha256_hash(&hashed_key_xor_opad, key_xor_opad, SHA256_INSIZE);
 
-       hmac_sha256_precomputed_v(out, &hashed_key_xor_ipad, &hashed_key_xor_opad, va);
+       if (tls->MAC_size == SHA256_OUTSIZE) {
+               sha256_begin(&hashed_key_xor_ipad);
+               sha256_begin(&hashed_key_xor_opad);
+       } else {
+               sha1_begin(&hashed_key_xor_ipad);
+               sha1_begin(&hashed_key_xor_opad);
+       }
+       md5sha_hash(&hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE);
+       md5sha_hash(&hashed_key_xor_opad, key_xor_opad, SHA_INSIZE);
+
+       i = hmac_sha_precomputed_v(out, &hashed_key_xor_ipad, &hashed_key_xor_opad, va);
        va_end(va);
+       return i;
 }
 
 // RFC 5246:
@@ -406,40 +441,41 @@ static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_
 //    PRF(secret, label, seed) = P_<hash>(secret, label + seed)
 //
 // The label is an ASCII string.
-static void prf_hmac_sha256(
+static void prf_hmac(tls_state_t *tls,
                uint8_t *outbuf, unsigned outbuf_size,
                uint8_t *secret, unsigned secret_size,
                const char *label,
                uint8_t *seed, unsigned seed_size)
 {
-       uint8_t a[SHA256_OUTSIZE];
+       uint8_t a[TLS_MAX_MAC_SIZE];
        uint8_t *out_p = outbuf;
        unsigned label_size = strlen(label);
+       unsigned MAC_size = tls->MAC_size;
 
        /* In P_hash() calculation, "seed" is "label + seed": */
 #define SEED   label, label_size, seed, seed_size
 #define SECRET secret, secret_size
-#define A      a, (int)(sizeof(a))
+#define A      a, MAC_size
 
        /* A(1) = HMAC_hash(secret, seed) */
-       hmac_sha256(a, SECRET, SEED, NULL);
-//TODO: convert hmac_sha256 to precomputed
+       hmac(tls, a, SECRET, SEED, NULL);
+//TODO: convert hmac to precomputed
 
        for(;;) {
                /* HMAC_hash(secret, A(1) + seed) */
-               if (outbuf_size <= SHA256_OUTSIZE) {
+               if (outbuf_size <= MAC_size) {
                        /* Last, possibly incomplete, block */
                        /* (use a[] as temp buffer) */
-                       hmac_sha256(a, SECRET, A, SEED, NULL);
+                       hmac(tls, a, SECRET, A, SEED, NULL);
                        memcpy(out_p, a, outbuf_size);
                        return;
                }
                /* Not last block. Store directly to result buffer */
-               hmac_sha256(out_p, SECRET, A, SEED, NULL);
-               out_p += SHA256_OUTSIZE;
-               outbuf_size -= SHA256_OUTSIZE;
+               hmac(tls, out_p, SECRET, A, SEED, NULL);
+               out_p += MAC_size;
+               outbuf_size -= MAC_size;
                /* A(2) = HMAC_hash(secret, A(1)) */
-               hmac_sha256(a, SECRET, A, NULL);
+               hmac(tls, a, SECRET, A, NULL);
        }
 #undef A
 #undef SECRET
@@ -484,11 +520,12 @@ static void tls_free_outbuf(tls_state_t *tls)
 
 static void *tls_get_outbuf(tls_state_t *tls, int len)
 {
-       if (len > MAX_OUTBUF)
+       if (len > TLS_MAX_OUTBUF)
                xfunc_die();
-       if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) {
-               tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX;
-               tls->outbuf = xrealloc(tls->outbuf, tls->outbuf_size);
+       len += OUTBUF_PFX + OUTBUF_SFX;
+       if (tls->outbuf_size < len) {
+               tls->outbuf_size = len;
+               tls->outbuf = xrealloc(tls->outbuf, len);
        }
        return tls->outbuf + OUTBUF_PFX;
 }
@@ -500,7 +537,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
        uint8_t padding_length;
 
        xhdr = (void*)(buf - RECHDR_LEN);
-       if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256)
+       if (tls->cipher_id != TLS_RSA_WITH_NULL_SHA256)
                xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCKSIZE); /* place for IV */
 
        xhdr->type = type;
@@ -511,16 +548,16 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
        xhdr->len16_lo = size & 0xff;
 
        /* Calculate MAC signature */
-//TODO: convert hmac_sha256 to precomputed
-       hmac_sha256(buf + size,
-                       tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key),
-                       &tls->write_seq64_be, sizeof(tls->write_seq64_be),
-                       xhdr, RECHDR_LEN,
-                       buf, size,
-                       NULL);
+       hmac(tls, buf + size, /* result */
+               tls->client_write_MAC_key, tls->MAC_size,
+               &tls->write_seq64_be, sizeof(tls->write_seq64_be),
+               xhdr, RECHDR_LEN,
+               buf, size,
+               NULL
+       );
        tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be));
 
-       size += SHA256_OUTSIZE;
+       size += tls->MAC_size;
 
        // RFC 5246
        // 6.2.3.1.  Null or Standard Stream Cipher
@@ -555,7 +592,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
        // --------  -----------  ----------  --------------
        // SHA       HMAC-SHA1       20            20
        // SHA256    HMAC-SHA256     32            32
-       if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) {
+       if (tls->cipher_id == TLS_RSA_WITH_NULL_SHA256) {
                /* No encryption, only signing */
                xhdr->len16_hi = size >> 8;
                xhdr->len16_lo = size & 0xff;
@@ -603,7 +640,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 
        /* Fill IV and padding in outbuf */
        tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
-       dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, SHA256_OUTSIZE);
+       dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, tls->MAC_size);
        // RFC is talking nonsense:
        //    "Padding that is added to force the length of the plaintext to be
        //    an integral multiple of the block cipher's block length."
@@ -628,7 +665,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
        {
                psCipherContext_t ctx;
                psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */
-                       tls->client_write_key, sizeof(tls->client_write_key)
+                       tls->client_write_key, tls->key_size /* selects 128/256 */
                );
                psAesEncrypt(&ctx,
                        buf, /* plaintext */
@@ -648,9 +685,9 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
        dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
 }
 
-static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
+static void xwrite_handshake_record(tls_state_t *tls, unsigned size)
 {
-       if (!tls->encrypt_on_write) {
+       //if (!tls->encrypt_on_write) {
                uint8_t *buf = tls->outbuf + OUTBUF_PFX;
                struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN);
 
@@ -662,8 +699,20 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
                dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
                xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
                dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
+       //      return;
+       //}
+       //xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
+}
+
+static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
+{
+       if (!tls->encrypt_on_write) {
+               uint8_t *buf;
+
+               xwrite_handshake_record(tls, size);
                /* Handshake hash does not include record headers */
-               sha256_hash_dbg(">> sha256:%s", &tls->hsd->handshake_sha256_ctx, buf, size);
+               buf = tls->outbuf + OUTBUF_PFX;
+               hash_handshake(tls, ">> hash:%s", buf, size);
                return;
        }
        xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
@@ -765,7 +814,7 @@ static int tls_xread_record(tls_state_t *tls)
        sz = target - RECHDR_LEN;
 
        /* Needs to be decrypted? */
-       if (tls->min_encrypted_len_on_read > SHA256_OUTSIZE) {
+       if (tls->min_encrypted_len_on_read > tls->MAC_size) {
                psCipherContext_t ctx;
                uint8_t *p = tls->inbuf + RECHDR_LEN;
                int padding_len;
@@ -777,7 +826,7 @@ static int tls_xread_record(tls_state_t *tls)
                }
                /* Decrypt content+MAC+padding, moving it over IV in the process */
                psAesInit(&ctx, p, /* IV */
-                       tls->server_write_key, sizeof(tls->server_write_key)
+                       tls->server_write_key, tls->key_size /* selects 128/256 */
                );
                sz -= AES_BLOCKSIZE; /* we will overwrite IV now */
                psAesDecrypt(&ctx,
@@ -788,7 +837,7 @@ static int tls_xread_record(tls_state_t *tls)
                padding_len = p[sz - 1];
                dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len);
                padding_len++;
-               sz -= SHA256_OUTSIZE + padding_len; /* drop MAC and padding */
+               sz -= tls->MAC_size + padding_len; /* drop MAC and padding */
                //if (sz < 0)
                //      bb_error_msg_and_die("bad padding size:%u", padding_len);
        } else {
@@ -834,8 +883,10 @@ static int tls_xread_record(tls_state_t *tls)
        /* RFC 5246 is not saying it explicitly, but sha256 hash
         * in our FINISHED record must include data of incoming packets too!
         */
-       if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE) {
-               sha256_hash_dbg("<< sha256:%s", &tls->hsd->handshake_sha256_ctx, tls->inbuf + RECHDR_LEN, sz);
+       if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE
+        && tls->MAC_size != 0 /* do we know which hash to use? (server_hello() does not!) */
+       ) {
+               hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz);
        }
  end:
        dbg("got block len:%u\n", sz);
@@ -1088,7 +1139,7 @@ static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, un
        h->len24_lo  = len & 0xff;
 }
 
-static void send_client_hello(tls_state_t *tls, const char *sni)
+static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
 {
        struct client_hello {
                uint8_t type;
@@ -1098,7 +1149,7 @@ static void send_client_hello(tls_state_t *tls, const char *sni)
                uint8_t session_id_len;
                /* uint8_t session_id[]; */
                uint8_t cipherid_len16_hi, cipherid_len16_lo;
-               uint8_t cipherid[2 * 2]; /* actually variable */
+               uint8_t cipherid[2 * (2 + !!CIPHER_ID2)]; /* actually variable */
                uint8_t comprtypes_len;
                uint8_t comprtypes[1]; /* actually variable */
                /* Extensions (SNI shown):
@@ -1136,17 +1187,19 @@ static void send_client_hello(tls_state_t *tls, const char *sni)
        tls_get_random(record->rand32, sizeof(record->rand32));
        if (TLS_DEBUG_FIXED_SECRETS)
                memset(record->rand32, 0x11, sizeof(record->rand32));
-       memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32));
        /* record->session_id_len = 0; - already is */
 
        /* record->cipherid_len16_hi = 0; */
-       record->cipherid_len16_lo = 2 * 2;
-       if ((CIPHER_ID >> 8) != 0)
-               record->cipherid[0] = CIPHER_ID >> 8;
-       record->cipherid[1] = CIPHER_ID & 0xff;
+       record->cipherid_len16_lo = sizeof(record->cipherid);
        /* RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */
-       /*record->cipherid[2] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */
-       record->cipherid[3] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff;
+       /*record->cipherid[0] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */
+       record->cipherid[1] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff;
+       if ((CIPHER_ID1 >> 8) != 0) record->cipherid[2] = CIPHER_ID1 >> 8;
+       /*************************/ record->cipherid[3] = CIPHER_ID1 & 0xff;
+#if CIPHER_ID2
+       if ((CIPHER_ID2 >> 8) != 0) record->cipherid[4] = CIPHER_ID2 >> 8;
+       /*************************/ record->cipherid[5] = CIPHER_ID2 & 0xff;
+#endif
 
        record->comprtypes_len = 1;
        /* record->comprtypes[0] = 0; */
@@ -1168,7 +1221,14 @@ static void send_client_hello(tls_state_t *tls, const char *sni)
        }
 
        dbg(">> CLIENT_HELLO\n");
-       xwrite_and_update_handshake_hash(tls, len);
+       /* Can hash it only when we know which MAC hash to use */
+       /*xwrite_and_update_handshake_hash(tls, len); - WRONG! */
+       xwrite_handshake_record(tls, len);
+
+       tls->hsd = xzalloc(sizeof(*tls->hsd) + len);
+       tls->hsd->saved_client_hello_size = len;
+       memcpy(tls->hsd->saved_client_hello, record, len);
+       memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32));
 }
 
 static void get_server_hello(tls_state_t *tls)
@@ -1188,7 +1248,8 @@ static void get_server_hello(tls_state_t *tls)
 
        struct server_hello *hp;
        uint8_t *cipherid;
-       int len;
+       unsigned cipher;
+       int len, len24;
 
        len = tls_xread_handshake_block(tls, 74);
 
@@ -1207,6 +1268,7 @@ static void get_server_hello(tls_state_t *tls)
        }
 
        cipherid = &hp->cipherid_hi;
+       len24 = hp->len24_lo;
        if (hp->session_id_len != 32) {
                if (hp->session_id_len != 0)
                        tls_error_die(tls);
@@ -1216,19 +1278,39 @@ static void get_server_hello(tls_state_t *tls)
                // may return an empty session_id to indicate that the session will
                // not be cached and therefore cannot be resumed."
                cipherid -= 32;
-               hp->len24_lo += 32; /* what len would be if session id would be present */
+               len24 += 32; /* what len would be if session id would be present */
        }
 
-       if (hp->len24_lo < 70
-        || cipherid[0]  != (CIPHER_ID >> 8)
-        || cipherid[1]  != (CIPHER_ID & 0xff)
-        || cipherid[2]  != 0 /* comprtype */
+       if (len24 < 70
+//      || cipherid[0]  != (CIPHER_ID >> 8)
+//      || cipherid[1]  != (CIPHER_ID & 0xff)
+//      || cipherid[2]  != 0 /* comprtype */
        ) {
                tls_error_die(tls);
        }
-
        dbg("<< SERVER_HELLO\n");
+
        memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32));
+
+       tls->cipher_id = cipher = 0x100 * cipherid[0] + cipherid[1];
+       dbg("server chose cipher %04x\n", cipher);
+
+       if (cipher == TLS_RSA_WITH_AES_128_CBC_SHA) {
+               tls->key_size = AES128_KEYSIZE;
+               tls->MAC_size = SHA1_OUTSIZE;
+               sha1_begin(&tls->hsd->handshake_hash_ctx);
+       }
+       else { /* TLS_RSA_WITH_AES_256_CBC_SHA256 */
+               tls->key_size = AES256_KEYSIZE;
+               tls->MAC_size = SHA256_OUTSIZE;
+               sha256_begin(&tls->hsd->handshake_hash_ctx);
+       }
+       hash_handshake(tls, ">> client hello hash:%s",
+               tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size
+       );
+       hash_handshake(tls, "<< server hello hash:%s",
+               tls->inbuf + RECHDR_LEN, len
+       );
 }
 
 static void get_server_cert(tls_state_t *tls)
@@ -1312,7 +1394,7 @@ static void send_client_key_exchange(tls_state_t *tls)
        //                          [0..47];
        // The master secret is always exactly 48 bytes in length.  The length
        // of the premaster secret will vary depending on key exchange method.
-       prf_hmac_sha256(
+       prf_hmac(tls,
                tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
                rsa_premaster, sizeof(rsa_premaster),
                "master secret",
@@ -1360,21 +1442,23 @@ static void send_client_key_exchange(tls_state_t *tls)
                memcpy(&tmp64[0] , &tls->hsd->client_and_server_rand32[32], 32);
                memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
 
-               prf_hmac_sha256(
-                       tls->client_write_MAC_key, 2 * (SHA256_OUTSIZE + AES256_KEYSIZE),
+               prf_hmac(tls,
+                       tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size),
                        // also fills:
-                       // server_write_MAC_key[SHA256_OUTSIZE]
-                       // client_write_key[AES256_KEYSIZE]
-                       // server_write_key[AES256_KEYSIZE]
+                       // server_write_MAC_key[]
+                       // client_write_key[]
+                       // server_write_key[]
                        tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
                        "key expansion",
                        tmp64, 64
                );
+               tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size);
+               tls->server_write_key = tls->client_write_key + tls->key_size;
                dump_hex("client_write_MAC_key:%s\n",
-                       tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key)
+                       tls->client_write_MAC_key, tls->MAC_size
                );
                dump_hex("client_write_key:%s\n",
-                       tls->client_write_key, sizeof(tls->client_write_key)
+                       tls->client_write_key, tls->key_size
                );
        }
 }
@@ -1435,15 +1519,17 @@ static void send_client_finished(tls_state_t *tls)
                uint8_t prf_result[12];
        };
        struct finished *record = tls_get_outbuf(tls, sizeof(*record));
-       uint8_t handshake_hash[SHA256_OUTSIZE];
+       uint8_t handshake_hash[TLS_MAX_MAC_SIZE];
+       unsigned len;
 
        fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record));
 
-       sha256_peek(&tls->hsd->handshake_sha256_ctx, handshake_hash);
-       prf_hmac_sha256(record->prf_result, sizeof(record->prf_result),
-                       tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
-                       "client finished",
-                       handshake_hash, sizeof(handshake_hash)
+       len = get_handshake_hash(tls, handshake_hash);
+       prf_hmac(tls,
+               record->prf_result, sizeof(record->prf_result),
+               tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
+               "client finished",
+               handshake_hash, len
        );
        dump_hex("from secret: %s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
        dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1);
@@ -1475,10 +1561,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
        // Application Data     <------>     Application Data
        int len;
 
-       tls->hsd = xzalloc(sizeof(*tls->hsd));
-       sha256_begin(&tls->hsd->handshake_sha256_ctx);
-
-       send_client_hello(tls, sni);
+       send_client_hello_and_alloc_hsd(tls, sni);
        get_server_hello(tls);
 
        // RFC 5246
@@ -1535,11 +1618,11 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
        if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
                tls_error_die(tls);
        dbg("<< CHANGE_CIPHER_SPEC\n");
-       if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256)
-               tls->min_encrypted_len_on_read = SHA256_OUTSIZE;
+       if (tls->cipher_id == TLS_RSA_WITH_NULL_SHA256)
+               tls->min_encrypted_len_on_read = tls->MAC_size;
        else
                /* all incoming packets now should be encrypted and have IV + MAC + padding */
-               tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE;
+               tls->min_encrypted_len_on_read = AES_BLOCKSIZE + tls->MAC_size + AES_BLOCKSIZE;
 
        /* Get (encrypted) FINISHED from the server */
        len = tls_xread_record(tls);
@@ -1550,7 +1633,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
 
        /* free handshake data */
 //     if (PARANOIA)
-//             memset(tls->hsd, 0, sizeof(*tls->hsd));
+//             memset(tls->hsd, 0, tls->hsd->hsd_size);
        free(tls->hsd);
        tls->hsd = NULL;
 }
@@ -1614,8 +1697,8 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
                                         * read, encrypt and send bigger chunks
                                         */
                                        inbuf_size += INBUF_STEP;
-                                       if (inbuf_size > MAX_OUTBUF)
-                                               inbuf_size = MAX_OUTBUF;
+                                       if (inbuf_size > TLS_MAX_OUTBUF)
+                                               inbuf_size = TLS_MAX_OUTBUF;
                                }
                                tls_xwrite(tls, nread);
                        }