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,©)))
+ if ((ret=s->session_ctx->get_session_cb(s,(unsigned char *) ctx->session_id,ctx->session_id_len,©)))
{
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.