X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fstatem%2Fextensions_clnt.c;h=cc4563b357622aa84342e955b6464544d355805c;hp=f357396d81a4eb8a8e761d60112a74e16ab6dc91;hb=73cc84a132a08a02253ae168600fc4d16cd400d8;hpb=426dfc9ff7c1afaf1ed5981a9c7846e310c7ae3e diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index f357396d81..cc4563b357 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -538,7 +538,9 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, for (currv = max_version; currv >= min_version; currv--) { /* TODO(TLS1.3): Remove this first if clause prior to release!! */ if (currv == TLS1_3_VERSION) { - if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) { + if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT) + || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT_27) + || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT_26)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, ERR_R_INTERNAL_ERROR); @@ -705,9 +707,10 @@ EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } -#endif - return EXT_RETURN_SENT; +#else + return EXT_RETURN_NOT_SENT; +#endif } EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context, @@ -743,6 +746,9 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { +#ifndef OPENSSL_NO_PSK + char identity[PSK_MAX_IDENTITY_LEN + 1]; +#endif /* OPENSSL_NO_PSK */ const unsigned char *id = NULL; size_t idlen = 0; SSL_SESSION *psksess = NULL; @@ -762,6 +768,60 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, return EXT_RETURN_FAIL; } +#ifndef OPENSSL_NO_PSK + 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); + } + } +#endif /* OPENSSL_NO_PSK */ + SSL_SESSION_free(s->psksession); s->psksession = psksess; if (psksess != NULL) { @@ -998,6 +1058,16 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, */ now = (uint32_t)time(NULL); agesec = now - (uint32_t)s->session->time; + /* + * We calculate the age in seconds but the server may work in ms. Due to + * rounding errors we could overestimate the age by up to 1s. It is + * better to underestimate it. Otherwise, if the RTT is very short, when + * the server calculates the age reported by the client it could be + * bigger than the age calculated on the server - which should never + * happen. + */ + if (agesec > 0) + agesec--; if (s->session->ext.tick_lifetime_hint < agesec) { /* Ticket is too old. Ignore it. */ @@ -1133,6 +1203,48 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, #endif } +EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ +#ifndef OPENSSL_NO_TLS1_3 + if (!s->pha_forced) { + int i, n = 0; + + /* check for cert, if present, we can do post-handshake auth */ + if (s->cert == NULL) + return EXT_RETURN_NOT_SENT; + + for (i = 0; i < SSL_PKEY_NUM; i++) { + if (s->cert->pkeys[i].x509 != NULL + && s->cert->pkeys[i].privatekey != NULL) + n++; + } + + /* no identity certificates, so no extension */ + if (n == 0) + return EXT_RETURN_NOT_SENT; + } + + /* construct extension - 0 length, no contents */ + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_post_handshake_auth) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH, + ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + s->post_handshake_auth = SSL_PHA_EXT_SENT; + + return EXT_RETURN_SENT; +#else + return EXT_RETURN_NOT_SENT; +#endif +} + + /* * Parse the server's renegotiation binding and abort if it's not right */ @@ -1202,7 +1314,7 @@ int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context, unsigned int value; if (PACKET_remaining(pkt) != 1 || !PACKET_get_1(pkt, &value)) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN, + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN, SSL_R_BAD_EXTENSION); return 0; } @@ -1273,7 +1385,7 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context, int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - unsigned int ecpointformats_len; + size_t ecpointformats_len; PACKET ecptformatlist; if (!PACKET_as_length_prefixed_1(pkt, &ecptformatlist)) { @@ -1283,8 +1395,13 @@ int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context, } if (!s->hit) { ecpointformats_len = PACKET_remaining(&ecptformatlist); - s->session->ext.ecpointformats_len = 0; + if (ecpointformats_len == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, + SSL_F_TLS_PARSE_STOC_EC_PT_FORMATS, SSL_R_BAD_LENGTH); + return 0; + } + s->session->ext.ecpointformats_len = 0; OPENSSL_free(s->session->ext.ecpointformats); s->session->ext.ecpointformats = OPENSSL_malloc(ecpointformats_len); if (s->session->ext.ecpointformats == NULL) { @@ -1340,6 +1457,12 @@ int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context, int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { + if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) { + /* We ignore this if the server sends a CertificateRequest */ + /* TODO(TLS1.3): Add support for this */ + return 1; + } + /* * MUST only be sent if we've requested a status * request message. In TLS <= 1.2 it must also be empty. @@ -1378,6 +1501,12 @@ int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context, int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { + if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) { + /* We ignore this if the server sends it in a CertificateRequest */ + /* TODO(TLS1.3): Add support for this */ + return 1; + } + /* * Only take it if we asked for it - i.e if there is no CT validation * callback set, then a custom extension MAY be processing it, so we @@ -1552,7 +1681,15 @@ int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, s->ext.early_data_ok = 0; } if (!s->hit) { - /* If a new session then update it with the selected ALPN */ + /* + * This is a new session and so alpn_selected should have been + * initialised to NULL. We should update it with the selected ALPN. + */ + if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN, + ERR_R_INTERNAL_ERROR); + return 0; + } s->session->ext.alpn_selected = OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len); if (s->session->ext.alpn_selected == NULL) { @@ -1654,23 +1791,25 @@ int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context, } /* TODO(TLS1.3): Remove this before release */ - if (version == TLS1_3_VERSION_DRAFT) + if (version == TLS1_3_VERSION_DRAFT + || version == TLS1_3_VERSION_DRAFT_27 + || version == TLS1_3_VERSION_DRAFT_26) version = TLS1_3_VERSION; + /* + * The only protocol version we support which is valid in this extension in + * a ServerHello is TLSv1.3 therefore we shouldn't be getting anything else. + */ + if (version != TLS1_3_VERSION) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, + SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, + SSL_R_BAD_PROTOCOL_VERSION_NUMBER); + return 0; + } + /* We ignore this extension for HRRs except to sanity check it */ - if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) { - /* - * The only protocol version we support which has an HRR message is - * TLSv1.3, therefore we shouldn't be getting an HRR for anything else. - */ - if (version != TLS1_3_VERSION) { - *al = SSL_AD_PROTOCOL_VERSION; - SSLerr(SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, - SSL_R_BAD_HRR_VERSION); - return 0; - } + if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) return 1; - } /* We just set it here. We validate it in ssl_choose_client_version */ s->version = version;