return 0;
}
- if (!s->hit) {
+ if (!s->hit || SSL_IS_TLS13(s)) {
if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) {
SSLfatal(s, SSL_AD_UNRECOGNIZED_NAME,
SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
return 0;
}
- OPENSSL_free(s->session->ext.hostname);
- s->session->ext.hostname = NULL;
- if (!PACKET_strndup(&hostname, &s->session->ext.hostname)) {
+ /*
+ * Store the requested SNI in the SSL as temporary storage.
+ * If we accept it, it will get stored in the SSL_SESSION as well.
+ */
+ OPENSSL_free(s->ext.hostname);
+ s->ext.hostname = NULL;
+ if (!PACKET_strndup(&hostname, &s->ext.hostname)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_SERVER_NAME,
ERR_R_INTERNAL_ERROR);
return 0;
}
s->servername_done = 1;
- } else {
+ }
+ if (s->hit) {
/*
* TODO(openssl-team): if the SNI doesn't match, we MUST
* fall back to a full handshake.
*/
- s->servername_done = s->session->ext.hostname
+ s->servername_done = (s->session->ext.hostname != NULL)
&& PACKET_equal(&hostname, s->session->ext.hostname,
strlen(s->session->ext.hostname));
{
PACKET responder_id_list, exts;
+ /* We ignore this in a resumption handshake */
+ if (s->hit)
+ return 1;
+
/* Not defined if we get one of these in a client Certificate */
if (x != NULL)
return 1;
int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx)
{
+#ifndef OPENSSL_NO_TLS1_3
unsigned int format, version, key_share, group_id;
EVP_MD_CTX *hctx;
EVP_PKEY *pkey;
unsigned long tm, now;
/* Ignore any cookie if we're not set up to verify it */
- if (s->ctx->app_verify_cookie_cb == NULL
+ if (s->ctx->verify_stateless_cookie_cb == NULL
|| (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
return 1;
/* Verify the HMAC of the cookie */
hctx = EVP_MD_CTX_create();
- pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
- s->session_ctx->ext.cookie_hmac_key,
- sizeof(s->session_ctx->ext.cookie_hmac_key));
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+ s->session_ctx->ext.cookie_hmac_key,
+ sizeof(s->session_ctx->ext
+ .cookie_hmac_key));
if (hctx == NULL || pkey == NULL) {
EVP_MD_CTX_free(hctx);
EVP_PKEY_free(pkey);
}
/* Verify the app cookie */
- if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&appcookie),
+ if (s->ctx->verify_stateless_cookie_cb(s, PACKET_data(&appcookie),
PACKET_remaining(&appcookie)) == 0) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
SSL_R_COOKIE_MISMATCH);
}
if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_supported_versions)
|| !WPACKET_start_sub_packet_u16(&hrrpkt)
- /* TODO(TLS1.3): Fix this before release */
- || !WPACKET_put_bytes_u16(&hrrpkt, TLS1_3_VERSION_DRAFT)
+ || !WPACKET_put_bytes_u16(&hrrpkt, s->version)
|| !WPACKET_close(&hrrpkt)) {
WPACKET_cleanup(&hrrpkt);
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
s->hello_retry_request = 1;
s->ext.cookieok = 1;
+#endif
return 1;
}
return 1;
}
+static SSL_TICKET_STATUS tls_get_stateful_ticket(SSL *s, PACKET *tick,
+ SSL_SESSION **sess)
+{
+ SSL_SESSION *tmpsess = NULL;
+
+ s->ext.ticket_expected = 1;
+
+ switch (PACKET_remaining(tick)) {
+ case 0:
+ return SSL_TICKET_EMPTY;
+
+ case SSL_MAX_SSL_SESSION_ID_LENGTH:
+ break;
+
+ default:
+ return SSL_TICKET_NO_DECRYPT;
+ }
+
+ tmpsess = lookup_sess_in_cache(s, PACKET_data(tick),
+ SSL_MAX_SSL_SESSION_ID_LENGTH);
+
+ if (tmpsess == NULL)
+ return SSL_TICKET_NO_DECRYPT;
+
+ *sess = tmpsess;
+ return SSL_TICKET_SUCCESS;
+}
+
int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx)
{
return 0;
}
+ s->ext.ticket_expected = 0;
for (id = 0; PACKET_remaining(&identities) != 0; id++) {
PACKET identity;
unsigned long ticket_agel;
return 0;
}
+#ifndef OPENSSL_NO_PSK
if(sess == NULL
&& s->psk_server_callback != NULL
&& idlen <= PSK_MAX_IDENTITY_LEN) {
OPENSSL_cleanse(pskdata, pskdatalen);
}
}
+#endif /* OPENSSL_NO_PSK */
if (sess != NULL) {
/* We found a PSK */
ext = 1;
if (id == 0)
s->ext.early_data_ok = 1;
+ s->ext.ticket_expected = 1;
} else {
uint32_t ticket_age = 0, now, agesec, agems;
- int ret = tls_decrypt_ticket(s, PACKET_data(&identity),
+ int ret;
+
+ /*
+ * If we are using anti-replay protection then we behave as if
+ * SSL_OP_NO_TICKET is set - we are caching tickets anyway so there
+ * is no point in using full stateless tickets.
+ */
+ if ((s->options & SSL_OP_NO_TICKET) != 0
+ || (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0))
+ ret = tls_get_stateful_ticket(s, &identity, &sess);
+ else
+ ret = tls_decrypt_ticket(s, PACKET_data(&identity),
PACKET_remaining(&identity), NULL, 0,
&sess);
+ if (ret == SSL_TICKET_EMPTY) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+ SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+
if (ret == SSL_TICKET_FATAL_ERR_MALLOC
|| ret == SSL_TICKET_FATAL_ERR_OTHER) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
return 0;
}
- if (ret == SSL_TICKET_NO_DECRYPT)
+ if (ret == SSL_TICKET_NONE || ret == SSL_TICKET_NO_DECRYPT)
continue;
+ /* Check for replay */
+ if (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0
+ && !SSL_CTX_remove_session(s->session_ctx, sess)) {
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ continue;
+ }
+
ticket_age = (uint32_t)ticket_agel;
now = (uint32_t)time(NULL);
agesec = now - (uint32_t)sess->time;
SSL_SESSION_free(sess);
sess = NULL;
s->ext.early_data_ok = 0;
+ s->ext.ticket_expected = 0;
continue;
}
break;
size_t chainidx)
{
if (s->hit || s->servername_done != 1
- || s->session->ext.hostname == NULL)
+ || s->ext.hostname == NULL)
return EXT_RETURN_NOT_SENT;
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
unsigned int context, X509 *x,
size_t chainidx)
{
- if (!SSL_IS_TLS13(s))
- return EXT_RETURN_NOT_SENT;
+ if (!ossl_assert(SSL_IS_TLS13(s))) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS,
+ ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
|| !WPACKET_start_sub_packet_u16(pkt)
- /* TODO(TLS1.3): Update to remove the TLSv1.3 draft indicator */
- || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)
+ || !WPACKET_put_bytes_u16(pkt, s->version)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS,
/* SSLfatal() already called */
return EXT_RETURN_FAIL;
}
-#endif
-
return EXT_RETURN_SENT;
+#else
+ return EXT_RETURN_FAIL;
+#endif
}
EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx)
{
+#ifndef OPENSSL_NO_TLS1_3
unsigned char *hashval1, *hashval2, *appcookie1, *appcookie2, *cookie;
unsigned char *hmac, *hmac2;
- size_t startlen, ciphlen, totcookielen, hashlen, hmaclen;
- unsigned int appcookielen;
+ size_t startlen, ciphlen, totcookielen, hashlen, hmaclen, appcookielen;
EVP_MD_CTX *hctx;
EVP_PKEY *pkey;
int ret = EXT_RETURN_FAIL;
if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
return EXT_RETURN_NOT_SENT;
- if (s->ctx->app_gen_cookie_cb == NULL) {
+ if (s->ctx->gen_stateless_cookie_cb == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
SSL_R_NO_COOKIE_CALLBACK_SET);
return EXT_RETURN_FAIL;
}
/* Generate the application cookie */
- if (s->ctx->app_gen_cookie_cb(s, appcookie1, &appcookielen) == 0) {
+ if (s->ctx->gen_stateless_cookie_cb(s, appcookie1, &appcookielen) == 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
return EXT_RETURN_FAIL;
/* HMAC the cookie */
hctx = EVP_MD_CTX_create();
- pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
- s->session_ctx->ext.cookie_hmac_key,
- sizeof(s->session_ctx->ext.cookie_hmac_key));
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+ s->session_ctx->ext.cookie_hmac_key,
+ sizeof(s->session_ctx->ext
+ .cookie_hmac_key));
if (hctx == NULL || pkey == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
ERR_R_MALLOC_FAILURE);
EVP_MD_CTX_free(hctx);
EVP_PKEY_free(pkey);
return ret;
+#else
+ return EXT_RETURN_FAIL;
+#endif
}
EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,