Implement Server side of PSK extension parsing
Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2259)
This commit is contained in:
parent
71c94d3c61
commit
1053a6e228
10 changed files with 297 additions and 131 deletions
|
@ -2324,6 +2324,7 @@ int ERR_load_SSL_strings(void);
|
|||
# define SSL_F_TLS_GET_MESSAGE_HEADER 387
|
||||
# define SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT 449
|
||||
# define SSL_F_TLS_PARSE_CTOS_KEY_SHARE 463
|
||||
# define SSL_F_TLS_PARSE_CTOS_PSK 505
|
||||
# define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464
|
||||
# define SSL_F_TLS_PARSE_CTOS_USE_SRTP 465
|
||||
# define SSL_F_TLS_PARSE_STOC_KEY_SHARE 445
|
||||
|
@ -2361,6 +2362,7 @@ int ERR_load_SSL_strings(void);
|
|||
# define SSL_F_TLS_PROCESS_SKE_ECDHE 420
|
||||
# define SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE 421
|
||||
# define SSL_F_TLS_PROCESS_SKE_SRP 422
|
||||
# define SSL_F_TLS_PSK_DO_BINDER 506
|
||||
# define SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT 450
|
||||
# define SSL_F_TLS_SETUP_HANDSHAKE 508
|
||||
# define SSL_F_USE_CERTIFICATE_CHAIN_FILE 220
|
||||
|
|
|
@ -2018,3 +2018,14 @@ int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const EVP_MD *ssl_cipher_get_handshake_md(int cipher_id)
|
||||
{
|
||||
const SSL_CIPHER *cipher = ssl3_get_cipher_by_id(cipher_id);
|
||||
if (cipher == NULL) {
|
||||
/* Don't recognise this cipher */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ssl_md(cipher->algorithm2);
|
||||
}
|
||||
|
|
|
@ -370,6 +370,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
|
|||
{ERR_FUNC(SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT),
|
||||
"tls_parse_clienthello_tlsext"},
|
||||
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_KEY_SHARE), "tls_parse_ctos_key_share"},
|
||||
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_PSK), "tls_parse_ctos_psk"},
|
||||
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE),
|
||||
"tls_parse_ctos_renegotiate"},
|
||||
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_USE_SRTP), "tls_parse_ctos_use_srtp"},
|
||||
|
@ -423,6 +424,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
|
|||
{ERR_FUNC(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE),
|
||||
"tls_process_ske_psk_preamble"},
|
||||
{ERR_FUNC(SSL_F_TLS_PROCESS_SKE_SRP), "tls_process_ske_srp"},
|
||||
{ERR_FUNC(SSL_F_TLS_PSK_DO_BINDER), "tls_psk_do_binder"},
|
||||
{ERR_FUNC(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT),
|
||||
"tls_scan_clienthello_tlsext"},
|
||||
{ERR_FUNC(SSL_F_TLS_SETUP_HANDSHAKE), "tls_setup_handshake"},
|
||||
|
|
|
@ -1956,6 +1956,7 @@ __owur int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
|
|||
__owur int ssl_cipher_get_cert_index(const SSL_CIPHER *c);
|
||||
__owur const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl,
|
||||
const unsigned char *ptr);
|
||||
__owur const EVP_MD *ssl_cipher_get_handshake_md(int cipher_id);
|
||||
__owur int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
|
||||
__owur int ssl_cert_set1_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
|
||||
__owur int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x);
|
||||
|
@ -2193,6 +2194,17 @@ void ssl_set_default_md(SSL *s);
|
|||
__owur int tls1_set_server_sigalgs(SSL *s);
|
||||
__owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
|
||||
SSL_SESSION **ret);
|
||||
|
||||
/* Return codes for tls_decrypt_ticket */
|
||||
#define TICKET_FATAL_ERR_MALLOC -2
|
||||
#define TICKET_FATAL_ERR_OTHER -1
|
||||
#define TICKET_NO_DECRYPT 2
|
||||
#define TICKET_SUCCESS 3
|
||||
#define TICKET_SUCCESS_RENEW 4
|
||||
__owur int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
||||
size_t eticklen, const unsigned char *sess_id,
|
||||
size_t sesslen, SSL_SESSION **psess);
|
||||
|
||||
__owur int tls_use_ticket(SSL *s);
|
||||
|
||||
__owur int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk,
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <openssl/rand.h>
|
||||
#include <openssl/engine.h>
|
||||
#include "ssl_locl.h"
|
||||
#include "statem/statem_locl.h"
|
||||
|
||||
static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
|
||||
static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s);
|
||||
|
@ -444,8 +445,9 @@ int ssl_get_new_session(SSL *s, int session)
|
|||
* hello: The parsed ClientHello data
|
||||
*
|
||||
* Returns:
|
||||
* -1: error
|
||||
* 0: a session may have been found.
|
||||
* -1: fatal error
|
||||
* 0: no session found
|
||||
* 1: a session may have been found.
|
||||
*
|
||||
* Side effects:
|
||||
* - If a session is found then s->session is pointed at it (after freeing an
|
||||
|
@ -459,27 +461,34 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
|
|||
|
||||
SSL_SESSION *ret = NULL;
|
||||
int fatal = 0;
|
||||
int try_session_cache = 1;
|
||||
int try_session_cache = 0;
|
||||
int r;
|
||||
|
||||
if (hello->session_id_len == 0)
|
||||
try_session_cache = 0;
|
||||
if (SSL_IS_TLS13(s)) {
|
||||
int al;
|
||||
|
||||
/* sets s->ext.ticket_expected */
|
||||
r = tls_get_ticket_from_client(s, hello, &ret);
|
||||
switch (r) {
|
||||
case -1: /* Error during processing */
|
||||
fatal = 1;
|
||||
goto err;
|
||||
case 0: /* No ticket found */
|
||||
case 1: /* Zero length ticket found */
|
||||
break; /* Ok to carry on processing session id. */
|
||||
case 2: /* Ticket found but not decrypted. */
|
||||
case 3: /* Ticket decrypted, *ret has been set. */
|
||||
try_session_cache = 0;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
if (!tls_parse_extension(s, TLSEXT_IDX_psk, EXT_CLIENT_HELLO,
|
||||
hello->pre_proc_exts, NULL, 0, &al))
|
||||
return -1;
|
||||
|
||||
ret = s->session;
|
||||
} else {
|
||||
/* sets s->ext.ticket_expected */
|
||||
r = tls_get_ticket_from_client(s, hello, &ret);
|
||||
switch (r) {
|
||||
case -1: /* Error during processing */
|
||||
fatal = 1;
|
||||
goto err;
|
||||
case 0: /* No ticket found */
|
||||
case 1: /* Zero length ticket found */
|
||||
try_session_cache = 1;
|
||||
break; /* Ok to carry on processing session id. */
|
||||
case 2: /* Ticket found but not decrypted. */
|
||||
case 3: /* Ticket decrypted, *ret has been set. */
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (try_session_cache &&
|
||||
|
@ -628,11 +637,15 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
|
|||
goto err;
|
||||
}
|
||||
|
||||
s->session_ctx->stats.sess_hit++;
|
||||
if (!SSL_IS_TLS13(s)) {
|
||||
/* We already did this for TLS1.3 */
|
||||
SSL_SESSION_free(s->session);
|
||||
s->session = ret;
|
||||
}
|
||||
|
||||
SSL_SESSION_free(s->session);
|
||||
s->session = ret;
|
||||
s->session_ctx->stats.sess_hit++;
|
||||
s->verify_result = s->session->verify_result;
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
|
|
|
@ -279,7 +279,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
|
|||
TLSEXT_TYPE_psk,
|
||||
EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO | EXT_TLS_IMPLEMENTATION_ONLY
|
||||
| EXT_TLS1_3_ONLY,
|
||||
NULL, NULL, tls_parse_stoc_psk, NULL, tls_construct_ctos_psk, NULL
|
||||
NULL, tls_parse_ctos_psk, tls_parse_stoc_psk, NULL,
|
||||
tls_construct_ctos_psk, NULL
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1002,3 +1003,97 @@ static int init_psk_kex_modes(SSL *s, unsigned int context)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
|
||||
size_t binderoffset, const unsigned char *binderin,
|
||||
unsigned char *binderout,
|
||||
SSL_SESSION *sess, int sign)
|
||||
{
|
||||
EVP_PKEY *mackey = NULL;
|
||||
EVP_MD_CTX *mctx = NULL;
|
||||
unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
|
||||
unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
|
||||
const char resumption_label[] = "resumption psk binder key";
|
||||
size_t hashsize = EVP_MD_size(md), bindersize;
|
||||
int ret = -1;
|
||||
|
||||
/* Generate the early_secret */
|
||||
if (!tls13_generate_secret(s, md, NULL, sess->master_key,
|
||||
sess->master_key_length,
|
||||
(unsigned char *)&s->early_secret)) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the handshake hash for the binder key...the messages so far are
|
||||
* empty!
|
||||
*/
|
||||
mctx = EVP_MD_CTX_new();
|
||||
if (mctx == NULL
|
||||
|| EVP_DigestInit_ex(mctx, md, NULL) <= 0
|
||||
|| EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Generate the binder key */
|
||||
if (!tls13_hkdf_expand(s, md, s->early_secret,
|
||||
(unsigned char *)resumption_label,
|
||||
sizeof(resumption_label) - 1, hash, binderkey,
|
||||
hashsize)) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Generate the finished key */
|
||||
if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a hash of the ClientHello up to the start of the binders.
|
||||
* TODO(TLS1.3): This will need to be tweaked when we implement
|
||||
* HelloRetryRequest to include the digest of the previous messages here.
|
||||
*/
|
||||
if (EVP_DigestInit_ex(mctx, md, NULL) <= 0
|
||||
|| EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
|
||||
|| EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, finishedkey, hashsize);
|
||||
if (mackey == NULL) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!sign)
|
||||
binderout = tmpbinder;
|
||||
|
||||
bindersize = hashsize;
|
||||
if (EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
|
||||
|| EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
|
||||
|| EVP_DigestSignFinal(mctx, binderout, &bindersize) <= 0
|
||||
|| bindersize != hashsize) {
|
||||
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
ret = 1;
|
||||
} else {
|
||||
/* HMAC keys can't do EVP_DigestVerify* - use CRYPTO_memcmp instead */
|
||||
ret = (CRYPTO_memcmp(binderin, binderout, hashsize) == 0);
|
||||
}
|
||||
|
||||
err:
|
||||
OPENSSL_cleanse(binderkey, sizeof(binderkey));
|
||||
OPENSSL_cleanse(finishedkey, sizeof(finishedkey));
|
||||
EVP_PKEY_free(mackey);
|
||||
EVP_MD_CTX_free(mctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -663,16 +663,10 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
|
|||
int *al)
|
||||
{
|
||||
#ifndef OPENSSL_NO_TLS1_3
|
||||
const SSL_CIPHER *cipher;
|
||||
uint32_t now, ages, agems;
|
||||
size_t hashsize, bindersize, binderoffset, msglen;
|
||||
size_t hashsize, binderoffset, msglen;
|
||||
unsigned char *binder = NULL, *msgstart = NULL;
|
||||
EVP_PKEY *mackey = NULL;
|
||||
const EVP_MD *md;
|
||||
EVP_MD_CTX *mctx = NULL;
|
||||
unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
|
||||
unsigned char finishedkey[EVP_MAX_MD_SIZE];
|
||||
const char resumption_label[] = "resumption psk binder key";
|
||||
int ret = 0;
|
||||
|
||||
s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
|
||||
|
@ -719,17 +713,12 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
|
|||
*/
|
||||
agems += s->session->ext.tick_age_add;
|
||||
|
||||
cipher = ssl3_get_cipher_by_id(s->session->cipher_id);
|
||||
if (cipher == NULL) {
|
||||
md = ssl_cipher_get_handshake_md(s->session->cipher_id);
|
||||
if (md == NULL) {
|
||||
/* Don't recognise this cipher so we can't use the session. Ignore it */
|
||||
return 1;
|
||||
}
|
||||
md = ssl_md(cipher->algorithm2);
|
||||
if (md == NULL) {
|
||||
/* Shouldn't happen!! */
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hashsize = EVP_MD_size(md);
|
||||
|
||||
/* Create the extension, but skip over the binder for now */
|
||||
|
@ -757,60 +746,8 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
|
|||
|
||||
msgstart = WPACKET_get_curr(pkt) - msglen;
|
||||
|
||||
/* Generate the early_secret */
|
||||
if (!tls13_generate_secret(s, md, NULL, s->session->master_key,
|
||||
s->session->master_key_length,
|
||||
(unsigned char *)&s->early_secret)) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the handshake hash for the binder key...the messages so far are
|
||||
* empty!
|
||||
*/
|
||||
mctx = EVP_MD_CTX_new();
|
||||
if (mctx == NULL
|
||||
|| EVP_DigestInit_ex(mctx, md, NULL) <= 0
|
||||
|| EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Generate the binder key */
|
||||
if (!tls13_hkdf_expand(s, md, s->early_secret,
|
||||
(unsigned char *)resumption_label,
|
||||
sizeof(resumption_label) - 1, hash, binderkey,
|
||||
hashsize)) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Generate the finished key */
|
||||
if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a hash of the ClientHello up to the start of the binders.
|
||||
* TODO(TLS1.3): This will need to be tweaked when we implement
|
||||
* HelloRetryRequest to include the digest of the previous messages here.
|
||||
*/
|
||||
if (EVP_DigestInit_ex(mctx, md, NULL) <= 0
|
||||
|| EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
|
||||
|| EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, finishedkey, hashsize);
|
||||
bindersize = hashsize;
|
||||
if (binderkey == NULL
|
||||
|| EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
|
||||
|| EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
|
||||
|| EVP_DigestSignFinal(mctx, binder, &bindersize) <= 0
|
||||
|| bindersize != hashsize) {
|
||||
if (tls_psk_do_binder(s, md, msgstart, binderoffset, NULL, binder,
|
||||
s->session, 1) != 1) {
|
||||
SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
@ -819,11 +756,6 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
|
|||
|
||||
ret = 1;
|
||||
err:
|
||||
OPENSSL_cleanse(binderkey, sizeof(binderkey));
|
||||
OPENSSL_cleanse(finishedkey, sizeof(finishedkey));
|
||||
EVP_PKEY_free(mackey);
|
||||
EVP_MD_CTX_free(mctx);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return 1;
|
||||
|
|
|
@ -655,10 +655,9 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!s->hit
|
||||
&& !PACKET_memdup(&supported_groups_list,
|
||||
&s->session->ext.supportedgroups,
|
||||
&s->session->ext.supportedgroups_len)) {
|
||||
if (!PACKET_memdup(&supported_groups_list,
|
||||
&s->session->ext.supportedgroups,
|
||||
&s->session->ext.supportedgroups_len)) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
@ -680,6 +679,96 @@ int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
|
||||
{
|
||||
PACKET identities, binders, binder;
|
||||
size_t binderoffset, hashsize;
|
||||
SSL_SESSION *sess = NULL;
|
||||
unsigned int id, i;
|
||||
const EVP_MD *md = NULL;
|
||||
|
||||
if (!PACKET_get_length_prefixed_2(pkt, &identities)) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (id = 0; PACKET_remaining(&identities) != 0; id++) {
|
||||
PACKET identity;
|
||||
unsigned long ticket_age;
|
||||
int ret;
|
||||
|
||||
if (!PACKET_get_length_prefixed_2(&identities, &identity)
|
||||
|| !PACKET_get_net_4(&identities, &ticket_age)) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tls_decrypt_ticket(s, PACKET_data(&identity),
|
||||
PACKET_remaining(&identity), NULL, 0, &sess);
|
||||
if (ret == TICKET_FATAL_ERR_MALLOC || ret == TICKET_FATAL_ERR_OTHER) {
|
||||
*al = SSL_AD_INTERNAL_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (ret == TICKET_NO_DECRYPT)
|
||||
continue;
|
||||
|
||||
md = ssl_cipher_get_handshake_md(sess->cipher_id);
|
||||
if (md == NULL) {
|
||||
/*
|
||||
* Don't recognise this cipher so we can't use the session.
|
||||
* Ignore it
|
||||
*/
|
||||
SSL_SESSION_free(sess);
|
||||
sess = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(TLS1.3): Somehow we need to handle the case of a ticket renewal.
|
||||
* Ignored for now
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (sess == NULL)
|
||||
return 1;
|
||||
|
||||
binderoffset = PACKET_data(pkt) - (const unsigned char *)s->init_buf->data;
|
||||
|
||||
hashsize = EVP_MD_size(md);
|
||||
|
||||
if (!PACKET_get_length_prefixed_2(pkt, &binders)) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i <= id; i++) {
|
||||
if (!PACKET_get_length_prefixed_1(&binders, &binder)) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (PACKET_remaining(&binder) != hashsize
|
||||
|| tls_psk_do_binder(s, md,
|
||||
(const unsigned char *)s->init_buf->data,
|
||||
binderoffset, PACKET_data(&binder), NULL,
|
||||
sess, 0) != 1) {
|
||||
*al = SSL_AD_DECODE_ERROR;
|
||||
SSLerr(SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
sess->ext.tick_identity = id;
|
||||
SSL_SESSION_free(s->session);
|
||||
s->session = sess;
|
||||
|
||||
return 1;
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the server's renegotiation binding
|
||||
*/
|
||||
|
|
|
@ -166,6 +166,12 @@ __owur int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts,
|
|||
__owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx, int *al);
|
||||
|
||||
__owur int tls_psk_do_binder(SSL *s, const EVP_MD *md,
|
||||
const unsigned char *msgstart,
|
||||
size_t binderoffset, const unsigned char *binderin,
|
||||
unsigned char *binderout,
|
||||
SSL_SESSION *sess, int sign);
|
||||
|
||||
/* Server Extension processing */
|
||||
int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
|
||||
int *al);
|
||||
|
@ -202,6 +208,7 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
|
|||
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
|
||||
int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
|
||||
int *al);
|
||||
int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
|
||||
|
||||
int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
|
||||
size_t chainidx, int *al);
|
||||
|
|
61
ssl/t1_lib.c
61
ssl/t1_lib.c
|
@ -20,10 +20,6 @@
|
|||
#include "ssl_locl.h"
|
||||
#include <openssl/ct.h>
|
||||
|
||||
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, size_t ticklen,
|
||||
const unsigned char *sess_id, size_t sesslen,
|
||||
SSL_SESSION **psess);
|
||||
|
||||
SSL3_ENC_METHOD const TLSv1_enc_data = {
|
||||
tls1_enc,
|
||||
tls1_mac,
|
||||
|
@ -1097,14 +1093,14 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
|
|||
retv = tls_decrypt_ticket(s, PACKET_data(&ticketext->data), size,
|
||||
hello->session_id, hello->session_id_len, ret);
|
||||
switch (retv) {
|
||||
case 2: /* ticket couldn't be decrypted */
|
||||
case TICKET_NO_DECRYPT: /* ticket couldn't be decrypted */
|
||||
s->ext.ticket_expected = 1;
|
||||
return 2;
|
||||
|
||||
case 3: /* ticket was decrypted */
|
||||
case TICKET_SUCCESS: /* ticket was decrypted */
|
||||
return 3;
|
||||
|
||||
case 4: /* ticket decrypted but need to renew */
|
||||
case TICKET_SUCCESS_RENEW: /* ticket decrypted but need to renew */
|
||||
s->ext.ticket_expected = 1;
|
||||
return 3;
|
||||
|
||||
|
@ -1124,20 +1120,27 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
|
|||
* point to the resulting session.
|
||||
*
|
||||
* Returns:
|
||||
* -2: fatal error, malloc failure.
|
||||
* -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.
|
||||
* TICKET_FATAL_ERR_MALLOC: fatal error, malloc failure.
|
||||
* TICKET_FATAL_ERR_OTHER: fatal error, either from parsing or decrypting the
|
||||
* ticket.
|
||||
* TICKET_NO_DECRYPT: the ticket couldn't be decrypted.
|
||||
* TICKET_SUCCESS: a ticket was successfully decrypted and *psess was
|
||||
* set.
|
||||
* TICKET_SUCCESS_RENEW: same as 3, but the ticket needs to be renewed
|
||||
*/
|
||||
static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
||||
size_t eticklen, const unsigned char *sess_id,
|
||||
size_t sesslen, SSL_SESSION **psess)
|
||||
#define TICKET_FATAL_ERR_MALLOC -2
|
||||
#define TICKET_FATAL_ERR_OTHER -1
|
||||
#define TICKET_NO_DECRYPT 2
|
||||
#define TICKET_SUCCESS 3
|
||||
#define TICKET_SUCCESS_RENEW 4
|
||||
int tls_decrypt_ticket(SSL *s, const unsigned char *etick, size_t eticklen,
|
||||
const unsigned char *sess_id, size_t sesslen,
|
||||
SSL_SESSION **psess)
|
||||
{
|
||||
SSL_SESSION *sess;
|
||||
unsigned char *sdec;
|
||||
const unsigned char *p;
|
||||
int slen, renew_ticket = 0, ret = -1, declen;
|
||||
int slen, renew_ticket = 0, ret = TICKET_FATAL_ERR_OTHER, declen;
|
||||
size_t mlen;
|
||||
unsigned char tick_hmac[EVP_MAX_MD_SIZE];
|
||||
HMAC_CTX *hctx = NULL;
|
||||
|
@ -1147,10 +1150,10 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
/* Initialize session ticket encryption and HMAC contexts */
|
||||
hctx = HMAC_CTX_new();
|
||||
if (hctx == NULL)
|
||||
return -2;
|
||||
return TICKET_FATAL_ERR_MALLOC;
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
ret = -2;
|
||||
ret = TICKET_FATAL_ERR_MALLOC;
|
||||
goto err;
|
||||
}
|
||||
if (tctx->ext.ticket_key_cb) {
|
||||
|
@ -1160,7 +1163,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
if (rv < 0)
|
||||
goto err;
|
||||
if (rv == 0) {
|
||||
ret = 2;
|
||||
ret = TICKET_NO_DECRYPT;
|
||||
goto err;
|
||||
}
|
||||
if (rv == 2)
|
||||
|
@ -1169,7 +1172,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
/* Check key name matches */
|
||||
if (memcmp(etick, tctx->ext.tick_key_name,
|
||||
sizeof(tctx->ext.tick_key_name)) != 0) {
|
||||
ret = 2;
|
||||
ret = TICKET_NO_DECRYPT;
|
||||
goto err;
|
||||
}
|
||||
if (HMAC_Init_ex(hctx, tctx->ext.tick_hmac_key,
|
||||
|
@ -1177,8 +1180,8 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
EVP_sha256(), NULL) <= 0
|
||||
|| EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
|
||||
tctx->ext.tick_aes_key,
|
||||
etick + sizeof(tctx->ext.tick_key_name)) <=
|
||||
0) {
|
||||
etick
|
||||
+ sizeof(tctx->ext.tick_key_name)) <= 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
@ -1193,7 +1196,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
/* Sanity check ticket length: must exceed keyname + IV + HMAC */
|
||||
if (eticklen <=
|
||||
TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx) + mlen) {
|
||||
ret = 2;
|
||||
ret = TICKET_NO_DECRYPT;
|
||||
goto err;
|
||||
}
|
||||
eticklen -= mlen;
|
||||
|
@ -1205,7 +1208,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
HMAC_CTX_free(hctx);
|
||||
if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return 2;
|
||||
return TICKET_NO_DECRYPT;
|
||||
}
|
||||
/* Attempt to decrypt session data */
|
||||
/* Move p after IV to start of encrypted ticket, update length */
|
||||
|
@ -1216,12 +1219,12 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
(int)eticklen) <= 0) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
OPENSSL_free(sdec);
|
||||
return -1;
|
||||
return TICKET_FATAL_ERR_OTHER;
|
||||
}
|
||||
if (EVP_DecryptFinal(ctx, sdec + slen, &declen) <= 0) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
OPENSSL_free(sdec);
|
||||
return 2;
|
||||
return TICKET_NO_DECRYPT;
|
||||
}
|
||||
slen += declen;
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
@ -1242,15 +1245,15 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick,
|
|||
sess->session_id_length = sesslen;
|
||||
*psess = sess;
|
||||
if (renew_ticket)
|
||||
return 4;
|
||||
return TICKET_SUCCESS_RENEW;
|
||||
else
|
||||
return 3;
|
||||
return TICKET_SUCCESS;
|
||||
}
|
||||
ERR_clear_error();
|
||||
/*
|
||||
* For session parse failure, indicate that we need to send a new ticket.
|
||||
*/
|
||||
return 2;
|
||||
return TICKET_NO_DECRYPT;
|
||||
err:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
HMAC_CTX_free(hctx);
|
||||
|
|
Loading…
Reference in a new issue