summaryrefslogtreecommitdiffstats
path: root/ssl/t1_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/t1_lib.c')
-rw-r--r--ssl/t1_lib.c154
1 files changed, 103 insertions, 51 deletions
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index cfb3b54565..93869fa83b 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1838,26 +1838,56 @@ int ssl_check_serverhello_tlsext(SSL *s)
}
}
-/* Since the server cache lookup is done early on in the processing of client
- * hello and other operations depend on the result we need to handle any TLS
- * session ticket extension at the same time.
+/* 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)
+ 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.
- */
+ * to permit stateful resumption.
+ */
if (SSL_get_options(s) & SSL_OP_NO_TICKET)
- return 1;
-
+ return 0;
if ((s->version <= SSL3_VERSION) || !limit)
- return 1;
+ return 0;
if (p >= limit)
return -1;
/* Skip past DTLS cookie */
@@ -1880,7 +1910,7 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
return -1;
/* Now at start of extensions */
if ((p + 2) >= limit)
- return 1;
+ return 0;
n2s(p, i);
while ((p + 4) <= limit)
{
@@ -1888,39 +1918,61 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
n2s(p, type);
n2s(p, size);
if (p + size > limit)
- return 1;
+ return 0;
if (type == TLSEXT_TYPE_session_ticket)
{
- /* If tickets disabled indicate cache miss which will
- * trigger a full handshake
- */
- if (SSL_get_options(s) & SSL_OP_NO_TICKET)
- return 1;
- /* If zero length note client will accept a ticket
- * and indicate cache miss to trigger full handshake
- */
+ int r;
if (size == 0)
{
+ /* The client will accept a ticket but doesn't
+ * currently have one. */
s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
+ return 1;
}
if (s->tls_session_secret_cb)
{
- /* Indicate cache miss here and instead of
- * generating the session from ticket now,
- * trigger abbreviated handshake based on
- * external mechanism to calculate the master
- * secret later. */
- return 0;
+ /* 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;
}
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
}
p += size;
}
- return 1;
+ 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)
@@ -1935,7 +1987,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
SSL_CTX *tctx = s->initial_ctx;
/* Need at least keyname + iv + some encrypted data */
if (eticklen < 48)
- goto tickerr;
+ return 2;
/* Initialize session ticket encryption and HMAC contexts */
HMAC_CTX_init(&hctx);
EVP_CIPHER_CTX_init(&ctx);
@@ -1947,7 +1999,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
if (rv < 0)
return -1;
if (rv == 0)
- goto tickerr;
+ return 2;
if (rv == 2)
renew_ticket = 1;
}
@@ -1955,15 +2007,15 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
{
/* Check key name matches */
if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
- goto tickerr;
+ 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.
- */
+ * integrity checks on ticket.
+ */
mlen = HMAC_size(&hctx);
if (mlen < 0)
{
@@ -1976,7 +2028,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
HMAC_Final(&hctx, tick_hmac, NULL);
HMAC_CTX_cleanup(&hctx);
if (memcmp(tick_hmac, etick + eticklen, mlen))
- goto tickerr;
+ 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);
@@ -1989,33 +2041,33 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
}
EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
- goto tickerr;
+ 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.
- */
+ /* 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;
- s->tlsext_ticket_expected = renew_ticket;
- return 1;
+ if (renew_ticket)
+ return 4;
+ else
+ return 3;
}
- /* If session decrypt failure indicate a cache miss and set state to
- * send a new ticket
- */
- tickerr:
- s->tlsext_ticket_expected = 1;
- return 0;
+ 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 */