Fallback on old style PSK callbacks if the new style ones aren't present

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5554)
This commit is contained in:
Matt Caswell 2018-03-06 16:41:51 +00:00
parent e73c6eaeff
commit f3d40db1b9
2 changed files with 107 additions and 2 deletions

View File

@ -744,6 +744,7 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
char identity[PSK_MAX_IDENTITY_LEN + 1];
const unsigned char *id = NULL;
size_t idlen = 0;
SSL_SESSION *psksess = NULL;
@ -763,6 +764,58 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
return EXT_RETURN_FAIL;
}
if (psksess == NULL && s->psk_client_callback != NULL) {
unsigned char psk[PSK_MAX_PSK_LEN];
size_t psklen = 0;
memset(identity, 0, sizeof(identity));
psklen = s->psk_client_callback(s, NULL, identity, sizeof(identity) - 1,
psk, sizeof(psk));
if (psklen > PSK_MAX_PSK_LEN) {
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
} else if (psklen > 0) {
const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
const SSL_CIPHER *cipher;
idlen = strlen(identity);
if (idlen > PSK_MAX_IDENTITY_LEN) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
id = (unsigned char *)identity;
/*
* We found a PSK using an old style callback. We don't know
* the digest so we default to SHA256 as per the TLSv1.3 spec
*/
cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
if (cipher == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
psksess = SSL_SESSION_new();
if (psksess == NULL
|| !SSL_SESSION_set1_master_key(psksess, psk, psklen)
|| !SSL_SESSION_set_cipher(psksess, cipher)
|| !SSL_SESSION_set_protocol_version(psksess, TLS1_3_VERSION)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA,
ERR_R_INTERNAL_ERROR);
OPENSSL_cleanse(psk, psklen);
return EXT_RETURN_FAIL;
}
OPENSSL_cleanse(psk, psklen);
}
}
SSL_SESSION_free(s->psksession);
s->psksession = psksess;
if (psksess != NULL) {

View File

@ -1028,6 +1028,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
for (id = 0; PACKET_remaining(&identities) != 0; id++) {
PACKET identity;
unsigned long ticket_agel;
size_t idlen;
if (!PACKET_get_length_prefixed_2(&identities, &identity)
|| !PACKET_get_net_4(&identities, &ticket_agel)) {
@ -1036,15 +1037,66 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 0;
}
idlen = PACKET_remaining(&identity);
if (s->psk_find_session_cb != NULL
&& !s->psk_find_session_cb(s, PACKET_data(&identity),
PACKET_remaining(&identity),
&& !s->psk_find_session_cb(s, PACKET_data(&identity), idlen,
&sess)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_PARSE_CTOS_PSK, SSL_R_BAD_EXTENSION);
return 0;
}
if(sess == NULL
&& s->psk_server_callback != NULL
&& idlen <= PSK_MAX_IDENTITY_LEN) {
char *pskid = NULL;
unsigned char pskdata[PSK_MAX_PSK_LEN];
unsigned int pskdatalen;
if (!PACKET_strndup(&identity, &pskid)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
ERR_R_INTERNAL_ERROR);
return 0;
}
pskdatalen = s->psk_server_callback(s, pskid, pskdata,
sizeof(pskdata));
OPENSSL_free(pskid);
if (pskdatalen > PSK_MAX_PSK_LEN) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
ERR_R_INTERNAL_ERROR);
return 0;
} else if (pskdatalen > 0) {
const SSL_CIPHER *cipher;
const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
/*
* We found a PSK using an old style callback. We don't know
* the digest so we default to SHA256 as per the TLSv1.3 spec
*/
cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
if (cipher == NULL) {
OPENSSL_cleanse(pskdata, pskdatalen);
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
ERR_R_INTERNAL_ERROR);
return 0;
}
sess = SSL_SESSION_new();
if (sess == NULL
|| !SSL_SESSION_set1_master_key(sess, pskdata,
pskdatalen)
|| !SSL_SESSION_set_cipher(sess, cipher)
|| !SSL_SESSION_set_protocol_version(sess,
TLS1_3_VERSION)) {
OPENSSL_cleanse(pskdata, pskdatalen);
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
ERR_R_INTERNAL_ERROR);
goto err;
}
OPENSSL_cleanse(pskdata, pskdatalen);
}
}
if (sess != NULL) {
/* We found a PSK */
SSL_SESSION *sesstmp = ssl_session_dup(sess, 0);