Update from stable branch.
diff --git a/CHANGES b/CHANGES
index ff51f47..cf5c17c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -680,6 +680,12 @@
      [NTT]
 
  Changes between 0.9.8g and 0.9.8h  [xx XXX xxxx]
+  
+  *) Add TLS session ticket callback. This allows an application to set
+     TLS ticket cipher and HMAC keys rather than relying on hardcoded fixed
+     values. This is useful for key rollover for example where several key
+     sets may exist with different names.
+     [Steve Henson]
 
   *) Reverse ENGINE-internal logic for caching default ENGINE handles.
      This was broken until now in 0.9.8 releases, such that the only way
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 00bc1b3..6844a43 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2770,6 +2770,13 @@
 		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;
+
 #endif
 	default:
 		return(0);
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index dee1f73..8a4faa6 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -2853,6 +2853,8 @@
 		unsigned int hlen;
 		EVP_CIPHER_CTX ctx;
 		HMAC_CTX hctx;
+		unsigned char iv[EVP_MAX_IV_LENGTH];
+		unsigned char key_name[16];
 
 		/* get session encoding length */
 		slen = i2d_SSL_SESSION(s->session, NULL);
@@ -2883,29 +2885,47 @@
 		*(p++)=SSL3_MT_NEWSESSION_TICKET;
 		/* Skip message length for now */
 		p += 3;
+		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 (s->ctx->tlsext_ticket_key_cb)
+			{
+			if (s->ctx->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,
+					s->ctx->tlsext_tick_aes_key, iv);
+			HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+					tlsext_tick_md(), NULL);
+			memcpy(key_name, s->ctx->tlsext_tick_key_name, 16);
+			}
 		l2n(s->session->tlsext_tick_lifetime_hint, p);
 		/* Skip ticket length for now */
 		p += 2;
 		/* Output key name */
 		macstart = p;
-		memcpy(p, s->ctx->tlsext_tick_key_name, 16);
+		memcpy(p, key_name, 16);
 		p += 16;
-		/* Generate and output IV */
-		RAND_pseudo_bytes(p, 16);
-		EVP_CIPHER_CTX_init(&ctx);
+		/* output IV */
+		memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
+		p += EVP_CIPHER_CTX_iv_length(&ctx);
 		/* Encrypt session data */
-		EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
-					s->ctx->tlsext_tick_aes_key, p);
-		p += 16;
 		EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
 		p += len;
 		EVP_EncryptFinal(&ctx, p, &len);
 		p += len;
 		EVP_CIPHER_CTX_cleanup(&ctx);
 
-		HMAC_CTX_init(&hctx);
-		HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
-				tlsext_tick_md(), NULL);
 		HMAC_Update(&hctx, macstart, p - macstart);
 		HMAC_Final(&hctx, p, &hlen);
 		HMAC_CTX_cleanup(&hctx);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 77a6d6a..53236ee 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -160,6 +160,7 @@
 #include <openssl/buffer.h>
 #endif
 #include <openssl/pem.h>
+#include <openssl/hmac.h>
 
 #include <openssl/kssl.h>
 #include <openssl/safestack.h>
@@ -807,6 +808,11 @@
 	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 */
@@ -1351,6 +1357,8 @@
 #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
 #endif
 
 #define SSL_session_reused(ssl) \
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 39629c2..f3c5a16 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1442,39 +1442,53 @@
 	SSL_SESSION *sess;
 	unsigned char *sdec;
 	const unsigned char *p;
-	int slen, mlen;
+	int slen, mlen, renew_ticket = 0;
 	unsigned char tick_hmac[EVP_MAX_MD_SIZE];
 	HMAC_CTX hctx;
 	EVP_CIPHER_CTX ctx;
-	/* Attempt to process session ticket, first conduct sanity and
- 	 * integrity checks on ticket.
- 	 */
-	mlen = EVP_MD_size(tlsext_tick_md());
-	eticklen -= mlen;
 	/* Need at least keyname + iv + some encrypted data */
 	if (eticklen < 48)
 		goto tickerr;
-	/* Check key name matches */
-	if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
-		goto tickerr;
-	/* Check HMAC of encrypted ticket */
+	/* Initialize session ticket encryption and HMAC contexts */
 	HMAC_CTX_init(&hctx);
-	HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
-				tlsext_tick_md(), NULL);
+	EVP_CIPHER_CTX_init(&ctx);
+	if (s->ctx->tlsext_ticket_key_cb)
+		{
+		unsigned char *nctick = (unsigned char *)etick;
+		int rv = s->ctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+							&ctx, &hctx, 0);
+		if (rv < 0)
+			return -1;
+		if (rv == 0)
+			goto tickerr;
+		if (rv == 2)
+			renew_ticket = 1;
+		}
+	else
+		{
+		/* Check key name matches */
+		if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
+			goto tickerr;
+		HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+					tlsext_tick_md(), NULL);
+		EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+				s->ctx->tlsext_tick_aes_key, etick + 16);
+		}
+	/* Attempt to process session ticket, first conduct sanity and
+ 	 * integrity checks on ticket.
+ 	 */
+	mlen = HMAC_size(&hctx);
+	eticklen -= mlen;
+	/* Check HMAC of encrypted ticket */
 	HMAC_Update(&hctx, etick, eticklen);
 	HMAC_Final(&hctx, tick_hmac, NULL);
 	HMAC_CTX_cleanup(&hctx);
 	if (memcmp(tick_hmac, etick + eticklen, mlen))
 		goto tickerr;
-	/* Set p to start of IV */
-	p = etick + 16;
-	EVP_CIPHER_CTX_init(&ctx);
 	/* Attempt to decrypt session data */
-	EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
-					s->ctx->tlsext_tick_aes_key, p);
 	/* Move p after IV to start of encrypted ticket, update length */
-	p += 16;
-	eticklen -= 32;
+	p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+	eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
 	sdec = OPENSSL_malloc(eticklen);
 	if (!sdec)
 		{
@@ -1501,7 +1515,7 @@
 			memcpy(sess->session_id, sess_id, sesslen);
 		sess->session_id_length = sesslen;
 		*psess = sess;
-		s->tlsext_ticket_expected = 0;
+		s->tlsext_ticket_expected = renew_ticket;
 		return 1;
 		}
 	/* If session decrypt failure indicate a cache miss and set state to
diff --git a/ssl/tls1.h b/ssl/tls1.h
index d831eec..22399b9 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -279,6 +279,9 @@
 #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)
+
 #endif
 
 /* PSK ciphersuites from 4279 */