From 8a2062fefedde7957f228e274d12155ca8660d4c Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 30 Apr 2008 16:14:02 +0000 Subject: [PATCH] Update from stable branch. --- CHANGES | 6 ++++++ ssl/s3_lib.c | 7 +++++++ ssl/s3_srvr.c | 40 +++++++++++++++++++++++++++++---------- ssl/ssl.h | 8 ++++++++ ssl/t1_lib.c | 52 ++++++++++++++++++++++++++++++++------------------- ssl/tls1.h | 3 +++ 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 #endif #include +#include #include #include @@ -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 */ -- 2.39.5