Early callback support.
This commit is contained in:
+73
-35
@@ -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 @@ int ssl3_accept(SSL *s)
|
||||
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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
* 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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
|
||||
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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
}
|
||||
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 @@ int ssl3_get_client_hello(SSL *s)
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -865,6 +865,30 @@ typedef struct ssl_aead_ctx_st SSL_AEAD_CTX;
|
||||
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 @@ struct ssl_ctx_st
|
||||
|
||||
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 @@ int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
|
||||
#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 @@ int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
|
||||
#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 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
|
||||
#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 @@ void ERR_load_SSL_strings(void);
|
||||
#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
|
||||
|
||||
@@ -260,6 +260,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
|
||||
{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 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
|
||||
{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"},
|
||||
|
||||
@@ -2823,6 +2823,9 @@ int SSL_get_error(const SSL *s,int i)
|
||||
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);
|
||||
|
||||
+5
-3
@@ -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 @@ SESS_CERT *ssl_sess_cert_new(void);
|
||||
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 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
|
||||
|
||||
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 @@ int dtls1_process_heartbeat(SSL *s);
|
||||
#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);
|
||||
|
||||
+10
-14
@@ -427,11 +427,8 @@ int ssl_get_new_session(SSL *s, int session)
|
||||
/* 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 @@ int ssl_get_new_session(SSL *s, int session)
|
||||
* - 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 ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
|
||||
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 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
|
||||
{
|
||||
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 ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
|
||||
{
|
||||
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())
|
||||
{
|
||||
|
||||
+211
-77
@@ -213,6 +213,176 @@ void tls1_clear(SSL *s)
|
||||
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 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
* 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 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
* 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.
|
||||
|
||||
Reference in New Issue
Block a user