summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--ssl/s3_lib.c7
-rw-r--r--ssl/s3_srvr.c40
-rw-r--r--ssl/ssl.h8
-rw-r--r--ssl/t1_lib.c52
-rw-r--r--ssl/tls1.h3
6 files changed, 87 insertions, 29 deletions
diff --git a/CHANGES b/CHANGES
index ff51f47907..cf5c17cfca 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 00bc1b3ea9..6844a43b9e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2770,6 +2770,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
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 dee1f73cde..8a4faa66fa 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -2853,6 +2853,8 @@ int ssl3_send_newsession_ticket(SSL *s)
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 @@ int ssl3_send_newsession_ticket(SSL *s)
*(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 77a6d6adeb..53236eebf5 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 @@ struct ssl_ctx_st
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 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#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 39629c273c..f3c5a16e48 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1442,39 +1442,53 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
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;
+ /* Need at least keyname + iv + some encrypted data */
+ if (eticklen < 48)
+ goto tickerr;
+ /* Initialize session ticket encryption and HMAC contexts */
+ HMAC_CTX_init(&hctx);
+ 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 = EVP_MD_size(tlsext_tick_md());
+ mlen = HMAC_size(&hctx);
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 */
- HMAC_CTX_init(&hctx);
- HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
- tlsext_tick_md(), NULL);
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 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
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 d831eecd87..22399b9e33 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -279,6 +279,9 @@ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(voi
#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 */