Inital import.

Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).

(This change contains substantial changes from the original and
effectively starts a new history.)
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
new file mode 100644
index 0000000..3e613b4
--- /dev/null
+++ b/ssl/CMakeLists.txt
@@ -0,0 +1,46 @@
+include_directories(. .. ../include)
+
+add_subdirectory(pqueue)
+
+add_library(
+	ssl
+
+	d1_both.c
+	d1_clnt.c
+	d1_enc.c
+	d1_lib.c
+	d1_meth.c
+	d1_pkt.c
+	d1_srtp.c
+	d1_srvr.c
+	s23_clnt.c
+	s23_lib.c
+	s23_meth.c
+	s23_pkt.c
+	s23_srvr.c
+	s3_both.c
+	s3_cbc.c
+	s3_clnt.c
+	s3_enc.c
+	s3_lib.c
+	s3_meth.c
+	s3_pkt.c
+	s3_srvr.c
+	ssl_algs.c
+	ssl_asn1.c
+	ssl_cert.c
+	ssl_ciph.c
+	ssl_error.c
+	ssl_lib.c
+	ssl_rsa.c
+	ssl_sess.c
+	ssl_txt.c
+	t1_clnt.c
+	t1_enc.c
+	t1_lib.c
+	t1_meth.c
+	t1_reneg.c
+	t1_srvr.c
+
+	$<TARGET_OBJECTS:pqueue>
+)
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
new file mode 100644
index 0000000..091a471
--- /dev/null
+++ b/ssl/d1_both.c
@@ -0,0 +1,1458 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 
+ */
+/* ====================================================================
+ * Copyright (c) 1998-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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
+
+#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
+			if ((end) - (start) <= 8) { \
+				long ii; \
+				for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
+			} else { \
+				long ii; \
+				bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
+				for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
+				bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
+			} }
+
+#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
+			long ii; \
+			assert((msg_len) > 0); \
+			is_complete = 1; \
+			if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
+			if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
+				if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
+
+#if 0
+#define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \
+			long ii; \
+			printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \
+			printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \
+			printf("\n"); }
+#endif
+
+static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
+static unsigned char bitmask_end_values[]   = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
+
+/* XDTLS:  figure out the right values */
+static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28};
+
+static unsigned int dtls1_guess_mtu(unsigned int curr_mtu);
+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);
+static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
+	unsigned long len, unsigned short seq_num, unsigned long frag_off, 
+	unsigned long frag_len);
+static long dtls1_get_message_fragment(SSL *s, int stn, 
+	long max, int *ok);
+
+static hm_fragment *
+dtls1_hm_fragment_new(unsigned long frag_len, int reassembly)
+	{
+	hm_fragment *frag = NULL;
+	unsigned char *buf = NULL;
+	unsigned char *bitmask = NULL;
+
+	frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
+	if ( frag == NULL)
+		return NULL;
+
+	if (frag_len)
+		{
+		buf = (unsigned char *)OPENSSL_malloc(frag_len);
+		if ( buf == NULL)
+			{
+			OPENSSL_free(frag);
+			return NULL;
+			}
+		}
+
+	/* zero length fragment gets zero frag->fragment */
+	frag->fragment = buf;
+
+	/* Initialize reassembly bitmask if necessary */
+	if (reassembly)
+		{
+		bitmask = (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len));
+		if (bitmask == NULL)
+			{
+			if (buf != NULL) OPENSSL_free(buf);
+			OPENSSL_free(frag);
+			return NULL;
+			}
+		memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len));
+		}
+
+	frag->reassembly = bitmask;
+
+	return frag;
+	}
+
+static void
+dtls1_hm_fragment_free(hm_fragment *frag)
+	{
+
+	if (frag->msg_header.is_ccs)
+		{
+		EVP_CIPHER_CTX_free(frag->msg_header.saved_retransmit_state.enc_write_ctx);
+		EVP_MD_CTX_destroy(frag->msg_header.saved_retransmit_state.write_hash);
+		}
+	if (frag->fragment) OPENSSL_free(frag->fragment);
+	if (frag->reassembly) OPENSSL_free(frag->reassembly);
+	OPENSSL_free(frag);
+	}
+
+/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
+int dtls1_do_write(SSL *s, int type)
+	{
+	int ret;
+	int curr_mtu;
+	unsigned int len, frag_off, mac_size, blocksize;
+
+	/* AHA!  Figure out the MTU, and stick to the right size */
+	if (s->d1->mtu < dtls1_min_mtu() && !(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->d1->mtu = 0;
+			s->d1->mtu = dtls1_guess_mtu(s->d1->mtu);
+			BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, 
+				s->d1->mtu, NULL);
+			}
+		}
+#if 0 
+	mtu = s->d1->mtu;
+
+	fprintf(stderr, "using MTU = %d\n", mtu);
+
+	mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+
+	curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
+
+	if ( curr_mtu > 0)
+		mtu = curr_mtu;
+	else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
+		return ret;
+
+	if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
+		{
+		ret = BIO_flush(SSL_get_wbio(s));
+		if ( ret <= 0)
+			return ret;
+		mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+		}
+#endif
+
+	assert(s->d1->mtu >= dtls1_min_mtu());  /* should have something reasonable now */
+
+	if ( s->init_off == 0  && type == SSL3_RT_HANDSHAKE)
+		assert(s->init_num == 
+			(int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
+
+	if (s->write_hash)
+		{
+		if (s->enc_write_ctx && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE)
+			mac_size = 0;
+		else
+			mac_size = EVP_MD_CTX_size(s->write_hash);
+		}
+	else
+		mac_size = 0;
+
+	if (s->enc_write_ctx && 
+		(EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
+		blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+	else
+		blocksize = 0;
+
+	frag_off = 0;
+	while( s->init_num)
+		{
+		curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - 
+			DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
+
+		if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
+			{
+			/* grr.. we could get an error if MTU picked was wrong */
+			ret = BIO_flush(SSL_get_wbio(s));
+			if ( ret <= 0)
+				return ret;
+			curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
+				mac_size - blocksize;
+			}
+
+		if ( s->init_num > curr_mtu)
+			len = curr_mtu;
+		else
+			len = s->init_num;
+
+
+		/* XDTLS: this function is too long.  split out the CCS part */
+		if ( type == SSL3_RT_HANDSHAKE)
+			{
+			if ( s->init_off != 0)
+				{
+				assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
+				s->init_off -= DTLS1_HM_HEADER_LENGTH;
+				s->init_num += DTLS1_HM_HEADER_LENGTH;
+
+				if ( s->init_num > curr_mtu)
+					len = curr_mtu;
+				else
+					len = s->init_num;
+				}
+
+			dtls1_fix_message_header(s, frag_off, 
+				len - DTLS1_HM_HEADER_LENGTH);
+
+			dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]);
+
+			assert(len >= DTLS1_HM_HEADER_LENGTH);
+			}
+
+		ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
+			len);
+		if (ret < 0)
+			{
+			/* might need to update MTU here, but we don't know
+			 * which previous packet caused the failure -- so can't
+			 * really retransmit anything.  continue as if everything
+			 * is fine and wait for an alert to handle the
+			 * retransmit 
+			 */
+			if ( BIO_ctrl(SSL_get_wbio(s),
+				BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
+				s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
+					BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+			else
+				return(-1);
+			}
+		else
+			{
+
+			/* bad if this assert fails, only part of the handshake
+			 * message got sent.  but why would this happen? */
+			assert(len == (unsigned int)ret);
+
+			if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
+				{
+				/* should not be done for 'Hello Request's, but in that case
+				 * we'll ignore the result anyway */
+				unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off];
+				const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+				int xlen;
+
+				if (frag_off == 0 && s->version != DTLS1_BAD_VER)
+					{
+					/* reconstruct message header is if it
+					 * is being sent in single fragment */
+					*p++ = msg_hdr->type;
+					l2n3(msg_hdr->msg_len,p);
+					s2n (msg_hdr->seq,p);
+					l2n3(0,p);
+					l2n3(msg_hdr->msg_len,p);
+					p  -= DTLS1_HM_HEADER_LENGTH;
+					xlen = ret;
+					}
+				else
+					{
+					p  += DTLS1_HM_HEADER_LENGTH;
+					xlen = ret - DTLS1_HM_HEADER_LENGTH;
+					}
+
+				ssl3_finish_mac(s, p, xlen);
+				}
+
+			if (ret == s->init_num)
+				{
+				if (s->msg_callback)
+					s->msg_callback(1, s->version, type, s->init_buf->data, 
+						(size_t)(s->init_off + s->init_num), s, 
+						s->msg_callback_arg);
+
+				s->init_off = 0;  /* done writing this message */
+				s->init_num = 0;
+
+				return(1);
+				}
+			s->init_off+=ret;
+			s->init_num-=ret;
+			frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
+			}
+		}
+	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 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)
+		{
+		s->s3->tmp.reuse_message=0;
+		if ((mt >= 0) && (s->s3->tmp.message_type != mt))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_get_message, SSL_R_UNEXPECTED_MESSAGE);
+			goto f_err;
+			}
+		*ok=1;
+		s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+		s->init_num = (int)s->s3->tmp.message_size;
+		return s->init_num;
+		}
+
+	msg_hdr = &s->d1->r_msg_hdr;
+	memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+again:
+	i = dtls1_get_message_fragment(s, stn, max, ok);
+	if ( i == DTLS1_HM_BAD_FRAGMENT ||
+		i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
+		goto again;
+	else if ( i <= 0 && !*ok)
+		return i;
+
+	p = (unsigned char *)s->init_buf->data;
+	msg_len = msg_hdr->msg_len;
+
+	/* reconstruct message header */
+	*(p++) = msg_hdr->type;
+	l2n3(msg_len,p);
+	s2n (msg_hdr->seq,p);
+	l2n3(0,p);
+	l2n3(msg_len,p);
+	if (s->version != DTLS1_BAD_VER) {
+		p       -= DTLS1_HM_HEADER_LENGTH;
+		msg_len += DTLS1_HM_HEADER_LENGTH;
+	}
+
+	ssl3_finish_mac(s, p, msg_len);
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+			p, msg_len,
+			s, s->msg_callback_arg);
+
+	memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+
+	/* Don't change sequence numbers while listening */
+	if (!s->d1->listen)
+		s->d1->handshake_read_seq++;
+
+	s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+	return s->init_num;
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	*ok = 0;
+	return -1;
+	}
+
+
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
+	{
+	size_t frag_off,frag_len,msg_len;
+
+	msg_len  = msg_hdr->msg_len;
+	frag_off = msg_hdr->frag_off;
+	frag_len = msg_hdr->frag_len;
+
+	/* sanity checking */
+	if ( (frag_off+frag_len) > msg_len)
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+		return SSL_AD_ILLEGAL_PARAMETER;
+		}
+
+	if ( (frag_off+frag_len) > (unsigned long)max)
+		{
+		OPENSSL_PUT_ERROR(SSL, 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 above */
+		if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH))
+			{
+			OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, ERR_R_BUF_LIB);
+			return SSL_AD_INTERNAL_ERROR;
+			}
+
+		s->s3->tmp.message_size  = msg_len;
+		s->d1->r_msg_hdr.msg_len = msg_len;
+		s->s3->tmp.message_type  = msg_hdr->type;
+		s->d1->r_msg_hdr.type    = msg_hdr->type;
+		s->d1->r_msg_hdr.seq     = msg_hdr->seq;
+		}
+	else if (msg_len != s->d1->r_msg_hdr.msg_len)
+		{
+		/* They must be playing with us! BTW, failure to enforce
+		 * upper limit would open possibility for buffer overrun. */
+		OPENSSL_PUT_ERROR(SSL, dtls1_preprocess_fragment, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+		return SSL_AD_ILLEGAL_PARAMETER;
+		}
+
+	return 0; /* no error */
+	}
+
+
+static int
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+	{
+	/* (0) check whether the desired fragment is available
+	 * if so:
+	 * (1) copy over the fragment to s->init_buf->data[]
+	 * (2) update s->init_num
+	 */
+	pitem *item;
+	hm_fragment *frag;
+	int al;
+
+	*ok = 0;
+	item = pqueue_peek(s->d1->buffered_messages);
+	if ( item == NULL)
+		return 0;
+
+	frag = (hm_fragment *)item->data;
+	
+	/* Don't return if reassembly still in progress */
+	if (frag->reassembly != NULL)
+		return 0;
+
+	if ( s->d1->handshake_read_seq == frag->msg_header.seq)
+		{
+		unsigned long frag_len = frag->msg_header.frag_len;
+		pqueue_pop(s->d1->buffered_messages);
+
+		al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
+
+		if (al==0) /* no alert */
+			{
+			unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+			memcpy(&p[frag->msg_header.frag_off],
+				frag->fragment,frag->msg_header.frag_len);
+			}
+
+		dtls1_hm_fragment_free(frag);
+		pitem_free(item);
+
+		if (al==0)
+			{
+			*ok = 1;
+			return frag_len;
+			}
+
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		s->init_num = 0;
+		*ok = 0;
+		return -1;
+		}
+	else
+		return 0;
+	}
+
+
+static int
+dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+	{
+	hm_fragment *frag = NULL;
+	pitem *item = NULL;
+	int i = -1, is_complete;
+	unsigned char seq64be[8];
+	unsigned long frag_len = msg_hdr->frag_len, max_len;
+
+	if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+		goto err;
+
+	/* Determine maximum allowed message size. Depends on (user set)
+	 * maximum certificate length, but 16k is minimum.
+	 */
+	if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list)
+		max_len = s->max_cert_list;
+	else
+		max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
+
+	if ((msg_hdr->frag_off+frag_len) > max_len)
+		goto err;
+
+	/* Try to find item in queue */
+	memset(seq64be,0,sizeof(seq64be));
+	seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
+	seq64be[7] = (unsigned char) msg_hdr->seq;
+	item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+	if (item == NULL)
+		{
+		frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
+		if ( frag == NULL)
+			goto err;
+		memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+		frag->msg_header.frag_len = frag->msg_header.msg_len;
+		frag->msg_header.frag_off = 0;
+		}
+	else
+		frag = (hm_fragment*) item->data;
+
+	/* If message is already reassembled, this must be a
+	 * retransmit and can be dropped.
+	 */
+	if (frag->reassembly == NULL)
+		{
+		unsigned char devnull [256];
+
+		while (frag_len)
+			{
+			i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+				devnull,
+				frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
+			if (i<=0) goto err;
+			frag_len -= i;
+			}
+		return DTLS1_HM_FRAGMENT_RETRY;
+		}
+
+	/* read the body of the fragment (header has already been read */
+	i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+		frag->fragment + msg_hdr->frag_off,frag_len,0);
+	if (i<=0 || (unsigned long)i!=frag_len)
+		goto err;
+
+	RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
+	                    (long)(msg_hdr->frag_off + frag_len));
+
+	RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
+	                           is_complete);
+
+	if (is_complete)
+		{
+		OPENSSL_free(frag->reassembly);
+		frag->reassembly = NULL;
+		}
+
+	if (item == NULL)
+		{
+		memset(seq64be,0,sizeof(seq64be));
+		seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
+		seq64be[7] = (unsigned char)(msg_hdr->seq);
+
+		item = pitem_new(seq64be, frag);
+		if (item == NULL)
+			{
+			goto err;
+			i = -1;
+			}
+
+		pqueue_insert(s->d1->buffered_messages, item);
+		}
+
+	return DTLS1_HM_FRAGMENT_RETRY;
+
+err:
+	if (frag != NULL) dtls1_hm_fragment_free(frag);
+	if (item != NULL) OPENSSL_free(item);
+	*ok = 0;
+	return i;
+	}
+
+
+static int
+dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+{
+	int i=-1;
+	hm_fragment *frag = NULL;
+	pitem *item = NULL;
+	unsigned char seq64be[8];
+	unsigned long frag_len = msg_hdr->frag_len;
+
+	if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+		goto err;
+
+	/* Try to find item in queue, to prevent duplicate entries */
+	memset(seq64be,0,sizeof(seq64be));
+	seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
+	seq64be[7] = (unsigned char) msg_hdr->seq;
+	item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+	/* If we already have an entry and this one is a fragment,
+	 * don't discard it and rather try to reassemble it.
+	 */
+	if (item != NULL && frag_len < msg_hdr->msg_len)
+		item = NULL;
+
+	/* Discard the message if sequence number was already there, is
+	 * too far in the future, already in the queue or if we received
+	 * a FINISHED before the SERVER_HELLO, which then must be a stale
+	 * retransmit.
+	 */
+	if (msg_hdr->seq <= s->d1->handshake_read_seq ||
+		msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
+		(s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED))
+		{
+		unsigned char devnull [256];
+
+		while (frag_len)
+			{
+			i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+				devnull,
+				frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
+			if (i<=0) goto err;
+			frag_len -= i;
+			}
+		}
+	else
+		{
+		if (frag_len && frag_len < msg_hdr->msg_len)
+			return dtls1_reassemble_fragment(s, msg_hdr, ok);
+
+		frag = dtls1_hm_fragment_new(frag_len, 0);
+		if ( frag == NULL)
+			goto err;
+
+		memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+		if (frag_len)
+			{
+			/* read the body of the fragment (header has already been read */
+			i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+				frag->fragment,frag_len,0);
+			if (i<=0 || (unsigned long)i!=frag_len)
+				goto err;
+			}
+
+		memset(seq64be,0,sizeof(seq64be));
+		seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
+		seq64be[7] = (unsigned char)(msg_hdr->seq);
+
+		item = pitem_new(seq64be, frag);
+		if ( item == NULL)
+			goto err;
+
+		pqueue_insert(s->d1->buffered_messages, item);
+		}
+
+	return DTLS1_HM_FRAGMENT_RETRY;
+
+err:
+	if ( frag != NULL) dtls1_hm_fragment_free(frag);
+	if ( item != NULL) OPENSSL_free(item);
+	*ok = 0;
+	return i;
+	}
+
+
+static long
+dtls1_get_message_fragment(SSL *s, int stn, long max, int *ok)
+	{
+	unsigned char wire[DTLS1_HM_HEADER_LENGTH];
+	unsigned long len, frag_off, frag_len;
+	int i,al;
+	struct hm_header_st msg_hdr;
+
+	/* see if we have the required fragment already */
+	if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
+		{
+		if (*ok)	s->init_num = frag_len;
+		return frag_len;
+		}
+
+	/* read handshake message header */
+	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
+		DTLS1_HM_HEADER_LENGTH, 0);
+	if (i <= 0) 	/* nbio, or an error */
+		{
+		s->rwstate=SSL_READING;
+		*ok = 0;
+		return i;
+		}
+	/* Handshake fails if message header is incomplete */
+	if (i != DTLS1_HM_HEADER_LENGTH)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, SSL_R_UNEXPECTED_MESSAGE);
+		goto f_err;
+		}
+
+	/* parse the message fragment header */
+	dtls1_get_message_header(wire, &msg_hdr);
+
+	/* 
+	 * if this is a future (or stale) message it gets buffered
+	 * (or dropped)--no further processing at this time
+	 * 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 && !(s->d1->listen && msg_hdr.seq == 1))
+		return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
+
+	len = msg_hdr.msg_len;
+	frag_off = msg_hdr.frag_off;
+	frag_len = msg_hdr.frag_len;
+
+	if (frag_len && frag_len < len)
+		return dtls1_reassemble_fragment(s, &msg_hdr, ok);
+
+	if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
+		wire[0] == SSL3_MT_HELLO_REQUEST)
+		{
+		/* The server may always send 'Hello Request' messages --
+		 * we are doing a handshake anyway now, so ignore them
+		 * if their format is correct. Does not count for
+		 * 'Finished' MAC. */
+		if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
+			{
+			if (s->msg_callback)
+				s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
+					wire, DTLS1_HM_HEADER_LENGTH, s, 
+					s->msg_callback_arg);
+			
+			s->init_num = 0;
+			return dtls1_get_message_fragment(s, stn,
+				max, ok);
+			}
+		else /* Incorrectly formated Hello request */
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, SSL_R_UNEXPECTED_MESSAGE);
+			goto f_err;
+			}
+		}
+
+	if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
+		goto f_err;
+
+	/* XDTLS:  ressurect this when restart is in place */
+	s->state=stn;
+
+	if ( frag_len > 0)
+		{
+		unsigned char *p=(unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+
+		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+			&p[frag_off],frag_len,0);
+		/* XDTLS:  fix this--message fragments cannot span multiple packets */
+		if (i <= 0)
+			{
+			s->rwstate=SSL_READING;
+			*ok = 0;
+			return i;
+			}
+		}
+	else
+		i = 0;
+
+	/* XDTLS:  an incorrectly formatted fragment should cause the 
+	 * handshake to fail */
+	if (i != (int)frag_len)
+		{
+		al=SSL3_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, dtls1_get_message_fragment, SSL3_AD_ILLEGAL_PARAMETER);
+		goto f_err;
+		}
+
+	*ok = 1;
+
+	/* 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;
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	s->init_num = 0;
+
+	*ok=0;
+	return(-1);
+	}
+
+/* for these 2 messages, we need to
+ * ssl->enc_read_ctx			re-init
+ * ssl->s3->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 dtls1_send_change_cipher_spec(SSL *s, int a, int b)
+	{ 
+	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;
+
+		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;
+
+		dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, 
+			s->d1->handshake_write_seq, 0, 0);
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 1);
+
+		s->state=b;
+		}
+
+	/* SSL3_ST_CW_CHANGE_B */
+	return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+	}
+
+int dtls1_read_failed(SSL *s, int code)
+	{
+	if ( code > 0)
+		{
+		fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
+		return 1;
+		}
+
+	if (!dtls1_is_timer_expired(s))
+		{
+		/* not a timeout, none of our business, 
+		   let higher layers handle this.  in fact it's probably an error */
+		return code;
+		}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	if (!SSL_in_init(s) && !s->tlsext_hb_pending)  /* done, no need to send a retransmit */
+#else
+	if (!SSL_in_init(s))  /* done, no need to send a retransmit */
+#endif
+		{
+		BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
+		return code;
+		}
+
+#if 0 /* for now, each alert contains only one record number */
+	item = pqueue_peek(state->rcvd_records);
+	if ( item )
+		{
+		/* send an alert immediately for all the missing records */
+		}
+	else
+#endif
+
+#if 0  /* no more alert sending, just retransmit the last set of messages */
+	if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
+		ssl3_send_alert(s,SSL3_AL_WARNING,
+			DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+#endif
+
+	return dtls1_handle_timeout(s);
+	}
+
+int
+dtls1_get_queue_priority(unsigned short seq, int is_ccs)
+	{
+	/* The index of the retransmission queue actually is the message sequence number,
+	 * since the queue only contains messages of a single handshake. However, the
+	 * ChangeCipherSpec has no message sequence number and so using only the sequence
+	 * will result in the CCS and Finished having the same index. To prevent this,
+	 * the sequence number is multiplied by 2. In case of a CCS 1 is subtracted.
+	 * This does not only differ CSS and Finished, it also maintains the order of the
+	 * index (important for priority queues) and fits in the unsigned short variable.
+	 */	
+	return seq * 2 - is_ccs;
+	}
+
+int
+dtls1_retransmit_buffered_messages(SSL *s)
+	{
+	pqueue sent = s->d1->sent_messages;
+	piterator iter;
+	pitem *item;
+	hm_fragment *frag;
+	int found = 0;
+
+	iter = pqueue_iterator(sent);
+
+	for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter))
+		{
+		frag = (hm_fragment *)item->data;
+			if ( dtls1_retransmit_message(s,
+				(unsigned short)dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs),
+				0, &found) <= 0 && found)
+			{
+			fprintf(stderr, "dtls1_retransmit_message() failed\n");
+			return -1;
+			}
+		}
+
+	return 1;
+	}
+
+int
+dtls1_buffer_message(SSL *s, int is_ccs)
+	{
+	pitem *item;
+	hm_fragment *frag;
+	unsigned char seq64be[8];
+
+	/* this function is called immediately after a message has 
+	 * been serialized */
+	assert(s->init_off == 0);
+
+	frag = dtls1_hm_fragment_new(s->init_num, 0);
+
+	memcpy(frag->fragment, s->init_buf->data, s->init_num);
+
+	if ( is_ccs)
+		{
+		assert(s->d1->w_msg_hdr.msg_len + 
+			       DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num);
+		}
+	else
+		{
+		assert(s->d1->w_msg_hdr.msg_len + 
+			DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num);
+		}
+
+	frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
+	frag->msg_header.seq = s->d1->w_msg_hdr.seq;
+	frag->msg_header.type = s->d1->w_msg_hdr.type;
+	frag->msg_header.frag_off = 0;
+	frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
+	frag->msg_header.is_ccs = is_ccs;
+
+	/* save current state*/
+	frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
+	frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
+	frag->msg_header.saved_retransmit_state.compress = s->compress;
+	frag->msg_header.saved_retransmit_state.session = s->session;
+	frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch;
+	
+	memset(seq64be,0,sizeof(seq64be));
+	seq64be[6] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
+														  frag->msg_header.is_ccs)>>8);
+	seq64be[7] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq,
+														  frag->msg_header.is_ccs));
+
+	item = pitem_new(seq64be, frag);
+	if ( item == NULL)
+		{
+		dtls1_hm_fragment_free(frag);
+		return 0;
+		}
+
+#if 0
+	fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type);
+	fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len);
+	fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num);
+#endif
+
+	pqueue_insert(s->d1->sent_messages, item);
+	return 1;
+	}
+
+int
+dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
+	int *found)
+	{
+	int ret;
+	/* XDTLS: for now assuming that read/writes are blocking */
+	pitem *item;
+	hm_fragment *frag ;
+	unsigned long header_length;
+	unsigned char seq64be[8];
+	struct dtls1_retransmit_state saved_state;
+	unsigned char save_write_sequence[8];
+
+	/*
+	  assert(s->init_num == 0);
+	  assert(s->init_off == 0);
+	 */
+
+	/* XDTLS:  the requested message ought to be found, otherwise error */
+	memset(seq64be,0,sizeof(seq64be));
+	seq64be[6] = (unsigned char)(seq>>8);
+	seq64be[7] = (unsigned char)seq;
+
+	item = pqueue_find(s->d1->sent_messages, seq64be);
+	if ( item == NULL)
+		{
+		fprintf(stderr, "retransmit:  message %d non-existant\n", seq);
+		*found = 0;
+		return 0;
+		}
+
+	*found = 1;
+	frag = (hm_fragment *)item->data;
+
+	if ( frag->msg_header.is_ccs)
+		header_length = DTLS1_CCS_HEADER_LENGTH;
+	else
+		header_length = DTLS1_HM_HEADER_LENGTH;
+
+	memcpy(s->init_buf->data, frag->fragment, 
+		frag->msg_header.msg_len + header_length);
+		s->init_num = frag->msg_header.msg_len + header_length;
+
+	dtls1_set_message_header_int(s, frag->msg_header.type, 
+		frag->msg_header.msg_len, frag->msg_header.seq, 0, 
+		frag->msg_header.frag_len);
+
+	/* save current state */
+	saved_state.enc_write_ctx = s->enc_write_ctx;
+	saved_state.write_hash = s->write_hash;
+	saved_state.compress = s->compress;
+	saved_state.session = s->session;
+	saved_state.epoch = s->d1->w_epoch;
+	saved_state.epoch = s->d1->w_epoch;
+	
+	s->d1->retransmitting = 1;
+	
+	/* restore state in which the message was originally sent */
+	s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx;
+	s->write_hash = frag->msg_header.saved_retransmit_state.write_hash;
+	s->compress = frag->msg_header.saved_retransmit_state.compress;
+	s->session = frag->msg_header.saved_retransmit_state.session;
+	s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch;
+	
+	if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+	{
+		memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+		memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence));
+	}
+	
+	ret = dtls1_do_write(s, frag->msg_header.is_ccs ? 
+						 SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+	
+	/* restore current state */
+	s->enc_write_ctx = saved_state.enc_write_ctx;
+	s->write_hash = saved_state.write_hash;
+	s->compress = saved_state.compress;
+	s->session = saved_state.session;
+	s->d1->w_epoch = saved_state.epoch;
+	
+	if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+	{
+		memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+		memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence));
+	}
+
+	s->d1->retransmitting = 0;
+
+	(void)BIO_flush(SSL_get_wbio(s));
+	return ret;
+	}
+
+/* call this function when the buffered messages are no longer needed */
+void
+dtls1_clear_record_buffer(SSL *s)
+	{
+	pitem *item;
+
+	for(item = pqueue_pop(s->d1->sent_messages);
+		item != NULL; item = pqueue_pop(s->d1->sent_messages))
+		{
+		dtls1_hm_fragment_free((hm_fragment *)item->data);
+		pitem_free(item);
+		}
+	}
+
+
+unsigned char *
+dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt,
+			unsigned long len, unsigned long frag_off, unsigned long frag_len)
+	{
+	/* Don't change sequence numbers while listening */
+	if (frag_off == 0 && !s->d1->listen)
+		{
+		s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+		s->d1->next_handshake_write_seq++;
+		}
+
+	dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
+		frag_off, frag_len);
+
+	return p += DTLS1_HM_HEADER_LENGTH;
+	}
+
+
+/* don't actually do the writing, wait till the MTU has been retrieved */
+static void
+dtls1_set_message_header_int(SSL *s, unsigned char mt,
+			    unsigned long len, unsigned short seq_num, unsigned long frag_off,
+			    unsigned long frag_len)
+	{
+	struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+	msg_hdr->type = mt;
+	msg_hdr->msg_len = len;
+	msg_hdr->seq = seq_num;
+	msg_hdr->frag_off = frag_off;
+	msg_hdr->frag_len = frag_len;
+	}
+
+static void
+dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+			unsigned long frag_len)
+	{
+	struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+	msg_hdr->frag_off = frag_off;
+	msg_hdr->frag_len = frag_len;
+	}
+
+static unsigned char *
+dtls1_write_message_header(SSL *s, unsigned char *p)
+	{
+	struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+	*p++ = msg_hdr->type;
+	l2n3(msg_hdr->msg_len, p);
+
+	s2n(msg_hdr->seq, p);
+	l2n3(msg_hdr->frag_off, p);
+	l2n3(msg_hdr->frag_len, p);
+
+	return p;
+	}
+
+unsigned int 
+dtls1_min_mtu(void)
+	{
+	return (g_probable_mtu[(sizeof(g_probable_mtu) / 
+		sizeof(g_probable_mtu[0])) - 1]);
+	}
+
+static unsigned int 
+dtls1_guess_mtu(unsigned int curr_mtu)
+	{
+	unsigned int i;
+
+	if ( curr_mtu == 0 )
+		return g_probable_mtu[0] ;
+
+	for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
+		if ( curr_mtu > g_probable_mtu[i])
+			return g_probable_mtu[i];
+
+	return curr_mtu;
+	}
+
+void
+dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
+	{
+	memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+	msg_hdr->type = *(data++);
+	n2l3(data, msg_hdr->msg_len);
+
+	n2s(data, msg_hdr->seq);
+	n2l3(data, msg_hdr->frag_off);
+	n2l3(data, msg_hdr->frag_len);
+	}
+
+void
+dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
+	{
+	memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
+
+	ccs_hdr->type = *(data++);
+	}
+
+int dtls1_shutdown(SSL *s)
+	{
+	int ret;
+	ret = ssl3_shutdown(s);
+	return ret;
+	}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+dtls1_process_heartbeat(SSL *s)
+	{
+	unsigned char *p = &s->s3->rrec.data[0], *pl;
+	unsigned short hbtype;
+	unsigned int payload;
+	unsigned int padding = 16; /* Use minimum padding */
+
+	/* Read type and payload length first */
+	hbtype = *p++;
+	n2s(p, payload);
+	pl = p;
+
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+			&s->s3->rrec.data[0], s->s3->rrec.length,
+			s, s->msg_callback_arg);
+
+	if (hbtype == TLS1_HB_REQUEST)
+		{
+		unsigned char *buffer, *bp;
+		int r;
+
+		/* Allocate memory for the response, size is 1 byte
+		 * message type, plus 2 bytes payload length, plus
+		 * payload, plus padding
+		 */
+		buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+		bp = buffer;
+
+		/* Enter response type, length and copy payload */
+		*bp++ = TLS1_HB_RESPONSE;
+		s2n(payload, bp);
+		memcpy(bp, pl, payload);
+		bp += payload;
+		/* Random padding */
+		RAND_pseudo_bytes(bp, padding);
+
+		r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+		if (r >= 0 && s->msg_callback)
+			s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+				buffer, 3 + payload + padding,
+				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;
+	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)
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_heartbeat, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+		return -1;
+		}
+
+	/* ...and there is none in flight yet... */
+	if (s->tlsext_hb_pending)
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_heartbeat, SSL_R_TLS_HEARTBEAT_PENDING);
+		return -1;
+		}
+
+	/* ...and no handshake in progress. */
+	if (SSL_in_init(s) || s->in_handshake)
+		{
+		OPENSSL_PUT_ERROR(SSL, 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.
+	 */
+	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);
+	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 */
+	RAND_pseudo_bytes(p, 16);
+	p += 16;
+	/* Random padding */
+	RAND_pseudo_bytes(p, padding);
+
+	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;
+		}
+
+	OPENSSL_free(buf);
+
+	return ret;
+	}
+#endif
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
new file mode 100644
index 0000000..b0adaa1
--- /dev/null
+++ b/ssl/d1_clnt.c
@@ -0,0 +1,683 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/bn.h>
+#include <openssl/buf.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+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;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state,skip=0;
+
+	ERR_clear_error();
+	ERR_clear_system_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)) SSL_clear(s); 
+
+#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))
+				{
+				OPENSSL_PUT_ERROR(SSL, dtls1_connect, ERR_R_INTERNAL_ERROR);
+				ret = -1;
+				goto end;
+				}
+				
+			/* s->version=SSL3_VERSION; */
+			s->type=SSL_ST_CONNECT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				buf=NULL;
+				}
+
+			if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
+
+			/* setup buffing BIO */
+			if (!ssl_init_wbio_buffer(s,0)) { ret= -1; 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;
+			break;
+
+		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;
+				/* turn on buffering for the next lot of output */
+				if (s->bbio != s->wbio)
+					s->wbio=BIO_push(s->bbio,s->wbio);
+
+			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)
+					{
+					s->state=SSL3_ST_CR_FINISHED_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:
+#ifndef OPENSSL_NO_TLSEXT
+			ret=ssl3_check_finished(s);
+			if (ret <= 0) goto end;
+			if (ret == 2)
+				{
+				s->hit = 1;
+				if (s->tlsext_ticket_expected)
+					s->state=SSL3_ST_CR_SESSION_TICKET_A;
+				else
+					s->state=SSL3_ST_CR_FINISHED_A;
+				s->init_num=0;
+				break;
+				}
+#endif
+			/* 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;
+#ifndef OPENSSL_NO_TLSEXT
+				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;
+				}
+#else
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
+			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;
+				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;
+			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;
+
+			/* 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
+				{
+				s->state=SSL3_ST_CW_CHANGE_A;
+				s->s3->change_cipher_spec=0;
+				}
+
+			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;
+			s->state=SSL3_ST_CW_CHANGE_A;
+			s->init_num=0;
+			s->s3->change_cipher_spec=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;
+			s->session->compress_meth=0;
+			if (!s->method->ssl3_enc->setup_key_block(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			if (!s->method->ssl3_enc->change_cipher_state(s,
+				SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+				{
+				ret= -1;
+				goto end;
+				}
+			
+			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;
+
+			/* clear flags */
+			s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
+			if (s->hit)
+				{
+				s->s3->tmp.next_state=SSL_ST_OK;
+				if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
+					{
+					s->state=SSL_ST_OK;
+					s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
+					s->s3->delay_buf_pop_ret=0;
+					}
+				}
+			else
+				{
+
+#ifndef OPENSSL_NO_TLSEXT
+				/* Allow NewSessionTicket if ticket expected */
+				if (s->tlsext_ticket_expected)
+					s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+				else
+#endif
+				
+				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+				}
+			s->init_num=0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		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_FINISHED_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;
+#endif
+
+		case SSL3_ST_CR_FINISHED_A:
+		case SSL3_ST_CR_FINISHED_B:
+			s->d1->change_cipher_spec_ok = 1;
+			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;
+
+			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);
+
+#if 0
+			if (s->init_buf != NULL)
+				{
+				BUF_MEM_free(s->init_buf);
+				s->init_buf=NULL;
+				}
+#endif
+
+			/* If we are not 'joining' the last two packets,
+			 * remove the buffering now */
+			if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
+				ssl_free_wbio_buffer(s);
+			/* else do it later in ssl3_write */
+
+			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; */
+			
+		default:
+			OPENSSL_PUT_ERROR(SSL, 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--;
+	
+	if (buf != NULL)
+		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;
+#if 0
+	if (s->method->version != DTLS_ANY_VERSION &&
+		((data[0] != (s->version>>8)) || (data[1] != (s->version&0xff))))
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_get_hello_verify, SSL_R_WRONG_SSL_VERSION);
+		s->version=(s->version&0xff00)|data[1];
+		al = SSL_AD_PROTOCOL_VERSION;
+		goto f_err;
+		}
+#endif
+	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);
+	return -1;
+	}
+
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
new file mode 100644
index 0000000..8e2cdc8
--- /dev/null
+++ b/ssl/d1_enc.c
@@ -0,0 +1,257 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 
+ */
+/* ====================================================================
+ * Copyright (c) 1998-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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 <assert.h>
+
+#include <openssl/comp.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+
+/* dtls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publically invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
+ *       an internal error occured. */
+int dtls1_enc(SSL *s, int send)
+	{
+	SSL3_RECORD *rec;
+	EVP_CIPHER_CTX *ds;
+	unsigned long l;
+	int bs,i,j,k,mac_size=0;
+	const EVP_CIPHER *enc;
+
+	if (send)
+		{
+		if (EVP_MD_CTX_md(s->write_hash))
+			{
+			mac_size=EVP_MD_CTX_size(s->write_hash);
+			if (mac_size < 0)
+				return -1;
+			}
+		ds=s->enc_write_ctx;
+		rec= &(s->s3->wrec);
+		if (s->enc_write_ctx == NULL)
+			enc=NULL;
+		else
+			{
+			enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+			if ( rec->data != rec->input)
+				/* we can't write into the input stream */
+				fprintf(stderr, "%s:%d: rec->data != rec->input\n",
+					__FILE__, __LINE__);
+			else if ( EVP_CIPHER_block_size(ds->cipher) > 1)
+				{
+				if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0)
+					return -1;
+				}
+			}
+		}
+	else
+		{
+		if (EVP_MD_CTX_md(s->read_hash))
+			{
+			mac_size=EVP_MD_CTX_size(s->read_hash);
+			assert(mac_size >= 0);
+			}
+		ds=s->enc_read_ctx;
+		rec= &(s->s3->rrec);
+		if (s->enc_read_ctx == NULL)
+			enc=NULL;
+		else
+			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+		}
+
+#ifdef KSSL_DEBUG
+	printf("dtls1_enc(%d)\n", send);
+#endif    /* KSSL_DEBUG */
+
+	if ((s->session == NULL) || (ds == NULL) ||
+		(enc == NULL))
+		{
+		memmove(rec->data,rec->input,rec->length);
+		rec->input=rec->data;
+		}
+	else
+		{
+		l=rec->length;
+		bs=EVP_CIPHER_block_size(ds->cipher);
+
+		if ((bs != 1) && send)
+			{
+			i=bs-((int)l%bs);
+
+			/* Add weird padding of upto 256 bytes */
+
+			/* we need to add 'i' padding bytes of value j */
+			j=i-1;
+			if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
+				{
+				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+					j++;
+				}
+			for (k=(int)l; k<(int)(l+i); k++)
+				rec->input[k]=j;
+			l+=i;
+			rec->length+=i;
+			}
+
+#ifdef KSSL_DEBUG
+		{
+                unsigned long ui;
+		printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
+                        ds,rec->data,rec->input,l);
+		printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
+                        ds->buf_len, ds->cipher->key_len,
+                        DES_KEY_SZ, DES_SCHEDULE_SZ,
+                        ds->cipher->iv_len);
+		printf("\t\tIV: ");
+		for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
+		printf("\n");
+		printf("\trec->input=");
+		for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
+		printf("\n");
+		}
+#endif	/* KSSL_DEBUG */
+
+		if (!send)
+			{
+			if (l == 0 || l%bs != 0)
+				return 0;
+			}
+		
+		EVP_Cipher(ds,rec->data,rec->input,l);
+
+#ifdef KSSL_DEBUG
+		{
+                unsigned long i;
+                printf("\trec->data=");
+		for (i=0; i<l; i++)
+                        printf(" %02x", rec->data[i]);  printf("\n");
+                }
+#endif	/* KSSL_DEBUG */
+
+		if ((bs != 1) && !send)
+			return tls1_cbc_remove_padding(s, rec, bs, mac_size);
+		}
+	return(1);
+	}
+
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
new file mode 100644
index 0000000..4dc3a2b
--- /dev/null
+++ b/ssl/d1_lib.c
@@ -0,0 +1,515 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/base.h>
+
+#include <stdio.h>
+
+#if defined(OPENSSL_WINDOWS)
+#include <sys/timeb.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "ssl_locl.h"
+
+static void get_current_time(struct timeval *t);
+static void 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);
+
+SSL3_ENC_METHOD DTLSv1_enc_data={
+    	tls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	tls1_export_keying_material,
+	SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV,
+	DTLS1_HM_HEADER_LENGTH,
+	dtls1_set_handshake_header,
+	dtls1_handshake_write	
+	};
+
+SSL3_ENC_METHOD DTLSv1_2_enc_data={
+    	tls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	tls1_export_keying_material,
+	SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS
+		|SSL_ENC_FLAG_SHA256_PRF|SSL_ENC_FLAG_TLS1_2_CIPHERS,
+	DTLS1_HM_HEADER_LENGTH,
+	dtls1_set_handshake_header,
+	dtls1_handshake_write	
+	};
+
+long dtls1_default_timeout(void)
+	{
+	/* 2 hours, the 24 hours mentioned in the DTLSv1 spec
+	 * is way too long for http, the cache would over fill */
+	return(60*60*2);
+	}
+
+int dtls1_new(SSL *s)
+	{
+	DTLS1_STATE *d1;
+
+	if (!ssl3_new(s)) return(0);
+	if ((d1=OPENSSL_malloc(sizeof *d1)) == NULL) return (0);
+	memset(d1,0, sizeof *d1);
+
+	/* d1->handshake_epoch=0; */
+
+	d1->unprocessed_rcds.q=pqueue_new();
+	d1->processed_rcds.q=pqueue_new();
+	d1->buffered_messages = pqueue_new();
+	d1->sent_messages=pqueue_new();
+	d1->buffered_app_data.q=pqueue_new();
+
+	if ( s->server)
+		{
+		d1->cookie_len = sizeof(s->d1->cookie);
+		}
+
+	if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q 
+        || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q)
+		{
+        if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
+        if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q);
+        if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
+		if ( d1->sent_messages) pqueue_free(d1->sent_messages);
+		if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q);
+		OPENSSL_free(d1);
+		return (0);
+		}
+
+	s->d1=d1;
+	s->method->ssl_clear(s);
+	return(1);
+	}
+
+static void dtls1_clear_queues(SSL *s)
+	{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
+	DTLS1_RECORD_DATA *rdata;
+
+    while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL)
+        {
+		rdata = (DTLS1_RECORD_DATA *) item->data;
+		if (rdata->rbuf.buf)
+			{
+			OPENSSL_free(rdata->rbuf.buf);
+			}
+        OPENSSL_free(item->data);
+        pitem_free(item);
+        }
+
+    while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL)
+        {
+		rdata = (DTLS1_RECORD_DATA *) item->data;
+		if (rdata->rbuf.buf)
+			{
+			OPENSSL_free(rdata->rbuf.buf);
+			}
+        OPENSSL_free(item->data);
+        pitem_free(item);
+        }
+
+    while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL)
+        {
+        frag = (hm_fragment *)item->data;
+        OPENSSL_free(frag->fragment);
+        OPENSSL_free(frag);
+        pitem_free(item);
+        }
+
+    while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL)
+        {
+        frag = (hm_fragment *)item->data;
+        OPENSSL_free(frag->fragment);
+        OPENSSL_free(frag);
+        pitem_free(item);
+        }
+
+	while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL)
+		{
+		frag = (hm_fragment *)item->data;
+		OPENSSL_free(frag->fragment);
+		OPENSSL_free(frag);
+		pitem_free(item);
+		}
+	}
+
+void dtls1_free(SSL *s)
+	{
+	ssl3_free(s);
+
+	dtls1_clear_queues(s);
+
+    pqueue_free(s->d1->unprocessed_rcds.q);
+    pqueue_free(s->d1->processed_rcds.q);
+    pqueue_free(s->d1->buffered_messages);
+	pqueue_free(s->d1->sent_messages);
+	pqueue_free(s->d1->buffered_app_data.q);
+
+	OPENSSL_free(s->d1);
+	s->d1 = NULL;
+	}
+
+void dtls1_clear(SSL *s)
+	{
+    pqueue unprocessed_rcds;
+    pqueue processed_rcds;
+    pqueue buffered_messages;
+	pqueue sent_messages;
+	pqueue buffered_app_data;
+	unsigned int mtu;
+
+	if (s->d1)
+		{
+		unprocessed_rcds = s->d1->unprocessed_rcds.q;
+		processed_rcds = s->d1->processed_rcds.q;
+		buffered_messages = s->d1->buffered_messages;
+		sent_messages = s->d1->sent_messages;
+		buffered_app_data = s->d1->buffered_app_data.q;
+		mtu = s->d1->mtu;
+
+		dtls1_clear_queues(s);
+
+		memset(s->d1, 0, sizeof(*(s->d1)));
+
+		if (s->server)
+			{
+			s->d1->cookie_len = sizeof(s->d1->cookie);
+			}
+
+		if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)
+			{
+			s->d1->mtu = mtu;
+			}
+
+		s->d1->unprocessed_rcds.q = unprocessed_rcds;
+		s->d1->processed_rcds.q = processed_rcds;
+		s->d1->buffered_messages = buffered_messages;
+		s->d1->sent_messages = sent_messages;
+		s->d1->buffered_app_data.q = buffered_app_data;
+		}
+
+	ssl3_clear(s);
+	if (s->options & SSL_OP_CISCO_ANYCONNECT)
+		s->version=DTLS1_BAD_VER;
+	else if (s->method->version == DTLS_ANY_VERSION)
+		s->version=DTLS1_2_VERSION;
+	else
+		s->version=s->method->version;
+	}
+
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
+	{
+	int ret=0;
+
+	switch (cmd)
+		{
+	case DTLS_CTRL_GET_TIMEOUT:
+		if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL)
+			{
+			ret = 1;
+			}
+		break;
+	case DTLS_CTRL_HANDLE_TIMEOUT:
+		ret = dtls1_handle_timeout(s);
+		break;
+	case DTLS_CTRL_LISTEN:
+		ret = dtls1_listen(s, parg);
+		break;
+
+	default:
+		ret = ssl3_ctrl(s, cmd, larg, parg);
+		break;
+		}
+	return(ret);
+	}
+
+/*
+ * As it's impossible to use stream ciphers in "datagram" mode, this
+ * simple filter is designed to disengage them in DTLS. Unfortunately
+ * there is no universal way to identify stream SSL_CIPHER, so we have
+ * to explicitly list their SSL_* codes. Currently RC4 is the only one
+ * available, but if new ones emerge, they will have to be added...
+ */
+const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
+	{
+	const SSL_CIPHER *ciph = ssl3_get_cipher(u);
+
+	if (ciph != NULL)
+		{
+		if (ciph->algorithm_enc == SSL_RC4)
+			return NULL;
+		}
+
+	return ciph;
+	}
+
+void dtls1_start_timer(SSL *s)
+	{
+	/* If timer is not set, initialize duration with 1 second */
+	if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+		{
+		s->d1->timeout_duration = 1;
+		}
+	
+	/* Set timeout to current time */
+	get_current_time(&(s->d1->next_timeout));
+
+	/* Add duration to current time */
+	s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
+	BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+	}
+
+struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft)
+	{
+	struct timeval timenow;
+
+	/* If no timeout is set, just return NULL */
+	if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+		{
+		return NULL;
+		}
+
+	/* Get current time */
+	get_current_time(&timenow);
+
+	/* If timer already expired, set remaining time to 0 */
+	if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
+		(s->d1->next_timeout.tv_sec == timenow.tv_sec &&
+		 s->d1->next_timeout.tv_usec <= timenow.tv_usec))
+		{
+		memset(timeleft, 0, sizeof(struct timeval));
+		return timeleft;
+		}
+
+	/* Calculate time left until timer expires */
+	memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
+	timeleft->tv_sec -= timenow.tv_sec;
+	timeleft->tv_usec -= timenow.tv_usec;
+	if (timeleft->tv_usec < 0)
+		{
+		timeleft->tv_sec--;
+		timeleft->tv_usec += 1000000;
+		}
+
+	/* If remaining time is less than 15 ms, set it to 0
+	 * to prevent issues because of small devergences with
+	 * socket timeouts.
+	 */
+	if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000)
+		{
+		memset(timeleft, 0, sizeof(struct timeval));
+		}
+	
+
+	return timeleft;
+	}
+
+int dtls1_is_timer_expired(SSL *s)
+	{
+	struct timeval timeleft;
+
+	/* Get time left until timeout, return false if no timer running */
+	if (dtls1_get_timeout(s, &timeleft) == NULL)
+		{
+		return 0;
+		}
+
+	/* Return false if timer is not expired yet */
+	if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0)
+		{
+		return 0;
+		}
+
+	/* Timer expired, so return true */	
+	return 1;
+	}
+
+void dtls1_double_timeout(SSL *s)
+	{
+	s->d1->timeout_duration *= 2;
+	if (s->d1->timeout_duration > 60)
+		s->d1->timeout_duration = 60;
+	dtls1_start_timer(s);
+	}
+
+void dtls1_stop_timer(SSL *s)
+	{
+	/* Reset everything */
+	memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st));
+	memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
+	s->d1->timeout_duration = 1;
+	BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+	/* Clear retransmission buffer */
+	dtls1_clear_record_buffer(s);
+	}
+
+int dtls1_check_timeout_num(SSL *s)
+	{
+	s->d1->timeout.num_alerts++;
+
+	/* Reduce MTU after 2 unsuccessful retransmissions */
+	if (s->d1->timeout.num_alerts > 2)
+		{
+		s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);		
+		}
+
+	if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+		{
+		/* fail the connection, enough alerts have been sent */
+		OPENSSL_PUT_ERROR(SSL, dtls1_check_timeout_num, SSL_R_READ_TIMEOUT_EXPIRED);
+		return -1;
+		}
+
+	return 0;
+	}
+
+int dtls1_handle_timeout(SSL *s)
+	{
+	/* if no timer is expired, don't do anything */
+	if (!dtls1_is_timer_expired(s))
+		{
+		return 0;
+		}
+
+	dtls1_double_timeout(s);
+
+	if (dtls1_check_timeout_num(s) < 0)
+		return -1;
+
+	s->d1->timeout.read_timeouts++;
+	if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
+		{
+		s->d1->timeout.read_timeouts = 1;
+		}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	if (s->tlsext_hb_pending)
+		{
+		s->tlsext_hb_pending = 0;
+		return dtls1_heartbeat(s);
+		}
+#endif
+
+	dtls1_start_timer(s);
+	return dtls1_retransmit_buffered_messages(s);
+	}
+
+static void get_current_time(struct timeval *t)
+{
+#ifdef OPENSSL_SYS_WIN32
+	struct _timeb tb;
+	_ftime(&tb);
+	t->tv_sec = (long)tb.time;
+	t->tv_usec = (long)tb.millitm * 1000;
+#else
+	gettimeofday(t, NULL);
+#endif
+}
+
+int dtls1_listen(SSL *s, struct sockaddr *client)
+	{
+	int ret;
+
+	SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
+	s->d1->listen = 1;
+
+	ret = SSL_accept(s);
+	if (ret <= 0) return ret;
+	
+	BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_GET_PEER, 0, &client);
+	return 1;
+	}
+
+static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len)
+	{
+	unsigned char *p = (unsigned char *)s->init_buf->data;
+	dtls1_set_message_header(s, p, htype, len, 0, len);
+	s->init_num = (int)len + DTLS1_HM_HEADER_LENGTH;
+	s->init_off = 0;
+	/* Buffer the message to handle re-xmits */
+	dtls1_buffer_message(s, 0);
+	}
+
+static int dtls1_handshake_write(SSL *s)
+	{
+	return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
+	}
diff --git a/ssl/d1_meth.c b/ssl/d1_meth.c
new file mode 100644
index 0000000..47e2d5c
--- /dev/null
+++ b/ssl/d1_meth.c
@@ -0,0 +1,95 @@
+/* ssl/d1_meth.h */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <stdio.h>
+
+#include <openssl/obj.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_pkt.c b/ssl/d1_pkt.c
new file mode 100644
index 0000000..d8508d2
--- /dev/null
+++ b/ssl/d1_pkt.c
@@ -0,0 +1,1825 @@
+/* DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */
+/* ====================================================================
+ * Copyright (c) 1998-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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 <errno.h>
+#include <assert.h>
+
+#include <openssl/buf.h>
+#include <openssl/mem.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+/* mod 128 saturating subtract of two 64-bit values in big-endian order */
+static int satsub64be(const unsigned char *v1,const unsigned char *v2)
+{	int ret,sat,brw,i;
+
+	if (sizeof(long) == 8) do
+	{	const union { long one; char little; } is_endian = {1};
+		long l;
+
+		if (is_endian.little)			break;
+		/* not reached on little-endians */
+		/* following test is redundant, because input is
+		 * always aligned, but I take no chances... */
+		if (((size_t)v1|(size_t)v2)&0x7)	break;
+
+		l  = *((long *)v1);
+		l -= *((long *)v2);
+		if (l>128)		return 128;
+		else if (l<-128)	return -128;
+		else			return (int)l;
+	} while (0);
+
+	ret = (int)v1[7]-(int)v2[7];
+	sat = 0;
+	brw = ret>>8;	/* brw is either 0 or -1 */
+	if (ret & 0x80)
+	{	for (i=6;i>=0;i--)
+		{	brw += (int)v1[i]-(int)v2[i];
+			sat |= ~brw;
+			brw >>= 8;
+		}
+	}
+	else
+	{	for (i=6;i>=0;i--)
+		{	brw += (int)v1[i]-(int)v2[i];
+			sat |= brw;
+			brw >>= 8;
+		}
+	}
+	brw <<= 8;	/* brw is either 0 or -256 */
+
+	if (sat&0xff)	return brw | 0x80;
+	else		return brw + (ret&0xFF);
+}
+
+static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
+	int len, int peek);
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, 
+    unsigned int *is_next_epoch);
+#if 0
+static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
+	unsigned short *priority, unsigned long *offset);
+#endif
+static int dtls1_buffer_record(SSL *s, record_pqueue *q,
+	unsigned char *priority);
+static int dtls1_process_record(SSL *s);
+
+/* copy buffered record into SSL structure */
+static int
+dtls1_copy_record(SSL *s, pitem *item)
+    {
+    DTLS1_RECORD_DATA *rdata;
+
+    rdata = (DTLS1_RECORD_DATA *)item->data;
+    
+    if (s->s3->rbuf.buf != NULL)
+        OPENSSL_free(s->s3->rbuf.buf);
+    
+    s->packet = rdata->packet;
+    s->packet_length = rdata->packet_length;
+    memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+    memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+	
+	/* Set proper sequence number for mac calculation */
+	memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
+    
+    return(1);
+    }
+
+
+static int
+dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
+	{
+	DTLS1_RECORD_DATA *rdata;
+	pitem *item;
+
+	/* Limit the size of the queue to prevent DOS attacks */
+	if (pqueue_size(queue->q) >= 100)
+		return 0;
+		
+	rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
+	item = pitem_new(priority, rdata);
+	if (rdata == NULL || item == NULL)
+		{
+		if (rdata != NULL) OPENSSL_free(rdata);
+		if (item != NULL) pitem_free(item);
+		
+		OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR);
+		return(0);
+		}
+	
+	rdata->packet = s->packet;
+	rdata->packet_length = s->packet_length;
+	memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
+	memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
+
+	item->data = rdata;
+
+	/* insert should not fail, since duplicates are dropped */
+	if (pqueue_insert(queue->q, item) == NULL)
+		{
+		OPENSSL_free(rdata);
+		pitem_free(item);
+		return(0);
+		}
+
+	s->packet = NULL;
+	s->packet_length = 0;
+	memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
+	memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
+	
+	if (!ssl3_setup_buffers(s))
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR);
+		OPENSSL_free(rdata);
+		pitem_free(item);
+		return(0);
+		}
+	
+	return(1);
+	}
+
+
+static int
+dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
+    {
+    pitem *item;
+
+    item = pqueue_pop(queue->q);
+    if (item)
+        {
+        dtls1_copy_record(s, item);
+
+        OPENSSL_free(item->data);
+		pitem_free(item);
+
+        return(1);
+        }
+
+    return(0);
+    }
+
+
+/* retrieve a buffered record that belongs to the new epoch, i.e., not processed 
+ * yet */
+#define dtls1_get_unprocessed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &((s)->d1->unprocessed_rcds))
+
+/* retrieve a buffered record that belongs to the current epoch, ie, processed */
+#define dtls1_get_processed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &((s)->d1->processed_rcds))
+
+static int
+dtls1_process_buffered_records(SSL *s)
+    {
+    pitem *item;
+    
+    item = pqueue_peek(s->d1->unprocessed_rcds.q);
+    if (item)
+        {
+        /* Check if epoch is current. */
+        if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
+            return(1);  /* Nothing to do. */
+        
+        /* Process all the records. */
+        while (pqueue_peek(s->d1->unprocessed_rcds.q))
+            {
+            dtls1_get_unprocessed_record(s);
+            if ( ! dtls1_process_record(s))
+                return(0);
+            dtls1_buffer_record(s, &(s->d1->processed_rcds), 
+                s->s3->rrec.seq_num);
+            }
+        }
+
+    /* sync epoch numbers once all the unprocessed records 
+     * have been processed */
+    s->d1->processed_rcds.epoch = s->d1->r_epoch;
+    s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
+
+    return(1);
+    }
+
+
+#if 0
+
+static int
+dtls1_get_buffered_record(SSL *s)
+	{
+	pitem *item;
+	PQ_64BIT priority = 
+		(((PQ_64BIT)s->d1->handshake_read_seq) << 32) | 
+		((PQ_64BIT)s->d1->r_msg_hdr.frag_off);
+	
+	if ( ! SSL_in_init(s))  /* if we're not (re)negotiating, 
+							   nothing buffered */
+		return 0;
+
+
+	item = pqueue_peek(s->d1->rcvd_records);
+	if (item && item->priority == priority)
+		{
+		/* Check if we've received the record of interest.  It must be
+		 * a handshake record, since data records as passed up without
+		 * buffering */
+		DTLS1_RECORD_DATA *rdata;
+		item = pqueue_pop(s->d1->rcvd_records);
+		rdata = (DTLS1_RECORD_DATA *)item->data;
+		
+		if (s->s3->rbuf.buf != NULL)
+			OPENSSL_free(s->s3->rbuf.buf);
+		
+		s->packet = rdata->packet;
+		s->packet_length = rdata->packet_length;
+		memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+		memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+		
+		OPENSSL_free(item->data);
+		pitem_free(item);
+		
+		/* s->d1->next_expected_seq_num++; */
+		return(1);
+		}
+	
+	return 0;
+	}
+
+#endif
+
+static int
+dtls1_process_record(SSL *s)
+{
+	int i,al;
+	int enc_err;
+	SSL_SESSION *sess;
+	SSL3_RECORD *rr;
+	unsigned int mac_size, orig_len;
+	unsigned char md[EVP_MAX_MD_SIZE];
+
+	rr= &(s->s3->rrec);
+	sess = s->session;
+
+	/* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+	 * and we have that many bytes in s->packet
+	 */
+	rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
+
+	/* ok, we can now read from 's->packet' data into 'rr'
+	 * rr->input points at rr->length bytes, which
+	 * need to be copied into rr->data by either
+	 * the decryption or by the decompression
+	 * When the data is 'copied' into the rr->data buffer,
+	 * rr->input will be pointed at the new buffer */ 
+
+	/* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+	 * rr->length bytes of encrypted compressed stuff. */
+
+	/* check is not needed I believe */
+	if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	/* decrypt in place in 'rr->input' */
+	rr->data=rr->input;
+
+	enc_err = s->method->ssl3_enc->enc(s,0);
+	/* enc_err is:
+	 *    0: (in non-constant time) if the record is publically invalid.
+	 *    1: if the padding is valid
+	 *    -1: if the padding is invalid */
+	if (enc_err == 0)
+		{
+		/* For DTLS we simply ignore bad packets. */
+		rr->length = 0;
+		s->packet_length = 0;
+		goto err;
+		}
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+	/* r->length is now the compressed data plus mac */
+	if ((sess != NULL) &&
+	    (s->enc_read_ctx != NULL) &&
+	    (EVP_MD_CTX_md(s->read_hash) != NULL))
+		{
+		/* s->read_hash != NULL => mac_size != -1 */
+		unsigned char *mac = NULL;
+		unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+		mac_size=EVP_MD_CTX_size(s->read_hash);
+		assert(mac_size <= EVP_MAX_MD_SIZE);
+
+		/* kludge: *_cbc_remove_padding passes padding length in rr->type */
+		orig_len = rr->length+((unsigned int)rr->type>>8);
+
+		/* orig_len is the length of the record before any padding was
+		 * removed. This is public information, as is the MAC in use,
+		 * therefore we can safely process the record in a different
+		 * amount of time if it's too short to possibly contain a MAC.
+		 */
+		if (orig_len < mac_size ||
+		    /* CBC records must have a padding length byte too. */
+		    (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+		     orig_len < mac_size+1))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_LENGTH_TOO_SHORT);
+			goto f_err;
+			}
+
+		if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
+			{
+			/* We update the length so that the TLS header bytes
+			 * can be constructed correctly but we need to extract
+			 * the MAC in constant time from within the record,
+			 * without leaking the contents of the padding bytes.
+			 * */
+			mac = mac_tmp;
+			ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
+			rr->length -= mac_size;
+			}
+		else
+			{
+			/* In this case there's no padding, so |orig_len|
+			 * equals |rec->length| and we checked that there's
+			 * enough bytes for |mac_size| above. */
+			rr->length -= mac_size;
+			mac = &rr->data[rr->length];
+			}
+
+		i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+		if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+			enc_err = -1;
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
+			enc_err = -1;
+		}
+
+	if (enc_err < 0)
+		{
+		/* decryption failed, silently discard message */
+		rr->length = 0;
+		s->packet_length = 0;
+		goto err;
+		}
+
+	/* r->length is now just compressed */
+	if (s->expand != NULL)
+		{
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH)
+			{
+			al=SSL_AD_RECORD_OVERFLOW;
+			OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+		if (!ssl3_do_uncompress(s))
+			{
+			al=SSL_AD_DECOMPRESSION_FAILURE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_BAD_DECOMPRESSION);
+			goto f_err;
+			}
+		}
+
+	if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		OPENSSL_PUT_ERROR(SSL, dtls1_process_record, SSL_R_DATA_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	rr->off=0;
+	/* So at this point the following is true
+	 * ssl->s3->rrec.type 	is the type of record
+	 * ssl->s3->rrec.length	== number of bytes in record
+	 * ssl->s3->rrec.off	== offset to first valid byte
+	 * ssl->s3->rrec.data	== where to take bytes from, increment
+	 *			   after use :-).
+	 */
+
+	/* we have pulled in a full packet so zero things */
+	s->packet_length=0;
+	dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
+	return(1);
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(0);
+}
+
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type    - is the type of record
+ * ssl->s3->rrec.data, 	 - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by dtls1_read_bytes */
+int dtls1_get_record(SSL *s)
+	{
+	int ssl_major,ssl_minor;
+	int i,n;
+	SSL3_RECORD *rr;
+	unsigned char *p = NULL;
+	unsigned short version;
+	DTLS1_BITMAP *bitmap;
+	unsigned int is_next_epoch;
+
+	rr= &(s->s3->rrec);
+
+	/* The epoch may have changed.  If so, process all the
+	 * pending records.  This is a non-blocking operation. */
+	dtls1_process_buffered_records(s);
+
+	/* if we're renegotiating, then there may be buffered records */
+	if (dtls1_get_processed_record(s))
+		return 1;
+
+	/* get something from the wire */
+again:
+	/* check if we have the header */
+	if (	(s->rstate != SSL_ST_READ_BODY) ||
+		(s->packet_length < DTLS1_RT_HEADER_LENGTH)) 
+		{
+		n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+		/* read timeout is handled by dtls1_read_bytes */
+		if (n <= 0) return(n); /* error or non-blocking */
+
+		/* this packet contained a partial record, dump it */
+		if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
+			{
+			s->packet_length = 0;
+			goto again;
+			}
+
+		s->rstate=SSL_ST_READ_BODY;
+
+		p=s->packet;
+
+		if (s->msg_callback)
+			s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+		/* Pull apart the header into the DTLS1_RECORD */
+		rr->type= *(p++);
+		ssl_major= *(p++);
+		ssl_minor= *(p++);
+		version=(ssl_major<<8)|ssl_minor;
+
+		/* sequence number is 64 bits, with top 2 bytes = epoch */ 
+		n2s(p,rr->epoch);
+
+		memcpy(&(s->s3->read_sequence[2]), p, 6);
+		p+=6;
+
+		n2s(p,rr->length);
+
+		/* Lets check version */
+		if (!s->first_packet)
+			{
+			if (version != s->version)
+				{
+				/* unexpected version, silently discard */
+				rr->length = 0;
+				s->packet_length = 0;
+				goto again;
+				}
+			}
+
+		if ((version & 0xff00) != (s->version & 0xff00))
+			{
+			/* wrong version, silently discard record */
+			rr->length = 0;
+			s->packet_length = 0;
+			goto again;
+			}
+
+		if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+			{
+			/* record too long, silently discard it */
+			rr->length = 0;
+			s->packet_length = 0;
+			goto again;
+			}
+
+		/* now s->rstate == SSL_ST_READ_BODY */
+		}
+
+	/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+	if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
+		{
+		/* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
+		i=rr->length;
+		n=ssl3_read_n(s,i,i,1);
+		if (n <= 0) return(n); /* error or non-blocking io */
+
+		/* this packet contained a partial record, dump it */
+		if ( n != i)
+			{
+			rr->length = 0;
+			s->packet_length = 0;
+			goto again;
+			}
+
+		/* now n == rr->length,
+		 * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
+		}
+	s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+	/* match epochs.  NULL means the packet is dropped on the floor */
+	bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+	if ( bitmap == NULL)
+		{
+		rr->length = 0;
+		s->packet_length = 0;  /* dump this record */
+		goto again;   /* get another record */
+		}
+
+		/* Check whether this is a repeat, or aged record.
+		 * Don't check if we're listening and this message is
+		 * a ClientHello. They can look as if they're replayed,
+		 * since they arrive from different connections and
+		 * would be dropped unnecessarily.
+		 */
+		if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+		    *p == SSL3_MT_CLIENT_HELLO) &&
+		    !dtls1_record_replay_check(s, bitmap))
+			{
+			rr->length = 0;
+			s->packet_length=0; /* dump this record */
+			goto again;     /* get another record */
+			}
+
+	/* just read a 0 length packet */
+	if (rr->length == 0) goto again;
+
+	/* If this record is from the next epoch (either HM or ALERT),
+	 * and a handshake is currently in progress, buffer it since it
+	 * cannot be processed at this time. However, do not buffer
+	 * anything while listening.
+	 */
+	if (is_next_epoch)
+		{
+		if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
+			{
+			dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+			}
+		rr->length = 0;
+		s->packet_length = 0;
+		goto again;
+		}
+
+	if (!dtls1_process_record(s))
+		{
+		rr->length = 0;
+		s->packet_length = 0;  /* dump this record */
+		goto again;   /* get another record */
+		}
+
+	return(1);
+
+	}
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ *   -  0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ *     Change cipher spec protocol
+ *             just 1 byte needed, no need for keeping anything stored
+ *     Alert protocol
+ *             2 bytes needed (AlertLevel, AlertDescription)
+ *     Handshake protocol
+ *             4 bytes needed (HandshakeType, uint24 length) -- we just have
+ *             to detect unexpected Client Hello and Hello Request messages
+ *             here, anything else is handled by higher layers
+ *     Application data protocol
+ *             none of our business
+ */
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+	{
+	int al,i,j,ret;
+	unsigned int n;
+	SSL3_RECORD *rr;
+	void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+	if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+		if (!ssl3_setup_buffers(s))
+			return(-1);
+
+    /* XXX: check what the second '&& type' is about */
+	if ((type && (type != SSL3_RT_APPLICATION_DATA) && 
+		(type != SSL3_RT_HANDSHAKE) && type) ||
+	    (peek && (type != SSL3_RT_APPLICATION_DATA)))
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+
+	/* check whether there's a handshake message (client hello?) waiting */
+	if ( (ret = have_handshake_fragment(s, type, buf, len, peek)))
+		return ret;
+
+	/* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+	if (!s->in_handshake && SSL_in_init(s))
+		{
+		/* type == SSL3_RT_APPLICATION_DATA */
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		}
+
+start:
+	s->rwstate=SSL_NOTHING;
+
+	/* s->s3->rrec.type	    - is the type of record
+	 * s->s3->rrec.data,    - data
+	 * s->s3->rrec.off,     - offset into 'data' for next read
+	 * s->s3->rrec.length,  - number of bytes. */
+	rr = &(s->s3->rrec);
+
+	/* 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 && rr->length == 0)
+		{
+		pitem *item;
+		item = pqueue_pop(s->d1->buffered_app_data.q);
+		if (item)
+			{
+			dtls1_copy_record(s, item);
+
+			OPENSSL_free(item->data);
+			pitem_free(item);
+			}
+		}
+
+	/* Check for timeout */
+	if (dtls1_handle_timeout(s) > 0)
+		goto start;
+
+	/* get new packet if necessary */
+	if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+		{
+		ret=dtls1_get_record(s);
+		if (ret <= 0) 
+			{
+			ret = dtls1_read_failed(s, ret);
+			/* anything other than a timeout is an error */
+			if (ret <= 0)  
+				return(ret);
+			else
+				goto start;
+			}
+		}
+
+	if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE)
+		{
+		rr->length = 0;
+		goto start;
+		}
+
+	/* we now have a packet which can be read and processed */
+
+	if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+	                               * reset by ssl3_get_finished */
+		&& (rr->type != SSL3_RT_HANDSHAKE))
+		{
+		/* We now have application data between CCS and Finished.
+		 * Most likely the packets were reordered on their way, so
+		 * buffer the application data for later processing rather
+		 * than dropping the connection.
+		 */
+		dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
+		rr->length = 0;
+		goto start;
+		}
+
+	/* If the other end has shut down, throw anything we read away
+	 * (even in 'peek' mode) */
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		rr->length=0;
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+
+
+	if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+		{
+		/* make sure that we are not getting application data when we
+		 * are doing a handshake for the first time */
+		if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+			(s->enc_read_ctx == NULL))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE);
+			goto f_err;
+			}
+
+		if (len <= 0) return(len);
+
+		if ((unsigned int)len > rr->length)
+			n = rr->length;
+		else
+			n = (unsigned int)len;
+
+		memcpy(buf,&(rr->data[rr->off]),n);
+		if (!peek)
+			{
+			rr->length-=n;
+			rr->off+=n;
+			if (rr->length == 0)
+				{
+				s->rstate=SSL_ST_READ_HEADER;
+				rr->off=0;
+				}
+			}
+
+		return(n);
+		}
+
+
+	/* If we get here, then type != rr->type; if we have a handshake
+	 * message, then it was unexpected (Hello Request or Client Hello). */
+
+	/* In case of record types for which we have 'fragment' storage,
+	 * fill that so that we can process the data at a fixed place.
+	 */
+		{
+		unsigned int k, dest_maxlen = 0;
+		unsigned char *dest = NULL;
+		unsigned int *dest_len = NULL;
+
+		if (rr->type == SSL3_RT_HANDSHAKE)
+			{
+			dest_maxlen = sizeof s->d1->handshake_fragment;
+			dest = s->d1->handshake_fragment;
+			dest_len = &s->d1->handshake_fragment_len;
+			}
+		else if (rr->type == SSL3_RT_ALERT)
+			{
+			dest_maxlen = sizeof(s->d1->alert_fragment);
+			dest = s->d1->alert_fragment;
+			dest_len = &s->d1->alert_fragment_len;
+			}
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (rr->type == TLS1_RT_HEARTBEAT)
+			{
+			dtls1_process_heartbeat(s);
+
+			/* Exit and notify application to read again */
+			rr->length = 0;
+			s->rwstate=SSL_READING;
+			BIO_clear_retry_flags(SSL_get_rbio(s));
+			BIO_set_retry_read(SSL_get_rbio(s));
+			return(-1);
+			}
+#endif
+		/* else it's a CCS message, or application data or wrong */
+		else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
+			{
+			/* Application data while renegotiating
+			 * is allowed. Try again reading.
+			 */
+			if (rr->type == SSL3_RT_APPLICATION_DATA)
+				{
+				BIO *bio;
+				s->s3->in_read_app_data=2;
+				bio=SSL_get_rbio(s);
+				s->rwstate=SSL_READING;
+				BIO_clear_retry_flags(bio);
+				BIO_set_retry_read(bio);
+				return(-1);
+				}
+
+			/* Not certain if this is the right error handling */
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
+			goto f_err;
+			}
+
+		if (dest_maxlen > 0)
+			{
+            /* XDTLS:  In a pathalogical case, the Client Hello
+             *  may be fragmented--don't always expect dest_maxlen bytes */
+			if ( rr->length < dest_maxlen)
+				{
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+				/*
+				 * for normal alerts rr->length is 2, while
+				 * dest_maxlen is 7 if we were to handle this
+				 * non-existing alert...
+				 */
+				FIX ME
+#endif
+				s->rstate=SSL_ST_READ_HEADER;
+				rr->length = 0;
+				goto start;
+				}
+
+			/* now move 'n' bytes: */
+			for ( k = 0; k < dest_maxlen; k++)
+				{
+				dest[k] = rr->data[rr->off++];
+				rr->length--;
+				}
+			*dest_len = dest_maxlen;
+			}
+		}
+
+	/* s->d1->handshake_fragment_len == 12  iff  rr->type == SSL3_RT_HANDSHAKE;
+	 * s->d1->alert_fragment_len == 7      iff  rr->type == SSL3_RT_ALERT.
+	 * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+	/* If we are a client, check for an incoming 'Hello Request': */
+	if ((!s->server) &&
+		(s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+		(s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+		(s->session != NULL) && (s->session->cipher != NULL))
+		{
+		s->d1->handshake_fragment_len = 0;
+
+		if ((s->d1->handshake_fragment[1] != 0) ||
+			(s->d1->handshake_fragment[2] != 0) ||
+			(s->d1->handshake_fragment[3] != 0))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HELLO_REQUEST);
+			goto err;
+			}
+
+		/* no need to check sequence number on HELLO REQUEST messages */
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
+				s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
+
+		if (SSL_is_init_finished(s) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+			!s->s3->renegotiate)
+			{
+			s->d1->handshake_read_seq++;
+			s->new_session = 1;
+			ssl3_renegotiate(s);
+			if (ssl3_renegotiate_check(s))
+				{
+				i=s->handshake_func(s);
+				if (i < 0) return(i);
+				if (i == 0)
+					{
+					OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+					return(-1);
+					}
+
+				if (!(s->mode & SSL_MODE_AUTO_RETRY))
+					{
+					if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+						{
+						BIO *bio;
+						/* In the case where we try to read application data,
+						 * but we trigger an SSL handshake, we return -1 with
+						 * the retry option set.  Otherwise renegotiation may
+						 * cause nasty problems in the blocking world */
+						s->rwstate=SSL_READING;
+						bio=SSL_get_rbio(s);
+						BIO_clear_retry_flags(bio);
+						BIO_set_retry_read(bio);
+						return(-1);
+						}
+					}
+				}
+			}
+		/* we either finished a handshake or ignored the request,
+		 * now try again to obtain the (application) data we were asked for */
+		goto start;
+		}
+
+	if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH)
+		{
+		int alert_level = s->d1->alert_fragment[0];
+		int alert_descr = s->d1->alert_fragment[1];
+
+		s->d1->alert_fragment_len = 0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_ALERT, 
+				s->d1->alert_fragment, 2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j = (alert_level << 8) | alert_descr;
+			cb(s, SSL_CB_READ_ALERT, j);
+			}
+
+		if (alert_level == 1) /* warning */
+			{
+			s->s3->warn_alert = alert_descr;
+			if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+				{
+				s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+				return(0);
+				}
+#if 0
+            /* XXX: this is a possible improvement in the future */
+			/* now check if it's a missing record */
+			if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+				{
+				unsigned short seq;
+				unsigned int frag_off;
+				unsigned char *p = &(s->d1->alert_fragment[2]);
+
+				n2s(p, seq);
+				n2l3(p, frag_off);
+
+				dtls1_retransmit_message(s,
+										 dtls1_get_queue_priority(frag->msg_header.seq, 0),
+										 frag_off, &found);
+				if ( ! found  && SSL_in_init(s))
+					{
+					/* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
+					/* requested a message not yet sent, 
+					   send an alert ourselves */
+					ssl3_send_alert(s,SSL3_AL_WARNING,
+						DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+					}
+				}
+#endif
+			}
+		else if (alert_level == 2) /* fatal */
+			{
+			char tmp[16];
+
+			s->rwstate=SSL_NOTHING;
+			s->s3->fatal_alert = alert_descr;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_AD_REASON_OFFSET + alert_descr);
+			BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+			ERR_add_error_data(2,"SSL alert number ",tmp);
+			s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+			SSL_CTX_remove_session(s->ctx,s->session);
+			return(0);
+			}
+		else
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE);
+			goto f_err;
+			}
+
+		goto start;
+		}
+
+	if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+		{
+		s->rwstate=SSL_NOTHING;
+		rr->length=0;
+		return(0);
+		}
+
+	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+		{
+		struct ccs_header_st ccs_hdr;
+		unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
+
+		dtls1_get_ccs_header(rr->data, &ccs_hdr);
+
+		if (s->version == DTLS1_BAD_VER)
+			ccs_hdr_len = 3;
+
+		/* 'Change Cipher Spec' is just a single byte, so we know
+		 * exactly what the record payload has to look like */
+		/* XDTLS: check that epoch is consistent */
+		if (	(rr->length != ccs_hdr_len) || 
+			(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
+			{
+			i=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+			goto err;
+			}
+
+		rr->length=0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, 
+				rr->data, 1, s, s->msg_callback_arg);
+
+		/* We can't process a CCS now, because previous handshake
+		 * messages are still missing, so just drop it.
+		 */
+		if (!s->d1->change_cipher_spec_ok)
+			{
+			goto start;
+			}
+
+		s->d1->change_cipher_spec_ok = 0;
+
+		s->s3->change_cipher_spec=1;
+		if (!ssl3_do_change_cipher_spec(s))
+			goto err;
+
+		/* do this whenever CCS is processed */
+		dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+		if (s->version == DTLS1_BAD_VER)
+			s->d1->handshake_read_seq++;
+
+		goto start;
+		}
+
+	/* Unexpected handshake message (Client Hello, or protocol violation) */
+	if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && 
+		!s->in_handshake)
+		{
+		struct hm_header_st msg_hdr;
+		
+		/* this may just be a stale retransmit */
+		dtls1_get_message_header(rr->data, &msg_hdr);
+		if( rr->epoch != s->d1->r_epoch)
+			{
+			rr->length = 0;
+			goto start;
+			}
+
+		/* If we are server, we may have a repeated FINISHED of the
+		 * client here, then retransmit our CCS and FINISHED.
+		 */
+		if (msg_hdr.type == SSL3_MT_FINISHED)
+			{
+			if (dtls1_check_timeout_num(s) < 0)
+				return -1;
+
+			dtls1_retransmit_buffered_messages(s);
+			rr->length = 0;
+			goto start;
+			}
+
+		if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+			{
+#if 0 /* worked only because C operator preferences are not as expected (and
+       * because this is not really needed for clients except for detecting
+       * protocol violations): */
+			s->state=SSL_ST_BEFORE|(s->server)
+				?SSL_ST_ACCEPT
+				:SSL_ST_CONNECT;
+#else
+			s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+			s->renegotiate=1;
+			s->new_session=1;
+			}
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+
+		if (!(s->mode & SSL_MODE_AUTO_RETRY))
+			{
+			if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+				{
+				BIO *bio;
+				/* In the case where we try to read application data,
+				 * but we trigger an SSL handshake, we return -1 with
+				 * the retry option set.  Otherwise renegotiation may
+				 * cause nasty problems in the blocking world */
+				s->rwstate=SSL_READING;
+				bio=SSL_get_rbio(s);
+				BIO_clear_retry_flags(bio);
+				BIO_set_retry_read(bio);
+				return(-1);
+				}
+			}
+		goto start;
+		}
+
+	switch (rr->type)
+		{
+	default:
+#ifndef OPENSSL_NO_TLS
+		/* TLS just ignores unknown message types */
+		if (s->version == TLS1_VERSION)
+			{
+			rr->length = 0;
+			goto start;
+			}
+#endif
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
+		goto f_err;
+	case SSL3_RT_CHANGE_CIPHER_SPEC:
+	case SSL3_RT_ALERT:
+	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 */
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR);
+		goto f_err;
+	case SSL3_RT_APPLICATION_DATA:
+		/* At this point, we were expecting handshake data,
+		 * but have application data.  If the library was
+		 * running inside ssl3_read() (i.e. in_read_app_data
+		 * is set) and it makes sense to read 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)
+					)
+				))
+			{
+			s->s3->in_read_app_data=2;
+			return(-1);
+			}
+		else
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
+			goto f_err;
+			}
+		}
+	/* not reached */
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(-1);
+	}
+
+int
+dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
+	{
+	int i;
+
+		if (SSL_in_init(s) && !s->in_handshake)
+		{
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return -1;
+			}
+		}
+
+	if (len > SSL3_RT_MAX_PLAIN_LENGTH)
+		{
+			OPENSSL_PUT_ERROR(SSL, dtls1_write_app_data_bytes, SSL_R_DTLS_MESSAGE_TOO_BIG);
+			return -1;
+		}
+
+	i = dtls1_write_bytes(s, type, buf_, len);
+	return i;
+	}
+
+
+	/* this only happens when a client hello is received and a handshake 
+	 * is started. */
+static int
+have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
+	int len, int peek)
+	{
+	
+	if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0))
+		/* (partially) satisfy request from storage */
+		{
+		unsigned char *src = s->d1->handshake_fragment;
+		unsigned char *dst = buf;
+		unsigned int k,n;
+		
+		/* peek == 0 */
+		n = 0;
+		while ((len > 0) && (s->d1->handshake_fragment_len > 0))
+			{
+			*dst++ = *src++;
+			len--; s->d1->handshake_fragment_len--;
+			n++;
+			}
+		/* move any remaining fragment bytes: */
+		for (k = 0; k < s->d1->handshake_fragment_len; k++)
+			s->d1->handshake_fragment[k] = *src++;
+		return n;
+		}
+	
+	return 0;
+	}
+
+
+
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len)
+	{
+	int i;
+
+	assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
+	s->rwstate=SSL_NOTHING;
+	i=do_dtls1_write(s, type, buf, len, 0);
+	return i;
+	}
+
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment)
+	{
+	unsigned char *p,*pseq;
+	int i,mac_size,clear=0;
+	int prefix_len = 0;
+	int eivlen;
+	SSL3_RECORD *wr;
+	SSL3_BUFFER *wb;
+	SSL_SESSION *sess;
+
+	/* first check if there is a SSL3_BUFFER still being written
+	 * out.  This will happen with non blocking IO */
+	if (s->s3->wbuf.left != 0)
+		{
+		assert(0); /* XDTLS:  want to see if we ever get here */
+		return(ssl3_write_pending(s,type,buf,len));
+		}
+
+	/* If we have an alert to send, lets send it */
+	if (s->s3->alert_dispatch)
+		{
+		i=s->method->ssl_dispatch_alert(s);
+		if (i <= 0)
+			return(i);
+		/* if it went, fall through and send more stuff */
+		}
+
+	if (len == 0 && !create_empty_fragment)
+		return 0;
+
+	wr= &(s->s3->wrec);
+	wb= &(s->s3->wbuf);
+	sess=s->session;
+
+	if (	(sess == NULL) ||
+		(s->enc_write_ctx == NULL) ||
+		(EVP_MD_CTX_md(s->write_hash) == NULL))
+		clear=1;
+
+	if (clear)
+		mac_size=0;
+	else
+		{
+		mac_size=EVP_MD_CTX_size(s->write_hash);
+		if (mac_size < 0)
+			goto err;
+		}
+
+	/* DTLS implements explicit IV, so no need for empty fragments */
+#if 0
+	/* 'create_empty_fragment' is true only when this function calls itself */
+	if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
+	    && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
+		{
+		/* countermeasure against known-IV weakness in CBC ciphersuites
+		 * (see http://www.openssl.org/~bodo/tls-cbc.txt) 
+		 */
+
+		if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+			{
+			/* recursive function call with 'create_empty_fragment' set;
+			 * this prepares and buffers the data for an empty fragment
+			 * (these 'prefix_len' bytes are sent out later
+			 * together with the actual payload) */
+			prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1);
+			if (prefix_len <= 0)
+				goto err;
+
+			if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+				{
+				/* insufficient space */
+				OPENSSL_PUT_ERROR(SSL, do_dtls1_write, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			}
+		
+		s->s3->empty_fragment_done = 1;
+		}
+#endif
+	p = wb->buf + prefix_len;
+
+	/* write the header */
+
+	*(p++)=type&0xff;
+	wr->type=type;
+	/* Special case: for hello verify request, client version 1.0 and
+	 * we haven't decided which version to use yet send back using 
+	 * version 1.0 header: otherwise some clients will ignore it.
+	 */
+	if (s->method->version == DTLS_ANY_VERSION)
+		{
+		*(p++)=DTLS1_VERSION>>8;
+		*(p++)=DTLS1_VERSION&0xff;
+		}
+	else
+		{
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+		}
+
+	/* field where we are to write out packet epoch, seq num and len */
+	pseq=p; 
+	p+=10;
+
+	/* Explicit IV length, block ciphers appropriate version flag */
+	if (s->enc_write_ctx)
+		{
+		int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+		if (mode == EVP_CIPH_CBC_MODE)
+			{
+			eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+			if (eivlen <= 1)
+				eivlen = 0;
+			}
+		/* Need explicit part of IV for GCM mode */
+		else if (mode == EVP_CIPH_GCM_MODE)
+			eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+		else
+			eivlen = 0;
+		}
+	else 
+		eivlen = 0;
+
+	/* lets setup the record stuff. */
+	wr->data=p + eivlen;  /* make room for IV in case of CBC */
+	wr->length=(int)len;
+	wr->input=(unsigned char *)buf;
+
+	/* we now 'read' from wr->input, wr->length bytes into
+	 * wr->data */
+
+	/* first we compress */
+	if (s->compress != NULL)
+		{
+		if (!ssl3_do_compress(s))
+			{
+			OPENSSL_PUT_ERROR(SSL, do_dtls1_write, SSL_R_COMPRESSION_FAILURE);
+			goto err;
+			}
+		}
+	else
+		{
+		memcpy(wr->data,wr->input,wr->length);
+		wr->input=wr->data;
+		}
+
+	/* we should still have the output to wr->data and the input
+	 * from wr->input.  Length should be wr->length.
+	 * wr->data still points in the wb->buf */
+
+	if (mac_size != 0)
+		{
+		if(s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
+			goto err;
+		wr->length+=mac_size;
+		}
+
+	/* this is true regardless of mac size */
+	wr->input=p;
+	wr->data=p;
+
+	if (eivlen)
+		wr->length += eivlen;
+
+	s->method->ssl3_enc->enc(s,1);
+
+	/* record length after mac and block padding */
+/*	if (type == SSL3_RT_APPLICATION_DATA ||
+	(type == SSL3_RT_ALERT && ! SSL_in_init(s))) */
+	
+	/* there's only one epoch between handshake and app data */
+	
+	s2n(s->d1->w_epoch, pseq);
+
+	/* XDTLS: ?? */
+/*	else
+	s2n(s->d1->handshake_epoch, pseq); */
+
+	memcpy(pseq, &(s->s3->write_sequence[2]), 6);
+	pseq+=6;
+	s2n(wr->length,pseq);
+
+	if (s->msg_callback)
+		s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+	/* we should now have
+	 * wr->data pointing to the encrypted data, which is
+	 * wr->length long */
+	wr->type=type; /* not needed but helps for debugging */
+	wr->length+=DTLS1_RT_HEADER_LENGTH;
+
+#if 0  /* this is now done at the message layer */
+	/* buffer the record, making it easy to handle retransmits */
+	if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC)
+		dtls1_buffer_record(s, wr->data, wr->length, 
+			*((PQ_64BIT *)&(s->s3->write_sequence[0])));
+#endif
+
+	ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
+
+	if (create_empty_fragment)
+		{
+		/* we are in a recursive call;
+		 * just return the length, don't write out anything here
+		 */
+		return wr->length;
+		}
+
+	/* now let's set up wb */
+	wb->left = prefix_len + wr->length;
+	wb->offset = 0;
+
+	/* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+	s->s3->wpend_tot=len;
+	s->s3->wpend_buf=buf;
+	s->s3->wpend_type=type;
+	s->s3->wpend_ret=len;
+
+	/* we now just need to write the buffer */
+	return ssl3_write_pending(s,type,buf,len);
+err:
+	return -1;
+	}
+
+
+
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
+	{
+	int cmp;
+	unsigned int shift;
+	const unsigned char *seq = s->s3->read_sequence;
+
+	cmp = satsub64be(seq,bitmap->max_seq_num);
+	if (cmp > 0)
+		{
+		memcpy (s->s3->rrec.seq_num,seq,8);
+		return 1; /* this record in new */
+		}
+	shift = -cmp;
+	if (shift >= sizeof(bitmap->map)*8)
+		return 0; /* stale, outside the window */
+	else if (bitmap->map & (1UL<<shift))
+		return 0; /* record previously received */
+
+	memcpy (s->s3->rrec.seq_num,seq,8);
+	return 1;
+	}
+
+
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
+	{
+	int cmp;
+	unsigned int shift;
+	const unsigned char *seq = s->s3->read_sequence;
+
+	cmp = satsub64be(seq,bitmap->max_seq_num);
+	if (cmp > 0)
+		{
+		shift = cmp;
+		if (shift < sizeof(bitmap->map)*8)
+			bitmap->map <<= shift, bitmap->map |= 1UL;
+		else
+			bitmap->map = 1UL;
+		memcpy(bitmap->max_seq_num,seq,8);
+		}
+	else	{
+		shift = -cmp;
+		if (shift < sizeof(bitmap->map)*8)
+			bitmap->map |= 1UL<<shift;
+		}
+	}
+
+
+int dtls1_dispatch_alert(SSL *s)
+	{
+	int i,j;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	unsigned char buf[DTLS1_AL_HEADER_LENGTH];
+	unsigned char *ptr = &buf[0];
+
+	s->s3->alert_dispatch=0;
+
+	memset(buf, 0x00, sizeof(buf));
+	*ptr++ = s->s3->send_alert[0];
+	*ptr++ = s->s3->send_alert[1];
+
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+	if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+		{	
+		s2n(s->d1->handshake_read_seq, ptr);
+#if 0
+		if ( s->d1->r_msg_hdr.frag_off == 0)  /* waiting for a new msg */
+
+		else
+			s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
+#endif
+
+#if 0
+		fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
+#endif
+		l2n3(s->d1->r_msg_hdr.frag_off, ptr);
+		}
+#endif
+
+	i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0);
+	if (i <= 0)
+		{
+		s->s3->alert_dispatch=1;
+		/* fprintf( stderr, "not done with alert\n" ); */
+		}
+	else
+		{
+		if (s->s3->send_alert[0] == SSL3_AL_FATAL
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+		    || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+#endif
+		    )
+			(void)BIO_flush(s->wbio);
+
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 
+				2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+			cb(s,SSL_CB_WRITE_ALERT,j);
+			}
+		}
+	return(i);
+	}
+
+
+static DTLS1_BITMAP *
+dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch)
+    {
+    
+    *is_next_epoch = 0;
+
+    /* In current epoch, accept HM, CCS, DATA, & ALERT */
+    if (rr->epoch == s->d1->r_epoch)
+        return &s->d1->bitmap;
+
+    /* Only HM and ALERT messages can be from the next epoch */
+    else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
+        (rr->type == SSL3_RT_HANDSHAKE ||
+            rr->type == SSL3_RT_ALERT))
+        {
+        *is_next_epoch = 1;
+        return &s->d1->next_bitmap;
+        }
+
+    return NULL;
+    }
+
+#if 0
+static int
+dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority,
+	unsigned long *offset)
+	{
+
+	/* alerts are passed up immediately */
+	if ( rr->type == SSL3_RT_APPLICATION_DATA ||
+		rr->type == SSL3_RT_ALERT)
+		return 0;
+
+	/* Only need to buffer if a handshake is underway.
+	 * (this implies that Hello Request and Client Hello are passed up
+	 * immediately) */
+	if ( SSL_in_init(s))
+		{
+		unsigned char *data = rr->data;
+		/* need to extract the HM/CCS sequence number here */
+		if ( rr->type == SSL3_RT_HANDSHAKE ||
+			rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+			{
+			unsigned short seq_num;
+			struct hm_header_st msg_hdr;
+			struct ccs_header_st ccs_hdr;
+
+			if ( rr->type == SSL3_RT_HANDSHAKE)
+				{
+				dtls1_get_message_header(data, &msg_hdr);
+				seq_num = msg_hdr.seq;
+				*offset = msg_hdr.frag_off;
+				}
+			else
+				{
+				dtls1_get_ccs_header(data, &ccs_hdr);
+				seq_num = ccs_hdr.seq;
+				*offset = 0;
+				}
+				
+			/* this is either a record we're waiting for, or a
+			 * retransmit of something we happened to previously 
+			 * receive (higher layers will drop the repeat silently */
+			if ( seq_num < s->d1->handshake_read_seq)
+				return 0;
+			if (rr->type == SSL3_RT_HANDSHAKE && 
+				seq_num == s->d1->handshake_read_seq &&
+				msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off)
+				return 0;
+			else if ( seq_num == s->d1->handshake_read_seq &&
+				(rr->type == SSL3_RT_CHANGE_CIPHER_SPEC ||
+					msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off))
+				return 0;
+			else
+				{
+				*priority = seq_num;
+				return 1;
+				}
+			}
+		else /* unknown record type */
+			return 0;
+		}
+
+	return 0;
+	}
+#endif
+
+void
+dtls1_reset_seq_numbers(SSL *s, int rw)
+	{
+	unsigned char *seq;
+	unsigned int seq_bytes = sizeof(s->s3->read_sequence);
+
+	if ( rw & SSL3_CC_READ)
+		{
+		seq = s->s3->read_sequence;
+		s->d1->r_epoch++;
+		memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
+		memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
+		}
+	else
+		{
+		seq = s->s3->write_sequence;
+		memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));
+		s->d1->w_epoch++;
+		}
+
+	memset(seq, 0x00, seq_bytes);
+	}
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
new file mode 100644
index 0000000..e98b512
--- /dev/null
+++ b/ssl/d1_srtp.c
@@ -0,0 +1,495 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/*
+  DTLS code by Eric Rescorla <ekr@rtfm.com>
+
+  Copyright (C) 2006, Network Resonance, Inc.
+  Copyright (C) 2011, RTFM, Inc.
+*/
+
+#ifndef OPENSSL_NO_SRTP
+
+#include <stdio.h>
+
+#include <openssl/obj.h>
+#include <openssl/err.h>
+
+#include "ssl_locl.h"
+#include "srtp.h"
+
+
+static SRTP_PROTECTION_PROFILE srtp_known_profiles[]=
+    {
+    {
+    "SRTP_AES128_CM_SHA1_80",
+    SRTP_AES128_CM_SHA1_80,
+    },
+    {
+    "SRTP_AES128_CM_SHA1_32",
+    SRTP_AES128_CM_SHA1_32,
+    },
+#if 0
+    {
+    "SRTP_NULL_SHA1_80",
+    SRTP_NULL_SHA1_80,
+    },
+    {
+    "SRTP_NULL_SHA1_32",
+    SRTP_NULL_SHA1_32,
+    },
+#endif
+    {0}
+    };
+
+static int find_profile_by_name(char *profile_name,
+				SRTP_PROTECTION_PROFILE **pptr,unsigned len)
+	{
+	SRTP_PROTECTION_PROFILE *p;
+
+	p=srtp_known_profiles;
+	while(p->name)
+		{
+		if((len == strlen(p->name)) && !strncmp(p->name,profile_name,
+							len))
+			{
+			*pptr=p;
+			return 0;
+			}
+
+		p++;
+		}
+
+	return 1;
+	}
+
+static int find_profile_by_num(unsigned profile_num,
+			       SRTP_PROTECTION_PROFILE **pptr)
+	{
+	SRTP_PROTECTION_PROFILE *p;
+
+	p=srtp_known_profiles;
+	while(p->name)
+		{
+		if(p->id == profile_num)
+			{
+			*pptr=p;
+			return 0;
+			}
+		p++;
+		}
+
+	return 1;
+	}
+
+static int ssl_ctx_make_profiles(const char *profiles_string,STACK_OF(SRTP_PROTECTION_PROFILE) **out)
+	{
+	STACK_OF(SRTP_PROTECTION_PROFILE) *profiles;
+
+	char *col;
+	char *ptr=(char *)profiles_string;
+    
+	SRTP_PROTECTION_PROFILE *p;
+
+	if(!(profiles=sk_SRTP_PROTECTION_PROFILE_new_null()))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
+		return 1;
+		}
+    
+	do
+		{
+		col=strchr(ptr,':');
+
+		if(!find_profile_by_name(ptr,&p,
+					 col ? col-ptr : (int)strlen(ptr)))
+			{
+			sk_SRTP_PROTECTION_PROFILE_push(profiles,p);
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
+			return 1;
+			}
+
+		if(col) ptr=col+1;
+		} while (col);
+
+	*out=profiles;
+    
+	return 0;
+	}
+    
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,const char *profiles)
+	{
+	return ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles);
+	}
+
+int SSL_set_tlsext_use_srtp(SSL *s,const char *profiles)
+	{
+	return ssl_ctx_make_profiles(profiles,&s->srtp_profiles);
+	}
+
+
+STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s)
+	{
+	if(s != NULL)
+		{
+		if(s->srtp_profiles != NULL)
+			{
+			return s->srtp_profiles;
+			}
+		else if((s->ctx != NULL) &&
+			(s->ctx->srtp_profiles != NULL))
+			{
+			return s->ctx->srtp_profiles;
+			}
+		}
+
+	return NULL;
+	}
+
+SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s)
+	{
+	return s->srtp_profile;
+	}
+
+/* Note: this function returns 0 length if there are no 
+   profiles specified */
+int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen)
+	{
+	int ct=0;
+	int i;
+	STACK_OF(SRTP_PROTECTION_PROFILE) *clnt=0;
+	SRTP_PROTECTION_PROFILE *prof;
+    
+	clnt=SSL_get_srtp_profiles(s);    
+	ct=sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */
+
+	if(p)
+		{
+		if(ct==0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
+			return 1;
+			}
+
+		if((2 + ct*2 + 1) > maxlen)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
+			return 1;
+			}
+
+                /* Add the length */
+                s2n(ct * 2, p);
+		for(i=0;i<ct;i++)
+			{
+			prof=sk_SRTP_PROTECTION_PROFILE_value(clnt,i);
+			s2n(prof->id,p);
+			}
+
+                /* Add an empty use_mki value */
+                *p++ = 0;
+		}
+
+	*len=2 + ct*2 + 1;
+    
+	return 0;
+	}
+
+
+int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al)
+	{
+	SRTP_PROTECTION_PROFILE *cprof,*sprof;
+	STACK_OF(SRTP_PROTECTION_PROFILE) *clnt=0,*srvr;
+        int ct;
+        int mki_len;
+	int i,j;
+	int id;
+	int ret;
+
+         /* Length value + the MKI length */
+        if(len < 3)
+		{            
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+                }
+
+        /* Pull off the length of the cipher suite list */
+        n2s(d, ct);
+        len -= 2;
+        
+        /* Check that it is even */
+	if(ct%2)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+        
+        /* Check that lengths are consistent */
+	if(len < (ct + 1)) 
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+
+        
+	clnt=sk_SRTP_PROTECTION_PROFILE_new_null();
+
+	while(ct)
+		{
+		n2s(d,id);
+		ct-=2;
+                len-=2;
+
+		if(!find_profile_by_num(id,&cprof))
+			{
+			sk_SRTP_PROTECTION_PROFILE_push(clnt,cprof);
+			}
+		else
+			{
+			; /* Ignore */
+			}
+		}
+
+        /* Now extract the MKI value as a sanity check, but discard it for now */
+        mki_len = *d;
+        d++; len--;
+
+        if (mki_len != len)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_use_srtp_ext, SSL_R_BAD_SRTP_MKI_VALUE);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+
+	srvr=SSL_get_srtp_profiles(s);
+
+	/* Pick our most preferred profile. If no profiles have been
+	 configured then the outer loop doesn't run 
+	 (sk_SRTP_PROTECTION_PROFILE_num() = -1)
+	 and so we just return without doing anything */
+	for(i=0;i<sk_SRTP_PROTECTION_PROFILE_num(srvr);i++)
+		{
+		sprof=sk_SRTP_PROTECTION_PROFILE_value(srvr,i);
+
+		for(j=0;j<sk_SRTP_PROTECTION_PROFILE_num(clnt);j++)
+			{
+			cprof=sk_SRTP_PROTECTION_PROFILE_value(clnt,j);
+            
+			if(cprof->id==sprof->id)
+				{
+				s->srtp_profile=sprof;
+				*al=0;
+				ret=0;
+				goto done;
+				}
+			}
+		}
+
+	ret=0;
+    
+done:
+	if(clnt) sk_SRTP_PROTECTION_PROFILE_free(clnt);
+
+	return ret;
+	}
+
+int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen)
+	{
+	if(p)
+		{
+		if(maxlen < 5)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
+			return 1;
+			}
+
+		if(s->srtp_profile==0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, SSL_R_USE_SRTP_NOT_NEGOTIATED);
+			return 1;
+			}
+                s2n(2, p);
+		s2n(s->srtp_profile->id,p);
+                *p++ = 0;
+		}
+	*len=5;
+    
+	return 0;
+	}
+    
+
+int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al)
+	{
+	unsigned id;
+	int i;
+        int ct;
+
+	STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
+	SRTP_PROTECTION_PROFILE *prof;
+
+	if(len!=5)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+
+        n2s(d, ct);
+	if(ct!=2)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+
+	n2s(d,id);
+        if (*d)  /* Must be no MKI, since we never offer one */
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, SSL_R_BAD_SRTP_MKI_VALUE);
+		*al=SSL_AD_ILLEGAL_PARAMETER;
+		return 1;
+		}
+
+	clnt=SSL_get_srtp_profiles(s);
+
+	/* Throw an error if the server gave us an unsolicited extension */
+	if (clnt == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, SSL_R_NO_SRTP_PROFILES);
+		*al=SSL_AD_DECODE_ERROR;
+		return 1;
+		}
+    
+	/* Check to see if the server gave us something we support
+	   (and presumably offered)
+	*/
+	for(i=0;i<sk_SRTP_PROTECTION_PROFILE_num(clnt);i++)
+		{
+		prof=sk_SRTP_PROTECTION_PROFILE_value(clnt,i);
+	    
+		if(prof->id == id)
+			{
+			s->srtp_profile=prof;
+			*al=0;
+			return 0;
+			}
+		}
+
+	OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_use_srtp_ext, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
+	*al=SSL_AD_DECODE_ERROR;
+	return 1;
+	}
+
+
+#endif
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
new file mode 100644
index 0000000..8fc9240
--- /dev/null
+++ b/ssl/d1_srvr.c
@@ -0,0 +1,793 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/bn.h>
+#include <openssl/buf.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+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;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	unsigned long alg_k;
+	int ret= -1;
+	int new_state,state,skip=0;
+	int listen;
+
+	ERR_clear_error();
+	ERR_clear_system_error();
+
+	if (s->info_callback != NULL)
+		cb=s->info_callback;
+	else if (s->ctx->info_callback != NULL)
+		cb=s->ctx->info_callback;
+	
+	listen = s->d1->listen;
+
+	/* init things to blank */
+	s->in_handshake++;
+	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+	s->d1->listen = listen;
+
+	if (s->cert == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, dtls1_accept, SSL_R_NO_CERTIFICATE_SET);
+		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)
+		{
+		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))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				}
+
+			if (!ssl3_setup_buffers(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			s->init_num=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 :-)
+				 */
+					if (!ssl_init_wbio_buffer(s,1)) { ret= -1; 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;
+
+			/* Reflect ClientHello sequence to remain stateless while listening */
+			if (listen)
+				{
+				memcpy(s->s3->write_sequence, s->s3->read_sequence, sizeof(s->s3->write_sequence));
+				}
+
+			/* If we're just listening, stop here */
+			if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
+				{
+				ret = 2;
+				s->d1->listen = 0;
+				/* Set expected sequence numbers
+				 * to continue the handshake.
+				 */
+				s->d1->handshake_read_seq = 2;
+				s->d1->handshake_write_seq = 1;
+				s->d1->next_handshake_write_seq = 1;
+				goto end;
+				}
+			
+			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;
+			
+
+		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_TLSEXT
+				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_CHANGE_A;
+#endif
+				}
+			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;
+#ifndef OPENSSL_NO_TLSEXT
+				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;
+				}
+#else
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
+			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 */
+			if ((s->options & SSL_OP_EPHEMERAL_RSA)
+				)
+				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+				 * even when forbidden by protocol specs
+				 * (handshake may fail as clients are not required to
+				 * be able to handle this) */
+				s->s3->tmp.use_rsa_tmp=1;
+			else
+				s->s3->tmp.use_rsa_tmp=0;
+
+			/* only send if a DH key exchange or
+			 * RSA but we have a sign only certificate */
+			if (s->s3->tmp.use_rsa_tmp
+			/* PSK: send ServerKeyExchange if PSK identity
+			 * hint if provided */
+#ifndef OPENSSL_NO_PSK
+			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+#endif
+			    || (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+			    || (alg_k & SSL_kEECDH)
+			    || ((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)) ||
+				 /* never request cert in Kerberos ciphersuites */
+				(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
+				/* 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;
+				}
+			else
+				{
+				s->s3->tmp.cert_request=1;
+				dtls1_start_timer(s);
+				ret=ssl3_send_certificate_request(s);
+				if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+				s->state=SSL3_ST_SW_FLUSH;
+				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#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:
+			/* Check for second client hello (MS SGC) */
+			ret = ssl3_check_client_hello(s);
+			if (ret <= 0)
+				goto end;
+			if (ret == 2)
+				{
+				dtls1_stop_timer(s);
+				s->state = SSL3_ST_SR_CLNT_HELLO_C;
+				}
+			else {
+				/* could be sent for a DH cert, even if we
+				 * have not asked for it :-) */
+				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;
+
+			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_FINISHED_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;
+				/* For sigalgs freeze the handshake buffer
+				 * at this point and digest cached records.
+				 */
+				if (!s->s3->handshake_buffer)
+					{
+					OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
+					return -1;
+					}
+				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+				if (!ssl3_digest_cached_records(s))
+					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:
+
+			s->d1->change_cipher_spec_ok = 1;
+			/* we should decide if we expected this one */
+			ret=ssl3_get_cert_verify(s);
+			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:
+			s->d1->change_cipher_spec_ok = 1;
+			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;
+#ifndef OPENSSL_NO_TLSEXT
+			else if (s->tlsext_ticket_expected)
+				s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
+			else
+				s->state=SSL3_ST_SW_CHANGE_A;
+			s->init_num=0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		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;
+
+#endif
+
+		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; goto end; }
+
+			ret=dtls1_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;
+				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_FINISHED_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);
+
+#if 0
+			BUF_MEM_free(s->init_buf);
+			s->init_buf=NULL;
+#endif
+
+			/* 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; */
+
+		default:
+			OPENSSL_PUT_ERROR(SSL, 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--;
+
+	if (cb != NULL)
+		cb(s,SSL_CB_ACCEPT_EXIT,ret);
+	return(ret);
+	}
+
+int dtls1_send_hello_verify_request(SSL *s)
+	{
+	unsigned int msg_len;
+	unsigned char *msg, *buf, *p;
+
+	if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A)
+		{
+		buf = (unsigned char *)s->init_buf->data;
+
+		msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
+		/* Always use DTLS 1.0 version: see RFC 6347 */
+		*(p++) = DTLS1_VERSION >> 8;
+		*(p++) = DTLS1_VERSION & 0xFF;
+
+		if (s->ctx->app_gen_cookie_cb == NULL ||
+		     s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+			 &(s->d1->cookie_len)) == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, dtls1_send_hello_verify_request, ERR_R_INTERNAL_ERROR);
+			return 0;
+			}
+
+		*(p++) = (unsigned char) s->d1->cookie_len;
+		memcpy(p, s->d1->cookie, s->d1->cookie_len);
+		p += s->d1->cookie_len;
+		msg_len = p - msg;
+
+		dtls1_set_message_header(s, buf,
+			DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, msg_len);
+
+		s->state=DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
+		/* number of bytes to write */
+		s->init_num=p-buf;
+		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/dtls1.h b/ssl/dtls1.h
new file mode 100644
index 0000000..6052f31
--- /dev/null
+++ b/ssl/dtls1.h
@@ -0,0 +1,265 @@
+/* ssl/dtls1.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DTLS1_H
+#define HEADER_DTLS1_H
+
+#include <openssl/buf.h>
+#include <openssl/pqueue.h>
+#if defined(OPENSSL_WINDOWS)
+/* Including winsock.h pollutes the namespace too much with defines for
+ * X509_NAME etc. */
+typedef struct timeval {
+	long tv_sec;
+	long tv_usec;
+} timeval;
+#else
+#include <sys/time.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define DTLS1_VERSION			0xFEFF
+#define DTLS1_BAD_VER			0x0100
+#define DTLS1_2_VERSION			0xFEFD
+/* Special value for method supporting multiple versions */
+#define DTLS_ANY_VERSION		0x1FFFF
+
+#if 0
+/* this alert description is not specified anywhere... */
+#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
+#endif
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH                     256
+
+#define DTLS1_RT_HEADER_LENGTH                  13
+
+#define DTLS1_HM_HEADER_LENGTH                  12
+
+#define DTLS1_HM_BAD_FRAGMENT                   -2
+#define DTLS1_HM_FRAGMENT_RETRY                 -3
+
+#define DTLS1_CCS_HEADER_LENGTH                  1
+
+#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
+#define DTLS1_AL_HEADER_LENGTH                   7
+#else
+#define DTLS1_AL_HEADER_LENGTH                   2
+#endif
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct dtls1_bitmap_st
+	{
+	unsigned long map;		/* track 32 packets on 32-bit systems
+					   and 64 - on 64-bit systems */
+	unsigned char max_seq_num[8];	/* max record number seen so far,
+					   64-bit value in big-endian
+					   encoding */
+	} DTLS1_BITMAP;
+
+struct dtls1_retransmit_state
+	{
+	EVP_CIPHER_CTX *enc_write_ctx;	/* cryptographic state */
+	EVP_MD_CTX *write_hash;			/* used for mac generation */
+	char *compress;
+	SSL_SESSION *session;
+	unsigned short epoch;
+	};
+
+struct hm_header_st
+	{
+	unsigned char type;
+	unsigned long msg_len;
+	unsigned short seq;
+	unsigned long frag_off;
+	unsigned long frag_len;
+	unsigned int is_ccs;
+	struct dtls1_retransmit_state saved_retransmit_state;
+	};
+
+struct ccs_header_st
+	{
+	unsigned char type;
+	unsigned short seq;
+	};
+
+struct dtls1_timeout_st
+	{
+	/* Number of read timeouts so far */
+	unsigned int read_timeouts;
+	
+	/* Number of write timeouts so far */
+	unsigned int write_timeouts;
+	
+	/* Number of alerts received so far */
+	unsigned int num_alerts;
+	};
+
+typedef struct record_pqueue_st
+	{
+	unsigned short epoch;
+	pqueue q;
+	} record_pqueue;
+
+typedef struct hm_fragment_st
+	{
+	struct hm_header_st msg_header;
+	unsigned char *fragment;
+	unsigned char *reassembly;
+	} hm_fragment;
+
+typedef struct dtls1_state_st
+	{
+	unsigned int send_cookie;
+	unsigned char cookie[DTLS1_COOKIE_LENGTH];
+	unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
+	unsigned int cookie_len;
+
+	/* 
+	 * The current data and handshake epoch.  This is initially
+	 * undefined, and starts at zero once the initial handshake is
+	 * completed 
+	 */
+	unsigned short r_epoch;
+	unsigned short w_epoch;
+
+	/* records being received in the current epoch */
+	DTLS1_BITMAP bitmap;
+
+	/* renegotiation starts a new set of sequence numbers */
+	DTLS1_BITMAP next_bitmap;
+
+	/* handshake message numbers */
+	unsigned short handshake_write_seq;
+	unsigned short next_handshake_write_seq;
+
+	unsigned short handshake_read_seq;
+
+	/* save last sequence number for retransmissions */
+	unsigned char last_write_sequence[8];
+
+	/* Received handshake records (processed and unprocessed) */
+	record_pqueue unprocessed_rcds;
+	record_pqueue processed_rcds;
+
+	/* Buffered handshake messages */
+	pqueue buffered_messages;
+
+	/* Buffered (sent) handshake records */
+	pqueue sent_messages;
+
+	/* Buffered application records.
+	 * Only for records between CCS and Finished
+	 * to prevent either protocol violation or
+	 * unnecessary message loss.
+	 */
+	record_pqueue buffered_app_data;
+
+	/* Is set when listening for new connections with dtls1_listen() */
+	unsigned int listen;
+
+	unsigned int mtu; /* max DTLS packet size */
+
+	struct hm_header_st w_msg_hdr;
+	struct hm_header_st r_msg_hdr;
+
+	struct dtls1_timeout_st timeout;
+
+	/* Indicates when the last handshake msg or heartbeat sent will timeout */
+	struct timeval next_timeout;
+
+	/* Timeout duration */
+	unsigned short timeout_duration;
+
+	/* storage for Alert/Handshake protocol data received but not
+	 * yet processed by ssl3_read_bytes: */
+	unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
+	unsigned int alert_fragment_len;
+	unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
+	unsigned int handshake_fragment_len;
+
+	unsigned int retransmitting;
+	unsigned int change_cipher_spec_ok;
+	} DTLS1_STATE;
+
+typedef struct dtls1_record_data_st
+	{
+	unsigned char *packet;
+	unsigned int   packet_length;
+	SSL3_BUFFER    rbuf;
+	SSL3_RECORD    rrec;
+	} DTLS1_RECORD_DATA;
+
+#endif
+
+/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
+#define DTLS1_TMO_READ_COUNT                      2
+#define DTLS1_TMO_WRITE_COUNT                     2
+
+#define DTLS1_TMO_ALERT_COUNT                     12
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
diff --git a/ssl/pqueue/CMakeLists.txt b/ssl/pqueue/CMakeLists.txt
new file mode 100644
index 0000000..58963ff
--- /dev/null
+++ b/ssl/pqueue/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(../../include)
+
+add_library(
+	pqueue
+
+	OBJECT
+
+	pqueue.c
+)
diff --git a/ssl/pqueue/pqueue.c b/ssl/pqueue/pqueue.c
new file mode 100644
index 0000000..c6cd34d
--- /dev/null
+++ b/ssl/pqueue/pqueue.c
@@ -0,0 +1,190 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include "pqueue.h"
+
+#include <openssl/mem.h>
+
+
+typedef struct _pqueue {
+  pitem *items;
+  unsigned count;
+} pqueue_s;
+
+
+pitem *pitem_new(uint8_t prio64be[8], void *data) {
+  pitem *item = (pitem *)OPENSSL_malloc(sizeof(pitem));
+  if (item == NULL) {
+    return NULL;
+  }
+
+  memcpy(item->priority, prio64be, sizeof(item->priority));
+
+  item->data = data;
+  item->next = NULL;
+
+  return item;
+}
+
+void pitem_free(pitem *item) {
+  if (item == NULL) {
+    return;
+  }
+
+  OPENSSL_free(item);
+}
+
+pqueue pqueue_new() {
+  pqueue_s *pq = (pqueue_s *)OPENSSL_malloc(sizeof(pqueue_s));
+  if (pq == NULL) {
+    return NULL;
+  }
+
+  memset(pq, 0, sizeof(pqueue_s));
+  return pq;
+}
+
+void pqueue_free(pqueue_s *pq) {
+  if (pq == NULL) {
+    return;
+  }
+
+  OPENSSL_free(pq);
+}
+
+pitem *pqueue_peek(pqueue_s *pq) { return pq->items; }
+
+pitem *pqueue_find(pqueue_s *pq, uint8_t *prio64be) {
+  pitem *curr;
+
+  for (curr = pq->items; curr; curr = curr->next) {
+    if (memcmp(curr->priority, prio64be, 8) == 0) {
+      return curr;
+    }
+  }
+
+  return NULL;
+}
+
+size_t pqueue_size(pqueue_s *pq) {
+  pitem *item = pq->items;
+  size_t count = 0;
+
+  while (item != NULL) {
+    count++;
+    item = item->next;
+  }
+  return count;
+}
+
+pitem *pqueue_iterator(pqueue_s *pq) { return pq->items; }
+
+pitem *pqueue_next(pitem **item) {
+  pitem *ret;
+
+  if (item == NULL || *item == NULL) {
+    return NULL;
+  }
+
+  ret = *item;
+  *item = (*item)->next;
+
+  return ret;
+}
+
+pitem *pqueue_insert(pqueue_s *pq, pitem *item) {
+  pitem *curr, *next;
+
+  if (pq->items == NULL) {
+    pq->items = item;
+    return item;
+  }
+
+  for (curr = NULL, next = pq->items; next != NULL;
+       curr = next, next = next->next) {
+    /* we can compare 64-bit value in big-endian encoding with memcmp. */
+    int cmp = memcmp(next->priority, item->priority, 8);
+    if (cmp > 0) /* next > item */
+    {
+      item->next = next;
+
+      if (curr == NULL) {
+        pq->items = item;
+      } else {
+        curr->next = item;
+      }
+
+      return item;
+    } else if (cmp == 0) /* duplicates not allowed */
+      return NULL;
+  }
+
+  item->next = NULL;
+  curr->next = item;
+
+  return item;
+}
+
+
+pitem *pqueue_pop(pqueue_s *pq) {
+  pitem *item = pq->items;
+
+  if (pq->items != NULL) {
+    pq->items = pq->items->next;
+  }
+
+  return item;
+}
diff --git a/ssl/pqueue/pqueue.h b/ssl/pqueue/pqueue.h
new file mode 100644
index 0000000..8ad023a
--- /dev/null
+++ b/ssl/pqueue/pqueue.h
@@ -0,0 +1,147 @@
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#ifndef OPENSSL_HEADER_PQUEUE_H
+#define OPENSSL_HEADER_PQUEUE_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Priority queue.
+ *
+ * The priority queue maintains a linked-list of nodes, each with a unique,
+ * 64-bit priority, in ascending priority order. */
+
+typedef struct _pqueue *pqueue;
+
+typedef struct _pitem {
+  uint8_t priority[8]; /* 64-bit value in big-endian encoding */
+  void *data;
+  struct _pitem *next;
+} pitem;
+
+typedef struct _pitem *piterator;
+
+
+/* Creating and freeing queues. */
+
+/* pqueue_new allocates a fresh, empty priority queue object and returns it, or
+ * NULL on error. */
+pqueue pqueue_new();
+
+/* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must
+ * be empty or a memory leak will occur. */
+void pqueue_free(pqueue pq);
+
+
+/* Creating and freeing items. */
+
+/* pitem_new allocates a fresh priority queue item that points at |data| and
+ * has a priority given by |prio64be|, which is a 64-bit, unsigned number
+ * expressed in big-endian form. It returns the fresh item, or NULL on
+ * error. */
+pitem *pitem_new(uint8_t prio64be[8], void *data);
+
+/* pitem_free frees |item|, but not any data that it points to. */
+void pitem_free(pitem *item);
+
+
+/* Queue accessor functions */
+
+/* pqueue_peek returns the item with the smallest priority from |pq|, or NULL
+ * if empty. */
+pitem *pqueue_peek(pqueue pq);
+
+/* pqueue_find returns the item whose priority matches |prio64be| or NULL if no
+ * such item exists. */
+pitem *pqueue_find(pqueue pq, unsigned char *prio64be);
+
+
+/* Queue mutation functions */
+
+/* pqueue_insert inserts |item| into |pq| and returns item. */
+pitem *pqueue_insert(pqueue pq, pitem *item);
+
+/* pqueue_pop takes the item with the least priority from |pq| and returns it,
+ * or NULL if |pq| is empty. */
+pitem *pqueue_pop(pqueue pq);
+
+/* pqueue_size returns the number of items in |pq|. */
+size_t pqueue_size(pqueue pq);
+
+
+/* Iterating */
+
+/* pqueue_iterator returns an iterator that can be used to iterate over the
+ * contents of the queue. */
+pitem *pqueue_iterator(pqueue pq);
+
+/* pqueue_next returns the current value of |iter| and advances it to the next
+ * position. If the iterator has advanced over all the elements, it returns
+ * NULL. */
+pitem *pqueue_next(piterator *iter);
+
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_PQUEUE_H */
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
new file mode 100644
index 0000000..e36d932
--- /dev/null
+++ b/ssl/s23_clnt.c
@@ -0,0 +1,716 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+static const SSL_METHOD *ssl23_get_client_method(int ver);
+static int ssl23_client_hello(SSL *s);
+static int ssl23_get_server_hello(SSL *s);
+static const SSL_METHOD *ssl23_get_client_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_client_method());
+	else if (ver == TLS1_VERSION)
+		return(TLSv1_client_method());
+	else if (ver == TLS1_1_VERSION)
+		return(TLSv1_1_client_method());
+	else if (ver == TLS1_2_VERSION)
+		return(TLSv1_2_client_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl23_meth_func(SSLv23_client_method,
+			ssl_undefined_function,
+			ssl23_connect,
+			ssl23_get_client_method)
+
+int ssl23_connect(SSL *s)
+	{
+	BUF_MEM *buf=NULL;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state;
+
+	ERR_clear_error();
+	ERR_clear_system_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)) SSL_clear(s); 
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch(s->state)
+			{
+		case SSL_ST_BEFORE:
+		case SSL_ST_CONNECT:
+		case SSL_ST_BEFORE|SSL_ST_CONNECT:
+		case SSL_ST_OK|SSL_ST_CONNECT:
+
+			if (s->session != NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_connect, SSL_R_SSL23_DOING_SESSION_ID_REUSE);
+				ret= -1;
+				goto end;
+				}
+			s->server=0;
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+			/* s->version=TLS1_VERSION; */
+			s->type=SSL_ST_CONNECT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				buf=NULL;
+				}
+
+			if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
+
+			ssl3_init_finished_mac(s);
+
+			s->state=SSL23_ST_CW_CLNT_HELLO_A;
+			s->ctx->stats.sess_connect++;
+			s->init_num=0;
+			break;
+
+		case SSL23_ST_CW_CLNT_HELLO_A:
+		case SSL23_ST_CW_CLNT_HELLO_B:
+
+			s->shutdown=0;
+			ret=ssl23_client_hello(s);
+			if (ret <= 0) goto end;
+			s->state=SSL23_ST_CR_SRVR_HELLO_A;
+			s->init_num=0;
+
+			break;
+
+		case SSL23_ST_CR_SRVR_HELLO_A:
+		case SSL23_ST_CR_SRVR_HELLO_B:
+			ret=ssl23_get_server_hello(s);
+			if (ret >= 0) cb=NULL;
+			goto end;
+			/* break; */
+
+		default:
+			OPENSSL_PUT_ERROR(SSL, ssl23_connect, SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* break; */
+			}
+
+		if (s->debug) { (void)BIO_flush(s->wbio); }
+
+		if ((cb != NULL) && (s->state != state))
+			{
+			new_state=s->state;
+			s->state=state;
+			cb(s,SSL_CB_CONNECT_LOOP,1);
+			s->state=new_state;
+			}
+		}
+end:
+	s->in_handshake--;
+	if (buf != NULL)
+		BUF_MEM_free(buf);
+	if (cb != NULL)
+		cb(s,SSL_CB_CONNECT_EXIT,ret);
+	return(ret);
+	}
+
+static int ssl23_no_ssl2_ciphers(SSL *s)
+	{
+	SSL_CIPHER *cipher;
+	STACK_OF(SSL_CIPHER) *ciphers;
+	int i;
+	ciphers = SSL_get_ciphers(s);
+	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++)
+		{
+		cipher = sk_SSL_CIPHER_value(ciphers, i);
+		if (cipher->algorithm_ssl == SSL_SSLV2)
+			return 0;
+		}
+	return 1;
+	}
+
+/* Fill a ClientRandom or ServerRandom field of length len. Returns <= 0
+ * on failure, 1 on success. */
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, int len)
+	{
+		int send_time = 0;
+		if (len < 4)
+			return 0;
+		if (server)
+			send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0;
+		else
+			send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0;
+		if (send_time)
+			{
+			unsigned long Time = (unsigned long)time(NULL);
+			unsigned char *p = result;
+			l2n(Time, p);
+			return RAND_pseudo_bytes(p, len-4);
+			}
+		else
+			return RAND_pseudo_bytes(result, len);
+	}
+
+static int ssl23_client_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i,ch_len;
+	unsigned long l;
+	int ssl2_compat;
+	int version = 0, version_major, version_minor;
+	int ret;
+	unsigned long mask, options = s->options;
+
+	ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1;
+
+	if (ssl2_compat && ssl23_no_ssl2_ciphers(s))
+		ssl2_compat = 0;
+
+	/*
+	 * SSL_OP_NO_X disables all protocols above X *if* there are
+	 * some protocols below X enabled. This is required in order
+	 * to maintain "version capability" vector contiguous. So
+	 * that if application wants to disable TLS1.0 in favour of
+	 * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+	 * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2.
+	 */
+	mask =	SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+		|SSL_OP_NO_SSLv3
+#endif
+		;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+	version = TLS1_2_VERSION;
+
+	if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
+		version = TLS1_1_VERSION;
+#else
+	version = TLS1_1_VERSION;
+#endif
+	mask &= ~SSL_OP_NO_TLSv1_1;
+	if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+		version = TLS1_VERSION;
+	mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+	if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+		version = SSL3_VERSION;
+	mask &= ~SSL_OP_NO_SSLv3;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (version != SSL2_VERSION)
+		{
+		/* have to disable SSL 2.0 compatibility if we need TLS extensions */
+
+		if (s->tlsext_hostname != NULL)
+			ssl2_compat = 0;
+		if (s->tlsext_status_type != -1)
+			ssl2_compat = 0;
+#ifdef TLSEXT_TYPE_opaque_prf_input
+		if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
+			ssl2_compat = 0;
+#endif
+		if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+			ssl2_compat = 0;
+		if (s->ctx->custom_cli_ext_records_count != 0)
+			ssl2_compat = 0;
+		}
+#endif
+
+	buf=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+		{
+#if 0
+		/* don't reuse session-id's */
+		if (!ssl_get_new_session(s,0))
+			{
+			return(-1);
+			}
+#endif
+
+		p=s->s3->client_random;
+		if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
+			return -1;
+
+		if (version == TLS1_2_VERSION)
+			{
+			version_major = TLS1_2_VERSION_MAJOR;
+			version_minor = TLS1_2_VERSION_MINOR;
+			}
+		else if (tls1_suiteb(s))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+			return -1;
+			}
+		else if (version == TLS1_1_VERSION)
+			{
+			version_major = TLS1_1_VERSION_MAJOR;
+			version_minor = TLS1_1_VERSION_MINOR;
+			}
+		else if (version == TLS1_VERSION)
+			{
+			version_major = TLS1_VERSION_MAJOR;
+			version_minor = TLS1_VERSION_MINOR;
+			}
+#ifdef OPENSSL_FIPS
+		else if(FIPS_mode())
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+			return -1;
+			}
+#endif
+		else if (version == SSL3_VERSION)
+			{
+			version_major = SSL3_VERSION_MAJOR;
+			version_minor = SSL3_VERSION_MINOR;
+			}
+		else if (version == SSL2_VERSION)
+			{
+			version_major = SSL2_VERSION_MAJOR;
+			version_minor = SSL2_VERSION_MINOR;
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_NO_PROTOCOLS_AVAILABLE);
+			return(-1);
+			}
+
+		s->client_version = version;
+
+		if (ssl2_compat)
+			{
+			/* create SSL 2.0 compatible Client Hello */
+
+			/* two byte record header will be written last */
+			d = &(buf[2]);
+			p = d + 9; /* leave space for message type, version, individual length fields */
+
+			*(d++) = SSL2_MT_CLIENT_HELLO;
+			*(d++) = version_major;
+			*(d++) = version_minor;
+			
+			/* Ciphers supported */
+			i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),p,0);
+			if (i == 0)
+				{
+				/* no ciphers */
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_NO_CIPHERS_AVAILABLE);
+				return -1;
+				}
+			s2n(i,d);
+			p+=i;
+			
+			/* put in the session-id length (zero since there is no reuse) */
+#if 0
+			s->session->session_id_length=0;
+#endif
+			s2n(0,d);
+
+			if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG)
+				ch_len=SSL2_CHALLENGE_LENGTH;
+			else
+				ch_len=SSL2_MAX_CHALLENGE_LENGTH;
+
+			/* write out sslv2 challenge */
+			/* Note that ch_len must be <= SSL3_RANDOM_SIZE (32),
+			   because it is one of SSL2_MAX_CHALLENGE_LENGTH (32)
+			   or SSL2_MAX_CHALLENGE_LENGTH (16), but leave the
+			   check in for futurproofing */
+			if (SSL3_RANDOM_SIZE < ch_len)
+				i=SSL3_RANDOM_SIZE;
+			else
+				i=ch_len;
+			s2n(i,d);
+			memset(&(s->s3->client_random[0]),0,SSL3_RANDOM_SIZE);
+			if (RAND_pseudo_bytes(&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i) <= 0)
+				return -1;
+
+			memcpy(p,&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i);
+			p+=i;
+
+			i= p- &(buf[2]);
+			buf[0]=((i>>8)&0xff)|0x80;
+			buf[1]=(i&0xff);
+
+			/* number of bytes to write */
+			s->init_num=i+2;
+			s->init_off=0;
+
+			ssl3_finish_mac(s,&(buf[2]),i);
+			}
+		else
+			{
+			/* create Client Hello in SSL 3.0/TLS 1.0 format */
+
+			/* do the record header (5 bytes) and handshake message header (4 bytes) last */
+			d = p = &(buf[9]);
+			
+			*(p++) = version_major;
+			*(p++) = version_minor;
+
+			/* Random stuff */
+			memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+			p += SSL3_RANDOM_SIZE;
+
+			/* Session ID (zero since there is no reuse) */
+			*(p++) = 0;
+
+			/* Ciphers supported (using SSL 3.0/TLS 1.0 format) */
+			i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),ssl3_put_cipher_by_char);
+			if (i == 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_NO_CIPHERS_AVAILABLE);
+				return -1;
+				}
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+			/* Some servers hang if client hello > 256 bytes
+			 * as hack workaround chop number of supported ciphers
+			 * to keep it well below this if we use TLS v1.2
+			 */
+			if (TLS1_get_version(s) >= TLS1_2_VERSION
+				&& i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+				i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
+			s2n(i,p);
+			p+=i;
+
+			/* COMPRESSION */
+			*(p++)=1;
+			*(p++)=0; /* Add the NULL method */
+
+#ifndef OPENSSL_NO_TLSEXT
+			/* TLS extensions*/
+			if (ssl_prepare_clienthello_tlsext(s) <= 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
+				return -1;
+				}
+			if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+#endif
+			
+			l = p-d;
+
+			/* fill in 4-byte handshake header */
+			d=&(buf[5]);
+			*(d++)=SSL3_MT_CLIENT_HELLO;
+			l2n3(l,d);
+
+			l += 4;
+
+			if (l > SSL3_RT_MAX_PLAIN_LENGTH)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+			
+			/* fill in 5-byte record header */
+			d=buf;
+			*(d++) = SSL3_RT_HANDSHAKE;
+			*(d++) = version_major;
+			/* Some servers hang if we use long client hellos
+			 * and a record number > TLS 1.0.
+			 */
+			if (TLS1_get_client_version(s) > TLS1_VERSION)
+				*(d++) = 1;
+			else
+				*(d++) = version_minor;
+			s2n((int)l,d);
+
+			/* number of bytes to write */
+			s->init_num=p-buf;
+			s->init_off=0;
+
+			ssl3_finish_mac(s,&(buf[5]), s->init_num - 5);
+			}
+
+		s->state=SSL23_ST_CW_CLNT_HELLO_B;
+		s->init_off=0;
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	ret = ssl23_write_bytes(s);
+
+	if ((ret >= 2) && s->msg_callback)
+		{
+		/* Client Hello has been sent; tell msg_callback */
+
+		if (ssl2_compat)
+			s->msg_callback(1, SSL2_VERSION, 0, s->init_buf->data+2, ret-2, s, s->msg_callback_arg);
+		else
+			{
+			s->msg_callback(1, version, SSL3_RT_HEADER, s->init_buf->data, 5, s, s->msg_callback_arg);
+			s->msg_callback(1, version, SSL3_RT_HANDSHAKE, s->init_buf->data+5, ret-5, s, s->msg_callback_arg);
+			}
+		}
+
+	return ret;
+	}
+
+static int ssl23_get_server_hello(SSL *s)
+	{
+	char buf[8];
+	unsigned char *p;
+	int i;
+	int n;
+
+	n=ssl23_read_bytes(s,7);
+
+	if (n != 7) return(n);
+	p=s->packet;
+
+	memcpy(buf,p,n);
+
+	if ((p[0] & 0x80) && (p[2] == SSL2_MT_SERVER_HELLO) &&
+		(p[5] == 0x00) && (p[6] == 0x02))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+		goto err;
+		}
+	else if (p[1] == SSL3_VERSION_MAJOR &&
+	         p[2] <= TLS1_2_VERSION_MINOR &&
+	         ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) ||
+	          (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2)))
+		{
+		/* we have sslv3 or tls1 (server hello or alert) */
+
+		if ((p[2] == SSL3_VERSION_MINOR) &&
+			!(s->options & SSL_OP_NO_SSLv3))
+			{
+#ifdef OPENSSL_FIPS
+			if(FIPS_mode())
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+				goto err;
+				}
+#endif
+			s->version=SSL3_VERSION;
+			s->method=SSLv3_client_method();
+			}
+		else if ((p[2] == TLS1_VERSION_MINOR) &&
+			!(s->options & SSL_OP_NO_TLSv1))
+			{
+			s->version=TLS1_VERSION;
+			s->method=TLSv1_client_method();
+			}
+		else if ((p[2] == TLS1_1_VERSION_MINOR) &&
+			!(s->options & SSL_OP_NO_TLSv1_1))
+			{
+			s->version=TLS1_1_VERSION;
+			s->method=TLSv1_1_client_method();
+			}
+		else if ((p[2] == TLS1_2_VERSION_MINOR) &&
+			!(s->options & SSL_OP_NO_TLSv1_2))
+			{
+			s->version=TLS1_2_VERSION;
+			s->method=TLSv1_2_client_method();
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+			goto err;
+			}
+
+		if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING)
+			{
+			/* fatal alert */
+
+			void (*cb)(const SSL *ssl,int type,int val)=NULL;
+			int j;
+
+			if (s->info_callback != NULL)
+				cb=s->info_callback;
+			else if (s->ctx->info_callback != NULL)
+				cb=s->ctx->info_callback;
+ 
+			i=p[5];
+			if (cb != NULL)
+				{
+				j=(i<<8)|p[6];
+				cb(s,SSL_CB_READ_ALERT,j);
+				}
+			
+			if (s->msg_callback)
+				{
+				s->msg_callback(0, s->version, SSL3_RT_HEADER, p, 5, s, s->msg_callback_arg);
+				s->msg_callback(0, s->version, SSL3_RT_ALERT, p+5, 2, s, s->msg_callback_arg);
+				}
+
+			s->rwstate=SSL_NOTHING;
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_AD_REASON_OFFSET + p[6]);
+			goto err;
+			}
+
+		if (!ssl_init_wbio_buffer(s,1)) goto err;
+
+		/* we are in this state */
+		s->state=SSL3_ST_CR_SRVR_HELLO_A;
+
+		/* put the 7 bytes we have read into the input buffer
+		 * for SSLv3 */
+		s->rstate=SSL_ST_READ_HEADER;
+		s->packet_length=n;
+		if (s->s3->rbuf.buf == NULL)
+			if (!ssl3_setup_read_buffer(s))
+				goto err;
+		s->packet= &(s->s3->rbuf.buf[0]);
+		memcpy(s->packet,buf,n);
+		s->s3->rbuf.left=n;
+		s->s3->rbuf.offset=0;
+
+		s->handshake_func=s->method->ssl_connect;
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_UNKNOWN_PROTOCOL);
+		goto err;
+		}
+	s->init_num=0;
+
+	/* Since, if we are sending a ssl23 client hello, we are not
+	 * reusing a session-id */
+	if (!ssl_get_new_session(s,0))
+		goto err;
+
+	return(SSL_connect(s));
+err:
+	return(-1);
+	}
diff --git a/ssl/s23_lib.c b/ssl/s23_lib.c
new file mode 100644
index 0000000..69b4c64
--- /dev/null
+++ b/ssl/s23_lib.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/err.h>
+#include <openssl/obj.h>
+
+#include "ssl_locl.h"
+
+long ssl23_default_timeout(void)
+	{
+	return(300);
+	}
+
+int ssl23_num_ciphers(void)
+	{
+	return(ssl3_num_ciphers()
+	    );
+	}
+
+const SSL_CIPHER *ssl23_get_cipher(unsigned int u)
+	{
+	unsigned int uu=ssl3_num_ciphers();
+
+	if (u < uu)
+		return(ssl3_get_cipher(u));
+	else
+		return(NULL);
+	}
+
+/* This function needs to check if the ciphers required are actually
+ * available */
+const SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p)
+	{
+	const SSL_CIPHER *cp;
+
+	cp=ssl3_get_cipher_by_char(p);
+	return(cp);
+	}
+
+int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p)
+	{
+	long l;
+
+	/* We can write SSLv2 and SSLv3 ciphers */
+	if (p != NULL)
+		{
+		l=c->id;
+		p[0]=((unsigned char)(l>>16L))&0xFF;
+		p[1]=((unsigned char)(l>> 8L))&0xFF;
+		p[2]=((unsigned char)(l     ))&0xFF;
+		}
+	return(3);
+	}
+
+int ssl23_read(SSL *s, void *buf, int len)
+	{
+	int n;
+
+	ERR_clear_system_error();
+	if (SSL_in_init(s) && (!s->in_handshake))
+		{
+		n=s->handshake_func(s);
+		if (n < 0) return(n);
+		if (n == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_read, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		return(SSL_read(s,buf,len));
+		}
+	else
+		{
+		ssl_undefined_function(s);
+		return(-1);
+		}
+	}
+
+int ssl23_peek(SSL *s, void *buf, int len)
+	{
+	int n;
+
+	ERR_clear_system_error();
+	if (SSL_in_init(s) && (!s->in_handshake))
+		{
+		n=s->handshake_func(s);
+		if (n < 0) return(n);
+		if (n == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_peek, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		return(SSL_peek(s,buf,len));
+		}
+	else
+		{
+		ssl_undefined_function(s);
+		return(-1);
+		}
+	}
+
+int ssl23_write(SSL *s, const void *buf, int len)
+	{
+	int n;
+
+	ERR_clear_system_error();
+	if (SSL_in_init(s) && (!s->in_handshake))
+		{
+		n=s->handshake_func(s);
+		if (n < 0) return(n);
+		if (n == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_write, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		return(SSL_write(s,buf,len));
+		}
+	else
+		{
+		ssl_undefined_function(s);
+		return(-1);
+		}
+	}
diff --git a/ssl/s23_meth.c b/ssl/s23_meth.c
new file mode 100644
index 0000000..16424d0
--- /dev/null
+++ b/ssl/s23_meth.c
@@ -0,0 +1,88 @@
+/* ssl/s23_meth.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/obj.h>
+
+#include "ssl_locl.h"
+
+
+static const SSL_METHOD *ssl23_get_method(int ver);
+static const SSL_METHOD *ssl23_get_method(int ver)
+	{
+#ifndef OPENSSL_NO_SSL3
+	if (ver == SSL3_VERSION)
+		return(SSLv3_method());
+	else
+#endif
+#ifndef OPENSSL_NO_TLS1
+	if (ver == TLS1_VERSION)
+		return(TLSv1_method());
+	else if (ver == TLS1_1_VERSION)
+		return(TLSv1_1_method());
+	else if (ver == TLS1_2_VERSION)
+		return(TLSv1_2_method());
+	else
+#endif
+		return(NULL);
+	}
+
+IMPLEMENT_ssl23_meth_func(SSLv23_method,
+			ssl23_accept,
+			ssl23_connect,
+			ssl23_get_method)
diff --git a/ssl/s23_pkt.c b/ssl/s23_pkt.c
new file mode 100644
index 0000000..796dcb3
--- /dev/null
+++ b/ssl/s23_pkt.c
@@ -0,0 +1,117 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 <errno.h>
+
+#include <openssl/buf.h>
+#include <openssl/evp.h>
+
+#include "ssl_locl.h"
+
+
+int ssl23_write_bytes(SSL *s)
+	{
+	int i,num,tot;
+	char *buf;
+
+	buf=s->init_buf->data;
+	tot=s->init_off;
+	num=s->init_num;
+	for (;;)
+		{
+		s->rwstate=SSL_WRITING;
+		i=BIO_write(s->wbio,&(buf[tot]),num);
+		if (i <= 0)
+			{
+			s->init_off=tot;
+			s->init_num=num;
+			return(i);
+			}
+		s->rwstate=SSL_NOTHING;
+		if (i == num) return(tot+i);
+
+		num-=i;
+		tot+=i;
+		}
+	}
+
+/* return regularly only when we have read (at least) 'n' bytes */
+int ssl23_read_bytes(SSL *s, int n)
+	{
+	unsigned char *p;
+	int j;
+
+	if (s->packet_length < (unsigned int)n)
+		{
+		p=s->packet;
+
+		for (;;)
+			{
+			s->rwstate=SSL_READING;
+			j=BIO_read(s->rbio,(char *)&(p[s->packet_length]),
+				n-s->packet_length);
+			if (j <= 0)
+				return(j);
+			s->rwstate=SSL_NOTHING;
+			s->packet_length+=j;
+			if (s->packet_length >= (unsigned int)n)
+				return(s->packet_length);
+			}
+		}
+	return(n);
+	}
+
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
new file mode 100644
index 0000000..55e503c
--- /dev/null
+++ b/ssl/s23_srvr.c
@@ -0,0 +1,593 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+static const SSL_METHOD *ssl23_get_server_method(int ver);
+int ssl23_get_client_hello(SSL *s);
+static const SSL_METHOD *ssl23_get_server_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_server_method());
+	else if (ver == TLS1_VERSION)
+		return(TLSv1_server_method());
+	else if (ver == TLS1_1_VERSION)
+		return(TLSv1_1_server_method());
+	else if (ver == TLS1_2_VERSION)
+		return(TLSv1_2_server_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl23_meth_func(SSLv23_server_method,
+			ssl23_accept,
+			ssl_undefined_function,
+			ssl23_get_server_method)
+
+int ssl23_accept(SSL *s)
+	{
+	BUF_MEM *buf;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state;
+
+	ERR_clear_error();
+	ERR_clear_system_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)) SSL_clear(s); 
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch(s->state)
+			{
+		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);
+
+			/* s->version=SSL3_VERSION; */
+			s->type=SSL_ST_ACCEPT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				}
+
+			ssl3_init_finished_mac(s);
+
+			s->state=SSL23_ST_SR_CLNT_HELLO_A;
+			s->ctx->stats.sess_accept++;
+			s->init_num=0;
+			break;
+
+		case SSL23_ST_SR_CLNT_HELLO_A:
+		case SSL23_ST_SR_CLNT_HELLO_B:
+
+			s->shutdown=0;
+			ret=ssl23_get_client_hello(s);
+			if (ret >= 0) cb=NULL;
+			goto end;
+			/* break; */
+
+		default:
+			OPENSSL_PUT_ERROR(SSL, ssl23_accept, SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* break; */
+			}
+
+		if ((cb != NULL) && (s->state != state))
+			{
+			new_state=s->state;
+			s->state=state;
+			cb(s,SSL_CB_ACCEPT_LOOP,1);
+			s->state=new_state;
+			}
+		}
+end:
+	s->in_handshake--;
+	if (cb != NULL)
+		cb(s,SSL_CB_ACCEPT_EXIT,ret);
+	return(ret);
+	}
+
+
+int ssl23_get_client_hello(SSL *s)
+	{
+	char buf_space[11]; /* Request this many bytes in initial read.
+	                     * We can detect SSL 3.0/TLS 1.0 Client Hellos
+	                     * ('type == 3') correctly only when the following
+	                     * is in a single record, which is not guaranteed by
+	                     * the protocol specification:
+	                     * Byte  Content
+	                     *  0     type            \
+	                     *  1/2   version          > record header
+	                     *  3/4   length          /
+	                     *  5     msg_type        \
+	                     *  6-8   length           > Client Hello message
+	                     *  9/10  client_version  /
+	                     */
+	char *buf= &(buf_space[0]);
+	unsigned char *p,*d,*d_len,*dd;
+	unsigned int i;
+	unsigned int csl,sil,cl;
+	int n=0,j;
+	int type=0;
+	int v[2];
+
+	if (s->state ==	SSL23_ST_SR_CLNT_HELLO_A)
+		{
+		/* read the initial header */
+		v[0]=v[1]=0;
+
+		if (!ssl3_setup_buffers(s)) goto err;
+
+		n=ssl23_read_bytes(s, sizeof buf_space);
+		if (n != sizeof buf_space) return(n); /* n == -1 || n == 0 */
+
+		p=s->packet;
+
+		memcpy(buf,p,n);
+
+		if ((p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO))
+			{
+			/*
+			 * SSLv2 header
+			 */
+			if ((p[3] == 0x00) && (p[4] == 0x02))
+				{
+				v[0]=p[3]; v[1]=p[4];
+				/* SSLv2 */
+				if (!(s->options & SSL_OP_NO_SSLv2))
+					type=1;
+				}
+			else if (p[3] == SSL3_VERSION_MAJOR)
+				{
+				v[0]=p[3]; v[1]=p[4];
+				/* SSLv3/TLSv1 */
+				if (p[4] >= TLS1_VERSION_MINOR)
+					{
+					if (p[4] >= TLS1_2_VERSION_MINOR &&
+					   !(s->options & SSL_OP_NO_TLSv1_2))
+						{
+						s->version=TLS1_2_VERSION;
+						s->state=SSL23_ST_SR_CLNT_HELLO_B;
+						}
+					else if (p[4] >= TLS1_1_VERSION_MINOR &&
+					   !(s->options & SSL_OP_NO_TLSv1_1))
+						{
+						s->version=TLS1_1_VERSION;
+						/* type=2; */ /* done later to survive restarts */
+						s->state=SSL23_ST_SR_CLNT_HELLO_B;
+						}
+					else if (!(s->options & SSL_OP_NO_TLSv1))
+						{
+						s->version=TLS1_VERSION;
+						/* type=2; */ /* done later to survive restarts */
+						s->state=SSL23_ST_SR_CLNT_HELLO_B;
+						}
+					else if (!(s->options & SSL_OP_NO_SSLv3))
+						{
+						s->version=SSL3_VERSION;
+						/* type=2; */
+						s->state=SSL23_ST_SR_CLNT_HELLO_B;
+						}
+					else if (!(s->options & SSL_OP_NO_SSLv2))
+						{
+						type=1;
+						}
+					}
+				else if (!(s->options & SSL_OP_NO_SSLv3))
+					{
+					s->version=SSL3_VERSION;
+					/* type=2; */
+					s->state=SSL23_ST_SR_CLNT_HELLO_B;
+					}
+				else if (!(s->options & SSL_OP_NO_SSLv2))
+					type=1;
+
+				}
+			}
+		else if ((p[0] == SSL3_RT_HANDSHAKE) &&
+			 (p[1] == SSL3_VERSION_MAJOR) &&
+			 (p[5] == SSL3_MT_CLIENT_HELLO) &&
+			 ((p[3] == 0 && p[4] < 5 /* silly record length? */)
+				|| (p[9] >= p[1])))
+			{
+			/*
+			 * SSLv3 or tls1 header
+			 */
+			
+			v[0]=p[1]; /* major version (= SSL3_VERSION_MAJOR) */
+			/* We must look at client_version inside the Client Hello message
+			 * to get the correct minor version.
+			 * However if we have only a pathologically small fragment of the
+			 * Client Hello message, this would be difficult, and we'd have
+			 * to read more records to find out.
+			 * No known SSL 3.0 client fragments ClientHello like this,
+			 * so we simply assume TLS 1.0 to avoid protocol version downgrade
+			 * attacks. */
+			if (p[3] == 0 && p[4] < 6)
+				{
+#if 0
+				OPENSSL_PUT_ERROR(SSL, XXX, SSL_R_RECORD_TOO_SMALL);
+				goto err;
+#else
+				v[1] = TLS1_VERSION_MINOR;
+#endif
+				}
+			/* if major version number > 3 set minor to a value
+			 * which will use the highest version 3 we support.
+			 * If TLS 2.0 ever appears we will need to revise
+			 * this....
+			 */
+			else if (p[9] > SSL3_VERSION_MAJOR)
+				v[1]=0xff;
+			else
+				v[1]=p[10]; /* minor version according to client_version */
+			if (v[1] >= TLS1_VERSION_MINOR)
+				{
+				if (v[1] >= TLS1_2_VERSION_MINOR &&
+					!(s->options & SSL_OP_NO_TLSv1_2))
+					{
+					s->version=TLS1_2_VERSION;
+					type=3;
+					}
+				else if (v[1] >= TLS1_1_VERSION_MINOR &&
+					!(s->options & SSL_OP_NO_TLSv1_1))
+					{
+					s->version=TLS1_1_VERSION;
+					type=3;
+					}
+				else if (!(s->options & SSL_OP_NO_TLSv1))
+					{
+					s->version=TLS1_VERSION;
+					type=3;
+					}
+				else if (!(s->options & SSL_OP_NO_SSLv3))
+					{
+					s->version=SSL3_VERSION;
+					type=3;
+					}
+				}
+			else
+				{
+				/* client requests SSL 3.0 */
+				if (!(s->options & SSL_OP_NO_SSLv3))
+					{
+					s->version=SSL3_VERSION;
+					type=3;
+					}
+				else if (!(s->options & SSL_OP_NO_TLSv1))
+					{
+					/* we won't be able to use TLS of course,
+					 * but this will send an appropriate alert */
+					s->version=TLS1_VERSION;
+					type=3;
+					}
+				}
+			}
+		else if ((strncmp("GET ", (char *)p,4) == 0) ||
+			 (strncmp("POST ",(char *)p,5) == 0) ||
+			 (strncmp("HEAD ",(char *)p,5) == 0) ||
+			 (strncmp("PUT ", (char *)p,4) == 0))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTP_REQUEST);
+			goto err;
+			}
+		else if (strncmp("CONNECT",(char *)p,7) == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTPS_PROXY_REQUEST);
+			goto err;
+			}
+		}
+
+	if (s->version < TLS1_2_VERSION && tls1_suiteb(s))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+		goto err;
+		}
+
+#ifdef OPENSSL_FIPS
+	if (FIPS_mode() && (s->version < TLS1_VERSION))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+		goto err;
+		}
+#endif
+
+	if (s->state == SSL23_ST_SR_CLNT_HELLO_B)
+		{
+		/* we have SSLv3/TLSv1 in an SSLv2 header
+		 * (other cases skip this state) */
+
+		type=2;
+		p=s->packet;
+		v[0] = p[3]; /* == SSL3_VERSION_MAJOR */
+		v[1] = p[4];
+
+		n=((p[0]&0x7f)<<8)|p[1];
+		if (n > (1024*4))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_TOO_LARGE);
+			goto err;
+			}
+
+		j=ssl23_read_bytes(s,n+2);
+		if (j <= 0) return(j);
+
+		ssl3_finish_mac(s, s->packet+2, s->packet_length-2);
+		if (s->msg_callback)
+			s->msg_callback(0, SSL2_VERSION, 0, s->packet+2, s->packet_length-2, s, s->msg_callback_arg); /* CLIENT-HELLO */
+
+		p=s->packet;
+		p+=5;
+		n2s(p,csl);
+		n2s(p,sil);
+		n2s(p,cl);
+		d=(unsigned char *)s->init_buf->data;
+		if ((csl+sil+cl+11) != s->packet_length) /* We can't have TLS extensions in SSL 2.0 format
+		                                          * Client Hello, can we? Error condition should be
+		                                          * '>' otherweise */
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_LENGTH_MISMATCH);
+			goto err;
+			}
+
+		/* record header: msg_type ... */
+		*(d++) = SSL3_MT_CLIENT_HELLO;
+		/* ... and length (actual value will be written later) */
+		d_len = d;
+		d += 3;
+
+		/* client_version */
+		*(d++) = SSL3_VERSION_MAJOR; /* == v[0] */
+		*(d++) = v[1];
+
+		/* lets populate the random area */
+		/* get the challenge_length */
+		i=(cl > SSL3_RANDOM_SIZE)?SSL3_RANDOM_SIZE:cl;
+		memset(d,0,SSL3_RANDOM_SIZE);
+		memcpy(&(d[SSL3_RANDOM_SIZE-i]),&(p[csl+sil]),i);
+		d+=SSL3_RANDOM_SIZE;
+
+		/* no session-id reuse */
+		*(d++)=0;
+
+		/* ciphers */
+		j=0;
+		dd=d;
+		d+=2;
+		for (i=0; i<csl; i+=3)
+			{
+			if (p[i] != 0) continue;
+			*(d++)=p[i+1];
+			*(d++)=p[i+2];
+			j+=2;
+			}
+		s2n(j,dd);
+
+		/* COMPRESSION */
+		*(d++)=1;
+		*(d++)=0;
+		
+#if 0
+                /* copy any remaining data with may be extensions */
+	        p = p+csl+sil+cl;
+		while (p <  s->packet+s->packet_length)
+			{
+			*(d++)=*(p++);
+			}
+#endif
+
+		i = (d-(unsigned char *)s->init_buf->data) - 4;
+		l2n3((long)i, d_len);
+
+		/* get the data reused from the init_buf */
+		s->s3->tmp.reuse_message=1;
+		s->s3->tmp.message_type=SSL3_MT_CLIENT_HELLO;
+		s->s3->tmp.message_size=i;
+		}
+
+	/* imaginary new state (for program structure): */
+	/* s->state = SSL23_SR_CLNT_HELLO_C */
+
+	if (type == 1)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+		goto err;
+		}
+
+	if ((type == 2) || (type == 3))
+		{
+		/* we have SSLv3/TLSv1 (type 2: SSL2 style, type 3: SSL3/TLS style) */
+
+		if (!ssl_init_wbio_buffer(s,1)) goto err;
+
+		/* we are in this state */
+		s->state=SSL3_ST_SR_CLNT_HELLO_A;
+
+		if (type == 3)
+			{
+			/* put the 'n' bytes we have read into the input buffer
+			 * for SSLv3 */
+			s->rstate=SSL_ST_READ_HEADER;
+			s->packet_length=n;
+			if (s->s3->rbuf.buf == NULL)
+				if (!ssl3_setup_read_buffer(s))
+					goto err;
+
+			s->packet= &(s->s3->rbuf.buf[0]);
+			memcpy(s->packet,buf,n);
+			s->s3->rbuf.left=n;
+			s->s3->rbuf.offset=0;
+			}
+		else
+			{
+			s->packet_length=0;
+			s->s3->rbuf.left=0;
+			s->s3->rbuf.offset=0;
+			}
+		if (s->version == TLS1_2_VERSION)
+			s->method = TLSv1_2_server_method();
+		else if (s->version == TLS1_1_VERSION)
+			s->method = TLSv1_1_server_method();
+		else if (s->version == TLS1_VERSION)
+			s->method = TLSv1_server_method();
+		else
+			s->method = SSLv3_server_method();
+#if 0 /* ssl3_get_client_hello does this */
+		s->client_version=(v[0]<<8)|v[1];
+#endif
+		s->handshake_func=s->method->ssl_accept;
+		}
+	
+	if ((type < 1) || (type > 3))
+		{
+		/* bad, very bad */
+		OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNKNOWN_PROTOCOL);
+		goto err;
+		}
+	s->init_num=0;
+
+	if (buf != buf_space) OPENSSL_free(buf);
+	return(SSL_accept(s));
+err:
+	if (buf != buf_space) OPENSSL_free(buf);
+	return(-1);
+	}
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
new file mode 100644
index 0000000..f49eab2
--- /dev/null
+++ b/ssl/s3_both.c
@@ -0,0 +1,776 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2002 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
+int ssl3_do_write(SSL *s, int type)
+	{
+	int ret;
+
+	ret=ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off],
+	                     s->init_num);
+	if (ret < 0) return(-1);
+	if (type == SSL3_RT_HANDSHAKE)
+		/* should not be done for 'Hello Request's, but in that case
+		 * we'll ignore the result anyway */
+		ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
+	
+	if (ret == s->init_num)
+		{
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, type, s->init_buf->data, (size_t)(s->init_off + s->init_num), s, s->msg_callback_arg);
+		return(1);
+		}
+	s->init_off+=ret;
+	s->init_num-=ret;
+	return(0);
+	}
+
+int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
+	{
+	unsigned char *p;
+	int i;
+	unsigned long l;
+
+	if (s->state == a)
+		{
+		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;
+
+                /* Copy the finished so we can use it for
+                   renegotiation checks */
+                if(s->type == SSL_ST_CONNECT)
+                        {
+                         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
+                        {
+                        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;
+                        }
+
+#ifdef OPENSSL_SYS_WIN16
+		/* MSVC 1.5 does not clear the top bytes of the word unless
+		 * I do this.
+		 */
+		l&=0xffff;
+#endif
+		ssl_set_handshake_header(s, SSL3_MT_FINISHED, l);
+		s->state=b;
+		}
+
+	/* SSL3_ST_SEND_xxxxxx_HELLO_B */
+	return ssl_do_write(s);
+	}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to far. */
+static void ssl3_take_mac(SSL *s)
+	{
+	const char *sender;
+	int slen;
+	/* If no new cipher setup return immediately: other functions will
+	 * set the appropriate error.
+	 */
+	if (s->s3->tmp.new_cipher == NULL)
+		return;
+	if (s->state & SSL_ST_CONNECT)
+		{
+		sender=s->method->ssl3_enc->server_finished_label;
+		slen=s->method->ssl3_enc->server_finished_label_len;
+		}
+	else
+		{
+		sender=s->method->ssl3_enc->client_finished_label;
+		slen=s->method->ssl3_enc->client_finished_label_len;
+		}
+
+	s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+		sender,slen,s->s3->tmp.peer_finish_md);
+	}
+#endif
+
+int ssl3_get_finished(SSL *s, int a, int b)
+	{
+	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
+
+	n=s->method->ssl_get_message(s,
+		a,
+		b,
+		SSL3_MT_FINISHED,
+		64, /* should actually be 36+4 :-) */
+		&ok);
+
+	if (!ok) return((int)n);
+
+	/* If this occurs, we have missed a message */
+	if (!s->s3->change_cipher_spec)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_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)
+		{
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_finished, SSL_R_BAD_DIGEST_LENGTH);
+		goto f_err;
+		}
+
+	if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
+		{
+		al=SSL_AD_DECRYPT_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_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)
+                {
+                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;
+                }
+        else
+                {
+                assert(i <= EVP_MAX_MD_SIZE);
+                memcpy(s->s3->previous_server_finished, 
+                    s->s3->tmp.peer_finish_md, i);
+                s->s3->previous_server_finished_len=i;
+                }
+
+	return(1);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	return(0);
+	}
+
+/* for these 2 messages, we need to
+ * ssl->enc_read_ctx			re-init
+ * ssl->s3->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)
+	{ 
+	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;
+		}
+
+	/* SSL3_ST_CW_CHANGE_B */
+	return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+	}
+
+unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
+	{
+	unsigned char *p;
+	unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s);
+
+	if (!ssl_add_cert_chain(s, cpk, &l))
+		return 0;
+
+	l -= 3 + SSL_HM_HEADER_LENGTH(s);
+	p = ssl_handshake_start(s);
+	l2n3(l,p);
+	l += 3;
+	ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l);
+	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)
+	{
+	unsigned char *p;
+	unsigned long l;
+	long n;
+	int i,al;
+
+	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;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE);
+			goto f_err;
+			}
+		*ok=1;
+		s->init_msg = s->init_buf->data + 4;
+		s->init_num = (int)s->s3->tmp.message_size;
+		return s->init_num;
+		}
+
+	p=(unsigned char *)s->init_buf->data;
+
+	if (s->state == st1) /* s->init_num < 4 */
+		{
+		int skip_message;
+
+		do
+			{
+			while (s->init_num < 4)
+				{
+				i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+					&p[s->init_num],4 - s->init_num, 0);
+				if (i <= 0)
+					{
+					s->rwstate=SSL_READING;
+					*ok = 0;
+					return i;
+					}
+				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_HANDSHAKE, p, 4, s, s->msg_callback_arg);
+						}
+			}
+		while (skip_message);
+
+		/* s->init_num == 4 */
+
+		if ((mt >= 0) && (*p != mt))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE);
+			goto f_err;
+			}
+		if ((mt < 0) && (*p == SSL3_MT_CLIENT_HELLO) &&
+					(st1 == SSL3_ST_SR_CERT_A) &&
+					(stn == SSL3_ST_SR_CERT_B))
+			{
+			/* At this point we have got an MS SGC second client
+			 * hello (maybe we should always allow the client to
+			 * start a new handshake?). We need to restart the mac.
+			 * Don't increment {num,total}_renegotiations because
+			 * we have not completed the handshake. */
+			ssl3_init_finished_mac(s);
+			}
+
+		s->s3->tmp.message_type= *(p++);
+
+		n2l3(p,l);
+		if (l > (unsigned long)max)
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+			goto f_err;
+			}
+		if (l > (INT_MAX-4)) /* BUF_MEM_grow takes an 'int' parameter */
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+			goto f_err;
+			}
+		if (l && !BUF_MEM_grow_clean(s->init_buf,(int)l+4))
+			{
+			OPENSSL_PUT_ERROR(SSL, 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 + 4;
+		s->init_num = 0;
+		}
+
+	/* next state (stn) */
+	p = s->init_msg;
+	n = s->s3->tmp.message_size - s->init_num;
+	while (n > 0)
+		{
+		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],n,0);
+		if (i <= 0)
+			{
+			s->rwstate=SSL_READING;
+			*ok = 0;
+			return i;
+			}
+		s->init_num += i;
+		n -= i;
+		}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	/* If receiving Finished, record MAC of prior handshake messages for
+	 * Finished verification. */
+	if (*s->init_buf->data == SSL3_MT_FINISHED)
+		ssl3_take_mac(s);
+#endif
+
+	/* Feed this message into MAC computation. */
+	ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4);
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, (size_t)s->init_num + 4, s, 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);
+	}
+
+int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
+	{
+	EVP_PKEY *pk;
+	int ret= -1,i;
+
+	if (pkey == NULL)
+		pk=X509_get_pubkey(x);
+	else
+		pk=pkey;
+	if (pk == NULL) goto err;
+
+	i=pk->type;
+	if (i == EVP_PKEY_RSA)
+		{
+		ret=SSL_PKEY_RSA_ENC;
+		}
+	else if (i == EVP_PKEY_DSA)
+		{
+		ret=SSL_PKEY_DSA_SIGN;
+		}
+#ifndef OPENSSL_NO_EC
+	else if (i == EVP_PKEY_EC)
+		{
+		ret = SSL_PKEY_ECC;
+		}	
+#endif
+	else if (i == NID_id_GostR3410_94 || i == NID_id_GostR3410_94_cc) 
+		{
+		ret = SSL_PKEY_GOST94;
+		}
+	else if (i == NID_id_GostR3410_2001 || i == NID_id_GostR3410_2001_cc) 
+		{
+		ret = SSL_PKEY_GOST01;
+		}
+	else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX))
+		{
+		/* For DH two cases: DH certificate signed with RSA and
+		 * DH certificate signed with DSA.
+		 */
+		i = X509_certificate_type(x, pk);
+		if (i & EVP_PKS_RSA)
+			ret = SSL_PKEY_DH_RSA;
+		else if (i & EVP_PKS_DSA)
+			ret = SSL_PKEY_DH_DSA;
+		}
+		
+err:
+	if(!pkey) EVP_PKEY_free(pk);
+	return(ret);
+	}
+
+int ssl_verify_alarm_type(long type)
+	{
+	int al;
+
+	switch(type)
+		{
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+	case X509_V_ERR_UNABLE_TO_GET_CRL:
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+		al=SSL_AD_UNKNOWN_CA;
+		break;
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_CRL_NOT_YET_VALID:
+	case X509_V_ERR_CERT_UNTRUSTED:
+	case X509_V_ERR_CERT_REJECTED:
+		al=SSL_AD_BAD_CERTIFICATE;
+		break;
+	case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+	case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+		al=SSL_AD_DECRYPT_ERROR;
+		break;
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_CRL_HAS_EXPIRED:
+		al=SSL_AD_CERTIFICATE_EXPIRED;
+		break;
+	case X509_V_ERR_CERT_REVOKED:
+		al=SSL_AD_CERTIFICATE_REVOKED;
+		break;
+	case X509_V_ERR_OUT_OF_MEM:
+		al=SSL_AD_INTERNAL_ERROR;
+		break;
+	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+	case X509_V_ERR_INVALID_CA:
+		al=SSL_AD_UNKNOWN_CA;
+		break;
+	case X509_V_ERR_APPLICATION_VERIFICATION:
+		al=SSL_AD_HANDSHAKE_FAILURE;
+		break;
+	case X509_V_ERR_INVALID_PURPOSE:
+		al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+		break;
+	default:
+		al=SSL_AD_CERTIFICATE_UNKNOWN;
+		break;
+		}
+	return(al);
+	}
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+/* On some platforms, malloc() performance is bad enough that you can't just
+ * free() and malloc() buffers all the time, so we need to use freelists from
+ * unused buffers.  Currently, each freelist holds memory chunks of only a
+ * given size (list->chunklen); other sized chunks are freed and malloced.
+ * This doesn't help much if you're using many different SSL option settings
+ * with a given context.  (The options affecting buffer size are
+ * max_send_fragment, read buffer vs write buffer,
+ * SSL_OP_MICROSOFT_BIG_WRITE_BUFFER, SSL_OP_NO_COMPRESSION, and
+ * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS.)  Using a separate freelist for every
+ * possible size is not an option, since max_send_fragment can take on many
+ * different values.
+ *
+ * If you are on a platform with a slow malloc(), and you're using SSL
+ * connections with many different settings for these options, and you need to
+ * use the SSL_MOD_RELEASE_BUFFERS feature, you have a few options:
+ *    - Link against a faster malloc implementation.
+ *    - Use a separate SSL_CTX for each option set.
+ *    - Improve this code.
+ */
+static void *
+freelist_extract(SSL_CTX *ctx, int for_read, int sz)
+	{
+	SSL3_BUF_FREELIST *list;
+	SSL3_BUF_FREELIST_ENTRY *ent = NULL;
+	void *result = NULL;
+
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist;
+	if (list != NULL && sz == (int)list->chunklen)
+		ent = list->head;
+	if (ent != NULL)
+		{
+		list->head = ent->next;
+		result = ent;
+		if (--list->len == 0)
+			list->chunklen = 0;
+		}
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	if (!result)
+		result = OPENSSL_malloc(sz);
+	return result;
+}
+
+static void
+freelist_insert(SSL_CTX *ctx, int for_read, size_t sz, void *mem)
+	{
+	SSL3_BUF_FREELIST *list;
+	SSL3_BUF_FREELIST_ENTRY *ent;
+
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist;
+	if (list != NULL &&
+	    (sz == list->chunklen || list->chunklen == 0) &&
+	    list->len < ctx->freelist_max_len &&
+	    sz >= sizeof(*ent))
+		{
+		list->chunklen = sz;
+		ent = mem;
+		ent->next = list->head;
+		list->head = ent;
+		++list->len;
+		mem = NULL;
+		}
+
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	if (mem)
+		OPENSSL_free(mem);
+	}
+#else
+#define freelist_extract(c,fr,sz) OPENSSL_malloc(sz)
+#define freelist_insert(c,fr,sz,m) OPENSSL_free(m)
+#endif
+
+int ssl3_setup_read_buffer(SSL *s)
+	{
+	unsigned char *p;
+	size_t len,align=0,headerlen;
+	
+	if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+		headerlen = DTLS1_RT_HEADER_LENGTH;
+	else
+		headerlen = SSL3_RT_HEADER_LENGTH;
+
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+	align = (-SSL3_RT_HEADER_LENGTH)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+
+	if (s->s3->rbuf.buf == NULL)
+		{
+		len = SSL3_RT_MAX_PLAIN_LENGTH
+			+ SSL3_RT_MAX_ENCRYPTED_OVERHEAD
+			+ headerlen + align;
+		if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
+			{
+			s->s3->init_extra = 1;
+			len += SSL3_RT_MAX_EXTRA;
+			}
+		if ((p=freelist_extract(s->ctx, 1, len)) == NULL)
+			goto err;
+		s->s3->rbuf.buf = p;
+		s->s3->rbuf.len = len;
+		}
+
+	s->packet= &(s->s3->rbuf.buf[0]);
+	return 1;
+
+err:
+	OPENSSL_PUT_ERROR(SSL, ssl3_setup_read_buffer, ERR_R_MALLOC_FAILURE);
+	return 0;
+	}
+
+int ssl3_setup_write_buffer(SSL *s)
+	{
+	unsigned char *p;
+	size_t len,align=0,headerlen;
+
+	if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+		headerlen = DTLS1_RT_HEADER_LENGTH + 1;
+	else
+		headerlen = SSL3_RT_HEADER_LENGTH;
+
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+	align = (-SSL3_RT_HEADER_LENGTH)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+
+	if (s->s3->wbuf.buf == NULL)
+		{
+		len = s->max_send_fragment
+			+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
+			+ headerlen + align;
+		if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
+			len += headerlen + align
+				+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+
+		if ((p=freelist_extract(s->ctx, 0, len)) == NULL)
+			goto err;
+		s->s3->wbuf.buf = p;
+		s->s3->wbuf.len = len;
+		}
+
+	return 1;
+
+err:
+	OPENSSL_PUT_ERROR(SSL, ssl3_setup_write_buffer, ERR_R_MALLOC_FAILURE);
+	return 0;
+	}
+
+
+int ssl3_setup_buffers(SSL *s)
+	{
+	if (!ssl3_setup_read_buffer(s))
+		return 0;
+	if (!ssl3_setup_write_buffer(s))
+		return 0;
+	return 1;
+	}
+
+int ssl3_release_write_buffer(SSL *s)
+	{
+	if (s->s3->wbuf.buf != NULL)
+		{
+		freelist_insert(s->ctx, 0, s->s3->wbuf.len, s->s3->wbuf.buf);
+		s->s3->wbuf.buf = NULL;
+		}
+	return 1;
+	}
+
+int ssl3_release_read_buffer(SSL *s)
+	{
+	if (s->s3->rbuf.buf != NULL)
+		{
+		freelist_insert(s->ctx, 1, s->s3->rbuf.len, s->s3->rbuf.buf);
+		s->s3->rbuf.buf = NULL;
+		}
+	return 1;
+	}
+
diff --git a/ssl/s3_cbc.c b/ssl/s3_cbc.c
new file mode 100644
index 0000000..d092593
--- /dev/null
+++ b/ssl/s3_cbc.c
@@ -0,0 +1,791 @@
+/* ====================================================================
+ * Copyright (c) 2012 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <assert.h>
+
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+#include <openssl/sha.h>
+
+#include "ssl_locl.h"
+
+
+/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length
+ * field. (SHA-384/512 have 128-bit length.) */
+#define MAX_HASH_BIT_COUNT_BYTES 16
+
+/* MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support.
+ * Currently SHA-384/512 has a 128-byte block size and that's the largest
+ * supported by TLS.) */
+#define MAX_HASH_BLOCK_SIZE 128
+
+/* Some utility functions are needed:
+ *
+ * These macros return the given value with the MSB copied to all the other
+ * bits. They use the fact that arithmetic shift shifts-in the sign bit.
+ * However, this is not ensured by the C standard so you may need to replace
+ * them with something else on odd CPUs. */
+#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned)( (int)(x) >> (sizeof(int)*8-1) ) )
+#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
+
+/* constant_time_lt returns 0xff if a<b and 0x00 otherwise. */
+static unsigned constant_time_lt(unsigned a, unsigned b)
+	{
+	a -= b;
+	return DUPLICATE_MSB_TO_ALL(a);
+	}
+
+/* constant_time_ge returns 0xff if a>=b and 0x00 otherwise. */
+static unsigned constant_time_ge(unsigned a, unsigned b)
+	{
+	a -= b;
+	return DUPLICATE_MSB_TO_ALL(~a);
+	}
+
+/* constant_time_eq_8 returns 0xff if a==b and 0x00 otherwise. */
+static unsigned char constant_time_eq_8(unsigned a, unsigned b)
+	{
+	unsigned c = a ^ b;
+	c--;
+	return DUPLICATE_MSB_TO_ALL_8(c);
+	}
+
+/* ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC
+ * record in |rec| by updating |rec->length| in constant time.
+ *
+ * block_size: the block size of the cipher used to encrypt the record.
+ * returns:
+ *   0: (in non-constant time) if the record is publicly invalid.
+ *   1: if the padding was valid
+ *  -1: otherwise. */
+int ssl3_cbc_remove_padding(const SSL* s,
+			    SSL3_RECORD *rec,
+			    unsigned block_size,
+			    unsigned mac_size)
+	{
+	unsigned padding_length, good;
+	const unsigned overhead = 1 /* padding length byte */ + mac_size;
+
+	/* These lengths are all public so we can test them in non-constant
+	 * time. */
+	if (overhead > rec->length)
+		return 0;
+
+	padding_length = rec->data[rec->length-1];
+	good = constant_time_ge(rec->length, padding_length+overhead);
+	/* SSLv3 requires that the padding is minimal. */
+	good &= constant_time_ge(block_size, padding_length+1);
+	padding_length = good & (padding_length+1);
+	rec->length -= padding_length;
+	rec->type |= padding_length<<8;	/* kludge: pass padding length */
+	return (int)((good & 1) | (~good & -1));
+}
+
+/* tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
+ * record in |rec| in constant time and returns 1 if the padding is valid and
+ * -1 otherwise. It also removes any explicit IV from the start of the record
+ * without leaking any timing about whether there was enough space after the
+ * padding was removed.
+ *
+ * block_size: the block size of the cipher used to encrypt the record.
+ * returns:
+ *   0: (in non-constant time) if the record is publicly invalid.
+ *   1: if the padding was valid
+ *  -1: otherwise. */
+int tls1_cbc_remove_padding(const SSL* s,
+			    SSL3_RECORD *rec,
+			    unsigned block_size,
+			    unsigned mac_size)
+	{
+	unsigned padding_length, good, to_check, i;
+	const unsigned overhead = 1 /* padding length byte */ + mac_size;
+	/* Check if version requires explicit IV */
+	if (SSL_USE_EXPLICIT_IV(s))
+		{
+		/* These lengths are all public so we can test them in
+		 * non-constant time.
+		 */
+		if (overhead + block_size > rec->length)
+			return 0;
+		/* We can now safely skip explicit IV */
+		rec->data += block_size;
+		rec->input += block_size;
+		rec->length -= block_size;
+		}
+	else if (overhead > rec->length)
+		return 0;
+
+	padding_length = rec->data[rec->length-1];
+
+	/* NB: if compression is in operation the first packet may not be of
+	 * even length so the padding bug check cannot be performed. This bug
+	 * workaround has been around since SSLeay so hopefully it is either
+	 * fixed now or no buggy implementation supports compression [steve]
+	 */
+	if ( (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG) && !s->expand)
+		{
+		/* First packet is even in size, so check */
+		if ((memcmp(s->s3->read_sequence, "\0\0\0\0\0\0\0\0",8) == 0) &&
+		    !(padding_length & 1))
+			{
+			s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
+			}
+		if ((s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) &&
+		    padding_length > 0)
+			{
+			padding_length--;
+			}
+		}
+
+	if (EVP_CIPHER_flags(s->enc_read_ctx->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
+		{
+		/* padding is already verified */
+		rec->length -= padding_length + 1;
+		return 1;
+		}
+
+	good = constant_time_ge(rec->length, overhead+padding_length);
+	/* The padding consists of a length byte at the end of the record and
+	 * then that many bytes of padding, all with the same value as the
+	 * length byte. Thus, with the length byte included, there are i+1
+	 * bytes of padding.
+	 *
+	 * We can't check just |padding_length+1| bytes because that leaks
+	 * decrypted information. Therefore we always have to check the maximum
+	 * amount of padding possible. (Again, the length of the record is
+	 * public information so we can use it.) */
+	to_check = 255; /* maximum amount of padding. */
+	if (to_check > rec->length-1)
+		to_check = rec->length-1;
+
+	for (i = 0; i < to_check; i++)
+		{
+		unsigned char mask = constant_time_ge(padding_length, i);
+		unsigned char b = rec->data[rec->length-1-i];
+		/* The final |padding_length+1| bytes should all have the value
+		 * |padding_length|. Therefore the XOR should be zero. */
+		good &= ~(mask&(padding_length ^ b));
+		}
+
+	/* If any of the final |padding_length+1| bytes had the wrong value,
+	 * one or more of the lower eight bits of |good| will be cleared. We
+	 * AND the bottom 8 bits together and duplicate the result to all the
+	 * bits. */
+	good &= good >> 4;
+	good &= good >> 2;
+	good &= good >> 1;
+	good <<= sizeof(good)*8-1;
+	good = DUPLICATE_MSB_TO_ALL(good);
+
+	padding_length = good & (padding_length+1);
+	rec->length -= padding_length;
+	rec->type |= padding_length<<8;	/* kludge: pass padding length */
+
+	return (int)((good & 1) | (~good & -1));
+	}
+
+/* ssl3_cbc_copy_mac copies |md_size| bytes from the end of |rec| to |out| in
+ * constant time (independent of the concrete value of rec->length, which may
+ * vary within a 256-byte window).
+ *
+ * ssl3_cbc_remove_padding or tls1_cbc_remove_padding must be called prior to
+ * this function.
+ *
+ * On entry:
+ *   rec->orig_len >= md_size
+ *   md_size <= EVP_MAX_MD_SIZE
+ *
+ * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with
+ * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into
+ * a single or pair of cache-lines, then the variable memory accesses don't
+ * actually affect the timing. CPUs with smaller cache-lines [if any] are
+ * not multi-core and are not considered vulnerable to cache-timing attacks.
+ */
+#define CBC_MAC_ROTATE_IN_PLACE
+
+void ssl3_cbc_copy_mac(unsigned char* out,
+		       const SSL3_RECORD *rec,
+		       unsigned md_size,unsigned orig_len)
+	{
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+	unsigned char rotated_mac_buf[64+EVP_MAX_MD_SIZE];
+	unsigned char *rotated_mac;
+#else
+	unsigned char rotated_mac[EVP_MAX_MD_SIZE];
+#endif
+
+	/* mac_end is the index of |rec->data| just after the end of the MAC. */
+	unsigned mac_end = rec->length;
+	unsigned mac_start = mac_end - md_size;
+	/* scan_start contains the number of bytes that we can ignore because
+	 * the MAC's position can only vary by 255 bytes. */
+	unsigned scan_start = 0;
+	unsigned i, j;
+	unsigned div_spoiler;
+	unsigned rotate_offset;
+
+	assert(orig_len >= md_size);
+	assert(md_size <= EVP_MAX_MD_SIZE);
+
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+	rotated_mac = rotated_mac_buf + ((0-(size_t)rotated_mac_buf)&63);
+#endif
+
+	/* This information is public so it's safe to branch based on it. */
+	if (orig_len > md_size + 255 + 1)
+		scan_start = orig_len - (md_size + 255 + 1);
+	/* div_spoiler contains a multiple of md_size that is used to cause the
+	 * modulo operation to be constant time. Without this, the time varies
+	 * based on the amount of padding when running on Intel chips at least.
+	 *
+	 * The aim of right-shifting md_size is so that the compiler doesn't
+	 * figure out that it can remove div_spoiler as that would require it
+	 * to prove that md_size is always even, which I hope is beyond it. */
+	div_spoiler = md_size >> 1;
+	div_spoiler <<= (sizeof(div_spoiler)-1)*8;
+	rotate_offset = (div_spoiler + mac_start - scan_start) % md_size;
+
+	memset(rotated_mac, 0, md_size);
+	for (i = scan_start, j = 0; i < orig_len; i++)
+		{
+		unsigned char mac_started = constant_time_ge(i, mac_start);
+		unsigned char mac_ended = constant_time_ge(i, mac_end);
+		unsigned char b = rec->data[i];
+		rotated_mac[j++] |= b & mac_started & ~mac_ended;
+		j &= constant_time_lt(j,md_size);
+		}
+
+	/* Now rotate the MAC */
+#if defined(CBC_MAC_ROTATE_IN_PLACE)
+	j = 0;
+	for (i = 0; i < md_size; i++)
+		{
+		/* in case cache-line is 32 bytes, touch second line */
+		((volatile unsigned char *)rotated_mac)[rotate_offset^32];
+		out[j++] = rotated_mac[rotate_offset++];
+		rotate_offset &= constant_time_lt(rotate_offset,md_size);
+		}
+#else
+	memset(out, 0, md_size);
+	rotate_offset = md_size - rotate_offset;
+	rotate_offset &= constant_time_lt(rotate_offset,md_size);
+	for (i = 0; i < md_size; i++)
+		{
+		for (j = 0; j < md_size; j++)
+			out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset);
+		rotate_offset++;
+		rotate_offset &= constant_time_lt(rotate_offset,md_size);
+		}
+#endif
+	}
+
+/* u32toLE serialises an unsigned, 32-bit number (n) as four bytes at (p) in
+ * little-endian order. The value of p is advanced by four. */
+#define u32toLE(n, p) \
+	(*((p)++)=(unsigned char)(n), \
+	 *((p)++)=(unsigned char)(n>>8), \
+	 *((p)++)=(unsigned char)(n>>16), \
+	 *((p)++)=(unsigned char)(n>>24))
+
+/* These functions serialize the state of a hash and thus perform the standard
+ * "final" operation without adding the padding and length that such a function
+ * typically does. */
+static void tls1_md5_final_raw(void* ctx, unsigned char *md_out)
+	{
+	MD5_CTX *md5 = ctx;
+	u32toLE(md5->A, md_out);
+	u32toLE(md5->B, md_out);
+	u32toLE(md5->C, md_out);
+	u32toLE(md5->D, md_out);
+	}
+
+static void tls1_sha1_final_raw(void* ctx, unsigned char *md_out)
+	{
+	SHA_CTX *sha1 = ctx;
+	l2n(sha1->h0, md_out);
+	l2n(sha1->h1, md_out);
+	l2n(sha1->h2, md_out);
+	l2n(sha1->h3, md_out);
+	l2n(sha1->h4, md_out);
+	}
+#define LARGEST_DIGEST_CTX SHA_CTX
+
+#ifndef OPENSSL_NO_SHA256
+static void tls1_sha256_final_raw(void* ctx, unsigned char *md_out)
+	{
+	SHA256_CTX *sha256 = ctx;
+	unsigned i;
+
+	for (i = 0; i < 8; i++)
+		{
+		l2n(sha256->h[i], md_out);
+		}
+	}
+#undef  LARGEST_DIGEST_CTX
+#define LARGEST_DIGEST_CTX SHA256_CTX
+#endif
+
+#ifndef OPENSSL_NO_SHA512
+static void tls1_sha512_final_raw(void* ctx, unsigned char *md_out)
+	{
+	SHA512_CTX *sha512 = ctx;
+	unsigned i;
+
+	for (i = 0; i < 8; i++)
+		{
+		l2n8(sha512->h[i], md_out);
+		}
+	}
+#undef  LARGEST_DIGEST_CTX
+#define LARGEST_DIGEST_CTX SHA512_CTX
+#endif
+
+/* ssl3_cbc_record_digest_supported returns 1 iff |ctx| uses a hash function
+ * which ssl3_cbc_digest_record supports. */
+char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx)
+	{
+#ifdef OPENSSL_FIPS
+	if (FIPS_mode())
+		return 0;
+#endif
+	switch (EVP_MD_CTX_type(ctx))
+		{
+		case NID_md5:
+		case NID_sha1:
+#ifndef OPENSSL_NO_SHA256
+		case NID_sha224:
+		case NID_sha256:
+#endif
+#ifndef OPENSSL_NO_SHA512
+		case NID_sha384:
+		case NID_sha512:
+#endif
+			return 1;
+		default:
+			return 0;
+		}
+	}
+
+/* ssl3_cbc_digest_record computes the MAC of a decrypted, padded SSLv3/TLS
+ * record.
+ *
+ *   ctx: the EVP_MD_CTX from which we take the hash function.
+ *     ssl3_cbc_record_digest_supported must return true for this EVP_MD_CTX.
+ *   md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written.
+ *   md_out_size: if non-NULL, the number of output bytes is written here.
+ *   header: the 13-byte, TLS record header.
+ *   data: the record data itself, less any preceeding explicit IV.
+ *   data_plus_mac_size: the secret, reported length of the data and MAC
+ *     once the padding has been removed.
+ *   data_plus_mac_plus_padding_size: the public length of the whole
+ *     record, including padding.
+ *   is_sslv3: non-zero if we are to use SSLv3. Otherwise, TLS.
+ *
+ * On entry: by virtue of having been through one of the remove_padding
+ * functions, above, we know that data_plus_mac_size is large enough to contain
+ * a padding byte and MAC. (If the padding was invalid, it might contain the
+ * padding too. ) */
+void ssl3_cbc_digest_record(
+	const EVP_MD_CTX *ctx,
+	unsigned char* md_out,
+	size_t* md_out_size,
+	const unsigned char header[13],
+	const unsigned char *data,
+	size_t data_plus_mac_size,
+	size_t data_plus_mac_plus_padding_size,
+	const unsigned char *mac_secret,
+	unsigned mac_secret_length,
+	char is_sslv3)
+	{
+	union {	double align;
+		unsigned char c[sizeof(LARGEST_DIGEST_CTX)]; } md_state;
+	void (*md_final_raw)(void *ctx, unsigned char *md_out);
+	void (*md_transform)(void *ctx, const unsigned char *block);
+	unsigned md_size, md_block_size = 64;
+	unsigned sslv3_pad_length = 40, header_length, variance_blocks,
+		 len, max_mac_bytes, num_blocks,
+		 num_starting_blocks, k, mac_end_offset, c, index_a, index_b;
+	unsigned int bits;	/* at most 18 bits */
+	unsigned char length_bytes[MAX_HASH_BIT_COUNT_BYTES];
+	/* hmac_pad is the masked HMAC key. */
+	unsigned char hmac_pad[MAX_HASH_BLOCK_SIZE];
+	unsigned char first_block[MAX_HASH_BLOCK_SIZE];
+	unsigned char mac_out[EVP_MAX_MD_SIZE];
+	unsigned i, j, md_out_size_u;
+	EVP_MD_CTX md_ctx;
+	/* mdLengthSize is the number of bytes in the length field that terminates
+	* the hash. */
+	unsigned md_length_size = 8;
+	char length_is_big_endian = 1;
+
+	/* This is a, hopefully redundant, check that allows us to forget about
+	 * many possible overflows later in this function. */
+	assert(data_plus_mac_plus_padding_size < 1024*1024);
+
+	switch (EVP_MD_CTX_type(ctx))
+		{
+		case NID_md5:
+			MD5_Init((MD5_CTX*)md_state.c);
+			md_final_raw = tls1_md5_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) MD5_Transform;
+			md_size = 16;
+			sslv3_pad_length = 48;
+			length_is_big_endian = 0;
+			break;
+		case NID_sha1:
+			SHA1_Init((SHA_CTX*)md_state.c);
+			md_final_raw = tls1_sha1_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA1_Transform;
+			md_size = 20;
+			break;
+#ifndef OPENSSL_NO_SHA256
+		case NID_sha224:
+			SHA224_Init((SHA256_CTX*)md_state.c);
+			md_final_raw = tls1_sha256_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;
+			md_size = 224/8;
+			break;
+		case NID_sha256:
+			SHA256_Init((SHA256_CTX*)md_state.c);
+			md_final_raw = tls1_sha256_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;
+			md_size = 32;
+			break;
+#endif
+#ifndef OPENSSL_NO_SHA512
+		case NID_sha384:
+			SHA384_Init((SHA512_CTX*)md_state.c);
+			md_final_raw = tls1_sha512_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;
+			md_size = 384/8;
+			md_block_size = 128;
+			md_length_size = 16;
+			break;
+		case NID_sha512:
+			SHA512_Init((SHA512_CTX*)md_state.c);
+			md_final_raw = tls1_sha512_final_raw;
+			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;
+			md_size = 64;
+			md_block_size = 128;
+			md_length_size = 16;
+			break;
+#endif
+		default:
+			/* ssl3_cbc_record_digest_supported should have been
+			 * called first to check that the hash function is
+			 * supported. */
+			assert(0);
+			if (md_out_size)
+				*md_out_size = -1;
+			return;
+		}
+
+	assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);
+	assert(md_block_size <= MAX_HASH_BLOCK_SIZE);
+	assert(md_size <= EVP_MAX_MD_SIZE);
+
+	header_length = 13;
+	if (is_sslv3)
+		{
+		header_length =
+			mac_secret_length +
+			sslv3_pad_length +
+			8 /* sequence number */ +
+			1 /* record type */ +
+			2 /* record length */;
+		}
+
+	/* variance_blocks is the number of blocks of the hash that we have to
+	 * calculate in constant time because they could be altered by the
+	 * padding value.
+	 *
+	 * In SSLv3, the padding must be minimal so the end of the plaintext
+	 * varies by, at most, 15+20 = 35 bytes. (We conservatively assume that
+	 * the MAC size varies from 0..20 bytes.) In case the 9 bytes of hash
+	 * termination (0x80 + 64-bit length) don't fit in the final block, we
+	 * say that the final two blocks can vary based on the padding.
+	 *
+	 * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
+	 * required to be minimal. Therefore we say that the final six blocks
+	 * can vary based on the padding.
+	 *
+	 * Later in the function, if the message is short and there obviously
+	 * cannot be this many blocks then variance_blocks can be reduced. */
+	variance_blocks = is_sslv3 ? 2 : 6;
+	/* From now on we're dealing with the MAC, which conceptually has 13
+	 * bytes of `header' before the start of the data (TLS) or 71/75 bytes
+	 * (SSLv3) */
+	len = data_plus_mac_plus_padding_size + header_length;
+	/* max_mac_bytes contains the maximum bytes of bytes in the MAC, including
+	* |header|, assuming that there's no padding. */
+	max_mac_bytes = len - md_size - 1;
+	/* num_blocks is the maximum number of hash blocks. */
+	num_blocks = (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size;
+	/* In order to calculate the MAC in constant time we have to handle
+	 * the final blocks specially because the padding value could cause the
+	 * end to appear somewhere in the final |variance_blocks| blocks and we
+	 * can't leak where. However, |num_starting_blocks| worth of data can
+	 * be hashed right away because no padding value can affect whether
+	 * they are plaintext. */
+	num_starting_blocks = 0;
+	/* k is the starting byte offset into the conceptual header||data where
+	 * we start processing. */
+	k = 0;
+	/* mac_end_offset is the index just past the end of the data to be
+	 * MACed. */
+	mac_end_offset = data_plus_mac_size + header_length - md_size;
+	/* c is the index of the 0x80 byte in the final hash block that
+	 * contains application data. */
+	c = mac_end_offset % md_block_size;
+	/* index_a is the hash block number that contains the 0x80 terminating
+	 * value. */
+	index_a = mac_end_offset / md_block_size;
+	/* index_b is the hash block number that contains the 64-bit hash
+	 * length, in bits. */
+	index_b = (mac_end_offset + md_length_size) / md_block_size;
+	/* bits is the hash-length in bits. It includes the additional hash
+	 * block for the masked HMAC key, or whole of |header| in the case of
+	 * SSLv3. */
+
+	/* For SSLv3, if we're going to have any starting blocks then we need
+	 * at least two because the header is larger than a single block. */
+	if (num_blocks > variance_blocks + (is_sslv3 ? 1 : 0))
+		{
+		num_starting_blocks = num_blocks - variance_blocks;
+		k = md_block_size*num_starting_blocks;
+		}
+
+	bits = 8*mac_end_offset;
+	if (!is_sslv3)
+		{
+		/* Compute the initial HMAC block. For SSLv3, the padding and
+		 * secret bytes are included in |header| because they take more
+		 * than a single block. */
+		bits += 8*md_block_size;
+		memset(hmac_pad, 0, md_block_size);
+		assert(mac_secret_length <= sizeof(hmac_pad));
+		memcpy(hmac_pad, mac_secret, mac_secret_length);
+		for (i = 0; i < md_block_size; i++)
+			hmac_pad[i] ^= 0x36;
+
+		md_transform(md_state.c, hmac_pad);
+		}
+
+	if (length_is_big_endian)
+		{
+		memset(length_bytes,0,md_length_size-4);
+		length_bytes[md_length_size-4] = (unsigned char)(bits>>24);
+		length_bytes[md_length_size-3] = (unsigned char)(bits>>16);
+		length_bytes[md_length_size-2] = (unsigned char)(bits>>8);
+		length_bytes[md_length_size-1] = (unsigned char)bits;
+		}
+	else
+		{
+		memset(length_bytes,0,md_length_size);
+		length_bytes[md_length_size-5] = (unsigned char)(bits>>24);
+		length_bytes[md_length_size-6] = (unsigned char)(bits>>16);
+		length_bytes[md_length_size-7] = (unsigned char)(bits>>8);
+		length_bytes[md_length_size-8] = (unsigned char)bits;
+		}
+
+	if (k > 0)
+		{
+		if (is_sslv3)
+			{
+			/* The SSLv3 header is larger than a single block.
+			 * overhang is the number of bytes beyond a single
+			 * block that the header consumes: either 7 bytes
+			 * (SHA1) or 11 bytes (MD5). */
+			unsigned overhang = header_length-md_block_size;
+			md_transform(md_state.c, header);
+			memcpy(first_block, header + md_block_size, overhang);
+			memcpy(first_block + overhang, data, md_block_size-overhang);
+			md_transform(md_state.c, first_block);
+			for (i = 1; i < k/md_block_size - 1; i++)
+				md_transform(md_state.c, data + md_block_size*i - overhang);
+			}
+		else
+			{
+			/* k is a multiple of md_block_size. */
+			memcpy(first_block, header, 13);
+			memcpy(first_block+13, data, md_block_size-13);
+			md_transform(md_state.c, first_block);
+			for (i = 1; i < k/md_block_size; i++)
+				md_transform(md_state.c, data + md_block_size*i - 13);
+			}
+		}
+
+	memset(mac_out, 0, sizeof(mac_out));
+
+	/* We now process the final hash blocks. For each block, we construct
+	 * it in constant time. If the |i==index_a| then we'll include the 0x80
+	 * bytes and zero pad etc. For each block we selectively copy it, in
+	 * constant time, to |mac_out|. */
+	for (i = num_starting_blocks; i <= num_starting_blocks+variance_blocks; i++)
+		{
+		unsigned char block[MAX_HASH_BLOCK_SIZE];
+		unsigned char is_block_a = constant_time_eq_8(i, index_a);
+		unsigned char is_block_b = constant_time_eq_8(i, index_b);
+		for (j = 0; j < md_block_size; j++)
+			{
+			unsigned char b = 0, is_past_c, is_past_cp1;
+			if (k < header_length)
+				b = header[k];
+			else if (k < data_plus_mac_plus_padding_size + header_length)
+				b = data[k-header_length];
+			k++;
+
+			is_past_c = is_block_a & constant_time_ge(j, c);
+			is_past_cp1 = is_block_a & constant_time_ge(j, c+1);
+			/* If this is the block containing the end of the
+			 * application data, and we are at the offset for the
+			 * 0x80 value, then overwrite b with 0x80. */
+			b = (b&~is_past_c) | (0x80&is_past_c);
+			/* If this the the block containing the end of the
+			 * application data and we're past the 0x80 value then
+			 * just write zero. */
+			b = b&~is_past_cp1;
+			/* If this is index_b (the final block), but not
+			 * index_a (the end of the data), then the 64-bit
+			 * length didn't fit into index_a and we're having to
+			 * add an extra block of zeros. */
+			b &= ~is_block_b | is_block_a;
+
+			/* The final bytes of one of the blocks contains the
+			 * length. */
+			if (j >= md_block_size - md_length_size)
+				{
+				/* If this is index_b, write a length byte. */
+				b = (b&~is_block_b) | (is_block_b&length_bytes[j-(md_block_size-md_length_size)]);
+				}
+			block[j] = b;
+			}
+
+		md_transform(md_state.c, block);
+		md_final_raw(md_state.c, block);
+		/* If this is index_b, copy the hash value to |mac_out|. */
+		for (j = 0; j < md_size; j++)
+			mac_out[j] |= block[j]&is_block_b;
+		}
+
+	EVP_MD_CTX_init(&md_ctx);
+	EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL /* engine */);
+	if (is_sslv3)
+		{
+		/* We repurpose |hmac_pad| to contain the SSLv3 pad2 block. */
+		memset(hmac_pad, 0x5c, sslv3_pad_length);
+
+		EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length);
+		EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length);
+		EVP_DigestUpdate(&md_ctx, mac_out, md_size);
+		}
+	else
+		{
+		/* Complete the HMAC in the standard manner. */
+		for (i = 0; i < md_block_size; i++)
+			hmac_pad[i] ^= 0x6a;
+
+		EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size);
+		EVP_DigestUpdate(&md_ctx, mac_out, md_size);
+		}
+	EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u);
+	if (md_out_size)
+		*md_out_size = md_out_size_u;
+	EVP_MD_CTX_cleanup(&md_ctx);
+	}
+
+#ifdef OPENSSL_FIPS
+
+/* Due to the need to use EVP in FIPS mode we can't reimplement digests but
+ * we can ensure the number of blocks processed is equal for all cases
+ * by digesting additional data.
+ */
+
+void tls_fips_digest_extra(
+	const EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *mac_ctx,
+	const unsigned char *data, size_t data_len, size_t orig_len)
+	{
+	size_t block_size, digest_pad, blocks_data, blocks_orig;
+	if (EVP_CIPHER_CTX_mode(cipher_ctx) != EVP_CIPH_CBC_MODE)
+		return;
+	block_size = EVP_MD_CTX_block_size(mac_ctx);
+	/* We are in FIPS mode if we get this far so we know we have only SHA*
+	 * digests and TLS to deal with.
+	 * Minimum digest padding length is 17 for SHA384/SHA512 and 9
+	 * otherwise.
+	 * Additional header is 13 bytes. To get the number of digest blocks
+	 * processed round up the amount of data plus padding to the nearest
+	 * block length. Block length is 128 for SHA384/SHA512 and 64 otherwise.
+	 * So we have:
+	 * blocks = (payload_len + digest_pad + 13 + block_size - 1)/block_size
+	 * equivalently:
+	 * blocks = (payload_len + digest_pad + 12)/block_size + 1
+	 * HMAC adds a constant overhead.
+	 * We're ultimately only interested in differences so this becomes
+	 * blocks = (payload_len + 29)/128
+	 * for SHA384/SHA512 and
+	 * blocks = (payload_len + 21)/64
+	 * otherwise.
+	 */
+	digest_pad = block_size == 64 ? 21 : 29;
+	blocks_orig = (orig_len + digest_pad)/block_size;
+	blocks_data = (data_len + digest_pad)/block_size;
+	/* MAC enough blocks to make up the difference between the original
+	 * and actual lengths plus one extra block to ensure this is never a
+	 * no op. The "data" pointer should always have enough space to
+	 * perform this operation as it is large enough for a maximum
+	 * length TLS buffer. 
+	 */
+	EVP_DigestSignUpdate(mac_ctx, data,
+				(blocks_orig - blocks_data + 1) * block_size);
+	}
+#endif
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
new file mode 100644
index 0000000..9698916
--- /dev/null
+++ b/ssl/s3_clnt.c
@@ -0,0 +1,3275 @@
+/* ssl/s3_clnt.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@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 <openssl/buf.h>
+#include <openssl/rand.h>
+#include <openssl/obj.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/md5.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/engine.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+#include "../crypto/dh/internal.h"
+
+static const SSL_METHOD *ssl3_get_client_method(int ver);
+
+static const SSL_METHOD *ssl3_get_client_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_client_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
+			ssl_undefined_function,
+			ssl3_connect,
+			ssl3_get_client_method)
+
+int ssl3_connect(SSL *s)
+	{
+	BUF_MEM *buf=NULL;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state,skip=0;
+
+	ERR_clear_error();
+	ERR_clear_system_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)) SSL_clear(s); 
+
+#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_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 ) != 0x0300)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_connect, ERR_R_INTERNAL_ERROR);
+				ret = -1;
+				goto end;
+				}
+				
+			/* s->version=SSL3_VERSION; */
+			s->type=SSL_ST_CONNECT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				buf=NULL;
+				}
+
+			if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
+
+			/* setup buffing BIO */
+			if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
+
+			/* 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;
+			break;
+
+		case SSL3_ST_CW_CLNT_HELLO_A:
+		case SSL3_ST_CW_CLNT_HELLO_B:
+
+			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;
+
+			/* turn on buffering for the next lot of output */
+			if (s->bbio != s->wbio)
+				s->wbio=BIO_push(s->bbio,s->wbio);
+
+			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;
+
+			if (s->hit)
+				{
+				s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+				if (s->tlsext_ticket_expected)
+					{
+					/* receive renewed session ticket */
+					s->state=SSL3_ST_CR_SESSION_TICKET_A;
+					}
+#endif
+				}
+			else
+				{
+#ifndef OPENSSL_NO_TLSEXT
+				/* The server hello indicated that
+				 * an audit proof would follow. */
+				if (s->s3->tlsext_authz_server_promised)
+					s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
+				else
+#endif
+					s->state=SSL3_ST_CR_CERT_A;
+				}
+			s->init_num=0;
+			break;
+#ifndef OPENSSL_NO_TLSEXT
+		case SSL3_ST_CR_SUPPLEMENTAL_DATA_A:
+		case SSL3_ST_CR_SUPPLEMENTAL_DATA_B:
+			ret = tls1_get_server_supplemental_data(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CR_CERT_A;
+			s->init_num = 0;
+			break;
+#endif
+		case SSL3_ST_CR_CERT_A:
+		case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+			ret=ssl3_check_finished(s);
+			if (ret <= 0) goto end;
+			if (ret == 2)
+				{
+				s->hit = 1;
+				if (s->tlsext_ticket_expected)
+					s->state=SSL3_ST_CR_SESSION_TICKET_A;
+				else
+					s->state=SSL3_ST_CR_FINISHED_A;
+				s->init_num=0;
+				break;
+				}
+#endif
+			/* Check if it is anon DH/ECDH */
+			/* 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;
+#ifndef OPENSSL_NO_TLSEXT
+				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;
+				}
+#else
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
+			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;
+				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;
+			if (s->s3->tmp.cert_req)
+				s->state=SSL3_ST_CW_CERT_A;
+			else
+				s->state=SSL3_ST_CW_KEY_EXCH_A;
+			s->init_num=0;
+
+			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 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 */
+			/* For TLS, cert_req is set to 2, so a cert chain
+			 * of nothing is sent, but no verify packet is sent */
+			/* XXX: For now, we do not support client 
+			 * authentication in ECDH cipher suites with
+			 * ECDH (rather than ECDSA) certificates.
+			 * We need to skip the certificate verify 
+			 * message when client'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;
+				}
+			else
+				{
+				s->state=SSL3_ST_CW_CHANGE_A;
+				s->s3->change_cipher_spec=0;
+				}
+			if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+				{
+				s->state=SSL3_ST_CW_CHANGE_A;
+				s->s3->change_cipher_spec=0;
+				}
+
+			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;
+			s->s3->change_cipher_spec=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;
+
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+			s->state=SSL3_ST_CW_FINISHED_A;
+#else
+			if (s->s3->next_proto_neg_seen)
+				s->state=SSL3_ST_CW_NEXT_PROTO_A;
+			else
+				s->state=SSL3_ST_CW_FINISHED_A;
+#endif
+			s->init_num=0;
+
+			s->session->cipher=s->s3->tmp.new_cipher;
+			s->session->compress_meth=0;
+			if (!s->method->ssl3_enc->setup_key_block(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			if (!s->method->ssl3_enc->change_cipher_state(s,
+				SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			break;
+
+#if !defined(OPENSSL_NO_TLSEXT) && !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
+
+		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;
+
+			/* clear flags */
+			s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
+			if (s->hit)
+				{
+				s->s3->tmp.next_state=SSL_ST_OK;
+				if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
+					{
+					s->state=SSL_ST_OK;
+					s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
+					s->s3->delay_buf_pop_ret=0;
+					}
+				}
+			else
+				{
+#ifndef OPENSSL_NO_TLSEXT
+				/* Allow NewSessionTicket if ticket expected */
+				if (s->tlsext_ticket_expected)
+					s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+				else
+#endif
+				
+				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+				}
+			s->init_num=0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		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_FINISHED_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;
+#endif
+
+		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;
+
+			if (s->hit)
+				s->state=SSL3_ST_CW_CHANGE_A;
+			else
+				s->state=SSL_ST_OK;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CW_FLUSH:
+			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 SSL_ST_OK:
+			/* clean a few things up */
+			ssl3_cleanup_key_block(s);
+
+			if (s->init_buf != NULL)
+				{
+				BUF_MEM_free(s->init_buf);
+				s->init_buf=NULL;
+				}
+
+			/* If we are not 'joining' the last two packets,
+			 * remove the buffering now */
+			if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
+				ssl_free_wbio_buffer(s);
+			/* else do it later in ssl3_write */
+
+			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=ssl3_connect;
+			s->ctx->stats.sess_connect_good++;
+
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+			goto end;
+			/* break; */
+			
+		default:
+			OPENSSL_PUT_ERROR(SSL, ssl3_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--;
+	if (buf != NULL)
+		BUF_MEM_free(buf);
+	if (cb != NULL)
+		cb(s,SSL_CB_CONNECT_EXIT,ret);
+	return(ret);
+	}
+
+
+int ssl3_client_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i;
+	unsigned long l;
+
+	buf=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
+		{
+		SSL_SESSION *sess = s->session;
+		if ((sess == NULL) ||
+			(sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+			!sess->session_id_length ||
+#else
+			(!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+			(sess->not_resumable))
+			{
+			if (!ssl_get_new_session(s,0))
+				goto err;
+			}
+		if (s->method->version == DTLS_ANY_VERSION)
+			{
+			/* Determine which DTLS version to use */
+			int options = s->options;
+			/* If DTLS 1.2 disabled correct the version number */
+			if (options & SSL_OP_NO_DTLSv1_2)
+				{
+				if (tls1_suiteb(s))
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+					goto err;
+					}
+				/* Disabling all versions is silly: return an
+				 * error.
+				 */
+				if (options & SSL_OP_NO_DTLSv1)
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_WRONG_SSL_VERSION);
+					goto err;
+					}
+				/* Update method so we don't use any DTLS 1.2
+				 * features.
+				 */
+				s->method = DTLSv1_client_method();
+				s->version = DTLS1_VERSION;
+				}
+			else
+				{
+				/* We only support one version: update method */
+				if (options & SSL_OP_NO_DTLSv1)
+					s->method = DTLSv1_2_client_method();
+				s->version = DTLS1_2_VERSION;
+				}
+			s->client_version = s->version;
+			}
+		/* else use the pre-loaded session */
+
+		p=s->s3->client_random;
+
+		/* 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;
+					}
+				}
+			}
+		else 
+			i = 1;
+
+		if (i)
+			ssl_fill_hello_random(s, 0, p,
+					      sizeof(s->s3->client_random));
+
+		/* 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.
+		 */
+#if 0
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+		s->client_version=s->version;
+#else
+		*(p++)=s->client_version>>8;
+		*(p++)=s->client_version&0xff;
+#endif
+
+		/* 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))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			memcpy(p,s->session->session_id,i);
+			p+=i;
+			}
+		
+		/* cookie stuff for DTLS */
+		if (SSL_IS_DTLS(s))
+			{
+			if ( s->d1->cookie_len > sizeof(s->d1->cookie))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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;
+			}
+		
+		/* Ciphers supported */
+		i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),0);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_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;
+#endif
+		s2n(i,p);
+		p+=i;
+
+		/* COMPRESSION */
+		*(p++)=1;
+		*(p++)=0; /* Add the NULL method */
+
+#ifndef OPENSSL_NO_TLSEXT
+		/* TLS extensions*/
+		if (ssl_prepare_clienthello_tlsext(s) <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
+			goto err;
+			}
+		if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+#endif
+		
+		l= p-d;
+		ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l);
+		s->state=SSL3_ST_CW_CLNT_HELLO_B;
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return ssl_do_write(s);
+err:
+	return(-1);
+	}
+
+int ssl3_get_server_hello(SSL *s)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+	const SSL_CIPHER *c;
+	CERT *ct = s->cert;
+	unsigned char *p,*d;
+	int al=SSL_AD_INTERNAL_ERROR,ok;
+	unsigned int j;
+	long n;
+	/* Hello verify request and/or server hello version may not
+	 * match so set first packet if we're negotiating version.
+	 */
+	if (SSL_IS_DTLS(s))
+		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);
+
+	if (SSL_IS_DTLS(s))
+		{
+		s->first_packet = 0;
+		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 */
+				{
+				al=SSL_AD_UNEXPECTED_MESSAGE;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_BAD_MESSAGE_TYPE);
+				goto f_err;
+				}
+			}
+		}
+	
+	if ( s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_BAD_MESSAGE_TYPE);
+		goto f_err;
+		}
+
+	d=p=(unsigned char *)s->init_msg;
+	if (s->method->version == DTLS_ANY_VERSION)
+		{
+		/* Work out correct protocol version to use */
+		int hversion = (p[0] << 8)|p[1];
+		int options = s->options;
+		if (hversion == DTLS1_2_VERSION
+			&& !(options & SSL_OP_NO_DTLSv1_2))
+			s->method = DTLSv1_2_client_method();
+		else if (tls1_suiteb(s))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+			s->version = hversion;
+			al = SSL_AD_PROTOCOL_VERSION;
+			goto f_err;
+			}
+		else if (hversion == DTLS1_VERSION
+			&& !(options & SSL_OP_NO_DTLSv1))
+			s->method = DTLSv1_client_method();
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION);
+			s->version = hversion;
+			al = SSL_AD_PROTOCOL_VERSION;
+			goto f_err;
+			}
+		s->version = s->client_version = s->method->version;
+		}
+
+	if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION);
+		s->version=(s->version&0xff00)|p[1];
+		al=SSL_AD_PROTOCOL_VERSION;
+		goto f_err;
+		}
+	p+=2;
+
+	/* load the server hello data */
+	/* load the server random */
+	memcpy(s->s3->server_random,p,SSL3_RANDOM_SIZE);
+	p+=SSL3_RANDOM_SIZE;
+
+	/* get the session-id */
+	j= *(p++);
+
+	if ((j > sizeof s->session->session_id) || (j > SSL3_SESSION_ID_SIZE))
+		{
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_SSL3_SESSION_ID_TOO_LONG);
+		goto f_err;
+		}
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* check if we want to resume the session based on external pre-shared secret */
+	if (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,
+					     NULL, &pref_cipher,
+					     s->tls_session_secret_cb_arg))
+			{
+			s->session->cipher = pref_cipher ?
+				pref_cipher : ssl_get_cipher_by_char(s, p+j);
+			}
+		}
+#endif /* OPENSSL_NO_TLSEXT */
+
+	if (j != 0 && j == s->session->session_id_length
+	    && memcmp(p,s->session->session_id,j) == 0)
+	    {
+	    if(s->sid_ctx_length != s->session->sid_ctx_length
+	       || memcmp(s->session->sid_ctx,s->sid_ctx,s->sid_ctx_length))
+		{
+		/* actually a client application bug */
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+		goto f_err;
+		}
+	    s->hit=1;
+	    }
+	else	/* a miss or crap from the other end */
+		{
+		/* If we were trying for session-id reuse, make a new
+		 * SSL_SESSION so we don't stuff up other people */
+		s->hit=0;
+		if (s->session->session_id_length > 0)
+			{
+			if (!ssl_get_new_session(s,0))
+				{
+				goto f_err;
+				}
+			}
+		s->session->session_id_length=j;
+		memcpy(s->session->session_id,p,j); /* j could be 0 */
+		}
+	p+=j;
+	c=ssl_get_cipher_by_char(s,p);
+	if (c == NULL)
+		{
+		/* unknown cipher */
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNKNOWN_CIPHER_RETURNED);
+		goto f_err;
+		}
+	/* If it is a disabled cipher we didn't send it in client hello,
+	 * so return an error.
+	 */
+	if (c->algorithm_ssl & ct->mask_ssl ||
+		c->algorithm_mkey & ct->mask_k ||
+		c->algorithm_auth & ct->mask_a)
+		{
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED);
+		goto f_err;
+		}
+	p+=ssl_put_cipher_by_char(s,NULL,NULL);
+
+	sk=ssl_get_ciphers_by_id(s);
+	if (!sk_SSL_CIPHER_find(sk, NULL, c))
+		{
+		/* we did not say we would use this cipher */
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_CIPHER_RETURNED);
+		goto f_err;
+		}
+
+	/* Depending on the session caching (internal/external), the cipher
+	   and/or cipher_id values may not be set. Make sure that
+	   cipher_id is set and use it for comparison. */
+	if (s->session->cipher)
+		s->session->cipher_id = s->session->cipher->id;
+	if (s->hit && (s->session->cipher_id != c->id))
+		{
+/* Workaround is now obsolete */
+#if 0
+		if (!(s->options &
+			SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
+#endif
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+			goto f_err;
+			}
+		}
+	s->s3->tmp.new_cipher=c;
+	/* Don't digest cached records if no sigalgs: we may need them for
+	 * client authentication.
+	 */
+	if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
+		goto f_err;
+	/* lets get the compression algorithm */
+	/* COMPRESSION */
+	if (*(p++) != 0)
+		{
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+		goto f_err;
+		}
+	/* If compression is disabled we'd better not try to resume a session
+	 * using compression.
+	 */
+	if (s->session->compress_meth != 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_INCONSISTENT_COMPRESSION);
+		goto f_err;
+		}
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extensions*/
+	if (!ssl_parse_serverhello_tlsext(s,&p,d,n))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_PARSE_TLSEXT);
+		goto err; 
+		}
+#endif
+
+	if (p != (d+n))
+		{
+		/* wrong packet length */
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_BAD_PACKET_LENGTH);
+		goto f_err;
+		}
+
+	return(1);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(-1);
+	}
+
+int ssl3_get_server_certificate(SSL *s)
+	{
+	int al,i,ok,ret= -1;
+	unsigned long n,nc,llen,l;
+	X509 *x=NULL;
+	const unsigned char *q,*p;
+	unsigned char *d;
+	STACK_OF(X509) *sk=NULL;
+	SESS_CERT *sc;
+	EVP_PKEY *pkey=NULL;
+	int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
+
+	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.new_cipher->algorithm_auth & SSL_aKRB5) && 
+		(s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)))
+		{
+		s->s3->tmp.reuse_message=1;
+		return(1);
+		}
+
+	if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_BAD_MESSAGE_TYPE);
+		goto f_err;
+		}
+	p=d=(unsigned char *)s->init_msg;
+
+	if ((sk=sk_X509_new_null()) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	n2l3(p,llen);
+	if (llen+3 != n)
+		{
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	for (nc=0; nc<llen; )
+		{
+		n2l3(p,l);
+		if ((l+nc+3) > llen)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+
+		q=p;
+		x=d2i_X509(NULL,&q,l);
+		if (x == NULL)
+			{
+			al=SSL_AD_BAD_CERTIFICATE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_ASN1_LIB);
+			goto f_err;
+			}
+		if (q != (p+l))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+		if (!sk_X509_push(sk,x))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		x=NULL;
+		nc+=l+3;
+		p=q;
+		}
+
+	i=ssl_verify_cert_chain(s,sk);
+	if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)
+		)
+		{
+		al=ssl_verify_alarm_type(s->verify_result);
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_CERTIFICATE_VERIFY_FAILED);
+		goto f_err; 
+		}
+	ERR_clear_error(); /* but we keep s->verify_result */
+
+	sc=ssl_sess_cert_new();
+	if (sc == NULL) goto err;
+
+	if (s->session->sess_cert) ssl_sess_cert_free(s->session->sess_cert);
+	s->session->sess_cert=sc;
+
+	sc->cert_chain=sk;
+	/* Inconsistency alert: cert_chain does include the peer's
+	 * certificate, which we don't include in s3_srvr.c */
+	x=sk_X509_value(sk,0);
+	sk=NULL;
+ 	/* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/
+
+	pkey=X509_get_pubkey(x);
+
+	/* VRS: allow null cert if auth == KRB5 */
+	need_cert = ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
+	            (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+	            ? 0 : 1;
+
+#ifdef KSSL_DEBUG
+	printf("pkey,x = %p, %p\n", pkey,x);
+	printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey));
+	printf("cipher, alg, nc = %s, %lx, %lx, %d\n", s->s3->tmp.new_cipher->name,
+		s->s3->tmp.new_cipher->algorithm_mkey, s->s3->tmp.new_cipher->algorithm_auth, need_cert);
+#endif    /* KSSL_DEBUG */
+
+	if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
+		{
+		x=NULL;
+		al=SSL3_AL_FATAL;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
+		goto f_err;
+		}
+
+	i=ssl_cert_type(x,pkey);
+	if (need_cert && i < 0)
+		{
+		x=NULL;
+		al=SSL3_AL_FATAL;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+		goto f_err;
+		}
+
+	if (need_cert)
+		{
+		int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+		if (exp_idx >= 0 && i != exp_idx)
+			{
+			x=NULL;
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_WRONG_CERTIFICATE_TYPE);
+			goto f_err;
+			}
+		sc->peer_cert_type=i;
+		CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+		/* Why would the following ever happen?
+		 * We just created sc a couple of lines ago. */
+		if (sc->peer_pkeys[i].x509 != NULL)
+			X509_free(sc->peer_pkeys[i].x509);
+		sc->peer_pkeys[i].x509=x;
+		sc->peer_key= &(sc->peer_pkeys[i]);
+
+		if (s->session->peer != NULL)
+			X509_free(s->session->peer);
+		CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+		s->session->peer=x;
+		}
+	else
+		{
+		sc->peer_cert_type=i;
+		sc->peer_key= NULL;
+
+		if (s->session->peer != NULL)
+			X509_free(s->session->peer);
+		s->session->peer=NULL;
+		}
+	s->session->verify_result = s->verify_result;
+
+	x=NULL;
+#ifndef OPENSSL_NO_TLSEXT
+	/* Check the audit proof. */
+	if (s->ctx->tlsext_authz_server_audit_proof_cb)
+		{
+		ret = s->ctx->tlsext_authz_server_audit_proof_cb(s,
+			s->ctx->tlsext_authz_server_audit_proof_cb_arg);
+		if (ret <= 0)
+			{
+			al = SSL_AD_BAD_CERTIFICATE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_INVALID_AUDIT_PROOF);
+			goto f_err;
+			}
+		}
+
+#endif
+	ret=1;
+	if (0)
+		{
+f_err:
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		}
+err:
+	EVP_PKEY_free(pkey);
+	X509_free(x);
+	sk_X509_pop_free(sk,X509_free);
+	return(ret);
+	}
+
+int ssl3_get_key_exchange(SSL *s)
+	{
+#ifndef OPENSSL_NO_RSA
+	unsigned char *q,md_buf[EVP_MAX_MD_SIZE*2];
+#endif
+	EVP_MD_CTX md_ctx;
+	unsigned char *param,*p;
+	int al,i,j,param_len,ok;
+	long n,alg_k,alg_a;
+	EVP_PKEY *pkey=NULL;
+	const EVP_MD *md = NULL;
+#ifndef OPENSSL_NO_RSA
+	RSA *rsa=NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *dh=NULL;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh = NULL;
+	BN_CTX *bn_ctx = NULL;
+	EC_POINT *srvr_ecpoint = NULL;
+	int curve_nid = 0;
+	int encoded_pt_len = 0;
+#endif
+
+	/* 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);
+
+	if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE)
+		{
+#ifndef OPENSSL_NO_PSK
+		/* In plain PSK ciphersuite, ServerKeyExchange can be
+		   omitted if no identity hint is sent. Set
+		   session->sess_cert anyway to avoid problems
+		   later.*/
+		if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+			{
+			s->session->sess_cert=ssl_sess_cert_new();
+			if (s->ctx->psk_identity_hint)
+				OPENSSL_free(s->ctx->psk_identity_hint);
+			s->ctx->psk_identity_hint = NULL;
+			}
+#endif
+		s->s3->tmp.reuse_message=1;
+		return(1);
+		}
+
+	param=p=(unsigned char *)s->init_msg;
+	if (s->session->sess_cert != NULL)
+		{
+#ifndef OPENSSL_NO_RSA
+		if (s->session->sess_cert->peer_rsa_tmp != NULL)
+			{
+			RSA_free(s->session->sess_cert->peer_rsa_tmp);
+			s->session->sess_cert->peer_rsa_tmp=NULL;
+			}
+#endif
+#ifndef OPENSSL_NO_DH
+		if (s->session->sess_cert->peer_dh_tmp)
+			{
+			DH_free(s->session->sess_cert->peer_dh_tmp);
+			s->session->sess_cert->peer_dh_tmp=NULL;
+			}
+#endif
+#ifndef OPENSSL_NO_ECDH
+		if (s->session->sess_cert->peer_ecdh_tmp)
+			{
+			EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
+			s->session->sess_cert->peer_ecdh_tmp=NULL;
+			}
+#endif
+		}
+	else
+		{
+		s->session->sess_cert=ssl_sess_cert_new();
+		}
+
+	param_len=0;
+	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+	EVP_MD_CTX_init(&md_ctx);
+
+#ifndef OPENSSL_NO_PSK
+	if (alg_k & SSL_kPSK)
+		{
+		char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
+
+		al=SSL_AD_HANDSHAKE_FAILURE;
+		n2s(p,i);
+		param_len=i+2;
+		/* Store PSK identity hint for later use, hint is used
+		 * in ssl3_send_client_key_exchange.  Assume that the
+		 * maximum length of a PSK identity hint can be as
+		 * long as the maximum length of a PSK identity. */
+		if (i > PSK_MAX_IDENTITY_LEN)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
+			goto f_err;
+			}
+		/* If received PSK identity hint contains NULL
+		 * characters, the hint is truncated from the first
+		 * NULL. p may not be ending with NULL, so create a
+		 * NULL-terminated string. */
+		memcpy(tmp_id_hint, p, i);
+		memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+		if (s->ctx->psk_identity_hint != NULL)
+			OPENSSL_free(s->ctx->psk_identity_hint);
+		s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+		if (s->ctx->psk_identity_hint == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_MALLOC_FAILURE);
+			goto f_err;
+			}	   
+
+		p+=i;
+		n-=param_len;
+		}
+	else
+#endif /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_RSA
+	if (alg_k & SSL_kRSA)
+		{
+		if ((rsa=RSA_new()) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		n2s(p,i);
+		param_len=i+2;
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_RSA_MODULUS_LENGTH);
+			goto f_err;
+			}
+		if (!(rsa->n=BN_bin2bn(p,i,rsa->n)))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_BN_LIB);
+			goto err;
+			}
+		p+=i;
+
+		n2s(p,i);
+		param_len+=i+2;
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_RSA_E_LENGTH);
+			goto f_err;
+			}
+		if (!(rsa->e=BN_bin2bn(p,i,rsa->e)))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_BN_LIB);
+			goto err;
+			}
+		p+=i;
+		n-=param_len;
+
+		/* this should be because we are using an export cipher */
+		if (alg_a & SSL_aRSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+		s->session->sess_cert->peer_rsa_tmp=rsa;
+		rsa=NULL;
+		}
+#else /* OPENSSL_NO_RSA */
+	if (0)
+		;
+#endif
+#ifndef OPENSSL_NO_DH
+	else if (alg_k & SSL_kEDH)
+		{
+		if ((dh=DH_new()) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_DH_LIB);
+			goto err;
+			}
+		n2s(p,i);
+		param_len=i+2;
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_DH_P_LENGTH);
+			goto f_err;
+			}
+		if (!(dh->p=BN_bin2bn(p,i,NULL)))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_BN_LIB);
+			goto err;
+			}
+		p+=i;
+
+		n2s(p,i);
+		param_len+=i+2;
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_DH_G_LENGTH);
+			goto f_err;
+			}
+		if (!(dh->g=BN_bin2bn(p,i,NULL)))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_BN_LIB);
+			goto err;
+			}
+		p+=i;
+
+		n2s(p,i);
+		param_len+=i+2;
+		if (param_len > n)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_DH_PUB_KEY_LENGTH);
+			goto f_err;
+			}
+		if (!(dh->pub_key=BN_bin2bn(p,i,NULL)))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_BN_LIB);
+			goto err;
+			}
+		p+=i;
+		n-=param_len;
+
+#ifndef OPENSSL_NO_RSA
+		if (alg_a & SSL_aRSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#else
+		if (0)
+			;
+#endif
+#ifndef OPENSSL_NO_DSA
+		else if (alg_a & SSL_aDSS)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+#endif
+		/* else anonymous DH, so no certificate or pkey. */
+
+		s->session->sess_cert->peer_dh_tmp=dh;
+		dh=NULL;
+		}
+	else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd))
+		{
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
+		goto f_err;
+		}
+#endif /* !OPENSSL_NO_DH */
+
+#ifndef OPENSSL_NO_ECDH
+	else if (alg_k & SSL_kEECDH)
+		{
+		EC_GROUP *ngroup;
+		const EC_GROUP *group;
+
+		if ((ecdh=EC_KEY_new()) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		/* Extract elliptic curve parameters and the
+		 * server's ephemeral ECDH public key.
+		 * Keep accumulating lengths of various components in
+		 * param_len and make sure it never exceeds n.
+		 */
+
+		/* XXX: For now we only support named (not generic) curves
+		 * and the ECParameters in this case is just three bytes.
+		 */
+		param_len=3;
+		/* Check curve is one of our prefrences, if not server has
+		 * sent an invalid curve.
+		 */
+		if (!tls1_check_curve(s, p, param_len))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_WRONG_CURVE);
+			goto f_err;
+			}
+
+		if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0) 
+			{
+			al=SSL_AD_INTERNAL_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+			goto f_err;
+			}
+
+		ngroup = EC_GROUP_new_by_curve_name(curve_nid);
+		if (ngroup == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_EC_LIB);
+			goto err;
+			}
+		if (EC_KEY_set_group(ecdh, ngroup) == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_EC_LIB);
+			goto err;
+			}
+		EC_GROUP_free(ngroup);
+
+		group = EC_KEY_get0_group(ecdh);
+
+		if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+		    (EC_GROUP_get_degree(group) > 163))
+			{
+			al=SSL_AD_EXPORT_RESTRICTION;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+			goto f_err;
+			}
+
+		p+=3;
+
+		/* Next, get the encoded ECPoint */
+		if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
+		    ((bn_ctx = BN_CTX_new()) == NULL))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		encoded_pt_len = *p;  /* length of encoded point */
+		p+=1;
+		param_len += (1 + encoded_pt_len);
+		if ((param_len > n) ||
+		    (EC_POINT_oct2point(group, srvr_ecpoint, 
+			p, encoded_pt_len, bn_ctx) == 0))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_ECPOINT);
+			goto f_err;
+			}
+
+		n-=param_len;
+		p+=encoded_pt_len;
+
+		/* The ECC/TLS specification does not mention
+		 * the use of DSA to sign ECParameters in the server
+		 * key exchange message. We do support RSA and ECDSA.
+		 */
+		if (0) ;
+#ifndef OPENSSL_NO_RSA
+		else if (alg_a & SSL_aRSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		else if (alg_a & SSL_aECDSA)
+			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+#endif
+		/* else anonymous ECDH, so no certificate or pkey. */
+		EC_KEY_set_public_key(ecdh, srvr_ecpoint);
+		s->session->sess_cert->peer_ecdh_tmp=ecdh;
+		ecdh=NULL;
+		BN_CTX_free(bn_ctx);
+		bn_ctx = NULL;
+		EC_POINT_free(srvr_ecpoint);
+		srvr_ecpoint = NULL;
+		}
+	else if (alg_k)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_UNEXPECTED_MESSAGE);
+		goto f_err;
+		}
+#endif /* !OPENSSL_NO_ECDH */
+
+
+	/* p points to the next byte, there are 'n' bytes left */
+
+	/* if it was signed, check the signature */
+	if (pkey != NULL)
+		{
+		if (SSL_USE_SIGALGS(s))
+			{
+			int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+			if (rv == -1)
+				goto 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
+			p += 2;
+			n -= 2;
+			}
+		else
+			md = EVP_sha1();
+			
+		n2s(p,i);
+		n-=2;
+		j=EVP_PKEY_size(pkey);
+
+		if ((i != n) || (n > j) || (n <= 0))
+			{
+			/* wrong packet length */
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_WRONG_SIGNATURE_LENGTH);
+			goto f_err;
+			}
+
+#ifndef OPENSSL_NO_RSA
+		if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
+			{
+			int num;
+
+			j=0;
+			q=md_buf;
+			for (num=2; num > 0; num--)
+				{
+				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,param,param_len);
+				EVP_DigestFinal_ex(&md_ctx,q,(unsigned int *)&i);
+				q+=i;
+				j+=i;
+				}
+			i=RSA_verify(NID_md5_sha1, md_buf, j, p, n,
+								pkey->pkey.rsa);
+			if (i < 0)
+				{
+				al=SSL_AD_DECRYPT_ERROR;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_RSA_DECRYPT);
+				goto f_err;
+				}
+			if (i == 0)
+				{
+				/* bad signature */
+				al=SSL_AD_DECRYPT_ERROR;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_SIGNATURE);
+				goto f_err;
+				}
+			}
+		else
+#endif
+			{
+			EVP_VerifyInit_ex(&md_ctx, md, NULL);
+			EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+			EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+			EVP_VerifyUpdate(&md_ctx,param,param_len);
+			if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
+				{
+				/* bad signature */
+				al=SSL_AD_DECRYPT_ERROR;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_BAD_SIGNATURE);
+				goto f_err;
+				}
+			}
+		}
+	else
+		{
+		/* aNULL or kPSK do not need public keys */
+		if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
+			{
+			/* Might be wrong key type, check it */
+			if (ssl3_check_cert_and_algorithm(s))
+				/* Otherwise this shouldn't happen */
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+		/* still data left over */
+		if (n != 0)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_EXTRA_DATA_IN_MESSAGE);
+			goto f_err;
+			}
+		}
+	EVP_PKEY_free(pkey);
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(1);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	EVP_PKEY_free(pkey);
+#ifndef OPENSSL_NO_RSA
+	if (rsa != NULL)
+		RSA_free(rsa);
+#endif
+#ifndef OPENSSL_NO_DH
+	if (dh != NULL)
+		DH_free(dh);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	BN_CTX_free(bn_ctx);
+	EC_POINT_free(srvr_ecpoint);
+	if (ecdh != NULL)
+		EC_KEY_free(ecdh);
+#endif
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(-1);
+	}
+
+static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b)
+	{
+	return(X509_NAME_cmp(*a,*b));
+	}
+
+int ssl3_get_certificate_request(SSL *s)
+	{
+	int ok,ret=0;
+	unsigned long n,nc,l;
+	unsigned int llen, ctype_num,i;
+	X509_NAME *xn=NULL;
+	const unsigned char *p,*q;
+	unsigned char *d;
+	STACK_OF(X509_NAME) *ca_sk=NULL;
+
+	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 (s->s3->handshake_buffer)
+			{
+			if (!ssl3_digest_cached_records(s))
+				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);
+		OPENSSL_PUT_ERROR(SSL, 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);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER);
+			goto err;
+			}
+		}
+
+	p=d=(unsigned char *)s->init_msg;
+
+	ca_sk = sk_X509_NAME_new(ca_dn_cmp);
+	if (ca_sk == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	/* get the certificate types */
+	ctype_num= *(p++);
+	if (s->cert->ctypes)
+		{
+		OPENSSL_free(s->cert->ctypes);
+		s->cert->ctypes = NULL;
+		}
+	if (ctype_num > SSL3_CT_NUMBER)
+		{
+		/* If we exceed static buffer copy all to cert structure */
+		s->cert->ctypes = OPENSSL_malloc(ctype_num);
+		memcpy(s->cert->ctypes, p, ctype_num);
+		s->cert->ctype_num = (size_t)ctype_num;
+		ctype_num=SSL3_CT_NUMBER;
+		}
+	for (i=0; i<ctype_num; i++)
+		s->s3->tmp.ctype[i]= p[i];
+	p+=p[-1];
+	if (SSL_USE_SIGALGS(s))
+		{
+		n2s(p, llen);
+		/* Check we have enough room for signature algorithms and
+		 * following length value.
+		 */
+		if ((unsigned long)(p - d + llen + 2) > n)
+			{
+			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+		/* Clear certificate digests and validity flags */
+		for (i = 0; i < SSL_PKEY_NUM; i++)
+			{
+			s->cert->pkeys[i].digest = NULL;
+			s->cert->pkeys[i].valid_flags = 0;
+			}
+		if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
+			{
+			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+			goto err;
+			}
+		p += llen;
+		}
+
+	/* get the CA RDNs */
+	n2s(p,llen);
+#if 0
+{
+FILE *out;
+out=fopen("/tmp/vsign.der","w");
+fwrite(p,1,llen,out);
+fclose(out);
+}
+#endif
+
+	if ((unsigned long)(p - d + llen) != n)
+		{
+		ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_LENGTH_MISMATCH);
+		goto err;
+		}
+
+	for (nc=0; nc<llen; )
+		{
+		n2s(p,l);
+		if ((l+nc+2) > llen)
+			{
+			if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+				goto cont; /* netscape bugs */
+			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_CA_DN_TOO_LONG);
+			goto err;
+			}
+
+		q=p;
+
+		if ((xn=d2i_X509_NAME(NULL,&q,l)) == NULL)
+			{
+			/* If netscape tolerance is on, ignore errors */
+			if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG)
+				goto cont;
+			else
+				{
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_ASN1_LIB);
+				goto err;
+				}
+			}
+
+		if (q != (p+l))
+			{
+			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_CA_DN_LENGTH_MISMATCH);
+			goto err;
+			}
+		if (!sk_X509_NAME_push(ca_sk,xn))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		p+=l;
+		nc+=l+2;
+		}
+
+	if (0)
+		{
+cont:
+		ERR_clear_error();
+		}
+
+	/* we should setup a certificate to return.... */
+	s->s3->tmp.cert_req=1;
+	s->s3->tmp.ctype_num=ctype_num;
+	if (s->s3->tmp.ca_names != NULL)
+		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
+	s->s3->tmp.ca_names=ca_sk;
+	ca_sk=NULL;
+
+	ret=1;
+err:
+	if (ca_sk != NULL) sk_X509_NAME_pop_free(ca_sk,X509_NAME_free);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_get_new_session_ticket(SSL *s)
+	{
+	int ok,al,ret=0, ticklen;
+	long n;
+	const unsigned char *p;
+	unsigned char *d;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_CR_SESSION_TICKET_A,
+		SSL3_ST_CR_SESSION_TICKET_B,
+		-1,
+		16384,
+		&ok);
+
+	if (!ok)
+		return((int)n);
+
+	if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+		{
+		s->s3->tmp.reuse_message=1;
+		return(1);
+		}
+	if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, SSL_R_BAD_MESSAGE_TYPE);
+		goto f_err;
+		}
+	if (n < 6)
+		{
+		/* need at least ticket_lifetime_hint + ticket length */
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+
+	p=d=(unsigned char *)s->init_msg;
+	n2l(p, s->session->tlsext_tick_lifetime_hint);
+	n2s(p, ticklen);
+	/* ticket_lifetime_hint + ticket_length + ticket */
+	if (ticklen + 6 != n)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	if (s->session->tlsext_tick)
+		{
+		OPENSSL_free(s->session->tlsext_tick);
+		s->session->tlsext_ticklen = 0;
+		}
+	s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+	if (!s->session->tlsext_tick)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_new_session_ticket, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	memcpy(s->session->tlsext_tick, p, ticklen);
+	s->session->tlsext_ticklen = ticklen;
+	/* There are two ways to detect a resumed ticket sesion.
+	 * One is to set an appropriate session ID and then the server
+	 * must return a match in ServerHello. This allows the normal
+	 * client session ID matching to work and we know much 
+	 * earlier that the ticket has been accepted.
+	 * 
+	 * The other way is to set zero length session ID when the
+	 * ticket is presented and rely on the handshake to determine
+	 * session resumption.
+	 *
+	 * We choose the former approach because this fits in with
+	 * assumptions elsewhere in OpenSSL. The session ID is set
+	 * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
+	 * ticket.
+	 */ 
+	EVP_Digest(p, ticklen,
+			s->session->session_id, &s->session->session_id_length,
+#ifndef OPENSSL_NO_SHA256
+							EVP_sha256(), NULL);
+#else
+							EVP_sha1(), NULL);
+#endif
+	ret=1;
+	return(ret);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(-1);
+	}
+
+int ssl3_get_cert_status(SSL *s)
+	{
+	int ok, al;
+	unsigned long resplen,n;
+	const unsigned char *p;
+
+	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 (n < 4)
+		{
+		/* need at least status type + length */
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	p = (unsigned char *)s->init_msg;
+	if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_UNSUPPORTED_STATUS_TYPE);
+		goto f_err;
+		}
+	n2l3(p, resplen);
+	if (resplen + 4 != n)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	if (s->tlsext_ocsp_resp)
+		OPENSSL_free(s->tlsext_ocsp_resp);
+	s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+	if (!s->tlsext_ocsp_resp)
+		{
+		al = SSL_AD_INTERNAL_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE);
+		goto f_err;
+		}
+	s->tlsext_ocsp_resplen = resplen;
+	if (s->ctx->tlsext_status_cb)
+		{
+		int ret;
+		ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+		if (ret == 0)
+			{
+			al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_INVALID_STATUS_RESPONSE);
+			goto f_err;
+			}
+		if (ret < 0)
+			{
+			al = SSL_AD_INTERNAL_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE);
+			goto f_err;
+			}
+		}
+	return 1;
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	return(-1);
+	}
+#endif
+
+int ssl3_get_server_done(SSL *s)
+	{
+	int ok,ret=0;
+	long n;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_CR_SRVR_DONE_A,
+		SSL3_ST_CR_SRVR_DONE_B,
+		SSL3_MT_SERVER_DONE,
+		30, /* should be very small, like 0 :-) */
+		&ok);
+
+	if (!ok) return((int)n);
+	if (n > 0)
+		{
+		/* should contain no data */
+		ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_done, SSL_R_LENGTH_MISMATCH);
+		return -1;
+		}
+	ret=1;
+	return(ret);
+	}
+
+
+int ssl3_send_client_key_exchange(SSL *s)
+	{
+	unsigned char *p;
+	int n;
+	unsigned long alg_k;
+#ifndef OPENSSL_NO_RSA
+	unsigned char *q;
+	EVP_PKEY *pkey=NULL;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *clnt_ecdh = NULL;
+	const EC_POINT *srvr_ecpoint = NULL;
+	EVP_PKEY *srvr_pub_pkey = NULL;
+	unsigned char *encodedPoint = NULL;
+	int encoded_pt_len = 0;
+	BN_CTX * bn_ctx = NULL;
+#endif
+
+	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
+		{
+		p = ssl_handshake_start(s);
+
+		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+
+		/* Fool emacs indentation */
+		if (0) {}
+#ifndef OPENSSL_NO_RSA
+		else if (alg_k & SSL_kRSA)
+			{
+			RSA *rsa;
+			unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+
+			if (s->session->sess_cert->peer_rsa_tmp != NULL)
+				rsa=s->session->sess_cert->peer_rsa_tmp;
+			else
+				{
+				pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+				if ((pkey == NULL) ||
+					(pkey->type != EVP_PKEY_RSA) ||
+					(pkey->pkey.rsa == NULL))
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+					goto err;
+					}
+				rsa=pkey->pkey.rsa;
+				EVP_PKEY_free(pkey);
+				}
+				
+			tmp_buf[0]=s->client_version>>8;
+			tmp_buf[1]=s->client_version&0xff;
+			if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+					goto err;
+
+			s->session->master_key_length=sizeof tmp_buf;
+
+			q=p;
+			/* Fix buf for TLS and beyond */
+			if (s->version > SSL3_VERSION)
+				p+=2;
+			n=RSA_public_encrypt(sizeof tmp_buf,
+				tmp_buf,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;
+#endif
+			if (n <= 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_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;
+				}
+
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,
+					tmp_buf,sizeof tmp_buf);
+			OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
+			}
+#endif
+#ifndef OPENSSL_NO_DH
+		else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+			{
+			DH *dh_srvr,*dh_clnt;
+			SESS_CERT *scert = s->session->sess_cert;
+
+			if (scert == NULL) 
+				{
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_UNEXPECTED_MESSAGE);
+				goto err;
+				}
+
+			if (scert->peer_dh_tmp != NULL)
+				dh_srvr=scert->peer_dh_tmp;
+			else
+				{
+				/* we get them from the cert */
+				int idx = scert->peer_cert_type;
+				EVP_PKEY *spkey = NULL;
+				dh_srvr = NULL;
+				if (idx >= 0)
+					spkey = X509_get_pubkey(
+						scert->peer_pkeys[idx].x509);
+				if (spkey)
+					{
+					dh_srvr = EVP_PKEY_get1_DH(spkey);
+					EVP_PKEY_free(spkey);
+					}
+				if (dh_srvr == NULL)
+					{
+					OPENSSL_PUT_ERROR(SSL, 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)
+					{
+					OPENSSL_PUT_ERROR(SSL, 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)
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+					goto err;
+					}
+				if (!DH_generate_key(dh_clnt))
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+					DH_free(dh_clnt);
+					goto err;
+					}
+				}
+
+			/* use the 'p' output buffer for the DH key, but
+			 * make sure to clear it out afterwards */
+
+			n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+			if (scert->peer_dh_tmp == NULL)
+				DH_free(dh_srvr);
+
+			if (n <= 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
+				DH_free(dh_clnt);
+				goto err;
+				}
+
+			/* generate master key from the result */
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,p,n);
+			/* clean up */
+			memset(p,0,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);
+
+			/* perhaps clean things up a bit EAY EAY EAY EAY*/
+			}
+#endif
+
+#ifndef OPENSSL_NO_ECDH 
+		else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+			{
+			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->session->sess_cert->peer_ecdh_tmp != NULL)
+				{
+				tkey = s->session->sess_cert->peer_ecdh_tmp;
+				}
+			else
+				{
+				/* Get the Server Public Key from Cert */
+				srvr_pub_pkey = X509_get_pubkey(s->session-> \
+				    sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
+				if ((srvr_pub_pkey == NULL) ||
+				    (srvr_pub_pkey->type != EVP_PKEY_EC) ||
+				    (srvr_pub_pkey->pkey.ec == NULL))
+					{
+					OPENSSL_PUT_ERROR(SSL, 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))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			if ((clnt_ecdh=EC_KEY_new()) == NULL) 
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+			if (!EC_KEY_set_group(clnt_ecdh, srvr_group))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+					goto err;
+					}
+				if (!EC_KEY_set_private_key(clnt_ecdh, priv_key))
+					{
+					OPENSSL_PUT_ERROR(SSL, 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)))
+					{
+					OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+				goto err;
+				}
+			n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
+			if (n <= 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+				goto err;
+				}
+
+			/* generate master key from the result */
+			s->session->master_key_length = s->method->ssl3_enc \
+			    -> generate_master_secret(s, 
+				s->session->master_key,
+				p, n);
+
+			memset(p, 0, n); /* clean up */
+
+			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)) 
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+					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((unsigned char *)p, encodedPoint, n);
+				/* increment n to account for length field */
+				n += 1; 
+				}
+
+			/* Free allocated memory */
+			BN_CTX_free(bn_ctx);
+			if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+			if (clnt_ecdh != NULL) 
+				 EC_KEY_free(clnt_ecdh);
+			EVP_PKEY_free(srvr_pub_pkey);
+			}
+#endif /* !OPENSSL_NO_ECDH */
+		else if (alg_k & SSL_kGOST) 
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_GOST_NOT_SUPPORTED);
+			goto err;
+			}
+#ifndef OPENSSL_NO_PSK
+		else if (alg_k & SSL_kPSK)
+			{
+			char identity[PSK_MAX_IDENTITY_LEN];
+			unsigned char *t = NULL;
+			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+			unsigned int pre_ms_len = 0, psk_len = 0;
+			int psk_err = 1;
+
+			n = 0;
+			if (s->psk_client_callback == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_NO_CLIENT_CB);
+				goto err;
+				}
+
+			psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+				identity, PSK_MAX_IDENTITY_LEN,
+				psk_or_pre_ms, sizeof(psk_or_pre_ms));
+			if (psk_len > PSK_MAX_PSK_LEN)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto psk_err;
+				}
+			else if (psk_len == 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND);
+				goto psk_err;
+				}
+
+			/* create PSK pre_master_secret */
+			pre_ms_len = 2+psk_len+2+psk_len;
+			t = psk_or_pre_ms;
+			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+			s2n(psk_len, t);
+			memset(t, 0, psk_len);
+			t+=psk_len;
+			s2n(psk_len, t);
+
+			if (s->session->psk_identity_hint != NULL)
+				OPENSSL_free(s->session->psk_identity_hint);
+			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+			if (s->ctx->psk_identity_hint != NULL &&
+				s->session->psk_identity_hint == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto psk_err;
+				}
+
+			if (s->session->psk_identity != NULL)
+				OPENSSL_free(s->session->psk_identity);
+			s->session->psk_identity = BUF_strdup(identity);
+			if (s->session->psk_identity == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto psk_err;
+				}
+
+			s->session->master_key_length =
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,
+					psk_or_pre_ms, pre_ms_len); 
+			n = strlen(identity);
+			s2n(n, p);
+			memcpy(p, identity, n);
+			n+=2;
+			psk_err = 0;
+		psk_err:
+			OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
+			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+			if (psk_err != 0)
+				{
+				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+				goto err;
+				}
+			}
+#endif
+		else
+			{
+			ssl3_send_alert(s, SSL3_AL_FATAL,
+			    SSL_AD_HANDSHAKE_FAILURE);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+
+		ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
+		s->state=SSL3_ST_CW_KEY_EXCH_B;
+		}
+
+	/* SSL3_ST_CW_KEY_EXCH_B */
+	return ssl_do_write(s);
+err:
+#ifndef OPENSSL_NO_ECDH
+	BN_CTX_free(bn_ctx);
+	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+	if (clnt_ecdh != NULL) 
+		EC_KEY_free(clnt_ecdh);
+	EVP_PKEY_free(srvr_pub_pkey);
+#endif
+	return(-1);
+	}
+
+int ssl3_send_client_verify(SSL *s)
+	{
+	unsigned char *p;
+	unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+	EVP_PKEY *pkey;
+	EVP_PKEY_CTX *pctx=NULL;
+	EVP_MD_CTX mctx;
+	unsigned u=0;
+	unsigned long n;
+	int j;
+
+	EVP_MD_CTX_init(&mctx);
+
+	if (s->state == SSL3_ST_CW_CERT_VRFY_A)
+		{
+		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();
+			}
+		/* For TLS v1.2 send signature algorithm and signature
+		 * using agreed digest and cached handshake records.
+		 */
+		if (SSL_USE_SIGALGS(s))
+			{
+			long hdatalen = 0;
+			char *hdata;
+			const EVP_MD *md = s->cert->key->digest;
+			hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,
+								&hdata);
+			if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			p += 2;
+#ifdef SSL_DEBUG
+			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))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_EVP_LIB);
+				goto err;
+				}
+			s2n(u,p);
+			n = u + 4;
+			if (!ssl3_digest_cached_records(s))
+				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 )
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_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))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_DSA_LIB);
+				goto err;
+				}
+			s2n(j,p);
+			n=j+2;
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+			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))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_ECDSA_LIB);
+				goto err;
+				}
+			s2n(j,p);
+			n=j+2;
+			}
+		else
+#endif
+		if (pkey->type == NID_id_GostR3410_94 || 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) {
+			OPENSSL_PUT_ERROR(SSL, 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
+		{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_INTERNAL_ERROR);
+			goto err;
+		}
+		ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
+		s->state=SSL3_ST_CW_CERT_VRFY_B;
+		}
+	EVP_MD_CTX_cleanup(&mctx);
+	EVP_PKEY_CTX_free(pctx);
+	return ssl_do_write(s);
+err:
+	EVP_MD_CTX_cleanup(&mctx);
+	EVP_PKEY_CTX_free(pctx);
+	return(-1);
+	}
+
+/* Check a certificate can be used for client authentication. Currently
+ * check cert exists, if we have a suitable digest for TLS 1.2 if
+ * static DH client certificates can be used and optionally checks
+ * suitability for Suite B.
+ */
+static int ssl3_check_client_certificate(SSL *s)
+	{
+	unsigned long alg_k;
+	if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
+		return 0;
+	/* If no suitable signature algorithm can't use certificate */
+	if (SSL_USE_SIGALGS(s) && !s->cert->key->digest)
+		return 0;
+	/* If strict mode check suitability of chain before using it.
+	 * This also adjusts suite B digest if necessary.
+	 */
+	if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+		!tls1_check_chain(s, NULL, NULL, NULL, -2))
+		return 0;
+	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+	/* See if we can use client certificate for fixed DH */
+	if (alg_k & (SSL_kDHr|SSL_kDHd))
+		{
+		SESS_CERT *scert = s->session->sess_cert;
+		int i = scert->peer_cert_type;
+		EVP_PKEY *clkey = NULL, *spkey = NULL;
+		clkey = s->cert->key->privatekey;
+		/* If client key not DH assume it can be used */
+		if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
+			return 1;
+		if (i >= 0)
+			spkey = X509_get_pubkey(scert->peer_pkeys[i].x509);
+		if (spkey)
+			{
+			/* Compare server and client parameters */
+			i = EVP_PKEY_cmp_parameters(clkey, spkey);
+			EVP_PKEY_free(spkey);
+			if (i != 1)
+				return 0;
+			}
+		s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+		}
+	return 1;
+	}
+
+int ssl3_send_client_certificate(SSL *s)
+	{
+	X509 *x509=NULL;
+	EVP_PKEY *pkey=NULL;
+	int i;
+
+	if (s->state ==	SSL3_ST_CW_CERT_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;
+				}
+			if (i == 0)
+				{
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+				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;
+		}
+
+	/* We need to get a client cert */
+	if (s->state == SSL3_ST_CW_CERT_B)
+		{
+		/* If we get an error, we need to
+		 * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
+		 * We then get retied later */
+		i=0;
+		i = ssl_do_client_cert_cb(s, &x509, &pkey);
+		if (i < 0)
+			{
+			s->rwstate=SSL_X509_LOOKUP;
+			return(-1);
+			}
+		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;
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+			}
+
+		if (x509 != NULL) X509_free(x509);
+		if (pkey != NULL) EVP_PKEY_free(pkey);
+		if (i && !ssl3_check_client_certificate(s))
+			i = 0;
+		if (i == 0)
+			{
+			if (s->version == SSL3_VERSION)
+				{
+				s->s3->tmp.cert_req=0;
+				ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_NO_CERTIFICATE);
+				return(1);
+				}
+			else
+				{
+				s->s3->tmp.cert_req=2;
+				}
+			}
+
+		/* Ok, we have a cert */
+		s->state=SSL3_ST_CW_CERT_C;
+		}
+
+	if (s->state == SSL3_ST_CW_CERT_C)
+		{
+		s->state=SSL3_ST_CW_CERT_D;
+		ssl3_output_cert_chain(s,
+			(s->s3->tmp.cert_req == 2)?NULL:s->cert->key);
+		}
+	/* SSL3_ST_CW_CERT_D */
+	return ssl_do_write(s);
+	}
+
+#define has_bits(i,m)	(((i)&(m)) == (m))
+
+int ssl3_check_cert_and_algorithm(SSL *s)
+	{
+	int i,idx;
+	long alg_k,alg_a;
+	EVP_PKEY *pkey=NULL;
+	SESS_CERT *sc;
+#ifndef OPENSSL_NO_RSA
+	RSA *rsa;
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *dh;
+#endif
+
+	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+
+	/* we don't have a certificate */
+	if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+		return(1);
+
+	sc=s->session->sess_cert;
+	if (sc == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+		goto err;
+		}
+
+#ifndef OPENSSL_NO_RSA
+	rsa=s->session->sess_cert->peer_rsa_tmp;
+#endif
+#ifndef OPENSSL_NO_DH
+	dh=s->session->sess_cert->peer_dh_tmp;
+#endif
+
+	/* This is the passed certificate */
+
+	idx=sc->peer_cert_type;
+#ifndef OPENSSL_NO_ECDH
+	if (idx == SSL_PKEY_ECC)
+		{
+		if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
+		    						s) == 0) 
+			{ /* check failed */
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_ECC_CERT);
+			goto f_err;
+			}
+		else 
+			{
+			return 1;
+			}
+		}
+	else if (alg_a & SSL_aECDSA)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_ECDSA_SIGNING_CERT);
+		goto f_err;
+		}
+	else if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_ECDH_CERT);
+		goto f_err;
+		}
+#endif
+	pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
+	i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
+	EVP_PKEY_free(pkey);
+
+	
+	/* Check that we have a certificate if we require one */
+	if ((alg_a & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_RSA_SIGNING_CERT);
+		goto f_err;
+		}
+#ifndef OPENSSL_NO_DSA
+	else if ((alg_a & SSL_aDSS) && !has_bits(i,EVP_PK_DSA|EVP_PKT_SIGN))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_DSA_SIGNING_CERT);
+		goto f_err;
+		}
+#endif
+#ifndef OPENSSL_NO_RSA
+	if ((alg_k & SSL_kRSA) &&
+		!(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL)))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+		goto f_err;
+		}
+#endif
+#ifndef OPENSSL_NO_DH
+	if ((alg_k & SSL_kEDH) && 
+		!(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_DH_KEY);
+		goto f_err;
+		}
+	else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
+		!has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_DH_RSA_CERT);
+		goto f_err;
+		}
+#ifndef OPENSSL_NO_DSA
+	else if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
+		!has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_DH_DSA_CERT);
+		goto f_err;
+		}
+#endif
+#endif
+
+	if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP))
+		{
+#ifndef OPENSSL_NO_RSA
+		if (alg_k & SSL_kRSA)
+			{
+			if (rsa == NULL
+			    || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+				goto f_err;
+				}
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_DH
+			if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+			    {
+			    if (dh == NULL
+				|| DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+				goto f_err;
+				}
+			}
+		else
+#endif
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+			goto f_err;
+			}
+		}
+	return(1);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+err:
+	return(0);
+	}
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+int ssl3_send_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);
+}
+#endif  /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+
+/* Check to see if handshake is full or resumed. Usually this is just a
+ * case of checking to see if a cache hit has occurred. In the case of
+ * session tickets we have to check the next message to be sure.
+ */
+
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_check_finished(SSL *s)
+	{
+	int ok;
+	long n;
+	/* If we have no ticket it cannot be a resumed session. */
+	if (!s->session->tlsext_tick)
+		return 1;
+	/* this function is called when we really expect a Certificate
+	 * message, so permit appropriate message length */
+	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);
+	s->s3->tmp.reuse_message = 1;
+	if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
+		|| (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
+		return 2;
+
+	return 1;
+	}
+#endif
+
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
+	{
+	int i = 0;
+        /* TODO(fork): remove */
+#if 0
+#ifndef OPENSSL_NO_ENGINE
+	if (s->ctx->client_cert_engine)
+		{
+		i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
+						SSL_get_client_CA_list(s),
+						px509, ppkey, NULL, NULL, NULL);
+		if (i != 0)
+			return i;
+		}
+#endif
+#endif
+	if (s->ctx->client_cert_cb)
+		i = s->ctx->client_cert_cb(s,px509,ppkey);
+	return i;
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+int tls1_get_server_supplemental_data(SSL *s)
+	{
+	int al;
+	int ok;
+	unsigned long supp_data_len, authz_data_len;
+	long n;
+	unsigned short supp_data_type, authz_data_type, proof_len;
+	const unsigned char *p;
+	unsigned char *new_proof;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_CR_SUPPLEMENTAL_DATA_A,
+		SSL3_ST_CR_SUPPLEMENTAL_DATA_B,
+		SSL3_MT_SUPPLEMENTAL_DATA,
+		/* use default limit */
+		TLSEXT_MAXLEN_supplemental_data,
+		&ok);
+
+	if (!ok) return((int)n);
+
+	p = (unsigned char *)s->init_msg;
+
+	/* The message cannot be empty */
+	if (n < 3)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Length of supplemental data */
+	n2l3(p,supp_data_len);
+	n -= 3;
+	/* We must have at least one supplemental data entry
+	 * with type (1 byte) and length (2 bytes). */
+	if (supp_data_len != (unsigned long) n || n < 4)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Supplemental data type: must be authz_data */
+	n2s(p,supp_data_type);
+	n -= 2;
+	if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data)
+		{
+		al = SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE);
+		goto f_err;
+		}
+	/* Authz data length */
+	n2s(p, authz_data_len);
+	n -= 2;
+	if (authz_data_len != (unsigned long) n || n < 1)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Authz data type: must be audit_proof */
+	authz_data_type = *(p++);
+	n -= 1;
+	if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_UNKNOWN_AUTHZ_DATA_TYPE);
+		goto f_err;
+		}
+	/* We have a proof: read its length */
+	if (n < 2)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	n2s(p, proof_len);
+	n -= 2;
+	if (proof_len != (unsigned long) n)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Store the proof */
+	new_proof = OPENSSL_realloc(s->session->audit_proof,
+				    proof_len);
+	if (new_proof == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	s->session->audit_proof_length = proof_len;
+	s->session->audit_proof = new_proof;
+	memcpy(s->session->audit_proof, p, proof_len);
+
+	/* Got the proof, but can't verify it yet. */
+	return 1;
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	return -1;
+	}
+#endif
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
new file mode 100644
index 0000000..ee54dfd
--- /dev/null
+++ b/ssl/s3_enc.c
@@ -0,0 +1,879 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *g
+ * 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@cryptsoft.com).
+ *g
+ * 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.
+ *g
+ * 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@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) fromg
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *g
+ * 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.
+ *g
+ * 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.g
+ *
+ * 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * 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 <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+
+#include "ssl_locl.h"
+
+static unsigned char ssl3_pad_1[48]={
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+	0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36 };
+
+static unsigned char ssl3_pad_2[48]={
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
+	0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c };
+static int ssl3_handshake_mac(SSL *s, int md_nid,
+	const char *sender, int len, unsigned char *p);
+static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
+	{
+	EVP_MD_CTX m5;
+	EVP_MD_CTX s1;
+	unsigned char buf[16],smd[SHA_DIGEST_LENGTH];
+	unsigned char c='A';
+	unsigned int i,j,k;
+
+#ifdef CHARSET_EBCDIC
+	c = os_toascii[c]; /*'A' in ASCII */
+#endif
+	k=0;
+	EVP_MD_CTX_init(&m5);
+	EVP_MD_CTX_init(&s1);
+	for (i=0; (int)i<num; i+=MD5_DIGEST_LENGTH)
+		{
+		k++;
+		if (k > sizeof buf)
+			{
+			/* bug: 'buf' is too small for this ciphersuite */
+			OPENSSL_PUT_ERROR(SSL, ssl3_generate_key_block, ERR_R_INTERNAL_ERROR);
+			return 0;
+			}
+		
+		for (j=0; j<k; j++)
+			buf[j]=c;
+		c++;
+		EVP_DigestInit_ex(&s1,EVP_sha1(), NULL);
+		EVP_DigestUpdate(&s1,buf,k);
+		EVP_DigestUpdate(&s1,s->session->master_key,
+			s->session->master_key_length);
+		EVP_DigestUpdate(&s1,s->s3->server_random,SSL3_RANDOM_SIZE);
+		EVP_DigestUpdate(&s1,s->s3->client_random,SSL3_RANDOM_SIZE);
+		EVP_DigestFinal_ex(&s1,smd,NULL);
+
+		EVP_DigestInit_ex(&m5,EVP_md5(), NULL);
+		EVP_DigestUpdate(&m5,s->session->master_key,
+			s->session->master_key_length);
+		EVP_DigestUpdate(&m5,smd,SHA_DIGEST_LENGTH);
+		if ((int)(i+MD5_DIGEST_LENGTH) > num)
+			{
+			EVP_DigestFinal_ex(&m5,smd,NULL);
+			memcpy(km,smd,(num-i));
+			}
+		else
+			EVP_DigestFinal_ex(&m5,km,NULL);
+
+		km+=MD5_DIGEST_LENGTH;
+		}
+	OPENSSL_cleanse(smd,SHA_DIGEST_LENGTH);
+	EVP_MD_CTX_cleanup(&m5);
+	EVP_MD_CTX_cleanup(&s1);
+	return 1;
+	}
+
+int ssl3_change_cipher_state(SSL *s, int which)
+	{
+	unsigned char *p,*mac_secret;
+	unsigned char exp_key[EVP_MAX_KEY_LENGTH];
+	unsigned char exp_iv[EVP_MAX_IV_LENGTH];
+	unsigned char *ms,*key,*iv,*er1,*er2;
+	EVP_CIPHER_CTX *dd;
+	const EVP_CIPHER *c;
+	const EVP_MD *m;
+	EVP_MD_CTX md;
+	int is_exp,n,i,j,k,cl;
+	int reuse_dd = 0;
+
+	is_exp=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
+	c=s->s3->tmp.new_sym_enc;
+	m=s->s3->tmp.new_hash;
+	/* m == NULL will lead to a crash later */
+	assert(m);
+
+	if (which & SSL3_CC_READ)
+		{
+		if (s->enc_read_ctx != NULL)
+			reuse_dd = 1;
+		else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
+			goto err;
+		else
+			/* make sure it's intialized in case we exit later with an error */
+			EVP_CIPHER_CTX_init(s->enc_read_ctx);
+		dd= s->enc_read_ctx;
+
+		ssl_replace_hash(&s->read_hash,m);
+		memset(&(s->s3->read_sequence[0]),0,8);
+		mac_secret= &(s->s3->read_mac_secret[0]);
+		}
+	else
+		{
+		if (s->enc_write_ctx != NULL)
+			reuse_dd = 1;
+		else if ((s->enc_write_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
+			goto err;
+		else
+			/* make sure it's intialized in case we exit later with an error */
+			EVP_CIPHER_CTX_init(s->enc_write_ctx);
+		dd= s->enc_write_ctx;
+		ssl_replace_hash(&s->write_hash,m);
+		memset(&(s->s3->write_sequence[0]),0,8);
+		mac_secret= &(s->s3->write_mac_secret[0]);
+		}
+
+	if (reuse_dd)
+		EVP_CIPHER_CTX_cleanup(dd);
+
+	p=s->s3->tmp.key_block;
+	i=EVP_MD_size(m);
+	cl=EVP_CIPHER_key_length(c);
+	j=is_exp ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
+		 cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
+	/* Was j=(is_exp)?5:EVP_CIPHER_key_length(c); */
+	k=EVP_CIPHER_iv_length(c);
+	if (	(which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+		(which == SSL3_CHANGE_CIPHER_SERVER_READ))
+		{
+		ms=  &(p[ 0]); n=i+i;
+		key= &(p[ n]); n+=j+j;
+		iv=  &(p[ n]); n+=k+k;
+		er1= &(s->s3->client_random[0]);
+		er2= &(s->s3->server_random[0]);
+		}
+	else
+		{
+		n=i;
+		ms=  &(p[ n]); n+=i+j;
+		key= &(p[ n]); n+=j+k;
+		iv=  &(p[ n]); n+=k;
+		er1= &(s->s3->server_random[0]);
+		er2= &(s->s3->client_random[0]);
+		}
+
+	if (n > s->s3->tmp.key_block_length)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_change_cipher_state, ERR_R_INTERNAL_ERROR);
+		goto err2;
+		}
+
+	EVP_MD_CTX_init(&md);
+	memcpy(mac_secret,ms,i);
+	if (is_exp)
+		{
+		/* In here I set both the read and write key/iv to the
+		 * same value since only the correct one will be used :-).
+		 */
+		EVP_DigestInit_ex(&md,EVP_md5(), NULL);
+		EVP_DigestUpdate(&md,key,j);
+		EVP_DigestUpdate(&md,er1,SSL3_RANDOM_SIZE);
+		EVP_DigestUpdate(&md,er2,SSL3_RANDOM_SIZE);
+		EVP_DigestFinal_ex(&md,&(exp_key[0]),NULL);
+		key= &(exp_key[0]);
+
+		if (k > 0)
+			{
+			EVP_DigestInit_ex(&md,EVP_md5(), NULL);
+			EVP_DigestUpdate(&md,er1,SSL3_RANDOM_SIZE);
+			EVP_DigestUpdate(&md,er2,SSL3_RANDOM_SIZE);
+			EVP_DigestFinal_ex(&md,&(exp_iv[0]),NULL);
+			iv= &(exp_iv[0]);
+			}
+		}
+
+	s->session->key_arg_length=0;
+
+	EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
+
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+	if (s->msg_callback)
+		{
+ 
+		int wh = which & SSL3_CC_WRITE ?
+				TLS1_RT_CRYPTO_WRITE : TLS1_RT_CRYPTO_READ;
+		s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_MAC,
+						mac_secret, EVP_MD_size(m),
+						s, s->msg_callback_arg);
+		if (c->key_len)
+			s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY,
+						key, c->key_len,
+						s, s->msg_callback_arg);
+		if (k)
+			{
+			s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_IV,
+						iv, k, s, s->msg_callback_arg);
+			}
+		}
+#endif
+
+	OPENSSL_cleanse(&(exp_key[0]),sizeof(exp_key));
+	OPENSSL_cleanse(&(exp_iv[0]),sizeof(exp_iv));
+	EVP_MD_CTX_cleanup(&md);
+	return(1);
+err:
+	OPENSSL_PUT_ERROR(SSL, ssl3_change_cipher_state, ERR_R_MALLOC_FAILURE);
+err2:
+	return(0);
+	}
+
+int ssl3_setup_key_block(SSL *s)
+	{
+	unsigned char *p;
+	const EVP_CIPHER *c;
+	const EVP_MD *hash;
+	size_t num;
+	int ret = 0;
+	SSL_COMP *comp;
+
+	if (s->s3->tmp.key_block_length != 0)
+		return(1);
+
+	if (!ssl_cipher_get_evp(s->session,&c,&hash,NULL,NULL,&comp))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_setup_key_block, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+		return(0);
+		}
+
+	s->s3->tmp.new_sym_enc=c;
+	s->s3->tmp.new_hash=hash;
+	s->s3->tmp.new_compression=NULL;
+
+	num=EVP_MD_size(hash);
+
+	num=EVP_CIPHER_key_length(c)+num+EVP_CIPHER_iv_length(c);
+	num*=2;
+
+	ssl3_cleanup_key_block(s);
+
+	if ((p=OPENSSL_malloc(num)) == NULL)
+		goto err;
+
+	s->s3->tmp.key_block_length=num;
+	s->s3->tmp.key_block=p;
+
+	ret = ssl3_generate_key_block(s,p,num);
+
+	if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
+		{
+		/* enable vulnerability countermeasure for CBC ciphers with
+		 * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt)
+		 */
+		s->s3->need_empty_fragments = 1;
+
+		if (s->session->cipher != NULL)
+			{
+			if (s->session->cipher->algorithm_enc == SSL_eNULL)
+				s->s3->need_empty_fragments = 0;
+			
+#ifndef OPENSSL_NO_RC4
+			if (s->session->cipher->algorithm_enc == SSL_RC4)
+				s->s3->need_empty_fragments = 0;
+#endif
+			}
+		}
+
+	return ret;
+		
+err:
+	OPENSSL_PUT_ERROR(SSL, ssl3_setup_key_block, ERR_R_MALLOC_FAILURE);
+	return(0);
+	}
+
+void ssl3_cleanup_key_block(SSL *s)
+	{
+	if (s->s3->tmp.key_block != NULL)
+		{
+		OPENSSL_cleanse(s->s3->tmp.key_block,
+			s->s3->tmp.key_block_length);
+		OPENSSL_free(s->s3->tmp.key_block);
+		s->s3->tmp.key_block=NULL;
+		}
+	s->s3->tmp.key_block_length=0;
+	}
+
+/* ssl3_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publically invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding is invalid or, if sending, an internal error
+ *       occured.
+ */
+int ssl3_enc(SSL *s, int send)
+	{
+	SSL3_RECORD *rec;
+	EVP_CIPHER_CTX *ds;
+	unsigned long l;
+	int bs,i,mac_size=0;
+	const EVP_CIPHER *enc;
+
+	if (send)
+		{
+		ds=s->enc_write_ctx;
+		rec= &(s->s3->wrec);
+		if (s->enc_write_ctx == NULL)
+			enc=NULL;
+		else
+			enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+		}
+	else
+		{
+		ds=s->enc_read_ctx;
+		rec= &(s->s3->rrec);
+		if (s->enc_read_ctx == NULL)
+			enc=NULL;
+		else
+			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+		}
+
+	if ((s->session == NULL) || (ds == NULL) ||
+		(enc == NULL))
+		{
+		memmove(rec->data,rec->input,rec->length);
+		rec->input=rec->data;
+		}
+	else
+		{
+		l=rec->length;
+		bs=EVP_CIPHER_block_size(ds->cipher);
+
+		/* COMPRESS */
+
+		if ((bs != 1) && send)
+			{
+			i=bs-((int)l%bs);
+
+			/* we need to add 'i-1' padding bytes */
+			l+=i;
+			/* the last of these zero bytes will be overwritten
+			 * with the padding length. */
+			memset(&rec->input[rec->length], 0, i);
+			rec->length+=i;
+			rec->input[l-1]=(i-1);
+			}
+		
+		if (!send)
+			{
+			if (l == 0 || l%bs != 0)
+				return 0;
+			/* otherwise, rec->length >= bs */
+			}
+		
+		EVP_Cipher(ds,rec->data,rec->input,l);
+
+		if (EVP_MD_CTX_md(s->read_hash) != NULL)
+			mac_size = EVP_MD_CTX_size(s->read_hash);
+		if ((bs != 1) && !send)
+			return ssl3_cbc_remove_padding(s, rec, bs, mac_size);
+		}
+	return(1);
+	}
+
+void ssl3_init_finished_mac(SSL *s)
+	{
+	if (s->s3->handshake_buffer) BIO_free(s->s3->handshake_buffer);
+	if (s->s3->handshake_dgst) ssl3_free_digest_list(s);
+    s->s3->handshake_buffer=BIO_new(BIO_s_mem());	
+	(void)BIO_set_close(s->s3->handshake_buffer,BIO_CLOSE);
+	}
+
+void ssl3_free_digest_list(SSL *s) 
+	{
+	int i;
+	if (!s->s3->handshake_dgst) return;
+	for (i=0;i<SSL_MAX_DIGEST;i++) 
+		{
+		if (s->s3->handshake_dgst[i])
+			EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
+		}
+	OPENSSL_free(s->s3->handshake_dgst);
+	s->s3->handshake_dgst=NULL;
+	}	
+
+
+
+void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
+	{
+	if (s->s3->handshake_buffer && !(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)) 
+		{
+		BIO_write (s->s3->handshake_buffer,(void *)buf,len);
+		} 
+	else 
+		{
+		int i;
+		for (i=0;i< SSL_MAX_DIGEST;i++) 
+			{
+			if (s->s3->handshake_dgst[i]!= NULL)
+			EVP_DigestUpdate(s->s3->handshake_dgst[i],buf,len);
+			}
+		}	
+	}
+
+int ssl3_digest_cached_records(SSL *s)
+	{
+	int i;
+	long mask;
+	const EVP_MD *md;
+	long hdatalen;
+	char *hdata;
+
+	/* Allocate handshake_dgst array */
+	ssl3_free_digest_list(s);
+	s->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
+	memset(s->s3->handshake_dgst,0,SSL_MAX_DIGEST *sizeof(EVP_MD_CTX *));
+	hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,&hdata);
+	if (hdatalen <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_digest_cached_records, SSL_R_BAD_HANDSHAKE_LENGTH);
+		return 0;
+		}
+
+	/* Loop through bitso of algorithm2 field and create MD_CTX-es */
+	for (i=0;ssl_get_handshake_digest(i,&mask,&md); i++) 
+		{
+		if ((mask & ssl_get_algorithm2(s)) && md) 
+			{
+			s->s3->handshake_dgst[i]=EVP_MD_CTX_create();
+			EVP_DigestInit_ex(s->s3->handshake_dgst[i],md,NULL);
+			EVP_DigestUpdate(s->s3->handshake_dgst[i],hdata,hdatalen);
+			} 
+		else 
+			{	
+			s->s3->handshake_dgst[i]=NULL;
+			}
+		}
+	if (!(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE))
+		{
+		/* Free handshake_buffer BIO */
+		BIO_free(s->s3->handshake_buffer);
+		s->s3->handshake_buffer = NULL;
+		}
+
+	return 1;
+	}
+
+int ssl3_cert_verify_mac(SSL *s, int md_nid, unsigned char *p)
+	{
+	return(ssl3_handshake_mac(s,md_nid,NULL,0,p));
+	}
+int ssl3_final_finish_mac(SSL *s, 
+	     const char *sender, int len, unsigned char *p)
+	{
+	int ret;
+	ret=ssl3_handshake_mac(s,NID_md5,sender,len,p);
+	p+=ret;
+	ret+=ssl3_handshake_mac(s,NID_sha1,sender,len,p);
+	return(ret);
+	}
+
+static int ssl3_handshake_mac(SSL *s, int md_nid,
+	     const char *sender, int len, unsigned char *p)
+	{
+	unsigned int ret;
+	int npad,n;
+	unsigned int i;
+	unsigned char md_buf[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX ctx,*d=NULL;
+
+	if (s->s3->handshake_buffer) 
+		if (!ssl3_digest_cached_records(s))
+			return 0;
+
+	/* Search for digest of specified type in the handshake_dgst
+	 * array*/
+	for (i=0;i<SSL_MAX_DIGEST;i++) 
+		{
+		  if (s->s3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid) 
+		  	{
+		  	d=s->s3->handshake_dgst[i];
+			break;
+			}
+		}
+	if (!d) {
+		OPENSSL_PUT_ERROR(SSL, ssl3_handshake_mac, SSL_R_NO_REQUIRED_DIGEST);
+		return 0;
+	}	
+	EVP_MD_CTX_init(&ctx);
+	EVP_MD_CTX_copy_ex(&ctx,d);
+	n=EVP_MD_CTX_size(&ctx);
+	if (n < 0)
+		return 0;
+
+	npad=(48/n)*n;
+	if (sender != NULL)
+		EVP_DigestUpdate(&ctx,sender,len);
+	EVP_DigestUpdate(&ctx,s->session->master_key,
+		s->session->master_key_length);
+	EVP_DigestUpdate(&ctx,ssl3_pad_1,npad);
+	EVP_DigestFinal_ex(&ctx,md_buf,&i);
+
+	EVP_DigestInit_ex(&ctx,EVP_MD_CTX_md(&ctx), NULL);
+	EVP_DigestUpdate(&ctx,s->session->master_key,
+		s->session->master_key_length);
+	EVP_DigestUpdate(&ctx,ssl3_pad_2,npad);
+	EVP_DigestUpdate(&ctx,md_buf,i);
+	EVP_DigestFinal_ex(&ctx,p,&ret);
+
+	EVP_MD_CTX_cleanup(&ctx);
+
+	return((int)ret);
+	}
+
+int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)
+	{
+	SSL3_RECORD *rec;
+	unsigned char *mac_sec,*seq;
+	EVP_MD_CTX md_ctx;
+	const EVP_MD_CTX *hash;
+	unsigned char *p,rec_char;
+	size_t md_size, orig_len;
+	int npad;
+	int t;
+
+	if (send)
+		{
+		rec= &(ssl->s3->wrec);
+		mac_sec= &(ssl->s3->write_mac_secret[0]);
+		seq= &(ssl->s3->write_sequence[0]);
+		hash=ssl->write_hash;
+		}
+	else
+		{
+		rec= &(ssl->s3->rrec);
+		mac_sec= &(ssl->s3->read_mac_secret[0]);
+		seq= &(ssl->s3->read_sequence[0]);
+		hash=ssl->read_hash;
+		}
+
+	t=EVP_MD_CTX_size(hash);
+	if (t < 0)
+		return -1;
+	md_size=t;
+	npad=(48/md_size)*md_size;
+
+	/* kludge: ssl3_cbc_remove_padding passes padding length in rec->type */
+	orig_len = rec->length+md_size+((unsigned int)rec->type>>8);
+	rec->type &= 0xff;
+
+	if (!send &&
+	    EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+	    ssl3_cbc_record_digest_supported(hash))
+		{
+		/* This is a CBC-encrypted record. We must avoid leaking any
+		 * timing-side channel information about how many blocks of
+		 * data we are hashing because that gives an attacker a
+		 * timing-oracle. */
+
+		/* npad is, at most, 48 bytes and that's with MD5:
+		 *   16 + 48 + 8 (sequence bytes) + 1 + 2 = 75.
+		 *
+		 * With SHA-1 (the largest hash speced for SSLv3) the hash size
+		 * goes up 4, but npad goes down by 8, resulting in a smaller
+		 * total size. */
+		unsigned char header[75];
+		unsigned j = 0;
+		memcpy(header+j, mac_sec, md_size);
+		j += md_size;
+		memcpy(header+j, ssl3_pad_1, npad);
+		j += npad;
+		memcpy(header+j, seq, 8);
+		j += 8;
+		header[j++] = rec->type;
+		header[j++] = rec->length >> 8;
+		header[j++] = rec->length & 0xff;
+
+		ssl3_cbc_digest_record(
+			hash,
+			md, &md_size,
+			header, rec->input,
+			rec->length + md_size, orig_len,
+			mac_sec, md_size,
+			1 /* is SSLv3 */);
+		}
+	else
+		{
+		unsigned int md_size_u;
+		/* Chop the digest off the end :-) */
+		EVP_MD_CTX_init(&md_ctx);
+
+		EVP_MD_CTX_copy_ex( &md_ctx,hash);
+		EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
+		EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad);
+		EVP_DigestUpdate(&md_ctx,seq,8);
+		rec_char=rec->type;
+		EVP_DigestUpdate(&md_ctx,&rec_char,1);
+		p=md;
+		s2n(rec->length,p);
+		EVP_DigestUpdate(&md_ctx,md,2);
+		EVP_DigestUpdate(&md_ctx,rec->input,rec->length);
+		EVP_DigestFinal_ex( &md_ctx,md,NULL);
+
+		EVP_MD_CTX_copy_ex( &md_ctx,hash);
+		EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
+		EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad);
+		EVP_DigestUpdate(&md_ctx,md,md_size);
+		EVP_DigestFinal_ex( &md_ctx,md,&md_size_u);
+		md_size = md_size_u;
+
+		EVP_MD_CTX_cleanup(&md_ctx);
+	}
+
+	ssl3_record_sequence_update(seq);
+	return(md_size);
+	}
+
+void ssl3_record_sequence_update(unsigned char *seq)
+	{
+	int i;
+
+	for (i=7; i>=0; i--)
+		{
+		++seq[i];
+		if (seq[i] != 0) break; 
+		}
+	}
+
+int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+	     int len)
+	{
+	static const unsigned char *salt[3]={
+#ifndef CHARSET_EBCDIC
+		(const unsigned char *)"A",
+		(const unsigned char *)"BB",
+		(const unsigned char *)"CCC",
+#else
+		(const unsigned char *)"\x41",
+		(const unsigned char *)"\x42\x42",
+		(const unsigned char *)"\x43\x43\x43",
+#endif
+		};
+	unsigned char buf[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX ctx;
+	int i,ret=0;
+	unsigned int n;
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+	unsigned char *tmpout = out;
+#endif
+
+	EVP_MD_CTX_init(&ctx);
+	for (i=0; i<3; i++)
+		{
+		EVP_DigestInit_ex(&ctx,s->ctx->sha1, NULL);
+		EVP_DigestUpdate(&ctx,salt[i],strlen((const char *)salt[i]));
+		EVP_DigestUpdate(&ctx,p,len);
+		EVP_DigestUpdate(&ctx,&(s->s3->client_random[0]),
+			SSL3_RANDOM_SIZE);
+		EVP_DigestUpdate(&ctx,&(s->s3->server_random[0]),
+			SSL3_RANDOM_SIZE);
+		EVP_DigestFinal_ex(&ctx,buf,&n);
+
+		EVP_DigestInit_ex(&ctx,s->ctx->md5, NULL);
+		EVP_DigestUpdate(&ctx,p,len);
+		EVP_DigestUpdate(&ctx,buf,n);
+		EVP_DigestFinal_ex(&ctx,out,&n);
+		out+=n;
+		ret+=n;
+		}
+	EVP_MD_CTX_cleanup(&ctx);
+
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+	if (s->msg_callback)
+		{
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_PREMASTER,
+						p, len, s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_CLIENT_RANDOM,
+					s->s3->client_random, SSL3_RANDOM_SIZE,
+						s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_SERVER_RANDOM,
+					s->s3->server_random, SSL3_RANDOM_SIZE,
+					s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_MASTER,
+					tmpout, SSL3_MASTER_SECRET_SIZE,
+					s, s->msg_callback_arg);
+		}
+#endif
+	return(ret);
+	}
+
+int ssl3_alert_code(int code)
+	{
+	switch (code)
+		{
+	case SSL_AD_CLOSE_NOTIFY:	return(SSL3_AD_CLOSE_NOTIFY);
+	case SSL_AD_UNEXPECTED_MESSAGE:	return(SSL3_AD_UNEXPECTED_MESSAGE);
+	case SSL_AD_BAD_RECORD_MAC:	return(SSL3_AD_BAD_RECORD_MAC);
+	case SSL_AD_DECRYPTION_FAILED:	return(SSL3_AD_BAD_RECORD_MAC);
+	case SSL_AD_RECORD_OVERFLOW:	return(SSL3_AD_BAD_RECORD_MAC);
+	case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE);
+	case SSL_AD_HANDSHAKE_FAILURE:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_NO_CERTIFICATE:	return(SSL3_AD_NO_CERTIFICATE);
+	case SSL_AD_BAD_CERTIFICATE:	return(SSL3_AD_BAD_CERTIFICATE);
+	case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE);
+	case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED);
+	case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED);
+	case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN);
+	case SSL_AD_ILLEGAL_PARAMETER:	return(SSL3_AD_ILLEGAL_PARAMETER);
+	case SSL_AD_UNKNOWN_CA:		return(SSL3_AD_BAD_CERTIFICATE);
+	case SSL_AD_ACCESS_DENIED:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_DECODE_ERROR:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_DECRYPT_ERROR:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_EXPORT_RESTRICTION:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_PROTOCOL_VERSION:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_INSUFFICIENT_SECURITY:return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_INTERNAL_ERROR:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_USER_CANCELLED:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_NO_RENEGOTIATION:	return(-1); /* Don't send it :-) */
+	case SSL_AD_UNSUPPORTED_EXTENSION: return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_UNRECOGNIZED_NAME:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY);
+	default:			return(-1);
+		}
+	}
+
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
new file mode 100644
index 0000000..3a53c68
--- /dev/null
+++ b/ssl/s3_lib.c
@@ -0,0 +1,4046 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@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 <openssl/dh.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "ssl_locl.h"
+
+#define SSL3_NUM_CIPHERS	(sizeof(ssl3_ciphers)/sizeof(SSL_CIPHER))
+
+/* list of available SSLv3 ciphers (sorted by id) */
+SSL_CIPHER ssl3_ciphers[]={
+
+/* The RSA ciphers */
+/* Cipher 01 */
+	{
+	1,
+	SSL3_TXT_RSA_NULL_MD5,
+	SSL3_CK_RSA_NULL_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eNULL,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_STRONG_NONE,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+/* Cipher 02 */
+	{
+	1,
+	SSL3_TXT_RSA_NULL_SHA,
+	SSL3_CK_RSA_NULL_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+/* Cipher 03 */
+	{
+	1,
+	SSL3_TXT_RSA_RC4_40_MD5,
+	SSL3_CK_RSA_RC4_40_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	128,
+	},
+
+/* Cipher 04 */
+	{
+	1,
+	SSL3_TXT_RSA_RC4_128_MD5,
+	SSL3_CK_RSA_RC4_128_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+/* Cipher 05 */
+	{
+	1,
+	SSL3_TXT_RSA_RC4_128_SHA,
+	SSL3_CK_RSA_RC4_128_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+/* Cipher 06 */
+	{
+	1,
+	SSL3_TXT_RSA_RC2_40_MD5,
+	SSL3_CK_RSA_RC2_40_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC2,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	128,
+	},
+
+/* Cipher 07 */
+#ifndef OPENSSL_NO_IDEA
+	{
+	1,
+	SSL3_TXT_RSA_IDEA_128_SHA,
+	SSL3_CK_RSA_IDEA_128_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_IDEA,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+#endif
+
+/* Cipher 08 */
+	{
+	1,
+	SSL3_TXT_RSA_DES_40_CBC_SHA,
+	SSL3_CK_RSA_DES_40_CBC_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	56,
+	},
+
+/* Cipher 09 */
+	{
+	1,
+	SSL3_TXT_RSA_DES_64_CBC_SHA,
+	SSL3_CK_RSA_DES_64_CBC_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 0A */
+	{
+	1,
+	SSL3_TXT_RSA_DES_192_CBC3_SHA,
+	SSL3_CK_RSA_DES_192_CBC3_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* The DH ciphers */
+/* Cipher 0B */
+	{
+	1,
+	SSL3_TXT_DH_DSS_DES_40_CBC_SHA,
+	SSL3_CK_DH_DSS_DES_40_CBC_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	56,
+	},
+
+/* Cipher 0C */
+	{
+	1,
+	SSL3_TXT_DH_DSS_DES_64_CBC_SHA,
+	SSL3_CK_DH_DSS_DES_64_CBC_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 0D */
+	{
+	1,
+	SSL3_TXT_DH_DSS_DES_192_CBC3_SHA,
+	SSL3_CK_DH_DSS_DES_192_CBC3_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* Cipher 0E */
+	{
+	1,
+	SSL3_TXT_DH_RSA_DES_40_CBC_SHA,
+	SSL3_CK_DH_RSA_DES_40_CBC_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	56,
+	},
+
+/* Cipher 0F */
+	{
+	1,
+	SSL3_TXT_DH_RSA_DES_64_CBC_SHA,
+	SSL3_CK_DH_RSA_DES_64_CBC_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 10 */
+	{
+	1,
+	SSL3_TXT_DH_RSA_DES_192_CBC3_SHA,
+	SSL3_CK_DH_RSA_DES_192_CBC3_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* The Ephemeral DH ciphers */
+/* Cipher 11 */
+	{
+	1,
+	SSL3_TXT_EDH_DSS_DES_40_CBC_SHA,
+	SSL3_CK_EDH_DSS_DES_40_CBC_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	56,
+	},
+
+/* Cipher 12 */
+	{
+	1,
+	SSL3_TXT_EDH_DSS_DES_64_CBC_SHA,
+	SSL3_CK_EDH_DSS_DES_64_CBC_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 13 */
+	{
+	1,
+	SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA,
+	SSL3_CK_EDH_DSS_DES_192_CBC3_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* Cipher 14 */
+	{
+	1,
+	SSL3_TXT_EDH_RSA_DES_40_CBC_SHA,
+	SSL3_CK_EDH_RSA_DES_40_CBC_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	56,
+	},
+
+/* Cipher 15 */
+	{
+	1,
+	SSL3_TXT_EDH_RSA_DES_64_CBC_SHA,
+	SSL3_CK_EDH_RSA_DES_64_CBC_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 16 */
+	{
+	1,
+	SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA,
+	SSL3_CK_EDH_RSA_DES_192_CBC3_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* Cipher 17 */
+	{
+	1,
+	SSL3_TXT_ADH_RC4_40_MD5,
+	SSL3_CK_ADH_RC4_40_MD5,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_RC4,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	128,
+	},
+
+/* Cipher 18 */
+	{
+	1,
+	SSL3_TXT_ADH_RC4_128_MD5,
+	SSL3_CK_ADH_RC4_128_MD5,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_RC4,
+	SSL_MD5,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+/* Cipher 19 */
+	{
+	1,
+	SSL3_TXT_ADH_DES_40_CBC_SHA,
+	SSL3_CK_ADH_DES_40_CBC_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_EXPORT|SSL_EXP40,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	40,
+	128,
+	},
+
+/* Cipher 1A */
+	{
+	1,
+	SSL3_TXT_ADH_DES_64_CBC_SHA,
+	SSL3_CK_ADH_DES_64_CBC_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_LOW,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+/* Cipher 1B */
+	{
+	1,
+	SSL3_TXT_ADH_DES_192_CBC_SHA,
+	SSL3_CK_ADH_DES_192_CBC_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+/* Fortezza ciphersuite from SSL 3.0 spec */
+#if 0
+/* Cipher 1C */
+	{
+	0,
+	SSL3_TXT_FZA_DMS_NULL_SHA,
+	SSL3_CK_FZA_DMS_NULL_SHA,
+	SSL_kFZA,
+	SSL_aFZA,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_STRONG_NONE,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+/* Cipher 1D */
+	{
+	0,
+	SSL3_TXT_FZA_DMS_FZA_SHA,
+	SSL3_CK_FZA_DMS_FZA_SHA,
+	SSL_kFZA,
+	SSL_aFZA,
+	SSL_eFZA,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_STRONG_NONE,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+/* Cipher 1E */
+	{
+	0,
+	SSL3_TXT_FZA_DMS_RC4_SHA,
+	SSL3_CK_FZA_DMS_RC4_SHA,
+	SSL_kFZA,
+	SSL_aFZA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_SSLV3,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+#endif
+
+/* New AES ciphersuites */
+/* Cipher 2F */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_128_SHA,
+	TLS1_CK_RSA_WITH_AES_128_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+/* Cipher 30 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_128_SHA,
+	TLS1_CK_DH_DSS_WITH_AES_128_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+/* Cipher 31 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_128_SHA,
+	TLS1_CK_DH_RSA_WITH_AES_128_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+/* Cipher 32 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_128_SHA,
+	TLS1_CK_DHE_DSS_WITH_AES_128_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+/* Cipher 33 */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_128_SHA,
+	TLS1_CK_DHE_RSA_WITH_AES_128_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+/* Cipher 34 */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_128_SHA,
+	TLS1_CK_ADH_WITH_AES_128_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+/* Cipher 35 */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_256_SHA,
+	TLS1_CK_RSA_WITH_AES_256_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+/* Cipher 36 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_256_SHA,
+	TLS1_CK_DH_DSS_WITH_AES_256_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+/* Cipher 37 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_256_SHA,
+	TLS1_CK_DH_RSA_WITH_AES_256_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+/* Cipher 38 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_256_SHA,
+	TLS1_CK_DHE_DSS_WITH_AES_256_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+/* Cipher 39 */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_256_SHA,
+	TLS1_CK_DHE_RSA_WITH_AES_256_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 3A */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_256_SHA,
+	TLS1_CK_ADH_WITH_AES_256_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* TLS v1.2 ciphersuites */
+	/* Cipher 3B */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_NULL_SHA256,
+	TLS1_CK_RSA_WITH_NULL_SHA256,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eNULL,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher 3C */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_128_SHA256,
+	TLS1_CK_RSA_WITH_AES_128_SHA256,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 3D */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_256_SHA256,
+	TLS1_CK_RSA_WITH_AES_256_SHA256,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 3E */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_128_SHA256,
+	TLS1_CK_DH_DSS_WITH_AES_128_SHA256,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 3F */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_128_SHA256,
+	TLS1_CK_DH_RSA_WITH_AES_128_SHA256,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 40 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256,
+	TLS1_CK_DHE_DSS_WITH_AES_128_SHA256,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+#ifndef OPENSSL_NO_CAMELLIA
+	/* Camellia ciphersuites from RFC4132 (128-bit portion) */
+
+	/* Cipher 41 */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 42 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 43 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 44 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 45 */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 46 */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA,
+	TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_CAMELLIA128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+#endif /* OPENSSL_NO_CAMELLIA */
+
+#if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES
+	/* New TLS Export CipherSuites from expired ID */
+#if 0
+	/* Cipher 60 */
+	{
+	1,
+	TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5,
+	TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_MD5,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	128,
+	},
+
+	/* Cipher 61 */
+	{
+	1,
+	TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5,
+	TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC2,
+	SSL_MD5,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	128,
+	},
+#endif
+
+	/* Cipher 62 */
+	{
+	1,
+	TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+	TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+	/* Cipher 63 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+	TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	56,
+	},
+
+	/* Cipher 64 */
+	{
+	1,
+	TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA,
+	TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	128,
+	},
+
+	/* Cipher 65 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
+	TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_EXPORT|SSL_EXP56,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	56,
+	128,
+	},
+
+	/* Cipher 66 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA,
+	TLS1_CK_DHE_DSS_WITH_RC4_128_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+#endif
+
+	/* TLS v1.2 ciphersuites */
+	/* Cipher 67 */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256,
+	TLS1_CK_DHE_RSA_WITH_AES_128_SHA256,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 68 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_256_SHA256,
+	TLS1_CK_DH_DSS_WITH_AES_256_SHA256,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 69 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_256_SHA256,
+	TLS1_CK_DH_RSA_WITH_AES_256_SHA256,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 6A */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256,
+	TLS1_CK_DHE_DSS_WITH_AES_256_SHA256,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 6B */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256,
+	TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 6C */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_128_SHA256,
+	TLS1_CK_ADH_WITH_AES_128_SHA256,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 6D */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_256_SHA256,
+	TLS1_CK_ADH_WITH_AES_256_SHA256,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES256,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* GOST Ciphersuites */
+
+	{
+	1,
+	"GOST94-GOST89-GOST89",
+	0x3000080,
+	SSL_kGOST,
+	SSL_aGOST94,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_GOST94|TLS1_PRF_GOST94|TLS1_STREAM_MAC,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST2001-GOST89-GOST89",
+	0x3000081,
+	SSL_kGOST,
+	SSL_aGOST01,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_GOST94|TLS1_PRF_GOST94|TLS1_STREAM_MAC,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST94-NULL-GOST94",
+	0x3000082,
+	SSL_kGOST,
+	SSL_aGOST94,
+	SSL_eNULL,
+	SSL_GOST94,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE,
+	SSL_HANDSHAKE_MAC_GOST94|TLS1_PRF_GOST94,
+	0,
+	0
+	},
+	{
+	1,
+	"GOST2001-NULL-GOST94",
+	0x3000083,
+	SSL_kGOST,
+	SSL_aGOST01,
+	SSL_eNULL,
+	SSL_GOST94,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE,
+	SSL_HANDSHAKE_MAC_GOST94|TLS1_PRF_GOST94,
+	0,
+	0
+	},
+
+#ifndef OPENSSL_NO_CAMELLIA
+	/* Camellia ciphersuites from RFC4132 (256-bit portion) */
+
+	/* Cipher 84 */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+	/* Cipher 85 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 86 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 87 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 88 */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher 89 */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA,
+	TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_CAMELLIA256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+#endif /* OPENSSL_NO_CAMELLIA */
+
+#ifndef OPENSSL_NO_PSK
+	/* Cipher 8A */
+	{
+	1,
+	TLS1_TXT_PSK_WITH_RC4_128_SHA,
+	TLS1_CK_PSK_WITH_RC4_128_SHA,
+	SSL_kPSK,
+	SSL_aPSK,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 8B */
+	{
+	1,
+	TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA,
+	TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA,
+	SSL_kPSK,
+	SSL_aPSK,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher 8C */
+	{
+	1,
+	TLS1_TXT_PSK_WITH_AES_128_CBC_SHA,
+	TLS1_CK_PSK_WITH_AES_128_CBC_SHA,
+	SSL_kPSK,
+	SSL_aPSK,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 8D */
+	{
+	1,
+	TLS1_TXT_PSK_WITH_AES_256_CBC_SHA,
+	TLS1_CK_PSK_WITH_AES_256_CBC_SHA,
+	SSL_kPSK,
+	SSL_aPSK,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+#endif  /* OPENSSL_NO_PSK */
+
+#ifndef OPENSSL_NO_SEED
+	/* SEED ciphersuites from RFC4162 */
+
+	/* Cipher 96 */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_SEED_SHA,
+	TLS1_CK_RSA_WITH_SEED_SHA,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 97 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_SEED_SHA,
+	TLS1_CK_DH_DSS_WITH_SEED_SHA,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 98 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_SEED_SHA,
+	TLS1_CK_DH_RSA_WITH_SEED_SHA,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 99 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_SEED_SHA,
+	TLS1_CK_DHE_DSS_WITH_SEED_SHA,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 9A */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_SEED_SHA,
+	TLS1_CK_DHE_RSA_WITH_SEED_SHA,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 9B */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_SEED_SHA,
+	TLS1_CK_ADH_WITH_SEED_SHA,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_SEED,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+#endif /* OPENSSL_NO_SEED */
+
+	/* GCM ciphersuites from RFC5288 */
+
+	/* Cipher 9C */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_RSA_WITH_AES_128_GCM_SHA256,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher 9D */
+	{
+	1,
+	TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_RSA_WITH_AES_256_GCM_SHA384,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher 9E */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher 9F */
+	{
+	1,
+	TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384,
+	SSL_kEDH,
+	SSL_aRSA,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher A0 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher A1 */
+	{
+	1,
+	TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384,
+	SSL_kDHr,
+	SSL_aDH,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher A2 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher A3 */
+	{
+	1,
+	TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384,
+	SSL_kEDH,
+	SSL_aDSS,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher A4 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher A5 */
+	{
+	1,
+	TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384,
+	SSL_kDHd,
+	SSL_aDH,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher A6 */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ADH_WITH_AES_128_GCM_SHA256,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher A7 */
+	{
+	1,
+	TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_ADH_WITH_AES_256_GCM_SHA384,
+	SSL_kEDH,
+	SSL_aNULL,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+	{
+	1,
+	"SCSV",
+	SSL3_CK_SCSV,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0
+	},
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	/* Cipher C001 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA,
+	TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher C002 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA,
+	TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C003 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA,
+	TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher C004 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C005 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher C006 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA,
+	TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher C007 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA,
+	TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C008 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
+	TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher C009 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C00A */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher C00B */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_NULL_SHA,
+	TLS1_CK_ECDH_RSA_WITH_NULL_SHA,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher C00C */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA,
+	TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C00D */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA,
+	TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher C00E */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA,
+	TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C00F */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA,
+	TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher C010 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA,
+	TLS1_CK_ECDHE_RSA_WITH_NULL_SHA,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher C011 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA,
+	TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C012 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
+	TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher C013 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+	TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C014 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+	TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+
+	/* Cipher C015 */
+	{
+	1,
+	TLS1_TXT_ECDH_anon_WITH_NULL_SHA,
+	TLS1_CK_ECDH_anon_WITH_NULL_SHA,
+	SSL_kEECDH,
+	SSL_aNULL,
+	SSL_eNULL,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_STRONG_NONE|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	0,
+	0,
+	},
+
+	/* Cipher C016 */
+	{
+	1,
+	TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA,
+	TLS1_CK_ECDH_anon_WITH_RC4_128_SHA,
+	SSL_kEECDH,
+	SSL_aNULL,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C017 */
+	{
+	1,
+	TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA,
+	TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA,
+	SSL_kEECDH,
+	SSL_aNULL,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	168,
+	168,
+	},
+
+	/* Cipher C018 */
+	{
+	1,
+	TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA,
+	TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aNULL,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher C019 */
+	{
+	1,
+	TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA,
+	TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA,
+	SSL_kEECDH,
+	SSL_aNULL,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+#endif	/* OPENSSL_NO_ECDH */
+
+#ifndef OPENSSL_NO_ECDH
+
+	/* HMAC based TLS v1.2 ciphersuites from RFC5289 */
+
+	/* Cipher C023 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C024 */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES256,
+	SSL_SHA384,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C025 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C026 */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES256,
+	SSL_SHA384,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C027 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256,
+	TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C028 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384,
+	TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA384,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C029 */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256,
+	TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C02A */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384,
+	TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES256,
+	SSL_SHA384,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* GCM based TLS v1.2 ciphersuites from RFC5289 */
+
+	/* Cipher C02B */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C02C */
+	{
+	1,
+	TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+	SSL_kEECDH,
+	SSL_aECDSA,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C02D */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C02E */
+	{
+	1,
+	TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+	SSL_kECDHe,
+	SSL_aECDH,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C02F */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C030 */
+	{
+	1,
+	TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+	SSL_kEECDH,
+	SSL_aRSA,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+	/* Cipher C031 */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C032 */
+	{
+	1,
+	TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+	TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+	SSL_kECDHr,
+	SSL_aECDH,
+	SSL_AES256GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+
+#endif /* OPENSSL_NO_ECDH */
+
+
+#ifdef TEMP_GOST_TLS
+/* Cipher FF00 */
+	{
+	1,
+	"GOST-MD5",
+	0x0300ff00,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_MD5,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+	{
+	1,
+	"GOST-GOST94",
+	0x0300ff01,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST94,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST-GOST89MAC",
+	0x0300ff02,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST-GOST89STREAM",
+	0x0300ff03,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF|TLS1_STREAM_MAC,
+	256,
+	256
+	},
+#endif
+
+/* end of list */
+	};
+
+SSL3_ENC_METHOD SSLv3_enc_data={
+	ssl3_enc,
+	n_ssl3_mac,
+	ssl3_setup_key_block,
+	ssl3_generate_master_secret,
+	ssl3_change_cipher_state,
+	ssl3_final_finish_mac,
+	MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
+	ssl3_cert_verify_mac,
+	SSL3_MD_CLIENT_FINISHED_CONST,4,
+	SSL3_MD_SERVER_FINISHED_CONST,4,
+	ssl3_alert_code,
+	(int (*)(SSL *, unsigned char *, size_t, const char *,
+		 size_t, const unsigned char *, size_t,
+		 int use_context))ssl_undefined_function,
+	0,
+	SSL3_HM_HEADER_LENGTH,
+	ssl3_set_handshake_header,
+	ssl3_handshake_write
+	};
+
+long ssl3_default_timeout(void)
+	{
+	/* 2 hours, the 24 hours mentioned in the SSLv3 spec
+	 * is way too long for http, the cache would over fill */
+	return(60*60*2);
+	}
+
+int ssl3_num_ciphers(void)
+	{
+	return(SSL3_NUM_CIPHERS);
+	}
+
+const SSL_CIPHER *ssl3_get_cipher(unsigned int u)
+	{
+	if (u < SSL3_NUM_CIPHERS)
+		return(&(ssl3_ciphers[SSL3_NUM_CIPHERS-1-u]));
+	else
+		return(NULL);
+	}
+
+int ssl3_pending(const SSL *s)
+	{
+	if (s->rstate == SSL_ST_READ_BODY)
+		return 0;
+	
+	return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length : 0;
+	}
+
+void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len)
+	{
+	unsigned char *p = (unsigned char *)s->init_buf->data;
+	*(p++) = htype;
+	l2n3(len, p);
+	s->init_num = (int)len + SSL3_HM_HEADER_LENGTH;
+	s->init_off = 0;
+	}
+
+int ssl3_handshake_write(SSL *s)
+	{
+	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	}
+
+int ssl3_new(SSL *s)
+	{
+	SSL3_STATE *s3;
+
+	if ((s3=OPENSSL_malloc(sizeof *s3)) == NULL) goto err;
+	memset(s3,0,sizeof *s3);
+	memset(s3->rrec.seq_num,0,sizeof(s3->rrec.seq_num));
+	memset(s3->wrec.seq_num,0,sizeof(s3->wrec.seq_num));
+
+	s->s3=s3;
+
+	s->method->ssl_clear(s);
+	return(1);
+err:
+	return(0);
+	}
+
+void ssl3_free(SSL *s)
+	{
+	if(s == NULL)
+	    return;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->client_opaque_prf_input != NULL)
+		OPENSSL_free(s->s3->client_opaque_prf_input);
+	if (s->s3->server_opaque_prf_input != NULL)
+		OPENSSL_free(s->s3->server_opaque_prf_input);
+#endif
+
+	ssl3_cleanup_key_block(s);
+	if (s->s3->rbuf.buf != NULL)
+		ssl3_release_read_buffer(s);
+	if (s->s3->wbuf.buf != NULL)
+		ssl3_release_write_buffer(s);
+	if (s->s3->rrec.comp != NULL)
+		OPENSSL_free(s->s3->rrec.comp);
+#ifndef OPENSSL_NO_DH
+	if (s->s3->tmp.dh != NULL)
+		DH_free(s->s3->tmp.dh);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if (s->s3->tmp.ecdh != NULL)
+		EC_KEY_free(s->s3->tmp.ecdh);
+#endif
+
+	if (s->s3->tmp.ca_names != NULL)
+		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
+	if (s->s3->handshake_buffer) {
+		BIO_free(s->s3->handshake_buffer);
+	}
+	if (s->s3->handshake_dgst) ssl3_free_digest_list(s);
+#ifndef OPENSSL_NO_TLSEXT
+	if (s->s3->alpn_selected)
+		OPENSSL_free(s->s3->alpn_selected);
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (s->s3->tlsext_authz_client_types != NULL)
+		OPENSSL_free(s->s3->tlsext_authz_client_types);
+	if (s->s3->tlsext_custom_types != NULL)
+		OPENSSL_free(s->s3->tlsext_custom_types);
+#endif
+	OPENSSL_cleanse(s->s3,sizeof *s->s3);
+	OPENSSL_free(s->s3);
+	s->s3=NULL;
+	}
+
+void ssl3_clear(SSL *s)
+	{
+	unsigned char *rp,*wp;
+	size_t rlen, wlen;
+	int init_extra;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->client_opaque_prf_input != NULL)
+		OPENSSL_free(s->s3->client_opaque_prf_input);
+	s->s3->client_opaque_prf_input = NULL;
+	if (s->s3->server_opaque_prf_input != NULL)
+		OPENSSL_free(s->s3->server_opaque_prf_input);
+	s->s3->server_opaque_prf_input = NULL;
+#endif
+
+	ssl3_cleanup_key_block(s);
+	if (s->s3->tmp.ca_names != NULL)
+		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
+
+	if (s->s3->rrec.comp != NULL)
+		{
+		OPENSSL_free(s->s3->rrec.comp);
+		s->s3->rrec.comp=NULL;
+		}
+#ifndef OPENSSL_NO_DH
+	if (s->s3->tmp.dh != NULL)
+		{
+		DH_free(s->s3->tmp.dh);
+		s->s3->tmp.dh = NULL;
+		}
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if (s->s3->tmp.ecdh != NULL)
+		{
+		EC_KEY_free(s->s3->tmp.ecdh);
+		s->s3->tmp.ecdh = NULL;
+		}
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	if (s->s3->tlsext_authz_client_types != NULL)
+		{
+		OPENSSL_free(s->s3->tlsext_authz_client_types);
+		s->s3->tlsext_authz_client_types = NULL;
+		}
+	if (s->s3->tlsext_custom_types != NULL)
+		{
+		OPENSSL_free(s->s3->tlsext_custom_types);
+		s->s3->tlsext_custom_types = NULL;
+		}
+	s->s3->tlsext_custom_types_count = 0;	
+#ifndef OPENSSL_NO_EC
+	s->s3->is_probably_safari = 0;
+#endif /* !OPENSSL_NO_EC */
+#endif /* !OPENSSL_NO_TLSEXT */
+
+	rp = s->s3->rbuf.buf;
+	wp = s->s3->wbuf.buf;
+	rlen = s->s3->rbuf.len;
+ 	wlen = s->s3->wbuf.len;
+	init_extra = s->s3->init_extra;
+	if (s->s3->handshake_buffer) {
+		BIO_free(s->s3->handshake_buffer);
+		s->s3->handshake_buffer = NULL;
+	}
+	if (s->s3->handshake_dgst) {
+		ssl3_free_digest_list(s);
+	}	
+
+#if !defined(OPENSSL_NO_TLSEXT)
+	if (s->s3->alpn_selected)
+		{
+		free(s->s3->alpn_selected);
+		s->s3->alpn_selected = NULL;
+		}
+#endif
+	memset(s->s3,0,sizeof *s->s3);
+	s->s3->rbuf.buf = rp;
+	s->s3->wbuf.buf = wp;
+	s->s3->rbuf.len = rlen;
+ 	s->s3->wbuf.len = wlen;
+	s->s3->init_extra = init_extra;
+
+	ssl_free_wbio_buffer(s);
+
+	s->packet_length=0;
+	s->s3->renegotiate=0;
+	s->s3->total_renegotiations=0;
+	s->s3->num_renegotiations=0;
+	s->s3->in_read_app_data=0;
+	s->version=SSL3_VERSION;
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+	if (s->next_proto_negotiated)
+		{
+		OPENSSL_free(s->next_proto_negotiated);
+		s->next_proto_negotiated = NULL;
+		s->next_proto_negotiated_len = 0;
+		}
+#endif
+	}
+
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len);
+
+long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
+	{
+	int ret=0;
+
+#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_RSA)
+	if (
+#ifndef OPENSSL_NO_RSA
+	    cmd == SSL_CTRL_SET_TMP_RSA ||
+	    cmd == SSL_CTRL_SET_TMP_RSA_CB ||
+#endif
+#ifndef OPENSSL_NO_DSA
+	    cmd == SSL_CTRL_SET_TMP_DH ||
+	    cmd == SSL_CTRL_SET_TMP_DH_CB ||
+#endif
+		0)
+		{
+		if (!ssl_cert_inst(&s->cert))
+		    	{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_MALLOC_FAILURE);
+			return(0);
+			}
+		}
+#endif
+
+	switch (cmd)
+		{
+	case SSL_CTRL_GET_SESSION_REUSED:
+		ret=s->hit;
+		break;
+	case SSL_CTRL_GET_CLIENT_CERT_REQUEST:
+		break;
+	case SSL_CTRL_GET_NUM_RENEGOTIATIONS:
+		ret=s->s3->num_renegotiations;
+		break;
+	case SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS:
+		ret=s->s3->num_renegotiations;
+		s->s3->num_renegotiations=0;
+		break;
+	case SSL_CTRL_GET_TOTAL_RENEGOTIATIONS:
+		ret=s->s3->total_renegotiations;
+		break;
+	case SSL_CTRL_GET_FLAGS:
+		ret=(int)(s->s3->flags);
+		break;
+#ifndef OPENSSL_NO_RSA
+	case SSL_CTRL_NEED_TMP_RSA:
+		if ((s->cert != NULL) && (s->cert->rsa_tmp == NULL) &&
+		    ((s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) ||
+		     (EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey) > (512/8))))
+			ret = 1;
+		break;
+	case SSL_CTRL_SET_TMP_RSA:
+		{
+			RSA *rsa = (RSA *)parg;
+			if (rsa == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_PASSED_NULL_PARAMETER);
+				return(ret);
+				}
+			if ((rsa = RSAPrivateKey_dup(rsa)) == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_RSA_LIB);
+				return(ret);
+				}
+			if (s->cert->rsa_tmp != NULL)
+				RSA_free(s->cert->rsa_tmp);
+			s->cert->rsa_tmp = rsa;
+			ret = 1;
+		}
+		break;
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_DH
+	case SSL_CTRL_SET_TMP_DH:
+		{
+			DH *dh = (DH *)parg;
+			if (dh == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_PASSED_NULL_PARAMETER);
+				return(ret);
+				}
+			if ((dh = DHparams_dup(dh)) == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_DH_LIB);
+				return(ret);
+				}
+			if (!(s->options & SSL_OP_SINGLE_DH_USE))
+				{
+				if (!DH_generate_key(dh))
+					{
+					DH_free(dh);
+					OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_DH_LIB);
+					return(ret);
+					}
+				}
+			if (s->cert->dh_tmp != NULL)
+				DH_free(s->cert->dh_tmp);
+			s->cert->dh_tmp = dh;
+			ret = 1;
+		}
+		break;
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH:
+		{
+		EC_KEY *ecdh = NULL;
+ 			
+		if (parg == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_PASSED_NULL_PARAMETER);
+			return(ret);
+			}
+		if (!EC_KEY_up_ref((EC_KEY *)parg))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_ECDH_LIB);
+			return(ret);
+			}
+		ecdh = (EC_KEY *)parg;
+		if (!(s->options & SSL_OP_SINGLE_ECDH_USE))
+			{
+			if (!EC_KEY_generate_key(ecdh))
+				{
+				EC_KEY_free(ecdh);
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_ECDH_LIB);
+				return(ret);
+				}
+			}
+		if (s->cert->ecdh_tmp != NULL)
+			EC_KEY_free(s->cert->ecdh_tmp);
+		s->cert->ecdh_tmp = ecdh;
+		ret = 1;
+		}
+		break;
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(ret);
+		}
+		break;
+#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_HOSTNAME:
+ 		if (larg == TLSEXT_NAMETYPE_host_name)
+			{
+			if (s->tlsext_hostname != NULL) 
+				OPENSSL_free(s->tlsext_hostname);
+			s->tlsext_hostname = NULL;
+
+			ret = 1;
+			if (parg == NULL) 
+				break;
+			if (strlen((char *)parg) > TLSEXT_MAXLEN_host_name)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+				return 0;
+				}
+			if ((s->tlsext_hostname = BUF_strdup((char *)parg)) == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, ERR_R_INTERNAL_ERROR);
+				return 0;
+				}
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
+			return 0;
+			}
+ 		break;
+	case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
+		s->tlsext_debug_arg=parg;
+		ret = 1;
+		break;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT:
+		if (larg > 12288) /* actual internal limit is 2^16 for the complete hello message
+		                   * (including the cert chain and everything) */
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctrl, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG);
+			break;
+			}
+		if (s->tlsext_opaque_prf_input != NULL)
+			OPENSSL_free(s->tlsext_opaque_prf_input);
+		if ((size_t)larg == 0)
+			s->tlsext_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+		else
+			s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg);
+		if (s->tlsext_opaque_prf_input != NULL)
+			{
+			s->tlsext_opaque_prf_input_len = (size_t)larg;
+			ret = 1;
+			}
+		else
+			s->tlsext_opaque_prf_input_len = 0;
+		break;
+#endif
+
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
+		s->tlsext_status_type=larg;
+		ret = 1;
+		break;
+
+	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS:
+		*(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts;
+		ret = 1;
+		break;
+
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS:
+		s->tlsext_ocsp_exts = parg;
+		ret = 1;
+		break;
+
+	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS:
+		*(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids;
+		ret = 1;
+		break;
+
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS:
+		s->tlsext_ocsp_ids = parg;
+		ret = 1;
+		break;
+
+	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP:
+		*(unsigned char **)parg = s->tlsext_ocsp_resp;
+		return s->tlsext_ocsp_resplen;
+		
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP:
+		if (s->tlsext_ocsp_resp)
+			OPENSSL_free(s->tlsext_ocsp_resp);
+		s->tlsext_ocsp_resp = parg;
+		s->tlsext_ocsp_resplen = larg;
+		ret = 1;
+		break;
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	case SSL_CTRL_TLS_EXT_SEND_HEARTBEAT:
+		if (SSL_IS_DTLS(s))
+			ret = dtls1_heartbeat(s);
+		else
+			ret = tls1_heartbeat(s);
+		break;
+
+	case SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING:
+		ret = s->tlsext_hb_pending;
+		break;
+
+	case SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS:
+		if (larg)
+			s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_RECV_REQUESTS;
+		else
+			s->tlsext_heartbeat &= ~SSL_TLSEXT_HB_DONT_RECV_REQUESTS;
+		ret = 1;
+		break;
+#endif
+
+#endif /* !OPENSSL_NO_TLSEXT */
+
+	case SSL_CTRL_CHAIN:
+		if (larg)
+			return ssl_cert_set1_chain(s->cert,
+						(STACK_OF (X509) *)parg);
+		else
+			return ssl_cert_set0_chain(s->cert,
+						(STACK_OF (X509) *)parg);
+
+	case SSL_CTRL_CHAIN_CERT:
+		if (larg)
+			return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg);
+		else
+			return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg);
+
+	case SSL_CTRL_GET_CHAIN_CERTS:
+		*(STACK_OF(X509) **)parg = s->cert->key->chain;
+		break;
+
+	case SSL_CTRL_SELECT_CURRENT_CERT:
+		return ssl_cert_select_current(s->cert, (X509 *)parg);
+
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_GET_CURVES:
+		{
+		unsigned char *clist;
+		size_t clistlen;
+		if (!s->session)
+			return 0;
+		clist = s->session->tlsext_ellipticcurvelist;
+		clistlen = s->session->tlsext_ellipticcurvelist_length / 2;
+		if (parg)
+			{
+			size_t i;
+			int *cptr = parg;
+			unsigned int cid, nid;
+			for (i = 0; i < clistlen; i++)
+				{
+				n2s(clist, cid);
+				nid = tls1_ec_curve_id2nid(cid);
+				if (nid != 0)
+					cptr[i] = nid;
+				else
+					cptr[i] = TLSEXT_nid_unknown | cid;
+				}
+			}
+		return (int)clistlen;
+		}
+
+	case SSL_CTRL_SET_CURVES:
+		return tls1_set_curves(&s->tlsext_ellipticcurvelist,
+					&s->tlsext_ellipticcurvelist_length,
+								parg, larg);
+
+	case SSL_CTRL_GET_SHARED_CURVE:
+		return tls1_shared_curve(s, larg);
+
+	case SSL_CTRL_SET_ECDH_AUTO:
+		s->cert->ecdh_tmp_auto = larg;
+		return 1;
+#endif
+	case SSL_CTRL_SET_SIGALGS:
+		return tls1_set_sigalgs(s->cert, parg, larg, 0);
+
+	case SSL_CTRL_SET_CLIENT_SIGALGS:
+		return tls1_set_sigalgs(s->cert, parg, larg, 1);
+
+	case SSL_CTRL_GET_CLIENT_CERT_TYPES:
+		{
+		const unsigned char **pctype = parg;
+		if (s->server || !s->s3->tmp.cert_req)
+			return 0;
+		if (s->cert->ctypes)
+			{
+			if (pctype)
+				*pctype = s->cert->ctypes;
+			return (int)s->cert->ctype_num;
+			}
+		if (pctype)
+			*pctype = (unsigned char *)s->s3->tmp.ctype;
+		return s->s3->tmp.ctype_num;
+		}
+
+	case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+		if (!s->server)
+			return 0;
+		return ssl3_set_req_cert_type(s->cert, parg, larg);
+
+	case SSL_CTRL_BUILD_CERT_CHAIN:
+		return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg);
+
+	case SSL_CTRL_SET_VERIFY_CERT_STORE:
+		return ssl_cert_set_cert_store(s->cert, parg, 0, larg);
+
+	case SSL_CTRL_SET_CHAIN_CERT_STORE:
+		return ssl_cert_set_cert_store(s->cert, parg, 1, larg);
+
+	case SSL_CTRL_GET_PEER_SIGNATURE_NID:
+		if (SSL_USE_SIGALGS(s))
+			{
+			if (s->session && s->session->sess_cert)
+				{
+				const EVP_MD *sig;
+				sig = s->session->sess_cert->peer_key->digest;
+				if (sig)
+					{
+					*(int *)parg = EVP_MD_type(sig);
+					return 1;
+					}
+				}
+			return 0;
+			}
+		/* Might want to do something here for other versions */
+		else
+			return 0;
+
+	case SSL_CTRL_GET_SERVER_TMP_KEY:
+		if (s->server || !s->session || !s->session->sess_cert)
+			return 0;
+		else
+			{
+			SESS_CERT *sc;
+			EVP_PKEY *ptmp;
+			int rv = 0;
+			sc = s->session->sess_cert;
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC)
+			if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp
+							&& !sc->peer_ecdh_tmp)
+				return 0;
+#endif
+			ptmp = EVP_PKEY_new();
+			if (!ptmp)
+				return 0;
+			if (0);
+#ifndef OPENSSL_NO_RSA
+			else if (sc->peer_rsa_tmp)
+				rv = EVP_PKEY_set1_RSA(ptmp, sc->peer_rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+			else if (sc->peer_dh_tmp)
+				rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+			else if (sc->peer_ecdh_tmp)
+				rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp);
+#endif
+			if (rv)
+				{
+				*(EVP_PKEY **)parg = ptmp;
+				return 1;
+				}
+			EVP_PKEY_free(ptmp);
+			return 0;
+			}
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_GET_EC_POINT_FORMATS:
+		{
+		SSL_SESSION *sess = s->session;
+		const unsigned char **pformat = parg;
+		if (!sess || !sess->tlsext_ecpointformatlist)
+			return 0;
+		*pformat = sess->tlsext_ecpointformatlist;
+		return (int)sess->tlsext_ecpointformatlist_length;
+		}
+#endif
+	default:
+		break;
+		}
+	return(ret);
+	}
+
+long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
+	{
+	int ret=0;
+
+#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_RSA)
+	if (
+#ifndef OPENSSL_NO_RSA
+	    cmd == SSL_CTRL_SET_TMP_RSA_CB ||
+#endif
+#ifndef OPENSSL_NO_DSA
+	    cmd == SSL_CTRL_SET_TMP_DH_CB ||
+#endif
+		0)
+		{
+		if (!ssl_cert_inst(&s->cert))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_callback_ctrl, ERR_R_MALLOC_FAILURE);
+			return(0);
+			}
+		}
+#endif
+
+	switch (cmd)
+		{
+#ifndef OPENSSL_NO_RSA
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		s->cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_DH
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_DEBUG_CB:
+		s->tlsext_debug_cb=(void (*)(SSL *,int ,int,
+					unsigned char *, int, void *))fp;
+		break;
+#endif
+	default:
+		break;
+		}
+	return(ret);
+	}
+
+long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+	{
+	CERT *cert;
+
+	cert=ctx->cert;
+
+	switch (cmd)
+		{
+#ifndef OPENSSL_NO_RSA
+	case SSL_CTRL_NEED_TMP_RSA:
+		if (	(cert->rsa_tmp == NULL) &&
+			((cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) ||
+			 (EVP_PKEY_size(cert->pkeys[SSL_PKEY_RSA_ENC].privatekey) > (512/8)))
+			)
+			return(1);
+		else
+			return(0);
+		/* break; */
+	case SSL_CTRL_SET_TMP_RSA:
+		{
+		RSA *rsa;
+		int i;
+
+		rsa=(RSA *)parg;
+		i=1;
+		if (rsa == NULL)
+			i=0;
+		else
+			{
+			if ((rsa=RSAPrivateKey_dup(rsa)) == NULL)
+				i=0;
+			}
+		if (!i)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_RSA_LIB);
+			return(0);
+			}
+		else
+			{
+			if (cert->rsa_tmp != NULL)
+				RSA_free(cert->rsa_tmp);
+			cert->rsa_tmp=rsa;
+			return(1);
+			}
+		}
+		/* break; */
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_DH
+	case SSL_CTRL_SET_TMP_DH:
+		{
+		DH *new=NULL,*dh;
+
+		dh=(DH *)parg;
+		if ((new=DHparams_dup(dh)) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_DH_LIB);
+			return 0;
+			}
+		if (!(ctx->options & SSL_OP_SINGLE_DH_USE))
+			{
+			if (!DH_generate_key(new))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_DH_LIB);
+				DH_free(new);
+				return 0;
+				}
+			}
+		if (cert->dh_tmp != NULL)
+			DH_free(cert->dh_tmp);
+		cert->dh_tmp=new;
+		return 1;
+		}
+		/*break; */
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH:
+		{
+		EC_KEY *ecdh = NULL;
+ 			
+		if (parg == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_ECDH_LIB);
+			return 0;
+			}
+		ecdh = EC_KEY_dup((EC_KEY *)parg);
+		if (ecdh == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_EC_LIB);
+			return 0;
+			}
+		if (!(ctx->options & SSL_OP_SINGLE_ECDH_USE))
+			{
+			if (!EC_KEY_generate_key(ecdh))
+				{
+				EC_KEY_free(ecdh);
+				OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_ECDH_LIB);
+				return 0;
+				}
+			}
+
+		if (cert->ecdh_tmp != NULL)
+			{
+			EC_KEY_free(cert->ecdh_tmp);
+			}
+		cert->ecdh_tmp = ecdh;
+		return 1;
+		}
+		/* break; */
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return(0);
+		}
+		break;
+#endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG:
+		ctx->tlsext_servername_arg=parg;
+		break;
+	case SSL_CTRL_SET_TLSEXT_TICKET_KEYS:
+	case SSL_CTRL_GET_TLSEXT_TICKET_KEYS:
+		{
+		unsigned char *keys = parg;
+		if (!keys)
+			return 48;
+		if (larg != 48)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_ctx_ctrl, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+			return 0;
+			}
+		if (cmd == SSL_CTRL_SET_TLSEXT_TICKET_KEYS)
+			{
+			memcpy(ctx->tlsext_tick_key_name, keys, 16);
+			memcpy(ctx->tlsext_tick_hmac_key, keys + 16, 16);
+			memcpy(ctx->tlsext_tick_aes_key, keys + 32, 16);
+			}
+		else
+			{
+			memcpy(keys, ctx->tlsext_tick_key_name, 16);
+			memcpy(keys + 16, ctx->tlsext_tick_hmac_key, 16);
+			memcpy(keys + 32, ctx->tlsext_tick_aes_key, 16);
+			}
+		return 1;
+		}
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG:
+		ctx->tlsext_opaque_prf_input_callback_arg = parg;
+		return 1;
+#endif
+
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
+		ctx->tlsext_status_arg=parg;
+		return 1;
+		break;
+
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_SET_CURVES:
+		return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
+					&ctx->tlsext_ellipticcurvelist_length,
+								parg, larg);
+
+	case SSL_CTRL_SET_ECDH_AUTO:
+		ctx->cert->ecdh_tmp_auto = larg;
+		return 1;
+#endif
+	case SSL_CTRL_SET_SIGALGS:
+		return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
+
+	case SSL_CTRL_SET_CLIENT_SIGALGS:
+		return tls1_set_sigalgs(ctx->cert, parg, larg, 1);
+
+	case SSL_CTRL_SET_CLIENT_CERT_TYPES:
+		return ssl3_set_req_cert_type(ctx->cert, parg, larg);
+
+	case SSL_CTRL_BUILD_CERT_CHAIN:
+		return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg);
+
+	case SSL_CTRL_SET_VERIFY_CERT_STORE:
+		return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg);
+
+	case SSL_CTRL_SET_CHAIN_CERT_STORE:
+		return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg);
+
+	case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG:
+		ctx->tlsext_authz_server_audit_proof_cb_arg = parg;
+		break;
+
+#endif /* !OPENSSL_NO_TLSEXT */
+
+	/* A Thawte special :-) */
+	case SSL_CTRL_EXTRA_CHAIN_CERT:
+		if (ctx->extra_certs == NULL)
+			{
+			if ((ctx->extra_certs=sk_X509_new_null()) == NULL)
+				return(0);
+			}
+		sk_X509_push(ctx->extra_certs,(X509 *)parg);
+		break;
+
+	case SSL_CTRL_GET_EXTRA_CHAIN_CERTS:
+		*(STACK_OF(X509) **)parg =  ctx->extra_certs;
+		break;
+
+	case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS:
+		if (ctx->extra_certs)
+			{
+			sk_X509_pop_free(ctx->extra_certs, X509_free);
+			ctx->extra_certs = NULL;
+			}
+		break;
+
+	case SSL_CTRL_CHAIN:
+		if (larg)
+			return ssl_cert_set1_chain(ctx->cert,
+						(STACK_OF (X509) *)parg);
+		else
+			return ssl_cert_set0_chain(ctx->cert,
+						(STACK_OF (X509) *)parg);
+
+	case SSL_CTRL_CHAIN_CERT:
+		if (larg)
+			return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg);
+		else
+			return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
+
+	case SSL_CTRL_GET_CHAIN_CERTS:
+		*(STACK_OF(X509) **)parg = ctx->cert->key->chain;
+		break;
+
+	case SSL_CTRL_SELECT_CURRENT_CERT:
+		return ssl_cert_select_current(ctx->cert, (X509 *)parg);
+
+	default:
+		return(0);
+		}
+	return(1);
+	}
+
+long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
+	{
+	CERT *cert;
+
+	cert=ctx->cert;
+
+	switch (cmd)
+		{
+#ifndef OPENSSL_NO_RSA
+	case SSL_CTRL_SET_TMP_RSA_CB:
+		{
+		cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_DH
+	case SSL_CTRL_SET_TMP_DH_CB:
+		{
+		cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	case SSL_CTRL_SET_TMP_ECDH_CB:
+		{
+		cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
+		}
+		break;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
+		ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
+		break;
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB:
+		ctx->tlsext_opaque_prf_input_callback = (int (*)(SSL *,void *, size_t, void *))fp;
+		break;
+#endif
+
+	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
+		ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp;
+		break;
+
+	case SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB:
+		ctx->tlsext_ticket_key_cb=(int (*)(SSL *,unsigned char  *,
+						unsigned char *,
+						EVP_CIPHER_CTX *,
+						HMAC_CTX *, int))fp;
+		break;
+
+	case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB:
+		ctx->tlsext_authz_server_audit_proof_cb =
+			(int (*)(SSL *, void *))fp;
+		break;
+
+#endif
+	default:
+		return(0);
+		}
+	return(1);
+	}
+
+/* This function needs to check if the ciphers required are actually
+ * available */
+const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p)
+	{
+	SSL_CIPHER c;
+	const SSL_CIPHER *cp;
+	unsigned long id;
+
+	id=0x03000000L|((unsigned long)p[0]<<8L)|(unsigned long)p[1];
+	c.id=id;
+	cp = bsearch(&c, ssl3_ciphers, SSL3_NUM_CIPHERS, sizeof(SSL_CIPHER), ssl_cipher_id_cmp);
+#ifdef DEBUG_PRINT_UNKNOWN_CIPHERSUITES
+if (cp == NULL) fprintf(stderr, "Unknown cipher ID %x\n", (p[0] << 8) | p[1]);
+#endif
+	return cp;
+	}
+
+int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p)
+	{
+	long l;
+
+	if (p != NULL)
+		{
+		l=c->id;
+		if ((l & 0xff000000) != 0x03000000) return(0);
+		p[0]=((unsigned char)(l>> 8L))&0xFF;
+		p[1]=((unsigned char)(l     ))&0xFF;
+		}
+	return(2);
+	}
+
+SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
+	     STACK_OF(SSL_CIPHER) *srvr)
+	{
+	SSL_CIPHER *c,*ret=NULL;
+	STACK_OF(SSL_CIPHER) *prio, *allow;
+	int i,ok;
+	size_t cipher_index;
+	CERT *cert;
+	unsigned long alg_k,alg_a,mask_k,mask_a,emask_k,emask_a;
+
+	/* Let's see which ciphers we can support */
+	cert=s->cert;
+
+#if 0
+	/* Do not set the compare functions, because this may lead to a
+	 * reordering by "id". We want to keep the original ordering.
+	 * We may pay a price in performance during sk_SSL_CIPHER_find(),
+	 * but would have to pay with the price of sk_SSL_CIPHER_dup().
+	 */
+	sk_SSL_CIPHER_set_cmp_func(srvr, ssl_cipher_ptr_id_cmp);
+	sk_SSL_CIPHER_set_cmp_func(clnt, ssl_cipher_ptr_id_cmp);
+#endif
+
+#ifdef CIPHER_DEBUG
+	printf("Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr), (void *)srvr);
+	for(i=0 ; i < sk_SSL_CIPHER_num(srvr) ; ++i)
+		{
+		c=sk_SSL_CIPHER_value(srvr,i);
+		printf("%p:%s\n",(void *)c,c->name);
+		}
+	printf("Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt), (void *)clnt);
+	for(i=0 ; i < sk_SSL_CIPHER_num(clnt) ; ++i)
+	    {
+	    c=sk_SSL_CIPHER_value(clnt,i);
+	    printf("%p:%s\n",(void *)c,c->name);
+	    }
+#endif
+
+	if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s))
+		{
+		prio = srvr;
+		allow = clnt;
+		}
+	else
+		{
+		prio = clnt;
+		allow = srvr;
+		}
+
+	tls1_set_cert_validity(s);
+
+	for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
+		{
+		c=sk_SSL_CIPHER_value(prio,i);
+
+		/* Skip TLS v1.2 only ciphersuites if not supported */
+		if ((c->algorithm_ssl & SSL_TLSV1_2) && 
+			!SSL_USE_TLS1_2_CIPHERS(s))
+			continue;
+
+		ssl_set_cert_masks(cert,c);
+		mask_k = cert->mask_k;
+		mask_a = cert->mask_a;
+		emask_k = cert->export_mask_k;
+		emask_a = cert->export_mask_a;
+			
+#ifdef KSSL_DEBUG
+/*		printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/
+#endif    /* KSSL_DEBUG */
+
+		alg_k=c->algorithm_mkey;
+		alg_a=c->algorithm_auth;
+
+#ifndef OPENSSL_NO_PSK
+		/* with PSK there must be server callback set */
+		if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL)
+			continue;
+#endif /* OPENSSL_NO_PSK */
+
+		if (SSL_C_IS_EXPORT(c))
+			{
+			ok = (alg_k & emask_k) && (alg_a & emask_a);
+#ifdef CIPHER_DEBUG
+			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s (export)\n",ok,alg_k,alg_a,emask_k,emask_a,
+			       (void *)c,c->name);
+#endif
+			}
+		else
+			{
+			ok = (alg_k & mask_k) && (alg_a & mask_a);
+#ifdef CIPHER_DEBUG
+			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n",ok,alg_k,alg_a,mask_k,mask_a,(void *)c,
+			       c->name);
+#endif
+			}
+
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+		/* if we are considering an ECC cipher suite that uses
+		 * an ephemeral EC key check it */
+		if (alg_k & SSL_kEECDH)
+			ok = ok && tls1_check_ec_tmp_key(s, c->id);
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
+
+		if (!ok) continue;
+		if (sk_SSL_CIPHER_find(allow, &cipher_index, c))
+			{
+#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT)
+			if ((alg_k & SSL_kEECDH) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari)
+				{
+				if (!ret) ret=sk_SSL_CIPHER_value(allow, cipher_index);
+				continue;
+				}
+#endif
+			ret=sk_SSL_CIPHER_value(allow, cipher_index);
+			break;
+			}
+		}
+	return(ret);
+	}
+
+int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
+	{
+	int ret=0;
+	const unsigned char *sig;
+	size_t i, siglen;
+	int have_rsa_sign = 0, have_dsa_sign = 0;
+#ifndef OPENSSL_NO_ECDSA
+	int have_ecdsa_sign = 0;
+#endif
+	int nostrict = 1;
+	unsigned long alg_k;
+
+	/* If we have custom certificate types set, use them */
+	if (s->cert->ctypes)
+		{
+		memcpy(p, s->cert->ctypes, s->cert->ctype_num);
+		return (int)s->cert->ctype_num;
+		}
+	/* get configured sigalgs */
+	siglen = tls12_get_psigalgs(s, &sig);
+	if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+		nostrict = 0;
+	for (i = 0; i < siglen; i+=2, sig+=2)
+		{
+		switch(sig[1])
+			{
+		case TLSEXT_signature_rsa:
+			have_rsa_sign = 1;
+			break;
+
+		case TLSEXT_signature_dsa:
+			have_dsa_sign = 1;
+			break;
+#ifndef OPENSSL_NO_ECDSA
+		case TLSEXT_signature_ecdsa:
+			have_ecdsa_sign = 1;
+			break;
+#endif
+			}
+		}
+
+	alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_GOST
+	if (s->version >= TLS1_VERSION)
+		{
+		if (alg_k & SSL_kGOST)
+			{
+			p[ret++]=TLS_CT_GOST94_SIGN;
+			p[ret++]=TLS_CT_GOST01_SIGN;
+			return(ret);
+			}
+		}
+#endif
+
+#ifndef OPENSSL_NO_DH
+	if (alg_k & (SSL_kDHr|SSL_kEDH))
+		{
+#  ifndef OPENSSL_NO_RSA
+		/* Since this refers to a certificate signed with an RSA
+		 * algorithm, only check for rsa signing in strict mode.
+		 */
+		if (nostrict || have_rsa_sign)
+			p[ret++]=SSL3_CT_RSA_FIXED_DH;
+#  endif
+#  ifndef OPENSSL_NO_DSA
+		if (nostrict || have_dsa_sign)
+			p[ret++]=SSL3_CT_DSS_FIXED_DH;
+#  endif
+		}
+	if ((s->version == SSL3_VERSION) &&
+		(alg_k & (SSL_kEDH|SSL_kDHd|SSL_kDHr)))
+		{
+#  ifndef OPENSSL_NO_RSA
+		p[ret++]=SSL3_CT_RSA_EPHEMERAL_DH;
+#  endif
+#  ifndef OPENSSL_NO_DSA
+		p[ret++]=SSL3_CT_DSS_EPHEMERAL_DH;
+#  endif
+		}
+#endif /* !OPENSSL_NO_DH */
+#ifndef OPENSSL_NO_RSA
+	if (have_rsa_sign)
+		p[ret++]=SSL3_CT_RSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_DSA
+	if (have_dsa_sign)
+		p[ret++]=SSL3_CT_DSS_SIGN;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->version >= TLS1_VERSION))
+		{
+		if (nostrict || have_rsa_sign)
+			p[ret++]=TLS_CT_RSA_FIXED_ECDH;
+		if (nostrict || have_ecdsa_sign)
+			p[ret++]=TLS_CT_ECDSA_FIXED_ECDH;
+		}
+#endif
+
+#ifndef OPENSSL_NO_ECDSA
+	/* ECDSA certs can be used with RSA cipher suites as well 
+	 * so we don't need to check for SSL_kECDH or SSL_kEECDH
+	 */
+	if (s->version >= TLS1_VERSION)
+		{
+		if (have_ecdsa_sign)
+			p[ret++]=TLS_CT_ECDSA_SIGN;
+		}
+#endif	
+	return(ret);
+	}
+
+static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len)
+	{
+	if (c->ctypes)
+		{
+		OPENSSL_free(c->ctypes);
+		c->ctypes = NULL;
+		}
+	if (!p || !len)
+		return 1;
+	if (len > 0xff)
+		return 0;
+	c->ctypes = OPENSSL_malloc(len);
+	if (!c->ctypes)
+		return 0;
+	memcpy(c->ctypes, p, len);
+	c->ctype_num = len;
+	return 1;
+	}
+
+int ssl3_shutdown(SSL *s)
+	{
+	int ret;
+
+	/* 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))
+		{
+		s->shutdown=(SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+		return(1);
+		}
+
+	if (!(s->shutdown & SSL_SENT_SHUTDOWN))
+		{
+		s->shutdown|=SSL_SENT_SHUTDOWN;
+#if 1
+		ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_CLOSE_NOTIFY);
+#endif
+		/* our shutdown alert has been sent now, and if it still needs
+	 	 * to be written, s->s3->alert_dispatch will be true */
+	 	if (s->s3->alert_dispatch)
+	 		return(-1);	/* return WANT_WRITE */
+		}
+	else if (s->s3->alert_dispatch)
+		{
+		/* resend it if not sent */
+#if 1
+		ret=s->method->ssl_dispatch_alert(s);
+		if(ret == -1)
+			{
+			/* we only get to return -1 here the 2nd/Nth
+			 * invocation, we must  have already signalled
+			 * return 0 upon a previous invoation,
+			 * return WANT_WRITE */
+			return(ret);
+			}
+#endif
+		}
+	else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
+		{
+		/* If we are waiting for a close from our peer, we are closed */
+		s->method->ssl_read_bytes(s,0,NULL,0,0);
+		if(!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
+			{
+			return(-1);	/* return WANT_READ */
+			}
+		}
+
+	if ((s->shutdown == (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) &&
+		!s->s3->alert_dispatch)
+		return(1);
+	else
+		return(0);
+	}
+
+int ssl3_write(SSL *s, const void *buf, int len)
+	{
+	int ret,n;
+
+#if 0
+	if (s->shutdown & SSL_SEND_SHUTDOWN)
+		{
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+#endif
+	ERR_clear_system_error();
+	if (s->s3->renegotiate) ssl3_renegotiate_check(s);
+
+	/* This is an experimental flag that sends the
+	 * last handshake message in the same packet as the first
+	 * use data - used to see if it helps the TCP protocol during
+	 * session-id reuse */
+	/* The second test is because the buffer may have been removed */
+	if ((s->s3->flags & SSL3_FLAGS_POP_BUFFER) && (s->wbio == s->bbio))
+		{
+		/* First time through, we write into the buffer */
+		if (s->s3->delay_buf_pop_ret == 0)
+			{
+			ret=ssl3_write_bytes(s,SSL3_RT_APPLICATION_DATA,
+					     buf,len);
+			if (ret <= 0) return(ret);
+
+			s->s3->delay_buf_pop_ret=ret;
+			}
+
+		s->rwstate=SSL_WRITING;
+		n=BIO_flush(s->wbio);
+		if (n <= 0) return(n);
+		s->rwstate=SSL_NOTHING;
+
+		/* We have flushed the buffer, so remove it */
+		ssl_free_wbio_buffer(s);
+		s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
+
+		ret=s->s3->delay_buf_pop_ret;
+		s->s3->delay_buf_pop_ret=0;
+		}
+	else
+		{
+		ret=s->method->ssl_write_bytes(s,SSL3_RT_APPLICATION_DATA,
+			buf,len);
+		if (ret <= 0) return(ret);
+		}
+
+	return(ret);
+	}
+
+static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
+	{
+	int ret;
+	
+	ERR_clear_system_error();
+	if (s->s3->renegotiate) ssl3_renegotiate_check(s);
+	s->s3->in_read_app_data=1;
+	ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+	if ((ret == -1) && (s->s3->in_read_app_data == 2))
+		{
+		/* ssl3_read_bytes decided to call s->handshake_func, which
+		 * called ssl3_read_bytes to read handshake data.
+		 * However, ssl3_read_bytes actually found application data
+		 * and thinks that application data makes sense here; so disable
+		 * handshake processing and try to read application data again. */
+		s->in_handshake++;
+		ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+		s->in_handshake--;
+		}
+	else
+		s->s3->in_read_app_data=0;
+
+	return(ret);
+	}
+
+int ssl3_read(SSL *s, void *buf, int len)
+	{
+	return ssl3_read_internal(s, buf, len, 0);
+	}
+
+int ssl3_peek(SSL *s, void *buf, int len)
+	{
+	return ssl3_read_internal(s, buf, len, 1);
+	}
+
+int ssl3_renegotiate(SSL *s)
+	{
+	if (s->handshake_func == NULL)
+		return(1);
+
+	if (s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
+		return(0);
+
+	s->s3->renegotiate=1;
+	return(1);
+	}
+
+int ssl3_renegotiate_check(SSL *s)
+	{
+	int ret=0;
+
+	if (s->s3->renegotiate)
+		{
+		if (	(s->s3->rbuf.left == 0) &&
+			(s->s3->wbuf.left == 0) &&
+			!SSL_in_init(s))
+			{
+/*
+if we are the server, and we have sent a 'RENEGOTIATE' message, we
+need to go to SSL_ST_ACCEPT.
+*/
+			/* SSL_ST_ACCEPT */
+			s->state=SSL_ST_RENEGOTIATE;
+			s->s3->renegotiate=0;
+			s->s3->num_renegotiations++;
+			s->s3->total_renegotiations++;
+			ret=1;
+			}
+		}
+	return(ret);
+	}
+/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF
+ * and handshake macs if required.
+ */
+long ssl_get_algorithm2(SSL *s)
+	{
+	long alg2 = s->s3->tmp.new_cipher->algorithm2;
+	if (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SHA256_PRF
+	    && alg2 == (SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF))
+		return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256;
+	return alg2;
+	}
+
diff --git a/ssl/s3_meth.c b/ssl/s3_meth.c
new file mode 100644
index 0000000..8099b53
--- /dev/null
+++ b/ssl/s3_meth.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/obj.h>
+
+#include "ssl_locl.h"
+
+
+static const SSL_METHOD *ssl3_get_method(int ver);
+static const SSL_METHOD *ssl3_get_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_method());
+	else 
+		return(NULL);
+	}
+
+IMPLEMENT_ssl3_meth_func(SSLv3_method,
+			 ssl3_accept,
+			 ssl3_connect,
+			 ssl3_get_method)
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
new file mode 100644
index 0000000..b66f15f
--- /dev/null
+++ b/ssl/s3_pkt.c
@@ -0,0 +1,1507 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2002 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+			 unsigned int len, int create_empty_fragment);
+static int ssl3_get_record(SSL *s);
+
+int ssl3_read_n(SSL *s, int n, int max, int extend)
+	{
+	/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
+	 * packet by another n bytes.
+	 * The packet will be in the sub-array of s->s3->rbuf.buf specified
+	 * by s->packet and s->packet_length.
+	 * (If s->read_ahead is set, 'max' bytes may be stored in rbuf
+	 * [plus s->packet_length bytes if extend == 1].)
+	 */
+	int i,len,left;
+	long align=0;
+	unsigned char *pkt;
+	SSL3_BUFFER *rb;
+
+	if (n <= 0) return n;
+
+	rb    = &(s->s3->rbuf);
+	if (rb->buf == NULL)
+		if (!ssl3_setup_read_buffer(s))
+			return -1;
+
+	left  = rb->left;
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+	align = (long)rb->buf + SSL3_RT_HEADER_LENGTH;
+	align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+
+	if (!extend)
+		{
+		/* start with empty packet ... */
+		if (left == 0)
+			rb->offset = align;
+		else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH)
+			{
+			/* check if next packet length is large
+			 * enough to justify payload alignment... */
+			pkt = rb->buf + rb->offset;
+			if (pkt[0] == SSL3_RT_APPLICATION_DATA
+			    && (pkt[3]<<8|pkt[4]) >= 128)
+				{
+				/* Note that even if packet is corrupted
+				 * and its length field is insane, we can
+				 * only be led to wrong decision about
+				 * whether memmove will occur or not.
+				 * Header values has no effect on memmove
+				 * arguments and therefore no buffer
+				 * overrun can be triggered. */
+				memmove (rb->buf+align,pkt,left);
+				rb->offset = align;
+				}
+			}
+		s->packet = rb->buf + rb->offset;
+		s->packet_length = 0;
+		/* ... now we can act as if 'extend' was set */
+		}
+
+	/* For DTLS/UDP reads should not span multiple packets
+	 * because the read operation returns the whole packet
+	 * at once (as long as it fits into the buffer). */
+	if (SSL_IS_DTLS(s))
+		{
+		if (left > 0 && n > left)
+			n = left;
+		}
+
+	/* if there is enough in the buffer from a previous read, take some */
+	if (left >= n)
+		{
+		s->packet_length+=n;
+		rb->left=left-n;
+		rb->offset+=n;
+		return(n);
+		}
+
+	/* else we need to read more data */
+
+	len = s->packet_length;
+	pkt = rb->buf+align;
+	/* Move any available bytes to front of buffer:
+	 * 'len' bytes already pointed to by 'packet',
+	 * 'left' extra ones at the end */
+	if (s->packet != pkt) /* len > 0 */
+		{
+		memmove(pkt, s->packet, len+left);
+		s->packet = pkt;
+		rb->offset = len + align;
+		}
+
+	if (n > (int)(rb->len - rb->offset)) /* does not happen */
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_read_n, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+
+	if (!s->read_ahead)
+		/* ignore max parameter */
+		max = n;
+	else
+		{
+		if (max < n)
+			max = n;
+		if (max > (int)(rb->len - rb->offset))
+			max = rb->len - rb->offset;
+		}
+
+	while (left < n)
+		{
+		/* Now we have len+left bytes at the front of s->s3->rbuf.buf
+		 * and need to read in more until we have len+n (up to
+		 * len+max if possible) */
+
+		ERR_clear_system_error();
+		if (s->rbio != NULL)
+			{
+			s->rwstate=SSL_READING;
+			i=BIO_read(s->rbio,pkt+len+left, max-left);
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_n, SSL_R_READ_BIO_NOT_SET);
+			i = -1;
+			}
+
+		if (i <= 0)
+			{
+			rb->left = left;
+			if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+				!SSL_IS_DTLS(s))
+				if (len+left == 0)
+					ssl3_release_read_buffer(s);
+			return(i);
+			}
+		left+=i;
+		/* reads should *never* span multiple packets for DTLS because
+		 * the underlying transport protocol is message oriented as opposed
+		 * to byte oriented as in the TLS case. */
+		if (SSL_IS_DTLS(s))
+			{
+			if (n > left)
+				n = left; /* makes the while condition false */
+			}
+		}
+
+	/* done reading, now the book-keeping */
+	rb->offset += n;
+	rb->left = left - n;
+	s->packet_length += n;
+	s->rwstate=SSL_NOTHING;
+	return(n);
+	}
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type    - is the type of record
+ * ssl->s3->rrec.data, 	 - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by ssl3_read_bytes */
+static int ssl3_get_record(SSL *s)
+	{
+	int ssl_major,ssl_minor,al;
+	int enc_err,n,i,ret= -1;
+	SSL3_RECORD *rr;
+	SSL_SESSION *sess;
+	unsigned char *p;
+	unsigned char md[EVP_MAX_MD_SIZE];
+	short version;
+	unsigned mac_size, orig_len;
+	size_t extra;
+
+	rr= &(s->s3->rrec);
+	sess=s->session;
+
+	if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
+		extra=SSL3_RT_MAX_EXTRA;
+	else
+		extra=0;
+	if (extra && !s->s3->init_extra)
+		{
+		/* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+		 * set after ssl3_setup_buffers() was done */
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+
+again:
+	/* check if we have the header */
+	if (	(s->rstate != SSL_ST_READ_BODY) ||
+		(s->packet_length < SSL3_RT_HEADER_LENGTH)) 
+		{
+		n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+		if (n <= 0) return(n); /* error or non-blocking */
+		s->rstate=SSL_ST_READ_BODY;
+
+		p=s->packet;
+		if (s->msg_callback)
+			s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, s->msg_callback_arg);
+
+		/* Pull apart the header into the SSL3_RECORD */
+		rr->type= *(p++);
+		ssl_major= *(p++);
+		ssl_minor= *(p++);
+		version=(ssl_major<<8)|ssl_minor;
+		n2s(p,rr->length);
+#if 0
+fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
+		/* Lets check version */
+		if (!s->first_packet)
+			{
+			if (version != s->version)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER);
+                                if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash)
+                                	/* Send back error using their minor version number :-) */
+					s->version = (unsigned short)version;
+				al=SSL_AD_PROTOCOL_VERSION;
+				goto f_err;
+				}
+			}
+
+		if ((version>>8) != SSL3_VERSION_MAJOR)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_WRONG_VERSION_NUMBER);
+			goto err;
+			}
+
+		if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
+			{
+			al=SSL_AD_RECORD_OVERFLOW;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_PACKET_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+
+		/* now s->rstate == SSL_ST_READ_BODY */
+		}
+
+	/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+	if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH)
+		{
+		/* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+		i=rr->length;
+		n=ssl3_read_n(s,i,i,1);
+		if (n <= 0) return(n); /* error or non-blocking io */
+		/* now n == rr->length,
+		 * and s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length */
+		}
+
+	s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+	/* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+	 * and we have that many bytes in s->packet
+	 */
+	rr->input= &(s->packet[SSL3_RT_HEADER_LENGTH]);
+
+	/* ok, we can now read from 's->packet' data into 'rr'
+	 * rr->input points at rr->length bytes, which
+	 * need to be copied into rr->data by either
+	 * the decryption or by the decompression
+	 * When the data is 'copied' into the rr->data buffer,
+	 * rr->input will be pointed at the new buffer */ 
+
+	/* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+	 * rr->length bytes of encrypted compressed stuff. */
+
+	/* check is not needed I believe */
+	if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	/* decrypt in place in 'rr->input' */
+	rr->data=rr->input;
+
+	enc_err = s->method->ssl3_enc->enc(s,0);
+	/* enc_err is:
+	 *    0: (in non-constant time) if the record is publically invalid.
+	 *    1: if the padding is valid
+	 *    -1: if the padding is invalid */
+	if (enc_err == 0)
+		{
+		al=SSL_AD_DECRYPTION_FAILED;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
+		goto f_err;
+		}
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+	/* r->length is now the compressed data plus mac */
+	if ((sess != NULL) &&
+	    (s->enc_read_ctx != NULL) &&
+	    (EVP_MD_CTX_md(s->read_hash) != NULL))
+		{
+		/* s->read_hash != NULL => mac_size != -1 */
+		unsigned char *mac = NULL;
+		unsigned char mac_tmp[EVP_MAX_MD_SIZE];
+		mac_size=EVP_MD_CTX_size(s->read_hash);
+		assert(mac_size <= EVP_MAX_MD_SIZE);
+
+		/* kludge: *_cbc_remove_padding passes padding length in rr->type */
+		orig_len = rr->length+((unsigned int)rr->type>>8);
+
+		/* orig_len is the length of the record before any padding was
+		 * removed. This is public information, as is the MAC in use,
+		 * therefore we can safely process the record in a different
+		 * amount of time if it's too short to possibly contain a MAC.
+		 */
+		if (orig_len < mac_size ||
+		    /* CBC records must have a padding length byte too. */
+		    (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+		     orig_len < mac_size+1))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_LENGTH_TOO_SHORT);
+			goto f_err;
+			}
+
+		if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
+			{
+			/* We update the length so that the TLS header bytes
+			 * can be constructed correctly but we need to extract
+			 * the MAC in constant time from within the record,
+			 * without leaking the contents of the padding bytes.
+			 * */
+			mac = mac_tmp;
+			ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
+			rr->length -= mac_size;
+			}
+		else
+			{
+			/* In this case there's no padding, so |orig_len|
+			 * equals |rec->length| and we checked that there's
+			 * enough bytes for |mac_size| above. */
+			rr->length -= mac_size;
+			mac = &rr->data[rr->length];
+			}
+
+		i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+		if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+			enc_err = -1;
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
+			enc_err = -1;
+		}
+
+	if (enc_err < 0)
+		{
+		/* A separate 'decryption_failed' alert was introduced with TLS 1.0,
+		 * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
+		 * failure is directly visible from the ciphertext anyway,
+		 * we should not reveal which kind of error occured -- this
+		 * might become visible to an attacker (e.g. via a logfile) */
+		al=SSL_AD_BAD_RECORD_MAC;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+		goto f_err;
+		}
+
+	/* r->length is now just compressed */
+	if (s->expand != NULL)
+		{
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra)
+			{
+			al=SSL_AD_RECORD_OVERFLOW;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+		if (!ssl3_do_uncompress(s))
+			{
+			al=SSL_AD_DECOMPRESSION_FAILURE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_BAD_DECOMPRESSION);
+			goto f_err;
+			}
+		}
+
+	if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, SSL_R_DATA_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	rr->off=0;
+	/* So at this point the following is true
+	 * ssl->s3->rrec.type 	is the type of record
+	 * ssl->s3->rrec.length	== number of bytes in record
+	 * ssl->s3->rrec.off	== offset to first valid byte
+	 * ssl->s3->rrec.data	== where to take bytes from, increment
+	 *			   after use :-).
+	 */
+
+	/* we have pulled in a full packet so zero things */
+	s->packet_length=0;
+
+	/* just read a 0 length packet */
+	if (rr->length == 0) goto again;
+
+#if 0
+fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
+	return(1);
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(ret);
+	}
+
+int ssl3_do_uncompress(SSL *ssl)
+	{
+	return(1);
+	}
+
+int ssl3_do_compress(SSL *ssl)
+	{
+	return(1);
+	}
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
+	{
+	const unsigned char *buf=buf_;
+	unsigned int tot,n,nw;
+	int i;
+
+	s->rwstate=SSL_NOTHING;
+	tot=s->s3->wnum;
+	s->s3->wnum=0;
+
+	if (SSL_in_init(s) && !s->in_handshake)
+		{
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_write_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return -1;
+			}
+		}
+
+	n=(len-tot);
+	for (;;)
+		{
+		if (n > s->max_send_fragment)
+			nw=s->max_send_fragment;
+		else
+			nw=n;
+
+		i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
+		if (i <= 0)
+			{
+			s->s3->wnum=tot;
+			return i;
+			}
+
+		if ((i == (int)n) ||
+			(type == SSL3_RT_APPLICATION_DATA &&
+			 (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
+			{
+			/* next chunk of data should get another prepended empty fragment
+			 * in ciphersuites with known-IV weakness: */
+			s->s3->empty_fragment_done = 0;
+			
+			return tot+i;
+			}
+
+		n-=i;
+		tot+=i;
+		}
+	}
+
+static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+			 unsigned int len, int create_empty_fragment)
+	{
+	unsigned char *p,*plen;
+	int i,mac_size,clear=0;
+	int prefix_len=0;
+	int eivlen;
+	long align=0;
+	SSL3_RECORD *wr;
+	SSL3_BUFFER *wb=&(s->s3->wbuf);
+	SSL_SESSION *sess;
+
+ 	if (wb->buf == NULL)
+		if (!ssl3_setup_write_buffer(s))
+			return -1;
+
+	/* first check if there is a SSL3_BUFFER still being written
+	 * out.  This will happen with non blocking IO */
+	if (wb->left != 0)
+		return(ssl3_write_pending(s,type,buf,len));
+
+	/* If we have an alert to send, lets send it */
+	if (s->s3->alert_dispatch)
+		{
+		i=s->method->ssl_dispatch_alert(s);
+		if (i <= 0)
+			return(i);
+		/* if it went, fall through and send more stuff */
+		}
+
+	if (len == 0 && !create_empty_fragment)
+		return 0;
+
+	wr= &(s->s3->wrec);
+	sess=s->session;
+
+	if (	(sess == NULL) ||
+		(s->enc_write_ctx == NULL) ||
+		(EVP_MD_CTX_md(s->write_hash) == NULL))
+		{
+#if 1
+		clear=s->enc_write_ctx?0:1;	/* must be AEAD cipher */
+#else
+		clear=1;
+#endif
+		mac_size=0;
+		}
+	else
+		{
+		mac_size=EVP_MD_CTX_size(s->write_hash);
+		if (mac_size < 0)
+			goto err;
+		}
+
+	/* 'create_empty_fragment' is true only when this function calls itself */
+	if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
+		{
+		/* countermeasure against known-IV weakness in CBC ciphersuites
+		 * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
+
+		if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+			{
+			/* recursive function call with 'create_empty_fragment' set;
+			 * this prepares and buffers the data for an empty fragment
+			 * (these 'prefix_len' bytes are sent out later
+			 * together with the actual payload) */
+			prefix_len = do_ssl3_write(s, type, buf, 0, 1);
+			if (prefix_len <= 0)
+				goto err;
+
+			if (prefix_len >
+		(SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD))
+				{
+				/* insufficient space */
+				OPENSSL_PUT_ERROR(SSL, do_ssl3_write, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			}
+		
+		s->s3->empty_fragment_done = 1;
+		}
+
+	if (create_empty_fragment)
+		{
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+		/* extra fragment would be couple of cipher blocks,
+		 * which would be multiple of SSL3_ALIGN_PAYLOAD, so
+		 * if we want to align the real payload, then we can
+		 * just pretent we simply have two headers. */
+		align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
+		align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+		p = wb->buf + align;
+		wb->offset  = align;
+		}
+	else if (prefix_len)
+		{
+		p = wb->buf + wb->offset + prefix_len;
+		}
+	else
+		{
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+		align = (long)wb->buf + SSL3_RT_HEADER_LENGTH;
+		align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+		p = wb->buf + align;
+		wb->offset  = align;
+		}
+
+	/* write the header */
+
+	*(p++)=type&0xff;
+	wr->type=type;
+
+	*(p++)=(s->version>>8);
+	/* 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
+				&& !s->renegotiate
+				&& TLS1_get_version(s) > TLS1_VERSION)
+		*(p++) = 0x1;
+	else
+		*(p++)=s->version&0xff;
+
+	/* field where we are to write out packet length */
+	plen=p; 
+	p+=2;
+	/* Explicit IV length, block ciphers appropriate version flag */
+	if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s))
+		{
+		int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+		if (mode == EVP_CIPH_CBC_MODE)
+			{
+			eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+			if (eivlen <= 1)
+				eivlen = 0;
+			}
+		/* Need explicit part of IV for GCM mode */
+		else if (mode == EVP_CIPH_GCM_MODE)
+			eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+		else
+			eivlen = 0;
+		}
+	else 
+		eivlen = 0;
+
+	/* lets setup the record stuff. */
+	wr->data=p + eivlen;
+	wr->length=(int)len;
+	wr->input=(unsigned char *)buf;
+
+	/* we now 'read' from wr->input, wr->length bytes into
+	 * wr->data */
+
+	/* first we compress */
+	if (s->compress != NULL)
+		{
+		if (!ssl3_do_compress(s))
+			{
+			OPENSSL_PUT_ERROR(SSL, do_ssl3_write, SSL_R_COMPRESSION_FAILURE);
+			goto err;
+			}
+		}
+	else
+		{
+		memcpy(wr->data,wr->input,wr->length);
+		wr->input=wr->data;
+		}
+
+	/* we should still have the output to wr->data and the input
+	 * from wr->input.  Length should be wr->length.
+	 * wr->data still points in the wb->buf */
+
+	if (mac_size != 0)
+		{
+		if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
+			goto err;
+		wr->length+=mac_size;
+		}
+
+	wr->input=p;
+	wr->data=p;
+
+	if (eivlen)
+		{
+	/*	if (RAND_pseudo_bytes(p, eivlen) <= 0)
+			goto err; */
+		wr->length += eivlen;
+		}
+
+	/* ssl3_enc can only have an error on read */
+	s->method->ssl3_enc->enc(s,1);
+
+	/* record length after mac and block padding */
+	s2n(wr->length,plen);
+
+	if (s->msg_callback)
+		s->msg_callback(1, 0, SSL3_RT_HEADER, plen - 5, 5, s, s->msg_callback_arg);
+
+	/* we should now have
+	 * wr->data pointing to the encrypted data, which is
+	 * wr->length long */
+	wr->type=type; /* not needed but helps for debugging */
+	wr->length+=SSL3_RT_HEADER_LENGTH;
+
+	if (create_empty_fragment)
+		{
+		/* we are in a recursive call;
+		 * just return the length, don't write out anything here
+		 */
+		return wr->length;
+		}
+
+	/* now let's set up wb */
+	wb->left = prefix_len + wr->length;
+
+	/* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+	s->s3->wpend_tot=len;
+	s->s3->wpend_buf=buf;
+	s->s3->wpend_type=type;
+	s->s3->wpend_ret=len;
+
+	/* we now just need to write the buffer */
+	return ssl3_write_pending(s,type,buf,len);
+err:
+	return -1;
+	}
+
+/* if s->s3->wbuf.left != 0, we need to call this */
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+	unsigned int len)
+	{
+	int i;
+	SSL3_BUFFER *wb=&(s->s3->wbuf);
+
+/* XXXX */
+	if ((s->s3->wpend_tot > (int)len)
+		|| ((s->s3->wpend_buf != buf) &&
+			!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))
+		|| (s->s3->wpend_type != type))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BAD_WRITE_RETRY);
+		return(-1);
+		}
+
+	for (;;)
+		{
+		ERR_clear_system_error();
+		if (s->wbio != NULL)
+			{
+			s->rwstate=SSL_WRITING;
+			i=BIO_write(s->wbio,
+				(char *)&(wb->buf[wb->offset]),
+				(unsigned int)wb->left);
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_write_pending, SSL_R_BIO_NOT_SET);
+			i= -1;
+			}
+		if (i == wb->left)
+			{
+			wb->left=0;
+			wb->offset+=i;
+			if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+				!SSL_IS_DTLS(s))
+				ssl3_release_write_buffer(s);
+			s->rwstate=SSL_NOTHING;
+			return(s->s3->wpend_ret);
+			}
+		else if (i <= 0) {
+			if (s->version == DTLS1_VERSION ||
+			    s->version == DTLS1_BAD_VER) {
+				/* For DTLS, just drop it. That's kind of the whole
+				   point in using a datagram service */
+				wb->left = 0;
+			}
+			return(i);
+		}
+		wb->offset+=i;
+		wb->left-=i;
+		}
+	}
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ *   -  0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ *     Change cipher spec protocol
+ *             just 1 byte needed, no need for keeping anything stored
+ *     Alert protocol
+ *             2 bytes needed (AlertLevel, AlertDescription)
+ *     Handshake protocol
+ *             4 bytes needed (HandshakeType, uint24 length) -- we just have
+ *             to detect unexpected Client Hello and Hello Request messages
+ *             here, anything else is handled by higher layers
+ *     Application data protocol
+ *             none of our business
+ */
+int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+	{
+	int al,i,j,ret;
+	unsigned int n;
+	SSL3_RECORD *rr;
+	void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+	if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+		if (!ssl3_setup_read_buffer(s))
+			return(-1);
+
+	if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||
+	    (peek && (type != SSL3_RT_APPLICATION_DATA)))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+
+	if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0))
+		/* (partially) satisfy request from storage */
+		{
+		unsigned char *src = s->s3->handshake_fragment;
+		unsigned char *dst = buf;
+		unsigned int k;
+
+		/* peek == 0 */
+		n = 0;
+		while ((len > 0) && (s->s3->handshake_fragment_len > 0))
+			{
+			*dst++ = *src++;
+			len--; s->s3->handshake_fragment_len--;
+			n++;
+			}
+		/* move any remaining fragment bytes: */
+		for (k = 0; k < s->s3->handshake_fragment_len; k++)
+			s->s3->handshake_fragment[k] = *src++;
+		return n;
+	}
+
+	/* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+	if (!s->in_handshake && SSL_in_init(s))
+		{
+		/* type == SSL3_RT_APPLICATION_DATA */
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		}
+start:
+	s->rwstate=SSL_NOTHING;
+
+	/* s->s3->rrec.type	    - is the type of record
+	 * s->s3->rrec.data,    - data
+	 * s->s3->rrec.off,     - offset into 'data' for next read
+	 * s->s3->rrec.length,  - number of bytes. */
+	rr = &(s->s3->rrec);
+
+	/* get new packet if necessary */
+	if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+		{
+		ret=ssl3_get_record(s);
+		if (ret <= 0) return(ret);
+		}
+
+	/* we now have a packet which can be read and processed */
+
+	if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+	                               * reset by ssl3_get_finished */
+		&& (rr->type != SSL3_RT_HANDSHAKE))
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
+		goto f_err;
+		}
+
+	/* If the other end has shut down, throw anything we read away
+	 * (even in 'peek' mode) */
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		rr->length=0;
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+
+
+	if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+		{
+		/* make sure that we are not getting application data when we
+		 * are doing a handshake for the first time */
+		if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+			(s->enc_read_ctx == NULL))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_APP_DATA_IN_HANDSHAKE);
+			goto f_err;
+			}
+
+		if (len <= 0) return(len);
+
+		if ((unsigned int)len > rr->length)
+			n = rr->length;
+		else
+			n = (unsigned int)len;
+
+		memcpy(buf,&(rr->data[rr->off]),n);
+		if (!peek)
+			{
+			rr->length-=n;
+			rr->off+=n;
+			if (rr->length == 0)
+				{
+				s->rstate=SSL_ST_READ_HEADER;
+				rr->off=0;
+				if (s->mode & SSL_MODE_RELEASE_BUFFERS)
+					ssl3_release_read_buffer(s);
+				}
+			}
+		return(n);
+		}
+
+
+	/* If we get here, then type != rr->type; if we have a handshake
+	 * message, then it was unexpected (Hello Request or Client Hello). */
+
+	/* In case of record types for which we have 'fragment' storage,
+	 * fill that so that we can process the data at a fixed place.
+	 */
+		{
+		unsigned int dest_maxlen = 0;
+		unsigned char *dest = NULL;
+		unsigned int *dest_len = NULL;
+
+		if (rr->type == SSL3_RT_HANDSHAKE)
+			{
+			dest_maxlen = sizeof s->s3->handshake_fragment;
+			dest = s->s3->handshake_fragment;
+			dest_len = &s->s3->handshake_fragment_len;
+			}
+		else if (rr->type == SSL3_RT_ALERT)
+			{
+			dest_maxlen = sizeof s->s3->alert_fragment;
+			dest = s->s3->alert_fragment;
+			dest_len = &s->s3->alert_fragment_len;
+			}
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (rr->type == TLS1_RT_HEARTBEAT)
+			{
+			tls1_process_heartbeat(s);
+
+			/* Exit and notify application to read again */
+			rr->length = 0;
+			s->rwstate=SSL_READING;
+			BIO_clear_retry_flags(SSL_get_rbio(s));
+			BIO_set_retry_read(SSL_get_rbio(s));
+			return(-1);
+			}
+#endif
+
+		if (dest_maxlen > 0)
+			{
+			n = dest_maxlen - *dest_len; /* available space in 'dest' */
+			if (rr->length < n)
+				n = rr->length; /* available bytes */
+
+			/* now move 'n' bytes: */
+			while (n-- > 0)
+				{
+				dest[(*dest_len)++] = rr->data[rr->off++];
+				rr->length--;
+				}
+
+			if (*dest_len < dest_maxlen)
+				goto start; /* fragment was too small */
+			}
+		}
+
+	/* s->s3->handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
+	 * s->s3->alert_fragment_len == 2      iff  rr->type == SSL3_RT_ALERT.
+	 * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+	/* If we are a client, check for an incoming 'Hello Request': */
+	if ((!s->server) &&
+		(s->s3->handshake_fragment_len >= 4) &&
+		(s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+		(s->session != NULL) && (s->session->cipher != NULL))
+		{
+		s->s3->handshake_fragment_len = 0;
+
+		if ((s->s3->handshake_fragment[1] != 0) ||
+			(s->s3->handshake_fragment[2] != 0) ||
+			(s->s3->handshake_fragment[3] != 0))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_HELLO_REQUEST);
+			goto f_err;
+			}
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
+
+		if (SSL_is_init_finished(s) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+			!s->s3->renegotiate)
+			{
+			ssl3_renegotiate(s);
+			if (ssl3_renegotiate_check(s))
+				{
+				i=s->handshake_func(s);
+				if (i < 0) return(i);
+				if (i == 0)
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+					return(-1);
+					}
+
+				if (!(s->mode & SSL_MODE_AUTO_RETRY))
+					{
+					if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+						{
+						BIO *bio;
+						/* In the case where we try to read application data,
+						 * but we trigger an SSL handshake, we return -1 with
+						 * the retry option set.  Otherwise renegotiation may
+						 * cause nasty problems in the blocking world */
+						s->rwstate=SSL_READING;
+						bio=SSL_get_rbio(s);
+						BIO_clear_retry_flags(bio);
+						BIO_set_retry_read(bio);
+						return(-1);
+						}
+					}
+				}
+			}
+		/* we either finished a handshake or ignored the request,
+		 * now try again to obtain the (application) data we were asked for */
+		goto start;
+		}
+	/* If we are a server and get a client hello when renegotiation isn't
+	 * allowed send back a no renegotiation alert and carry on.
+	 * WARNING: experimental code, needs reviewing (steve)
+	 */
+	if (s->server &&
+		SSL_is_init_finished(s) &&
+    		!s->s3->send_connection_binding &&
+		(s->version > SSL3_VERSION) &&
+		(s->s3->handshake_fragment_len >= 4) &&
+		(s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
+		(s->session != NULL) && (s->session->cipher != NULL) &&
+		!(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+		
+		{
+		/*s->s3->handshake_fragment_len = 0;*/
+		rr->length = 0;
+		ssl3_send_alert(s,SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
+		goto start;
+		}
+	if (s->s3->alert_fragment_len >= 2)
+		{
+		int alert_level = s->s3->alert_fragment[0];
+		int alert_descr = s->s3->alert_fragment[1];
+
+		s->s3->alert_fragment_len = 0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j = (alert_level << 8) | alert_descr;
+			cb(s, SSL_CB_READ_ALERT, j);
+			}
+
+		if (alert_level == 1) /* warning */
+			{
+			s->s3->warn_alert = alert_descr;
+			if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+				{
+				s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+				return(0);
+				}
+			/* This is a warning but we receive it if we requested
+			 * renegotiation and the peer denied it. Terminate with
+			 * a fatal alert because if application tried to
+			 * renegotiatie it presumably had a good reason and
+			 * expects it to succeed.
+			 *
+			 * In future we might have a renegotiation where we
+			 * don't care if the peer refused it where we carry on.
+			 */
+			else if (alert_descr == SSL_AD_NO_RENEGOTIATION)
+				{
+				al = SSL_AD_HANDSHAKE_FAILURE;
+				OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION);
+				goto f_err;
+				}
+#ifdef SSL_AD_MISSING_SRP_USERNAME
+			else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME)
+				return(0);
+#endif
+			}
+		else if (alert_level == 2) /* fatal */
+			{
+			char tmp[16];
+
+			s->rwstate=SSL_NOTHING;
+			s->s3->fatal_alert = alert_descr;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_AD_REASON_OFFSET + alert_descr);
+			BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+			ERR_add_error_data(2,"SSL alert number ",tmp);
+			s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+			SSL_CTX_remove_session(s->ctx,s->session);
+			return(0);
+			}
+		else
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNKNOWN_ALERT_TYPE);
+			goto f_err;
+			}
+
+		goto start;
+		}
+
+	if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+		{
+		s->rwstate=SSL_NOTHING;
+		rr->length=0;
+		return(0);
+		}
+
+	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+		{
+		/* 'Change Cipher Spec' is just a single byte, so we know
+		 * exactly what the record payload has to look like */
+		if (	(rr->length != 1) || (rr->off != 0) ||
+			(rr->data[0] != SSL3_MT_CCS))
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+			goto f_err;
+			}
+
+		/* Check we have a cipher to change to */
+		if (s->s3->tmp.new_cipher == NULL)
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_CCS_RECEIVED_EARLY);
+			goto f_err;
+			}
+
+		rr->length=0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
+
+		s->s3->change_cipher_spec=1;
+		if (!ssl3_do_change_cipher_spec(s))
+			goto err;
+		else
+			goto start;
+		}
+
+	/* Unexpected handshake message (Client Hello, or protocol violation) */
+	if ((s->s3->handshake_fragment_len >= 4) &&	!s->in_handshake)
+		{
+		if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+			{
+#if 0 /* worked only because C operator preferences are not as expected (and
+       * because this is not really needed for clients except for detecting
+       * protocol violations): */
+			s->state=SSL_ST_BEFORE|(s->server)
+				?SSL_ST_ACCEPT
+				:SSL_ST_CONNECT;
+#else
+			s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+			s->renegotiate=1;
+			s->new_session=1;
+			}
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+
+		if (!(s->mode & SSL_MODE_AUTO_RETRY))
+			{
+			if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+				{
+				BIO *bio;
+				/* In the case where we try to read application data,
+				 * but we trigger an SSL handshake, we return -1 with
+				 * the retry option set.  Otherwise renegotiation may
+				 * cause nasty problems in the blocking world */
+				s->rwstate=SSL_READING;
+				bio=SSL_get_rbio(s);
+				BIO_clear_retry_flags(bio);
+				BIO_set_retry_read(bio);
+				return(-1);
+				}
+			}
+		goto start;
+		}
+
+	switch (rr->type)
+		{
+	default:
+#ifndef OPENSSL_NO_TLS
+		/* TLS up to v1.1 just ignores unknown message types:
+		 * TLS v1.2 give an unexpected message alert.
+		 */
+		if (s->version >= TLS1_VERSION && s->version <= TLS1_1_VERSION)
+			{
+			rr->length = 0;
+			goto start;
+			}
+#endif
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD);
+		goto f_err;
+	case SSL3_RT_CHANGE_CIPHER_SPEC:
+	case SSL3_RT_ALERT:
+	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 */
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, ERR_R_INTERNAL_ERROR);
+		goto f_err;
+	case SSL3_RT_APPLICATION_DATA:
+		/* At this point, we were expecting handshake data,
+		 * but have application data.  If the library was
+		 * running inside ssl3_read() (i.e. in_read_app_data
+		 * is set) and it makes sense to read 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)
+					)
+				))
+			{
+			s->s3->in_read_app_data=2;
+			return(-1);
+			}
+		else
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_UNEXPECTED_RECORD);
+			goto f_err;
+			}
+		}
+	/* not reached */
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(-1);
+	}
+
+int ssl3_do_change_cipher_spec(SSL *s)
+	{
+	int i;
+	const char *sender;
+	int slen;
+
+	if (s->state & SSL_ST_ACCEPT)
+		i=SSL3_CHANGE_CIPHER_SERVER_READ;
+	else
+		i=SSL3_CHANGE_CIPHER_CLIENT_READ;
+
+	if (s->s3->tmp.key_block == NULL)
+		{
+		if (s->session == NULL) 
+			{
+			/* might happen if dtls1_read_bytes() calls this */
+			OPENSSL_PUT_ERROR(SSL, ssl3_do_change_cipher_spec, SSL_R_CCS_RECEIVED_EARLY);
+			return (0);
+			}
+
+		s->session->cipher=s->s3->tmp.new_cipher;
+		if (!s->method->ssl3_enc->setup_key_block(s)) return(0);
+		}
+
+	if (!s->method->ssl3_enc->change_cipher_state(s,i))
+		return(0);
+
+	/* 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)
+		{
+		sender=s->method->ssl3_enc->server_finished_label;
+		slen=s->method->ssl3_enc->server_finished_label_len;
+		}
+	else
+		{
+		sender=s->method->ssl3_enc->client_finished_label;
+		slen=s->method->ssl3_enc->client_finished_label_len;
+		}
+
+	i = s->method->ssl3_enc->final_finish_mac(s,
+		sender,slen,s->s3->tmp.peer_finish_md);
+	if (i == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_do_change_cipher_spec, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+	s->s3->tmp.peer_finish_md_len = i;
+
+	return(1);
+	}
+
+int ssl3_send_alert(SSL *s, int level, int desc)
+	{
+	/* Map tls/ssl alert value to correct one */
+	desc=s->method->ssl3_enc->alert_value(desc);
+	if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
+		desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
+	if (desc < 0) return -1;
+	/* If a fatal one, remove from cache */
+	if ((level == 2) && (s->session != NULL))
+		SSL_CTX_remove_session(s->ctx,s->session);
+
+	s->s3->alert_dispatch=1;
+	s->s3->send_alert[0]=level;
+	s->s3->send_alert[1]=desc;
+	if (s->s3->wbuf.left == 0) /* data still being written out? */
+		return s->method->ssl_dispatch_alert(s);
+	/* else data is still being written out, we will get written
+	 * some time in the future */
+	return -1;
+	}
+
+int ssl3_dispatch_alert(SSL *s)
+	{
+	int i,j;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+
+	s->s3->alert_dispatch=0;
+	i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
+	if (i <= 0)
+		{
+		s->s3->alert_dispatch=1;
+		}
+	else
+		{
+		/* Alert sent to BIO.  If it is important, flush it now.
+		 * If the message does not get sent due to non-blocking IO,
+		 * we will not worry too much. */
+		if (s->s3->send_alert[0] == SSL3_AL_FATAL)
+			(void)BIO_flush(s->wbio);
+
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+			cb(s,SSL_CB_WRITE_ALERT,j);
+			}
+		}
+	return(i);
+	}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
new file mode 100644
index 0000000..3a39cfd
--- /dev/null
+++ b/ssl/s3_srvr.c
@@ -0,0 +1,3299 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@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. */
+
+#define REUSE_CIPHER_BUG
+#define NETSCAPE_HANG_BUG
+
+#include <stdio.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/cipher.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+#include "../crypto/dh/internal.h"
+
+static const SSL_METHOD *ssl3_get_server_method(int ver);
+
+static const SSL_METHOD *ssl3_get_server_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_server_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+			ssl3_accept,
+			ssl_undefined_function,
+			ssl3_get_server_method)
+
+int ssl3_accept(SSL *s)
+	{
+	BUF_MEM *buf;
+	unsigned long alg_k;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state,skip=0;
+
+	ERR_clear_error();
+	ERR_clear_system_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)) SSL_clear(s);
+
+	if (s->cert == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_NO_CERTIFICATE_SET);
+		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)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_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;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				}
+
+			if (!ssl3_setup_buffers(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			s->init_num=0;
+			s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
+			s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
+
+			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; 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.
+				 */
+				OPENSSL_PUT_ERROR(SSL, ssl3_accept, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+				ret = -1;
+				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:
+
+			s->shutdown=0;
+			ret=ssl3_get_client_hello(s);
+			if (ret <= 0) goto end;
+			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;
+#ifndef OPENSSL_NO_TLSEXT
+			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
+			if (s->hit)
+					s->state=SSL3_ST_SW_CHANGE_A;
+#endif
+			else
+#ifndef OPENSSL_NO_TLSEXT
+				s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A;
+#else
+			s->state = SSL3_ST_SW_CERT_A;
+#endif
+			s->init_num = 0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		case SSL3_ST_SW_SUPPLEMENTAL_DATA_A:
+		case SSL3_ST_SW_SUPPLEMENTAL_DATA_B:
+			/* We promised to send an audit proof in the hello. */
+			if (s->s3->tlsext_authz_promised_to_client)
+				{
+				ret = tls1_send_server_supplemental_data(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip = 1;
+
+			s->state = SSL3_ST_SW_CERT_A;
+			s->init_num = 0;
+			break;
+#endif
+
+		case SSL3_ST_SW_CERT_A:
+		case SSL3_ST_SW_CERT_B:
+			/* Check if it is anon DH or anon ECDH, */
+			/* normal PSK or KRB5 or SRP */
+			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+				&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+				&& !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+				{
+				ret=ssl3_send_server_certificate(s);
+				if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+				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;
+				}
+#else
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
+			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 */
+			if ((s->options & SSL_OP_EPHEMERAL_RSA)
+				)
+				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+				 * even when forbidden by protocol specs
+				 * (handshake may fail as clients are not required to
+				 * be able to handle this) */
+				s->s3->tmp.use_rsa_tmp=1;
+			else
+				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 (s->s3->tmp.use_rsa_tmp
+			/* PSK: send ServerKeyExchange if PSK identity
+			 * hint if provided */
+#ifndef OPENSSL_NO_PSK
+			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+#endif
+			    || (alg_k & SSL_kEDH)
+			    || (alg_k & SSL_kEECDH)
+			    || ((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)) ||
+				 /* never request cert in Kerberos ciphersuites */
+				(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)
+				/* 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;
+				if (s->s3->handshake_buffer)
+					if (!ssl3_digest_cached_records(s))
+						return -1;
+				}
+			else
+				{
+				s->s3->tmp.cert_request=1;
+				ret=ssl3_send_certificate_request(s);
+				if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+				s->state=SSL3_ST_SW_FLUSH;
+				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
+				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:
+			/* Check for second client hello (MS SGC) */
+			ret = ssl3_check_client_hello(s);
+			if (ret <= 0)
+				goto end;
+			if (ret == 2)
+				s->state = SSL3_ST_SR_CLNT_HELLO_C;
+			else {
+				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.
+				 */
+#if defined(OPENSSL_NO_TLSEXT) || 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;
+				}
+			else if (SSL_USE_SIGALGS(s))
+				{
+				s->state=SSL3_ST_SR_CERT_VRFY_A;
+				s->init_num=0;
+				if (!s->session->peer)
+					break;
+				/* For sigalgs freeze the handshake buffer
+				 * at this point and digest cached records.
+				 */
+				if (!s->s3->handshake_buffer)
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
+					return -1;
+					}
+				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+				if (!ssl3_digest_cached_records(s))
+					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 (s->s3->handshake_buffer)
+					if (!ssl3_digest_cached_records(s))
+						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)
+							{
+							ret = -1;
+							goto end;
+							}
+						offset+=dgst_size;
+						}		
+				}
+			break;
+
+		case SSL3_ST_SR_CERT_VRFY_A:
+		case SSL3_ST_SR_CERT_VRFY_B:
+
+			/* we should decide if we expected this one */
+			ret=ssl3_get_cert_verify(s);
+			if (ret <= 0) goto end;
+
+#if defined(OPENSSL_NO_TLSEXT) || 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;
+
+#if !defined(OPENSSL_NO_TLSEXT) && !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_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;
+#ifndef OPENSSL_NO_TLSEXT
+			else if (s->tlsext_ticket_expected)
+				s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
+			else
+				s->state=SSL3_ST_SW_CHANGE_A;
+			s->init_num=0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		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;
+
+#endif
+
+		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; 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;
+				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)
+				{
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#else
+				if (s->s3->next_proto_neg_seen)
+					s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
+				else
+					s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#endif
+				}
+			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; */
+
+		default:
+			OPENSSL_PUT_ERROR(SSL, 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)
+		{
+		ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0);
+		s->state=SSL3_ST_SW_HELLO_REQ_B;
+		}
+
+	/* SSL3_ST_SW_HELLO_REQ_B */
+	return ssl_do_write(s);
+	}
+
+int ssl3_check_client_hello(SSL *s)
+	{
+	int ok;
+	long n;
+
+	/* this function is called when we really expect a Certificate message,
+	 * so permit appropriate message length */
+	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);
+	s->s3->tmp.reuse_message = 1;
+	if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
+		{
+		/* We only allow the client to restart the handshake once per
+		 * negotiation. */
+		if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_check_client_hello, SSL_R_MULTIPLE_SGC_RESTARTS);
+			return -1;
+			}
+		/* Throw away what we have done so far in the current handshake,
+		 * which will now be aborted. (A full SSL_clear would be too much.) */
+#ifndef OPENSSL_NO_DH
+		if (s->s3->tmp.dh != NULL)
+			{
+			DH_free(s->s3->tmp.dh);
+			s->s3->tmp.dh = NULL;
+			}
+#endif
+#ifndef OPENSSL_NO_ECDH
+		if (s->s3->tmp.ecdh != NULL)
+			{
+			EC_KEY_free(s->s3->tmp.ecdh);
+			s->s3->tmp.ecdh = NULL;
+			}
+#endif
+		s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
+		return 2;
+		}
+	return 1;
+}
+
+int ssl3_get_client_hello(SSL *s)
+	{
+	int i,j,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
+	unsigned int cookie_len;
+	long n;
+	unsigned long id;
+	unsigned char *p,*d;
+	SSL_CIPHER *c;
+	STACK_OF(SSL_CIPHER) *ciphers=NULL;
+
+	if (s->state == SSL3_ST_SR_CLNT_HELLO_C)
+		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;
+	d=p=(unsigned char *)s->init_msg;
+
+	/* use version from inside client hello, not from record header
+	 * (may differ: see RFC 2246, Appendix E, second paragraph) */
+	s->client_version=(((int)p[0])<<8)|(int)p[1];
+	p+=2;
+
+	if (SSL_IS_DTLS(s)  ?	(s->client_version > s->version &&
+				 s->method->version != DTLS_ANY_VERSION)
+			    :	(s->client_version < s->version))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_WRONG_VERSION_NUMBER);
+		if ((s->client_version>>8) == SSL3_VERSION_MAJOR &&
+			!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;
+		}
+
+	/* 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)
+		{
+		unsigned int session_length, cookie_length;
+		
+		session_length = *(p + SSL3_RANDOM_SIZE);
+		cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
+
+		if (cookie_length == 0)
+			return 1;
+		}
+
+	/* load the client random */
+	memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
+	p+=SSL3_RANDOM_SIZE;
+
+	/* get the session-id */
+	j= *(p++);
+
+	s->hit=0;
+	/* 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 ((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, p, j, d + n);
+		if (i == 1)
+			{ /* previous session */
+			s->hit=1;
+			}
+		else if (i == -1)
+			goto err;
+		else /* i == 0 */
+			{
+			if (!ssl_get_new_session(s,1))
+				goto err;
+			}
+		}
+
+	p+=j;
+
+	if (SSL_IS_DTLS(s))
+		{
+		/* cookie stuff */
+		cookie_len = *(p++);
+
+		/* 
+		 * The ClientHello may contain a cookie even if the
+		 * HelloVerify message has not been sent--make sure that it
+		 * does not cause an overflow.
+		 */
+		if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+			{
+			/* too much data */
+			al = SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH);
+			goto f_err;
+			}
+
+		/* verify the cookie if appropriate option is set. */
+		if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+			cookie_len > 0)
+			{
+			memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+			if ( s->ctx->app_verify_cookie_cb != NULL)
+				{
+				if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+					cookie_len) == 0)
+					{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH);
+					goto f_err;
+					}
+				/* else cookie verification succeeded */
+				}
+			else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie, 
+						  s->d1->cookie_len) != 0) /* default verification */
+				{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH);
+					goto f_err;
+				}
+			/* Set to -2 so if successful we return 2 */
+			ret = -2;
+			}
+
+		p += cookie_len;
+		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))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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
+				{
+				OPENSSL_PUT_ERROR(SSL, 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;
+			}
+		}
+
+	n2s(p,i);
+	if ((i == 0) && (j != 0))
+		{
+		/* we need a cipher if we are not resuming a session */
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_CIPHERS_SPECIFIED);
+		goto f_err;
+		}
+	if ((p+i) >= (d+n))
+		{
+		/* not enough data */
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	if ((i > 0) && (ssl_bytes_to_cipher_list(s,p,i,&(ciphers))
+		== NULL))
+		{
+		goto err;
+		}
+	p+=i;
+
+	/* If it is a hit, check that the cipher is in the list */
+	if ((s->hit) && (i > 0))
+		{
+		j=0;
+		id=s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+		printf("client sent %d ciphers\n",sk_num(ciphers));
+#endif
+		for (i=0; i<sk_SSL_CIPHER_num(ciphers); i++)
+			{
+			c=sk_SSL_CIPHER_value(ciphers,i);
+#ifdef CIPHER_DEBUG
+			printf("client [%2d of %2d]:%s\n",
+				i,sk_num(ciphers),SSL_CIPHER_get_name(c));
+#endif
+			if (c->id == id)
+				{
+				j=1;
+				break;
+				}
+			}
+/* Disabled because it can be used in a ciphersuite downgrade
+ * attack: CVE-2010-4180.
+ */
+#if 0
+		if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
+			{
+			/* Special case as client bug workaround: the previously used cipher may
+			 * not be in the current list, the client instead might be trying to
+			 * continue using a cipher that before wasn't chosen due to server
+			 * preferences.  We'll have to reject the connection if the cipher is not
+			 * enabled, though. */
+			c = sk_SSL_CIPHER_value(ciphers, 0);
+			if (sk_SSL_CIPHER_find(SSL_get_ciphers(s), c) >= 0)
+				{
+				s->session->cipher = c;
+				j = 1;
+				}
+			}
+#endif
+		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;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_REQUIRED_CIPHER_MISSING);
+			goto f_err;
+			}
+		}
+
+	/* compression */
+	i= *(p++);
+	if ((p+i) > (d+n))
+		{
+		/* not enough data */
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	for (j=0; j<i; j++)
+		{
+		if (p[j] == 0) break;
+		}
+
+	p+=i;
+	if (j >= i)
+		{
+		/* no compress */
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_COMPRESSION_SPECIFIED);
+		goto f_err;
+		}
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extensions*/
+	if (s->version >= SSL3_VERSION)
+		{
+		if (!ssl_parse_clienthello_tlsext(s,&p,d,n))
+			{
+			OPENSSL_PUT_ERROR(SSL, 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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_SHARED_CIPHER);
+				goto f_err;
+				}
+
+			s->session->cipher=pref_cipher;
+
+			if (s->cipher_list)
+				sk_SSL_CIPHER_free(s->cipher_list);
+
+			if (s->cipher_list_by_id)
+				sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+			}
+		}
+#endif
+
+	/* Worst case, we will use the NULL compression, but if we have other
+	 * options, we will now look for them.  We have i-1 compression
+	 * algorithms from the client, starting at q. */
+	s->s3->tmp.new_compression=NULL;
+	/* If compression is disabled we'd better not try to resume a session
+	 * using compression.
+	 */
+	if (s->session->compress_meth != 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_INCONSISTENT_COMPRESSION);
+		goto f_err;
+		}
+
+	/* Given s->session->ciphers and SSL_get_ciphers, we must
+	 * pick a cipher */
+
+	if (!s->hit)
+		{
+		s->session->compress_meth=0;
+		if (s->session->ciphers != NULL)
+			sk_SSL_CIPHER_free(s->session->ciphers);
+		s->session->ciphers=ciphers;
+		if (ciphers == NULL)
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_CIPHERS_PASSED);
+			goto f_err;
+			}
+		ciphers=NULL;
+		/* 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;
+				OPENSSL_PUT_ERROR(SSL, 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;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_NO_SHARED_CIPHER);
+			goto f_err;
+			}
+		s->s3->tmp.new_cipher=c;
+		}
+	else
+		{
+		/* Session-id reuse */
+#ifdef REUSE_CIPHER_BUG
+		STACK_OF(SSL_CIPHER) *sk;
+		SSL_CIPHER *nc=NULL;
+		SSL_CIPHER *ec=NULL;
+
+		if (s->options & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)
+			{
+			sk=s->session->ciphers;
+			for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+				{
+				c=sk_SSL_CIPHER_value(sk,i);
+				if (c->algorithm_enc & SSL_eNULL)
+					nc=c;
+				if (SSL_C_IS_EXPORT(c))
+					ec=c;
+				}
+			if (nc != NULL)
+				s->s3->tmp.new_cipher=nc;
+			else if (ec != NULL)
+				s->s3->tmp.new_cipher=ec;
+			else
+				s->s3->tmp.new_cipher=s->session->cipher;
+			}
+		else
+#endif
+		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))
+			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->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)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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:
+	if (ciphers != NULL) 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;
+	unsigned long l;
+
+	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+		{
+		buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
+		p=s->s3->server_random;
+		if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0)
+			return -1;
+#endif
+		/* Do the message type and length last */
+		d=p= ssl_handshake_start(s);
+
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+
+		/* Random stuff */
+		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->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))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
+			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 */
+			*(p++)=0;
+#ifndef OPENSSL_NO_TLSEXT
+		if (ssl_prepare_serverhello_tlsext(s) <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, SSL_R_SERVERHELLO_TLSEXT);
+			return -1;
+			}
+		if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+#endif
+		/* do the header */
+		l=(p-d);
+		ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l);
+		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)
+		{
+		ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0);
+		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_ECDH
+	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_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;
+					OPENSSL_PUT_ERROR(SSL, 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;
+				OPENSSL_PUT_ERROR(SSL, 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_kEDH)
+			{
+			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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.dh != NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			if ((dh=DHparams_dup(dhp)) == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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))
+				    {
+				    OPENSSL_PUT_ERROR(SSL, 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))
+					{
+					OPENSSL_PUT_ERROR(SSL, 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_ECDH
+			if (type & SSL_kEECDH)
+			{
+			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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_MISSING_TMP_ECDH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.ecdh != NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			/* Duplicate the ECDH structure. */
+			if (ecdhp == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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))
+				    {
+				    OPENSSL_PUT_ERROR(SSL, 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))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)) 
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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))
+				{
+				OPENSSL_PUT_ERROR(SSL, 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) 
+				{
+				OPENSSL_PUT_ERROR(SSL, 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_ECDH */
+#ifndef OPENSSL_NO_PSK
+			if (type & SSL_kPSK)
+				{
+				/* reserve size for record length and PSK identity hint*/
+				n+=2+strlen(s->ctx->psk_identity_hint);
+				}
+			else
+#endif /* !OPENSSL_NO_PSK */
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			OPENSSL_PUT_ERROR(SSL, 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]);
+			n+=2+nr[i];
+			}
+
+		if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+			&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+			{
+			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))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_BUF);
+			goto err;
+			}
+		d = p = ssl_handshake_start(s);
+
+		for (i=0; i < 4 && r[i] != NULL; i++)
+			{
+			s2n(nr[i],p);
+			BN_bn2bin(r[i],p);
+			p+=nr[i];
+			}
+
+#ifndef OPENSSL_NO_ECDH
+		if (type & SSL_kEECDH) 
+			{
+			/* 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((unsigned char*)p, 
+			    (unsigned char *)encodedPoint, 
+			    encodedlen);
+			OPENSSL_free(encodedPoint);
+			encodedPoint = NULL;
+			p += encodedlen;
+			}
+#endif
+
+#ifndef OPENSSL_NO_PSK
+		if (type & SSL_kPSK)
+			{
+			/* copy PSK identity hint */
+			s2n(strlen(s->ctx->psk_identity_hint), p); 
+			strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+			p+=strlen(s->ctx->psk_identity_hint);
+			}
+#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_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)
+					{
+					OPENSSL_PUT_ERROR(SSL, 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;
+						OPENSSL_PUT_ERROR(SSL, 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))
+					{
+					OPENSSL_PUT_ERROR(SSL, 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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_UNKNOWN_PKEY_TYPE);
+				goto f_err;
+				}
+			}
+
+		ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n);
+		}
+
+	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_ECDH
+	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+	BN_CTX_free(bn_ctx);
+#endif
+	EVP_MD_CTX_cleanup(&md_ctx);
+	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;
+			nl = tls12_get_psigalgs(s, &psigs);
+			s2n(nl, p);
+			memcpy(p, psigs, nl);
+			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))
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_certificate_request, ERR_R_BUF_LIB);
+					goto err;
+					}
+				p = ssl_handshake_start(s) + n;
+				if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+					{
+					s2n(j,p);
+					i2d_X509_NAME(name,&p);
+					n+=2+j;
+					nl+=2+j;
+					}
+				else
+					{
+					d=p;
+					i2d_X509_NAME(name,&p);
+					j-=2; s2n(j,d); j+=2;
+					n+=j;
+					nl+=j;
+					}
+				}
+			}
+		/* else no CA names */
+		p = ssl_handshake_start(s) + off;
+		s2n(nl,p);
+
+		ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n);
+
+#ifdef NETSCAPE_HANG_BUG
+		if (!SSL_IS_DTLS(s))
+			{
+			p=(unsigned char *)s->init_buf->data + s->init_num;
+			/* do the header */
+			*(p++)=SSL3_MT_SERVER_DONE;
+			*(p++)=0;
+			*(p++)=0;
+			*(p++)=0;
+			s->init_num += 4;
+			}
+#endif
+
+		s->state = SSL3_ST_SW_CERT_REQ_B;
+		}
+
+	/* SSL3_ST_SW_CERT_REQ_B */
+	return ssl_do_write(s);
+err:
+	return(-1);
+	}
+
+int ssl3_get_client_key_exchange(SSL *s)
+	{
+	int i,al,ok;
+	long n;
+	unsigned long alg_k;
+	unsigned char *p;
+#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_ECDH
+	EC_KEY *srvr_ecdh = NULL;
+	EVP_PKEY *clnt_pub_pkey = NULL;
+	EC_POINT *clnt_ecpoint = NULL;
+	BN_CTX *bn_ctx = NULL; 
+#endif
+
+	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);
+	p=(unsigned char *)s->init_msg;
+
+	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_RSA
+	if (alg_k & SSL_kRSA)
+		{
+		/* 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;
+				OPENSSL_PUT_ERROR(SSL, 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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_RSA_CERTIFICATE);
+				goto f_err;
+				}
+			rsa=pkey->pkey.rsa;
+			}
+
+		/* TLS and [incidentally] DTLS{0xFEFF} */
+		if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER)
+			{
+			n2s(p,i);
+			if (n != i+2)
+				{
+				if (!(s->options & SSL_OP_TLS_D5_BUG))
+					{
+					OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
+					goto err;
+					}
+				else
+					p-=2;
+				}
+			else
+				n=i;
+			}
+
+		i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
+
+		al = -1;
+		
+		if (i != SSL_MAX_MASTER_KEY_LENGTH)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			/* OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BAD_RSA_DECRYPT); */
+			}
+
+		if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (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) &&
+				(p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+				{
+				al=SSL_AD_DECODE_ERROR;
+				/* OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
+
+				/* 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" -- an alert would
+				 * reveal that the plaintext corresponding to some ciphertext
+				 * made up by the adversary is properly formatted except
+				 * that the version number is wrong.  To avoid such attacks,
+				 * we should treat this just like any other decryption error. */
+				}
+			}
+
+		if (al != -1)
+			{
+			/* Some decryption failure -- use random value instead as countermeasure
+			 * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
+			 * (see RFC 2246, section 7.4.7.1). */
+			ERR_clear_error();
+			i = SSL_MAX_MASTER_KEY_LENGTH;
+			p[0] = s->client_version >> 8;
+			p[1] = s->client_version & 0xff;
+			if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
+				goto err;
+			}
+	
+		s->session->master_key_length=
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,
+				p,i);
+		OPENSSL_cleanse(p,i);
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_DH
+		if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+		{
+		int idx = -1;
+		EVP_PKEY *skey = NULL;
+		if (n)
+			n2s(p,i);
+		else
+			i = 0;
+		if (n && n != i+2)
+			{
+			if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+				goto err;
+				}
+			else
+				{
+				p-=2;
+				i=(int)n;
+				}
+			}
+		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;
+				OPENSSL_PUT_ERROR(SSL, 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;
+			OPENSSL_PUT_ERROR(SSL, 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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
+				goto f_err;
+				}
+			EVP_PKEY_free(clkey);
+			pub = dh_clnt->pub_key;
+			}
+		else
+			pub=BN_bin2bn(p,i,NULL);
+		if (pub == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BN_LIB);
+			goto err;
+			}
+
+		i=DH_compute_key(p,pub,dh_srvr);
+
+		if (i <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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;
+		s->session->master_key_length=
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,p,i);
+		OPENSSL_cleanse(p,i);
+		if (dh_clnt)
+			return 2;
+		}
+	else
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+		if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+		{
+		int ret = 1;
+		int field_size = 0;
+		const EC_KEY   *tkey;
+		const EC_GROUP *group;
+		const BIGNUM *priv_key;
+
+		/* initialize structures for server's ECDH key pair */
+		if ((srvr_ecdh = EC_KEY_new()) == NULL) 
+			{
+			OPENSSL_PUT_ERROR(SSL, 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))
+			{
+			OPENSSL_PUT_ERROR(SSL, 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)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		if (n == 0L) 
+			{
+			/* Client Publickey was in Client Certificate */
+
+			 if (alg_k & SSL_kEECDH)
+				 {
+				 al=SSL_AD_HANDSHAKE_FAILURE;
+				 OPENSSL_PUT_ERROR(SSL, 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;
+			   	OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+			/* Get encoded point length */
+			i = *p; 
+			p += 1;
+			if (n != 1 + i)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+				goto err;
+				}
+			if (EC_POINT_oct2point(group, 
+			    clnt_ecpoint, p, i, bn_ctx) == 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+				goto err;
+				}
+			/* p is pointing to somewhere in the buffer
+			 * currently, so set it to the start 
+			 */ 
+			p=(unsigned char *)s->init_buf->data;
+			}
+
+		/* Compute the shared pre-master secret */
+		field_size = EC_GROUP_get_degree(group);
+		if (field_size <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB);
+			goto err;
+			}
+		i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
+		if (i <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_ECDH_LIB);
+			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; 
+
+		/* Compute the master secret */
+		s->session->master_key_length = s->method->ssl3_enc-> \
+		    generate_master_secret(s, s->session->master_key, p, i);
+		
+		OPENSSL_cleanse(p, i);
+		return (ret);
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_PSK
+		if (alg_k & SSL_kPSK)
+			{
+			unsigned char *t = NULL;
+			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+			unsigned int pre_ms_len = 0, psk_len = 0;
+			int psk_err = 1;
+			char tmp_id[PSK_MAX_IDENTITY_LEN+1];
+
+			al=SSL_AD_HANDSHAKE_FAILURE;
+
+			n2s(p,i);
+			if (n != i+2)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+				goto psk_err;
+				}
+			if (i > PSK_MAX_IDENTITY_LEN)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
+				goto psk_err;
+				}
+			if (s->psk_server_callback == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_PSK_NO_SERVER_CB);
+				goto psk_err;
+				}
+
+			/* Create guaranteed NULL-terminated identity
+			 * string for the callback */
+			memcpy(tmp_id, p, i);
+			memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+			psk_len = s->psk_server_callback(s, tmp_id,
+				psk_or_pre_ms, sizeof(psk_or_pre_ms));
+			OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
+
+			if (psk_len > PSK_MAX_PSK_LEN)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto psk_err;
+				}
+			else if (psk_len == 0)
+				{
+				/* PSK related to the given identity not found */
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND);
+				al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+				goto psk_err;
+				}
+
+			/* create PSK pre_master_secret */
+			pre_ms_len=2+psk_len+2+psk_len;
+			t = psk_or_pre_ms;
+			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+			s2n(psk_len, t);
+			memset(t, 0, psk_len);
+			t+=psk_len;
+			s2n(psk_len, t);
+
+			if (s->session->psk_identity != NULL)
+				OPENSSL_free(s->session->psk_identity);
+			s->session->psk_identity = BUF_strdup((char *)p);
+			if (s->session->psk_identity == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto psk_err;
+				}
+
+			if (s->session->psk_identity_hint != NULL)
+				OPENSSL_free(s->session->psk_identity_hint);
+			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+			if (s->ctx->psk_identity_hint != NULL &&
+				s->session->psk_identity_hint == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto psk_err;
+				}
+
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key, psk_or_pre_ms, pre_ms_len);
+			psk_err = 0;
+		psk_err:
+			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+			if (psk_err != 0)
+				goto f_err;
+			}
+		else
+#endif
+		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;
+
+			/* Get our certificate private key*/
+			alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+			if (alg_a & SSL_aGOST94)
+				pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
+			else 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 ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) 
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECRYPTION_FAILED);
+				goto gerr;
+				}
+			if (p[1] == 0x81)
+				{
+				start = p+3;
+				inlen = p[2];
+				}
+			else if (p[1] < 0x80)
+				{
+				start = p+2;
+				inlen = p[1];
+				}
+			else
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECRYPTION_FAILED);
+				goto gerr;
+				}
+			if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) 
+
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECRYPTION_FAILED);
+				goto gerr;
+				}
+			/* Generate master secret */
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,premaster_secret,32);
+			/* 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;
+			else
+				goto err;
+			}
+		else
+		{
+		al=SSL_AD_HANDSHAKE_FAILURE;
+		OPENSSL_PUT_ERROR(SSL, 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_ECDH)
+err:
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EVP_PKEY_free(clnt_pub_pkey);
+	EC_POINT_free(clnt_ecpoint);
+	if (srvr_ecdh != NULL) 
+		EC_KEY_free(srvr_ecdh);
+	BN_CTX_free(bn_ctx);
+#endif
+	return(-1);
+	}
+
+int ssl3_get_cert_verify(SSL *s)
+	{
+	EVP_PKEY *pkey=NULL;
+	unsigned char *p;
+	int al,ok,ret=0;
+	long n;
+	int type=0,i,j;
+	X509 *peer;
+	const EVP_MD *md = NULL;
+	EVP_MD_CTX mctx;
+	EVP_MD_CTX_init(&mctx);
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_CERT_VRFY_A,
+		SSL3_ST_SR_CERT_VRFY_B,
+		-1,
+		516, /* Enough for 4096 bit RSA key with TLS v1.2 */
+		&ok);
+
+	if (!ok) return((int)n);
+
+	if (s->session->peer != NULL)
+		{
+		peer=s->session->peer;
+		pkey=X509_get_pubkey(peer);
+		type=X509_certificate_type(peer,pkey);
+		}
+	else
+		{
+		peer=NULL;
+		pkey=NULL;
+		}
+
+	if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
+		{
+		s->s3->tmp.reuse_message=1;
+		if ((peer != NULL) && (type & EVP_PKT_SIGN))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_MISSING_VERIFY_MESSAGE);
+			goto f_err;
+			}
+		ret=1;
+		goto end;
+		}
+
+	if (peer == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_NO_CLIENT_CERT_RECEIVED);
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		goto f_err;
+		}
+
+	if (!(type & EVP_PKT_SIGN))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		goto f_err;
+		}
+
+	if (s->s3->change_cipher_spec)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_CCS_RECEIVED_EARLY);
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		goto f_err;
+		}
+
+	/* we now have a signature that we need to verify */
+	p=(unsigned char *)s->init_msg;
+	/* 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_94 ||
+		pkey->type == NID_id_GostR3410_2001) )
+		{
+		i=64;
+		} 
+	else 
+		{	
+		if (SSL_USE_SIGALGS(s))
+			{
+			int rv = tls12_check_peer_sigalg(&md, s, p, 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
+			p += 2;
+			n -= 2;
+			}
+		n2s(p,i);
+		n-=2;
+		if (i > n)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_LENGTH_MISMATCH);
+			al=SSL_AD_DECODE_ERROR;
+			goto f_err;
+			}
+    	}
+	j=EVP_PKEY_size(pkey);
+	if ((i > j) || (n > j) || (n <= 0))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_WRONG_SIGNATURE_SIZE);
+		al=SSL_AD_DECODE_ERROR;
+		goto f_err;
+		}
+
+	if (SSL_USE_SIGALGS(s))
+		{
+		long hdatalen = 0;
+		char *hdata;
+		hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+		if (hdatalen <= 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB);
+			al=SSL_AD_INTERNAL_ERROR;
+			goto f_err;
+			}
+
+		if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
+			{
+			al=SSL_AD_DECRYPT_ERROR;
+			OPENSSL_PUT_ERROR(SSL, 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, p, i, 
+							pkey->pkey.rsa);
+		if (i < 0)
+			{
+			al=SSL_AD_DECRYPT_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_DECRYPT);
+			goto f_err;
+			}
+		if (i == 0)
+			{
+			al=SSL_AD_DECRYPT_ERROR;
+			OPENSSL_PUT_ERROR(SSL, 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,p,i,pkey->pkey.dsa);
+		if (j <= 0)
+			{
+			/* bad signature */
+			al=SSL_AD_DECRYPT_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_DSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (pkey->type == EVP_PKEY_EC)
+		{
+		j=ECDSA_verify(pkey->save_type,
+			&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+			SHA_DIGEST_LENGTH,p,i,pkey->pkey.ec);
+		if (j <= 0)
+			{
+			/* bad signature */
+			al=SSL_AD_DECRYPT_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
+	if (pkey->type == NID_id_GostR3410_94 || 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 (i!=64) {
+				fprintf(stderr,"GOST signature length is %d",i);
+			}	
+			for (idx=0;idx<64;idx++) {
+				signature[63-idx]=p[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;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
+				goto f_err;
+				}	
+		}
+	else	
+		{
+		OPENSSL_PUT_ERROR(SSL, 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);
+		}
+end:
+	if (s->s3->handshake_buffer)
+		{
+		BIO_free(s->s3->handshake_buffer);
+		s->s3->handshake_buffer = NULL;
+		s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+		}
+	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,nc,llen,n;
+	const unsigned char *p,*q;
+	unsigned char *d;
+	STACK_OF(X509) *sk=NULL;
+
+	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))
+			{
+			OPENSSL_PUT_ERROR(SSL, 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)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_WRONG_MESSAGE_TYPE);
+		goto f_err;
+		}
+	p=d=(unsigned char *)s->init_msg;
+
+	if ((sk=sk_X509_new_null()) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	n2l3(p,llen);
+	if (llen+3 != n)
+		{
+		al=SSL_AD_DECODE_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	for (nc=0; nc<llen; )
+		{
+		n2l3(p,l);
+		if ((l+nc+3) > llen)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+
+		q=p;
+		x=d2i_X509(NULL,&p,l);
+		if (x == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_ASN1_LIB);
+			goto err;
+			}
+		if (p != (q+l))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+		if (!sk_X509_push(sk,x))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		x=NULL;
+		nc+=l+3;
+		}
+
+	if (sk_X509_num(sk) <= 0)
+		{
+		/* TLS does not mind 0 certs returned */
+		if (s->version == SSL3_VERSION)
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			OPENSSL_PUT_ERROR(SSL, 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))
+			{
+			OPENSSL_PUT_ERROR(SSL, 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))
+			{
+			al=SSL_AD_INTERNAL_ERROR;
+			goto f_err;
+			}
+		}
+	else
+		{
+		i=ssl_verify_cert_chain(s,sk);
+		if (i <= 0)
+			{
+			al=ssl_verify_alarm_type(s->verify_result);
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, SSL_R_CERTIFICATE_VERIFY_FAILED);
+			goto f_err;
+			}
+		}
+
+	if (s->session->peer != NULL) /* This should not be needed */
+		X509_free(s->session->peer);
+	s->session->peer=sk_X509_shift(sk);
+	s->session->verify_result = s->verify_result;
+
+	/* With the current implementation, sess_cert will always be NULL
+	 * when we arrive here. */
+	if (s->session->sess_cert == NULL)
+		{
+		s->session->sess_cert = ssl_sess_cert_new();
+		if (s->session->sess_cert == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_certificate, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		}
+	if (s->session->sess_cert->cert_chain != NULL)
+		sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
+	s->session->sess_cert->cert_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;
+	if (0)
+		{
+f_err:
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		}
+err:
+	if (x != NULL) X509_free(x);
+	if (sk != NULL) 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)
+			{
+			/* VRS: allow null cert if auth == KRB5 */
+			if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
+			    (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_server_certificate, ERR_R_INTERNAL_ERROR);
+				return(0);
+				}
+			}
+
+		ssl3_output_cert_chain(s,cpk);
+		s->state=SSL3_ST_SW_CERT_B;
+		}
+
+	/* SSL3_ST_SW_CERT_B */
+	return ssl_do_write(s);
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+/* send a new session ticket (not necessarily for a new session) */
+int ssl3_send_newsession_ticket(SSL *s)
+	{
+	if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+		{
+		unsigned char *p, *senc, *macstart;
+		const unsigned char *const_p;
+		int len, slen_full, slen;
+		SSL_SESSION *sess;
+		unsigned int hlen;
+		EVP_CIPHER_CTX ctx;
+		HMAC_CTX hctx;
+		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 > 0xFF00)
+			return -1;
+		senc = OPENSSL_malloc(slen_full);
+		if (!senc)
+			return -1;
+		p = senc;
+		i2d_SSL_SESSION(s->session, &p);
+
+		/* 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)
+			{
+			OPENSSL_free(senc);
+			return -1;
+			}
+		sess->session_id_length = 0; /* ID is irrelevant for the ticket */
+
+		slen = i2d_SSL_SESSION(sess, NULL);
+		if (slen > slen_full) /* shouldn't ever happen */
+			{
+			OPENSSL_free(senc);
+			return -1;
+			}
+		p = senc;
+		i2d_SSL_SESSION(sess, &p);
+		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))
+			return -1;
+		p = ssl_handshake_start(s);
+		EVP_CIPHER_CTX_init(&ctx);
+		HMAC_CTX_init(&hctx);
+		/* 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)
+				{
+				OPENSSL_free(senc);
+				return -1;
+				}
+			}
+		else
+			{
+			RAND_pseudo_bytes(iv, 16);
+			EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+					tctx->tlsext_tick_aes_key, iv);
+			HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+					tlsext_tick_md(), NULL);
+			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 */
+		EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+		p += len;
+		EVP_EncryptFinal_ex(&ctx, p, &len);
+		p += len;
+		EVP_CIPHER_CTX_cleanup(&ctx);
+
+		HMAC_Update(&hctx, macstart, p - macstart);
+		HMAC_Final(&hctx, p, &hlen);
+		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);
+		ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len);
+		/* Skip ticket lifetime hint */
+		p = ssl_handshake_start(s) + 4;
+		s2n(len - 6, p);
+		s->state=SSL3_ST_SW_SESSION_TICKET_B;
+		OPENSSL_free(senc);
+		}
+
+	/* SSL3_ST_SW_SESSION_TICKET_B */
+	return ssl_do_write(s);
+	}
+
+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))
+			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;
+	int proto_len, padding_len;
+	long n;
+	const unsigned char *p;
+
+	/* Clients cannot send a NextProtocol message if we didn't see the
+	 * extension in their ClientHello */
+	if (!s->s3->next_proto_neg_seen)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+		return -1;
+		}
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_NEXT_PROTO_A,
+		SSL3_ST_SR_NEXT_PROTO_B,
+		SSL3_MT_NEXT_PROTO,
+		514,  /* See the payload format below */
+		&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)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
+		return -1;
+		}
+
+	if (n < 2)
+		return 0;  /* The body must be > 1 bytes long */
+
+	p=(unsigned char *)s->init_msg;
+
+	/* The payload looks like:
+	 *   uint8 proto_len;
+	 *   uint8 proto[proto_len];
+	 *   uint8 padding_len;
+	 *   uint8 padding[padding_len];
+	 */
+	proto_len = p[0];
+	if (proto_len + 2 > s->init_num)
+		return 0;
+	padding_len = p[proto_len + 1];
+	if (proto_len + padding_len + 2 != s->init_num)
+		return 0;
+
+	s->next_proto_negotiated = OPENSSL_malloc(proto_len);
+	if (!s->next_proto_negotiated)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_next_proto, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	memcpy(s->next_proto_negotiated, p + 1, proto_len);
+	s->next_proto_negotiated_len = proto_len;
+
+	return 1;
+	}
+# endif
+
+int tls1_send_server_supplemental_data(SSL *s)
+	{
+	size_t length = 0;
+	const unsigned char *authz, *orig_authz;
+	unsigned char *p;
+	size_t authz_length, i;
+
+	if (s->state != SSL3_ST_SW_SUPPLEMENTAL_DATA_A)
+		return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+
+	orig_authz = authz = ssl_get_authz_data(s, &authz_length);
+	if (authz == NULL)
+		{
+		/* This should never occur. */
+		return 0;
+		}
+
+	/* First we walk over the authz data to see how long the handshake
+	 * message will be. */
+	for (i = 0; i < authz_length; i++)
+		{
+		unsigned short len;
+		unsigned char type;
+
+		type = *(authz++);
+		n2s(authz, len);
+		/* n2s increments authz by 2*/
+		i += 2;
+
+		if (memchr(s->s3->tlsext_authz_client_types,
+			   type,
+			   s->s3->tlsext_authz_client_types_len) != NULL)
+			length += 1 /* authz type */ + 2 /* length */ + len;
+
+		authz += len;
+		i += len;
+		}
+
+	length += 1 /* handshake type */ +
+		  3 /* handshake length */ +
+		  3 /* supplemental data length */ +
+		  2 /* supplemental entry type */ +
+		  2 /* supplemental entry length */;
+
+	if (!BUF_MEM_grow_clean(s->init_buf, length))
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_send_server_supplemental_data, ERR_R_BUF_LIB);
+		return 0;
+		}
+
+	p = (unsigned char *)s->init_buf->data;
+	*(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+	/* Handshake length */
+	l2n3(length - 4, p);
+	/* Length of supplemental data */
+	l2n3(length - 7, p);
+	/* Supplemental data type */
+	s2n(TLSEXT_SUPPLEMENTALDATATYPE_authz_data, p);
+	/* Its length */
+	s2n(length - 11, p);
+
+	authz = orig_authz;
+
+	/* Walk over the authz again and append the selected elements. */
+	for (i = 0; i < authz_length; i++)
+		{
+		unsigned short len;
+		unsigned char type;
+
+		type = *(authz++);
+		n2s(authz, len);
+		/* n2s increments authz by 2 */
+		i += 2;
+
+		if (memchr(s->s3->tlsext_authz_client_types,
+			   type,
+			   s->s3->tlsext_authz_client_types_len) != NULL)
+			{
+			*(p++) = type;
+			s2n(len, p);
+			memcpy(p, authz, len);
+			p += len;
+			}
+
+		authz += len;
+		i += len;
+		}
+
+	s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+	s->init_num = length;
+	s->init_off = 0;
+
+	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	}
+#endif
diff --git a/ssl/srtp.h b/ssl/srtp.h
new file mode 100644
index 0000000..c0cf33e
--- /dev/null
+++ b/ssl/srtp.h
@@ -0,0 +1,145 @@
+/* ssl/tls1.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/*
+  DTLS code by Eric Rescorla <ekr@rtfm.com>
+
+  Copyright (C) 2006, Network Resonance, Inc.
+  Copyright (C) 2011, RTFM, Inc.
+*/
+
+#ifndef HEADER_D1_SRTP_H
+#define HEADER_D1_SRTP_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+     
+#define SRTP_AES128_CM_SHA1_80 0x0001
+#define SRTP_AES128_CM_SHA1_32 0x0002
+#define SRTP_AES128_F8_SHA1_80 0x0003
+#define SRTP_AES128_F8_SHA1_32 0x0004
+#define SRTP_NULL_SHA1_80      0x0005
+#define SRTP_NULL_SHA1_32      0x0006
+
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles);
+int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles);
+SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
+
+STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl);
+SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ssl/ssl.h b/ssl/ssl.h
new file mode 100644
index 0000000..91f52ce
--- /dev/null
+++ b/ssl/ssl.h
@@ -0,0 +1,2877 @@
+/* ssl/ssl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * 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.
+ */
+
+#ifndef HEADER_SSL_H
+#define HEADER_SSL_H
+
+#include <openssl/base.h>
+
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/hmac.h>
+#include <openssl/lhash.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+/* Some code expected to get the threading functions by including ssl.h. */
+#include <openssl/thread.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* SSLeay version number for ASN.1 encoding of the session information */
+/* Version 0 - initial version
+ * Version 1 - added the optional peer certificate
+ */
+#define SSL_SESSION_ASN1_VERSION 0x0001
+
+/* text strings for the ciphers */
+#define SSL_TXT_NULL_WITH_MD5		SSL2_TXT_NULL_WITH_MD5			
+#define SSL_TXT_RC4_128_WITH_MD5	SSL2_TXT_RC4_128_WITH_MD5		
+#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5	
+#define SSL_TXT_RC2_128_CBC_WITH_MD5	SSL2_TXT_RC2_128_CBC_WITH_MD5		
+#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5	
+#define SSL_TXT_IDEA_128_CBC_WITH_MD5	SSL2_TXT_IDEA_128_CBC_WITH_MD5		
+#define SSL_TXT_DES_64_CBC_WITH_MD5	SSL2_TXT_DES_64_CBC_WITH_MD5		
+#define SSL_TXT_DES_64_CBC_WITH_SHA	SSL2_TXT_DES_64_CBC_WITH_SHA		
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5	
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA	
+
+/*    VRS Additional Kerberos5 entries
+ */
+#define SSL_TXT_KRB5_DES_64_CBC_SHA   SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_RC4_128_SHA      SSL3_TXT_KRB5_RC4_128_SHA
+#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5   SSL3_TXT_KRB5_DES_64_CBC_MD5       
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5       
+#define SSL_TXT_KRB5_RC4_128_MD5      SSL3_TXT_KRB5_RC4_128_MD5
+#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5 
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA   SSL3_TXT_KRB5_DES_40_CBC_SHA 
+#define SSL_TXT_KRB5_RC2_40_CBC_SHA   SSL3_TXT_KRB5_RC2_40_CBC_SHA 
+#define SSL_TXT_KRB5_RC4_40_SHA	      SSL3_TXT_KRB5_RC4_40_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5   SSL3_TXT_KRB5_DES_40_CBC_MD5 
+#define SSL_TXT_KRB5_RC2_40_CBC_MD5   SSL3_TXT_KRB5_RC2_40_CBC_MD5 
+#define SSL_TXT_KRB5_RC4_40_MD5	      SSL3_TXT_KRB5_RC4_40_MD5
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA   SSL3_TXT_KRB5_DES_40_CBC_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5   SSL3_TXT_KRB5_DES_40_CBC_MD5
+#define SSL_TXT_KRB5_DES_64_CBC_SHA   SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5   SSL3_TXT_KRB5_DES_64_CBC_MD5
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
+#define SSL_MAX_KRB5_PRINCIPAL_LENGTH  256
+
+#define SSL_MAX_SSL_SESSION_ID_LENGTH		32
+#define SSL_MAX_SID_CTX_LENGTH			32
+
+#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES	(512/8)
+#define SSL_MAX_KEY_ARG_LENGTH			8
+#define SSL_MAX_MASTER_KEY_LENGTH		48
+
+
+/* These are used to specify which ciphers to use and not to use */
+
+#define SSL_TXT_EXP40		"EXPORT40"
+#define SSL_TXT_EXP56		"EXPORT56"
+#define SSL_TXT_LOW		"LOW"
+#define SSL_TXT_MEDIUM		"MEDIUM"
+#define SSL_TXT_HIGH		"HIGH"
+#define SSL_TXT_FIPS		"FIPS"
+
+#define SSL_TXT_kFZA		"kFZA" /* unused! */
+#define	SSL_TXT_aFZA		"aFZA" /* unused! */
+#define SSL_TXT_eFZA		"eFZA" /* unused! */
+#define SSL_TXT_FZA		"FZA"  /* unused! */
+
+#define	SSL_TXT_aNULL		"aNULL"
+#define	SSL_TXT_eNULL		"eNULL"
+#define	SSL_TXT_NULL		"NULL"
+
+#define SSL_TXT_kRSA		"kRSA"
+#define SSL_TXT_kDHr		"kDHr" 
+#define SSL_TXT_kDHd		"kDHd"
+#define SSL_TXT_kDH 		"kDH"
+#define SSL_TXT_kEDH		"kEDH"
+#define SSL_TXT_kKRB5     	"kKRB5"
+#define SSL_TXT_kECDHr		"kECDHr"
+#define SSL_TXT_kECDHe		"kECDHe"
+#define SSL_TXT_kECDH		"kECDH"
+#define SSL_TXT_kEECDH		"kEECDH"
+#define SSL_TXT_kPSK            "kPSK"
+#define SSL_TXT_kGOST		"kGOST"
+#define SSL_TXT_kSRP		"kSRP"
+
+#define	SSL_TXT_aRSA		"aRSA"
+#define	SSL_TXT_aDSS		"aDSS"
+#define	SSL_TXT_aDH		"aDH"
+#define	SSL_TXT_aECDH		"aECDH"
+#define SSL_TXT_aKRB5     	"aKRB5"
+#define SSL_TXT_aECDSA		"aECDSA"
+#define SSL_TXT_aPSK            "aPSK"
+#define SSL_TXT_aGOST94	"aGOST94"
+#define SSL_TXT_aGOST01 "aGOST01"
+#define SSL_TXT_aGOST  "aGOST"
+
+#define	SSL_TXT_DSS		"DSS"
+#define SSL_TXT_DH		"DH"
+#define SSL_TXT_EDH		"EDH" /* same as "kEDH:-ADH" */
+#define SSL_TXT_ADH		"ADH"
+#define SSL_TXT_RSA		"RSA"
+#define SSL_TXT_ECDH		"ECDH"
+#define SSL_TXT_EECDH		"EECDH" /* same as "kEECDH:-AECDH" */
+#define SSL_TXT_AECDH		"AECDH"
+#define SSL_TXT_ECDSA		"ECDSA"
+#define SSL_TXT_KRB5      	"KRB5"
+#define SSL_TXT_PSK             "PSK"
+#define SSL_TXT_SRP		"SRP"
+
+#define SSL_TXT_DES		"DES"
+#define SSL_TXT_3DES		"3DES"
+#define SSL_TXT_RC4		"RC4"
+#define SSL_TXT_RC2		"RC2"
+#define SSL_TXT_IDEA		"IDEA"
+#define SSL_TXT_SEED		"SEED"
+#define SSL_TXT_AES128		"AES128"
+#define SSL_TXT_AES256		"AES256"
+#define SSL_TXT_AES		"AES"
+#define SSL_TXT_AES_GCM		"AESGCM"
+#define SSL_TXT_CAMELLIA128	"CAMELLIA128"
+#define SSL_TXT_CAMELLIA256	"CAMELLIA256"
+#define SSL_TXT_CAMELLIA	"CAMELLIA"
+
+#define SSL_TXT_MD5		"MD5"
+#define SSL_TXT_SHA1		"SHA1"
+#define SSL_TXT_SHA		"SHA" /* same as "SHA1" */
+#define SSL_TXT_GOST94		"GOST94" 
+#define SSL_TXT_GOST89MAC		"GOST89MAC" 
+#define SSL_TXT_SHA256		"SHA256"
+#define SSL_TXT_SHA384		"SHA384"
+
+#define SSL_TXT_SSLV2		"SSLv2"
+#define SSL_TXT_SSLV3		"SSLv3"
+#define SSL_TXT_TLSV1		"TLSv1"
+#define SSL_TXT_TLSV1_1		"TLSv1.1"
+#define SSL_TXT_TLSV1_2		"TLSv1.2"
+
+#define SSL_TXT_EXP		"EXP"
+#define SSL_TXT_EXPORT		"EXPORT"
+
+#define SSL_TXT_ALL		"ALL"
+
+/*
+ * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
+ * ciphers normally not being used.
+ * Example: "RC4" will activate all ciphers using RC4 including ciphers
+ * without authentication, which would normally disabled by DEFAULT (due
+ * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT"
+ * will make sure that it is also disabled in the specific selection.
+ * COMPLEMENTOF* identifiers are portable between version, as adjustments
+ * to the default cipher setup will also be included here.
+ *
+ * COMPLEMENTOFDEFAULT does not experience the same special treatment that
+ * DEFAULT gets, as only selection is being done and no sorting as needed
+ * for DEFAULT.
+ */
+#define SSL_TXT_CMPALL		"COMPLEMENTOFALL"
+#define SSL_TXT_CMPDEF		"COMPLEMENTOFDEFAULT"
+
+/* The following cipher list is used by default.
+ * It also is substituted when an application-defined cipher list string
+ * starts with 'DEFAULT'. */
+#define SSL_DEFAULT_CIPHER_LIST	"ALL:!aNULL:!eNULL:!SSLv2"
+/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
+ * starts with a reasonable order, and all we have to do for DEFAULT is
+ * throwing out anonymous and unencrypted ciphersuites!
+ * (The latter are not actually enabled by ALL, but "ALL:RSA" would enable
+ * some of them.)
+ */
+
+/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
+#define SSL_SENT_SHUTDOWN	1
+#define SSL_RECEIVED_SHUTDOWN	2
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define SSL_FILETYPE_ASN1	X509_FILETYPE_ASN1
+#define SSL_FILETYPE_PEM	X509_FILETYPE_PEM
+
+/* This is needed to stop compilers complaining about the
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_cipher_st SSL_CIPHER;
+typedef struct ssl_session_st SSL_SESSION;
+typedef struct tls_sigalgs_st TLS_SIGALGS;
+typedef struct ssl_conf_ctx_st SSL_CONF_CTX;
+
+DECLARE_STACK_OF(SSL_CIPHER)
+
+/* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/
+typedef struct srtp_protection_profile_st
+       {
+       const char *name;
+       unsigned long id;
+       } SRTP_PROTECTION_PROFILE;
+
+DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
+
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
+#ifndef OPENSSL_NO_TLSEXT
+/* Callbacks and structures for handling custom TLS Extensions: 
+ *   cli_ext_first_cb  - sends data for ClientHello TLS Extension
+ *   cli_ext_second_cb - receives data from ServerHello TLS Extension
+ *   srv_ext_first_cb  - receives data from ClientHello TLS Extension
+ *   srv_ext_second_cb - sends data for ServerHello TLS Extension
+ *
+ *   All these functions return nonzero on success.  Zero will terminate
+ *   the handshake (and return a specific TLS Fatal alert, if the function
+ *   declaration has an "al" parameter).  -1 for the "sending" functions
+ *   will cause the TLS Extension to be omitted.
+ * 
+ *   "ext_type" is a TLS "ExtensionType" from 0-65535.
+ *   "in" is a pointer to TLS "extension_data" being provided to the cb.
+ *   "out" is used by the callback to return a pointer to "extension data"
+ *     which OpenSSL will later copy into the TLS handshake.  The contents
+ *     of this buffer should not be changed until the handshake is complete.
+ *   "inlen" and "outlen" are TLS Extension lengths from 0-65535.
+ *   "al" is a TLS "AlertDescription" from 0-255 which WILL be sent as a 
+ *     fatal TLS alert, if the callback returns zero.
+ */
+typedef int (*custom_cli_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
+					  const unsigned char **out,
+					  unsigned short *outlen, void *arg);
+typedef int (*custom_cli_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
+					   const unsigned char *in,
+					   unsigned short inlen, int *al,
+					   void *arg); 
+
+typedef int (*custom_srv_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
+					  const unsigned char *in,
+					  unsigned short inlen, int *al,
+					  void *arg);
+typedef int (*custom_srv_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
+					   const unsigned char **out,
+					   unsigned short *outlen, void *arg); 
+
+typedef struct {
+	unsigned short ext_type;
+	custom_cli_ext_first_cb_fn fn1; 
+	custom_cli_ext_second_cb_fn fn2; 
+	void *arg;
+} custom_cli_ext_record;
+
+typedef struct {
+	unsigned short ext_type;
+	custom_srv_ext_first_cb_fn fn1; 
+	custom_srv_ext_second_cb_fn fn2; 
+	void *arg;
+} custom_srv_ext_record;
+#endif
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+/* used to hold info on the particular ciphers used */
+struct ssl_cipher_st
+	{
+	int valid;
+	const char *name;		/* text name */
+	unsigned long id;		/* id, 4 bytes, first is version */
+
+	/* changed in 0.9.9: these four used to be portions of a single value 'algorithms' */
+	unsigned long algorithm_mkey;	/* key exchange algorithm */
+	unsigned long algorithm_auth;	/* server authentication */
+	unsigned long algorithm_enc;	/* symmetric encryption */
+	unsigned long algorithm_mac;	/* symmetric authentication */
+	unsigned long algorithm_ssl;	/* (major) protocol version */
+
+	unsigned long algo_strength;	/* strength and export flags */
+	unsigned long algorithm2;	/* Extra flags */
+	int strength_bits;		/* Number of bits really used */
+	int alg_bits;			/* Number of bits for algorithm */
+	};
+
+
+/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+struct ssl_method_st
+	{
+	int version;
+	int (*ssl_new)(SSL *s);
+	void (*ssl_clear)(SSL *s);
+	void (*ssl_free)(SSL *s);
+	int (*ssl_accept)(SSL *s);
+	int (*ssl_connect)(SSL *s);
+	int (*ssl_read)(SSL *s,void *buf,int len);
+	int (*ssl_peek)(SSL *s,void *buf,int len);
+	int (*ssl_write)(SSL *s,const void *buf,int len);
+	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, unsigned char *buf, int len, 
+		int peek);
+	int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
+	int (*ssl_dispatch_alert)(SSL *s);
+	long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
+	long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
+	const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
+	int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
+	int (*ssl_pending)(const SSL *s);
+	int (*num_ciphers)(void);
+	const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
+	const struct ssl_method_st *(*get_ssl_method)(int version);
+	long (*get_timeout)(void);
+	struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
+	int (*ssl_version)(void);
+	long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
+	long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
+	};
+
+/* Lets make this into an ASN.1 type structure as follows
+ * SSL_SESSION_ID ::= SEQUENCE {
+ *	version 		INTEGER,	-- structure version number
+ *	SSLversion 		INTEGER,	-- SSL version number
+ *	Cipher 			OCTET STRING,	-- the 3 byte cipher ID
+ *	Session_ID 		OCTET STRING,	-- the Session ID
+ *	Master_key 		OCTET STRING,	-- the master key
+ *	KRB5_principal		OCTET STRING	-- optional Kerberos principal
+ *	Key_Arg [ 0 ] IMPLICIT	OCTET STRING,	-- the optional Key argument
+ *	Time [ 1 ] EXPLICIT	INTEGER,	-- optional Start Time
+ *	Timeout [ 2 ] EXPLICIT	INTEGER,	-- optional Timeout ins seconds
+ *	Peer [ 3 ] EXPLICIT	X509,		-- optional Peer Certificate
+ *	Session_ID_context [ 4 ] EXPLICIT OCTET STRING,   -- the Session ID context
+ *	Verify_result [ 5 ] EXPLICIT INTEGER,   -- X509_V_... code for `Peer'
+ *	HostName [ 6 ] EXPLICIT OCTET STRING,   -- optional HostName from servername TLS extension 
+ *	PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
+ *	PSK_identity [ 8 ] EXPLICIT OCTET STRING,  -- optional PSK identity
+ *	Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
+ *	Ticket [10]             EXPLICIT OCTET STRING, -- session ticket (clients only)
+ *	Compression_meth [11]   EXPLICIT OCTET STRING, -- optional compression method
+ *	SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
+ *	}
+ * Look in ssl/ssl_asn1.c for more details
+ * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
+ */
+struct ssl_session_st
+	{
+	int ssl_version;	/* what ssl version session info is
+				 * being kept in here? */
+
+	/* only really used in SSLv2 */
+	unsigned int key_arg_length;
+	unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
+	int master_key_length;
+	unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+	/* session_id - valid? */
+	unsigned int session_id_length;
+	unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+	/* this is used to determine whether the session is being reused in
+	 * the appropriate context. It is up to the application to set this,
+	 * via SSL_new */
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+#ifndef OPENSSL_NO_PSK
+	char *psk_identity_hint;
+	char *psk_identity;
+#endif
+	/* Used to indicate that session resumption is not allowed.
+	 * Applications can also set this bit for a new session via
+	 * not_resumable_session_cb to disable session caching and tickets. */
+	int not_resumable;
+
+	/* The cert is the certificate used to establish this connection */
+	struct sess_cert_st /* SESS_CERT */ *sess_cert;
+
+	/* This is the cert for the other end.
+	 * On clients, it will be the same as sess_cert->peer_key->x509
+	 * (the latter is not enough as sess_cert is not retained
+	 * in the external representation of sessions, see ssl_asn1.c). */
+	X509 *peer;
+	/* when app_verify_callback accepts a session where the peer's certificate
+	 * is not ok, we must remember the error for session reuse: */
+	long verify_result; /* only for servers */
+
+	int references;
+	long timeout;
+	long time;
+
+	unsigned int compress_meth;	/* Need to lookup the method */
+
+	const SSL_CIPHER *cipher;
+	unsigned long cipher_id;	/* when ASN.1 loaded, this
+					 * needs to be used to load
+					 * the 'cipher' structure */
+
+	STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
+
+	CRYPTO_EX_DATA ex_data; /* application specific data */
+
+	/* These are used to make removal of session-ids more
+	 * efficient and to implement a maximum cache size. */
+	struct ssl_session_st *prev,*next;
+#ifndef OPENSSL_NO_TLSEXT
+	char *tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+	size_t tlsext_ecpointformatlist_length;
+	unsigned char *tlsext_ecpointformatlist; /* peer's list */
+	size_t tlsext_ellipticcurvelist_length;
+	unsigned char *tlsext_ellipticcurvelist; /* peer's list */
+#endif /* OPENSSL_NO_EC */
+	/* RFC4507 info */
+	unsigned char *tlsext_tick;	/* Session ticket */
+	size_t tlsext_ticklen;		/* Session ticket length */
+	long tlsext_tick_lifetime_hint;	/* Session lifetime hint in seconds */
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	/* Used by client: the proof for this session.
+	 * We store it outside the sess_cert structure, since the proof
+	 * is received before the certificate. */
+	unsigned char *audit_proof;
+	size_t audit_proof_length;
+#endif
+	};
+
+#endif
+
+#define SSL_OP_MICROSOFT_SESS_ID_BUG			0x00000001L
+#define SSL_OP_NETSCAPE_CHALLENGE_BUG			0x00000002L
+/* Allow initial connection to servers that don't support RI */
+#define SSL_OP_LEGACY_SERVER_CONNECT			0x00000004L
+#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG		0x00000008L
+#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG		0x00000010L
+#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER		0x00000020L
+#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG			0x00000040L
+#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG			0x00000080L
+#define SSL_OP_TLS_D5_BUG				0x00000100L
+#define SSL_OP_TLS_BLOCK_PADDING_BUG			0x00000200L
+
+/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */
+#define SSL_OP_MSIE_SSLV2_RSA_PADDING			0x0
+
+/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
+ * in OpenSSL 0.9.6d.  Usually (depending on the application protocol)
+ * the workaround is not needed.  Unfortunately some broken SSL/TLS
+ * implementations cannot handle it at all, which is why we include
+ * it in SSL_OP_ALL. */
+#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS              0x00000800L /* added in 0.9.6e */
+
+/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
+ *             This used to be 0x000FFFFFL before 0.9.7. */
+#define SSL_OP_ALL					0x80000BFFL
+
+/* DTLS options */
+#define SSL_OP_NO_QUERY_MTU                 0x00001000L
+/* Turn on Cookie Exchange (on relevant for servers) */
+#define SSL_OP_COOKIE_EXCHANGE              0x00002000L
+/* Don't use RFC4507 ticket extension */
+#define SSL_OP_NO_TICKET	            0x00004000L
+/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client)  */
+#define SSL_OP_CISCO_ANYCONNECT		    0x00008000L
+
+/* As server, disallow session resumption on renegotiation */
+#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
+/* Don't use compression even if supported */
+#define SSL_OP_NO_COMPRESSION				0x00020000L
+/* Permit unsafe legacy renegotiation */
+#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION	0x00040000L
+/* If set, always create a new key when using tmp_ecdh parameters */
+#define SSL_OP_SINGLE_ECDH_USE				0x00080000L
+/* If set, always create a new key when using tmp_dh parameters */
+#define SSL_OP_SINGLE_DH_USE				0x00100000L
+/* Set to always use the tmp_rsa key when doing RSA operations,
+ * even when this violates protocol specs */
+#define SSL_OP_EPHEMERAL_RSA				0x00200000L
+/* Set on servers to choose the cipher according to the server's
+ * preferences */
+#define SSL_OP_CIPHER_SERVER_PREFERENCE			0x00400000L
+/* If set, a server will allow a client to issue a SSLv3.0 version number
+ * as latest version supported in the premaster secret, even when TLSv1.0
+ * (version 3.1) was announced in the client hello. Normally this is
+ * forbidden to prevent version rollback attacks. */
+#define SSL_OP_TLS_ROLLBACK_BUG				0x00800000L
+
+#define SSL_OP_NO_SSLv2					0x01000000L
+#define SSL_OP_NO_SSLv3					0x02000000L
+#define SSL_OP_NO_TLSv1					0x04000000L
+#define SSL_OP_NO_TLSv1_2				0x08000000L
+#define SSL_OP_NO_TLSv1_1				0x10000000L
+
+#define SSL_OP_NO_DTLSv1				0x04000000L
+#define SSL_OP_NO_DTLSv1_2				0x08000000L
+
+#define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|\
+	SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2)
+
+/* These next two were never actually used for anything since SSLeay
+ * zap so we have some more flags.
+ */
+/* The next flag deliberately changes the ciphertest, this is a check
+ * for the PKCS#1 attack */
+#define SSL_OP_PKCS1_CHECK_1				0x0
+#define SSL_OP_PKCS1_CHECK_2				0x0
+
+#define SSL_OP_NETSCAPE_CA_DN_BUG			0x20000000L
+#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG		0x40000000L
+/* Make server add server-hello extension from early version of
+ * cryptopro draft, when GOST ciphersuite is negotiated. 
+ * Required for interoperability with CryptoPro CSP 3.x 
+ */
+#define SSL_OP_CRYPTOPRO_TLSEXT_BUG			0x80000000L
+
+/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
+ * when just a single record has been written): */
+#define SSL_MODE_ENABLE_PARTIAL_WRITE       0x00000001L
+/* Make it possible to retry SSL_write() with changed buffer location
+ * (buffer contents must stay the same!); this is not the default to avoid
+ * the misconception that non-blocking SSL_write() behaves like
+ * non-blocking write(): */
+#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
+/* Never bother the application with retries if the transport
+ * is blocking: */
+#define SSL_MODE_AUTO_RETRY 0x00000004L
+/* Don't attempt to automatically build certificate chain */
+#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
+/* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
+ * TLS only.)  "Released" buffers are put onto a free-list in the context
+ * or just freed (depending on the context's setting for freelist_max_len). */
+#define SSL_MODE_RELEASE_BUFFERS 0x00000010L
+/* Send the current time in the Random fields of the ClientHello and
+ * ServerHello records for compatibility with hypothetical implementations
+ * that require it.
+ */
+#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L
+#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L
+
+/* Cert related flags */
+/* Many implementations ignore some aspects of the TLS standards such as
+ * enforcing certifcate chain algorithms. When this is set we enforce them.
+ */
+#define SSL_CERT_FLAG_TLS_STRICT		0x00000001L
+
+/* Suite B modes, takes same values as certificate verify flags */
+#define SSL_CERT_FLAG_SUITEB_128_LOS_ONLY	0x10000
+/* Suite B 192 bit only mode */
+#define SSL_CERT_FLAG_SUITEB_192_LOS		0x20000
+/* Suite B 128 bit mode allowing 192 bit algorithms */
+#define SSL_CERT_FLAG_SUITEB_128_LOS		0x30000
+
+/* Perform all sorts of protocol violations for testing purposes */
+#define SSL_CERT_FLAG_BROKEN_PROTOCOL		0x10000000
+
+/* Flags for building certificate chains */
+/* Treat any existing certificates as untrusted CAs */
+#define SSL_BUILD_CHAIN_FLAG_UNTRUSTED	0x1
+/* Don't include root CA in chain */
+#define SSL_BUILD_CHAIN_FLAG_NO_ROOT	0x2
+
+/* Flags returned by SSL_check_chain */
+/* Certificate can be used with this session */
+#define CERT_PKEY_VALID		0x1
+/* Certificate can also be used for signing */
+#define CERT_PKEY_SIGN		0x2
+/* EE certificate signing algorithm OK */
+#define CERT_PKEY_EE_SIGNATURE	0x10
+/* CA signature algorithms OK */
+#define CERT_PKEY_CA_SIGNATURE	0x20
+/* EE certificate parameters OK */
+#define CERT_PKEY_EE_PARAM	0x40
+/* CA certificate parameters OK */
+#define CERT_PKEY_CA_PARAM	0x80
+/* Signing explicitly allowed as opposed to SHA1 fallback */
+#define CERT_PKEY_EXPLICIT_SIGN	0x100
+/* Client CA issuer names match (always set for server cert) */
+#define CERT_PKEY_ISSUER_NAME	0x200
+/* Cert type matches client types (always set for server cert) */
+#define CERT_PKEY_CERT_TYPE	0x400
+/* Cert chain suitable to Suite B */
+#define CERT_PKEY_SUITEB	0x800
+
+#define SSL_CONF_FLAG_CMDLINE		0x1
+#define SSL_CONF_FLAG_FILE		0x2
+#define SSL_CONF_FLAG_CLIENT		0x4
+#define SSL_CONF_FLAG_SERVER		0x8
+#define SSL_CONF_FLAG_SHOW_ERRORS	0x10
+#define SSL_CONF_FLAG_CERTIFICATE	0x20
+/* Configuration value types */
+#define SSL_CONF_TYPE_UNKNOWN		0x0
+#define SSL_CONF_TYPE_STRING		0x1
+#define SSL_CONF_TYPE_FILE		0x2
+#define SSL_CONF_TYPE_DIR		0x3
+
+/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
+ * they cannot be used to clear bits. */
+
+#define SSL_CTX_set_options(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_CTX_clear_options(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
+#define SSL_CTX_get_options(ctx) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
+#define SSL_set_options(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_clear_options(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
+#define SSL_get_options(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
+
+#define SSL_CTX_set_mode(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define SSL_CTX_clear_mode(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL)
+#define SSL_CTX_get_mode(ctx) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
+#define SSL_clear_mode(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL)
+#define SSL_set_mode(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
+#define SSL_get_mode(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mtu(ssl, mtu) \
+        SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
+
+#define SSL_get_secure_renegotiation_support(ssl) \
+	SSL_ctrl((SSL*) (ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL)
+
+#ifndef OPENSSL_NO_HEARTBEATS
+#define SSL_heartbeat(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_TLS_EXT_SEND_HEARTBEAT,0,NULL)
+#endif
+
+#define SSL_CTX_set_cert_flags(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_CERT_FLAGS,(op),NULL)
+#define SSL_set_cert_flags(s,op) \
+	SSL_ctrl((s),SSL_CTRL_CERT_FLAGS,(op),NULL)
+#define SSL_CTX_clear_cert_flags(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_CERT_FLAGS,(op),NULL)
+#define SSL_clear_cert_flags(s,op) \
+	SSL_ctrl((s),SSL_CTRL_CLEAR_CERT_FLAGS,(op),NULL)
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+
+
+#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
+#else
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */
+#endif
+
+#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT	(1024*20)
+
+/* This callback type is used inside SSL_CTX, SSL, and in the functions that set
+ * them. It is used to override the generation of SSL/TLS session IDs in a
+ * server. Return value should be zero on an error, non-zero to proceed. Also,
+ * callbacks should themselves check if the id they generate is unique otherwise
+ * the SSL handshake will fail with an error - callbacks can do this using the
+ * 'ssl' value they're passed by;
+ *      SSL_has_matching_session_id(ssl, id, *id_len)
+ * The length value passed in is set at the maximum size the session ID can be.
+ * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback
+ * can alter this length to be less if desired, but under SSLv2 session IDs are
+ * supposed to be fixed at 16 bytes so the id will be padded after the callback
+ * returns in this case. It is also an error for the callback to set the size to
+ * zero. */
+typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
+				unsigned int *id_len);
+
+typedef struct ssl_comp_st SSL_COMP;
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+struct ssl_comp_st
+	{
+	int id;
+	const char *name;
+	char *method;
+	};
+
+DECLARE_STACK_OF(SSL_COMP)
+DECLARE_LHASH_OF(SSL_SESSION);
+
+struct ssl_ctx_st
+	{
+	const SSL_METHOD *method;
+
+	STACK_OF(SSL_CIPHER) *cipher_list;
+	/* same as above but sorted for lookup */
+	STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+	struct x509_store_st /* X509_STORE */ *cert_store;
+	LHASH_OF(SSL_SESSION) *sessions;
+	/* Most session-ids that will be cached, default is
+	 * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
+	unsigned long session_cache_size;
+	struct ssl_session_st *session_cache_head;
+	struct ssl_session_st *session_cache_tail;
+
+	/* This can have one of 2 values, ored together,
+	 * SSL_SESS_CACHE_CLIENT,
+	 * SSL_SESS_CACHE_SERVER,
+	 * Default is SSL_SESSION_CACHE_SERVER, which means only
+	 * SSL_accept which cache SSL_SESSIONS. */
+	int session_cache_mode;
+
+	/* If timeout is not 0, it is the default timeout value set
+	 * when SSL_new() is called.  This has been put in to make
+	 * life easier to set things up */
+	long session_timeout;
+
+	/* If this callback is not null, it will be called each
+	 * time a session id is added to the cache.  If this function
+	 * returns 1, it means that the callback will do a
+	 * SSL_SESSION_free() when it has finished using it.  Otherwise,
+	 * on 0, it means the callback has finished with it.
+	 * If remove_session_cb is not null, it will be called when
+	 * a session-id is removed from the cache.  After the call,
+	 * OpenSSL will SSL_SESSION_free() it. */
+	int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
+	void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
+	SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
+		unsigned char *data,int len,int *copy);
+
+	struct
+		{
+		int sess_connect;	/* SSL new conn - started */
+		int sess_connect_renegotiate;/* SSL reneg - requested */
+		int sess_connect_good;	/* SSL new conne/reneg - finished */
+		int sess_accept;	/* SSL new accept - started */
+		int sess_accept_renegotiate;/* SSL reneg - requested */
+		int sess_accept_good;	/* SSL accept/reneg - finished */
+		int sess_miss;		/* session lookup misses  */
+		int sess_timeout;	/* reuse attempt on timeouted session */
+		int sess_cache_full;	/* session removed due to full cache */
+		int sess_hit;		/* session reuse actually done */
+		int sess_cb_hit;	/* session-id that was not
+					 * in the cache was
+					 * passed back via the callback.  This
+					 * indicates that the application is
+					 * supplying session-id's from other
+					 * processes - spooky :-) */
+		} stats;
+
+	int references;
+
+	/* if defined, these override the X509_verify_cert() calls */
+	int (*app_verify_callback)(X509_STORE_CTX *, void *);
+	void *app_verify_arg;
+	/* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
+	 * ('app_verify_callback' was called with just one argument) */
+
+	/* Default password callback. */
+	pem_password_cb *default_passwd_callback;
+
+	/* Default password callback user data. */
+	void *default_passwd_callback_userdata;
+
+	/* get client cert callback */
+	int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+
+    /* cookie generate callback */
+    int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int *cookie_len);
+
+    /* verify cookie callback */
+    int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int cookie_len);
+
+	CRYPTO_EX_DATA ex_data;
+
+	const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
+	const EVP_MD *md5;	/* For SSLv3/TLSv1 'ssl3-md5' */
+	const EVP_MD *sha1;   /* For SSLv3/TLSv1 'ssl3->sha1' */
+
+	STACK_OF(X509) *extra_certs;
+	STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
+
+
+	/* Default values used when no per-SSL value is defined follow */
+
+	void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
+
+	/* what we put in client cert requests */
+	STACK_OF(X509_NAME) *client_CA;
+
+
+	/* Default values to use in SSL structures follow (these are copied by SSL_new) */
+
+	unsigned long options;
+	unsigned long mode;
+	long max_cert_list;
+
+	struct cert_st /* CERT */ *cert;
+	int read_ahead;
+
+	/* callback that allows applications to peek at protocol messages */
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+	void *msg_callback_arg;
+
+	int verify_mode;
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+	int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
+
+	/* Default generate session ID callback. */
+	GEN_SESSION_CB generate_session_id;
+
+	X509_VERIFY_PARAM *param;
+
+#if 0
+	int purpose;		/* Purpose setting */
+	int trust;		/* Trust setting */
+#endif
+
+	int quiet_shutdown;
+
+	/* Maximum amount of data to send in one fragment.
+	 * actual record size can be more than this due to
+	 * padding and MAC overheads.
+	 */
+	unsigned int max_send_fragment;
+
+#ifndef OPENSSL_ENGINE
+	/* Engine to pass requests for client certs to
+	 */
+	ENGINE *client_cert_engine;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extensions servername callback */
+	int (*tlsext_servername_callback)(SSL*, int *, void *);
+	void *tlsext_servername_arg;
+	/* RFC 4507 session ticket keys */
+	unsigned char tlsext_tick_key_name[16];
+	unsigned char tlsext_tick_hmac_key[16];
+	unsigned char tlsext_tick_aes_key[16];
+	/* Callback to support customisation of ticket key setting */
+	int (*tlsext_ticket_key_cb)(SSL *ssl,
+					unsigned char *name, unsigned char *iv,
+					EVP_CIPHER_CTX *ectx,
+ 					HMAC_CTX *hctx, int enc);
+
+	/* certificate status request info */
+	/* Callback for status request */
+	int (*tlsext_status_cb)(SSL *ssl, void *arg);
+	void *tlsext_status_arg;
+
+	/* draft-rescorla-tls-opaque-prf-input-00.txt information */
+	int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
+	void *tlsext_opaque_prf_input_callback_arg;
+#endif
+
+#ifndef OPENSSL_NO_PSK
+	char *psk_identity_hint;
+	unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
+		unsigned int max_identity_len, unsigned char *psk,
+		unsigned int max_psk_len);
+	unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+		unsigned char *psk, unsigned int max_psk_len);
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+#define SSL_MAX_BUF_FREELIST_LEN_DEFAULT 32
+	unsigned int freelist_max_len;
+	struct ssl3_buf_freelist_st *wbuf_freelist;
+	struct ssl3_buf_freelist_st *rbuf_freelist;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+	/* Next protocol negotiation information */
+	/* (for experimental NPN extension). */
+
+	/* For a server, this contains a callback function by which the set of
+	 * advertised protocols can be provided. */
+	int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf,
+			                 unsigned int *len, void *arg);
+	void *next_protos_advertised_cb_arg;
+	/* For a client, this contains a callback function that selects the
+	 * next protocol from the list provided by the server. */
+	int (*next_proto_select_cb)(SSL *s, unsigned char **out,
+				    unsigned char *outlen,
+				    const unsigned char *in,
+				    unsigned int inlen,
+				    void *arg);
+	void *next_proto_select_cb_arg;
+# endif
+
+	/* ALPN information
+	 * (we are in the process of transitioning from NPN to ALPN.) */
+
+	/* For a server, this contains a callback function that allows the
+	 * server to select the protocol for the connection.
+	 *   out: on successful return, this must point to the raw protocol
+	 *        name (without the length prefix).
+	 *   outlen: on successful return, this contains the length of |*out|.
+	 *   in: points to the client's list of supported protocols in
+	 *       wire-format.
+	 *   inlen: the length of |in|. */
+	int (*alpn_select_cb)(SSL *s,
+			      const unsigned char **out,
+			      unsigned char *outlen,
+			      const unsigned char* in,
+			      unsigned int inlen,
+			      void *arg);
+	void *alpn_select_cb_arg;
+
+	/* For a client, this contains the list of supported protocols in wire
+	 * format. */
+	unsigned char* alpn_client_proto_list;
+	unsigned alpn_client_proto_list_len;
+
+        /* SRTP profiles we are willing to do from RFC 5764 */
+	STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
+# ifndef OPENSSL_NO_EC
+	/* EC extension values inherited by SSL structure */
+	size_t tlsext_ecpointformatlist_length;
+	unsigned char *tlsext_ecpointformatlist;
+	size_t tlsext_ellipticcurvelist_length;
+	unsigned char *tlsext_ellipticcurvelist;
+# endif /* OPENSSL_NO_EC */
+	int (*tlsext_authz_server_audit_proof_cb)(SSL *s, void *arg);
+	void *tlsext_authz_server_audit_proof_cb_arg;
+#endif
+
+	/* Arrays containing the callbacks for custom TLS Extensions. */
+	custom_cli_ext_record *custom_cli_ext_records;
+	size_t custom_cli_ext_records_count;
+	custom_srv_ext_record *custom_srv_ext_records;
+	size_t custom_srv_ext_records_count;
+	};
+
+#endif
+
+#define SSL_SESS_CACHE_OFF			0x0000
+#define SSL_SESS_CACHE_CLIENT			0x0001
+#define SSL_SESS_CACHE_SERVER			0x0002
+#define SSL_SESS_CACHE_BOTH	(SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)
+#define SSL_SESS_CACHE_NO_AUTO_CLEAR		0x0080
+/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */
+#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP	0x0100
+#define SSL_SESS_CACHE_NO_INTERNAL_STORE	0x0200
+#define SSL_SESS_CACHE_NO_INTERNAL \
+	(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx);
+#define SSL_CTX_sess_number(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL)
+#define SSL_CTX_sess_connect(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL)
+#define SSL_CTX_sess_connect_good(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL)
+#define SSL_CTX_sess_connect_renegotiate(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL)
+#define SSL_CTX_sess_accept_renegotiate(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept_good(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL)
+#define SSL_CTX_sess_hits(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL)
+#define SSL_CTX_sess_cb_hits(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL)
+#define SSL_CTX_sess_misses(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL)
+#define SSL_CTX_sess_timeouts(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL)
+#define SSL_CTX_sess_cache_full(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL)
+
+void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess));
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess);
+void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess));
+void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess);
+void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy));
+SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy);
+void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val));
+void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val);
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));
+int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+#ifndef OPENSSL_NO_ENGINE
+int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e);
+#endif
+void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len));
+void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len));
+#ifndef OPENSSL_NO_NEXTPROTONEG
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s,
+					   int (*cb) (SSL *ssl,
+						      const unsigned char **out,
+						      unsigned int *outlen,
+						      void *arg), void *arg);
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
+				      int (*cb) (SSL *ssl, unsigned char **out,
+						 unsigned char *outlen,
+						 const unsigned char *in,
+						 unsigned int inlen, void *arg),
+				      void *arg);
+void SSL_get0_next_proto_negotiated(const SSL *s,
+				    const unsigned char **data, unsigned *len);
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+			  const unsigned char *in, unsigned int inlen,
+			  const unsigned char *client, unsigned int client_len);
+#endif
+
+#define OPENSSL_NPN_UNSUPPORTED	0
+#define OPENSSL_NPN_NEGOTIATED	1
+#define OPENSSL_NPN_NO_OVERLAP	2
+
+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos,
+			    unsigned protos_len);
+int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos,
+			unsigned protos_len);
+void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx,
+				int (*cb) (SSL *ssl,
+					   const unsigned char **out,
+					   unsigned char *outlen,
+					   const unsigned char *in,
+					   unsigned int inlen,
+					   void *arg),
+				void *arg);
+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
+			    unsigned *len);
+
+#ifndef OPENSSL_NO_PSK
+/* the maximum length of the buffer given to callbacks containing the
+ * resulting identity/psk */
+#define PSK_MAX_IDENTITY_LEN 128
+#define PSK_MAX_PSK_LEN 256
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, 
+	unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, 
+		char *identity, unsigned int max_identity_len, unsigned char *psk,
+		unsigned int max_psk_len));
+void SSL_set_psk_client_callback(SSL *ssl, 
+	unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, 
+		char *identity, unsigned int max_identity_len, unsigned char *psk,
+		unsigned int max_psk_len));
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, 
+	unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+		unsigned char *psk, unsigned int max_psk_len));
+void SSL_set_psk_server_callback(SSL *ssl,
+	unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+		unsigned char *psk, unsigned int max_psk_len));
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint);
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint);
+const char *SSL_get_psk_identity_hint(const SSL *s);
+const char *SSL_get_psk_identity(const SSL *s);
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+/* Register callbacks to handle custom TLS Extensions as client or server.
+ * 
+ * Returns nonzero on success.  You cannot register twice for the same 
+ * extension number, and registering for an extension number already 
+ * handled by OpenSSL will succeed, but the callbacks will not be invoked.
+ *
+ * NULL can be registered for any callback function.  For the client
+ * functions, a NULL custom_cli_ext_first_cb_fn sends an empty ClientHello
+ * Extension, and a NULL custom_cli_ext_second_cb_fn ignores the ServerHello
+ * response (if any).
+ *
+ * For the server functions, a NULL custom_srv_ext_first_cb_fn means the
+ * ClientHello extension's data will be ignored, but the extension will still
+ * be noted and custom_srv_ext_second_cb_fn will still be invoked.  A NULL
+ * custom_srv_ext_second_cb doesn't send a ServerHello extension.
+ */
+int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_cli_ext_first_cb_fn fn1, 
+			       custom_cli_ext_second_cb_fn fn2, void *arg);
+
+int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_srv_ext_first_cb_fn fn1, 
+			       custom_srv_ext_second_cb_fn fn2, void *arg);
+#endif
+
+#define SSL_NOTHING	1
+#define SSL_WRITING	2
+#define SSL_READING	3
+#define SSL_X509_LOOKUP	4
+
+/* These will only be used when doing non-blocking IO */
+#define SSL_want_nothing(s)	(SSL_want(s) == SSL_NOTHING)
+#define SSL_want_read(s)	(SSL_want(s) == SSL_READING)
+#define SSL_want_write(s)	(SSL_want(s) == SSL_WRITING)
+#define SSL_want_x509_lookup(s)	(SSL_want(s) == SSL_X509_LOOKUP)
+
+#define SSL_MAC_FLAG_READ_MAC_STREAM 1
+#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+struct ssl_st
+	{
+	/* protocol version
+	 * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
+	 */
+	int version;
+	int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
+
+	const SSL_METHOD *method; /* SSLv3 */
+
+	/* There are 2 BIO's even though they are normally both the
+	 * same.  This is so data can be read and written to different
+	 * handlers */
+
+#ifndef OPENSSL_NO_BIO
+	BIO *rbio; /* used by SSL_read */
+	BIO *wbio; /* used by SSL_write */
+	BIO *bbio; /* used during session-id reuse to concatenate
+		    * messages */
+#else
+	char *rbio; /* used by SSL_read */
+	char *wbio; /* used by SSL_write */
+	char *bbio;
+#endif
+	/* This holds a variable that indicates what we were doing
+	 * when a 0 or -1 is returned.  This is needed for
+	 * non-blocking IO so we know what 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 as SSL_set_{accept/connect}_state
+	 * is called for the first time, so that "state" and
+	 * "handshake_func" are properly initialized.  But as
+	 * handshake_func is == 0 until then, we use this
+	 * test instead of an "init" member.
+	 */
+
+	int server;	/* are we the server side? - mostly used by SSL_clear*/
+
+	int new_session;/* Generate a new session or reuse an old one.
+	                 * NB: For servers, the 'new' session may actually be a previously
+	                 * cached session or even the previous session unless
+	                 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+	int quiet_shutdown;/* don't send shutdown packets */
+	int shutdown;	/* we have shut things down, 0x01 sent, 0x02
+			 * for received */
+	int state;	/* where we are */
+	int rstate;	/* where we are when reading */
+
+	BUF_MEM *init_buf;	/* buffer used during init */
+	void *init_msg;   	/* pointer to handshake message body, set by ssl3_get_message() */
+	int init_num;		/* amount read/written */
+	int init_off;		/* amount read/written */
+
+	/* used internally to point at a raw packet */
+	unsigned char *packet;
+	unsigned int packet_length;
+
+	struct ssl2_state_st *s2; /* SSLv2 variables */
+	struct ssl3_state_st *s3; /* SSLv3 variables */
+	struct dtls1_state_st *d1; /* DTLSv1 variables */
+
+	int read_ahead;		/* Read as many input bytes as possible
+	               	 	 * (for non-blocking reads) */
+
+	/* callback that allows applications to peek at protocol messages */
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+	void *msg_callback_arg;
+
+	int hit;		/* reusing a previous session */
+
+	X509_VERIFY_PARAM *param;
+
+#if 0
+	int purpose;		/* Purpose setting */
+	int trust;		/* Trust setting */
+#endif
+
+	/* crypto */
+	STACK_OF(SSL_CIPHER) *cipher_list;
+	STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+	/* These are the ones being used, the ones in SSL_SESSION are
+	 * the ones to be 'copied' into these ones */
+	int mac_flags; 
+	EVP_CIPHER_CTX *enc_read_ctx;		/* cryptographic state */
+	EVP_MD_CTX *read_hash;		/* used for mac generation */
+	char *expand;
+
+	EVP_CIPHER_CTX *enc_write_ctx;		/* cryptographic state */
+	EVP_MD_CTX *write_hash;		/* used for mac generation */
+	char *compress;	
+
+	/* session info */
+
+	/* client cert? */
+	/* This is used to hold the server certificate used */
+	struct cert_st /* CERT */ *cert;
+
+	/* the session_id_context is used to ensure sessions are only reused
+	 * in the appropriate context */
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+	/* This can also be in the session once a session is established */
+	SSL_SESSION *session;
+
+	/* Default generate session ID callback. */
+	GEN_SESSION_CB generate_session_id;
+
+	/* Used in SSL2 and SSL3 */
+	int verify_mode;	/* 0 don't care about verify failure.
+				 * 1 fail if verify fails */
+	int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
+
+	void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
+
+	int error;		/* error bytes to be written */
+	int error_code;		/* actual code */
+
+#ifndef OPENSSL_NO_PSK
+	unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
+		unsigned int max_identity_len, unsigned char *psk,
+		unsigned int max_psk_len);
+	unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
+		unsigned char *psk, unsigned int max_psk_len);
+#endif
+
+	SSL_CTX *ctx;
+	/* set this flag to 1 and a sleep(1) is put into all SSL_read()
+	 * and SSL_write() calls, good for nbio debuging :-) */
+	int debug;	
+
+	/* extra application data */
+	long verify_result;
+	CRYPTO_EX_DATA ex_data;
+
+	/* for server side, keep the list of CA_dn we can use */
+	STACK_OF(X509_NAME) *client_CA;
+
+	int references;
+	unsigned long options; /* protocol behaviour */
+	unsigned long mode; /* API behaviour */
+	long max_cert_list;
+	int first_packet;
+	int client_version;	/* what was passed, used for
+				 * SSLv3/TLS rollback check */
+	unsigned int max_send_fragment;
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extension debug callback */
+	void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
+					unsigned char *data, int len,
+					void *arg);
+	void *tlsext_debug_arg;
+	char *tlsext_hostname;
+	int servername_done;   /* no further mod of servername 
+	                          0 : call the servername extension callback.
+	                          1 : prepare 2, allow last ack just after in server callback.
+	                          2 : don't call servername callback, no ack in server hello
+	                       */
+	/* certificate status request info */
+	/* Status type or -1 if no status type */
+	int tlsext_status_type;
+	/* Expect OCSP CertificateStatus message */
+	int tlsext_status_expected;
+	/* OCSP status request only */
+	STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
+	X509_EXTENSIONS *tlsext_ocsp_exts;
+	/* OCSP response received or to be sent */
+	unsigned char *tlsext_ocsp_resp;
+	int tlsext_ocsp_resplen;
+
+	/* RFC4507 session ticket expected to be received or sent */
+	int tlsext_ticket_expected;
+#ifndef OPENSSL_NO_EC
+	size_t tlsext_ecpointformatlist_length;
+	unsigned char *tlsext_ecpointformatlist; /* our list */
+	size_t tlsext_ellipticcurvelist_length;
+	unsigned char *tlsext_ellipticcurvelist; /* our list */
+#endif /* OPENSSL_NO_EC */
+
+	/* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
+	void *tlsext_opaque_prf_input;
+	size_t tlsext_opaque_prf_input_len;
+
+	/* TLS Session Ticket extension override */
+	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+	/* TLS Session Ticket extension callback */
+	tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
+	void *tls_session_ticket_ext_cb_arg;
+
+	/* TLS pre-shared secret session resumption */
+	tls_session_secret_cb_fn tls_session_secret_cb;
+	void *tls_session_secret_cb_arg;
+
+	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	/* Next protocol negotiation. For the client, this is the protocol that
+	 * we sent in NextProtocol and is set when handling ServerHello
+	 * extensions.
+	 *
+	 * For a server, this is the client's selected_protocol from
+	 * NextProtocol and is set when handling the NextProtocol message,
+	 * before the Finished message. */
+	unsigned char *next_proto_negotiated;
+	unsigned char next_proto_negotiated_len;
+#endif
+
+#define session_ctx initial_ctx
+
+	STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;  /* What we'll do */
+	SRTP_PROTECTION_PROFILE *srtp_profile;            /* What's been chosen */
+
+	unsigned int tlsext_heartbeat;  /* Is use of the Heartbeat extension negotiated?
+	                                   0: disabled
+	                                   1: enabled
+	                                   2: enabled, but not allowed to send Requests
+	                                 */
+	unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
+	unsigned int tlsext_hb_seq;     /* HeartbeatRequest sequence number */
+
+	/* For a client, this contains the list of supported protocols in wire
+	 * format. */
+	unsigned char* alpn_client_proto_list;
+	unsigned alpn_client_proto_list_len;
+#else
+#define session_ctx ctx
+#endif /* OPENSSL_NO_TLSEXT */
+
+	int renegotiate;/* 1 if we are renegotiating.
+	                 * 2 if we are a server and are inside a handshake
+	                 * (i.e. not just sending a HelloRequest) */
+
+#ifndef OPENSSL_NO_DANE
+	unsigned char *tlsa_record;
+	int tlsa_witness;
+#endif
+	};
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <openssl/ssl2.h>
+#include <openssl/ssl3.h>
+#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
+#include <openssl/dtls1.h> /* Datagram TLS */
+#include <openssl/ssl23.h>
+#include <openssl/srtp.h>  /* Support for the use_srtp extension */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* compatibility */
+#define SSL_set_app_data(s,arg)		(SSL_set_ex_data(s,0,(char *)arg))
+#define SSL_get_app_data(s)		(SSL_get_ex_data(s,0))
+#define SSL_SESSION_set_app_data(s,a)	(SSL_SESSION_set_ex_data(s,0,(char *)a))
+#define SSL_SESSION_get_app_data(s)	(SSL_SESSION_get_ex_data(s,0))
+#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 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 */
+
+#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_CB_LOOP			0x01
+#define SSL_CB_EXIT			0x02
+#define SSL_CB_READ			0x04
+#define SSL_CB_WRITE			0x08
+#define SSL_CB_ALERT			0x4000 /* used in callback */
+#define SSL_CB_READ_ALERT		(SSL_CB_ALERT|SSL_CB_READ)
+#define SSL_CB_WRITE_ALERT		(SSL_CB_ALERT|SSL_CB_WRITE)
+#define SSL_CB_ACCEPT_LOOP		(SSL_ST_ACCEPT|SSL_CB_LOOP)
+#define SSL_CB_ACCEPT_EXIT		(SSL_ST_ACCEPT|SSL_CB_EXIT)
+#define SSL_CB_CONNECT_LOOP		(SSL_ST_CONNECT|SSL_CB_LOOP)
+#define SSL_CB_CONNECT_EXIT		(SSL_ST_CONNECT|SSL_CB_EXIT)
+#define SSL_CB_HANDSHAKE_START		0x10
+#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)
+
+/* The following 2 states are kept in ssl->rstate when reads fail,
+ * you should not need these */
+#define SSL_ST_READ_HEADER			0xF0
+#define SSL_ST_READ_BODY			0xF1
+#define SSL_ST_READ_DONE			0xF2
+
+/* Obtain latest Finished message
+ *   -- that we sent (SSL_get_finished)
+ *   -- that we expected from peer (SSL_get_peer_finished).
+ * Returns length (0 == no Finished so far), copies up to 'count' bytes. */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
+
+/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
+ * are 'ored' with SSL_VERIFY_PEER if they are desired */
+#define SSL_VERIFY_NONE			0x00
+#define SSL_VERIFY_PEER			0x01
+#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT	0x02
+#define SSL_VERIFY_CLIENT_ONCE		0x04
+
+#define OpenSSL_add_ssl_algorithms()	SSL_library_init()
+#define SSLeay_add_ssl_algorithms()	SSL_library_init()
+
+/* this is for backward compatibility */
+#if 0 /* NEW_SSLEAY */
+#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
+#define SSL_set_pref_cipher(c,n)	SSL_set_cipher_list(c,n)
+#define SSL_add_session(a,b)            SSL_CTX_add_session((a),(b))
+#define SSL_remove_session(a,b)		SSL_CTX_remove_session((a),(b))
+#define SSL_flush_sessions(a,b)		SSL_CTX_flush_sessions((a),(b))
+#endif
+/* More backward compatibility */
+#define SSL_get_cipher(s) \
+		SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_cipher_bits(s,np) \
+		SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
+#define SSL_get_cipher_version(s) \
+		SSL_CIPHER_get_version(SSL_get_current_cipher(s))
+#define SSL_get_cipher_name(s) \
+		SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_time(a)		SSL_SESSION_get_time(a)
+#define SSL_set_time(a,b)	SSL_SESSION_set_time((a),(b))
+#define SSL_get_timeout(a)	SSL_SESSION_get_timeout(a)
+#define SSL_set_timeout(a,b)	SSL_SESSION_set_timeout((a),(b))
+
+#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id)
+#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id)
+
+DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
+
+#define SSL_AD_REASON_OFFSET		1000 /* offset to get SSL_R_... value from SSL_AD_... */
+
+/* These alert types are for SSLv3 and TLSv1 */
+#define SSL_AD_CLOSE_NOTIFY		SSL3_AD_CLOSE_NOTIFY
+#define SSL_AD_UNEXPECTED_MESSAGE	SSL3_AD_UNEXPECTED_MESSAGE /* fatal */
+#define SSL_AD_BAD_RECORD_MAC		SSL3_AD_BAD_RECORD_MAC     /* fatal */
+#define SSL_AD_DECRYPTION_FAILED	TLS1_AD_DECRYPTION_FAILED
+#define SSL_AD_RECORD_OVERFLOW		TLS1_AD_RECORD_OVERFLOW
+#define SSL_AD_DECOMPRESSION_FAILURE	SSL3_AD_DECOMPRESSION_FAILURE/* fatal */
+#define SSL_AD_HANDSHAKE_FAILURE	SSL3_AD_HANDSHAKE_FAILURE/* fatal */
+#define SSL_AD_NO_CERTIFICATE		SSL3_AD_NO_CERTIFICATE /* Not for TLS */
+#define SSL_AD_BAD_CERTIFICATE		SSL3_AD_BAD_CERTIFICATE
+#define SSL_AD_UNSUPPORTED_CERTIFICATE	SSL3_AD_UNSUPPORTED_CERTIFICATE
+#define SSL_AD_CERTIFICATE_REVOKED	SSL3_AD_CERTIFICATE_REVOKED
+#define SSL_AD_CERTIFICATE_EXPIRED	SSL3_AD_CERTIFICATE_EXPIRED
+#define SSL_AD_CERTIFICATE_UNKNOWN	SSL3_AD_CERTIFICATE_UNKNOWN
+#define SSL_AD_ILLEGAL_PARAMETER	SSL3_AD_ILLEGAL_PARAMETER   /* fatal */
+#define SSL_AD_UNKNOWN_CA		TLS1_AD_UNKNOWN_CA	/* fatal */
+#define SSL_AD_ACCESS_DENIED		TLS1_AD_ACCESS_DENIED	/* fatal */
+#define SSL_AD_DECODE_ERROR		TLS1_AD_DECODE_ERROR	/* fatal */
+#define SSL_AD_DECRYPT_ERROR		TLS1_AD_DECRYPT_ERROR
+#define SSL_AD_EXPORT_RESTRICTION	TLS1_AD_EXPORT_RESTRICTION/* fatal */
+#define SSL_AD_PROTOCOL_VERSION		TLS1_AD_PROTOCOL_VERSION /* fatal */
+#define SSL_AD_INSUFFICIENT_SECURITY	TLS1_AD_INSUFFICIENT_SECURITY/* fatal */
+#define SSL_AD_INTERNAL_ERROR		TLS1_AD_INTERNAL_ERROR	/* fatal */
+#define SSL_AD_USER_CANCELLED		TLS1_AD_USER_CANCELLED
+#define SSL_AD_NO_RENEGOTIATION		TLS1_AD_NO_RENEGOTIATION
+#define SSL_AD_UNSUPPORTED_EXTENSION	TLS1_AD_UNSUPPORTED_EXTENSION
+#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
+#define SSL_AD_UNRECOGNIZED_NAME	TLS1_AD_UNRECOGNIZED_NAME
+#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
+#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE
+#define SSL_AD_UNKNOWN_PSK_IDENTITY     TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */
+
+#define SSL_ERROR_NONE			0
+#define SSL_ERROR_SSL			1
+#define SSL_ERROR_WANT_READ		2
+#define SSL_ERROR_WANT_WRITE		3
+#define SSL_ERROR_WANT_X509_LOOKUP	4
+#define SSL_ERROR_SYSCALL		5 /* look at error stack/return value/errno */
+#define SSL_ERROR_ZERO_RETURN		6
+#define SSL_ERROR_WANT_CONNECT		7
+#define SSL_ERROR_WANT_ACCEPT		8
+
+#define SSL_CTRL_NEED_TMP_RSA			1
+#define SSL_CTRL_SET_TMP_RSA			2
+#define SSL_CTRL_SET_TMP_DH			3
+#define SSL_CTRL_SET_TMP_ECDH			4
+#define SSL_CTRL_SET_TMP_RSA_CB			5
+#define SSL_CTRL_SET_TMP_DH_CB			6
+#define SSL_CTRL_SET_TMP_ECDH_CB		7
+
+#define SSL_CTRL_GET_SESSION_REUSED		8
+#define SSL_CTRL_GET_CLIENT_CERT_REQUEST	9
+#define SSL_CTRL_GET_NUM_RENEGOTIATIONS		10
+#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS	11
+#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS	12
+#define SSL_CTRL_GET_FLAGS			13
+#define SSL_CTRL_EXTRA_CHAIN_CERT		14
+
+#define SSL_CTRL_SET_MSG_CALLBACK               15
+#define SSL_CTRL_SET_MSG_CALLBACK_ARG           16
+
+/* only applies to datagram connections */
+#define SSL_CTRL_SET_MTU                17
+/* Stats */
+#define SSL_CTRL_SESS_NUMBER			20
+#define SSL_CTRL_SESS_CONNECT			21
+#define SSL_CTRL_SESS_CONNECT_GOOD		22
+#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE	23
+#define SSL_CTRL_SESS_ACCEPT			24
+#define SSL_CTRL_SESS_ACCEPT_GOOD		25
+#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE	26
+#define SSL_CTRL_SESS_HIT			27
+#define SSL_CTRL_SESS_CB_HIT			28
+#define SSL_CTRL_SESS_MISSES			29
+#define SSL_CTRL_SESS_TIMEOUTS			30
+#define SSL_CTRL_SESS_CACHE_FULL		31
+#define SSL_CTRL_OPTIONS			32
+#define SSL_CTRL_MODE				33
+
+#define SSL_CTRL_GET_READ_AHEAD			40
+#define SSL_CTRL_SET_READ_AHEAD			41
+#define SSL_CTRL_SET_SESS_CACHE_SIZE		42
+#define SSL_CTRL_GET_SESS_CACHE_SIZE		43
+#define SSL_CTRL_SET_SESS_CACHE_MODE		44
+#define SSL_CTRL_GET_SESS_CACHE_MODE		45
+
+#define SSL_CTRL_GET_MAX_CERT_LIST		50
+#define SSL_CTRL_SET_MAX_CERT_LIST		51
+
+#define SSL_CTRL_SET_MAX_SEND_FRAGMENT		52
+
+/* see tls1.h for macros based on these */
+#ifndef OPENSSL_NO_TLSEXT
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB	53
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG	54
+#define SSL_CTRL_SET_TLSEXT_HOSTNAME		55
+#define SSL_CTRL_SET_TLSEXT_DEBUG_CB		56
+#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG		57
+#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS		58
+#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS		59
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT	60
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB	61
+#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB	63
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG	64
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE	65
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS	66
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS	67
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS	68
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS	69
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP	70
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP	71
+
+#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB	72
+
+#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB	75
+#define SSL_CTRL_SET_SRP_VERIFY_PARAM_CB		76
+#define SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB		77
+
+#define SSL_CTRL_SET_SRP_ARG		78
+#define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME		79
+#define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH		80
+#define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD		81
+#ifndef OPENSSL_NO_HEARTBEATS
+#define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT				85
+#define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING		86
+#define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS	87
+#endif
+/* Callback for verifying audit proofs (client only) */
+#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB 95
+#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG 96
+#endif /* OPENSSL_NO_TLSEXT */
+
+#define DTLS_CTRL_GET_TIMEOUT		73
+#define DTLS_CTRL_HANDLE_TIMEOUT	74
+#define DTLS_CTRL_LISTEN			75
+
+#define SSL_CTRL_GET_RI_SUPPORT			76
+#define SSL_CTRL_CLEAR_OPTIONS			77
+#define SSL_CTRL_CLEAR_MODE			78
+
+#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS		82
+#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS	83
+
+#define SSL_CTRL_CHAIN				88
+#define SSL_CTRL_CHAIN_CERT			89
+
+#define SSL_CTRL_GET_CURVES			90
+#define SSL_CTRL_SET_CURVES			91
+#define SSL_CTRL_SET_CURVES_LIST		92
+#define SSL_CTRL_GET_SHARED_CURVE		93
+#define SSL_CTRL_SET_ECDH_AUTO			94
+#define SSL_CTRL_SET_SIGALGS			97
+#define SSL_CTRL_SET_SIGALGS_LIST		98
+#define SSL_CTRL_CERT_FLAGS			99
+#define SSL_CTRL_CLEAR_CERT_FLAGS		100
+#define SSL_CTRL_SET_CLIENT_SIGALGS		101
+#define SSL_CTRL_SET_CLIENT_SIGALGS_LIST	102
+#define SSL_CTRL_GET_CLIENT_CERT_TYPES		103
+#define SSL_CTRL_SET_CLIENT_CERT_TYPES		104
+#define SSL_CTRL_BUILD_CERT_CHAIN		105
+#define SSL_CTRL_SET_VERIFY_CERT_STORE		106
+#define SSL_CTRL_SET_CHAIN_CERT_STORE		107
+#define SSL_CTRL_GET_PEER_SIGNATURE_NID		108
+#define SSL_CTRL_GET_SERVER_TMP_KEY		109
+#define SSL_CTRL_GET_RAW_CIPHERLIST		110
+#define SSL_CTRL_GET_EC_POINT_FORMATS		111
+#define SSL_CTRL_GET_TLSA_RECORD		112
+#define SSL_CTRL_SET_TLSA_RECORD		113
+#define SSL_CTRL_PULL_TLSA_RECORD		114
+
+#define SSL_CTRL_GET_CHAIN_CERTS		115
+#define SSL_CTRL_SELECT_CURRENT_CERT		116
+
+#define DTLSv1_get_timeout(ssl, arg) \
+	SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
+#define DTLSv1_handle_timeout(ssl) \
+	SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
+#define DTLSv1_listen(ssl, peer) \
+	SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)
+
+#define SSL_session_reused(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
+#define SSL_num_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_clear_num_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_total_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL)
+
+#define SSL_CTX_need_tmp_RSA(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_CTX_set_tmp_rsa(ctx,rsa) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_CTX_set_tmp_dh(ctx,dh) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_need_tmp_RSA(ssl) \
+	SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_set_tmp_rsa(ssl,rsa) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_set_tmp_dh(ssl,dh) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_set_tmp_ecdh(ssl,ecdh) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_CTX_add_extra_chain_cert(ctx,x509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+#define SSL_CTX_get_extra_chain_certs(ctx,px509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,0,px509)
+#define SSL_CTX_clear_extra_chain_certs(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
+
+#define SSL_CTX_set0_chain(ctx,sk) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk)
+#define SSL_CTX_set1_chain(ctx,sk) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk)
+#define SSL_CTX_add0_chain_cert(ctx,x509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509)
+#define SSL_CTX_add1_chain_cert(ctx,x509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509)
+#define SSL_CTX_get0_chain_certs(ctx,px509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509)
+#define SSL_CTX_clear_chain_certs(ctx) \
+	SSL_CTX_set0_chain(ctx,NULL)
+#define SSL_CTX_build_cert_chain(ctx, flags) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL)
+#define SSL_CTX_select_current_cert(ctx,x509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509)
+
+#define SSL_CTX_set0_verify_cert_store(ctx,st) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st)
+#define SSL_CTX_set1_verify_cert_store(ctx,st) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st)
+#define SSL_CTX_set0_chain_cert_store(ctx,st) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st)
+#define SSL_CTX_set1_chain_cert_store(ctx,st) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st)
+
+#define SSL_set0_chain(ctx,sk) \
+	SSL_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk)
+#define SSL_set1_chain(ctx,sk) \
+	SSL_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk)
+#define SSL_add0_chain_cert(ctx,x509) \
+	SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509)
+#define SSL_add1_chain_cert(ctx,x509) \
+	SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509)
+#define SSL_get0_chain_certs(ctx,px509) \
+	SSL_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509)
+#define SSL_clear_chain_certs(ctx) \
+	SSL_set0_chain(ctx,NULL)
+#define SSL_build_cert_chain(s, flags) \
+	SSL_ctrl(s,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL)
+#define SSL_select_current_cert(ctx,x509) \
+	SSL_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509)
+
+#define SSL_set0_verify_cert_store(s,st) \
+	SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st)
+#define SSL_set1_verify_cert_store(s,st) \
+	SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st)
+#define SSL_set0_chain_cert_store(s,st) \
+	SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st)
+#define SSL_set1_chain_cert_store(s,st) \
+	SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st)
+
+#define SSL_get1_curves(ctx, s) \
+	SSL_ctrl(ctx,SSL_CTRL_GET_CURVES,0,(char *)s)
+#define SSL_CTX_set1_curves(ctx, clist, clistlen) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist)
+#define SSL_CTX_set1_curves_list(ctx, s) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s)
+#define SSL_set1_curves(ctx, clist, clistlen) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist)
+#define SSL_set1_curves_list(ctx, s) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s)
+#define SSL_get_shared_curve(s, n) \
+	SSL_ctrl(s,SSL_CTRL_GET_SHARED_CURVE,n,NULL)
+#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_ECDH_AUTO,onoff,NULL)
+#define SSL_set_ecdh_auto(s, onoff) \
+	SSL_ctrl(s,SSL_CTRL_SET_ECDH_AUTO,onoff,NULL)
+
+#define SSL_CTX_set1_sigalgs(ctx, slist, slistlen) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SIGALGS,slistlen,(int *)slist)
+#define SSL_CTX_set1_sigalgs_list(ctx, s) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SIGALGS_LIST,0,(char *)s)
+#define SSL_set1_sigalgs(ctx, slist, slistlen) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_SIGALGS,clistlen,(int *)slist)
+#define SSL_set1_sigalgs_list(ctx, s) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_SIGALGS_LIST,0,(char *)s)
+
+#define SSL_CTX_set1_client_sigalgs(ctx, slist, slistlen) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS,slistlen,(int *)slist)
+#define SSL_CTX_set1_client_sigalgs_list(ctx, s) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS_LIST,0,(char *)s)
+#define SSL_set1_client_sigalgs(ctx, slist, slistlen) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS,clistlen,(int *)slist)
+#define SSL_set1_client_sigalgs_list(ctx, s) \
+	SSL_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS_LIST,0,(char *)s)
+
+#define SSL_get0_certificate_types(s, clist) \
+	SSL_ctrl(s, SSL_CTRL_GET_CLIENT_CERT_TYPES, 0, (char *)clist)
+
+#define SSL_CTX_set1_client_certificate_types(ctx, clist, clistlen) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist)
+#define SSL_set1_client_certificate_types(s, clist, clistlen) \
+	SSL_ctrl(s,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist)
+
+#define SSL_get_peer_signature_nid(s, pn) \
+	SSL_ctrl(s,SSL_CTRL_GET_PEER_SIGNATURE_NID,0,pn)
+
+#define SSL_get_server_tmp_key(s, pk) \
+	SSL_ctrl(s,SSL_CTRL_GET_SERVER_TMP_KEY,0,pk)
+
+#define SSL_get0_raw_cipherlist(s, plst) \
+	SSL_ctrl(s,SSL_CTRL_GET_RAW_CIPHERLIST,0,(char *)plst)
+
+#define SSL_get0_ec_point_formats(s, plst) \
+	SSL_ctrl(s,SSL_CTRL_GET_EC_POINT_FORMATS,0,(char *)plst)
+
+#define SSL_set_tlsa_record(s,tlsa) \
+	SSL_ctrl(s,SSL_CTRL_SET_TLSA_RECORD,0,(void *)tlsa)
+#define SSL_pull_tlsa_record(s,host,port) \
+	SSL_ctrl(s,SSL_CTRL_PULL_TLSA_RECORD,port,host)
+
+#ifndef OPENSSL_NO_BIO
+BIO_METHOD *BIO_f_ssl(void);
+BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
+BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
+BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);
+int BIO_ssl_copy_session_id(BIO *to,BIO *from);
+void BIO_ssl_shutdown(BIO *ssl_bio);
+
+#endif
+
+int	SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
+void	SSL_CTX_free(SSL_CTX *);
+long SSL_CTX_set_timeout(SSL_CTX *ctx,long t);
+long SSL_CTX_get_timeout(const SSL_CTX *ctx);
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
+void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *);
+int SSL_want(const SSL *s);
+int	SSL_clear(SSL *s);
+
+void	SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm);
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
+int	SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits);
+char *	SSL_CIPHER_get_version(const SSL_CIPHER *c);
+const char *	SSL_CIPHER_get_name(const SSL_CIPHER *c);
+unsigned long 	SSL_CIPHER_get_id(const SSL_CIPHER *c);
+
+int	SSL_get_fd(const SSL *s);
+int	SSL_get_rfd(const SSL *s);
+int	SSL_get_wfd(const SSL *s);
+const char  * SSL_get_cipher_list(const SSL *s,int n);
+char *	SSL_get_shared_ciphers(const SSL *s, char *buf, int len);
+int	SSL_get_read_ahead(const SSL * s);
+int	SSL_pending(const SSL *s);
+#ifndef OPENSSL_NO_SOCK
+int	SSL_set_fd(SSL *s, int fd);
+int	SSL_set_rfd(SSL *s, int fd);
+int	SSL_set_wfd(SSL *s, int fd);
+#endif
+#ifndef OPENSSL_NO_BIO
+void	SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio);
+BIO *	SSL_get_rbio(const SSL *s);
+BIO *	SSL_get_wbio(const SSL *s);
+#endif
+int	SSL_set_cipher_list(SSL *s, const char *str);
+void	SSL_set_read_ahead(SSL *s, int yes);
+int	SSL_get_verify_mode(const SSL *s);
+int	SSL_get_verify_depth(const SSL *s);
+int	(*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *);
+void	SSL_set_verify(SSL *s, int mode,
+		       int (*callback)(int ok,X509_STORE_CTX *ctx));
+void	SSL_set_verify_depth(SSL *s, int depth);
+void SSL_set_cert_cb(SSL *s, int (*cb)(SSL *ssl, void *arg), void *arg);
+#ifndef OPENSSL_NO_RSA
+int	SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
+#endif
+int	SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
+int	SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
+int	SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
+int	SSL_use_certificate(SSL *ssl, X509 *x);
+int	SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
+
+#ifndef OPENSSL_NO_TLSEXT
+/* Set authz data for the current active cert. */
+int	SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz, size_t authz_length);
+int	SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length);
+/* Get the authz of type 'type' associated with the current active cert. */
+const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
+					    size_t *data_length);
+#ifndef OPENSSL_NO_STDIO
+int	SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file);
+int	SSL_use_authz_file(SSL *ssl, const char *file);
+#endif
+
+/* Set serverinfo data for the current active cert. */
+int	SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
+			       size_t serverinfo_length);
+#ifndef OPENSSL_NO_STDIO
+int	SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file);
+#endif /* NO_STDIO */
+
+#endif
+
+#ifndef OPENSSL_NO_STDIO
+int	SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
+int	SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
+int	SSL_use_certificate_file(SSL *ssl, const char *file, int type);
+int	SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
+int	SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+					    const char *file);
+#ifndef OPENSSL_SYS_VMS
+#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */
+int	SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+					   const char *dir);
+#endif
+#endif
+
+#endif
+
+void	SSL_load_error_strings(void );
+const char *SSL_state_string(const SSL *s);
+const char *SSL_rstate_string(const SSL *s);
+const char *SSL_state_string_long(const SSL *s);
+const char *SSL_rstate_string_long(const SSL *s);
+long	SSL_SESSION_get_time(const SSL_SESSION *s);
+long	SSL_SESSION_set_time(SSL_SESSION *s, long t);
+long	SSL_SESSION_get_timeout(const SSL_SESSION *s);
+long	SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
+void	SSL_copy_session_id(SSL *to,const SSL *from);
+X509 *SSL_SESSION_get0_peer(SSL_SESSION *s);
+int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
+			       unsigned int sid_ctx_len);
+
+SSL_SESSION *SSL_SESSION_new(void);
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s,
+					unsigned int *len);
+unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s);
+#ifndef OPENSSL_NO_FP_API
+int	SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
+#endif
+#ifndef OPENSSL_NO_BIO
+int	SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s,
+	size_t *proof_length);
+#endif
+void	SSL_SESSION_free(SSL_SESSION *ses);
+int	i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
+int	SSL_set_session(SSL *to, SSL_SESSION *session);
+int	SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
+int	SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
+int	SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
+int	SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
+int	SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+					unsigned int id_len);
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp,
+			     long length);
+
+#ifdef HEADER_X509_H
+X509 *	SSL_get_peer_certificate(const SSL *s);
+#endif
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx);
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *);
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,
+			int (*callback)(int, X509_STORE_CTX *));
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth);
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg);
+void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb)(SSL *ssl, void *arg), void *arg);
+#ifndef OPENSSL_NO_RSA
+int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
+#endif
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len);
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
+int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx,
+	const unsigned char *d, long len);
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d);
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx);
+int SSL_check_private_key(const SSL *ctx);
+
+int	SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+				       unsigned int sid_ctx_len);
+
+SSL *	SSL_new(SSL_CTX *ctx);
+int	SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+				   unsigned int sid_ctx_len);
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose);
+int SSL_set_purpose(SSL *s, int purpose);
+int SSL_CTX_set_trust(SSL_CTX *s, int trust);
+int SSL_set_trust(SSL *s, int trust);
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm);
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm);
+
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx);
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl);
+
+void	SSL_certs_clear(SSL *s);
+void	SSL_free(SSL *ssl);
+int 	SSL_accept(SSL *ssl);
+int 	SSL_connect(SSL *ssl);
+int 	SSL_read(SSL *ssl,void *buf,int num);
+int 	SSL_peek(SSL *ssl,void *buf,int num);
+int 	SSL_write(SSL *ssl,const void *buf,int num);
+long	SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
+long	SSL_callback_ctrl(SSL *, int, void (*)(void));
+long	SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
+long	SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
+
+int	SSL_get_error(const SSL *s,int ret_code);
+const char *SSL_get_version(const SSL *s);
+
+/* This sets the 'default' SSL version that SSL_new() will create */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth);
+
+const SSL_METHOD *SSLv3_method(void);		/* SSLv3 */
+const SSL_METHOD *SSLv3_server_method(void);	/* SSLv3 */
+const SSL_METHOD *SSLv3_client_method(void);	/* SSLv3 */
+
+const SSL_METHOD *SSLv23_method(void);	/* SSLv3 but can rollback to v2 */
+const SSL_METHOD *SSLv23_server_method(void);	/* SSLv3 but can rollback to v2 */
+const SSL_METHOD *SSLv23_client_method(void);	/* SSLv3 but can rollback to v2 */
+
+const SSL_METHOD *TLSv1_method(void);		/* TLSv1.0 */
+const SSL_METHOD *TLSv1_server_method(void);	/* TLSv1.0 */
+const SSL_METHOD *TLSv1_client_method(void);	/* TLSv1.0 */
+
+const SSL_METHOD *TLSv1_1_method(void);		/* TLSv1.1 */
+const SSL_METHOD *TLSv1_1_server_method(void);	/* TLSv1.1 */
+const SSL_METHOD *TLSv1_1_client_method(void);	/* TLSv1.1 */
+
+const SSL_METHOD *TLSv1_2_method(void);		/* TLSv1.2 */
+const SSL_METHOD *TLSv1_2_server_method(void);	/* TLSv1.2 */
+const SSL_METHOD *TLSv1_2_client_method(void);	/* TLSv1.2 */
+
+
+const SSL_METHOD *DTLSv1_method(void);		/* DTLSv1.0 */
+const SSL_METHOD *DTLSv1_server_method(void);	/* DTLSv1.0 */
+const SSL_METHOD *DTLSv1_client_method(void);	/* DTLSv1.0 */
+
+const SSL_METHOD *DTLSv1_2_method(void);	/* DTLSv1.2 */
+const SSL_METHOD *DTLSv1_2_server_method(void);	/* DTLSv1.2 */
+const SSL_METHOD *DTLSv1_2_client_method(void);	/* DTLSv1.2 */
+
+const SSL_METHOD *DTLS_method(void);		/* DTLS 1.0 and 1.2 */
+const SSL_METHOD *DTLS_server_method(void);	/* DTLS 1.0 and 1.2 */
+const SSL_METHOD *DTLS_client_method(void);	/* DTLS 1.0 and 1.2 */
+
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
+
+int SSL_do_handshake(SSL *s);
+int SSL_renegotiate(SSL *s);
+int SSL_renegotiate_abbreviated(SSL *s);
+int SSL_renegotiate_pending(SSL *s);
+int SSL_shutdown(SSL *s);
+
+const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx);
+const SSL_METHOD *SSL_get_ssl_method(SSL *s);
+int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
+const char *SSL_alert_type_string_long(int value);
+const char *SSL_alert_type_string(int value);
+const char *SSL_alert_desc_string_long(int value);
+const char *SSL_alert_desc_string(int value);
+
+void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list);
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list);
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s);
+int SSL_add_client_CA(SSL *ssl,X509 *x);
+int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x);
+
+void SSL_set_connect_state(SSL *s);
+void SSL_set_accept_state(SSL *s);
+
+long SSL_get_default_timeout(const SSL *s);
+
+int SSL_library_init(void );
+
+char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size);
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
+
+X509 *SSL_get_certificate(const SSL *ssl);
+/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(const SSL *ssl);
+
+X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx);
+EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx);
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode);
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx);
+void SSL_set_quiet_shutdown(SSL *ssl,int mode);
+int SSL_get_quiet_shutdown(const SSL *ssl);
+void SSL_set_shutdown(SSL *ssl,int mode);
+int SSL_get_shutdown(const SSL *ssl);
+int SSL_version(const SSL *ssl);
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+	const char *CApath);
+#define SSL_get0_session SSL_get_session /* just peek at pointer */
+SSL_SESSION *SSL_get_session(const SSL *ssl);
+SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx);
+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);
+int SSL_state(const SSL *ssl);
+void SSL_set_state(SSL *ssl, int state);
+
+void SSL_set_verify_result(SSL *ssl,long v);
+long SSL_get_verify_result(const SSL *ssl);
+
+int SSL_set_ex_data(SSL *ssl,int idx,void *data);
+void *SSL_get_ex_data(const SSL *ssl,int idx);
+int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data);
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx);
+int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data);
+void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx);
+int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void );
+
+#define SSL_CTX_sess_set_cache_size(ctx,t) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
+#define SSL_CTX_sess_get_cache_size(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL)
+#define SSL_CTX_set_session_cache_mode(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
+#define SSL_CTX_get_session_cache_mode(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL)
+
+#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx)
+#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m)
+#define SSL_CTX_get_read_ahead(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL)
+#define SSL_CTX_set_read_ahead(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL)
+#define SSL_CTX_get_max_cert_list(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_CTX_set_max_cert_list(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+#define SSL_get_max_cert_list(ssl) \
+	SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_set_max_cert_list(ssl,m) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+
+#define SSL_CTX_set_max_send_fragment(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+#define SSL_set_max_send_fragment(ssl,m) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+
+     /* NB: the keylength is only applicable when is_export is true */
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
+				  RSA *(*cb)(SSL *ssl,int is_export,
+					     int keylength));
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,
+				  RSA *(*cb)(SSL *ssl,int is_export,
+					     int keylength));
+#endif
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
+				 DH *(*dh)(SSL *ssl,int is_export,
+					   int keylength));
+void SSL_set_tmp_dh_callback(SSL *ssl,
+				 DH *(*dh)(SSL *ssl,int is_export,
+					   int keylength));
+#endif
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+void SSL_set_tmp_ecdh_callback(SSL *ssl,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+#endif
+
+const void *SSL_get_current_compression(SSL *s);
+const void *SSL_get_current_expansion(SSL *s);
+const char *SSL_COMP_get_name(const void *comp);
+void *SSL_COMP_get_compression_methods(void);
+int SSL_COMP_add_compression_method(int id,void *cm);
+
+const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr);
+
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+				  void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
+void SSL_set_debug(SSL *s, int debug);
+int SSL_cache_hit(SSL *s);
+int SSL_is_server(SSL *s);
+
+SSL_CONF_CTX *SSL_CONF_CTX_new(void);
+int SSL_CONF_CTX_finish(SSL_CONF_CTX *cctx);
+void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx);
+unsigned int SSL_CONF_CTX_set_flags(SSL_CONF_CTX *cctx, unsigned int flags);
+unsigned int SSL_CONF_CTX_clear_flags(SSL_CONF_CTX *cctx, unsigned int flags);
+int SSL_CONF_CTX_set1_prefix(SSL_CONF_CTX *cctx, const char *pre);
+
+void SSL_CONF_CTX_set_ssl(SSL_CONF_CTX *cctx, SSL *ssl);
+void SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *cctx, SSL_CTX *ctx);
+
+int SSL_CONF_cmd(SSL_CONF_CTX *cctx, const char *cmd, const char *value);
+int SSL_CONF_cmd_argv(SSL_CONF_CTX *cctx, int *pargc, char ***pargv);
+int SSL_CONF_cmd_value_type(SSL_CONF_CTX *cctx, const char *cmd);
+
+#ifndef OPENSSL_NO_SSL_TRACE
+void SSL_trace(int write_p, int version, int content_type,
+		const void *buf, size_t len, SSL *ssl, void *arg);
+const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c);
+#endif
+
+unsigned char *SSL_get_tlsa_record_byname(const char *name,int port,int type);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_SSL_strings(void);
+
+
+#ifdef  __cplusplus
+}
+#endif
+#define SSL_F_SSL_use_PrivateKey_file 100
+#define SSL_F_dtls1_write_app_data_bytes 101
+#define SSL_F_ssl_cipher_process_rulestr 102
+#define SSL_F_SSL_set_session_id_context 103
+#define SSL_F_SSL_read 104
+#define SSL_F_ssl_cert_new 105
+#define SSL_F_dtls1_heartbeat 106
+#define SSL_F_ssl3_digest_cached_records 107
+#define SSL_F_SSL_set_wfd 108
+#define SSL_F_SSL_CTX_use_serverinfo 109
+#define SSL_F_ssl_set_pkey 110
+#define SSL_F_SSL_CTX_use_certificate 111
+#define SSL_F_dtls1_read_bytes 112
+#define SSL_F_ssl23_write 113
+#define SSL_F_ssl3_check_client_hello 114
+#define SSL_F_SSL_use_certificate_ASN1 115
+#define SSL_F_ssl_verify_cert_chain 116
+#define SSL_F_ssl_parse_serverhello_renegotiate_ext 117
+#define SSL_F_ssl_undefined_const_function 118
+#define SSL_F_ssl3_get_server_certificate 119
+#define SSL_F_tls1_get_server_supplemental_data 120
+#define SSL_F_dtls1_buffer_record 121
+#define SSL_F_ssl_prepare_clienthello_tlsext 122
+#define SSL_F_ssl3_get_server_hello 123
+#define SSL_F_ssl3_send_client_key_exchange 124
+#define SSL_F_ssl3_write_bytes 125
+#define SSL_F_SSL_use_RSAPrivateKey_file 126
+#define SSL_F_ssl_bad_method 127
+#define SSL_F_ssl3_connect 128
+#define SSL_F_dtls1_connect 129
+#define SSL_F_SSL_use_RSAPrivateKey 130
+#define SSL_F_tls1_PRF 131
+#define SSL_F_ssl_bytes_to_cipher_list 132
+#define SSL_F_ssl3_do_change_cipher_spec 133
+#define SSL_F_SSL_SESSION_set1_id_context 134
+#define SSL_F_ssl_add_serverhello_tlsext 135
+#define SSL_F_read_authz 136
+#define SSL_F_ssl3_get_client_hello 137
+#define SSL_F_ssl3_get_certificate_request 138
+#define SSL_F_authz_find_data 139
+#define SSL_F_ssl_add_cert_to_buf 140
+#define SSL_F_ssl_add_serverhello_renegotiate_ext 141
+#define SSL_F_ssl3_get_message 142
+#define SSL_F_ssl_check_srvr_ecc_cert_and_alg 143
+#define SSL_F_ssl_parse_clienthello_tlsext 144
+#define SSL_F_SSL_add_file_cert_subjects_to_stack 145
+#define SSL_F_ssl3_ctx_ctrl 146
+#define SSL_F_ssl3_get_record 147
+#define SSL_F_SSL_CTX_use_RSAPrivateKey 148
+#define SSL_F_SSL_use_certificate_file 149
+#define SSL_F_SSL_CTX_use_serverinfo_file 150
+#define SSL_F_SSL_load_client_CA_file 151
+#define SSL_F_dtls1_preprocess_fragment 152
+#define SSL_F_SSL_CTX_check_private_key 153
+#define SSL_F_ssl3_get_cert_status 154
+#define SSL_F_printf 155
+#define SSL_F_SSL_CTX_new 156
+#define SSL_F_ssl23_accept 157
+#define SSL_F_SSL_use_authz 158
+#define SSL_F_ssl_undefined_function 159
+#define SSL_F_dtls1_send_hello_verify_request 160
+#define SSL_F_ssl_build_cert_chain 161
+#define SSL_F_SSL_SESSION_print_fp 162
+#define SSL_F_tls1_change_cipher_state 163
+#define SSL_F_tls12_check_peer_sigalg 164
+#define SSL_F_ssl_sess_cert_new 165
+#define SSL_F_ssl3_read_bytes 166
+#define SSL_F_dtls1_get_hello_verify 167
+#define SSL_F_tls1_cert_verify_mac 168
+#define SSL_F_ssl23_client_hello 169
+#define SSL_F_SSL_shutdown 170
+#define SSL_F_ssl_init_wbio_buffer 171
+#define SSL_F_SSL_use_certificate 172
+#define SSL_F_SSL_CTX_use_RSAPrivateKey_ASN1 173
+#define SSL_F_ssl_set_authz 174
+#define SSL_F_ssl23_peek 175
+#define SSL_F_SSL_use_psk_identity_hint 176
+#define SSL_F_ssl3_get_cert_verify 177
+#define SSL_F_ssl_ctx_make_profiles 178
+#define SSL_F_ssl_add_clienthello_use_srtp_ext 179
+#define SSL_F_ssl3_get_client_key_exchange 180
+#define SSL_F_do_ssl3_write 181
+#define SSL_F_ssl3_handshake_mac 182
+#define SSL_F_tls1_setup_key_block 183
+#define SSL_F_SSL_set_fd 184
+#define SSL_F_SSL_check_private_key 185
+#define SSL_F_ssl3_send_client_verify 186
+#define SSL_F_ssl3_write_pending 187
+#define SSL_F_ssl_cert_inst 188
+#define SSL_F_ssl3_change_cipher_state 189
+#define SSL_F_ssl23_get_server_hello 190
+#define SSL_F_SSL_write 191
+#define SSL_F_ssl_get_sign_pkey 192
+#define SSL_F_ssl_set_cert 193
+#define SSL_F_SSL_CTX_use_RSAPrivateKey_file 194
+#define SSL_F_SSL_CTX_use_authz 195
+#define SSL_F_ssl_get_new_session 196
+#define SSL_F_SSL_set_session_ticket_ext 197
+#define SSL_F_ssl_add_clienthello_renegotiate_ext 198
+#define SSL_F_ssl3_send_server_key_exchange 199
+#define SSL_F_fprintf 200
+#define SSL_F_ssl3_get_new_session_ticket 201
+#define SSL_F_SSL_CTX_use_certificate_ASN1 202
+#define SSL_F_ssl_add_cert_chain 203
+#define SSL_F_ssl_create_cipher_list 204
+#define SSL_F_ssl3_callback_ctrl 205
+#define SSL_F_SSL_CTX_set_cipher_list 206
+#define SSL_F_ssl3_send_certificate_request 207
+#define SSL_F_SSL_use_PrivateKey_ASN1 208
+#define SSL_F_SSL_CTX_use_certificate_chain_file 209
+#define SSL_F_SSL_SESSION_new 210
+#define SSL_F_check_suiteb_cipher_list 211
+#define SSL_F_ssl_scan_clienthello_tlsext 212
+#define SSL_F_ssl3_client_hello 213
+#define SSL_F_SSL_use_RSAPrivateKey_ASN1 214
+#define SSL_F_ssl3_ctrl 215
+#define SSL_F_ssl3_setup_write_buffer 216
+#define SSL_F_ssl_parse_serverhello_use_srtp_ext 217
+#define SSL_F_ssl3_get_key_exchange 218
+#define SSL_F_ssl3_send_server_hello 219
+#define SSL_F_SSL_add_dir_cert_subjects_to_stack 220
+#define SSL_F_ssl_check_serverhello_tlsext 221
+#define SSL_F_ssl3_get_server_done 222
+#define SSL_F_ssl3_check_cert_and_algorithm 223
+#define SSL_F_do_dtls1_write 224
+#define SSL_F_dtls1_check_timeout_num 225
+#define SSL_F_tls1_export_keying_material 226
+#define SSL_F_SSL_CTX_set_session_id_context 227
+#define SSL_F_SSL_set_rfd 228
+#define SSL_F_ssl3_send_client_certificate 229
+#define SSL_F_ssl_cert_dup 230
+#define SSL_F_dtls1_process_record 231
+#define SSL_F_ssl_new 232
+#define SSL_F_ssl_get_server_cert_index 233
+#define SSL_F_tls1_send_server_supplemental_data 234
+#define SSL_F_D2I_SSL_SESSION 235
+#define SSL_F_ssl_cipher_strength_sort 236
+#define SSL_F_dtls1_get_message 237
+#define SSL_F_ssl23_connect 238
+#define SSL_F_tls1_heartbeat 239
+#define SSL_F_ssl3_read_n 240
+#define SSL_F_ssl_get_prev_session 241
+#define SSL_F_ssl_parse_clienthello_renegotiate_ext 242
+#define SSL_F_ssl3_setup_read_buffer 243
+#define SSL_F_SSL_CTX_set_ssl_version 244
+#define SSL_F_SSL_peek 245
+#define SSL_F_ssl3_send_server_certificate 246
+#define SSL_F_SSL_do_handshake 247
+#define SSL_F_ssl_undefined_void_function 248
+#define SSL_F_ssl_add_serverhello_use_srtp_ext 249
+#define SSL_F_fclose 250
+#define SSL_F_SSL_use_PrivateKey 251
+#define SSL_F_SSL_CTX_use_certificate_file 252
+#define SSL_F_SSL_CTX_use_PrivateKey 253
+#define SSL_F_SSL_set_session 254
+#define SSL_F_SSL_CTX_use_psk_identity_hint 255
+#define SSL_F_ssl_scan_serverhello_tlsext 256
+#define SSL_F_ssl23_read 257
+#define SSL_F_ssl_parse_clienthello_use_srtp_ext 258
+#define SSL_F_ssl3_accept 259
+#define SSL_F_ssl3_get_client_certificate 260
+#define SSL_F_SSL_CTX_use_PrivateKey_ASN1 261
+#define SSL_F_dtls1_get_message_fragment 262
+#define SSL_F_SSL_clear 263
+#define SSL_F_dtls1_accept 264
+#define SSL_F_ssl3_get_next_proto 265
+#define SSL_F_SSL_set_cipher_list 266
+#define SSL_F_ssl_add_clienthello_tlsext 267
+#define SSL_F_ssl23_get_client_hello 268
+#define SSL_F_SSL_CTX_use_PrivateKey_file 269
+#define SSL_F_ssl3_get_finished 270
+#define SSL_F_ssl3_generate_key_block 271
+#define SSL_F_ssl3_setup_key_block 272
+#define SSL_F_SSL_new 273
+#define SSL_F_ssl_parse_serverhello_tlsext 274
+#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 100
+#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 101
+#define SSL_R_INVALID_NULL_CMD_NAME 102
+#define SSL_R_BAD_RSA_DECRYPT 103
+#define SSL_R_NO_SHARED_CIPHER 104
+#define SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH 105
+#define SSL_R_SSL_HANDSHAKE_FAILURE 106
+#define SSL_R_INVALID_TICKET_KEYS_LENGTH 107
+#define SSL_R_PEER_ERROR 108
+#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 109
+#define SSL_R_INCONSISTENT_COMPRESSION 110
+#define SSL_R_BAD_HELLO_REQUEST 111
+#define SSL_R_NULL_SSL_METHOD_PASSED 112
+#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 113
+#define SSL_R_BAD_ECDSA_SIGNATURE 114
+#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 115
+#define SSL_R_BAD_DH_PUB_KEY_LENGTH 116
+#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 117
+#define SSL_R_APP_DATA_IN_HANDSHAKE 118
+#define SSL_R_NO_PEM_EXTENSIONS 119
+#define SSL_R_BAD_SRP_B_LENGTH 120
+#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 121
+#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 122
+#define SSL_R_MISSING_SRP_PARAM 123
+#define SSL_R_MISSING_RSA_SIGNING_CERT 124
+#define SSL_R_MISSING_DSA_SIGNING_CERT 125
+#define SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE 126
+#define SSL_R_UNEXPECTED_RECORD 127
+#define SSL_R_BAD_DIGEST_LENGTH 128
+#define SSL_R_READ_TIMEOUT_EXPIRED 129
+#define SSL_R_KRB5_C_GET_CRED 130
+#define SSL_R_NULL_SSL_CTX 131
+#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 132
+#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 133
+#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 134
+#define SSL_R_SSL3_SESSION_ID_TOO_LONG 135
+#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 136
+#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 137
+#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 138
+#define SSL_R_COOKIE_MISMATCH 139
+#define SSL_R_UNINITIALIZED 140
+#define SSL_R_BAD_CHANGE_CIPHER_SPEC 141
+#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 142
+#define SSL_R_BAD_SRP_G_LENGTH 143
+#define SSL_R_NO_CERTIFICATE_ASSIGNED 144
+#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 145
+#define SSL_R_PEM_NAME_TOO_SHORT 146
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 147
+#define SSL_R_PROTOCOL_IS_SHUTDOWN 148
+#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 149
+#define SSL_R_WRONG_MESSAGE_TYPE 150
+#define SSL_R_BAD_RSA_MODULUS_LENGTH 151
+#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 152
+#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 153
+#define SSL_R_NO_CLIENT_CERT_RECEIVED 154
+#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 155
+#define SSL_R_CERT_LENGTH_MISMATCH 156
+#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 157
+#define SSL_R_DUPLICATE_COMPRESSION_ID 158
+#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT 159
+#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 160
+#define SSL_R_DATA_LENGTH_TOO_LONG 161
+#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 162
+#define SSL_R_WRONG_SIGNATURE_LENGTH 163
+#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 164
+#define SSL_R_WRONG_VERSION_NUMBER 165
+#define SSL_R_RECORD_TOO_LARGE 166
+#define SSL_R_BIO_NOT_SET 167
+#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 168
+#define SSL_R_TLSV1_ALERT_DECODE_ERROR 169
+#define SSL_R_UNKNOWN_PKEY_TYPE 170
+#define SSL_R_CIPHER_CODE_WRONG_LENGTH 171
+#define SSL_R_SSL_SESSION_ID_CONFLICT 172
+#define SSL_R_INVALID_COMMAND 173
+#define SSL_R_NO_PROTOCOLS_AVAILABLE 174
+#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 175
+#define SSL_R_LIBRARY_BUG 176
+#define SSL_R_UNSUPPORTED_CIPHER 177
+#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 178
+#define SSL_R_WRONG_SIGNATURE_TYPE 179
+#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 180
+#define SSL_R_PSK_NO_SERVER_CB 181
+#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 182
+#define SSL_R_INVALID_TRUST 183
+#define SSL_R_PARSE_TLSEXT 184
+#define SSL_R_NO_SRTP_PROFILES 185
+#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 186
+#define SSL_R_UNKNOWN_STATE 187
+#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 188
+#define SSL_R_BAD_WRITE_RETRY 189
+#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 190
+#define SSL_R_BAD_AUTHENTICATION_TYPE 191
+#define SSL_R_BAD_MAC_DECODE 192
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 193
+#define SSL_R_UNKNOWN_DIGEST 194
+#define SSL_R_INVALID_AUTHZ_DATA 195
+#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 196
+#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 197
+#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 198
+#define SSL_R_NO_PUBLICKEY 199
+#define SSL_R_MISSING_TMP_RSA_PKEY 200
+#define SSL_R_INVALID_AUDIT_PROOF 201
+#define SSL_R_BAD_DH_G_LENGTH 202
+#define SSL_R_BAD_RSA_ENCRYPT 203
+#define SSL_R_PACKET_LENGTH_TOO_LONG 204
+#define SSL_R_BAD_DECOMPRESSION 205
+#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 206
+#define SSL_R_BAD_RSA_SIGNATURE 207
+#define SSL_R_TLSV1_UNRECOGNIZED_NAME 208
+#define SSL_R_SRP_A_CALC 209
+#define SSL_R_ILLEGAL_PADDING 210
+#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 211
+#define SSL_R_PEM_NAME_BAD_PREFIX 212
+#define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 213
+#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 214
+#define SSL_R_BAD_SSL_FILETYPE 215
+#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 216
+#define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 217
+#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 218
+#define SSL_R_KRB5_S_TKT_EXPIRED 219
+#define SSL_R_LIBRARY_HAS_NO_CIPHERS 220
+#define SSL_R_NO_CIPHERS_SPECIFIED 221
+#define SSL_R_BAD_SIGNATURE 222
+#define SSL_R_MISSING_DH_DSA_CERT 223
+#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 224
+#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 225
+#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 226
+#define SSL_R_NO_CLIENT_CERT_METHOD 227
+#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 228
+#define SSL_R_CERTIFICATE_VERIFY_FAILED 229
+#define SSL_R_BAD_RSA_E_LENGTH 230
+#define SSL_R_KRB5_C_CC_PRINC 231
+#define SSL_R_CCS_RECEIVED_EARLY 232
+#define SSL_R_RENEGOTIATION_MISMATCH 233
+#define SSL_R_CONNECTION_ID_IS_DIFFERENT 234
+#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 235
+#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 236
+#define SSL_R_COMPRESSION_FAILURE 237
+#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 238
+#define SSL_R_BAD_RESPONSE_ARGUMENT 239
+#define SSL_R_READ_BIO_NOT_SET 240
+#define SSL_R_PEER_ERROR_CERTIFICATE 241
+#define SSL_R_BAD_ALERT_RECORD 242
+#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 243
+#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 244
+#define SSL_R_HTTPS_PROXY_REQUEST 245
+#define SSL_R_RECORD_LENGTH_MISMATCH 246
+#define SSL_R_INVALID_SERVERINFO_DATA 247
+#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 248
+#define SSL_R_BAD_CHECKSUM 249
+#define SSL_R_INVALID_CHALLENGE_LENGTH 250
+#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 251
+#define SSL_R_INVALID_STATUS_RESPONSE 252
+#define SSL_R_EXCESSIVE_MESSAGE_SIZE 253
+#define SSL_R_SHORT_READ 254
+#define SSL_R_KRB5_S_TKT_SKEW 255
+#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 256
+#define SSL_R_MISSING_TMP_DH_KEY 257
+#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 258
+#define SSL_R_NO_CERTIFICATES_RETURNED 259
+#define SSL_R_X509_LIB 260
+#define SSL_R_CIPHER_TABLE_SRC_ERROR 261
+#define SSL_R_ILLEGAL_SUITEB_DIGEST 262
+#define SSL_R_UNKNOWN_CIPHER_RETURNED 263
+#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 264
+#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 265
+#define SSL_R_INVALID_SRP_USERNAME 266
+#define SSL_R_BAD_SRP_S_LENGTH 267
+#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 268
+#define SSL_R_BAD_MESSAGE_TYPE 269
+#define SSL_R_LENGTH_TOO_SHORT 270
+#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 271
+#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 272
+#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 273
+#define SSL_R_NO_SHARED_SIGATURE_ALGORITHMS 274
+#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 275
+#define SSL_R_PSK_IDENTITY_NOT_FOUND 276
+#define SSL_R_UNSUPPORTED_STATUS_TYPE 277
+#define SSL_R_BAD_ECC_CERT 278
+#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 279
+#define SSL_R_KRB5_C_INIT 280
+#define SSL_R_WRONG_CURVE 281
+#define SSL_R_CONNECTION_TYPE_NOT_SET 282
+#define SSL_R_MISSING_ECDH_CERT 283
+#define SSL_R_PATH_TOO_LONG 284
+#define SSL_R_PUBLIC_KEY_NOT_RSA 285
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 286
+#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 287
+#define SSL_R_MISSING_TMP_RSA_KEY 288
+#define SSL_R_BN_LIB 289
+#define SSL_R_CA_DN_LENGTH_MISMATCH 290
+#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 291
+#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 292
+#define SSL_R_UNKNOWN_CMD_NAME 293
+#define SSL_R_TLS_HEARTBEAT_PENDING 294
+#define SSL_R_DECRYPTION_FAILED 295
+#define SSL_R_PEER_ERROR_NO_CIPHER 296
+#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 297
+#define SSL_R_NO_COMPRESSION_SPECIFIED 298
+#define SSL_R_RENEGOTIATION_ENCODING_ERR 299
+#define SSL_R_UNSUPPORTED_DIGEST_TYPE 300
+#define SSL_R_KRB5 301
+#define SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE 302
+#define SSL_R_MISSING_VERIFY_MESSAGE 303
+#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 304
+#define SSL_R_BAD_ECPOINT 305
+#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 306
+#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 307
+#define SSL_R_UNKNOWN_AUTHZ_DATA_TYPE 308
+#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 309
+#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 310
+#define SSL_R_INVALID_PURPOSE 311
+#define SSL_R_MISSING_DH_KEY 312
+#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 313
+#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 314
+#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 315
+#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 316
+#define SSL_R_NO_VERIFY_CALLBACK 317
+#define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 318
+#define SSL_R_COMPRESSION_DISABLED 319
+#define SSL_R_HTTP_REQUEST 320
+#define SSL_R_MISSING_TMP_ECDH_KEY 321
+#define SSL_R_BAD_DSA_SIGNATURE 322
+#define SSL_R_NO_REQUIRED_DIGEST 323
+#define SSL_R_WRITE_BIO_NOT_SET 324
+#define SSL_R_COMPRESSION_LIBRARY_ERROR 325
+#define SSL_R_NO_CIPHERS_PASSED 326
+#define SSL_R_MISSING_RSA_CERTIFICATE 327
+#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 328
+#define SSL_R_NO_RENEGOTIATION 329
+#define SSL_R_AUTHZ_DATA_TOO_LARGE 330
+#define SSL_R_KRB5_C_MK_REQ 331
+#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 332
+#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 333
+#define SSL_R_BAD_SRTP_MKI_VALUE 334
+#define SSL_R_KRB5_S_BAD_TICKET 335
+#define SSL_R_SERVERHELLO_TLSEXT 336
+#define SSL_R_BAD_DH_P_LENGTH 337
+#define SSL_R_CA_DN_TOO_LONG 338
+#define SSL_R_DTLS_MESSAGE_TOO_BIG 339
+#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 340
+#define SSL_R_BAD_VALUE 341
+#define SSL_R_PEER_ERROR_NO_CERTIFICATE 342
+#define SSL_R_NO_CERTIFICATE_SET 343
+#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 344
+#define SSL_R_NO_CIPHER_LIST 345
+#define SSL_R_UNSUPPORTED_PROTOCOL 346
+#define SSL_R_UNKNOWN_SSL_VERSION 347
+#define SSL_R_CLIENTHELLO_TLSEXT 348
+#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 349
+#define SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE 350
+#define SSL_R_UNKNOWN_PROTOCOL 351
+#define SSL_R_INVALID_COMPRESSION_ALGORITHM 352
+#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 353
+#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 354
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 355
+#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 356
+#define SSL_R_BAD_SRP_A_LENGTH 357
+#define SSL_R_NO_CERTIFICATE_SPECIFIED 358
+#define SSL_R_USE_SRTP_NOT_NEGOTIATED 359
+#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 360
+#define SSL_R_DIGEST_CHECK_FAILED 361
+#define SSL_R_KRB5_S_INIT 362
+#define SSL_R_NO_CIPHER_MATCH 363
+#define SSL_R_WRONG_SIGNATURE_SIZE 364
+#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 365
+#define SSL_R_KEY_ARG_TOO_LONG 366
+#define SSL_R_REQUIRED_CIPHER_MISSING 367
+#define SSL_R_MULTIPLE_SGC_RESTARTS 368
+#define SSL_R_LENGTH_MISMATCH 369
+#define SSL_R_BAD_LENGTH 370
+#define SSL_R_BAD_STATE 371
+#define SSL_R_READ_WRONG_PACKET_TYPE 372
+#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 373
+#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 374
+#define SSL_R_PSK_NO_CLIENT_CB 375
+#define SSL_R_MESSAGE_TOO_LONG 376
+#define SSL_R_GOST_NOT_SUPPORTED 377
+#define SSL_R_BAD_DATA 378
+#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 379
+#define SSL_R_BAD_MAC_LENGTH 380
+#define SSL_R_WRONG_SSL_VERSION 381
+#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 382
+#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 383
+#define SSL_R_KRB5_S_TKT_NYV 384
+#define SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT 385
+#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 386
+#define SSL_R_NO_CIPHERS_AVAILABLE 387
+#define SSL_R_BAD_PACKET_LENGTH 388
+#define SSL_R_MISSING_ECDSA_SIGNING_CERT 389
+#define SSL_R_MISSING_DH_RSA_CERT 390
+#define SSL_R_BAD_HANDSHAKE_LENGTH 391
+#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 392
+#define SSL_R_NO_METHOD_SPECIFIED 393
+#define SSL_R_CHALLENGE_IS_DIFFERENT 394
+#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 395
+#define SSL_R_WRONG_CIPHER_RETURNED 396
+#define SSL_R_WRONG_CERTIFICATE_TYPE 397
+#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 398
+#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 399
+#define SSL_R_UNKNOWN_CIPHER_TYPE 400
+#define SSL_R_UNSUPPORTED_SSL_VERSION 401
+#define SSL_R_BAD_SRP_N_LENGTH 402
+#define SSL_R_KRB5_S_RD_REQ 403
+#define SSL_R_TLSV1_ALERT_USER_CANCELLED 404
+#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 405
+#define SSL_R_EXTRA_DATA_IN_MESSAGE 406
+#define SSL_R_RECORD_TOO_SMALL 407
+#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 408
+#define SSL_R_UNKNOWN_ALERT_TYPE 409
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 410
+#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 411
+#define SSL_R_NON_SSLV2_INITIAL_PACKET 412
+#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 413
+#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 414
+#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 415
+#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 416
+#define SSL_R_CERT_CB_ERROR 417
+#define SSL_R_NO_CERTIFICATE_RETURNED 418
+#define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 419
+#define SSL_R_NO_PRIVATEKEY 420
+#define SSL_R_UNEXPECTED_MESSAGE 421
+
+#endif
diff --git a/ssl/ssl2.h b/ssl/ssl2.h
new file mode 100644
index 0000000..eb25dcb
--- /dev/null
+++ b/ssl/ssl2.h
@@ -0,0 +1,272 @@
+/* ssl/ssl2.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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.]
+ */
+
+#ifndef HEADER_SSL2_H 
+#define HEADER_SSL2_H 
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Protocol Version Codes */
+#define SSL2_VERSION		0x0002
+#define SSL2_VERSION_MAJOR	0x00
+#define SSL2_VERSION_MINOR	0x02
+/* #define SSL2_CLIENT_VERSION	0x0002 */
+/* #define SSL2_SERVER_VERSION	0x0002 */
+
+/* Protocol Message Codes */
+#define SSL2_MT_ERROR			0
+#define SSL2_MT_CLIENT_HELLO		1
+#define SSL2_MT_CLIENT_MASTER_KEY	2
+#define SSL2_MT_CLIENT_FINISHED		3
+#define SSL2_MT_SERVER_HELLO		4
+#define SSL2_MT_SERVER_VERIFY		5
+#define SSL2_MT_SERVER_FINISHED		6
+#define SSL2_MT_REQUEST_CERTIFICATE	7
+#define SSL2_MT_CLIENT_CERTIFICATE	8
+
+/* Error Message Codes */
+#define SSL2_PE_UNDEFINED_ERROR		0x0000
+#define SSL2_PE_NO_CIPHER		0x0001
+#define SSL2_PE_NO_CERTIFICATE		0x0002
+#define SSL2_PE_BAD_CERTIFICATE		0x0004
+#define SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006
+
+/* Cipher Kind Values */
+#define SSL2_CK_NULL_WITH_MD5			0x02000000 /* v3 */
+#define SSL2_CK_RC4_128_WITH_MD5		0x02010080
+#define SSL2_CK_RC4_128_EXPORT40_WITH_MD5	0x02020080
+#define SSL2_CK_RC2_128_CBC_WITH_MD5		0x02030080
+#define SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5	0x02040080
+#define SSL2_CK_IDEA_128_CBC_WITH_MD5		0x02050080
+#define SSL2_CK_DES_64_CBC_WITH_MD5		0x02060040
+#define SSL2_CK_DES_64_CBC_WITH_SHA		0x02060140 /* v3 */
+#define SSL2_CK_DES_192_EDE3_CBC_WITH_MD5	0x020700c0
+#define SSL2_CK_DES_192_EDE3_CBC_WITH_SHA	0x020701c0 /* v3 */
+#define SSL2_CK_RC4_64_WITH_MD5			0x02080080 /* MS hack */
+ 
+#define SSL2_CK_DES_64_CFB64_WITH_MD5_1		0x02ff0800 /* SSLeay */
+#define SSL2_CK_NULL				0x02ff0810 /* SSLeay */
+
+#define SSL2_TXT_DES_64_CFB64_WITH_MD5_1	"DES-CFB-M1"
+#define SSL2_TXT_NULL_WITH_MD5			"NULL-MD5"
+#define SSL2_TXT_RC4_128_WITH_MD5		"RC4-MD5"
+#define SSL2_TXT_RC4_128_EXPORT40_WITH_MD5	"EXP-RC4-MD5"
+#define SSL2_TXT_RC2_128_CBC_WITH_MD5		"RC2-CBC-MD5"
+#define SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5	"EXP-RC2-CBC-MD5"
+#define SSL2_TXT_IDEA_128_CBC_WITH_MD5		"IDEA-CBC-MD5"
+#define SSL2_TXT_DES_64_CBC_WITH_MD5		"DES-CBC-MD5"
+#define SSL2_TXT_DES_64_CBC_WITH_SHA		"DES-CBC-SHA"
+#define SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5	"DES-CBC3-MD5"
+#define SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA	"DES-CBC3-SHA"
+#define SSL2_TXT_RC4_64_WITH_MD5		"RC4-64-MD5"
+
+#define SSL2_TXT_NULL				"NULL"
+
+/* Flags for the SSL_CIPHER.algorithm2 field */
+#define SSL2_CF_5_BYTE_ENC			0x01
+#define SSL2_CF_8_BYTE_ENC			0x02
+
+/* Certificate Type Codes */
+#define SSL2_CT_X509_CERTIFICATE		0x01
+
+/* Authentication Type Code */
+#define SSL2_AT_MD5_WITH_RSA_ENCRYPTION		0x01
+
+#define SSL2_MAX_SSL_SESSION_ID_LENGTH		32
+
+/* Upper/Lower Bounds */
+#define SSL2_MAX_MASTER_KEY_LENGTH_IN_BITS	256
+#ifdef OPENSSL_SYS_MPE
+#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER	29998u
+#else
+#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER	32767u  /* 2^15-1 */
+#endif
+#define SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER	16383 /* 2^14-1 */
+
+#define SSL2_CHALLENGE_LENGTH	16
+/*#define SSL2_CHALLENGE_LENGTH	32 */
+#define SSL2_MIN_CHALLENGE_LENGTH	16
+#define SSL2_MAX_CHALLENGE_LENGTH	32
+#define SSL2_CONNECTION_ID_LENGTH	16
+#define SSL2_MAX_CONNECTION_ID_LENGTH	16
+#define SSL2_SSL_SESSION_ID_LENGTH	16
+#define SSL2_MAX_CERT_CHALLENGE_LENGTH	32
+#define SSL2_MIN_CERT_CHALLENGE_LENGTH	16
+#define SSL2_MAX_KEY_MATERIAL_LENGTH	24
+
+#ifndef HEADER_SSL_LOCL_H
+#define  CERT		char
+#endif
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct ssl2_state_st
+	{
+	int three_byte_header;
+	int clear_text;		/* clear text */
+	int escape;		/* not used in SSLv2 */
+	int ssl2_rollback;	/* used if SSLv23 rolled back to SSLv2 */
+
+	/* non-blocking io info, used to make sure the same
+	 * args were passwd */
+	unsigned int wnum;	/* number of bytes sent so far */
+	int wpend_tot;
+	const unsigned char *wpend_buf;
+
+	int wpend_off;	/* offset to data to write */
+	int wpend_len; 	/* number of bytes passwd to write */
+	int wpend_ret; 	/* number of bytes to return to caller */
+
+	/* buffer raw data */
+	int rbuf_left;
+	int rbuf_offs;
+	unsigned char *rbuf;
+	unsigned char *wbuf;
+
+	unsigned char *write_ptr;/* used to point to the start due to
+				  * 2/3 byte header. */
+
+	unsigned int padding;
+	unsigned int rlength; /* passed to ssl2_enc */
+	int ract_data_length; /* Set when things are encrypted. */
+	unsigned int wlength; /* passed to ssl2_enc */
+	int wact_data_length; /* Set when things are decrypted. */
+	unsigned char *ract_data;
+	unsigned char *wact_data;
+	unsigned char *mac_data;
+
+	unsigned char *read_key;
+	unsigned char *write_key;
+
+		/* Stuff specifically to do with this SSL session */
+	unsigned int challenge_length;
+	unsigned char challenge[SSL2_MAX_CHALLENGE_LENGTH];
+	unsigned int conn_id_length;
+	unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH];
+	unsigned int key_material_length;
+	unsigned char key_material[SSL2_MAX_KEY_MATERIAL_LENGTH*2];
+
+	unsigned long read_sequence;
+	unsigned long write_sequence;
+
+	struct	{
+		unsigned int conn_id_length;
+		unsigned int cert_type;	
+		unsigned int cert_length;
+		unsigned int csl; 
+		unsigned int clear;
+		unsigned int enc; 
+		unsigned char ccl[SSL2_MAX_CERT_CHALLENGE_LENGTH];
+		unsigned int cipher_spec_length;
+		unsigned int session_id_length;
+		unsigned int clen;
+		unsigned int rlen;
+		} tmp;
+	} SSL2_STATE;
+
+#endif
+
+/* SSLv2 */
+/* client */
+#define SSL2_ST_SEND_CLIENT_HELLO_A		(0x10|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_HELLO_B		(0x11|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_HELLO_A		(0x20|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_HELLO_B		(0x21|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_MASTER_KEY_A	(0x30|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_MASTER_KEY_B	(0x31|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_FINISHED_A		(0x40|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_FINISHED_B		(0x41|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_A	(0x50|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_B	(0x51|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_C	(0x52|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_D	(0x53|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_VERIFY_A		(0x60|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_VERIFY_B		(0x61|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_FINISHED_A		(0x70|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_FINISHED_B		(0x71|SSL_ST_CONNECT)
+#define SSL2_ST_CLIENT_START_ENCRYPTION		(0x80|SSL_ST_CONNECT)
+#define SSL2_ST_X509_GET_CLIENT_CERTIFICATE	(0x90|SSL_ST_CONNECT)
+/* server */
+#define SSL2_ST_GET_CLIENT_HELLO_A		(0x10|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_HELLO_B		(0x11|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_HELLO_C		(0x12|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_HELLO_A		(0x20|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_HELLO_B		(0x21|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_MASTER_KEY_A		(0x30|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_MASTER_KEY_B		(0x31|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_A		(0x40|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_B		(0x41|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_C		(0x42|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_FINISHED_A		(0x50|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_FINISHED_B		(0x51|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_FINISHED_A		(0x60|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_FINISHED_B		(0x61|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_A	(0x70|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_B	(0x71|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_C	(0x72|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_D	(0x73|SSL_ST_ACCEPT)
+#define SSL2_ST_SERVER_START_ENCRYPTION		(0x80|SSL_ST_ACCEPT)
+#define SSL2_ST_X509_GET_SERVER_CERTIFICATE	(0x90|SSL_ST_ACCEPT)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
diff --git a/ssl/ssl23.h b/ssl/ssl23.h
new file mode 100644
index 0000000..d322898
--- /dev/null
+++ b/ssl/ssl23.h
@@ -0,0 +1,83 @@
+/* ssl/ssl23.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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.]
+ */
+
+#ifndef HEADER_SSL23_H 
+#define HEADER_SSL23_H 
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*client */
+/* write to server */
+#define SSL23_ST_CW_CLNT_HELLO_A	(0x210|SSL_ST_CONNECT)
+#define SSL23_ST_CW_CLNT_HELLO_B	(0x211|SSL_ST_CONNECT)
+/* read from server */
+#define SSL23_ST_CR_SRVR_HELLO_A	(0x220|SSL_ST_CONNECT)
+#define SSL23_ST_CR_SRVR_HELLO_B	(0x221|SSL_ST_CONNECT)
+
+/* server */
+/* read from client */
+#define SSL23_ST_SR_CLNT_HELLO_A	(0x210|SSL_ST_ACCEPT)
+#define SSL23_ST_SR_CLNT_HELLO_B	(0x211|SSL_ST_ACCEPT)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
new file mode 100644
index 0000000..e2bb36f
--- /dev/null
+++ b/ssl/ssl3.h
@@ -0,0 +1,731 @@
+/* ssl/ssl3.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2002 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_SSL3_H 
+#define HEADER_SSL3_H 
+
+#include <openssl/buf.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */
+#define SSL3_CK_SCSV				0x030000FF
+
+#define SSL3_CK_RSA_NULL_MD5			0x03000001
+#define SSL3_CK_RSA_NULL_SHA			0x03000002
+#define SSL3_CK_RSA_RC4_40_MD5 			0x03000003
+#define SSL3_CK_RSA_RC4_128_MD5			0x03000004
+#define SSL3_CK_RSA_RC4_128_SHA			0x03000005
+#define SSL3_CK_RSA_RC2_40_MD5			0x03000006
+#define SSL3_CK_RSA_IDEA_128_SHA		0x03000007
+#define SSL3_CK_RSA_DES_40_CBC_SHA		0x03000008
+#define SSL3_CK_RSA_DES_64_CBC_SHA		0x03000009
+#define SSL3_CK_RSA_DES_192_CBC3_SHA		0x0300000A
+
+#define SSL3_CK_DH_DSS_DES_40_CBC_SHA		0x0300000B
+#define SSL3_CK_DH_DSS_DES_64_CBC_SHA		0x0300000C
+#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 	0x0300000D
+#define SSL3_CK_DH_RSA_DES_40_CBC_SHA		0x0300000E
+#define SSL3_CK_DH_RSA_DES_64_CBC_SHA		0x0300000F
+#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 	0x03000010
+
+#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA		0x03000011
+#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA		0x03000012
+#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA	0x03000013
+#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA		0x03000014
+#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA		0x03000015
+#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA	0x03000016
+
+#define SSL3_CK_ADH_RC4_40_MD5			0x03000017
+#define SSL3_CK_ADH_RC4_128_MD5			0x03000018
+#define SSL3_CK_ADH_DES_40_CBC_SHA		0x03000019
+#define SSL3_CK_ADH_DES_64_CBC_SHA		0x0300001A
+#define SSL3_CK_ADH_DES_192_CBC_SHA		0x0300001B
+
+#if 0
+	#define SSL3_CK_FZA_DMS_NULL_SHA		0x0300001C
+	#define SSL3_CK_FZA_DMS_FZA_SHA			0x0300001D
+	#if 0 /* Because it clashes with KRB5, is never used any more, and is safe
+		 to remove according to David Hopwood <david.hopwood@zetnet.co.uk>
+		 of the ietf-tls list */
+	#define SSL3_CK_FZA_DMS_RC4_SHA			0x0300001E
+	#endif
+#endif
+
+/*    VRS Additional Kerberos5 entries
+ */
+#define SSL3_CK_KRB5_DES_64_CBC_SHA		0x0300001E
+#define SSL3_CK_KRB5_DES_192_CBC3_SHA		0x0300001F
+#define SSL3_CK_KRB5_RC4_128_SHA		0x03000020
+#define SSL3_CK_KRB5_IDEA_128_CBC_SHA	       	0x03000021
+#define SSL3_CK_KRB5_DES_64_CBC_MD5       	0x03000022
+#define SSL3_CK_KRB5_DES_192_CBC3_MD5       	0x03000023
+#define SSL3_CK_KRB5_RC4_128_MD5	       	0x03000024
+#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 		0x03000025
+
+#define SSL3_CK_KRB5_DES_40_CBC_SHA 		0x03000026
+#define SSL3_CK_KRB5_RC2_40_CBC_SHA 		0x03000027
+#define SSL3_CK_KRB5_RC4_40_SHA	 		0x03000028
+#define SSL3_CK_KRB5_DES_40_CBC_MD5 		0x03000029
+#define SSL3_CK_KRB5_RC2_40_CBC_MD5 		0x0300002A
+#define SSL3_CK_KRB5_RC4_40_MD5	 		0x0300002B
+
+#define SSL3_TXT_RSA_NULL_MD5			"NULL-MD5"
+#define SSL3_TXT_RSA_NULL_SHA			"NULL-SHA"
+#define SSL3_TXT_RSA_RC4_40_MD5 		"EXP-RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_MD5		"RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_SHA		"RC4-SHA"
+#define SSL3_TXT_RSA_RC2_40_MD5			"EXP-RC2-CBC-MD5"
+#define SSL3_TXT_RSA_IDEA_128_SHA		"IDEA-CBC-SHA"
+#define SSL3_TXT_RSA_DES_40_CBC_SHA		"EXP-DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_64_CBC_SHA		"DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_192_CBC3_SHA		"DES-CBC3-SHA"
+
+#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA		"EXP-DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA		"DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA 	"DH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA		"EXP-DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA		"DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA 	"DH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA		"EXP-EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA		"EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA	"EDH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA		"EXP-EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA		"EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA	"EDH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_ADH_RC4_40_MD5			"EXP-ADH-RC4-MD5"
+#define SSL3_TXT_ADH_RC4_128_MD5		"ADH-RC4-MD5"
+#define SSL3_TXT_ADH_DES_40_CBC_SHA		"EXP-ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_64_CBC_SHA		"ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_192_CBC_SHA		"ADH-DES-CBC3-SHA"
+
+#if 0
+	#define SSL3_TXT_FZA_DMS_NULL_SHA		"FZA-NULL-SHA"
+	#define SSL3_TXT_FZA_DMS_FZA_SHA		"FZA-FZA-CBC-SHA"
+	#define SSL3_TXT_FZA_DMS_RC4_SHA		"FZA-RC4-SHA"
+#endif
+
+#define SSL3_TXT_KRB5_DES_64_CBC_SHA		"KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_192_CBC3_SHA		"KRB5-DES-CBC3-SHA"
+#define SSL3_TXT_KRB5_RC4_128_SHA		"KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA	       	"KRB5-IDEA-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_64_CBC_MD5       	"KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_DES_192_CBC3_MD5       	"KRB5-DES-CBC3-MD5"
+#define SSL3_TXT_KRB5_RC4_128_MD5		"KRB5-RC4-MD5"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 		"KRB5-IDEA-CBC-MD5"
+
+#define SSL3_TXT_KRB5_DES_40_CBC_SHA 		"EXP-KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_RC2_40_CBC_SHA 		"EXP-KRB5-RC2-CBC-SHA"
+#define SSL3_TXT_KRB5_RC4_40_SHA	 	"EXP-KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_DES_40_CBC_MD5 		"EXP-KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 		"EXP-KRB5-RC2-CBC-MD5"
+#define SSL3_TXT_KRB5_RC4_40_MD5	 	"EXP-KRB5-RC4-MD5"
+
+#define SSL3_SSL_SESSION_ID_LENGTH		32
+#define SSL3_MAX_SSL_SESSION_ID_LENGTH		32
+
+#define SSL3_MASTER_SECRET_SIZE			48
+#define SSL3_RANDOM_SIZE			32
+#define SSL3_SESSION_ID_SIZE			32
+#define SSL3_RT_HEADER_LENGTH			5
+
+#define SSL3_HM_HEADER_LENGTH                  4
+
+#ifndef SSL3_ALIGN_PAYLOAD
+ /* Some will argue that this increases memory footprint, but it's
+  * not actually true. Point is that malloc has to return at least
+  * 64-bit aligned pointers, meaning that allocating 5 bytes wastes
+  * 3 bytes in either case. Suggested pre-gaping simply moves these
+  * wasted bytes from the end of allocated region to its front,
+  * but makes data payload aligned, which improves performance:-) */
+# define SSL3_ALIGN_PAYLOAD			8
+#else
+# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0
+#  error "insane SSL3_ALIGN_PAYLOAD"
+#  undef SSL3_ALIGN_PAYLOAD
+# endif
+#endif
+
+/* This is the maximum MAC (digest) size used by the SSL library.
+ * Currently maximum of 20 is used by SHA1, but we reserve for
+ * future extension for 512-bit hashes.
+ */
+
+#define SSL3_RT_MAX_MD_SIZE			64
+
+/* Maximum block size used in all ciphersuites. Currently 16 for AES.
+ */
+
+#define	SSL_RT_MAX_CIPHER_BLOCK_SIZE		16
+
+#define SSL3_RT_MAX_EXTRA			(16384)
+
+/* Maximum plaintext length: defined by SSL/TLS standards */
+#define SSL3_RT_MAX_PLAIN_LENGTH		16384
+/* Maximum compression overhead: defined by SSL/TLS standards */
+#define SSL3_RT_MAX_COMPRESSED_OVERHEAD		1024
+
+/* The standards give a maximum encryption overhead of 1024 bytes.
+ * In practice the value is lower than this. The overhead is the maximum
+ * number of padding bytes (256) plus the mac size.
+ */
+#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD	(256 + SSL3_RT_MAX_MD_SIZE)
+
+/* OpenSSL currently only uses a padding length of at most one block so
+ * the send overhead is smaller.
+ */
+
+#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \
+			(SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE)
+
+/* If compression isn't used don't include the compression overhead */
+
+#define SSL3_RT_MAX_COMPRESSED_LENGTH	\
+		(SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD)
+#define SSL3_RT_MAX_ENCRYPTED_LENGTH	\
+		(SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH)
+#define SSL3_RT_MAX_PACKET_SIZE		\
+		(SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
+
+#define SSL3_MD_CLIENT_FINISHED_CONST	"\x43\x4C\x4E\x54"
+#define SSL3_MD_SERVER_FINISHED_CONST	"\x53\x52\x56\x52"
+
+#define SSL3_VERSION			0x0300
+#define SSL3_VERSION_MAJOR		0x03
+#define SSL3_VERSION_MINOR		0x00
+
+#define SSL3_RT_CHANGE_CIPHER_SPEC	20
+#define SSL3_RT_ALERT			21
+#define SSL3_RT_HANDSHAKE		22
+#define SSL3_RT_APPLICATION_DATA	23
+#define TLS1_RT_HEARTBEAT		24
+
+/* Pseudo content types to indicate additional parameters */
+#define TLS1_RT_CRYPTO			0x1000
+#define TLS1_RT_CRYPTO_PREMASTER	(TLS1_RT_CRYPTO | 0x1)
+#define TLS1_RT_CRYPTO_CLIENT_RANDOM	(TLS1_RT_CRYPTO | 0x2)
+#define TLS1_RT_CRYPTO_SERVER_RANDOM	(TLS1_RT_CRYPTO | 0x3)
+#define TLS1_RT_CRYPTO_MASTER		(TLS1_RT_CRYPTO | 0x4)
+
+#define TLS1_RT_CRYPTO_READ		0x0000
+#define TLS1_RT_CRYPTO_WRITE		0x0100
+#define TLS1_RT_CRYPTO_MAC		(TLS1_RT_CRYPTO | 0x5)
+#define TLS1_RT_CRYPTO_KEY		(TLS1_RT_CRYPTO | 0x6)
+#define TLS1_RT_CRYPTO_IV		(TLS1_RT_CRYPTO | 0x7)
+#define TLS1_RT_CRYPTO_FIXED_IV		(TLS1_RT_CRYPTO | 0x8)
+
+/* Pseudo content type for SSL/TLS header info */
+#define SSL3_RT_HEADER			0x100
+
+#define SSL3_AL_WARNING			1
+#define SSL3_AL_FATAL			2
+
+#define SSL3_AD_CLOSE_NOTIFY		 0
+#define SSL3_AD_UNEXPECTED_MESSAGE	10	/* fatal */
+#define SSL3_AD_BAD_RECORD_MAC		20	/* fatal */
+#define SSL3_AD_DECOMPRESSION_FAILURE	30	/* fatal */
+#define SSL3_AD_HANDSHAKE_FAILURE	40	/* fatal */
+#define SSL3_AD_NO_CERTIFICATE		41
+#define SSL3_AD_BAD_CERTIFICATE		42
+#define SSL3_AD_UNSUPPORTED_CERTIFICATE	43
+#define SSL3_AD_CERTIFICATE_REVOKED	44
+#define SSL3_AD_CERTIFICATE_EXPIRED	45
+#define SSL3_AD_CERTIFICATE_UNKNOWN	46
+#define SSL3_AD_ILLEGAL_PARAMETER	47	/* fatal */
+
+#define TLS1_HB_REQUEST		1
+#define TLS1_HB_RESPONSE	2
+	
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct ssl3_record_st
+	{
+/*r */	int type;               /* type of record */
+/*rw*/	unsigned int length;    /* How many bytes available */
+/*r */	unsigned int off;       /* read/write offset into 'buf' */
+/*rw*/	unsigned char *data;    /* pointer to the record data */
+/*rw*/	unsigned char *input;   /* where the decode bytes are */
+/*r */	unsigned char *comp;    /* only used with decompression - malloc()ed */
+/*r */  unsigned long epoch;    /* epoch number, needed by DTLS1 */
+/*r */  unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
+	} SSL3_RECORD;
+
+typedef struct ssl3_buffer_st
+	{
+	unsigned char *buf;     /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
+	                         * see ssl3_setup_buffers() */
+	size_t len;             /* buffer size */
+	int offset;             /* where to 'copy from' */
+	int left;               /* how many bytes left */
+	} SSL3_BUFFER;
+
+#endif
+
+#define SSL3_CT_RSA_SIGN			1
+#define SSL3_CT_DSS_SIGN			2
+#define SSL3_CT_RSA_FIXED_DH			3
+#define SSL3_CT_DSS_FIXED_DH			4
+#define SSL3_CT_RSA_EPHEMERAL_DH		5
+#define SSL3_CT_DSS_EPHEMERAL_DH		6
+#define SSL3_CT_FORTEZZA_DMS			20
+/* SSL3_CT_NUMBER is used to size arrays and it must be large
+ * enough to contain all of the cert types defined either for
+ * SSLv3 and TLSv1.
+ */
+#define SSL3_CT_NUMBER			9
+
+
+#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
+#define SSL3_FLAGS_DELAY_CLIENT_FINISHED	0x0002
+#define SSL3_FLAGS_POP_BUFFER			0x0004
+#define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
+#define TLS1_FLAGS_SKIP_CERT_VERIFY		0x0010
+#define TLS1_FLAGS_KEEP_HANDSHAKE		0x0020
+ 
+/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
+ * restart a handshake because of MS SGC and so prevents us
+ * from restarting the handshake in a loop. It's reset on a
+ * renegotiation, so effectively limits the client to one restart
+ * per negotiation. This limits the possibility of a DDoS
+ * attack where the client handshakes in a loop using SGC to
+ * restart. Servers which permit renegotiation can still be
+ * effected, but we can't prevent that.
+ */
+#define SSL3_FLAGS_SGC_RESTART_DONE		0x0040
+
+#ifndef OPENSSL_NO_SSL_INTERN
+
+typedef struct ssl3_state_st
+	{
+	long flags;
+	int delay_buf_pop_ret;
+
+	unsigned char read_sequence[8];
+	int read_mac_secret_size;
+	unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
+	unsigned char write_sequence[8];
+	int write_mac_secret_size;
+	unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
+
+	unsigned char server_random[SSL3_RANDOM_SIZE];
+	unsigned char client_random[SSL3_RANDOM_SIZE];
+
+	/* flags for countermeasure against known-IV weakness */
+	int need_empty_fragments;
+	int empty_fragment_done;
+
+	/* The value of 'extra' when the buffers were initialized */
+	int init_extra;
+
+	SSL3_BUFFER rbuf;	/* read IO goes into here */
+	SSL3_BUFFER wbuf;	/* write IO goes into here */
+
+	SSL3_RECORD rrec;	/* each decoded record goes in here */
+	SSL3_RECORD wrec;	/* goes out from here */
+
+	/* storage for Alert/Handshake protocol data received but not
+	 * yet processed by ssl3_read_bytes: */
+	unsigned char alert_fragment[2];
+	unsigned int alert_fragment_len;
+	unsigned char handshake_fragment[4];
+	unsigned int handshake_fragment_len;
+
+	/* partial write - check the numbers match */
+	unsigned int wnum;	/* number of bytes sent so far */
+	int wpend_tot;		/* number bytes written */
+	int wpend_type;
+	int wpend_ret;		/* number of bytes submitted */
+	const unsigned char *wpend_buf;
+
+	/* used during startup, digest all incoming/outgoing packets */
+	BIO *handshake_buffer;
+	/* When set of handshake digests is determined, buffer is hashed
+	 * and freed and MD_CTX-es for all required digests are stored in
+	 * this array */
+	EVP_MD_CTX **handshake_dgst;
+	/* this is set whenerver we see a change_cipher_spec message
+	 * come in when we are not looking for one */
+	int change_cipher_spec;
+
+	int warn_alert;
+	int fatal_alert;
+	/* we allow one fatal and one warning alert to be outstanding,
+	 * send close alert via the warning alert */
+	int alert_dispatch;
+	unsigned char send_alert[2];
+
+	/* This flag is set when we should renegotiate ASAP, basically when
+	 * there is no more data in the read or write buffers */
+	int renegotiate;
+	int total_renegotiations;
+	int num_renegotiations;
+
+	int in_read_app_data;
+
+	/* Opaque PRF input as used for the current handshake.
+	 * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
+	 * (otherwise, they are merely present to improve binary compatibility) */
+	void *client_opaque_prf_input;
+	size_t client_opaque_prf_input_len;
+	void *server_opaque_prf_input;
+	size_t server_opaque_prf_input_len;
+
+	struct	{
+		/* actually only needs to be 16+20 */
+		unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
+
+		/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
+		unsigned char finish_md[EVP_MAX_MD_SIZE*2];
+		int finish_md_len;
+		unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
+		int peer_finish_md_len;
+
+		unsigned long message_size;
+		int message_type;
+
+		/* used to hold the new cipher we are going to use */
+		const SSL_CIPHER *new_cipher;
+#ifndef OPENSSL_NO_DH
+		DH *dh;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+		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;
+		char ctype[SSL3_CT_NUMBER];
+		STACK_OF(X509_NAME) *ca_names;
+
+		int use_rsa_tmp;
+
+		int key_block_length;
+		unsigned char *key_block;
+
+		const EVP_CIPHER *new_sym_enc;
+		const EVP_MD *new_hash;
+		int new_mac_pkey_type;
+		int new_mac_secret_size;
+		char *new_compression;
+		int cert_request;
+		} tmp;
+
+        /* Connection binding to prevent renegotiation attacks */
+        unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
+        unsigned char previous_client_finished_len;
+        unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
+        unsigned char previous_server_finished_len;
+        int send_connection_binding; /* TODOEKR */
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	/* Set if we saw the Next Protocol Negotiation extension from our peer. */
+	int next_proto_neg_seen;
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* tlsext_authz_client_types contains an array of supported authz
+	 * types, as advertised by the client. The array is sorted and
+	 * does not contain any duplicates. */
+	unsigned char *tlsext_authz_client_types;
+	size_t tlsext_authz_client_types_len;
+	/* tlsext_authz_promised_to_client is true iff we're a server and we
+	 * echoed the client's supplemental data extension and therefore must
+	 * send a supplemental data handshake message. */
+	char tlsext_authz_promised_to_client;
+	/* tlsext_authz_server_promised is true iff we're a client and the
+	 * server echoed our server_authz extension and therefore must send us
+	 * a supplemental data handshake message. */
+	char tlsext_authz_server_promised;
+
+	/* tlsext_custom_types contains an array of TLS Extension types which 
+	 * were advertised by the client in its ClientHello, which were not 
+	 * otherwise handled by OpenSSL, and which the server has registered
+	 * a custom_srv_ext_record to handle.
+	 * The array does not contain any duplicates, and is in the same order
+	 * as the types were received in the client hello. */
+	unsigned short *tlsext_custom_types;
+	size_t tlsext_custom_types_count; /* how many tlsext_custom_types */
+
+#ifndef OPENSSL_NO_EC
+	/* This is set to true if we believe that this is a version of Safari
+	 * running on OS X 10.6 or newer. We wish to know this because Safari
+	 * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
+	char is_probably_safari;
+#endif /* !OPENSSL_NO_EC */
+
+	/* ALPN information
+	 * (we are in the process of transitioning from NPN to ALPN.) */
+
+	/* In a server these point to the selected ALPN protocol after the
+	 * ClientHello has been processed. In a client these contain the
+	 * protocol that the server selected once the ServerHello has been
+	 * processed. */
+	unsigned char *alpn_selected;
+	unsigned alpn_selected_len;
+#endif	/* OPENSSL_NO_TLSEXT */
+	} SSL3_STATE;
+
+#endif
+
+/* SSLv3 */
+/*client */
+/* extra state */
+#define SSL3_ST_CW_FLUSH		(0x100|SSL_ST_CONNECT)
+/* 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)
+#define SSL3_ST_CR_SUPPLEMENTAL_DATA_A	(0x210|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SUPPLEMENTAL_DATA_B  (0x211|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)
+/* 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_ST_SW_SUPPLEMENTAL_DATA_A	(0x220|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B	(0x221|SSL_ST_ACCEPT)
+
+#define SSL3_MT_HELLO_REQUEST			0
+#define SSL3_MT_CLIENT_HELLO			1
+#define SSL3_MT_SERVER_HELLO			2
+#define	SSL3_MT_NEWSESSION_TICKET		4
+#define SSL3_MT_CERTIFICATE			11
+#define SSL3_MT_SERVER_KEY_EXCHANGE		12
+#define SSL3_MT_CERTIFICATE_REQUEST		13
+#define SSL3_MT_SERVER_DONE			14
+#define SSL3_MT_CERTIFICATE_VERIFY		15
+#define SSL3_MT_CLIENT_KEY_EXCHANGE		16
+#define SSL3_MT_FINISHED			20
+#define SSL3_MT_CERTIFICATE_STATUS		22
+#define SSL3_MT_SUPPLEMENTAL_DATA		23
+#ifndef OPENSSL_NO_NEXTPROTONEG
+#define SSL3_MT_NEXT_PROTO			67
+#endif
+#define DTLS1_MT_HELLO_VERIFY_REQUEST    3
+
+
+#define SSL3_MT_CCS				1
+
+/* These are used when changing over to a new cipher */
+#define SSL3_CC_READ		0x01
+#define SSL3_CC_WRITE		0x02
+#define SSL3_CC_CLIENT		0x10
+#define SSL3_CC_SERVER		0x20
+#define SSL3_CHANGE_CIPHER_CLIENT_WRITE	(SSL3_CC_CLIENT|SSL3_CC_WRITE)	
+#define SSL3_CHANGE_CIPHER_SERVER_READ	(SSL3_CC_SERVER|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_CLIENT_READ	(SSL3_CC_CLIENT|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_SERVER_WRITE	(SSL3_CC_SERVER|SSL3_CC_WRITE)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c
new file mode 100644
index 0000000..8f7ede6
--- /dev/null
+++ b/ssl/ssl_algs.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 "ssl_locl.h"
+
+
+extern const ERR_STRING_DATA SSL_error_string_data[];
+
+int SSL_library_init(void)
+	{
+	ERR_load_crypto_strings();
+	ERR_load_strings(SSL_error_string_data);
+	ssl_load_ciphers();
+	return(1);
+	}
+
+void SSL_load_error_strings(void)
+	{
+	ERR_load_crypto_strings();
+	ERR_load_strings(SSL_error_string_data);
+	}
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
new file mode 100644
index 0000000..267c3b2
--- /dev/null
+++ b/ssl/ssl_asn1.c
@@ -0,0 +1,545 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+OPENSSL_DECLARE_ERROR_REASON(SSL, CIPHER_CODE_WRONG_LENGTH);
+OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_SSL_VERSION);
+OPENSSL_DECLARE_ERROR_REASON(SSL, BAD_LENGTH);
+OPENSSL_DECLARE_ERROR_FUNCTION(SSL, D2I_SSL_SESSION);
+
+
+typedef struct ssl_session_asn1_st
+	{
+	ASN1_INTEGER version;
+	ASN1_INTEGER ssl_version;
+	ASN1_OCTET_STRING cipher;
+	ASN1_OCTET_STRING comp_id;
+	ASN1_OCTET_STRING master_key;
+	ASN1_OCTET_STRING session_id;
+	ASN1_OCTET_STRING session_id_context;
+	ASN1_OCTET_STRING key_arg;
+	ASN1_INTEGER time;
+	ASN1_INTEGER timeout;
+	ASN1_INTEGER verify_result;
+#ifndef OPENSSL_NO_TLSEXT
+	ASN1_OCTET_STRING tlsext_hostname;
+	ASN1_INTEGER tlsext_tick_lifetime;
+	ASN1_OCTET_STRING tlsext_tick;
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+	ASN1_OCTET_STRING psk_identity_hint;
+	ASN1_OCTET_STRING psk_identity;
+#endif /* OPENSSL_NO_PSK */
+	} SSL_SESSION_ASN1;
+
+int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
+	{
+#define LSIZE2 (sizeof(long)*2)
+	int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0;
+	unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
+	unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
+#ifndef OPENSSL_NO_TLSEXT
+	int v6=0,v9=0,v10=0;
+	unsigned char ibuf6[LSIZE2];
+#endif
+	long l;
+	SSL_SESSION_ASN1 a;
+	M_ASN1_I2D_vars(in);
+
+	if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
+		return(0);
+
+	/* Note that I cheat in the following 2 assignments.  I know
+	 * that if the ASN1_INTEGER passed to ASN1_INTEGER_set
+	 * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed.
+	 * This is a bit evil but makes things simple, no dynamic allocation
+	 * to clean up :-) */
+	a.version.length=LSIZE2;
+	a.version.type=V_ASN1_INTEGER;
+	a.version.data=ibuf1;
+	ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION);
+
+	a.ssl_version.length=LSIZE2;
+	a.ssl_version.type=V_ASN1_INTEGER;
+	a.ssl_version.data=ibuf2;
+	ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version);
+
+	a.cipher.type=V_ASN1_OCTET_STRING;
+	a.cipher.data=buf;
+
+	if (in->cipher == NULL)
+		l=in->cipher_id;
+	else
+		l=in->cipher->id;
+	if (in->ssl_version == SSL2_VERSION)
+		{
+		a.cipher.length=3;
+		buf[0]=((unsigned char)(l>>16L))&0xff;
+		buf[1]=((unsigned char)(l>> 8L))&0xff;
+		buf[2]=((unsigned char)(l     ))&0xff;
+		}
+	else
+		{
+		a.cipher.length=2;
+		buf[0]=((unsigned char)(l>>8L))&0xff;
+		buf[1]=((unsigned char)(l    ))&0xff;
+		}
+
+
+	a.master_key.length=in->master_key_length;
+	a.master_key.type=V_ASN1_OCTET_STRING;
+	a.master_key.data=in->master_key;
+
+	a.session_id.length=in->session_id_length;
+	a.session_id.type=V_ASN1_OCTET_STRING;
+	a.session_id.data=in->session_id;
+
+	a.session_id_context.length=in->sid_ctx_length;
+	a.session_id_context.type=V_ASN1_OCTET_STRING;
+	a.session_id_context.data=in->sid_ctx;
+
+	a.key_arg.length=in->key_arg_length;
+	a.key_arg.type=V_ASN1_OCTET_STRING;
+	a.key_arg.data=in->key_arg;
+
+	if (in->time != 0L)
+		{
+		a.time.length=LSIZE2;
+		a.time.type=V_ASN1_INTEGER;
+		a.time.data=ibuf3;
+		ASN1_INTEGER_set(&(a.time),in->time);
+		}
+
+	if (in->timeout != 0L)
+		{
+		a.timeout.length=LSIZE2;
+		a.timeout.type=V_ASN1_INTEGER;
+		a.timeout.data=ibuf4;
+		ASN1_INTEGER_set(&(a.timeout),in->timeout);
+		}
+
+	if (in->verify_result != X509_V_OK)
+		{
+		a.verify_result.length=LSIZE2;
+		a.verify_result.type=V_ASN1_INTEGER;
+		a.verify_result.data=ibuf5;
+		ASN1_INTEGER_set(&a.verify_result,in->verify_result);
+		}
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_hostname)
+                {
+                a.tlsext_hostname.length=strlen(in->tlsext_hostname);
+                a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
+                a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
+                }
+	if (in->tlsext_tick)
+                {
+                a.tlsext_tick.length= in->tlsext_ticklen;
+                a.tlsext_tick.type=V_ASN1_OCTET_STRING;
+                a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
+                }
+	if (in->tlsext_tick_lifetime_hint > 0)
+		{
+		a.tlsext_tick_lifetime.length=LSIZE2;
+		a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
+		a.tlsext_tick_lifetime.data=ibuf6;
+		ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
+		}
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+	if (in->psk_identity_hint)
+		{
+		a.psk_identity_hint.length=strlen(in->psk_identity_hint);
+		a.psk_identity_hint.type=V_ASN1_OCTET_STRING;
+		a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint);
+		}
+	if (in->psk_identity)
+		{
+		a.psk_identity.length=strlen(in->psk_identity);
+		a.psk_identity.type=V_ASN1_OCTET_STRING;
+		a.psk_identity.data=(unsigned char *)(in->psk_identity);
+		}
+#endif /* OPENSSL_NO_PSK */
+
+	M_ASN1_I2D_len(&(a.version),		i2d_ASN1_INTEGER);
+	M_ASN1_I2D_len(&(a.ssl_version),	i2d_ASN1_INTEGER);
+	M_ASN1_I2D_len(&(a.cipher),		i2d_ASN1_OCTET_STRING);
+	M_ASN1_I2D_len(&(a.session_id),		i2d_ASN1_OCTET_STRING);
+	M_ASN1_I2D_len(&(a.master_key),		i2d_ASN1_OCTET_STRING);
+	if (in->key_arg_length > 0)
+		M_ASN1_I2D_len_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING);
+	if (in->time != 0L)
+		M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
+	if (in->timeout != 0L)
+		M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
+	if (in->peer != NULL)
+		M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3);
+	M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4);
+	if (in->verify_result != X509_V_OK)
+		M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_tick_lifetime_hint > 0)
+      	 	M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+	if (in->tlsext_tick)
+        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+	if (in->tlsext_hostname)
+        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+	if (in->psk_identity_hint)
+        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
+	if (in->psk_identity)
+        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
+#endif /* OPENSSL_NO_PSK */
+
+	M_ASN1_I2D_seq_total();
+
+	M_ASN1_I2D_put(&(a.version),		i2d_ASN1_INTEGER);
+	M_ASN1_I2D_put(&(a.ssl_version),	i2d_ASN1_INTEGER);
+	M_ASN1_I2D_put(&(a.cipher),		i2d_ASN1_OCTET_STRING);
+	M_ASN1_I2D_put(&(a.session_id),		i2d_ASN1_OCTET_STRING);
+	M_ASN1_I2D_put(&(a.master_key),		i2d_ASN1_OCTET_STRING);
+	if (in->key_arg_length > 0)
+		M_ASN1_I2D_put_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING,0);
+	if (in->time != 0L)
+		M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
+	if (in->timeout != 0L)
+		M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
+	if (in->peer != NULL)
+		M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3);
+	M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,
+			       v4);
+	if (in->verify_result != X509_V_OK)
+		M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_hostname)
+        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_PSK
+	if (in->psk_identity_hint)
+		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
+	if (in->psk_identity)
+		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
+#endif /* OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_tick_lifetime_hint > 0)
+      	 	M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+	if (in->tlsext_tick)
+        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+#endif /* OPENSSL_NO_TLSEXT */
+	M_ASN1_I2D_finish();
+	}
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
+			     long length)
+	{
+	int ssl_version=0,i;
+	long id;
+	ASN1_INTEGER ai,*aip;
+	ASN1_OCTET_STRING os,*osp;
+	M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new);
+
+	aip= &ai;
+	osp= &os;
+
+	M_ASN1_D2I_Init();
+	M_ASN1_D2I_start_sequence();
+
+	ai.data=NULL; ai.length=0;
+	M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
+	if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+
+	/* we don't care about the version right now :-) */
+	M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
+	ssl_version=(int)ASN1_INTEGER_get(aip);
+	ret->ssl_version=ssl_version;
+	if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+
+	os.data=NULL; os.length=0;
+	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+	if (ssl_version == SSL2_VERSION)
+		{
+		if (os.length != 3)
+			{
+			c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
+			goto err;
+			}
+		id=0x02000000L|
+			((unsigned long)os.data[0]<<16L)|
+			((unsigned long)os.data[1]<< 8L)|
+			 (unsigned long)os.data[2];
+		}
+	else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
+		{
+		if (os.length != 2)
+			{
+			c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
+			goto err;
+			}
+		id=0x03000000L|
+			((unsigned long)os.data[0]<<8L)|
+			 (unsigned long)os.data[1];
+		}
+	else
+		{
+		c.error=SSL_R_UNKNOWN_SSL_VERSION;
+		goto err;
+		}
+	
+	ret->cipher=NULL;
+	ret->cipher_id=id;
+
+	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+	if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
+		i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
+	else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
+		i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
+
+	if (os.length > i)
+		os.length = i;
+	if (os.length > (int)sizeof(ret->session_id)) /* can't happen */
+		os.length = sizeof(ret->session_id);
+
+	ret->session_id_length=os.length;
+	assert(os.length <= (int)sizeof(ret->session_id));
+	memcpy(ret->session_id,os.data,os.length);
+
+	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
+	if (os.length > SSL_MAX_MASTER_KEY_LENGTH)
+		ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
+	else
+		ret->master_key_length=os.length;
+	memcpy(ret->master_key,os.data,ret->master_key_length);
+
+	os.length=0;
+
+	M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING);
+	if (os.length > SSL_MAX_KEY_ARG_LENGTH)
+		ret->key_arg_length=SSL_MAX_KEY_ARG_LENGTH;
+	else
+		ret->key_arg_length=os.length;
+	memcpy(ret->key_arg,os.data,ret->key_arg_length);
+	if (os.data != NULL) OPENSSL_free(os.data);
+
+	ai.length=0;
+	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1);
+	if (ai.data != NULL)
+		{
+		ret->time=ASN1_INTEGER_get(aip);
+		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+		}
+	else
+		ret->time=(unsigned long)time(NULL);
+
+	ai.length=0;
+	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2);
+	if (ai.data != NULL)
+		{
+		ret->timeout=ASN1_INTEGER_get(aip);
+		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+		}
+	else
+		ret->timeout=3;
+
+	if (ret->peer != NULL)
+		{
+		X509_free(ret->peer);
+		ret->peer=NULL;
+		}
+	M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3);
+
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4);
+
+	if(os.data != NULL)
+	    {
+	    if (os.length > SSL_MAX_SID_CTX_LENGTH)
+		{
+		c.error=SSL_R_BAD_LENGTH;
+		goto err;
+		}
+	    else
+		{
+		ret->sid_ctx_length=os.length;
+		memcpy(ret->sid_ctx,os.data,os.length);
+		}
+	    OPENSSL_free(os.data); os.data=NULL; os.length=0;
+	    }
+	else
+	    ret->sid_ctx_length=0;
+
+	ai.length=0;
+	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5);
+	if (ai.data != NULL)
+		{
+		ret->verify_result=ASN1_INTEGER_get(aip);
+		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+		}
+	else
+		ret->verify_result=X509_V_OK;
+
+#ifndef OPENSSL_NO_TLSEXT
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+	if (os.data)
+		{
+		ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
+		OPENSSL_free(os.data);
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		ret->tlsext_hostname=NULL;
+#endif /* OPENSSL_NO_TLSEXT */
+
+#ifndef OPENSSL_NO_PSK
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+	if (os.data)
+		{
+		ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
+		OPENSSL_free(os.data);
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		ret->psk_identity_hint=NULL;
+
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
+	if (os.data)
+		{
+		ret->psk_identity = BUF_strndup((char *)os.data, os.length);
+		OPENSSL_free(os.data);
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		ret->psk_identity=NULL;
+#endif /* OPENSSL_NO_PSK */
+
+#ifndef OPENSSL_NO_TLSEXT
+	ai.length=0;
+	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
+	if (ai.data != NULL)
+		{
+		ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
+		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+		}
+	else if (ret->tlsext_ticklen && ret->session_id_length)
+		ret->tlsext_tick_lifetime_hint = -1;
+	else
+		ret->tlsext_tick_lifetime_hint=0;
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
+	if (os.data)
+		{
+		ret->tlsext_tick = os.data;
+		ret->tlsext_ticklen = os.length;
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		ret->tlsext_tick=NULL;
+#endif /* OPENSSL_NO_TLSEXT */
+
+	M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
+	}
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
new file mode 100644
index 0000000..4fa041b
--- /dev/null
+++ b/ssl/ssl_cert.c
@@ -0,0 +1,1385 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */
+
+#include <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+
+#include "../crypto/dh/internal.h"
+#include "../crypto/directory.h"
+#include "ssl_locl.h"
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+	{
+	static volatile int ssl_x509_store_ctx_idx= -1;
+	int got_write_lock = 0;
+
+	CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+
+	if (ssl_x509_store_ctx_idx < 0)
+		{
+		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+		CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+		got_write_lock = 1;
+		
+		if (ssl_x509_store_ctx_idx < 0)
+			{
+			ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index(
+				0,"SSL for verify callback",NULL,NULL,NULL);
+			}
+		}
+
+	if (got_write_lock)
+		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	else
+		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+	
+	return ssl_x509_store_ctx_idx;
+	}
+
+void ssl_cert_set_default_md(CERT *cert)
+	{
+	/* Set digest values to defaults */
+#ifndef OPENSSL_NO_DSA
+	cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_RSA
+	cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+	cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+	cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+#endif
+	}
+
+CERT *ssl_cert_new(void)
+	{
+	CERT *ret;
+
+	ret=(CERT *)OPENSSL_malloc(sizeof(CERT));
+	if (ret == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE);
+		return(NULL);
+		}
+	memset(ret,0,sizeof(CERT));
+
+	ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
+	ret->references=1;
+	ssl_cert_set_default_md(ret);
+	return(ret);
+	}
+
+CERT *ssl_cert_dup(CERT *cert)
+	{
+	CERT *ret;
+	int i;
+
+	ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+	if (ret == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+		return(NULL);
+		}
+
+	memset(ret, 0, sizeof(CERT));
+
+	ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
+	/* or ret->key = ret->pkeys + (cert->key - cert->pkeys),
+	 * if you find that more readable */
+
+	ret->valid = cert->valid;
+	ret->mask_k = cert->mask_k;
+	ret->mask_a = cert->mask_a;
+	ret->export_mask_k = cert->export_mask_k;
+	ret->export_mask_a = cert->export_mask_a;
+
+#ifndef OPENSSL_NO_RSA
+	if (cert->rsa_tmp != NULL)
+		{
+		RSA_up_ref(cert->rsa_tmp);
+		ret->rsa_tmp = cert->rsa_tmp;
+		}
+	ret->rsa_tmp_cb = cert->rsa_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_DH
+	if (cert->dh_tmp != NULL)
+		{
+		ret->dh_tmp = DHparams_dup(cert->dh_tmp);
+		if (ret->dh_tmp == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_DH_LIB);
+			goto err;
+			}
+		if (cert->dh_tmp->priv_key)
+			{
+			BIGNUM *b = BN_dup(cert->dh_tmp->priv_key);
+			if (!b)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB);
+				goto err;
+				}
+			ret->dh_tmp->priv_key = b;
+			}
+		if (cert->dh_tmp->pub_key)
+			{
+			BIGNUM *b = BN_dup(cert->dh_tmp->pub_key);
+			if (!b)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_BN_LIB);
+				goto err;
+				}
+			ret->dh_tmp->pub_key = b;
+			}
+		}
+	ret->dh_tmp_cb = cert->dh_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	if (cert->ecdh_tmp)
+		{
+		ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp);
+		if (ret->ecdh_tmp == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_EC_LIB);
+			goto err;
+			}
+		}
+	ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
+	ret->ecdh_tmp_auto = cert->ecdh_tmp_auto;
+#endif
+
+	for (i = 0; i < SSL_PKEY_NUM; i++)
+		{
+		CERT_PKEY *cpk = cert->pkeys + i;
+		CERT_PKEY *rpk = ret->pkeys + i;
+		if (cpk->x509 != NULL)
+			{
+			rpk->x509 = cpk->x509;
+			CRYPTO_add(&rpk->x509->references, 1, CRYPTO_LOCK_X509);
+			}
+		
+		if (cpk->privatekey != NULL)
+			{
+			rpk->privatekey = cpk->privatekey;
+			CRYPTO_add(&cpk->privatekey->references, 1,
+				CRYPTO_LOCK_EVP_PKEY);
+
+			switch(i) 
+				{
+				/* If there was anything special to do for
+				 * certain types of keys, we'd do it here.
+				 * (Nothing at the moment, I think.) */
+
+			case SSL_PKEY_RSA_ENC:
+			case SSL_PKEY_RSA_SIGN:
+				/* We have an RSA key. */
+				break;
+				
+			case SSL_PKEY_DSA_SIGN:
+				/* We have a DSA key. */
+				break;
+				
+			case SSL_PKEY_DH_RSA:
+			case SSL_PKEY_DH_DSA:
+				/* We have a DH key. */
+				break;
+
+			case SSL_PKEY_ECC:
+				/* We have an ECC key */
+				break;
+
+			default:
+				/* Can't happen. */
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, SSL_R_LIBRARY_BUG);
+				}
+			}
+
+		if (cpk->chain)
+			{
+			rpk->chain = X509_chain_up_ref(cpk->chain);
+			if (!rpk->chain)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		rpk->valid_flags = 0;
+#ifndef OPENSSL_NO_TLSEXT
+     if (cert->pkeys[i].authz != NULL)
+			{
+			/* Just copy everything. */
+			ret->pkeys[i].authz_length =
+				cert->pkeys[i].authz_length;
+			ret->pkeys[i].authz =
+				OPENSSL_malloc(ret->pkeys[i].authz_length);
+			if (ret->pkeys[i].authz == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+				return NULL;
+				}
+			memcpy(ret->pkeys[i].authz,
+			       cert->pkeys[i].authz,
+			       cert->pkeys[i].authz_length);
+			}
+
+		if (cert->pkeys[i].serverinfo != NULL)
+			{
+			/* Just copy everything. */
+			ret->pkeys[i].serverinfo =
+				OPENSSL_malloc(cert->pkeys[i].serverinfo_length);
+			if (ret->pkeys[i].serverinfo == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+				return NULL;
+				}
+			ret->pkeys[i].serverinfo_length =
+				cert->pkeys[i].serverinfo_length;
+			memcpy(ret->pkeys[i].serverinfo,
+			       cert->pkeys[i].serverinfo,
+			       cert->pkeys[i].serverinfo_length);
+			}
+#endif
+		}
+	
+	ret->references=1;
+	/* Set digests to defaults. NB: we don't copy existing values as they
+	 * will be set during handshake.
+	 */
+	ssl_cert_set_default_md(ret);
+	/* Peer sigalgs set to NULL as we get these from handshake too */
+	ret->peer_sigalgs = NULL;
+	ret->peer_sigalgslen = 0;
+	/* Configured sigalgs however we copy across */
+
+	if (cert->conf_sigalgs)
+		{
+		ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen);
+		if (!ret->conf_sigalgs)
+			goto err;
+		memcpy(ret->conf_sigalgs, cert->conf_sigalgs,
+						cert->conf_sigalgslen);
+		ret->conf_sigalgslen = cert->conf_sigalgslen;
+		}
+	else
+		ret->conf_sigalgs = NULL;
+
+	if (cert->client_sigalgs)
+		{
+		ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen);
+		if (!ret->client_sigalgs)
+			goto err;
+		memcpy(ret->client_sigalgs, cert->client_sigalgs,
+						cert->client_sigalgslen);
+		ret->client_sigalgslen = cert->client_sigalgslen;
+		}
+	else
+		ret->client_sigalgs = NULL;
+	/* Shared sigalgs also NULL */
+	ret->shared_sigalgs = NULL;
+	/* Copy any custom client certificate types */
+	if (cert->ctypes)
+		{
+		ret->ctypes = OPENSSL_malloc(cert->ctype_num);
+		if (!ret->ctypes)
+			goto err;
+		memcpy(ret->ctypes, cert->ctypes, cert->ctype_num);
+		ret->ctype_num = cert->ctype_num;
+		}
+
+	ret->cert_flags = cert->cert_flags;
+
+	ret->cert_cb = cert->cert_cb;
+	ret->cert_cb_arg = cert->cert_cb_arg;
+
+	if (cert->verify_store)
+		{
+		CRYPTO_add(&cert->verify_store->references, 1, CRYPTO_LOCK_X509_STORE);
+		ret->verify_store = cert->verify_store;
+		}
+
+	if (cert->chain_store)
+		{
+		CRYPTO_add(&cert->chain_store->references, 1, CRYPTO_LOCK_X509_STORE);
+		ret->chain_store = cert->chain_store;
+		}
+
+	ret->ciphers_raw = NULL;
+
+	return(ret);
+	
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
+err:
+#endif
+#ifndef OPENSSL_NO_RSA
+	if (ret->rsa_tmp != NULL)
+		RSA_free(ret->rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+	if (ret->dh_tmp != NULL)
+		DH_free(ret->dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if (ret->ecdh_tmp != NULL)
+		EC_KEY_free(ret->ecdh_tmp);
+#endif
+
+	ssl_cert_clear_certs(ret);
+
+	return NULL;
+	}
+
+/* Free up and clear all certificates and chains */
+
+void ssl_cert_clear_certs(CERT *c)
+	{
+	int i;
+	if (c == NULL)
+		return;
+	for (i = 0; i<SSL_PKEY_NUM; i++)
+		{
+		CERT_PKEY *cpk = c->pkeys + i;
+		if (cpk->x509)
+			{
+			X509_free(cpk->x509);
+			cpk->x509 = NULL;
+			}
+		if (cpk->privatekey)
+			{
+			EVP_PKEY_free(cpk->privatekey);
+			cpk->privatekey = NULL;
+			}
+		if (cpk->chain)
+			{
+			sk_X509_pop_free(cpk->chain, X509_free);
+			cpk->chain = NULL;
+			}
+#ifndef OPENSSL_NO_TLSEXT
+		if (cpk->authz)
+			{
+			OPENSSL_free(cpk->authz);
+			cpk->authz = NULL;
+			}
+		if (cpk->serverinfo)
+			{
+			OPENSSL_free(cpk->serverinfo);
+			cpk->serverinfo = NULL;
+			cpk->serverinfo_length = 0;
+			}
+#endif
+		/* Clear all flags apart from explicit sign */
+		cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;
+		}
+	}
+
+void ssl_cert_free(CERT *c)
+	{
+	int i;
+
+	if(c == NULL)
+	    return;
+
+	i=CRYPTO_add(&c->references,-1,CRYPTO_LOCK_SSL_CERT);
+#ifdef REF_PRINT
+	REF_PRINT("CERT",c);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"ssl_cert_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+#ifndef OPENSSL_NO_RSA
+	if (c->rsa_tmp) RSA_free(c->rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+	if (c->dh_tmp) DH_free(c->dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
+#endif
+
+	ssl_cert_clear_certs(c);
+	if (c->peer_sigalgs)
+		OPENSSL_free(c->peer_sigalgs);
+	if (c->conf_sigalgs)
+		OPENSSL_free(c->conf_sigalgs);
+	if (c->client_sigalgs)
+		OPENSSL_free(c->client_sigalgs);
+	if (c->shared_sigalgs)
+		OPENSSL_free(c->shared_sigalgs);
+	if (c->ctypes)
+		OPENSSL_free(c->ctypes);
+	if (c->verify_store)
+		X509_STORE_free(c->verify_store);
+	if (c->chain_store)
+		X509_STORE_free(c->chain_store);
+	if (c->ciphers_raw)
+		OPENSSL_free(c->ciphers_raw);
+	OPENSSL_free(c);
+	}
+
+int ssl_cert_inst(CERT **o)
+	{
+	/* Create a CERT if there isn't already one
+	 * (which cannot really happen, as it is initially created in
+	 * SSL_CTX_new; but the earlier code usually allows for that one
+	 * being non-existant, so we follow that behaviour, as it might
+	 * turn out that there actually is a reason for it -- but I'm
+	 * not sure that *all* of the existing code could cope with
+	 * s->cert being NULL, otherwise we could do without the
+	 * initialization in SSL_CTX_new).
+	 */
+	
+	if (o == NULL) 
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_cert_inst, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (*o == NULL)
+		{
+		if ((*o = ssl_cert_new()) == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE);
+			return(0);
+			}
+		}
+	return(1);
+	}
+
+int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain)
+	{
+	CERT_PKEY *cpk = c->key;
+	if (!cpk)
+		return 0;
+	if (cpk->chain)
+		sk_X509_pop_free(cpk->chain, X509_free);
+	cpk->chain = chain;
+	return 1;
+	}
+
+int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain)
+	{
+	STACK_OF(X509) *dchain;
+	if (!chain)
+		return ssl_cert_set0_chain(c, NULL);
+	dchain = X509_chain_up_ref(chain);
+	if (!dchain)
+		return 0;
+	if (!ssl_cert_set0_chain(c, dchain))
+		{
+		sk_X509_pop_free(dchain, X509_free);
+		return 0;
+		}
+	return 1;
+	}
+
+int ssl_cert_add0_chain_cert(CERT *c, X509 *x)
+	{
+	CERT_PKEY *cpk = c->key;
+	if (!cpk)
+		return 0;
+	if (!cpk->chain)
+		cpk->chain = sk_X509_new_null();
+	if (!cpk->chain || !sk_X509_push(cpk->chain, x))
+		return 0;
+	return 1;
+	}
+
+int ssl_cert_add1_chain_cert(CERT *c, X509 *x)
+	{
+	if (!ssl_cert_add0_chain_cert(c, x))
+		return 0;
+	CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+	return 1;
+	}
+
+int ssl_cert_select_current(CERT *c, X509 *x)
+	{
+	int i;
+	if (x == NULL)
+		return 0;
+	for (i = 0; i < SSL_PKEY_NUM; i++)
+		{
+		if (c->pkeys[i].x509 == x)
+			{
+			c->key = &c->pkeys[i];
+			return 1;
+			}
+		}
+
+	for (i = 0; i < SSL_PKEY_NUM; i++)
+		{
+		if (c->pkeys[i].x509 && !X509_cmp(c->pkeys[i].x509, x))
+			{
+			c->key = &c->pkeys[i];
+			return 1;
+			}
+		}
+	return 0;
+	}
+
+void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg)
+	{
+	c->cert_cb = cb;
+	c->cert_cb_arg = arg;
+	}
+
+SESS_CERT *ssl_sess_cert_new(void)
+	{
+	SESS_CERT *ret;
+
+	ret = OPENSSL_malloc(sizeof *ret);
+	if (ret == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_sess_cert_new, ERR_R_MALLOC_FAILURE);
+		return NULL;
+		}
+
+	memset(ret, 0 ,sizeof *ret);
+	ret->peer_key = &(ret->peer_pkeys[SSL_PKEY_RSA_ENC]);
+	ret->references = 1;
+
+	return ret;
+	}
+
+void ssl_sess_cert_free(SESS_CERT *sc)
+	{
+	int i;
+
+	if (sc == NULL)
+		return;
+
+	i = CRYPTO_add(&sc->references, -1, CRYPTO_LOCK_SSL_SESS_CERT);
+#ifdef REF_PRINT
+	REF_PRINT("SESS_CERT", sc);
+#endif
+	if (i > 0)
+		return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"ssl_sess_cert_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	/* i == 0 */
+	if (sc->cert_chain != NULL)
+		sk_X509_pop_free(sc->cert_chain, X509_free);
+	for (i = 0; i < SSL_PKEY_NUM; i++)
+		{
+		if (sc->peer_pkeys[i].x509 != NULL)
+			X509_free(sc->peer_pkeys[i].x509);
+#if 0 /* We don't have the peer's private key.  These lines are just
+	   * here as a reminder that we're still using a not-quite-appropriate
+	   * data structure. */
+		if (sc->peer_pkeys[i].privatekey != NULL)
+			EVP_PKEY_free(sc->peer_pkeys[i].privatekey);
+#endif
+		}
+
+#ifndef OPENSSL_NO_RSA
+	if (sc->peer_rsa_tmp != NULL)
+		RSA_free(sc->peer_rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+	if (sc->peer_dh_tmp != NULL)
+		DH_free(sc->peer_dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	if (sc->peer_ecdh_tmp != NULL)
+		EC_KEY_free(sc->peer_ecdh_tmp);
+#endif
+
+	OPENSSL_free(sc);
+	}
+
+int ssl_set_peer_cert_type(SESS_CERT *sc,int type)
+	{
+	sc->peer_cert_type = type;
+	return(1);
+	}
+
+#ifndef OPENSSL_NO_DANE
+/*
+ * return value:
+ * -1:	format or digest error
+ *  0:	match
+ *  1:	no match
+ */
+int tlsa_cmp(const X509 *cert, const unsigned char *tlsa_record, unsigned int reclen)
+{
+	const EVP_MD *md;
+	unsigned char digest[EVP_MAX_MD_SIZE];
+	unsigned int len, selector, matching_type;
+	int ret;
+
+	if (reclen<3) return -1;
+
+	selector      = tlsa_record[1];
+	matching_type = tlsa_record[2];
+	tlsa_record   += 3;
+	reclen        -= 3;
+
+	switch (matching_type) {
+	case 0:				/* exact match */
+		if (selector==0) {	/* full certificate */
+			ret = EVP_Digest(tlsa_record,reclen,digest,&len,EVP_sha1(),NULL);
+			return ret ? memcmp(cert->sha1_hash,digest,len)!=0 : -1;
+		}
+		else if (selector==1) {	/* SubjectPublicKeyInfo */
+			ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(cert);
+
+			if (key == NULL) return -1;
+			if (key->length != reclen) return 1;
+
+			return memcmp(key->data,tlsa_record,reclen)!=0;
+		}
+		return -1;
+
+	case 1:				/* SHA256 */
+	case 2:				/* SHA512 */
+		md = matching_type==1 ? EVP_sha256() : EVP_sha512();
+
+		if (reclen!=EVP_MD_size(md)) return -1;
+
+		if (selector==0) {	/* full certificate */
+			ret = X509_digest(cert,md,digest,&len);
+		}
+		else if (selector==1) {	/* SubjectPublicKeyInfo */
+			ret = X509_pubkey_digest(cert,md,digest,&len);
+		}
+		else
+			return -1;
+
+		return ret ? memcmp(tlsa_record,digest,len)!=0 : -1;
+	default:
+		return -1;
+	}
+}
+
+int dane_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+	SSL *s = X509_STORE_CTX_get_ex_data(ctx,SSL_get_ex_data_X509_STORE_CTX_idx());
+	int depth=X509_STORE_CTX_get_error_depth(ctx);
+	X509 *cert = sk_X509_value(ctx->chain,depth);
+	unsigned int reclen, certificate_usage;
+	const unsigned char *tlsa_record = s->tlsa_record;
+	int tlsa_ret = -1;
+
+	if (s->verify_callback)	ok = s->verify_callback(ok,ctx);
+
+	if (tlsa_record == NULL) return ok;
+
+	if (tlsa_record == (void*)-1) {
+		ctx->error = X509_V_ERR_INVALID_CA;	/* temporary code? */
+		return 0;
+	}
+
+	while ((reclen = *(unsigned int *)tlsa_record)) {
+		tlsa_record += sizeof(unsigned int);
+
+		/*
+		 * tlsa_record[0]	Certificate Usage field
+		 * tlsa_record[1]	Selector field
+		 * tlsa_record[2]	Matching Type Field
+		 * tlsa_record+3	Certificate Association data
+		 */
+		certificate_usage = tlsa_record[0];
+
+		if (depth==0 || certificate_usage==0 || certificate_usage==2) {
+			tlsa_ret = tlsa_cmp(cert,tlsa_record,reclen);
+			if (tlsa_ret==0) {
+				s->tlsa_witness = depth<<8|certificate_usage;
+				break;
+			}
+			else if (tlsa_ret==-1)
+				s->tlsa_witness = -1;	/* something phishy? */
+		}
+
+		tlsa_record += reclen;
+	}
+
+	if (depth==0) {
+		switch (s->tlsa_witness&0xff) {		/* witnessed usage */
+		case 0:	/* CA constraint */
+			if (s->tlsa_witness<0 && ctx->error==X509_V_OK)
+				ctx->error = X509_V_ERR_INVALID_CA;
+			return 0;
+		case 1:	/* service certificate constraint */
+			if (tlsa_ret!=0 && ctx->error==X509_V_OK)
+				ctx->error = X509_V_ERR_CERT_UNTRUSTED;
+			return 0;
+		case 2:	/* trust anchor assertion */
+			if ((s->tlsa_witness>>8)>0 && ctx->error==X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
+				ctx->error = X509_V_OK;
+			break;
+		case 3:	/* domain-issued certificate */
+			if (tlsa_ret==0)
+				ctx->error = X509_V_OK; /* override all errors? */
+			break;
+		default:/* there were TLSA records, but something phishy happened */
+			ctx->error = X509_V_ERR_CERT_UNTRUSTED;
+			return ok;
+		}
+	}
+
+	/*
+	 * returning 1 makes verify procedure traverse the whole chain,
+	 * not actually approve it...
+	 */
+	return 1;
+}
+#endif
+
+int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
+	{
+	X509 *x;
+	int i;
+	X509_STORE *verify_store;
+	X509_STORE_CTX ctx;
+
+	if (s->cert->verify_store)
+		verify_store = s->cert->verify_store;
+	else
+		verify_store = s->ctx->cert_store;
+
+	if ((sk == NULL) || (sk_X509_num(sk) == 0))
+		return(0);
+
+	x=sk_X509_value(sk,0);
+	if(!X509_STORE_CTX_init(&ctx,verify_store,x,sk))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_verify_cert_chain, ERR_R_X509_LIB);
+		return(0);
+		}
+	/* Set suite B flags if needed */
+	X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s));
+#if 0
+	if (SSL_get_verify_depth(s) >= 0)
+		X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s));
+#endif
+	X509_STORE_CTX_set_ex_data(&ctx,SSL_get_ex_data_X509_STORE_CTX_idx(),s);
+
+	/* We need to inherit the verify parameters. These can be determined by
+	 * the context: if its a server it will verify SSL client certificates
+	 * or vice versa.
+	 */
+
+	X509_STORE_CTX_set_default(&ctx,
+				s->server ? "ssl_client" : "ssl_server");
+	/* Anything non-default in "param" should overwrite anything in the
+	 * ctx.
+	 */
+	X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
+
+#ifndef OPENSSL_NO_DANE
+	X509_STORE_CTX_set_verify_cb(&ctx, dane_verify_callback);
+	s->tlsa_witness = -1;
+#else
+	if (s->verify_callback)
+		X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
+#endif
+
+	if (s->ctx->app_verify_callback != NULL)
+#if 1 /* new with OpenSSL 0.9.7 */
+		i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg); 
+#else
+		i=s->ctx->app_verify_callback(&ctx); /* should pass app_verify_arg */
+#endif
+	else
+		{
+#ifndef OPENSSL_NO_X509_VERIFY
+		i=X509_verify_cert(&ctx);
+#else
+		i=0;
+		ctx.error=X509_V_ERR_APPLICATION_VERIFICATION;
+		OPENSSL_PUT_ERROR(SSL, ssl_verify_cert_chain, SSL_R_NO_VERIFY_CALLBACK);
+#endif
+		}
+
+	s->verify_result=ctx.error;
+	X509_STORE_CTX_cleanup(&ctx);
+
+	return(i);
+	}
+
+static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list,STACK_OF(X509_NAME) *name_list)
+	{
+	if (*ca_list != NULL)
+		sk_X509_NAME_pop_free(*ca_list,X509_NAME_free);
+
+	*ca_list=name_list;
+	}
+
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk)
+	{
+	int i;
+	STACK_OF(X509_NAME) *ret;
+	X509_NAME *name;
+
+	ret=sk_X509_NAME_new_null();
+	for (i=0; i<sk_X509_NAME_num(sk); i++)
+		{
+		name=X509_NAME_dup(sk_X509_NAME_value(sk,i));
+		if ((name == NULL) || !sk_X509_NAME_push(ret,name))
+			{
+			sk_X509_NAME_pop_free(ret,X509_NAME_free);
+			return(NULL);
+			}
+		}
+	return(ret);
+	}
+
+void SSL_set_client_CA_list(SSL *s,STACK_OF(X509_NAME) *name_list)
+	{
+	set_client_CA_list(&(s->client_CA),name_list);
+	}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx,STACK_OF(X509_NAME) *name_list)
+	{
+	set_client_CA_list(&(ctx->client_CA),name_list);
+	}
+
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
+	{
+	return(ctx->client_CA);
+	}
+
+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->version>>8) == SSL3_VERSION_MAJOR) &&
+			(s->s3 != NULL))
+			return(s->s3->tmp.ca_names);
+		else
+			return(NULL);
+		}
+	else
+		{
+		if (s->client_CA != NULL)
+			return(s->client_CA);
+		else
+			return(s->ctx->client_CA);
+		}
+	}
+
+static int add_client_CA(STACK_OF(X509_NAME) **sk,X509 *x)
+	{
+	X509_NAME *name;
+
+	if (x == NULL) return(0);
+	if ((*sk == NULL) && ((*sk=sk_X509_NAME_new_null()) == NULL))
+		return(0);
+		
+	if ((name=X509_NAME_dup(X509_get_subject_name(x))) == NULL)
+		return(0);
+
+	if (!sk_X509_NAME_push(*sk,name))
+		{
+		X509_NAME_free(name);
+		return(0);
+		}
+	return(1);
+	}
+
+int SSL_add_client_CA(SSL *ssl,X509 *x)
+	{
+	return(add_client_CA(&(ssl->client_CA),x));
+	}
+
+int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x)
+	{
+	return(add_client_CA(&(ctx->client_CA),x));
+	}
+
+static int xname_cmp(const X509_NAME **a, const X509_NAME **b)
+	{
+	return(X509_NAME_cmp(*a,*b));
+	}
+
+#ifndef OPENSSL_NO_STDIO
+/*!
+ * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
+ * it doesn't really have anything to do with clients (except that a common use
+ * for a stack of CAs is to send it to the client). Actually, it doesn't have
+ * much to do with CAs, either, since it will load any old cert.
+ * \param file the file containing one or more certs.
+ * \return a ::STACK containing the certs.
+ */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
+	{
+	BIO *in;
+	X509 *x=NULL;
+	X509_NAME *xn=NULL;
+	STACK_OF(X509_NAME) *ret = NULL,*sk;
+
+	sk=sk_X509_NAME_new(xname_cmp);
+
+	in=BIO_new(BIO_s_file());
+
+	if ((sk == NULL) || (in == NULL))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	
+	if (!BIO_read_filename(in,file))
+		goto err;
+
+	for (;;)
+		{
+		if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
+			break;
+		if (ret == NULL)
+			{
+			ret = sk_X509_NAME_new_null();
+			if (ret == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, SSL_load_client_CA_file, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		if ((xn=X509_get_subject_name(x)) == NULL) goto err;
+		/* check for duplicates */
+		xn=X509_NAME_dup(xn);
+		if (xn == NULL) goto err;
+		if (sk_X509_NAME_find(sk, NULL, xn))
+			X509_NAME_free(xn);
+		else
+			{
+			sk_X509_NAME_push(sk,xn);
+			sk_X509_NAME_push(ret,xn);
+			}
+		}
+
+	if (0)
+		{
+err:
+		if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free);
+		ret=NULL;
+		}
+	if (sk != NULL) sk_X509_NAME_free(sk);
+	if (in != NULL) BIO_free(in);
+	if (x != NULL) X509_free(x);
+	if (ret != NULL)
+		ERR_clear_error();
+	return(ret);
+	}
+#endif
+
+/*!
+ * Add a file of certs to a stack.
+ * \param stack the stack to add to.
+ * \param file the file to add from. All certs in this file that are not
+ * already in the stack will be added.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+					const char *file)
+	{
+	BIO *in;
+	X509 *x=NULL;
+	X509_NAME *xn=NULL;
+	int ret=1;
+	int (*oldcmp)(const X509_NAME **a, const X509_NAME **b);
+	
+	oldcmp=sk_X509_NAME_set_cmp_func(stack,xname_cmp);
+	
+	in=BIO_new(BIO_s_file());
+	
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_add_file_cert_subjects_to_stack, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	
+	if (!BIO_read_filename(in,file))
+		goto err;
+	
+	for (;;)
+		{
+		if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
+			break;
+		if ((xn=X509_get_subject_name(x)) == NULL) goto err;
+		xn=X509_NAME_dup(xn);
+		if (xn == NULL) goto err;
+		if (sk_X509_NAME_find(stack, NULL, xn))
+			X509_NAME_free(xn);
+		else
+			sk_X509_NAME_push(stack,xn);
+		}
+
+	ERR_clear_error();
+
+	if (0)
+		{
+err:
+		ret=0;
+		}
+	if(in != NULL)
+		BIO_free(in);
+	if(x != NULL)
+		X509_free(x);
+	
+	(void)sk_X509_NAME_set_cmp_func(stack,oldcmp);
+
+	return ret;
+	}
+
+/*!
+ * Add a directory of certs to a stack.
+ * \param stack the stack to append to.
+ * \param dir the directory to append from. All files in this directory will be
+ * examined as potential certs. Any that are acceptable to
+ * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will be
+ * included.
+ * \return 1 for success, 0 for failure. Note that in the case of failure some
+ * certs may have been added to \c stack.
+ */
+
+int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
+				       const char *dir)
+	{
+	OPENSSL_DIR_CTX *d = NULL;
+	const char *filename;
+	int ret = 0;
+
+	CRYPTO_w_lock(CRYPTO_LOCK_READDIR);
+
+	/* Note that a side effect is that the CAs will be sorted by name */
+
+	while((filename = OPENSSL_DIR_read(&d, dir)))
+		{
+		char buf[1024];
+		int r;
+
+		if(strlen(dir)+strlen(filename)+2 > sizeof buf)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_add_dir_cert_subjects_to_stack, SSL_R_PATH_TOO_LONG);
+			goto err;
+			}
+
+#ifdef OPENSSL_SYS_VMS
+		r = BIO_snprintf(buf,sizeof buf,"%s%s",dir,filename);
+#else
+		r = BIO_snprintf(buf,sizeof buf,"%s/%s",dir,filename);
+#endif
+		if (r <= 0 || r >= (int)sizeof(buf))
+			goto err;
+		if(!SSL_add_file_cert_subjects_to_stack(stack,buf))
+			goto err;
+		}
+
+	if (errno)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_add_file_cert_subjects_to_stack, ERR_R_SYS_LIB);
+		ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
+		goto err;
+		}
+
+	ret = 1;
+
+err:
+	if (d) OPENSSL_DIR_end(&d);
+	CRYPTO_w_unlock(CRYPTO_LOCK_READDIR);
+	return ret;
+	}
+
+/* Add a certificate to a BUF_MEM structure */
+
+static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
+	{
+	int n;
+	unsigned char *p;
+
+	n=i2d_X509(x,NULL);
+	if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3)))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_cert_to_buf, ERR_R_BUF_LIB);
+		return 0;
+		}
+	p=(unsigned char *)&(buf->data[*l]);
+	l2n3(n,p);
+	i2d_X509(x,&p);
+	*l+=n+3;
+
+	return 1;
+	}
+
+/* Add certificate chain to internal SSL BUF_MEM strcuture */
+int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
+	{
+	BUF_MEM *buf = s->init_buf;
+	int no_chain;
+	int i;
+
+	X509 *x;
+	STACK_OF(X509) *extra_certs;
+	X509_STORE *chain_store;
+
+	if (cpk)
+		x = cpk->x509;
+	else
+		x = NULL;
+
+	if (s->cert->chain_store)
+		chain_store = s->cert->chain_store;
+	else
+		chain_store = s->ctx->cert_store;
+
+	/* If we have a certificate specific chain use it, else use
+	 * parent ctx.
+	 */
+	if (cpk && cpk->chain)
+		extra_certs = cpk->chain;
+	else
+		extra_certs = s->ctx->extra_certs;
+
+	if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs)
+		no_chain = 1;
+	else
+		no_chain = 0;
+
+	/* TLSv1 sends a chain with nothing in it, instead of an alert */
+	if (!BUF_MEM_grow_clean(buf,10))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, ERR_R_BUF_LIB);
+		return 0;
+		}
+	if (x != NULL)
+		{
+		if (no_chain)
+			{
+			if (!ssl_add_cert_to_buf(buf, l, x))
+				return 0;
+			}
+		else
+			{
+			X509_STORE_CTX xs_ctx;
+
+			if (!X509_STORE_CTX_init(&xs_ctx,chain_store,x,NULL))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_add_cert_chain, ERR_R_X509_LIB);
+				return(0);
+				}
+			X509_verify_cert(&xs_ctx);
+			/* Don't leave errors in the queue */
+			ERR_clear_error();
+			for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
+				{
+				x = sk_X509_value(xs_ctx.chain, i);
+
+				if (!ssl_add_cert_to_buf(buf, l, x))
+					{
+					X509_STORE_CTX_cleanup(&xs_ctx);
+					return 0;
+					}
+				}
+			X509_STORE_CTX_cleanup(&xs_ctx);
+			}
+		}
+	for (i=0; i<sk_X509_num(extra_certs); i++)
+		{
+		x=sk_X509_value(extra_certs,i);
+		if (!ssl_add_cert_to_buf(buf, l, x))
+			return 0;
+		}
+
+	return 1;
+	}
+
+/* Build a certificate chain for current certificate */
+int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
+	{
+	CERT_PKEY *cpk = c->key;
+	X509_STORE_CTX xs_ctx;
+	STACK_OF(X509) *chain = NULL, *untrusted = NULL;
+	X509 *x;
+	int i;
+
+	if (!cpk->x509)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_NO_CERTIFICATE_SET);
+		return 0;
+		}
+
+	if (c->chain_store)
+		chain_store = c->chain_store;
+
+	if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED)
+		untrusted = cpk->chain;
+
+	if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, ERR_R_X509_LIB);
+		return 0;
+		}
+	/* Set suite B flags if needed */
+	X509_STORE_CTX_set_flags(&xs_ctx, c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS);
+
+	i = X509_verify_cert(&xs_ctx);
+	if (i > 0)
+		chain = X509_STORE_CTX_get1_chain(&xs_ctx);
+	X509_STORE_CTX_cleanup(&xs_ctx);
+	if (i <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_CERTIFICATE_VERIFY_FAILED);
+		return 0;
+		}
+	if (cpk->chain)
+		sk_X509_pop_free(cpk->chain, X509_free);
+	/* Remove EE certificate from chain */
+	x = sk_X509_shift(chain);
+	X509_free(x);
+	if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT)
+		{
+		x = sk_X509_pop(chain);
+		X509_free(x);
+		}
+	cpk->chain = chain;
+
+	return 1;
+	}
+
+int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref)
+	{
+	X509_STORE **pstore;
+	if (chain)
+		pstore = &c->chain_store;
+	else
+		pstore = &c->verify_store;
+	if (*pstore)
+		X509_STORE_free(*pstore);
+	*pstore = store;
+	if (ref && store)
+		CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
+	return 1;
+	}
+
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
new file mode 100644
index 0000000..03702cb
--- /dev/null
+++ b/ssl/ssl_ciph.c
@@ -0,0 +1,1754 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * 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 <assert.h>
+
+#include <openssl/comp.h>
+#include <openssl/engine.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "ssl_locl.h"
+
+#define SSL_ENC_DES_IDX		0
+#define SSL_ENC_3DES_IDX	1
+#define SSL_ENC_RC4_IDX		2
+#define SSL_ENC_RC2_IDX		3
+#define SSL_ENC_IDEA_IDX	4
+#define SSL_ENC_NULL_IDX	5
+#define SSL_ENC_AES128_IDX	6
+#define SSL_ENC_AES256_IDX	7
+#define SSL_ENC_CAMELLIA128_IDX	8
+#define SSL_ENC_CAMELLIA256_IDX	9
+#define SSL_ENC_GOST89_IDX	10
+#define SSL_ENC_SEED_IDX    	11
+#define SSL_ENC_AES128GCM_IDX	12
+#define SSL_ENC_AES256GCM_IDX	13
+#define SSL_ENC_NUM_IDX		14
+
+
+static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]={
+	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
+	};
+
+#define SSL_COMP_NULL_IDX	0
+#define SSL_COMP_ZLIB_IDX	1
+#define SSL_COMP_NUM_IDX	2
+
+static STACK_OF(SSL_COMP) *ssl_comp_methods=NULL;
+
+#define SSL_MD_MD5_IDX	0
+#define SSL_MD_SHA1_IDX	1
+#define SSL_MD_GOST94_IDX 2
+#define SSL_MD_GOST89MAC_IDX 3
+#define SSL_MD_SHA256_IDX 4
+#define SSL_MD_SHA384_IDX 5
+/*Constant SSL_MAX_DIGEST equal to size of digests array should be 
+ * defined in the
+ * ssl_locl.h */
+#define SSL_MD_NUM_IDX	SSL_MAX_DIGEST 
+static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX]={
+	NULL,NULL,NULL,NULL,NULL,NULL
+	};
+/* PKEY_TYPE for GOST89MAC is known in advance, but, because
+ * implementation is engine-provided, we'll fill it only if
+ * corresponding EVP_PKEY_METHOD is found 
+ */
+static int  ssl_mac_pkey_id[SSL_MD_NUM_IDX]={
+	EVP_PKEY_HMAC,EVP_PKEY_HMAC,EVP_PKEY_HMAC,NID_undef,
+	EVP_PKEY_HMAC,EVP_PKEY_HMAC
+	};
+
+static int ssl_mac_secret_size[SSL_MD_NUM_IDX]={
+	0,0,0,0,0,0
+	};
+
+static int ssl_handshake_digest_flag[SSL_MD_NUM_IDX]={
+	SSL_HANDSHAKE_MAC_MD5,SSL_HANDSHAKE_MAC_SHA,
+	SSL_HANDSHAKE_MAC_GOST94, 0, SSL_HANDSHAKE_MAC_SHA256,
+	SSL_HANDSHAKE_MAC_SHA384
+	};
+
+#define CIPHER_ADD	1
+#define CIPHER_KILL	2
+#define CIPHER_DEL	3
+#define CIPHER_ORD	4
+#define CIPHER_SPECIAL	5
+
+typedef struct cipher_order_st
+	{
+	const SSL_CIPHER *cipher;
+	int active;
+	int dead;
+	struct cipher_order_st *next,*prev;
+	} CIPHER_ORDER;
+
+static const SSL_CIPHER cipher_aliases[]={
+	/* "ALL" doesn't include eNULL (must be specifically enabled) */
+	{0,SSL_TXT_ALL,0,     0,0,~SSL_eNULL,0,0,0,0,0,0},
+	/* "COMPLEMENTOFALL" */
+	{0,SSL_TXT_CMPALL,0,  0,0,SSL_eNULL,0,0,0,0,0,0},
+
+	/* "COMPLEMENTOFDEFAULT" (does *not* include ciphersuites not found in ALL!) */
+	{0,SSL_TXT_CMPDEF,0,  SSL_kEDH|SSL_kEECDH,SSL_aNULL,~SSL_eNULL,0,0,0,0,0,0},
+
+	/* key exchange aliases
+	 * (some of those using only a single bit here combine
+	 * multiple key exchange algs according to the RFCs,
+	 * e.g. kEDH combines DHE_DSS and DHE_RSA) */
+	{0,SSL_TXT_kRSA,0,    SSL_kRSA,  0,0,0,0,0,0,0,0},
+
+	{0,SSL_TXT_kDHr,0,    SSL_kDHr,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kDHd,0,    SSL_kDHd,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kDH,0,     SSL_kDHr|SSL_kDHd,0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kEDH,0,    SSL_kEDH,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_DH,0,      SSL_kDHr|SSL_kDHd|SSL_kEDH,0,0,0,0,0,0,0,0},
+
+	{0,SSL_TXT_kKRB5,0,   SSL_kKRB5, 0,0,0,0,0,0,0,0},
+
+	{0,SSL_TXT_kECDHr,0,  SSL_kECDHr,0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kECDHe,0,  SSL_kECDHe,0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kECDH,0,   SSL_kECDHr|SSL_kECDHe,0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kEECDH,0,  SSL_kEECDH,0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_ECDH,0,    SSL_kECDHr|SSL_kECDHe|SSL_kEECDH,0,0,0,0,0,0,0,0},
+
+        {0,SSL_TXT_kPSK,0,    SSL_kPSK,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kSRP,0,    SSL_kSRP,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kGOST,0, SSL_kGOST,0,0,0,0,0,0,0,0},
+
+	/* server authentication aliases */
+	{0,SSL_TXT_aRSA,0,    0,SSL_aRSA,  0,0,0,0,0,0,0},
+	{0,SSL_TXT_aDSS,0,    0,SSL_aDSS,  0,0,0,0,0,0,0},
+	{0,SSL_TXT_DSS,0,     0,SSL_aDSS,   0,0,0,0,0,0,0},
+	{0,SSL_TXT_aKRB5,0,   0,SSL_aKRB5, 0,0,0,0,0,0,0},
+	{0,SSL_TXT_aNULL,0,   0,SSL_aNULL, 0,0,0,0,0,0,0},
+	{0,SSL_TXT_aDH,0,     0,SSL_aDH,   0,0,0,0,0,0,0}, /* no such ciphersuites supported! */
+	{0,SSL_TXT_aECDH,0,   0,SSL_aECDH, 0,0,0,0,0,0,0},
+	{0,SSL_TXT_aECDSA,0,  0,SSL_aECDSA,0,0,0,0,0,0,0},
+	{0,SSL_TXT_ECDSA,0,   0,SSL_aECDSA, 0,0,0,0,0,0,0},
+        {0,SSL_TXT_aPSK,0,    0,SSL_aPSK,  0,0,0,0,0,0,0},
+	{0,SSL_TXT_aGOST94,0,0,SSL_aGOST94,0,0,0,0,0,0,0},
+	{0,SSL_TXT_aGOST01,0,0,SSL_aGOST01,0,0,0,0,0,0,0},
+	{0,SSL_TXT_aGOST,0,0,SSL_aGOST94|SSL_aGOST01,0,0,0,0,0,0,0},
+
+	/* aliases combining key exchange and server authentication */
+	{0,SSL_TXT_EDH,0,     SSL_kEDH,~SSL_aNULL,0,0,0,0,0,0,0},
+	{0,SSL_TXT_EECDH,0,   SSL_kEECDH,~SSL_aNULL,0,0,0,0,0,0,0},
+	{0,SSL_TXT_NULL,0,    0,0,SSL_eNULL, 0,0,0,0,0,0},
+	{0,SSL_TXT_KRB5,0,    SSL_kKRB5,SSL_aKRB5,0,0,0,0,0,0,0},
+	{0,SSL_TXT_RSA,0,     SSL_kRSA,SSL_aRSA,0,0,0,0,0,0,0},
+	{0,SSL_TXT_ADH,0,     SSL_kEDH,SSL_aNULL,0,0,0,0,0,0,0},
+	{0,SSL_TXT_AECDH,0,   SSL_kEECDH,SSL_aNULL,0,0,0,0,0,0,0},
+        {0,SSL_TXT_PSK,0,     SSL_kPSK,SSL_aPSK,0,0,0,0,0,0,0},
+	{0,SSL_TXT_SRP,0,     SSL_kSRP,0,0,0,0,0,0,0,0},
+
+
+	/* symmetric encryption aliases */
+	{0,SSL_TXT_DES,0,     0,0,SSL_DES,   0,0,0,0,0,0},
+	{0,SSL_TXT_3DES,0,    0,0,SSL_3DES,  0,0,0,0,0,0},
+	{0,SSL_TXT_RC4,0,     0,0,SSL_RC4,   0,0,0,0,0,0},
+	{0,SSL_TXT_RC2,0,     0,0,SSL_RC2,   0,0,0,0,0,0},
+	{0,SSL_TXT_IDEA,0,    0,0,SSL_IDEA,  0,0,0,0,0,0},
+	{0,SSL_TXT_SEED,0,    0,0,SSL_SEED,  0,0,0,0,0,0},
+	{0,SSL_TXT_eNULL,0,   0,0,SSL_eNULL, 0,0,0,0,0,0},
+	{0,SSL_TXT_AES128,0,  0,0,SSL_AES128|SSL_AES128GCM,0,0,0,0,0,0},
+	{0,SSL_TXT_AES256,0,  0,0,SSL_AES256|SSL_AES256GCM,0,0,0,0,0,0},
+	{0,SSL_TXT_AES,0,     0,0,SSL_AES,0,0,0,0,0,0},
+	{0,SSL_TXT_AES_GCM,0, 0,0,SSL_AES128GCM|SSL_AES256GCM,0,0,0,0,0,0},
+	{0,SSL_TXT_CAMELLIA128,0,0,0,SSL_CAMELLIA128,0,0,0,0,0,0},
+	{0,SSL_TXT_CAMELLIA256,0,0,0,SSL_CAMELLIA256,0,0,0,0,0,0},
+	{0,SSL_TXT_CAMELLIA   ,0,0,0,SSL_CAMELLIA128|SSL_CAMELLIA256,0,0,0,0,0,0},
+
+	/* MAC aliases */	
+	{0,SSL_TXT_MD5,0,     0,0,0,SSL_MD5,   0,0,0,0,0},
+	{0,SSL_TXT_SHA1,0,    0,0,0,SSL_SHA1,  0,0,0,0,0},
+	{0,SSL_TXT_SHA,0,     0,0,0,SSL_SHA1,  0,0,0,0,0},
+	{0,SSL_TXT_GOST94,0,     0,0,0,SSL_GOST94,  0,0,0,0,0},
+	{0,SSL_TXT_GOST89MAC,0,     0,0,0,SSL_GOST89MAC,  0,0,0,0,0},
+	{0,SSL_TXT_SHA256,0,    0,0,0,SSL_SHA256,  0,0,0,0,0},
+	{0,SSL_TXT_SHA384,0,    0,0,0,SSL_SHA384,  0,0,0,0,0},
+
+	/* protocol version aliases */
+	{0,SSL_TXT_SSLV2,0,   0,0,0,0,SSL_SSLV2, 0,0,0,0},
+	{0,SSL_TXT_SSLV3,0,   0,0,0,0,SSL_SSLV3, 0,0,0,0},
+	{0,SSL_TXT_TLSV1,0,   0,0,0,0,SSL_TLSV1, 0,0,0,0},
+	{0,SSL_TXT_TLSV1_2,0, 0,0,0,0,SSL_TLSV1_2, 0,0,0,0},
+
+	/* export flag */
+	{0,SSL_TXT_EXP,0,     0,0,0,0,0,SSL_EXPORT,0,0,0},
+	{0,SSL_TXT_EXPORT,0,  0,0,0,0,0,SSL_EXPORT,0,0,0},
+
+	/* strength classes */
+	{0,SSL_TXT_EXP40,0,   0,0,0,0,0,SSL_EXP40, 0,0,0},
+	{0,SSL_TXT_EXP56,0,   0,0,0,0,0,SSL_EXP56, 0,0,0},
+	{0,SSL_TXT_LOW,0,     0,0,0,0,0,SSL_LOW,   0,0,0},
+	{0,SSL_TXT_MEDIUM,0,  0,0,0,0,0,SSL_MEDIUM,0,0,0},
+	{0,SSL_TXT_HIGH,0,    0,0,0,0,0,SSL_HIGH,  0,0,0},
+	/* FIPS 140-2 approved ciphersuite */
+	{0,SSL_TXT_FIPS,0,    0,0,~SSL_eNULL,0,0,SSL_FIPS,  0,0,0},
+	};
+
+void ssl_load_ciphers(void)
+	{
+	ssl_cipher_methods[SSL_ENC_DES_IDX]= EVP_des_cbc();
+	ssl_cipher_methods[SSL_ENC_3DES_IDX]= EVP_des_ede3_cbc();
+	ssl_cipher_methods[SSL_ENC_RC4_IDX]= EVP_rc4();
+	ssl_cipher_methods[SSL_ENC_AES128_IDX]= EVP_aes_128_cbc();
+	ssl_cipher_methods[SSL_ENC_AES256_IDX]= EVP_aes_256_cbc();
+
+	ssl_cipher_methods[SSL_ENC_AES128GCM_IDX]= EVP_aes_128_gcm();
+	ssl_cipher_methods[SSL_ENC_AES256GCM_IDX]= EVP_aes_256_gcm();
+
+	ssl_digest_methods[SSL_MD_MD5_IDX]= EVP_md5();
+	ssl_mac_secret_size[SSL_MD_MD5_IDX]= EVP_MD_size(EVP_md5());
+	assert(ssl_mac_secret_size[SSL_MD_MD5_IDX] >= 0);
+	ssl_digest_methods[SSL_MD_SHA1_IDX]=EVP_sha1();
+	ssl_mac_secret_size[SSL_MD_SHA1_IDX]= EVP_MD_size(EVP_sha1());
+	assert(ssl_mac_secret_size[SSL_MD_SHA1_IDX] >= 0);
+
+	ssl_digest_methods[SSL_MD_SHA256_IDX]= EVP_sha256();
+	ssl_mac_secret_size[SSL_MD_SHA256_IDX]= EVP_MD_size(EVP_sha256());
+	ssl_digest_methods[SSL_MD_SHA384_IDX]= EVP_sha384();
+	ssl_mac_secret_size[SSL_MD_SHA384_IDX]= EVP_MD_size(EVP_sha384());
+	}
+
+int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
+	     const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size,SSL_COMP **comp)
+	{
+	size_t compression_index;
+	int i;
+	const SSL_CIPHER *c;
+
+	c=s->cipher;
+	if (c == NULL) return(0);
+	if (comp != NULL)
+		{
+		SSL_COMP ctmp;
+
+		*comp=NULL;
+		ctmp.id=s->compress_meth;
+		if (ssl_comp_methods != NULL)
+			{
+			if (sk_SSL_COMP_find(ssl_comp_methods, &compression_index, &ctmp))
+				*comp=sk_SSL_COMP_value(ssl_comp_methods, compression_index);
+			else
+				*comp=NULL;
+			}
+		}
+
+	if ((enc == NULL) || (md == NULL)) return(0);
+
+	switch (c->algorithm_enc)
+		{
+	case SSL_DES:
+		i=SSL_ENC_DES_IDX;
+		break;
+	case SSL_3DES:
+		i=SSL_ENC_3DES_IDX;
+		break;
+	case SSL_RC4:
+		i=SSL_ENC_RC4_IDX;
+		break;
+	case SSL_RC2:
+		i=SSL_ENC_RC2_IDX;
+		break;
+	case SSL_IDEA:
+		i=SSL_ENC_IDEA_IDX;
+		break;
+	case SSL_eNULL:
+		i=SSL_ENC_NULL_IDX;
+		break;
+	case SSL_AES128:
+		i=SSL_ENC_AES128_IDX;
+		break;
+	case SSL_AES256:
+		i=SSL_ENC_AES256_IDX;
+		break;
+	case SSL_CAMELLIA128:
+		i=SSL_ENC_CAMELLIA128_IDX;
+		break;
+	case SSL_CAMELLIA256:
+		i=SSL_ENC_CAMELLIA256_IDX;
+		break;
+	case SSL_eGOST2814789CNT:
+		i=SSL_ENC_GOST89_IDX;
+		break;
+	case SSL_SEED:
+		i=SSL_ENC_SEED_IDX;
+		break;
+	case SSL_AES128GCM:
+		i=SSL_ENC_AES128GCM_IDX;
+		break;
+	case SSL_AES256GCM:
+		i=SSL_ENC_AES256GCM_IDX;
+		break;
+	default:
+		i= -1;
+		break;
+		}
+
+	if ((i < 0) || (i > SSL_ENC_NUM_IDX))
+		*enc=NULL;
+	else
+		{
+		if (i == SSL_ENC_NULL_IDX)
+			*enc = EVP_enc_null();
+
+		*enc=ssl_cipher_methods[i];
+		}
+
+	switch (c->algorithm_mac)
+		{
+	case SSL_MD5:
+		i=SSL_MD_MD5_IDX;
+		break;
+	case SSL_SHA1:
+		i=SSL_MD_SHA1_IDX;
+		break;
+	case SSL_SHA256:
+		i=SSL_MD_SHA256_IDX;
+		break;
+	case SSL_SHA384:
+		i=SSL_MD_SHA384_IDX;
+		break;
+	case SSL_GOST94:
+		i = SSL_MD_GOST94_IDX;
+		break;
+	case SSL_GOST89MAC:
+		i = SSL_MD_GOST89MAC_IDX;
+		break;
+	default:
+		i= -1;
+		break;
+		}
+	if ((i < 0) || (i > SSL_MD_NUM_IDX))
+	{
+		*md=NULL; 
+		if (mac_pkey_type!=NULL) *mac_pkey_type = NID_undef;
+		if (mac_secret_size!=NULL) *mac_secret_size = 0;
+		if (c->algorithm_mac == SSL_AEAD)
+			mac_pkey_type = NULL;
+	}
+	else
+	{
+		*md=ssl_digest_methods[i];
+		if (mac_pkey_type!=NULL) *mac_pkey_type = ssl_mac_pkey_id[i];
+		if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i];
+	}
+
+	if ((*enc != NULL) &&
+	    (*md != NULL || (EVP_CIPHER_flags(*enc)&EVP_CIPH_FLAG_AEAD_CIPHER)) &&
+	    (!mac_pkey_type||*mac_pkey_type != NID_undef))
+		{
+		if (s->ssl_version>>8 != TLS1_VERSION_MAJOR ||
+		    s->ssl_version < TLS1_VERSION)
+			return 1;
+
+#ifdef OPENSSL_FIPS
+		if (FIPS_mode())
+			return 1;
+#endif
+
+		/* TODO(fork): enable the stitched cipher modes. */
+#if 0
+		if	(c->algorithm_enc == SSL_RC4 &&
+			 c->algorithm_mac == SSL_MD5 &&
+			 (evp=EVP_get_cipherbyname("RC4-HMAC-MD5")))
+			*enc = evp, *md = NULL;
+		else if (c->algorithm_enc == SSL_AES128 &&
+			 c->algorithm_mac == SSL_SHA1 &&
+			 (evp=EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1")))
+			*enc = evp, *md = NULL;
+		else if (c->algorithm_enc == SSL_AES256 &&
+			 c->algorithm_mac == SSL_SHA1 &&
+			 (evp=EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1")))
+			*enc = evp, *md = NULL;
+#endif
+		return(1);
+		}
+	else
+		return(0);
+	}
+
+int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md) 
+{
+	if (idx <0||idx>=SSL_MD_NUM_IDX) 
+		{
+		return 0;
+		}
+	*mask = ssl_handshake_digest_flag[idx];
+	if (*mask)
+		*md = ssl_digest_methods[idx];
+	else
+		*md = NULL;
+	return 1;
+}
+
+#define ITEM_SEP(a) \
+	(((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ','))
+
+static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+	     CIPHER_ORDER **tail)
+	{
+	if (curr == *tail) return;
+	if (curr == *head)
+		*head=curr->next;
+	if (curr->prev != NULL)
+		curr->prev->next=curr->next;
+	if (curr->next != NULL)
+		curr->next->prev=curr->prev;
+	(*tail)->next=curr;
+	curr->prev= *tail;
+	curr->next=NULL;
+	*tail=curr;
+	}
+
+static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr,
+	     CIPHER_ORDER **tail)
+	{
+	if (curr == *head) return;
+	if (curr == *tail)
+		*tail=curr->prev;
+	if (curr->next != NULL)
+		curr->next->prev=curr->prev;
+	if (curr->prev != NULL)
+		curr->prev->next=curr->next;
+	(*head)->prev=curr;
+	curr->next= *head;
+	curr->prev=NULL;
+	*head=curr;
+	}
+
+static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *enc, unsigned long *mac, unsigned long *ssl)
+	{
+	*mkey = 0;
+	*auth = 0;
+	*enc = 0;
+	*mac = 0;
+	*ssl = 0;
+
+#ifdef OPENSSL_NO_RSA
+	*mkey |= SSL_kRSA;
+	*auth |= SSL_aRSA;
+#endif
+#ifdef OPENSSL_NO_DSA
+	*auth |= SSL_aDSS;
+#endif
+#ifdef OPENSSL_NO_DH
+	*mkey |= SSL_kDHr|SSL_kDHd|SSL_kEDH;
+	*auth |= SSL_aDH;
+#endif
+#ifdef OPENSSL_NO_ECDSA
+	*auth |= SSL_aECDSA;
+#endif
+#ifdef OPENSSL_NO_ECDH
+	*mkey |= SSL_kECDHe|SSL_kECDHr;
+	*auth |= SSL_aECDH;
+#endif
+#ifdef OPENSSL_NO_PSK
+	*mkey |= SSL_kPSK;
+	*auth |= SSL_aPSK;
+#endif
+#ifdef SSL_FORBID_ENULL
+	*enc |= SSL_eNULL;
+#endif
+		
+
+
+	*enc |= (ssl_cipher_methods[SSL_ENC_DES_IDX ] == NULL) ? SSL_DES :0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_3DES_IDX] == NULL) ? SSL_3DES:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_RC4_IDX ] == NULL) ? SSL_RC4 :0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_RC2_IDX ] == NULL) ? SSL_RC2 :0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_IDEA_IDX] == NULL) ? SSL_IDEA:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_AES128_IDX] == NULL) ? SSL_AES128:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_AES256_IDX] == NULL) ? SSL_AES256:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_AES128GCM_IDX] == NULL) ? SSL_AES128GCM:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_AES256GCM_IDX] == NULL) ? SSL_AES256GCM:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_CAMELLIA128_IDX] == NULL) ? SSL_CAMELLIA128:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_CAMELLIA256_IDX] == NULL) ? SSL_CAMELLIA256:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_GOST89_IDX] == NULL) ? SSL_eGOST2814789CNT:0;
+	*enc |= (ssl_cipher_methods[SSL_ENC_SEED_IDX] == NULL) ? SSL_SEED:0;
+
+	*mac |= (ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL) ? SSL_MD5 :0;
+	*mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1:0;
+	*mac |= (ssl_digest_methods[SSL_MD_SHA256_IDX] == NULL) ? SSL_SHA256:0;
+	*mac |= (ssl_digest_methods[SSL_MD_SHA384_IDX] == NULL) ? SSL_SHA384:0;
+	*mac |= (ssl_digest_methods[SSL_MD_GOST94_IDX] == NULL) ? SSL_GOST94:0;
+	*mac |= (ssl_digest_methods[SSL_MD_GOST89MAC_IDX] == NULL || ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]==NID_undef)? SSL_GOST89MAC:0;
+
+	}
+
+static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
+                int num_of_ciphers,
+                unsigned long disabled_mkey, unsigned long disabled_auth,
+                unsigned long disabled_enc, unsigned long disabled_mac,
+                unsigned long disabled_ssl,
+                CIPHER_ORDER *co_list,
+                CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p)
+	{
+	int i, co_list_num;
+	const SSL_CIPHER *c;
+
+	/*
+	 * We have num_of_ciphers descriptions compiled in, depending on the
+	 * method selected (SSLv2 and/or SSLv3, TLSv1 etc).
+	 * These will later be sorted in a linked list with at most num
+	 * entries.
+	 */
+
+	/* Get the initial list of ciphers */
+	co_list_num = 0;	/* actual count of ciphers */
+	for (i = 0; i < num_of_ciphers; i++)
+		{
+		c = ssl_method->get_cipher(i);
+		/* drop those that use any of that is not available */
+		if ((c != NULL) && c->valid &&
+#ifdef OPENSSL_FIPS
+		    (!FIPS_mode() || (c->algo_strength & SSL_FIPS)) &&
+#endif
+		    !(c->algorithm_mkey & disabled_mkey) &&
+		    !(c->algorithm_auth & disabled_auth) &&
+		    !(c->algorithm_enc & disabled_enc) &&
+		    !(c->algorithm_mac & disabled_mac) &&
+		    !(c->algorithm_ssl & disabled_ssl))
+			{
+			co_list[co_list_num].cipher = c;
+			co_list[co_list_num].next = NULL;
+			co_list[co_list_num].prev = NULL;
+			co_list[co_list_num].active = 0;
+			co_list_num++;
+#ifdef KSSL_DEBUG
+			printf("\t%d: %s %lx %lx %lx\n",i,c->name,c->id,c->algorithm_mkey,c->algorithm_auth);
+#endif	/* KSSL_DEBUG */
+			/*
+			if (!sk_push(ca_list,(char *)c)) goto err;
+			*/
+			}
+		}
+
+	/*
+	 * Prepare linked list from list entries
+	 */	
+	if (co_list_num > 0)
+		{
+		co_list[0].prev = NULL;
+
+		if (co_list_num > 1)
+			{
+			co_list[0].next = &co_list[1];
+			
+			for (i = 1; i < co_list_num - 1; i++)
+				{
+				co_list[i].prev = &co_list[i - 1];
+				co_list[i].next = &co_list[i + 1];
+				}
+
+			co_list[co_list_num - 1].prev = &co_list[co_list_num - 2];
+			}
+		
+		co_list[co_list_num - 1].next = NULL;
+
+		*head_p = &co_list[0];
+		*tail_p = &co_list[co_list_num - 1];
+		}
+	}
+
+static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list,
+                        int num_of_group_aliases,
+                        unsigned long disabled_mkey, unsigned long disabled_auth,
+                        unsigned long disabled_enc, unsigned long disabled_mac,
+                        unsigned long disabled_ssl,
+			CIPHER_ORDER *head)
+	{
+	CIPHER_ORDER *ciph_curr;
+	const SSL_CIPHER **ca_curr;
+	int i;
+	unsigned long mask_mkey = ~disabled_mkey;
+	unsigned long mask_auth = ~disabled_auth;
+	unsigned long mask_enc = ~disabled_enc;
+	unsigned long mask_mac = ~disabled_mac;
+	unsigned long mask_ssl = ~disabled_ssl;
+
+	/*
+	 * First, add the real ciphers as already collected
+	 */
+	ciph_curr = head;
+	ca_curr = ca_list;
+	while (ciph_curr != NULL)
+		{
+		*ca_curr = ciph_curr->cipher;
+		ca_curr++;
+		ciph_curr = ciph_curr->next;
+		}
+
+	/*
+	 * Now we add the available ones from the cipher_aliases[] table.
+	 * They represent either one or more algorithms, some of which
+	 * in any affected category must be supported (set in enabled_mask),
+	 * or represent a cipher strength value (will be added in any case because algorithms=0).
+	 */
+	for (i = 0; i < num_of_group_aliases; i++)
+		{
+		unsigned long algorithm_mkey = cipher_aliases[i].algorithm_mkey;
+		unsigned long algorithm_auth = cipher_aliases[i].algorithm_auth;
+		unsigned long algorithm_enc = cipher_aliases[i].algorithm_enc;
+		unsigned long algorithm_mac = cipher_aliases[i].algorithm_mac;
+		unsigned long algorithm_ssl = cipher_aliases[i].algorithm_ssl;
+
+		if (algorithm_mkey)
+			if ((algorithm_mkey & mask_mkey) == 0)
+				continue;
+	
+		if (algorithm_auth)
+			if ((algorithm_auth & mask_auth) == 0)
+				continue;
+		
+		if (algorithm_enc)
+			if ((algorithm_enc & mask_enc) == 0)
+				continue;
+		
+		if (algorithm_mac)
+			if ((algorithm_mac & mask_mac) == 0)
+				continue;
+		
+		if (algorithm_ssl)
+			if ((algorithm_ssl & mask_ssl) == 0)
+				continue;
+		
+		*ca_curr = (SSL_CIPHER *)(cipher_aliases + i);
+		ca_curr++;
+		}
+
+	*ca_curr = NULL;	/* end of list */
+	}
+
+static void ssl_cipher_apply_rule(unsigned long cipher_id,
+                unsigned long alg_mkey, unsigned long alg_auth,
+                unsigned long alg_enc, unsigned long alg_mac,
+                unsigned long alg_ssl,
+		unsigned long algo_strength,
+		int rule, int strength_bits,
+		CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p)
+	{
+	CIPHER_ORDER *head, *tail, *curr, *curr2, *last;
+	const SSL_CIPHER *cp;
+	int reverse = 0;
+
+#ifdef CIPHER_DEBUG
+	printf("Applying rule %d with %08lx/%08lx/%08lx/%08lx/%08lx %08lx (%d)\n",
+		rule, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, strength_bits);
+#endif
+
+	if (rule == CIPHER_DEL)
+		reverse = 1; /* needed to maintain sorting between currently deleted ciphers */
+
+	head = *head_p;
+	tail = *tail_p;
+
+	if (reverse)
+		{
+		curr = tail;
+		last = head;
+		}
+	else
+		{
+		curr = head;
+		last = tail;
+		}
+
+	curr2 = curr;
+	for (;;)
+		{
+		if ((curr == NULL) || (curr == last)) break;
+		curr = curr2;
+		curr2 = reverse ? curr->prev : curr->next;
+
+		cp = curr->cipher;
+
+		/*
+		 * Selection criteria is either the value of strength_bits
+		 * or the algorithms used.
+		 */
+		if (strength_bits >= 0)
+			{
+			if (strength_bits != cp->strength_bits)
+				continue;
+			}
+		else
+			{
+#ifdef CIPHER_DEBUG
+			printf("\nName: %s:\nAlgo = %08lx/%08lx/%08lx/%08lx/%08lx Algo_strength = %08lx\n", cp->name, cp->algorithm_mkey, cp->algorithm_auth, cp->algorithm_enc, cp->algorithm_mac, cp->algorithm_ssl, cp->algo_strength);
+#endif
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+			if (cipher_id && cipher_id != cp->id)
+				continue;
+#endif
+			if (alg_mkey && !(alg_mkey & cp->algorithm_mkey))
+				continue;
+			if (alg_auth && !(alg_auth & cp->algorithm_auth))
+				continue;
+			if (alg_enc && !(alg_enc & cp->algorithm_enc))
+				continue;
+			if (alg_mac && !(alg_mac & cp->algorithm_mac))
+				continue;
+			if (alg_ssl && !(alg_ssl & cp->algorithm_ssl))
+				continue;
+			if ((algo_strength & SSL_EXP_MASK) && !(algo_strength & SSL_EXP_MASK & cp->algo_strength))
+				continue;
+			if ((algo_strength & SSL_STRONG_MASK) && !(algo_strength & SSL_STRONG_MASK & cp->algo_strength))
+				continue;
+			}
+
+#ifdef CIPHER_DEBUG
+		printf("Action = %d\n", rule);
+#endif
+
+		/* add the cipher if it has not been added yet. */
+		if (rule == CIPHER_ADD)
+			{
+			/* reverse == 0 */
+			if (!curr->active)
+				{
+				ll_append_tail(&head, curr, &tail);
+				curr->active = 1;
+				}
+			}
+		/* Move the added cipher to this location */
+		else if (rule == CIPHER_ORD)
+			{
+			/* reverse == 0 */
+			if (curr->active)
+				{
+				ll_append_tail(&head, curr, &tail);
+				}
+			}
+		else if	(rule == CIPHER_DEL)
+			{
+			/* reverse == 1 */
+			if (curr->active)
+				{
+				/* most recently deleted ciphersuites get best positions
+				 * for any future CIPHER_ADD (note that the CIPHER_DEL loop
+				 * works in reverse to maintain the order) */
+				ll_append_head(&head, curr, &tail);
+				curr->active = 0;
+				}
+			}
+		else if (rule == CIPHER_KILL)
+			{
+			/* reverse == 0 */
+			if (head == curr)
+				head = curr->next;
+			else
+				curr->prev->next = curr->next;
+			if (tail == curr)
+				tail = curr->prev;
+			curr->active = 0;
+			if (curr->next != NULL)
+				curr->next->prev = curr->prev;
+			if (curr->prev != NULL)
+				curr->prev->next = curr->next;
+			curr->next = NULL;
+			curr->prev = NULL;
+			}
+		}
+
+	*head_p = head;
+	*tail_p = tail;
+	}
+
+static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
+				    CIPHER_ORDER **tail_p)
+	{
+	int max_strength_bits, i, *number_uses;
+	CIPHER_ORDER *curr;
+
+	/*
+	 * This routine sorts the ciphers with descending strength. The sorting
+	 * must keep the pre-sorted sequence, so we apply the normal sorting
+	 * routine as '+' movement to the end of the list.
+	 */
+	max_strength_bits = 0;
+	curr = *head_p;
+	while (curr != NULL)
+		{
+		if (curr->active &&
+		    (curr->cipher->strength_bits > max_strength_bits))
+		    max_strength_bits = curr->cipher->strength_bits;
+		curr = curr->next;
+		}
+
+	number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int));
+	if (!number_uses)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_cipher_strength_sort, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int));
+
+	/*
+	 * Now find the strength_bits values actually used
+	 */
+	curr = *head_p;
+	while (curr != NULL)
+		{
+		if (curr->active)
+			number_uses[curr->cipher->strength_bits]++;
+		curr = curr->next;
+		}
+	/*
+	 * Go through the list of used strength_bits values in descending
+	 * order.
+	 */
+	for (i = max_strength_bits; i >= 0; i--)
+		if (number_uses[i] > 0)
+			ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, head_p, tail_p);
+
+	OPENSSL_free(number_uses);
+	return(1);
+	}
+
+static int ssl_cipher_process_rulestr(const char *rule_str,
+                CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p,
+                const SSL_CIPHER **ca_list)
+	{
+	unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength;
+	const char *l, *buf;
+	int j, multi, found, rule, retval, ok, buflen;
+	unsigned long cipher_id = 0;
+	char ch;
+
+	retval = 1;
+	l = rule_str;
+	for (;;)
+		{
+		ch = *l;
+
+		if (ch == '\0')
+			break;		/* done */
+		if (ch == '-')
+			{ rule = CIPHER_DEL; l++; }
+		else if (ch == '+')
+			{ rule = CIPHER_ORD; l++; }
+		else if (ch == '!')
+			{ rule = CIPHER_KILL; l++; }
+		else if (ch == '@')
+			{ rule = CIPHER_SPECIAL; l++; }
+		else
+			{ rule = CIPHER_ADD; }
+
+		if (ITEM_SEP(ch))
+			{
+			l++;
+			continue;
+			}
+
+		alg_mkey = 0;
+		alg_auth = 0;
+		alg_enc = 0;
+		alg_mac = 0;
+		alg_ssl = 0;
+		algo_strength = 0;
+
+		for (;;)
+			{
+			ch = *l;
+			buf = l;
+			buflen = 0;
+#ifndef CHARSET_EBCDIC
+			while (	((ch >= 'A') && (ch <= 'Z')) ||
+				((ch >= '0') && (ch <= '9')) ||
+				((ch >= 'a') && (ch <= 'z')) ||
+				 (ch == '-') || (ch == '.'))
+#else
+			while (	isalnum(ch) || (ch == '-') || (ch == '.'))
+#endif
+				 {
+				 ch = *(++l);
+				 buflen++;
+				 }
+
+			if (buflen == 0)
+				{
+				/*
+				 * We hit something we cannot deal with,
+				 * it is no command or separator nor
+				 * alphanumeric, so we call this an error.
+				 */
+				OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND);
+				retval = found = 0;
+				l++;
+				break;
+				}
+
+			if (rule == CIPHER_SPECIAL)
+				{
+				found = 0; /* unused -- avoid compiler warning */
+				break;	/* special treatment */
+				}
+
+			/* check for multi-part specification */
+			if (ch == '+')
+				{
+				multi=1;
+				l++;
+				}
+			else
+				multi=0;
+
+			/*
+			 * Now search for the cipher alias in the ca_list. Be careful
+			 * with the strncmp, because the "buflen" limitation
+			 * will make the rule "ADH:SOME" and the cipher
+			 * "ADH-MY-CIPHER" look like a match for buflen=3.
+			 * So additionally check whether the cipher name found
+			 * has the correct length. We can save a strlen() call:
+			 * just checking for the '\0' at the right place is
+			 * sufficient, we have to strncmp() anyway. (We cannot
+			 * use strcmp(), because buf is not '\0' terminated.)
+			 */
+			j = found = 0;
+			cipher_id = 0;
+			while (ca_list[j])
+				{
+				if (!strncmp(buf, ca_list[j]->name, buflen) &&
+				    (ca_list[j]->name[buflen] == '\0'))
+					{
+					found = 1;
+					break;
+					}
+				else
+					j++;
+				}
+
+			if (!found)
+				break;	/* ignore this entry */
+
+			if (ca_list[j]->algorithm_mkey)
+				{
+				if (alg_mkey)
+					{
+					alg_mkey &= ca_list[j]->algorithm_mkey;
+					if (!alg_mkey) { found = 0; break; }
+					}
+				else
+					alg_mkey = ca_list[j]->algorithm_mkey;
+				}
+
+			if (ca_list[j]->algorithm_auth)
+				{
+				if (alg_auth)
+					{
+					alg_auth &= ca_list[j]->algorithm_auth;
+					if (!alg_auth) { found = 0; break; }
+					}
+				else
+					alg_auth = ca_list[j]->algorithm_auth;
+				}
+			
+			if (ca_list[j]->algorithm_enc)
+				{
+				if (alg_enc)
+					{
+					alg_enc &= ca_list[j]->algorithm_enc;
+					if (!alg_enc) { found = 0; break; }
+					}
+				else
+					alg_enc = ca_list[j]->algorithm_enc;
+				}
+						
+			if (ca_list[j]->algorithm_mac)
+				{
+				if (alg_mac)
+					{
+					alg_mac &= ca_list[j]->algorithm_mac;
+					if (!alg_mac) { found = 0; break; }
+					}
+				else
+					alg_mac = ca_list[j]->algorithm_mac;
+				}
+			
+			if (ca_list[j]->algo_strength & SSL_EXP_MASK)
+				{
+				if (algo_strength & SSL_EXP_MASK)
+					{
+					algo_strength &= (ca_list[j]->algo_strength & SSL_EXP_MASK) | ~SSL_EXP_MASK;
+					if (!(algo_strength & SSL_EXP_MASK)) { found = 0; break; }
+					}
+				else
+					algo_strength |= ca_list[j]->algo_strength & SSL_EXP_MASK;
+				}
+
+			if (ca_list[j]->algo_strength & SSL_STRONG_MASK)
+				{
+				if (algo_strength & SSL_STRONG_MASK)
+					{
+					algo_strength &= (ca_list[j]->algo_strength & SSL_STRONG_MASK) | ~SSL_STRONG_MASK;
+					if (!(algo_strength & SSL_STRONG_MASK)) { found = 0; break; }
+					}
+				else
+					algo_strength |= ca_list[j]->algo_strength & SSL_STRONG_MASK;
+				}
+			
+			if (ca_list[j]->valid)
+				{
+				/* explicit ciphersuite found; its protocol version
+				 * does not become part of the search pattern!*/
+
+				cipher_id = ca_list[j]->id;
+				}
+			else
+				{
+				/* not an explicit ciphersuite; only in this case, the
+				 * protocol version is considered part of the search pattern */
+
+				if (ca_list[j]->algorithm_ssl)
+					{
+					if (alg_ssl)
+						{
+						alg_ssl &= ca_list[j]->algorithm_ssl;
+						if (!alg_ssl) { found = 0; break; }
+						}
+					else
+						alg_ssl = ca_list[j]->algorithm_ssl;
+					}
+				}
+			
+			if (!multi) break;
+			}
+
+		/*
+		 * Ok, we have the rule, now apply it
+		 */
+		if (rule == CIPHER_SPECIAL)
+			{	/* special command */
+			ok = 0;
+			if ((buflen == 8) &&
+				!strncmp(buf, "STRENGTH", 8))
+				ok = ssl_cipher_strength_sort(head_p, tail_p);
+			else
+				OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND);
+			if (ok == 0)
+				retval = 0;
+			/*
+			 * We do not support any "multi" options
+			 * together with "@", so throw away the
+			 * rest of the command, if any left, until
+			 * end or ':' is found.
+			 */
+			while ((*l != '\0') && !ITEM_SEP(*l))
+				l++;
+			}
+		else if (found)
+			{
+			ssl_cipher_apply_rule(cipher_id,
+				alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength,
+				rule, -1, head_p, tail_p);
+			}
+		else
+			{
+			while ((*l != '\0') && !ITEM_SEP(*l))
+				l++;
+			}
+		if (*l == '\0') break; /* done */
+		}
+
+	return(retval);
+	}
+#ifndef OPENSSL_NO_EC
+static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
+					const char **prule_str)
+	{
+	unsigned int suiteb_flags = 0, suiteb_comb2 = 0;
+	if (!strcmp(*prule_str, "SUITEB128"))
+		suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS;
+	else if (!strcmp(*prule_str, "SUITEB128ONLY"))
+		suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS_ONLY;
+	else if (!strcmp(*prule_str, "SUITEB128C2"))
+		{
+		suiteb_comb2 = 1;
+		suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS;
+		}
+	else if (!strcmp(*prule_str, "SUITEB192"))
+		suiteb_flags = SSL_CERT_FLAG_SUITEB_192_LOS;
+
+	if (suiteb_flags)
+		{
+		c->cert_flags &= ~SSL_CERT_FLAG_SUITEB_128_LOS;
+		c->cert_flags |= suiteb_flags;
+		}
+	else
+		suiteb_flags = c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS;
+
+	if (!suiteb_flags)
+		return 1;
+	/* Check version: if TLS 1.2 ciphers allowed we can use Suite B */
+
+	if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS))
+		{
+		if (meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
+			OPENSSL_PUT_ERROR(SSL, check_suiteb_cipher_list, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+		else
+			OPENSSL_PUT_ERROR(SSL, check_suiteb_cipher_list, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+		return 0;
+		}
+
+	switch(suiteb_flags)
+		{
+	case SSL_CERT_FLAG_SUITEB_128_LOS:
+		if (suiteb_comb2)
+			*prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384";
+		else
+			*prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384";
+		break;
+	case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+		*prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256";
+		break;
+	case SSL_CERT_FLAG_SUITEB_192_LOS:
+		*prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384";
+		break;
+		}
+	/* Set auto ECDH parameter determination */
+	c->ecdh_tmp_auto = 1;
+	return 1;
+	}
+#endif
+
+
+STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
+		STACK_OF(SSL_CIPHER) **cipher_list,
+		STACK_OF(SSL_CIPHER) **cipher_list_by_id,
+		const char *rule_str, CERT *c)
+	{
+	int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases;
+	unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl;
+	STACK_OF(SSL_CIPHER) *cipherstack, *tmp_cipher_list;
+	const char *rule_p;
+	CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
+	const SSL_CIPHER **ca_list = NULL;
+
+	/*
+	 * Return with error if nothing to do.
+	 */
+	if (rule_str == NULL || cipher_list == NULL || cipher_list_by_id == NULL)
+		return NULL;
+#ifndef OPENSSL_NO_EC
+	if (!check_suiteb_cipher_list(ssl_method, c, &rule_str))
+		return NULL;
+#endif
+
+	/*
+	 * To reduce the work to do we only want to process the compiled
+	 * in algorithms, so we first get the mask of disabled ciphers.
+	 */
+	ssl_cipher_get_disabled(&disabled_mkey, &disabled_auth, &disabled_enc, &disabled_mac, &disabled_ssl);
+
+	/*
+	 * Now we have to collect the available ciphers from the compiled
+	 * in ciphers. We cannot get more than the number compiled in, so
+	 * it is used for allocation.
+	 */
+	num_of_ciphers = ssl_method->num_ciphers();
+#ifdef KSSL_DEBUG
+	printf("ssl_create_cipher_list() for %d ciphers\n", num_of_ciphers);
+#endif    /* KSSL_DEBUG */
+	co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers);
+	if (co_list == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE);
+		return(NULL);	/* Failure */
+		}
+
+	ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers,
+	                           disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl,
+	                           co_list, &head, &tail);
+
+
+	/* Now arrange all ciphers by preference: */
+
+	/* Everything else being equal, prefer ephemeral ECDH over other key exchange mechanisms */
+	ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
+	ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
+
+	/* AES is our preferred symmetric cipher */
+	ssl_cipher_apply_rule(0, 0, 0, SSL_AES, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
+
+	/* Temporarily enable everything else for sorting */
+	ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
+
+	/* Low priority for MD5 */
+	ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head, &tail);
+
+	/* Move anonymous ciphers to the end.  Usually, these will remain disabled.
+	 * (For applications that allow them, they aren't too bad, but we prefer
+	 * authenticated ciphers.) */
+	ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+
+	/* Move ciphers without forward secrecy to the end */
+	ssl_cipher_apply_rule(0, 0, SSL_aECDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+	/* ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail); */
+	ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+	ssl_cipher_apply_rule(0, SSL_kPSK, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+	ssl_cipher_apply_rule(0, SSL_kKRB5, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+
+	/* RC4 is sort-of broken -- move the the end */
+	ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+
+	/* Now sort by symmetric encryption strength.  The above ordering remains
+	 * in force within each class */
+	if (!ssl_cipher_strength_sort(&head, &tail))
+		{
+		OPENSSL_free(co_list);
+		return NULL;
+		}
+
+	/* Now disable everything (maintaining the ordering!) */
+	ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
+
+
+	/*
+	 * We also need cipher aliases for selecting based on the rule_str.
+	 * There might be two types of entries in the rule_str: 1) names
+	 * of ciphers themselves 2) aliases for groups of ciphers.
+	 * For 1) we need the available ciphers and for 2) the cipher
+	 * groups of cipher_aliases added together in one list (otherwise
+	 * we would be happy with just the cipher_aliases table).
+	 */
+	num_of_group_aliases = sizeof(cipher_aliases) / sizeof(SSL_CIPHER);
+	num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1;
+	ca_list = OPENSSL_malloc(sizeof(SSL_CIPHER *) * num_of_alias_max);
+	if (ca_list == NULL)
+		{
+		OPENSSL_free(co_list);
+		OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE);
+		return(NULL);	/* Failure */
+		}
+	ssl_cipher_collect_aliases(ca_list, num_of_group_aliases,
+	                           disabled_mkey, disabled_auth, disabled_enc,
+				   disabled_mac, disabled_ssl, head);
+
+	/*
+	 * If the rule_string begins with DEFAULT, apply the default rule
+	 * before using the (possibly available) additional rules.
+	 */
+	ok = 1;
+	rule_p = rule_str;
+	if (strncmp(rule_str,"DEFAULT",7) == 0)
+		{
+		ok = ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST,
+			&head, &tail, ca_list);
+		rule_p += 7;
+		if (*rule_p == ':')
+			rule_p++;
+		}
+
+	if (ok && (strlen(rule_p) > 0))
+		ok = ssl_cipher_process_rulestr(rule_p, &head, &tail, ca_list);
+
+	OPENSSL_free((void *)ca_list);	/* Not needed anymore */
+
+	if (!ok)
+		{	/* Rule processing failure */
+		OPENSSL_free(co_list);
+		return(NULL);
+		}
+	
+	/*
+	 * Allocate new "cipherstack" for the result, return with error
+	 * if we cannot get one.
+	 */
+	if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL)
+		{
+		OPENSSL_free(co_list);
+		return(NULL);
+		}
+
+	/*
+	 * The cipher selection for the list is done. The ciphers are added
+	 * to the resulting precedence to the STACK_OF(SSL_CIPHER).
+	 */
+	for (curr = head; curr != NULL; curr = curr->next)
+		{
+#ifdef OPENSSL_FIPS
+		if (curr->active && (!FIPS_mode() || curr->cipher->algo_strength & SSL_FIPS))
+#else
+		if (curr->active)
+#endif
+			{
+			sk_SSL_CIPHER_push(cipherstack, curr->cipher);
+#ifdef CIPHER_DEBUG
+			printf("<%s>\n",curr->cipher->name);
+#endif
+			}
+		}
+	OPENSSL_free(co_list);	/* Not needed any longer */
+
+	tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack);
+	if (tmp_cipher_list == NULL)
+		{
+		sk_SSL_CIPHER_free(cipherstack);
+		return NULL;
+		}
+	if (*cipher_list != NULL)
+		sk_SSL_CIPHER_free(*cipher_list);
+	*cipher_list = cipherstack;
+	if (*cipher_list_by_id != NULL)
+		sk_SSL_CIPHER_free(*cipher_list_by_id);
+	*cipher_list_by_id = tmp_cipher_list;
+	(void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
+
+	sk_SSL_CIPHER_sort(*cipher_list_by_id);
+	return(cipherstack);
+	}
+
+char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
+	{
+	int is_export,pkl,kl;
+	const char *ver,*exp_str;
+	const char *kx,*au,*enc,*mac;
+	unsigned long alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl,alg2;
+#ifdef KSSL_DEBUG
+	static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s AL=%lx/%lx/%lx/%lx/%lx\n";
+#else
+	static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s\n";
+#endif /* KSSL_DEBUG */
+
+	alg_mkey = cipher->algorithm_mkey;
+	alg_auth = cipher->algorithm_auth;
+	alg_enc = cipher->algorithm_enc;
+	alg_mac = cipher->algorithm_mac;
+	alg_ssl = cipher->algorithm_ssl;
+
+	alg2=cipher->algorithm2;
+
+	is_export=SSL_C_IS_EXPORT(cipher);
+	pkl=SSL_C_EXPORT_PKEYLENGTH(cipher);
+	kl=SSL_C_EXPORT_KEYLENGTH(cipher);
+	exp_str=is_export?" export":"";
+	
+	if (alg_ssl & SSL_SSLV2)
+		ver="SSLv2";
+	else if (alg_ssl & SSL_SSLV3)
+		ver="SSLv3";
+	else if (alg_ssl & SSL_TLSV1_2)
+		ver="TLSv1.2";
+	else
+		ver="unknown";
+
+	switch (alg_mkey)
+		{
+	case SSL_kRSA:
+		kx=is_export?(pkl == 512 ? "RSA(512)" : "RSA(1024)"):"RSA";
+		break;
+	case SSL_kDHr:
+		kx="DH/RSA";
+		break;
+	case SSL_kDHd:
+		kx="DH/DSS";
+		break;
+        case SSL_kKRB5:
+		kx="KRB5";
+		break;
+	case SSL_kEDH:
+		kx=is_export?(pkl == 512 ? "DH(512)" : "DH(1024)"):"DH";
+		break;
+	case SSL_kECDHr:
+		kx="ECDH/RSA";
+		break;
+	case SSL_kECDHe:
+		kx="ECDH/ECDSA";
+		break;
+	case SSL_kEECDH:
+		kx="ECDH";
+		break;
+	case SSL_kPSK:
+		kx="PSK";
+		break;
+	case SSL_kSRP:
+		kx="SRP";
+		break;
+	default:
+		kx="unknown";
+		}
+
+	switch (alg_auth)
+		{
+	case SSL_aRSA:
+		au="RSA";
+		break;
+	case SSL_aDSS:
+		au="DSS";
+		break;
+	case SSL_aDH:
+		au="DH";
+		break;
+        case SSL_aKRB5:
+		au="KRB5";
+		break;
+        case SSL_aECDH:
+		au="ECDH";
+		break;
+	case SSL_aNULL:
+		au="None";
+		break;
+	case SSL_aECDSA:
+		au="ECDSA";
+		break;
+	case SSL_aPSK:
+		au="PSK";
+		break;
+	default:
+		au="unknown";
+		break;
+		}
+
+	switch (alg_enc)
+		{
+	case SSL_DES:
+		enc=(is_export && kl == 5)?"DES(40)":"DES(56)";
+		break;
+	case SSL_3DES:
+		enc="3DES(168)";
+		break;
+	case SSL_RC4:
+		enc=is_export?(kl == 5 ? "RC4(40)" : "RC4(56)")
+		  :((alg2&SSL2_CF_8_BYTE_ENC)?"RC4(64)":"RC4(128)");
+		break;
+	case SSL_RC2:
+		enc=is_export?(kl == 5 ? "RC2(40)" : "RC2(56)"):"RC2(128)";
+		break;
+	case SSL_IDEA:
+		enc="IDEA(128)";
+		break;
+	case SSL_eNULL:
+		enc="None";
+		break;
+	case SSL_AES128:
+		enc="AES(128)";
+		break;
+	case SSL_AES256:
+		enc="AES(256)";
+		break;
+	case SSL_AES128GCM:
+		enc="AESGCM(128)";
+		break;
+	case SSL_AES256GCM:
+		enc="AESGCM(256)";
+		break;
+	case SSL_CAMELLIA128:
+		enc="Camellia(128)";
+		break;
+	case SSL_CAMELLIA256:
+		enc="Camellia(256)";
+		break;
+	case SSL_SEED:
+		enc="SEED(128)";
+		break;
+	default:
+		enc="unknown";
+		break;
+		}
+
+	switch (alg_mac)
+		{
+	case SSL_MD5:
+		mac="MD5";
+		break;
+	case SSL_SHA1:
+		mac="SHA1";
+		break;
+	case SSL_SHA256:
+		mac="SHA256";
+		break;
+	case SSL_SHA384:
+		mac="SHA384";
+		break;
+	case SSL_AEAD:
+		mac="AEAD";
+		break;
+	default:
+		mac="unknown";
+		break;
+		}
+
+	if (buf == NULL)
+		{
+		len=128;
+		buf=OPENSSL_malloc(len);
+		if (buf == NULL) return("OPENSSL_malloc Error");
+		}
+	else if (len < 128)
+		return("Buffer too small");
+
+#ifdef KSSL_DEBUG
+	BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac,exp_str,alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl);
+#else
+	BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac,exp_str);
+#endif /* KSSL_DEBUG */
+	return(buf);
+	}
+
+char *SSL_CIPHER_get_version(const SSL_CIPHER *c)
+	{
+	int i;
+
+	if (c == NULL) return("(NONE)");
+	i=(int)(c->id>>24L);
+	if (i == 3)
+		return("TLSv1/SSLv3");
+	else if (i == 2)
+		return("SSLv2");
+	else
+		return("unknown");
+	}
+
+/* return the actual cipher being used */
+const char *SSL_CIPHER_get_name(const SSL_CIPHER *c)
+	{
+	if (c != NULL)
+		return(c->name);
+	return("(NONE)");
+	}
+
+/* number of bits for symmetric cipher */
+int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits)
+	{
+	int ret=0;
+
+	if (c != NULL)
+		{
+		if (alg_bits != NULL) *alg_bits = c->alg_bits;
+		ret = c->strength_bits;
+		}
+	return(ret);
+	}
+
+unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c)
+	{
+	return c->id;
+	}
+
+SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n)
+	{
+	SSL_COMP *ctmp;
+	int i,nn;
+
+	if ((n == 0) || (sk == NULL)) return(NULL);
+	nn=sk_SSL_COMP_num(sk);
+	for (i=0; i<nn; i++)
+		{
+		ctmp=sk_SSL_COMP_value(sk,i);
+		if (ctmp->id == n)
+			return(ctmp);
+		}
+	return(NULL);
+	}
+
+void *SSL_COMP_get_compression_methods(void)
+	{
+	return NULL;
+	}
+int SSL_COMP_add_compression_method(int id, void *cm)
+	{
+	return 1;
+	}
+
+const char *SSL_COMP_get_name(const void *comp)
+	{
+	return NULL;
+	}
+
+/* For a cipher return the index corresponding to the certificate type */
+int ssl_cipher_get_cert_index(const SSL_CIPHER *c)
+	{
+ 	unsigned long alg_k, alg_a;
+
+	alg_k = c->algorithm_mkey;
+	alg_a = c->algorithm_auth;
+
+	if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+		{
+		/* we don't need to look at SSL_kEECDH
+		 * since no certificate is needed for
+		 * anon ECDH and for authenticated
+		 * EECDH, the check for the auth
+		 * algorithm will set i correctly
+		 * NOTE: For ECDH-RSA, we need an ECC
+		 * not an RSA cert but for EECDH-RSA
+		 * we need an RSA cert. Placing the
+		 * checks for SSL_kECDH before RSA
+		 * checks ensures the correct cert is chosen.
+		 */
+		return SSL_PKEY_ECC;
+		}
+	else if (alg_a & SSL_aECDSA)
+		return SSL_PKEY_ECC;
+	else if (alg_k & SSL_kDHr)
+		return SSL_PKEY_DH_RSA;
+	else if (alg_k & SSL_kDHd)
+		return SSL_PKEY_DH_DSA;
+	else if (alg_a & SSL_aDSS)
+		return SSL_PKEY_DSA_SIGN;
+	else if (alg_a & SSL_aRSA)
+		return SSL_PKEY_RSA_ENC;
+	else if (alg_a & SSL_aKRB5)
+		/* VRS something else here? */
+		return -1;
+	else if (alg_a & SSL_aGOST94) 
+		return SSL_PKEY_GOST94;
+	else if (alg_a & SSL_aGOST01)
+		return SSL_PKEY_GOST01;
+	return -1;
+	}
+
+const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr)
+	{
+	const SSL_CIPHER *c;
+	c = ssl->method->get_cipher_by_char(ptr);
+	if (c == NULL || c->valid == 0)
+		return NULL;
+	return c;
+	}
+
+const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr)
+	{
+	return ssl->method->get_cipher_by_char(ptr);
+	}
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
new file mode 100644
index 0000000..ac8f6e8
--- /dev/null
+++ b/ssl/ssl_error.c
@@ -0,0 +1,518 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "ssl.h"
+
+const ERR_STRING_DATA SSL_error_string_data[] = {
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_D2I_SSL_SESSION, 0), "D2I_SSL_SESSION"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_check_private_key, 0), "SSL_CTX_check_private_key"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_new, 0), "SSL_CTX_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_cipher_list, 0), "SSL_CTX_set_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_session_id_context, 0), "SSL_CTX_set_session_id_context"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_set_ssl_version, 0), "SSL_CTX_set_ssl_version"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey, 0), "SSL_CTX_use_PrivateKey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey_ASN1, 0), "SSL_CTX_use_PrivateKey_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_PrivateKey_file, 0), "SSL_CTX_use_PrivateKey_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey, 0), "SSL_CTX_use_RSAPrivateKey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey_ASN1, 0), "SSL_CTX_use_RSAPrivateKey_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_RSAPrivateKey_file, 0), "SSL_CTX_use_RSAPrivateKey_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_authz, 0), "SSL_CTX_use_authz"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate, 0), "SSL_CTX_use_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_ASN1, 0), "SSL_CTX_use_certificate_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_chain_file, 0), "SSL_CTX_use_certificate_chain_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_certificate_file, 0), "SSL_CTX_use_certificate_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_psk_identity_hint, 0), "SSL_CTX_use_psk_identity_hint"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_serverinfo, 0), "SSL_CTX_use_serverinfo"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_use_serverinfo_file, 0), "SSL_CTX_use_serverinfo_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_new, 0), "SSL_SESSION_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_print_fp, 0), "SSL_SESSION_print_fp"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_set1_id_context, 0), "SSL_SESSION_set1_id_context"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_dir_cert_subjects_to_stack, 0), "SSL_add_dir_cert_subjects_to_stack"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_file_cert_subjects_to_stack, 0), "SSL_add_file_cert_subjects_to_stack"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_check_private_key, 0), "SSL_check_private_key"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_clear, 0), "SSL_clear"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_do_handshake, 0), "SSL_do_handshake"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_load_client_CA_file, 0), "SSL_load_client_CA_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_new, 0), "SSL_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_peek, 0), "SSL_peek"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_read, 0), "SSL_read"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_cipher_list, 0), "SSL_set_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_fd, 0), "SSL_set_fd"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_rfd, 0), "SSL_set_rfd"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session, 0), "SSL_set_session"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session_id_context, 0), "SSL_set_session_id_context"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_session_ticket_ext, 0), "SSL_set_session_ticket_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_set_wfd, 0), "SSL_set_wfd"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_shutdown, 0), "SSL_shutdown"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey, 0), "SSL_use_PrivateKey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey_ASN1, 0), "SSL_use_PrivateKey_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_PrivateKey_file, 0), "SSL_use_PrivateKey_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey, 0), "SSL_use_RSAPrivateKey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey_ASN1, 0), "SSL_use_RSAPrivateKey_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_RSAPrivateKey_file, 0), "SSL_use_RSAPrivateKey_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_authz, 0), "SSL_use_authz"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate, 0), "SSL_use_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate_ASN1, 0), "SSL_use_certificate_ASN1"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_certificate_file, 0), "SSL_use_certificate_file"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_use_psk_identity_hint, 0), "SSL_use_psk_identity_hint"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_write, 0), "SSL_write"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_authz_find_data, 0), "authz_find_data"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_check_suiteb_cipher_list, 0), "check_suiteb_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_do_dtls1_write, 0), "do_dtls1_write"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_do_ssl3_write, 0), "do_ssl3_write"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_accept, 0), "dtls1_accept"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_buffer_record, 0), "dtls1_buffer_record"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_check_timeout_num, 0), "dtls1_check_timeout_num"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_connect, 0), "dtls1_connect"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_hello_verify, 0), "dtls1_get_hello_verify"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_message, 0), "dtls1_get_message"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_get_message_fragment, 0), "dtls1_get_message_fragment"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_heartbeat, 0), "dtls1_heartbeat"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_preprocess_fragment, 0), "dtls1_preprocess_fragment"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_process_record, 0), "dtls1_process_record"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_read_bytes, 0), "dtls1_read_bytes"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_send_hello_verify_request, 0), "dtls1_send_hello_verify_request"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_write_app_data_bytes, 0), "dtls1_write_app_data_bytes"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_fclose, 0), "fclose"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_fprintf, 0), "fprintf"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_printf, 0), "printf"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_read_authz, 0), "read_authz"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_accept, 0), "ssl23_accept"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_client_hello, 0), "ssl23_client_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_connect, 0), "ssl23_connect"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_get_client_hello, 0), "ssl23_get_client_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_get_server_hello, 0), "ssl23_get_server_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_peek, 0), "ssl23_peek"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_read, 0), "ssl23_read"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_write, 0), "ssl23_write"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_accept, 0), "ssl3_accept"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_callback_ctrl, 0), "ssl3_callback_ctrl"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_change_cipher_state, 0), "ssl3_change_cipher_state"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_cert_and_algorithm, 0), "ssl3_check_cert_and_algorithm"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_client_hello, 0), "ssl3_check_client_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_client_hello, 0), "ssl3_client_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_connect, 0), "ssl3_connect"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctrl, 0), "ssl3_ctrl"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctx_ctrl, 0), "ssl3_ctx_ctrl"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_digest_cached_records, 0), "ssl3_digest_cached_records"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_do_change_cipher_spec, 0), "ssl3_do_change_cipher_spec"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_generate_key_block, 0), "ssl3_generate_key_block"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_cert_status, 0), "ssl3_get_cert_status"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_cert_verify, 0), "ssl3_get_cert_verify"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_certificate_request, 0), "ssl3_get_certificate_request"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_certificate, 0), "ssl3_get_client_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_hello, 0), "ssl3_get_client_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_client_key_exchange, 0), "ssl3_get_client_key_exchange"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_finished, 0), "ssl3_get_finished"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_key_exchange, 0), "ssl3_get_key_exchange"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_message, 0), "ssl3_get_message"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_new_session_ticket, 0), "ssl3_get_new_session_ticket"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_next_proto, 0), "ssl3_get_next_proto"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_record, 0), "ssl3_get_record"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_certificate, 0), "ssl3_get_server_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_done, 0), "ssl3_get_server_done"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_get_server_hello, 0), "ssl3_get_server_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_handshake_mac, 0), "ssl3_handshake_mac"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_bytes, 0), "ssl3_read_bytes"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_n, 0), "ssl3_read_n"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_certificate_request, 0), "ssl3_send_certificate_request"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_verify, 0), "ssl3_send_client_verify"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_key_block, 0), "ssl3_setup_key_block"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_read_buffer, 0), "ssl3_setup_read_buffer"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_setup_write_buffer, 0), "ssl3_setup_write_buffer"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_write_bytes, 0), "ssl3_write_bytes"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_write_pending, 0), "ssl3_write_pending"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_cert_chain, 0), "ssl_add_cert_chain"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_cert_to_buf, 0), "ssl_add_cert_to_buf"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_renegotiate_ext, 0), "ssl_add_clienthello_renegotiate_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_tlsext, 0), "ssl_add_clienthello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_clienthello_use_srtp_ext, 0), "ssl_add_clienthello_use_srtp_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_renegotiate_ext, 0), "ssl_add_serverhello_renegotiate_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_tlsext, 0), "ssl_add_serverhello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_add_serverhello_use_srtp_ext, 0), "ssl_add_serverhello_use_srtp_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_bad_method, 0), "ssl_bad_method"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_build_cert_chain, 0), "ssl_build_cert_chain"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_bytes_to_cipher_list, 0), "ssl_bytes_to_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_dup, 0), "ssl_cert_dup"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_inst, 0), "ssl_cert_inst"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cert_new, 0), "ssl_cert_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_check_serverhello_tlsext, 0), "ssl_check_serverhello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_check_srvr_ecc_cert_and_alg, 0), "ssl_check_srvr_ecc_cert_and_alg"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_process_rulestr, 0), "ssl_cipher_process_rulestr"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_strength_sort, 0), "ssl_cipher_strength_sort"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_create_cipher_list, 0), "ssl_create_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_make_profiles, 0), "ssl_ctx_make_profiles"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_new_session, 0), "ssl_get_new_session"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_prev_session, 0), "ssl_get_prev_session"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_server_cert_index, 0), "ssl_get_server_cert_index"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_sign_pkey, 0), "ssl_get_sign_pkey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_init_wbio_buffer, 0), "ssl_init_wbio_buffer"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_new, 0), "ssl_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_renegotiate_ext, 0), "ssl_parse_clienthello_renegotiate_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_tlsext, 0), "ssl_parse_clienthello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_clienthello_use_srtp_ext, 0), "ssl_parse_clienthello_use_srtp_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_renegotiate_ext, 0), "ssl_parse_serverhello_renegotiate_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_tlsext, 0), "ssl_parse_serverhello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_parse_serverhello_use_srtp_ext, 0), "ssl_parse_serverhello_use_srtp_ext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_prepare_clienthello_tlsext, 0), "ssl_prepare_clienthello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_scan_clienthello_tlsext, 0), "ssl_scan_clienthello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_scan_serverhello_tlsext, 0), "ssl_scan_serverhello_tlsext"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_sess_cert_new, 0), "ssl_sess_cert_new"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_authz, 0), "ssl_set_authz"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_cert, 0), "ssl_set_cert"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_set_pkey, 0), "ssl_set_pkey"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_const_function, 0), "ssl_undefined_const_function"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_function, 0), "ssl_undefined_function"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_undefined_void_function, 0), "ssl_undefined_void_function"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_verify_cert_chain, 0), "ssl_verify_cert_chain"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls12_check_peer_sigalg, 0), "tls12_check_peer_sigalg"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_PRF, 0), "tls1_PRF"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_cert_verify_mac, 0), "tls1_cert_verify_mac"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_change_cipher_state, 0), "tls1_change_cipher_state"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_export_keying_material, 0), "tls1_export_keying_material"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_get_server_supplemental_data, 0), "tls1_get_server_supplemental_data"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_heartbeat, 0), "tls1_heartbeat"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_send_server_supplemental_data, 0), "tls1_send_server_supplemental_data"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_tls1_setup_key_block, 0), "tls1_setup_key_block"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APP_DATA_IN_HANDSHAKE), "APP_DATA_IN_HANDSHAKE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT), "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AUTHZ_DATA_TOO_LARGE), "AUTHZ_DATA_TOO_LARGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ALERT_RECORD), "BAD_ALERT_RECORD"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_AUTHENTICATION_TYPE), "BAD_AUTHENTICATION_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC), "BAD_CHANGE_CIPHER_SPEC"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHECKSUM), "BAD_CHECKSUM"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "BAD_DATA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), "BAD_DATA_RETURNED_BY_CALLBACK"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "BAD_DECOMPRESSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_G_LENGTH), "BAD_DH_G_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_PUB_KEY_LENGTH), "BAD_DH_PUB_KEY_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_P_LENGTH), "BAD_DH_P_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DIGEST_LENGTH), "BAD_DIGEST_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DSA_SIGNATURE), "BAD_DSA_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECC_CERT), "BAD_ECC_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECDSA_SIGNATURE), "BAD_ECDSA_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECPOINT), "BAD_ECPOINT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_LENGTH), "BAD_HANDSHAKE_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HELLO_REQUEST), "BAD_HELLO_REQUEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_LENGTH), "BAD_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MAC_DECODE), "BAD_MAC_DECODE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MAC_LENGTH), "BAD_MAC_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_MESSAGE_TYPE), "BAD_MESSAGE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET_LENGTH), "BAD_PACKET_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PROTOCOL_VERSION_NUMBER), "BAD_PROTOCOL_VERSION_NUMBER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH), "BAD_PSK_IDENTITY_HINT_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RESPONSE_ARGUMENT), "BAD_RESPONSE_ARGUMENT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_DECRYPT), "BAD_RSA_DECRYPT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_ENCRYPT), "BAD_RSA_ENCRYPT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_E_LENGTH), "BAD_RSA_E_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_MODULUS_LENGTH), "BAD_RSA_MODULUS_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_SIGNATURE), "BAD_RSA_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SIGNATURE), "BAD_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_A_LENGTH), "BAD_SRP_A_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_B_LENGTH), "BAD_SRP_B_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_G_LENGTH), "BAD_SRP_G_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_N_LENGTH), "BAD_SRP_N_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_S_LENGTH), "BAD_SRP_S_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_MKI_VALUE), "BAD_SRTP_MKI_VALUE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST), "BAD_SRTP_PROTECTION_PROFILE_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_FILETYPE), "BAD_SSL_FILETYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_SESSION_ID_LENGTH), "BAD_SSL_SESSION_ID_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_STATE), "BAD_STATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_VALUE), "BAD_VALUE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_WRITE_RETRY), "BAD_WRITE_RETRY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BIO_NOT_SET), "BIO_NOT_SET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG), "BLOCK_CIPHER_PAD_IS_WRONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BN_LIB), "BN_LIB"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_LENGTH_MISMATCH), "CA_DN_LENGTH_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_TOO_LONG), "CA_DN_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CCS_RECEIVED_EARLY), "CCS_RECEIVED_EARLY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERTIFICATE_VERIFY_FAILED), "CERTIFICATE_VERIFY_FAILED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_CB_ERROR), "CERT_CB_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_LENGTH_MISMATCH), "CERT_LENGTH_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CHALLENGE_IS_DIFFERENT), "CHALLENGE_IS_DIFFERENT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_CODE_WRONG_LENGTH), "CIPHER_CODE_WRONG_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_OR_HASH_UNAVAILABLE), "CIPHER_OR_HASH_UNAVAILABLE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_TABLE_SRC_ERROR), "CIPHER_TABLE_SRC_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CLIENTHELLO_TLSEXT), "CLIENTHELLO_TLSEXT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSED_LENGTH_TOO_LONG), "COMPRESSED_LENGTH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_DISABLED), "COMPRESSION_DISABLED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_FAILURE), "COMPRESSION_FAILURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE), "COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_LIBRARY_ERROR), "COMPRESSION_LIBRARY_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_ID_IS_DIFFERENT), "CONNECTION_ID_IS_DIFFERENT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_TYPE_NOT_SET), "CONNECTION_TYPE_NOT_SET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_MISMATCH), "COOKIE_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED), "DATA_BETWEEN_CCS_AND_FINISHED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_LENGTH_TOO_LONG), "DATA_LENGTH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED), "DECRYPTION_FAILED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC), "DECRYPTION_FAILED_OR_BAD_RECORD_MAC"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG), "DH_PUBLIC_VALUE_LENGTH_IS_WRONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DIGEST_CHECK_FAILED), "DIGEST_CHECK_FAILED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DTLS_MESSAGE_TOO_BIG), "DTLS_MESSAGE_TOO_BIG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DUPLICATE_COMPRESSION_ID), "DUPLICATE_COMPRESSION_ID"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT), "ECC_CERT_NOT_FOR_KEY_AGREEMENT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_SIGNING), "ECC_CERT_NOT_FOR_SIGNING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE), "ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE), "ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER), "ECGROUP_TOO_LARGE_FOR_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST), "EMPTY_SRTP_PROTECTION_PROFILE_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ENCRYPTED_LENGTH_TOO_LONG), "ENCRYPTED_LENGTH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_GENERATING_TMP_RSA_KEY), "ERROR_GENERATING_TMP_RSA_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST), "ERROR_IN_RECEIVED_CIPHER_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCESSIVE_MESSAGE_SIZE), "EXCESSIVE_MESSAGE_SIZE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTRA_DATA_IN_MESSAGE), "EXTRA_DATA_IN_MESSAGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOST_NOT_SUPPORTED), "GOST_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_A_FIN_BEFORE_A_CCS), "GOT_A_FIN_BEFORE_A_CCS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS), "GOT_NEXT_PROTO_BEFORE_A_CCS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION), "GOT_NEXT_PROTO_WITHOUT_EXTENSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTPS_PROXY_REQUEST), "HTTPS_PROXY_REQUEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "HTTP_REQUEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_PADDING), "ILLEGAL_PADDING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_SUITEB_DIGEST), "ILLEGAL_SUITEB_DIGEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION), "INCONSISTENT_COMPRESSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUDIT_PROOF), "INVALID_AUDIT_PROOF"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUTHZ_DATA), "INVALID_AUTHZ_DATA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CHALLENGE_LENGTH), "INVALID_CHALLENGE_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "INVALID_COMMAND"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMPRESSION_ALGORITHM), "INVALID_COMPRESSION_ALGORITHM"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_NULL_CMD_NAME), "INVALID_NULL_CMD_NAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_PURPOSE), "INVALID_PURPOSE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "INVALID_SERVERINFO_DATA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "INVALID_SRP_USERNAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), "INVALID_STATUS_RESPONSE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH), "INVALID_TICKET_KEYS_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TRUST), "INVALID_TRUST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KEY_ARG_TOO_LONG), "KEY_ARG_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5), "KRB5"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_CC_PRINC), "KRB5_C_CC_PRINC"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_GET_CRED), "KRB5_C_GET_CRED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_INIT), "KRB5_C_INIT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_C_MK_REQ), "KRB5_C_MK_REQ"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_BAD_TICKET), "KRB5_S_BAD_TICKET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_INIT), "KRB5_S_INIT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_RD_REQ), "KRB5_S_RD_REQ"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_EXPIRED), "KRB5_S_TKT_EXPIRED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_NYV), "KRB5_S_TKT_NYV"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_KRB5_S_TKT_SKEW), "KRB5_S_TKT_SKEW"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_MISMATCH), "LENGTH_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_SHORT), "LENGTH_TOO_SHORT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_BUG), "LIBRARY_BUG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_HAS_NO_CIPHERS), "LIBRARY_HAS_NO_CIPHERS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MESSAGE_TOO_LONG), "MESSAGE_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_DSA_CERT), "MISSING_DH_DSA_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_KEY), "MISSING_DH_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DH_RSA_CERT), "MISSING_DH_RSA_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DSA_SIGNING_CERT), "MISSING_DSA_SIGNING_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDH_CERT), "MISSING_ECDH_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT), "MISSING_ECDSA_SIGNING_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_EXPORT_TMP_DH_KEY), "MISSING_EXPORT_TMP_DH_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_EXPORT_TMP_RSA_KEY), "MISSING_EXPORT_TMP_RSA_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE), "MISSING_RSA_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT), "MISSING_RSA_ENCRYPTING_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_SIGNING_CERT), "MISSING_RSA_SIGNING_CERT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SRP_PARAM), "MISSING_SRP_PARAM"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_DH_KEY), "MISSING_TMP_DH_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_ECDH_KEY), "MISSING_TMP_ECDH_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_KEY), "MISSING_TMP_RSA_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_PKEY), "MISSING_TMP_RSA_PKEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_VERIFY_MESSAGE), "MISSING_VERIFY_MESSAGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MULTIPLE_SGC_RESTARTS), "MULTIPLE_SGC_RESTARTS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NON_SSLV2_INITIAL_PACKET), "NON_SSLV2_INITIAL_PACKET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED), "NO_CERTIFICATES_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_ASSIGNED), "NO_CERTIFICATE_ASSIGNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_RETURNED), "NO_CERTIFICATE_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SET), "NO_CERTIFICATE_SET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SPECIFIED), "NO_CERTIFICATE_SPECIFIED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_AVAILABLE), "NO_CIPHERS_AVAILABLE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_PASSED), "NO_CIPHERS_PASSED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_SPECIFIED), "NO_CIPHERS_SPECIFIED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_LIST), "NO_CIPHER_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_MATCH), "NO_CIPHER_MATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_METHOD), "NO_CLIENT_CERT_METHOD"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_RECEIVED), "NO_CLIENT_CERT_RECEIVED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COMPRESSION_SPECIFIED), "NO_COMPRESSION_SPECIFIED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER), "NO_GOST_CERTIFICATE_SENT_BY_PEER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_METHOD_SPECIFIED), "NO_METHOD_SPECIFIED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PEM_EXTENSIONS), "NO_PEM_EXTENSIONS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATEKEY), "NO_PRIVATEKEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATE_KEY_ASSIGNED), "NO_PRIVATE_KEY_ASSIGNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PROTOCOLS_AVAILABLE), "NO_PROTOCOLS_AVAILABLE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PUBLICKEY), "NO_PUBLICKEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_RENEGOTIATION), "NO_RENEGOTIATION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_REQUIRED_DIGEST), "NO_REQUIRED_DIGEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_CIPHER), "NO_SHARED_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS), "NO_SHARED_SIGATURE_ALGORITHMS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SRTP_PROFILES), "NO_SRTP_PROFILES"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VERIFY_CALLBACK), "NO_VERIFY_CALLBACK"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_CTX), "NULL_SSL_CTX"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_METHOD_PASSED), "NULL_SSL_METHOD_PASSED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED), "OLD_SESSION_CIPHER_NOT_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED), "OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE), "ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE), "ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE), "ONLY_TLS_ALLOWED_IN_FIPS_MODE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG), "OPAQUE_PRF_INPUT_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PACKET_LENGTH_TOO_LONG), "PACKET_LENGTH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PARSE_TLSEXT), "PARSE_TLSEXT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PATH_TOO_LONG), "PATH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE), "PEER_DID_NOT_RETURN_A_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR), "PEER_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_CERTIFICATE), "PEER_ERROR_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_NO_CERTIFICATE), "PEER_ERROR_NO_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_NO_CIPHER), "PEER_ERROR_NO_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE), "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_BAD_PREFIX), "PEM_NAME_BAD_PREFIX"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_TOO_SHORT), "PEM_NAME_TOO_SHORT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PRE_MAC_LENGTH_TOO_LONG), "PRE_MAC_LENGTH_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS), "PROBLEMS_MAPPING_CIPHER_FUNCTIONS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN), "PROTOCOL_IS_SHUTDOWN"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND), "PSK_IDENTITY_NOT_FOUND"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_CLIENT_CB), "PSK_NO_CLIENT_CB"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_SERVER_CB), "PSK_NO_SERVER_CB"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_ENCRYPT_ERROR), "PUBLIC_KEY_ENCRYPT_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_IS_NOT_RSA), "PUBLIC_KEY_IS_NOT_RSA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PUBLIC_KEY_NOT_RSA), "PUBLIC_KEY_NOT_RSA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_BIO_NOT_SET), "READ_BIO_NOT_SET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_TIMEOUT_EXPIRED), "READ_TIMEOUT_EXPIRED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_WRONG_PACKET_TYPE), "READ_WRONG_PACKET_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LENGTH_MISMATCH), "RECORD_LENGTH_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_LARGE), "RECORD_TOO_LARGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_SMALL), "RECORD_TOO_SMALL"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATE_EXT_TOO_LONG), "RENEGOTIATE_EXT_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_ENCODING_ERR), "RENEGOTIATION_ENCODING_ERR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_MISMATCH), "RENEGOTIATION_MISMATCH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_CIPHER_MISSING), "REQUIRED_CIPHER_MISSING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING), "REQUIRED_COMPRESSSION_ALGORITHM_MISSING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CERT_LENGTH_NOT_ZERO), "REUSE_CERT_LENGTH_NOT_ZERO"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CERT_TYPE_NOT_ZERO), "REUSE_CERT_TYPE_NOT_ZERO"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REUSE_CIPHER_LIST_NOT_ZERO), "REUSE_CIPHER_LIST_NOT_ZERO"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING), "SCSV_RECEIVED_WHEN_RENEGOTIATING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SERVERHELLO_TLSEXT), "SERVERHELLO_TLSEXT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED), "SESSION_ID_CONTEXT_UNINITIALIZED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), "SHORT_READ"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_ALGORITHMS_ERROR), "SIGNATURE_ALGORITHMS_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE), "SIGNATURE_FOR_NON_SIGNING_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRP_A_CALC), "SRP_A_CALC"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES), "SRTP_COULD_NOT_ALLOCATE_PROFILES"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG), "SRTP_PROTECTION_PROFILE_LIST_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE), "SRTP_UNKNOWN_PROTECTION_PROFILE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL23_DOING_SESSION_ID_REUSE), "SSL23_DOING_SESSION_ID_REUSE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL2_CONNECTION_ID_TOO_LONG), "SSL2_CONNECTION_ID_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT), "SSL3_EXT_INVALID_ECPOINTFORMAT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME), "SSL3_EXT_INVALID_SERVERNAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE), "SSL3_EXT_INVALID_SERVERNAME_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_LONG), "SSL3_SESSION_ID_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_SHORT), "SSL3_SESSION_ID_TOO_SHORT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE), "SSLV3_ALERT_BAD_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC), "SSLV3_ALERT_BAD_RECORD_MAC"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED), "SSLV3_ALERT_CERTIFICATE_EXPIRED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED), "SSLV3_ALERT_CERTIFICATE_REVOKED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN), "SSLV3_ALERT_CERTIFICATE_UNKNOWN"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE), "SSLV3_ALERT_DECOMPRESSION_FAILURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE), "SSLV3_ALERT_HANDSHAKE_FAILURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER), "SSLV3_ALERT_ILLEGAL_PARAMETER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_NO_CERTIFICATE), "SSLV3_ALERT_NO_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE), "SSLV3_ALERT_UNEXPECTED_MESSAGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE), "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION), "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_HANDSHAKE_FAILURE), "SSL_HANDSHAKE_FAILURE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS), "SSL_LIBRARY_HAS_NO_CIPHERS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED), "SSL_SESSION_ID_CALLBACK_FAILED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONFLICT), "SSL_SESSION_ID_CONFLICT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG), "SSL_SESSION_ID_CONTEXT_TOO_LONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH), "SSL_SESSION_ID_HAS_BAD_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_IS_DIFFERENT), "SSL_SESSION_ID_IS_DIFFERENT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_ACCESS_DENIED), "TLSV1_ALERT_ACCESS_DENIED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECODE_ERROR), "TLSV1_ALERT_DECODE_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED), "TLSV1_ALERT_DECRYPTION_FAILED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR), "TLSV1_ALERT_DECRYPT_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION), "TLSV1_ALERT_EXPORT_RESTRICTION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY), "TLSV1_ALERT_INSUFFICIENT_SECURITY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR), "TLSV1_ALERT_INTERNAL_ERROR"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION), "TLSV1_ALERT_NO_RENEGOTIATION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION), "TLSV1_ALERT_PROTOCOL_VERSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW), "TLSV1_ALERT_RECORD_OVERFLOW"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_UNKNOWN_CA), "TLSV1_ALERT_UNKNOWN_CA"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_USER_CANCELLED), "TLSV1_ALERT_USER_CANCELLED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE), "TLSV1_BAD_CERTIFICATE_HASH_VALUE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE), "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE), "TLSV1_CERTIFICATE_UNOBTAINABLE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNRECOGNIZED_NAME), "TLSV1_UNRECOGNIZED_NAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION), "TLSV1_UNSUPPORTED_EXTENSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER), "TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT), "TLS_HEARTBEAT_PEER_DOESNT_ACCEPT"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_HEARTBEAT_PENDING), "TLS_HEARTBEAT_PENDING"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL), "TLS_ILLEGAL_EXPORTER_LABEL"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST), "TLS_INVALID_ECPOINTFORMAT_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST), "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG), "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER), "TRIED_TO_USE_UNSUPPORTED_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_DECODE_DH_CERTS), "UNABLE_TO_DECODE_DH_CERTS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS), "UNABLE_TO_DECODE_ECDH_CERTS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY), "UNABLE_TO_EXTRACT_PUBLIC_KEY"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_DH_PARAMETERS), "UNABLE_TO_FIND_DH_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS), "UNABLE_TO_FIND_ECDH_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS), "UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_SSL_METHOD), "UNABLE_TO_FIND_SSL_METHOD"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL2_MD5_ROUTINES"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL3_MD5_ROUTINES"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), "UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "UNEXPECTED_MESSAGE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "UNEXPECTED_RECORD"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "UNINITIALIZED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "UNKNOWN_ALERT_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_AUTHZ_DATA_TYPE), "UNKNOWN_AUTHZ_DATA_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CERTIFICATE_TYPE), "UNKNOWN_CERTIFICATE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_RETURNED), "UNKNOWN_CIPHER_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_TYPE), "UNKNOWN_CIPHER_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CMD_NAME), "UNKNOWN_CMD_NAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE), "UNKNOWN_KEY_EXCHANGE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PKEY_TYPE), "UNKNOWN_PKEY_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PROTOCOL), "UNKNOWN_PROTOCOL"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_REMOTE_ERROR_TYPE), "UNKNOWN_REMOTE_ERROR_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SSL_VERSION), "UNKNOWN_SSL_VERSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_STATE), "UNKNOWN_STATE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE), "UNKNOWN_SUPPLEMENTAL_DATA_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED), "UNSAFE_LEGACY_RENEGOTIATION_DISABLED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_CIPHER), "UNSUPPORTED_CIPHER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM), "UNSUPPORTED_COMPRESSION_ALGORITHM"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_DIGEST_TYPE), "UNSUPPORTED_DIGEST_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE), "UNSUPPORTED_ELLIPTIC_CURVE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_PROTOCOL), "UNSUPPORTED_PROTOCOL"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_SSL_VERSION), "UNSUPPORTED_SSL_VERSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_STATUS_TYPE), "UNSUPPORTED_STATUS_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_USE_SRTP_NOT_NEGOTIATED), "USE_SRTP_NOT_NEGOTIATED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRITE_BIO_NOT_SET), "WRITE_BIO_NOT_SET"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CERTIFICATE_TYPE), "WRONG_CERTIFICATE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED), "WRONG_CIPHER_RETURNED"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "WRONG_CURVE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_MESSAGE_TYPE), "WRONG_MESSAGE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_NUMBER_OF_KEY_BITS), "WRONG_NUMBER_OF_KEY_BITS"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH), "WRONG_SIGNATURE_LENGTH"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE), "WRONG_SIGNATURE_SIZE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_TYPE), "WRONG_SIGNATURE_TYPE"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SSL_VERSION), "WRONG_SSL_VERSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_VERSION_NUMBER), "WRONG_VERSION_NUMBER"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_LIB), "X509_LIB"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS), "X509_VERIFICATION_SETUP_PROBLEMS"},
+  {0, NULL},
+};
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
new file mode 100644
index 0000000..eec32b2
--- /dev/null
+++ b/ssl/ssl_lib.c
@@ -0,0 +1,3344 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * 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 <assert.h>
+
+#include <openssl/dh.h>
+#include <openssl/engine.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+
+#include "ssl_locl.h"
+
+SSL3_ENC_METHOD ssl3_undef_enc_method={
+	/* evil casts, but these functions are only called if there's a library bug */
+	(int (*)(SSL *,int))ssl_undefined_function,
+	(int (*)(SSL *, unsigned char *, int))ssl_undefined_function,
+	ssl_undefined_function,
+	(int (*)(SSL *, unsigned char *, unsigned char *, int))ssl_undefined_function,
+	(int (*)(SSL*, int))ssl_undefined_function,
+	(int (*)(SSL *,  const char*, int, unsigned char *))ssl_undefined_function,
+	0,	/* finish_mac_length */
+	(int (*)(SSL *, int, unsigned char *))ssl_undefined_function,
+	NULL,	/* client_finished_label */
+	0,	/* client_finished_label_len */
+	NULL,	/* server_finished_label */
+	0,	/* server_finished_label_len */
+	(int (*)(int))ssl_undefined_function,
+	(int (*)(SSL *, unsigned char *, size_t, const char *,
+		 size_t, const unsigned char *, size_t,
+		 int use_context)) ssl_undefined_function,
+	};
+
+int SSL_clear(SSL *s)
+	{
+
+	if (s->method == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_clear, SSL_R_NO_METHOD_SPECIFIED);
+		return(0);
+		}
+
+	if (ssl_clear_bad_session(s))
+		{
+		SSL_SESSION_free(s->session);
+		s->session=NULL;
+		}
+
+	s->error=0;
+	s->hit=0;
+	s->shutdown=0;
+
+#if 0 /* Disabled since version 1.10 of this file (early return not
+       * needed because SSL_clear is not called when doing renegotiation) */
+	/* This is set if we are doing dynamic renegotiation so keep
+	 * the old cipher.  It is sort of a SSL_clear_lite :-) */
+	if (s->renegotiate) return(1);
+#else
+	if (s->renegotiate)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_clear, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+#endif
+
+	s->type=0;
+
+	s->state=SSL_ST_BEFORE|((s->server)?SSL_ST_ACCEPT:SSL_ST_CONNECT);
+
+	s->version=s->method->version;
+	s->client_version=s->version;
+	s->rwstate=SSL_NOTHING;
+	s->rstate=SSL_ST_READ_HEADER;
+#if 0
+	s->read_ahead=s->ctx->read_ahead;
+#endif
+
+	if (s->init_buf != NULL)
+		{
+		BUF_MEM_free(s->init_buf);
+		s->init_buf=NULL;
+		}
+
+	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
+
+	s->first_packet=0;
+
+#if 1
+	/* 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) && (s->method != s->ctx->method))
+		{
+		s->method->ssl_free(s);
+		s->method=s->ctx->method;
+		if (!s->method->ssl_new(s))
+			return(0);
+		}
+	else
+#endif
+		s->method->ssl_clear(s);
+	return(1);
+	}
+
+/** Used to change an SSL_CTXs default SSL method type */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx,const SSL_METHOD *meth)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+
+	ctx->method=meth;
+
+	sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
+		&(ctx->cipher_list_by_id),
+		meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ctx->cert);
+	if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_ssl_version, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
+		return(0);
+		}
+	return(1);
+	}
+
+SSL *SSL_new(SSL_CTX *ctx)
+	{
+	SSL *s;
+
+	if (ctx == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_NULL_SSL_CTX);
+		return(NULL);
+		}
+	if (ctx->method == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_new, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+		return(NULL);
+		}
+
+	s=(SSL *)OPENSSL_malloc(sizeof(SSL));
+	if (s == NULL) goto err;
+	memset(s,0,sizeof(SSL));
+
+	s->options=ctx->options;
+	s->mode=ctx->mode;
+	s->max_cert_list=ctx->max_cert_list;
+
+	if (ctx->cert != NULL)
+		{
+		/* Earlier library versions used to copy the pointer to
+		 * the CERT, not its contents; only when setting new
+		 * parameters for the per-SSL copy, ssl_cert_new would be
+		 * called (and the direct reference to the per-SSL_CTX
+		 * settings would be lost, but those still were indirectly
+		 * accessed for various purposes, and for that reason they
+		 * used to be known as s->ctx->default_cert).
+		 * Now we don't look at the SSL_CTX's CERT after having
+		 * duplicated it once. */
+
+		s->cert = ssl_cert_dup(ctx->cert);
+		if (s->cert == NULL)
+			goto err;
+		}
+	else
+		s->cert=NULL; /* Cannot really happen (see SSL_CTX_new) */
+
+	s->read_ahead=ctx->read_ahead;
+	s->msg_callback=ctx->msg_callback;
+	s->msg_callback_arg=ctx->msg_callback_arg;
+	s->verify_mode=ctx->verify_mode;
+#if 0
+	s->verify_depth=ctx->verify_depth;
+#endif
+	s->sid_ctx_length=ctx->sid_ctx_length;
+	assert(s->sid_ctx_length <= sizeof s->sid_ctx);
+	memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx));
+	s->verify_callback=ctx->default_verify_callback;
+	s->generate_session_id=ctx->generate_session_id;
+
+	s->param = X509_VERIFY_PARAM_new();
+	if (!s->param)
+		goto err;
+	X509_VERIFY_PARAM_inherit(s->param, ctx->param);
+#if 0
+	s->purpose = ctx->purpose;
+	s->trust = ctx->trust;
+#endif
+	s->quiet_shutdown=ctx->quiet_shutdown;
+	s->max_send_fragment = ctx->max_send_fragment;
+
+	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+	s->ctx=ctx;
+#ifndef OPENSSL_NO_TLSEXT
+	s->tlsext_debug_cb = 0;
+	s->tlsext_debug_arg = NULL;
+	s->tlsext_ticket_expected = 0;
+	s->tlsext_status_type = -1;
+	s->tlsext_status_expected = 0;
+	s->tlsext_ocsp_ids = NULL;
+	s->tlsext_ocsp_exts = NULL;
+	s->tlsext_ocsp_resp = NULL;
+	s->tlsext_ocsp_resplen = -1;
+	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+	s->initial_ctx=ctx;
+#ifndef OPENSSL_NO_EC
+	if (ctx->tlsext_ecpointformatlist)
+		{
+		s->tlsext_ecpointformatlist =
+			BUF_memdup(ctx->tlsext_ecpointformatlist,
+					ctx->tlsext_ecpointformatlist_length);
+		if (!s->tlsext_ecpointformatlist)
+			goto err;
+		s->tlsext_ecpointformatlist_length =
+					ctx->tlsext_ecpointformatlist_length;
+		}
+	if (ctx->tlsext_ellipticcurvelist)
+		{
+		s->tlsext_ellipticcurvelist =
+			BUF_memdup(ctx->tlsext_ellipticcurvelist,
+					ctx->tlsext_ellipticcurvelist_length);
+		if (!s->tlsext_ellipticcurvelist)
+			goto err;
+		s->tlsext_ellipticcurvelist_length = 
+					ctx->tlsext_ellipticcurvelist_length;
+		}
+#endif
+# ifndef OPENSSL_NO_NEXTPROTONEG
+	s->next_proto_negotiated = NULL;
+# endif
+
+	if (s->ctx->alpn_client_proto_list)
+		{
+		s->alpn_client_proto_list =
+			OPENSSL_malloc(s->ctx->alpn_client_proto_list_len);
+		if (s->alpn_client_proto_list == NULL)
+			goto err;
+		memcpy(s->alpn_client_proto_list, s->ctx->alpn_client_proto_list,
+		       s->ctx->alpn_client_proto_list_len);
+		s->alpn_client_proto_list_len = s->ctx->alpn_client_proto_list_len;
+		}
+#endif
+
+	s->verify_result=X509_V_OK;
+
+	s->method=ctx->method;
+
+	if (!s->method->ssl_new(s))
+		goto err;
+
+	s->references=1;
+	s->server=(ctx->method->ssl_accept == ssl_undefined_function)?0:1;
+
+	SSL_clear(s);
+
+	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+#ifndef OPENSSL_NO_PSK
+	s->psk_client_callback=ctx->psk_client_callback;
+	s->psk_server_callback=ctx->psk_server_callback;
+#endif
+
+	return(s);
+err:
+	if (s != NULL)
+		{
+		if (s->cert != NULL)
+			ssl_cert_free(s->cert);
+		if (s->ctx != NULL)
+			SSL_CTX_free(s->ctx); /* decrement reference count */
+		OPENSSL_free(s);
+		}
+	OPENSSL_PUT_ERROR(SSL, SSL_new, ERR_R_MALLOC_FAILURE);
+	return(NULL);
+	}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+				   unsigned int sid_ctx_len)
+    {
+    if(sid_ctx_len > sizeof ctx->sid_ctx)
+	{
+	OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_session_id_context, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+	return 0;
+	}
+    ctx->sid_ctx_length=sid_ctx_len;
+    memcpy(ctx->sid_ctx,sid_ctx,sid_ctx_len);
+
+    return 1;
+    }
+
+int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+			       unsigned int sid_ctx_len)
+    {
+    if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
+	{
+	OPENSSL_PUT_ERROR(SSL, SSL_set_session_id_context, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+	return 0;
+	}
+    ssl->sid_ctx_length=sid_ctx_len;
+    memcpy(ssl->sid_ctx,sid_ctx,sid_ctx_len);
+
+    return 1;
+    }
+
+int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
+	{
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	ctx->generate_session_id = cb;
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	return 1;
+	}
+
+int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
+	{
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+	ssl->generate_session_id = cb;
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+	return 1;
+	}
+
+int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+				unsigned int id_len)
+	{
+	/* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
+	 * we can "construct" a session to give us the desired check - ie. to
+	 * find if there's a session in the hash table that would conflict with
+	 * any new session built out of this id/id_len and the ssl_version in
+	 * use by this SSL. */
+	SSL_SESSION r, *p;
+
+	if(id_len > sizeof r.session_id)
+		return 0;
+
+	r.ssl_version = ssl->version;
+	r.session_id_length = id_len;
+	memcpy(r.session_id, id, id_len);
+	/* NB: SSLv2 always uses a fixed 16-byte session ID, so even if a
+	 * callback is calling us to check the uniqueness of a shorter ID, it
+	 * must be compared as a padded-out ID because that is what it will be
+	 * converted to when the callback has finished choosing it. */
+	if((r.ssl_version == SSL2_VERSION) &&
+			(id_len < SSL2_SSL_SESSION_ID_LENGTH))
+		{
+		memset(r.session_id + id_len, 0,
+			SSL2_SSL_SESSION_ID_LENGTH - id_len);
+		r.session_id_length = SSL2_SSL_SESSION_ID_LENGTH;
+		}
+
+	CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+	p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r);
+	CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+	return (p != NULL);
+	}
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
+	{
+	return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+	}
+
+int SSL_set_purpose(SSL *s, int purpose)
+	{
+	return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+	}
+
+int SSL_CTX_set_trust(SSL_CTX *s, int trust)
+	{
+	return X509_VERIFY_PARAM_set_trust(s->param, trust);
+	}
+
+int SSL_set_trust(SSL *s, int trust)
+	{
+	return X509_VERIFY_PARAM_set_trust(s->param, trust);
+	}
+
+int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
+	{
+	return X509_VERIFY_PARAM_set1(ctx->param, vpm);
+	}
+
+int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
+	{
+	return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+	}
+
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
+	{
+	return ctx->param;
+	}
+
+X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
+	{
+	return ssl->param;
+	}
+
+void SSL_certs_clear(SSL *s)
+	{
+	ssl_cert_clear_certs(s->cert);
+	}
+
+void SSL_free(SSL *s)
+	{
+	int i;
+
+	if(s == NULL)
+	    return;
+
+	i=CRYPTO_add(&s->references,-1,CRYPTO_LOCK_SSL);
+#ifdef REF_PRINT
+	REF_PRINT("SSL",s);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"SSL_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	if (s->param)
+		X509_VERIFY_PARAM_free(s->param);
+
+	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+	if (s->bbio != NULL)
+		{
+		/* If the buffering BIO is in place, pop it off */
+		if (s->bbio == s->wbio)
+			{
+			s->wbio=BIO_pop(s->wbio);
+			}
+		BIO_free(s->bbio);
+		s->bbio=NULL;
+		}
+	if (s->rbio != NULL)
+		BIO_free_all(s->rbio);
+	if ((s->wbio != NULL) && (s->wbio != s->rbio))
+		BIO_free_all(s->wbio);
+
+	if (s->init_buf != NULL) BUF_MEM_free(s->init_buf);
+
+	/* add extra stuff */
+	if (s->cipher_list != NULL) sk_SSL_CIPHER_free(s->cipher_list);
+	if (s->cipher_list_by_id != NULL) sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+	/* Make the next call work :-) */
+	if (s->session != NULL)
+		{
+		ssl_clear_bad_session(s);
+		SSL_SESSION_free(s->session);
+		}
+
+	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
+
+	if (s->cert != NULL) ssl_cert_free(s->cert);
+	/* Free up if allocated */
+
+#ifndef OPENSSL_NO_TLSEXT
+	if (s->tlsext_hostname)
+		OPENSSL_free(s->tlsext_hostname);
+	if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
+#ifndef OPENSSL_NO_EC
+	if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
+	if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
+#endif /* OPENSSL_NO_EC */
+	if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
+	if (s->tlsext_ocsp_exts)
+		sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+						X509_EXTENSION_free);
+        /* TODO(fork): OCSP support */
+#if 0
+	if (s->tlsext_ocsp_ids)
+		sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+#endif
+	if (s->tlsext_ocsp_resp)
+		OPENSSL_free(s->tlsext_ocsp_resp);
+	if (s->alpn_client_proto_list)
+		OPENSSL_free(s->alpn_client_proto_list);
+#endif
+
+	if (s->client_CA != NULL)
+		sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
+
+	if (s->method != NULL) s->method->ssl_free(s);
+
+	if (s->ctx) SSL_CTX_free(s->ctx);
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+	if (s->next_proto_negotiated)
+		OPENSSL_free(s->next_proto_negotiated);
+#endif
+
+        if (s->srtp_profiles)
+            sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
+
+#ifndef OPENSSL_NO_DANE
+	if (s->tlsa_record && s->tlsa_record!=(void *)-1)
+		OPENSSL_free(s->tlsa_record);
+#endif
+
+	OPENSSL_free(s);
+	}
+
+void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
+	{
+	/* If the output buffering BIO is still in place, remove it
+	 */
+	if (s->bbio != NULL)
+		{
+		if (s->wbio == s->bbio)
+			{
+			s->wbio=s->wbio->next_bio;
+			s->bbio->next_bio=NULL;
+			}
+		}
+	if ((s->rbio != NULL) && (s->rbio != rbio))
+		BIO_free_all(s->rbio);
+	if ((s->wbio != NULL) && (s->wbio != wbio) && (s->rbio != s->wbio))
+		BIO_free_all(s->wbio);
+	s->rbio=rbio;
+	s->wbio=wbio;
+	}
+
+BIO *SSL_get_rbio(const SSL *s)
+	{ return(s->rbio); }
+
+BIO *SSL_get_wbio(const SSL *s)
+	{ return(s->wbio); }
+
+int SSL_get_fd(const SSL *s)
+	{
+	return(SSL_get_rfd(s));
+	}
+
+int SSL_get_rfd(const SSL *s)
+	{
+	int ret= -1;
+	BIO *b,*r;
+
+	b=SSL_get_rbio(s);
+	r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+	if (r != NULL)
+		BIO_get_fd(r,&ret);
+	return(ret);
+	}
+
+int SSL_get_wfd(const SSL *s)
+	{
+	int ret= -1;
+	BIO *b,*r;
+
+	b=SSL_get_wbio(s);
+	r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+	if (r != NULL)
+		BIO_get_fd(r,&ret);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_SOCK
+int SSL_set_fd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	bio=BIO_new(BIO_s_fd());
+
+	if (bio == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_set_fd, ERR_R_BUF_LIB);
+		goto err;
+		}
+	BIO_set_fd(bio,fd,BIO_NOCLOSE);
+	SSL_set_bio(s,bio,bio);
+	ret=1;
+err:
+	return(ret);
+	}
+
+int SSL_set_wfd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	if ((s->rbio == NULL) || (BIO_method_type(s->rbio) != BIO_TYPE_FD)
+		|| ((int)BIO_get_fd(s->rbio,NULL) != fd))
+		{
+		bio=BIO_new(BIO_s_fd());
+
+		if (bio == NULL)
+			{
+                        OPENSSL_PUT_ERROR(SSL, SSL_set_wfd, ERR_R_BUF_LIB);
+                        goto err;
+                        }
+		BIO_set_fd(bio,fd,BIO_NOCLOSE);
+		SSL_set_bio(s,SSL_get_rbio(s),bio);
+		}
+	else
+		SSL_set_bio(s,SSL_get_rbio(s),SSL_get_rbio(s));
+	ret=1;
+err:
+	return(ret);
+	}
+
+int SSL_set_rfd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	if ((s->wbio == NULL) || (BIO_method_type(s->wbio) != BIO_TYPE_FD)
+		|| ((int)BIO_get_fd(s->wbio,NULL) != fd))
+		{
+		bio=BIO_new(BIO_s_fd());
+
+		if (bio == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_set_rfd, ERR_R_BUF_LIB);
+			goto err;
+			}
+		BIO_set_fd(bio,fd,BIO_NOCLOSE);
+		SSL_set_bio(s,bio,SSL_get_wbio(s));
+		}
+	else
+		SSL_set_bio(s,SSL_get_wbio(s),SSL_get_wbio(s));
+	ret=1;
+err:
+	return(ret);
+	}
+#endif
+
+
+/* return length of latest Finished message we sent, copy to 'buf' */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
+	{
+	size_t ret = 0;
+	
+	if (s->s3 != NULL)
+		{
+		ret = s->s3->tmp.finish_md_len;
+		if (count > ret)
+			count = ret;
+		memcpy(buf, s->s3->tmp.finish_md, count);
+		}
+	return ret;
+	}
+
+/* return length of latest Finished message we expected, copy to 'buf' */
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
+	{
+	size_t ret = 0;
+	
+	if (s->s3 != NULL)
+		{
+		ret = s->s3->tmp.peer_finish_md_len;
+		if (count > ret)
+			count = ret;
+		memcpy(buf, s->s3->tmp.peer_finish_md, count);
+		}
+	return ret;
+	}
+
+
+int SSL_get_verify_mode(const SSL *s)
+	{
+	return(s->verify_mode);
+	}
+
+int SSL_get_verify_depth(const SSL *s)
+	{
+	return X509_VERIFY_PARAM_get_depth(s->param);
+	}
+
+int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *)
+	{
+	return(s->verify_callback);
+	}
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
+	{
+	return(ctx->verify_mode);
+	}
+
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
+	{
+	return X509_VERIFY_PARAM_get_depth(ctx->param);
+	}
+
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *)
+	{
+	return(ctx->default_verify_callback);
+	}
+
+void SSL_set_verify(SSL *s,int mode,
+		    int (*callback)(int ok,X509_STORE_CTX *ctx))
+	{
+	s->verify_mode=mode;
+	if (callback != NULL)
+		s->verify_callback=callback;
+	}
+
+void SSL_set_verify_depth(SSL *s,int depth)
+	{
+	X509_VERIFY_PARAM_set_depth(s->param, depth);
+	}
+
+void SSL_set_read_ahead(SSL *s,int yes)
+	{
+	s->read_ahead=yes;
+	}
+
+int SSL_get_read_ahead(const SSL *s)
+	{
+	return(s->read_ahead);
+	}
+
+int SSL_pending(const SSL *s)
+	{
+	/* SSL_pending cannot work properly if read-ahead is enabled
+	 * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)),
+	 * and it is impossible to fix since SSL_pending cannot report
+	 * errors that may be observed while scanning the new data.
+	 * (Note that SSL_pending() is often used as a boolean value,
+	 * so we'd better not return -1.)
+	 */
+	return(s->method->ssl_pending(s));
+	}
+
+X509 *SSL_get_peer_certificate(const SSL *s)
+	{
+	X509 *r;
+	
+	if ((s == NULL) || (s->session == NULL))
+		r=NULL;
+	else
+		r=s->session->peer;
+
+	if (r == NULL) return(r);
+
+	CRYPTO_add(&r->references,1,CRYPTO_LOCK_X509);
+
+	return(r);
+	}
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
+	{
+	STACK_OF(X509) *r;
+	
+	if ((s == NULL) || (s->session == NULL) || (s->session->sess_cert == NULL))
+		r=NULL;
+	else
+		r=s->session->sess_cert->cert_chain;
+
+	/* If we are a client, cert_chain includes the peer's own
+	 * certificate; if we are a server, it does not. */
+	
+	return(r);
+	}
+
+/* Now in theory, since the calling process own 't' it should be safe to
+ * modify.  We need to be able to read f without being hassled */
+void SSL_copy_session_id(SSL *t,const SSL *f)
+	{
+	CERT *tmp;
+
+	/* Do we need to to SSL locking? */
+	SSL_set_session(t,SSL_get_session(f));
+
+	/* what if we are setup as SSLv2 but want to talk SSLv3 or
+	 * vice-versa */
+	if (t->method != f->method)
+		{
+		t->method->ssl_free(t);	/* cleanup current */
+		t->method=f->method;	/* change method */
+		t->method->ssl_new(t);	/* setup new */
+		}
+
+	tmp=t->cert;
+	if (f->cert != NULL)
+		{
+		CRYPTO_add(&f->cert->references,1,CRYPTO_LOCK_SSL_CERT);
+		t->cert=f->cert;
+		}
+	else
+		t->cert=NULL;
+	if (tmp != NULL) ssl_cert_free(tmp);
+	SSL_set_session_id_context(t,f->sid_ctx,f->sid_ctx_length);
+	}
+
+/* Fix this so it checks all the valid key/cert options */
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+	{
+	if (	(ctx == NULL) ||
+		(ctx->cert == NULL) ||
+		(ctx->cert->key->x509 == NULL))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key, SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return(0);
+		}
+	if 	(ctx->cert->key->privatekey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+		return(0);
+		}
+	return(X509_check_private_key(ctx->cert->key->x509, ctx->cert->key->privatekey));
+	}
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl)
+	{
+	if (ssl == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (ssl->cert == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return 0;
+		}
+	if (ssl->cert->key->x509 == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return(0);
+		}
+	if (ssl->cert->key->privatekey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_check_private_key, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+		return(0);
+		}
+	return(X509_check_private_key(ssl->cert->key->x509,
+		ssl->cert->key->privatekey));
+	}
+
+int SSL_accept(SSL *s)
+	{
+	if (s->handshake_func == 0)
+		/* Not properly initialized yet */
+		SSL_set_accept_state(s);
+
+	return(s->method->ssl_accept(s));
+	}
+
+int SSL_connect(SSL *s)
+	{
+	if (s->handshake_func == 0)
+		/* Not properly initialized yet */
+		SSL_set_connect_state(s);
+
+	return(s->method->ssl_connect(s));
+	}
+
+long SSL_get_default_timeout(const SSL *s)
+	{
+	return(s->method->get_timeout());
+	}
+
+int SSL_read(SSL *s,void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_read, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+	return(s->method->ssl_read(s,buf,num));
+	}
+
+int SSL_peek(SSL *s,void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_peek, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		return(0);
+		}
+	return(s->method->ssl_peek(s,buf,num));
+	}
+
+int SSL_write(SSL *s,const void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_SENT_SHUTDOWN)
+		{
+		s->rwstate=SSL_NOTHING;
+		OPENSSL_PUT_ERROR(SSL, SSL_write, SSL_R_PROTOCOL_IS_SHUTDOWN);
+		return(-1);
+		}
+	return(s->method->ssl_write(s,buf,num));
+	}
+
+int SSL_shutdown(SSL *s)
+	{
+	/* Note that this function behaves differently from what one might
+	 * expect.  Return values are 0 for no success (yet),
+	 * 1 for success; but calling it once is usually not enough,
+	 * even if blocking I/O is used (see ssl3_shutdown).
+	 */
+
+	if (s->handshake_func == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_shutdown, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if ((s != NULL) && !SSL_in_init(s))
+		return(s->method->ssl_shutdown(s));
+	else
+		return(1);
+	}
+
+int SSL_renegotiate(SSL *s)
+	{
+	if (s->renegotiate == 0)
+		s->renegotiate=1;
+
+	s->new_session=1;
+
+	return(s->method->ssl_renegotiate(s));
+	}
+
+int SSL_renegotiate_abbreviated(SSL *s)
+	{
+	if (s->renegotiate == 0)
+		s->renegotiate=1;
+
+	s->new_session=0;
+
+	return(s->method->ssl_renegotiate(s));
+	}
+
+int SSL_renegotiate_pending(SSL *s)
+	{
+	/* becomes true when negotiation is requested;
+	 * false again once a handshake has finished */
+	return (s->renegotiate != 0);
+	}
+
+long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
+	{
+	long l;
+
+	switch (cmd)
+		{
+	case SSL_CTRL_GET_READ_AHEAD:
+		return(s->read_ahead);
+	case SSL_CTRL_SET_READ_AHEAD:
+		l=s->read_ahead;
+		s->read_ahead=larg;
+		return(l);
+
+	case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+		s->msg_callback_arg = parg;
+		return 1;
+
+	case SSL_CTRL_OPTIONS:
+		return(s->options|=larg);
+	case SSL_CTRL_CLEAR_OPTIONS:
+		return(s->options&=~larg);
+	case SSL_CTRL_MODE:
+		return(s->mode|=larg);
+	case SSL_CTRL_CLEAR_MODE:
+		return(s->mode &=~larg);
+	case SSL_CTRL_GET_MAX_CERT_LIST:
+		return(s->max_cert_list);
+	case SSL_CTRL_SET_MAX_CERT_LIST:
+		l=s->max_cert_list;
+		s->max_cert_list=larg;
+		return(l);
+	case SSL_CTRL_SET_MTU:
+#ifndef OPENSSL_NO_DTLS1
+		if (larg < (long)dtls1_min_mtu())
+			return 0;
+#endif
+
+		if (SSL_IS_DTLS(s))
+			{
+			s->d1->mtu = larg;
+			return larg;
+			}
+		return 0;
+	case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+		if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+			return 0;
+		s->max_send_fragment = larg;
+		return 1;
+	case SSL_CTRL_GET_RI_SUPPORT:
+		if (s->s3)
+			return s->s3->send_connection_binding;
+		else return 0;
+	case SSL_CTRL_CERT_FLAGS:
+		return(s->cert->cert_flags|=larg);
+	case SSL_CTRL_CLEAR_CERT_FLAGS:
+		return(s->cert->cert_flags &=~larg);
+
+	case SSL_CTRL_GET_RAW_CIPHERLIST:
+		if (parg)
+			{
+			if (s->cert->ciphers_raw == NULL)
+				return 0;
+			*(unsigned char **)parg = s->cert->ciphers_raw;
+			return (int)s->cert->ciphers_rawlen;
+			}
+		else
+			return ssl_put_cipher_by_char(s,NULL,NULL);
+	default:
+		return(s->method->ssl_ctrl(s,cmd,larg,parg));
+		}
+	}
+
+long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
+	{
+	switch(cmd)
+		{
+	case SSL_CTRL_SET_MSG_CALLBACK:
+		s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+		return 1;
+		
+	default:
+		return(s->method->ssl_callback_ctrl(s,cmd,fp));
+		}
+	}
+
+LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
+	{
+	return ctx->sessions;
+	}
+
+long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
+	{
+	long l;
+
+	switch (cmd)
+		{
+	case SSL_CTRL_GET_READ_AHEAD:
+		return(ctx->read_ahead);
+	case SSL_CTRL_SET_READ_AHEAD:
+		l=ctx->read_ahead;
+		ctx->read_ahead=larg;
+		return(l);
+		
+	case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+		ctx->msg_callback_arg = parg;
+		return 1;
+
+	case SSL_CTRL_GET_MAX_CERT_LIST:
+		return(ctx->max_cert_list);
+	case SSL_CTRL_SET_MAX_CERT_LIST:
+		l=ctx->max_cert_list;
+		ctx->max_cert_list=larg;
+		return(l);
+
+	case SSL_CTRL_SET_SESS_CACHE_SIZE:
+		l=ctx->session_cache_size;
+		ctx->session_cache_size=larg;
+		return(l);
+	case SSL_CTRL_GET_SESS_CACHE_SIZE:
+		return(ctx->session_cache_size);
+	case SSL_CTRL_SET_SESS_CACHE_MODE:
+		l=ctx->session_cache_mode;
+		ctx->session_cache_mode=larg;
+		return(l);
+	case SSL_CTRL_GET_SESS_CACHE_MODE:
+		return(ctx->session_cache_mode);
+
+	case SSL_CTRL_SESS_NUMBER:
+		return(lh_SSL_SESSION_num_items(ctx->sessions));
+	case SSL_CTRL_SESS_CONNECT:
+		return(ctx->stats.sess_connect);
+	case SSL_CTRL_SESS_CONNECT_GOOD:
+		return(ctx->stats.sess_connect_good);
+	case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
+		return(ctx->stats.sess_connect_renegotiate);
+	case SSL_CTRL_SESS_ACCEPT:
+		return(ctx->stats.sess_accept);
+	case SSL_CTRL_SESS_ACCEPT_GOOD:
+		return(ctx->stats.sess_accept_good);
+	case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
+		return(ctx->stats.sess_accept_renegotiate);
+	case SSL_CTRL_SESS_HIT:
+		return(ctx->stats.sess_hit);
+	case SSL_CTRL_SESS_CB_HIT:
+		return(ctx->stats.sess_cb_hit);
+	case SSL_CTRL_SESS_MISSES:
+		return(ctx->stats.sess_miss);
+	case SSL_CTRL_SESS_TIMEOUTS:
+		return(ctx->stats.sess_timeout);
+	case SSL_CTRL_SESS_CACHE_FULL:
+		return(ctx->stats.sess_cache_full);
+	case SSL_CTRL_OPTIONS:
+		return(ctx->options|=larg);
+	case SSL_CTRL_CLEAR_OPTIONS:
+		return(ctx->options&=~larg);
+	case SSL_CTRL_MODE:
+		return(ctx->mode|=larg);
+	case SSL_CTRL_CLEAR_MODE:
+		return(ctx->mode&=~larg);
+	case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+		if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+			return 0;
+		ctx->max_send_fragment = larg;
+		return 1;
+	case SSL_CTRL_CERT_FLAGS:
+		return(ctx->cert->cert_flags|=larg);
+	case SSL_CTRL_CLEAR_CERT_FLAGS:
+		return(ctx->cert->cert_flags &=~larg);
+	default:
+		return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
+		}
+	}
+
+long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
+	{
+	switch(cmd)
+		{
+	case SSL_CTRL_SET_MSG_CALLBACK:
+		ctx->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+		return 1;
+
+	default:
+		return(ctx->method->ssl_ctx_callback_ctrl(ctx,cmd,fp));
+		}
+	}
+
+int ssl_cipher_id_cmp(const void *in_a, const void *in_b)
+	{
+	long l;
+	const SSL_CIPHER *a = in_a;
+	const SSL_CIPHER *b = in_b;
+	const long a_id = a->id;
+	const long b_id = b->id;
+
+	l = a_id - b_id;
+	if (l == 0L)
+		return(0);
+	else
+		return((l > 0)?1:-1);
+	}
+
+int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp)
+	{
+	long l;
+	const long a_id = (*ap)->id;
+	const long b_id = (*bp)->id;
+
+	l = a_id - b_id;
+	if (l == 0)
+		return(0);
+	else
+		return((l > 0)?1:-1);
+	}
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * preference */
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
+	{
+	if (s != NULL)
+		{
+		if (s->cipher_list != NULL)
+			{
+			return(s->cipher_list);
+			}
+		else if ((s->ctx != NULL) &&
+			(s->ctx->cipher_list != NULL))
+			{
+			return(s->ctx->cipher_list);
+			}
+		}
+	return(NULL);
+	}
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * algorithm id */
+STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
+	{
+	if (s != NULL)
+		{
+		if (s->cipher_list_by_id != NULL)
+			{
+			return(s->cipher_list_by_id);
+			}
+		else if ((s->ctx != NULL) &&
+			(s->ctx->cipher_list_by_id != NULL))
+			{
+			return(s->ctx->cipher_list_by_id);
+			}
+		}
+	return(NULL);
+	}
+
+/** The old interface to get the same thing as SSL_get_ciphers() */
+const char *SSL_get_cipher_list(const SSL *s,int n)
+	{
+	SSL_CIPHER *c;
+	STACK_OF(SSL_CIPHER) *sk;
+
+	if (s == NULL) return(NULL);
+	sk=SSL_get_ciphers(s);
+	if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
+		return(NULL);
+	c=sk_SSL_CIPHER_value(sk,n);
+	if (c == NULL) return(NULL);
+	return(c->name);
+	}
+
+/** specify the ciphers to be used by default by the SSL_CTX */
+int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+	
+	sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
+		&ctx->cipher_list_by_id,str, ctx->cert);
+	/* ssl_create_cipher_list may return an empty stack if it
+	 * was unable to find a cipher matching the given rule string
+	 * (for example if the rule string specifies a cipher which
+	 * has been disabled). This is not an error as far as
+	 * ssl_create_cipher_list is concerned, and hence
+	 * ctx->cipher_list and ctx->cipher_list_by_id has been
+	 * updated. */
+	if (sk == NULL)
+		return 0;
+	else if (sk_SSL_CIPHER_num(sk) == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_cipher_list, SSL_R_NO_CIPHER_MATCH);
+		return 0;
+		}
+	return 1;
+	}
+
+/** specify the ciphers to be used by the SSL */
+int SSL_set_cipher_list(SSL *s,const char *str)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+	
+	sk=ssl_create_cipher_list(s->ctx->method,&s->cipher_list,
+		&s->cipher_list_by_id,str, s->cert);
+	/* see comment in SSL_CTX_set_cipher_list */
+	if (sk == NULL)
+		return 0;
+	else if (sk_SSL_CIPHER_num(sk) == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_set_cipher_list, SSL_R_NO_CIPHER_MATCH);
+		return 0;
+		}
+	return 1;
+	}
+
+/* works well for SSLv2, not so good for SSLv3 */
+char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
+	{
+	char *p;
+	STACK_OF(SSL_CIPHER) *sk;
+	SSL_CIPHER *c;
+	int i;
+
+	if ((s->session == NULL) || (s->session->ciphers == NULL) ||
+		(len < 2))
+		return(NULL);
+
+	p=buf;
+	sk=s->session->ciphers;
+	for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+		{
+		int n;
+
+		c=sk_SSL_CIPHER_value(sk,i);
+		n=strlen(c->name);
+		if (n+1 > len)
+			{
+			if (p != buf)
+				--p;
+			*p='\0';
+			return buf;
+			}
+		strcpy(p,c->name);
+		p+=n;
+		*(p++)=':';
+		len-=n+1;
+		}
+	p[-1]='\0';
+	return(buf);
+	}
+
+int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
+			     int (*put_cb)(const SSL_CIPHER *, unsigned char *))
+	{
+	int i,j=0;
+	SSL_CIPHER *c;
+	CERT *ct = s->cert;
+	unsigned char *q;
+	int no_scsv = s->renegotiate;
+	/* Set disabled masks for this session */
+	ssl_set_client_disabled(s);
+
+	if (sk == NULL) return(0);
+	q=p;
+
+	for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+		{
+		c=sk_SSL_CIPHER_value(sk,i);
+		/* Skip disabled ciphers */
+		if (c->algorithm_ssl & ct->mask_ssl ||
+			c->algorithm_mkey & ct->mask_k ||
+			c->algorithm_auth & ct->mask_a)
+			continue;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+		if (c->id == SSL3_CK_SCSV)
+			{
+			if (no_scsv)
+				continue;
+			else
+				no_scsv = 1;
+			}
+#endif
+		j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
+		p+=j;
+		}
+	/* If p == q, no ciphers and caller indicates an error. Otherwise
+	 * add SCSV if not renegotiating.
+	 */
+	if (p != q && !no_scsv)
+		{
+		static SSL_CIPHER scsv =
+			{
+			0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+			};
+		j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p);
+		p+=j;
+#ifdef OPENSSL_RI_DEBUG
+		fprintf(stderr, "SCSV sent by client\n");
+#endif
+		}
+
+	return(p-q);
+	}
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
+					       STACK_OF(SSL_CIPHER) **skp)
+	{
+	const SSL_CIPHER *c;
+	STACK_OF(SSL_CIPHER) *sk;
+	int i,n;
+	if (s->s3)
+		s->s3->send_connection_binding = 0;
+
+	n=ssl_put_cipher_by_char(s,NULL,NULL);
+	if ((num%n) != 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+		return(NULL);
+		}
+	if ((skp == NULL) || (*skp == NULL))
+		sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
+	else
+		{
+		sk= *skp;
+		sk_SSL_CIPHER_zero(sk);
+		}
+
+	if (s->cert->ciphers_raw)
+		OPENSSL_free(s->cert->ciphers_raw);
+	s->cert->ciphers_raw = BUF_memdup(p, num);
+	if (s->cert->ciphers_raw == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	s->cert->ciphers_rawlen = (size_t)num;
+
+	for (i=0; i<num; i+=n)
+		{
+		/* Check for SCSV */
+		if (s->s3 && (n != 3 || !p[0]) &&
+			(p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+			(p[n-1] == (SSL3_CK_SCSV & 0xff)))
+			{
+			/* SCSV fatal if renegotiating */
+			if (s->renegotiate)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); 
+				goto err;
+				}
+			s->s3->send_connection_binding = 1;
+			p += n;
+#ifdef OPENSSL_RI_DEBUG
+			fprintf(stderr, "SCSV received by server\n");
+#endif
+			continue;
+			}
+
+		c=ssl_get_cipher_by_char(s,p);
+		p+=n;
+		if (c != NULL)
+			{
+			if (!sk_SSL_CIPHER_push(sk,c))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		}
+
+	if (skp != NULL)
+		*skp=sk;
+	return(sk);
+err:
+	if ((skp == NULL) || (*skp == NULL))
+		sk_SSL_CIPHER_free(sk);
+	return(NULL);
+	}
+
+
+#ifndef OPENSSL_NO_TLSEXT
+/** return a servername extension value if provided in Client Hello, or NULL.
+ * So far, only host_name types are defined (RFC 3546).
+ */
+
+const char *SSL_get_servername(const SSL *s, const int type)
+	{
+	if (type != TLSEXT_NAMETYPE_host_name)
+		return NULL;
+
+	return s->session && !s->tlsext_hostname ?
+		s->session->tlsext_hostname :
+		s->tlsext_hostname;
+	}
+
+int SSL_get_servername_type(const SSL *s)
+	{
+	if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
+		return TLSEXT_NAMETYPE_host_name;
+	return -1;
+	}
+
+/* SSL_select_next_proto implements the standard protocol selection. It is
+ * expected that this function is called from the callback set by
+ * SSL_CTX_set_next_proto_select_cb.
+ *
+ * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
+ * strings. The length byte itself is not included in the length. A byte
+ * string of length 0 is invalid. No byte string may be truncated.
+ *
+ * The current, but experimental algorithm for selecting the protocol is:
+ *
+ * 1) If the server doesn't support NPN then this is indicated to the
+ * callback. In this case, the client application has to abort the connection
+ * or have a default application level protocol.
+ *
+ * 2) If the server supports NPN, but advertises an empty list then the
+ * client selects the first protcol in its list, but indicates via the
+ * API that this fallback case was enacted.
+ *
+ * 3) Otherwise, the client finds the first protocol in the server's list
+ * that it supports and selects this protocol. This is because it's
+ * assumed that the server has better information about which protocol
+ * a client should use.
+ *
+ * 4) If the client doesn't support any of the server's advertised
+ * protocols, then this is treated the same as case 2.
+ *
+ * It returns either
+ * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
+ * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
+ */
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
+	{
+	unsigned int i, j;
+	const unsigned char *result;
+	int status = OPENSSL_NPN_UNSUPPORTED;
+
+	/* For each protocol in server preference order, see if we support it. */
+	for (i = 0; i < server_len; )
+		{
+		for (j = 0; j < client_len; )
+			{
+			if (server[i] == client[j] &&
+			    memcmp(&server[i+1], &client[j+1], server[i]) == 0)
+				{
+				/* We found a match */
+				result = &server[i];
+				status = OPENSSL_NPN_NEGOTIATED;
+				goto found;
+				}
+			j += client[j];
+			j++;
+			}
+		i += server[i];
+		i++;
+		}
+
+	/* There's no overlap between our protocols and the server's list. */
+	result = client;
+	status = OPENSSL_NPN_NO_OVERLAP;
+
+	found:
+	*out = (unsigned char *) result + 1;
+	*outlen = result[0];
+	return status;
+	}
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
+ * requested protocol for this connection and returns 0. If the client didn't
+ * request any protocol, then *data is set to NULL.
+ *
+ * Note that the client can request any protocol it chooses. The value returned
+ * from this function need not be a member of the list of supported protocols
+ * provided by the callback.
+ */
+void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len)
+	{
+	*data = s->next_proto_negotiated;
+	if (!*data) {
+		*len = 0;
+	} else {
+		*len = s->next_proto_negotiated_len;
+	}
+}
+
+/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
+ * TLS server needs a list of supported protocols for Next Protocol
+ * Negotiation. The returned list must be in wire format.  The list is returned
+ * by setting |out| to point to it and |outlen| to its length. This memory will
+ * not be modified, but one should assume that the SSL* keeps a reference to
+ * it.
+ *
+ * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Otherwise, no
+ * such extension will be included in the ServerHello. */
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg)
+	{
+	ctx->next_protos_advertised_cb = cb;
+	ctx->next_protos_advertised_cb_arg = arg;
+	}
+
+/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
+ * client needs to select a protocol from the server's provided list. |out|
+ * must be set to point to the selected protocol (which may be within |in|).
+ * The length of the protocol name must be written into |outlen|. The server's
+ * advertised protocols are provided in |in| and |inlen|. The callback can
+ * assume that |in| is syntactically valid.
+ *
+ * The client must select a protocol. It is fatal to the connection if this
+ * callback returns a value other than SSL_TLSEXT_ERR_OK.
+ */
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
+	{
+	ctx->next_proto_select_cb = cb;
+	ctx->next_proto_select_cb_arg = arg;
+	}
+# endif
+
+int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_cli_ext_first_cb_fn fn1, 
+			       custom_cli_ext_second_cb_fn fn2, void* arg)
+	{
+	size_t i;
+	custom_cli_ext_record* record;
+
+	/* Check for duplicates */
+	for (i=0; i < ctx->custom_cli_ext_records_count; i++)
+		if (ext_type == ctx->custom_cli_ext_records[i].ext_type)
+			return 0;
+
+	ctx->custom_cli_ext_records = OPENSSL_realloc(ctx->custom_cli_ext_records,
+						      (ctx->custom_cli_ext_records_count + 1) * 
+						      sizeof(custom_cli_ext_record));
+	if (!ctx->custom_cli_ext_records) {
+		ctx->custom_cli_ext_records_count = 0;
+		return 0;
+	}
+	ctx->custom_cli_ext_records_count++;
+	record = &ctx->custom_cli_ext_records[ctx->custom_cli_ext_records_count - 1];
+	record->ext_type = ext_type;
+	record->fn1 = fn1;
+	record->fn2 = fn2;
+	record->arg = arg;
+	return 1;
+	}
+
+int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_srv_ext_first_cb_fn fn1, 
+			       custom_srv_ext_second_cb_fn fn2, void* arg)
+	{
+	size_t i;
+	custom_srv_ext_record* record;
+
+	/* Check for duplicates */	
+	for (i=0; i < ctx->custom_srv_ext_records_count; i++)
+		if (ext_type == ctx->custom_srv_ext_records[i].ext_type)
+			return 0;
+
+	ctx->custom_srv_ext_records = OPENSSL_realloc(ctx->custom_srv_ext_records,
+						      (ctx->custom_srv_ext_records_count + 1) * 
+						      sizeof(custom_srv_ext_record));
+	if (!ctx->custom_srv_ext_records) {
+		ctx->custom_srv_ext_records_count = 0;
+		return 0;
+	}
+	ctx->custom_srv_ext_records_count++;
+	record = &ctx->custom_srv_ext_records[ctx->custom_srv_ext_records_count - 1];
+	record->ext_type = ext_type;
+	record->fn1 = fn1;
+	record->fn2 = fn2;
+	record->arg = arg;
+	return 1;
+	}
+
+/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings).
+ *
+ * Returns 0 on success. */
+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos,
+			    unsigned protos_len)
+	{
+	if (ctx->alpn_client_proto_list)
+		OPENSSL_free(ctx->alpn_client_proto_list);
+
+	ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len);
+	if (!ctx->alpn_client_proto_list)
+		return 1;
+	memcpy(ctx->alpn_client_proto_list, protos, protos_len);
+	ctx->alpn_client_proto_list_len = protos_len;
+
+	return 0;
+	}
+
+/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings).
+ *
+ * Returns 0 on success. */
+int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos,
+			unsigned protos_len)
+	{
+	if (ssl->alpn_client_proto_list)
+		OPENSSL_free(ssl->alpn_client_proto_list);
+
+	ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len);
+	if (!ssl->alpn_client_proto_list)
+		return 1;
+	memcpy(ssl->alpn_client_proto_list, protos, protos_len);
+	ssl->alpn_client_proto_list_len = protos_len;
+
+	return 0;
+	}
+
+/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
+ * during ClientHello processing in order to select an ALPN protocol from the
+ * client's list of offered protocols. */
+void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx,
+				int (*cb) (SSL *ssl,
+					   const unsigned char **out,
+					   unsigned char *outlen,
+					   const unsigned char *in,
+					   unsigned int inlen,
+					   void *arg),
+				void *arg)
+	{
+	ctx->alpn_select_cb = cb;
+	ctx->alpn_select_cb_arg = arg;
+	}
+
+/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|.
+ * On return it sets |*data| to point to |*len| bytes of protocol name (not
+ * including the leading length-prefix byte). If the server didn't respond with
+ * a negotiated protocol then |*len| will be zero. */
+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
+			    unsigned *len)
+	{
+	*data = NULL;
+	if (ssl->s3)
+		*data = ssl->s3->alpn_selected;
+	if (*data == NULL)
+		*len = 0;
+	else
+		*len = ssl->s3->alpn_selected_len;
+	}
+#endif /* !OPENSSL_NO_TLSEXT */
+
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+	const char *label, size_t llen, const unsigned char *p, size_t plen,
+	int use_context)
+	{
+	if (s->version < TLS1_VERSION)
+		return -1;
+
+	return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+							   llen, p, plen,
+							   use_context);
+	}
+
+static uint32_t ssl_session_hash(const SSL_SESSION *a)
+	{
+	uint32_t hash = ((uint32_t) a->session_id[0]) ||
+			((uint32_t) a->session_id[1] << 8) ||
+			((uint32_t) a->session_id[2] << 16) ||
+			((uint32_t) a->session_id[3] << 24);
+
+	return hash;
+	}
+
+/* NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
+ * able to construct an SSL_SESSION that will collide with any existing session
+ * with a matching session ID. */
+static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
+	{
+	if (a->ssl_version != b->ssl_version)
+		return(1);
+	if (a->session_id_length != b->session_id_length)
+		return(1);
+	return(memcmp(a->session_id,b->session_id,a->session_id_length));
+	}
+
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+	{
+	SSL_CTX *ret=NULL;
+
+	if (meth == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_NULL_SSL_METHOD_PASSED);
+		return(NULL);
+		}
+
+#ifdef OPENSSL_FIPS
+	if (FIPS_mode() && (meth->version < TLS1_VERSION))	
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+		return NULL;
+		}
+#endif
+
+	if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+		goto err;
+		}
+	ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
+	if (ret == NULL)
+		goto err;
+
+	memset(ret,0,sizeof(SSL_CTX));
+
+	ret->method=meth;
+
+	ret->cert_store=NULL;
+	ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
+	ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
+	ret->session_cache_head=NULL;
+	ret->session_cache_tail=NULL;
+
+	/* We take the system default */
+	ret->session_timeout=meth->get_timeout();
+
+	ret->new_session_cb=0;
+	ret->remove_session_cb=0;
+	ret->get_session_cb=0;
+	ret->generate_session_id=0;
+
+	memset((char *)&ret->stats,0,sizeof(ret->stats));
+
+	ret->references=1;
+	ret->quiet_shutdown=0;
+
+/*	ret->cipher=NULL;*/
+/*	ret->s2->challenge=NULL;
+	ret->master_key=NULL;
+	ret->key_arg=NULL;
+	ret->s2->conn_id=NULL; */
+
+	ret->info_callback=NULL;
+
+	ret->app_verify_callback=0;
+	ret->app_verify_arg=NULL;
+
+	ret->max_cert_list=SSL_MAX_CERT_LIST_DEFAULT;
+	ret->read_ahead=0;
+	ret->msg_callback=0;
+	ret->msg_callback_arg=NULL;
+	ret->verify_mode=SSL_VERIFY_NONE;
+#if 0
+	ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
+#endif
+	ret->sid_ctx_length=0;
+	ret->default_verify_callback=NULL;
+	if ((ret->cert=ssl_cert_new()) == NULL)
+		goto err;
+
+	ret->default_passwd_callback=0;
+	ret->default_passwd_callback_userdata=NULL;
+	ret->client_cert_cb=0;
+	ret->app_gen_cookie_cb=0;
+	ret->app_verify_cookie_cb=0;
+
+	ret->sessions=lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp);
+	if (ret->sessions == NULL) goto err;
+	ret->cert_store=X509_STORE_new();
+	if (ret->cert_store == NULL) goto err;
+
+	ssl_create_cipher_list(ret->method,
+		&ret->cipher_list,&ret->cipher_list_by_id,
+		meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ret->cert);
+	if (ret->cipher_list == NULL
+	    || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_LIBRARY_HAS_NO_CIPHERS);
+		goto err2;
+		}
+
+	ret->param = X509_VERIFY_PARAM_new();
+	if (!ret->param)
+		goto err;
+
+	ret->rsa_md5 = EVP_md5();
+	ret->md5 = EVP_md5();
+	ret->sha1 = EVP_sha1();
+
+	if ((ret->client_CA=sk_X509_NAME_new_null()) == NULL)
+		goto err;
+
+	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data);
+
+	ret->extra_certs=NULL;
+	/* No compression for DTLS */
+	if (meth->version != DTLS1_VERSION)
+		ret->comp_methods=SSL_COMP_get_compression_methods();
+
+	ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_TLSEXT
+	ret->tlsext_servername_callback = 0;
+	ret->tlsext_servername_arg = NULL;
+	/* Setup RFC4507 ticket keys */
+	if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
+		|| (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
+		|| (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
+		ret->options |= SSL_OP_NO_TICKET;
+
+	ret->tlsext_status_cb = 0;
+	ret->tlsext_status_arg = NULL;
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+	ret->next_protos_advertised_cb = 0;
+	ret->next_proto_select_cb = 0;
+# endif
+#endif
+#ifndef OPENSSL_NO_PSK
+	ret->psk_identity_hint=NULL;
+	ret->psk_client_callback=NULL;
+	ret->psk_server_callback=NULL;
+#endif
+	ret->custom_cli_ext_records = NULL;
+	ret->custom_cli_ext_records_count = 0;
+	ret->custom_srv_ext_records = NULL;
+	ret->custom_srv_ext_records_count = 0;
+#ifndef OPENSSL_NO_BUF_FREELISTS
+	ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
+	ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+	if (!ret->rbuf_freelist)
+		goto err;
+	ret->rbuf_freelist->chunklen = 0;
+	ret->rbuf_freelist->len = 0;
+	ret->rbuf_freelist->head = NULL;
+	ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
+	if (!ret->wbuf_freelist)
+		{
+		OPENSSL_free(ret->rbuf_freelist);
+		goto err;
+		}
+	ret->wbuf_freelist->chunklen = 0;
+	ret->wbuf_freelist->len = 0;
+	ret->wbuf_freelist->head = NULL;
+#endif
+#ifndef OPENSSL_NO_ENGINE
+	ret->client_cert_engine = NULL;
+#ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
+#define eng_strx(x)	#x
+#define eng_str(x)	eng_strx(x)
+	/* Use specific client engine automatically... ignore errors */
+	{
+	ENGINE *eng;
+	eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+	if (!eng)
+		{
+		ERR_clear_error();
+		ENGINE_load_builtin_engines();
+		eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO));
+		}
+	if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng))
+		ERR_clear_error();
+	}
+#endif
+#endif
+	/* Default is to connect to non-RI servers. When RI is more widely
+	 * deployed might change this.
+	 */
+	ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+
+	return(ret);
+err:
+	OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, ERR_R_MALLOC_FAILURE);
+err2:
+	if (ret != NULL) SSL_CTX_free(ret);
+	return(NULL);
+	}
+
+#if 0
+static void SSL_COMP_free(SSL_COMP *comp)
+    { OPENSSL_free(comp); }
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+static void
+ssl_buf_freelist_free(SSL3_BUF_FREELIST *list)
+	{
+	SSL3_BUF_FREELIST_ENTRY *ent, *next;
+	for (ent = list->head; ent; ent = next)
+		{
+		next = ent->next;
+		OPENSSL_free(ent);
+		}
+	OPENSSL_free(list);
+	}
+#endif
+
+void SSL_CTX_free(SSL_CTX *a)
+	{
+	int i;
+
+	if (a == NULL) return;
+
+	i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_SSL_CTX);
+#ifdef REF_PRINT
+	REF_PRINT("SSL_CTX",a);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"SSL_CTX_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	if (a->param)
+		X509_VERIFY_PARAM_free(a->param);
+
+	/*
+	 * Free internal session cache. However: the remove_cb() may reference
+	 * the ex_data of SSL_CTX, thus the ex_data store can only be removed
+	 * after the sessions were flushed.
+	 * As the ex_data handling routines might also touch the session cache,
+	 * the most secure solution seems to be: empty (flush) the cache, then
+	 * free ex_data, then finally free the cache.
+	 * (See ticket [openssl.org #212].)
+	 */
+	if (a->sessions != NULL)
+		SSL_CTX_flush_sessions(a,0);
+
+	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
+
+	if (a->sessions != NULL)
+		lh_SSL_SESSION_free(a->sessions);
+
+	if (a->cert_store != NULL)
+		X509_STORE_free(a->cert_store);
+	if (a->cipher_list != NULL)
+		sk_SSL_CIPHER_free(a->cipher_list);
+	if (a->cipher_list_by_id != NULL)
+		sk_SSL_CIPHER_free(a->cipher_list_by_id);
+	if (a->cert != NULL)
+		ssl_cert_free(a->cert);
+	if (a->client_CA != NULL)
+		sk_X509_NAME_pop_free(a->client_CA,X509_NAME_free);
+	if (a->extra_certs != NULL)
+		sk_X509_pop_free(a->extra_certs,X509_free);
+#if 0 /* This should never be done, since it removes a global database */
+	if (a->comp_methods != NULL)
+		sk_SSL_COMP_pop_free(a->comp_methods,SSL_COMP_free);
+#else
+	a->comp_methods = NULL;
+#endif
+
+        if (a->srtp_profiles)
+                sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
+
+#ifndef OPENSSL_NO_PSK
+	if (a->psk_identity_hint)
+		OPENSSL_free(a->psk_identity_hint);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	OPENSSL_free(a->custom_cli_ext_records);
+	OPENSSL_free(a->custom_srv_ext_records);
+#endif
+
+	/* TODO(fork): remove. */
+#if 0
+#ifndef OPENSSL_NO_ENGINE
+	if (a->client_cert_engine)
+		ENGINE_finish(a->client_cert_engine);
+#endif
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+	if (a->wbuf_freelist)
+		ssl_buf_freelist_free(a->wbuf_freelist);
+	if (a->rbuf_freelist)
+		ssl_buf_freelist_free(a->rbuf_freelist);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+# ifndef OPENSSL_NO_EC
+	if (a->tlsext_ecpointformatlist)
+		OPENSSL_free(a->tlsext_ecpointformatlist);
+	if (a->tlsext_ellipticcurvelist)
+		OPENSSL_free(a->tlsext_ellipticcurvelist);
+# endif /* OPENSSL_NO_EC */
+	if (a->alpn_client_proto_list != NULL)
+		OPENSSL_free(a->alpn_client_proto_list);
+#endif
+
+	OPENSSL_free(a);
+	}
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
+	{
+	ctx->default_passwd_callback=cb;
+	}
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx,void *u)
+	{
+	ctx->default_passwd_callback_userdata=u;
+	}
+
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg)
+	{
+	ctx->app_verify_callback=cb;
+	ctx->app_verify_arg=arg;
+	}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*cb)(int, X509_STORE_CTX *))
+	{
+	ctx->verify_mode=mode;
+	ctx->default_verify_callback=cb;
+	}
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth)
+	{
+	X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+	}
+
+void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb)(SSL *ssl, void *arg), void *arg)
+	{
+	ssl_cert_set_cert_cb(c->cert, cb, arg);
+	}
+
+void SSL_set_cert_cb(SSL *s, int (*cb)(SSL *ssl, void *arg), void *arg)
+	{
+	ssl_cert_set_cert_cb(s->cert, cb, arg);
+	}
+
+void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
+	{
+	CERT_PKEY *cpk;
+	int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
+	int rsa_enc_export,dh_rsa_export,dh_dsa_export;
+	int rsa_tmp_export,dh_tmp_export,kl;
+	unsigned long mask_k,mask_a,emask_k,emask_a;
+#ifndef OPENSSL_NO_ECDSA
+	int have_ecc_cert, ecdsa_ok, ecc_pkey_size;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	int have_ecdh_tmp, ecdh_ok;
+#endif
+#ifndef OPENSSL_NO_EC
+	X509 *x = NULL;
+	EVP_PKEY *ecc_pkey = NULL;
+	int signature_nid = 0, pk_nid = 0, md_nid = 0;
+#endif
+	if (c == NULL) return;
+
+	kl=SSL_C_EXPORT_PKEYLENGTH(cipher);
+
+#ifndef OPENSSL_NO_RSA
+	rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
+	rsa_tmp_export=(c->rsa_tmp_cb != NULL ||
+		(rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));
+#else
+	rsa_tmp=rsa_tmp_export=0;
+#endif
+#ifndef OPENSSL_NO_DH
+	dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
+	dh_tmp_export=(c->dh_tmp_cb != NULL ||
+		(dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
+#else
+	dh_tmp=dh_tmp_export=0;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	have_ecdh_tmp=(c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
+#endif
+	cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
+	rsa_enc= cpk->valid_flags & CERT_PKEY_VALID;
+	rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
+	rsa_sign= cpk->valid_flags & CERT_PKEY_SIGN;
+	cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]);
+	dsa_sign= cpk->valid_flags & CERT_PKEY_SIGN;
+	cpk= &(c->pkeys[SSL_PKEY_DH_RSA]);
+	dh_rsa=  cpk->valid_flags & CERT_PKEY_VALID;
+	dh_rsa_export=(dh_rsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_DH_DSA]);
+/* FIX THIS EAY EAY EAY */
+	dh_dsa=  cpk->valid_flags & CERT_PKEY_VALID;
+	dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_ECC]);
+#ifndef OPENSSL_NO_EC
+	have_ecc_cert= cpk->valid_flags & CERT_PKEY_VALID;
+#endif
+	mask_k=0;
+	mask_a=0;
+	emask_k=0;
+	emask_a=0;
+
+	
+
+#ifdef CIPHER_DEBUG
+	printf("rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
+	        rsa_tmp,rsa_tmp_export,dh_tmp,have_ecdh_tmp,
+		rsa_enc,rsa_enc_export,rsa_sign,dsa_sign,dh_rsa,dh_dsa);
+#endif
+	
+	cpk = &(c->pkeys[SSL_PKEY_GOST01]);
+	if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+		mask_k |= SSL_kGOST;
+		mask_a |= SSL_aGOST01;
+	}
+	cpk = &(c->pkeys[SSL_PKEY_GOST94]);
+	if (cpk->x509 != NULL && cpk->privatekey !=NULL) {
+		mask_k |= SSL_kGOST;
+		mask_a |= SSL_aGOST94;
+	}
+
+	if (rsa_enc || (rsa_tmp && rsa_sign))
+		mask_k|=SSL_kRSA;
+	if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
+		emask_k|=SSL_kRSA;
+
+#if 0
+	/* The match needs to be both kEDH and aRSA or aDSA, so don't worry */
+	if (	(dh_tmp || dh_rsa || dh_dsa) &&
+		(rsa_enc || rsa_sign || dsa_sign))
+		mask_k|=SSL_kEDH;
+	if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) &&
+		(rsa_enc || rsa_sign || dsa_sign))
+		emask_k|=SSL_kEDH;
+#endif
+
+	if (dh_tmp_export)
+		emask_k|=SSL_kEDH;
+
+	if (dh_tmp)
+		mask_k|=SSL_kEDH;
+
+	if (dh_rsa) mask_k|=SSL_kDHr;
+	if (dh_rsa_export) emask_k|=SSL_kDHr;
+
+	if (dh_dsa) mask_k|=SSL_kDHd;
+	if (dh_dsa_export) emask_k|=SSL_kDHd;
+
+	if (emask_k & (SSL_kDHr|SSL_kDHd))
+		mask_a |= SSL_aDH;
+
+	if (rsa_enc || rsa_sign)
+		{
+		mask_a|=SSL_aRSA;
+		emask_a|=SSL_aRSA;
+		}
+
+	if (dsa_sign)
+		{
+		mask_a|=SSL_aDSS;
+		emask_a|=SSL_aDSS;
+		}
+
+	mask_a|=SSL_aNULL;
+	emask_a|=SSL_aNULL;
+
+	/* An ECC certificate may be usable for ECDH and/or
+	 * ECDSA cipher suites depending on the key usage extension.
+	 */
+#ifndef OPENSSL_NO_EC
+	if (have_ecc_cert)
+		{
+		cpk = &c->pkeys[SSL_PKEY_ECC];
+		x = cpk->x509;
+		/* This call populates extension flags (ex_flags) */
+		X509_check_purpose(x, -1, 0);
+		ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1;
+		ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
+		if (!(cpk->valid_flags & CERT_PKEY_SIGN))
+			ecdsa_ok = 0;
+		ecc_pkey = X509_get_pubkey(x);
+		ecc_pkey_size = (ecc_pkey != NULL) ?
+		    EVP_PKEY_bits(ecc_pkey) : 0;
+		EVP_PKEY_free(ecc_pkey);
+		if ((x->sig_alg) && (x->sig_alg->algorithm))
+			{
+			signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+			OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+			}
+#ifndef OPENSSL_NO_ECDH
+		if (ecdh_ok)
+			{
+
+			if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa)
+				{
+				mask_k|=SSL_kECDHr;
+				mask_a|=SSL_aECDH;
+				if (ecc_pkey_size <= 163)
+					{
+					emask_k|=SSL_kECDHr;
+					emask_a|=SSL_aECDH;
+					}
+				}
+
+			if (pk_nid == NID_X9_62_id_ecPublicKey)
+				{
+				mask_k|=SSL_kECDHe;
+				mask_a|=SSL_aECDH;
+				if (ecc_pkey_size <= 163)
+					{
+					emask_k|=SSL_kECDHe;
+					emask_a|=SSL_aECDH;
+					}
+				}
+			}
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (ecdsa_ok)
+			{
+			mask_a|=SSL_aECDSA;
+			emask_a|=SSL_aECDSA;
+			}
+#endif
+		}
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	if (have_ecdh_tmp)
+		{
+		mask_k|=SSL_kEECDH;
+		emask_k|=SSL_kEECDH;
+		}
+#endif
+
+#ifndef OPENSSL_NO_PSK
+	mask_k |= SSL_kPSK;
+	mask_a |= SSL_aPSK;
+	emask_k |= SSL_kPSK;
+	emask_a |= SSL_aPSK;
+#endif
+
+	c->mask_k=mask_k;
+	c->mask_a=mask_a;
+	c->export_mask_k=emask_k;
+	c->export_mask_a=emask_a;
+	c->valid=1;
+	}
+
+/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
+#define ku_reject(x, usage) \
+	(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+
+#ifndef OPENSSL_NO_EC
+
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
+	{
+	unsigned long alg_k, alg_a;
+	EVP_PKEY *pkey = NULL;
+	int keysize = 0;
+	int signature_nid = 0, md_nid = 0, pk_nid = 0;
+	const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
+
+	alg_k = cs->algorithm_mkey;
+	alg_a = cs->algorithm_auth;
+
+	if (SSL_C_IS_EXPORT(cs))
+		{
+		/* ECDH key length in export ciphers must be <= 163 bits */
+		pkey = X509_get_pubkey(x);
+		if (pkey == NULL) return 0;
+		keysize = EVP_PKEY_bits(pkey);
+		EVP_PKEY_free(pkey);
+		if (keysize > 163) return 0;
+		}
+
+	/* This call populates the ex_flags field correctly */
+	X509_check_purpose(x, -1, 0);
+	if ((x->sig_alg) && (x->sig_alg->algorithm))
+		{
+		signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+		OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid);
+		}
+	if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr)
+		{
+		/* key usage, if present, must allow key agreement */
+		if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
+			return 0;
+			}
+		if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION)
+			{
+			/* signature alg must be ECDSA */
+			if (pk_nid != NID_X9_62_id_ecPublicKey)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE);
+				return 0;
+				}
+			}
+		if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION)
+			{
+			/* signature alg must be RSA */
+
+			if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE);
+				return 0;
+				}
+			}
+		}
+	if (alg_a & SSL_aECDSA)
+		{
+		/* key usage, if present, must allow signing */
+		if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_check_srvr_ecc_cert_and_alg, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+			return 0;
+			}
+		}
+
+	return 1;  /* all checks are ok */
+	}
+
+#endif
+
+static int ssl_get_server_cert_index(const SSL *s)
+	{
+	int idx;
+	idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+	if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509)
+		idx = SSL_PKEY_RSA_SIGN;
+	if (idx == -1)
+		OPENSSL_PUT_ERROR(SSL, ssl_get_server_cert_index, ERR_R_INTERNAL_ERROR);
+	return idx;
+	}
+
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
+	{
+	CERT *c;
+	int i;
+
+	c = s->cert;
+	ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
+
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+	/* Broken protocol test: return last used certificate: which may
+	 * mismatch the one expected.
+	 */
+	if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+		return c->key;
+#endif
+
+	i = ssl_get_server_cert_index(s);
+
+	/* This may or may not be an error. */
+	if (i < 0)
+		return NULL;
+
+	/* May be NULL. */
+	return &c->pkeys[i];
+	}
+
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
+	{
+	unsigned long alg_a;
+	CERT *c;
+	int idx = -1;
+
+	alg_a = cipher->algorithm_auth;
+	c=s->cert;
+
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+	/* Broken protocol test: use last key: which may
+	 * mismatch the one expected.
+	 */
+	if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+		idx = c->key - c->pkeys;
+	else
+#endif
+
+	if ((alg_a & SSL_aDSS) &&
+		(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
+		idx = SSL_PKEY_DSA_SIGN;
+	else if (alg_a & SSL_aRSA)
+		{
+		if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
+			idx = SSL_PKEY_RSA_SIGN;
+		else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
+			idx = SSL_PKEY_RSA_ENC;
+		}
+	else if ((alg_a & SSL_aECDSA) &&
+	         (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
+		idx = SSL_PKEY_ECC;
+	if (idx == -1)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_get_sign_pkey, ERR_R_INTERNAL_ERROR);
+		return(NULL);
+		}
+	if (pmd)
+		*pmd = c->pkeys[idx].digest;
+	return c->pkeys[idx].privatekey;
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length)
+	{
+	CERT *c;
+	int i;
+
+	c = s->cert;
+	i = ssl_get_server_cert_index(s);
+
+	if (i == -1)
+		return NULL;
+
+	*authz_length = 0;
+	if (c->pkeys[i].authz == NULL)
+		return(NULL);
+	*authz_length = c->pkeys[i].authz_length;
+
+	return c->pkeys[i].authz;
+	}
+
+int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
+				   size_t *serverinfo_length)
+	{
+	CERT *c = NULL;
+	int i = 0;
+	*serverinfo_length = 0;
+
+	c = s->cert;
+	i = ssl_get_server_cert_index(s);
+
+	if (i == -1)
+		return 0;
+	if (c->pkeys[i].serverinfo == NULL)
+		return 0;
+
+	*serverinfo = c->pkeys[i].serverinfo;
+	*serverinfo_length = c->pkeys[i].serverinfo_length;
+	return 1;
+	}
+#endif
+
+void ssl_update_cache(SSL *s,int mode)
+	{
+	int i;
+
+	/* If the session_id_length is 0, we are not supposed to cache it,
+	 * and it would be rather hard to do anyway :-) */
+	if (s->session->session_id_length == 0) return;
+
+	i=s->session_ctx->session_cache_mode;
+	if ((i & mode) && (!s->hit)
+		&& ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
+		    || SSL_CTX_add_session(s->session_ctx,s->session))
+		&& (s->session_ctx->new_session_cb != NULL))
+		{
+		CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
+		if (!s->session_ctx->new_session_cb(s,s->session))
+			SSL_SESSION_free(s->session);
+		}
+
+	/* auto flush every 255 connections */
+	if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) &&
+		((i & mode) == mode))
+		{
+		if (  (((mode & SSL_SESS_CACHE_CLIENT)
+			?s->session_ctx->stats.sess_connect_good
+			:s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
+			{
+			SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
+			}
+		}
+	}
+
+const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx)
+	{
+	return ctx->method;
+	}
+
+const SSL_METHOD *SSL_get_ssl_method(SSL *s)
+	{
+	return(s->method);
+	}
+
+int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
+	{
+	int conn= -1;
+	int ret=1;
+
+	if (s->method != meth)
+		{
+		if (s->handshake_func != NULL)
+			conn=(s->handshake_func == s->method->ssl_connect);
+
+		if (s->method->version == meth->version)
+			s->method=meth;
+		else
+			{
+			s->method->ssl_free(s);
+			s->method=meth;
+			ret=s->method->ssl_new(s);
+			}
+
+		if (conn == 1)
+			s->handshake_func=meth->ssl_connect;
+		else if (conn == 0)
+			s->handshake_func=meth->ssl_accept;
+		}
+	return(ret);
+	}
+
+int SSL_get_error(const SSL *s,int i)
+	{
+	int reason;
+	unsigned long l;
+	BIO *bio;
+
+	if (i > 0) return(SSL_ERROR_NONE);
+
+	/* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake
+	 * etc, where we do encode the error */
+	if ((l=ERR_peek_error()) != 0)
+		{
+		if (ERR_GET_LIB(l) == ERR_LIB_SYS)
+			return(SSL_ERROR_SYSCALL);
+		else
+			return(SSL_ERROR_SSL);
+		}
+
+	if ((i < 0) && SSL_want_read(s))
+		{
+		bio=SSL_get_rbio(s);
+		if (BIO_should_read(bio))
+			return(SSL_ERROR_WANT_READ);
+		else if (BIO_should_write(bio))
+			/* This one doesn't make too much sense ... We never try
+			 * to write to the rbio, and an application program where
+			 * rbio and wbio are separate couldn't even know what it
+			 * should wait for.
+			 * However if we ever set s->rwstate incorrectly
+			 * (so that we have SSL_want_read(s) instead of
+			 * SSL_want_write(s)) and rbio and wbio *are* the same,
+			 * this test works around that bug; so it might be safer
+			 * to keep it. */
+			return(SSL_ERROR_WANT_WRITE);
+		else if (BIO_should_io_special(bio))
+			{
+			reason=BIO_get_retry_reason(bio);
+			if (reason == BIO_RR_CONNECT)
+				return(SSL_ERROR_WANT_CONNECT);
+			else if (reason == BIO_RR_ACCEPT)
+				return(SSL_ERROR_WANT_ACCEPT);
+			else
+				return(SSL_ERROR_SYSCALL); /* unknown */
+			}
+		}
+
+	if ((i < 0) && SSL_want_write(s))
+		{
+		bio=SSL_get_wbio(s);
+		if (BIO_should_write(bio))
+			return(SSL_ERROR_WANT_WRITE);
+		else if (BIO_should_read(bio))
+			/* See above (SSL_want_read(s) with BIO_should_write(bio)) */
+			return(SSL_ERROR_WANT_READ);
+		else if (BIO_should_io_special(bio))
+			{
+			reason=BIO_get_retry_reason(bio);
+			if (reason == BIO_RR_CONNECT)
+				return(SSL_ERROR_WANT_CONNECT);
+			else if (reason == BIO_RR_ACCEPT)
+				return(SSL_ERROR_WANT_ACCEPT);
+			else
+				return(SSL_ERROR_SYSCALL);
+			}
+		}
+	if ((i < 0) && SSL_want_x509_lookup(s))
+		{
+		return(SSL_ERROR_WANT_X509_LOOKUP);
+		}
+
+	if (i == 0)
+		{
+		if (s->version == SSL2_VERSION)
+			{
+			/* assume it is the socket being closed */
+			return(SSL_ERROR_ZERO_RETURN);
+			}
+		else
+			{
+			if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
+				(s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY))
+				return(SSL_ERROR_ZERO_RETURN);
+			}
+		}
+	return(SSL_ERROR_SYSCALL);
+	}
+
+int SSL_do_handshake(SSL *s)
+	{
+	int ret=1;
+
+	if (s->handshake_func == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_do_handshake, SSL_R_CONNECTION_TYPE_NOT_SET);
+		return(-1);
+		}
+
+	s->method->ssl_renegotiate_check(s);
+
+	if (SSL_in_init(s) || SSL_in_before(s))
+		{
+		ret=s->handshake_func(s);
+		}
+	return(ret);
+	}
+
+/* For the next 2 functions, SSL_clear() sets shutdown and so
+ * one of these calls will reset it */
+void SSL_set_accept_state(SSL *s)
+	{
+	s->server=1;
+	s->shutdown=0;
+	s->state=SSL_ST_ACCEPT|SSL_ST_BEFORE;
+	s->handshake_func=s->method->ssl_accept;
+	/* clear the current cipher */
+	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
+	}
+
+void SSL_set_connect_state(SSL *s)
+	{
+	s->server=0;
+	s->shutdown=0;
+	s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
+	s->handshake_func=s->method->ssl_connect;
+	/* clear the current cipher */
+	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
+	}
+
+int ssl_undefined_function(SSL *s)
+	{
+	OPENSSL_PUT_ERROR(SSL, ssl_undefined_function, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+int ssl_undefined_void_function(void)
+	{
+	OPENSSL_PUT_ERROR(SSL, ssl_undefined_void_function, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+int ssl_undefined_const_function(const SSL *s)
+	{
+	OPENSSL_PUT_ERROR(SSL, ssl_undefined_const_function, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+SSL_METHOD *ssl_bad_method(int ver)
+	{
+	OPENSSL_PUT_ERROR(SSL, ssl_bad_method, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(NULL);
+	}
+
+const char *SSL_get_version(const SSL *s)
+	{
+	if (s->version == TLS1_2_VERSION)
+		return("TLSv1.2");
+	else if (s->version == TLS1_1_VERSION)
+		return("TLSv1.1");
+	else if (s->version == TLS1_VERSION)
+		return("TLSv1");
+	else if (s->version == SSL3_VERSION)
+		return("SSLv3");
+	else if (s->version == SSL2_VERSION)
+		return("SSLv2");
+	else
+		return("unknown");
+	}
+
+void ssl_clear_cipher_ctx(SSL *s)
+	{
+	if (s->enc_read_ctx != NULL)
+		{
+		EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
+		OPENSSL_free(s->enc_read_ctx);
+		s->enc_read_ctx=NULL;
+		}
+	if (s->enc_write_ctx != NULL)
+		{
+		EVP_CIPHER_CTX_cleanup(s->enc_write_ctx);
+		OPENSSL_free(s->enc_write_ctx);
+		s->enc_write_ctx=NULL;
+		}
+	}
+
+X509 *SSL_get_certificate(const SSL *s)
+	{
+	if (s->cert != NULL)
+		return(s->cert->key->x509);
+	else
+		return(NULL);
+	}
+
+EVP_PKEY *SSL_get_privatekey(const SSL *s)
+	{
+	if (s->cert != NULL)
+		return(s->cert->key->privatekey);
+	else
+		return(NULL);
+	}
+
+X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx)
+	{
+	if (ctx->cert != NULL)
+		return ctx->cert->key->x509;
+	else
+		return NULL;
+	}
+
+EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx)
+	{
+	if (ctx->cert != NULL)
+		return ctx->cert->key->privatekey;
+	else
+		return NULL ;
+	}
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+	{
+	if ((s->session != NULL) && (s->session->cipher != NULL))
+		return(s->session->cipher);
+	return(NULL);
+	}
+const void *SSL_get_current_compression(SSL *s)
+	{
+	return NULL;
+	}
+const void *SSL_get_current_expansion(SSL *s)
+	{
+	return NULL;
+	}
+
+int ssl_init_wbio_buffer(SSL *s,int push)
+	{
+	BIO *bbio;
+
+	if (s->bbio == NULL)
+		{
+		bbio=BIO_new(BIO_f_buffer());
+		if (bbio == NULL) return(0);
+		s->bbio=bbio;
+		}
+	else
+		{
+		bbio=s->bbio;
+		if (s->bbio == s->wbio)
+			s->wbio=BIO_pop(s->wbio);
+		}
+	(void)BIO_reset(bbio);
+/*	if (!BIO_set_write_buffer_size(bbio,16*1024)) */
+	if (!BIO_set_read_buffer_size(bbio,1))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_init_wbio_buffer, ERR_R_BUF_LIB);
+		return(0);
+		}
+	if (push)
+		{
+		if (s->wbio != bbio)
+			s->wbio=BIO_push(bbio,s->wbio);
+		}
+	else
+		{
+		if (s->wbio == bbio)
+			s->wbio=BIO_pop(bbio);
+		}
+	return(1);
+	}
+
+void ssl_free_wbio_buffer(SSL *s)
+	{
+	if (s->bbio == NULL) return;
+
+	if (s->bbio == s->wbio)
+		{
+		/* remove buffering */
+		s->wbio=BIO_pop(s->wbio);
+#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids adding one more preprocessor symbol */
+		assert(s->wbio != NULL);
+#endif
+	}
+	BIO_free(s->bbio);
+	s->bbio=NULL;
+	}
+	
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode)
+	{
+	ctx->quiet_shutdown=mode;
+	}
+
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
+	{
+	return(ctx->quiet_shutdown);
+	}
+
+void SSL_set_quiet_shutdown(SSL *s,int mode)
+	{
+	s->quiet_shutdown=mode;
+	}
+
+int SSL_get_quiet_shutdown(const SSL *s)
+	{
+	return(s->quiet_shutdown);
+	}
+
+void SSL_set_shutdown(SSL *s,int mode)
+	{
+	s->shutdown=mode;
+	}
+
+int SSL_get_shutdown(const SSL *s)
+	{
+	return(s->shutdown);
+	}
+
+int SSL_version(const SSL *s)
+	{
+	return(s->version);
+	}
+
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
+	{
+	return(ssl->ctx);
+	}
+
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
+	{
+	if (ssl->ctx == ctx)
+		return ssl->ctx;
+#ifndef OPENSSL_NO_TLSEXT
+	if (ctx == NULL)
+		ctx = ssl->initial_ctx;
+#endif
+	if (ssl->cert != NULL)
+		ssl_cert_free(ssl->cert);
+	ssl->cert = ssl_cert_dup(ctx->cert);
+	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+	if (ssl->ctx != NULL)
+		SSL_CTX_free(ssl->ctx); /* decrement reference count */
+	ssl->ctx = ctx;
+	return(ssl->ctx);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+	{
+	return(X509_STORE_set_default_paths(ctx->cert_store));
+	}
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+		const char *CApath)
+	{
+	return(X509_STORE_load_locations(ctx->cert_store,CAfile,CApath));
+	}
+#endif
+
+void SSL_set_info_callback(SSL *ssl,
+	void (*cb)(const SSL *ssl,int type,int val))
+	{
+	ssl->info_callback=cb;
+	}
+
+/* One compiler (Diab DCC) doesn't like argument names in returned
+   function pointer.  */
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL * /*ssl*/,int /*type*/,int /*val*/)
+	{
+	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;
+	}
+
+long SSL_get_verify_result(const SSL *ssl)
+	{
+	return(ssl->verify_result);
+	}
+
+int SSL_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+			 CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+	{
+	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp,
+				new_func, dup_func, free_func);
+	}
+
+int SSL_set_ex_data(SSL *s,int idx,void *arg)
+	{
+	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+	}
+
+void *SSL_get_ex_data(const SSL *s,int idx)
+	{
+	return(CRYPTO_get_ex_data(&s->ex_data,idx));
+	}
+
+int SSL_CTX_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+			     CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+	{
+	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp,
+				new_func, dup_func, free_func);
+	}
+
+int SSL_CTX_set_ex_data(SSL_CTX *s,int idx,void *arg)
+	{
+	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+	}
+
+void *SSL_CTX_get_ex_data(const SSL_CTX *s,int idx)
+	{
+	return(CRYPTO_get_ex_data(&s->ex_data,idx));
+	}
+
+int ssl_ok(SSL *s)
+	{
+	return(1);
+	}
+
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
+	{
+	return(ctx->cert_store);
+	}
+
+void SSL_CTX_set_cert_store(SSL_CTX *ctx,X509_STORE *store)
+	{
+	if (ctx->cert_store != NULL)
+		X509_STORE_free(ctx->cert_store);
+	ctx->cert_store=store;
+	}
+
+int SSL_want(const SSL *s)
+	{
+	return(s->rwstate);
+	}
+
+/*!
+ * \brief Set the callback for generating temporary RSA keys.
+ * \param ctx the SSL context.
+ * \param cb the callback
+ */
+
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,
+							  int is_export,
+							  int keylength))
+    {
+    SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+    }
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,
+						  int is_export,
+						  int keylength))
+    {
+    SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+    }
+#endif
+
+#ifdef DOXYGEN
+/*!
+ * \brief The RSA temporary key callback function.
+ * \param ssl the SSL session.
+ * \param is_export \c TRUE if the temp RSA key is for an export ciphersuite.
+ * \param keylength if \c is_export is \c TRUE, then \c keylength is the size
+ * of the required key in bits.
+ * \return the temporary RSA key.
+ * \sa SSL_CTX_set_tmp_rsa_callback, SSL_set_tmp_rsa_callback
+ */
+
+RSA *cb(SSL *ssl,int is_export,int keylength)
+    {}
+#endif
+
+/*!
+ * \brief Set the callback for generating temporary DH keys.
+ * \param ctx the SSL context.
+ * \param dh the callback
+ */
+
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
+                                                        int keylength))
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+	}
+
+void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
+                                                int keylength))
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+	}
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+                                                                int keylength))
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+	}
+
+void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+                                                        int keylength))
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+	}
+#endif
+
+#ifndef OPENSSL_NO_PSK
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
+	{
+	if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_psk_identity_hint, SSL_R_DATA_LENGTH_TOO_LONG);
+		return 0;
+		}
+	if (ctx->psk_identity_hint != NULL)
+		OPENSSL_free(ctx->psk_identity_hint);
+	if (identity_hint != NULL)
+		{
+		ctx->psk_identity_hint = BUF_strdup(identity_hint);
+		if (ctx->psk_identity_hint == NULL)
+			return 0;
+		}
+	else
+		ctx->psk_identity_hint = NULL;
+	return 1;
+	}
+
+int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
+	{
+	if (s == NULL)
+		return 0;
+
+	if (s->session == NULL)
+		return 1; /* session not created yet, ignored */
+
+	if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_psk_identity_hint, SSL_R_DATA_LENGTH_TOO_LONG);
+		return 0;
+		}
+	if (s->session->psk_identity_hint != NULL)
+		OPENSSL_free(s->session->psk_identity_hint);
+	if (identity_hint != NULL)
+		{
+		s->session->psk_identity_hint = BUF_strdup(identity_hint);
+		if (s->session->psk_identity_hint == NULL)
+			return 0;
+		}
+	else
+		s->session->psk_identity_hint = NULL;
+	return 1;
+	}
+
+const char *SSL_get_psk_identity_hint(const SSL *s)
+	{
+	if (s == NULL || s->session == NULL)
+		return NULL;
+	return(s->session->psk_identity_hint);
+	}
+
+const char *SSL_get_psk_identity(const SSL *s)
+	{
+	if (s == NULL || s->session == NULL)
+		return NULL;
+	return(s->session->psk_identity);
+	}
+
+void SSL_set_psk_client_callback(SSL *s,
+    unsigned int (*cb)(SSL *ssl, const char *hint,
+                       char *identity, unsigned int max_identity_len, unsigned char *psk,
+                       unsigned int max_psk_len))
+	{
+	s->psk_client_callback = cb;
+	}
+
+void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
+    unsigned int (*cb)(SSL *ssl, const char *hint,
+                       char *identity, unsigned int max_identity_len, unsigned char *psk,
+                       unsigned int max_psk_len))
+	{
+	ctx->psk_client_callback = cb;
+	}
+
+void SSL_set_psk_server_callback(SSL *s,
+    unsigned int (*cb)(SSL *ssl, const char *identity,
+                       unsigned char *psk, unsigned int max_psk_len))
+	{
+	s->psk_server_callback = cb;
+	}
+
+void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
+    unsigned int (*cb)(SSL *ssl, const char *identity,
+                       unsigned char *psk, unsigned int max_psk_len))
+	{
+	ctx->psk_server_callback = cb;
+	}
+#endif
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+	}
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+	}
+
+/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
+ * vairable, freeing  EVP_MD_CTX previously stored in that variable, if
+ * any. If EVP_MD pointer is passed, initializes ctx with this md
+ * Returns newly allocated ctx;
+ */
+
+EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) 
+{
+	ssl_clear_hash_ctx(hash);
+	*hash = EVP_MD_CTX_create();
+	if (md) EVP_DigestInit_ex(*hash,md,NULL);
+	return *hash;
+}
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash) 
+{
+
+	if (*hash) EVP_MD_CTX_destroy(*hash);
+	*hash=NULL;
+}
+
+void SSL_set_debug(SSL *s, int debug)
+	{
+	s->debug = debug;
+	}
+
+int SSL_cache_hit(SSL *s)
+	{
+	return s->hit;
+	}
+
+int SSL_is_server(SSL *s)
+	{
+	return s->server;
+	}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
new file mode 100644
index 0000000..f0b6d42
--- /dev/null
+++ b/ssl/ssl_locl.h
@@ -0,0 +1,1348 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * 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.
+ */
+
+#ifndef HEADER_SSL_LOCL_H
+#define HEADER_SSL_LOCL_H
+
+#include <openssl/base.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+
+#undef PKCS1_CHECK
+
+#define c2l(c,l)	(l = ((unsigned long)(*((c)++)))     , \
+			 l|=(((unsigned long)(*((c)++)))<< 8), \
+			 l|=(((unsigned long)(*((c)++)))<<16), \
+			 l|=(((unsigned long)(*((c)++)))<<24))
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n)	{ \
+			c+=n; \
+			l1=l2=0; \
+			switch (n) { \
+			case 8: l2 =((unsigned long)(*(--(c))))<<24; \
+			case 7: l2|=((unsigned long)(*(--(c))))<<16; \
+			case 6: l2|=((unsigned long)(*(--(c))))<< 8; \
+			case 5: l2|=((unsigned long)(*(--(c))));     \
+			case 4: l1 =((unsigned long)(*(--(c))))<<24; \
+			case 3: l1|=((unsigned long)(*(--(c))))<<16; \
+			case 2: l1|=((unsigned long)(*(--(c))))<< 8; \
+			case 1: l1|=((unsigned long)(*(--(c))));     \
+				} \
+			}
+
+#define l2c(l,c)	(*((c)++)=(unsigned char)(((l)    )&0xff), \
+			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+#define n2l(c,l)	(l =((unsigned long)(*((c)++)))<<24, \
+			 l|=((unsigned long)(*((c)++)))<<16, \
+			 l|=((unsigned long)(*((c)++)))<< 8, \
+			 l|=((unsigned long)(*((c)++))))
+
+#define l2n(l,c)	(*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+			 *((c)++)=(unsigned char)(((l)    )&0xff))
+
+#define l2n6(l,c)	(*((c)++)=(unsigned char)(((l)>>40)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+			 *((c)++)=(unsigned char)(((l)    )&0xff))
+
+#define l2n8(l,c)	(*((c)++)=(unsigned char)(((l)>>56)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>48)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>40)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+			 *((c)++)=(unsigned char)(((l)    )&0xff))
+
+#define n2l6(c,l)	(l =((BN_ULLONG)(*((c)++)))<<40, \
+			 l|=((BN_ULLONG)(*((c)++)))<<32, \
+			 l|=((BN_ULLONG)(*((c)++)))<<24, \
+			 l|=((BN_ULLONG)(*((c)++)))<<16, \
+			 l|=((BN_ULLONG)(*((c)++)))<< 8, \
+			 l|=((BN_ULLONG)(*((c)++))))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n)	{ \
+			c+=n; \
+			switch (n) { \
+			case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+			case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+			case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+			case 5: *(--(c))=(unsigned char)(((l2)    )&0xff); \
+			case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+			case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+			case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+			case 1: *(--(c))=(unsigned char)(((l1)    )&0xff); \
+				} \
+			}
+
+#define n2s(c,s)	((s=(((unsigned int)(c[0]))<< 8)| \
+			    (((unsigned int)(c[1]))    )),c+=2)
+#define s2n(s,c)	((c[0]=(unsigned char)(((s)>> 8)&0xff), \
+			  c[1]=(unsigned char)(((s)    )&0xff)),c+=2)
+
+#define n2l3(c,l)	((l =(((unsigned long)(c[0]))<<16)| \
+			     (((unsigned long)(c[1]))<< 8)| \
+			     (((unsigned long)(c[2]))    )),c+=3)
+
+#define l2n3(l,c)	((c[0]=(unsigned char)(((l)>>16)&0xff), \
+			  c[1]=(unsigned char)(((l)>> 8)&0xff), \
+			  c[2]=(unsigned char)(((l)    )&0xff)),c+=3)
+
+/* LOCAL STUFF */
+
+#define SSL_DECRYPT	0
+#define SSL_ENCRYPT	1
+
+#define TWO_BYTE_BIT	0x80
+#define SEC_ESC_BIT	0x40
+#define TWO_BYTE_MASK	0x7fff
+#define THREE_BYTE_MASK	0x3fff
+
+#define INC32(a)	((a)=((a)+1)&0xffffffffL)
+#define DEC32(a)	((a)=((a)-1)&0xffffffffL)
+#define MAX_MAC_SIZE	20 /* up from 16 for SSLv3 */
+
+/*
+ * Define the Bitmasks for SSL_CIPHER.algorithms.
+ * This bits are used packed as dense as possible. If new methods/ciphers
+ * etc will be added, the bits a likely to change, so this information
+ * is for internal library use only, even though SSL_CIPHER.algorithms
+ * can be publicly accessed.
+ * Use the according functions for cipher management instead.
+ *
+ * The bit mask handling in the selection and sorting scheme in
+ * ssl_create_cipher_list() has only limited capabilities, reflecting
+ * that the different entities within are mutually exclusive:
+ * ONLY ONE BIT PER MASK CAN BE SET AT A TIME.
+ */
+
+/* Bits for algorithm_mkey (key exchange algorithm) */
+#define SSL_kRSA		0x00000001L /* RSA key exchange */
+#define SSL_kDHr		0x00000002L /* DH cert, RSA CA cert */
+#define SSL_kDHd		0x00000004L /* DH cert, DSA CA cert */
+#define SSL_kEDH		0x00000008L /* tmp DH key no DH cert */
+#define SSL_kKRB5		0x00000010L /* Kerberos5 key exchange */
+#define SSL_kECDHr		0x00000020L /* ECDH cert, RSA CA cert */
+#define SSL_kECDHe		0x00000040L /* ECDH cert, ECDSA CA cert */
+#define SSL_kEECDH		0x00000080L /* ephemeral ECDH */
+#define SSL_kPSK		0x00000100L /* PSK */
+#define SSL_kGOST       0x00000200L /* GOST key exchange */
+#define SSL_kSRP        0x00000400L /* SRP */
+
+/* Bits for algorithm_auth (server authentication) */
+#define SSL_aRSA		0x00000001L /* RSA auth */
+#define SSL_aDSS 		0x00000002L /* DSS auth */
+#define SSL_aNULL 		0x00000004L /* no auth (i.e. use ADH or AECDH) */
+#define SSL_aDH 		0x00000008L /* Fixed DH auth (kDHd or kDHr) */
+#define SSL_aECDH 		0x00000010L /* Fixed ECDH auth (kECDHe or kECDHr) */
+#define SSL_aKRB5               0x00000020L /* KRB5 auth */
+#define SSL_aECDSA              0x00000040L /* ECDSA auth*/
+#define SSL_aPSK                0x00000080L /* PSK auth */
+#define SSL_aGOST94				0x00000100L /* GOST R 34.10-94 signature auth */
+#define SSL_aGOST01 			0x00000200L /* GOST R 34.10-2001 signature auth */
+
+
+/* Bits for algorithm_enc (symmetric encryption) */
+#define SSL_DES			0x00000001L
+#define SSL_3DES		0x00000002L
+#define SSL_RC4			0x00000004L
+#define SSL_RC2			0x00000008L
+#define SSL_IDEA		0x00000010L
+#define SSL_eNULL		0x00000020L
+#define SSL_AES128		0x00000040L
+#define SSL_AES256		0x00000080L
+#define SSL_CAMELLIA128		0x00000100L
+#define SSL_CAMELLIA256		0x00000200L
+#define SSL_eGOST2814789CNT	0x00000400L
+#define SSL_SEED		0x00000800L
+#define SSL_AES128GCM		0x00001000L
+#define SSL_AES256GCM		0x00002000L
+
+#define SSL_AES        		(SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM)
+#define SSL_CAMELLIA		(SSL_CAMELLIA128|SSL_CAMELLIA256)
+
+
+/* Bits for algorithm_mac (symmetric authentication) */
+
+#define SSL_MD5			0x00000001L
+#define SSL_SHA1		0x00000002L
+#define SSL_GOST94      0x00000004L
+#define SSL_GOST89MAC   0x00000008L
+#define SSL_SHA256		0x00000010L
+#define SSL_SHA384		0x00000020L
+/* Not a real MAC, just an indication it is part of cipher */
+#define SSL_AEAD		0x00000040L
+
+/* Bits for algorithm_ssl (protocol version) */
+#define SSL_SSLV2		0x00000001L
+#define SSL_SSLV3		0x00000002L
+#define SSL_TLSV1		SSL_SSLV3	/* for now */
+#define SSL_TLSV1_2		0x00000004L
+
+
+/* Bits for algorithm2 (handshake digests and other extra flags) */
+
+#define SSL_HANDSHAKE_MAC_MD5 0x10
+#define SSL_HANDSHAKE_MAC_SHA 0x20
+#define SSL_HANDSHAKE_MAC_GOST94 0x40
+#define SSL_HANDSHAKE_MAC_SHA256 0x80
+#define SSL_HANDSHAKE_MAC_SHA384 0x100
+#define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)
+
+/* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX
+ * make sure to update this constant too */
+#define SSL_MAX_DIGEST 6
+
+#define TLS1_PRF_DGST_MASK	(0xff << TLS1_PRF_DGST_SHIFT)
+
+#define TLS1_PRF_DGST_SHIFT 10
+#define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
+#define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT)
+#define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT)
+#define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT)
+#define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
+#define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
+
+/* Stream MAC for GOST ciphersuites from cryptopro draft
+ * (currently this also goes into algorithm2) */
+#define TLS1_STREAM_MAC 0x04
+
+
+
+/*
+ * Export and cipher strength information. For each cipher we have to decide
+ * whether it is exportable or not. This information is likely to change
+ * over time, since the export control rules are no static technical issue.
+ *
+ * Independent of the export flag the cipher strength is sorted into classes.
+ * SSL_EXP40 was denoting the 40bit US export limit of past times, which now
+ * is at 56bit (SSL_EXP56). If the exportable cipher class is going to change
+ * again (eg. to 64bit) the use of "SSL_EXP*" becomes blurred even more,
+ * since SSL_EXP64 could be similar to SSL_LOW.
+ * For this reason SSL_MICRO and SSL_MINI macros are included to widen the
+ * namespace of SSL_LOW-SSL_HIGH to lower values. As development of speed
+ * and ciphers goes, another extension to SSL_SUPER and/or SSL_ULTRA would
+ * be possible.
+ */
+#define SSL_EXP_MASK		0x00000003L
+#define SSL_STRONG_MASK		0x000001fcL
+
+#define SSL_NOT_EXP		0x00000001L
+#define SSL_EXPORT		0x00000002L
+
+#define SSL_STRONG_NONE		0x00000004L
+#define SSL_EXP40		0x00000008L
+#define SSL_MICRO		(SSL_EXP40)
+#define SSL_EXP56		0x00000010L
+#define SSL_MINI		(SSL_EXP56)
+#define SSL_LOW			0x00000020L
+#define SSL_MEDIUM		0x00000040L
+#define SSL_HIGH		0x00000080L
+#define SSL_FIPS		0x00000100L
+
+/* we have used 000001ff - 23 bits left to go */
+
+/*
+ * Macros to check the export status and cipher strength for export ciphers.
+ * Even though the macros for EXPORT and EXPORT40/56 have similar names,
+ * their meaning is different:
+ * *_EXPORT macros check the 'exportable' status.
+ * *_EXPORT40/56 macros are used to check whether a certain cipher strength
+ *          is given.
+ * Since the SSL_IS_EXPORT* and SSL_EXPORT* macros depend on the correct
+ * algorithm structure element to be passed (algorithms, algo_strength) and no
+ * typechecking can be done as they are all of type unsigned long, their
+ * direct usage is discouraged.
+ * Use the SSL_C_* macros instead.
+ */
+#define SSL_IS_EXPORT(a)	((a)&SSL_EXPORT)
+#define SSL_IS_EXPORT56(a)	((a)&SSL_EXP56)
+#define SSL_IS_EXPORT40(a)	((a)&SSL_EXP40)
+#define SSL_C_IS_EXPORT(c)	SSL_IS_EXPORT((c)->algo_strength)
+#define SSL_C_IS_EXPORT56(c)	SSL_IS_EXPORT56((c)->algo_strength)
+#define SSL_C_IS_EXPORT40(c)	SSL_IS_EXPORT40((c)->algo_strength)
+
+#define SSL_EXPORT_KEYLENGTH(a,s)	(SSL_IS_EXPORT40(s) ? 5 : \
+				 (a) == SSL_DES ? 8 : 7)
+#define SSL_EXPORT_PKEYLENGTH(a) (SSL_IS_EXPORT40(a) ? 512 : 1024)
+#define SSL_C_EXPORT_KEYLENGTH(c)	SSL_EXPORT_KEYLENGTH((c)->algorithm_enc, \
+				(c)->algo_strength)
+#define SSL_C_EXPORT_PKEYLENGTH(c)	SSL_EXPORT_PKEYLENGTH((c)->algo_strength)
+
+/* Check if an SSL structure is using DTLS */
+#define SSL_IS_DTLS(s)	(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
+/* See if we need explicit IV */
+#define SSL_USE_EXPLICIT_IV(s)	\
+		(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
+/* See if we use signature algorithms extension
+ * and signature algorithm before signatures.
+ */
+#define SSL_USE_SIGALGS(s)	\
+			(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SIGALGS)
+/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2:
+ * may apply to others in future.
+ */
+#define SSL_USE_TLS1_2_CIPHERS(s)	\
+		(s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)
+/* Determine if a client can use TLS 1.2 ciphersuites: can't rely on method
+ * flags because it may not be set to correct version yet.
+ */
+#define SSL_CLIENT_USE_TLS1_2_CIPHERS(s)	\
+		((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \
+		(!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION))
+
+/* Mostly for SSLv3 */
+#define SSL_PKEY_RSA_ENC	0
+#define SSL_PKEY_RSA_SIGN	1
+#define SSL_PKEY_DSA_SIGN	2
+#define SSL_PKEY_DH_RSA		3
+#define SSL_PKEY_DH_DSA		4
+#define SSL_PKEY_ECC            5
+#define SSL_PKEY_GOST94		6
+#define SSL_PKEY_GOST01		7
+#define SSL_PKEY_NUM		8
+
+/* SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) |
+ * 	    <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN)
+ * SSL_kDH  <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN)
+ * SSL_kEDH <- RSA_ENC | RSA_SIGN | DSA_SIGN
+ * SSL_aRSA <- RSA_ENC | RSA_SIGN
+ * SSL_aDSS <- DSA_SIGN
+ */
+
+/*
+#define CERT_INVALID		0
+#define CERT_PUBLIC_KEY		1
+#define CERT_PRIVATE_KEY	2
+*/
+
+#ifndef OPENSSL_NO_EC
+/* From ECC-TLS draft, used in encoding the curve type in 
+ * ECParameters
+ */
+#define EXPLICIT_PRIME_CURVE_TYPE  1   
+#define EXPLICIT_CHAR2_CURVE_TYPE  2
+#define NAMED_CURVE_TYPE           3
+#endif  /* OPENSSL_NO_EC */
+
+typedef struct cert_pkey_st
+	{
+	X509 *x509;
+	EVP_PKEY *privatekey;
+	/* Digest to use when signing */
+	const EVP_MD *digest;
+	/* Chain for this certificate */
+	STACK_OF(X509) *chain;
+#ifndef OPENSSL_NO_TLSEXT
+	/* authz/authz_length contain authz data for this certificate. The data
+	 * is in wire format, specifically it's a series of records like:
+	 *   uint8_t authz_type;  // (RFC 5878, AuthzDataFormat)
+	 *   uint16_t length;
+	 *   uint8_t data[length]; */
+	unsigned char *authz;
+	size_t authz_length;
+
+	/* serverinfo data for this certificate.  The data is in TLS Extension
+	 * wire format, specifically it's a series of records like:
+	 *   uint16_t extension_type; // (RFC 5246, 7.4.1.4, Extension)
+	 *   uint16_t length;
+	 *   uint8_t data[length]; */
+	unsigned char *serverinfo;
+	size_t serverinfo_length;
+#endif
+	/* Set if CERT_PKEY can be used with current SSL session: e.g.
+	 * appropriate curve, signature algorithms etc. If zero it can't be
+	 * used at all.
+	 */
+	int valid_flags;
+	} CERT_PKEY;
+/* Retrieve Suite B flags */
+#define tls1_suiteb(s)	(s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS)
+/* Uses to check strict mode: suite B modes are always strict */
+#define SSL_CERT_FLAGS_CHECK_TLS_STRICT \
+	(SSL_CERT_FLAG_SUITEB_128_LOS|SSL_CERT_FLAG_TLS_STRICT)
+
+typedef struct cert_st
+	{
+	/* Current active set */
+	CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array
+			 * Probably it would make more sense to store
+			 * an index, not a pointer. */
+ 
+	/* For servers the following masks are for the key and auth
+	 * algorithms that are supported by the certs below.
+	 * For clients they are masks of *disabled* algorithms based
+	 * on the current session.
+	 */
+	int valid;
+	unsigned long mask_k;
+	unsigned long mask_a;
+	unsigned long export_mask_k;
+	unsigned long export_mask_a;
+	/* Client only */
+	unsigned long mask_ssl;
+#ifndef OPENSSL_NO_RSA
+	RSA *rsa_tmp;
+	RSA *(*rsa_tmp_cb)(SSL *ssl,int is_export,int keysize);
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *dh_tmp;
+	DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize);
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh_tmp;
+	/* Callback for generating ephemeral ECDH keys */
+	EC_KEY *(*ecdh_tmp_cb)(SSL *ssl,int is_export,int keysize);
+	/* Select ECDH parameters automatically */
+	int ecdh_tmp_auto;
+#endif
+	/* Flags related to certificates */
+	unsigned int cert_flags;
+	CERT_PKEY pkeys[SSL_PKEY_NUM];
+
+	/* Certificate types (received or sent) in certificate request
+	 * message. On receive this is only set if number of certificate
+	 * types exceeds SSL3_CT_NUMBER.
+	 */
+	unsigned char *ctypes;
+	size_t ctype_num;
+
+	/* signature algorithms peer reports: e.g. supported signature
+	 * algorithms extension for server or as part of a certificate
+	 * request for client.
+	 */
+	unsigned char *peer_sigalgs;
+	/* Size of above array */
+	size_t peer_sigalgslen;
+	/* suppported signature algorithms.
+	 * When set on a client this is sent in the client hello as the 
+	 * supported signature algorithms extension. For servers
+	 * it represents the signature algorithms we are willing to use.
+	 */
+	unsigned char *conf_sigalgs;
+	/* Size of above array */
+	size_t conf_sigalgslen;
+	/* Client authentication signature algorithms, if not set then
+	 * uses conf_sigalgs. On servers these will be the signature
+	 * algorithms sent to the client in a cerificate request for TLS 1.2.
+	 * On a client this represents the signature algortithms we are
+	 * willing to use for client authentication.
+	 */
+	unsigned char *client_sigalgs;
+	/* Size of above array */
+	size_t client_sigalgslen;
+	/* Signature algorithms shared by client and server: cached
+	 * because these are used most often.
+	 */
+	TLS_SIGALGS *shared_sigalgs;
+	size_t shared_sigalgslen;
+
+	/* Certificate setup callback: if set is called whenever a
+	 * certificate may be required (client or server). the callback
+	 * can then examine any appropriate parameters and setup any
+	 * certificates required. This allows advanced applications
+	 * to select certificates on the fly: for example based on
+	 * supported signature algorithms or curves.
+	 */
+	int (*cert_cb)(SSL *ssl, void *arg);
+	void *cert_cb_arg;
+
+	/* Optional X509_STORE for chain building or certificate validation
+	 * If NULL the parent SSL_CTX store is used instead.
+	 */
+	X509_STORE *chain_store;
+	X509_STORE *verify_store;
+
+	/* Raw values of the cipher list from a client */
+	unsigned char *ciphers_raw;
+	size_t ciphers_rawlen;
+
+	int references; /* >1 only if SSL_copy_session_id is used */
+	} CERT;
+
+
+typedef struct sess_cert_st
+	{
+	STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */
+
+	/* The 'peer_...' members are used only by clients. */
+	int peer_cert_type;
+
+	CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never NULL!) */
+	CERT_PKEY peer_pkeys[SSL_PKEY_NUM];
+	/* Obviously we don't have the private keys of these,
+	 * so maybe we shouldn't even use the CERT_PKEY type here. */
+
+#ifndef OPENSSL_NO_RSA
+	RSA *peer_rsa_tmp; /* not used for SSL 2 */
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *peer_dh_tmp; /* not used for SSL 2 */
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *peer_ecdh_tmp;
+#endif
+
+	int references; /* actually always 1 at the moment */
+	} SESS_CERT;
+/* Structure containing decoded values of signature algorithms extension */
+struct tls_sigalgs_st
+	{
+	/* NID of hash algorithm */
+	int hash_nid;
+	/* NID of signature algorithm */
+	int sign_nid;
+	/* Combined hash and signature NID */
+	int signandhash_nid;
+	/* Raw values used in extension */
+	unsigned char rsign;
+	unsigned char rhash;
+	};
+
+/*#define MAC_DEBUG	*/
+
+/*#define ERR_DEBUG	*/
+/*#define ABORT_DEBUG	*/
+/*#define PKT_DEBUG 1   */
+/*#define DES_DEBUG	*/
+/*#define DES_OFB_DEBUG	*/
+/*#define SSL_DEBUG	*/
+/*#define RSA_DEBUG	*/ 
+/*#define IDEA_DEBUG	*/ 
+
+#define FP_ICC  (int (*)(const void *,const void *))
+#define ssl_put_cipher_by_char(ssl,ciph,ptr) \
+		((ssl)->method->put_cipher_by_char((ciph),(ptr)))
+
+/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff
+ * It is a bit of a mess of functions, but hell, think of it as
+ * an opaque structure :-) */
+typedef struct ssl3_enc_method
+	{
+	int (*enc)(SSL *, int);
+	int (*mac)(SSL *, unsigned char *, int);
+	int (*setup_key_block)(SSL *);
+	int (*generate_master_secret)(SSL *, unsigned char *, unsigned char *, int);
+	int (*change_cipher_state)(SSL *, int);
+	int (*final_finish_mac)(SSL *,  const char *, int, unsigned char *);
+	int finish_mac_length;
+	int (*cert_verify_mac)(SSL *, int, unsigned char *);
+	const char *client_finished_label;
+	int client_finished_label_len;
+	const char *server_finished_label;
+	int server_finished_label_len;
+	int (*alert_value)(int);
+	int (*export_keying_material)(SSL *, unsigned char *, size_t,
+				      const char *, size_t,
+				      const unsigned char *, size_t,
+				      int use_context);
+	/* Various flags indicating protocol version requirements */
+	unsigned int enc_flags;
+	/* Handshake header length */
+	unsigned int hhlen;
+	/* Set the handshake header */
+	void (*set_handshake_header)(SSL *s, int type, unsigned long len);
+	/* Write out handshake message */
+	int (*do_write)(SSL *s);
+	} SSL3_ENC_METHOD;
+
+#define SSL_HM_HEADER_LENGTH(s)	s->method->ssl3_enc->hhlen
+#define ssl_handshake_start(s) \
+	(((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen)
+#define ssl_set_handshake_header(s, htype, len) \
+	s->method->ssl3_enc->set_handshake_header(s, htype, len)
+#define ssl_do_write(s)  s->method->ssl3_enc->do_write(s)
+
+/* Values for enc_flags */
+
+/* Uses explicit IV for CBC mode */
+#define SSL_ENC_FLAG_EXPLICIT_IV	0x1
+/* Uses signature algorithms extension */
+#define SSL_ENC_FLAG_SIGALGS		0x2
+/* Uses SHA256 default PRF */
+#define SSL_ENC_FLAG_SHA256_PRF		0x4
+/* Is DTLS */
+#define SSL_ENC_FLAG_DTLS		0x8
+/* Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2:
+ * may apply to others in future.
+ */
+#define SSL_ENC_FLAG_TLS1_2_CIPHERS	0x10
+
+#ifndef OPENSSL_NO_COMP
+/* Used for holding the relevant compression methods loaded into SSL_CTX */
+typedef struct ssl3_comp_st
+	{
+	int comp_id;	/* The identifier byte for this compression type */
+	char *name;	/* Text name used for the compression type */
+	COMP_METHOD *method; /* The method :-) */
+	} SSL3_COMP;
+#endif
+
+#ifndef OPENSSL_NO_BUF_FREELISTS
+typedef struct ssl3_buf_freelist_st
+	{
+	size_t chunklen;
+	unsigned int len;
+	struct ssl3_buf_freelist_entry_st *head;
+	} SSL3_BUF_FREELIST;
+
+typedef struct ssl3_buf_freelist_entry_st
+	{
+	struct ssl3_buf_freelist_entry_st *next;
+	} SSL3_BUF_FREELIST_ENTRY;
+#endif
+
+extern SSL3_ENC_METHOD ssl3_undef_enc_method;
+extern const SSL_CIPHER ssl2_ciphers[];
+extern SSL_CIPHER ssl3_ciphers[];
+
+
+SSL_METHOD *ssl_bad_method(int ver);
+
+extern SSL3_ENC_METHOD TLSv1_enc_data;
+extern SSL3_ENC_METHOD TLSv1_1_enc_data;
+extern SSL3_ENC_METHOD TLSv1_2_enc_data;
+extern SSL3_ENC_METHOD SSLv3_enc_data;
+extern SSL3_ENC_METHOD DTLSv1_enc_data;
+extern SSL3_ENC_METHOD DTLSv1_2_enc_data;
+
+#define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \
+				s_get_meth, enc_data) \
+const SSL_METHOD *func_name(void)  \
+	{ \
+	static const SSL_METHOD func_name##_data= { \
+		version, \
+		tls1_new, \
+		tls1_clear, \
+		tls1_free, \
+		s_accept, \
+		s_connect, \
+		ssl3_read, \
+		ssl3_peek, \
+		ssl3_write, \
+		ssl3_shutdown, \
+		ssl3_renegotiate, \
+		ssl3_renegotiate_check, \
+		ssl3_get_message, \
+		ssl3_read_bytes, \
+		ssl3_write_bytes, \
+		ssl3_dispatch_alert, \
+		ssl3_ctrl, \
+		ssl3_ctx_ctrl, \
+		ssl3_get_cipher_by_char, \
+		ssl3_put_cipher_by_char, \
+		ssl3_pending, \
+		ssl3_num_ciphers, \
+		ssl3_get_cipher, \
+		s_get_meth, \
+		tls1_default_timeout, \
+		&enc_data, \
+		ssl_undefined_void_function, \
+		ssl3_callback_ctrl, \
+		ssl3_ctx_callback_ctrl, \
+	}; \
+	return &func_name##_data; \
+	}
+
+#define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect, s_get_meth) \
+const SSL_METHOD *func_name(void)  \
+	{ \
+	static const SSL_METHOD func_name##_data= { \
+		SSL3_VERSION, \
+		ssl3_new, \
+		ssl3_clear, \
+		ssl3_free, \
+		s_accept, \
+		s_connect, \
+		ssl3_read, \
+		ssl3_peek, \
+		ssl3_write, \
+		ssl3_shutdown, \
+		ssl3_renegotiate, \
+		ssl3_renegotiate_check, \
+		ssl3_get_message, \
+		ssl3_read_bytes, \
+		ssl3_write_bytes, \
+		ssl3_dispatch_alert, \
+		ssl3_ctrl, \
+		ssl3_ctx_ctrl, \
+		ssl3_get_cipher_by_char, \
+		ssl3_put_cipher_by_char, \
+		ssl3_pending, \
+		ssl3_num_ciphers, \
+		ssl3_get_cipher, \
+		s_get_meth, \
+		ssl3_default_timeout, \
+		&SSLv3_enc_data, \
+		ssl_undefined_void_function, \
+		ssl3_callback_ctrl, \
+		ssl3_ctx_callback_ctrl, \
+	}; \
+	return &func_name##_data; \
+	}
+
+#define IMPLEMENT_ssl23_meth_func(func_name, s_accept, s_connect, s_get_meth) \
+const SSL_METHOD *func_name(void)  \
+	{ \
+	static const SSL_METHOD func_name##_data= { \
+	TLS1_2_VERSION, \
+	tls1_new, \
+	tls1_clear, \
+	tls1_free, \
+	s_accept, \
+	s_connect, \
+	ssl23_read, \
+	ssl23_peek, \
+	ssl23_write, \
+	ssl_undefined_function, \
+	ssl_undefined_function, \
+	ssl_ok, \
+	ssl3_get_message, \
+	ssl3_read_bytes, \
+	ssl3_write_bytes, \
+	ssl3_dispatch_alert, \
+	ssl3_ctrl, \
+	ssl3_ctx_ctrl, \
+	ssl23_get_cipher_by_char, \
+	ssl23_put_cipher_by_char, \
+	ssl_undefined_const_function, \
+	ssl23_num_ciphers, \
+	ssl23_get_cipher, \
+	s_get_meth, \
+	ssl23_default_timeout, \
+	&TLSv1_2_enc_data, \
+	ssl_undefined_void_function, \
+	ssl3_callback_ctrl, \
+	ssl3_ctx_callback_ctrl, \
+	}; \
+	return &func_name##_data; \
+	}
+
+#define IMPLEMENT_ssl2_meth_func(func_name, s_accept, s_connect, s_get_meth) \
+const SSL_METHOD *func_name(void)  \
+	{ \
+	static const SSL_METHOD func_name##_data= { \
+		SSL2_VERSION, \
+		ssl2_new,	/* local */ \
+		ssl2_clear,	/* local */ \
+		ssl2_free,	/* local */ \
+		s_accept, \
+		s_connect, \
+		ssl2_read, \
+		ssl2_peek, \
+		ssl2_write, \
+		ssl2_shutdown, \
+		ssl_ok,	/* NULL - renegotiate */ \
+		ssl_ok,	/* NULL - check renegotiate */ \
+		NULL, /* NULL - ssl_get_message */ \
+		NULL, /* NULL - ssl_get_record */ \
+		NULL, /* NULL - ssl_write_bytes */ \
+		NULL, /* NULL - dispatch_alert */ \
+		ssl2_ctrl,	/* local */ \
+		ssl2_ctx_ctrl,	/* local */ \
+		ssl2_get_cipher_by_char, \
+		ssl2_put_cipher_by_char, \
+		ssl2_pending, \
+		ssl2_num_ciphers, \
+		ssl2_get_cipher, \
+		s_get_meth, \
+		ssl2_default_timeout, \
+		&ssl3_undef_enc_method, \
+		ssl_undefined_void_function, \
+		ssl2_callback_ctrl,	/* local */ \
+		ssl2_ctx_callback_ctrl,	/* local */ \
+	}; \
+	return &func_name##_data; \
+	}
+
+#define IMPLEMENT_dtls1_meth_func(version, func_name, s_accept, s_connect, \
+					s_get_meth, enc_data) \
+const SSL_METHOD *func_name(void)  \
+	{ \
+	static const SSL_METHOD func_name##_data= { \
+		version, \
+		dtls1_new, \
+		dtls1_clear, \
+		dtls1_free, \
+		s_accept, \
+		s_connect, \
+		ssl3_read, \
+		ssl3_peek, \
+		ssl3_write, \
+		dtls1_shutdown, \
+		ssl3_renegotiate, \
+		ssl3_renegotiate_check, \
+		dtls1_get_message, \
+		dtls1_read_bytes, \
+		dtls1_write_app_data_bytes, \
+		dtls1_dispatch_alert, \
+		dtls1_ctrl, \
+		ssl3_ctx_ctrl, \
+		ssl3_get_cipher_by_char, \
+		ssl3_put_cipher_by_char, \
+		ssl3_pending, \
+		ssl3_num_ciphers, \
+		dtls1_get_cipher, \
+		s_get_meth, \
+		dtls1_default_timeout, \
+		&enc_data, \
+		ssl_undefined_void_function, \
+		ssl3_callback_ctrl, \
+		ssl3_ctx_callback_ctrl, \
+	}; \
+	return &func_name##_data; \
+	}
+
+void ssl_clear_cipher_ctx(SSL *s);
+int ssl_clear_bad_session(SSL *s);
+CERT *ssl_cert_new(void);
+CERT *ssl_cert_dup(CERT *cert);
+void ssl_cert_set_default_md(CERT *cert);
+int ssl_cert_inst(CERT **o);
+void ssl_cert_clear_certs(CERT *c);
+void ssl_cert_free(CERT *c);
+SESS_CERT *ssl_sess_cert_new(void);
+void ssl_sess_cert_free(SESS_CERT *sc);
+int ssl_set_peer_cert_type(SESS_CERT *c, int type);
+int ssl_get_new_session(SSL *s, int session);
+int ssl_get_prev_session(SSL *s, unsigned char *session,int len, const unsigned char *limit);
+int ssl_cipher_id_cmp(const void *in_a, const void *in_b);
+int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp);
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
+					       STACK_OF(SSL_CIPHER) **skp);
+int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
+                             int (*put_cb)(const SSL_CIPHER *, unsigned char *));
+STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth,
+					     STACK_OF(SSL_CIPHER) **pref,
+					     STACK_OF(SSL_CIPHER) **sorted,
+					     const char *rule_str, CERT *c);
+void ssl_update_cache(SSL *s, int mode);
+int ssl_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
+		       const EVP_MD **md,int *mac_pkey_type,int *mac_secret_size, SSL_COMP **comp);
+int ssl_get_handshake_digest(int i,long *mask,const EVP_MD **md);
+int ssl_cipher_get_cert_index(const SSL_CIPHER *c);
+const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr);
+int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain);
+int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain);
+int ssl_cert_add0_chain_cert(CERT *c, X509 *x);
+int ssl_cert_add1_chain_cert(CERT *c, X509 *x);
+int ssl_cert_select_current(CERT *c, X509 *x);
+void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg);
+
+int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk);
+int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l);
+int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags);
+int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref);
+int ssl_undefined_function(SSL *s);
+int ssl_undefined_void_function(void);
+int ssl_undefined_const_function(const SSL *s);
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length);
+int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
+				   size_t *serverinfo_length);
+#endif
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
+int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
+void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher);
+STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
+int ssl_verify_alarm_type(long type);
+void ssl_load_ciphers(void);
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len);
+
+int ssl2_enc_init(SSL *s, int client);
+int ssl2_generate_key_material(SSL *s);
+void ssl2_enc(SSL *s,int send_data);
+void ssl2_mac(SSL *s,unsigned char *mac,int send_data);
+const SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p);
+int ssl2_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
+int ssl2_part_read(SSL *s, unsigned long f, int i);
+int ssl2_do_write(SSL *s);
+int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data);
+void ssl2_return_error(SSL *s,int reason);
+void ssl2_write_error(SSL *s);
+int ssl2_num_ciphers(void);
+const SSL_CIPHER *ssl2_get_cipher(unsigned int u);
+int	ssl2_new(SSL *s);
+void	ssl2_free(SSL *s);
+int	ssl2_accept(SSL *s);
+int	ssl2_connect(SSL *s);
+int	ssl2_read(SSL *s, void *buf, int len);
+int	ssl2_peek(SSL *s, void *buf, int len);
+int	ssl2_write(SSL *s, const void *buf, int len);
+int	ssl2_shutdown(SSL *s);
+void	ssl2_clear(SSL *s);
+long	ssl2_ctrl(SSL *s,int cmd, long larg, void *parg);
+long	ssl2_ctx_ctrl(SSL_CTX *s,int cmd, long larg, void *parg);
+long	ssl2_callback_ctrl(SSL *s,int cmd, void (*fp)(void));
+long	ssl2_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)(void));
+int	ssl2_pending(const SSL *s);
+long	ssl2_default_timeout(void );
+
+const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
+int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
+void ssl3_init_finished_mac(SSL *s);
+int ssl3_send_server_certificate(SSL *s);
+int ssl3_send_newsession_ticket(SSL *s);
+int ssl3_send_cert_status(SSL *s);
+int ssl3_get_finished(SSL *s,int state_a,int state_b);
+int ssl3_setup_key_block(SSL *s);
+int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
+int ssl3_change_cipher_state(SSL *s,int which);
+void ssl3_cleanup_key_block(SSL *s);
+int ssl3_do_write(SSL *s,int type);
+int ssl3_send_alert(SSL *s,int level, int desc);
+int ssl3_generate_master_secret(SSL *s, unsigned char *out,
+	unsigned char *p, int len);
+int ssl3_get_req_cert_type(SSL *s,unsigned char *p);
+long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+int ssl3_send_finished(SSL *s, int a, int b, const char *sender,int slen);
+int ssl3_num_ciphers(void);
+const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
+int ssl3_renegotiate(SSL *ssl); 
+int ssl3_renegotiate_check(SSL *ssl); 
+int ssl3_dispatch_alert(SSL *s);
+int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
+int ssl3_write_bytes(SSL *s, int type, const void *buf, int len);
+int ssl3_final_finish_mac(SSL *s, const char *sender, int slen,unsigned char *p);
+int ssl3_cert_verify_mac(SSL *s, int md_nid, unsigned char *p);
+void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len);
+int ssl3_enc(SSL *s, int send_data);
+int n_ssl3_mac(SSL *ssl, unsigned char *md, int send_data);
+void ssl3_free_digest_list(SSL *s);
+unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk);
+SSL_CIPHER *ssl3_choose_cipher(SSL *ssl,STACK_OF(SSL_CIPHER) *clnt,
+			       STACK_OF(SSL_CIPHER) *srvr);
+int	ssl3_setup_buffers(SSL *s);
+int	ssl3_setup_read_buffer(SSL *s);
+int	ssl3_setup_write_buffer(SSL *s);
+int	ssl3_release_read_buffer(SSL *s);
+int	ssl3_release_write_buffer(SSL *s);
+int	ssl3_digest_cached_records(SSL *s);
+int	ssl3_new(SSL *s);
+void	ssl3_free(SSL *s);
+int	ssl3_accept(SSL *s);
+int	ssl3_connect(SSL *s);
+int	ssl3_read(SSL *s, void *buf, int len);
+int	ssl3_peek(SSL *s, void *buf, int len);
+int	ssl3_write(SSL *s, const void *buf, int len);
+int	ssl3_shutdown(SSL *s);
+void	ssl3_clear(SSL *s);
+long	ssl3_ctrl(SSL *s,int cmd, long larg, void *parg);
+long	ssl3_ctx_ctrl(SSL_CTX *s,int cmd, long larg, void *parg);
+long	ssl3_callback_ctrl(SSL *s,int cmd, void (*fp)(void));
+long	ssl3_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)(void));
+int	ssl3_pending(const SSL *s);
+
+void ssl3_record_sequence_update(unsigned char *seq);
+int ssl3_do_change_cipher_spec(SSL *ssl);
+long ssl3_default_timeout(void );
+
+void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
+int ssl3_handshake_write(SSL *s);
+
+int ssl23_num_ciphers(void );
+const SSL_CIPHER *ssl23_get_cipher(unsigned int u);
+int ssl23_read(SSL *s, void *buf, int len);
+int ssl23_peek(SSL *s, void *buf, int len);
+int ssl23_write(SSL *s, const void *buf, int len);
+int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p);
+const SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p);
+long ssl23_default_timeout(void );
+
+long tls1_default_timeout(void);
+int dtls1_do_write(SSL *s,int type);
+int ssl3_read_n(SSL *s, int n, int max, int extend);
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
+int ssl3_do_compress(SSL *ssl);
+int ssl3_do_uncompress(SSL *ssl);
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+	unsigned int len);
+unsigned char *dtls1_set_message_header(SSL *s, 
+	unsigned char *p, unsigned char mt,	unsigned long len, 
+	unsigned long frag_off, unsigned long frag_len);
+
+int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len);
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
+
+int dtls1_send_change_cipher_spec(SSL *s, int a, int b);
+int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen);
+unsigned long dtls1_output_cert_chain(SSL *s, CERT_PKEY *cpk);
+int dtls1_read_failed(SSL *s, int code);
+int dtls1_buffer_message(SSL *s, int ccs);
+int dtls1_retransmit_message(SSL *s, unsigned short seq, 
+	unsigned long frag_off, int *found);
+int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
+int dtls1_retransmit_buffered_messages(SSL *s);
+void dtls1_clear_record_buffer(SSL *s);
+void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr);
+void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
+void dtls1_reset_seq_numbers(SSL *s, int rw);
+long dtls1_default_timeout(void);
+struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft);
+int dtls1_check_timeout_num(SSL *s);
+int dtls1_handle_timeout(SSL *s);
+const SSL_CIPHER *dtls1_get_cipher(unsigned int u);
+void dtls1_start_timer(SSL *s);
+void dtls1_stop_timer(SSL *s);
+int dtls1_is_timer_expired(SSL *s);
+void dtls1_double_timeout(SSL *s);
+int dtls1_send_newsession_ticket(SSL *s);
+unsigned int dtls1_min_mtu(void);
+
+/* some client-only functions */
+int ssl3_client_hello(SSL *s);
+int ssl3_get_server_hello(SSL *s);
+int ssl3_get_certificate_request(SSL *s);
+int ssl3_get_new_session_ticket(SSL *s);
+int ssl3_get_cert_status(SSL *s);
+int ssl3_get_server_done(SSL *s);
+int ssl3_send_client_verify(SSL *s);
+int ssl3_send_client_certificate(SSL *s);
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
+int ssl3_send_client_key_exchange(SSL *s);
+int ssl3_get_key_exchange(SSL *s);
+int ssl3_get_server_certificate(SSL *s);
+int ssl3_check_cert_and_algorithm(SSL *s);
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_check_finished(SSL *s);
+# ifndef OPENSSL_NO_NEXTPROTONEG
+int ssl3_send_next_proto(SSL *s);
+# endif
+#endif
+
+int dtls1_client_hello(SSL *s);
+
+/* some server-only functions */
+int ssl3_get_client_hello(SSL *s);
+int ssl3_send_server_hello(SSL *s);
+int ssl3_send_hello_request(SSL *s);
+int ssl3_send_server_key_exchange(SSL *s);
+int ssl3_send_certificate_request(SSL *s);
+int ssl3_send_server_done(SSL *s);
+int ssl3_check_client_hello(SSL *s);
+int ssl3_get_client_certificate(SSL *s);
+int ssl3_get_client_key_exchange(SSL *s);
+int ssl3_get_cert_verify(SSL *s);
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int ssl3_get_next_proto(SSL *s);
+#endif
+
+int ssl23_accept(SSL *s);
+int ssl23_connect(SSL *s);
+int ssl23_read_bytes(SSL *s, int n);
+int ssl23_write_bytes(SSL *s);
+
+int tls1_new(SSL *s);
+void tls1_free(SSL *s);
+void tls1_clear(SSL *s);
+long tls1_ctrl(SSL *s,int cmd, long larg, void *parg);
+long tls1_callback_ctrl(SSL *s,int cmd, void (*fp)(void));
+
+int dtls1_new(SSL *s);
+int	dtls1_accept(SSL *s);
+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);
+int dtls1_shutdown(SSL *s);
+
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+int dtls1_get_record(SSL *s);
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+	unsigned int len, int create_empty_fragement);
+int dtls1_dispatch_alert(SSL *s);
+int dtls1_enc(SSL *s, int snd);
+
+int ssl_init_wbio_buffer(SSL *s, int push);
+void ssl_free_wbio_buffer(SSL *s);
+
+int tls1_change_cipher_state(SSL *s, int which);
+int tls1_setup_key_block(SSL *s);
+int tls1_enc(SSL *s, int snd);
+int tls1_final_finish_mac(SSL *s,
+	const char *str, int slen, unsigned char *p);
+int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *p);
+int tls1_mac(SSL *ssl, unsigned char *md, int snd);
+int tls1_generate_master_secret(SSL *s, unsigned char *out,
+	unsigned char *p, int len);
+int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+	const char *label, size_t llen,
+	const unsigned char *p, size_t plen, int use_context);
+int tls1_alert_code(int code);
+int ssl3_alert_code(int code);
+int ssl_ok(SSL *s);
+
+#ifndef OPENSSL_NO_ECDH
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
+#endif
+
+SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
+
+#ifndef OPENSSL_NO_EC
+int tls1_ec_curve_id2nid(int curve_id);
+int tls1_ec_nid2curve_id(int nid);
+int tls1_check_curve(SSL *s, const unsigned char *p, size_t len);
+int tls1_shared_curve(SSL *s, int nmatch);
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+			int *curves, size_t ncurves);
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
+				const char *str);
+int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
+#endif /* OPENSSL_NO_EC */
+
+#ifndef OPENSSL_NO_TLSEXT
+int tls1_shared_list(SSL *s,
+			const unsigned char *l1, size_t l1len,
+			const unsigned char *l2, size_t l2len,
+			int nmatch);
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n);
+int ssl_check_clienthello_tlsext_late(SSL *s);
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n);
+int ssl_prepare_clienthello_tlsext(SSL *s);
+int ssl_prepare_serverhello_tlsext(SSL *s);
+
+/* server only */
+int tls1_send_server_supplemental_data(SSL *s);
+/* client only */
+int tls1_get_server_supplemental_data(SSL *s);
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int tls1_heartbeat(SSL *s);
+int dtls1_heartbeat(SSL *s);
+int tls1_process_heartbeat(SSL *s);
+int dtls1_process_heartbeat(SSL *s);
+#endif
+
+#ifdef OPENSSL_NO_SHA256
+#define tlsext_tick_md	EVP_sha1
+#else
+#define tlsext_tick_md	EVP_sha256
+#endif
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+				const unsigned char *limit, SSL_SESSION **ret);
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
+				const EVP_MD *md);
+int tls12_get_sigid(const EVP_PKEY *pk);
+const EVP_MD *tls12_get_hash(unsigned char hash_alg);
+
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client);
+int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client);
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+								int idx);
+void tls1_set_cert_validity(SSL *s);
+
+#endif
+EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
+int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+					int maxlen);
+int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+					  int *al);
+int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+					int maxlen);
+int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+					  int *al);
+long ssl_get_algorithm2(SSL *s);
+int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize);
+size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs);
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+				const unsigned char *sig, EVP_PKEY *pkey);
+void ssl_set_client_disabled(SSL *s);
+
+int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen);
+int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al);
+int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen);
+int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al);
+
+/* s3_cbc.c */
+void ssl3_cbc_copy_mac(unsigned char* out,
+		       const SSL3_RECORD *rec,
+		       unsigned md_size,unsigned orig_len);
+int ssl3_cbc_remove_padding(const SSL* s,
+			    SSL3_RECORD *rec,
+			    unsigned block_size,
+			    unsigned mac_size);
+int tls1_cbc_remove_padding(const SSL* s,
+			    SSL3_RECORD *rec,
+			    unsigned block_size,
+			    unsigned mac_size);
+char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
+void ssl3_cbc_digest_record(
+	const EVP_MD_CTX *ctx,
+	unsigned char* md_out,
+	size_t* md_out_size,
+	const unsigned char header[13],
+	const unsigned char *data,
+	size_t data_plus_mac_size,
+	size_t data_plus_mac_plus_padding_size,
+	const unsigned char *mac_secret,
+	unsigned mac_secret_length,
+	char is_sslv3);
+
+void tls_fips_digest_extra(
+	const EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *mac_ctx,
+	const unsigned char *data, size_t data_len, size_t orig_len);
+
+#endif
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
new file mode 100644
index 0000000..04bbabe
--- /dev/null
+++ b/ssl/ssl_rsa.c
@@ -0,0 +1,1293 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/bio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+static int ssl_set_cert(CERT *c, X509 *x509);
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl_set_authz(CERT *c, unsigned char *authz,
+			 size_t authz_length);
+#endif
+int SSL_use_certificate(SSL *ssl, X509 *x)
+	{
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ssl->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	return(ssl_set_cert(ssl->cert,x));
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
+	{
+	int reason_code;
+	BIO *in;
+	int ret=0;
+	X509 *x=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if (type == SSL_FILETYPE_ASN1)
+		{
+		reason_code =ERR_R_ASN1_LIB;
+		x=d2i_X509_bio(in,NULL);
+		}
+	else if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		x=PEM_read_bio_X509(in,NULL,ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_file,reason_code);
+		goto end;
+		}
+
+	ret=SSL_use_certificate(ssl,x);
+end:
+	if (x != NULL) X509_free(x);
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len)
+	{
+	X509 *x;
+	int ret;
+
+	x=d2i_X509(NULL,&d,(long)len);
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_certificate_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_use_certificate(ssl,x);
+	X509_free(x);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_RSA
+int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa)
+	{
+	EVP_PKEY *pkey;
+	int ret;
+
+	if (rsa == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ssl->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	if ((pkey=EVP_PKEY_new()) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey, ERR_R_EVP_LIB);
+		return(0);
+		}
+
+	RSA_up_ref(rsa);
+	EVP_PKEY_assign_RSA(pkey,rsa);
+
+	ret=ssl_set_pkey(ssl->cert,pkey);
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+#endif
+
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
+	{
+	int i;
+	/* Special case for DH: check two DH certificate types for a match.
+	 * This means for DH certificates we must set the certificate first.
+	 */
+	if (pkey->type == EVP_PKEY_DH)
+		{
+		X509 *x;
+		i = -1;
+		x = c->pkeys[SSL_PKEY_DH_RSA].x509;
+		if (x && X509_check_private_key(x, pkey))
+				i = SSL_PKEY_DH_RSA;
+		x = c->pkeys[SSL_PKEY_DH_DSA].x509;
+		if (i == -1 && x && X509_check_private_key(x, pkey))
+				i = SSL_PKEY_DH_DSA;
+		ERR_clear_error();
+		}
+	else 
+		i=ssl_cert_type(NULL,pkey);
+	if (i < 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_set_pkey, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+		return(0);
+		}
+
+	if (c->pkeys[i].x509 != NULL)
+		{
+		EVP_PKEY *pktmp;
+		pktmp =	X509_get_pubkey(c->pkeys[i].x509);
+		EVP_PKEY_copy_parameters(pktmp,pkey);
+		EVP_PKEY_free(pktmp);
+		ERR_clear_error();
+
+                /* TODO(fork): remove this? */
+#if 0
+#ifndef OPENSSL_NO_RSA
+		/* Don't check the public/private key, this is mostly
+		 * for smart cards. */
+		if ((pkey->type == EVP_PKEY_RSA) &&
+			(RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK))
+			;
+		else
+#endif
+#endif
+		if (!X509_check_private_key(c->pkeys[i].x509,pkey))
+			{
+			X509_free(c->pkeys[i].x509);
+			c->pkeys[i].x509 = NULL;
+			return 0;
+			}
+		}
+
+	if (c->pkeys[i].privatekey != NULL)
+		EVP_PKEY_free(c->pkeys[i].privatekey);
+	CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
+	c->pkeys[i].privatekey=pkey;
+	c->key= &(c->pkeys[i]);
+
+	c->valid=0;
+	return(1);
+	}
+
+#ifndef OPENSSL_NO_RSA
+#ifndef OPENSSL_NO_STDIO
+int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type)
+	{
+	int reason_code,ret=0;
+	BIO *in;
+	RSA *rsa=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if	(type == SSL_FILETYPE_ASN1)
+		{
+		reason_code=ERR_R_ASN1_LIB;
+		rsa=d2i_RSAPrivateKey_bio(in,NULL);
+		}
+	else if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		rsa=PEM_read_bio_RSAPrivateKey(in,NULL,
+			ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+	if (rsa == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_file,reason_code);
+		goto end;
+		}
+	ret=SSL_use_RSAPrivateKey(ssl,rsa);
+	RSA_free(rsa);
+end:
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len)
+	{
+	int ret;
+	const unsigned char *p;
+	RSA *rsa;
+
+	p=d;
+	if ((rsa=d2i_RSAPrivateKey(NULL,&p,(long)len)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_use_RSAPrivateKey(ssl,rsa);
+	RSA_free(rsa);
+	return(ret);
+	}
+#endif /* !OPENSSL_NO_RSA */
+
+int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
+	{
+	int ret;
+
+	if (pkey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ssl->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	ret=ssl_set_pkey(ssl->cert,pkey);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type)
+	{
+	int reason_code,ret=0;
+	BIO *in;
+	EVP_PKEY *pkey=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		pkey=PEM_read_bio_PrivateKey(in,NULL,
+			ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata);
+		}
+	else if (type == SSL_FILETYPE_ASN1)
+		{
+		reason_code = ERR_R_ASN1_LIB;
+		pkey = d2i_PrivateKey_bio(in,NULL);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+	if (pkey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_file,reason_code);
+		goto end;
+		}
+	ret=SSL_use_PrivateKey(ssl,pkey);
+	EVP_PKEY_free(pkey);
+end:
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len)
+	{
+	int ret;
+	const unsigned char *p;
+	EVP_PKEY *pkey;
+
+	p=d;
+	if ((pkey=d2i_PrivateKey(type,NULL,&p,(long)len)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_PrivateKey_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_use_PrivateKey(ssl,pkey);
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
+	{
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	return(ssl_set_cert(ctx->cert, x));
+	}
+
+static int ssl_set_cert(CERT *c, X509 *x)
+	{
+	EVP_PKEY *pkey;
+	int i;
+
+	pkey=X509_get_pubkey(x);
+	if (pkey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_X509_LIB);
+		return(0);
+		}
+
+	i=ssl_cert_type(x,pkey);
+	if (i < 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+		EVP_PKEY_free(pkey);
+		return(0);
+		}
+
+	if (c->pkeys[i].privatekey != NULL)
+		{
+		EVP_PKEY_copy_parameters(pkey,c->pkeys[i].privatekey);
+		ERR_clear_error();
+
+                /* TODO(fork): remove this? */
+#if 0
+#ifndef OPENSSL_NO_RSA
+		/* Don't check the public/private key, this is mostly
+		 * for smart cards. */
+		if ((c->pkeys[i].privatekey->type == EVP_PKEY_RSA) &&
+			(RSA_flags(c->pkeys[i].privatekey->pkey.rsa) &
+			 RSA_METHOD_FLAG_NO_CHECK))
+			 ;
+		else
+#endif /* OPENSSL_NO_RSA */
+#endif
+		if (!X509_check_private_key(x,c->pkeys[i].privatekey))
+			{
+			/* don't fail for a cert/key mismatch, just free
+			 * current private key (when switching to a different
+			 * cert & key, first this function should be used,
+			 * then ssl_set_pkey */
+			EVP_PKEY_free(c->pkeys[i].privatekey);
+			c->pkeys[i].privatekey=NULL;
+			/* clear error queue */
+			ERR_clear_error();
+			}
+		}
+
+	EVP_PKEY_free(pkey);
+
+	if (c->pkeys[i].x509 != NULL)
+		X509_free(c->pkeys[i].x509);
+	CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
+	c->pkeys[i].x509=x;
+	c->key= &(c->pkeys[i]);
+
+	c->valid=0;
+	return(1);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
+	{
+	int reason_code;
+	BIO *in;
+	int ret=0;
+	X509 *x=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if (type == SSL_FILETYPE_ASN1)
+		{
+		reason_code=ERR_R_ASN1_LIB;
+		x=d2i_X509_bio(in,NULL);
+		}
+	else if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_file,reason_code);
+		goto end;
+		}
+
+	ret=SSL_CTX_use_certificate(ctx,x);
+end:
+	if (x != NULL) X509_free(x);
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d)
+	{
+	X509 *x;
+	int ret;
+
+	x=d2i_X509(NULL,&d,(long)len);
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_CTX_use_certificate(ctx,x);
+	X509_free(x);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_RSA
+int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa)
+	{
+	int ret;
+	EVP_PKEY *pkey;
+
+	if (rsa == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	if ((pkey=EVP_PKEY_new()) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey, ERR_R_EVP_LIB);
+		return(0);
+		}
+
+	RSA_up_ref(rsa);
+	EVP_PKEY_assign_RSA(pkey,rsa);
+
+	ret=ssl_set_pkey(ctx->cert, pkey);
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type)
+	{
+	int reason_code,ret=0;
+	BIO *in;
+	RSA *rsa=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if	(type == SSL_FILETYPE_ASN1)
+		{
+		reason_code=ERR_R_ASN1_LIB;
+		rsa=d2i_RSAPrivateKey_bio(in,NULL);
+		}
+	else if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		rsa=PEM_read_bio_RSAPrivateKey(in,NULL,
+			ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+	if (rsa == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_file,reason_code);
+		goto end;
+		}
+	ret=SSL_CTX_use_RSAPrivateKey(ctx,rsa);
+	RSA_free(rsa);
+end:
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len)
+	{
+	int ret;
+	const unsigned char *p;
+	RSA *rsa;
+
+	p=d;
+	if ((rsa=d2i_RSAPrivateKey(NULL,&p,(long)len)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_RSAPrivateKey_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_CTX_use_RSAPrivateKey(ctx,rsa);
+	RSA_free(rsa);
+	return(ret);
+	}
+#endif /* !OPENSSL_NO_RSA */
+
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
+	{
+	if (pkey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	return(ssl_set_pkey(ctx->cert,pkey));
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
+	{
+	int reason_code,ret=0;
+	BIO *in;
+	EVP_PKEY *pkey=NULL;
+
+	in=BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+	if (type == SSL_FILETYPE_PEM)
+		{
+		reason_code=ERR_R_PEM_LIB;
+		pkey=PEM_read_bio_PrivateKey(in,NULL,
+			ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
+		}
+	else if (type == SSL_FILETYPE_ASN1)
+		{
+		reason_code = ERR_R_ASN1_LIB;
+		pkey = d2i_PrivateKey_bio(in,NULL);
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file, SSL_R_BAD_SSL_FILETYPE);
+		goto end;
+		}
+	if (pkey == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_file,reason_code);
+		goto end;
+		}
+	ret=SSL_CTX_use_PrivateKey(ctx,pkey);
+	EVP_PKEY_free(pkey);
+end:
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const unsigned char *d,
+	     long len)
+	{
+	int ret;
+	const unsigned char *p;
+	EVP_PKEY *pkey;
+
+	p=d;
+	if ((pkey=d2i_PrivateKey(type,NULL,&p,(long)len)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_PrivateKey_ASN1, ERR_R_ASN1_LIB);
+		return(0);
+		}
+
+	ret=SSL_CTX_use_PrivateKey(ctx,pkey);
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+
+
+#ifndef OPENSSL_NO_STDIO
+/* Read a file that contains our certificate in "PEM" format,
+ * possibly followed by a sequence of CA certificates that should be
+ * sent to the peer in the Certificate message.
+ */
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
+	{
+	BIO *in;
+	int ret=0;
+	X509 *x=NULL;
+
+	ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */
+
+	in = BIO_new(BIO_s_file());
+	if (in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+
+	x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,
+				ctx->default_passwd_callback_userdata);
+	if (x == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_certificate_chain_file, ERR_R_PEM_LIB);
+		goto end;
+		}
+
+	ret = SSL_CTX_use_certificate(ctx, x);
+
+	if (ERR_peek_error() != 0)
+		ret = 0;  /* Key/certificate mismatch doesn't imply ret==0 ... */
+	if (ret)
+		{
+		/* If we could set up our certificate, now proceed to
+		 * the CA certificates.
+		 */
+		X509 *ca;
+		int r;
+		unsigned long err;
+
+		SSL_CTX_clear_chain_certs(ctx);
+		
+		while ((ca = PEM_read_bio_X509(in, NULL,
+					ctx->default_passwd_callback,
+					ctx->default_passwd_callback_userdata))
+			!= NULL)
+			{
+			r = SSL_CTX_add0_chain_cert(ctx, ca);
+			if (!r) 
+				{
+				X509_free(ca);
+				ret = 0;
+				goto end;
+				}
+			/* Note that we must not free r if it was successfully
+			 * added to the chain (while we must free the main
+			 * certificate, since its reference count is increased
+			 * by SSL_CTX_use_certificate). */
+			}
+		/* When the while loop ends, it's usually just EOF. */
+		err = ERR_peek_last_error();
+		if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
+			ERR_clear_error();
+		else 
+			ret = 0; /* some real error */
+		}
+
+end:
+	if (x != NULL) X509_free(x);
+	if (in != NULL) BIO_free(in);
+	return(ret);
+	}
+#endif
+
+#ifndef OPENSSL_NO_TLSEXT
+/* authz_validate returns true iff authz is well formed, i.e. that it meets the
+ * wire format as documented in the CERT_PKEY structure and that there are no
+ * duplicate entries. */
+static char authz_validate(const unsigned char *authz, size_t length)
+	{
+	unsigned char types_seen_bitmap[32];
+
+	if (!authz)
+		return 1;
+
+	memset(types_seen_bitmap, 0, sizeof(types_seen_bitmap));
+
+	for (;;)
+		{
+		unsigned char type, byte, bit;
+		unsigned short len;
+
+		if (!length)
+			return 1;
+
+		type = *(authz++);
+		length--;
+
+		byte = type / 8;
+		bit = type & 7;
+		if (types_seen_bitmap[byte] & (1 << bit))
+			return 0;
+		types_seen_bitmap[byte] |= (1 << bit);
+
+		if (length < 2)
+			return 0;
+		len = ((unsigned short) authz[0]) << 8 |
+		      ((unsigned short) authz[1]);
+		authz += 2;
+		length -= 2;
+
+		if (length < len)
+			return 0;
+
+		authz += len;
+		length -= len;
+		}
+	}
+
+static int serverinfo_find_extension(const unsigned char *serverinfo,
+				     size_t serverinfo_length,
+				     unsigned short extension_type,
+				     const unsigned char **extension_data,
+				     unsigned short *extension_length)
+	{
+	*extension_data = NULL;
+	*extension_length = 0;
+	if (serverinfo == NULL || serverinfo_length == 0)
+		return 0;
+	for (;;)
+		{
+		unsigned short type = 0; /* uint16 */
+		unsigned short len = 0;  /* uint16 */
+
+		/* end of serverinfo */
+		if (serverinfo_length == 0)
+			return -1; /* Extension not found */
+
+		/* read 2-byte type field */
+		if (serverinfo_length < 2)
+			return 0; /* Error */
+		type = (serverinfo[0] << 8) + serverinfo[1];
+		serverinfo += 2;
+		serverinfo_length -= 2;
+
+		/* read 2-byte len field */
+		if (serverinfo_length < 2)
+			return 0; /* Error */
+		len = (serverinfo[0] << 8) + serverinfo[1];
+		serverinfo += 2;
+		serverinfo_length -= 2;
+
+		if (len > serverinfo_length)
+			return 0; /* Error */
+
+		if (type == extension_type)
+			{
+			*extension_data = serverinfo;
+			*extension_length = len;
+			return 1; /* Success */
+			}
+
+		serverinfo += len;
+		serverinfo_length -= len;
+		}
+	return 0; /* Error */
+	}
+
+static int serverinfo_srv_first_cb(SSL *s, unsigned short ext_type,
+				   const unsigned char *in,
+				   unsigned short inlen, int *al,
+				   void *arg)
+	{
+	if (inlen != 0)
+		{
+		*al = SSL_AD_DECODE_ERROR;
+		return 0;
+		}
+	return 1;
+	}
+
+static int serverinfo_srv_second_cb(SSL *s, unsigned short ext_type,
+			            const unsigned char **out, unsigned short *outlen, 
+			            void *arg)
+	{
+	const unsigned char *serverinfo = NULL;
+	size_t serverinfo_length = 0;
+
+	/* Is there serverinfo data for the chosen server cert? */
+	if ((ssl_get_server_cert_serverinfo(s, &serverinfo,
+					    &serverinfo_length)) != 0)
+		{
+		/* Find the relevant extension from the serverinfo */
+		int retval = serverinfo_find_extension(serverinfo, serverinfo_length,
+					      	       ext_type, out, outlen);
+		if (retval == 0)
+			return 0; /* Error */
+		if (retval == -1)
+			return -1; /* No extension found, don't send extension */
+		return 1; /* Send extension */
+		}
+	return -1; /* No serverinfo data found, don't send extension */
+	}
+
+/* With a NULL context, this function just checks that the serverinfo data
+   parses correctly.  With a non-NULL context, it registers callbacks for 
+   the included extensions. */
+static int serverinfo_process_buffer(const unsigned char *serverinfo, 
+			    	     size_t serverinfo_length, SSL_CTX *ctx)
+	{
+	if (serverinfo == NULL || serverinfo_length == 0)
+		return 0;
+	for (;;)
+		{
+		unsigned short ext_type = 0; /* uint16 */
+		unsigned short len = 0;  /* uint16 */
+
+		/* end of serverinfo */
+		if (serverinfo_length == 0)
+			return 1;
+
+		/* read 2-byte type field */
+		if (serverinfo_length < 2)
+			return 0;
+		/* FIXME: check for types we understand explicitly? */
+
+		/* Register callbacks for extensions */
+		ext_type = (serverinfo[0] << 8) + serverinfo[1];
+		if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type, 
+						       serverinfo_srv_first_cb,
+						       serverinfo_srv_second_cb, NULL))
+			return 0;
+
+		serverinfo += 2;
+		serverinfo_length -= 2;
+
+		/* read 2-byte len field */
+		if (serverinfo_length < 2)
+			return 0;
+		len = (serverinfo[0] << 8) + serverinfo[1];
+		serverinfo += 2;
+		serverinfo_length -= 2;
+
+		if (len > serverinfo_length)
+			return 0;
+
+		serverinfo += len;
+		serverinfo_length -= len;
+		}
+	}
+
+static const unsigned char *authz_find_data(const unsigned char *authz,
+					    size_t authz_length,
+					    unsigned char data_type,
+					    size_t *data_length)
+	{
+	if (authz == NULL) return NULL;
+	if (!authz_validate(authz, authz_length))
+		{
+		OPENSSL_PUT_ERROR(SSL, authz_find_data, SSL_R_INVALID_AUTHZ_DATA);
+		return NULL;
+		}
+
+	for (;;)
+		{
+		unsigned char type;
+		unsigned short len;
+		if (!authz_length)
+			return NULL;
+
+		type = *(authz++);
+		authz_length--;
+
+		/* We've validated the authz data, so we don't have to
+		 * check again that we have enough bytes left. */
+		len = ((unsigned short) authz[0]) << 8 |
+		      ((unsigned short) authz[1]);
+		authz += 2;
+		authz_length -= 2;
+		if (type == data_type)
+			{
+			*data_length = len;
+			return authz;
+			}
+		authz += len;
+		authz_length -= len;
+		}
+	/* No match */
+	return NULL;
+	}
+
+static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length)
+	{
+	CERT_PKEY *current_key = c->key;
+	if (current_key == NULL)
+		return 0;
+	if (!authz_validate(authz, authz_length))
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_set_authz, SSL_R_INVALID_AUTHZ_DATA);
+		return(0);
+		}
+	current_key->authz = OPENSSL_realloc(current_key->authz, authz_length);
+	if (current_key->authz == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_set_authz, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	current_key->authz_length = authz_length;
+	memcpy(current_key->authz, authz, authz_length);
+	return 1;
+	}
+
+int SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz,
+		      size_t authz_length)
+	{
+	if (authz == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_authz, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_authz, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	return ssl_set_authz(ctx->cert, authz, authz_length);
+	}
+
+int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
+			   size_t serverinfo_length)
+	{
+	if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, SSL_R_INVALID_SERVERINFO_DATA);
+		return 0;
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	if (ctx->cert->key == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+	ctx->cert->key->serverinfo = OPENSSL_realloc(ctx->cert->key->serverinfo,
+						     serverinfo_length);
+	if (ctx->cert->key->serverinfo == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	memcpy(ctx->cert->key->serverinfo, serverinfo, serverinfo_length);
+	ctx->cert->key->serverinfo_length = serverinfo_length;
+
+	/* Now that the serverinfo is validated and stored, go ahead and 
+	 * register callbacks. */
+	if (!serverinfo_process_buffer(serverinfo, serverinfo_length, ctx))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo, SSL_R_INVALID_SERVERINFO_DATA);
+		return 0;
+		}
+	return 1;
+	}
+
+int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length)
+	{
+	if (authz == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_authz, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	if (!ssl_cert_inst(&ssl->cert))
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_use_authz, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	return ssl_set_authz(ssl->cert, authz, authz_length);
+	}
+
+const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
+					    size_t *data_length)
+	{
+	CERT_PKEY *current_key;
+
+	if (ctx->cert == NULL)
+		return NULL;
+	current_key = ctx->cert->key;
+	if (current_key->authz == NULL)
+		return NULL;
+	return authz_find_data(current_key->authz,
+		current_key->authz_length, type, data_length);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+/* read_authz returns a newly allocated buffer with authz data */
+static unsigned char *read_authz(const char *file, size_t *authz_length)
+	{
+	BIO *authz_in = NULL;
+	unsigned char *authz = NULL;
+	/* Allow authzs up to 64KB. */
+	static const size_t authz_limit = 65536;
+	size_t read_length;
+	unsigned char *ret = NULL;
+
+	authz_in = BIO_new(BIO_s_file());
+	if (authz_in == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, read_authz, ERR_R_BUF_LIB);
+		goto end;
+		}
+
+	if (BIO_read_filename(authz_in,file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, read_authz, ERR_R_SYS_LIB);
+		goto end;
+		}
+
+	authz = OPENSSL_malloc(authz_limit);
+	read_length = BIO_read(authz_in, authz, authz_limit);
+	if (read_length == authz_limit || read_length <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, read_authz, SSL_R_AUTHZ_DATA_TOO_LARGE);
+		OPENSSL_free(authz);
+		goto end;
+		}
+	*authz_length = read_length;
+	ret = authz;
+end:
+	if (authz_in != NULL) BIO_free(authz_in);
+	return ret;
+	}
+
+int SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file)
+	{
+	unsigned char *authz = NULL;
+	size_t authz_length = 0;
+	int ret;
+
+	authz = read_authz(file, &authz_length);
+	if (authz == NULL)
+		return 0;
+
+	ret = SSL_CTX_use_authz(ctx, authz, authz_length);
+	/* SSL_CTX_use_authz makes a local copy of the authz. */
+	OPENSSL_free(authz);
+	return ret;
+	}
+
+int SSL_use_authz_file(SSL *ssl, const char *file)
+	{
+	unsigned char *authz = NULL;
+	size_t authz_length = 0;
+	int ret;
+
+	authz = read_authz(file, &authz_length);
+	if (authz == NULL)
+		return 0;
+
+	ret = SSL_use_authz(ssl, authz, authz_length);
+	/* SSL_use_authz makes a local copy of the authz. */
+	OPENSSL_free(authz);
+	return ret;
+	}
+
+int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
+	{
+	unsigned char *serverinfo = NULL;
+	size_t serverinfo_length = 0;
+	unsigned char* extension = 0;
+	long extension_length = 0;
+	char* name = NULL;
+	char* header = NULL;
+	char namePrefix[] = "SERVERINFO FOR ";
+	int ret = 0;
+	BIO *bin = NULL;
+	size_t num_extensions = 0;
+
+	if (ctx == NULL || file == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, ERR_R_PASSED_NULL_PARAMETER);
+		goto end;
+		}
+
+	bin = BIO_new(BIO_s_file());
+	if (bin == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, ERR_R_BUF_LIB);
+		goto end;
+		}
+	if (BIO_read_filename(bin, file) <= 0)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, ERR_R_SYS_LIB);
+		goto end;
+		}
+
+	for (num_extensions=0;; num_extensions++)
+		{
+		if (PEM_read_bio(bin, &name, &header, &extension, &extension_length) == 0)
+			{
+			/* There must be at least one extension in this file */
+			if (num_extensions == 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, SSL_R_NO_PEM_EXTENSIONS);
+				goto end;
+				}
+			else /* End of file, we're done */
+				break;
+			}
+		/* Check that PEM name starts with "BEGIN SERVERINFO FOR " */
+		if (strlen(name) < strlen(namePrefix))
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, SSL_R_PEM_NAME_TOO_SHORT);
+			goto end;
+			}
+		if (strncmp(name, namePrefix, strlen(namePrefix)) != 0)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, SSL_R_PEM_NAME_BAD_PREFIX);
+			goto end;
+			}
+		/* Check that the decoded PEM data is plausible (valid length field) */
+		if (extension_length < 4 || (extension[2] << 8) + extension[3] != extension_length - 4)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, SSL_R_BAD_DATA);
+			goto end;
+			}
+		/* Append the decoded extension to the serverinfo buffer */
+		serverinfo = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length);
+		if (serverinfo == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_CTX_use_serverinfo_file, ERR_R_MALLOC_FAILURE);
+			goto end;
+			}
+		memcpy(serverinfo + serverinfo_length, extension, extension_length);
+		serverinfo_length += extension_length;
+
+		OPENSSL_free(name); name = NULL;
+		OPENSSL_free(header); header = NULL;
+		OPENSSL_free(extension); extension = NULL;
+		}
+
+	ret = SSL_CTX_use_serverinfo(ctx, serverinfo, serverinfo_length);
+end:
+	/* SSL_CTX_use_serverinfo makes a local copy of the serverinfo. */
+	OPENSSL_free(name);
+	OPENSSL_free(header);
+	OPENSSL_free(extension);
+	OPENSSL_free(serverinfo);
+	if (bin != NULL)
+		BIO_free(bin);
+	return ret;
+	}
+#endif /* OPENSSL_NO_STDIO */
+#endif /* OPENSSL_NO_TLSEXT */
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
new file mode 100644
index 0000000..9054fd1
--- /dev/null
+++ b/ssl/ssl_sess.c
@@ -0,0 +1,1106 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * 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 <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
+static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
+
+SSL_SESSION *SSL_get_session(const SSL *ssl)
+/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */
+	{
+	return(ssl->session);
+	}
+
+SSL_SESSION *SSL_get1_session(SSL *ssl)
+/* variant of SSL_get_session: caller really gets something */
+	{
+	SSL_SESSION *sess;
+	/* Need to lock this all up rather than just use CRYPTO_add so that
+	 * somebody doesn't free ssl->session between when we check it's
+	 * non-null and when we up the reference count. */
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION);
+	sess = ssl->session;
+	if(sess)
+		sess->references++;
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION);
+	return(sess);
+	}
+
+int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
+	{
+	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp,
+			new_func, dup_func, free_func);
+	}
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg)
+	{
+	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+	}
+
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx)
+	{
+	return(CRYPTO_get_ex_data(&s->ex_data,idx));
+	}
+
+SSL_SESSION *SSL_SESSION_new(void)
+	{
+	SSL_SESSION *ss;
+
+	ss=(SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
+	if (ss == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_SESSION_new, ERR_R_MALLOC_FAILURE);
+		return(0);
+		}
+	memset(ss,0,sizeof(SSL_SESSION));
+
+	ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */
+	ss->references=1;
+	ss->timeout=60*5+4; /* 5 minute timeout by default */
+	ss->time=(unsigned long)time(NULL);
+	ss->prev=NULL;
+	ss->next=NULL;
+	ss->compress_meth=0;
+#ifndef OPENSSL_NO_TLSEXT
+	ss->tlsext_hostname = NULL; 
+#ifndef OPENSSL_NO_EC
+	ss->tlsext_ecpointformatlist_length = 0;
+	ss->tlsext_ecpointformatlist = NULL;
+	ss->tlsext_ellipticcurvelist_length = 0;
+	ss->tlsext_ellipticcurvelist = NULL;
+#endif
+#endif
+	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
+#ifndef OPENSSL_NO_PSK
+	ss->psk_identity_hint=NULL;
+	ss->psk_identity=NULL;
+#endif
+	return(ss);
+	}
+
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
+	{
+	if(len)
+		*len = s->session_id_length;
+	return s->session_id;
+	}
+
+unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s)
+	{
+	return s->compress_meth;
+	}
+
+/* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1
+ * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly
+ * until we have no conflict is going to complete in one iteration pretty much
+ * "most" of the time (btw: understatement). So, if it takes us 10 iterations
+ * and we still can't avoid a conflict - well that's a reasonable point to call
+ * it quits. Either the RAND code is broken or someone is trying to open roughly
+ * very close to 2^128 (or 2^256) SSL sessions to our server. How you might
+ * store that many sessions is perhaps a more interesting question ... */
+
+#define MAX_SESS_ID_ATTEMPTS 10
+static int def_generate_session_id(const SSL *ssl, unsigned char *id,
+				unsigned int *id_len)
+{
+	unsigned int retry = 0;
+	do
+		if (RAND_pseudo_bytes(id, *id_len) <= 0)
+			return 0;
+	while(SSL_has_matching_session_id(ssl, id, *id_len) &&
+		(++retry < MAX_SESS_ID_ATTEMPTS));
+	if(retry < MAX_SESS_ID_ATTEMPTS)
+		return 1;
+	/* else - woops a session_id match */
+	/* XXX We should also check the external cache --
+	 * but the probability of a collision is negligible, and
+	 * we could not prevent the concurrent creation of sessions
+	 * with identical IDs since we currently don't have means
+	 * to atomically check whether a session ID already exists
+	 * and make a reservation for it if it does not
+	 * (this problem applies to the internal cache as well).
+	 */
+	return 0;
+}
+
+int ssl_get_new_session(SSL *s, int session)
+	{
+	/* This gets used by clients and servers. */
+
+	unsigned int tmp;
+	SSL_SESSION *ss=NULL;
+	GEN_SESSION_CB cb = def_generate_session_id;
+
+	if ((ss=SSL_SESSION_new()) == NULL) return(0);
+
+	/* If the context has a default timeout, use it */
+	if (s->session_ctx->session_timeout == 0)
+		ss->timeout=SSL_get_default_timeout(s);
+	else
+		ss->timeout=s->session_ctx->session_timeout;
+
+	if (s->session != NULL)
+		{
+		SSL_SESSION_free(s->session);
+		s->session=NULL;
+		}
+
+	if (session)
+		{
+		if (s->version == SSL2_VERSION)
+			{
+			ss->ssl_version=SSL2_VERSION;
+			ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == SSL3_VERSION)
+			{
+			ss->ssl_version=SSL3_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == TLS1_VERSION)
+			{
+			ss->ssl_version=TLS1_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == TLS1_1_VERSION)
+			{
+			ss->ssl_version=TLS1_1_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == TLS1_2_VERSION)
+			{
+			ss->ssl_version=TLS1_2_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == DTLS1_BAD_VER)
+			{
+			ss->ssl_version=DTLS1_BAD_VER;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == DTLS1_VERSION)
+			{
+			ss->ssl_version=DTLS1_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else if (s->version == DTLS1_2_VERSION)
+			{
+			ss->ssl_version=DTLS1_2_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
+		else
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, SSL_R_UNSUPPORTED_SSL_VERSION);
+			SSL_SESSION_free(ss);
+			return(0);
+			}
+#ifndef OPENSSL_NO_TLSEXT
+		/* If RFC4507 ticket use empty session ID */
+		if (s->tlsext_ticket_expected)
+			{
+			ss->session_id_length = 0;
+			goto sess_id_done;
+			}
+#endif
+		/* Choose which callback will set the session ID */
+		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+		if(s->generate_session_id)
+			cb = s->generate_session_id;
+		else if(s->session_ctx->generate_session_id)
+			cb = s->session_ctx->generate_session_id;
+		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+		/* Choose a session ID */
+		tmp = ss->session_id_length;
+		if(!cb(s, ss->session_id, &tmp))
+			{
+			/* The callback failed */
+			OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED);
+			SSL_SESSION_free(ss);
+			return(0);
+			}
+		/* Don't allow the callback to set the session length to zero.
+		 * nor set it higher than it was. */
+		if(!tmp || (tmp > ss->session_id_length))
+			{
+			/* The callback set an illegal length */
+			OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH);
+			SSL_SESSION_free(ss);
+			return(0);
+			}
+		/* If the session length was shrunk and we're SSLv2, pad it */
+		if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION))
+			memset(ss->session_id + tmp, 0, ss->session_id_length - tmp);
+		else
+			ss->session_id_length = tmp;
+		/* Finally, check for a conflict */
+		if(SSL_has_matching_session_id(s, ss->session_id,
+						ss->session_id_length))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, SSL_R_SSL_SESSION_ID_CONFLICT);
+			SSL_SESSION_free(ss);
+			return(0);
+			}
+#ifndef OPENSSL_NO_TLSEXT
+		sess_id_done:
+		if (s->tlsext_hostname) {
+			ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
+			if (ss->tlsext_hostname == NULL) {
+				OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
+				SSL_SESSION_free(ss);
+				return 0;
+				}
+			}
+#endif
+		}
+	else
+		{
+		ss->session_id_length=0;
+		}
+
+	if (s->sid_ctx_length > sizeof ss->sid_ctx)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_get_new_session, ERR_R_INTERNAL_ERROR);
+		SSL_SESSION_free(ss);
+		return 0;
+		}
+	memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length);
+	ss->sid_ctx_length=s->sid_ctx_length;
+	s->session=ss;
+	ss->ssl_version=s->version;
+	ss->verify_result = X509_V_OK;
+
+	return(1);
+	}
+
+/* ssl_get_prev attempts to find an SSL_SESSION to be used to resume this
+ * connection. It is only called by servers.
+ *
+ *   session_id: points at the session ID in the ClientHello. This code will
+ *       read past the end of this in order to parse out the session ticket
+ *       extension, if any.
+ *   len: the length of the session ID.
+ *   limit: a pointer to the first byte after the ClientHello.
+ *
+ * Returns:
+ *   -1: error
+ *    0: a session may have been found.
+ *
+ * Side effects:
+ *   - If a session is found then s->session is pointed at it (after freeing an
+ *     existing session if need be) and s->verify_result is set from the session.
+ *   - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1
+ *     if the server should issue a new session ticket (to 0 otherwise).
+ */
+int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
+			const unsigned char *limit)
+	{
+	/* This is used only by servers. */
+
+	SSL_SESSION *ret=NULL;
+	int fatal = 0;
+	int try_session_cache = 1;
+#ifndef OPENSSL_NO_TLSEXT
+	int r;
+#endif
+
+	if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
+		goto err;
+
+	if (len == 0)
+		try_session_cache = 0;
+
+#ifndef OPENSSL_NO_TLSEXT
+	r = tls1_process_ticket(s, session_id, len, limit, &ret); /* sets s->tlsext_ticket_expected */
+	switch (r)
+		{
+	case -1: /* Error during processing */
+		fatal = 1;
+		goto err;
+	case 0: /* No ticket found */
+	case 1: /* Zero length ticket found */
+		break; /* Ok to carry on processing session id. */
+	case 2: /* Ticket found but not decrypted. */
+	case 3: /* Ticket decrypted, *ret has been set. */
+		try_session_cache = 0;
+		break;
+	default:
+		abort();
+		}
+#endif
+
+	if (try_session_cache &&
+	    ret == NULL &&
+	    !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
+		{
+		SSL_SESSION data;
+		data.ssl_version=s->version;
+		data.session_id_length=len;
+		if (len == 0)
+			return 0;
+		memcpy(data.session_id,session_id,len);
+		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+		ret=lh_SSL_SESSION_retrieve(s->session_ctx->sessions,&data);
+		if (ret != NULL)
+			{
+			/* don't allow other threads to steal it: */
+			CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
+			}
+		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+		if (ret == NULL)
+			s->session_ctx->stats.sess_miss++;
+		}
+
+	if (try_session_cache &&
+	    ret == NULL &&
+	    s->session_ctx->get_session_cb != NULL)
+		{
+		int copy=1;
+	
+		if ((ret=s->session_ctx->get_session_cb(s,session_id,len,&copy)))
+			{
+			s->session_ctx->stats.sess_cb_hit++;
+
+			/* Increment reference count now if the session callback
+			 * asks us to do so (note that if the session structures
+			 * returned by the callback are shared between threads,
+			 * it must handle the reference count itself [i.e. copy == 0],
+			 * or things won't be thread-safe). */
+			if (copy)
+				CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION);
+
+			/* Add the externally cached session to the internal
+			 * cache as well if and only if we are supposed to. */
+			if(!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE))
+				/* The following should not return 1, otherwise,
+				 * things are very strange */
+				SSL_CTX_add_session(s->session_ctx,ret);
+			}
+		}
+
+	if (ret == NULL)
+		goto err;
+
+	/* Now ret is non-NULL and we own one of its reference counts. */
+
+	if (ret->sid_ctx_length != s->sid_ctx_length
+	    || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))
+		{
+		/* We have the session requested by the client, but we don't
+		 * want to use it in this context. */
+		goto err; /* treat like cache miss */
+		}
+	
+	if((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0)
+		{
+		/* We can't be sure if this session is being used out of
+		 * context, which is especially important for SSL_VERIFY_PEER.
+		 * The application should have used SSL[_CTX]_set_session_id_context.
+		 *
+		 * For this error case, we generate an error instead of treating
+		 * the event like a cache miss (otherwise it would be easy for
+		 * applications to effectively disable the session cache by
+		 * accident without anyone noticing).
+		 */
+		
+		OPENSSL_PUT_ERROR(SSL, ssl_get_prev_session, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED);
+		fatal = 1;
+		goto err;
+		}
+
+	if (ret->cipher == NULL)
+		{
+		unsigned char buf[5],*p;
+		unsigned long l;
+
+		p=buf;
+		l=ret->cipher_id;
+		l2n(l,p);
+		if ((ret->ssl_version>>8) >= SSL3_VERSION_MAJOR)
+			ret->cipher=ssl_get_cipher_by_char(s,&(buf[2]));
+		else 
+			ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
+		if (ret->cipher == NULL)
+			goto err;
+		}
+
+	if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */
+		{
+		s->session_ctx->stats.sess_timeout++;
+		if (try_session_cache)
+			{
+			/* session was from the cache, so remove it */
+			SSL_CTX_remove_session(s->session_ctx,ret);
+			}
+		goto err;
+		}
+
+	s->session_ctx->stats.sess_hit++;
+
+	if (s->session != NULL)
+		SSL_SESSION_free(s->session);
+	s->session=ret;
+	s->verify_result = s->session->verify_result;
+	return 1;
+
+ err:
+	if (ret != NULL)
+		{
+		SSL_SESSION_free(ret);
+#ifndef OPENSSL_NO_TLSEXT
+		if (!try_session_cache)
+			{
+			/* The session was from a ticket, so we should
+			 * issue a ticket for the new session */
+			s->tlsext_ticket_expected = 1;
+			}
+#endif
+		}
+	if (fatal)
+		return -1;
+	else
+		return 0;
+	}
+
+int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
+	{
+	int ret=0;
+	SSL_SESSION *s;
+
+	/* add just 1 reference count for the SSL_CTX's session cache
+	 * even though it has two ways of access: each session is in a
+	 * doubly linked list and an lhash */
+	CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION);
+	/* if session c is in already in cache, we take back the increment later */
+
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	if (!lh_SSL_SESSION_insert(ctx->sessions,&s,c)) {
+          return 0;
+        }
+	
+	/* s != NULL iff we already had a session with the given PID.
+	 * In this case, s == c should hold (then we did not really modify
+	 * ctx->sessions), or we're in trouble. */
+	if (s != NULL && s != c)
+		{
+		/* We *are* in trouble ... */
+		SSL_SESSION_list_remove(ctx,s);
+		SSL_SESSION_free(s);
+		/* ... so pretend the other session did not exist in cache
+		 * (we cannot handle two SSL_SESSION structures with identical
+		 * session ID in the same cache, which could happen e.g. when
+		 * two threads concurrently obtain the same session from an external
+		 * cache) */
+		s = NULL;
+		}
+
+ 	/* Put at the head of the queue unless it is already in the cache */
+	if (s == NULL)
+		SSL_SESSION_list_add(ctx,c);
+
+	if (s != NULL)
+		{
+		/* existing cache entry -- decrement previously incremented reference
+		 * count because it already takes into account the cache */
+
+		SSL_SESSION_free(s); /* s == c */
+		ret=0;
+		}
+	else
+		{
+		/* new cache entry -- remove old ones if cache has become too large */
+		
+		ret=1;
+
+		if (SSL_CTX_sess_get_cache_size(ctx) > 0)
+			{
+			while (SSL_CTX_sess_number(ctx) >
+				SSL_CTX_sess_get_cache_size(ctx))
+				{
+				if (!remove_session_lock(ctx,
+					ctx->session_cache_tail, 0))
+					break;
+				else
+					ctx->stats.sess_cache_full++;
+				}
+			}
+		}
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	return(ret);
+	}
+
+int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c)
+{
+	return remove_session_lock(ctx, c, 1);
+}
+
+static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck)
+	{
+	SSL_SESSION *r;
+	int ret=0;
+
+	if ((c != NULL) && (c->session_id_length != 0))
+		{
+		if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+		if ((r = lh_SSL_SESSION_retrieve(ctx->sessions,c)) == c)
+			{
+			ret=1;
+			r=lh_SSL_SESSION_delete(ctx->sessions,c);
+			SSL_SESSION_list_remove(ctx,c);
+			}
+
+		if(lck) CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+
+		if (ret)
+			{
+			r->not_resumable=1;
+			if (ctx->remove_session_cb != NULL)
+				ctx->remove_session_cb(ctx,r);
+			SSL_SESSION_free(r);
+			}
+		}
+	else
+		ret=0;
+	return(ret);
+	}
+
+void SSL_SESSION_free(SSL_SESSION *ss)
+	{
+	int i;
+
+	if(ss == NULL)
+	    return;
+
+	i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION);
+#ifdef REF_PRINT
+	REF_PRINT("SSL_SESSION",ss);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"SSL_SESSION_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
+
+	OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg);
+	OPENSSL_cleanse(ss->master_key,sizeof ss->master_key);
+	OPENSSL_cleanse(ss->session_id,sizeof ss->session_id);
+	if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert);
+	if (ss->peer != NULL) X509_free(ss->peer);
+	if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
+#ifndef OPENSSL_NO_TLSEXT
+	if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
+	if (ss->tlsext_tick != NULL) OPENSSL_free(ss->tlsext_tick);
+#ifndef OPENSSL_NO_EC
+	ss->tlsext_ecpointformatlist_length = 0;
+	if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
+	ss->tlsext_ellipticcurvelist_length = 0;
+	if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
+#endif /* OPENSSL_NO_EC */
+	if (ss->audit_proof != NULL) OPENSSL_free(ss->audit_proof);
+	ss->audit_proof_length = 0;
+#endif
+#ifndef OPENSSL_NO_PSK
+	if (ss->psk_identity_hint != NULL)
+		OPENSSL_free(ss->psk_identity_hint);
+	if (ss->psk_identity != NULL)
+		OPENSSL_free(ss->psk_identity);
+#endif
+	OPENSSL_cleanse(ss,sizeof(*ss));
+	OPENSSL_free(ss);
+	}
+
+int SSL_set_session(SSL *s, SSL_SESSION *session)
+	{
+	int ret=0;
+	const SSL_METHOD *meth;
+
+	if (session != NULL)
+		{
+		meth=s->ctx->method->get_ssl_method(session->ssl_version);
+		if (meth == NULL)
+			meth=s->method->get_ssl_method(session->ssl_version);
+		if (meth == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_set_session, SSL_R_UNABLE_TO_FIND_SSL_METHOD);
+			return(0);
+			}
+
+		if (meth != s->method)
+			{
+			if (!SSL_set_ssl_method(s,meth))
+				return(0);
+			}
+
+		/* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/
+		CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION);
+		if (s->session != NULL)
+			SSL_SESSION_free(s->session);
+		s->session=session;
+		s->verify_result = s->session->verify_result;
+		/* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/
+		ret=1;
+		}
+	else
+		{
+		if (s->session != NULL)
+			{
+			SSL_SESSION_free(s->session);
+			s->session=NULL;
+			}
+
+		meth=s->ctx->method;
+		if (meth != s->method)
+			{
+			if (!SSL_set_ssl_method(s,meth))
+				return(0);
+			}
+		ret=1;
+		}
+	return(ret);
+	}
+
+long SSL_SESSION_set_timeout(SSL_SESSION *s, long t)
+	{
+	if (s == NULL) return(0);
+	s->timeout=t;
+	return(1);
+	}
+
+long SSL_SESSION_get_timeout(const SSL_SESSION *s)
+	{
+	if (s == NULL) return(0);
+	return(s->timeout);
+	}
+
+long SSL_SESSION_get_time(const SSL_SESSION *s)
+	{
+	if (s == NULL) return(0);
+	return(s->time);
+	}
+
+long SSL_SESSION_set_time(SSL_SESSION *s, long t)
+	{
+	if (s == NULL) return(0);
+	s->time=t;
+	return(t);
+	}
+
+X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
+	{
+	return s->peer;
+	}
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
+			       unsigned int sid_ctx_len)
+	{
+	if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_SESSION_set1_id_context, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+		return 0;
+		}
+	s->sid_ctx_length=sid_ctx_len;
+	memcpy(s->sid_ctx,sid_ctx,sid_ctx_len);
+
+	return 1;
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s, size_t *proof_length)
+	{
+	if (s->audit_proof != NULL)
+		*proof_length = s->audit_proof_length;
+	return s->audit_proof;
+	}
+#endif
+
+long SSL_CTX_set_timeout(SSL_CTX *s, long t)
+	{
+	long l;
+	if (s == NULL) return(0);
+	l=s->session_timeout;
+	s->session_timeout=t;
+	return(l);
+	}
+
+long SSL_CTX_get_timeout(const SSL_CTX *s)
+	{
+	if (s == NULL) return(0);
+	return(s->session_timeout);
+	}
+
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+	{
+	if (s == NULL) return(0);
+	s->tls_session_secret_cb = tls_session_secret_cb;
+	s->tls_session_secret_cb_arg = arg;
+	return(1);
+	}
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+				  void *arg)
+	{
+	if (s == NULL) return(0);
+	s->tls_session_ticket_ext_cb = cb;
+	s->tls_session_ticket_ext_cb_arg = arg;
+	return(1);
+	}
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+	{
+	if (s->version >= TLS1_VERSION)
+		{
+		if (s->tlsext_session_ticket)
+			{
+			OPENSSL_free(s->tlsext_session_ticket);
+			s->tlsext_session_ticket = NULL;
+			}
+
+		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+		if (!s->tlsext_session_ticket)
+			{
+			OPENSSL_PUT_ERROR(SSL, SSL_set_session_ticket_ext, ERR_R_MALLOC_FAILURE);
+			return 0;
+			}
+
+		if (ext_data)
+			{
+			s->tlsext_session_ticket->length = ext_len;
+			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
+			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
+			}
+		else
+			{
+			s->tlsext_session_ticket->length = 0;
+			s->tlsext_session_ticket->data = NULL;
+			}
+
+		return 1;
+		}
+
+	return 0;
+	}
+#endif /* OPENSSL_NO_TLSEXT */
+
+typedef struct timeout_param_st
+	{
+	SSL_CTX *ctx;
+	long time;
+	LHASH_OF(SSL_SESSION) *cache;
+	} TIMEOUT_PARAM;
+
+static void timeout_doall_arg(SSL_SESSION *sess, void *void_param)
+	{
+	TIMEOUT_PARAM *param = void_param;
+
+	if ((param->time == 0) || (param->time > (sess->time+sess->timeout))) /* timeout */
+		{
+		/* The reason we don't call SSL_CTX_remove_session() is to
+		 * save on locking overhead */
+		(void)lh_SSL_SESSION_delete(param->cache,sess);
+		SSL_SESSION_list_remove(param->ctx,sess);
+		sess->not_resumable=1;
+		if (param->ctx->remove_session_cb != NULL)
+			param->ctx->remove_session_cb(param->ctx,sess);
+		SSL_SESSION_free(sess);
+		}
+	}
+
+void SSL_CTX_flush_sessions(SSL_CTX *s, long t)
+	{
+	TIMEOUT_PARAM tp;
+
+	tp.ctx=s;
+	tp.cache=s->sessions;
+	if (tp.cache == NULL) return;
+	tp.time=t;
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp);
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	}
+
+int ssl_clear_bad_session(SSL *s)
+	{
+	if (	(s->session != NULL) &&
+		!(s->shutdown & SSL_SENT_SHUTDOWN) &&
+		!(SSL_in_init(s) || SSL_in_before(s)))
+		{
+		SSL_CTX_remove_session(s->ctx,s->session);
+		return(1);
+		}
+	else
+		return(0);
+	}
+
+/* locked by SSL_CTX in the calling function */
+static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s)
+	{
+	if ((s->next == NULL) || (s->prev == NULL)) return;
+
+	if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail))
+		{ /* last element in list */
+		if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
+			{ /* only one element in list */
+			ctx->session_cache_head=NULL;
+			ctx->session_cache_tail=NULL;
+			}
+		else
+			{
+			ctx->session_cache_tail=s->prev;
+			s->prev->next=(SSL_SESSION *)&(ctx->session_cache_tail);
+			}
+		}
+	else
+		{
+		if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head))
+			{ /* first element in list */
+			ctx->session_cache_head=s->next;
+			s->next->prev=(SSL_SESSION *)&(ctx->session_cache_head);
+			}
+		else
+			{ /* middle of list */
+			s->next->prev=s->prev;
+			s->prev->next=s->next;
+			}
+		}
+	s->prev=s->next=NULL;
+	}
+
+static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s)
+	{
+	if ((s->next != NULL) && (s->prev != NULL))
+		SSL_SESSION_list_remove(ctx,s);
+
+	if (ctx->session_cache_head == NULL)
+		{
+		ctx->session_cache_head=s;
+		ctx->session_cache_tail=s;
+		s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
+		s->next=(SSL_SESSION *)&(ctx->session_cache_tail);
+		}
+	else
+		{
+		s->next=ctx->session_cache_head;
+		s->next->prev=s;
+		s->prev=(SSL_SESSION *)&(ctx->session_cache_head);
+		ctx->session_cache_head=s;
+		}
+	}
+
+void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
+	int (*cb)(struct ssl_st *ssl,SSL_SESSION *sess))
+	{
+	ctx->new_session_cb=cb;
+	}
+
+int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, SSL_SESSION *sess)
+	{
+	return ctx->new_session_cb;
+	}
+
+void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx,
+	void (*cb)(SSL_CTX *ctx,SSL_SESSION *sess))
+	{
+	ctx->remove_session_cb=cb;
+	}
+
+void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(SSL_CTX * ctx,SSL_SESSION *sess)
+	{
+	return ctx->remove_session_cb;
+	}
+
+void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx,
+	SSL_SESSION *(*cb)(struct ssl_st *ssl,
+	         unsigned char *data,int len,int *copy))
+	{
+	ctx->get_session_cb=cb;
+	}
+
+SSL_SESSION * (*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(SSL *ssl,
+	         unsigned char *data,int len,int *copy)
+	{
+	return ctx->get_session_cb;
+	}
+
+void SSL_CTX_set_info_callback(SSL_CTX *ctx, 
+	void (*cb)(const SSL *ssl,int type,int val))
+	{
+	ctx->info_callback=cb;
+	}
+
+void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val)
+	{
+	return ctx->info_callback;
+	}
+
+void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx,
+	int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey))
+	{
+	ctx->client_cert_cb=cb;
+	}
+
+int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL * ssl, X509 ** x509 , EVP_PKEY **pkey)
+	{
+	return ctx->client_cert_cb;
+	}
+
+void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx,
+	int (*cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len))
+	{
+	ctx->app_gen_cookie_cb=cb;
+	}
+
+void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx,
+	int (*cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len))
+	{
+	ctx->app_verify_cookie_cb=cb;
+	}
+
+IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c
new file mode 100644
index 0000000..c8851ff
--- /dev/null
+++ b/ssl/ssl_stat.c
@@ -0,0 +1,487 @@
+/* ssl/ssl_stat.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 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"
+
+const char *SSL_state_string_long(const SSL *s)
+	{
+	const char *str;
+
+	switch (s->state)
+		{
+case SSL_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: 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;
+
+#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";break;
+case SSL3_ST_CR_SESSION_TICKET_B: str="SSLv3 read server session ticket B";break;
+case SSL3_ST_CR_SRVR_DONE_A:	str="SSLv3 read server done A"; break;
+case SSL3_ST_CR_SRVR_DONE_B:	str="SSLv3 read server done B"; break;
+case SSL3_ST_CW_CERT_A:		str="SSLv3 write client certificate A"; break;
+case SSL3_ST_CW_CERT_B:		str="SSLv3 write client certificate B"; break;
+case SSL3_ST_CW_CERT_C:		str="SSLv3 write client certificate C"; break;
+case SSL3_ST_CW_CERT_D:		str="SSLv3 write client certificate D"; break;
+case SSL3_ST_CW_KEY_EXCH_A:	str="SSLv3 write client key exchange A"; 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"; 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"; break;
+case SSL3_ST_CR_CHANGE_A:	
+case SSL3_ST_SR_CHANGE_A:	str="SSLv3 read change cipher spec A"; break;
+case SSL3_ST_CR_CHANGE_B:	
+case SSL3_ST_SR_CHANGE_B:	str="SSLv3 read change cipher spec B"; 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"; 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"; break;
+case SSL3_ST_SW_CERT_REQ_B:	str="SSLv3 write certificate request B"; break;
+case SSL3_ST_SW_SESSION_TICKET_A: str="SSLv3 write session ticket A"; break;
+case SSL3_ST_SW_SESSION_TICKET_B: str="SSLv3 write session ticket B"; break;
+case SSL3_ST_SW_SRVR_DONE_A:	str="SSLv3 write server done A"; break;
+case SSL3_ST_SW_SRVR_DONE_B:	str="SSLv3 write server done B"; break;
+case SSL3_ST_SR_CERT_A:		str="SSLv3 read client certificate A"; break;
+case SSL3_ST_SR_CERT_B:		str="SSLv3 read client certificate B"; break;
+case SSL3_ST_SR_KEY_EXCH_A:	str="SSLv3 read client key exchange A"; break;
+case SSL3_ST_SR_KEY_EXCH_B:	str="SSLv3 read client key exchange B"; break;
+case SSL3_ST_SR_CERT_VRFY_A:	str="SSLv3 read certificate verify A"; break;
+case SSL3_ST_SR_CERT_VRFY_B:	str="SSLv3 read certificate verify B"; break;
+#endif
+
+#if !defined(OPENSSL_NO_SSL3)
+/* SSLv2/v3 compatibility states */
+/* client */
+case SSL23_ST_CW_CLNT_HELLO_A:	str="SSLv2/v3 write client hello A"; break;
+case SSL23_ST_CW_CLNT_HELLO_B:	str="SSLv2/v3 write client hello B"; break;
+case SSL23_ST_CR_SRVR_HELLO_A:	str="SSLv2/v3 read server hello A"; break;
+case SSL23_ST_CR_SRVR_HELLO_B:	str="SSLv2/v3 read server hello B"; break;
+/* server */
+case SSL23_ST_SR_CLNT_HELLO_A:	str="SSLv2/v3 read client hello A"; break;
+case SSL23_ST_SR_CLNT_HELLO_B:	str="SSLv2/v3 read client hello 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"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: str="DTLS1 write hello verify request B"; break;
+
+default:	str="unknown state"; break;
+		}
+	return(str);
+	}
+
+const char *SSL_rstate_string_long(const SSL *s)
+	{
+	const char *str;
+
+	switch (s->rstate)
+		{
+	case SSL_ST_READ_HEADER: str="read header"; break;
+	case SSL_ST_READ_BODY: str="read body"; break;
+	case SSL_ST_READ_DONE: str="read done"; break;
+	default: str="unknown"; break;
+		}
+	return(str);
+	}
+
+const char *SSL_state_string(const SSL *s)
+	{
+	const char *str;
+
+	switch (s->state)
+		{
+case SSL_ST_BEFORE:				str="PINIT "; break;
+case SSL_ST_ACCEPT:				str="AINIT "; break;
+case SSL_ST_CONNECT:				str="CINIT "; break;
+case SSL_ST_OK:			 		str="SSLOK "; 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"; break;
+case SSL3_ST_CR_SRVR_DONE_B:			str="3RSD_B"; break;
+case SSL3_ST_CW_CERT_A:				str="3WCC_A"; break;
+case SSL3_ST_CW_CERT_B:				str="3WCC_B"; break;
+case SSL3_ST_CW_CERT_C:				str="3WCC_C"; break;
+case SSL3_ST_CW_CERT_D:				str="3WCC_D"; break;
+case SSL3_ST_CW_KEY_EXCH_A:			str="3WCKEA"; break;
+case SSL3_ST_CW_KEY_EXCH_B:			str="3WCKEB"; break;
+case SSL3_ST_CW_CERT_VRFY_A:			str="3WCV_A"; break;
+case SSL3_ST_CW_CERT_VRFY_B:			str="3WCV_B"; 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"; break;
+case SSL3_ST_SR_CHANGE_B:
+case SSL3_ST_CR_CHANGE_B:			str="3RCCSB"; break;
+case SSL3_ST_SR_FINISHED_A:
+case SSL3_ST_CR_FINISHED_A:			str="3RFINA"; break;
+case SSL3_ST_SR_FINISHED_B:
+case SSL3_ST_CR_FINISHED_B:			str="3RFINB"; 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"; break;
+case SSL3_ST_SW_SRVR_HELLO_A:			str="3WSH_A"; break;
+case SSL3_ST_SW_SRVR_HELLO_B:			str="3WSH_B"; break;
+case SSL3_ST_SW_CERT_A:				str="3WSC_A"; break;
+case SSL3_ST_SW_CERT_B:				str="3WSC_B"; break;
+case SSL3_ST_SW_KEY_EXCH_A:			str="3WSKEA"; break;
+case SSL3_ST_SW_KEY_EXCH_B:			str="3WSKEB"; break;
+case SSL3_ST_SW_CERT_REQ_A:			str="3WCR_A"; break;
+case SSL3_ST_SW_CERT_REQ_B:			str="3WCR_B"; break;
+case SSL3_ST_SW_SRVR_DONE_A:			str="3WSD_A"; 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
+
+#if !defined(OPENSSL_NO_SSL3)
+/* SSLv2/v3 compatibility states */
+/* client */
+case SSL23_ST_CW_CLNT_HELLO_A:			str="23WCHA"; break;
+case SSL23_ST_CW_CLNT_HELLO_B:			str="23WCHB"; break;
+case SSL23_ST_CR_SRVR_HELLO_A:			str="23RSHA"; break;
+case SSL23_ST_CR_SRVR_HELLO_B:			str="23RSHA"; break;
+/* server */
+case SSL23_ST_SR_CLNT_HELLO_A:			str="23RCHA"; break;
+case SSL23_ST_SR_CLNT_HELLO_B:			str="23RCHB"; 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"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: str="DWCHVB"; break;
+
+default:					str="UNKWN "; break;
+		}
+	return(str);
+	}
+
+const char *SSL_alert_type_string_long(int value)
+	{
+	value>>=8;
+	if (value == SSL3_AL_WARNING)
+		return("warning");
+	else if (value == SSL3_AL_FATAL)
+		return("fatal");
+	else
+		return("unknown");
+	}
+
+const char *SSL_alert_type_string(int value)
+	{
+	value>>=8;
+	if (value == SSL3_AL_WARNING)
+		return("W");
+	else if (value == SSL3_AL_FATAL)
+		return("F");
+	else
+		return("U");
+	}
+
+const char *SSL_alert_desc_string(int value)
+	{
+	const char *str;
+
+	switch (value & 0xff)
+		{
+	case SSL3_AD_CLOSE_NOTIFY:		str="CN"; break;
+	case SSL3_AD_UNEXPECTED_MESSAGE:	str="UM"; break;
+	case SSL3_AD_BAD_RECORD_MAC:		str="BM"; break;
+	case SSL3_AD_DECOMPRESSION_FAILURE:	str="DF"; break;
+	case SSL3_AD_HANDSHAKE_FAILURE:		str="HF"; break;
+	case SSL3_AD_NO_CERTIFICATE:		str="NC"; break;
+	case SSL3_AD_BAD_CERTIFICATE:		str="BC"; break;
+	case SSL3_AD_UNSUPPORTED_CERTIFICATE:	str="UC"; break;
+	case SSL3_AD_CERTIFICATE_REVOKED:	str="CR"; break;
+	case SSL3_AD_CERTIFICATE_EXPIRED:	str="CE"; break;
+	case SSL3_AD_CERTIFICATE_UNKNOWN:	str="CU"; break;
+	case SSL3_AD_ILLEGAL_PARAMETER:		str="IP"; break;
+	case TLS1_AD_DECRYPTION_FAILED:		str="DC"; break;
+	case TLS1_AD_RECORD_OVERFLOW:		str="RO"; break;
+	case TLS1_AD_UNKNOWN_CA:		str="CA"; break;
+	case TLS1_AD_ACCESS_DENIED:		str="AD"; break;
+	case TLS1_AD_DECODE_ERROR:		str="DE"; break;
+	case TLS1_AD_DECRYPT_ERROR:		str="CY"; break;
+	case TLS1_AD_EXPORT_RESTRICTION:	str="ER"; break;
+	case TLS1_AD_PROTOCOL_VERSION:		str="PV"; break;
+	case TLS1_AD_INSUFFICIENT_SECURITY:	str="IS"; break;
+	case TLS1_AD_INTERNAL_ERROR:		str="IE"; break;
+	case TLS1_AD_USER_CANCELLED:		str="US"; break;
+	case TLS1_AD_NO_RENEGOTIATION:		str="NR"; break;
+	case TLS1_AD_UNSUPPORTED_EXTENSION:	str="UE"; break;
+	case TLS1_AD_CERTIFICATE_UNOBTAINABLE:	str="CO"; break;
+	case TLS1_AD_UNRECOGNIZED_NAME:		str="UN"; break;
+	case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: str="BR"; break;
+	case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: str="BH"; break;
+	case TLS1_AD_UNKNOWN_PSK_IDENTITY:	str="UP"; break;
+	default:				str="UK"; break;
+		}
+	return(str);
+	}
+
+const char *SSL_alert_desc_string_long(int value)
+	{
+	const char *str;
+
+	switch (value & 0xff)
+		{
+	case SSL3_AD_CLOSE_NOTIFY:
+		str="close notify";
+		break;
+	case SSL3_AD_UNEXPECTED_MESSAGE:
+		str="unexpected_message";
+		break;
+	case SSL3_AD_BAD_RECORD_MAC:
+		str="bad record mac";
+		break;
+	case SSL3_AD_DECOMPRESSION_FAILURE:
+		str="decompression failure";
+		break;
+	case SSL3_AD_HANDSHAKE_FAILURE:
+		str="handshake failure";
+		break;
+	case SSL3_AD_NO_CERTIFICATE:
+		str="no certificate";
+		break;
+	case SSL3_AD_BAD_CERTIFICATE:
+		str="bad certificate";
+		break;
+	case SSL3_AD_UNSUPPORTED_CERTIFICATE:
+		str="unsupported certificate";
+		break;
+	case SSL3_AD_CERTIFICATE_REVOKED:
+		str="certificate revoked";
+		break;
+	case SSL3_AD_CERTIFICATE_EXPIRED:
+		str="certificate expired";
+		break;
+	case SSL3_AD_CERTIFICATE_UNKNOWN:
+		str="certificate unknown";
+		break;
+	case SSL3_AD_ILLEGAL_PARAMETER:
+		str="illegal parameter";
+		break;
+	case TLS1_AD_DECRYPTION_FAILED:
+		str="decryption failed";
+		break;
+	case TLS1_AD_RECORD_OVERFLOW:
+		str="record overflow";
+		break;
+	case TLS1_AD_UNKNOWN_CA:
+		str="unknown CA";
+		break;
+	case TLS1_AD_ACCESS_DENIED:
+		str="access denied";
+		break;
+	case TLS1_AD_DECODE_ERROR:
+		str="decode error";
+		break;
+	case TLS1_AD_DECRYPT_ERROR:
+		str="decrypt error";
+		break;
+	case TLS1_AD_EXPORT_RESTRICTION:
+		str="export restriction";
+		break;
+	case TLS1_AD_PROTOCOL_VERSION:
+		str="protocol version";
+		break;
+	case TLS1_AD_INSUFFICIENT_SECURITY:
+		str="insufficient security";
+		break;
+	case TLS1_AD_INTERNAL_ERROR:
+		str="internal error";
+		break;
+	case TLS1_AD_USER_CANCELLED:
+		str="user canceled";
+		break;
+	case TLS1_AD_NO_RENEGOTIATION:
+		str="no renegotiation";
+		break;
+	case TLS1_AD_UNSUPPORTED_EXTENSION:
+		str="unsupported extension";
+		break;
+	case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+		str="certificate unobtainable";
+		break;
+	case TLS1_AD_UNRECOGNIZED_NAME:
+		str="unrecognized name";
+		break;
+	case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+		str="bad certificate status response";
+		break;
+	case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
+		str="bad certificate hash value";
+		break;
+	case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+		str="unknown PSK identity";
+		break;
+	default: str="unknown"; break;
+		}
+	return(str);
+	}
+
+const char *SSL_rstate_string(const SSL *s)
+	{
+	const char *str;
+
+	switch (s->rstate)
+		{
+	case SSL_ST_READ_HEADER:str="RH"; break;
+	case SSL_ST_READ_BODY:	str="RB"; break;
+	case SSL_ST_READ_DONE:	str="RD"; break;
+	default: str="unknown"; break;
+		}
+	return(str);
+	}
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c
new file mode 100644
index 0000000..da48076
--- /dev/null
+++ b/ssl/ssl_txt.c
@@ -0,0 +1,217 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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 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 <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "ssl_locl.h"
+
+int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x)
+	{
+	BIO *b;
+	int ret;
+
+	if ((b=BIO_new(BIO_s_file())) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, SSL_SESSION_print_fp, ERR_R_BUF_LIB);
+		return(0);
+		}
+	BIO_set_fp(b,fp,BIO_NOCLOSE);
+	ret=SSL_SESSION_print(b,x);
+	BIO_free(b);
+	return(ret);
+	}
+
+int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
+	{
+	unsigned int i;
+	const char *s;
+
+	if (x == NULL) goto err;
+	if (BIO_puts(bp,"SSL-Session:\n") <= 0) goto err;
+	if (x->ssl_version == SSL2_VERSION)
+		s="SSLv2";
+	else if (x->ssl_version == SSL3_VERSION)
+		s="SSLv3";
+	else if (x->ssl_version == TLS1_2_VERSION)
+		s="TLSv1.2";
+	else if (x->ssl_version == TLS1_1_VERSION)
+		s="TLSv1.1";
+	else if (x->ssl_version == TLS1_VERSION)
+		s="TLSv1";
+	else if (x->ssl_version == DTLS1_VERSION)
+		s="DTLSv1";
+	else if (x->ssl_version == DTLS1_2_VERSION)
+		s="DTLSv1.2";
+	else if (x->ssl_version == DTLS1_BAD_VER)
+		s="DTLSv1-bad";
+	else
+		s="unknown";
+	if (BIO_printf(bp,"    Protocol  : %s\n",s) <= 0) goto err;
+
+	if (x->cipher == NULL)
+		{
+		if (((x->cipher_id) & 0xff000000) == 0x02000000)
+			{
+			if (BIO_printf(bp,"    Cipher    : %06lX\n",x->cipher_id&0xffffff) <= 0)
+				goto err;
+			}
+		else
+			{
+			if (BIO_printf(bp,"    Cipher    : %04lX\n",x->cipher_id&0xffff) <= 0)
+				goto err;
+			}
+		}
+	else
+		{
+		if (BIO_printf(bp,"    Cipher    : %s\n",((x->cipher == NULL)?"unknown":x->cipher->name)) <= 0)
+			goto err;
+		}
+	if (BIO_puts(bp,"    Session-ID: ") <= 0) goto err;
+	for (i=0; i<x->session_id_length; i++)
+		{
+		if (BIO_printf(bp,"%02X",x->session_id[i]) <= 0) goto err;
+		}
+	if (BIO_puts(bp,"\n    Session-ID-ctx: ") <= 0) goto err;
+	for (i=0; i<x->sid_ctx_length; i++)
+		{
+		if (BIO_printf(bp,"%02X",x->sid_ctx[i]) <= 0)
+			goto err;
+		}
+	if (BIO_puts(bp,"\n    Master-Key: ") <= 0) goto err;
+	for (i=0; i<(unsigned int)x->master_key_length; i++)
+		{
+		if (BIO_printf(bp,"%02X",x->master_key[i]) <= 0) goto err;
+		}
+	if (BIO_puts(bp,"\n    Key-Arg   : ") <= 0) goto err;
+	if (x->key_arg_length == 0)
+		{
+		if (BIO_puts(bp,"None") <= 0) goto err;
+		}
+	else
+		for (i=0; i<x->key_arg_length; i++)
+			{
+			if (BIO_printf(bp,"%02X",x->key_arg[i]) <= 0) goto err;
+			}
+#ifndef OPENSSL_NO_PSK
+	if (BIO_puts(bp,"\n    PSK identity: ") <= 0) goto err;
+	if (BIO_printf(bp, "%s", x->psk_identity ? x->psk_identity : "None") <= 0) goto err;
+	if (BIO_puts(bp,"\n    PSK identity hint: ") <= 0) goto err;
+	if (BIO_printf(bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0) goto err;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	if (x->tlsext_tick_lifetime_hint)
+		{
+		if (BIO_printf(bp,
+			"\n    TLS session ticket lifetime hint: %ld (seconds)",
+			x->tlsext_tick_lifetime_hint) <=0)
+			goto err;
+		}
+	if (x->tlsext_tick)
+		{
+		if (BIO_puts(bp, "\n    TLS session ticket:\n") <= 0) goto err;
+		if (BIO_hexdump(bp, x->tlsext_tick, x->tlsext_ticklen, 4) <= 0)
+			goto err;
+		}
+#endif
+
+	if (x->time != 0L)
+		{
+		if (BIO_printf(bp, "\n    Start Time: %ld",x->time) <= 0) goto err;
+		}
+	if (x->timeout != 0L)
+		{
+		if (BIO_printf(bp, "\n    Timeout   : %ld (sec)",x->timeout) <= 0) goto err;
+		}
+	if (BIO_puts(bp,"\n") <= 0) goto err;
+
+	if (BIO_puts(bp, "    Verify return code: ") <= 0) goto err;
+	if (BIO_printf(bp, "%ld (%s)\n", x->verify_result,
+		X509_verify_cert_error_string(x->verify_result)) <= 0) goto err;
+		
+	return(1);
+err:
+	return(0);
+	}
diff --git a/ssl/t1_clnt.c b/ssl/t1_clnt.c
new file mode 100644
index 0000000..e83c79c
--- /dev/null
+++ b/ssl/t1_clnt.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/buf.h>
+#include <openssl/rand.h>
+#include <openssl/obj.h>
+#include <openssl/evp.h>
+
+#include "ssl_locl.h"
+
+
+static const SSL_METHOD *tls1_get_client_method(int ver);
+static const SSL_METHOD *tls1_get_client_method(int ver)
+	{
+	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();
+	return NULL;
+	}
+
+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)
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
new file mode 100644
index 0000000..a0bfda0
--- /dev/null
+++ b/ssl/t1_enc.c
@@ -0,0 +1,1237 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * 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 <assert.h>
+
+#include <openssl/comp.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
+			int sec_len,
+			const void *seed1, int seed1_len,
+			const void *seed2, int seed2_len,
+			const void *seed3, int seed3_len,
+			const void *seed4, int seed4_len,
+			const void *seed5, int seed5_len,
+			unsigned char *out, int olen)
+	{
+	int chunk;
+	size_t j;
+	EVP_MD_CTX ctx, ctx_tmp, ctx_init;
+	EVP_PKEY *mac_key;
+	unsigned char A1[EVP_MAX_MD_SIZE];
+	size_t A1_len;
+	int ret = 0;
+	
+	chunk=EVP_MD_size(md);
+
+	EVP_MD_CTX_init(&ctx);
+	EVP_MD_CTX_init(&ctx_tmp);
+	EVP_MD_CTX_init(&ctx_init);
+	mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
+	if (!mac_key)
+		goto err;
+	if (!EVP_DigestSignInit(&ctx_init,NULL,md, NULL, mac_key))
+		goto err;
+	if (!EVP_MD_CTX_copy_ex(&ctx,&ctx_init))
+		goto err;
+	if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
+		goto err;
+	if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
+		goto err;
+	if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
+		goto err;
+	if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
+		goto err;
+	if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
+		goto err;
+	if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
+		goto err;
+
+	for (;;)
+		{
+		/* Reinit mac contexts */
+		if (!EVP_MD_CTX_copy_ex(&ctx,&ctx_init))
+			goto err;
+		if (!EVP_DigestSignUpdate(&ctx,A1,A1_len))
+			goto err;
+		if (olen>chunk && !EVP_MD_CTX_copy_ex(&ctx_tmp,&ctx))
+			goto err;
+		if (seed1 && !EVP_DigestSignUpdate(&ctx,seed1,seed1_len))
+			goto err;
+		if (seed2 && !EVP_DigestSignUpdate(&ctx,seed2,seed2_len))
+			goto err;
+		if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
+			goto err;
+		if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
+			goto err;
+		if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
+			goto err;
+
+		if (olen > chunk)
+			{
+			if (!EVP_DigestSignFinal(&ctx,out,&j))
+				goto err;
+			out+=j;
+			olen-=j;
+			/* calc the next A1 value */
+			if (!EVP_DigestSignFinal(&ctx_tmp,A1,&A1_len))
+				goto err;
+			}
+		else	/* last one */
+			{
+			if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
+				goto err;
+			memcpy(out,A1,olen);
+			break;
+			}
+		}
+	ret = 1;
+err:
+	EVP_PKEY_free(mac_key);
+	EVP_MD_CTX_cleanup(&ctx);
+	EVP_MD_CTX_cleanup(&ctx_tmp);
+	EVP_MD_CTX_cleanup(&ctx_init);
+	OPENSSL_cleanse(A1,sizeof(A1));
+	return ret;
+	}
+
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_PRF(long digest_mask,
+		     const void *seed1, int seed1_len,
+		     const void *seed2, int seed2_len,
+		     const void *seed3, int seed3_len,
+		     const void *seed4, int seed4_len,
+		     const void *seed5, int seed5_len,
+		     const unsigned char *sec, int slen,
+		     unsigned char *out1,
+		     unsigned char *out2, int olen)
+	{
+	int len,i,idx,count;
+	const unsigned char *S1;
+	long m;
+	const EVP_MD *md;
+	int ret = 0;
+
+	/* Count number of digests and partition sec evenly */
+	count=0;
+	for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
+		if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++;
+	}	
+	len=slen/count;
+	if (count == 1)
+		slen = 0;
+	S1=sec;
+	memset(out1,0,olen);
+	for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) {
+		if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) {
+			if (!md) {
+				OPENSSL_PUT_ERROR(SSL, tls1_PRF, SSL_R_UNSUPPORTED_DIGEST_TYPE);
+				goto err;				
+			}
+			if (!tls1_P_hash(md ,S1,len+(slen&1),
+					seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+					out2,olen))
+				goto err;
+			S1+=len;
+			for (i=0; i<olen; i++)
+			{
+				out1[i]^=out2[i];
+			}
+		}
+	}
+	ret = 1;
+err:
+	return ret;
+}
+static int tls1_generate_key_block(SSL *s, unsigned char *km,
+	     unsigned char *tmp, int num)
+	{
+	int ret;
+	ret = tls1_PRF(ssl_get_algorithm2(s),
+		 TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
+		 s->s3->server_random,SSL3_RANDOM_SIZE,
+		 s->s3->client_random,SSL3_RANDOM_SIZE,
+		 NULL,0,NULL,0,
+		 s->session->master_key,s->session->master_key_length,
+		 km,tmp,num);
+#ifdef KSSL_DEBUG
+	printf("tls1_generate_key_block() ==> %d byte master_key =\n\t",
+                s->session->master_key_length);
+	{
+        int i;
+        for (i=0; i < s->session->master_key_length; i++)
+                {
+                printf("%02X", s->session->master_key[i]);
+                }
+        printf("\n");  }
+#endif    /* KSSL_DEBUG */
+	return ret;
+	}
+
+int tls1_change_cipher_state(SSL *s, int which)
+	{
+	static const unsigned char empty[]="";
+	unsigned char *p,*mac_secret;
+	unsigned char *exp_label;
+	unsigned char tmp1[EVP_MAX_KEY_LENGTH];
+	unsigned char tmp2[EVP_MAX_KEY_LENGTH];
+	unsigned char iv1[EVP_MAX_IV_LENGTH*2];
+	unsigned char iv2[EVP_MAX_IV_LENGTH*2];
+	unsigned char *ms,*key,*iv;
+	int client_write;
+	EVP_CIPHER_CTX *dd;
+	const EVP_CIPHER *c;
+	const EVP_MD *m;
+	int mac_type;
+	int *mac_secret_size;
+	EVP_MD_CTX *mac_ctx;
+	EVP_PKEY *mac_key;
+	int is_export,n,i,j,k,exp_label_len,cl;
+	int reuse_dd = 0;
+
+	is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
+	c=s->s3->tmp.new_sym_enc;
+	m=s->s3->tmp.new_hash;
+	mac_type = s->s3->tmp.new_mac_pkey_type;
+
+#ifdef KSSL_DEBUG
+	printf("tls1_change_cipher_state(which= %d) w/\n", which);
+	printf("\talg= %ld/%ld, comp= %p\n",
+	       s->s3->tmp.new_cipher->algorithm_mkey,
+	       s->s3->tmp.new_cipher->algorithm_auth,
+	       comp);
+	printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c);
+	printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n",
+                c->nid,c->block_size,c->key_len,c->iv_len);
+	printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length);
+	{
+        int i;
+        for (i=0; i<s->s3->tmp.key_block_length; i++)
+		printf("%02x", s->s3->tmp.key_block[i]);  printf("\n");
+        }
+#endif	/* KSSL_DEBUG */
+
+	if (which & SSL3_CC_READ)
+		{
+		if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+			s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
+		else
+			s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
+
+		if (s->enc_read_ctx != NULL)
+			reuse_dd = 1;
+		else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
+			goto err;
+		else
+			/* make sure it's intialized in case we exit later with an error */
+			EVP_CIPHER_CTX_init(s->enc_read_ctx);
+		dd= s->enc_read_ctx;
+		mac_ctx=ssl_replace_hash(&s->read_hash,NULL);
+		/* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ 		if (s->version != DTLS1_VERSION)
+			memset(&(s->s3->read_sequence[0]),0,8);
+		mac_secret= &(s->s3->read_mac_secret[0]);
+		mac_secret_size=&(s->s3->read_mac_secret_size);
+		}
+	else
+		{
+		if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+			s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
+			else
+			s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
+		if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s))
+			reuse_dd = 1;
+		else if ((s->enc_write_ctx=EVP_CIPHER_CTX_new()) == NULL)
+			goto err;
+		dd= s->enc_write_ctx;
+		if (SSL_IS_DTLS(s))
+			{
+			mac_ctx = EVP_MD_CTX_create();
+			if (!mac_ctx)
+				goto err;
+			s->write_hash = mac_ctx;
+			}
+		else
+			mac_ctx = ssl_replace_hash(&s->write_hash,NULL);
+		/* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ 		if (s->version != DTLS1_VERSION)
+			memset(&(s->s3->write_sequence[0]),0,8);
+		mac_secret= &(s->s3->write_mac_secret[0]);
+		mac_secret_size = &(s->s3->write_mac_secret_size);
+		}
+
+	if (reuse_dd)
+		EVP_CIPHER_CTX_cleanup(dd);
+
+	p=s->s3->tmp.key_block;
+	i=*mac_secret_size=s->s3->tmp.new_mac_secret_size;
+
+	cl=EVP_CIPHER_key_length(c);
+	j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
+	               cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
+	/* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
+	/* If GCM mode only part of IV comes from PRF */
+	if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+		k = EVP_GCM_TLS_FIXED_IV_LEN;
+	else
+		k=EVP_CIPHER_iv_length(c);
+	if (	(which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
+		(which == SSL3_CHANGE_CIPHER_SERVER_READ))
+		{
+		ms=  &(p[ 0]); n=i+i;
+		key= &(p[ n]); n+=j+j;
+		iv=  &(p[ n]); n+=k+k;
+		exp_label=(unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST;
+		exp_label_len=TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
+		client_write=1;
+		}
+	else
+		{
+		n=i;
+		ms=  &(p[ n]); n+=i+j;
+		key= &(p[ n]); n+=j+k;
+		iv=  &(p[ n]); n+=k;
+		exp_label=(unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST;
+		exp_label_len=TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
+		client_write=0;
+		}
+
+	if (n > s->s3->tmp.key_block_length)
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_INTERNAL_ERROR);
+		goto err2;
+		}
+
+	memcpy(mac_secret,ms,i);
+
+	if (!(EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER))
+		{
+		mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
+				mac_secret,*mac_secret_size);
+		EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
+		EVP_PKEY_free(mac_key);
+		}
+#ifdef TLS_DEBUG
+printf("which = %04X\nmac key=",which);
+{ int z; for (z=0; z<i; z++) printf("%02X%c",ms[z],((z+1)%16)?' ':'\n'); }
+#endif
+	if (is_export)
+		{
+		/* In here I set both the read and write key/iv to the
+		 * same value since only the correct one will be used :-).
+		 */
+		if (!tls1_PRF(ssl_get_algorithm2(s),
+				exp_label,exp_label_len,
+				s->s3->client_random,SSL3_RANDOM_SIZE,
+				s->s3->server_random,SSL3_RANDOM_SIZE,
+				NULL,0,NULL,0,
+				key,j,tmp1,tmp2,EVP_CIPHER_key_length(c)))
+			goto err2;
+		key=tmp1;
+
+		if (k > 0)
+			{
+			if (!tls1_PRF(ssl_get_algorithm2(s),
+					TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
+					s->s3->client_random,SSL3_RANDOM_SIZE,
+					s->s3->server_random,SSL3_RANDOM_SIZE,
+					NULL,0,NULL,0,
+					empty,0,iv1,iv2,k*2))
+				goto err2;
+			if (client_write)
+				iv=iv1;
+			else
+				iv= &(iv1[k]);
+			}
+		}
+
+	s->session->key_arg_length=0;
+#ifdef KSSL_DEBUG
+	{
+        int i;
+	printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n");
+	printf("\tkey= "); for (i=0; i<c->key_len; i++) printf("%02x", key[i]);
+	printf("\n");
+	printf("\t iv= "); for (i=0; i<c->iv_len; i++) printf("%02x", iv[i]);
+	printf("\n");
+	}
+#endif	/* KSSL_DEBUG */
+
+	if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+		{
+		EVP_CipherInit_ex(dd,c,NULL,key,NULL,(which & SSL3_CC_WRITE));
+		EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv);
+		}
+	else	
+		EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
+
+	/* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
+	if ((EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size)
+		EVP_CIPHER_CTX_ctrl(dd,EVP_CTRL_AEAD_SET_MAC_KEY,
+				*mac_secret_size,mac_secret);
+
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+	if (s->msg_callback)
+		{
+		int wh = which & SSL3_CC_WRITE ? TLS1_RT_CRYPTO_WRITE : 0;
+		if (*mac_secret_size)
+			s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_MAC,
+						mac_secret, *mac_secret_size,
+						s, s->msg_callback_arg);
+		if (c->key_len)
+			s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY,
+						key, c->key_len,
+						s, s->msg_callback_arg);
+		if (k)
+			{
+			if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
+				wh |= TLS1_RT_CRYPTO_FIXED_IV;
+			else
+				wh |= TLS1_RT_CRYPTO_IV;
+			s->msg_callback(2, s->version, wh, iv, k,
+						s, s->msg_callback_arg);
+			}
+		}
+#endif
+
+#ifdef TLS_DEBUG
+printf("which = %04X\nkey=",which);
+{ int z; for (z=0; z<EVP_CIPHER_key_length(c); z++) printf("%02X%c",key[z],((z+1)%16)?' ':'\n'); }
+printf("\niv=");
+{ int z; for (z=0; z<k; z++) printf("%02X%c",iv[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+	OPENSSL_cleanse(tmp1,sizeof(tmp1));
+	OPENSSL_cleanse(tmp2,sizeof(tmp1));
+	OPENSSL_cleanse(iv1,sizeof(iv1));
+	OPENSSL_cleanse(iv2,sizeof(iv2));
+	return(1);
+err:
+	OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state, ERR_R_MALLOC_FAILURE);
+err2:
+	return(0);
+	}
+
+int tls1_setup_key_block(SSL *s)
+	{
+	unsigned char *p1,*p2=NULL;
+	const EVP_CIPHER *c;
+	const EVP_MD *hash;
+	int num;
+	SSL_COMP *comp;
+	int mac_type= NID_undef,mac_secret_size=0;
+	int ret=0;
+
+#ifdef KSSL_DEBUG
+	printf ("tls1_setup_key_block()\n");
+#endif	/* KSSL_DEBUG */
+
+	if (s->s3->tmp.key_block_length != 0)
+		return(1);
+
+	if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp))
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+		return(0);
+		}
+
+	s->s3->tmp.new_sym_enc=c;
+	s->s3->tmp.new_hash=hash;
+	s->s3->tmp.new_mac_pkey_type = mac_type;
+	s->s3->tmp.new_mac_secret_size = mac_secret_size;
+	num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c);
+	num*=2;
+
+	ssl3_cleanup_key_block(s);
+
+	if ((p1=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	s->s3->tmp.key_block_length=num;
+	s->s3->tmp.key_block=p1;
+
+	if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+#ifdef TLS_DEBUG
+printf("client random\n");
+{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->client_random[z],((z+1)%16)?' ':'\n'); }
+printf("server random\n");
+{ int z; for (z=0; z<SSL3_RANDOM_SIZE; z++) printf("%02X%c",s->s3->server_random[z],((z+1)%16)?' ':'\n'); }
+printf("pre-master\n");
+{ int z; for (z=0; z<s->session->master_key_length; z++) printf("%02X%c",s->session->master_key[z],((z+1)%16)?' ':'\n'); }
+#endif
+	if (!tls1_generate_key_block(s,p1,p2,num))
+		goto err;
+#ifdef TLS_DEBUG
+printf("\nkey block\n");
+{ int z; for (z=0; z<num; z++) printf("%02X%c",p1[z],((z+1)%16)?' ':'\n'); }
+#endif
+
+	if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
+		&& s->method->version <= TLS1_VERSION)
+		{
+		/* enable vulnerability countermeasure for CBC ciphers with
+		 * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt)
+		 */
+		s->s3->need_empty_fragments = 1;
+
+		if (s->session->cipher != NULL)
+			{
+			if (s->session->cipher->algorithm_enc == SSL_eNULL)
+				s->s3->need_empty_fragments = 0;
+			
+#ifndef OPENSSL_NO_RC4
+			if (s->session->cipher->algorithm_enc == SSL_RC4)
+				s->s3->need_empty_fragments = 0;
+#endif
+			}
+		}
+		
+	ret = 1;
+err:
+	if (p2)
+		{
+		OPENSSL_cleanse(p2,num);
+		OPENSSL_free(p2);
+		}
+	return(ret);
+	}
+
+/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publically invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
+ *       an internal error occured.
+ */
+int tls1_enc(SSL *s, int send)
+	{
+	SSL3_RECORD *rec;
+	EVP_CIPHER_CTX *ds;
+	unsigned long l;
+	int bs,i,j,k,pad=0,ret,mac_size=0;
+	const EVP_CIPHER *enc;
+
+	if (send)
+		{
+		ds=s->enc_write_ctx;
+		rec= &(s->s3->wrec);
+		if (s->enc_write_ctx == NULL)
+			enc=NULL;
+		else
+			{
+			int ivlen;
+			enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+			/* For TLSv1.1 and later explicit IV */
+			if (SSL_USE_EXPLICIT_IV(s)
+				&& EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE)
+				ivlen = EVP_CIPHER_iv_length(enc);
+			else
+				ivlen = 0;
+			if (ivlen > 1)
+				{
+				if ( rec->data != rec->input)
+					/* we can't write into the input stream:
+					 * Can this ever happen?? (steve)
+					 */
+					fprintf(stderr,
+						"%s:%d: rec->data != rec->input\n",
+						__FILE__, __LINE__);
+				else if (RAND_bytes(rec->input, ivlen) <= 0)
+					return -1;
+				}
+			}
+		}
+	else
+		{
+		ds=s->enc_read_ctx;
+		rec= &(s->s3->rrec);
+		if (s->enc_read_ctx == NULL)
+			enc=NULL;
+		else
+			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+		}
+
+#ifdef KSSL_DEBUG
+	printf("tls1_enc(%d)\n", send);
+#endif    /* KSSL_DEBUG */
+
+	if ((s->session == NULL) || (ds == NULL) || (enc == NULL))
+		{
+		memmove(rec->data,rec->input,rec->length);
+		rec->input=rec->data;
+		ret = 1;
+		}
+	else
+		{
+		l=rec->length;
+		bs=EVP_CIPHER_block_size(ds->cipher);
+
+		if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
+			{
+			unsigned char buf[13],*seq;
+
+			seq = send?s->s3->write_sequence:s->s3->read_sequence;
+
+			if (SSL_IS_DTLS(s))
+				{
+				unsigned char dtlsseq[9],*p=dtlsseq;
+
+				s2n(send?s->d1->w_epoch:s->d1->r_epoch,p);
+				memcpy(p,&seq[2],6);
+				memcpy(buf,dtlsseq,8);
+				}
+			else
+				{
+				memcpy(buf,seq,8);
+				for (i=7; i>=0; i--)	/* increment */
+					{
+					++seq[i];
+					if (seq[i] != 0) break; 
+					}
+				}
+
+			buf[8]=rec->type;
+			buf[9]=(unsigned char)(s->version>>8);
+			buf[10]=(unsigned char)(s->version);
+			buf[11]=rec->length>>8;
+			buf[12]=rec->length&0xff;
+			pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf);
+			if (send)
+				{
+				l+=pad;
+				rec->length+=pad;
+				}
+			}
+		else if ((bs != 1) && send)
+			{
+			i=bs-((int)l%bs);
+
+			/* Add weird padding of upto 256 bytes */
+
+			/* we need to add 'i' padding bytes of value j */
+			j=i-1;
+			if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
+				{
+				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+					j++;
+				}
+			for (k=(int)l; k<(int)(l+i); k++)
+				rec->input[k]=j;
+			l+=i;
+			rec->length+=i;
+			}
+
+#ifdef KSSL_DEBUG
+		{
+		unsigned long ui;
+		printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
+			ds,rec->data,rec->input,l);
+		printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
+			ds->buf_len, ds->cipher->key_len,
+			DES_KEY_SZ, DES_SCHEDULE_SZ,
+			ds->cipher->iv_len);
+		printf("\t\tIV: ");
+		for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
+		printf("\n");
+		printf("\trec->input=");
+		for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
+		printf("\n");
+		}
+#endif	/* KSSL_DEBUG */
+
+		if (!send)
+			{
+			if (l == 0 || l%bs != 0)
+				return 0;
+			}
+		
+		i = EVP_Cipher(ds,rec->data,rec->input,l);
+		if ((EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_CUSTOM_CIPHER)
+						?(i<0)
+						:(i==0))
+			return -1;	/* AEAD can fail to verify MAC */
+		if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send)
+			{
+			rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+			rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+			rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+			}
+
+#ifdef KSSL_DEBUG
+		{
+		unsigned long i;
+		printf("\trec->data=");
+		for (i=0; i<l; i++)
+			printf(" %02x", rec->data[i]);  printf("\n");
+		}
+#endif	/* KSSL_DEBUG */
+
+		ret = 1;
+		if (EVP_MD_CTX_md(s->read_hash) != NULL)
+			mac_size = EVP_MD_CTX_size(s->read_hash);
+		if ((bs != 1) && !send)
+			ret = tls1_cbc_remove_padding(s, rec, bs, mac_size);
+		if (pad && !send)
+			rec->length -= pad;
+		}
+	return ret;
+	}
+
+int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
+	{
+	unsigned int ret;
+	EVP_MD_CTX ctx, *d=NULL;
+	int i;
+
+	if (s->s3->handshake_buffer) 
+		if (!ssl3_digest_cached_records(s))
+			return 0;
+
+	for (i=0;i<SSL_MAX_DIGEST;i++) 
+		{
+		  if (s->s3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid) 
+		  	{
+		  	d=s->s3->handshake_dgst[i];
+			break;
+			}
+		}
+	if (!d) {
+		OPENSSL_PUT_ERROR(SSL, tls1_cert_verify_mac, SSL_R_NO_REQUIRED_DIGEST);
+		return 0;
+	}	
+
+	EVP_MD_CTX_init(&ctx);
+	EVP_MD_CTX_copy_ex(&ctx,d);
+	EVP_DigestFinal_ex(&ctx,out,&ret);
+	EVP_MD_CTX_cleanup(&ctx);
+	return((int)ret);
+	}
+
+int tls1_final_finish_mac(SSL *s,
+	     const char *str, int slen, unsigned char *out)
+	{
+	unsigned int i;
+	EVP_MD_CTX ctx;
+	unsigned char buf[2*EVP_MAX_MD_SIZE];
+	unsigned char *q,buf2[12];
+	int idx;
+	long mask;
+	int err=0;
+	const EVP_MD *md; 
+
+	q=buf;
+
+	if (s->s3->handshake_buffer) 
+		if (!ssl3_digest_cached_records(s))
+			return 0;
+
+	EVP_MD_CTX_init(&ctx);
+
+	for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
+		{
+		if (mask & ssl_get_algorithm2(s))
+			{
+			int hashsize = EVP_MD_size(md);
+			EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
+			if (!hdgst || hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf)))
+				{
+				/* internal error: 'buf' is too small for this cipersuite! */
+				err = 1;
+				}
+			else
+				{
+				if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) ||
+					!EVP_DigestFinal_ex(&ctx,q,&i) ||
+					(i != (unsigned int)hashsize))
+					err = 1;
+				q+=hashsize;
+				}
+			}
+		}
+		
+	if (!tls1_PRF(ssl_get_algorithm2(s),
+			str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
+			s->session->master_key,s->session->master_key_length,
+			out,buf2,sizeof buf2))
+		err = 1;
+	EVP_MD_CTX_cleanup(&ctx);
+
+	if (err)
+		return 0;
+	else
+		return sizeof buf2;
+	}
+
+int tls1_mac(SSL *ssl, unsigned char *md, int send)
+	{
+	SSL3_RECORD *rec;
+	unsigned char *seq;
+	EVP_MD_CTX *hash;
+	size_t md_size, orig_len;
+	int i;
+	EVP_MD_CTX hmac, *mac_ctx;
+	unsigned char header[13];
+	int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM));
+	int t;
+
+	if (send)
+		{
+		rec= &(ssl->s3->wrec);
+		seq= &(ssl->s3->write_sequence[0]);
+		hash=ssl->write_hash;
+		}
+	else
+		{
+		rec= &(ssl->s3->rrec);
+		seq= &(ssl->s3->read_sequence[0]);
+		hash=ssl->read_hash;
+		}
+
+	t=EVP_MD_CTX_size(hash);
+	assert(t >= 0);
+	md_size=t;
+
+	/* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
+	if (stream_mac) 
+		{
+			mac_ctx = hash;
+		}
+		else
+		{
+			EVP_MD_CTX_copy(&hmac,hash);
+			mac_ctx = &hmac;
+		}
+
+	if (SSL_IS_DTLS(ssl))
+		{
+		unsigned char dtlsseq[8],*p=dtlsseq;
+
+		s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
+		memcpy (p,&seq[2],6);
+
+		memcpy(header, dtlsseq, 8);
+		}
+	else
+		memcpy(header, seq, 8);
+
+	/* kludge: tls1_cbc_remove_padding passes padding length in rec->type */
+	orig_len = rec->length+md_size+((unsigned int)rec->type>>8);
+	rec->type &= 0xff;
+
+	header[8]=rec->type;
+	header[9]=(unsigned char)(ssl->version>>8);
+	header[10]=(unsigned char)(ssl->version);
+	header[11]=(rec->length)>>8;
+	header[12]=(rec->length)&0xff;
+
+	if (!send &&
+	    EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+	    ssl3_cbc_record_digest_supported(mac_ctx))
+		{
+		/* This is a CBC-encrypted record. We must avoid leaking any
+		 * timing-side channel information about how many blocks of
+		 * data we are hashing because that gives an attacker a
+		 * timing-oracle. */
+		ssl3_cbc_digest_record(
+			mac_ctx,
+			md, &md_size,
+			header, rec->input,
+			rec->length + md_size, orig_len,
+			ssl->s3->read_mac_secret,
+			ssl->s3->read_mac_secret_size,
+			0 /* not SSLv3 */);
+		}
+	else
+		{
+		EVP_DigestSignUpdate(mac_ctx,header,sizeof(header));
+		EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
+		t=EVP_DigestSignFinal(mac_ctx,md,&md_size);
+		assert(t > 0);
+#ifdef OPENSSL_FIPS
+		if (!send && FIPS_mode())
+			tls_fips_digest_extra(
+	    				ssl->enc_read_ctx,
+					mac_ctx, rec->input,
+					rec->length, orig_len);
+#endif
+		}
+		
+	if (!stream_mac)
+		EVP_MD_CTX_cleanup(&hmac);
+#ifdef TLS_DEBUG
+printf("sec=");
+{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); }
+printf("seq=");
+{int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); }
+printf("buf=");
+{int z; for (z=0; z<5; z++) printf("%02X ",buf[z]); printf("\n"); }
+printf("rec=");
+{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
+#endif
+
+	if (!SSL_IS_DTLS(ssl))
+		{
+		for (i=7; i>=0; i--)
+			{
+			++seq[i];
+			if (seq[i] != 0) break; 
+			}
+		}
+
+#ifdef TLS_DEBUG
+{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",md[z]); printf("\n"); }
+#endif
+	return(md_size);
+	}
+
+int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+	     int len)
+	{
+	unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
+	const void *co = NULL, *so = NULL;
+	int col = 0, sol = 0;
+
+
+#ifdef KSSL_DEBUG
+	printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
+#endif	/* KSSL_DEBUG */
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL &&
+	    s->s3->client_opaque_prf_input_len > 0 &&
+	    s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len)
+		{
+		co = s->s3->client_opaque_prf_input;
+		col = s->s3->server_opaque_prf_input_len;
+		so = s->s3->server_opaque_prf_input;
+		sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */
+		}
+#endif
+
+	tls1_PRF(ssl_get_algorithm2(s),
+		TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
+		s->s3->client_random,SSL3_RANDOM_SIZE,
+		co, col,
+		s->s3->server_random,SSL3_RANDOM_SIZE,
+		so, sol,
+		p,len,
+		s->session->master_key,buff,sizeof buff);
+#ifdef SSL_DEBUG
+	fprintf(stderr, "Premaster Secret:\n");
+	BIO_dump_fp(stderr, (char *)p, len);
+	fprintf(stderr, "Client Random:\n");
+	BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
+	fprintf(stderr, "Server Random:\n");
+	BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
+	fprintf(stderr, "Master Secret:\n");
+	BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE);
+#endif
+
+#ifdef OPENSSL_SSL_TRACE_CRYPTO
+	if (s->msg_callback)
+		{
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_PREMASTER,
+						p, len, s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_CLIENT_RANDOM,
+					s->s3->client_random, SSL3_RANDOM_SIZE,
+						s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_SERVER_RANDOM,
+					s->s3->server_random, SSL3_RANDOM_SIZE,
+					s, s->msg_callback_arg);
+		s->msg_callback(2, s->version, TLS1_RT_CRYPTO_MASTER,
+					s->session->master_key,
+					SSL3_MASTER_SECRET_SIZE,
+					s, s->msg_callback_arg);
+		}
+#endif
+
+#ifdef KSSL_DEBUG
+	printf ("tls1_generate_master_secret() complete\n");
+#endif	/* KSSL_DEBUG */
+	return(SSL3_MASTER_SECRET_SIZE);
+	}
+
+int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+	 const char *label, size_t llen, const unsigned char *context,
+	 size_t contextlen, int use_context)
+	{
+	unsigned char *buff;
+	unsigned char *val = NULL;
+	size_t vallen, currentvalpos;
+	int rv;
+
+#ifdef KSSL_DEBUG
+	printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen);
+#endif	/* KSSL_DEBUG */
+
+	buff = OPENSSL_malloc(olen);
+	if (buff == NULL) goto err2;
+
+	/* construct PRF arguments
+	 * we construct the PRF argument ourself rather than passing separate
+	 * values into the TLS PRF to ensure that the concatenation of values
+	 * does not create a prohibited label.
+	 */
+	vallen = llen + SSL3_RANDOM_SIZE * 2;
+	if (use_context)
+		{
+		vallen += 2 + contextlen;
+		}
+
+	val = OPENSSL_malloc(vallen);
+	if (val == NULL) goto err2;
+	currentvalpos = 0;
+	memcpy(val + currentvalpos, (unsigned char *) label, llen);
+	currentvalpos += llen;
+	memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE);
+	currentvalpos += SSL3_RANDOM_SIZE;
+	memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE);
+	currentvalpos += SSL3_RANDOM_SIZE;
+
+	if (use_context)
+		{
+		val[currentvalpos] = (contextlen >> 8) & 0xff;
+		currentvalpos++;
+		val[currentvalpos] = contextlen & 0xff;
+		currentvalpos++;
+		if ((contextlen > 0) || (context != NULL))
+			{
+			memcpy(val + currentvalpos, context, contextlen);
+			}
+		}
+
+	/* disallow prohibited labels
+	 * note that SSL3_RANDOM_SIZE > max(prohibited label len) =
+	 * 15, so size of val > max(prohibited label len) = 15 and the
+	 * comparisons won't have buffer overflow
+	 */
+	if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST,
+		 TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) goto err1;
+	if (memcmp(val, TLS_MD_SERVER_FINISH_CONST,
+		 TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) goto err1;
+	if (memcmp(val, TLS_MD_MASTER_SECRET_CONST,
+		 TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) goto err1;
+	if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST,
+		 TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) goto err1;
+
+	rv = tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+		      val, vallen,
+		      NULL, 0,
+		      NULL, 0,
+		      NULL, 0,
+		      NULL, 0,
+		      s->session->master_key,s->session->master_key_length,
+		      out,buff,olen);
+
+#ifdef KSSL_DEBUG
+	printf ("tls1_export_keying_material() complete\n");
+#endif	/* KSSL_DEBUG */
+	goto ret;
+err1:
+	OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
+	rv = 0;
+	goto ret;
+err2:
+	OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, ERR_R_MALLOC_FAILURE);
+	rv = 0;
+ret:
+	if (buff != NULL) OPENSSL_free(buff);
+	if (val != NULL) OPENSSL_free(val);
+	return(rv);
+	}
+
+int tls1_alert_code(int code)
+	{
+	switch (code)
+		{
+	case SSL_AD_CLOSE_NOTIFY:	return(SSL3_AD_CLOSE_NOTIFY);
+	case SSL_AD_UNEXPECTED_MESSAGE:	return(SSL3_AD_UNEXPECTED_MESSAGE);
+	case SSL_AD_BAD_RECORD_MAC:	return(SSL3_AD_BAD_RECORD_MAC);
+	case SSL_AD_DECRYPTION_FAILED:	return(TLS1_AD_DECRYPTION_FAILED);
+	case SSL_AD_RECORD_OVERFLOW:	return(TLS1_AD_RECORD_OVERFLOW);
+	case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE);
+	case SSL_AD_HANDSHAKE_FAILURE:	return(SSL3_AD_HANDSHAKE_FAILURE);
+	case SSL_AD_NO_CERTIFICATE:	return(-1);
+	case SSL_AD_BAD_CERTIFICATE:	return(SSL3_AD_BAD_CERTIFICATE);
+	case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE);
+	case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED);
+	case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED);
+	case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN);
+	case SSL_AD_ILLEGAL_PARAMETER:	return(SSL3_AD_ILLEGAL_PARAMETER);
+	case SSL_AD_UNKNOWN_CA:		return(TLS1_AD_UNKNOWN_CA);
+	case SSL_AD_ACCESS_DENIED:	return(TLS1_AD_ACCESS_DENIED);
+	case SSL_AD_DECODE_ERROR:	return(TLS1_AD_DECODE_ERROR);
+	case SSL_AD_DECRYPT_ERROR:	return(TLS1_AD_DECRYPT_ERROR);
+	case SSL_AD_EXPORT_RESTRICTION:	return(TLS1_AD_EXPORT_RESTRICTION);
+	case SSL_AD_PROTOCOL_VERSION:	return(TLS1_AD_PROTOCOL_VERSION);
+	case SSL_AD_INSUFFICIENT_SECURITY:return(TLS1_AD_INSUFFICIENT_SECURITY);
+	case SSL_AD_INTERNAL_ERROR:	return(TLS1_AD_INTERNAL_ERROR);
+	case SSL_AD_USER_CANCELLED:	return(TLS1_AD_USER_CANCELLED);
+	case SSL_AD_NO_RENEGOTIATION:	return(TLS1_AD_NO_RENEGOTIATION);
+	case SSL_AD_UNSUPPORTED_EXTENSION: return(TLS1_AD_UNSUPPORTED_EXTENSION);
+	case SSL_AD_CERTIFICATE_UNOBTAINABLE: return(TLS1_AD_CERTIFICATE_UNOBTAINABLE);
+	case SSL_AD_UNRECOGNIZED_NAME:	return(TLS1_AD_UNRECOGNIZED_NAME);
+	case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE);
+	case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE);
+	case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY);
+#if 0 /* not appropriate for TLS, not used for DTLS */
+	case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return 
+					  (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+#endif
+	default:			return(-1);
+		}
+	}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
new file mode 100644
index 0000000..644d70b
--- /dev/null
+++ b/ssl/t1_lib.c
@@ -0,0 +1,4593 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+#include "ssl_locl.h"
+#ifndef OPENSSL_NO_TLSEXT
+static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
+				const unsigned char *sess_id, int sesslen,
+				SSL_SESSION **psess);
+static int ssl_check_clienthello_tlsext_early(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
+#endif
+
+SSL3_ENC_METHOD TLSv1_enc_data={
+	tls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	tls1_export_keying_material,
+	0,
+	SSL3_HM_HEADER_LENGTH,
+	ssl3_set_handshake_header,
+	ssl3_handshake_write
+	};
+
+SSL3_ENC_METHOD TLSv1_1_enc_data={
+	tls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	tls1_export_keying_material,
+	SSL_ENC_FLAG_EXPLICIT_IV,
+	SSL3_HM_HEADER_LENGTH,
+	ssl3_set_handshake_header,
+	ssl3_handshake_write
+	};
+
+SSL3_ENC_METHOD TLSv1_2_enc_data={
+	tls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	tls1_export_keying_material,
+	SSL_ENC_FLAG_EXPLICIT_IV|SSL_ENC_FLAG_SIGALGS|SSL_ENC_FLAG_SHA256_PRF
+		|SSL_ENC_FLAG_TLS1_2_CIPHERS,
+	SSL3_HM_HEADER_LENGTH,
+	ssl3_set_handshake_header,
+	ssl3_handshake_write
+	};
+
+long tls1_default_timeout(void)
+	{
+	/* 2 hours, the 24 hours mentioned in the TLSv1 spec
+	 * is way too long for http, the cache would over fill */
+	return(60*60*2);
+	}
+
+int tls1_new(SSL *s)
+	{
+	if (!ssl3_new(s)) return(0);
+	s->method->ssl_clear(s);
+	return(1);
+	}
+
+void tls1_free(SSL *s)
+	{
+#ifndef OPENSSL_NO_TLSEXT
+	if (s->tlsext_session_ticket)
+		{
+		OPENSSL_free(s->tlsext_session_ticket);
+		}
+#endif /* OPENSSL_NO_TLSEXT */
+	ssl3_free(s);
+	}
+
+void tls1_clear(SSL *s)
+	{
+	ssl3_clear(s);
+	s->version = s->method->version;
+	}
+
+#ifndef OPENSSL_NO_EC
+
+static int nid_list[] =
+	{
+		NID_sect163k1, /* sect163k1 (1) */
+		NID_sect163r1, /* sect163r1 (2) */
+		NID_sect163r2, /* sect163r2 (3) */
+		NID_sect193r1, /* sect193r1 (4) */ 
+		NID_sect193r2, /* sect193r2 (5) */ 
+		NID_sect233k1, /* sect233k1 (6) */
+		NID_sect233r1, /* sect233r1 (7) */ 
+		NID_sect239k1, /* sect239k1 (8) */ 
+		NID_sect283k1, /* sect283k1 (9) */
+		NID_sect283r1, /* sect283r1 (10) */ 
+		NID_sect409k1, /* sect409k1 (11) */ 
+		NID_sect409r1, /* sect409r1 (12) */
+		NID_sect571k1, /* sect571k1 (13) */ 
+		NID_sect571r1, /* sect571r1 (14) */ 
+		NID_secp160k1, /* secp160k1 (15) */
+		NID_secp160r1, /* secp160r1 (16) */ 
+		NID_secp160r2, /* secp160r2 (17) */ 
+		NID_secp192k1, /* secp192k1 (18) */
+		NID_X9_62_prime192v1, /* secp192r1 (19) */ 
+		NID_secp224k1, /* secp224k1 (20) */ 
+		NID_secp224r1, /* secp224r1 (21) */
+		NID_secp256k1, /* secp256k1 (22) */ 
+		NID_X9_62_prime256v1, /* secp256r1 (23) */ 
+		NID_secp384r1, /* secp384r1 (24) */
+		NID_secp521r1,  /* secp521r1 (25) */	
+		NID_brainpoolP256r1,  /* brainpoolP256r1 (26) */	
+		NID_brainpoolP384r1,  /* brainpoolP384r1 (27) */	
+		NID_brainpoolP512r1  /* brainpool512r1 (28) */	
+	};
+
+
+static const unsigned char ecformats_default[] = 
+	{
+	TLSEXT_ECPOINTFORMAT_uncompressed,
+	TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+	TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+	};
+
+static const unsigned char eccurves_default[] =
+	{
+		0,14, /* sect571r1 (14) */ 
+		0,13, /* sect571k1 (13) */ 
+		0,25, /* secp521r1 (25) */	
+		0,28, /* brainpool512r1 (28) */	
+		0,11, /* sect409k1 (11) */ 
+		0,12, /* sect409r1 (12) */
+		0,27, /* brainpoolP384r1 (27) */	
+		0,24, /* secp384r1 (24) */
+		0,9,  /* sect283k1 (9) */
+		0,10, /* sect283r1 (10) */ 
+		0,26, /* brainpoolP256r1 (26) */	
+		0,22, /* secp256k1 (22) */ 
+		0,23, /* secp256r1 (23) */ 
+		0,8,  /* sect239k1 (8) */ 
+		0,6,  /* sect233k1 (6) */
+		0,7,  /* sect233r1 (7) */ 
+		0,20, /* secp224k1 (20) */ 
+		0,21, /* secp224r1 (21) */
+		0,4,  /* sect193r1 (4) */ 
+		0,5,  /* sect193r2 (5) */ 
+		0,18, /* secp192k1 (18) */
+		0,19, /* secp192r1 (19) */ 
+		0,1,  /* sect163k1 (1) */
+		0,2,  /* sect163r1 (2) */
+		0,3,  /* sect163r2 (3) */
+		0,15, /* secp160k1 (15) */
+		0,16, /* secp160r1 (16) */ 
+		0,17, /* secp160r2 (17) */ 
+	};
+
+static const unsigned char suiteb_curves[] =
+	{
+		0, TLSEXT_curve_P_256,
+		0, TLSEXT_curve_P_384
+	};
+
+int tls1_ec_curve_id2nid(int curve_id)
+	{
+	/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+	if ((curve_id < 1) || ((unsigned int)curve_id >
+				sizeof(nid_list)/sizeof(nid_list[0])))
+		return 0;
+	return nid_list[curve_id-1];
+	}
+
+int tls1_ec_nid2curve_id(int nid)
+	{
+	/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+	switch (nid)
+		{
+	case NID_sect163k1: /* sect163k1 (1) */
+		return 1;
+	case NID_sect163r1: /* sect163r1 (2) */
+		return 2;
+	case NID_sect163r2: /* sect163r2 (3) */
+		return 3;
+	case NID_sect193r1: /* sect193r1 (4) */ 
+		return 4;
+	case NID_sect193r2: /* sect193r2 (5) */ 
+		return 5;
+	case NID_sect233k1: /* sect233k1 (6) */
+		return 6;
+	case NID_sect233r1: /* sect233r1 (7) */ 
+		return 7;
+	case NID_sect239k1: /* sect239k1 (8) */ 
+		return 8;
+	case NID_sect283k1: /* sect283k1 (9) */
+		return 9;
+	case NID_sect283r1: /* sect283r1 (10) */ 
+		return 10;
+	case NID_sect409k1: /* sect409k1 (11) */ 
+		return 11;
+	case NID_sect409r1: /* sect409r1 (12) */
+		return 12;
+	case NID_sect571k1: /* sect571k1 (13) */ 
+		return 13;
+	case NID_sect571r1: /* sect571r1 (14) */ 
+		return 14;
+	case NID_secp160k1: /* secp160k1 (15) */
+		return 15;
+	case NID_secp160r1: /* secp160r1 (16) */ 
+		return 16;
+	case NID_secp160r2: /* secp160r2 (17) */ 
+		return 17;
+	case NID_secp192k1: /* secp192k1 (18) */
+		return 18;
+	case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+		return 19;
+	case NID_secp224k1: /* secp224k1 (20) */ 
+		return 20;
+	case NID_secp224r1: /* secp224r1 (21) */
+		return 21;
+	case NID_secp256k1: /* secp256k1 (22) */ 
+		return 22;
+	case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+		return 23;
+	case NID_secp384r1: /* secp384r1 (24) */
+		return 24;
+	case NID_secp521r1:  /* secp521r1 (25) */	
+		return 25;
+	case NID_brainpoolP256r1:  /* brainpoolP256r1 (26) */
+		return 26;
+	case NID_brainpoolP384r1:  /* brainpoolP384r1 (27) */
+		return 27;
+	case NID_brainpoolP512r1:  /* brainpool512r1 (28) */
+		return 28;
+	default:
+		return 0;
+		}
+	}
+/* Get curves list, if "sess" is set return client curves otherwise
+ * preferred list
+ */
+static void tls1_get_curvelist(SSL *s, int sess,
+					const unsigned char **pcurves,
+					size_t *pcurveslen)
+	{
+	if (sess)
+		{
+		*pcurves = s->session->tlsext_ellipticcurvelist;
+		*pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+		return;
+		}
+	/* For Suite B mode only include P-256, P-384 */
+	switch (tls1_suiteb(s))
+		{
+	case SSL_CERT_FLAG_SUITEB_128_LOS:
+		*pcurves = suiteb_curves;
+		*pcurveslen = sizeof(suiteb_curves);
+		break;
+
+	case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+		*pcurves = suiteb_curves;
+		*pcurveslen = 2;
+		break;
+
+	case SSL_CERT_FLAG_SUITEB_192_LOS:
+		*pcurves = suiteb_curves + 2;
+		*pcurveslen = 2;
+		break;
+	default:
+		*pcurves = s->tlsext_ellipticcurvelist;
+		*pcurveslen = s->tlsext_ellipticcurvelist_length;
+		}
+	if (!*pcurves)
+		{
+		*pcurves = eccurves_default;
+		*pcurveslen = sizeof(eccurves_default);
+		}
+	}
+/* Check a curve is one of our preferences */
+int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
+	{
+	const unsigned char *curves;
+	size_t curveslen, i;
+	unsigned int suiteb_flags = tls1_suiteb(s);
+	if (len != 3 || p[0] != NAMED_CURVE_TYPE)
+		return 0;
+	/* Check curve matches Suite B preferences */
+	if (suiteb_flags)
+		{
+		unsigned long cid = s->s3->tmp.new_cipher->id;
+		if (p[1])
+			return 0;
+		if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+			{
+			if (p[2] != TLSEXT_curve_P_256)
+				return 0;
+			}
+		else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+			{
+			if (p[2] != TLSEXT_curve_P_384)
+				return 0;
+			}
+		else	/* Should never happen */
+			return 0;
+		}
+	tls1_get_curvelist(s, 0, &curves, &curveslen);
+	for (i = 0; i < curveslen; i += 2, curves += 2)
+		{
+		if (p[1] == curves[0] && p[2] == curves[1])
+			return 1;
+		}
+	return 0;
+	}
+
+/* Return nth shared curve. If nmatch == -1 return number of
+ * matches. For nmatch == -2 return the NID of the curve to use for
+ * an EC tmp key.
+ */
+
+int tls1_shared_curve(SSL *s, int nmatch)
+	{
+	const unsigned char *pref, *supp;
+	size_t preflen, supplen, i, j;
+	int k;
+	/* Can't do anything on client side */
+	if (s->server == 0)
+		return -1;
+	if (nmatch == -2)
+		{
+		if (tls1_suiteb(s))
+			{
+			/* For Suite B ciphersuite determines curve: we 
+			 * already know these are acceptable due to previous
+			 * checks.
+			 */
+			unsigned long cid = s->s3->tmp.new_cipher->id;
+			if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+				return NID_X9_62_prime256v1; /* P-256 */
+			if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+				return NID_secp384r1; /* P-384 */
+			/* Should never happen */
+			return NID_undef;
+			}
+		/* If not Suite B just return first preference shared curve */
+		nmatch = 0;
+		}
+	tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+				&supp, &supplen);
+	tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+				&pref, &preflen);
+	preflen /= 2;
+	supplen /= 2;
+	k = 0;
+	for (i = 0; i < preflen; i++, pref+=2)
+		{
+		const unsigned char *tsupp = supp;
+		for (j = 0; j < supplen; j++, tsupp+=2)
+			{
+			if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
+				{
+				if (nmatch == k)
+					{
+					int id = (pref[0] << 8) | pref[1];
+					return tls1_ec_curve_id2nid(id);
+					}
+				k++;
+				}
+			}
+		}
+	if (nmatch == -1)
+		return k;
+	return 0;
+	}
+
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+			int *curves, size_t ncurves)
+	{
+	unsigned char *clist, *p;
+	size_t i;
+	/* Bitmap of curves included to detect duplicates: only works
+	 * while curve ids < 32 
+	 */
+	unsigned long dup_list = 0;
+	clist = OPENSSL_malloc(ncurves * 2);
+	if (!clist)
+		return 0;
+	for (i = 0, p = clist; i < ncurves; i++)
+		{
+		unsigned long idmask;
+		int id;
+		id = tls1_ec_nid2curve_id(curves[i]);
+		idmask = 1L << id;
+		if (!id || (dup_list & idmask))
+			{
+			OPENSSL_free(clist);
+			return 0;
+			}
+		dup_list |= idmask;
+		s2n(id, p);
+		}
+	if (*pext)
+		OPENSSL_free(*pext);
+	*pext = clist;
+	*pextlen = ncurves * 2;
+	return 1;
+	}
+
+/* TODO(fork): remove */
+#if 0
+#define MAX_CURVELIST	28
+
+typedef struct
+	{
+	size_t nidcnt;
+	int nid_arr[MAX_CURVELIST];
+	} nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+	{
+	nid_cb_st *narg = arg;
+	size_t i;
+	int nid;
+	char etmp[20];
+	if (narg->nidcnt == MAX_CURVELIST)
+		return 0;
+	if (len > (int)(sizeof(etmp) - 1))
+		return 0;
+	memcpy(etmp, elem, len);
+	etmp[len] = 0;
+	nid = EC_curve_nist2nid(etmp);
+	if (nid == NID_undef)
+		nid = OBJ_sn2nid(etmp);
+	if (nid == NID_undef)
+		nid = OBJ_ln2nid(etmp);
+	if (nid == NID_undef)
+		return 0;
+	for (i = 0; i < narg->nidcnt; i++)
+		if (narg->nid_arr[i] == nid)
+			return 0;
+	narg->nid_arr[narg->nidcnt++] = nid;
+	return 1;
+	}
+/* Set curves based on a colon separate list */
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
+				const char *str)
+	{
+	nid_cb_st ncb;
+	ncb.nidcnt = 0;
+	if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
+		return 0;
+	if (pext == NULL)
+		return 1;
+	return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
+	}
+#endif
+
+/* For an EC key set TLS id and required compression based on parameters */
+static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id,
+				EC_KEY *ec)
+	{
+	int is_prime = 1, id;
+	const EC_GROUP *grp;
+	if (!ec)
+		return 0;
+
+        /* TODO(fork): remove. All curves are prime now. */
+	grp = EC_KEY_get0_group(ec);
+	if (!grp)
+		return 0;
+#if 0
+	/* Determine if it is a prime field */
+        meth = EC_GROUP_method_of(grp);
+	if (!meth)
+		return 0;
+        if (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field)
+		is_prime = 1;
+	else
+		is_prime = 0;
+#endif
+
+	/* Determine curve ID */
+	id = EC_GROUP_get_curve_name(grp);
+	id = tls1_ec_nid2curve_id(id);
+	/* If we have an ID set it, otherwise set arbitrary explicit curve */
+	if (id)
+		{
+		curve_id[0] = 0;
+		curve_id[1] = (unsigned char)id;
+		}
+	else
+		{
+		curve_id[0] = 0xff;
+		if (is_prime)
+			curve_id[1] = 0x01;
+		else
+			curve_id[1] = 0x02;
+		}
+	if (comp_id)
+		{
+        	if (EC_KEY_get0_public_key(ec) == NULL)
+			return 0;
+		if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED)
+			{
+			if (is_prime)
+				*comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+			else
+				*comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+			}
+		else
+			*comp_id = TLSEXT_ECPOINTFORMAT_uncompressed;
+		}
+	return 1;
+	}
+/* Check an EC key is compatible with extensions */
+static int tls1_check_ec_key(SSL *s,
+			unsigned char *curve_id, unsigned char *comp_id)
+	{
+	const unsigned char *p;
+	size_t plen, i;
+	int j;
+	/* If point formats extension present check it, otherwise everything
+	 * is supported (see RFC4492).
+	 */
+	if (comp_id && s->session->tlsext_ecpointformatlist)
+		{
+		p = s->session->tlsext_ecpointformatlist;
+		plen = s->session->tlsext_ecpointformatlist_length;
+		for (i = 0; i < plen; i++, p++)
+			{
+			if (*comp_id == *p)
+				break;
+			}
+		if (i == plen)
+			return 0;
+		}
+	if (!curve_id)
+		return 1;
+	/* Check curve is consistent with client and server preferences */
+	for (j = 0; j <= 1; j++)
+		{
+		tls1_get_curvelist(s, j, &p, &plen);
+		for (i = 0; i < plen; i+=2, p+=2)
+			{
+			if (p[0] == curve_id[0] && p[1] == curve_id[1])
+				break;
+			}
+		if (i == plen)
+			return 0;
+		/* For clients can only check sent curve list */
+		if (!s->server)
+			return 1;
+		}
+	return 1;
+	}
+
+static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+					size_t *pformatslen)
+	{
+	/* If we have a custom point format list use it otherwise
+	 * use default */
+	if (s->tlsext_ecpointformatlist)
+		{
+		*pformats = s->tlsext_ecpointformatlist;
+		*pformatslen = s->tlsext_ecpointformatlist_length;
+		}
+	else
+		{
+		*pformats = ecformats_default;
+		/* For Suite B we don't support char2 fields */
+		if (tls1_suiteb(s))
+			*pformatslen = sizeof(ecformats_default) - 1;
+		else
+			*pformatslen = sizeof(ecformats_default);
+		}
+	}
+
+/* Check cert parameters compatible with extensions: currently just checks
+ * EC certificates have compatible curves and compression.
+ */
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
+	{
+	unsigned char comp_id, curve_id[2];
+	EVP_PKEY *pkey;
+	int rv;
+	pkey = X509_get_pubkey(x);
+	if (!pkey)
+		return 0;
+	/* If not EC nothing to do */
+	if (pkey->type != EVP_PKEY_EC)
+		{
+		EVP_PKEY_free(pkey);
+		return 1;
+		}
+	rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec);
+	EVP_PKEY_free(pkey);
+	if (!rv)
+		return 0;
+	/* Can't check curve_id for client certs as we don't have a
+	 * supported curves extension.
+	 */
+	rv = tls1_check_ec_key(s, s->server ? curve_id : NULL, &comp_id);
+	if (!rv)
+		return 0;
+	/* Special case for suite B. We *MUST* sign using SHA256+P-256 or
+	 * SHA384+P-384, adjust digest if necessary.
+	 */
+	if (set_ee_md && tls1_suiteb(s))
+		{
+		int check_md;
+		size_t i;
+		CERT *c = s->cert;
+		if (curve_id[0])
+			return 0;
+		/* Check to see we have necessary signing algorithm */
+		if (curve_id[1] == TLSEXT_curve_P_256)
+			check_md = NID_ecdsa_with_SHA256;
+		else if (curve_id[1] == TLSEXT_curve_P_384)
+			check_md = NID_ecdsa_with_SHA384;
+		else
+			return 0; /* Should never happen */
+		for (i = 0; i < c->shared_sigalgslen; i++)
+			if (check_md == c->shared_sigalgs[i].signandhash_nid)
+				break;
+		if (i == c->shared_sigalgslen)
+			return 0;
+		if (set_ee_md == 2)
+			{
+			if (check_md == NID_ecdsa_with_SHA256)
+				c->pkeys[SSL_PKEY_ECC].digest = EVP_sha256();
+			else
+				c->pkeys[SSL_PKEY_ECC].digest = EVP_sha384();
+			}
+		}
+	return rv;
+	}
+/* Check EC temporary key is compatible with client extensions */
+int tls1_check_ec_tmp_key(SSL *s, unsigned long cid)
+	{
+	unsigned char curve_id[2];
+	EC_KEY *ec = s->cert->ecdh_tmp;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+	/* Allow any curve: not just those peer supports */
+	if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+		return 1;
+#endif
+	/* If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384,
+	 * no other curves permitted.
+	 */
+	if (tls1_suiteb(s))
+		{
+		/* Curve to check determined by ciphersuite */
+		if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+			curve_id[1] = TLSEXT_curve_P_256;
+		else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+			curve_id[1] = TLSEXT_curve_P_384;
+		else
+			return 0;
+		curve_id[0] = 0;
+		/* Check this curve is acceptable */
+		if (!tls1_check_ec_key(s, curve_id, NULL))
+			return 0;
+		/* If auto or setting curve from callback assume OK */
+		if (s->cert->ecdh_tmp_auto || s->cert->ecdh_tmp_cb)
+			return 1;
+		/* Otherwise check curve is acceptable */
+		else 
+			{
+			unsigned char curve_tmp[2];
+			if (!ec)
+				return 0;
+			if (!tls1_set_ec_id(curve_tmp, NULL, ec))
+				return 0;
+			if (!curve_tmp[0] || curve_tmp[1] == curve_id[1])
+				return 1;
+			return 0;
+			}
+			
+		}
+	if (s->cert->ecdh_tmp_auto)
+		{
+		/* Need a shared curve */
+		if (tls1_shared_curve(s, 0))
+			return 1;
+		else return 0;
+		}
+	if (!ec)
+		{
+		if (s->cert->ecdh_tmp_cb)
+			return 1;
+		else
+			return 0;
+		}
+	if (!tls1_set_ec_id(curve_id, NULL, ec))
+		return 0;
+/* Set this to allow use of invalid curves for testing */
+#if 0
+	return 1;
+#else
+	return tls1_check_ec_key(s, curve_id, NULL);
+#endif
+	}
+
+#else
+
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
+	{
+	return 1;
+	}
+
+#endif /* OPENSSL_NO_EC */
+
+#ifndef OPENSSL_NO_TLSEXT
+
+/* List of supported signature algorithms and hashes. Should make this
+ * customisable at some point, for now include everything we support.
+ */
+
+#ifdef OPENSSL_NO_RSA
+#define tlsext_sigalg_rsa(md) /* */
+#else
+#define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa,
+#endif
+
+#ifdef OPENSSL_NO_DSA
+#define tlsext_sigalg_dsa(md) /* */
+#else
+#define tlsext_sigalg_dsa(md) md, TLSEXT_signature_dsa,
+#endif
+
+#ifdef OPENSSL_NO_ECDSA
+#define tlsext_sigalg_ecdsa(md) /* */
+#else
+#define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa,
+#endif
+
+#define tlsext_sigalg(md) \
+		tlsext_sigalg_rsa(md) \
+		tlsext_sigalg_dsa(md) \
+		tlsext_sigalg_ecdsa(md)
+
+static unsigned char tls12_sigalgs[] = {
+#ifndef OPENSSL_NO_SHA512
+	tlsext_sigalg(TLSEXT_hash_sha512)
+	tlsext_sigalg(TLSEXT_hash_sha384)
+#endif
+#ifndef OPENSSL_NO_SHA256
+	tlsext_sigalg(TLSEXT_hash_sha256)
+	tlsext_sigalg(TLSEXT_hash_sha224)
+#endif
+#ifndef OPENSSL_NO_SHA
+	tlsext_sigalg(TLSEXT_hash_sha1)
+#endif
+};
+#ifndef OPENSSL_NO_ECDSA
+static unsigned char suiteb_sigalgs[] = {
+	tlsext_sigalg_ecdsa(TLSEXT_hash_sha256)
+	tlsext_sigalg_ecdsa(TLSEXT_hash_sha384)
+};
+#endif
+size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
+	{
+	/* If Suite B mode use Suite B sigalgs only, ignore any other
+	 * preferences.
+	 */
+#ifndef OPENSSL_NO_EC
+	switch (tls1_suiteb(s))
+		{
+	case SSL_CERT_FLAG_SUITEB_128_LOS:
+		*psigs = suiteb_sigalgs;
+		return sizeof(suiteb_sigalgs);
+
+	case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+		*psigs = suiteb_sigalgs;
+		return 2;
+
+	case SSL_CERT_FLAG_SUITEB_192_LOS:
+		*psigs = suiteb_sigalgs + 2;
+		return 2;
+		}
+#endif
+	/* If server use client authentication sigalgs if not NULL */
+	if (s->server && s->cert->client_sigalgs)
+		{
+		*psigs = s->cert->client_sigalgs;
+		return s->cert->client_sigalgslen;
+		}
+	else if (s->cert->conf_sigalgs)
+		{
+		*psigs = s->cert->conf_sigalgs;
+		return s->cert->conf_sigalgslen;
+		}
+	else
+		{
+		*psigs = tls12_sigalgs;
+		return sizeof(tls12_sigalgs);
+		}
+	}
+/* Check signature algorithm is consistent with sent supported signature
+ * algorithms and if so return relevant digest.
+ */
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+				const unsigned char *sig, EVP_PKEY *pkey)
+	{
+	const unsigned char *sent_sigs;
+	size_t sent_sigslen, i;
+	int sigalg = tls12_get_sigid(pkey);
+	/* Should never happen */
+	if (sigalg == -1)
+		return -1;
+	/* Check key type is consistent with signature */
+	if (sigalg != (int)sig[1])
+		{
+		OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE);
+		return 0;
+		}
+#ifndef OPENSSL_NO_EC
+	if (pkey->type == EVP_PKEY_EC)
+		{
+		unsigned char curve_id[2], comp_id;
+		/* Check compression and curve matches extensions */
+		if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec))
+			return 0;
+		if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id))
+			{
+			OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_CURVE);
+			return 0;
+			}
+		/* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
+		if (tls1_suiteb(s))
+			{
+			if (curve_id[0])
+				return 0;
+			if (curve_id[1] == TLSEXT_curve_P_256)
+				{
+				if (sig[0] != TLSEXT_hash_sha256)
+					{
+					OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_ILLEGAL_SUITEB_DIGEST);
+					return 0;
+					}
+				}
+			else if (curve_id[1] == TLSEXT_curve_P_384)
+				{
+				if (sig[0] != TLSEXT_hash_sha384)
+					{
+					OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_ILLEGAL_SUITEB_DIGEST);
+					return 0;
+					}
+				}
+			else
+				return 0;
+			}
+		}
+	else if (tls1_suiteb(s))
+		return 0;
+#endif
+
+	/* Check signature matches a type we sent */
+	sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
+	for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2)
+		{
+		if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1])
+			break;
+		}
+	/* Allow fallback to SHA1 if not strict mode */
+	if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
+		{
+		OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE);
+		return 0;
+		}
+	*pmd = tls12_get_hash(sig[0]);
+	if (*pmd == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_UNKNOWN_DIGEST);
+		return 0;
+		}
+	/* Store the digest used so applications can retrieve it if they
+	 * wish.
+	 */
+	if (s->session && s->session->sess_cert)
+		s->session->sess_cert->peer_key->digest = *pmd;
+	return 1;
+	}
+/* Get a mask of disabled algorithms: an algorithm is disabled
+ * if it isn't supported or doesn't appear in supported signature
+ * algorithms. Unlike ssl_cipher_get_disabled this applies to a specific
+ * session and not global settings.
+ * 
+ */
+void ssl_set_client_disabled(SSL *s)
+	{
+	CERT *c = s->cert;
+	const unsigned char *sigalgs;
+	size_t i, sigalgslen;
+	int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
+	c->mask_a = 0;
+	c->mask_k = 0;
+	/* Don't allow TLS 1.2 only ciphers if we don't suppport them */
+	if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
+		c->mask_ssl = SSL_TLSV1_2;
+	else
+		c->mask_ssl = 0;
+	/* Now go through all signature algorithms seeing if we support
+	 * any for RSA, DSA, ECDSA. Do this for all versions not just
+	 * TLS 1.2.
+	 */
+	sigalgslen = tls12_get_psigalgs(s, &sigalgs);
+	for (i = 0; i < sigalgslen; i += 2, sigalgs += 2)
+		{
+		switch(sigalgs[1])
+			{
+#ifndef OPENSSL_NO_RSA
+		case TLSEXT_signature_rsa:
+			have_rsa = 1;
+			break;
+#endif
+#ifndef OPENSSL_NO_DSA
+		case TLSEXT_signature_dsa:
+			have_dsa = 1;
+			break;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		case TLSEXT_signature_ecdsa:
+			have_ecdsa = 1;
+			break;
+#endif
+			}
+		}
+	/* Disable auth and static DH if we don't include any appropriate
+	 * signature algorithms.
+	 */
+	if (!have_rsa)
+		{
+		c->mask_a |= SSL_aRSA;
+		c->mask_k |= SSL_kDHr|SSL_kECDHr;
+		}
+	if (!have_dsa)
+		{
+		c->mask_a |= SSL_aDSS;
+		c->mask_k |= SSL_kDHd;
+		}
+	if (!have_ecdsa)
+		{
+		c->mask_a |= SSL_aECDSA;
+		c->mask_k |= SSL_kECDHe;
+		}
+#ifndef OPENSSL_NO_PSK
+	/* with PSK there must be client callback set */
+	if (!s->psk_client_callback)
+		{
+		c->mask_a |= SSL_aPSK;
+		c->mask_k |= SSL_kPSK;
+		}
+#endif /* OPENSSL_NO_PSK */
+	c->valid = 1;
+	}
+
+/* byte_compare is a compare function for qsort(3) that compares bytes. */
+static int byte_compare(const void *in_a, const void *in_b)
+	{
+	unsigned char a = *((const unsigned char*) in_a);
+	unsigned char b = *((const unsigned char*) in_b);
+
+	if (a > b)
+		return 1;
+	else if (a < b)
+		return -1;
+	return 0;
+}
+
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+	{
+	int extdatalen=0;
+	unsigned char *ret = p;
+#ifndef OPENSSL_NO_EC
+	/* See if we support any ECC ciphersuites */
+	int using_ecc = 0;
+	if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s))
+		{
+		int i;
+		unsigned long alg_k, alg_a;
+		STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+		for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+			{
+			SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+			alg_k = c->algorithm_mkey;
+			alg_a = c->algorithm_auth;
+			if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)
+				|| (alg_a & SSL_aECDSA)))
+				{
+				using_ecc = 1;
+				break;
+				}
+			}
+		}
+#endif
+
+	/* don't add extensions for SSLv3 unless doing secure renegotiation */
+	if (s->client_version == SSL3_VERSION
+					&& !s->s3->send_connection_binding)
+		return p;
+
+	ret+=2;
+
+	if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+ 	if (s->tlsext_hostname != NULL)
+		{ 
+		/* Add TLS extension servername to the Client Hello message */
+		unsigned long size_str;
+		long lenmax; 
+
+		/* check for enough space.
+		   4 for the servername type and entension length
+		   2 for servernamelist length
+		   1 for the hostname type
+		   2 for hostname length
+		   + hostname length 
+		*/
+		   
+		if ((lenmax = limit - ret - 9) < 0 
+		    || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) 
+			return NULL;
+			
+		/* extension type and length */
+		s2n(TLSEXT_TYPE_server_name,ret); 
+		s2n(size_str+5,ret);
+		
+		/* length of servername list */
+		s2n(size_str+3,ret);
+	
+		/* hostname type, length and hostname */
+		*(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
+		s2n(size_str,ret);
+		memcpy(ret, s->tlsext_hostname, size_str);
+		ret+=size_str;
+		}
+
+        /* Add RI if renegotiating */
+        if (s->renegotiate)
+          {
+          int el;
+          
+          if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
+              {
+              OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
+              return NULL;
+              }
+
+          if((limit - p - 4 - el) < 0) return NULL;
+          
+          s2n(TLSEXT_TYPE_renegotiate,ret);
+          s2n(el,ret);
+
+          if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
+              {
+              OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
+              return NULL;
+              }
+
+          ret += el;
+        }
+
+
+#ifndef OPENSSL_NO_EC
+	if (using_ecc)
+		{
+		/* Add TLS extension ECPointFormats to the ClientHello message */
+		long lenmax; 
+		const unsigned char *plist;
+		size_t plistlen;
+
+		tls1_get_formatlist(s, &plist, &plistlen);
+
+		if ((lenmax = limit - ret - 5) < 0) return NULL; 
+		if (plistlen > (size_t)lenmax) return NULL;
+		if (plistlen > 255)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
+			return NULL;
+			}
+		
+		s2n(TLSEXT_TYPE_ec_point_formats,ret);
+		s2n(plistlen + 1,ret);
+		*(ret++) = (unsigned char)plistlen ;
+		memcpy(ret, plist, plistlen);
+		ret+=plistlen;
+
+		/* Add TLS extension EllipticCurves to the ClientHello message */
+		plist = s->tlsext_ellipticcurvelist;
+		tls1_get_curvelist(s, 0, &plist, &plistlen);
+
+		if ((lenmax = limit - ret - 6) < 0) return NULL; 
+		if (plistlen > (size_t)lenmax) return NULL;
+		if (plistlen > 65532)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
+			return NULL;
+			}
+		
+		s2n(TLSEXT_TYPE_elliptic_curves,ret);
+		s2n(plistlen + 2, ret);
+
+		/* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
+		 * elliptic_curve_list, but the examples use two bytes.
+		 * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
+		 * resolves this to two bytes.
+		 */
+		s2n(plistlen, ret);
+		memcpy(ret, plist, plistlen);
+		ret+=plistlen;
+		}
+#endif /* OPENSSL_NO_EC */
+
+	if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
+		{
+		int ticklen;
+		if (!s->new_session && s->session && s->session->tlsext_tick)
+			ticklen = s->session->tlsext_ticklen;
+		else if (s->session && s->tlsext_session_ticket &&
+			 s->tlsext_session_ticket->data)
+			{
+			ticklen = s->tlsext_session_ticket->length;
+			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+			if (!s->session->tlsext_tick)
+				return NULL;
+			memcpy(s->session->tlsext_tick,
+			       s->tlsext_session_ticket->data,
+			       ticklen);
+			s->session->tlsext_ticklen = ticklen;
+			}
+		else
+			ticklen = 0;
+		if (ticklen == 0 && s->tlsext_session_ticket &&
+		    s->tlsext_session_ticket->data == NULL)
+			goto skip_ext;
+		/* Check for enough room 2 for extension type, 2 for len
+ 		 * rest for ticket
+  		 */
+		if ((long)(limit - ret - 4 - ticklen) < 0) return NULL;
+		s2n(TLSEXT_TYPE_session_ticket,ret); 
+		s2n(ticklen,ret);
+		if (ticklen)
+			{
+			memcpy(ret, s->session->tlsext_tick, ticklen);
+			ret += ticklen;
+			}
+		}
+		skip_ext:
+
+	if (SSL_USE_SIGALGS(s))
+		{
+		size_t salglen;
+		const unsigned char *salg;
+		salglen = tls12_get_psigalgs(s, &salg);
+		if ((size_t)(limit - ret) < salglen + 6)
+			return NULL; 
+		s2n(TLSEXT_TYPE_signature_algorithms,ret);
+		s2n(salglen + 2, ret);
+		s2n(salglen, ret);
+		memcpy(ret, salg, salglen);
+		ret += salglen;
+		}
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->client_opaque_prf_input != NULL)
+		{
+		size_t col = s->s3->client_opaque_prf_input_len;
+		
+		if ((long)(limit - ret - 6 - col < 0))
+			return NULL;
+		if (col > 0xFFFD) /* can't happen */
+			return NULL;
+
+		s2n(TLSEXT_TYPE_opaque_prf_input, ret); 
+		s2n(col + 2, ret);
+		s2n(col, ret);
+		memcpy(ret, s->s3->client_opaque_prf_input, col);
+		ret += col;
+		}
+#endif
+
+        /* TODO(fork): we probably want OCSP stapling, but it currently pulls in a lot of code. */
+#if 0
+	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+		{
+		int i;
+		long extlen, idlen, itmp;
+		OCSP_RESPID *id;
+
+		idlen = 0;
+		for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+			{
+			id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+			itmp = i2d_OCSP_RESPID(id, NULL);
+			if (itmp <= 0)
+				return NULL;
+			idlen += itmp + 2;
+			}
+
+		if (s->tlsext_ocsp_exts)
+			{
+			extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+			if (extlen < 0)
+				return NULL;
+			}
+		else
+			extlen = 0;
+			
+		if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
+		s2n(TLSEXT_TYPE_status_request, ret);
+		if (extlen + idlen > 0xFFF0)
+			return NULL;
+		s2n(extlen + idlen + 5, ret);
+		*(ret++) = TLSEXT_STATUSTYPE_ocsp;
+		s2n(idlen, ret);
+		for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+			{
+			/* save position of id len */
+			unsigned char *q = ret;
+			id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+			/* skip over id len */
+			ret += 2;
+			itmp = i2d_OCSP_RESPID(id, &ret);
+			/* write id len */
+			s2n(itmp, q);
+			}
+		s2n(extlen, ret);
+		if (extlen > 0)
+			i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+		}
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	/* Add Heartbeat extension */
+	s2n(TLSEXT_TYPE_heartbeat,ret);
+	s2n(1,ret);
+	/* Set mode:
+	 * 1: peer may send requests
+	 * 2: peer not allowed to send requests
+	 */
+	if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+		*(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+	else
+		*(ret++) = SSL_TLSEXT_HB_ENABLED;
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
+		{
+		/* The client advertises an emtpy extension to indicate its
+		 * support for Next Protocol Negotiation */
+		if (limit - ret - 4 < 0)
+			return NULL;
+		s2n(TLSEXT_TYPE_next_proto_neg,ret);
+		s2n(0,ret);
+		}
+#endif
+
+	if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len)
+		{
+		if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
+			return NULL;
+		s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
+		s2n(2 + s->alpn_client_proto_list_len,ret);
+		s2n(s->alpn_client_proto_list_len,ret);
+		memcpy(ret, s->alpn_client_proto_list,
+		       s->alpn_client_proto_list_len);
+		ret += s->alpn_client_proto_list_len;
+		}
+
+        if(SSL_get_srtp_profiles(s))
+                {
+                int el;
+
+                ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
+                
+                if((limit - p - 4 - el) < 0) return NULL;
+
+                s2n(TLSEXT_TYPE_use_srtp,ret);
+                s2n(el,ret);
+
+                if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
+			return NULL;
+			}
+                ret += el;
+                }
+
+	/* Add TLS extension Server_Authz_DataFormats to the ClientHello */
+	/* 2 bytes for extension type */
+	/* 2 bytes for extension length */
+	/* 1 byte for the list length */
+	/* 1 byte for the list (we only support audit proofs) */
+	if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+		{
+                const unsigned short ext_len = 2;
+                const unsigned char list_len = 1;
+
+		if (limit < ret + 6)
+			return NULL;
+
+		s2n(TLSEXT_TYPE_server_authz, ret);
+                /* Extension length: 2 bytes */
+		s2n(ext_len, ret);
+		*(ret++) = list_len;
+		*(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
+		}
+
+	/* Add custom TLS Extensions to ClientHello */
+	if (s->ctx->custom_cli_ext_records_count)
+		{
+		size_t i;
+		custom_cli_ext_record* record;
+
+		for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+			{
+			const unsigned char* out = NULL;
+			unsigned short outlen = 0;
+
+			record = &s->ctx->custom_cli_ext_records[i];
+			/* NULL callback sends empty extension */ 
+			/* -1 from callback omits extension */
+			if (record->fn1)
+				{
+				int cb_retval = 0;
+				cb_retval = record->fn1(s, record->ext_type,
+							&out, &outlen,
+							record->arg);
+				if (cb_retval == 0)
+					return NULL; /* error */
+				if (cb_retval == -1)
+					continue; /* skip this extension */
+				}
+			if (limit < ret + 4 + outlen)
+				return NULL;
+			s2n(record->ext_type, ret);
+			s2n(outlen, ret);
+			memcpy(ret, out, outlen);
+			ret += outlen;
+			}
+		}
+
+#ifdef TLSEXT_TYPE_padding
+	/* Add padding to workaround bugs in F5 terminators.
+	 * See https://tools.ietf.org/html/draft-agl-tls-padding-02
+	 *
+	 * NB: because this code works out the length of all existing
+	 * extensions it MUST always appear last.
+	 */
+	{
+	int hlen = ret - (unsigned char *)s->init_buf->data;
+	/* The code in s23_clnt.c to build ClientHello messages includes the
+	 * 5-byte record header in the buffer, while the code in s3_clnt.c does
+	 * not. */
+	if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+		hlen -= 5;
+	if (hlen > 0xff && hlen < 0x200)
+		{
+		hlen = 0x200 - hlen;
+		if (hlen >= 4)
+			hlen -= 4;
+		else
+			hlen = 0;
+
+		s2n(TLSEXT_TYPE_padding, ret);
+		s2n(hlen, ret);
+		memset(ret, 0, hlen);
+		ret += hlen;
+		}
+#endif
+
+	if ((extdatalen = ret-p-2) == 0)
+		return p;
+
+	s2n(extdatalen,p);
+	return ret;
+	}
+
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+	{
+	int extdatalen=0;
+	unsigned char *ret = p;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	int next_proto_neg_seen;
+#endif
+#ifndef OPENSSL_NO_EC
+	unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+	unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+	int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
+	using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+#endif
+	/* don't add extensions for SSLv3, unless doing secure renegotiation */
+	if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
+		return p;
+	
+	ret+=2;
+	if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+	if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
+		{ 
+		if ((long)(limit - ret - 4) < 0) return NULL; 
+
+		s2n(TLSEXT_TYPE_server_name,ret);
+		s2n(0,ret);
+		}
+
+	if(s->s3->send_connection_binding)
+        {
+          int el;
+          
+          if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
+              {
+              OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
+              return NULL;
+              }
+
+          if((limit - p - 4 - el) < 0) return NULL;
+          
+          s2n(TLSEXT_TYPE_renegotiate,ret);
+          s2n(el,ret);
+
+          if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
+              {
+              OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
+              return NULL;
+              }
+
+          ret += el;
+        }
+
+#ifndef OPENSSL_NO_EC
+	if (using_ecc)
+		{
+		const unsigned char *plist;
+		size_t plistlen;
+		/* Add TLS extension ECPointFormats to the ServerHello message */
+		long lenmax; 
+
+		tls1_get_formatlist(s, &plist, &plistlen);
+
+		if ((lenmax = limit - ret - 5) < 0) return NULL; 
+		if (plistlen > (size_t)lenmax) return NULL;
+		if (plistlen > 255)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
+			return NULL;
+			}
+		
+		s2n(TLSEXT_TYPE_ec_point_formats,ret);
+		s2n(plistlen + 1,ret);
+		*(ret++) = (unsigned char) plistlen;
+		memcpy(ret, plist, plistlen);
+		ret+=plistlen;
+
+		}
+	/* Currently the server should not respond with a SupportedCurves extension */
+#endif /* OPENSSL_NO_EC */
+
+	if (s->tlsext_ticket_expected
+		&& !(SSL_get_options(s) & SSL_OP_NO_TICKET)) 
+		{ 
+		if ((long)(limit - ret - 4) < 0) return NULL; 
+		s2n(TLSEXT_TYPE_session_ticket,ret);
+		s2n(0,ret);
+		}
+
+	if (s->tlsext_status_expected)
+		{ 
+		if ((long)(limit - ret - 4) < 0) return NULL; 
+		s2n(TLSEXT_TYPE_status_request,ret);
+		s2n(0,ret);
+		}
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->server_opaque_prf_input != NULL)
+		{
+		size_t sol = s->s3->server_opaque_prf_input_len;
+		
+		if ((long)(limit - ret - 6 - sol) < 0)
+			return NULL;
+		if (sol > 0xFFFD) /* can't happen */
+			return NULL;
+
+		s2n(TLSEXT_TYPE_opaque_prf_input, ret); 
+		s2n(sol + 2, ret);
+		s2n(sol, ret);
+		memcpy(ret, s->s3->server_opaque_prf_input, sol);
+		ret += sol;
+		}
+#endif
+
+        if(s->srtp_profile)
+                {
+                int el;
+
+                ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
+                
+                if((limit - p - 4 - el) < 0) return NULL;
+
+                s2n(TLSEXT_TYPE_use_srtp,ret);
+                s2n(el,ret);
+
+                if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
+			return NULL;
+			}
+                ret+=el;
+                }
+
+	if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) 
+		&& (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
+		{ const unsigned char cryptopro_ext[36] = {
+			0xfd, 0xe8, /*65000*/
+			0x00, 0x20, /*32 bytes length*/
+			0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, 
+			0x03,   0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06, 
+			0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08, 
+			0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
+			if (limit-ret<36) return NULL;
+			memcpy(ret,cryptopro_ext,36);
+			ret+=36;
+
+		}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	/* Add Heartbeat extension if we've received one */
+	if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
+		{
+		s2n(TLSEXT_TYPE_heartbeat,ret);
+		s2n(1,ret);
+		/* Set mode:
+		 * 1: peer may send requests
+		 * 2: peer not allowed to send requests
+		 */
+		if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+			*(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+		else
+			*(ret++) = SSL_TLSEXT_HB_ENABLED;
+
+		}
+#endif
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	next_proto_neg_seen = s->s3->next_proto_neg_seen;
+	s->s3->next_proto_neg_seen = 0;
+	if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
+		{
+		const unsigned char *npa;
+		unsigned int npalen;
+		int r;
+
+		r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
+		if (r == SSL_TLSEXT_ERR_OK)
+			{
+			if ((long)(limit - ret - 4 - npalen) < 0) return NULL;
+			s2n(TLSEXT_TYPE_next_proto_neg,ret);
+			s2n(npalen,ret);
+			memcpy(ret, npa, npalen);
+			ret += npalen;
+			s->s3->next_proto_neg_seen = 1;
+			}
+		}
+#endif
+
+	/* If the client supports authz then see whether we have any to offer
+	 * to it. */
+	if (s->s3->tlsext_authz_client_types_len)
+		{
+		size_t authz_length;
+		/* By now we already know the new cipher, so we can look ahead
+		 * to see whether the cert we are going to send
+		 * has any authz data attached to it. */
+		const unsigned char* authz = ssl_get_authz_data(s, &authz_length);
+		const unsigned char* const orig_authz = authz;
+		size_t i;
+		unsigned authz_count = 0;
+
+		/* The authz data contains a number of the following structures:
+		 * 	uint8_t authz_type
+		 * 	uint16_t length
+		 * 	uint8_t data[length]
+		 *
+		 * First we walk over it to find the number of authz elements. */
+		for (i = 0; i < authz_length; i++)
+			{
+			unsigned short length;
+			unsigned char type;
+
+			type = *(authz++);
+			if (memchr(s->s3->tlsext_authz_client_types,
+				   type,
+				   s->s3->tlsext_authz_client_types_len) != NULL)
+				authz_count++;
+
+			n2s(authz, length);
+			/* n2s increments authz by 2 */
+			i += 2;
+			authz += length;
+			i += length;
+			}
+
+		if (authz_count)
+			{
+			/* Add TLS extension server_authz to the ServerHello message
+			 * 2 bytes for extension type
+			 * 2 bytes for extension length
+			 * 1 byte for the list length
+			 * n bytes for the list */
+			const unsigned short ext_len = 1 + authz_count;
+
+			if ((long)(limit - ret - 4 - ext_len) < 0) return NULL;
+			s2n(TLSEXT_TYPE_server_authz, ret);
+			s2n(ext_len, ret);
+			*(ret++) = authz_count;
+			s->s3->tlsext_authz_promised_to_client = 1;
+			}
+
+		authz = orig_authz;
+		for (i = 0; i < authz_length; i++)
+			{
+			unsigned short length;
+			unsigned char type;
+
+			authz_count++;
+			type = *(authz++);
+			if (memchr(s->s3->tlsext_authz_client_types,
+				   type,
+				   s->s3->tlsext_authz_client_types_len) != NULL)
+				*(ret++) = type;
+			n2s(authz, length);
+			/* n2s increments authz by 2 */
+			i += 2;
+			authz += length;
+			i += length;
+			}
+		}
+
+	/* If custom types were sent in ClientHello, add ServerHello responses */
+	if (s->s3->tlsext_custom_types_count)
+		{
+		size_t i;
+
+		for (i = 0; i < s->s3->tlsext_custom_types_count; i++)
+			{
+			size_t j;
+			custom_srv_ext_record *record;
+
+			for (j = 0; j < s->ctx->custom_srv_ext_records_count; j++)
+				{
+				record = &s->ctx->custom_srv_ext_records[j];
+				if (s->s3->tlsext_custom_types[i] == record->ext_type)
+					{
+					const unsigned char *out = NULL;
+					unsigned short outlen = 0;
+					int cb_retval = 0;
+
+					/* NULL callback or -1 omits extension */
+					if (!record->fn2)
+						break;
+					cb_retval = record->fn2(s, record->ext_type,
+						    		&out, &outlen,
+						    		record->arg);
+					if (cb_retval == 0)
+						return NULL; /* error */
+					if (cb_retval == -1)
+						break; /* skip this extension */
+					if (limit < ret + 4 + outlen)
+						return NULL;
+					s2n(record->ext_type, ret);
+					s2n(outlen, ret);
+					memcpy(ret, out, outlen);
+					ret += outlen;
+					break;
+					}
+				}
+			}
+		}
+
+	if (s->s3->alpn_selected)
+		{
+		const unsigned char *selected = s->s3->alpn_selected;
+		unsigned len = s->s3->alpn_selected_len;
+
+		if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
+			return NULL;
+		s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
+		s2n(3 + len,ret);
+		s2n(1 + len,ret);
+		*ret++ = len;
+		memcpy(ret, selected, len);
+		ret += len;
+		}
+
+	if ((extdatalen = ret-p-2)== 0) 
+		return p;
+
+	s2n(extdatalen,p);
+	return ret;
+	}
+
+#ifndef OPENSSL_NO_EC
+/* ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ *   SNI,
+ *   elliptic_curves
+ *   ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
+	unsigned short type, size;
+	static const unsigned char kSafariExtensionsBlock[] = {
+		0x00, 0x0a,  /* elliptic_curves extension */
+		0x00, 0x08,  /* 8 bytes */
+		0x00, 0x06,  /* 6 bytes of curve ids */
+		0x00, 0x17,  /* P-256 */
+		0x00, 0x18,  /* P-384 */
+		0x00, 0x19,  /* P-521 */
+
+		0x00, 0x0b,  /* ec_point_formats */
+		0x00, 0x02,  /* 2 bytes */
+		0x01,        /* 1 point format */
+		0x00,        /* uncompressed */
+	};
+
+	/* The following is only present in TLS 1.2 */
+	static const unsigned char kSafariTLS12ExtensionsBlock[] = {
+		0x00, 0x0d,  /* signature_algorithms */
+		0x00, 0x0c,  /* 12 bytes */
+		0x00, 0x0a,  /* 10 bytes */
+		0x05, 0x01,  /* SHA-384/RSA */
+		0x04, 0x01,  /* SHA-256/RSA */
+		0x02, 0x01,  /* SHA-1/RSA */
+		0x04, 0x03,  /* SHA-256/ECDSA */
+		0x02, 0x03,  /* SHA-1/ECDSA */
+	};
+
+	if (data >= (d+n-2))
+		return;
+	data += 2;
+
+	if (data > (d+n-4))
+		return;
+	n2s(data,type);
+	n2s(data,size);
+
+	if (type != TLSEXT_TYPE_server_name)
+		return;
+
+	if (data+size > d+n)
+		return;
+	data += size;
+
+	if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+		{
+		const size_t len1 = sizeof(kSafariExtensionsBlock);
+		const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
+
+		if (data + len1 + len2 != d+n)
+			return;
+		if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+			return;
+		if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+			return;
+		}
+	else
+		{
+		const size_t len = sizeof(kSafariExtensionsBlock);
+
+		if (data + len != d+n)
+			return;
+		if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+			return;
+		}
+
+	s->s3->is_probably_safari = 1;
+}
+#endif /* !OPENSSL_NO_EC */
+
+/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
+ * ClientHello.
+ *   data: the contents of the extension, not including the type and length.
+ *   data_len: the number of bytes in |data|
+ *   al: a pointer to the alert value to send in the event of a non-zero
+ *       return.
+ *
+ *   returns: 0 on success. */
+static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
+					 unsigned data_len, int *al)
+	{
+	unsigned i;
+	unsigned proto_len;
+	const unsigned char *selected;
+	unsigned char selected_len;
+	int r;
+
+	if (s->ctx->alpn_select_cb == NULL)
+		return 0;
+
+	if (data_len < 2)
+		goto parse_error;
+
+	/* data should contain a uint16 length followed by a series of 8-bit,
+	 * length-prefixed strings. */
+	i = ((unsigned) data[0]) << 8 |
+	    ((unsigned) data[1]);
+	data_len -= 2;
+	data += 2;
+	if (data_len != i)
+		goto parse_error;
+
+	if (data_len < 2)
+		goto parse_error;
+
+	for (i = 0; i < data_len;)
+		{
+		proto_len = data[i];
+		i++;
+
+		if (proto_len == 0)
+			goto parse_error;
+
+		if (i + proto_len < i || i + proto_len > data_len)
+			goto parse_error;
+
+		i += proto_len;
+		}
+
+	r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len,
+				   s->ctx->alpn_select_cb_arg);
+	if (r == SSL_TLSEXT_ERR_OK) {
+		if (s->s3->alpn_selected)
+			OPENSSL_free(s->s3->alpn_selected);
+		s->s3->alpn_selected = OPENSSL_malloc(selected_len);
+		if (!s->s3->alpn_selected)
+			{
+			*al = SSL_AD_INTERNAL_ERROR;
+			return -1;
+			}
+		memcpy(s->s3->alpn_selected, selected, selected_len);
+		s->s3->alpn_selected_len = selected_len;
+	}
+	return 0;
+
+parse_error:
+	*al = SSL_AD_DECODE_ERROR;
+	return -1;
+	}
+
+static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) 
+	{	
+	unsigned short type;
+	unsigned short size;
+	unsigned short len;
+	unsigned char *data = *p;
+	int renegotiate_seen = 0;
+	size_t i;
+
+	s->servername_done = 0;
+	s->tlsext_status_type = -1;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	s->s3->next_proto_neg_seen = 0;
+#endif
+
+	/* Clear observed custom extensions */
+	s->s3->tlsext_custom_types_count = 0;
+	if (s->s3->tlsext_custom_types != NULL)
+		{
+		OPENSSL_free(s->s3->tlsext_custom_types);
+		s->s3->tlsext_custom_types = NULL;
+		}		
+
+	if (s->s3->alpn_selected)
+		{
+		OPENSSL_free(s->s3->alpn_selected);
+		s->s3->alpn_selected = NULL;
+		}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+	                       SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
+
+#ifndef OPENSSL_NO_EC
+	if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+		ssl_check_for_safari(s, data, d, n);
+#endif /* !OPENSSL_NO_EC */
+
+	/* Clear any signature algorithms extension received */
+	if (s->cert->peer_sigalgs)
+		{
+		OPENSSL_free(s->cert->peer_sigalgs);
+		s->cert->peer_sigalgs = NULL;
+		}
+	/* Clear any shared sigtnature algorithms */
+	if (s->cert->shared_sigalgs)
+		{
+		OPENSSL_free(s->cert->shared_sigalgs);
+		s->cert->shared_sigalgs = NULL;
+		}
+	/* Clear certificate digests and validity flags */
+	for (i = 0; i < SSL_PKEY_NUM; i++)
+		{
+		s->cert->pkeys[i].digest = NULL;
+		s->cert->pkeys[i].valid_flags = 0;
+		}
+
+	if (data >= (d+n-2))
+		goto ri_check;
+	n2s(data,len);
+
+	if (data > (d+n-len)) 
+		goto ri_check;
+
+	while (data <= (d+n-4))
+		{
+		n2s(data,type);
+		n2s(data,size);
+
+		if (data+size > (d+n))
+	   		goto ri_check;
+#if 0
+		fprintf(stderr,"Received extension type %d size %d\n",type,size);
+#endif
+		if (s->tlsext_debug_cb)
+			s->tlsext_debug_cb(s, 0, type, data, size,
+						s->tlsext_debug_arg);
+/* The servername extension is treated as follows:
+
+   - Only the hostname type is supported with a maximum length of 255.
+   - The servername is rejected if too long or if it contains zeros,
+     in which case an fatal alert is generated.
+   - The servername field is maintained together with the session cache.
+   - When a session is resumed, the servername call back invoked in order
+     to allow the application to position itself to the right context. 
+   - The servername is acknowledged if it is new for a session or when 
+     it is identical to a previously used for the same session. 
+     Applications can control the behaviour.  They can at any time
+     set a 'desirable' servername for a new SSL object. This can be the
+     case for example with HTTPS when a Host: header field is received and
+     a renegotiation is requested. In this case, a possible servername
+     presented in the new client hello is only acknowledged if it matches
+     the value of the Host: field. 
+   - Applications must  use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+     if they provide for changing an explicit servername context for the session,
+     i.e. when the session has been established with a servername extension. 
+   - On session reconnect, the servername extension may be absent. 
+
+*/      
+
+		if (type == TLSEXT_TYPE_server_name)
+			{
+			unsigned char *sdata;
+			int servname_type;
+			int dsize; 
+		
+			if (size < 2) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			n2s(data,dsize);  
+			size -= 2;
+			if (dsize > size  ) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				} 
+
+			sdata = data;
+			while (dsize > 3) 
+				{
+	 			servname_type = *(sdata++); 
+				n2s(sdata,len);
+				dsize -= 3;
+
+				if (len > dsize) 
+					{
+					*al = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+				if (s->servername_done == 0)
+				switch (servname_type)
+					{
+				case TLSEXT_NAMETYPE_host_name:
+					if (!s->hit)
+						{
+						if(s->session->tlsext_hostname)
+							{
+							*al = SSL_AD_DECODE_ERROR;
+							return 0;
+							}
+						if (len > TLSEXT_MAXLEN_host_name)
+							{
+							*al = TLS1_AD_UNRECOGNIZED_NAME;
+							return 0;
+							}
+						if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
+							{
+							*al = TLS1_AD_INTERNAL_ERROR;
+							return 0;
+							}
+						memcpy(s->session->tlsext_hostname, sdata, len);
+						s->session->tlsext_hostname[len]='\0';
+						if (strlen(s->session->tlsext_hostname) != len) {
+							OPENSSL_free(s->session->tlsext_hostname);
+							s->session->tlsext_hostname = NULL;
+							*al = TLS1_AD_UNRECOGNIZED_NAME;
+							return 0;
+						}
+						s->servername_done = 1; 
+
+						}
+					else 
+						s->servername_done = s->session->tlsext_hostname
+							&& strlen(s->session->tlsext_hostname) == len 
+							&& strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
+					
+					break;
+
+				default:
+					break;
+					}
+				 
+				dsize -= len;
+				}
+			if (dsize != 0) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			}
+
+#ifndef OPENSSL_NO_EC
+		else if (type == TLSEXT_TYPE_ec_point_formats)
+			{
+			unsigned char *sdata = data;
+			int ecpointformatlist_length = *(sdata++);
+
+			if (ecpointformatlist_length != size - 1 || 
+				ecpointformatlist_length < 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			if (!s->hit)
+				{
+				if(s->session->tlsext_ecpointformatlist)
+					{
+					OPENSSL_free(s->session->tlsext_ecpointformatlist);
+					s->session->tlsext_ecpointformatlist = NULL;
+					}
+				s->session->tlsext_ecpointformatlist_length = 0;
+				if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+					{
+					*al = TLS1_AD_INTERNAL_ERROR;
+					return 0;
+					}
+				s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+				memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+				}
+#if 0
+			fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
+			sdata = s->session->tlsext_ecpointformatlist;
+			for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+				fprintf(stderr,"%i ",*(sdata++));
+			fprintf(stderr,"\n");
+#endif
+			}
+		else if (type == TLSEXT_TYPE_elliptic_curves)
+			{
+			unsigned char *sdata = data;
+			int ellipticcurvelist_length = (*(sdata++) << 8);
+			ellipticcurvelist_length += (*(sdata++));
+
+			if (ellipticcurvelist_length != size - 2 ||
+				ellipticcurvelist_length < 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			if (!s->hit)
+				{
+				if(s->session->tlsext_ellipticcurvelist)
+					{
+					*al = TLS1_AD_DECODE_ERROR;
+					return 0;
+					}
+				s->session->tlsext_ellipticcurvelist_length = 0;
+				if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+					{
+					*al = TLS1_AD_INTERNAL_ERROR;
+					return 0;
+					}
+				s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
+				memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
+				}
+#if 0
+			fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
+			sdata = s->session->tlsext_ellipticcurvelist;
+			for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+				fprintf(stderr,"%i ",*(sdata++));
+			fprintf(stderr,"\n");
+#endif
+			}
+#endif /* OPENSSL_NO_EC */
+#ifdef TLSEXT_TYPE_opaque_prf_input
+		else if (type == TLSEXT_TYPE_opaque_prf_input)
+			{
+			unsigned char *sdata = data;
+
+			if (size < 2)
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			n2s(sdata, s->s3->client_opaque_prf_input_len);
+			if (s->s3->client_opaque_prf_input_len != size - 2)
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+				OPENSSL_free(s->s3->client_opaque_prf_input);
+			if (s->s3->client_opaque_prf_input_len == 0)
+				s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+			else
+				s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
+			if (s->s3->client_opaque_prf_input == NULL)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			}
+#endif
+		else if (type == TLSEXT_TYPE_session_ticket)
+			{
+			if (s->tls_session_ticket_ext_cb &&
+			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			}
+		else if (type == TLSEXT_TYPE_renegotiate)
+			{
+			if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+				return 0;
+			renegotiate_seen = 1;
+			}
+		else if (type == TLSEXT_TYPE_signature_algorithms)
+			{
+			int dsize;
+			if (s->cert->peer_sigalgs || size < 2) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			n2s(data,dsize);
+			size -= 2;
+			if (dsize != size || dsize & 1 || !dsize) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			if (!tls1_process_sigalgs(s, data, dsize))
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			/* If sigalgs received and no shared algorithms fatal
+			 * error.
+			 */
+			if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
+				*al = SSL_AD_ILLEGAL_PARAMETER;
+				return 0;
+				}
+			}
+
+                /* TODO(fork): we probably want OCSP stapling support, but this pulls in a lot of code. */
+#if 0
+		else if (type == TLSEXT_TYPE_status_request)
+			{
+		
+			if (size < 5) 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			s->tlsext_status_type = *data++;
+			size--;
+			if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+				{
+				const unsigned char *sdata;
+				int dsize;
+				/* Read in responder_id_list */
+				n2s(data,dsize);
+				size -= 2;
+				if (dsize > size  ) 
+					{
+					*al = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+				while (dsize > 0)
+					{
+					OCSP_RESPID *id;
+					int idsize;
+					if (dsize < 4)
+						{
+						*al = SSL_AD_DECODE_ERROR;
+						return 0;
+						}
+					n2s(data, idsize);
+					dsize -= 2 + idsize;
+					size -= 2 + idsize;
+					if (dsize < 0)
+						{
+						*al = SSL_AD_DECODE_ERROR;
+						return 0;
+						}
+					sdata = data;
+					data += idsize;
+					id = d2i_OCSP_RESPID(NULL,
+								&sdata, idsize);
+					if (!id)
+						{
+						*al = SSL_AD_DECODE_ERROR;
+						return 0;
+						}
+					if (data != sdata)
+						{
+						OCSP_RESPID_free(id);
+						*al = SSL_AD_DECODE_ERROR;
+						return 0;
+						}
+					if (!s->tlsext_ocsp_ids
+						&& !(s->tlsext_ocsp_ids =
+						sk_OCSP_RESPID_new_null()))
+						{
+						OCSP_RESPID_free(id);
+						*al = SSL_AD_INTERNAL_ERROR;
+						return 0;
+						}
+					if (!sk_OCSP_RESPID_push(
+							s->tlsext_ocsp_ids, id))
+						{
+						OCSP_RESPID_free(id);
+						*al = SSL_AD_INTERNAL_ERROR;
+						return 0;
+						}
+					}
+
+				/* Read in request_extensions */
+				if (size < 2)
+					{
+					*al = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+				n2s(data,dsize);
+				size -= 2;
+				if (dsize != size)
+					{
+					*al = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+				sdata = data;
+				if (dsize > 0)
+					{
+					if (s->tlsext_ocsp_exts)
+						{
+						sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+									   X509_EXTENSION_free);
+						}
+
+					s->tlsext_ocsp_exts =
+						d2i_X509_EXTENSIONS(NULL,
+							&sdata, dsize);
+					if (!s->tlsext_ocsp_exts
+						|| (data + dsize != sdata))
+						{
+						*al = SSL_AD_DECODE_ERROR;
+						return 0;
+						}
+					}
+				}
+				/* We don't know what to do with any other type
+ 			 	* so ignore it.
+ 			 	*/
+				else
+					s->tlsext_status_type = -1;
+			}
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (type == TLSEXT_TYPE_heartbeat)
+			{
+			switch(data[0])
+				{
+				case 0x01:	/* Client allows us to send HB requests */
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+							break;
+				case 0x02:	/* Client doesn't accept HB requests */
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+							break;
+				default:	*al = SSL_AD_ILLEGAL_PARAMETER;
+							return 0;
+				}
+			}
+#endif
+#ifndef OPENSSL_NO_NEXTPROTONEG
+		else if (type == TLSEXT_TYPE_next_proto_neg &&
+			 s->s3->tmp.finish_md_len == 0 &&
+			 s->s3->alpn_selected == NULL)
+			{
+			/* We shouldn't accept this extension on a
+			 * renegotiation.
+			 *
+			 * s->new_session will be set on renegotiation, but we
+			 * probably shouldn't rely that it couldn't be set on
+			 * the initial renegotation too in certain cases (when
+			 * there's some other reason to disallow resuming an
+			 * earlier session -- the current code won't be doing
+			 * anything like that, but this might change).
+
+			 * A valid sign that there's been a previous handshake
+			 * in this connection is if s->s3->tmp.finish_md_len >
+			 * 0.  (We are talking about a check that will happen
+			 * in the Hello protocol round, well before a new
+			 * Finished message could have been computed.) */
+			s->s3->next_proto_neg_seen = 1;
+			}
+#endif
+
+		else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
+			 s->ctx->alpn_select_cb &&
+			 s->s3->tmp.finish_md_len == 0)
+			{
+			if (tls1_alpn_handle_client_hello(s, data, size, al) != 0)
+				return 0;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+			/* ALPN takes precedence over NPN. */
+			s->s3->next_proto_neg_seen = 0;
+#endif
+			}
+
+		/* session ticket processed earlier */
+		else if (type == TLSEXT_TYPE_use_srtp)
+                        {
+			if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
+							      al))
+				return 0;
+                        }
+
+		else if (type == TLSEXT_TYPE_server_authz)
+			{
+			unsigned char *sdata = data;
+			unsigned char server_authz_dataformatlist_length;
+
+			if (size == 0)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			server_authz_dataformatlist_length = *(sdata++);
+
+			if (server_authz_dataformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			/* Successful session resumption uses the same authz
+			 * information as the original session so we ignore this
+			 * in the case of a session resumption. */
+			if (!s->hit)
+				{
+				if (s->s3->tlsext_authz_client_types != NULL)
+					OPENSSL_free(s->s3->tlsext_authz_client_types);
+				s->s3->tlsext_authz_client_types =
+					OPENSSL_malloc(server_authz_dataformatlist_length);
+				if (!s->s3->tlsext_authz_client_types)
+					{
+					*al = TLS1_AD_INTERNAL_ERROR;
+					return 0;
+					}
+
+				s->s3->tlsext_authz_client_types_len =
+					server_authz_dataformatlist_length;
+				memcpy(s->s3->tlsext_authz_client_types,
+				       sdata,
+				       server_authz_dataformatlist_length);
+
+				/* Sort the types in order to check for duplicates. */
+				qsort(s->s3->tlsext_authz_client_types,
+				      server_authz_dataformatlist_length,
+				      1 /* element size */,
+				      byte_compare);
+
+				for (i = 0; i < server_authz_dataformatlist_length; i++)
+					{
+					if (i > 0 &&
+					    s->s3->tlsext_authz_client_types[i] ==
+					      s->s3->tlsext_authz_client_types[i-1])
+						{
+						*al = TLS1_AD_DECODE_ERROR;
+						return 0;
+						}
+					}
+				}
+			}
+
+		/* If this ClientHello extension was unhandled and this is 
+		 * a nonresumed connection, check whether the extension is a 
+		 * custom TLS Extension (has a custom_srv_ext_record), and if
+		 * so call the callback and record the extension number so that
+		 * an appropriate ServerHello may be later returned.
+		 */
+		else if (!s->hit && s->ctx->custom_srv_ext_records_count)
+			{
+			custom_srv_ext_record *record;
+
+			for (i=0; i < s->ctx->custom_srv_ext_records_count; i++)
+				{
+				record = &s->ctx->custom_srv_ext_records[i];
+				if (type == record->ext_type)
+					{
+					size_t j;
+
+					/* Error on duplicate TLS Extensions */
+					for (j = 0; j < s->s3->tlsext_custom_types_count; j++)
+						{
+						if (type == s->s3->tlsext_custom_types[j])
+							{
+							*al = TLS1_AD_DECODE_ERROR;
+							return 0;
+							}
+						}
+
+					/* NULL callback still notes the extension */ 
+					if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
+						return 0;
+						
+					/* Add the (non-duplicated) entry */
+					s->s3->tlsext_custom_types_count++;
+					s->s3->tlsext_custom_types = OPENSSL_realloc(
+							s->s3->tlsext_custom_types,
+							s->s3->tlsext_custom_types_count * 2);
+					if (s->s3->tlsext_custom_types == NULL)
+						{
+						s->s3->tlsext_custom_types = 0;
+						*al = TLS1_AD_INTERNAL_ERROR;
+						return 0;
+						}
+					s->s3->tlsext_custom_types[
+							s->s3->tlsext_custom_types_count - 1] = type;
+					}						
+				}
+			}
+
+		data+=size;
+		}
+
+	*p = data;
+
+	ri_check:
+
+	/* Need RI if renegotiating */
+
+	if (!renegotiate_seen && s->renegotiate &&
+		!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+		{
+		*al = SSL_AD_HANDSHAKE_FAILURE;
+	 	OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+		return 0;
+		}
+	/* If no signature algorithms extension set default values */
+	if (!s->cert->peer_sigalgs)
+		ssl_cert_set_default_md(s->cert);
+
+	return 1;
+	}
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) 
+	{
+	int al = -1;
+	if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0) 
+		{
+		ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+		return 0;
+		}
+
+	if (ssl_check_clienthello_tlsext_early(s) <= 0) 
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_CLIENTHELLO_TLSEXT);
+		return 0;
+		}
+	return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
+ * elements of zero length are allowed and the set of elements must exactly fill
+ * the length of the block. */
+static char ssl_next_proto_validate(unsigned char *d, unsigned len)
+	{
+	unsigned int off = 0;
+
+	while (off < len)
+		{
+		if (d[off] == 0)
+			return 0;
+		off += d[off];
+		off++;
+		}
+
+	return off == len;
+	}
+#endif
+
+static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+	{
+	unsigned short length;
+	unsigned short type;
+	unsigned short size;
+	unsigned char *data = *p;
+	int tlsext_servername = 0;
+	int renegotiate_seen = 0;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+	s->s3->next_proto_neg_seen = 0;
+#endif
+
+	if (s->s3->alpn_selected)
+		{
+		OPENSSL_free(s->s3->alpn_selected);
+		s->s3->alpn_selected = NULL;
+		}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+	s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+	                       SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+#endif
+
+	if (data >= (d+n-2))
+		goto ri_check;
+
+	n2s(data,length);
+	if (data+length != d+n)
+		{
+		*al = SSL_AD_DECODE_ERROR;
+		return 0;
+		}
+
+	while(data <= (d+n-4))
+		{
+		n2s(data,type);
+		n2s(data,size);
+
+		if (data+size > (d+n))
+	   		goto ri_check;
+
+		if (s->tlsext_debug_cb)
+			s->tlsext_debug_cb(s, 1, type, data, size,
+						s->tlsext_debug_arg);
+
+		if (type == TLSEXT_TYPE_server_name)
+			{
+			if (s->tlsext_hostname == NULL || size > 0)
+				{
+				*al = TLS1_AD_UNRECOGNIZED_NAME;
+				return 0;
+				}
+			tlsext_servername = 1;   
+			}
+
+#ifndef OPENSSL_NO_EC
+		else if (type == TLSEXT_TYPE_ec_point_formats)
+			{
+			unsigned char *sdata = data;
+			int ecpointformatlist_length = *(sdata++);
+
+			if (ecpointformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = 0;
+			if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
+			if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+			memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+			fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+			sdata = s->session->tlsext_ecpointformatlist;
+			for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+				fprintf(stderr,"%i ",*(sdata++));
+			fprintf(stderr,"\n");
+#endif
+			}
+#endif /* OPENSSL_NO_EC */
+
+		else if (type == TLSEXT_TYPE_session_ticket)
+			{
+			if (s->tls_session_ticket_ext_cb &&
+			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+				|| (size > 0))
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+			s->tlsext_ticket_expected = 1;
+			}
+#ifdef TLSEXT_TYPE_opaque_prf_input
+		else if (type == TLSEXT_TYPE_opaque_prf_input)
+			{
+			unsigned char *sdata = data;
+
+			if (size < 2)
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			n2s(sdata, s->s3->server_opaque_prf_input_len);
+			if (s->s3->server_opaque_prf_input_len != size - 2)
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			
+			if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+				OPENSSL_free(s->s3->server_opaque_prf_input);
+			if (s->s3->server_opaque_prf_input_len == 0)
+				s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+			else
+				s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
+
+			if (s->s3->server_opaque_prf_input == NULL)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			}
+#endif
+		else if (type == TLSEXT_TYPE_status_request)
+			{
+			/* MUST be empty and only sent if we've requested
+			 * a status request message.
+			 */ 
+			if ((s->tlsext_status_type == -1) || (size > 0))
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+			/* Set flag to expect CertificateStatus message */
+			s->tlsext_status_expected = 1;
+			}
+#ifndef OPENSSL_NO_NEXTPROTONEG
+		else if (type == TLSEXT_TYPE_next_proto_neg &&
+			 s->s3->tmp.finish_md_len == 0)
+			{
+			unsigned char *selected;
+			unsigned char selected_len;
+
+			/* We must have requested it. */
+			if (s->ctx->next_proto_select_cb == NULL)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+			/* The data must be valid */
+			if (!ssl_next_proto_validate(data, size))
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			s->next_proto_negotiated = OPENSSL_malloc(selected_len);
+			if (!s->next_proto_negotiated)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			memcpy(s->next_proto_negotiated, selected, selected_len);
+			s->next_proto_negotiated_len = selected_len;
+			s->s3->next_proto_neg_seen = 1;
+			}
+#endif
+
+		else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation)
+			{
+			unsigned len;
+
+			/* We must have requested it. */
+			if (s->alpn_client_proto_list == NULL)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+			if (size < 4)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			/* The extension data consists of:
+			 *   uint16 list_length
+			 *   uint8 proto_length;
+			 *   uint8 proto[proto_length]; */
+			len = data[0];
+			len <<= 8;
+			len |= data[1];
+			if (len != (unsigned) size - 2)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			len = data[2];
+			if (len != (unsigned) size - 3)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			if (s->s3->alpn_selected)
+				OPENSSL_free(s->s3->alpn_selected);
+			s->s3->alpn_selected = OPENSSL_malloc(len);
+			if (!s->s3->alpn_selected)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			memcpy(s->s3->alpn_selected, data + 3, len);
+			s->s3->alpn_selected_len = len;
+			}
+
+		else if (type == TLSEXT_TYPE_renegotiate)
+			{
+			if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
+				return 0;
+			renegotiate_seen = 1;
+			}
+#ifndef OPENSSL_NO_HEARTBEATS
+		else if (type == TLSEXT_TYPE_heartbeat)
+			{
+			switch(data[0])
+				{
+				case 0x01:	/* Server allows us to send HB requests */
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+							break;
+				case 0x02:	/* Server doesn't accept HB requests */
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+							s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+							break;
+				default:	*al = SSL_AD_ILLEGAL_PARAMETER;
+							return 0;
+				}
+			}
+#endif
+		else if (type == TLSEXT_TYPE_use_srtp)
+                        {
+                        if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
+							      al))
+                                return 0;
+                        }
+
+		else if (type == TLSEXT_TYPE_server_authz)
+			{
+			/* We only support audit proofs. It's an error to send
+			 * an authz hello extension if the client
+			 * didn't request a proof. */
+			unsigned char *sdata = data;
+			unsigned char server_authz_dataformatlist_length;
+
+			if (!s->ctx->tlsext_authz_server_audit_proof_cb)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+
+			if (!size)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			server_authz_dataformatlist_length = *(sdata++);
+			if (server_authz_dataformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			/* We only support audit proofs, so a legal ServerHello
+			 * authz list contains exactly one entry. */
+			if (server_authz_dataformatlist_length != 1 ||
+				sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+
+			s->s3->tlsext_authz_server_promised = 1;
+			}
+
+		/* If this extension type was not otherwise handled, but 
+		 * matches a custom_cli_ext_record, then send it to the c
+		 * callback */
+		else if (s->ctx->custom_cli_ext_records_count)
+			{
+			size_t i;
+			custom_cli_ext_record* record;
+
+			for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+				{
+				record = &s->ctx->custom_cli_ext_records[i];
+				if (record->ext_type == type)
+					{
+					if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg))
+						return 0;
+					break;
+					}
+				}			
+			}
+ 
+		data += size;
+		}
+
+	if (data != d+n)
+		{
+		*al = SSL_AD_DECODE_ERROR;
+		return 0;
+		}
+
+	if (!s->hit && tlsext_servername == 1)
+		{
+ 		if (s->tlsext_hostname)
+			{
+			if (s->session->tlsext_hostname == NULL)
+				{
+				s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);	
+				if (!s->session->tlsext_hostname)
+					{
+					*al = SSL_AD_UNRECOGNIZED_NAME;
+					return 0;
+					}
+				}
+			else 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			}
+		}
+
+	*p = data;
+
+	ri_check:
+
+	/* Determine if we need to see RI. Strictly speaking if we want to
+	 * avoid an attack we should *always* see RI even on initial server
+	 * hello because the client doesn't see any renegotiation during an
+	 * attack. However this would mean we could not connect to any server
+	 * which doesn't support RI so for the immediate future tolerate RI
+	 * absence on initial connect only.
+	 */
+	if (!renegotiate_seen
+		&& !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+		&& !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+		{
+		*al = SSL_AD_HANDSHAKE_FAILURE;
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+		return 0;
+		}
+
+	return 1;
+	}
+
+
+int ssl_prepare_clienthello_tlsext(SSL *s)
+	{
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ 	{
+		int r = 1;
+	
+		if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+			{
+			r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+			if (!r)
+				return -1;
+			}
+
+		if (s->tlsext_opaque_prf_input != NULL)
+			{
+			if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+				OPENSSL_free(s->s3->client_opaque_prf_input);
+
+			if (s->tlsext_opaque_prf_input_len == 0)
+				s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+			else
+				s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+			if (s->s3->client_opaque_prf_input == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_MALLOC_FAILURE);
+				return -1;
+				}
+			s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+			}
+
+		if (r == 2)
+			/* at callback's request, insist on receiving an appropriate server opaque PRF input */
+			s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+	}
+#endif
+
+	return 1;
+	}
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+	{
+	return 1;
+	}
+
+static int ssl_check_clienthello_tlsext_early(SSL *s)
+	{
+	int ret=SSL_TLSEXT_ERR_NOACK;
+	int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+	/* The handling of the ECPointFormats extension is done elsewhere, namely in 
+	 * ssl3_choose_cipher in s3_lib.c.
+	 */
+	/* The handling of the EllipticCurves extension is done elsewhere, namely in 
+	 * ssl3_choose_cipher in s3_lib.c.
+	 */
+#endif
+
+	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+	else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) 		
+		ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ 	{
+		/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
+		 * but we might be sending an alert in response to the client hello,
+		 * so this has to happen here in
+		 * ssl_check_clienthello_tlsext_early(). */
+
+		int r = 1;
+	
+		if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+			{
+			r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+			if (!r)
+				{
+				ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+				al = SSL_AD_INTERNAL_ERROR;
+				goto err;
+				}
+			}
+
+		if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+			OPENSSL_free(s->s3->server_opaque_prf_input);
+		s->s3->server_opaque_prf_input = NULL;
+
+		if (s->tlsext_opaque_prf_input != NULL)
+			{
+			if (s->s3->client_opaque_prf_input != NULL &&
+				s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
+				{
+				/* can only use this extension if we have a server opaque PRF input
+				 * of the same length as the client opaque PRF input! */
+
+				if (s->tlsext_opaque_prf_input_len == 0)
+					s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+				else
+					s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+				if (s->s3->server_opaque_prf_input == NULL)
+					{
+					ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+					al = SSL_AD_INTERNAL_ERROR;
+					goto err;
+					}
+				s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+				}
+			}
+
+		if (r == 2 && s->s3->server_opaque_prf_input == NULL)
+			{
+			/* The callback wants to enforce use of the extension,
+			 * but we can't do that with the client opaque PRF input;
+			 * abort the handshake.
+			 */
+			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+			al = SSL_AD_HANDSHAKE_FAILURE;
+			}
+	}
+
+ err:
+#endif
+	switch (ret)
+		{
+		case SSL_TLSEXT_ERR_ALERT_FATAL:
+			ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+			return -1;
+
+		case SSL_TLSEXT_ERR_ALERT_WARNING:
+			ssl3_send_alert(s,SSL3_AL_WARNING,al);
+			return 1; 
+					
+		case SSL_TLSEXT_ERR_NOACK:
+			s->servername_done=0;
+			default:
+		return 1;
+		}
+	}
+
+int ssl_check_clienthello_tlsext_late(SSL *s)
+	{
+	int ret = SSL_TLSEXT_ERR_OK;
+	int al;
+
+	/* If status request then ask callback what to do.
+ 	 * Note: this must be called after servername callbacks in case
+ 	 * the certificate has changed, and must be called after the cipher
+	 * has been chosen because this may influence which certificate is sent
+ 	 */
+	if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+		{
+		int r;
+		CERT_PKEY *certpkey;
+		certpkey = ssl_get_server_send_pkey(s);
+		/* If no certificate can't return certificate status */
+		if (certpkey == NULL)
+			{
+			s->tlsext_status_expected = 0;
+			return 1;
+			}
+		/* Set current certificate to one we will use so
+		 * SSL_get_certificate et al can pick it up.
+		 */
+		s->cert->key = certpkey;
+		r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+		switch (r)
+			{
+			/* We don't want to send a status request response */
+			case SSL_TLSEXT_ERR_NOACK:
+				s->tlsext_status_expected = 0;
+				break;
+			/* status request response should be sent */
+			case SSL_TLSEXT_ERR_OK:
+				if (s->tlsext_ocsp_resp)
+					s->tlsext_status_expected = 1;
+				else
+					s->tlsext_status_expected = 0;
+				break;
+			/* something bad happened */
+			case SSL_TLSEXT_ERR_ALERT_FATAL:
+				ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+				al = SSL_AD_INTERNAL_ERROR;
+				goto err;
+			}
+		}
+	else
+		s->tlsext_status_expected = 0;
+
+ err:
+	switch (ret)
+		{
+		case SSL_TLSEXT_ERR_ALERT_FATAL:
+			ssl3_send_alert(s, SSL3_AL_FATAL, al);
+			return -1;
+
+		case SSL_TLSEXT_ERR_ALERT_WARNING:
+			ssl3_send_alert(s, SSL3_AL_WARNING, al);
+			return 1; 
+
+		default:
+			return 1;
+		}
+	}
+
+int ssl_check_serverhello_tlsext(SSL *s)
+	{
+	int ret=SSL_TLSEXT_ERR_NOACK;
+	int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+	/* If we are client and using an elliptic curve cryptography cipher
+	 * suite, then if server returns an EC point formats lists extension
+	 * it must contain uncompressed.
+	 */
+	unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+	unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+	if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && 
+	    (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && 
+	    ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
+		{
+		/* we are using an ECC cipher */
+		size_t i;
+		unsigned char *list;
+		int found_uncompressed = 0;
+		list = s->session->tlsext_ecpointformatlist;
+		for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+			{
+			if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+				{
+				found_uncompressed = 1;
+				break;
+				}
+			}
+		if (!found_uncompressed)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+			return -1;
+			}
+		}
+	ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
+	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+	else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) 		
+		ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+	if (s->s3->server_opaque_prf_input_len > 0)
+		{
+		/* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
+		 * So first verify that we really have a value from the server too. */
+
+		if (s->s3->server_opaque_prf_input == NULL)
+			{
+			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+			al = SSL_AD_HANDSHAKE_FAILURE;
+			}
+		
+		/* Anytime the server *has* sent an opaque PRF input, we need to check
+		 * that we have a client opaque PRF input of the same size. */
+		if (s->s3->client_opaque_prf_input == NULL ||
+		    s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
+			{
+			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+			al = SSL_AD_ILLEGAL_PARAMETER;
+			}
+		}
+#endif
+
+	/* If we've requested certificate status and we wont get one
+ 	 * tell the callback
+ 	 */
+	if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+			&& s->ctx && s->ctx->tlsext_status_cb)
+		{
+		int r;
+		/* Set resp to NULL, resplen to -1 so callback knows
+ 		 * there is no response.
+ 		 */
+		if (s->tlsext_ocsp_resp)
+			{
+			OPENSSL_free(s->tlsext_ocsp_resp);
+			s->tlsext_ocsp_resp = NULL;
+			}
+		s->tlsext_ocsp_resplen = -1;
+		r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+		if (r == 0)
+			{
+			al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+			}
+		if (r < 0)
+			{
+			al = SSL_AD_INTERNAL_ERROR;
+			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+			}
+		}
+
+	switch (ret)
+		{
+		case SSL_TLSEXT_ERR_ALERT_FATAL:
+			ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+			return -1;
+
+		case SSL_TLSEXT_ERR_ALERT_WARNING:
+			ssl3_send_alert(s,SSL3_AL_WARNING,al);
+			return 1; 
+					
+		case SSL_TLSEXT_ERR_NOACK:
+			s->servername_done=0;
+			default:
+		return 1;
+		}
+	}
+
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) 
+	{
+	int al = -1;
+	if (s->version < SSL3_VERSION)
+		return 1;
+	if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0) 
+		{
+		ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+		return 0;
+		}
+
+	if (ssl_check_serverhello_tlsext(s) <= 0) 
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_SERVERHELLO_TLSEXT);
+		return 0;
+		}
+	return 1;
+}
+
+/* Since the server cache lookup is done early on in the processing of the
+ * ClientHello, and other operations depend on the result, we need to handle
+ * any TLS session ticket extension at the same time.
+ *
+ *   session_id: points at the session ID in the ClientHello. This code will
+ *       read past the end of this in order to parse out the session ticket
+ *       extension, if any.
+ *   len: the length of the session ID.
+ *   limit: a pointer to the first byte after the ClientHello.
+ *   ret: (output) on return, if a ticket was decrypted, then this is set to
+ *       point to the resulting session.
+ *
+ * If s->tls_session_secret_cb is set then we are expecting a pre-shared key
+ * ciphersuite, in which case we have no use for session tickets and one will
+ * never be decrypted, nor will s->tlsext_ticket_expected be set to 1.
+ *
+ * Returns:
+ *   -1: fatal error, either from parsing or decrypting the ticket.
+ *    0: no ticket was found (or was ignored, based on settings).
+ *    1: a zero length extension was found, indicating that the client supports
+ *       session tickets but doesn't currently have one to offer.
+ *    2: either s->tls_session_secret_cb was set, or a ticket was offered but
+ *       couldn't be decrypted because of a non-fatal error.
+ *    3: a ticket was successfully decrypted and *ret was set.
+ *
+ * Side effects:
+ *   Sets s->tlsext_ticket_expected to 1 if the server will have to issue
+ *   a new session ticket to the client because the client indicated support
+ *   (and s->tls_session_secret_cb is NULL) but the client either doesn't have
+ *   a session ticket or we couldn't use the one it gave us, or if
+ *   s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket.
+ *   Otherwise, s->tlsext_ticket_expected is set to 0.
+ */
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+			const unsigned char *limit, SSL_SESSION **ret)
+	{
+	/* Point after session ID in client hello */
+	const unsigned char *p = session_id + len;
+	unsigned short i;
+
+	*ret = NULL;
+	s->tlsext_ticket_expected = 0;
+
+	/* If tickets disabled behave as if no ticket present
+	 * to permit stateful resumption.
+	 */
+	if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+		return 0;
+	if ((s->version <= SSL3_VERSION) || !limit)
+		return 0;
+	if (p >= limit)
+		return -1;
+	/* Skip past DTLS cookie */
+	if (SSL_IS_DTLS(s))
+		{
+		i = *(p++);
+		p+= i;
+		if (p >= limit)
+			return -1;
+		}
+	/* Skip past cipher list */
+	n2s(p, i);
+	p+= i;
+	if (p >= limit)
+		return -1;
+	/* Skip past compression algorithm list */
+	i = *(p++);
+	p += i;
+	if (p > limit)
+		return -1;
+	/* Now at start of extensions */
+	if ((p + 2) >= limit)
+		return 0;
+	n2s(p, i);
+	while ((p + 4) <= limit)
+		{
+		unsigned short type, size;
+		n2s(p, type);
+		n2s(p, size);
+		if (p + size > limit)
+			return 0;
+		if (type == TLSEXT_TYPE_session_ticket)
+			{
+			int r;
+			if (size == 0)
+				{
+				/* The client will accept a ticket but doesn't
+				 * currently have one. */
+				s->tlsext_ticket_expected = 1;
+				return 1;
+				}
+			if (s->tls_session_secret_cb)
+				{
+				/* Indicate that the ticket couldn't be
+				 * decrypted rather than generating the session
+				 * from ticket now, trigger abbreviated
+				 * handshake based on external mechanism to
+				 * calculate the master secret later. */
+				return 2;
+				}
+			r = tls_decrypt_ticket(s, p, size, session_id, len, ret);
+			switch (r)
+				{
+				case 2: /* ticket couldn't be decrypted */
+					s->tlsext_ticket_expected = 1;
+					return 2;
+				case 3: /* ticket was decrypted */
+					return r;
+				case 4: /* ticket decrypted but need to renew */
+					s->tlsext_ticket_expected = 1;
+					return 3;
+				default: /* fatal error */
+					return -1;
+				}
+			}
+		p += size;
+		}
+	return 0;
+	}
+
+/* tls_decrypt_ticket attempts to decrypt a session ticket.
+ *
+ *   etick: points to the body of the session ticket extension.
+ *   eticklen: the length of the session tickets extenion.
+ *   sess_id: points at the session ID.
+ *   sesslen: the length of the session ID.
+ *   psess: (output) on return, if a ticket was decrypted, then this is set to
+ *       point to the resulting session.
+ *
+ * Returns:
+ *   -1: fatal error, either from parsing or decrypting the ticket.
+ *    2: the ticket couldn't be decrypted.
+ *    3: a ticket was successfully decrypted and *psess was set.
+ *    4: same as 3, but the ticket needs to be renewed.
+ */
+static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
+				const unsigned char *sess_id, int sesslen,
+				SSL_SESSION **psess)
+	{
+	SSL_SESSION *sess;
+	unsigned char *sdec;
+	const unsigned char *p;
+	int slen, mlen, renew_ticket = 0;
+	unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+	HMAC_CTX hctx;
+	EVP_CIPHER_CTX ctx;
+	SSL_CTX *tctx = s->initial_ctx;
+	/* Need at least keyname + iv + some encrypted data */
+	if (eticklen < 48)
+		return 2;
+	/* Initialize session ticket encryption and HMAC contexts */
+	HMAC_CTX_init(&hctx);
+	EVP_CIPHER_CTX_init(&ctx);
+	if (tctx->tlsext_ticket_key_cb)
+		{
+		unsigned char *nctick = (unsigned char *)etick;
+		int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+							&ctx, &hctx, 0);
+		if (rv < 0)
+			return -1;
+		if (rv == 0)
+			return 2;
+		if (rv == 2)
+			renew_ticket = 1;
+		}
+	else
+		{
+		/* Check key name matches */
+		if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
+			return 2;
+		HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+					tlsext_tick_md(), NULL);
+		EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+				tctx->tlsext_tick_aes_key, etick + 16);
+		}
+	/* Attempt to process session ticket, first conduct sanity and
+	 * integrity checks on ticket.
+	 */
+	mlen = HMAC_size(&hctx);
+	if (mlen < 0)
+		{
+		EVP_CIPHER_CTX_cleanup(&ctx);
+		return -1;
+		}
+	eticklen -= mlen;
+	/* Check HMAC of encrypted ticket */
+	HMAC_Update(&hctx, etick, eticklen);
+	HMAC_Final(&hctx, tick_hmac, NULL);
+	HMAC_CTX_cleanup(&hctx);
+	if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
+		return 2;
+	/* Attempt to decrypt session data */
+	/* Move p after IV to start of encrypted ticket, update length */
+	p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+	eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+	sdec = OPENSSL_malloc(eticklen);
+	if (!sdec)
+		{
+		EVP_CIPHER_CTX_cleanup(&ctx);
+		return -1;
+		}
+	EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
+	if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0)
+		return 2;
+	slen += mlen;
+	EVP_CIPHER_CTX_cleanup(&ctx);
+	p = sdec;
+
+	sess = d2i_SSL_SESSION(NULL, &p, slen);
+	OPENSSL_free(sdec);
+	if (sess)
+		{
+		/* The session ID, if non-empty, is used by some clients to
+		 * detect that the ticket has been accepted. So we copy it to
+		 * the session structure. If it is empty set length to zero
+		 * as required by standard.
+		 */
+		if (sesslen)
+			memcpy(sess->session_id, sess_id, sesslen);
+		sess->session_id_length = sesslen;
+		*psess = sess;
+		if (renew_ticket)
+			return 4;
+		else
+			return 3;
+		}
+        ERR_clear_error();
+	/* For session parse failure, indicate that we need to send a new
+	 * ticket. */
+	return 2;
+	}
+
+/* Tables to translate from NIDs to TLS v1.2 ids */
+
+typedef struct 
+	{
+	int nid;
+	int id;
+	} tls12_lookup;
+
+static tls12_lookup tls12_md[] = {
+	{NID_md5, TLSEXT_hash_md5},
+	{NID_sha1, TLSEXT_hash_sha1},
+	{NID_sha224, TLSEXT_hash_sha224},
+	{NID_sha256, TLSEXT_hash_sha256},
+	{NID_sha384, TLSEXT_hash_sha384},
+	{NID_sha512, TLSEXT_hash_sha512}
+};
+
+static tls12_lookup tls12_sig[] = {
+	{EVP_PKEY_RSA, TLSEXT_signature_rsa},
+	{EVP_PKEY_DSA, TLSEXT_signature_dsa},
+	{EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+};
+
+static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
+	{
+	size_t i;
+	for (i = 0; i < tlen; i++)
+		{
+		if (table[i].nid == nid)
+			return table[i].id;
+		}
+	return -1;
+	}
+
+static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
+	{
+	size_t i;
+	for (i = 0; i < tlen; i++)
+		{
+		if ((table[i].id) == id)
+			return table[i].nid;
+		}
+	return NID_undef;
+	}
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
+	{
+	int sig_id, md_id;
+	if (!md)
+		return 0;
+	md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
+				sizeof(tls12_md)/sizeof(tls12_lookup));
+	if (md_id == -1)
+		return 0;
+	sig_id = tls12_get_sigid(pk);
+	if (sig_id == -1)
+		return 0;
+	p[0] = (unsigned char)md_id;
+	p[1] = (unsigned char)sig_id;
+	return 1;
+	}
+
+int tls12_get_sigid(const EVP_PKEY *pk)
+	{
+	return tls12_find_id(pk->type, tls12_sig,
+				sizeof(tls12_sig)/sizeof(tls12_lookup));
+	}
+
+const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+	{
+	switch(hash_alg)
+		{
+#ifndef OPENSSL_NO_MD5
+		case TLSEXT_hash_md5:
+#ifdef OPENSSL_FIPS
+		if (FIPS_mode())
+			return NULL;
+#endif
+		return EVP_md5();
+#endif
+#ifndef OPENSSL_NO_SHA
+		case TLSEXT_hash_sha1:
+		return EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_SHA256
+		case TLSEXT_hash_sha224:
+		return EVP_sha224();
+
+		case TLSEXT_hash_sha256:
+		return EVP_sha256();
+#endif
+#ifndef OPENSSL_NO_SHA512
+		case TLSEXT_hash_sha384:
+		return EVP_sha384();
+
+		case TLSEXT_hash_sha512:
+		return EVP_sha512();
+#endif
+		default:
+		return NULL;
+
+		}
+	}
+
+static int tls12_get_pkey_idx(unsigned char sig_alg)
+	{
+	switch(sig_alg)
+		{
+#ifndef OPENSSL_NO_RSA
+	case TLSEXT_signature_rsa:
+		return SSL_PKEY_RSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_DSA
+	case TLSEXT_signature_dsa:
+		return SSL_PKEY_DSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+	case TLSEXT_signature_ecdsa:
+		return SSL_PKEY_ECC;
+#endif
+		}
+	return -1;
+	}
+
+/* Convert TLS 1.2 signature algorithm extension values into NIDs */
+static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
+			int *psignhash_nid, const unsigned char *data)
+	{
+	int sign_nid = 0, hash_nid = 0;
+	if (!phash_nid && !psign_nid && !psignhash_nid)
+		return;
+	if (phash_nid || psignhash_nid)
+		{
+		hash_nid = tls12_find_nid(data[0], tls12_md,
+					sizeof(tls12_md)/sizeof(tls12_lookup));
+		if (phash_nid)
+			*phash_nid = hash_nid;
+		}
+	if (psign_nid || psignhash_nid)
+		{
+		sign_nid = tls12_find_nid(data[1], tls12_sig,
+					sizeof(tls12_sig)/sizeof(tls12_lookup));
+		if (psign_nid)
+			*psign_nid = sign_nid;
+		}
+	if (psignhash_nid)
+		{
+		if (sign_nid && hash_nid)
+			OBJ_find_sigid_by_algs(psignhash_nid,
+							hash_nid, sign_nid);
+		else
+			*psignhash_nid = NID_undef;
+		}
+	}
+/* Given preference and allowed sigalgs set shared sigalgs */
+static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
+				const unsigned char *pref, size_t preflen,
+				const unsigned char *allow, size_t allowlen)
+	{
+	const unsigned char *ptmp, *atmp;
+	size_t i, j, nmatch = 0;
+	for (i = 0, ptmp = pref; i < preflen; i+=2, ptmp+=2)
+		{
+		/* Skip disabled hashes or signature algorithms */
+		if (tls12_get_hash(ptmp[0]) == NULL)
+			continue;
+		if (tls12_get_pkey_idx(ptmp[1]) == -1)
+			continue;
+		for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
+			{
+			if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1])
+				{
+				nmatch++;
+				if (shsig)
+					{
+					shsig->rhash = ptmp[0];
+					shsig->rsign = ptmp[1];
+					tls1_lookup_sigalg(&shsig->hash_nid,
+						&shsig->sign_nid,
+						&shsig->signandhash_nid,
+						ptmp);
+					shsig++;
+					}
+				break;
+				}
+			}
+		}
+	return nmatch;
+	}
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+	{
+	const unsigned char *pref, *allow, *conf;
+	size_t preflen, allowlen, conflen;
+	size_t nmatch;
+	TLS_SIGALGS *salgs = NULL;
+	CERT *c = s->cert;
+	unsigned int is_suiteb = tls1_suiteb(s);
+	/* If client use client signature algorithms if not NULL */
+	if (!s->server && c->client_sigalgs && !is_suiteb)
+		{
+		conf = c->client_sigalgs;
+		conflen = c->client_sigalgslen;
+		}
+	else if (c->conf_sigalgs && !is_suiteb)
+		{
+		conf = c->conf_sigalgs;
+		conflen = c->conf_sigalgslen;
+		}
+	else
+		conflen = tls12_get_psigalgs(s, &conf);
+	if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb)
+		{
+		pref = conf;
+		preflen = conflen;
+		allow = c->peer_sigalgs;
+		allowlen = c->peer_sigalgslen;
+		}
+	else
+		{
+		allow = conf;
+		allowlen = conflen;
+		pref = c->peer_sigalgs;
+		preflen = c->peer_sigalgslen;
+		}
+	nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
+	if (!nmatch)
+		return 1;
+	salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+	if (!salgs)
+		return 0;
+	nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
+	c->shared_sigalgs = salgs;
+	c->shared_sigalgslen = nmatch;
+	return 1;
+	}
+		
+
+/* Set preferred digest for each key type */
+
+int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+	{
+	int idx;
+	size_t i;
+	const EVP_MD *md;
+	CERT *c = s->cert;
+	TLS_SIGALGS *sigptr;
+	/* Extension ignored for inappropriate versions */
+	if (!SSL_USE_SIGALGS(s))
+		return 1;
+	/* Should never happen */
+	if (!c)
+		return 0;
+
+	c->peer_sigalgs = OPENSSL_malloc(dsize);
+	if (!c->peer_sigalgs)
+		return 0;
+	c->peer_sigalgslen = dsize;
+	memcpy(c->peer_sigalgs, data, dsize);
+
+	tls1_set_shared_sigalgs(s);
+
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+	if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+		{
+		/* Use first set signature preference to force message
+		 * digest, ignoring any peer preferences.
+		 */
+		const unsigned char *sigs = NULL;
+		if (s->server)
+			sigs = c->conf_sigalgs;
+		else
+			sigs = c->client_sigalgs;
+		if (sigs)
+			{
+			idx = tls12_get_pkey_idx(sigs[1]);
+			md = tls12_get_hash(sigs[0]);
+			c->pkeys[idx].digest = md;
+			c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+			if (idx == SSL_PKEY_RSA_SIGN)
+				{
+				c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+				c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+				}
+			}
+		}
+#endif
+
+	for (i = 0, sigptr = c->shared_sigalgs;
+			i < c->shared_sigalgslen; i++, sigptr++)
+		{
+		idx = tls12_get_pkey_idx(sigptr->rsign);
+		if (idx > 0 && c->pkeys[idx].digest == NULL)
+			{
+			md = tls12_get_hash(sigptr->rhash);
+			c->pkeys[idx].digest = md;
+			c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+			if (idx == SSL_PKEY_RSA_SIGN)
+				{
+				c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+				c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+				}
+			}
+
+		}
+	/* In strict mode leave unset digests as NULL to indicate we can't
+	 * use the certificate for signing.
+	 */
+	if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
+		{
+		/* Set any remaining keys to default values. NOTE: if alg is
+		 * not supported it stays as NULL.
+	 	 */
+#ifndef OPENSSL_NO_DSA
+		if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
+			c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_RSA
+		if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
+			{
+			c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+			c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+			}
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (!c->pkeys[SSL_PKEY_ECC].digest)
+			c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+#endif
+		}
+	return 1;
+	}
+
+
+int SSL_get_sigalgs(SSL *s, int idx,
+			int *psign, int *phash, int *psignhash,
+			unsigned char *rsig, unsigned char *rhash)
+	{
+	const unsigned char *psig = s->cert->peer_sigalgs;
+	if (psig == NULL)
+		return 0;
+	if (idx >= 0)
+		{
+		idx <<= 1;
+		if (idx >= (int)s->cert->peer_sigalgslen)
+			return 0;
+		psig += idx;
+		if (rhash)
+			*rhash = psig[0];
+		if (rsig)
+			*rsig = psig[1];
+		tls1_lookup_sigalg(phash, psign, psignhash, psig);
+		}
+	return s->cert->peer_sigalgslen / 2;
+	}
+
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+			int *psign, int *phash, int *psignhash,
+			unsigned char *rsig, unsigned char *rhash)
+	{
+	TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
+	if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen)
+		return 0;
+	shsigalgs += idx;
+	if (phash)
+		*phash = shsigalgs->hash_nid;
+	if (psign)
+		*psign = shsigalgs->sign_nid;
+	if (psignhash)
+		*psignhash = shsigalgs->signandhash_nid;
+	if (rsig)
+		*rsig = shsigalgs->rsign;
+	if (rhash)
+		*rhash = shsigalgs->rhash;
+	return s->cert->shared_sigalgslen;
+	}
+	
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+tls1_process_heartbeat(SSL *s)
+	{
+	unsigned char *p = &s->s3->rrec.data[0], *pl;
+	unsigned short hbtype;
+	unsigned int payload;
+	unsigned int padding = 16; /* Use minimum padding */
+
+	/* Read type and payload length first */
+	hbtype = *p++;
+	n2s(p, payload);
+	pl = p;
+
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+			&s->s3->rrec.data[0], s->s3->rrec.length,
+			s, s->msg_callback_arg);
+
+	if (hbtype == TLS1_HB_REQUEST)
+		{
+		unsigned char *buffer, *bp;
+		int r;
+
+		/* Allocate memory for the response, size is 1 bytes
+		 * message type, plus 2 bytes payload length, plus
+		 * payload, plus padding
+		 */
+		buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+		bp = buffer;
+		
+		/* Enter response type, length and copy payload */
+		*bp++ = TLS1_HB_RESPONSE;
+		s2n(payload, bp);
+		memcpy(bp, pl, payload);
+		bp += payload;
+		/* Random padding */
+		RAND_pseudo_bytes(bp, padding);
+
+		r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+		if (r >= 0 && s->msg_callback)
+			s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+				buffer, 3 + payload + padding,
+				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)
+			{
+			s->tlsext_hb_seq++;
+			s->tlsext_hb_pending = 0;
+			}
+		}
+
+	return 0;
+	}
+
+int
+tls1_heartbeat(SSL *s)
+	{
+	unsigned char *buf, *p;
+	int ret;
+	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)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+		return -1;
+		}
+
+	/* ...and there is none in flight yet... */
+	if (s->tlsext_hb_pending)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_HEARTBEAT_PENDING);
+		return -1;
+		}
+		
+	/* ...and no handshake in progress. */
+	if (SSL_in_init(s) || s->in_handshake)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, 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.
+	 */
+	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);
+	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 */
+	RAND_pseudo_bytes(p, 16);
+	p += 16;
+	/* Random padding */
+	RAND_pseudo_bytes(p, padding);
+
+	ret = ssl3_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);
+
+		s->tlsext_hb_pending = 1;
+		}
+		
+	OPENSSL_free(buf);
+
+	return ret;
+	}
+#endif
+
+/* TODO(fork): remove */
+#if 0
+#define MAX_SIGALGLEN	(TLSEXT_hash_num * TLSEXT_signature_num * 2)
+
+typedef struct
+	{
+	size_t sigalgcnt;
+	int sigalgs[MAX_SIGALGLEN];
+	} sig_cb_st;
+
+static int sig_cb(const char *elem, int len, void *arg)
+	{
+	sig_cb_st *sarg = arg;
+	size_t i;
+	char etmp[20], *p;
+	int sig_alg, hash_alg;
+	if (sarg->sigalgcnt == MAX_SIGALGLEN)
+		return 0;
+	if (len > (int)(sizeof(etmp) - 1))
+		return 0;
+	memcpy(etmp, elem, len);
+	etmp[len] = 0;
+	p = strchr(etmp, '+');
+	if (!p)
+		return 0;
+	*p = 0;
+	p++;
+	if (!*p)
+		return 0;
+
+	if (!strcmp(etmp, "RSA"))
+		sig_alg = EVP_PKEY_RSA;
+	else if (!strcmp(etmp, "DSA"))
+		sig_alg = EVP_PKEY_DSA;
+	else if (!strcmp(etmp, "ECDSA"))
+		sig_alg = EVP_PKEY_EC;
+	else return 0;
+
+	hash_alg = OBJ_sn2nid(p);
+	if (hash_alg == NID_undef)
+		hash_alg = OBJ_ln2nid(p);
+	if (hash_alg == NID_undef)
+		return 0;
+
+	for (i = 0; i < sarg->sigalgcnt; i+=2)
+		{
+		if (sarg->sigalgs[i] == sig_alg
+			&& sarg->sigalgs[i + 1] == hash_alg)
+			return 0;
+		}
+	sarg->sigalgs[sarg->sigalgcnt++] = hash_alg;
+	sarg->sigalgs[sarg->sigalgcnt++] = sig_alg;
+	return 1;
+	}
+
+/* Set suppored signature algorithms based on a colon separated list
+ * of the form sig+hash e.g. RSA+SHA512:DSA+SHA512 */
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
+	{
+	sig_cb_st sig;
+	sig.sigalgcnt = 0;
+	if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+		return 0;
+	if (c == NULL)
+		return 1;
+	return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
+	}
+#endif
+
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
+	{
+	unsigned char *sigalgs, *sptr;
+	int rhash, rsign;
+	size_t i;
+	if (salglen & 1)
+		return 0;
+	sigalgs = OPENSSL_malloc(salglen);
+	if (sigalgs == NULL)
+		return 0;
+	for (i = 0, sptr = sigalgs; i < salglen; i+=2)
+		{
+		rhash = tls12_find_id(*psig_nids++, tls12_md,
+					sizeof(tls12_md)/sizeof(tls12_lookup));
+		rsign = tls12_find_id(*psig_nids++, tls12_sig,
+				sizeof(tls12_sig)/sizeof(tls12_lookup));
+
+		if (rhash == -1 || rsign == -1)
+			goto err;
+		*sptr++ = rhash;
+		*sptr++ = rsign;
+		}
+
+	if (client)
+		{
+		if (c->client_sigalgs)
+			OPENSSL_free(c->client_sigalgs);
+		c->client_sigalgs = sigalgs;
+		c->client_sigalgslen = salglen;
+		}
+	else
+		{
+		if (c->conf_sigalgs)
+			OPENSSL_free(c->conf_sigalgs);
+		c->conf_sigalgs = sigalgs;
+		c->conf_sigalgslen = salglen;
+		}
+
+	return 1;
+
+	err:
+	OPENSSL_free(sigalgs);
+	return 0;
+	}
+
+static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid)
+	{
+	int sig_nid;
+	size_t i;
+	if (default_nid == -1)
+		return 1;
+	sig_nid = X509_get_signature_nid(x);
+	if (default_nid)
+		return sig_nid == default_nid ? 1 : 0;
+	for (i = 0; i < c->shared_sigalgslen; i++)
+		if (sig_nid == c->shared_sigalgs[i].signandhash_nid)
+			return 1;
+	return 0;
+	}
+/* Check to see if a certificate issuer name matches list of CA names */
+static int ssl_check_ca_name(STACK_OF(X509_NAME) *names, X509 *x)
+	{
+	X509_NAME *nm;
+	int i;
+	nm = X509_get_issuer_name(x);
+	for (i = 0; i < sk_X509_NAME_num(names); i++)
+		{
+		if(!X509_NAME_cmp(nm, sk_X509_NAME_value(names, i)))
+			return 1;
+		}
+	return 0;
+	}
+
+/* Check certificate chain is consistent with TLS extensions and is
+ * usable by server. This servers two purposes: it allows users to 
+ * check chains before passing them to the server and it allows the
+ * server to check chains before attempting to use them.
+ */
+
+/* Flags which need to be set for a certificate when stict mode not set */
+
+#define CERT_PKEY_VALID_FLAGS \
+	(CERT_PKEY_EE_SIGNATURE|CERT_PKEY_EE_PARAM)
+/* Strict mode flags */
+#define CERT_PKEY_STRICT_FLAGS \
+	 (CERT_PKEY_VALID_FLAGS|CERT_PKEY_CA_SIGNATURE|CERT_PKEY_CA_PARAM \
+	 | CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE)
+
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+									int idx)
+	{
+	int i;
+	int rv = 0;
+	int check_flags = 0, strict_mode;
+	CERT_PKEY *cpk = NULL;
+	CERT *c = s->cert;
+	unsigned int suiteb_flags = tls1_suiteb(s);
+	/* idx == -1 means checking server chains */
+	if (idx != -1)
+		{
+		/* idx == -2 means checking client certificate chains */
+		if (idx == -2)
+			{
+			cpk = c->key;
+			idx = cpk - c->pkeys;
+			}
+		else
+			cpk = c->pkeys + idx;
+		x = cpk->x509;
+		pk = cpk->privatekey;
+		chain = cpk->chain;
+		strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
+		/* If no cert or key, forget it */
+		if (!x || !pk)
+			goto end;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+		/* Allow any certificate to pass test */
+		if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+			{
+			rv = CERT_PKEY_STRICT_FLAGS|CERT_PKEY_EXPLICIT_SIGN|CERT_PKEY_VALID|CERT_PKEY_SIGN;
+			cpk->valid_flags = rv;
+			return rv;
+			}
+#endif
+		}
+	else
+		{
+		if (!x || !pk)
+			goto end;
+		idx = ssl_cert_type(x, pk);
+		if (idx == -1)
+			goto end;
+		cpk = c->pkeys + idx;
+		if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+			check_flags = CERT_PKEY_STRICT_FLAGS;
+		else
+			check_flags = CERT_PKEY_VALID_FLAGS;
+		strict_mode = 1;
+		}
+
+	if (suiteb_flags)
+		{
+		int ok;
+		if (check_flags)
+			check_flags |= CERT_PKEY_SUITEB;
+		ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
+		if (ok != X509_V_OK)
+			{
+			if (check_flags)
+				rv |= CERT_PKEY_SUITEB;
+			else
+				goto end;
+			}
+		}
+
+	/* Check all signature algorithms are consistent with
+	 * signature algorithms extension if TLS 1.2 or later
+	 * and strict mode.
+	 */
+	if (TLS1_get_version(s) >= TLS1_2_VERSION && strict_mode)
+		{
+		int default_nid;
+		unsigned char rsign = 0;
+		if (c->peer_sigalgs)
+			default_nid = 0;
+		/* If no sigalgs extension use defaults from RFC5246 */
+		else
+			{
+			switch(idx)
+				{	
+			case SSL_PKEY_RSA_ENC:
+			case SSL_PKEY_RSA_SIGN:
+			case SSL_PKEY_DH_RSA:
+				rsign = TLSEXT_signature_rsa;
+				default_nid = NID_sha1WithRSAEncryption;
+				break;
+
+			case SSL_PKEY_DSA_SIGN:
+			case SSL_PKEY_DH_DSA:
+				rsign = TLSEXT_signature_dsa;
+				default_nid = NID_dsaWithSHA1;
+				break;
+
+			case SSL_PKEY_ECC:
+				rsign = TLSEXT_signature_ecdsa;
+				default_nid = NID_ecdsa_with_SHA1;
+				break;
+
+			default:
+				default_nid = -1;
+				break;
+				}
+			}
+		/* If peer sent no signature algorithms extension and we
+		 * have set preferred signature algorithms check we support
+		 * sha1.
+		 */
+		if (default_nid > 0 && c->conf_sigalgs)
+			{
+			size_t j;
+			const unsigned char *p = c->conf_sigalgs;
+			for (j = 0; j < c->conf_sigalgslen; j += 2, p += 2)
+				{
+				if (p[0] == TLSEXT_hash_sha1 && p[1] == rsign)
+					break;
+				}
+			if (j == c->conf_sigalgslen)
+				{
+				if (check_flags)
+					goto skip_sigs;
+				else
+					goto end;
+				}
+			}
+		/* Check signature algorithm of each cert in chain */
+		if (!tls1_check_sig_alg(c, x, default_nid))
+			{
+			if (!check_flags) goto end;
+			}
+		else
+			rv |= CERT_PKEY_EE_SIGNATURE;
+		rv |= CERT_PKEY_CA_SIGNATURE;
+		for (i = 0; i < sk_X509_num(chain); i++)
+			{
+			if (!tls1_check_sig_alg(c, sk_X509_value(chain, i),
+							default_nid))
+				{
+				if (check_flags)
+					{
+					rv &= ~CERT_PKEY_CA_SIGNATURE;
+					break;
+					}
+				else
+					goto end;
+				}
+			}
+		}
+	/* Else not TLS 1.2, so mark EE and CA signing algorithms OK */
+	else if(check_flags)
+		rv |= CERT_PKEY_EE_SIGNATURE|CERT_PKEY_CA_SIGNATURE;
+	skip_sigs:
+	/* Check cert parameters are consistent */
+	if (tls1_check_cert_param(s, x, check_flags ? 1 : 2))
+		rv |= CERT_PKEY_EE_PARAM;
+	else if (!check_flags)
+		goto end;
+	if (!s->server)
+		rv |= CERT_PKEY_CA_PARAM;
+	/* In strict mode check rest of chain too */
+	else if (strict_mode)
+		{
+		rv |= CERT_PKEY_CA_PARAM;
+		for (i = 0; i < sk_X509_num(chain); i++)
+			{
+			X509 *ca = sk_X509_value(chain, i);
+			if (!tls1_check_cert_param(s, ca, 0))
+				{
+				if (check_flags)
+					{
+					rv &= ~CERT_PKEY_CA_PARAM;
+					break;
+					}
+				else
+					goto end;
+				}
+			}
+		}
+	if (!s->server && strict_mode)
+		{
+		STACK_OF(X509_NAME) *ca_dn;
+		int check_type = 0;
+		switch (pk->type)
+			{
+		case EVP_PKEY_RSA:
+			check_type = TLS_CT_RSA_SIGN;
+			break;
+		case EVP_PKEY_DSA:
+			check_type = TLS_CT_DSS_SIGN;
+			break;
+		case EVP_PKEY_EC:
+			check_type = TLS_CT_ECDSA_SIGN;
+			break;
+		case EVP_PKEY_DH:
+		case EVP_PKEY_DHX:
+				{
+				int cert_type = X509_certificate_type(x, pk);
+				if (cert_type & EVP_PKS_RSA)
+					check_type = TLS_CT_RSA_FIXED_DH;
+				if (cert_type & EVP_PKS_DSA)
+					check_type = TLS_CT_DSS_FIXED_DH;
+				}
+			}
+		if (check_type)
+			{
+			const unsigned char *ctypes;
+			int ctypelen;
+			if (c->ctypes)
+				{
+				ctypes = c->ctypes;
+				ctypelen = (int)c->ctype_num;
+				}
+			else
+				{
+				ctypes = (unsigned char *)s->s3->tmp.ctype;
+				ctypelen = s->s3->tmp.ctype_num;
+				}
+			for (i = 0; i < ctypelen; i++)
+				{
+				if (ctypes[i] == check_type)
+					{
+					rv |= CERT_PKEY_CERT_TYPE;
+					break;
+					}
+				}
+			if (!(rv & CERT_PKEY_CERT_TYPE) && !check_flags)
+				goto end;
+			}
+		else
+			rv |= CERT_PKEY_CERT_TYPE;
+
+
+		ca_dn = s->s3->tmp.ca_names;
+
+		if (!sk_X509_NAME_num(ca_dn))
+			rv |= CERT_PKEY_ISSUER_NAME;
+
+		if (!(rv & CERT_PKEY_ISSUER_NAME))
+			{
+			if (ssl_check_ca_name(ca_dn, x))
+				rv |= CERT_PKEY_ISSUER_NAME;
+			}
+		if (!(rv & CERT_PKEY_ISSUER_NAME))
+			{
+			for (i = 0; i < sk_X509_num(chain); i++)
+				{
+				X509 *xtmp = sk_X509_value(chain, i);
+				if (ssl_check_ca_name(ca_dn, xtmp))
+					{
+					rv |= CERT_PKEY_ISSUER_NAME;
+					break;
+					}
+				}
+			}
+		if (!check_flags && !(rv & CERT_PKEY_ISSUER_NAME))
+			goto end;
+		}
+	else
+		rv |= CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE;
+
+	if (!check_flags || (rv & check_flags) == check_flags)
+		rv |= CERT_PKEY_VALID;
+
+	end:
+
+	if (TLS1_get_version(s) >= TLS1_2_VERSION)
+		{
+		if (cpk->valid_flags & CERT_PKEY_EXPLICIT_SIGN)
+			rv |= CERT_PKEY_EXPLICIT_SIGN|CERT_PKEY_SIGN;
+		else if (cpk->digest)
+			rv |= CERT_PKEY_SIGN;
+		}
+	else
+		rv |= CERT_PKEY_SIGN|CERT_PKEY_EXPLICIT_SIGN;
+
+	/* When checking a CERT_PKEY structure all flags are irrelevant
+	 * if the chain is invalid.
+	 */
+	if (!check_flags)
+		{
+		if (rv & CERT_PKEY_VALID)
+			cpk->valid_flags = rv;
+		else
+			{
+			/* Preserve explicit sign flag, clear rest */
+			cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;
+			return 0;
+			}
+		}
+	return rv;
+	}
+
+/* Set validity of certificates in an SSL structure */
+void tls1_set_cert_validity(SSL *s)
+	{
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_ENC);
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_SIGN);
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN);
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_RSA);
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_DSA);
+	tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
+	}
+/* User level utiity function to check a chain is suitable */
+int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+	{
+	return tls1_check_chain(s, x, pk, chain, -1);
+	}
+
+#endif
diff --git a/ssl/t1_meth.c b/ssl/t1_meth.c
new file mode 100644
index 0000000..313ce65
--- /dev/null
+++ b/ssl/t1_meth.c
@@ -0,0 +1,92 @@
+/* ssl/t1_meth.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/obj.h>
+
+#include "ssl_locl.h"
+
+
+static const SSL_METHOD *tls1_get_method(int ver)
+	{
+	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();
+	return NULL;
+	}
+
+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)
diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c
new file mode 100644
index 0000000..e5b181d
--- /dev/null
+++ b/ssl/t1_reneg.c
@@ -0,0 +1,294 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2009 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <openssl/obj.h>
+#include <openssl/err.h>
+
+#include "ssl_locl.h"
+
+/* Add the client's renegotiation binding */
+int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+					int maxlen)
+    {
+    if(p)
+        {
+	if((s->s3->previous_client_finished_len+1) > maxlen)
+            {
+            OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_renegotiate_ext, SSL_R_RENEGOTIATE_EXT_TOO_LONG);
+            return 0;
+            }
+            
+        /* Length byte */
+	*p = s->s3->previous_client_finished_len;
+        p++;
+
+        memcpy(p, s->s3->previous_client_finished,
+	       s->s3->previous_client_finished_len);
+#ifdef OPENSSL_RI_DEBUG
+    fprintf(stderr, "%s RI extension sent by client\n",
+		s->s3->previous_client_finished_len ? "Non-empty" : "Empty");
+#endif
+        }
+    
+    *len=s->s3->previous_client_finished_len + 1;
+
+ 
+    return 1;
+    }
+
+/* Parse the client's renegotiation binding and abort if it's not
+   right */
+int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+					  int *al)
+    {
+    int ilen;
+
+    /* Parse the length byte */
+    if(len < 1)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al=SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+        }
+    ilen = *d;
+    d++;
+
+    /* Consistency check */
+    if((ilen+1) != len)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al=SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+        }
+
+    /* Check that the extension matches */
+    if(ilen != s->s3->previous_client_finished_len)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, SSL_R_RENEGOTIATION_MISMATCH);
+        *al=SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+        }
+    
+    if(memcmp(d, s->s3->previous_client_finished,
+	      s->s3->previous_client_finished_len))
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_renegotiate_ext, SSL_R_RENEGOTIATION_MISMATCH);
+        *al=SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+        }
+#ifdef OPENSSL_RI_DEBUG
+    fprintf(stderr, "%s RI extension received by server\n",
+				ilen ? "Non-empty" : "Empty");
+#endif
+
+    s->s3->send_connection_binding=1;
+
+    return 1;
+    }
+
+/* Add the server's renegotiation binding */
+int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+					int maxlen)
+    {
+    if(p)
+        {
+        if((s->s3->previous_client_finished_len +
+            s->s3->previous_server_finished_len + 1) > maxlen)
+            {
+            OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_renegotiate_ext, SSL_R_RENEGOTIATE_EXT_TOO_LONG);
+            return 0;
+            }
+        
+        /* Length byte */
+        *p = s->s3->previous_client_finished_len + s->s3->previous_server_finished_len;
+        p++;
+
+        memcpy(p, s->s3->previous_client_finished,
+	       s->s3->previous_client_finished_len);
+        p += s->s3->previous_client_finished_len;
+
+        memcpy(p, s->s3->previous_server_finished,
+	       s->s3->previous_server_finished_len);
+#ifdef OPENSSL_RI_DEBUG
+    fprintf(stderr, "%s RI extension sent by server\n",
+    		s->s3->previous_client_finished_len ? "Non-empty" : "Empty");
+#endif
+        }
+    
+    *len=s->s3->previous_client_finished_len
+	+ s->s3->previous_server_finished_len + 1;
+    
+    return 1;
+    }
+
+/* Parse the server's renegotiation binding and abort if it's not
+   right */
+int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+					  int *al)
+    {
+    int expected_len=s->s3->previous_client_finished_len
+	+ s->s3->previous_server_finished_len;
+    int ilen;
+
+    /* Check for logic errors */
+    assert(!expected_len || s->s3->previous_client_finished_len);
+    assert(!expected_len || s->s3->previous_server_finished_len);
+    
+    /* Parse the length byte */
+    if(len < 1)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al=SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+        }
+    ilen = *d;
+    d++;
+
+    /* Consistency check */
+    if(ilen+1 != len)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, SSL_R_RENEGOTIATION_ENCODING_ERR);
+        *al=SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+        }
+    
+    /* Check that the extension matches */
+    if(ilen != expected_len)
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, SSL_R_RENEGOTIATION_MISMATCH);
+        *al=SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+        }
+
+    if(memcmp(d, s->s3->previous_client_finished,
+	      s->s3->previous_client_finished_len))
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, SSL_R_RENEGOTIATION_MISMATCH);
+        *al=SSL_AD_HANDSHAKE_FAILURE;
+        return 0;
+        }
+    d += s->s3->previous_client_finished_len;
+
+    if(memcmp(d, s->s3->previous_server_finished,
+	      s->s3->previous_server_finished_len))
+        {
+        OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_renegotiate_ext, SSL_R_RENEGOTIATION_MISMATCH);
+        *al=SSL_AD_ILLEGAL_PARAMETER;
+        return 0;
+        }
+#ifdef OPENSSL_RI_DEBUG
+    fprintf(stderr, "%s RI extension received by client\n",
+				ilen ? "Non-empty" : "Empty");
+#endif
+    s->s3->send_connection_binding=1;
+
+    return 1;
+    }
diff --git a/ssl/t1_srvr.c b/ssl/t1_srvr.c
new file mode 100644
index 0000000..6fa7da6
--- /dev/null
+++ b/ssl/t1_srvr.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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/buf.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "ssl_locl.h"
+
+
+static const SSL_METHOD *tls1_get_server_method(int ver);
+static const SSL_METHOD *tls1_get_server_method(int ver)
+	{
+	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();
+	return NULL;
+	}
+
+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)
diff --git a/ssl/test/CMakeLists.txt b/ssl/test/CMakeLists.txt
new file mode 100644
index 0000000..7d073c1
--- /dev/null
+++ b/ssl/test/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(../../include)
+
+add_executable(
+	client_shim
+
+	client_shim.cc
+)
+
+target_link_libraries(client_shim ssl crypto)
diff --git a/ssl/test/client_shim.cc b/ssl/test/client_shim.cc
new file mode 100644
index 0000000..9beaf59
--- /dev/null
+++ b/ssl/test/client_shim.cc
@@ -0,0 +1,93 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+
+
+SSL *setup_test() {
+  if (!SSL_library_init()) {
+    return NULL;
+  }
+
+  SSL_CTX *client_ctx = NULL;
+  SSL *client = NULL;
+  BIO *bio = NULL;
+
+  client_ctx = SSL_CTX_new(SSLv23_client_method());
+  if (client_ctx == NULL) {
+    goto err;
+  }
+
+  if (!SSL_CTX_set_cipher_list(client_ctx, "ALL")) {
+    goto err;
+  }
+
+  client = SSL_new(client_ctx);
+  if (client == NULL) {
+    goto err;
+  }
+
+  bio = BIO_new_fd(3, 1 /* take ownership */);
+  if (bio == NULL) {
+    goto err;
+  }
+
+  SSL_set_bio(client, bio, bio);
+  SSL_CTX_free(client_ctx);
+
+  return client;
+
+err:
+  if (bio != NULL) {
+    BIO_free(bio);
+  }
+  if (client != NULL) {
+    SSL_free(client);
+  }
+  if (client_ctx != NULL) {
+    SSL_CTX_free(client_ctx);
+  }
+  return NULL;
+}
+
+int main() {
+  SSL *client = setup_test();
+  if (client == NULL) {
+    BIO_print_errors_fp(stdout);
+    return 1;
+  }
+
+  if (SSL_connect(client) != 1) {
+    SSL_free(client);
+    BIO_print_errors_fp(stdout);
+    return 2;
+  }
+
+  for (;;) {
+    uint8_t buf[512];
+    int n = SSL_read(client, buf, sizeof(buf));
+    if (n < 0) {
+      SSL_free(client);
+      BIO_print_errors_fp(stdout);
+      return 3;
+    } else if (n == 0) {
+      break;
+    } else {
+      for (int i = 0; i < n; i++) {
+        buf[i] ^= 0xff;
+      }
+      int w = SSL_write(client, buf, n);
+      if (w != n) {
+        SSL_free(client);
+        BIO_print_errors_fp(stdout);
+        return 4;
+      }
+    }
+  }
+
+  SSL_free(client);
+  return 0;
+}
diff --git a/ssl/test/runner/alert.go b/ssl/test/runner/alert.go
new file mode 100644
index 0000000..b48ab2a
--- /dev/null
+++ b/ssl/test/runner/alert.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "strconv"
+
+type alert uint8
+
+const (
+	// alert level
+	alertLevelWarning = 1
+	alertLevelError   = 2
+)
+
+const (
+	alertCloseNotify            alert = 0
+	alertUnexpectedMessage      alert = 10
+	alertBadRecordMAC           alert = 20
+	alertDecryptionFailed       alert = 21
+	alertRecordOverflow         alert = 22
+	alertDecompressionFailure   alert = 30
+	alertHandshakeFailure       alert = 40
+	alertBadCertificate         alert = 42
+	alertUnsupportedCertificate alert = 43
+	alertCertificateRevoked     alert = 44
+	alertCertificateExpired     alert = 45
+	alertCertificateUnknown     alert = 46
+	alertIllegalParameter       alert = 47
+	alertUnknownCA              alert = 48
+	alertAccessDenied           alert = 49
+	alertDecodeError            alert = 50
+	alertDecryptError           alert = 51
+	alertProtocolVersion        alert = 70
+	alertInsufficientSecurity   alert = 71
+	alertInternalError          alert = 80
+	alertUserCanceled           alert = 90
+	alertNoRenegotiation        alert = 100
+)
+
+var alertText = map[alert]string{
+	alertCloseNotify:            "close notify",
+	alertUnexpectedMessage:      "unexpected message",
+	alertBadRecordMAC:           "bad record MAC",
+	alertDecryptionFailed:       "decryption failed",
+	alertRecordOverflow:         "record overflow",
+	alertDecompressionFailure:   "decompression failure",
+	alertHandshakeFailure:       "handshake failure",
+	alertBadCertificate:         "bad certificate",
+	alertUnsupportedCertificate: "unsupported certificate",
+	alertCertificateRevoked:     "revoked certificate",
+	alertCertificateExpired:     "expired certificate",
+	alertCertificateUnknown:     "unknown certificate",
+	alertIllegalParameter:       "illegal parameter",
+	alertUnknownCA:              "unknown certificate authority",
+	alertAccessDenied:           "access denied",
+	alertDecodeError:            "error decoding message",
+	alertDecryptError:           "error decrypting message",
+	alertProtocolVersion:        "protocol version not supported",
+	alertInsufficientSecurity:   "insufficient security level",
+	alertInternalError:          "internal error",
+	alertUserCanceled:           "user canceled",
+	alertNoRenegotiation:        "no renegotiation",
+}
+
+func (e alert) String() string {
+	s, ok := alertText[e]
+	if ok {
+		return s
+	}
+	return "alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+	return e.String()
+}
diff --git a/ssl/test/runner/cert.pem b/ssl/test/runner/cert.pem
new file mode 100644
index 0000000..4de4f49
--- /dev/null
+++ b/ssl/test/runner/cert.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci
+HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV
+W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV
+HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f
+Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht
+ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr
+T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f
+j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
new file mode 100644
index 0000000..11c8bdd
--- /dev/null
+++ b/ssl/test/runner/cipher_suites.go
@@ -0,0 +1,290 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/rc4"
+	"crypto/sha1"
+	"crypto/x509"
+	"hash"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+	// On the server side, the first two methods are called in order.
+
+	// In the case that the key agreement protocol doesn't use a
+	// ServerKeyExchange message, generateServerKeyExchange can return nil,
+	// nil.
+	generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+	processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+	// On the client side, the next two methods are called in order.
+
+	// This method may not be called if the server doesn't send a
+	// ServerKeyExchange message.
+	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+	generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
+}
+
+const (
+	// suiteECDH indicates that the cipher suite involves elliptic curve
+	// Diffie-Hellman. This means that it should only be selected when the
+	// client indicates that it supports ECC with a curve and point format
+	// that we're happy with.
+	suiteECDHE = 1 << iota
+	// suiteECDSA indicates that the cipher suite involves an ECDSA
+	// signature and therefore may only be selected when the server's
+	// certificate is ECDSA. If this is not set then the cipher suite is
+	// RSA based.
+	suiteECDSA
+	// suiteTLS12 indicates that the cipher suite should only be advertised
+	// and accepted when using TLS 1.2.
+	suiteTLS12
+	// suiteSHA384 indicates that the cipher suite uses SHA384 as the
+	// handshake hash.
+	suiteSHA384
+)
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type cipherSuite struct {
+	id uint16
+	// the lengths, in bytes, of the key material needed for each component.
+	keyLen int
+	macLen int
+	ivLen  int
+	ka     func(version uint16) keyAgreement
+	// flags is a bitmask of the suite* values, above.
+	flags  int
+	cipher func(key, iv []byte, isRead bool) interface{}
+	mac    func(version uint16, macKey []byte) macFunction
+	aead   func(key, fixedNonce []byte) cipher.AEAD
+}
+
+var cipherSuites = []*cipherSuite{
+	// Ciphersuite order is chosen so that ECDHE comes before plain RSA
+	// and RC4 comes before AES (because of the Lucky13 attack).
+	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
+	{TLS_RSA_WITH_RC4_128_MD5, 16, 16, 0, rsaKA, 0, cipherRC4, macMD5, nil},
+	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+	cipher, _ := rc4.NewCipher(key)
+	return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) interface{} {
+	block, _ := des.NewTripleDESCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+	block, _ := aes.NewCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a macFunction for the given protocol version.
+func macSHA1(version uint16, key []byte) macFunction {
+	if version == VersionSSL30 {
+		mac := ssl30MAC{
+			h:   sha1.New(),
+			key: make([]byte, len(key)),
+		}
+		copy(mac.key, key)
+		return mac
+	}
+	return tls10MAC{hmac.New(sha1.New, key)}
+}
+
+func macMD5(version uint16, key []byte) macFunction {
+	if version == VersionSSL30 {
+		mac := ssl30MAC{
+			h:   md5.New(),
+			key: make([]byte, len(key)),
+		}
+		copy(mac.key, key)
+		return mac
+	}
+	return tls10MAC{hmac.New(md5.New, key)}
+}
+
+type macFunction interface {
+	Size() int
+	MAC(digestBuf, seq, header, data []byte) []byte
+}
+
+// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type fixedNonceAEAD struct {
+	// sealNonce and openNonce are buffers where the larger nonce will be
+	// constructed. Since a seal and open operation may be running
+	// concurrently, there is a separate buffer for each.
+	sealNonce, openNonce []byte
+	aead                 cipher.AEAD
+}
+
+func (f *fixedNonceAEAD) NonceSize() int { return 8 }
+func (f *fixedNonceAEAD) Overhead() int  { return f.aead.Overhead() }
+
+func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+	copy(f.sealNonce[len(f.sealNonce)-8:], nonce)
+	return f.aead.Seal(out, f.sealNonce, plaintext, additionalData)
+}
+
+func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+	copy(f.openNonce[len(f.openNonce)-8:], nonce)
+	return f.aead.Open(out, f.openNonce, plaintext, additionalData)
+}
+
+func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
+	aes, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+	aead, err := cipher.NewGCM(aes)
+	if err != nil {
+		panic(err)
+	}
+
+	nonce1, nonce2 := make([]byte, 12), make([]byte, 12)
+	copy(nonce1, fixedNonce)
+	copy(nonce2, fixedNonce)
+
+	return &fixedNonceAEAD{nonce1, nonce2, aead}
+}
+
+// ssl30MAC implements the SSLv3 MAC function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
+type ssl30MAC struct {
+	h   hash.Hash
+	key []byte
+}
+
+func (s ssl30MAC) Size() int {
+	return s.h.Size()
+}
+
+var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
+
+var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
+
+func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+	padLength := 48
+	if s.h.Size() == 20 {
+		padLength = 40
+	}
+
+	s.h.Reset()
+	s.h.Write(s.key)
+	s.h.Write(ssl30Pad1[:padLength])
+	s.h.Write(seq)
+	s.h.Write(header[:1])
+	s.h.Write(header[3:5])
+	s.h.Write(data)
+	digestBuf = s.h.Sum(digestBuf[:0])
+
+	s.h.Reset()
+	s.h.Write(s.key)
+	s.h.Write(ssl30Pad2[:padLength])
+	s.h.Write(digestBuf)
+	return s.h.Sum(digestBuf[:0])
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
+type tls10MAC struct {
+	h hash.Hash
+}
+
+func (s tls10MAC) Size() int {
+	return s.h.Size()
+}
+
+func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+	s.h.Reset()
+	s.h.Write(seq)
+	s.h.Write(header)
+	s.h.Write(data)
+	return s.h.Sum(digestBuf[:0])
+}
+
+func rsaKA(version uint16) keyAgreement {
+	return rsaKeyAgreement{}
+}
+
+func ecdheECDSAKA(version uint16) keyAgreement {
+	return &ecdheKeyAgreement{
+		sigType: signatureECDSA,
+		version: version,
+	}
+}
+
+func ecdheRSAKA(version uint16) keyAgreement {
+	return &ecdheKeyAgreement{
+		sigType: signatureRSA,
+		version: version,
+	}
+}
+
+// mutualCipherSuite returns a cipherSuite given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
+	for _, id := range have {
+		if id == want {
+			for _, suite := range cipherSuites {
+				if suite.id == want {
+					return suite
+				}
+			}
+			return nil
+		}
+	}
+	return nil
+}
+
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+	TLS_RSA_WITH_RC4_128_MD5                uint16 = 0x0004
+	TLS_RSA_WITH_RC4_128_SHA                uint16 = 0x0005
+	TLS_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0x000a
+	TLS_RSA_WITH_AES_128_CBC_SHA            uint16 = 0x002f
+	TLS_RSA_WITH_AES_256_CBC_SHA            uint16 = 0x0035
+	TLS_ECDHE_ECDSA_WITH_RC4_128_SHA        uint16 = 0xc007
+	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA    uint16 = 0xc009
+	TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA    uint16 = 0xc00a
+	TLS_ECDHE_RSA_WITH_RC4_128_SHA          uint16 = 0xc011
+	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA     uint16 = 0xc012
+	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA      uint16 = 0xc013
+	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
+	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
+)
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
new file mode 100644
index 0000000..9812bde
--- /dev/null
+++ b/ssl/test/runner/common.go
@@ -0,0 +1,598 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"container/list"
+	"crypto"
+	"crypto/rand"
+	"crypto/x509"
+	"fmt"
+	"io"
+	"math/big"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	VersionSSL30 = 0x0300
+	VersionTLS10 = 0x0301
+	VersionTLS11 = 0x0302
+	VersionTLS12 = 0x0303
+)
+
+const (
+	maxPlaintext    = 16384        // maximum plaintext payload length
+	maxCiphertext   = 16384 + 2048 // maximum ciphertext payload length
+	recordHeaderLen = 5            // record header length
+	maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
+
+	minVersion = VersionSSL30
+	maxVersion = VersionTLS12
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+	recordTypeChangeCipherSpec recordType = 20
+	recordTypeAlert            recordType = 21
+	recordTypeHandshake        recordType = 22
+	recordTypeApplicationData  recordType = 23
+)
+
+// TLS handshake message types.
+const (
+	typeClientHello        uint8 = 1
+	typeServerHello        uint8 = 2
+	typeNewSessionTicket   uint8 = 4
+	typeCertificate        uint8 = 11
+	typeServerKeyExchange  uint8 = 12
+	typeCertificateRequest uint8 = 13
+	typeServerHelloDone    uint8 = 14
+	typeCertificateVerify  uint8 = 15
+	typeClientKeyExchange  uint8 = 16
+	typeFinished           uint8 = 20
+	typeCertificateStatus  uint8 = 22
+	typeNextProtocol       uint8 = 67 // Not IANA assigned
+)
+
+// TLS compression types.
+const (
+	compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+	extensionServerName          uint16 = 0
+	extensionStatusRequest       uint16 = 5
+	extensionSupportedCurves     uint16 = 10
+	extensionSupportedPoints     uint16 = 11
+	extensionSignatureAlgorithms uint16 = 13
+	extensionSessionTicket       uint16 = 35
+	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
+	extensionRenegotiationInfo   uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+	scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+type CurveID uint16
+
+const (
+	CurveP256 CurveID = 23
+	CurveP384 CurveID = 24
+	CurveP521 CurveID = 25
+)
+
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+	pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+	statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+	certTypeRSASign    = 1 // A certificate containing an RSA key
+	certTypeDSSSign    = 2 // A certificate containing a DSA key
+	certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+	certTypeDSSFixedDH = 4 // A certificate containing a static DH key
+
+	// See RFC4492 sections 3 and 5.5.
+	certTypeECDSASign      = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA.
+	certTypeRSAFixedECDH   = 65 // A certificate containing an ECDH-capable public key, signed with RSA.
+	certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA.
+
+	// Rest of these are reserved by the TLS spec
+)
+
+// Hash functions for TLS 1.2 (See RFC 5246, section A.4.1)
+const (
+	hashSHA1   uint8 = 2
+	hashSHA256 uint8 = 4
+)
+
+// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
+const (
+	signatureRSA   uint8 = 1
+	signatureECDSA uint8 = 3
+)
+
+// signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See
+// RFC 5246, section A.4.1.
+type signatureAndHash struct {
+	hash, signature uint8
+}
+
+// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
+// that the code advertises as supported in a TLS 1.2 ClientHello.
+var supportedSKXSignatureAlgorithms = []signatureAndHash{
+	{hashSHA256, signatureRSA},
+	{hashSHA256, signatureECDSA},
+	{hashSHA1, signatureRSA},
+	{hashSHA1, signatureECDSA},
+}
+
+// supportedClientCertSignatureAlgorithms contains the signature and hash
+// algorithms that the code advertises as supported in a TLS 1.2
+// CertificateRequest.
+var supportedClientCertSignatureAlgorithms = []signatureAndHash{
+	{hashSHA256, signatureRSA},
+	{hashSHA256, signatureECDSA},
+}
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+	Version                    uint16                // TLS version used by the connection (e.g. VersionTLS12)
+	HandshakeComplete          bool                  // TLS handshake is complete
+	DidResume                  bool                  // connection resumes a previous TLS connection
+	CipherSuite                uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+	NegotiatedProtocol         string                // negotiated next protocol (from Config.NextProtos)
+	NegotiatedProtocolIsMutual bool                  // negotiated protocol was advertised by server
+	ServerName                 string                // server name requested by client, if any (server side only)
+	PeerCertificates           []*x509.Certificate   // certificate chain presented by remote peer
+	VerifiedChains             [][]*x509.Certificate // verified chains built from PeerCertificates
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+	NoClientCert ClientAuthType = iota
+	RequestClientCert
+	RequireAnyClientCert
+	VerifyClientCertIfGiven
+	RequireAndVerifyClientCert
+)
+
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+	sessionTicket      []uint8             // Encrypted ticket used for session resumption with server
+	vers               uint16              // SSL/TLS version negotiated for the session
+	cipherSuite        uint16              // Ciphersuite negotiated for the session
+	masterSecret       []byte              // MasterSecret generated by client on a full handshake
+	serverCertificates []*x509.Certificate // Certificate chain presented by the server
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ClientSessionCache interface {
+	// Get searches for a ClientSessionState associated with the given key.
+	// On return, ok is true if one was found.
+	Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+	// Put adds the ClientSessionState to the cache with the given key.
+	Put(sessionKey string, cs *ClientSessionState)
+}
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+	// Rand provides the source of entropy for nonces and RSA blinding.
+	// If Rand is nil, TLS uses the cryptographic random reader in package
+	// crypto/rand.
+	// The Reader must be safe for use by multiple goroutines.
+	Rand io.Reader
+
+	// Time returns the current time as the number of seconds since the epoch.
+	// If Time is nil, TLS uses time.Now.
+	Time func() time.Time
+
+	// Certificates contains one or more certificate chains
+	// to present to the other side of the connection.
+	// Server configurations must include at least one certificate.
+	Certificates []Certificate
+
+	// NameToCertificate maps from a certificate name to an element of
+	// Certificates. Note that a certificate name can be of the form
+	// '*.example.com' and so doesn't have to be a domain name as such.
+	// See Config.BuildNameToCertificate
+	// The nil value causes the first element of Certificates to be used
+	// for all connections.
+	NameToCertificate map[string]*Certificate
+
+	// RootCAs defines the set of root certificate authorities
+	// that clients use when verifying server certificates.
+	// If RootCAs is nil, TLS uses the host's root CA set.
+	RootCAs *x509.CertPool
+
+	// NextProtos is a list of supported, application level protocols.
+	NextProtos []string
+
+	// ServerName is used to verify the hostname on the returned
+	// certificates unless InsecureSkipVerify is given. It is also included
+	// in the client's handshake to support virtual hosting.
+	ServerName string
+
+	// ClientAuth determines the server's policy for
+	// TLS Client Authentication. The default is NoClientCert.
+	ClientAuth ClientAuthType
+
+	// ClientCAs defines the set of root certificate authorities
+	// that servers use if required to verify a client certificate
+	// by the policy in ClientAuth.
+	ClientCAs *x509.CertPool
+
+	// InsecureSkipVerify controls whether a client verifies the
+	// server's certificate chain and host name.
+	// If InsecureSkipVerify is true, TLS accepts any certificate
+	// presented by the server and any host name in that certificate.
+	// In this mode, TLS is susceptible to man-in-the-middle attacks.
+	// This should be used only for testing.
+	InsecureSkipVerify bool
+
+	// CipherSuites is a list of supported cipher suites. If CipherSuites
+	// is nil, TLS uses a list of suites supported by the implementation.
+	CipherSuites []uint16
+
+	// PreferServerCipherSuites controls whether the server selects the
+	// client's most preferred ciphersuite, or the server's most preferred
+	// ciphersuite. If true then the server's preference, as expressed in
+	// the order of elements in CipherSuites, is used.
+	PreferServerCipherSuites bool
+
+	// SessionTicketsDisabled may be set to true to disable session ticket
+	// (resumption) support.
+	SessionTicketsDisabled bool
+
+	// SessionTicketKey is used by TLS servers to provide session
+	// resumption. See RFC 5077. If zero, it will be filled with
+	// random data before the first server handshake.
+	//
+	// If multiple servers are terminating connections for the same host
+	// they should all have the same SessionTicketKey. If the
+	// SessionTicketKey leaks, previously recorded and future TLS
+	// connections using that key are compromised.
+	SessionTicketKey [32]byte
+
+	// SessionCache is a cache of ClientSessionState entries for TLS session
+	// resumption.
+	ClientSessionCache ClientSessionCache
+
+	// MinVersion contains the minimum SSL/TLS version that is acceptable.
+	// If zero, then SSLv3 is taken as the minimum.
+	MinVersion uint16
+
+	// MaxVersion contains the maximum SSL/TLS version that is acceptable.
+	// If zero, then the maximum version supported by this package is used,
+	// which is currently TLS 1.2.
+	MaxVersion uint16
+
+	// CurvePreferences contains the elliptic curves that will be used in
+	// an ECDHE handshake, in preference order. If empty, the default will
+	// be used.
+	CurvePreferences []CurveID
+
+	// Bugs specifies optional misbehaviour to be used for testing other
+	// implementations.
+	Bugs ProtocolBugs
+
+	serverInitOnce sync.Once // guards calling (*Config).serverInit
+}
+
+type BadValue int
+
+const (
+	BadValueNone BadValue = iota
+	BadValueNegative
+	BadValueZero
+	BadValueLimit
+	BadValueLarge
+	NumBadValues
+)
+
+type ProtocolBugs struct {
+	// InvalidSKXSignature specifies that the signature in a
+	// ServerKeyExchange message should be invalid.
+	InvalidSKXSignature bool
+
+	// InvalidSKXCurve causes the curve ID in the ServerKeyExchange message
+	// to be wrong.
+	InvalidSKXCurve bool
+
+	// BadECDSAR controls ways in which the 'r' value of an ECDSA signature
+	// can be invalid.
+	BadECDSAR BadValue
+	BadECDSAS BadValue
+}
+
+func (c *Config) serverInit() {
+	if c.SessionTicketsDisabled {
+		return
+	}
+
+	// If the key has already been set then we have nothing to do.
+	for _, b := range c.SessionTicketKey {
+		if b != 0 {
+			return
+		}
+	}
+
+	if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+		c.SessionTicketsDisabled = true
+	}
+}
+
+func (c *Config) rand() io.Reader {
+	r := c.Rand
+	if r == nil {
+		return rand.Reader
+	}
+	return r
+}
+
+func (c *Config) time() time.Time {
+	t := c.Time
+	if t == nil {
+		t = time.Now
+	}
+	return t()
+}
+
+func (c *Config) cipherSuites() []uint16 {
+	s := c.CipherSuites
+	if s == nil {
+		s = defaultCipherSuites()
+	}
+	return s
+}
+
+func (c *Config) minVersion() uint16 {
+	if c == nil || c.MinVersion == 0 {
+		return minVersion
+	}
+	return c.MinVersion
+}
+
+func (c *Config) maxVersion() uint16 {
+	if c == nil || c.MaxVersion == 0 {
+		return maxVersion
+	}
+	return c.MaxVersion
+}
+
+var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+	if c == nil || len(c.CurvePreferences) == 0 {
+		return defaultCurvePreferences
+	}
+	return c.CurvePreferences
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer.
+func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
+	minVersion := c.minVersion()
+	maxVersion := c.maxVersion()
+
+	if vers < minVersion {
+		return 0, false
+	}
+	if vers > maxVersion {
+		vers = maxVersion
+	}
+	return vers, true
+}
+
+// getCertificateForName returns the best certificate for the given name,
+// defaulting to the first element of c.Certificates if there are no good
+// options.
+func (c *Config) getCertificateForName(name string) *Certificate {
+	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
+		// There's only one choice, so no point doing any work.
+		return &c.Certificates[0]
+	}
+
+	name = strings.ToLower(name)
+	for len(name) > 0 && name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+
+	if cert, ok := c.NameToCertificate[name]; ok {
+		return cert
+	}
+
+	// try replacing labels in the name with wildcards until we get a
+	// match.
+	labels := strings.Split(name, ".")
+	for i := range labels {
+		labels[i] = "*"
+		candidate := strings.Join(labels, ".")
+		if cert, ok := c.NameToCertificate[candidate]; ok {
+			return cert
+		}
+	}
+
+	// If nothing matches, return the first certificate.
+	return &c.Certificates[0]
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+func (c *Config) BuildNameToCertificate() {
+	c.NameToCertificate = make(map[string]*Certificate)
+	for i := range c.Certificates {
+		cert := &c.Certificates[i]
+		x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+		if err != nil {
+			continue
+		}
+		if len(x509Cert.Subject.CommonName) > 0 {
+			c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+		}
+		for _, san := range x509Cert.DNSNames {
+			c.NameToCertificate[san] = cert
+		}
+	}
+}
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+	Certificate [][]byte
+	PrivateKey  crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey
+	// OCSPStaple contains an optional OCSP response which will be served
+	// to clients that request it.
+	OCSPStaple []byte
+	// Leaf is the parsed form of the leaf certificate, which may be
+	// initialized using x509.ParseCertificate to reduce per-handshake
+	// processing for TLS clients doing client authentication. If nil, the
+	// leaf certificate will be parsed as needed.
+	Leaf *x509.Certificate
+}
+
+// A TLS record.
+type record struct {
+	contentType  recordType
+	major, minor uint8
+	payload      []byte
+}
+
+type handshakeMessage interface {
+	marshal() []byte
+	unmarshal([]byte) bool
+}
+
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+	sync.Mutex
+
+	m        map[string]*list.Element
+	q        *list.List
+	capacity int
+}
+
+type lruSessionCacheEntry struct {
+	sessionKey string
+	state      *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+	const defaultSessionCacheCapacity = 64
+
+	if capacity < 1 {
+		capacity = defaultSessionCacheCapacity
+	}
+	return &lruSessionCache{
+		m:        make(map[string]*list.Element),
+		q:        list.New(),
+		capacity: capacity,
+	}
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		entry := elem.Value.(*lruSessionCacheEntry)
+		entry.state = cs
+		c.q.MoveToFront(elem)
+		return
+	}
+
+	if c.q.Len() < c.capacity {
+		entry := &lruSessionCacheEntry{sessionKey, cs}
+		c.m[sessionKey] = c.q.PushFront(entry)
+		return
+	}
+
+	elem := c.q.Back()
+	entry := elem.Value.(*lruSessionCacheEntry)
+	delete(c.m, entry.sessionKey)
+	entry.sessionKey = sessionKey
+	entry.state = cs
+	c.q.MoveToFront(elem)
+	c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		c.q.MoveToFront(elem)
+		return elem.Value.(*lruSessionCacheEntry).state, true
+	}
+	return nil, false
+}
+
+// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
+type dsaSignature struct {
+	R, S *big.Int
+}
+
+type ecdsaSignature dsaSignature
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+	return &emptyConfig
+}
+
+var (
+	once                   sync.Once
+	varDefaultCipherSuites []uint16
+)
+
+func defaultCipherSuites() []uint16 {
+	once.Do(initDefaultCipherSuites)
+	return varDefaultCipherSuites
+}
+
+func initDefaultCipherSuites() {
+	varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+	for i, suite := range cipherSuites {
+		varDefaultCipherSuites[i] = suite.id
+	}
+}
+
+func unexpectedMessageError(wanted, got interface{}) error {
+	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
new file mode 100644
index 0000000..d130895
--- /dev/null
+++ b/ssl/test/runner/conn.go
@@ -0,0 +1,1019 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TLS low level connection and record layer
+
+package main
+
+import (
+	"bytes"
+	"crypto/cipher"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"sync"
+	"time"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+	// constant
+	conn     net.Conn
+	isClient bool
+
+	// constant after handshake; protected by handshakeMutex
+	handshakeMutex    sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+	handshakeErr      error      // error resulting from handshake
+	vers              uint16     // TLS version
+	haveVers          bool       // version has been negotiated
+	config            *Config    // configuration passed to constructor
+	handshakeComplete bool
+	didResume         bool // whether this connection was a session resumption
+	cipherSuite       uint16
+	ocspResponse      []byte // stapled OCSP response
+	peerCertificates  []*x509.Certificate
+	// verifiedChains contains the certificate chains that we built, as
+	// opposed to the ones presented by the server.
+	verifiedChains [][]*x509.Certificate
+	// serverName contains the server name indicated by the client, if any.
+	serverName string
+
+	clientProtocol         string
+	clientProtocolFallback bool
+
+	// input/output
+	in, out  halfConn     // in.Mutex < out.Mutex
+	rawInput *block       // raw input, right off the wire
+	input    *block       // application data waiting to be read
+	hand     bytes.Buffer // handshake data waiting to be read
+
+	tmp [16]byte
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+	return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+	return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+	return c.conn.SetWriteDeadline(t)
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+	sync.Mutex
+
+	err     error       // first permanent error
+	version uint16      // protocol version
+	cipher  interface{} // cipher algorithm
+	mac     macFunction
+	seq     [8]byte // 64-bit sequence number
+	bfree   *block  // list of free blocks
+
+	nextCipher interface{} // next encryption state
+	nextMac    macFunction // next MAC algorithm
+
+	// used to save allocating a new buffer for each MAC.
+	inDigestBuf, outDigestBuf []byte
+}
+
+func (hc *halfConn) setErrorLocked(err error) error {
+	hc.err = err
+	return err
+}
+
+func (hc *halfConn) error() error {
+	hc.Lock()
+	err := hc.err
+	hc.Unlock()
+	return err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
+	hc.version = version
+	hc.nextCipher = cipher
+	hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() error {
+	if hc.nextCipher == nil {
+		return alertInternalError
+	}
+	hc.cipher = hc.nextCipher
+	hc.mac = hc.nextMac
+	hc.nextCipher = nil
+	hc.nextMac = nil
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+	return nil
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+	for i := 7; i >= 0; i-- {
+		hc.seq[i]++
+		if hc.seq[i] != 0 {
+			return
+		}
+	}
+
+	// Not allowed to let sequence number wrap.
+	// Instead, must renegotiate before it does.
+	// Not likely enough to bother.
+	panic("TLS: sequence number wraparound")
+}
+
+// resetSeq resets the sequence number to zero.
+func (hc *halfConn) resetSeq() {
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+}
+
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+	if len(payload) < 1 {
+		return payload, 0
+	}
+
+	paddingLen := payload[len(payload)-1]
+	t := uint(len(payload)-1) - uint(paddingLen)
+	// if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+	good := byte(int32(^t) >> 31)
+
+	toCheck := 255 // the maximum possible padding length
+	// The length of the padded data is public, so we can use an if here
+	if toCheck+1 > len(payload) {
+		toCheck = len(payload) - 1
+	}
+
+	for i := 0; i < toCheck; i++ {
+		t := uint(paddingLen) - uint(i)
+		// if i <= paddingLen then the MSB of t is zero
+		mask := byte(int32(^t) >> 31)
+		b := payload[len(payload)-1-i]
+		good &^= mask&paddingLen ^ mask&b
+	}
+
+	// We AND together the bits of good and replicate the result across
+	// all the bits.
+	good &= good << 4
+	good &= good << 2
+	good &= good << 1
+	good = uint8(int8(good) >> 7)
+
+	toRemove := good&paddingLen + 1
+	return payload[:len(payload)-int(toRemove)], good
+}
+
+// removePaddingSSL30 is a replacement for removePadding in the case that the
+// protocol version is SSLv3. In this version, the contents of the padding
+// are random and cannot be checked.
+func removePaddingSSL30(payload []byte) ([]byte, byte) {
+	if len(payload) < 1 {
+		return payload, 0
+	}
+
+	paddingLen := int(payload[len(payload)-1]) + 1
+	if paddingLen > len(payload) {
+		return payload, 0
+	}
+
+	return payload[:len(payload)-paddingLen], 255
+}
+
+func roundUp(a, b int) int {
+	return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+	cipher.BlockMode
+	SetIV([]byte)
+}
+
+// decrypt checks and strips the mac and decrypts the data in b. Returns a
+// success boolean, the number of bytes to skip from the start of the record in
+// order to get the application payload, and an optional alert value.
+func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) {
+	// pull out payload
+	payload := b.data[recordHeaderLen:]
+
+	macSize := 0
+	if hc.mac != nil {
+		macSize = hc.mac.Size()
+	}
+
+	paddingGood := byte(255)
+	explicitIVLen := 0
+
+	// decrypt
+	if hc.cipher != nil {
+		switch c := hc.cipher.(type) {
+		case cipher.Stream:
+			c.XORKeyStream(payload, payload)
+		case cipher.AEAD:
+			explicitIVLen = 8
+			if len(payload) < explicitIVLen {
+				return false, 0, alertBadRecordMAC
+			}
+			nonce := payload[:8]
+			payload = payload[8:]
+
+			var additionalData [13]byte
+			copy(additionalData[:], hc.seq[:])
+			copy(additionalData[8:], b.data[:3])
+			n := len(payload) - c.Overhead()
+			additionalData[11] = byte(n >> 8)
+			additionalData[12] = byte(n)
+			var err error
+			payload, err = c.Open(payload[:0], nonce, payload, additionalData[:])
+			if err != nil {
+				return false, 0, alertBadRecordMAC
+			}
+			b.resize(recordHeaderLen + explicitIVLen + len(payload))
+		case cbcMode:
+			blockSize := c.BlockSize()
+			if hc.version >= VersionTLS11 {
+				explicitIVLen = blockSize
+			}
+
+			if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
+				return false, 0, alertBadRecordMAC
+			}
+
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
+			c.CryptBlocks(payload, payload)
+			if hc.version == VersionSSL30 {
+				payload, paddingGood = removePaddingSSL30(payload)
+			} else {
+				payload, paddingGood = removePadding(payload)
+			}
+			b.resize(recordHeaderLen + explicitIVLen + len(payload))
+
+			// note that we still have a timing side-channel in the
+			// MAC check, below. An attacker can align the record
+			// so that a correct padding will cause one less hash
+			// block to be calculated. Then they can iteratively
+			// decrypt a record by breaking each byte. See
+			// "Password Interception in a SSL/TLS Channel", Brice
+			// Canvel et al.
+			//
+			// However, our behavior matches OpenSSL, so we leak
+			// only as much as they do.
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// check, strip mac
+	if hc.mac != nil {
+		if len(payload) < macSize {
+			return false, 0, alertBadRecordMAC
+		}
+
+		// strip mac off payload, b.data
+		n := len(payload) - macSize
+		b.data[3] = byte(n >> 8)
+		b.data[4] = byte(n)
+		b.resize(recordHeaderLen + explicitIVLen + n)
+		remoteMAC := payload[n:]
+		localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n])
+
+		if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
+			return false, 0, alertBadRecordMAC
+		}
+		hc.inDigestBuf = localMAC
+	}
+	hc.incSeq()
+
+	return true, recordHeaderLen + explicitIVLen, 0
+}
+
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+	overrun := len(payload) % blockSize
+	paddingLen := blockSize - overrun
+	prefix = payload[:len(payload)-overrun]
+	finalBlock = make([]byte, blockSize)
+	copy(finalBlock, payload[len(payload)-overrun:])
+	for i := overrun; i < blockSize; i++ {
+		finalBlock[i] = byte(paddingLen - 1)
+	}
+	return
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
+	// mac
+	if hc.mac != nil {
+		mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+
+		n := len(b.data)
+		b.resize(n + len(mac))
+		copy(b.data[n:], mac)
+		hc.outDigestBuf = mac
+	}
+
+	payload := b.data[recordHeaderLen:]
+
+	// encrypt
+	if hc.cipher != nil {
+		switch c := hc.cipher.(type) {
+		case cipher.Stream:
+			c.XORKeyStream(payload, payload)
+		case cipher.AEAD:
+			payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
+			b.resize(len(b.data) + c.Overhead())
+			nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+			payload := b.data[recordHeaderLen+explicitIVLen:]
+			payload = payload[:payloadLen]
+
+			var additionalData [13]byte
+			copy(additionalData[:], hc.seq[:])
+			copy(additionalData[8:], b.data[:3])
+			additionalData[11] = byte(payloadLen >> 8)
+			additionalData[12] = byte(payloadLen)
+
+			c.Seal(payload[:0], nonce, payload, additionalData[:])
+		case cbcMode:
+			blockSize := c.BlockSize()
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
+			prefix, finalBlock := padToBlockSize(payload, blockSize)
+			b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// update length to include MAC and any block padding needed.
+	n := len(b.data) - recordHeaderLen
+	b.data[3] = byte(n >> 8)
+	b.data[4] = byte(n)
+	hc.incSeq()
+
+	return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+	data []byte
+	off  int // index for Read
+	link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+	if n > cap(b.data) {
+		b.reserve(n)
+	}
+	b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+	if cap(b.data) >= n {
+		return
+	}
+	m := cap(b.data)
+	if m == 0 {
+		m = 1024
+	}
+	for m < n {
+		m *= 2
+	}
+	data := make([]byte, len(b.data), m)
+	copy(data, b.data)
+	b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) error {
+	// quick case
+	if len(b.data) >= n {
+		return nil
+	}
+
+	// read until have enough.
+	b.reserve(n)
+	for {
+		m, err := r.Read(b.data[len(b.data):cap(b.data)])
+		b.data = b.data[0 : len(b.data)+m]
+		if len(b.data) >= n {
+			// TODO(bradfitz,agl): slightly suspicious
+			// that we're throwing away r.Read's err here.
+			break
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (b *block) Read(p []byte) (n int, err error) {
+	n = copy(p, b.data[b.off:])
+	b.off += n
+	return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+	b := hc.bfree
+	if b == nil {
+		return new(block)
+	}
+	hc.bfree = b.link
+	b.link = nil
+	b.resize(0)
+	return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+	b.link = hc.bfree
+	hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remainder.  the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+	if len(b.data) <= n {
+		return b, nil
+	}
+	bb := hc.newBlock()
+	bb.resize(len(b.data) - n)
+	copy(bb.data, b.data[n:])
+	b.data = b.data[0:n]
+	return b, bb
+}
+
+// readRecord reads the next TLS record from the connection
+// and updates the record layer state.
+// c.in.Mutex <= L; c.input == nil.
+func (c *Conn) readRecord(want recordType) error {
+	// Caller must be in sync with connection:
+	// handshake data if handshake not yet completed,
+	// else application data.  (We don't support renegotiation.)
+	switch want {
+	default:
+		c.sendAlert(alertInternalError)
+		return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
+	case recordTypeHandshake, recordTypeChangeCipherSpec:
+		if c.handshakeComplete {
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
+		}
+	case recordTypeApplicationData:
+		if !c.handshakeComplete {
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
+		}
+	}
+
+Again:
+	if c.rawInput == nil {
+		c.rawInput = c.in.newBlock()
+	}
+	b := c.rawInput
+
+	// Read header, payload.
+	if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+		// RFC suggests that EOF without an alertCloseNotify is
+		// an error, but popular web sites seem to do this,
+		// so we can't make it an error.
+		// if err == io.EOF {
+		// 	err = io.ErrUnexpectedEOF
+		// }
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+	typ := recordType(b.data[0])
+
+	// No valid TLS record has a type of 0x80, however SSLv2 handshakes
+	// start with a uint16 length where the MSB is set and the first record
+	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+	// an SSLv2 client.
+	if want == recordTypeHandshake && typ == 0x80 {
+		c.sendAlert(alertProtocolVersion)
+		return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
+	}
+
+	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+	n := int(b.data[3])<<8 | int(b.data[4])
+	if c.haveVers && vers != c.vers {
+		c.sendAlert(alertProtocolVersion)
+		return c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
+	}
+	if n > maxCiphertext {
+		c.sendAlert(alertRecordOverflow)
+		return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
+	}
+	if !c.haveVers {
+		// First message, be extra suspicious:
+		// this might not be a TLS client.
+		// Bail out before reading a full 'body', if possible.
+		// The current max version is 3.1.
+		// If the version is >= 16.0, it's probably not real.
+		// Similarly, a clientHello message encodes in
+		// well under a kilobyte.  If the length is >= 12 kB,
+		// it's probably not real.
+		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
+			c.sendAlert(alertUnexpectedMessage)
+			return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
+		}
+	}
+	if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+		if err == io.EOF {
+			err = io.ErrUnexpectedEOF
+		}
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+
+	// Process message.
+	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+	ok, off, err := c.in.decrypt(b)
+	if !ok {
+		c.in.setErrorLocked(c.sendAlert(err))
+	}
+	b.off = off
+	data := b.data[b.off:]
+	if len(data) > maxPlaintext {
+		err := c.sendAlert(alertRecordOverflow)
+		c.in.freeBlock(b)
+		return c.in.setErrorLocked(err)
+	}
+
+	switch typ {
+	default:
+		c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+	case recordTypeAlert:
+		if len(data) != 2 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		if alert(data[1]) == alertCloseNotify {
+			c.in.setErrorLocked(io.EOF)
+			break
+		}
+		switch data[0] {
+		case alertLevelWarning:
+			// drop on the floor
+			c.in.freeBlock(b)
+			goto Again
+		case alertLevelError:
+			c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+		default:
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+
+	case recordTypeChangeCipherSpec:
+		if typ != want || len(data) != 1 || data[0] != 1 {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		err := c.in.changeCipherSpec()
+		if err != nil {
+			c.in.setErrorLocked(c.sendAlert(err.(alert)))
+		}
+
+	case recordTypeApplicationData:
+		if typ != want {
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+			break
+		}
+		c.input = b
+		b = nil
+
+	case recordTypeHandshake:
+		// TODO(rsc): Should at least pick off connection close.
+		if typ != want {
+			return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+		}
+		c.hand.Write(data)
+	}
+
+	if b != nil {
+		c.in.freeBlock(b)
+	}
+	return c.in.err
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(err alert) error {
+	switch err {
+	case alertNoRenegotiation, alertCloseNotify:
+		c.tmp[0] = alertLevelWarning
+	default:
+		c.tmp[0] = alertLevelError
+	}
+	c.tmp[1] = byte(err)
+	c.writeRecord(recordTypeAlert, c.tmp[0:2])
+	// closeNotify is a special case in that it isn't an error:
+	if err != alertCloseNotify {
+		return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+	}
+	return nil
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) error {
+	c.out.Lock()
+	defer c.out.Unlock()
+	return c.sendAlertLocked(err)
+}
+
+// writeRecord writes a TLS record with the given type and payload
+// to the connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
+	b := c.out.newBlock()
+	for len(data) > 0 {
+		m := len(data)
+		if m > maxPlaintext {
+			m = maxPlaintext
+		}
+		explicitIVLen := 0
+		explicitIVIsSeq := false
+
+		var cbc cbcMode
+		if c.out.version >= VersionTLS11 {
+			var ok bool
+			if cbc, ok = c.out.cipher.(cbcMode); ok {
+				explicitIVLen = cbc.BlockSize()
+			}
+		}
+		if explicitIVLen == 0 {
+			if _, ok := c.out.cipher.(cipher.AEAD); ok {
+				explicitIVLen = 8
+				// The AES-GCM construction in TLS has an
+				// explicit nonce so that the nonce can be
+				// random. However, the nonce is only 8 bytes
+				// which is too small for a secure, random
+				// nonce. Therefore we use the sequence number
+				// as the nonce.
+				explicitIVIsSeq = true
+			}
+		}
+		b.resize(recordHeaderLen + explicitIVLen + m)
+		b.data[0] = byte(typ)
+		vers := c.vers
+		if vers == 0 {
+			// Some TLS servers fail if the record version is
+			// greater than TLS 1.0 for the initial ClientHello.
+			vers = VersionTLS10
+		}
+		b.data[1] = byte(vers >> 8)
+		b.data[2] = byte(vers)
+		b.data[3] = byte(m >> 8)
+		b.data[4] = byte(m)
+		if explicitIVLen > 0 {
+			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+			if explicitIVIsSeq {
+				copy(explicitIV, c.out.seq[:])
+			} else {
+				if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
+					break
+				}
+			}
+		}
+		copy(b.data[recordHeaderLen+explicitIVLen:], data)
+		c.out.encrypt(b, explicitIVLen)
+		_, err = c.conn.Write(b.data)
+		if err != nil {
+			break
+		}
+		n += m
+		data = data[m:]
+	}
+	c.out.freeBlock(b)
+
+	if typ == recordTypeChangeCipherSpec {
+		err = c.out.changeCipherSpec()
+		if err != nil {
+			// Cannot call sendAlert directly,
+			// because we already hold c.out.Mutex.
+			c.tmp[0] = alertLevelError
+			c.tmp[1] = byte(err.(alert))
+			c.writeRecord(recordTypeAlert, c.tmp[0:2])
+			return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+		}
+	}
+	return
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, error) {
+	for c.hand.Len() < 4 {
+		if err := c.in.err; err != nil {
+			return nil, err
+		}
+		if err := c.readRecord(recordTypeHandshake); err != nil {
+			return nil, err
+		}
+	}
+
+	data := c.hand.Bytes()
+	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if n > maxHandshake {
+		return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
+	}
+	for c.hand.Len() < 4+n {
+		if err := c.in.err; err != nil {
+			return nil, err
+		}
+		if err := c.readRecord(recordTypeHandshake); err != nil {
+			return nil, err
+		}
+	}
+	data = c.hand.Next(4 + n)
+	var m handshakeMessage
+	switch data[0] {
+	case typeClientHello:
+		m = new(clientHelloMsg)
+	case typeServerHello:
+		m = new(serverHelloMsg)
+	case typeNewSessionTicket:
+		m = new(newSessionTicketMsg)
+	case typeCertificate:
+		m = new(certificateMsg)
+	case typeCertificateRequest:
+		m = &certificateRequestMsg{
+			hasSignatureAndHash: c.vers >= VersionTLS12,
+		}
+	case typeCertificateStatus:
+		m = new(certificateStatusMsg)
+	case typeServerKeyExchange:
+		m = new(serverKeyExchangeMsg)
+	case typeServerHelloDone:
+		m = new(serverHelloDoneMsg)
+	case typeClientKeyExchange:
+		m = new(clientKeyExchangeMsg)
+	case typeCertificateVerify:
+		m = &certificateVerifyMsg{
+			hasSignatureAndHash: c.vers >= VersionTLS12,
+		}
+	case typeNextProtocol:
+		m = new(nextProtoMsg)
+	case typeFinished:
+		m = new(finishedMsg)
+	default:
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+
+	// The handshake message unmarshallers
+	// expect to be able to keep references to data,
+	// so pass in a fresh copy that won't be overwritten.
+	data = append([]byte(nil), data...)
+
+	if !m.unmarshal(data) {
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+	return m, nil
+}
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (int, error) {
+	if err := c.Handshake(); err != nil {
+		return 0, err
+	}
+
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	if err := c.out.err; err != nil {
+		return 0, err
+	}
+
+	if !c.handshakeComplete {
+		return 0, alertInternalError
+	}
+
+	// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
+	// attack when using block mode ciphers due to predictable IVs.
+	// This can be prevented by splitting each Application Data
+	// record into two records, effectively randomizing the IV.
+	//
+	// http://www.openssl.org/~bodo/tls-cbc.txt
+	// https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+	// http://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+	var m int
+	if len(b) > 1 && c.vers <= VersionTLS10 {
+		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+			n, err := c.writeRecord(recordTypeApplicationData, b[:1])
+			if err != nil {
+				return n, c.out.setErrorLocked(err)
+			}
+			m, b = 1, b[1:]
+		}
+	}
+
+	n, err := c.writeRecord(recordTypeApplicationData, b)
+	return n + m, c.out.setErrorLocked(err)
+}
+
+// Read can be made to time out and return a net.Error with Timeout() == true
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *Conn) Read(b []byte) (n int, err error) {
+	if err = c.Handshake(); err != nil {
+		return
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	// Some OpenSSL servers send empty records in order to randomize the
+	// CBC IV. So this loop ignores a limited number of empty records.
+	const maxConsecutiveEmptyRecords = 100
+	for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
+		for c.input == nil && c.in.err == nil {
+			if err := c.readRecord(recordTypeApplicationData); err != nil {
+				// Soft error, like EAGAIN
+				return 0, err
+			}
+		}
+		if err := c.in.err; err != nil {
+			return 0, err
+		}
+
+		n, err = c.input.Read(b)
+		if c.input.off >= len(c.input.data) {
+			c.in.freeBlock(c.input)
+			c.input = nil
+		}
+
+		// If a close-notify alert is waiting, read it so that
+		// we can return (n, EOF) instead of (n, nil), to signal
+		// to the HTTP response reading goroutine that the
+		// connection is now closed. This eliminates a race
+		// where the HTTP response reading goroutine would
+		// otherwise not observe the EOF until its next read,
+		// by which time a client goroutine might have already
+		// tried to reuse the HTTP connection for a new
+		// request.
+		// See https://codereview.appspot.com/76400046
+		// and http://golang.org/issue/3514
+		if ri := c.rawInput; ri != nil &&
+			n != 0 && err == nil &&
+			c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+			if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+				err = recErr // will be io.EOF on closeNotify
+			}
+		}
+
+		if n != 0 || err != nil {
+			return n, err
+		}
+	}
+
+	return 0, io.ErrNoProgress
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+	var alertErr error
+
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if c.handshakeComplete {
+		alertErr = c.sendAlert(alertCloseNotify)
+	}
+
+	if err := c.conn.Close(); err != nil {
+		return err
+	}
+	return alertErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+func (c *Conn) Handshake() error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if err := c.handshakeErr; err != nil {
+		return err
+	}
+	if c.handshakeComplete {
+		return nil
+	}
+
+	if c.isClient {
+		c.handshakeErr = c.clientHandshake()
+	} else {
+		c.handshakeErr = c.serverHandshake()
+	}
+	return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	var state ConnectionState
+	state.HandshakeComplete = c.handshakeComplete
+	if c.handshakeComplete {
+		state.Version = c.vers
+		state.NegotiatedProtocol = c.clientProtocol
+		state.DidResume = c.didResume
+		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
+		state.CipherSuite = c.cipherSuite
+		state.PeerCertificates = c.peerCertificates
+		state.VerifiedChains = c.verifiedChains
+		state.ServerName = c.serverName
+	}
+
+	return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host.  If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if !c.isClient {
+		return errors.New("tls: VerifyHostname called on TLS server connection")
+	}
+	if !c.handshakeComplete {
+		return errors.New("tls: handshake has not yet been performed")
+	}
+	return c.peerCertificates[0].VerifyHostname(host)
+}
diff --git a/ssl/test/runner/ecdsa_cert.pem b/ssl/test/runner/ecdsa_cert.pem
new file mode 100644
index 0000000..50bcbf5
--- /dev/null
+++ b/ssl/test/runner/ecdsa_cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBzzCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
+QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
+dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ
+BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni
+v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa
+HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw
+HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ
+BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E
+BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=
+-----END CERTIFICATE-----
diff --git a/ssl/test/runner/ecdsa_key.pem b/ssl/test/runner/ecdsa_key.pem
new file mode 100644
index 0000000..b9116f0
--- /dev/null
+++ b/ssl/test/runner/ecdsa_key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAcPCHJ61KBKnN1ZyU2JaHcItW/JXTB3DujRyc4Ki7RqoAoGCCqGSM49
+AwEHoUQDQgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY
++cPEox5W4nyDSNsWGhz1HX7xlC1Lz3IiwQ==
+-----END EC PRIVATE KEY-----
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
new file mode 100644
index 0000000..f335d03
--- /dev/null
+++ b/ssl/test/runner/handshake_client.go
@@ -0,0 +1,601 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"encoding/asn1"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"strconv"
+)
+
+type clientHandshakeState struct {
+	c            *Conn
+	serverHello  *serverHelloMsg
+	hello        *clientHelloMsg
+	suite        *cipherSuite
+	finishedHash finishedHash
+	masterSecret []byte
+	session      *ClientSessionState
+}
+
+func (c *Conn) clientHandshake() error {
+	if c.config == nil {
+		c.config = defaultConfig()
+	}
+
+	if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
+		return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+	}
+
+	hello := &clientHelloMsg{
+		vers:                c.config.maxVersion(),
+		compressionMethods:  []uint8{compressionNone},
+		random:              make([]byte, 32),
+		ocspStapling:        true,
+		serverName:          c.config.ServerName,
+		supportedCurves:     c.config.curvePreferences(),
+		supportedPoints:     []uint8{pointFormatUncompressed},
+		nextProtoNeg:        len(c.config.NextProtos) > 0,
+		secureRenegotiation: true,
+	}
+
+	possibleCipherSuites := c.config.cipherSuites()
+	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
+
+NextCipherSuite:
+	for _, suiteId := range possibleCipherSuites {
+		for _, suite := range cipherSuites {
+			if suite.id != suiteId {
+				continue
+			}
+			// Don't advertise TLS 1.2-only cipher suites unless
+			// we're attempting TLS 1.2.
+			if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+				continue
+			}
+			hello.cipherSuites = append(hello.cipherSuites, suiteId)
+			continue NextCipherSuite
+		}
+	}
+
+	_, err := io.ReadFull(c.config.rand(), hello.random)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: short read from Rand: " + err.Error())
+	}
+
+	if hello.vers >= VersionTLS12 {
+		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
+	}
+
+	var session *ClientSessionState
+	var cacheKey string
+	sessionCache := c.config.ClientSessionCache
+	if c.config.SessionTicketsDisabled {
+		sessionCache = nil
+	}
+
+	if sessionCache != nil {
+		hello.ticketSupported = true
+
+		// Try to resume a previously negotiated TLS session, if
+		// available.
+		cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+		candidateSession, ok := sessionCache.Get(cacheKey)
+		if ok {
+			// Check that the ciphersuite/version used for the
+			// previous session are still valid.
+			cipherSuiteOk := false
+			for _, id := range hello.cipherSuites {
+				if id == candidateSession.cipherSuite {
+					cipherSuiteOk = true
+					break
+				}
+			}
+
+			versOk := candidateSession.vers >= c.config.minVersion() &&
+				candidateSession.vers <= c.config.maxVersion()
+			if versOk && cipherSuiteOk {
+				session = candidateSession
+			}
+		}
+	}
+
+	if session != nil {
+		hello.sessionTicket = session.sessionTicket
+		// A random session ID is used to detect when the
+		// server accepted the ticket and is resuming a session
+		// (see RFC 5077).
+		hello.sessionId = make([]byte, 16)
+		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: short read from Rand: " + err.Error())
+		}
+	}
+
+	c.writeRecord(recordTypeHandshake, hello.marshal())
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	serverHello, ok := msg.(*serverHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverHello, msg)
+	}
+
+	vers, ok := c.config.mutualVersion(serverHello.vers)
+	if !ok || vers < VersionTLS10 {
+		// TLS 1.0 is the minimum version supported as a client.
+		c.sendAlert(alertProtocolVersion)
+		return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
+	}
+	c.vers = vers
+	c.haveVers = true
+
+	suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+	if suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return fmt.Errorf("tls: server selected an unsupported cipher suite")
+	}
+
+	hs := &clientHandshakeState{
+		c:            c,
+		serverHello:  serverHello,
+		hello:        hello,
+		suite:        suite,
+		finishedHash: newFinishedHash(c.vers, suite),
+		session:      session,
+	}
+
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
+	isResume, err := hs.processServerHello()
+	if err != nil {
+		return err
+	}
+
+	if isResume {
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+	} else {
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
+	}
+
+	if sessionCache != nil && hs.session != nil && session != hs.session {
+		sessionCache.Put(cacheKey, hs.session)
+	}
+
+	c.didResume = isResume
+	c.handshakeComplete = true
+	c.cipherSuite = suite.id
+	return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	certMsg, ok := msg.(*certificateMsg)
+	if !ok || len(certMsg.certificates) == 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	hs.finishedHash.Write(certMsg.marshal())
+
+	certs := make([]*x509.Certificate, len(certMsg.certificates))
+	for i, asn1Data := range certMsg.certificates {
+		cert, err := x509.ParseCertificate(asn1Data)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to parse certificate from server: " + err.Error())
+		}
+		certs[i] = cert
+	}
+
+	if !c.config.InsecureSkipVerify {
+		opts := x509.VerifyOptions{
+			Roots:         c.config.RootCAs,
+			CurrentTime:   c.config.time(),
+			DNSName:       c.config.ServerName,
+			Intermediates: x509.NewCertPool(),
+		}
+
+		for i, cert := range certs {
+			if i == 0 {
+				continue
+			}
+			opts.Intermediates.AddCert(cert)
+		}
+		c.verifiedChains, err = certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	switch certs[0].PublicKey.(type) {
+	case *rsa.PublicKey, *ecdsa.PublicKey:
+		break
+	default:
+		c.sendAlert(alertUnsupportedCertificate)
+		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+	}
+
+	c.peerCertificates = certs
+
+	if hs.serverHello.ocspStapling {
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+		cs, ok := msg.(*certificateStatusMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(cs, msg)
+		}
+		hs.finishedHash.Write(cs.marshal())
+
+		if cs.statusType == statusTypeOCSP {
+			c.ocspResponse = cs.response
+		}
+	}
+
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+
+	skx, ok := msg.(*serverKeyExchangeMsg)
+	if ok {
+		hs.finishedHash.Write(skx.marshal())
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
+		if err != nil {
+			c.sendAlert(alertUnexpectedMessage)
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	var chainToSend *Certificate
+	var certRequested bool
+	certReq, ok := msg.(*certificateRequestMsg)
+	if ok {
+		certRequested = true
+
+		// RFC 4346 on the certificateAuthorities field:
+		// A list of the distinguished names of acceptable certificate
+		// authorities. These distinguished names may specify a desired
+		// distinguished name for a root CA or for a subordinate CA;
+		// thus, this message can be used to describe both known roots
+		// and a desired authorization space. If the
+		// certificate_authorities list is empty then the client MAY
+		// send any certificate of the appropriate
+		// ClientCertificateType, unless there is some external
+		// arrangement to the contrary.
+
+		hs.finishedHash.Write(certReq.marshal())
+
+		var rsaAvail, ecdsaAvail bool
+		for _, certType := range certReq.certificateTypes {
+			switch certType {
+			case certTypeRSASign:
+				rsaAvail = true
+			case certTypeECDSASign:
+				ecdsaAvail = true
+			}
+		}
+
+		// We need to search our list of client certs for one
+		// where SignatureAlgorithm is RSA and the Issuer is in
+		// certReq.certificateAuthorities
+	findCert:
+		for i, chain := range c.config.Certificates {
+			if !rsaAvail && !ecdsaAvail {
+				continue
+			}
+
+			for j, cert := range chain.Certificate {
+				x509Cert := chain.Leaf
+				// parse the certificate if this isn't the leaf
+				// node, or if chain.Leaf was nil
+				if j != 0 || x509Cert == nil {
+					if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+						c.sendAlert(alertInternalError)
+						return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+					}
+				}
+
+				switch {
+				case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
+				case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
+				default:
+					continue findCert
+				}
+
+				if len(certReq.certificateAuthorities) == 0 {
+					// they gave us an empty list, so just take the
+					// first RSA cert from c.config.Certificates
+					chainToSend = &chain
+					break findCert
+				}
+
+				for _, ca := range certReq.certificateAuthorities {
+					if bytes.Equal(x509Cert.RawIssuer, ca) {
+						chainToSend = &chain
+						break findCert
+					}
+				}
+			}
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	shd, ok := msg.(*serverHelloDoneMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(shd, msg)
+	}
+	hs.finishedHash.Write(shd.marshal())
+
+	// If the server requested a certificate then we have to send a
+	// Certificate message, even if it's empty because we don't have a
+	// certificate to send.
+	if certRequested {
+		certMsg = new(certificateMsg)
+		if chainToSend != nil {
+			certMsg.certificates = chainToSend.Certificate
+		}
+		hs.finishedHash.Write(certMsg.marshal())
+		c.writeRecord(recordTypeHandshake, certMsg.marshal())
+	}
+
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	if ckx != nil {
+		hs.finishedHash.Write(ckx.marshal())
+		c.writeRecord(recordTypeHandshake, ckx.marshal())
+	}
+
+	if chainToSend != nil {
+		var signed []byte
+		certVerify := &certificateVerifyMsg{
+			hasSignatureAndHash: c.vers >= VersionTLS12,
+		}
+
+		switch key := c.config.Certificates[0].PrivateKey.(type) {
+		case *ecdsa.PrivateKey:
+			digest, _, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
+			r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
+			if err == nil {
+				signed, err = asn1.Marshal(ecdsaSignature{r, s})
+			}
+			certVerify.signatureAndHash.signature = signatureECDSA
+			certVerify.signatureAndHash.hash = hashId
+		case *rsa.PrivateKey:
+			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
+			signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
+			certVerify.signatureAndHash.signature = signatureRSA
+			certVerify.signatureAndHash.hash = hashId
+		default:
+			err = errors.New("unknown private key type")
+		}
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
+		}
+		certVerify.signature = signed
+
+		hs.finishedHash.Write(certVerify.marshal())
+		c.writeRecord(recordTypeHandshake, certVerify.marshal())
+	}
+
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+	var clientCipher, serverCipher interface{}
+	var clientHash, serverHash macFunction
+	if hs.suite.cipher != nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+		clientHash = hs.suite.mac(c.vers, clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+		serverHash = hs.suite.mac(c.vers, serverMAC)
+	} else {
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
+	}
+
+	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+	c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+	// If the server responded with the same sessionId then it means the
+	// sessionTicket is being used to resume a TLS session.
+	return hs.session != nil && hs.hello.sessionId != nil &&
+		bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+	c := hs.c
+
+	if hs.serverHello.compressionMethod != compressionNone {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, errors.New("tls: server selected unsupported compression format")
+	}
+
+	if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("server advertised unrequested NPN extension")
+	}
+
+	if hs.serverResumedSession() {
+		// Restore masterSecret and peerCerts from previous state
+		hs.masterSecret = hs.session.masterSecret
+		c.peerCertificates = hs.session.serverCertificates
+		return true, nil
+	}
+	return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished() error {
+	c := hs.c
+
+	c.readRecord(recordTypeChangeCipherSpec)
+	if err := c.in.error(); err != nil {
+		return err
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	serverFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverFinished, msg)
+	}
+
+	verify := hs.finishedHash.serverSum(hs.masterSecret)
+	if len(verify) != len(serverFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server's Finished message was incorrect")
+	}
+	hs.finishedHash.Write(serverFinished.marshal())
+	return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+	if !hs.serverHello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(sessionTicketMsg, msg)
+	}
+	hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+	hs.session = &ClientSessionState{
+		sessionTicket:      sessionTicketMsg.ticket,
+		vers:               c.vers,
+		cipherSuite:        hs.suite.id,
+		masterSecret:       hs.masterSecret,
+		serverCertificates: c.peerCertificates,
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeState) sendFinished() error {
+	c := hs.c
+
+	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	if hs.serverHello.nextProtoNeg {
+		nextProto := new(nextProtoMsg)
+		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
+		nextProto.proto = proto
+		c.clientProtocol = proto
+		c.clientProtocolFallback = fallback
+
+		hs.finishedHash.Write(nextProto.marshal())
+		c.writeRecord(recordTypeHandshake, nextProto.marshal())
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	c.writeRecord(recordTypeHandshake, finished.marshal())
+	return nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+	if len(config.ServerName) > 0 {
+		return config.ServerName
+	}
+	return serverAddr.String()
+}
+
+// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
+// set of client and server supported protocols. The set of client supported
+// protocols must not be empty. It returns the resulting protocol and flag
+// indicating if the fallback case was reached.
+func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
+	for _, s := range serverProtos {
+		for _, c := range clientProtos {
+			if s == c {
+				return s, false
+			}
+		}
+	}
+
+	return clientProtos[0], true
+}
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
new file mode 100644
index 0000000..e31f47b
--- /dev/null
+++ b/ssl/test/runner/handshake_messages.go
@@ -0,0 +1,1344 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "bytes"
+
+type clientHelloMsg struct {
+	raw                 []byte
+	vers                uint16
+	random              []byte
+	sessionId           []byte
+	cipherSuites        []uint16
+	compressionMethods  []uint8
+	nextProtoNeg        bool
+	serverName          string
+	ocspStapling        bool
+	supportedCurves     []CurveID
+	supportedPoints     []uint8
+	ticketSupported     bool
+	sessionTicket       []uint8
+	signatureAndHashes  []signatureAndHash
+	secureRenegotiation bool
+}
+
+func (m *clientHelloMsg) equal(i interface{}) bool {
+	m1, ok := i.(*clientHelloMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.vers == m1.vers &&
+		bytes.Equal(m.random, m1.random) &&
+		bytes.Equal(m.sessionId, m1.sessionId) &&
+		eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+		bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
+		m.nextProtoNeg == m1.nextProtoNeg &&
+		m.serverName == m1.serverName &&
+		m.ocspStapling == m1.ocspStapling &&
+		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
+		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
+		m.ticketSupported == m1.ticketSupported &&
+		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
+		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
+		m.secureRenegotiation == m1.secureRenegotiation
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+	numExtensions := 0
+	extensionsLength := 0
+	if m.nextProtoNeg {
+		numExtensions++
+	}
+	if m.ocspStapling {
+		extensionsLength += 1 + 2 + 2
+		numExtensions++
+	}
+	if len(m.serverName) > 0 {
+		extensionsLength += 5 + len(m.serverName)
+		numExtensions++
+	}
+	if len(m.supportedCurves) > 0 {
+		extensionsLength += 2 + 2*len(m.supportedCurves)
+		numExtensions++
+	}
+	if len(m.supportedPoints) > 0 {
+		extensionsLength += 1 + len(m.supportedPoints)
+		numExtensions++
+	}
+	if m.ticketSupported {
+		extensionsLength += len(m.sessionTicket)
+		numExtensions++
+	}
+	if len(m.signatureAndHashes) > 0 {
+		extensionsLength += 2 + 2*len(m.signatureAndHashes)
+		numExtensions++
+	}
+	if m.secureRenegotiation {
+		extensionsLength += 1
+		numExtensions++
+	}
+	if numExtensions > 0 {
+		extensionsLength += 4 * numExtensions
+		length += 2 + extensionsLength
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeClientHello
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[4] = uint8(m.vers >> 8)
+	x[5] = uint8(m.vers)
+	copy(x[6:38], m.random)
+	x[38] = uint8(len(m.sessionId))
+	copy(x[39:39+len(m.sessionId)], m.sessionId)
+	y := x[39+len(m.sessionId):]
+	y[0] = uint8(len(m.cipherSuites) >> 7)
+	y[1] = uint8(len(m.cipherSuites) << 1)
+	for i, suite := range m.cipherSuites {
+		y[2+i*2] = uint8(suite >> 8)
+		y[3+i*2] = uint8(suite)
+	}
+	z := y[2+len(m.cipherSuites)*2:]
+	z[0] = uint8(len(m.compressionMethods))
+	copy(z[1:], m.compressionMethods)
+
+	z = z[1+len(m.compressionMethods):]
+	if numExtensions > 0 {
+		z[0] = byte(extensionsLength >> 8)
+		z[1] = byte(extensionsLength)
+		z = z[2:]
+	}
+	if m.nextProtoNeg {
+		z[0] = byte(extensionNextProtoNeg >> 8)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
+		// The length is always 0
+		z = z[4:]
+	}
+	if len(m.serverName) > 0 {
+		z[0] = byte(extensionServerName >> 8)
+		z[1] = byte(extensionServerName & 0xff)
+		l := len(m.serverName) + 5
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+
+		// RFC 3546, section 3.1
+		//
+		// struct {
+		//     NameType name_type;
+		//     select (name_type) {
+		//         case host_name: HostName;
+		//     } name;
+		// } ServerName;
+		//
+		// enum {
+		//     host_name(0), (255)
+		// } NameType;
+		//
+		// opaque HostName<1..2^16-1>;
+		//
+		// struct {
+		//     ServerName server_name_list<1..2^16-1>
+		// } ServerNameList;
+
+		z[0] = byte((len(m.serverName) + 3) >> 8)
+		z[1] = byte(len(m.serverName) + 3)
+		z[3] = byte(len(m.serverName) >> 8)
+		z[4] = byte(len(m.serverName))
+		copy(z[5:], []byte(m.serverName))
+		z = z[l:]
+	}
+	if m.ocspStapling {
+		// RFC 4366, section 3.6
+		z[0] = byte(extensionStatusRequest >> 8)
+		z[1] = byte(extensionStatusRequest)
+		z[2] = 0
+		z[3] = 5
+		z[4] = 1 // OCSP type
+		// Two zero valued uint16s for the two lengths.
+		z = z[9:]
+	}
+	if len(m.supportedCurves) > 0 {
+		// http://tools.ietf.org/html/rfc4492#section-5.5.1
+		z[0] = byte(extensionSupportedCurves >> 8)
+		z[1] = byte(extensionSupportedCurves)
+		l := 2 + 2*len(m.supportedCurves)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 2
+		z[4] = byte(l >> 8)
+		z[5] = byte(l)
+		z = z[6:]
+		for _, curve := range m.supportedCurves {
+			z[0] = byte(curve >> 8)
+			z[1] = byte(curve)
+			z = z[2:]
+		}
+	}
+	if len(m.supportedPoints) > 0 {
+		// http://tools.ietf.org/html/rfc4492#section-5.5.2
+		z[0] = byte(extensionSupportedPoints >> 8)
+		z[1] = byte(extensionSupportedPoints)
+		l := 1 + len(m.supportedPoints)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l--
+		z[4] = byte(l)
+		z = z[5:]
+		for _, pointFormat := range m.supportedPoints {
+			z[0] = byte(pointFormat)
+			z = z[1:]
+		}
+	}
+	if m.ticketSupported {
+		// http://tools.ietf.org/html/rfc5077#section-3.2
+		z[0] = byte(extensionSessionTicket >> 8)
+		z[1] = byte(extensionSessionTicket)
+		l := len(m.sessionTicket)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+		copy(z, m.sessionTicket)
+		z = z[len(m.sessionTicket):]
+	}
+	if len(m.signatureAndHashes) > 0 {
+		// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+		z[0] = byte(extensionSignatureAlgorithms >> 8)
+		z[1] = byte(extensionSignatureAlgorithms)
+		l := 2 + 2*len(m.signatureAndHashes)
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z = z[4:]
+
+		l -= 2
+		z[0] = byte(l >> 8)
+		z[1] = byte(l)
+		z = z[2:]
+		for _, sigAndHash := range m.signatureAndHashes {
+			z[0] = sigAndHash.hash
+			z[1] = sigAndHash.signature
+			z = z[2:]
+		}
+	}
+	if m.secureRenegotiation {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = 1
+		z = z[5:]
+	}
+
+	m.raw = x
+
+	return x
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+	if len(data) < 42 {
+		return false
+	}
+	m.raw = data
+	m.vers = uint16(data[4])<<8 | uint16(data[5])
+	m.random = data[6:38]
+	sessionIdLen := int(data[38])
+	if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+		return false
+	}
+	m.sessionId = data[39 : 39+sessionIdLen]
+	data = data[39+sessionIdLen:]
+	if len(data) < 2 {
+		return false
+	}
+	// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+	// they are uint16s, the number must be even.
+	cipherSuiteLen := int(data[0])<<8 | int(data[1])
+	if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+		return false
+	}
+	numCipherSuites := cipherSuiteLen / 2
+	m.cipherSuites = make([]uint16, numCipherSuites)
+	for i := 0; i < numCipherSuites; i++ {
+		m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+		if m.cipherSuites[i] == scsvRenegotiation {
+			m.secureRenegotiation = true
+		}
+	}
+	data = data[2+cipherSuiteLen:]
+	if len(data) < 1 {
+		return false
+	}
+	compressionMethodsLen := int(data[0])
+	if len(data) < 1+compressionMethodsLen {
+		return false
+	}
+	m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+	data = data[1+compressionMethodsLen:]
+
+	m.nextProtoNeg = false
+	m.serverName = ""
+	m.ocspStapling = false
+	m.ticketSupported = false
+	m.sessionTicket = nil
+	m.signatureAndHashes = nil
+
+	if len(data) == 0 {
+		// ClientHello is optionally followed by extension data
+		return true
+	}
+	if len(data) < 2 {
+		return false
+	}
+
+	extensionsLength := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if extensionsLength != len(data) {
+		return false
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return false
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return false
+		}
+
+		switch extension {
+		case extensionServerName:
+			if length < 2 {
+				return false
+			}
+			numNames := int(data[0])<<8 | int(data[1])
+			d := data[2:]
+			for i := 0; i < numNames; i++ {
+				if len(d) < 3 {
+					return false
+				}
+				nameType := d[0]
+				nameLen := int(d[1])<<8 | int(d[2])
+				d = d[3:]
+				if len(d) < nameLen {
+					return false
+				}
+				if nameType == 0 {
+					m.serverName = string(d[0:nameLen])
+					break
+				}
+				d = d[nameLen:]
+			}
+		case extensionNextProtoNeg:
+			if length > 0 {
+				return false
+			}
+			m.nextProtoNeg = true
+		case extensionStatusRequest:
+			m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+		case extensionSupportedCurves:
+			// http://tools.ietf.org/html/rfc4492#section-5.5.1
+			if length < 2 {
+				return false
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l%2 == 1 || length != l+2 {
+				return false
+			}
+			numCurves := l / 2
+			m.supportedCurves = make([]CurveID, numCurves)
+			d := data[2:]
+			for i := 0; i < numCurves; i++ {
+				m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
+				d = d[2:]
+			}
+		case extensionSupportedPoints:
+			// http://tools.ietf.org/html/rfc4492#section-5.5.2
+			if length < 1 {
+				return false
+			}
+			l := int(data[0])
+			if length != l+1 {
+				return false
+			}
+			m.supportedPoints = make([]uint8, l)
+			copy(m.supportedPoints, data[1:])
+		case extensionSessionTicket:
+			// http://tools.ietf.org/html/rfc5077#section-3.2
+			m.ticketSupported = true
+			m.sessionTicket = data[:length]
+		case extensionSignatureAlgorithms:
+			// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+			if length < 2 || length&1 != 0 {
+				return false
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 {
+				return false
+			}
+			n := l / 2
+			d := data[2:]
+			m.signatureAndHashes = make([]signatureAndHash, n)
+			for i := range m.signatureAndHashes {
+				m.signatureAndHashes[i].hash = d[0]
+				m.signatureAndHashes[i].signature = d[1]
+				d = d[2:]
+			}
+		case extensionRenegotiationInfo + 1:
+			if length != 1 || data[0] != 0 {
+				return false
+			}
+			m.secureRenegotiation = true
+		}
+		data = data[length:]
+	}
+
+	return true
+}
+
+type serverHelloMsg struct {
+	raw                 []byte
+	vers                uint16
+	random              []byte
+	sessionId           []byte
+	cipherSuite         uint16
+	compressionMethod   uint8
+	nextProtoNeg        bool
+	nextProtos          []string
+	ocspStapling        bool
+	ticketSupported     bool
+	secureRenegotiation bool
+}
+
+func (m *serverHelloMsg) equal(i interface{}) bool {
+	m1, ok := i.(*serverHelloMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.vers == m1.vers &&
+		bytes.Equal(m.random, m1.random) &&
+		bytes.Equal(m.sessionId, m1.sessionId) &&
+		m.cipherSuite == m1.cipherSuite &&
+		m.compressionMethod == m1.compressionMethod &&
+		m.nextProtoNeg == m1.nextProtoNeg &&
+		eqStrings(m.nextProtos, m1.nextProtos) &&
+		m.ocspStapling == m1.ocspStapling &&
+		m.ticketSupported == m1.ticketSupported &&
+		m.secureRenegotiation == m1.secureRenegotiation
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 38 + len(m.sessionId)
+	numExtensions := 0
+	extensionsLength := 0
+
+	nextProtoLen := 0
+	if m.nextProtoNeg {
+		numExtensions++
+		for _, v := range m.nextProtos {
+			nextProtoLen += len(v)
+		}
+		nextProtoLen += len(m.nextProtos)
+		extensionsLength += nextProtoLen
+	}
+	if m.ocspStapling {
+		numExtensions++
+	}
+	if m.ticketSupported {
+		numExtensions++
+	}
+	if m.secureRenegotiation {
+		extensionsLength += 1
+		numExtensions++
+	}
+	if numExtensions > 0 {
+		extensionsLength += 4 * numExtensions
+		length += 2 + extensionsLength
+	}
+
+	x := make([]byte, 4+length)
+	x[0] = typeServerHello
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[4] = uint8(m.vers >> 8)
+	x[5] = uint8(m.vers)
+	copy(x[6:38], m.random)
+	x[38] = uint8(len(m.sessionId))
+	copy(x[39:39+len(m.sessionId)], m.sessionId)
+	z := x[39+len(m.sessionId):]
+	z[0] = uint8(m.cipherSuite >> 8)
+	z[1] = uint8(m.cipherSuite)
+	z[2] = uint8(m.compressionMethod)
+
+	z = z[3:]
+	if numExtensions > 0 {
+		z[0] = byte(extensionsLength >> 8)
+		z[1] = byte(extensionsLength)
+		z = z[2:]
+	}
+	if m.nextProtoNeg {
+		z[0] = byte(extensionNextProtoNeg >> 8)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
+		z[2] = byte(nextProtoLen >> 8)
+		z[3] = byte(nextProtoLen)
+		z = z[4:]
+
+		for _, v := range m.nextProtos {
+			l := len(v)
+			if l > 255 {
+				l = 255
+			}
+			z[0] = byte(l)
+			copy(z[1:], []byte(v[0:l]))
+			z = z[1+l:]
+		}
+	}
+	if m.ocspStapling {
+		z[0] = byte(extensionStatusRequest >> 8)
+		z[1] = byte(extensionStatusRequest)
+		z = z[4:]
+	}
+	if m.ticketSupported {
+		z[0] = byte(extensionSessionTicket >> 8)
+		z[1] = byte(extensionSessionTicket)
+		z = z[4:]
+	}
+	if m.secureRenegotiation {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = 1
+		z = z[5:]
+	}
+
+	m.raw = x
+
+	return x
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+	if len(data) < 42 {
+		return false
+	}
+	m.raw = data
+	m.vers = uint16(data[4])<<8 | uint16(data[5])
+	m.random = data[6:38]
+	sessionIdLen := int(data[38])
+	if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+		return false
+	}
+	m.sessionId = data[39 : 39+sessionIdLen]
+	data = data[39+sessionIdLen:]
+	if len(data) < 3 {
+		return false
+	}
+	m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+	m.compressionMethod = data[2]
+	data = data[3:]
+
+	m.nextProtoNeg = false
+	m.nextProtos = nil
+	m.ocspStapling = false
+	m.ticketSupported = false
+
+	if len(data) == 0 {
+		// ServerHello is optionally followed by extension data
+		return true
+	}
+	if len(data) < 2 {
+		return false
+	}
+
+	extensionsLength := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if len(data) != extensionsLength {
+		return false
+	}
+
+	for len(data) != 0 {
+		if len(data) < 4 {
+			return false
+		}
+		extension := uint16(data[0])<<8 | uint16(data[1])
+		length := int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if len(data) < length {
+			return false
+		}
+
+		switch extension {
+		case extensionNextProtoNeg:
+			m.nextProtoNeg = true
+			d := data[:length]
+			for len(d) > 0 {
+				l := int(d[0])
+				d = d[1:]
+				if l == 0 || l > len(d) {
+					return false
+				}
+				m.nextProtos = append(m.nextProtos, string(d[:l]))
+				d = d[l:]
+			}
+		case extensionStatusRequest:
+			if length > 0 {
+				return false
+			}
+			m.ocspStapling = true
+		case extensionSessionTicket:
+			if length > 0 {
+				return false
+			}
+			m.ticketSupported = true
+		case extensionRenegotiationInfo:
+			if length != 1 || data[0] != 0 {
+				return false
+			}
+			m.secureRenegotiation = true
+		}
+		data = data[length:]
+	}
+
+	return true
+}
+
+type certificateMsg struct {
+	raw          []byte
+	certificates [][]byte
+}
+
+func (m *certificateMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		eqByteSlices(m.certificates, m1.certificates)
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var i int
+	for _, slice := range m.certificates {
+		i += len(slice)
+	}
+
+	length := 3 + 3*len(m.certificates) + i
+	x = make([]byte, 4+length)
+	x[0] = typeCertificate
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	certificateOctets := length - 3
+	x[4] = uint8(certificateOctets >> 16)
+	x[5] = uint8(certificateOctets >> 8)
+	x[6] = uint8(certificateOctets)
+
+	y := x[7:]
+	for _, slice := range m.certificates {
+		y[0] = uint8(len(slice) >> 16)
+		y[1] = uint8(len(slice) >> 8)
+		y[2] = uint8(len(slice))
+		copy(y[3:], slice)
+		y = y[3+len(slice):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+	if len(data) < 7 {
+		return false
+	}
+
+	m.raw = data
+	certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+	if uint32(len(data)) != certsLen+7 {
+		return false
+	}
+
+	numCerts := 0
+	d := data[7:]
+	for certsLen > 0 {
+		if len(d) < 4 {
+			return false
+		}
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		if uint32(len(d)) < 3+certLen {
+			return false
+		}
+		d = d[3+certLen:]
+		certsLen -= 3 + certLen
+		numCerts++
+	}
+
+	m.certificates = make([][]byte, numCerts)
+	d = data[7:]
+	for i := 0; i < numCerts; i++ {
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		m.certificates[i] = d[3 : 3+certLen]
+		d = d[3+certLen:]
+	}
+
+	return true
+}
+
+type serverKeyExchangeMsg struct {
+	raw []byte
+	key []byte
+}
+
+func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
+	m1, ok := i.(*serverKeyExchangeMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.key, m1.key)
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.key)
+	x := make([]byte, length+4)
+	x[0] = typeServerKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.key)
+
+	m.raw = x
+	return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 4 {
+		return false
+	}
+	m.key = data[4:]
+	return true
+}
+
+type certificateStatusMsg struct {
+	raw        []byte
+	statusType uint8
+	response   []byte
+}
+
+func (m *certificateStatusMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateStatusMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.statusType == m1.statusType &&
+		bytes.Equal(m.response, m1.response)
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var x []byte
+	if m.statusType == statusTypeOCSP {
+		x = make([]byte, 4+4+len(m.response))
+		x[0] = typeCertificateStatus
+		l := len(m.response) + 4
+		x[1] = byte(l >> 16)
+		x[2] = byte(l >> 8)
+		x[3] = byte(l)
+		x[4] = statusTypeOCSP
+
+		l -= 4
+		x[5] = byte(l >> 16)
+		x[6] = byte(l >> 8)
+		x[7] = byte(l)
+		copy(x[8:], m.response)
+	} else {
+		x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+	}
+
+	m.raw = x
+	return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 5 {
+		return false
+	}
+	m.statusType = data[4]
+
+	m.response = nil
+	if m.statusType == statusTypeOCSP {
+		if len(data) < 8 {
+			return false
+		}
+		respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+		if uint32(len(data)) != 4+4+respLen {
+			return false
+		}
+		m.response = data[8:]
+	}
+	return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) equal(i interface{}) bool {
+	_, ok := i.(*serverHelloDoneMsg)
+	return ok
+}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+	x := make([]byte, 4)
+	x[0] = typeServerHelloDone
+	return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+	raw        []byte
+	ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
+	m1, ok := i.(*clientKeyExchangeMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.ciphertext, m1.ciphertext)
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.ciphertext)
+	x := make([]byte, length+4)
+	x[0] = typeClientKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.ciphertext)
+
+	m.raw = x
+	return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 4 {
+		return false
+	}
+	l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if l != len(data)-4 {
+		return false
+	}
+	m.ciphertext = data[4:]
+	return true
+}
+
+type finishedMsg struct {
+	raw        []byte
+	verifyData []byte
+}
+
+func (m *finishedMsg) equal(i interface{}) bool {
+	m1, ok := i.(*finishedMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.verifyData, m1.verifyData)
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	x = make([]byte, 4+len(m.verifyData))
+	x[0] = typeFinished
+	x[3] = byte(len(m.verifyData))
+	copy(x[4:], m.verifyData)
+	m.raw = x
+	return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 4 {
+		return false
+	}
+	m.verifyData = data[4:]
+	return true
+}
+
+type nextProtoMsg struct {
+	raw   []byte
+	proto string
+}
+
+func (m *nextProtoMsg) equal(i interface{}) bool {
+	m1, ok := i.(*nextProtoMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.proto == m1.proto
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	l := len(m.proto)
+	if l > 255 {
+		l = 255
+	}
+
+	padding := 32 - (l+2)%32
+	length := l + padding + 2
+	x := make([]byte, length+4)
+	x[0] = typeNextProtocol
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	y := x[4:]
+	y[0] = byte(l)
+	copy(y[1:], []byte(m.proto[0:l]))
+	y = y[1+l:]
+	y[0] = byte(padding)
+
+	m.raw = x
+
+	return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 5 {
+		return false
+	}
+	data = data[4:]
+	protoLen := int(data[0])
+	data = data[1:]
+	if len(data) < protoLen {
+		return false
+	}
+	m.proto = string(data[0:protoLen])
+	data = data[protoLen:]
+
+	if len(data) < 1 {
+		return false
+	}
+	paddingLen := int(data[0])
+	data = data[1:]
+	if len(data) != paddingLen {
+		return false
+	}
+
+	return true
+}
+
+type certificateRequestMsg struct {
+	raw []byte
+	// hasSignatureAndHash indicates whether this message includes a list
+	// of signature and hash functions. This change was introduced with TLS
+	// 1.2.
+	hasSignatureAndHash bool
+
+	certificateTypes       []byte
+	signatureAndHashes     []signatureAndHash
+	certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateRequestMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
+		eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
+		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc4346#section-7.4.4
+	length := 1 + len(m.certificateTypes) + 2
+	casLength := 0
+	for _, ca := range m.certificateAuthorities {
+		casLength += 2 + len(ca)
+	}
+	length += casLength
+
+	if m.hasSignatureAndHash {
+		length += 2 + 2*len(m.signatureAndHashes)
+	}
+
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateRequest
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	x[4] = uint8(len(m.certificateTypes))
+
+	copy(x[5:], m.certificateTypes)
+	y := x[5+len(m.certificateTypes):]
+
+	if m.hasSignatureAndHash {
+		n := len(m.signatureAndHashes) * 2
+		y[0] = uint8(n >> 8)
+		y[1] = uint8(n)
+		y = y[2:]
+		for _, sigAndHash := range m.signatureAndHashes {
+			y[0] = sigAndHash.hash
+			y[1] = sigAndHash.signature
+			y = y[2:]
+		}
+	}
+
+	y[0] = uint8(casLength >> 8)
+	y[1] = uint8(casLength)
+	y = y[2:]
+	for _, ca := range m.certificateAuthorities {
+		y[0] = uint8(len(ca) >> 8)
+		y[1] = uint8(len(ca))
+		y = y[2:]
+		copy(y, ca)
+		y = y[len(ca):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 5 {
+		return false
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return false
+	}
+
+	numCertTypes := int(data[4])
+	data = data[5:]
+	if numCertTypes == 0 || len(data) <= numCertTypes {
+		return false
+	}
+
+	m.certificateTypes = make([]byte, numCertTypes)
+	if copy(m.certificateTypes, data) != numCertTypes {
+		return false
+	}
+
+	data = data[numCertTypes:]
+
+	if m.hasSignatureAndHash {
+		if len(data) < 2 {
+			return false
+		}
+		sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
+		data = data[2:]
+		if sigAndHashLen&1 != 0 {
+			return false
+		}
+		if len(data) < int(sigAndHashLen) {
+			return false
+		}
+		numSigAndHash := sigAndHashLen / 2
+		m.signatureAndHashes = make([]signatureAndHash, numSigAndHash)
+		for i := range m.signatureAndHashes {
+			m.signatureAndHashes[i].hash = data[0]
+			m.signatureAndHashes[i].signature = data[1]
+			data = data[2:]
+		}
+	}
+
+	if len(data) < 2 {
+		return false
+	}
+	casLength := uint16(data[0])<<8 | uint16(data[1])
+	data = data[2:]
+	if len(data) < int(casLength) {
+		return false
+	}
+	cas := make([]byte, casLength)
+	copy(cas, data)
+	data = data[casLength:]
+
+	m.certificateAuthorities = nil
+	for len(cas) > 0 {
+		if len(cas) < 2 {
+			return false
+		}
+		caLen := uint16(cas[0])<<8 | uint16(cas[1])
+		cas = cas[2:]
+
+		if len(cas) < int(caLen) {
+			return false
+		}
+
+		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+		cas = cas[caLen:]
+	}
+	if len(data) > 0 {
+		return false
+	}
+
+	return true
+}
+
+type certificateVerifyMsg struct {
+	raw                 []byte
+	hasSignatureAndHash bool
+	signatureAndHash    signatureAndHash
+	signature           []byte
+}
+
+func (m *certificateVerifyMsg) equal(i interface{}) bool {
+	m1, ok := i.(*certificateVerifyMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.hasSignatureAndHash == m1.hasSignatureAndHash &&
+		m.signatureAndHash.hash == m1.signatureAndHash.hash &&
+		m.signatureAndHash.signature == m1.signatureAndHash.signature &&
+		bytes.Equal(m.signature, m1.signature)
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc4346#section-7.4.8
+	siglength := len(m.signature)
+	length := 2 + siglength
+	if m.hasSignatureAndHash {
+		length += 2
+	}
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateVerify
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	y := x[4:]
+	if m.hasSignatureAndHash {
+		y[0] = m.signatureAndHash.hash
+		y[1] = m.signatureAndHash.signature
+		y = y[2:]
+	}
+	y[0] = uint8(siglength >> 8)
+	y[1] = uint8(siglength)
+	copy(y[2:], m.signature)
+
+	m.raw = x
+
+	return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 6 {
+		return false
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return false
+	}
+
+	data = data[4:]
+	if m.hasSignatureAndHash {
+		m.signatureAndHash.hash = data[0]
+		m.signatureAndHash.signature = data[1]
+		data = data[2:]
+	}
+
+	if len(data) < 2 {
+		return false
+	}
+	siglength := int(data[0])<<8 + int(data[1])
+	data = data[2:]
+	if len(data) != siglength {
+		return false
+	}
+
+	m.signature = data
+
+	return true
+}
+
+type newSessionTicketMsg struct {
+	raw    []byte
+	ticket []byte
+}
+
+func (m *newSessionTicketMsg) equal(i interface{}) bool {
+	m1, ok := i.(*newSessionTicketMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.ticket, m1.ticket)
+}
+
+func (m *newSessionTicketMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See http://tools.ietf.org/html/rfc5077#section-3.3
+	ticketLen := len(m.ticket)
+	length := 2 + 4 + ticketLen
+	x = make([]byte, 4+length)
+	x[0] = typeNewSessionTicket
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[8] = uint8(ticketLen >> 8)
+	x[9] = uint8(ticketLen)
+	copy(x[10:], m.ticket)
+
+	m.raw = x
+
+	return
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 10 {
+		return false
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return false
+	}
+
+	ticketLen := int(data[8])<<8 + int(data[9])
+	if len(data)-10 != ticketLen {
+		return false
+	}
+
+	m.ticket = data[10:]
+
+	return true
+}
+
+func eqUint16s(x, y []uint16) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqCurveIDs(x, y []CurveID) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqStrings(x, y []string) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func eqByteSlices(x, y [][]byte) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if !bytes.Equal(v, y[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+func eqSignatureAndHashes(x, y []signatureAndHash) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		v2 := y[i]
+		if v.hash != v2.hash || v.signature != v2.signature {
+			return false
+		}
+	}
+	return true
+}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
new file mode 100644
index 0000000..7a44a94
--- /dev/null
+++ b/ssl/test/runner/handshake_server.go
@@ -0,0 +1,659 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"encoding/asn1"
+	"errors"
+	"fmt"
+	"io"
+)
+
+// serverHandshakeState contains details of a server handshake in progress.
+// It's discarded once the handshake has completed.
+type serverHandshakeState struct {
+	c               *Conn
+	clientHello     *clientHelloMsg
+	hello           *serverHelloMsg
+	suite           *cipherSuite
+	ellipticOk      bool
+	ecdsaOk         bool
+	sessionState    *sessionState
+	finishedHash    finishedHash
+	masterSecret    []byte
+	certsFromClient [][]byte
+	cert            *Certificate
+}
+
+// serverHandshake performs a TLS handshake as a server.
+func (c *Conn) serverHandshake() error {
+	config := c.config
+
+	// If this is the first server handshake, we generate a random key to
+	// encrypt the tickets with.
+	config.serverInitOnce.Do(config.serverInit)
+
+	hs := serverHandshakeState{
+		c: c,
+	}
+	isResume, err := hs.readClientHello()
+	if err != nil {
+		return err
+	}
+
+	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+	if isResume {
+		// The client has included a session ticket and so we do an abbreviated handshake.
+		if err := hs.doResumeHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
+		c.didResume = true
+	} else {
+		// The client didn't include a session ticket, or it wasn't
+		// valid so we do a full handshake.
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
+		if err := hs.sendSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+	}
+	c.handshakeComplete = true
+
+	return nil
+}
+
+// readClientHello reads a ClientHello message from the client and decides
+// whether we will perform session resumption.
+func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
+	config := hs.c.config
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return false, err
+	}
+	var ok bool
+	hs.clientHello, ok = msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, unexpectedMessageError(hs.clientHello, msg)
+	}
+	c.vers, ok = config.mutualVersion(hs.clientHello.vers)
+	if !ok {
+		c.sendAlert(alertProtocolVersion)
+		return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
+	}
+	c.haveVers = true
+
+	hs.hello = new(serverHelloMsg)
+
+	supportedCurve := false
+	preferredCurves := config.curvePreferences()
+Curves:
+	for _, curve := range hs.clientHello.supportedCurves {
+		for _, supported := range preferredCurves {
+			if supported == curve {
+				supportedCurve = true
+				break Curves
+			}
+		}
+	}
+
+	supportedPointFormat := false
+	for _, pointFormat := range hs.clientHello.supportedPoints {
+		if pointFormat == pointFormatUncompressed {
+			supportedPointFormat = true
+			break
+		}
+	}
+	hs.ellipticOk = supportedCurve && supportedPointFormat
+
+	foundCompression := false
+	// We only support null compression, so check that the client offered it.
+	for _, compression := range hs.clientHello.compressionMethods {
+		if compression == compressionNone {
+			foundCompression = true
+			break
+		}
+	}
+
+	if !foundCompression {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: client does not support uncompressed connections")
+	}
+
+	hs.hello.vers = c.vers
+	hs.hello.random = make([]byte, 32)
+	_, err = io.ReadFull(config.rand(), hs.hello.random)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return false, err
+	}
+	hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+	hs.hello.compressionMethod = compressionNone
+	if len(hs.clientHello.serverName) > 0 {
+		c.serverName = hs.clientHello.serverName
+	}
+	// Although sending an empty NPN extension is reasonable, Firefox has
+	// had a bug around this. Best to send nothing at all if
+	// config.NextProtos is empty. See
+	// https://code.google.com/p/go/issues/detail?id=5445.
+	if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+		hs.hello.nextProtoNeg = true
+		hs.hello.nextProtos = config.NextProtos
+	}
+
+	if len(config.Certificates) == 0 {
+		c.sendAlert(alertInternalError)
+		return false, errors.New("tls: no certificates configured")
+	}
+	hs.cert = &config.Certificates[0]
+	if len(hs.clientHello.serverName) > 0 {
+		hs.cert = config.getCertificateForName(hs.clientHello.serverName)
+	}
+
+	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+
+	if hs.checkForResumption() {
+		return true, nil
+	}
+
+	var preferenceList, supportedList []uint16
+	if c.config.PreferServerCipherSuites {
+		preferenceList = c.config.cipherSuites()
+		supportedList = hs.clientHello.cipherSuites
+	} else {
+		preferenceList = hs.clientHello.cipherSuites
+		supportedList = c.config.cipherSuites()
+	}
+
+	for _, id := range preferenceList {
+		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
+			break
+		}
+	}
+
+	if hs.suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: no cipher suite supported by both client and server")
+	}
+
+	return false, nil
+}
+
+// checkForResumption returns true if we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() bool {
+	c := hs.c
+
+	var ok bool
+	if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
+		return false
+	}
+
+	if hs.sessionState.vers > hs.clientHello.vers {
+		return false
+	}
+	if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+		return false
+	}
+
+	cipherSuiteOk := false
+	// Check that the client is still offering the ciphersuite in the session.
+	for _, id := range hs.clientHello.cipherSuites {
+		if id == hs.sessionState.cipherSuite {
+			cipherSuiteOk = true
+			break
+		}
+	}
+	if !cipherSuiteOk {
+		return false
+	}
+
+	// Check that we also support the ciphersuite from the session.
+	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
+	if hs.suite == nil {
+		return false
+	}
+
+	sessionHasClientCerts := len(hs.sessionState.certificates) != 0
+	needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert
+	if needClientCerts && !sessionHasClientCerts {
+		return false
+	}
+	if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+		return false
+	}
+
+	return true
+}
+
+func (hs *serverHandshakeState) doResumeHandshake() error {
+	c := hs.c
+
+	hs.hello.cipherSuite = hs.suite.id
+	// We echo the client's session ID in the ServerHello to let it know
+	// that we're doing a resumption.
+	hs.hello.sessionId = hs.clientHello.sessionId
+
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+
+	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+
+	if len(hs.sessionState.certificates) > 0 {
+		if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
+			return err
+		}
+	}
+
+	hs.masterSecret = hs.sessionState.masterSecret
+
+	return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+	config := hs.c.config
+	c := hs.c
+
+	if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+		hs.hello.ocspStapling = true
+	}
+
+	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
+	hs.hello.cipherSuite = hs.suite.id
+
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+
+	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+
+	certMsg := new(certificateMsg)
+	certMsg.certificates = hs.cert.Certificate
+	hs.finishedHash.Write(certMsg.marshal())
+	c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+	if hs.hello.ocspStapling {
+		certStatus := new(certificateStatusMsg)
+		certStatus.statusType = statusTypeOCSP
+		certStatus.response = hs.cert.OCSPStaple
+		hs.finishedHash.Write(certStatus.marshal())
+		c.writeRecord(recordTypeHandshake, certStatus.marshal())
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+	skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if skx != nil {
+		hs.finishedHash.Write(skx.marshal())
+		c.writeRecord(recordTypeHandshake, skx.marshal())
+	}
+
+	if config.ClientAuth >= RequestClientCert {
+		// Request a client certificate
+		certReq := new(certificateRequestMsg)
+		certReq.certificateTypes = []byte{
+			byte(certTypeRSASign),
+			byte(certTypeECDSASign),
+		}
+		if c.vers >= VersionTLS12 {
+			certReq.hasSignatureAndHash = true
+			certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
+		}
+
+		// An empty list of certificateAuthorities signals to
+		// the client that it may send any certificate in response
+		// to our request. When we know the CAs we trust, then
+		// we can send them down, so that the client can choose
+		// an appropriate certificate to give to us.
+		if config.ClientCAs != nil {
+			certReq.certificateAuthorities = config.ClientCAs.Subjects()
+		}
+		hs.finishedHash.Write(certReq.marshal())
+		c.writeRecord(recordTypeHandshake, certReq.marshal())
+	}
+
+	helloDone := new(serverHelloDoneMsg)
+	hs.finishedHash.Write(helloDone.marshal())
+	c.writeRecord(recordTypeHandshake, helloDone.marshal())
+
+	var pub crypto.PublicKey // public key for client auth, if any
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	var ok bool
+	// If we requested a client certificate, then the client must send a
+	// certificate message, even if it's empty.
+	if config.ClientAuth >= RequestClientCert {
+		if certMsg, ok = msg.(*certificateMsg); !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+		hs.finishedHash.Write(certMsg.marshal())
+
+		if len(certMsg.certificates) == 0 {
+			// The client didn't actually send a certificate
+			switch config.ClientAuth {
+			case RequireAnyClientCert, RequireAndVerifyClientCert:
+				c.sendAlert(alertBadCertificate)
+				return errors.New("tls: client didn't provide a certificate")
+			}
+		}
+
+		pub, err = hs.processCertsFromClient(certMsg.certificates)
+		if err != nil {
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	// Get client key exchange
+	ckx, ok := msg.(*clientKeyExchangeMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(ckx, msg)
+	}
+	hs.finishedHash.Write(ckx.marshal())
+
+	// If we received a client cert in response to our certificate request message,
+	// the client will send us a certificateVerifyMsg immediately after the
+	// clientKeyExchangeMsg.  This message is a digest of all preceding
+	// handshake-layer messages that is signed using the private key corresponding
+	// to the client's certificate. This allows us to verify that the client is in
+	// possession of the private key of the certificate.
+	if len(c.peerCertificates) > 0 {
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+		certVerify, ok := msg.(*certificateVerifyMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
+		}
+
+		switch key := pub.(type) {
+		case *ecdsa.PublicKey:
+			ecdsaSig := new(ecdsaSignature)
+			if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
+				break
+			}
+			if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+				err = errors.New("ECDSA signature contained zero or negative values")
+				break
+			}
+			digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA)
+			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
+				err = errors.New("ECDSA verification failure")
+				break
+			}
+		case *rsa.PublicKey:
+			digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA)
+			err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
+		}
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("could not validate signature of connection nonces: " + err.Error())
+		}
+
+		hs.finishedHash.Write(certVerify.marshal())
+	}
+
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+
+	return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+
+	var clientCipher, serverCipher interface{}
+	var clientHash, serverHash macFunction
+
+	if hs.suite.aead == nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+		clientHash = hs.suite.mac(c.vers, clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+		serverHash = hs.suite.mac(c.vers, serverMAC)
+	} else {
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
+	}
+
+	c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+	return nil
+}
+
+func (hs *serverHandshakeState) readFinished() error {
+	c := hs.c
+
+	c.readRecord(recordTypeChangeCipherSpec)
+	if err := c.in.error(); err != nil {
+		return err
+	}
+
+	if hs.hello.nextProtoNeg {
+		msg, err := c.readHandshake()
+		if err != nil {
+			return err
+		}
+		nextProto, ok := msg.(*nextProtoMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(nextProto, msg)
+		}
+		hs.finishedHash.Write(nextProto.marshal())
+		c.clientProtocol = nextProto.proto
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	clientFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientFinished, msg)
+	}
+
+	verify := hs.finishedHash.clientSum(hs.masterSecret)
+	if len(verify) != len(clientFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: client's Finished message is incorrect")
+	}
+
+	hs.finishedHash.Write(clientFinished.marshal())
+	return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+	if !hs.hello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	m := new(newSessionTicketMsg)
+
+	var err error
+	state := sessionState{
+		vers:         c.vers,
+		cipherSuite:  hs.suite.id,
+		masterSecret: hs.masterSecret,
+		certificates: hs.certsFromClient,
+	}
+	m.ticket, err = c.encryptTicket(&state)
+	if err != nil {
+		return err
+	}
+	m.ticket = make([]byte, 16105+62)
+	for i := range m.ticket {
+		m.ticket[i] = 'A'
+	}
+
+	hs.finishedHash.Write(m.marshal())
+	c.writeRecord(recordTypeHandshake, m.marshal())
+
+	return nil
+}
+
+func (hs *serverHandshakeState) sendFinished() error {
+	c := hs.c
+
+	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	c.writeRecord(recordTypeHandshake, finished.marshal())
+
+	c.cipherSuite = hs.suite.id
+
+	return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message or from a sessionState and verifies them. It returns
+// the public key of the leaf certificate.
+func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) {
+	c := hs.c
+
+	hs.certsFromClient = certificates
+	certs := make([]*x509.Certificate, len(certificates))
+	var err error
+	for i, asn1Data := range certificates {
+		if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return nil, errors.New("tls: failed to parse client certificate: " + err.Error())
+		}
+	}
+
+	if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+		opts := x509.VerifyOptions{
+			Roots:         c.config.ClientCAs,
+			CurrentTime:   c.config.time(),
+			Intermediates: x509.NewCertPool(),
+			KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+		}
+
+		for _, cert := range certs[1:] {
+			opts.Intermediates.AddCert(cert)
+		}
+
+		chains, err := certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
+		}
+
+		ok := false
+		for _, ku := range certs[0].ExtKeyUsage {
+			if ku == x509.ExtKeyUsageClientAuth {
+				ok = true
+				break
+			}
+		}
+		if !ok {
+			c.sendAlert(alertHandshakeFailure)
+			return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
+		}
+
+		c.verifiedChains = chains
+	}
+
+	if len(certs) > 0 {
+		var pub crypto.PublicKey
+		switch key := certs[0].PublicKey.(type) {
+		case *ecdsa.PublicKey, *rsa.PublicKey:
+			pub = key
+		default:
+			c.sendAlert(alertUnsupportedCertificate)
+			return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+		}
+		c.peerCertificates = certs
+		return pub, nil
+	}
+
+	return nil, nil
+}
+
+// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
+// is acceptable to use.
+func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
+	for _, supported := range supportedCipherSuites {
+		if id == supported {
+			var candidate *cipherSuite
+
+			for _, s := range cipherSuites {
+				if s.id == id {
+					candidate = s
+					break
+				}
+			}
+			if candidate == nil {
+				continue
+			}
+			// Don't select a ciphersuite which we can't
+			// support for this client.
+			if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
+				continue
+			}
+			if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+				continue
+			}
+			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
+				continue
+			}
+			return candidate
+		}
+	}
+
+	return nil
+}
diff --git a/ssl/test/runner/key.pem b/ssl/test/runner/key.pem
new file mode 100644
index 0000000..e9107bf
--- /dev/null
+++ b/ssl/test/runner/key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92
+kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF
+KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB
+AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe
+i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+
+WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ
+m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj
+QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk
+aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj
+LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk
+104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/
+tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd
+moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==
+-----END RSA PRIVATE KEY-----
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
new file mode 100644
index 0000000..991a91d
--- /dev/null
+++ b/ssl/test/runner/key_agreement.go
@@ -0,0 +1,436 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/md5"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/asn1"
+	"errors"
+	"io"
+	"math/big"
+)
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	preMasterSecret := make([]byte, 48)
+	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+	if err != nil {
+		return nil, err
+	}
+
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+
+	ciphertext := ckx.ciphertext
+	if version != VersionSSL30 {
+		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+		if ciphertextLen != len(ckx.ciphertext)-2 {
+			return nil, errClientKeyExchange
+		}
+		ciphertext = ckx.ciphertext[2:]
+	}
+
+	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
+	if err != nil {
+		return nil, err
+	}
+	// We don't check the version number in the premaster secret.  For one,
+	// by checking it, we would leak information about the validity of the
+	// encrypted pre-master secret. Secondly, it provides only a small
+	// benefit against a downgrade attack and some implementations send the
+	// wrong version anyway. See the discussion at the end of section
+	// 7.4.7.1 of RFC 4346.
+	return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	preMasterSecret := make([]byte, 48)
+	preMasterSecret[0] = byte(clientHello.vers >> 8)
+	preMasterSecret[1] = byte(clientHello.vers)
+	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+	if err != nil {
+		return nil, nil, err
+	}
+
+	encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
+	if err != nil {
+		return nil, nil, err
+	}
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, len(encrypted)+2)
+	ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+	ckx.ciphertext[1] = byte(len(encrypted))
+	copy(ckx.ciphertext[2:], encrypted)
+	return preMasterSecret, ckx, nil
+}
+
+// sha1Hash calculates a SHA1 hash over the given byte slices.
+func sha1Hash(slices [][]byte) []byte {
+	hsha1 := sha1.New()
+	for _, slice := range slices {
+		hsha1.Write(slice)
+	}
+	return hsha1.Sum(nil)
+}
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices [][]byte) []byte {
+	md5sha1 := make([]byte, md5.Size+sha1.Size)
+	hmd5 := md5.New()
+	for _, slice := range slices {
+		hmd5.Write(slice)
+	}
+	copy(md5sha1, hmd5.Sum(nil))
+	copy(md5sha1[md5.Size:], sha1Hash(slices))
+	return md5sha1
+}
+
+// sha256Hash implements TLS 1.2's hash function.
+func sha256Hash(slices [][]byte) []byte {
+	h := sha256.New()
+	for _, slice := range slices {
+		h.Write(slice)
+	}
+	return h.Sum(nil)
+}
+
+// hashForServerKeyExchange hashes the given slices and returns their digest
+// and the identifier of the hash function used. The hashFunc argument is only
+// used for >= TLS 1.2 and precisely identifies the hash function to use.
+func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+	if version >= VersionTLS12 {
+		switch hashFunc {
+		case hashSHA256:
+			return sha256Hash(slices), crypto.SHA256, nil
+		case hashSHA1:
+			return sha1Hash(slices), crypto.SHA1, nil
+		default:
+			return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer")
+		}
+	}
+	if sigType == signatureECDSA {
+		return sha1Hash(slices), crypto.SHA1, nil
+	}
+	return md5SHA1Hash(slices), crypto.MD5SHA1, nil
+}
+
+// pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
+// ServerKeyExchange given the signature type being used and the client's
+// advertized list of supported signature and hash combinations.
+func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
+	if len(clientSignatureAndHashes) == 0 {
+		// If the client didn't specify any signature_algorithms
+		// extension then we can assume that it supports SHA1. See
+		// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+		return hashSHA1, nil
+	}
+
+	for _, sigAndHash := range clientSignatureAndHashes {
+		if sigAndHash.signature != sigType {
+			continue
+		}
+		switch sigAndHash.hash {
+		case hashSHA1, hashSHA256:
+			return sigAndHash.hash, nil
+		}
+	}
+
+	return 0, errors.New("tls: client doesn't support any common hash functions")
+}
+
+func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+	switch id {
+	case CurveP256:
+		return elliptic.P256(), true
+	case CurveP384:
+		return elliptic.P384(), true
+	case CurveP521:
+		return elliptic.P521(), true
+	default:
+		return nil, false
+	}
+
+}
+
+// ecdheRSAKeyAgreement implements a TLS key agreement where the server
+// generates a ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// either be ECDSA or RSA.
+type ecdheKeyAgreement struct {
+	version    uint16
+	sigType    uint8
+	privateKey []byte
+	curve      elliptic.Curve
+	x, y       *big.Int
+}
+
+func maybeCorruptECDSAValue(n *big.Int, typeOfCorruption BadValue, limit *big.Int) *big.Int {
+	switch typeOfCorruption {
+	case BadValueNone:
+		return n
+	case BadValueNegative:
+		return new(big.Int).Neg(n)
+	case BadValueZero:
+		return big.NewInt(0)
+	case BadValueLimit:
+		return limit
+	case BadValueLarge:
+		bad := new(big.Int).Set(limit)
+		return bad.Lsh(bad, 20)
+	default:
+		panic("unknown BadValue type")
+	}
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	var curveid CurveID
+	preferredCurves := config.curvePreferences()
+
+NextCandidate:
+	for _, candidate := range preferredCurves {
+		for _, c := range clientHello.supportedCurves {
+			if candidate == c {
+				curveid = c
+				break NextCandidate
+			}
+		}
+	}
+
+	if curveid == 0 {
+		return nil, errors.New("tls: no supported elliptic curves offered")
+	}
+
+	var ok bool
+	if ka.curve, ok = curveForCurveID(curveid); !ok {
+		return nil, errors.New("tls: preferredCurves includes unsupported curve")
+	}
+
+	var x, y *big.Int
+	var err error
+	ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
+	if err != nil {
+		return nil, err
+	}
+	ecdhePublic := elliptic.Marshal(ka.curve, x, y)
+
+	// http://tools.ietf.org/html/rfc4492#section-5.4
+	serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
+	serverECDHParams[0] = 3 // named curve
+	serverECDHParams[1] = byte(curveid >> 8)
+	serverECDHParams[2] = byte(curveid)
+	if config.Bugs.InvalidSKXCurve {
+		serverECDHParams[2] ^= 0xff
+	}
+	serverECDHParams[3] = byte(len(ecdhePublic))
+	copy(serverECDHParams[4:], ecdhePublic)
+
+	var tls12HashId uint8
+	if ka.version >= VersionTLS12 {
+		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
+			return nil, err
+		}
+	}
+
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
+	if err != nil {
+		return nil, err
+	}
+
+	if config.Bugs.InvalidSKXSignature {
+		digest[0] ^= 0x80
+	}
+
+	var sig []byte
+	switch ka.sigType {
+	case signatureECDSA:
+		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
+		}
+		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
+		if err != nil {
+			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+		}
+		order := privKey.Curve.Params().N
+		r = maybeCorruptECDSAValue(r, config.Bugs.BadECDSAR, order)
+		s = maybeCorruptECDSAValue(s, config.Bugs.BadECDSAS, order)
+		sig, err = asn1.Marshal(ecdsaSignature{r, s})
+	case signatureRSA:
+		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("ECDHE RSA requires a RSA server private key")
+		}
+		sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
+		if err != nil {
+			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+		}
+	default:
+		return nil, errors.New("unknown ECDHE signature algorithm")
+	}
+
+	skx := new(serverKeyExchangeMsg)
+	sigAndHashLen := 0
+	if ka.version >= VersionTLS12 {
+		sigAndHashLen = 2
+	}
+	skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig))
+	copy(skx.key, serverECDHParams)
+	k := skx.key[len(serverECDHParams):]
+	if ka.version >= VersionTLS12 {
+		k[0] = tls12HashId
+		k[1] = ka.sigType
+		k = k[2:]
+	}
+	k[0] = byte(len(sig) >> 8)
+	k[1] = byte(len(sig))
+	copy(k[2:], sig)
+
+	return skx, nil
+}
+
+func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+		return nil, errClientKeyExchange
+	}
+	x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
+	if x == nil {
+		return nil, errClientKeyExchange
+	}
+	x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
+	preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
+	xBytes := x.Bytes()
+	copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+	return preMasterSecret, nil
+}
+
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	if len(skx.key) < 4 {
+		return errServerKeyExchange
+	}
+	if skx.key[0] != 3 { // named curve
+		return errors.New("tls: server selected unsupported curve")
+	}
+	curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
+
+	var ok bool
+	if ka.curve, ok = curveForCurveID(curveid); !ok {
+		return errors.New("tls: server selected unsupported curve")
+	}
+
+	publicLen := int(skx.key[3])
+	if publicLen+4 > len(skx.key) {
+		return errServerKeyExchange
+	}
+	ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen])
+	if ka.x == nil {
+		return errServerKeyExchange
+	}
+	serverECDHParams := skx.key[:4+publicLen]
+
+	sig := skx.key[4+publicLen:]
+	if len(sig) < 2 {
+		return errServerKeyExchange
+	}
+
+	var tls12HashId uint8
+	if ka.version >= VersionTLS12 {
+		// handle SignatureAndHashAlgorithm
+		var sigAndHash []uint8
+		sigAndHash, sig = sig[:2], sig[2:]
+		if sigAndHash[1] != ka.sigType {
+			return errServerKeyExchange
+		}
+		tls12HashId = sigAndHash[0]
+		if len(sig) < 2 {
+			return errServerKeyExchange
+		}
+	}
+	sigLen := int(sig[0])<<8 | int(sig[1])
+	if sigLen+2 != len(sig) {
+		return errServerKeyExchange
+	}
+	sig = sig[2:]
+
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+	if err != nil {
+		return err
+	}
+	switch ka.sigType {
+	case signatureECDSA:
+		pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
+		if !ok {
+			return errors.New("ECDHE ECDSA requires a ECDSA server public key")
+		}
+		ecdsaSig := new(ecdsaSignature)
+		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
+			return err
+		}
+		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+			return errors.New("ECDSA signature contained zero or negative values")
+		}
+		if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
+			return errors.New("ECDSA verification failure")
+		}
+	case signatureRSA:
+		pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
+		if !ok {
+			return errors.New("ECDHE RSA requires a RSA server public key")
+		}
+		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
+			return err
+		}
+	default:
+		return errors.New("unknown ECDHE signature algorithm")
+	}
+
+	return nil
+}
+
+func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	if ka.curve == nil {
+		return nil, nil, errors.New("missing ServerKeyExchange message")
+	}
+	priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
+	if err != nil {
+		return nil, nil, err
+	}
+	x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
+	preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
+	xBytes := x.Bytes()
+	copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+	serialized := elliptic.Marshal(ka.curve, mx, my)
+
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, 1+len(serialized))
+	ckx.ciphertext[0] = byte(len(serialized))
+	copy(ckx.ciphertext[1:], serialized)
+
+	return preMasterSecret, ckx, nil
+}
diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go
new file mode 100644
index 0000000..acb9654
--- /dev/null
+++ b/ssl/test/runner/prf.go
@@ -0,0 +1,303 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"crypto"
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"hash"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+	s1 = secret[0 : (len(secret)+1)/2]
+	s2 = secret[len(secret)/2:]
+	return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+	h := hmac.New(hash, secret)
+	h.Write(seed)
+	a := h.Sum(nil)
+
+	j := 0
+	for j < len(result) {
+		h.Reset()
+		h.Write(a)
+		h.Write(seed)
+		b := h.Sum(nil)
+		todo := len(b)
+		if j+todo > len(result) {
+			todo = len(result) - j
+		}
+		copy(result[j:j+todo], b)
+		j += todo
+
+		h.Reset()
+		h.Write(a)
+		a = h.Sum(nil)
+	}
+}
+
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func prf10(result, secret, label, seed []byte) {
+	hashSHA1 := sha1.New
+	hashMD5 := md5.New
+
+	labelAndSeed := make([]byte, len(label)+len(seed))
+	copy(labelAndSeed, label)
+	copy(labelAndSeed[len(label):], seed)
+
+	s1, s2 := splitPreMasterSecret(secret)
+	pHash(result, s1, labelAndSeed, hashMD5)
+	result2 := make([]byte, len(result))
+	pHash(result2, s2, labelAndSeed, hashSHA1)
+
+	for i, b := range result2 {
+		result[i] ^= b
+	}
+}
+
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
+	return func(result, secret, label, seed []byte) {
+		labelAndSeed := make([]byte, len(label)+len(seed))
+		copy(labelAndSeed, label)
+		copy(labelAndSeed[len(label):], seed)
+
+		pHash(result, secret, labelAndSeed, hashFunc)
+	}
+}
+
+// prf30 implements the SSL 3.0 pseudo-random function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
+func prf30(result, secret, label, seed []byte) {
+	hashSHA1 := sha1.New()
+	hashMD5 := md5.New()
+
+	done := 0
+	i := 0
+	// RFC5246 section 6.3 says that the largest PRF output needed is 128
+	// bytes. Since no more ciphersuites will be added to SSLv3, this will
+	// remain true. Each iteration gives us 16 bytes so 10 iterations will
+	// be sufficient.
+	var b [11]byte
+	for done < len(result) {
+		for j := 0; j <= i; j++ {
+			b[j] = 'A' + byte(i)
+		}
+
+		hashSHA1.Reset()
+		hashSHA1.Write(b[:i+1])
+		hashSHA1.Write(secret)
+		hashSHA1.Write(seed)
+		digest := hashSHA1.Sum(nil)
+
+		hashMD5.Reset()
+		hashMD5.Write(secret)
+		hashMD5.Write(digest)
+
+		done += copy(result[done:], hashMD5.Sum(nil))
+		i++
+	}
+}
+
+const (
+	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
+	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
+	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+	switch version {
+	case VersionSSL30:
+		return prf30
+	case VersionTLS10, VersionTLS11:
+		return prf10
+	case VersionTLS12:
+		if suite.flags&suiteSHA384 != 0 {
+			return prf12(sha512.New384)
+		}
+		return prf12(sha256.New)
+	default:
+		panic("unknown version")
+	}
+}
+
+// masterFromPreMasterSecret generates the master secret from the pre-master
+// secret. See http://tools.ietf.org/html/rfc5246#section-8.1
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+	var seed [tlsRandomLength * 2]byte
+	copy(seed[0:len(clientRandom)], clientRandom)
+	copy(seed[len(clientRandom):], serverRandom)
+	masterSecret := make([]byte, masterSecretLength)
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+	return masterSecret
+}
+
+// keysFromMasterSecret generates the connection keys from the master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+	var seed [tlsRandomLength * 2]byte
+	copy(seed[0:len(clientRandom)], serverRandom)
+	copy(seed[len(serverRandom):], clientRandom)
+
+	n := 2*macLen + 2*keyLen + 2*ivLen
+	keyMaterial := make([]byte, n)
+	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+	clientMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	serverMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	clientKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	serverKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	clientIV = keyMaterial[:ivLen]
+	keyMaterial = keyMaterial[ivLen:]
+	serverIV = keyMaterial[:ivLen]
+	return
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+	if version >= VersionTLS12 {
+		newHash := sha256.New
+		if cipherSuite.flags&suiteSHA384 != 0 {
+			newHash = sha512.New384
+		}
+
+		return finishedHash{newHash(), newHash(), nil, nil, version, prf12(newHash)}
+	}
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version, prf10}
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+	client hash.Hash
+	server hash.Hash
+
+	// Prior to TLS 1.2, an additional MD5 hash is required.
+	clientMD5 hash.Hash
+	serverMD5 hash.Hash
+
+	version uint16
+	prf     func(result, secret, label, seed []byte)
+}
+
+func (h finishedHash) Write(msg []byte) (n int, err error) {
+	h.client.Write(msg)
+	h.server.Write(msg)
+
+	if h.version < VersionTLS12 {
+		h.clientMD5.Write(msg)
+		h.serverMD5.Write(msg)
+	}
+	return len(msg), nil
+}
+
+// finishedSum30 calculates the contents of the verify_data member of a SSLv3
+// Finished message given the MD5 and SHA1 hashes of a set of handshake
+// messages.
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
+	md5.Write(magic[:])
+	md5.Write(masterSecret)
+	md5.Write(ssl30Pad1[:])
+	md5Digest := md5.Sum(nil)
+
+	md5.Reset()
+	md5.Write(masterSecret)
+	md5.Write(ssl30Pad2[:])
+	md5.Write(md5Digest)
+	md5Digest = md5.Sum(nil)
+
+	sha1.Write(magic[:])
+	sha1.Write(masterSecret)
+	sha1.Write(ssl30Pad1[:40])
+	sha1Digest := sha1.Sum(nil)
+
+	sha1.Reset()
+	sha1.Write(masterSecret)
+	sha1.Write(ssl30Pad2[:40])
+	sha1.Write(sha1Digest)
+	sha1Digest = sha1.Sum(nil)
+
+	ret := make([]byte, len(md5Digest)+len(sha1Digest))
+	copy(ret, md5Digest)
+	copy(ret[len(md5Digest):], sha1Digest)
+	return ret
+}
+
+var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
+var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+	if h.version == VersionSSL30 {
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
+	}
+
+	out := make([]byte, finishedVerifyLength)
+	if h.version >= VersionTLS12 {
+		seed := h.client.Sum(nil)
+		h.prf(out, masterSecret, clientFinishedLabel, seed)
+	} else {
+		seed := make([]byte, 0, md5.Size+sha1.Size)
+		seed = h.clientMD5.Sum(seed)
+		seed = h.client.Sum(seed)
+		h.prf(out, masterSecret, clientFinishedLabel, seed)
+	}
+	return out
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+	if h.version == VersionSSL30 {
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
+	}
+
+	out := make([]byte, finishedVerifyLength)
+	if h.version >= VersionTLS12 {
+		seed := h.server.Sum(nil)
+		h.prf(out, masterSecret, serverFinishedLabel, seed)
+	} else {
+		seed := make([]byte, 0, md5.Size+sha1.Size)
+		seed = h.serverMD5.Sum(seed)
+		seed = h.server.Sum(seed)
+		h.prf(out, masterSecret, serverFinishedLabel, seed)
+	}
+	return out
+}
+
+// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
+// id suitable for signing by a TLS client certificate.
+func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
+	if h.version >= VersionTLS12 {
+		digest := h.server.Sum(nil)
+		return digest, crypto.SHA256, hashSHA256
+	}
+	if sigType == signatureECDSA {
+		digest := h.server.Sum(nil)
+		return digest, crypto.SHA1, hashSHA1
+	}
+
+	digest := make([]byte, 0, 36)
+	digest = h.serverMD5.Sum(digest)
+	digest = h.server.Sum(digest)
+	return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
new file mode 100644
index 0000000..1edd00b
--- /dev/null
+++ b/ssl/test/runner/runner.go
@@ -0,0 +1,365 @@
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+	"syscall"
+)
+
+var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+
+var rsaCertificate, ecdsaCertificate Certificate
+
+func initCertificates() {
+	var err error
+	rsaCertificate, err = LoadX509KeyPair("cert.pem", "key.pem")
+	if err != nil {
+		panic(err)
+	}
+
+	ecdsaCertificate, err = LoadX509KeyPair("ecdsa_cert.pem", "ecdsa_key.pem")
+	if err != nil {
+		panic(err)
+	}
+}
+
+var certificateOnce sync.Once
+
+func getRSACertificate() Certificate {
+	certificateOnce.Do(initCertificates)
+	return rsaCertificate
+}
+
+func getECDSACertificate() Certificate {
+	certificateOnce.Do(initCertificates)
+	return ecdsaCertificate
+}
+
+type testCase struct {
+	name          string
+	config        Config
+	shouldFail    bool
+	expectedError string
+}
+
+var clientTests = []testCase{
+	{
+		name: "BadRSASignature",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXSignature: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":BAD_SIGNATURE:",
+	},
+	{
+		name: "BadECDSASignature",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXSignature: true,
+			},
+			Certificates: []Certificate{getECDSACertificate()},
+		},
+		shouldFail:    true,
+		expectedError: ":BAD_SIGNATURE:",
+	},
+	{
+		name: "BadECDSACurve",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXCurve: true,
+			},
+			Certificates: []Certificate{getECDSACertificate()},
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	},
+}
+
+var testMessage = []byte("testing")
+
+func doExchange(tlsConn *Conn) error {
+	if err := tlsConn.Handshake(); err != nil {
+		return err
+	}
+	tlsConn.Write(testMessage)
+
+	buf := make([]byte, len(testMessage))
+	_, err := io.ReadFull(tlsConn, buf)
+	if err != nil {
+		return err
+	}
+
+	for i, v := range buf {
+		if v != testMessage[i]^0xff {
+			return fmt.Errorf("bad reply contents at byte %d", i)
+		}
+	}
+
+	return nil
+}
+
+func valgrindOf(dbAttach bool, baseArgs ...string) *exec.Cmd {
+	args := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
+	if dbAttach {
+		args = append(args, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
+	}
+	args = append(args, baseArgs...)
+
+	return exec.Command("valgrind", args...)
+}
+
+func gdbOf(baseArgs ...string) *exec.Cmd {
+	args := []string{"-e", "gdb", "--args"}
+	args = append(args, baseArgs...)
+
+	return exec.Command("xterm", args...)
+}
+
+func runTest(test *testCase) error {
+	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	syscall.CloseOnExec(socks[0])
+	syscall.CloseOnExec(socks[1])
+	clientEnd := os.NewFile(uintptr(socks[0]), "client end")
+	connFile := os.NewFile(uintptr(socks[1]), "our end")
+	conn, err := net.FileConn(connFile)
+	connFile.Close()
+	if err != nil {
+		panic(err)
+	}
+
+	const shim_path = "../../../build/ssl/test/client_shim"
+	var client *exec.Cmd
+	if *useValgrind {
+		client = valgrindOf(false, shim_path)
+	} else {
+		client = exec.Command(shim_path)
+	}
+	//client := gdbOf(shim_path)
+	client.ExtraFiles = []*os.File{clientEnd}
+	client.Stdin = os.Stdin
+	var stdoutBuf, stderrBuf bytes.Buffer
+	client.Stdout = &stdoutBuf
+	client.Stderr = &stderrBuf
+
+	if err := client.Start(); err != nil {
+		panic(err)
+	}
+	clientEnd.Close()
+
+	config := test.config
+	if len(config.Certificates) == 0 {
+		config.Certificates = []Certificate{getRSACertificate()}
+	}
+
+	tlsConn := Server(conn, &config)
+	err = doExchange(tlsConn)
+
+	conn.Close()
+	childErr := client.Wait()
+
+	stdout := string(stdoutBuf.Bytes())
+	stderr := string(stderrBuf.Bytes())
+	failed := err != nil || childErr != nil
+	correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
+
+	if failed != test.shouldFail || failed && !correctFailure {
+		localError := "none"
+		childError := "none"
+		if err != nil {
+			localError = err.Error()
+		}
+		if childErr != nil {
+			childError = childErr.Error()
+		}
+
+		var msg string
+		switch {
+		case failed && !test.shouldFail:
+			msg = "unexpected failure"
+		case !failed && test.shouldFail:
+			msg = "unexpected success"
+		case failed && !correctFailure:
+			msg = "bad error (wanted '" + test.expectedError + "')"
+		default:
+			panic("internal error")
+		}
+
+		return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
+	}
+
+	if !*useValgrind && len(stderr) > 0 {
+		println(stderr)
+	}
+
+	return nil
+}
+
+var tlsVersions = []struct {
+	name    string
+	version uint16
+}{
+	{"SSL3", VersionSSL30},
+	{"TLS1", VersionTLS10},
+	{"TLS11", VersionTLS11},
+	{"TLS12", VersionTLS12},
+}
+
+var testCipherSuites = []struct {
+	name string
+	id   uint16
+}{
+	{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+	{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+	{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+	{"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
+	{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
+	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
+}
+
+func addCipherSuiteTests() {
+	for _, suite := range testCipherSuites {
+		var cert Certificate
+		if strings.Contains(suite.name, "ECDSA") {
+			cert = getECDSACertificate()
+		} else {
+			cert = getRSACertificate()
+		}
+
+		for _, ver := range tlsVersions {
+			if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
+				continue
+			}
+
+			clientTests = append(clientTests, testCase{
+				name: ver.name + "-" + suite.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					CipherSuites: []uint16{suite.id},
+					Certificates: []Certificate{cert},
+				},
+			})
+		}
+	}
+}
+
+func addBadECDSASignatureTests() {
+	for badR := BadValue(1); badR < NumBadValues; badR++ {
+		for badS := BadValue(1); badS < NumBadValues; badS++ {
+			clientTests = append(clientTests, testCase{
+				name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
+				config: Config{
+					CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+					Certificates: []Certificate{getECDSACertificate()},
+					Bugs: ProtocolBugs{
+						BadECDSAR: badR,
+						BadECDSAS: badS,
+					},
+				},
+				shouldFail:    true,
+				expectedError: "SIGNATURE",
+			})
+		}
+	}
+}
+
+func worker(statusChan chan statusMsg, c chan *testCase, wg *sync.WaitGroup) {
+	defer wg.Done()
+
+	for test := range c {
+		statusChan <- statusMsg{test: test, started: true}
+		err := runTest(test)
+		statusChan <- statusMsg{test: test, err: err}
+	}
+}
+
+type statusMsg struct {
+	test    *testCase
+	started bool
+	err     error
+}
+
+func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
+	var started, done, failed, lineLen int
+	defer close(doneChan)
+
+	for msg := range statusChan {
+		if msg.started {
+			started++
+		} else {
+			done++
+		}
+
+		fmt.Printf("\x1b[%dD\x1b[K", lineLen)
+
+		if msg.err != nil {
+			fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
+			failed++
+		}
+		line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
+		lineLen = len(line)
+		os.Stdout.WriteString(line)
+	}
+}
+
+func main() {
+	var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
+
+	flag.Parse()
+
+	addCipherSuiteTests()
+	addBadECDSASignatureTests()
+
+	var wg sync.WaitGroup
+
+	const numWorkers = 64
+
+	statusChan := make(chan statusMsg, numWorkers)
+	testChan := make(chan *testCase, numWorkers)
+	doneChan := make(chan struct{})
+
+	go statusPrinter(doneChan, statusChan, len(clientTests))
+
+	for i := 0; i < numWorkers; i++ {
+		wg.Add(1)
+		go worker(statusChan, testChan, &wg)
+	}
+
+	for i := range clientTests {
+		if len(*flagTest) == 0 || *flagTest == clientTests[i].name {
+			testChan <- &clientTests[i]
+		}
+	}
+
+	close(testChan)
+	wg.Wait()
+	close(statusChan)
+	<-doneChan
+
+	fmt.Printf("\n")
+}
diff --git a/ssl/test/runner/ticket.go b/ssl/test/runner/ticket.go
new file mode 100644
index 0000000..70e91cf
--- /dev/null
+++ b/ssl/test/runner/ticket.go
@@ -0,0 +1,182 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"crypto/subtle"
+	"errors"
+	"io"
+)
+
+// sessionState contains the information that is serialized into a session
+// ticket in order to later resume a connection.
+type sessionState struct {
+	vers         uint16
+	cipherSuite  uint16
+	masterSecret []byte
+	certificates [][]byte
+}
+
+func (s *sessionState) equal(i interface{}) bool {
+	s1, ok := i.(*sessionState)
+	if !ok {
+		return false
+	}
+
+	if s.vers != s1.vers ||
+		s.cipherSuite != s1.cipherSuite ||
+		!bytes.Equal(s.masterSecret, s1.masterSecret) {
+		return false
+	}
+
+	if len(s.certificates) != len(s1.certificates) {
+		return false
+	}
+
+	for i := range s.certificates {
+		if !bytes.Equal(s.certificates[i], s1.certificates[i]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (s *sessionState) marshal() []byte {
+	length := 2 + 2 + 2 + len(s.masterSecret) + 2
+	for _, cert := range s.certificates {
+		length += 4 + len(cert)
+	}
+
+	ret := make([]byte, length)
+	x := ret
+	x[0] = byte(s.vers >> 8)
+	x[1] = byte(s.vers)
+	x[2] = byte(s.cipherSuite >> 8)
+	x[3] = byte(s.cipherSuite)
+	x[4] = byte(len(s.masterSecret) >> 8)
+	x[5] = byte(len(s.masterSecret))
+	x = x[6:]
+	copy(x, s.masterSecret)
+	x = x[len(s.masterSecret):]
+
+	x[0] = byte(len(s.certificates) >> 8)
+	x[1] = byte(len(s.certificates))
+	x = x[2:]
+
+	for _, cert := range s.certificates {
+		x[0] = byte(len(cert) >> 24)
+		x[1] = byte(len(cert) >> 16)
+		x[2] = byte(len(cert) >> 8)
+		x[3] = byte(len(cert))
+		copy(x[4:], cert)
+		x = x[4+len(cert):]
+	}
+
+	return ret
+}
+
+func (s *sessionState) unmarshal(data []byte) bool {
+	if len(data) < 8 {
+		return false
+	}
+
+	s.vers = uint16(data[0])<<8 | uint16(data[1])
+	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
+	masterSecretLen := int(data[4])<<8 | int(data[5])
+	data = data[6:]
+	if len(data) < masterSecretLen {
+		return false
+	}
+
+	s.masterSecret = data[:masterSecretLen]
+	data = data[masterSecretLen:]
+
+	if len(data) < 2 {
+		return false
+	}
+
+	numCerts := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+
+	s.certificates = make([][]byte, numCerts)
+	for i := range s.certificates {
+		if len(data) < 4 {
+			return false
+		}
+		certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+		data = data[4:]
+		if certLen < 0 {
+			return false
+		}
+		if len(data) < certLen {
+			return false
+		}
+		s.certificates[i] = data[:certLen]
+		data = data[certLen:]
+	}
+
+	if len(data) > 0 {
+		return false
+	}
+
+	return true
+}
+
+func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
+	serialized := state.marshal()
+	encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
+	iv := encrypted[:aes.BlockSize]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
+		return nil, err
+	}
+	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	if err != nil {
+		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
+	}
+	cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
+
+	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	mac.Write(encrypted[:len(encrypted)-sha256.Size])
+	mac.Sum(macBytes[:0])
+
+	return encrypted, nil
+}
+
+func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
+	if len(encrypted) < aes.BlockSize+sha256.Size {
+		return nil, false
+	}
+
+	iv := encrypted[:aes.BlockSize]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	mac.Write(encrypted[:len(encrypted)-sha256.Size])
+	expected := mac.Sum(nil)
+
+	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+		return nil, false
+	}
+
+	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	if err != nil {
+		return nil, false
+	}
+	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+	plaintext := ciphertext
+	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+	state := new(sessionState)
+	ok := state.unmarshal(plaintext)
+	return state, ok
+}
diff --git a/ssl/test/runner/tls.go b/ssl/test/runner/tls.go
new file mode 100644
index 0000000..c062a41
--- /dev/null
+++ b/ssl/test/runner/tls.go
@@ -0,0 +1,275 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246.
+package main
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"io/ioutil"
+	"net"
+	"strings"
+	"time"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Server(conn net.Conn, config *Config) *Conn {
+	return &Conn{conn: conn, config: config}
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerHostname or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *Conn {
+	return &Conn{conn: conn, config: config, isClient: true}
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+	net.Listener
+	config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
+func (l *listener) Accept() (c net.Conn, err error) {
+	c, err = l.Listener.Accept()
+	if err != nil {
+		return
+	}
+	c = Server(c, l.config)
+	return
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+	l := new(listener)
+	l.Listener = inner
+	l.config = config
+	return l
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
+	if config == nil || len(config.Certificates) == 0 {
+		return nil, errors.New("tls.Listen: no certificates in configuration")
+	}
+	l, err := net.Listen(network, laddr)
+	if err != nil {
+		return nil, err
+	}
+	return NewListener(l, config), nil
+}
+
+type timeoutError struct{}
+
+func (timeoutError) Error() string   { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool   { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+	// We want the Timeout and Deadline values from dialer to cover the
+	// whole process: TCP connection and TLS handshake. This means that we
+	// also need to start our own timers now.
+	timeout := dialer.Timeout
+
+	if !dialer.Deadline.IsZero() {
+		deadlineTimeout := dialer.Deadline.Sub(time.Now())
+		if timeout == 0 || deadlineTimeout < timeout {
+			timeout = deadlineTimeout
+		}
+	}
+
+	var errChannel chan error
+
+	if timeout != 0 {
+		errChannel = make(chan error, 2)
+		time.AfterFunc(timeout, func() {
+			errChannel <- timeoutError{}
+		})
+	}
+
+	rawConn, err := dialer.Dial(network, addr)
+	if err != nil {
+		return nil, err
+	}
+
+	colonPos := strings.LastIndex(addr, ":")
+	if colonPos == -1 {
+		colonPos = len(addr)
+	}
+	hostname := addr[:colonPos]
+
+	if config == nil {
+		config = defaultConfig()
+	}
+	// If no ServerName is set, infer the ServerName
+	// from the hostname we're connecting to.
+	if config.ServerName == "" {
+		// Make a copy to avoid polluting argument or default.
+		c := *config
+		c.ServerName = hostname
+		config = &c
+	}
+
+	conn := Client(rawConn, config)
+
+	if timeout == 0 {
+		err = conn.Handshake()
+	} else {
+		go func() {
+			errChannel <- conn.Handshake()
+		}()
+
+		err = <-errChannel
+	}
+
+	if err != nil {
+		rawConn.Close()
+		return nil, err
+	}
+
+	return conn, nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
+	certPEMBlock, err := ioutil.ReadFile(certFile)
+	if err != nil {
+		return
+	}
+	keyPEMBlock, err := ioutil.ReadFile(keyFile)
+	if err != nil {
+		return
+	}
+	return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
+	var certDERBlock *pem.Block
+	for {
+		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+		if certDERBlock == nil {
+			break
+		}
+		if certDERBlock.Type == "CERTIFICATE" {
+			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+		}
+	}
+
+	if len(cert.Certificate) == 0 {
+		err = errors.New("crypto/tls: failed to parse certificate PEM data")
+		return
+	}
+
+	var keyDERBlock *pem.Block
+	for {
+		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
+		if keyDERBlock == nil {
+			err = errors.New("crypto/tls: failed to parse key PEM data")
+			return
+		}
+		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
+			break
+		}
+	}
+
+	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
+	if err != nil {
+		return
+	}
+
+	// We don't need to parse the public key for TLS, but we so do anyway
+	// to check that it looks sane and matches the private key.
+	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+	if err != nil {
+		return
+	}
+
+	switch pub := x509Cert.PublicKey.(type) {
+	case *rsa.PublicKey:
+		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		if !ok {
+			err = errors.New("crypto/tls: private key type does not match public key type")
+			return
+		}
+		if pub.N.Cmp(priv.N) != 0 {
+			err = errors.New("crypto/tls: private key does not match public key")
+			return
+		}
+	case *ecdsa.PublicKey:
+		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		if !ok {
+			err = errors.New("crypto/tls: private key type does not match public key type")
+			return
+
+		}
+		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
+			err = errors.New("crypto/tls: private key does not match public key")
+			return
+		}
+	default:
+		err = errors.New("crypto/tls: unknown public key algorithm")
+		return
+	}
+
+	return
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+		return key, nil
+	}
+	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+		switch key := key.(type) {
+		case *rsa.PrivateKey, *ecdsa.PrivateKey:
+			return key, nil
+		default:
+			return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
+		}
+	}
+	if key, err := x509.ParseECPrivateKey(der); err == nil {
+		return key, nil
+	}
+
+	return nil, errors.New("crypto/tls: failed to parse private key")
+}
diff --git a/ssl/tls1.h b/ssl/tls1.h
new file mode 100644
index 0000000..c2976f6
--- /dev/null
+++ b/ssl/tls1.h
@@ -0,0 +1,779 @@
+/* ssl/tls1.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@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@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@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@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-2006 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@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@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@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.
+ */
+
+#ifndef HEADER_TLS1_H 
+#define HEADER_TLS1_H 
+
+#include <openssl/buf.h>
+#include <openssl/stack.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES	0
+
+#define TLS1_2_VERSION			0x0303
+#define TLS1_2_VERSION_MAJOR		0x03
+#define TLS1_2_VERSION_MINOR		0x03
+
+#define TLS1_1_VERSION			0x0302
+#define TLS1_1_VERSION_MAJOR		0x03
+#define TLS1_1_VERSION_MINOR		0x02
+
+#define TLS1_VERSION			0x0301
+#define TLS1_VERSION_MAJOR		0x03
+#define TLS1_VERSION_MINOR		0x01
+
+#define TLS1_get_version(s) \
+		((s->version >> 8) == TLS1_VERSION_MAJOR ? s->version : 0)
+
+#define TLS1_get_client_version(s) \
+		((s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0)
+
+#define TLS1_AD_DECRYPTION_FAILED	21
+#define TLS1_AD_RECORD_OVERFLOW		22
+#define TLS1_AD_UNKNOWN_CA		48	/* fatal */
+#define TLS1_AD_ACCESS_DENIED		49	/* fatal */
+#define TLS1_AD_DECODE_ERROR		50	/* fatal */
+#define TLS1_AD_DECRYPT_ERROR		51
+#define TLS1_AD_EXPORT_RESTRICTION	60	/* fatal */
+#define TLS1_AD_PROTOCOL_VERSION	70	/* fatal */
+#define TLS1_AD_INSUFFICIENT_SECURITY	71	/* fatal */
+#define TLS1_AD_INTERNAL_ERROR		80	/* fatal */
+#define TLS1_AD_USER_CANCELLED		90
+#define TLS1_AD_NO_RENEGOTIATION	100
+/* codes 110-114 are from RFC3546 */
+#define TLS1_AD_UNSUPPORTED_EXTENSION	110
+#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
+#define TLS1_AD_UNRECOGNIZED_NAME 	112
+#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113
+#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
+#define TLS1_AD_UNKNOWN_PSK_IDENTITY	115	/* fatal */
+
+/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */
+#define TLSEXT_TYPE_server_name			0
+#define TLSEXT_TYPE_max_fragment_length		1
+#define TLSEXT_TYPE_client_certificate_url	2
+#define TLSEXT_TYPE_trusted_ca_keys		3
+#define TLSEXT_TYPE_truncated_hmac		4
+#define TLSEXT_TYPE_status_request		5
+/* ExtensionType values from RFC4681 */
+#define TLSEXT_TYPE_user_mapping		6
+
+/* ExtensionType values from RFC5878 */
+#define TLSEXT_TYPE_client_authz		7
+#define TLSEXT_TYPE_server_authz		8
+
+/* ExtensionType values from RFC6091 */
+#define TLSEXT_TYPE_cert_type		9
+
+/* ExtensionType values from RFC4492 */
+#define TLSEXT_TYPE_elliptic_curves		10
+#define TLSEXT_TYPE_ec_point_formats		11
+
+/* ExtensionType value from RFC5054 */
+#define TLSEXT_TYPE_srp				12
+
+/* ExtensionType values from RFC5246 */
+#define TLSEXT_TYPE_signature_algorithms	13
+
+/* ExtensionType value from RFC5764 */
+#define TLSEXT_TYPE_use_srtp	14
+
+/* ExtensionType value from RFC5620 */
+#define TLSEXT_TYPE_heartbeat	15
+
+/* ExtensionType value from draft-ietf-tls-applayerprotoneg-00 */
+#define TLSEXT_TYPE_application_layer_protocol_negotiation 16
+
+/* ExtensionType value from RFC4507 */
+#define TLSEXT_TYPE_session_ticket		35
+
+/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */
+#if 0 /* will have to be provided externally for now ,
+       * i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183
+       * using whatever extension number you'd like to try */
+# define TLSEXT_TYPE_opaque_prf_input		?? */
+#endif
+
+/* Temporary extension type */
+#define TLSEXT_TYPE_renegotiate                 0xff01
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/* This is not an IANA defined extension number */
+#define TLSEXT_TYPE_next_proto_neg		13172
+#endif
+
+/* NameType value from RFC 3546 */
+#define TLSEXT_NAMETYPE_host_name 0
+/* status request value from RFC 3546 */
+#define TLSEXT_STATUSTYPE_ocsp 1
+
+/* ECPointFormat values from draft-ietf-tls-ecc-12 */
+#define TLSEXT_ECPOINTFORMAT_first			0
+#define TLSEXT_ECPOINTFORMAT_uncompressed		0
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime	1
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2	2
+#define TLSEXT_ECPOINTFORMAT_last			2
+
+/* Signature and hash algorithms from RFC 5246 */
+
+#define TLSEXT_signature_anonymous			0
+#define TLSEXT_signature_rsa				1
+#define TLSEXT_signature_dsa				2
+#define TLSEXT_signature_ecdsa				3
+
+/* Total number of different signature algorithms */
+#define TLSEXT_signature_num				4
+
+#define TLSEXT_hash_none				0
+#define TLSEXT_hash_md5					1
+#define TLSEXT_hash_sha1				2
+#define TLSEXT_hash_sha224				3
+#define TLSEXT_hash_sha256				4
+#define TLSEXT_hash_sha384				5
+#define TLSEXT_hash_sha512				6
+
+/* Total number of different digest algorithms */
+
+#define TLSEXT_hash_num					7
+
+/* Flag set for unrecognised algorithms */
+#define TLSEXT_nid_unknown				0x1000000
+
+/* ECC curves */
+
+#define TLSEXT_curve_P_256				23
+#define TLSEXT_curve_P_384				24
+
+#ifndef OPENSSL_NO_TLSEXT
+
+#define TLSEXT_MAXLEN_host_name 255
+
+/* From RFC 5878 */
+#define TLSEXT_SUPPLEMENTALDATATYPE_authz_data 16386
+/* This is not IANA assigned. See
+ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#authorization-data-rules */
+#define TLSEXT_AUTHZDATAFORMAT_audit_proof 182
+
+#define TLSEXT_MAXLEN_supplemental_data 1024*16 /* Let's limit to 16k */
+
+const char *SSL_get_servername(const SSL *s, const int type);
+int SSL_get_servername_type(const SSL *s);
+/* SSL_export_keying_material exports a value derived from the master secret,
+ * as specified in RFC 5705. It writes |olen| bytes to |out| given a label and
+ * optional context. (Since a zero length context is allowed, the |use_context|
+ * flag controls whether a context is included.)
+ *
+ * It returns 1 on success and zero otherwise.
+ */
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+	const char *label, size_t llen, const unsigned char *p, size_t plen,
+	int use_context);
+
+int SSL_get_sigalgs(SSL *s, int idx,
+			int *psign, int *phash, int *psignandhash,
+			unsigned char *rsig, unsigned char *rhash);
+
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+			int *psign, int *phash, int *psignandhash,
+			unsigned char *rsig, unsigned char *rhash);
+
+int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain);
+
+#define SSL_set_tlsext_host_name(s,name) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
+
+#define SSL_set_tlsext_debug_callback(ssl, cb) \
+SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
+
+#define SSL_set_tlsext_debug_arg(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
+
+#define SSL_set_tlsext_status_type(ssl, type) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL)
+
+#define SSL_get_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg)
+
+#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
+
+#define SSL_TLSEXT_ERR_OK 0
+#define SSL_TLSEXT_ERR_ALERT_WARNING 1
+#define SSL_TLSEXT_ERR_ALERT_FATAL 2
+#define SSL_TLSEXT_ERR_NOACK 3
+
+#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
+
+#define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLSEXT_TICKET_KEYS,(keylen),(keys))
+#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLSEXT_TICKET_KEYS,(keylen),(keys))
+
+#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \
+SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb)
+
+#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \
+SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg)
+
+#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
+#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb)
+#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
+
+#define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \
+SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
+
+/* Used by clients to process audit proofs. */
+#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB,(void (*)(void))cb)
+
+#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG, 0, arg);
+
+#ifndef OPENSSL_NO_HEARTBEATS
+#define SSL_TLSEXT_HB_ENABLED				0x01
+#define SSL_TLSEXT_HB_DONT_SEND_REQUESTS	0x02
+#define SSL_TLSEXT_HB_DONT_RECV_REQUESTS	0x04
+
+#define SSL_get_tlsext_heartbeat_pending(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING,0,NULL)
+#define SSL_set_tlsext_heartbeat_no_requests(ssl, arg) \
+        SSL_ctrl((ssl),SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS,arg,NULL)
+#endif
+#endif
+
+/* PSK ciphersuites from 4279 */
+#define TLS1_CK_PSK_WITH_RC4_128_SHA                    0x0300008A
+#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA               0x0300008B
+#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA                0x0300008C
+#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA                0x0300008D
+
+/* Additional TLS ciphersuites from expired Internet Draft
+ * draft-ietf-tls-56-bit-ciphersuites-01.txt
+ * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see
+ * s3_lib.c).  We actually treat them like SSL 3.0 ciphers, which we probably
+ * shouldn't.  Note that the first two are actually not in the IDs. */
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5		0x03000060 /* not in ID */
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5	0x03000061 /* not in ID */
+#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA		0x03000062
+#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA	0x03000063
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA		0x03000064
+#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA	0x03000065
+#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA		0x03000066
+
+/* AES ciphersuites from RFC3268 */
+
+#define TLS1_CK_RSA_WITH_AES_128_SHA			0x0300002F
+#define TLS1_CK_DH_DSS_WITH_AES_128_SHA			0x03000030
+#define TLS1_CK_DH_RSA_WITH_AES_128_SHA			0x03000031
+#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA		0x03000032
+#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA		0x03000033
+#define TLS1_CK_ADH_WITH_AES_128_SHA			0x03000034
+
+#define TLS1_CK_RSA_WITH_AES_256_SHA			0x03000035
+#define TLS1_CK_DH_DSS_WITH_AES_256_SHA			0x03000036
+#define TLS1_CK_DH_RSA_WITH_AES_256_SHA			0x03000037
+#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA		0x03000038
+#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA		0x03000039
+#define TLS1_CK_ADH_WITH_AES_256_SHA			0x0300003A
+
+/* TLS v1.2 ciphersuites */
+#define TLS1_CK_RSA_WITH_NULL_SHA256			0x0300003B
+#define TLS1_CK_RSA_WITH_AES_128_SHA256			0x0300003C
+#define TLS1_CK_RSA_WITH_AES_256_SHA256			0x0300003D
+#define TLS1_CK_DH_DSS_WITH_AES_128_SHA256		0x0300003E
+#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256		0x0300003F
+#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256		0x03000040
+
+/* Camellia ciphersuites from RFC4132 */
+#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA		0x03000041
+#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA	0x03000042
+#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA	0x03000043
+#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA	0x03000044
+#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA	0x03000045
+#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA		0x03000046
+
+/* TLS v1.2 ciphersuites */
+#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256		0x03000067
+#define TLS1_CK_DH_DSS_WITH_AES_256_SHA256		0x03000068
+#define TLS1_CK_DH_RSA_WITH_AES_256_SHA256		0x03000069
+#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256		0x0300006A
+#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256		0x0300006B
+#define TLS1_CK_ADH_WITH_AES_128_SHA256			0x0300006C
+#define TLS1_CK_ADH_WITH_AES_256_SHA256			0x0300006D
+
+/* Camellia ciphersuites from RFC4132 */
+#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA		0x03000084
+#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA	0x03000085
+#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA	0x03000086
+#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA	0x03000087
+#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA	0x03000088
+#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA		0x03000089
+
+/* SEED ciphersuites from RFC4162 */
+#define TLS1_CK_RSA_WITH_SEED_SHA                       0x03000096
+#define TLS1_CK_DH_DSS_WITH_SEED_SHA                    0x03000097
+#define TLS1_CK_DH_RSA_WITH_SEED_SHA                    0x03000098
+#define TLS1_CK_DHE_DSS_WITH_SEED_SHA                   0x03000099
+#define TLS1_CK_DHE_RSA_WITH_SEED_SHA                   0x0300009A
+#define TLS1_CK_ADH_WITH_SEED_SHA                	0x0300009B
+
+/* TLS v1.2 GCM ciphersuites from RFC5288 */
+#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256		0x0300009C
+#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384		0x0300009D
+#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256		0x0300009E
+#define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384		0x0300009F
+#define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256		0x030000A0
+#define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384		0x030000A1
+#define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256		0x030000A2
+#define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384		0x030000A3
+#define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256		0x030000A4
+#define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384		0x030000A5
+#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256		0x030000A6
+#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384		0x030000A7
+
+/* ECC ciphersuites from draft-ietf-tls-ecc-12.txt with changes soon to be in draft 13 */
+#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA                0x0300C001
+#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA             0x0300C002
+#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA        0x0300C003
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA         0x0300C004
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA         0x0300C005
+
+#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA               0x0300C006
+#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA            0x0300C007
+#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA       0x0300C008
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA        0x0300C009
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA        0x0300C00A
+
+#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA                  0x0300C00B
+#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA               0x0300C00C
+#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA          0x0300C00D
+#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA           0x0300C00E
+#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA           0x0300C00F
+
+#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA                 0x0300C010
+#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA              0x0300C011
+#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA         0x0300C012
+#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA          0x0300C013
+#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA          0x0300C014
+
+#define TLS1_CK_ECDH_anon_WITH_NULL_SHA                 0x0300C015
+#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA              0x0300C016
+#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA         0x0300C017
+#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA          0x0300C018
+#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA          0x0300C019
+
+/* SRP ciphersuites from RFC 5054 */
+#define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA		0x0300C01A
+#define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA	0x0300C01B
+#define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA	0x0300C01C
+#define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA		0x0300C01D
+#define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA	0x0300C01E
+#define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA	0x0300C01F
+#define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA		0x0300C020
+#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA	0x0300C021
+#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA	0x0300C022
+
+/* ECDH HMAC based ciphersuites from RFC5289 */
+
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256         0x0300C023
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384         0x0300C024
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256          0x0300C025
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384          0x0300C026
+#define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256           0x0300C027
+#define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384           0x0300C028
+#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256            0x0300C029
+#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384            0x0300C02A
+
+/* ECDH GCM based ciphersuites from RFC5289 */
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256	0x0300C02B
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384	0x0300C02C
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256      0x0300C02D
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384      0x0300C02E
+#define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256       0x0300C02F
+#define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384       0x0300C030
+#define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256        0x0300C031
+#define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384        0x0300C032
+
+/* XXX
+ * Inconsistency alert:
+ * The OpenSSL names of ciphers with ephemeral DH here include the string
+ * "DHE", while elsewhere it has always been "EDH".
+ * (The alias for the list of all such ciphers also is "EDH".)
+ * The specifications speak of "EDH"; maybe we should allow both forms
+ * for everything. */
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5		"EXP1024-RC4-MD5"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5	"EXP1024-RC2-CBC-MD5"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA	"EXP1024-DES-CBC-SHA"
+#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA	"EXP1024-DHE-DSS-DES-CBC-SHA"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA		"EXP1024-RC4-SHA"
+#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA	"EXP1024-DHE-DSS-RC4-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA		"DHE-DSS-RC4-SHA"
+
+/* AES ciphersuites from RFC3268 */
+#define TLS1_TXT_RSA_WITH_AES_128_SHA			"AES128-SHA"
+#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA		"DH-DSS-AES128-SHA"
+#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA		"DH-RSA-AES128-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA		"DHE-DSS-AES128-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA		"DHE-RSA-AES128-SHA"
+#define TLS1_TXT_ADH_WITH_AES_128_SHA			"ADH-AES128-SHA"
+
+#define TLS1_TXT_RSA_WITH_AES_256_SHA			"AES256-SHA"
+#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA		"DH-DSS-AES256-SHA"
+#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA		"DH-RSA-AES256-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA		"DHE-DSS-AES256-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA		"DHE-RSA-AES256-SHA"
+#define TLS1_TXT_ADH_WITH_AES_256_SHA			"ADH-AES256-SHA"
+
+/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA               "ECDH-ECDSA-NULL-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA            "ECDH-ECDSA-RC4-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA       "ECDH-ECDSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA        "ECDH-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA        "ECDH-ECDSA-AES256-SHA"
+
+#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA              "ECDHE-ECDSA-NULL-SHA"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA           "ECDHE-ECDSA-RC4-SHA"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA      "ECDHE-ECDSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA       "ECDHE-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA       "ECDHE-ECDSA-AES256-SHA"
+
+#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA                 "ECDH-RSA-NULL-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA              "ECDH-RSA-RC4-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA         "ECDH-RSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA          "ECDH-RSA-AES128-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA          "ECDH-RSA-AES256-SHA"
+
+#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA                "ECDHE-RSA-NULL-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA             "ECDHE-RSA-RC4-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA        "ECDHE-RSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA         "ECDHE-RSA-AES128-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA         "ECDHE-RSA-AES256-SHA"
+
+#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA                "AECDH-NULL-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA             "AECDH-RC4-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA        "AECDH-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA         "AECDH-AES128-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA         "AECDH-AES256-SHA"
+
+/* PSK ciphersuites from RFC 4279 */
+#define TLS1_TXT_PSK_WITH_RC4_128_SHA			"PSK-RC4-SHA"
+#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA		"PSK-3DES-EDE-CBC-SHA"
+#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA		"PSK-AES128-CBC-SHA"
+#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA		"PSK-AES256-CBC-SHA"
+
+/* SRP ciphersuite from RFC 5054 */
+#define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA		"SRP-3DES-EDE-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA	"SRP-RSA-3DES-EDE-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA	"SRP-DSS-3DES-EDE-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA		"SRP-AES-128-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA	"SRP-RSA-AES-128-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA	"SRP-DSS-AES-128-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA		"SRP-AES-256-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA	"SRP-RSA-AES-256-CBC-SHA"
+#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA	"SRP-DSS-AES-256-CBC-SHA"
+
+/* Camellia ciphersuites from RFC4132 */
+#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA		"CAMELLIA128-SHA"
+#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA	"DH-DSS-CAMELLIA128-SHA"
+#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA	"DH-RSA-CAMELLIA128-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA	"DHE-DSS-CAMELLIA128-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA	"DHE-RSA-CAMELLIA128-SHA"
+#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA		"ADH-CAMELLIA128-SHA"
+
+#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA		"CAMELLIA256-SHA"
+#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA	"DH-DSS-CAMELLIA256-SHA"
+#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA	"DH-RSA-CAMELLIA256-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA	"DHE-DSS-CAMELLIA256-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA	"DHE-RSA-CAMELLIA256-SHA"
+#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA		"ADH-CAMELLIA256-SHA"
+
+/* SEED ciphersuites from RFC4162 */
+#define TLS1_TXT_RSA_WITH_SEED_SHA                      "SEED-SHA"
+#define TLS1_TXT_DH_DSS_WITH_SEED_SHA                   "DH-DSS-SEED-SHA"
+#define TLS1_TXT_DH_RSA_WITH_SEED_SHA                   "DH-RSA-SEED-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA                  "DHE-DSS-SEED-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA                  "DHE-RSA-SEED-SHA"
+#define TLS1_TXT_ADH_WITH_SEED_SHA                      "ADH-SEED-SHA"
+
+/* TLS v1.2 ciphersuites */
+#define TLS1_TXT_RSA_WITH_NULL_SHA256			"NULL-SHA256"
+#define TLS1_TXT_RSA_WITH_AES_128_SHA256		"AES128-SHA256"
+#define TLS1_TXT_RSA_WITH_AES_256_SHA256		"AES256-SHA256"
+#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256		"DH-DSS-AES128-SHA256"
+#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256		"DH-RSA-AES128-SHA256"
+#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256		"DHE-DSS-AES128-SHA256"
+#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256		"DHE-RSA-AES128-SHA256"
+#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256		"DH-DSS-AES256-SHA256"
+#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256		"DH-RSA-AES256-SHA256"
+#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256		"DHE-DSS-AES256-SHA256"
+#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256		"DHE-RSA-AES256-SHA256"
+#define TLS1_TXT_ADH_WITH_AES_128_SHA256		"ADH-AES128-SHA256"
+#define TLS1_TXT_ADH_WITH_AES_256_SHA256		"ADH-AES256-SHA256"
+
+/* TLS v1.2 GCM ciphersuites from RFC5288 */
+#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256		"AES128-GCM-SHA256"
+#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384		"AES256-GCM-SHA384"
+#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256	"DHE-RSA-AES128-GCM-SHA256"
+#define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384	"DHE-RSA-AES256-GCM-SHA384"
+#define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256		"DH-RSA-AES128-GCM-SHA256"
+#define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384		"DH-RSA-AES256-GCM-SHA384"
+#define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256	"DHE-DSS-AES128-GCM-SHA256"
+#define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384	"DHE-DSS-AES256-GCM-SHA384"
+#define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256		"DH-DSS-AES128-GCM-SHA256"
+#define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384		"DH-DSS-AES256-GCM-SHA384"
+#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256		"ADH-AES128-GCM-SHA256"
+#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384		"ADH-AES256-GCM-SHA384"
+
+/* ECDH HMAC based ciphersuites from RFC5289 */
+
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256    "ECDHE-ECDSA-AES128-SHA256"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384    "ECDHE-ECDSA-AES256-SHA384"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256     "ECDH-ECDSA-AES128-SHA256"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384     "ECDH-ECDSA-AES256-SHA384"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256      "ECDHE-RSA-AES128-SHA256"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384      "ECDHE-RSA-AES256-SHA384"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256       "ECDH-RSA-AES128-SHA256"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384       "ECDH-RSA-AES256-SHA384"
+
+/* ECDH GCM based ciphersuites from RFC5289 */
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256    "ECDHE-ECDSA-AES128-GCM-SHA256"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384    "ECDHE-ECDSA-AES256-GCM-SHA384"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256     "ECDH-ECDSA-AES128-GCM-SHA256"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384     "ECDH-ECDSA-AES256-GCM-SHA384"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256      "ECDHE-RSA-AES128-GCM-SHA256"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384      "ECDHE-RSA-AES256-GCM-SHA384"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256       "ECDH-RSA-AES128-GCM-SHA256"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384       "ECDH-RSA-AES256-GCM-SHA384"
+
+#define TLS_CT_RSA_SIGN			1
+#define TLS_CT_DSS_SIGN			2
+#define TLS_CT_RSA_FIXED_DH		3
+#define TLS_CT_DSS_FIXED_DH		4
+#define TLS_CT_ECDSA_SIGN		64
+#define TLS_CT_RSA_FIXED_ECDH		65
+#define TLS_CT_ECDSA_FIXED_ECDH 	66
+#define TLS_CT_GOST94_SIGN		21
+#define TLS_CT_GOST01_SIGN		22
+/* when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see
+ * comment there) */
+#define TLS_CT_NUMBER			9
+
+#define TLS1_FINISH_MAC_LENGTH		12
+
+#define TLS_MD_MAX_CONST_SIZE			20
+#define TLS_MD_CLIENT_FINISH_CONST		"client finished"
+#define TLS_MD_CLIENT_FINISH_CONST_SIZE		15
+#define TLS_MD_SERVER_FINISH_CONST		"server finished"
+#define TLS_MD_SERVER_FINISH_CONST_SIZE		15
+#define TLS_MD_SERVER_WRITE_KEY_CONST		"server write key"
+#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_KEY_EXPANSION_CONST		"key expansion"
+#define TLS_MD_KEY_EXPANSION_CONST_SIZE		13
+#define TLS_MD_CLIENT_WRITE_KEY_CONST		"client write key"
+#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_SERVER_WRITE_KEY_CONST		"server write key"
+#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_IV_BLOCK_CONST			"IV block"
+#define TLS_MD_IV_BLOCK_CONST_SIZE		8
+#define TLS_MD_MASTER_SECRET_CONST		"master secret"
+#define TLS_MD_MASTER_SECRET_CONST_SIZE		13
+
+#ifdef CHARSET_EBCDIC
+#undef TLS_MD_CLIENT_FINISH_CONST
+#define TLS_MD_CLIENT_FINISH_CONST    "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64"  /*client finished*/
+#undef TLS_MD_SERVER_FINISH_CONST
+#define TLS_MD_SERVER_FINISH_CONST    "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64"  /*server finished*/
+#undef TLS_MD_SERVER_WRITE_KEY_CONST
+#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*server write key*/
+#undef TLS_MD_KEY_EXPANSION_CONST
+#define TLS_MD_KEY_EXPANSION_CONST    "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e"  /*key expansion*/
+#undef TLS_MD_CLIENT_WRITE_KEY_CONST
+#define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*client write key*/
+#undef TLS_MD_SERVER_WRITE_KEY_CONST
+#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*server write key*/
+#undef TLS_MD_IV_BLOCK_CONST
+#define TLS_MD_IV_BLOCK_CONST         "\x49\x56\x20\x62\x6c\x6f\x63\x6b"  /*IV block*/
+#undef TLS_MD_MASTER_SECRET_CONST
+#define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+#endif
+
+/* TLS Session Ticket extension struct */
+struct tls_session_ticket_ext_st
+	{
+	unsigned short length;
+	void *data;
+	};
+
+#ifdef  __cplusplus
+}
+#endif
+#endif