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.