From f3d40db1b947f546541b815a0363de3120c16506 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 6 Mar 2018 16:41:51 +0000 Subject: [PATCH] Fallback on old style PSK callbacks if the new style ones aren't present Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/5554) --- ssl/statem/extensions_clnt.c | 53 ++++++++++++++++++++++++++++++++++ ssl/statem/extensions_srvr.c | 56 ++++++++++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index fa6c65b266..9bf2d1cb38 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -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) { diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index d1be32c2bc..bcabb858be 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -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); -- 2.40.0