Early callback support.
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 1cbc26c..0245b9b 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -146,7 +146,8 @@
  * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
  * OTHERWISE. */
 
-#define REUSE_CIPHER_BUG
+/* Undefined in Google code. We've never enabled this workaround
+ * #define REUSE_CIPHER_BUG */
 #define NETSCAPE_HANG_BUG
 
 #include <stdio.h>
@@ -329,10 +330,14 @@
 			s->shutdown=0;
 			ret=ssl3_get_client_hello(s);
 			if (ret == PENDING_SESSION) {
-				s->state = SSL3_ST_SR_CLNT_HELLO_D;
 				s->rwstate = SSL_PENDING_SESSION;
 				goto end;
 			}
+			if (ret == CERTIFICATE_SELECTION_PENDING)
+				{
+				s->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
+				goto end;
+				}
 			if (ret <= 0) goto end;
 			s->renegotiate = 2;
 			s->state=SSL3_ST_SW_SRVR_HELLO_A;
@@ -914,9 +919,7 @@
 	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;
+	struct ssl_early_callback_ctx early_ctx;
 
 	/* 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,
@@ -924,13 +927,11 @@
 	 * If we are SSLv3, we will respond with SSLv3, even if prompted with
 	 * TLSv1.
 	 */
-	if (s->state == SSL3_ST_SR_CLNT_HELLO_A
-		)
-		{
+	switch (s->state) {
+	case SSL3_ST_SR_CLNT_HELLO_A:
 		s->state=SSL3_ST_SR_CLNT_HELLO_B;
-		}
-	if (s->state != SSL3_ST_SR_CLNT_HELLO_D)
-		{
+		/* fallthrough */
+	case SSL3_ST_SR_CLNT_HELLO_B:
 		s->first_packet=1;
 		n=s->method->ssl_get_message(s,
 			SSL3_ST_SR_CLNT_HELLO_B,
@@ -941,14 +942,67 @@
 
 		if (!ok) return((int)n);
 		s->first_packet=0;
-		}
-	else
-		{
-		/* We have previously parsed the ClientHello message, and can't
-		 * call ssl_get_message again without hashing the message into
-		 * the Finished digest again. */
+
+		/* 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;
+			p = (unsigned char *) s->init_msg;
+
+			if (n < 2 + SSL3_RANDOM_SIZE)
+				return 1;
+			session_length = *(p + 2 + SSL3_RANDOM_SIZE);
+			if (n < 2 + SSL3_RANDOM_SIZE + 1 + session_length)
+				return 1;
+			cookie_length =
+				*(p + 2 + SSL3_RANDOM_SIZE + 1 + session_length);
+			if (cookie_length == 0)
+				return 1;
+			}
+		s->state = SSL3_ST_SR_CLNT_HELLO_C;
+		/* fallthrough */
+	case SSL3_ST_SR_CLNT_HELLO_C:
+	case SSL3_ST_SR_CLNT_HELLO_D:
+		/* We have previously parsed the ClientHello message,
+		 * and can't call ssl_get_message again without hashing
+		 * the message into the Finished digest again. */
 		n = s->init_num;
-		}
+
+		memset(&early_ctx, 0, sizeof(early_ctx));
+		early_ctx.ssl = s;
+		early_ctx.client_hello = s->init_msg;
+		early_ctx.client_hello_len = n;
+		if (!ssl_early_callback_init(&early_ctx))
+			{
+			al = SSL_AD_DECODE_ERROR;
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_PARSE_FAILED);
+			goto f_err;
+			}
+
+		if (s->state == SSL3_ST_SR_CLNT_HELLO_C &&
+		    s->ctx->select_certificate_cb != NULL)
+			{
+			int ret;
+
+			s->state = SSL3_ST_SR_CLNT_HELLO_D;
+			ret = s->ctx->select_certificate_cb(&early_ctx);
+			if (ret == 0)
+				return CERTIFICATE_SELECTION_PENDING;
+			else if (ret == -1)
+				{
+				/* Connection rejected. */
+				al = SSL_AD_ACCESS_DENIED;
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CONNECTION_REJECTED);
+				goto f_err;
+				}
+			}
+		s->state = SSL3_ST_SR_CLNT_HELLO_D;
+	default:
+		return -1;
+	}
 
 	d=p=(unsigned char *)s->init_msg;
 
@@ -972,21 +1026,6 @@
 		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;
@@ -1013,7 +1052,7 @@
 		}
 	else
 		{
-		i=ssl_get_prev_session(s, p, j, d + n);
+		i=ssl_get_prev_session(s, &early_ctx);
 		if (i == 1)
 			{ /* previous session */
 			s->hit=1;
@@ -1301,7 +1340,6 @@
 			}
 		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);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 13bf5cb..0040cbb 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -865,6 +865,30 @@
 typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
 				unsigned int *id_len);
 
+/* ssl_early_callback_ctx is passed to certain callbacks that are called very
+ * early on during the server handshake. At this point, much of the SSL*
+ * hasn't been filled out and only the ClientHello can be depended on. */
+struct ssl_early_callback_ctx
+	{
+	SSL *ssl;
+	const unsigned char *client_hello;       size_t client_hello_len;
+	const unsigned char *session_id;         size_t session_id_len;
+	const unsigned char *cipher_suites;      size_t cipher_suites_len;
+	const unsigned char *compression_methods;size_t compression_methods_len;
+	const unsigned char *extensions;         size_t extensions_len;
+	};
+
+/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for
+ * an extension of the given type. If not found, it returns zero. Otherwise
+ * it sets |out_data| to point to the extension contents (not including the type
+ * and length bytes), sets |out_len| to the length of the extension contents
+ * and returns one. */
+char
+SSL_early_callback_ctx_extension_get(const struct ssl_early_callback_ctx *ctx,
+				     uint16_t extension_type,
+				     const unsigned char **out_data,
+				     size_t *out_len);
+
 typedef struct ssl_comp_st SSL_COMP;
 
 #ifndef OPENSSL_NO_SSL_INTERN
@@ -1051,6 +1075,13 @@
 
 	X509_VERIFY_PARAM *param;
 
+	/* select_certificate_cb is called before most ClientHello processing
+	 * and before the decision whether to resume a session is made.
+	 * It may return one to continue the handshake or zero to cause the
+	 * handshake loop to return with an error and cause SSL_get_error to
+	 * return SSL_ERROR_PENDING_CERTIFICATE. */
+	int (*select_certificate_cb) (const struct ssl_early_callback_ctx *);
+
 #if 0
 	int purpose;		/* Purpose setting */
 	int trust;		/* Trust setting */
@@ -1353,6 +1384,7 @@
 #define SSL_X509_LOOKUP	4
 #define SSL_CHANNEL_ID_LOOKUP	5
 #define SSL_PENDING_SESSION	7
+#define SSL_CERTIFICATE_SELECTION_PENDING	8
 
 /* These will only be used when doing non-blocking IO */
 #define SSL_want_nothing(s)	(SSL_want(s) == SSL_NOTHING)
@@ -1361,6 +1393,7 @@
 #define SSL_want_x509_lookup(s)	(SSL_want(s) == SSL_X509_LOOKUP)
 #define SSL_want_channel_id_lookup(s)	(SSL_want(s) == SSL_CHANNEL_ID_LOOKUP)
 #define SSL_want_session(s)	(SSL_want(s) == SSL_PENDING_SESSION)
+#define SSL_want_certificate(s)	(SSL_want(s) == SSL_CERTIFICATE_SELECTION_PENDING)
 
 #define SSL_MAC_FLAG_READ_MAC_STREAM 1
 #define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
@@ -1787,6 +1820,7 @@
 #define SSL_ERROR_WANT_ACCEPT		8
 #define SSL_ERROR_WANT_CHANNEL_ID_LOOKUP	9
 #define SSL_ERROR_PENDING_SESSION	11
+#define SSL_ERROR_PENDING_CERTIFICATE	12
 
 #define SSL_CTRL_NEED_TMP_RSA			1
 #define SSL_CTRL_SET_TMP_RSA			2
@@ -3059,5 +3093,7 @@
 #define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 434
 #define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 435
 #define SSL_R_INAPPROPRIATE_FALLBACK 436
+#define SSL_R_CLIENTHELLO_PARSE_FAILED 437
+#define SSL_R_CONNECTION_REJECTED 438
 
 #endif
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index 57a45cb..7124172 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -260,6 +260,7 @@
   {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_PARSE_FAILED), "CLIENTHELLO_PARSE_FAILED"},
   {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"},
@@ -267,6 +268,7 @@
   {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_REJECTED), "CONNECTION_REJECTED"},
   {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_D2I_ECDSA_SIG), "D2I_ECDSA_SIG"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index c753e50..f4d6205 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2823,6 +2823,9 @@
 	if ((i < 0) && SSL_want_session(s))
 		return(SSL_ERROR_PENDING_SESSION);
 
+	if ((i < 0) && SSL_want_certificate(s))
+		return(SSL_ERROR_PENDING_CERTIFICATE);
+
 	if ((i < 0) && SSL_want_read(s))
 		{
 		bio=SSL_get_rbio(s);
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index d61a03c..e33e07f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -492,6 +492,7 @@
 */
 
 #define PENDING_SESSION -10000
+#define CERTIFICATE_SELECTION_PENDING -10001
 
 #ifndef OPENSSL_NO_EC
 /* From ECC-TLS draft, used in encoding the curve type in 
@@ -996,7 +997,7 @@
 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_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx);
 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,
@@ -1281,6 +1282,7 @@
 
 SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 
+char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx);
 #ifndef OPENSSL_NO_EC
 int tls1_ec_curve_id2nid(int curve_id);
 int tls1_ec_nid2curve_id(int nid);
@@ -1323,8 +1325,8 @@
 #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 tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx,
+			SSL_SESSION **ret);
 
 int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
 				const EVP_MD *md);
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 206f0b1..923a992 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -427,11 +427,8 @@
 /* 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.
+ *   ctx: contains the early callback context, which is the result of a
+ *       shallow parse of the ClientHello.
  *
  * Returns:
  *   -1: error
@@ -443,8 +440,7 @@
  *   - 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)
+int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx)
 	{
 	/* This is used only by servers. */
 
@@ -455,14 +451,14 @@
 	int r;
 #endif
 
-	if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
+	if (ctx->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH)
 		goto err;
 
-	if (len == 0)
+	if (ctx->session_id_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 */
+	r = tls1_process_ticket(s, ctx, &ret); /* sets s->tlsext_ticket_expected */
 	switch (r)
 		{
 	case -1: /* Error during processing */
@@ -486,10 +482,10 @@
 		{
 		SSL_SESSION data;
 		data.ssl_version=s->version;
-		data.session_id_length=len;
-		if (len == 0)
+		data.session_id_length=ctx->session_id_len;
+		if (ctx->session_id_len == 0)
 			return 0;
-		memcpy(data.session_id,session_id,len);
+		memcpy(data.session_id,ctx->session_id,ctx->session_id_len);
 		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
 		ret=lh_SSL_SESSION_retrieve(s->session_ctx->sessions,&data);
 		if (ret != NULL)
@@ -508,7 +504,7 @@
 		{
 		int copy=1;
 	
-		if ((ret=s->session_ctx->get_session_cb(s,session_id,len,&copy)))
+		if ((ret=s->session_ctx->get_session_cb(s,(unsigned char *) ctx->session_id,ctx->session_id_len,&copy)))
 			{
 			if (ret == SSL_magic_pending_session_ptr())
 				{
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 726ec51..d1a67b3 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -213,6 +213,176 @@
 	s->version = s->method->version;
 	}
 
+char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx)
+	{
+	size_t len = ctx->client_hello_len;
+	const unsigned char *p = ctx->client_hello;
+	uint16_t *extension_types;
+	unsigned num_extensions;
+
+	/* Skip client version. */
+	if (len < 2)
+		return 0;
+	len -= 2; p += 2;
+
+	/* Skip client nonce. */
+	if (len < 32)
+		return 0;
+	len -= 32; p += 32;
+
+	/* Get length of session id. */
+	if (len < 1)
+		return 0;
+	ctx->session_id_len = *p;
+	p++; len--;
+
+	ctx->session_id = p;
+	if (len < ctx->session_id_len)
+		return 0;
+	p += ctx->session_id_len; len -= ctx->session_id_len;
+
+	/* Skip past DTLS cookie */
+	if (ctx->ssl->version == DTLS1_VERSION || ctx->ssl->version == DTLS1_BAD_VER)
+		{
+		unsigned cookie_len;
+
+		if (len < 1)
+			return 0;
+		cookie_len = *p;
+		p++; len--;
+		if (len < cookie_len)
+			return 0;
+		p += cookie_len; len -= cookie_len;
+		}
+
+	/* Skip cipher suites. */
+	if (len < 2)
+		return 0;
+	n2s(p, ctx->cipher_suites_len);
+	len -= 2;
+
+	if ((ctx->cipher_suites_len & 1) != 0)
+		return 0;
+
+	ctx->cipher_suites = p;
+	if (len < ctx->cipher_suites_len)
+		return 0;
+	p += ctx->cipher_suites_len; len -= ctx->cipher_suites_len;
+
+	/* Skip compression methods. */
+	if (len < 1)
+		return 0;
+	ctx->compression_methods_len = *p;
+	p++; len--;
+
+	ctx->compression_methods = p;
+	if (len < ctx->compression_methods_len)
+		return 0;
+	p += ctx->compression_methods_len; len -= ctx->compression_methods_len;
+
+	/* If the ClientHello ends here then it's valid, but doesn't have any
+	 * extensions. (E.g. SSLv3.) */
+	if (len == 0)
+		{
+		ctx->extensions = NULL;
+		ctx->extensions_len = 0;
+		return 1;
+		}
+
+	if (len < 2)
+		return 0;
+	n2s(p, ctx->extensions_len);
+	len -= 2;
+
+	if (ctx->extensions_len == 0 && len == 0)
+		{
+		ctx->extensions = NULL;
+		return 1;
+		}
+
+	ctx->extensions = p;
+	if (len != ctx->extensions_len)
+		return 0;
+
+	/* Verify that the extensions have valid lengths and that there are
+	 * no duplicates. Each extension takes, at least, four bytes, so
+	 * we can allocate a buffer of extensions_len/4 elements and be sure
+	 * that we have enough space for all the extension types. */
+	extension_types =
+		OPENSSL_malloc(sizeof(uint16_t) * ctx->extensions_len/4);
+	if (extension_types == NULL)
+		return 0;
+	num_extensions = 0;
+
+	while (len != 0)
+		{
+		uint16_t extension_type, extension_len;
+		unsigned i;
+
+		if (len < 4)
+			goto err;
+		n2s(p, extension_type);
+		n2s(p, extension_len);
+		len -= 4;
+
+		if (len < extension_len)
+			goto err;
+		p += extension_len; len -= extension_len;
+
+		for (i = 0; i < num_extensions; i++)
+			{
+			if (extension_types[i] == extension_type)
+				{
+				/* Duplicate extension type. */
+				goto err;
+				}
+			}
+		extension_types[num_extensions] = extension_type;
+		num_extensions++;
+		}
+
+	OPENSSL_free(extension_types);
+	return 1;
+
+err:
+	OPENSSL_free(extension_types);
+	return 0;
+	}
+
+char
+SSL_early_callback_ctx_extension_get(const struct ssl_early_callback_ctx *ctx,
+				     uint16_t extension_type,
+				     const unsigned char **out_data,
+				     size_t *out_len)
+	{
+	size_t len = ctx->extensions_len;
+	const unsigned char *p = ctx->extensions;
+
+	while (len != 0)
+		{
+		uint16_t ext_type, ext_len;
+
+		if (len < 4)
+			return 0;
+		n2s(p, ext_type);
+		n2s(p, ext_len);
+		len -= 4;
+
+		if (len < ext_len)
+			return 0;
+		if (ext_type == extension_type)
+			{
+			*out_data = p;
+			*out_len = ext_len;
+			return 1;
+			}
+
+		p += ext_len; len -= ext_len;
+		}
+
+	return 0;
+	}
+
 #ifndef OPENSSL_NO_EC
 
 static int nid_list[] =
@@ -3423,11 +3593,8 @@
  * 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.
+ *   ctx: contains the early callback context, which is the result of a
+ *       shallow parse of the ClientHello.
  *   ret: (output) on return, if a ticket was decrypted, then this is set to
  *       point to the resulting session.
  *
@@ -3452,91 +3619,58 @@
  *   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)
+int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx,
+			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;
+	const unsigned char *data;
+	size_t len;
+	int r;
 
 	/* 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)
+	if ((s->version <= SSL3_VERSION) && !ctx->extensions)
 		return 0;
-	if (p >= limit)
-		return -1;
-	/* Skip past DTLS cookie */
-	if (SSL_IS_DTLS(s))
+	if (!SSL_early_callback_ctx_extension_get(
+		ctx, TLSEXT_TYPE_session_ticket, &data, &len))
 		{
-		i = *(p++);
-		p+= i;
-		if (p >= limit)
+		return 0;
+		}
+	if (len == 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, data, len, ctx->session_id,
+			       ctx->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;
 		}
-	/* 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.