diff --git a/CMakeLists.txt b/CMakeLists.txt index cc58e40efed6..e957502ec707 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ option(USE_PKCS11_HELPER_LIBRARY "Build mbed TLS with the pkcs11-helper library. option(ENABLE_ZLIB_SUPPORT "Build mbed TLS with zlib library." OFF) option(ENABLE_PROGRAMS "Build mbed TLS programs." ON) +option(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL "Building TLS 1.3 stack." ON) option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF) option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON) @@ -188,6 +189,7 @@ if(CMAKE_COMPILER_IS_GNU) if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wlogical-op") endif() + if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") endif() diff --git a/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt b/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt new file mode 100644 index 000000000000..608956541372 --- /dev/null +++ b/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt @@ -0,0 +1,3 @@ +Changes + * Reduce stack usage significantly during sliding window exponentiation. + Reported in #3591 and fix contributed in #3592 by Daniel Otte. diff --git a/Makefile b/Makefile index 6a8b23007736..b96b9ece3db6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ DESTDIR=/usr/local PREFIX=mbedtls_ +MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL=y +export MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL .SILENT: @@ -131,7 +133,9 @@ C_SOURCE_FILES = $(wildcard \ 3rdparty/*/include/*/*.h 3rdparty/*/include/*/*/*.h 3rdparty/*/include/*/*/*/*.h \ 3rdparty/*/*.c 3rdparty/*/*/*.c 3rdparty/*/*/*/*.c 3rdparty/*/*/*/*/*.c \ include/*/*.h \ + include/*/*/*.h \ library/*.[hc] \ + library/*/*.[hc] \ programs/*/*.[hc] \ tests/include/*/*.h tests/include/*/*/*.h \ tests/src/*.c tests/src/*/*.c \ diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index be5c548e5614..2f09ffeeba8b 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -738,7 +738,7 @@ #if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ - !defined(MBEDTLS_SSL_PROTO_TLS1_2)) + !defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) #error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" #endif @@ -762,6 +762,10 @@ #error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" #endif +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_SRV_C) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) #error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" @@ -918,6 +922,120 @@ #endif /* MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && \ + ( !defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ) +#error "ZeroRTT requires MBEDTLS_ZERO_RTT and MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED to be defined." +#endif + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#error "MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE defined, but not all prerequesites." +#endif + +/* + * The following extensions are no longer applicable to TLS 1.3, + * although TLS 1.3 clients MAY send them if they are willing to negotiate + * them with prior versions of TLS.TLS 1.3 servers MUST ignore these extensions + * if they are negotiating TLS 1.3: + * + * - truncated_hmac[RFC6066], + * - srp[RFC5054] + * - encrypt_then_mac[RFC7366] + * - extended_master_secret[RFC7627] + * - SessionTicket[RFC5077], and + * - renegotiation_info[RFC5746]. + */ + + /* Truncated Mac extension is not applicable to TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_TRUNCATED_HMAC) +#error "Truncated Mac extension is not applicable to TLS 1.3" +#endif + + + /* Encrypt-then-Mac extension is not applicable to TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +#error "Encrypt-then-Mac extension is not applicable to TLS 1.3" +#endif + +/* Key derivation works differently in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +#error "Extended master secret extension is not applicable to TLS 1.3" +#endif + + /* Secure renegotiation support in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_RENEGOTIATION) +#error "Renegotiation is not supported in TLS 1.3" +#endif + + /* No Compression support in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZLIB_SUPPORT) +#error "No compression is supported in TLS 1.3" +#endif + + /* Session tickets in TLS 1.3 does not use RFC 5077 anymore + * Hence, when TLS 1.3 is used then MBEDTLS_SSL_SESSION_TICKETS cannot be enabled. + * + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_SESSION_TICKETS) +#error "RFC 5077 is not supported with TLS 1.3" +#endif + + /* JPAKE extension does not work with TLS 1.3 + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECJPAKE_C) +#error " JPAKE extension does not work with TLS 1.3" +#endif + + + /* The following C processor directives are not applicable to TLS 1.3 + */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#error "No ECDH-ECDSA ciphersuite available in TLS 1.3" +#endif + + + /* The following functionality is not yet supported with this TLS 1.3 implementation. + */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)) +#error "RSA-based ciphersuites not supported with this TLS 1.3 implementation" +#endif + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK) +#error "DHE-PSK-based ciphersuites not supported with this TLS 1.3 implementation" +#endif + + /* Caching in TLS 1.3 works differently than in TLS 1.2 + * Hence, SSL Cache MUST NOT be enabled. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_CACHE_C) +#error "SSL Caching not supported with TLS 1.3" +#endif + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_SESSION_TICKETS) +#error "The new session ticket concept is only available with TLS 1.3 and is not compatible with RFC 5077-style session tickets." +#endif + + /* Either SHA-256 or SHA-512 must be enabled. + * + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && ( !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "With TLS 1.3 SHA-256 and/or SHA-384 must be enabled" +#endif + +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && (MBEDTLS_PSK_MAX_LEN==32) +#error "MBEDTLS_PSK_MAX_LEN needs to be set to 48 bytes" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && !defined(MBEDTLS_HKDF_C) +#error "MBEDTLS_HKDF_C is required for TLS 1_3 to work. " +#endif #if defined(MBEDTLS_SSL_DTLS_SRTP) && ( !defined(MBEDTLS_SSL_PROTO_DTLS) ) #error "MBEDTLS_SSL_DTLS_SRTP defined, but not all prerequisites" #endif diff --git a/include/mbedtls/compat-1.3.h b/include/mbedtls/compat-1.3.h index 40177512cabb..94ee9a8b95dd 100644 --- a/include/mbedtls/compat-1.3.h +++ b/include/mbedtls/compat-1.3.h @@ -1248,9 +1248,9 @@ #define POLARSSL_KEY_EXCHANGE_PSK MBEDTLS_KEY_EXCHANGE_PSK #define POLARSSL_KEY_EXCHANGE_RSA MBEDTLS_KEY_EXCHANGE_RSA #define POLARSSL_KEY_EXCHANGE_RSA_PSK MBEDTLS_KEY_EXCHANGE_RSA_PSK -#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED -#define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED -#define POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED +#define POLARSSL_KEY_EXCHANGE_SOME_ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED +#define POLARSSL_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_WITH_CERT_ENABLED MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED #define POLARSSL_KEY_LENGTH_DES MBEDTLS_KEY_LENGTH_DES #define POLARSSL_KEY_LENGTH_DES_EDE MBEDTLS_KEY_LENGTH_DES_EDE #define POLARSSL_KEY_LENGTH_DES_EDE3 MBEDTLS_KEY_LENGTH_DES_EDE3 diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 1cd6eb663487..0bb1d32ac7ea 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -961,7 +961,7 @@ * See dhm.h for more details. * */ -#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED @@ -1006,7 +1006,7 @@ * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA */ -#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED @@ -1034,7 +1034,7 @@ * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 */ -#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED @@ -1067,7 +1067,7 @@ * See dhm.h for more details. * */ -#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED @@ -1092,7 +1092,7 @@ * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA */ -#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED @@ -1140,7 +1140,7 @@ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 */ -#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED @@ -1164,7 +1164,7 @@ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 */ -#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED @@ -1556,7 +1556,14 @@ * * Uncomment to enable support for record checking. */ -#define MBEDTLS_SSL_RECORD_CHECKING +//#define MBEDTLS_SSL_RECORD_CHECKING + +/** + * \def MBEDTLS_SSL_USE_MPS + * + * TODO: Document + */ +#define MBEDTLS_SSL_USE_MPS /** * \def MBEDTLS_SSL_DTLS_CONNECTION_ID @@ -1622,7 +1629,7 @@ * * Comment to disable the context serialization APIs. */ -#define MBEDTLS_SSL_CONTEXT_SERIALIZATION +//#define MBEDTLS_SSL_CONTEXT_SERIALIZATION /** * \def MBEDTLS_SSL_DEBUG_ALL @@ -1656,7 +1663,7 @@ * * Comment this macro to disable support for Encrypt-then-MAC */ -#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +//#define MBEDTLS_SSL_ENCRYPT_THEN_MAC /** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET * @@ -1674,7 +1681,7 @@ * * Comment this macro to disable support for Extended Master Secret. */ -#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +//#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET /** * \def MBEDTLS_SSL_FALLBACK_SCSV @@ -1739,7 +1746,7 @@ * * Comment this macro to disable 1/n-1 record splitting. */ -#define MBEDTLS_SSL_CBC_RECORD_SPLITTING +//#define MBEDTLS_SSL_CBC_RECORD_SPLITTING /** * \def MBEDTLS_SSL_RENEGOTIATION @@ -1761,7 +1768,7 @@ * configuration of this extension). * */ -#define MBEDTLS_SSL_RENEGOTIATION +//#define MBEDTLS_SSL_RENEGOTIATION /** * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO @@ -1793,7 +1800,7 @@ * * Comment this macro to disable support for the max_fragment_length extension */ -#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +//#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH /** * \def MBEDTLS_SSL_PROTO_SSL3 @@ -1820,7 +1827,7 @@ * * Comment this macro to disable support for TLS 1.0 */ -#define MBEDTLS_SSL_PROTO_TLS1 +//#define MBEDTLS_SSL_PROTO_TLS1 /** * \def MBEDTLS_SSL_PROTO_TLS1_1 @@ -1832,7 +1839,7 @@ * * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 */ -#define MBEDTLS_SSL_PROTO_TLS1_1 +//#define MBEDTLS_SSL_PROTO_TLS1_1 /** * \def MBEDTLS_SSL_PROTO_TLS1_2 @@ -1844,7 +1851,7 @@ * * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 */ -#define MBEDTLS_SSL_PROTO_TLS1_2 +//#define MBEDTLS_SSL_PROTO_TLS1_2 /** * \def MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL @@ -1863,7 +1870,82 @@ * Uncomment this macro to enable experimental and partial * functionality specific to TLS 1.3. */ -//#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + +/* \def MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE + * + * Enable TLS 1.3 middlebox compatibility mode. + * + * As specified in Section D.4 of RFC 8449, TLS 1.3 offers a compatibility + * mode to make a TLS 1.3 connection more likely to pass through middle boxes + * expecting TLS 1.2 traffic. + * + * Turning on the compatibility mode comes at the cost of a few added bytes + * on the wire, but it doesn't affect compatibility with TLS 1.3 implementations + * that don't use it. Therefore, unless transmission bandwidth is critical and + * you know that middlebox compatibility issues won't occur, it is therefore + * recommended to set this option. + * + * Comment to disable compatibility mode for TLS 1.3. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_3 + * + */ +#define MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE + +/** +* \def MBEDTLS_SSL_EARLY_DATA_MAX_DELAY +* +* Tolerance window for ticket age value. +* Outside this tolerance window, 0-RTT mode will be disabled. +* +*/ + +#define MBEDTLS_SSL_EARLY_DATA_MAX_DELAY 10000 + +/** +* \def MBEDTLS_ZERO_RTT +* +* Allows to add functionality for TLS/DTLS 1.3 Zero-RTT. +* +*/ +#define MBEDTLS_ZERO_RTT + +/** +* \def MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES +* +* Enables debug output for handshake hashes +* +* Requires: +* +* Uncomment this macro to print handshake hash information +*/ +//#define MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES + +/* +* \def MBEDTLS_SSL_TICKET_NONCE_LENGTH +* +* Allows adjusting the length of the nonce field in the ticket. +* +* The default value is 32 bytes. +*/ +#define MBEDTLS_SSL_TICKET_NONCE_LENGTH 32 + +/* +* \def MBEDTLS_SSL_NEW_SESSION_TICKET +* +* Enable support for TLS 1.3 session tickets. +* Client-side, provides full support for session tickets (maintainance of a +* session store remains the responsibility of the application, though). +* Server-side, you also need to provide callbacks for writing and parsing +* tickets, including authenticated encryption and key management. Example +* callbacks are provided by MBEDTLS_SSL_TICKET_C. +* +* Comment this macro to +* - be able to issue tickets by TLS 1.3 servers, and +* - use them in TLS 1.3 clients. +*/ +#define MBEDTLS_SSL_NEW_SESSION_TICKET /** * \def MBEDTLS_SSL_PROTO_DTLS @@ -1878,7 +1960,7 @@ * * Comment this macro to disable support for DTLS */ -#define MBEDTLS_SSL_PROTO_DTLS +//#define MBEDTLS_SSL_PROTO_DTLS /** * \def MBEDTLS_SSL_ALPN @@ -1887,7 +1969,7 @@ * * Comment this macro to disable support for ALPN. */ -#define MBEDTLS_SSL_ALPN +//#define MBEDTLS_SSL_ALPN /** * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY @@ -1902,7 +1984,7 @@ * * Comment this to disable anti-replay in DTLS. */ -#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY /** * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY @@ -1920,7 +2002,7 @@ * * Comment this to disable support for HelloVerifyRequest. */ -#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +//#define MBEDTLS_SSL_DTLS_HELLO_VERIFY /** * \def MBEDTLS_SSL_DTLS_SRTP @@ -1967,7 +2049,7 @@ * * Comment this to disable support for clients reusing the source port. */ -#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +//#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE /** * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT @@ -1978,7 +2060,7 @@ * * Requires: MBEDTLS_SSL_PROTO_DTLS */ -#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT +//#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT /** * \def MBEDTLS_SSL_SESSION_TICKETS @@ -1992,7 +2074,7 @@ * * Comment this macro to disable support for SSL session tickets */ -#define MBEDTLS_SSL_SESSION_TICKETS +//#define MBEDTLS_SSL_SESSION_TICKETS /** * \def MBEDTLS_SSL_EXPORT_KEYS @@ -2022,7 +2104,7 @@ * * Comment this macro to disable support for truncated HMAC in SSL */ -#define MBEDTLS_SSL_TRUNCATED_HMAC +//#define MBEDTLS_SSL_TRUNCATED_HMAC /** * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT @@ -2279,7 +2361,7 @@ * * Comment this macro to disallow using RSASSA-PSS in certificates. */ -#define MBEDTLS_X509_RSASSA_PSS_SUPPORT +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT /** * \def MBEDTLS_ZLIB_SUPPORT @@ -3314,7 +3396,7 @@ * * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C */ -#define MBEDTLS_RSA_C +//#define MBEDTLS_RSA_C /** * \def MBEDTLS_SHA1_C @@ -3368,7 +3450,7 @@ * * This module adds support for SHA-384 and SHA-512. */ -#define MBEDTLS_SHA512_C + #define MBEDTLS_SHA512_C /** * \def MBEDTLS_SSL_CACHE_C @@ -3380,7 +3462,7 @@ * * Requires: MBEDTLS_SSL_CACHE_C */ -#define MBEDTLS_SSL_CACHE_C +//#define MBEDTLS_SSL_CACHE_C /** * \def MBEDTLS_SSL_COOKIE_C @@ -4010,8 +4092,13 @@ //#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ -//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ -//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +/* TODO: Define those macros in ssl_internal.h when they're not defined here! */ +/* TODO: This is somehow hardcoded to 48 Bytes - is that intentional? It certainly doesn't match the comment. */ +#define MBEDTLS_PSK_MAX_LEN 48 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +/* TODO: Document appropriately */ +#define MBEDTLS_PSK_IDENTITY_MAX_LEN 250 /**< Max size of psk identity, in bytes */ +#define MBEDTLS_SSL_TICKET_AGE_TOLERANCE 6000 /**< Tolerance window for ticket lifetime */ /** \def MBEDTLS_TLS_EXT_CID * diff --git a/include/mbedtls/mps/allocator.h b/include/mbedtls/mps/allocator.h new file mode 100644 index 000000000000..005c7e808c52 --- /dev/null +++ b/include/mbedtls/mps/allocator.h @@ -0,0 +1,115 @@ +/** + * \file allocator.h + * + * \brief The allocation interface used by various parts of MPS + * to acquire and release memory. + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_ALLOCATOR_H +#define MBEDTLS_MPS_ALLOCATOR_H + +#include "error.h" + +#include +#include + +struct mps_alloc; +typedef struct mps_alloc mps_alloc; + +typedef enum +{ + MPS_ALLOC_L1_IN = 0, + MPS_ALLOC_L1_OUT +} mps_alloc_type; + +/** + * \brief Initialize an MPS allocator context. + * + * \param ctx The allocator context to initialize. + * \param l1_len The length of the buffers passed to the + * read- and write-sides of MPS Layer 1. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_alloc_init( mps_alloc *ctx, + mbedtls_mps_size_t l1_len ); + +/** + * \brief Free an MPS allocator context. + * + * \param ctx The allocator context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_alloc_free( mps_alloc *ctx ); + +/** + * \brief Request a buffer for a given purpose from the allocator. + * + * \param ctx The allocator context to use. + * \param purpose The identifier indicating the purpose of the buffer. + * \param buf The address to which to write the address of the + * buffer returned from allocator. + * \param buflen The address to which to write the length of the + * provided buffer. + * + * \return \c 0 on success. + * \return #MPS_ERR_ALLOC_INVALID_PURPOSE if the provided + * purpose is invalid. + * \return #MPS_ERR_ALLOC_OUT_OF_SPACE if a buffer + * for the requested purpose couldn't be provided. + */ +int mps_alloc_acquire( mps_alloc *ctx, mps_alloc_type purpose, + unsigned char **buf, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Release a buffer previously acquired from the allocator. + * + * \param ctx The allocator context to use. + * \param purpose The identifier indicating the purpose of the buffer. + * + * \return \c 0 on success. + * \return #MPS_ERR_ALLOC_INVALID_PURPOSE if the provided + * purpose is invalid. + * \return #MPS_ERR_ALLOC_NOT_ALLOCATED if the buffer + * hasn't been allocated. + */ +int mps_alloc_release( mps_alloc* ctx, mps_alloc_type purpose ); + +/** + * \brief Reference implementation of the allocator, maintaining + * different buffers for each purpose. + */ +struct mps_alloc +{ + uint32_t alloc_state; /*!< Bit-flag indicating the status + * of allocation. */ + + unsigned char *l1_in; /*!< The buffer for the read-side of Layer 1. */ + size_t l1_in_len; /*!< The length in bytes of l1_in. */ + + unsigned char *l1_out; /*!< The buffer for the write-side of Layer 1. */ + size_t l1_out_len; /*!< The length in bytes of l1_out. */ +}; + +#endif /* MBEDTLS_MPS_ALLOCATOR_H */ diff --git a/include/mbedtls/mps/common.h b/include/mbedtls/mps/common.h new file mode 100644 index 000000000000..efb4d347b4d3 --- /dev/null +++ b/include/mbedtls/mps/common.h @@ -0,0 +1,713 @@ +/** + * \file common.h + * + * \brief Common functions and macros used by MPS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MPS_COMMON_H +#define MBEDTLS_MPS_COMMON_H + +#ifndef MBEDTLS_MPS_ERR_BASE +#define MBEDTLS_MPS_ERR_BASE ( 1 << 10 ) +#endif + +#ifndef MBEDTLS_MPS_READER_ERR_BASE +#define MBEDTLS_MPS_READER_ERR_BASE ( 1 << 11 ) +#endif + +#ifndef MBEDTLS_WRITER_ERR_BASE +#define MBEDTLS_WRITER_ERR_BASE ( 1 << 12 ) +#endif + +#define MBEDTLS_MPS_MAKE_ERROR(code) \ + ( -( MBEDTLS_MPS_ERR_BASE | (code) ) ) + +#define MBEDTLS_MPS_READER_MAKE_ERROR(code) \ + ( -( MBEDTLS_MPS_READER_ERR_BASE | (code) ) ) + +#define MBEDTLS_WRITER_MAKE_ERROR(code) \ + ( -( MBEDTLS_WRITER_ERR_BASE | (code) ) ) + +#include +#include +#include "error.h" + +/** + * \name SECTION: MPS Configuration + * + * \{ + */ + +/*! This numerical option controls the maximum level of interleaving + * of records of different content types that should be supported. + * + * - A value of \c 1 indicates that a sequence of records jointly + * carrying some message (e.g., a long handshake message fragmented + * across multiple records) must not be interleaved with records + * of other content types (e.g., an alert record). + * + * - A value of \c n indicates that the stack is able of processing + * up to \c n messages of different content types carried over + * interleaved records. + * + * TLS 1.3 forbids interleaving of records of different content types, + * and the value of this option is irrelevant in this case: The stack + * will behave as if the value was \c 1. + * + * For earlier versions of TLS, there are two reasons to consider + * using a value bigger than \c 1: + * + * - The default value of \c 2 allows to receive and handle a fatal alert + * while accumulating a fragmented handshake message. + * + * - A value greater than \c 2 is currently purely academic: It would e.g. + * allow to receive a CCS while receiving a fragmented handshake message + * _and_ a fragmented alert (which is only possible if the alert is carried + * in two 1-byte records). + * It is supported for experimentation and because the complexity of the + * current implementation does not depend on the value of this option. + * + */ +#define MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING 2 + +/*! This flag controls whether the MPS-internal components + * (reader, writer, Layer 1-3) perform validation of the + * expected abstract state at the entry of API calls. + * + * Context: All MPS API functions impose assumptions/preconditions on the + * context on which they operate. For example, every structure has a notion of + * state integrity which is established by `xxx_init()` and preserved by any + * calls to the MPS API which satisfy their preconditions and either succeed, + * or fail with an error code which is explicitly documented to not corrupt + * structure integrity (such as #MPS_ERR_WANT_READ and #MPS_ERR_WANT_WRITE); + * apart from `xxx_init()` any function assumes state integrity as a + * precondition (but usually more). If any of the preconditions is violated, + * the function's behavior is entirely undefined. + * In addition to state integrity, all MPS structures have a more refined + * notion of abstract state that the API operates on. For example, all layers + * have a notion of 'abtract read state' which indicates if incoming data has + * been passed to the user, e.g. through mps_l2_read_start() for Layer 2 + * or mps_l3_read() in Layer 3. After such a call, it doesn't make sense to + * call these reading functions again until the incoming data has been + * explicitly 'consumed', e.g. through mps_l2_read_consume() for Layer 2 or + * mps_l3_read_consume() on Layer 3. However, even if it doesn't make sense, + * it's a design choice whether the API should fail gracefully on such + * non-sensical calls or not, and that's what this option is about: + * + * This option determines whether the expected abstract state + * is part of the API preconditions or not. If it is, the function's + * behavior is undefined if the abstract state is not as expected. + * If it is set, API is required to fail gracefully with error + * #MPS_ERR_OPERATION_UNEXPECTED, and without changing the abstract + * state of the input context, if the abstract state is unexpected but + * all other preconditions are satisfied. + * + * For example: Enabling this makes mps_l2_read_done() fail if + * no incoming record is currently open; disabling this would + * lead to undefined behavior in this case. + * + * Comment this to remove state validation. + */ +#define MBEDTLS_MPS_STATE_VALIDATION + +/*! This flag enables/disables assertions on the internal state of MPS. + * + * Assertions are sanity checks that should never trigger when MPS + * is used within the bounds of its API and preconditions. + * + * Enabling this increases security by limiting the scope of + * potential bugs, but comes at the cost of increased code size. + * + * At the time of writing (Jan '19), assertions increase + * the code size by ~160 bytes. + * + * Note: So far, there is no guiding principle as to what + * expected conditions merit an assertion, and which don't. + * + * Comment this to disable assertions. + */ +#define MBEDTLS_MPS_ENABLE_ASSERTIONS + +/*! This flag determines whether MPS should perform sanity + * checks on the data returned by the record protection API. + * + * MPS Layer 2 doesn't control the actual record protection + * but only interfaces with it through the API defined in + * transform.h. + */ +#define MBEDTLS_MPS_TRANSFORM_VALIDATION + +/*! This flag controls whether tracing for MPS should be enabled. */ +//#define MBEDTLS_MPS_ENABLE_TRACE + +/*! This internal macro determines whether all Layers of MPS should + * be compiled into a single source file. + * + * Comment to merge all MPS Layers into a single compilation unit, + * solely exposing the top-level MPS API. + */ +#define MBEDTLS_MPS_SEPARATE_LAYERS + +/*! This test-only flag controls whether all usually static helper + * function in MPS should have external linkage. + * + * This is useful when analyzing the code-size of MPS. + * + * Uncomment to give all MPS helper functions external linkage, + * making them visible in the generated object file. + */ +//#define MBEDTLS_MPS_NO_STATIC_FUNCTIONS + +/*! This flag enables support for the TLS protocol. + * + * Uncomment if only DTLS is needed. + */ +#define MBEDTLS_MPS_PROTO_TLS + +/*! This flag enables support for the DTLS protocol. + * + * Uncomment if only TLS is needed. + */ +#define MBEDTLS_MPS_PROTO_DTLS + +/*! The number of epochs Layer 2 can handle simultaneously. + * + * A value of \c 2 should be sufficient for all versions + * of TLS and DTLS. + * + * TODO: Currently, TLS 1.3 needs an epoch window of 3: + * By the time the client parses the SH and creates + * the handshake traffic keys, it uses the + * - initial epoch for incoming traffic + * - the 0-RTT epoch for outgoing traffic + * - trying to register a new one for handshake traffic. + * The resolution here is to allow to somehow mark the + * initial epoch as no longer used without at the same + * time registering a new epoch for incoming traffic. + * One could temporarily register the 0-RTT keys for + * incoming traffic, but that seems wrong. + * + * TODO: The setting of 4 is temporary as long as we don't + * use MPS for reading. It should be possible to at + * least reduce to 3 when perform the reading. + */ +typedef uint8_t mbedtls_mps_epoch_offset_t; +#define MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ( (mbedtls_mps_epoch_offset_t) 4 ) + +/*! Whether MPS should support epoch window shifting. + * + * Commenting this saves code and a bit of RAM, but + * means that no more than MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE + * epochs can be configured in MPS. + * + * In practice, you may comment this if you don't need renegotiation. + */ +#define MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING + +/* + * Internal helper macros derived from the MPS configuration. + */ + +#if MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING >= 2 +#define MBEDTLS_MPS_SUPPORT_TWO_INTERLEAVED_MESSAGES +#endif + +#if defined(MBEDTLS_MPS_STATE_VALIDATION) + +#define MBEDTLS_MPS_STATE_VALIDATE( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MPS_CHK( MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ); \ + } \ + } while( 0 ) + +#define MBEDTLS_MPS_STATE_VALIDATE_RAW( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ); \ + } \ + } while( 0 ) + +#else /* MBEDTLS_MPS_STATE_VALIDATION */ + +#define MBEDTLS_MPS_STATE_VALIDATE( cond, string ) \ + do \ + { \ + (void) ( cond ); \ + } while( 0 ) + +#define MBEDTLS_MPS_STATE_VALIDATE_RAW( cond, string ) \ + do \ + { \ + (void)( cond ); \ + } while( 0 ) + +#endif /* MBEDTLS_MPS_STATE_VALIDATION */ + +#if defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) + +#define MBEDTLS_MPS_ASSERT( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MPS_CHK( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); \ + } \ + } while( 0 ) + +#define MBEDTLS_MPS_ASSERT_RAW( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); \ + } \ + } while( 0 ) + +#else /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +#define MBEDTLS_MPS_ASSERT( cond, string ) \ + do { int val = (cond); ((void) val); } while( 0 ) +#define MBEDTLS_MPS_ASSERT_RAW( cond, string ) \ + do { int val = (cond); ((void) val); } while( 0 ) + +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +#if defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) +#define MBEDTLS_MPS_STATIC +#define MBEDTLS_MPS_INLINE +#define MBEDTLS_MPS_ALWAYS_INLINE +#else +#define MBEDTLS_MPS_STATIC static +#define MBEDTLS_MPS_INLINE static inline +#if defined(__arm__) || defined(__gcc__) +#define MBEDTLS_MPS_ALWAYS_INLINE __attribute__((always_inline)) static inline +#else +#define MBEDTLS_MPS_ALWAYS_INLINE static inline +#endif +#endif /* MBEDTLS_MPS_NO_STATIC_FUNCTIONS */ + +#if !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#define MBEDTLS_MPS_INTERNAL_API MBEDTLS_MPS_STATIC +#else +#define MBEDTLS_MPS_INTERNAL_API +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS */ + +/** Internal macro sanity check. */ +#if defined(MBEDTLS_MPS_TRACE) && \ + !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#error "Tracing (MBEDTLS_MPS_TRACE) is only possible in multi-unit MPS (MBEDTLS_MPS_SEPARATE_LAYERS)" +#endif /* MBEDTLS_MPS_TRACE && !MBEDTLS_MPS_SEPARATE_LAYERS */ + +/** Internal macro sanity check. */ +#if !defined(MBEDTLS_MPS_PROTO_TLS) && \ + !defined(MBEDTLS_MPS_PROTO_DTLS) +#error "Either MBEDTLS_MPS_PROTO_TLS or MBEDTLS_MPS_PROTO_DTLS must be set." +#endif /* !MBEDTLS_MPS_PROTO_TLS && !MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) && \ + defined(MBEDTLS_MPS_PROTO_DTLS) +#define MBEDTLS_MPS_PROTO_BOTH +#endif + +/* \} name SECTION: MPS Configuration */ + +/** + * \name SECTION: Common types + * + * Various common types used throughout MPS. + * \{ + */ + +/*! This determines whether internal computations with values + * of small range (such as record content types) should declare the + * variables holding those values using the smallest possible type. + * + * This is just to make it easier to investigate the effect + * on code size that the choice of integer type has. + * + * Currently, this is disabled by default because allowing + * the compiler to use the most natural choice of type for the + * target platform appears to lead to slightly smaller code. + * + * TODO: This feature is experimental and doesn't work properly yet! + * + */ +//#define MBEDTLS_MPS_INTERNAL_SMALL_TYPES + +/*! This determines whether structure fields always use the + * smallest possible type to hold the possible values. + * + * This is just to make it easier to investigate the effect + * on code size that the choice of integer type has. + * + * Enabling this significantly reduces RAM usage of MPS structures, + * but slightly increases its code-size. + * + * TODO: This feature is experimental and doesn't work properly yet! + */ +//#define MBEDTLS_MPS_STORED_SMALL_TYPES + +typedef uint8_t mbedtls_mps_transport_type; +/* MBEDTLS_SSL_TRANSPORT_STREAM */ +#define MBEDTLS_MPS_MODE_STREAM ((mbedtls_mps_transport_type) 0) + /* MBEDTLS_SSL_TRANSPORT_DATAGRAM */ +#define MBEDTLS_MPS_MODE_DATAGRAM ((mbedtls_mps_transport_type) 1) + +/* Helper macros to check whether TLS/DTLS are enabled. */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if defined(MBEDTLS_MPS_PROTO_BOTH) +#define MBEDTLS_MPS_IS_TLS(mode) ((mode) == MBEDTLS_MPS_MODE_STREAM) +#else +#define MBEDTLS_MPS_IS_TLS(mode) (((void) mode), 1) +#endif /* MBEDTLS_MPS_PROTO_BOTH */ +#else /* MBEDTLS_MPS_PROTO_TLS */ +#define MBEDTLS_MPS_IS_TLS(mode) (((void) mode), 0) +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#define MBEDTLS_MPS_IF_TLS(mode) if( MBEDTLS_MPS_IS_TLS( mode ) ) +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if defined(MBEDTLS_MPS_PROTO_BOTH) +#define MBEDTLS_MPS_IS_DTLS(mode) ((mode) == MBEDTLS_MPS_MODE_DATAGRAM) +#define MBEDTLS_MPS_ELSE_IF_DTLS(mode) else if(((void)mode), 1) +#else /* MBEDTLS_MPS_PROTO_BOTH */ +#define MBEDTLS_MPS_IS_DTLS(mode) (((void) mode), 1) +#define MBEDTLS_MPS_ELSE_IF_DTLS( mode ) if( MBEDTLS_MPS_IS_DTLS( mode ) ) +#endif /* MBEDTLS_MPS_PROTO_BOTH */ +#else /* MBEDTLS_MPS_PROTO_DTLS */ +#define MBEDTLS_MPS_IS_DTLS(mode) (((void) mode), 0 ) +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +#define MBEDTLS_MPS_IF_DTLS( mode ) if(MBEDTLS_MPS_IS_DTLS(mode)) + +/*! The enumeration of record content types recognized by MPS. + * + * \note Not all of these are visible on the MPS boundary. For example, + * ACK messages are handled by MPS internally and are never signalled + * to the user. + * + * \note The values are aligned to the ContentType field in [D]TLS records. + */ + +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_msg_type_t; +#else +typedef unsigned mbedtls_mps_stored_msg_type_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_msg_type_t mbedtls_mps_msg_type_t; +#else +typedef uint_fast8_t mbedtls_mps_msg_type_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/*! This is a placeholder to indicate that no record is + * currently open for reading or writing. */ +#define MBEDTLS_MPS_MSG_NONE ( (mbedtls_mps_msg_type_t) 0 ) +/*! This represents Application data messages. */ +#define MBEDTLS_MPS_MSG_APP ( (mbedtls_mps_msg_type_t) 23 ) +/*! This represents Handshake messages. */ +#define MBEDTLS_MPS_MSG_HS ( (mbedtls_mps_msg_type_t) 22 ) +/*!< This represents Alert messages. */ +#define MBEDTLS_MPS_MSG_ALERT ( (mbedtls_mps_msg_type_t) 21 ) +/*!< This represents ChangeCipherSpec messages. */ +#define MBEDTLS_MPS_MSG_CCS ( (mbedtls_mps_msg_type_t) 20 ) +/*!< This represents ACK messages (used in DTLS 1.3 only). */ +#define MBEDTLS_MPS_MSG_ACK ( (mbedtls_mps_msg_type_t) 25 ) + +#define MBEDTLS_MPS_MSG_MAX ( (mbedtls_mps_msg_type_t) 31 ) + +/* TODO: Document */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_hs_type; +#else +typedef unsigned mbedtls_mps_stored_hs_type; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_hs_type mbedtls_mps_hs_type; +#else +typedef uint_fast8_t mbedtls_mps_hs_type; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + + +/** \brief The type of epoch IDs. */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef int8_t mbedtls_mps_stored_epoch_id; +#else +typedef int mbedtls_mps_stored_epoch_id; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_epoch_id mbedtls_mps_epoch_id; +#else +typedef int_fast8_t mbedtls_mps_epoch_id; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/*! The first unusable unusable epoch ID. */ +#define MBEDTLS_MPS_EPOCH_MAX ( ( mbedtls_mps_epoch_id ) 100 /* 0x7FFF */ ) +/*! An identifier for the invalid epoch. */ +#define MBEDTLS_MPS_EPOCH_NONE ( (mbedtls_mps_epoch_id) -1 ) + +/** \brief The type of handshake sequence numbers used in MPS structures. + * + * By the DTLS 1.2 standard (RFC 6347), handshake sequence numbers + * are 16-bit, so for full compliance one needs to use a type of + * width at least 16 bits here. + * + * The reason to pick a value as small as possible here is + * to reduce the size of MPS structures. + * + * \warning Care has to be taken when using a narrower type + * than ::mbedtls_mps_stored_hs_seq_nr_t here because of + * potential truncation during conversion. + */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_hs_seq_nr_t; +#else +typedef unsigned mbedtls_mps_stored_hs_seq_nr_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#define MBEDTLS_MPS_HS_SEQ_MAX ( (mbedtls_mps_stored_hs_seq_nr_t) -1 ) + +/** \brief The type of handshake sequence numbers used + * in the implementation. + * + * This must be at least as wide as + * ::mbedtls_mps_stored_hs_seq_nr_t but may be chosen + * to be strictly larger if more suitable for the + * target architecture. + */ +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_hs_seq_nr_t mbedtls_mps_hs_seq_nr_t; +#else +typedef unsigned mbedtls_mps_hs_seq_nr_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/** \brief The type of buffer sizes and offsets used in MPS structures. + * + * This is an unsigned integer type that should be large enough to + * hold the length of any buffer resp. message processed by MPS. + * + * The reason to pick a value as small as possible here is + * to reduce the size of MPS structures. + * + * \warning Care has to be taken when using a narrower type + * than ::mbedtls_mps_size_t here because of + * potential truncation during conversion. + * + * \warning Handshake messages in TLS may be up to 2^24 ~ 16Mb in size. + * If mbedtls_mps_[opt_]stored_size_t is smaller than that, the + * maximum handshake message is restricted accordingly. + * + * TODO: !!! This isn't yet implemented !!! + * + */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint16_t mbedtls_mps_stored_size_t; +typedef int16_t mbedtls_mps_stored_opt_size_t; +#else +typedef size_t mbedtls_mps_stored_size_t; +typedef int mbedtls_mps_stored_opt_size_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#define MBEDTLS_MPS_SIZE_MAX ( (mbedtls_mps_stored_size_t) -1 ) +#define MBEDTLS_MPS_SIZE_UNKNOWN ( (mbedtls_mps_stored_opt_size_t) -1 ) + +#define MBEDTLS_MPS_MAX_HS_LENGTH 1000 + +/* \brief The type of buffer sizes and offsets used in the MPS API + * and implementation. + * + * This must be at least as wide as ::mbedtls_stored_size_t but + * may be chosen to be strictly larger if more suitable for the + * target architecture. + * + * For example, in a test build for ARM Thumb, using uint_fast16_t + * instead of uint16_t reduced the code size from 1060 Byte to 962 Byte, + * so almost 10%. + */ +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_size_t mbedtls_mps_size_t; +#else +typedef size_t mbedtls_mps_size_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +#if (mbedtls_mps_size_t) -1 > (mbedtls_mps_stored_size_t) -1 +#error "Misconfiguration of mbedtls_mps_size_t and mbedtls_mps_stored_size_t." +#endif + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +#undef MBEDTLS_MPS_INTERNAL_SMALL_TYPES +#endif + +/* \} SECTION: Common types */ + +/** + * \name SECTION: Hardcoded configurations + * + * By default, each MPS Layer can be configured dynamically by setting + * the corresponding field in the configuration structure at runtime. + * While this gives flexibility that is necessary for the use of + * Mbed TLS as a dynamically linked library, it leads to unnecessary + * code and RAM overhead on constrained applications that use a fixed + * configuration only. + * + * The following options therefore allow to hardcode parts of the + * MPS configuration at compile-time. + * + * \{ + */ + +/* #define MBEDTLS_MPS_CONF_VERSION 3 /\*!< TLS v1.2 *\/ */ +/* #define MBEDTLS_MPS_CONF_ANTI_REPLAY 1 */ +/* #define MBEDTLS_MPS_CONF_MAX_PLAIN_IN 1000 */ +/* #define MBEDTLS_MPS_CONF_MAX_PLAIN_OUT 1000 */ +/* #define MBEDTLS_MPS_CONF_MAX_CIPHER IN 1000 */ +/* #define MBEDTLS_MPS_CONF_TYPE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_MERGE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_PAUSE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_EMPTY_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_BADMAC_LIMIT ( (uint32_t) 10000 ) */ +/* #define MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN 1000 */ +/* #define MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX 32000 */ + +/* TLS vs. DTLS configuration is automatically deduced from + * the settings of MBEDTLS_MPS_PROTO_TLS / MBEDTLS_MPS_PROTO_DTLS + * and should not be set directly. */ +#if !defined(MBEDTLS_MPS_PROTO_BOTH) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_CONF_MODE MBEDTLS_MPS_MODE_STREAM +#else +#define MBEDTLS_MPS_CONF_MODE MBEDTLS_MPS_MODE_DATAGRAM +#endif +#endif /* !MBEDTLS_MPS_PROTO_BOTH */ + +/* \} SECTION: Hardcoded configurations */ + +/** + * \name SECTION: Parsing and writing macros + * + * Macros to be used for parsing various types of fields. + * \{ + */ + +#define MPS_READ_UINT8_BE( src, dst ) \ + do \ + { \ + *( dst ) = ( (uint8_t*) ( src ) )[0]; \ + } while( 0 ) + +#define MPS_WRITE_UINT8_BE( src, dst ) \ + do \ + { \ + *( dst ) = ( (uint8_t*) ( src ) )[0]; \ + } while( 0 ) + +#define MPS_READ_UINT16_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint16_t) ( (uint8_t*) ( src ) )[0] ) << 8 ) + \ + ( ( (uint16_t) ( (uint8_t*) ( src ) )[1] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT16_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + + +#define MPS_WRITE_UINT24_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT24_BE( src, dst ) \ + do \ + { \ + *(dst) = \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[0] ) << 16 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[1] ) << 8 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[2] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT32_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 24 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 3 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT32_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[0] ) << 24 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[1] ) << 16 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[2] ) << 8 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[3] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT48_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 40 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 32 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 24 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 3 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 4 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 5 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT48_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[0] ) << 40 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[1] ) << 32 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[2] ) << 24 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[3] ) << 16 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[4] ) << 8 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[5] ) << 0 ); \ + } while( 0 ) + +/* \} name SECTION: Parsing and writing macros */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define UNUSED +#else +#define UNUSED __attribute__((unused)) +#endif + +#endif /* MBEDTLS_MPS_COMMON_H */ diff --git a/include/mbedtls/mps/error.h b/include/mbedtls/mps/error.h new file mode 100644 index 000000000000..221e42aa61da --- /dev/null +++ b/include/mbedtls/mps/error.h @@ -0,0 +1,332 @@ +/** + * \file error.h + * + * \brief Message Processing Stack + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_ERROR_H +#define MBEDTLS_MPS_ERROR_H + +#include "common.h" + +/** + * MPS-specific error codes + */ + +/* + * Error codes visible at the MPS boundary. + */ + +/*! A request for dynamic memory allocation failed. */ +#define MBEDTLS_ERR_MPS_OUT_OF_MEMORY MBEDTLS_MPS_MAKE_ERROR( 0x01 ) +/*! The requested operation is not supported. */ +#define MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED MBEDTLS_MPS_MAKE_ERROR( 0x02 ) +/*! The requested operation cannot be performed in the current state. */ +#define MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED MBEDTLS_MPS_MAKE_ERROR( 0x03 ) +/*! The peer has sent a closure notification alert. */ +#define MBEDTLS_ERR_MPS_CLOSE_NOTIFY MBEDTLS_MPS_MAKE_ERROR( 0x04 ) +/*! The MPS is blocked. */ +#define MBEDTLS_ERR_MPS_BLOCKED MBEDTLS_MPS_MAKE_ERROR( 0x05 ) +/*! The peer has sent a fatal alert. */ +#define MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED MBEDTLS_MPS_MAKE_ERROR( 0x07 ) +/*! An internal assertion has failed - should never happen. */ +#define MBEDTLS_ERR_MPS_INTERNAL_ERROR MBEDTLS_MPS_MAKE_ERROR( 0x08 ) +#define MBEDTLS_ERR_MPS_RETRY MBEDTLS_MPS_MAKE_ERROR( 0x09 ) +#define MBEDTLS_ERR_MPS_COUNTER_WRAP MBEDTLS_MPS_MAKE_ERROR( 0x0a ) +#define MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG MBEDTLS_MPS_MAKE_ERROR( 0x0b ) + +/*! MPS cannot handle the amount of record fragmentation used by the peer. + * This happens e.g. if fragmented handshake records are interleaved with + * fragmented alert records. */ +#define MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION MBEDTLS_MPS_MAKE_ERROR( 0x0c ) +/*! Layer 2 has been asked to pause a non-pausable record type. */ +#define MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION MBEDTLS_MPS_MAKE_ERROR( 0x0d ) +/*! The epoch under consideration exceeds the current epoch window. */ +#define MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS MBEDTLS_MPS_MAKE_ERROR( 0x0e ) +#define MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS MBEDTLS_MPS_MAKE_ERROR( 0x0f ) +/*! The underlying transport does not have enough incoming data available + * to perform the requested read operation. */ +#define MBEDTLS_ERR_MPS_WANT_READ MBEDTLS_MPS_MAKE_ERROR( 0x10 ) +/*! The underlying transport has been closed. */ +#define MBEDTLS_ERR_MPS_CONN_EOF MBEDTLS_MPS_MAKE_ERROR( 0x70 ) +/*! The underlying transport is unavailable perform the send operation. */ +#define MBEDTLS_ERR_MPS_WANT_WRITE MBEDTLS_MPS_MAKE_ERROR( 0x11 ) +#define MBEDTLS_ERR_MPS_BAD_TRANSFORM MBEDTLS_MPS_MAKE_ERROR( 0x12 ) +/*! An internal buffer was too small for a necessary operation. + * This is at the moment returned in the following situations: + * - The read-buffer handed out by the allocator is not large enough + * to hold an incoming TLS record. The user should revise either + * + the configuration of the allocator, or + * + the configuration of the maximum record length. + * TODO: This max record length configuration still needs to be written. + * - The user requested more data from the reader handed out by MPS + * than what was passed to as `max_read` to mbedtls_mps_init(). + * TODO: Add this to mbedtls_mps_init() and mbedtls_mps_l3_init(), and + * forward it to mbedtls_mps_l2_init() accordingly, where the + * `max_read` and `max_write` parameters are already present. + */ +#define MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL MBEDTLS_MPS_MAKE_ERROR( 0x13 ) +/*! A request was made to send non-handshake data while an + * an outgoing handshake message was paused. */ +#define MBEDTLS_ERR_MPS_NO_INTERLEAVING MBEDTLS_MPS_MAKE_ERROR( 0x14 ) +/*! A request was made to prematurely end the reading/writing + * of a handshake message. For reading, this means that strictly + * less data was read and committed from the handshake reader than + * what was specified in the handshake message header. For writing, + * this means that strictly less data was written and committed to the + * handshake writer than what was specified as the total handshake + * length when calling mbedtls_mps_write_handshake(). */ +#define MBEDTLS_ERR_MPS_UNFINISHED_HS_MSG MBEDTLS_MPS_MAKE_ERROR( 0x15 ) +/*! The allocator used by MPS couldn't serve an allocation request. */ +#define MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE MBEDTLS_MPS_MAKE_ERROR( 0x16 ) +/*! The parameter validation failed. */ +#define MBEDTLS_ERR_MPS_INVALID_ARGS MBEDTLS_MPS_MAKE_ERROR( 0x17 ) +/*! The user passed an invalid epoch to + * mbedtls_mps_set_incoming_keys() or + * mbedtls_mps_set_outgoing_keys(). */ +#define MBEDTLS_ERR_MPS_INVALID_EPOCH MBEDTLS_MPS_MAKE_ERROR( 0x18 ) +/*! The record header is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_CONTENT MBEDTLS_MPS_MAKE_ERROR( 0x19 ) +/*! The record header is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_RECORD MBEDTLS_MPS_MAKE_ERROR( 0x1a ) +/*! The record MAC is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_MAC MBEDTLS_MPS_MAKE_ERROR( 0x1b ) +#define MBEDTLS_ERR_MPS_BAD_TRANSPORT MBEDTLS_MPS_MAKE_ERROR( 0x21 ) + +/* + * Internal error codes + */ + +#define MBEDTLS_ERR_MPS_NO_FORWARD MBEDTLS_MPS_MAKE_ERROR( 0x0c ) +#define MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION MBEDTLS_MPS_MAKE_ERROR( 0x1c ) +#define MBEDTLS_ERR_MPS_REPLAYED_RECORD MBEDTLS_MPS_MAKE_ERROR( 0x1d ) +#define MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS MBEDTLS_MPS_MAKE_ERROR( 0x1e ) +#define MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED MBEDTLS_MPS_MAKE_ERROR( 0x1f ) +#define MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE MBEDTLS_MPS_MAKE_ERROR( 0x20 ) + +/* + * Helper macro to traverse MPS error codes + * + * This macro unfolds to the concatenation of applications of + * ``` + * MBEDTLS_MPS_ERROR_INFO( string, code, flags ) + * ``` + * where there is one application per error-code, and the + * macro is being passed + * - the string representation of the error, e.g. + * "MBEDTLS_ERR_MPS_INVALID_RECORD" + * - the numeric error code + * - error flags indicating whether the error code is + * externally visible, fatal, TLS only, ... + * + * See the generic failure handler in mps.c for an example of + * how to use this macro. + */ + +#define MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ( 1u << 0 ) +#define MBEDTLS_MPS_ERROR_FLAGS_FATAL ( 1u << 1 ) +#define MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ( 1u << 2 ) + +#define MBEDTLS_MPS_ERROR_IS_FATAL( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_FATAL ) != 0 ) +#define MBEDTLS_MPS_ERROR_IS_TLS_ONLY( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ) != 0 ) +#define MBEDTLS_MPS_ERROR_IS_EXTERNAL( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ) != 0 ) + +#define MBEDTLS_MPS_MAKE_ERROR_INFO( flags, name ) \ + #name, name, flags + +#define EXPAND(x) x +#define MBEDTLS_MPS_ERROR_INFO_WRAP( x ) EXPAND(MBEDTLS_MPS_ERROR_INFO(x)) + +#define MBEDTLS_ERR_MPS_ERROR_LIST \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OUT_OF_MEMORY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_CLOSE_NOTIFY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_BLOCKED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INTERNAL_ERROR ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_RETRY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_NO_FORWARD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_COUNTER_WRAP ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_CONN_EOF ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_WANT_READ ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_WANT_WRITE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_SSL_WANT_READ ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_SSL_WANT_WRITE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BAD_TRANSFORM ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_NO_INTERLEAVING ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_UNFINISHED_HS_MSG ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_ARGS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_EPOCH ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_CONTENT ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL | \ + MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ), \ + MBEDTLS_ERR_MPS_INVALID_RECORD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL | \ + MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ), \ + MBEDTLS_ERR_MPS_INVALID_MAC ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BAD_TRANSPORT ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REPLAYED_RECORD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) ) + +#endif /* MBEDTLS_MPS_ERROR_H */ diff --git a/include/mbedtls/mps/layer1.h b/include/mbedtls/mps/layer1.h new file mode 100644 index 000000000000..d98d4ce6b37c --- /dev/null +++ b/include/mbedtls/mps/layer1.h @@ -0,0 +1,560 @@ +/** + * \file layer1.h + * + * \brief The buffering and datagram layer of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_BUFFER_LAYER_H +#define MBEDTLS_MPS_BUFFER_LAYER_H + +#include +#include + +#include "common.h" +#include "allocator.h" +#include "error.h" + +/* + * External interface to layer 0 + */ +typedef int mps_l0_recv_t( void* ctx, unsigned char *buf, size_t buflen ); +typedef int mps_l0_send_t( void* ctx, unsigned char const *buf, size_t buflen ); + +/* + * + * Structure definitions for datagram/stream implementations. + * + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +/* + * Stream-based implementation + */ + +/** Context maintaining the reading-side of a stream-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the read-buffer used by Layer 1. */ + + void *recv_ctx; /*!< The opaque context to be passed to the + * receive callback. This may be \c NULL. */ + mps_l0_recv_t *recv; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the data read from Layer 0 */ + mbedtls_mps_stored_size_t buf_len; /*!< The size of \c buf. */ + + /*! Total number of bytes read from the underlying transport so far. + * Must not be larger than \c buf_len. */ + mbedtls_mps_stored_size_t bytes_read; + + /*! Total number of bytes provided to the user at the last fetch call if + * that call was successful. If it failed, or if mps_l1_fetch() hasn't + * been called at all, this is \c 0. + * + * This field determines the read buffer in the abstract state of the + * Layer 1 context that the user has to keep in mind. + * + * Must not be larger than bytes_read. */ + mbedtls_mps_stored_size_t bytes_fetched; + +} mps_l1_stream_read; + +typedef enum +{ + MPS_L1_STREAM_STATUS_READY=0, + MPS_L1_STREAM_STATUS_FLUSH, + MPS_L1_STREAM_STATUS_WRITE +} mps_l1_stream_state; + +/* NOTE: The following struct allows to buffer outgoing data until a + * certain amount is ready. Alternatively, one might transfer + * any outgoing data to Layer 0 immediately once ready; this way, + * the fields bytes_written and flush wouldn't be needed. + */ + +/** Context maintaining the writing-side of a stream-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the write-buffer used by Layer 1. */ + + void *send_ctx; /*!< The opaque context to be passed to the + * send callback. This may be \c NULL. */ + mps_l0_send_t *send; /*!< The Layer 0 send callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the data to be + * passed to Layer 0 */ + mbedtls_mps_stored_size_t buf_len; /*!< The size of \c buf. */ + + /*! Number of bytes written and dispatched by the user. + * This must not be larger than buf_len. */ + mbedtls_mps_stored_size_t bytes_ready; + + /*! The number of bytes already transferred to Layer 0 during flushing. + * This is only used if status is MPS_L1_STREAM_STATUS_FLUSH; + * otherwise, its value is 0. + * This must not be larger than bytes_ready. */ + mbedtls_mps_stored_size_t bytes_written; + + /*!< Internal state: + * - L1_STREAM_STATUS_READY: + * Write-buffer can be requested, awaiting write call. + * - L1_STREAM_STATUS_FLUSH: + * Outgoing data is pending to be flushed to Layer 0 + * before write-buffer can be requested. + * - L1_STREAM_STATUS_WRITE: + * Write-buffer has been passed to the user, awaiting dispatch call. + */ + mps_l1_stream_state status; + +} mps_l1_stream_write; + +typedef struct +{ + mps_l1_stream_read rd; /*!< Reading-side of the Layer 1 context. */ + mps_l1_stream_write wr; /*!< Writing-side of the Layer 1 context. */ +} mps_l1_stream; + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Datagram-based implementation + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +/** Context maintaining the reading-side of a datagram-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the read-buffer used by Layer 1. */ + + void *recv_ctx; /*!< The opaque context to be passed to the + * receive callback. This may be \c NULL. */ + mps_l0_recv_t *recv; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the datagram received + * from the underlying Layer 0 transport. */ + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + + /*!< The current read-position within buf. */ + mbedtls_mps_stored_size_t window_base; + /*! The length of the fragment last handed out to the user in a call to + * mps_l1_fetch. If that call was unsuccessful, or if no such call has + * been made, the value is \c 0. */ + mbedtls_mps_stored_size_t window_len; + + + mbedtls_mps_stored_size_t msg_len; /*!< The size of the current datagram (or 0 + * if none has been fetched yet). */ + +} mps_l1_dgram_read; + +/** Context maintaining the writing-side of a datagram-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the write-buffer used by Layer 1. */ + + void *send_ctx; /*!< The opaque context to be passed to the + * send callback. This may be \c NULL. */ + mps_l0_send_t *send; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer wherein the outgoing data + * should be prepared. */ + + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + /*! Number of bytes written and dispatched by the user */ + mbedtls_mps_stored_size_t bytes_ready; + + uint8_t flush; /*!< Indicates if a flush is necessary before + * serving the next write request. */ + +} mps_l1_dgram_write; + +typedef struct +{ + mps_l1_dgram_read rd; + mps_l1_dgram_write wr; +} mps_l1_dgram; + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Generic implementation + */ +struct mps_l1 +{ + /* Selector for following union + * Valid values: + * - MPS_L1_MODE_STREAM + * - MPS_L1_MODE_DGRAM + */ +#if defined(MBEDTLS_MPS_PROTO_BOTH) + uint8_t mode; +#endif /* MBEDTLS_MPS_PROTO_BOTH */ + + union + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + mps_l1_stream stream; +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps_l1_dgram dgram; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + } raw; +}; +typedef struct mps_l1 mps_l1; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l1_get_mode( mps_l1 *l1 ) +{ + return( l1->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l1_get_mode( mps_l1 *l1 ) +{ + ((void) l1); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +/* + * + * Layer 1 interface + * + */ + +/** + * Allocator ID bits used when Layer 1 requests memory from the allocator. + * + * The base ID used a layer 1 context uses when interfacing with the underlying + * allocator is set in the mps_l1_init() function. This ID must always have its + * lowest bit cleared, allowing for the allocator to use different ID's + * for reading and writing by setting/clearing bit 0. + * + */ +#define MPS_L1_ALLOC_ID_MASK 0x1 +#define MPS_L1_ALLOC_BUFFER_READ 0 +#define MPS_L1_ALLOC_BUFFER_WRITE 1 + +/* + * Maintenance + */ + +#define MPS_L1_MODE_STREAM 0 /*!< Stream mode of operation */ +#define MPS_L1_MODE_DATAGRAM 1 /*!< Datagram mode of operation */ + +/** + * \brief Initialize a Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context to initialize. + * \param mode The mode of operation for the Layer 1 context. + * Possible values are: + * - #MPS_L1_MODE_STREAM, if the underlying Layer 0 + * transport is a stream transport. + * - #MPS_L1_MODE_DGRAM, if the underlying Layer 0 + * transport is a datagram transport. + * \param alloc The allocator context to use to acquire and release + * \param send_ctx The opaque context pointer to be passed to the + * sending function \p send. + * \param send The callback to the sending function of the underlying + * Layer 0 transport. + * \param recv_ctx The opaque context pointer to be passed to the + * receiving function \p recv. + * \param recv The callback to the receiving function of the underlying + * Layer 0 transport. + * + * \warning The preconditions listed below are *not* checked in + * a production build. The function's behavior is undefined + * if they are violated. + * + * \pre \p ctx must point to a writable ::mps_l1 instance; + * in particular, it must not be \c NULL. + * \pre \p mode must be either #MPS_L1_MODE_STREAM or + * #MPS_L1_MODE_STREAM. + * \pre \p alloc must point to an initalized allocator context. + * \pre \p send must be a valid function pointer; + * in particular, it must not be \c NULL. + * \pre \p recv must be a valid function pointer; + * in particular, it must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l1_init( mps_l1 *ctx, uint8_t mode, mps_alloc *alloc, + void* send_ctx, mps_l0_send_t *send, + void* recv_ctx, mps_l0_recv_t *recv ); + +/** + * \brief Set the callbacks to the underlying transport. + * + * \param ctx The pointer to the Layer 1 context to configure. + * \param send_ctx The opaque context pointer to be passed to the + * sending function \p send. + * \param send The callback to the sending function of the underlying + * Layer 0 transport. + * \param recv_ctx The opaque context pointer to be passed to the + * receiving function \p recv. + * \param recv The callback to the receiving function of the underlying + * Layer 0 transport. + * + * \warning The preconditions listed below are *not* checked in + * a production build. The function's behavior is undefined + * if they are violated. + * + * \pre \p ctx must point to a writable ::mps_l1 instance; + * in particular, it must not be \c NULL. + * \pre \p mode must be either #MPS_L1_MODE_STREAM or + * #MPS_L1_MODE_STREAM. + * \pre \p alloc must point to an initalized allocator context. + * \pre \p send must be a valid function pointer; + * in particular, it must not be \c NULL. + * \pre \p recv must be a valid function pointer; + * in particular, it must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l1_set_bio( mps_l1 *ctx, + void* send_ctx, mps_l0_send_t *send, + void* recv_ctx, mps_l0_recv_t *recv ); + +/** + * \brief Free a Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context to free. + * + * \pre \p ctx must point to a writable, initialized + * Layer 1 context. + * + */ +void mps_l1_free( mps_l1 *ctx ); + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/* + * Read interface + */ + +/** + * \brief Attempt to fetch some amount of data from Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context. + * \param buf Address to store the address of the + * incoming data buffer at. + * \param desired Amount of data to be fetched. + * + * \return \c 0 on success. In this case, \c *buf points to a + * buffer of size \p desired which is valid until the + * next call to mps_l1_consume() or mps_l1_stash(). + * \return #MPS_ERR_WANT_READ if not enough data is available on + * the underlying transport. In this case, the Layer 1 + * context remains intact, and the call should be repeated once + * more incoming data is ready on the underlying transport. + * \return Another negative error code on a different failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_fetch( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t desired ); + +/** + * \brief Mark the previously fetched data as consumed. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return 0 on success. + * \return A non-zero error code on failure. + * + * \warning All buffers previously obtained by calls to mps_l1_fetch() + * are invalid after this call and must not be accessed anymore. + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_consume( mps_l1 *ctx ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/** + * \brief Skip a message unit within a Layer 1 context. + * Discard the currently processed message unit. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 on success + * \return A negative error code on failure. + * + * \note This function is currently only meaningful for + * datagram-based Layer 1 contexts, in which case + * it should ignore the currently processed datagram. + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_skip( mps_l1 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Write interface + */ + +/** + * \brief Request a buffer to provide outgoing data in. + * + * \param ctx The pointer to the Layer 1 context. + * \param buf The address to store the address of the + * outgoing data buffer at. + * \param buflen The address to store the size of the + * outgoing data buffer at. + * + * \return \c 0 on success + * \return #MPS_ERR_WANT_WRITE if data is currently + * pending to be written but the underlying transport + * is not available, or another negative error code on + * different failure. + * + * \note If #MPS_ERR_WANT_WRITE is returned, the Layer 1 context + * remains intact, and the call should be repeated once + * the underlying transport is ready to send more data. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_write( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Dispatch data provided in the outgoing data buffer. + * + * \param ctx The pointer to the Layer 1 context. + * \param len The amount of data to dispatch. + * \param pending The number of bytes now pending to be delivered, + * including the bytes just dispatched. May be \c NULL + * if this information is not required. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + * + * \warning This function invalidates the buffers previously + * obtained from calls to mps_l1_write(). + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_dispatch( mps_l1 *ctx, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +/** + * \brief Deliver all previously dispatched data + * to the underlying transport. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if data is currently + * pending to be written but the underlying transport + * is not available, or another negative error code on + * different failure. + * + * \note If #MPS_ERR_WANT_WRITE is returned, the Layer 1 context + * remains intact, and the call should be repeated once + * the underlying transport is ready to send more data. + * + * \note If this function is called and returns #MPS_ERR_WANT_WRITE, + * subsequent calls to mps_l1_write() won't succeed until the + * flushing is complete. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_flush( mps_l1 *ctx ); + +/** + * \brief Check if a read request will necessarily involve + * interaction with the underlying transport. + * + * If no incoming data is buffered, a read request + * will necessarily involve the underlying transport, + * hence it is safe to wait with the call until + * it is available. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 if incoming data is buffered and the next + * read request will be attempted to be served from it. + * \return \c -1 if no incoming data is buffered and any read request + * will necessarily involve the underlying transport. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_read_dependency( mps_l1 *ctx ); + +/** + * \brief Check if a write request can be potentially be served + * without interaction with the underlying transport. + * + * \param ctx The pointer to the Layer 1 context. + * + * \note Layer 1 does never transfer dispatched data to the + * underlying transport immediately when mps_l1_dispatch() + * is called. Instead, it transfers it either when the + * user calls mps_l1_flush(), or on a subsequent call to + * mps_l1_write() which finds the internal output buffer + * exceeding an implementation-defined threshold. + * This function indicates if the latter might happen; + * if not, Layer 1 is guaranteed to be able to serve another + * write request via mps_l1_write() without transferring any + * data to the underlying transport first. + * + * \return \c 0 if a write request can potentially be served + * without involving the underlying transport. + * \return \c -1 if any write request will involve the underlying + * transport. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_write_dependency( mps_l1 *ctx ); + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT || + MBEDTLS_MPS_NO_STATIC_FUNCTIONS */ + +#endif /* MBEDTLS_MPS_BUFFER_LAYER_H */ diff --git a/include/mbedtls/mps/layer2.h b/include/mbedtls/mps/layer2.h new file mode 100644 index 000000000000..63820d7b4cac --- /dev/null +++ b/include/mbedtls/mps/layer2.h @@ -0,0 +1,1339 @@ +/** + * \file layer2.h + * + * \brief The record layer implementation of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_RECORD_LAYER_H +#define MBEDTLS_MPS_RECORD_LAYER_H + +#include "layer1.h" +#include "common.h" + +#include "reader.h" +#include "writer.h" + +#include "error.h" +#include "transform.h" + +#include + +/* + * Copied from existing headers -- remove when integrating MPS + */ + +#define MBEDTLS_SSL_MAJOR_VERSION_3 3 +#define MBEDTLS_SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define MBEDTLS_SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ +#define MBEDTLS_SSL_MINOR_VERSION_4 4 /*!< TLS v1.3 */ + +/* End of external copies to be removed later */ + +#define MBEDTLS_MPS_L2_VERSION_UNSPECIFIED 0x3f + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#define MBEDTLS_MPS_ANTI_REPLAY_DISABLED 0 +#define MBEDTLS_MPS_ANTI_REPLAY_ENABLED 1 +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#define MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR + +#if defined(MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING) +#define MBEDTLS_MPS_L2_NUM_SLOTS MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING +#else +#define MBEDTLS_MPS_L2_NUM_SLOTS 2 +#endif + +/*! The type of epoch usage flags */ +typedef uint8_t mbedtls_mps_epoch_usage; + +/*! This macro generates an epoch usage flag indicating + * that the epoch is needed for reading, for a specific + * reason that is encoded as an integral parameter. + * + * The prime example for this is the DTLS retransmission + * state machine: There's always the epoch of the next + * expected incoming message, but we must also detect + * retransmission of earlier messages, and potentially + * earlier epochs. The DTLS retransmission state machine + * can separate these usage reasons through this macro. + * + * Currently, only `0` and `1` are supported as values + * for `reason`. + */ +#define MPS_EPOCH_USAGE_READ_OFFSET 0 +#define MPS_EPOCH_USAGE_READ( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( \ + MPS_EPOCH_USAGE_READ_OFFSET + reason ) ) ) + +#define MPS_EPOCH_USAGE_WRITE_OFFSET 2 +#define MPS_EPOCH_USAGE_WRITE( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( \ + MPS_EPOCH_USAGE_WRITE_OFFSET + ( reason ) ) ) ) + +#define MPS_EPOCH_READ_MASK ( MPS_EPOCH_USAGE_READ( 0 ) | \ + MPS_EPOCH_USAGE_READ( 1 ) ) +#define MPS_EPOCH_WRITE_MASK ( MPS_EPOCH_USAGE_WRITE( 0 ) | \ + MPS_EPOCH_USAGE_WRITE( 1 ) ) + +#define MPS_EPOCH_USAGE_ALL ( MPS_EPOCH_READ_MASK | MPS_EPOCH_WRITE_MASK ) + +struct mbedtls_mps_l2; +typedef struct mbedtls_mps_l2 mbedtls_mps_l2; + +/** + * \brief Handle to incoming data of a specific content type and epoch. + */ +typedef struct +{ + /*! The type of the incoming data. It is entirely opaque to + * Layer 2, that is, no distinction is made between HS, App, + * CCS, or Alert records. */ + mbedtls_mps_stored_msg_type_t type; + /*!< The epoch through which the incoming data is protected. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *rd; /*!< The reader providing access to the + * incoming data. */ +} mps_l2_in; + +/** + * \brief Handle to outgoing data of a specific content type and epoch. + */ +typedef struct +{ + /*! The type of the outgoing data. It is entirely opaque to Layer 2, + * that is, no distinction is made between HS, App, CCS, + * or Alert records. */ + mbedtls_mps_stored_msg_type_t type; + /*!< The epoch through which the outgoing data will be protected. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_writer *wr; /*!< The writer providing access to the + * outgoing data buffers. */ +} mps_l2_out; + +/*! The type of states of readers managed by Layer 2. + * + * Possible values are: + * - #MBEDTLS_MPS_L2_READER_STATE_UNSET + * The reader does neither manage an incoming Layer 1 record buffer + * nor hold back any data for pausing. + * - #MBEDTLS_MPS_L2_READER_STATE_PAUSED + * The reader doesn't manage an incoming Layer 1 record buffer + * but holds back data for pausing. + * - #MBEDTLS_MPS_L2_READER_STATE_INTERNAL + * The reader manages an incoming Layer 1 record buffer + * but is currently not passed to the user. + * - #MBEDTLS_MPS_L2_READER_STATE_EXTERNAL + * The reader manages an incoming Layer 1 record + * buffer and is passed to the user. + */ +typedef uint8_t mbedtls_mps_l2_reader_state; +#define MBEDTLS_MPS_L2_READER_STATE_UNSET ( (mbedtls_mps_l2_reader_state) 0 ) +#define MBEDTLS_MPS_L2_READER_STATE_INTERNAL ( (mbedtls_mps_l2_reader_state) 1 ) +#define MBEDTLS_MPS_L2_READER_STATE_EXTERNAL ( (mbedtls_mps_l2_reader_state) 2 ) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_L2_READER_STATE_PAUSED ( (mbedtls_mps_l2_reader_state) 3 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/*! The type of state of writers manages by Layer 2. + * + * Possible values are: + * - #MBEDTLS_MPS_L2_WRITER_STATE_UNSET + * The writer does neither manage an outgoing Layer 1 record buffer + * nor hold back any queued data. + * - #MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL + * The writer manages an outgoing Layer 1 record buffer but + * is currently not passed to the user. + * - #MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL + * The writer manages an outgoing Layer 1 record buffer and + * has been passed to the user. + * - #MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING + * The writer doesn't manage an outgoing Layer 1 record buffer but + * has data queued for transmission (TLS only). + */ +typedef uint8_t mbedtls_mps_l2_writer_state; +#define MBEDTLS_MPS_L2_WRITER_STATE_UNSET ( (mbedtls_mps_l2_writer_state) 0 ) +#define MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ( (mbedtls_mps_l2_writer_state) 1 ) +#define MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL ( (mbedtls_mps_l2_writer_state) 2 ) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING ( (mbedtls_mps_l2_writer_state) 3 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Instances of this internal structure represent incoming + * data streams of varying content type and epoch. + */ +struct mbedtls_mps_l2_in_internal +{ + /*! The state of the stream. See ::mbedtls_mps_l2_reader_state + * for more information. */ + mbedtls_mps_l2_reader_state state; + /*! The record content type of the incoming data stream. */ + mbedtls_mps_stored_msg_type_t type; + /*! The epoch through which the data is secured. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The reader managing the incoming data after decryption. */ + mbedtls_mps_reader rd; +}; +typedef struct mbedtls_mps_l2_in_internal mbedtls_mps_l2_in_internal; + +/** + * \brief Instances of this L2-internal structure represent outgoing + * data streams of varying content type and epoch. + */ +struct mbedtls_mps_l2_out_internal +{ + /*! The record content type of the outgoing data stream. */ + mbedtls_mps_stored_msg_type_t type; + /*! The epoch through which the data is secured. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The writer managing the incoming data before encryption. */ + mbedtls_writer wr; +}; +typedef struct mbedtls_mps_l2_out_internal mbedtls_mps_l2_out_internal; + +/* These are constants from the standard and are NOT configurable. + * For the purpose of configuring the internal maximum record size, + * see the `max_plain_in/out` values in the Layer 2 configuration + * below, as well as the configuration of the allocator serving the + * internal record buffers. */ +#define TLS_MAX_PLAINTEXT_LEN 16384 +#define TLS_MAX_COMPRESSED_LEN_1_2 ( TLS_MAX_PLAINTEXT_LEN + 1024 ) +#define TLS_MAX_CIPHERTEXT_LEN_1_2 ( TLS_MAX_COMPRESSED_LEN_1_2 + 1024 ) +#define TLS_MAX_CIPHERTEXT_LEN_1_3 ( TLS_MAX_PLAINTEXT_LEN + 256 ) + +/** + * \brief This structure represents a (D)TLS connection state / epoch. + * + * It contains information about the current incoming and outgoing + * sequence numbers (including replay protection windows for DTLS) + * as well as the record protection mechanism to be used. + */ +struct mbedtls_mps_l2_epoch_t +{ + /*! Information about the usage of incoming and outgoing + * sequence numbers for this connection state. */ + union + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + struct + { + /*! The outgoing record sequence number + * + * This is the implicit record sequence number of + * the current or next outgoing record (depending + * on whether a record is currently open or not). + */ + uint32_t out_ctr[2]; + + /*! The incoming record sequence number. + * + * This is the implicit record sequence number of + * the current or next incoming record (depending + * on whether a record is currently open or not). + */ + uint32_t in_ctr[2]; + + } tls; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + struct + { + /*! The outgoing record sequence number + * + * This is the explicit record sequence number of + * the current or next outgoing record (depending + * on whether a record is currently open or not). + */ + uint32_t out_ctr[2]; + + /*! The record sequence number of the last valid record. + * + * This must be remembered because a server + * replying to a ClientHello with a HelloVerifyRequest + * must copy the record sequence number of the ClientHello: + * + * Quoting RFC 6347: + * In order to avoid sequence number duplication in case + * of multiple HelloVerifyRequests, the server MUST use + * the record sequence number in the ClientHello as + * the record sequence number in the HelloVerifyRequest. + */ + uint32_t last_seen[2]; + + /*! The replay protection window. */ + struct + { + /*! The top of the replay protection window, + * i.e. the highest validated record sequence + * number seen so far. */ + uint32_t in_window_top_hi; + uint32_t in_window_top_lo; + + /*! The bitmask indicating for which + * record sequence numbers in the interval + * [in_window_top-63, .., in_window_top] + * we have seen a valid record. */ + uint32_t in_window; + + } replay; + + } dtls; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + } stats; + + /*! The usage flags for the epoch. + * + * This comprises + * - user-specified read- and write-flags, + * - internal flags set by the implementation to keep + * track of the epochs usage. + * + * An epoch with no usage flags is considered unnecessary + * and is cleaned up by the epoch 'garbage collection'. + * + * For example: + * - The DTLS retransmission state machine might + * set read/write flags for an epoch because it's the currently + * used epoch, or it's an old epoch which however is still + * needed to detect or generate flight retransmissions. + * - The implementation might want to track that data is + * still pending to be written for some epoch, even if + * the user has already marked the epoch as no longer used. + */ + mbedtls_mps_epoch_usage usage; + + /*! The record protection to be applied to records of this epoch. + * A value of \c NULL represents the identity transform. */ + mbedtls_mps_transform_t *transform; + +}; +typedef struct mbedtls_mps_l2_epoch_t mbedtls_mps_l2_epoch_t; + +/** + * \brief This structure contains the configuration parameters + * for a Layer 2 instance. + */ +struct mbedtls_mps_l2_config +{ + mps_l1 *l1; /*!< The underlying buffering / datagram layer. */ + +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; /*!< This specifies whether the Layer 2 instance + * the TLS (0) or DTLS (1) record protocol. */ +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + uint8_t version; /*!< This field indicates the TLS/DTLS version + * the Layer 2 instance uses. + * + * This field may initially be unspecified, in + * which case multiple [D]TLS versions can be + * received until the exact [D]TLS version has + * been agreed upon. */ +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) + uint8_t anti_replay; /*!< This field indicates whether anti replay + * protection should be applied (DTLS only). + * Possible values are: + * - #MBEDTLS_MPS_L2_ANTI_REPLAY_DISABLED + * - #MBEDTLS_MPS_L2_ANTI_REPLAY_ENABLED. + */ +#endif /* MBEDTLS_MPS_CONF_ANTI_REPLAY */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) + /*! The maximum length of record plaintext (including inner plaintext + * header and padding in TLS 1.3) of outgoing records. */ + mbedtls_mps_stored_size_t max_plain_out; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) + /*! The Maximum length of record plaintext (including inner plaintext + * header and padding in TLS 1.3) of incoming records. */ + mbedtls_mps_stored_size_t max_plain_in; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) + mbedtls_mps_stored_size_t max_cipher_in; +#endif /* MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) + /* The following members are bitflags indexed by record types in + * the range of 0 .. 31. Record content types >= 32 are not used + * and considered invalid. */ + uint32_t type_flag; /*!< This member indicates which record content + * type ID's the Layer 2 instance should allow. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * Incoming record of invalid record content + * types, or attempts to send data of invalid + * content types, are reported through the error + * code MBEDTLS_ERR_MPS_INVALID_RECORD. */ +#endif /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + uint32_t pause_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * merging contents of multiple incoming records + * of the same record content type. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + uint32_t merge_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * multiple messages (that is, data written by + * the user between two calls of mps_l2_write_start + * and mps_l2_write_end) to be merged within + * the same record. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + uint32_t empty_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * empty records to be sent and received. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * empty records of content type ID n is allowed. + * This must be a sub-field of \p type_flag. + * If empty records are not allowed, requests + * to send them will be silently ignored, while + * incoming empty records are treated as errors. */ +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) + uint32_t ignore_flag; /*!< This member defines the record content types + * which the Layer 2 instance will silently ignore. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * empty records of content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + + /* Notes: + * - Both record size limit values are usually negotiated with + * either the maximum_fragment_length extension or the new + * record_size_limit extension. + * - Both limits must not exceed the default value of + * TLS_MAX_CONTENT_LEN == 16384. + * - The values configured here are entirely independent of + * the sizes of the internal buffers the implementation uses + * to hold records! These are owned by Layer 1 and obtained + * from the allocator, and it is the responsibility of the + * code orchestrating the various layers to ensure that their + * respective thresholds are in sync. + */ + + int (*f_rng)( void *, unsigned char *, + size_t ); /*!< A PRNG function. + * May be \c NULL if the record protection + * mechanism used by the Layer 2 instance + * doesn't need random number generation. */ + void *p_rng; /*!< A PRNG context for use with \c f_rng. + * May be \c NULL if \c f_rng is \c NULL or + * if no context information is needed by + * the PRNG, or is stored elsewhere. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) + uint32_t badmac_limit; /*!< Determines how many records with bad MAC + * are silently tolerated before an error + * is raised. Possible values are: + * - \c 0: Records with bad MAC are always + * tolerated. + * - \c n greater \c 0: The n-th record + * with a bad MAC will lead to an error. + */ +#endif /* MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* TLS-1.3-NOTE: A boolean flag needs to be added to indicate whether + * Layer 2 should silently discard records that cannot + * be authenticated. This is necessary to ignore EarlyData + * if the server doesn't support it. */ + +}; +typedef struct mbedtls_mps_l2_config mbedtls_mps_l2_config; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l2_conf_get_mode( mbedtls_mps_l2_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l2_conf_get_mode( mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) +static inline +uint8_t mbedtls_mps_l2_conf_get_version( mbedtls_mps_l2_config *conf ) +{ + return( conf->version ); +} +#else /* !MBEDTLS_MPS_CONF_VERSION */ +static inline +uint8_t mbedtls_mps_l2_conf_get_version( mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_VERSION ); +} +#endif /* MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) +static inline uint8_t mbedtls_mps_l2_conf_get_anti_replay( + mbedtls_mps_l2_config *conf ) +{ + return( conf->anti_replay ); +} +#else /* !MBEDTLS_MPS_CONF_ANTI_REPLAY */ +static inline uint8_t mbedtls_mps_l2_conf_get_anti_replay( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_ANTI_REPLAY ); +} +#endif /* MBEDTLS_MPS_CONF_ANTI_REPLAY */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_out( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_plain_out ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_out( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_PLAIN_OUT ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_in( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_plain_in ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_in( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_PLAIN_IN ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_cipher_in( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_cipher_in ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_cipher_in( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_CIPHER_IN ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_type_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->type_flag ); +} +#else /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_type_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_TYPE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_pause_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->pause_flag ); +} +#else /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_pause_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_PAUSE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_merge_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->merge_flag ); +} +#else /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_merge_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MERGE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_empty_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->empty_flag ); +} +#else /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_empty_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_EMPTY_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_ignore_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->ignore_flag ); +} +#else /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_ignore_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_IGNORE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) +static inline uint32_t mbedtls_mps_l2_conf_get_badmac_limit( + mbedtls_mps_l2_config *conf ) +{ + return( conf->badmac_limit ); +} +#else /* !MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +static inline uint32_t mbedtls_mps_l2_conf_get_badmac_limit( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_BADMAC_LIMIT ); +} +#endif /* MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/** + * \brief The context structure for Layer 2 instance. + */ +struct mbedtls_mps_l2 +{ + /*! The configuration of the Layer 2 instance. */ + mbedtls_mps_l2_config conf; + + /** + * \brief The substructure holding all data related + * to outgoing records. + */ + struct + { + struct + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + /*! The queue for outgoing data of pausable record content types. */ + unsigned char *queue; + /*! The size of the queue in Bytes. */ + mbedtls_mps_stored_size_t queue_len; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /** This variable indicates if preparation of a new outgoing record + * must be preceded by a flush on the underlying Layer 1 first. + * + * The rationale for having this as a separate field as opposed + * to triggering the flush immediately once the necessity arises + * is that it allows the user to be in control of which Layer 2 API + * calls will require interfacing with the underlying transport. */ + uint8_t clearing; + + /** This variable indicates if all pending outgoing data + * needs to be flushed before the next write can happen. + * + * This flag cannot be set while serving a write request. */ + uint8_t flush; + + /* Further explanation on the meaning and difference + * between `flush` and `clearing`: + * + * The `flush` state lives at a higher level than `clearing`: + * If `flush` is set, Layer 2 must make sure that everything + * that has been dispatched by the user is delivered before + * the writing can continue. Internally, this splits into ... + * (1) ... the data that has been dispatched by the user + * but which Layer 2 didn't yet dispatch to Layer 1, + * e.g. because Layer 2 waiting to see if it can put + * more data in the present record. + * (2) ... the data that has been dispatched to Layer 1, but + * which Layer 1 might not yet have flushed. + * Handling the `flush` state means dispatching the pending + * data of type (1) first, ensuring that nothing of type (1) + * is left, and then calling a flush on Layer 1 to handle + * the data of type (2). + * + * In contrast, `clearing` solely deals with the data + * of type (2): If it is set, the data of type (2) must + * be flushed before any progress on writing can be made. + * + * Handling `flush` is done by dispatching the data of type (1) + * to Layer 1, and then setting `clearing` to ensure the handling + * of data of type (2) through a flush. If no progress can be + * made on the clearing of (1) because Layer 1 is out of writing + * space, `clearing` needs to be set in order to flush Layer 1 + * first, emptying (2), before the processing of type (1) data + * can continue. This flow is implemented in l2_clear_pending(). + * + */ + + /* Layer 2 manages two types of data related to outgoing records: + * + * 1) The raw buffers holding the header, plaintext and ciphertext + * of the current outgoing record. They are internal and never + * passed to the user. + * The relevant fields are `hdr`, `hdr_len` and `payload` + * and they are explained in more detail below. + * + * 2) The structure `writer` representing the ongoing write from + * the perspective of the user, consisting of an epoch, + * a record content type and a writer object. + * + * The basic states during writing are the following: + * 1. Initially,and whenever no outgoing record has been prepared, + * hdr, hdr_len and payload are unset, as is the writer. + * 2. After preparing an outgoing record, hdr and payload are + * set up with buffers from Layer 1, while the writer is UNSET. + * 3. The writer manages `payload` and is in INTERNAL state, + * indicating that is hasn't yet been provided to the user. + * 4. The writer manages `payload` and is in EXTERNAL state, + * indicating that is has been provided to the user who then can + * use the writer API to provide the record contents. + * + * State 2 is not visible at the API boundary, but used internally + * as an intermediate step when transitioning between the states, + * which is done by the following functions: + * + * - l2_out_prepare_record transitions from state 1 to 2. + * - l2_out_dispatch_record transitions from state 2 to 1. + * - l2_out_track_record transitions from state 2 to 3. + * - l2_out_release_record transitions from 3 to 2. + */ + + /* Once an outgoing record has been prepared, we're maintaining + * three buffers: + * 1. The header buffer, holding the record header in the end. + * 2. The content buffer, holding the plaintext or ciphertext, + * depending on the state of encryption. + * 3. The work buffer, surrounding the plaintext/ciphertext buffer. + * + * The concatenation of header buffer and the work buffer is the + * write buffer obtained from the underlying Layer 1 instance. + * + * During record encryption, the content buffer grows within the + * work buffer due to the addition of MAC, IV, or the inner + * plaintext record header in case of TLS 1.3. The offset of the + * content buffer from the work buffer should be zero after + * encryption, and is chosen during record preparation to ensure + * this property. + * + * +-----------+---------------------------------------------------+ + * | | +------------------------+ | + * | header | | plaintext / ciphertext | | + * | | +------------------------+ | + * | | \__ payload.data_len __/ | + * | | payload.data_offset | + * | |---------------------| | + * +-----------+---------------------------------------------------+ + * hdr payload.buf + * \_ hdr_len _/\______________ payload.buf_len ___________________/ + * + */ + + /** The address of the header of the current outgoing record, + * or \c NULL if there is no such. */ + /* OPTIMIZATION: + * This is the same as the buffer obtained from + * Layer 1. Consider removing this reference + * and querying Layer 1 when it's needed instead. */ + unsigned char *hdr; + /** The length of the header buffer pointed to by \c hdr. */ + /* OPTIMIZATION: + * This can be inferred from the epoch through l2_get_header_len(). + * Consider removing this field. */ + mbedtls_mps_stored_size_t hdr_len; + + /** The buffer pair consisting of content buffer + * (plaintext or ciphertext) and work buffer. */ + /* OPTIMIZATION: + * This has overlap with \c hdr: the outer buffer in the + * \c payload buffer pair always starts at `hdr + hdr_len`. + * Consider removing this redundancy provided (?) it's possible + * to do so without sacrificing structure and clarity of the code. */ + mps_l2_bufpair payload; + + /** The structure through which the content type, the epoch + * and the state of plaintext writing of the current outgoing + * record is tracked. */ + /* OPTIMIZATION: + * The fragment managed by the writer the inner + * buffer in the \c payload buffer pair before + * encryption. Consider removing this redundancy + * provided (?) it's possible to do so without + * sacrificing structure and clarity of the code. */ + mbedtls_mps_l2_out_internal writer; + + /** The state of the \c writer field. See the documentation of + * l2_writer_state for more information. */ + mbedtls_mps_l2_writer_state state; + + } out; + + /** + * \brief The substructure holding all data related to incoming records. + */ + + /* OPTIMIZATION: + * Consider making reading and writing mutually exclusive and using + * a union for store the incoming and outgoing data structures. + * Together with the corresponding changes in the other layers, this + * might save a significant amount of RAM. + */ + struct + { + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /*! The accumulator for incoming data of pausable + * record content types. */ + unsigned char *accumulator; + /*! The size of the accumulator in Bytes.*/ + mbedtls_mps_stored_size_t acc_len; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /* Note: In contrast to the write-side, the read-side of Layer 2 does + * not remember the raw record buffers obtained from Layer 1 as they + * can be handled on the stack when a new record is fetched. */ + + /** The current Layer 2 implementation uses a configurable + * array of readers to handle the incoming record contents. + * See MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING for more details. + * + * The Layer 2 implementation does never use this array directly, + * but only through the following internal interface: + * - mps_l2_readers_init + * - mps_l2_readers_free + * - mps_l2_readers_active_state + * - mps_l2_readers_get_active + * - mps_l2_readers_pause_active + * - mps_l2_find_suitable_slot + */ + mbedtls_mps_l2_in_internal slots[ MBEDTLS_MPS_L2_NUM_SLOTS ]; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + uint32_t bad_mac_ctr; /* The number of records with bad MAC that + * have been received so far. DTLS only. */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + } in; + + } io; + + /** + * \brief The substructure holding all data related + * to connection states / epochs. + */ + struct + { + /* Layer 2 maintains an window of epochs indexed by + * epoch ID's. The base-ID of the window is stored in \c base, and + * the actual (offset-indexed) array of epochs is stored in `window`. + * There should never be more than 2 epochs in simultaneous use, so a + * window size of 2 should do, but the larger flexibility comes without + * cost and allows to test if, indeed, despite of the large number + * of epochs in [D]TLS 1.3, never more than two are used at once. */ + + /*! The first epoch ID within the current epoch window. */ + mbedtls_mps_stored_epoch_id base; + + /* The offset of the next free epoch slot. */ + mbedtls_mps_epoch_offset_t next; + +#if defined(MBEDTLS_MPS_PROTO_TLS) + mbedtls_mps_stored_epoch_id default_in; + mbedtls_mps_stored_epoch_id default_out; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /*! The window of connection states for the epochs of ID + * base, ..., base + + * MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE - 1. */ + mbedtls_mps_l2_epoch_t window[ MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ]; + + + } epochs; +}; + +static inline mps_l1* mbedtls_mps_l2_get_l1( mbedtls_mps_l2 *l2 ) +{ + return( l2->conf.l1 ); +} + +/** + * \brief This function initializes a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to initialize. + * \param l1 The address of an initialized Layer 1 context + * to use for reading/writing data. + * \param mode The mode of operation for the Layer 2 context. + * Either #MPS_L2_MODE_STREAM if the underlying Layer 0 + * transport is a stream transport, or #MPS_L2_MODE_DATAGRAM + * if the underlying Layer 0 transport is a datagram transport. + * \param max_read The maximum number of bytes that the user can request + * to read between two consecutive read-commits such that + * Layer 2 still guarantees progress. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but Layer 2 doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_READER_OUT_OF_DATA or + * #MPS_ERR_WANT_READ error code while reading, closing + * and reopening the read-port in this case must eventually + * lead to success, provided enough data is (eventually) + * available on the underlying transport. + * This TLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented incoming data himself. + * \param max_write The maximum number of bytes that the user can request + * to write between two consecutive write-commits such that + * Layer 2 still guarantees progress. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but Layer 2 doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_WRITER_OUT_OF_DATA or + * #MPS_ERR_WANT_WRITE error code while writing, closing + * and reopening the write-port in this case must eventually + * lead to success, provided the underlying transport + * is (eventually) available to send the request amount + * of data. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented outgoing data himself. + * This TLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * \param f_rng The PRNG to use for record protection. + * \param p_rng The PRNG context to use \p f_rng with. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ + +int mps_l2_init( mbedtls_mps_l2 *ctx, mps_l1 *l1, uint8_t mode, + mbedtls_mps_size_t max_read, + mbedtls_mps_size_t max_write, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This functions frees a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l2_free( mbedtls_mps_l2 *ctx ); + +typedef uint8_t mbedtls_mps_record_split_config_t; +#define MBEDTLS_MPS_SPLIT_DISABLED ( (mbedtls_mps_record_split_config_t) 0 ) +#define MBEDTLS_MPS_SPLIT_ENABLED ( (mbedtls_mps_record_split_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_pack_config_t; +#define MBEDTLS_MPS_PACK_DISABLED ( (mbedtls_mps_record_pack_config_t) 0 ) +#define MBEDTLS_MPS_PACK_ENABLED ( (mbedtls_mps_record_pack_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_empty_config_t; +#define MBEDTLS_MPS_EMPTY_FORBIDDEN ( (mbedtls_mps_record_empty_config_t) 0 ) +#define MBEDTLS_MPS_EMPTY_ALLOWED ( (mbedtls_mps_record_empty_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_ignore_config_t; +#define MBEDTLS_MPS_IGNORE_KEEP ( (mbedtls_mps_record_ignore_config_t) 0 ) +#define MBEDTLS_MPS_IGNORE_DROP ( (mbedtls_mps_record_ignore_config_t) 1 ) + +/** + * \brief Configure Layer 2 context to accept records + * of a given record content type. + * + * This function must only be called exactly once + * for each record content type to be used. + * + * \param ctx The address of the Layer 2 context to use. + * \param type The record content type to configure. + * \param pausing This parameter indicates whether content of type + * \p type is allowed to be split across multiple records + * (value #MBEDTLS_MPS_SPLIT_ENABLED) or not + * (value #MBEDTLS_MPS_SPLIT_DISABLED). + * E.g., handshake messages are allowed to be + * split across multiple records in all versions of TLS, + * while in TLS 1.3 alert messages must not be split. + * See the documentation of the \c pause_flag + * member of ::mps_l2_config for more information. + * \param merging This parameter indicates whether successive read/write + * requests for content type \p type is allowed to be served + * from the same record (value #MBEDTLS_MPS_PACK_ENABLED) or not + * (value #MBEDTLS_MPS_PACK_DISABLED). + * E.g., multiple handshake messages are allowed to be packed + * in the same record in all versions of TLS, while in TLS 1.3 + * a single record must not contain multiple alert messages. + * See the documentation of \c merge_flag + * member of ::mps_l2_config for more information. + * \param empty This parameter indicates whether empty records of content + * type \p type are allowed to be sent + * (value #MBEDTLS_MPS_EMPTY_ALLOWED) or not + * (value #MBEDTLS_MPS_EMPTY_DISCARD). + * See the documentation of \c empty_flag + * member of ::mps_l2_config for more information. + * \param ignore This parameter indicates whether incoming records of + * content type \p type should be silently ignored. + * (value #MBEDTLS_MPS_IGNORE_DROP) or not + * (value #MBEDTLS_MPS_IGNORE_KEEP). + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +static inline int mps_l2_config_add_type( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_record_split_config_t pausing, + mbedtls_mps_record_pack_config_t merging, + mbedtls_mps_record_empty_config_t empty, + mbedtls_mps_record_empty_config_t ignore ) +{ + uint32_t mask; + + if( type >= MBEDTLS_MPS_MSG_MAX ) + return( MBEDTLS_ERR_MPS_INVALID_RECORD ); + +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + mask = ( (uint32_t) 1u << type ); + if( mbedtls_mps_l2_conf_get_type_flag( &ctx->conf ) & mask ) + return( MBEDTLS_ERR_MPS_INVALID_ARGS ); + + ctx->conf.type_flag |= mask; +#else + ((void) mask); +#endif /* MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + ctx->conf.pause_flag |= ( pausing == MBEDTLS_MPS_SPLIT_ENABLED ) * mask; +#endif /* MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#else + ((void) pausing); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + ctx->conf.merge_flag |= ( merging == MBEDTLS_MPS_PACK_ENABLED ) * mask; +#endif /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + ctx->conf.empty_flag |= ( empty == MBEDTLS_MPS_EMPTY_ALLOWED ) * mask; +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) + ctx->conf.ignore_flag |= ( ignore == MBEDTLS_MPS_IGNORE_DROP ) * mask; +#endif /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + return( 0 ); +} + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/** + * \brief Configure the TLS/DTLS version to be used + * by a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to use. + * \param version The TLS or DTLS version to use. + * TODO: Name the allowed values + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ + +int mps_l2_config_version( mbedtls_mps_l2 *ctx, uint8_t version ); + +/** + * \brief Query a Layer 2 context for incoming data. + * + * \param ctx The address of the Layer 2 context to use. + * \param in The address at which to store type, epoch + * and content information of the incoming + * data on success. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_READ if no data is + * available on the underlying transport. + * In this case, the context remains usable, and + * the user should call the function again at a + * later stage (either in a loop or event-driven). + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_read_start( mbedtls_mps_l2 *ctx, mps_l2_in *in ); + +/** + * \brief Signal that incoming data previously + * obtained from mps_l2_read_start() has + * been fully processed. + * + * \param ctx The address of the Layer 2 context to use. + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_read_done( mbedtls_mps_l2 *ctx ); + +/** + * \brief Request to prepare the writing of data of + * given record content type and epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param out The partially filled outgoing data context + * to use. The \c type and \c epoch fields must + * be set by the user and are left unchanged + * by this function; the \c wr field is set to + * the address of a writer object that can be + * used to write the record contents on success. + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_start( mbedtls_mps_l2 *ctx, mps_l2_out *out ); + +/** + * \brief Signal that the writing of outgoing data via + * the handle obtained from mps_l2_write_start() + * is done. + * + * \param ctx The address of the Layer 2 context to use. + * + * \note This function does not guarantee that the + * data is immediately delivered to the underlying + * transport. To ensure this, the user must + * call mps_l2_write_flush(). + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_done( mbedtls_mps_l2 *ctx ); + +/** + * \brief Attempt to deliver all outgoing data previously + * dispatched via calls to mps_l2_write_done() + * to the underlying transport. + * + * \param ctx The address of the Layer 2 context to use. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if the underlying transport + * was not ready to send all pending outgoing data. + * In this case, the function should be called + * again until it succeeds. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_flush( mbedtls_mps_l2 *ctx ); + +/** + * \brief Configure Layer 2 context to allow communication + * with a given epoch and set the payload protection + * through which the communication should be secured. + * + * \param ctx The Layer 2 context to use. + * \param transform The context defining the payload protection to apply + * for epoch \p epoch. This is a context processed + * by the \c transform_xxx functions. + * Currently, \p transform must be heap-allocated, + * and this call transfers ownership entirely to + * the Layer 2 context. In particular, no read, write + * or deallocation operation must be performed on + * \p transform by the user after this function has + * been called. This leads to the following asymmetric + * control-flow: + * 1. User allocates an ::mbedtls_mps_transform_t instance + * from the heap. + * 2. User initializes and configures the instance. + * 3. User binds the instance to an epoch ID via + * mps_l2_epoch_add(), thereby transferring the + * ownership to Layer 2. + * 4. Layer 2 maintains the transformation and destroys + * and frees it once it becomes unused or the Layer 2 + * context is destroyed through a call to mps_l2_free(). + * This is analogous to passing a unique_pointer via + * move-semantics in C++. + * \param epoch The address to which to write the identifier for + * the keying material on success. + * + * \note In case of TLS, this function modifies the incoming + * epoch ID or the outgoing epoch ID, or both (depending + * on the value of \p usage). + * + * \note Another copy-less alternative would be to + * have the user query Layer 2 for space for a + * fresh ::mbedtls_mps_transform_t instance to be used + * with a to-be-registered epoch ID, and to have an + * API call to Layer 2 to signal when the preparation + * is done and the epoch should become active. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_epoch_add( mbedtls_mps_l2 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ); + +/** + * \brief Modify the usage configuration for a previously added epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to configure. + * \param clear The usage flags to clear. + * \param set The usage flags to set. + * + * \note In case of TLS, this function modifies the incoming + * epoch ID or the outgoing epoch ID, or both (depending + * on the value of \p usage). + * + * \return \c 0 on success. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_epoch_usage( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/** + * \brief Enforce that the next outgoing record of the + * specified epoch uses a particular record sequence number. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to configure. + * \param ctr The record sequence number to be used for the + * next outgoing record of epoch \p epoch_id. + * + * \note This function constitutes an abstraction break + * but is enforced by the following requirement from RFC 6347: + * Upon receipt of the ServerHello, the client MUST verify + * that the server version values match. In order to avoid + * sequence number duplication in case of multiple + * HelloVerifyRequests, the server MUST use the record + * sequence number in the ClientHello as the record sequence + * number in the HelloVerifyRequest. + * + * \return \c 0 on success. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_force_next_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ); + +/** + * \brief Get the sequence number of last incoming record + * protected with a given epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to use. + * \param ctr The address to write the sequence number of the + * last incoming record of epoch \p epoch_id to. + * + * \note This function constitutes an abstraction break + * but is enforced by the following requirement from RFC 6347: + * Upon receipt of the ServerHello, the client MUST verify + * that the server version values match. In order to avoid + * sequence number duplication in case of multiple + * HelloVerifyRequests, the server MUST use the record + * sequence number in the ClientHello as the record sequence + * number in the HelloVerifyRequest. + * + * \return \c 0 on success. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_get_last_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ + +#endif /* MBEDTLS_MPS_RECORD_LAYER_H */ diff --git a/include/mbedtls/mps/layer3.h b/include/mbedtls/mps/layer3.h new file mode 100644 index 000000000000..69e78fe97196 --- /dev/null +++ b/include/mbedtls/mps/layer3.h @@ -0,0 +1,831 @@ +/** + * \file layer3.h + * + * \brief The message extraction layer of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H +#define MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H + +#include + +#include "reader.h" +#include "writer.h" + +#include "layer2.h" +#include "common.h" + +#include "transform.h" +#include "error.h" + +/* + * Layer 3 compile-time configuration + */ + +/** + * \def MPS_L3_ALLOW_INTERLEAVED_SENDING + * + * If this macro is set, Layer 3 can be configured to allow + * interleaving of records when sending messages of different + * types. + * + * For example, the writing of a long handshake message split + * across multiple records could this way be interleaved with + * an ApplicationData record. + * + * Uncomment to allow interleaving of messages of different types. + * + */ +#define MPS_L3_ALLOW_INTERLEAVED_SENDING + +struct mps_l3; +struct mps_l3_handshake_in; +struct mps_l3_handshake_out; +struct mps_l3_hs_in_internal; +struct mps_l3_hs_out_internal; +struct mps_l3_alert_in; +struct mps_l3_alert_in_internal; +struct mps_l3_alert_out; +struct mps_l3_app_in; +struct mps_l3_app_out; +struct mps_l3_ccs_in; +struct mps_l3_ccs_out; + +typedef struct mps_l3 mps_l3; +typedef struct mps_l3_handshake_in mps_l3_handshake_in; +typedef struct mps_l3_handshake_out mps_l3_handshake_out; +typedef struct mps_l3_hs_in_internal mps_l3_hs_in_internal; +typedef struct mps_l3_hs_out_internal mps_l3_hs_out_internal; +typedef struct mps_l3_alert_in mps_l3_alert_in; +typedef struct mps_l3_alert_in_internal mps_l3_alert_in_internal; +typedef struct mps_l3_alert_out mps_l3_alert_out; +typedef struct mps_l3_app_in mps_l3_app_in; +typedef struct mps_l3_app_out mps_l3_app_out; +typedef struct mps_l3_ccs_in mps_l3_ccs_in; +typedef struct mps_l3_ccs_out mps_l3_ccs_out; + +typedef enum mps_l3_hs_state +{ + MPS_L3_HS_NONE=0, /*!< No handshake message is currently + * active or paused. */ + MPS_L3_HS_ACTIVE, /*!< A handshake message is currently open + * for reading/writing. */ + MPS_L3_HS_PAUSED /*!< The reading/writing of a handshake + * message has commenced but been paused. */ +} mps_l3_hs_state; + +/** + * \brief This structure represents handles to outgoing handshake messages. + * + * It is used in the following way: When users want to prepare + * an outgoing handshake message, they create an instance of this + * structure and set fields indicating the intended epoch, + * handshake type, and handshake message length. They then call + * mps_l3_write_handshake() which, on success, sets the \c wr + * within this struct to point to a valid writer that can be used + * to provide the actual message contents. + * + * When the writing is done, users call mps_l3_dispatch() to prepare + * the message for delivery; if the writing cannot be completed + * because the provided writer does not provide enough space for + * outgoing data, the write can be paused via mps_l3_pause_handshake() + * and subsequently be continued via another call to + * mps_l3_write_handshake() which must use the the same epoch, + * handshake type and length parameters as the initial one. + * + * The handshake message length must be known in advance if pausing + * is needed for the message. If pausing is not needed, the length + * field can be set to #MBEDTLS_MPS_SIZE_UNKNOWN and will be be + * determined automatically on closing. + */ +struct mps_l3_handshake_out +{ + /*! The total length of the handshake message (regardless of fragmentation), + * or #MBEDTLS_MPS_SIZE_UNKNOWN if the length will be determined at + * write-time. In this case, pausing is not possible for the handshake + * message (because the headers for handshake fragments include the total + * length of the handshake message). This must be set by the user + * before calling mps_l3_write_handshake(). */ + mbedtls_mps_stored_opt_size_t len; + + /*! The epoch to use to protect the handshake message. + * This must be set by the user before calling mps_l3_write_handshake(). */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake message type. This must be set by + * the user before calling mps_l3_write_handshake().*/ + mbedtls_mps_stored_hs_type type; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + /*! The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from the + * beginning of the handshake message.*/ + mbedtls_mps_stored_size_t frag_offset; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /*! The writer providing buffers to which the message + * contents can be written, and keeping track of message bounds. + * This must be \c NULL when the user calls mps_l3_write_handshake(), which + * will modify it to point to a valid writer on success. */ + mbedtls_writer *wr; +}; + +/** + * \brief This structure represents handles to + * incoming handshake messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * a handshake message has been received (by returning + * #MBEDTLS_MPS_MSG_HS), mps_l3_read_handshake() will + * provide an instance of this structure giving access + * to the epoch, the handshake type, the total length + * of the received handshake message, as well as a reader + * providing access to the handshake message contents. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). If the reader within this + * structure cannot provide enough data to finish the + * processing of the handshake message, the user should + * call mps_l3_pause_handshake() to temporaily suspend + * the reading. The next successful call to mps_l3_read() + * returning #MBEDTLS_MPS_MSG_HS is then guaranteed + * to yield a handle that can be used to continue the + * processing at the stage where the initial call stopped + * (determined by the last call to mps_l3_reader_commit_ext()). + * + */ +struct mps_l3_handshake_in +{ + /*! The epoch used to protect the handshake message.*/ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation). */ + mbedtls_mps_stored_size_t len; + + /*! The length of the current handshake fragment. */ + mbedtls_mps_stored_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*! The handshake sequence number.*/ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*!< The reader giving access to the message contents. */ + mbedtls_mps_reader *rd; +}; + +/** + * \brief This structure represents handles to + * incoming alert messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * a handshake message has been received (by returning + * #MBEDTLS_MPS_MSG_ALERT), mps_l3_read_alert() will + * provide an instance of this structure giving access + * to the epoch, alert type and alert level. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + */ +struct mps_l3_alert_in +{ + /*! The epoch used to protect the alert. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The level of the incoming alert. */ + uint8_t level; + /*! The type of the incoming alert. */ + uint8_t type; +}; + +struct mps_l3_alert_out +{ + /*! The epoch to use to protect the alert message. Set by user. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The level of the incoming alert. */ + uint8_t *level; + /*! The type of the incoming alert. */ + uint8_t *type; +}; + +/** + * \brief This structure represents handles to + * incoming application data messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * application data has been received (by returning + * #MBEDTLS_MPS_MSG_APP), mps_l3_read_app() will + * provide an instance of this structure giving access + * to the epoch as well as a reader giving rise to the + * actual data. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + */ +struct mps_l3_app_in +{ + /*! The epoch used to protect the application data. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *rd; +}; + +struct mps_l3_app_out +{ + /*! The epoch used to protect the application data. Set by the user. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_writer *wr; /*!< The writer to use to supply the + * actual application data. Set by MPS. */ +}; + +/** + * \brief This structure represents handles to + * incoming ChangeCipherSpec (CCS) messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * application data has been received (by returning + * #MBEDTLS_MPS_MSG_CCS), mps_l3_read_app() will provide + * an instance of this structure giving access to the epoch + * used for the CCS message. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + * \note Currently, Layer 3 validates the static single-byte content + * of CCS messages and returns an error code from mps_l3_read() + * if it doesn't match the value MPS_TLS_CCS_VALUE prescribed + * by the standard. We might want to revise this, leaving all + * content validation to Layer 4. + * + */ +struct mps_l3_ccs_in +{ + /*! The epoch used to protect the ChangeCipherSpec message. */ + mbedtls_mps_stored_epoch_id epoch; +}; + +struct mps_l3_ccs_out +{ + /*!< The epoch to use to protect the CCS message. Set by the user. */ + mbedtls_mps_stored_epoch_id epoch; +}; + +/* + * Internal siblings for the structures used by the Layer 3 API. + */ + +struct mps_l3_hs_in_internal +{ + /*!< The epoch used to protect the handshake message. */ + mbedtls_mps_stored_epoch_id epoch; + mps_l3_hs_state state; /*!< Indicates if the incoming message + * is currently being paused or not. */ + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation). */ + mbedtls_mps_stored_size_t len; + + /* DTLS-specific fields. */ + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of f the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*!< The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; +}; + +struct mps_l3_hs_out_internal +{ + /*!< The epoch used to protect the handshake message. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! Indicates if the outgoing message is currently being paused or not. */ + mps_l3_hs_state state; + + /*! The handshake message type. */ + + /* OPTIMIZATION: + * Consider removing handshake metadata from Layer 3. + * See the corresponding comments in mps.h. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation), + * or #MBEDTLS_MPS_SIZE_UNKNOWN if it is not yet known. */ + mbedtls_mps_stored_opt_size_t len; + + /*! The buffer that should hold the handshake header once + * the length of the handshake message is known. */ + unsigned char* hdr; + /*! The size of the header buffer. */ + mbedtls_mps_stored_size_t hdr_len; + + mbedtls_mps_stored_size_t hdr_offset; + + /* DTLS-specific fields. */ + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*! The handshake sequence number. */ + + /* OPTIMIZATION: + * Consider removing handshake metadata from Layer 3. + * See the corresponding comments in mps.h. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; +}; + +struct mps_l3_alert_in_internal +{ + uint8_t level; /*!< The level of the incoming alert. */ + uint8_t type; /*!< The type of the incoming alert. */ +}; + +/** + * \brief The Layer 3 configuration structure. + */ +typedef struct +{ +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; +#endif /* MBEDTLS_MPS_CONF_MODE */ + mbedtls_mps_l2 *l2; +} mps_l3_config; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l3_conf_get_mode( mps_l3_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l3_conf_get_mode( mps_l3_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +/** + * \brief The Layer 3 context structure. + */ +struct mps_l3 +{ + mps_l3_config conf; + + struct + { + struct + { + /* Global reading state */ + + /*! Indicates if and which record type is currently open for reading. */ + mbedtls_mps_stored_msg_type_t state; + + /* Raw record data. */ + + /*! Epoch of current incoming message. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *raw_in; /*!< Reader providing raw access to incoming + * data of the type indicated by \c state + * (including headers in case of handshake + * messages). */ + + /* Type-specific structures for accessing the contents of + * of the messages of the given type. */ + + mps_l3_hs_in_internal hs; /*!< Handle to incoming + * handshake message. */ + + mps_l3_alert_in_internal alert; /*!< Type + Level of incoming alert. */ + + } in; + + struct + { + uint8_t clearing; /*!< This indicates if preparation of a new + * outgoing record necessitates a flush on + * the underlying Layer 2 first. + * The rationale for having this as a separate + * field as opposed to triggering the flush + * immediately once the necessity arises is + * that it allows the user to be in control + * of which Layer 3 API calls will require + * interfacing with the underlying transport. */ + + /* Note that there is no distinction between `flush` and `clearing` + * as in the Layer 2 implementation because Layer 3 doesn't buffer + * outgoing data but always passes it to Layer 2 immediately. */ + + /* Global writing state */ + + /*!< Indicates which record type is currently open for writing. */ + mbedtls_mps_stored_msg_type_t state; + + /* Raw outgoing record data */ + + /* OPTIMIZATION: + * If not NULL, this always points to the writer + * maintained by the underlying Layer 2 instance. + * Consider using this instance directly. */ + mbedtls_writer *raw_out; /*!< Writer providing raw access to outgoing + * data buffers (including such to be used + * for headers in case of handshake + * messages). */ + + /* Type-specific structures */ + + /* OPTIMIZATION: + * Why do we need to store meta-data such as the handshake + * sequence number here? We should be able to write the + * handshake header in mps_l3_write_handshake(), and afterwards + * the sequence number isn't needed anymore -- or is it? */ + mps_l3_hs_out_internal hs; /*!< Handle to outgoing handshake message. */ + + } out; + + } io; + +}; + +static inline mbedtls_mps_l2* mbedtls_mps_l3_get_l2( mps_l3 *l3 ) +{ + return( l3->conf.l2 ); +} + +/** + * \brief Initialize a Layer 3 context. + * + * \param l3 The pointer to the Layer 3 context to be initialized. + * \param l2 The pointer to the underlying Layer 2 context to + * to be used by \p l3. + * \param mode The mode of operation for the Layer 3 context: + * Either #MBEDTLS_MODE_STREAM for stream transports, + * or #MBEDTLS_MPS_MODE_DATAGRAM for datagram transports. + * + * \note Layer 3 doesn't own its underlying Layer 2 context; + * the Layer 2 context \p l2 must already be initialized + * when calling this function. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ + +int mps_l3_init( mps_l3 *l3, mbedtls_mps_l2 *l2, uint8_t mode ); + +/** + * \brief Free a Layer 3 context. + * + * \param l3 The pointer to the Layer 3 context to be freed. + * + * \note Layer 3 doesn't own its underlying Layer 2 context; + * the latter must be freed separately. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_l3_free( mps_l3 *l3 ); + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/** + * \brief Request an incoming message from Layer 3. + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return + * - One of the positive status codes #MBEDTLS_MPS_MSG_HS, + * #MBEDTLS_MPS_MSG_APP, #MBEDTLS_MPS_MSG_ALERT, + * #MBEDTLS_MPS_MSG_ALERT, #MBEDTLS_MPS_MSG_CCS or + * #MBEDTLS_MPS_MSG_ACK success, indicating which type + * of message has been received. + * - A negative error code on failure. + * + * \note To inspect the contents of the message that has been + * received, use the appropriate function \c mps_l3_read_xxx; + * e.g., the contents of a handshake message can be accessed + * via mps_l3_read_handshake(). + * + */ +/* OPTIMIZATION: + * Subsume mps_l3_read() with mps_l3_read_XXX() by filling + * an indexed union of mps_l3_in_xxx on success. */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read( mps_l3 *l3 ); + +/** + * \brief Check if a message has been read. + * + * \param l3 The Layer 3 context to use. + * + * \return #MBEDTLS_MPS_MSG_NONE if no message is available. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS, + * otherwise, indicating the message's record content type. + * + * \note This function doesn't do any processing and + * and only reports if a message is available + * through a prior call to mps_l3_read(). + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_check( mps_l3 * l3 ); + +/** + * \brief Get a handle to the contents of an incoming handshake message. + * + * \param l3 The pointer to the Layer 3 context. + * \param hs The address to hold the address of the handshake handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note The handle returned by this function is owned by + * the Layer 3 context and must not be freed by the user. + * It must also not be used after the read has been acknowledged + * through a call to mps_l3_dispatch(), or paused through a + * a call to mps_l3_pause_handshake(). + */ +/* TODO: Consider making this function static inline + * to avoid a layer of indirection. */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_handshake( mps_l3 *l3, mps_l3_handshake_in *hs ); + +/** + * \brief Get a handle to the contents of an incoming + * application data message. + * + * \param l3 The pointer to the Layer 3 context. + * \param app The address to hold the address of + * the application data handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note The handle returned by this function is owned by + * the Layer 3 context and must not be freed by the user. + * It must also not be used after the read has been acknowledged + * through a call to mps_l3_dispatch(). + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_app( mps_l3 *l3, mps_l3_app_in *app ); + +/** + * \brief Get a handle to the contents of an incoming alert message. + * + * \param l3 The pointer to the Layer 3 context. + * \param alert The address to hold the address of the alert handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_alert( mps_l3 *l3, mps_l3_alert_in *alert ); + +/** + * \brief Get a handle to the contents of an incoming CCS message. + * + * \param l3 The pointer to the Layer 3 context. + * \param ccs The address to hold the address of the alert handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_ccs( mps_l3 *l3, mps_l3_ccs_in *ccs ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/** + * \brief Pause the reading of an incoming handshake message. + * + * This function must be called when a handshake message + * has been received but the handshake handle returned by + * mps_l3_read_handshake() cannot provide the entire + * handshake contents. In this case, this function pauses + * the processing of the handshake message until it is + * continued on the next successful call to mps_l3_read() + * signaling incoming handshake data. + * It is currently the responsibility of the user to remember + * the state of content processing. + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \warning This call invalidates the handle returned by + * mps_l3_read_handshake(). When continuing the reading, + * the user must call mps_l3_read_handshake() again to + * retrieve the handle to use. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_pause_handshake( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Conclude the reading of the current incoming message. + * + * This function must be called after the user has successfully + * received and processed an incoming message through calls to + * mps_l3_read() and potentially \c mps_l3_read_xxx. + * It invalidates all content handles associated to the incoming + * messages, and puts the Layer 3 context in a state ready for + * a next call to mps_l3_read(). + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return \c 0 on success. + * \return #MPS_ERR_UNFINISHED_HS_MSG if the handshake message + * hasn't been fully fetched and committed. In this case, + * the state of \p l3 is unchanged; in particular, it + * remains intact and can be still be used. + * \return Another negative error code for other kinds of failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_consume( mps_l3 *l3 ); + +/** + * \brief Start writing an outgoing handshake message. + * + * \param l3 The pointer to the Layer 3 context to use. + * \param hs The address to store the handshake handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_handshake( mps_l3 *l3, mps_l3_handshake_out *hs ); + +/** + * \brief Start writing outgoing application data. + * + * \param l3 The pointer to the Layer 3 context to use. + * \param app The address to store the application data handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_app( mps_l3 *l3, mps_l3_app_out *app ); + +/** + * \brief Start writing an outgoing alert message. + * + * \param l3 The pointer to Layer 3 context. + * \param alert Address to store the alert handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_alert( mps_l3 *l3, mps_l3_alert_out *alert ); + +/** + * \brief Start writing an outgoing CCS message. + * + * \param l3 The pointer to Layer 3 context. + * \param ccs Address to store the CCS handle at. + * + * \return 0 on success, a negative error code on failure. + * + * \note The contents of a CCS message are determined by the + * the standard, and hence this function does not return + * an actual write-handle. Nonetheless, the writing of a CCS + * message must be concluded by a call to mps_l3_dispatch() + * in the same way as the writing of messages of + * other content types. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_ccs( mps_l3 *l3, mps_l3_ccs_out *ccs ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/** + * \brief Pause the writing of an outgoing handshake message. + * + * This function must be called when the writing of an + * outgoing handshake message has commenced, but the write + * handle returned by mps_l3_write_handshake() cannot provide + * enough space to write the entire handshake message contents. + * In this case, this function pauses the writing of the + * handshake message until it is continued on the next + * successful call to mps_l3_write_handshake(). + * + * It is currently the responsibility of the user to remember + * the state of content processing. + * + * \param l3 The pointer to Layer 3 context. + * + * \return 0 on success, a negative error code on failure. + * + * \warning This call invalidates the handle returned by + * mps_l3_write_handshake(). When continuing the write, + * the user must call mps_l3_write_handshake() again to + * retrieve the handle to use. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_pause_handshake( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Conclude the writing of the current outgoing message. + * + * This function must be called after the user has requested + * the writing of an outgoing message via a successful call to + * \c mps_l3_write_xxx and has prepared its contents through the + * provided write-handles. + * + * It invalidates all content handles associated to the outgoing + * messages, and puts the Layer 3 context in a state ready for + * a next call to \c mps_l3_write_xxx. + * + * \param l3 Pointer to Layer 3 context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_dispatch( mps_l3 *l3 ); + +/** + * \brief Flush all outgoing messages dispatched so far + * + * This function attempts to deliver all messages previously + * dispatched via mps_l3_dispatch() to the underlying transport. + * It delivery is not possible immediately, it remembers the + * ongoing flush and guarantees that no subsequent write will + * commence until the flush has completed. + * + * \param l3 Pointer to Layer 3 context. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if the flush couldn't be completed. + * \return A different negative error code for other kinds of failure. + * + * \note In case #MPS_ERR_WANT_WRITE is returned, the function can + * be called again to retry the flush. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_flush( mps_l3 *l3 ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_epoch_add( mps_l3 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_epoch_usage( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_INTERNAL_API int mps_l3_force_next_sequence_number( + mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_get_last_sequence_number( + mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ + +#endif /* MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H */ diff --git a/include/mbedtls/mps/mps.h b/include/mbedtls/mps/mps.h new file mode 100644 index 000000000000..17477274f8a7 --- /dev/null +++ b/include/mbedtls/mps/mps.h @@ -0,0 +1,1907 @@ +/** + * \file mps.h + * + * \brief Message Processing Stack + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_H +#define MBEDTLS_MPS_H + +#include "common.h" +#include "transport.h" +#include "transform.h" +#include "error.h" +#include "reader.h" +#include "writer.h" +#include "layer3.h" + +#include "../timing.h" + +struct mbedtls_mps_handshake_out_internal; +struct mbedtls_mps_retransmission_handle; +struct mbedtls_mps_recognition_info; +struct mbedtls_mps_config; +struct mbedtls_mps; +struct mbedtls_mps_reassembly; +struct mbedtls_mps_msg_reassembly; +struct mbedtls_mps_msg_reassembly_window; +struct mbedtls_mps_handshake_out; +struct mbedtls_mps_app_out; +struct mbedtls_mps_msg_metadata; +typedef struct mbedtls_mps_msg_metadata mbedtls_mps_msg_metadata; +typedef struct mbedtls_mps_handshake_out_internal mbedtls_mps_handshake_out_internal; +typedef struct mbedtls_mps_retransmission_handle mbedtls_mps_retransmission_handle; +typedef struct mbedtls_mps_recognition_info mbedtls_mps_recognition_info; +typedef struct mbedtls_mps_retransmission_detection mbedtls_mps_retransmission_detection; +typedef struct mbedtls_mps_config mbedtls_mps_config; +typedef struct mbedtls_mps mbedtls_mps; +typedef struct mbedtls_mps_reassembly mbedtls_mps_reassembly; +typedef struct mbedtls_mps_msg_reassembly mbedtls_mps_msg_reassembly; +typedef struct mbedtls_mps_msg_reassembly_window mbedtls_mps_msg_reassembly_window; +typedef struct mbedtls_mps_handshake_out mbedtls_mps_handshake_out; +typedef struct mbedtls_mps_app_out mbedtls_mps_app_out; + +/*! (DTLS only) The maximum number of messages in a flight. + * + * This is used to allocate space for retransmission backup handles. */ +#define MBEDTLS_MPS_MAX_FLIGHT_LENGTH 5 + +/*! The maximum allowed handshake sequence number. + * This must not be larger than #MBEDTLS_MPS_HS_SEQ_MAX. */ +#define MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER MBEDTLS_MPS_HS_SEQ_MAX + +/*! (DTLS only) The maximum number of future messages to be buffered. */ +#define MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS 4 + +#define MBEDTLS_MPS_RETRANSMISSION_CALLBACK_SUCCESS 0 +#define MBEDTLS_MPS_RETRANSMISSION_CALLBACK_PAUSE 1 + +/*! The type of reassembly/buffering states handshake messages. + * - #MPS_REASSEMBLY_NONE + * Reassembly hasn't started. + * - #MPS_REASSEMBLY_NO_FRAGMENTATION + * The message has been received in a single fragment and no reassembly was + * necessary; a reader is available which gives access to the contents. + * - #MPS_REASSEMBLY_WINDOW + * Some fragments have been received and reassembly is in progress. + * The state #MPS_REASSEMBLY_NO_FRAGMENTATION is only possible for the next + * message, as for future messages we need to make a copy of the L3 data anyway. + * + * NOTE: There are more alternatives, for example one could always wait until a + * new fragment comes in which continues the initial part of the message + * that has already been received; this way, no additional buffers would + * be needed (if the parsing routines make use of pausing). However, this + * seems to be suitable only for very reliable networks, or in DTLS-1.3 + * where a more elaborate acknowledgement scheme is available. + */ +typedef uint8_t mbedtls_mps_msg_reassembly_state; +#define MBEDTLS_MPS_REASSEMBLY_NONE \ + ( (mbedtls_mps_msg_reassembly_state) 0 ) +#define MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION \ + ( (mbedtls_mps_msg_reassembly_state) 1 ) +#define MBEDTLS_MPS_REASSEMBLY_WINDOW \ + ( (mbedtls_mps_msg_reassembly_state) 2 ) + +/*! Messages of the last incoming flight are tagged with values of this type + * to indicate whether a re-receipt should lead to retransmission of our + * own last outgoing flight, or not. */ +typedef uint8_t mbedtls_mps_retransmission_detection_state; +#define MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED \ + ( (mbedtls_mps_retransmission_detection_state) 0 ) +#define MBEDTLS_MPS_RETRANSMISSION_DETECTION_ON_HOLD \ + ( (mbedtls_mps_retransmission_detection_state) 1 ) + +/*! The enumeration of (D)TLS alerts. */ +typedef uint8_t mbedtls_mps_alert_t; +/* TODO: Add (D)TLS alert types here, see ssl.h. + * Either use the same constants as in the standard, + * or keep them abstract here and provide a translation + * function. */ + +/*! The type of reasons for MPS being blocked. + * + * Possible values are: + * - #MBEDTLS_MPS_ERROR_NONE + * No blocking reason has been recorded. + * - #MBEDTLS_MPS_ERROR_ALERT_SENT + * A fatal alert has been sent by the user. + * - #MBEDTLS_MPS_ERROR_ALERT_RECEIVED + * A fatal alert has been received from the peer. + * - #MBEDTLS_MPS_ERROR_INTERNAL_ERROR + * An internal error lead to blocking MPS. + */ +typedef uint8_t mbedtls_mps_blocking_reason_t; +#define MBEDTLS_MPS_ERROR_UNKNOWN ( (mbedtls_mps_blocking_reason_t) 0 ) +#define MBEDTLS_MPS_ERROR_ALERT_SENT ( (mbedtls_mps_blocking_reason_t) 1 ) +#define MBEDTLS_MPS_ERROR_ALERT_RECEIVED ( (mbedtls_mps_blocking_reason_t) 2 ) +#define MBEDTLS_MPS_ERROR_INTERNAL_ERROR ( (mbedtls_mps_blocking_reason_t) 3 ) + +/*! The type of MPS connection states. + * + * Possible values are: + * - #MBEDTLS_MPS_STATE_OPEN + * The connection is open. + * - #MBEDTLS_MPS_STATE_WRITE_ONLY + * The peer has closed its writing side, but we may still send data. + * - #MBEDTLS_MPS_STATE_READ_ONLY + * We have closed the writing side, but the peer may still send data. + * - #MBEDTLS_MPS_STATE_CLOSED + * The connection is fully closed. + * - #MBEDTLS_MPS_STATE_BLOCKED + * The MPS is blocked after an error. + */ +typedef uint8_t mbedtls_mps_connection_state_t; +#define MBEDTLS_MPS_STATE_OPEN ( (mbedtls_mps_connection_state_t) ( 1u << 0 ) ) +#define MBEDTLS_MPS_STATE_WRITE_ONLY ( (mbedtls_mps_connection_state_t) ( 1u << 1 ) ) +#define MBEDTLS_MPS_STATE_READ_ONLY ( (mbedtls_mps_connection_state_t) ( 1u << 2 ) ) +#define MBEDTLS_MPS_STATE_CLOSED ( (mbedtls_mps_connection_state_t) ( 1u << 3 ) ) +#define MBEDTLS_MPS_STATE_BLOCKED ( (mbedtls_mps_connection_state_t) ( 1u << 4 ) ) + +/* This works only if the values have no bit in common. + * I'd expect it to generate slightly smaller code. Is it actually true? */ +#define MBEDTLS_MPS_STATE_EITHER_OR( state, option_a, option_b ) \ + ( ( state & ~( option_a | option_b ) ) == 0 ) +/* This alternative would work regardless of the values of the enumeration: */ +/* #define MBEDTLS_MPS_STATE_EITHER_OR( state, option_a, option_b ) \ */ +/* ( ( state == option_a ) || \ */ +/* ( state == option_b ) ) */ + +/*! The type of flight exchange states. + * + * Possible values are: + * - #MBEDTLS_MPS_FLIGHT_DONE + * No flight exchange is in progress. + * - #MBEDTLS_MPS_FLIGHT_RECVINIT + * We're in the process of receiving and reassembling a handshake message + * from the peer that initializes a flight exchange (e.g. a ClientHello). + * This state is the same as #MBEDTLS_MPS_FLIGHT_DONE to the user, + * but internally it is different because the reassembly context + * has already been setup. + * - #MBEDTLS_MPS_FLIGHT_AWAIT + * We're waiting for the first message of the next flight from the peer. + * In this state, we're not yet sure whether the peer has fully received + * our last outgoing flight, and we retransmit the latter on timeout. + * This state is the same as #MBEDTLS_MPS_FLIGHT_RECEIVE to the user, + * but internally it is different: During #MBEDTLS_MPS_FLIGHT_AWAIT, we + * retain the memory of the last incoming flight but don't yet initialize + * the reassembly context for the next incoming flight, while during + * #MBEDTLS_MPS_FLIGHT_RECEIVE, the memory of the last incoming flight is + * erased and the reassembly context for the next incoming flight is setup. + * - #MBEDTLS_MPS_FLIGHT_RECEIVE + * We're receiving the next flight from the peer. This is different + * from #MBEDTLS_MPS_FLIGHT_AWAIT in that we must already have received + * some part of the next incoming flight, witnessing that the peer has + * received our last outgoing flight. In this mode, we're sending + * retransmission requests on a timeout, but not necessarily fully + * retransmit our last outgoing flight. + * This state is the same as #MBEDTLS_MPS_FLIGHT_AWAIT to the user. + * - #MBEDTLS_MPS_FLIGHT_PREPARE + * We're preparing out next outgoing flight. This is treated as a + * separate state from #MBEDTLS_MPS_FLIGHT_SEND because we can potentially + * temporarily free large parts of the MPS structure in that state, + * allowing other costly operations to have more RAM available. + * - #MBEDTLS_MPS_FLIGHT_SEND, + * We're in the process of sending our next outgoing flight. + * - #MBEDTLS_MPS_FLIGHT_FINALIZE + * The flight exchange has been completed with an outgoing flight of ours, + * but we're holding it back in case the peer didn't receive it. + * This state is the same as #MBEDTLS_MPS_FLIGHT_DONE to the user, + * but internally it is different because we must remember the last + * flight for potential retransmission. + * + * The state transitions are as follows: + * + * Finish outgoing flight, but not handshake + * .----------------------------------------------------------. + * | | + * v | + * .--------------. .--------------. Finish .--------------. + * | | | | flight + HS | | + * | Await | | Finalize |<------------| Send | + * | | | | | | + * '--------------' '--------------' '--------------' + * | | Witness that peer ^ ^ + * | | has received last | | + * | | flight, or timeout | | + * | v | | + * | Finish incoming .--------------. | | + * Receive frag flight + HS | | Start HS | | + * of msg from .--------------->| Done |-----------------' | + * next flight | | | | + * | | '--------------' Send first + * | | | ^ msg of next + * | | Receive frag of | | flight + * | | first HS message | | | + * v | v | | + * .--------------. .--------------. .--------------. + * | | | | | | + * | Receive |<-------------| RecvInit | | Prepare | + * | | First HS msg | | | | + * '--------------' signalled to '--------------' '--------------' + * | user ^ + * | | + * '----------------------------------------------------------' + * Finish incoming flight, but not handshake + * + * + * The retransmission state machine maintains the following submodules: + * - Reassembly module (piecing together and buffering next incoming flight) + * - Retransmission module (remembering last outgoing flight) + * - Retransmission detection module (remembering sufficient data from the + * last incoming flight to detect retransmissions). + * + * These submodules are valid in the following states: + * + * - Reassembly module + * + * Valid in + * MBEDTLS_MPS_FLIGHT_RECVINIT + * MBEDTLS_MPS_FLIGHT_RECEIVE + * + * This means it is affected by the following state transitions; + * + * + Initialized (mps_reassembly_init()) on transition + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_RECVINIT + * + Kept during transition + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed (mps_reassembly_free()) during transitions + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_PREPARE + * + * - Retransmission module + * + * Valid in + * MBEDTLS_MPS_FLIGHT_SEND + * MBEDTLS_MPS_FLIGHT_AWAIT + * MBEDTLS_MPS_FLIGHT_FINALIZE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_RECEIVE + * + * + Initialized (mps_out_flight_init()) on transition + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_SEND + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * MBEDTLS_MPS_FLIGHT_PREPARE -> MBEDTLS_MPS_FLIGHT_SEND + * + Kept on transition + * MBEDTLS_MPS_FLIGHT_SEND -> MBEDTLS_MPS_FLIGHT_AWAIT + * MBEDTLS_MPS_FLIGHT_SEND -> MBEDTLS_MPS_FLIGHT_FINALIZE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed (mps_out_flight_free()) on transition + * MBEDTLS_MPS_FLIGHT_FINALIZE -> MBEDTLS_MPS_FLIGHT_DONE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_PREPARE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * If DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + * (See the documentation of + * mbedtls_mps_retransmission_handle_incoming_fragment() + * for the explanation of this distinction on DTLS 1.3.) + * + * - Retransmission detection (memory of last incoming flight) + * (empty in DTLS 1.3 because retransmission requests are handled + * through ACKs; old handshake messages are always ignored) + * + * Valid in + * MBEDTLS_MPS_RECEIVE + * MBEDTLS_MPS_AWAIT + * MBEDTLS_MPS_PREPARE + * MBEDTLS_MPS_SEND + * + * + Initialized on transition + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_SEND + * + Reset on transition + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed on transition + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_FINALIZE -> MBEDTLS_MPS_FLIGHT_DONE + */ +typedef uint8_t mbedtls_mps_flight_state_t; +#define MBEDTLS_MPS_FLIGHT_DONE ( (mbedtls_mps_flight_state_t) ( 1u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_RECVINIT ( (mbedtls_mps_flight_state_t) ( 1u << 1 ) ) +#define MBEDTLS_MPS_FLIGHT_AWAIT ( (mbedtls_mps_flight_state_t) ( 1u << 2 ) ) +#define MBEDTLS_MPS_FLIGHT_RECEIVE ( (mbedtls_mps_flight_state_t) ( 1u << 3 ) ) +#define MBEDTLS_MPS_FLIGHT_PREPARE ( (mbedtls_mps_flight_state_t) ( 1u << 4 ) ) +#define MBEDTLS_MPS_FLIGHT_SEND ( (mbedtls_mps_flight_state_t) ( 1u << 5 ) ) +#define MBEDTLS_MPS_FLIGHT_FINALIZE ( (mbedtls_mps_flight_state_t) ( 1u << 6 ) ) + +/* This works only if the values have no bit in common. + * I'd expect it to generate slightly smaller code. Is it actually true? */ +#define MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( state, option_a, option_b ) \ + ( ( state & ~( option_a | option_b ) ) == 0 ) +/* This alternative would work regardless of the valus of the enumeration. */ +/* #define MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( state, option_a, option_b ) \ */ +/* ( ( state == option_a ) || \ */ +/* ( state == option_b ) ) */ + +/** + * Retransmission state + */ + +/*! The type of retransmission states. + * + * Possible values are: + * - #MBEDTLS_MPS_RETRANSMIT_NONE + * No retransmission or retransmission request ongoing. + * - #MBEDTLS_MPS_RETRANSMIT_RESEND + * We are currently resending our last outgoing flight. + * This happens in flight-exchange states + * #MBEDTLS_MPS_FLIGHT_AWAIT or #MBEDTLS_MPS_FLIGHT_FINALIZE. + * - #MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND + * We are in flight-exchange state #MBEDTLS_MPS_FLIGHT_RECEIVE, + * observed a disruption during the receipt of the next incoming flight, + * and are requesting a retransmission from the peer. + * In DTLS 1.0 and 1.2, this is done by retransmitting our last + * outgoing flight entirely (so the handling of this state is + * the same as the one for #MBEDTLS_MPS_RETRANSMIT_RESEND), + * which introduces an unnecessary network load because we already + * know that the peer has fully received our flight (otherwise + * it wouldn't have started sending). In DTLS 1.3, this + * state can be more efficiently handled by sending + * ACK messages which indicate to the peer which messages + * we have already received. + */ +typedef uint8_t mbedtls_mps_retransmit_state_t; +#define MBEDTLS_MPS_RETRANSMIT_NONE \ + ( (mbedtls_mps_retransmit_state_t) 0 ) +#define MBEDTLS_MPS_RETRANSMIT_RESEND \ + ( (mbedtls_mps_retransmit_state_t) 1 ) +#define MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND \ + ( (mbedtls_mps_retransmit_state_t) 2 ) + +/*! The type of message flags indicating their contribution + * to the current flight and flight exchange. + * + * Bit(s) Meaning + * 0 .. 1 Contribution to flight & handshake: + * 0: No contribution + * 1: Contributes to flight + * 2: Ends flight + * 3: Ends handshake + * + * 2 .. 6 Reserved + * + * 7 Validity flag + * Used to determine if the flags have been set + * This bit realized the `Optional` nature of the + * `Options` variable in the read state. + */ +typedef uint8_t mbedtls_mps_msg_flags; +#define MBEDTLS_MPS_FLAGS_MASK ( (mbedtls_mps_msg_flags) ( 1u << 7 ) ) +#define MBEDTLS_MPS_FLIGHT_MASK ( (mbedtls_mps_msg_flags) ( 3u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_NONE ( (mbedtls_mps_msg_flags) ( 0u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_ADD ( (mbedtls_mps_msg_flags) ( 1u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_END ( (mbedtls_mps_msg_flags) ( 2u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_FINISHED ( (mbedtls_mps_msg_flags) ( 3u << 0 ) ) + +/*! Type of bitflags signaling external dependencies. + * + * Defined bits are: + * - #MBEDTLS_MPS_BLOCK_READ + * Progress can only be made when the underlying transport + * has data ready to be read. + * - #MBEDTLS_MPS_BLOCK_WRITE + * Progress can only be made when the underlying transport + * is ready to send data. + */ +typedef uint8_t mbedtls_mps_dependencies; +#define MBEDTLS_MPS_BLOCK_READ ( (mbedtls_mps_dependencies) ( 1u << 0 ) ) +#define MBEDTLS_MPS_BLOCK_WRITE ( (mbedtls_mps_dependencies) ( 1u << 1 ) ) + +/* + * Return values from parsing/writing functions + */ +#define MBEDTLS_MPS_HANDSHAKE_DONE 0 +#define MBEDTLS_MPS_HANDSHAKE_PAUSE 1 + +/** + * The security parameter struct mbedtls_ssl_transform is entirely opaque + * to the MPS. The MPS only uses its instances through configurable payload + * encryption and decryption functions of type mbedtls_transform_record_t + * defined below. + */ + +typedef void mbedtls_mps_write_cb_ctx_t; +/** + * \brief Callback for retransmission of outgoing handshake messages. + * + * \param ctx Opaque context passed to the retransmission function. + * Must not be altered because multiple retransmissions + * must be guaranteed to produce the same results. + * \param writer The writer to use to (re-)write the message contents. + * + * \note If possible, it is advisable to use the same function + * that was used to write the message in the first place. + */ +typedef int (*mbedtls_mps_write_cb_t)( mbedtls_mps_write_cb_ctx_t const *ctx, + mbedtls_writer *writer ); + +/*! Enumeration of states of ::mbedtls_mps_handshake_out_internal. */ +typedef uint8_t mbedtls_mps_hs_state; +/*! This state indicates that the structure is not initialized. + * TODO: Clarify whether this means that it's at least zeroized. */ +#define MBEDTLS_MPS_HS_NONE ( (mbedtls_mps_hs_state) 0 ) +/*! This state indicates an initialized structure representing + an outgoing handshake message whose user-facing writer is in + writing-mode. */ +#define MBEDTLS_MPS_HS_ACTIVE ( (mbedtls_mps_hs_state) 1 ) +/*! This state indicates an initialized structure representing + * an outgoing handshake message has been completely written + * by the user, but which still needs to be dispatched to + * Layer 3. */ +#define MBEDTLS_MPS_HS_QUEUED ( (mbedtls_mps_hs_state) 2 ) +/*! This state indicates an initialized structure representing + * an outgoing handshake message which has not yet been fully + * written by the user */ +#define MBEDTLS_MPS_HS_PAUSED ( (mbedtls_mps_hs_state) 3 ) + +/* + * \brief Internal structure representing an outgoing handshake message. + * + * This is usually a 'fresh' message requested by the handshake + * logic layer, but can also be the retransmission of an old message, + * triggered by the retransmission state machine. + * + */ +struct mbedtls_mps_handshake_out_internal +{ + mbedtls_mps_hs_state state; /*!< Indicates if the handshake message is + * currently being paused or not. */ + + /* + * Static information about the message. + */ + + /* OPTIMIZATION: + * This has significant overlap with Layer 3, which also + * stores the metadata for handshake messages. Consider + * optimizing this. + * + * Initial thoughts: + * - For DTLS, handshake metadata isn't used after + * the initial call to mps_l3_write_handshake() + * anymore because the handshake header is written + * immediately. It should therefore not be stored + * in the Layer 3 structure in this case. + * - For TLS, Layer 3 currently uses the stored metadata + * to check that the handshake message metadata doesn't + * change during paused-and-continued handshake writes. + * This is a legitimate use and makes the API harder + * to abuse. + * - For DTLS, Layer 4 needs to store the handshake + * metadata: If a large handshake message is written + * by the user which fits in the writer's queue but + * cannot be dispatched to Layer 3 in one go, the + * calls to Layer 3 dispatching the remaining fragments + * need the metadata. + * - Again for DTLS, Layer 4 uses the stored handshake + * metadata to check consistency across paused-and-continued + * handshake writes, making the API harder to abuse. + * + * It seems worth considering to remove the metadata from + * Layer 3 and storing it solely at Layer 4. + */ + + mbedtls_mps_msg_metadata *metadata; + + + /* + * Progress of writing + */ + + /*! Indicates the offset of the fragment that's currently being written. */ + mbedtls_mps_stored_size_t offset; + + /* TODO: Document! When is this set? */ + mbedtls_mps_stored_size_t frag_len; + + /* OPTIMIZATION: + * Consider removing this pointer; the reader can be queried + * from Layer 3 anytime, and there's no need to keep its + * address here. Moreover, the querying might be done through + * an inline function so that the compiler is able to optimize + * this into a direct structure field access. + * In general, care has to be taken to not have the + * layered structure of MPS come at the cost of information + * duplication and too many layers of indirections. + */ + + /* OPTIMIZATION: + * Consider removing the extended writer from Layer 3. + * Currently, it is only needed to keep track of handshake + * message bounds during TLS handshake fragmentation, but + * these bounds checks could as well be moved to Layer 4. + * This would weaken the API guarantees of Layer 3 in that + * it'd allow to write fragmented handshake messages longer + * than indicated in their handshake header, but given + * that the logic layer only interfaces with Layer 4 + * and the API guarantees of Layer 4 stay the same, this + * seems acceptable. + * This change would lead to conceptual simplification, + * less code, and saving one extended writer of RAM. + * + * Removing the extended writer from Layer 3 would mean that + * we'd safe a pointer to a raw writer here (which, however, + * might be removed due to the previous optimization + * opportunity). */ + mbedtls_writer *wr_l3; /*!< The writer obtained from Layer 3 to + * write the next handshake fragment.*/ + + /* + * User-facing writers + */ + + /* OPTIMIZATION: + * The queue and its length are already stored in the writer, + * and one should be able to avoid duplicating them here. */ + mbedtls_mps_stored_size_t queue_len; + unsigned char *queue; + mbedtls_writer wr; + +}; + +/** + * Retransmission backup + */ + +/*! The type of retransmission handle types. + * + * Supported values are: + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE + * to characterize uninitialized handles. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW + * for a handshake message retransmission + * based on a raw backup of the message. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK + * for a handshake message retransmission + * based on a callback. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS + * for a CCS message retransmission. + */ +typedef uint8_t mbedtls_mps_retransmission_handle_type; +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE \ + ( (mbedtls_mps_retransmission_handle_type) 0 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW \ + ( (mbedtls_mps_retransmission_handle_type) 1 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK \ + ( (mbedtls_mps_retransmission_handle_type) 2 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS \ + ( (mbedtls_mps_retransmission_handle_type) 3 ) + +struct mbedtls_mps_msg_metadata +{ + /*! The handshake type; unused for CCS retransmissions. */ + mbedtls_mps_stored_hs_type type; + + /*! The handshake sequence number; unused for CCS retransmissions. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! The epoch used to send the message. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The total handshake message length. */ + mbedtls_mps_stored_opt_size_t len; +}; +typedef struct mbedtls_mps_msg_metadata mbedtls_mps_msg_metadata; + +struct mbedtls_mps_retransmission_handle +{ + /*! The type of the retransmission handle. See the documentation + * of ::mps_retransmission_handle_type for more information. */ + mbedtls_mps_retransmission_handle_type handle_type; + + mbedtls_mps_msg_metadata metadata; + + /*! Union indexed by \c handle_type containing the actual + * retransmission handle providing the message content. */ + union + { + /*! The raw buffer holding the backup of the outgoing message. This is + * valid if and only if \c type has value + * #MPS_RETRANSMISSION_HANDLE_HS_RAW. */ + struct + { + /*!< The buffer holding the message backup. */ + unsigned char *buf; + + /*!< Total size of \c buf. This may be larger than `len` above if + * the length of the handshake message was initially not known. */ + mbedtls_mps_stored_size_t len; + } raw; + + /*! The callback for retransmission. This is valid if and only if + * \c type has value #MPS_RETRANSMISSION_HANDLE_CALLBACK. */ + struct + { + mbedtls_mps_write_cb_t cb; /*!< The retransmission + * callback. */ + mbedtls_mps_write_cb_ctx_t *ctx; /*!< The context to be passed + * to the callback \c cb. */ + } callback; + + /* No data for CCS messages, i.e. if \c type + * has value #MPS_RETRANSMISSION_CALLBACK_CCS */ + struct + { + int unused[1]; + } ccs; + + } handle; + +}; + +typedef void mbedtls_mps_set_timer_t( void * ctx, + uint32_t int_ms, + uint32_t fin_ms ); +typedef int mbedtls_mps_get_timer_t( void * ctx ); + +/** + * \brief This structure represents partial backups of messages belonging + * to incoming flights that we keep to recognize retransmissions. + * + * Currently, we recognize retransmissions by looking at the epoch + * and the sequence number only, ignoring the handshake type, + * handshake length, and contents. + * + * See the documentation of ::mbedtls_mps::dtls::retransmission_detection + * for more information on this. + */ +struct mbedtls_mps_recognition_info +{ + /*! The epoch through which the handshake message was secured. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + +}; + +/** + * MPS Configuration + */ + +struct mbedtls_mps_config +{ +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; +#endif /* MBEDTLS_MPS_CONF_MODE */ + + mps_l3 *l3; + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) + /*! The initial value of the retransmission timeout (ms). */ + uint32_t hs_timeout_min; +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) + /*! The maximum value of the retransmission timeout (ms). */ + uint32_t hs_timeout_max; +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + + /*! The retransmission timer context. */ + void* p_timer; + /*! Callback to obtain state of timer. */ + mbedtls_mps_get_timer_t *f_get_timer; + /*! Callback to set or reset timer. */ + mbedtls_mps_set_timer_t *f_set_timer; + +}; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_conf_get_mode( mbedtls_mps_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_conf_get_mode( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_min( mbedtls_mps_config *conf ) +{ + return( conf->hs_timeout_min ); +} +#else /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_min( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN ); +} +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_max( mbedtls_mps_config *conf ) +{ + return( conf->hs_timeout_max ); +} +#else /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_max( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX ); +} +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + +typedef union +{ + mbedtls_mps_alert_t alert; + int err; +} mbedtls_mps_blocking_info_t; + +/** + * MPS context + */ + +struct mbedtls_mps +{ + mbedtls_mps_config conf; + + /* Security configuration */ + + /*! The current incoming epoch specified by the user. + * Only messages from this epoch will be handed to the + * user. However, messages from different epochs might + * still be handlded internally, e.g. to detect + * retransmission. */ + mbedtls_mps_stored_epoch_id in_epoch; + + /*! The current outgoing epoch specified by the user. + * Write requests by the user will be served by using + * this epoch. */ + mbedtls_mps_stored_epoch_id out_epoch; + + /* Connection state */ + + /*! This indicates if an alert needs to be sent. + * If it is set, the type of alert is determined + * by \c state and \c blocking_info. Specifically: + * - If \c state indicates an orderly connection closure, + * a ClosureAlert will be sent. + * - If \c state indicates a blocked MPS, a fatal alert + * based in the data in \c blocking_info will be sent. + */ + uint8_t alert_pending; /* TODO: Are there other binary flags + * that could be subsumed in a bitfield? */ + + /*! The state of the connection. See the documentation of + * ::mbedtls_mps_connection_state_t for the possible values. */ + mbedtls_mps_connection_state_t state; + + /*! The reason for blocking MPS (if applicable). */ + mbedtls_mps_blocking_reason_t blocking_reason; + + /*! This is a union indexed by \c blocking_reason giving + * more information about the reason for blocking MPS. + * Specifically: + * - If \c blocking_reason is #MBEDTLS_MPS_ERROR_ALERT_SENT or + * #MBEDTLS_MPS_ERROR_ALERT_RECEIVED, \c info.alert is valid. + * and contains the type of alert sent or received, respectively. + * - If \c blocking_reason is #MBEDTLS_MPS_ERROR_INTERNAL_ERROR, + * \c avail.err is valid and contains the internal error + * code that lead to blocking MPS. + * - Otherwise, \c blocking_info is invalid. + */ + mbedtls_mps_blocking_info_t blocking_info; + + /* Read state */ + struct + { + mbedtls_mps_stored_msg_type_t state; + + /* DTLS only */ + mbedtls_mps_msg_flags flags; /*!< Indicates if and how the incoming + * message contributes to an ongoing + * handshake. */ + + /* Note: + * This is slightly memory-inefficient because the data + * is already stored in the underlying Layer 3 context. + * Comments: + * - It is unavoidable to use an mps_l3_handshake_in instance + * at some point, because that's how Layer 3 reports the + * handshake contents. For TLS, it might be stack-allocated in + * mbedtls_mps_read_handshake(), setup via mps_l3_read_handshake() + * and used to fill the target structure mbedtls_mps_handshake_in + * in that function. + * - For DTLS, it is unavoidable to have a separate instance of + * mps_l3_handshake_in than the one reported by Layer 3, because + * of handshake message reassembly. So, in this case at least, + * we must store it in the MPS context. + * Currently, we decided to treat TLS and DTLS uniformly by + * having the mps_l3_handshake_in instance in the MPS context + * in any case. + * Given that choice, it comes at no additional cost to also + * have the alert type and reader pointer here. + */ + union + { + mbedtls_mps_alert_t alert; + mbedtls_mps_reader* app; + mps_l3_handshake_in hs; + } data; + + } in; + + /* Write state */ + struct + { + uint8_t flush; /*!< Indicates if a flush has been requested that + * needs to complete before the next read or write + * can commence. */ + + mbedtls_mps_stored_msg_type_t state; + + } out; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + /*! The DTLS retransmission state machine. */ + struct + { + /*! This indicates the state of the retransmission state machine. + * See the documentation of ::mbedtls_mps_flight_state_t. */ + mbedtls_mps_flight_state_t state; + + /*! The handshake sequence number for the next incoming + * or outgoing handshake message. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! This indicates if we're currently retransmitting our last outgoing + * flight, or are requesting retransmission from the peer. + * This may be viewed as introducing sub-states to the state \c state + * of the retransmission state machine. + * See the documentation of ::mbedtls_mps_retransmit_state_t. + * + * THINK: Perhaps this should be reconciled with \c state? + * Retransmission of the last outgoing flight can be + * seen as a substate of MBEDTLS_MPS_FLIGHT_AWAIT, + * and requesting retransmission can be seen as a + * substate of MBEDTLS_MPS_FLIGHT_RECEIVE. */ + mbedtls_mps_retransmit_state_t retransmit_state; + + /*! This structure is used when waiting for the next incoming + * flight of the peer. It captures the time to wait until we + * resend our last outgoing flight (in case we haven't received + * anything so far) or request retransmission from the peer + * (in case at least one message from the peer has been received, + * implicitly witnessing receipt of our last outgoing flight). + * Further, if we are in the process of resending our last flight or + * requesting retransmission from the peer, it holds the sending state. + * Note: Retransmission requests are handled differently + * between DTLS 1.2 and DTLS 1.3; see the documentation of + * ::mbedtls_mps_retransmit_state_t for more. */ + struct + { + /*! The current retransmission timeout (ms). Increases with + * every retransmission until a configurable threshold + * is reached. */ + uint32_t retransmit_timeout; + + /*! In case of a retransmission, this is the index of the + * message to be retransmitted next in the \c backup array + * in the \c outgoing structure. */ + uint8_t resend_offset; + + } wait; + + /*! The state of outgoing flights. */ + struct + { + /*! The number of messages in the current/last outgoing flight. */ + uint8_t flight_len; + + /*! A list of backup handles to be used in case the flight, + * or parts of it, need to be retransmitted. See the documentation + * of ::mps_retransmission_handle_backup for more. */ + mbedtls_mps_retransmission_handle + backup[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + } outgoing; + + /*! Structures representing state of incoming and outgoing handshake + * messages. + * + * Eventually, we want to be able to use a union here. */ + struct + { + struct + { + /*! This flag indicates if and how the outgoing + * message contributes to an ongoing handshake. + * See the documentation of ::mbedtls_mps_msg_flags. */ + mbedtls_mps_msg_flags flags; + + /*! This structure controls the state of outgoing + * handshake messages and their fragmentation. + * It is used both for the initial sending of + * messages as well as for retransmissions. */ + mbedtls_mps_handshake_out_internal hs; + + } out; + + struct + { + /*! Incoming message buffering and reassembly + * + * Contains all state related to message reassembly + * and buffering of future messages. + * + * To the user, it has the following states: + * - Inactive: + * No incoming handshake message is ready to be read. + * - Available: + * The next incoming handshake message is available + * and can be requested by the user. + * - Active: + * The next incoming handshake message is available + * and has been requested by the user. + * - Paused: + * The reading of the next incoming handshake message + * has been paused. + * + * The interface is the following: + * + * - Initialize + * This takes the expected sequence number of the first + * handshake message in the next incoming flight. + * + * - Reset + * + * - Feed a new handshake fragment + * + * This is valid only in inactive state. + * The reassembly submodule reacts by indicating whether the + * new handshake fragment allowed to produce (parts of) the + * next expected incoming handshake message to be delivered + * to the user. If so, it switches to the `available` state, + * and takes ownership of the handshake fragment until the + * user has requested and passed back the handshake message. + * + * - Request a new handshake message + * + * This is valid in state `Available` only. + * In this case, it provides the user with a handle to + * the next incoming handshake message, and moves + * to state `Active`. + * + * - Finalize the reading of the current handshake message. + * + * This is valid in state `Active` only and moves to + * state `Inactive` or `Available`, depending on whether + * the next handshake messages are already available + * or not. + * + * - Pause the reading of the current handshake message. + * + * Internally, the complexity is in the feeding call. + * When facing a new handshake message fragment, the + * reassembly submodule may perform the following actions: + * + * (1) If the fragment is an entire handshake message of + * the expected epoch and sequence number, directly + * pass it through to the user. + * (3) If the fragment is proper and belongs to the next + * incoming handshake message, extract its content + * and update the reassembly process for that message. + * If the fragment leads to a fully reassembled message, + * or at least a sufficiently large next contiguous + * chunk, it is passed to the user. + * (4) If the fragment belongs to a future message and + * the implementation supports buffering of future + * messages, back it up. + * (5) Ignore otherwise (message duplication should be + * detected by the replay protection of Layer 2, but + * we might receive retransmitted messages of the + * current incoming flight that we have already seen). + * + * Note: It is not the responsibility of the reassembly + * submodule to detect retransmissions. This should + * be done before, on the basis of the recognition + * info structures of the last incoming flight. + */ + struct mbedtls_mps_reassembly + { + /* QUESTION: + * Consider storing ::mps_reassembly on the heap + * and only allocate it when necessary. + */ + + /* TODO: Document how to infer the abstract state described + * above from the C structure instance. */ + + /*! The reader and extended reader managing the contents + * of the current incoming handshake message. + * + * TODO: Document in which states this is valid. + */ + mbedtls_mps_reader rd; + + /*! The array of structures representing future and/or + * partially received handshake messages. */ + struct mbedtls_mps_msg_reassembly + { + /*! The reassembly state of the message. + * See ::mbedtls_mps_msg_reassembly_state for more. */ + mbedtls_mps_msg_reassembly_state status; + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The epoch of the incoming handshake message. + * This must be stored to detect a change of epoch + * between buffering and reading of the message, + * or an epoch change across fragments. + * Examples for that: + * - MPS does not have any knowledge about the structure + * of flights and the evolution of epochs within them. + * In particular, it would buffer a future Finished + * message in a DTLS 1.2 handshake even if it is unencrypted. + * However, remembering the epoch here allows to error out + * by the time the user switches the incoming epoch before + * asking for the Finished message. + * - In DTLS 1.3, there can be key changes at flight + * boundaries, in which case we have multiple incoming + * epochs active when waiting for the next incoming flight, + * because we must be able to detect retransmissions. + * In this case, we must not piece together new messages + * with fragments coming from different epochs. + */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The total handshake message length. Remembered to + * check that it is consistent across fragments. */ + mbedtls_mps_stored_size_t length; + + /*!< Union indexed by \c status giving rise to the + * message contents fetched so far. */ + union + { + /*! The extended reader owned by Layer 3 giving rise to the + * contents of the handshake message. This is valid if and + * only if \c status is #MPS_REASSEMBLY_NO_FRAGMENTATION */ + mbedtls_mps_reader *rd_l3; + + /*! The reassembly buffer holding the partially received + * handshake message. This is valid if and only if + * \c status is #MPS_REASSEMBLY_WINDOW. */ + struct mbedtls_mps_msg_reassembly_window + { + unsigned char *buf; /*!< The reassembly buffer. */ + unsigned char *bitmask; /*!< The bitmask indicating + * the state of reassembly. */ + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + } window; + + } data; + + } reassembly[ 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ]; + + } incoming; + + } in; + + } io; + + /*! Memory of last incoming flight + * + * If the flight state is #MBEDTLS_MPS_FLIGHT_AWAIT, + * #MBEDTLS_MPS_FLIGHT_SEND or #MBEDTLS_MPS_FLIGHT_RESEND, + * this structure contains the last incoming flight, + * remembered in order to be able to recognize + * retransmissions. + * + * If the flight state is #MEDTLS_MPS_FLIGHT_RECEIVE, + * it contains the ongoing incoming flight. + * + * The transition from #MBEDTLS_MPS_FLIGHT_AWAIT + * to #MBEDTLS_MPS_FLIGHT_RECEIVE occurs when the + * first message of the next incoming flight is + * received, implicitly acknowledging that the peer + * has received our last outgoing flight, and thereby + * justifying removing our memory of it. + * + * QUESTION: + * We should not always trigger retransmission when we + * receive a retransmitted message from an old flight: + * Since DTLS-1.2 does not use per-message acknowledging, + * flights are always retransmitted in their entirety, so if + * _any_ message from an old flight would trigger retransmission, + * we'd retransmit our last outgoing flight as many times as there + * are messages in the last incoming flight. + * The previous retransmission state machine implementation + * triggered retransmission only when observing the _last_ message + * of the previous flight. While this does prevent multiple + * retransmissions being triggered by a single retransmission + * of our peer, it may happen that the last message gets dropped + * and we miss a retransmission, thereby delaying the handshake. + * + * Are there better solutions? + * + * One approach is to have any message from the last incoming + * flight trigger a retransmission, but to remember that the + * other messages should not immediately trigger another + * retransmission when seen. This can be realized by maintaining + * two states for each message from the last incoming flight, + * 'active' and 'on hold', with the following semantics: + * - If a retransmission is observed for an 'active' message, + * it (1) triggers retransmission of the last outgoing flight, + * (2) the message stays 'active', and (3) all other messages + * are moved to 'on hold' state. + * - If a retransmission is observed for an 'on hold' message, + * its state is changed to 'active', but no retransmission happens. + * This way, there will never be more than one retransmission + * triggered per peer-retransmitted incoming flight. + */ + struct mbedtls_mps_retransmission_detection + { + /*! The number of handshake messages in the current or last + * incoming flight that we use for flight retransmission + * detection; at the same time, the number of entries + * in \c msgs which are valid. + * + * Note: We don't remember CCS messages of incoming flights. + */ + uint8_t flight_len; + + /*! This indicates which messages should currently trigger + * a retransmission. See the documentation of + * ::mbedtls_mps_recognition_state for more. + * + * NOTE: Currently, ::mbedtls_mps_retransmission_detection_state + * has only two values, so a bitfield would do here, but that + * doesn't save many bytes. */ + mbedtls_mps_retransmission_detection_state + msg_state[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + /*! Aspects of the current or last incoming flight that + * we remember for the purpose of recognizing retransmissions. + * Currently, we base recognition of retransmitted messages + * on the handshake sequence number and epoch only. */ + mbedtls_mps_recognition_info msgs[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + } retransmission_detection; + + /* + * DTLS-1.3-NOTE: + * For DTLS 1.3 we must explicitly acknowledge handshake records through + * ACK messages and therefore need to add another structure remembering + * the record sequence number of the handshake records that we received. + * Note, though, that this lives at a different level than the structure + * mps_recognition_info used to detect handshake retransmissions. + */ + + } dtls; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +}; + +static inline mps_l3* mbedtls_mps_l4_get_l3( mbedtls_mps *l4 ) +{ + return( l4->conf.l3 ); +} + +/** + * \brief Set the underlying transport callbacks for the MPS. + * + * \param mps The MPS context to use. + * \param f_send Send data to underlying transport + * \param f_recv Receive data from underlying transport + * \param f_recv_timeout Receive data from underlying transport, with timeout. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_set_bio( mbedtls_mps *mps, void *p_bio, + mbedtls_mps_send_t *f_send, + mbedtls_mps_recv_t *f_recv, + mbedtls_mps_recv_timeout_t *f_recv_timeout ); + +/** + * MPS maintenance + */ + +/** + * \brief Initialize an MPS context. + * + * \param mps The MPS context to initialize. + * \param l3 The underlying Layer 3 context. + * This must be freshly initialized. + * \param mode The mode of operation for the MPS context. + * Either #MBEDTLS_MPS_MODE_STREAM if the underlying + * Layer 0 transport is a stream transport, or + * #MBEDTLS_MPS_MODE_DATAGRAM if the underlying + * Layer 0 transport is a datagram transport. + * \param max_write The maximum number of bytes that the user can request + * to write between two consecutive write-commits such that + * MPS still guarantees progress in DTLS. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but MPS doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_WRITER_OUT_OF_DATA or + * #MPS_ERR_WANT_WRITE error code while writing, closing + * and reopening the write-port in this case must eventually + * lead to success, provided the underlying transport + * is (eventually) available to send the request amount + * of data. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented outgoing data himself. + * This is DTLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * + * \note The \p max_write parameter is DTLS only. To establish the + * aforementioned write-progress guarantee for TLS, you need + * to pass \p max_write during initialization of the Layer 2 + * context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_init( mbedtls_mps *mps, + mps_l3 *l3, uint8_t mode, + size_t max_write ); + +/** + * \brief Free an MPS context. + * + * \param mps The MPS context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_free( mbedtls_mps *mps ); + +/** + * Read interface + */ + +/* Structure representing an incoming handshake message. */ +typedef struct +{ + uint8_t type; /*!< Type of handshake message */ + size_t length; /*!< Length of entire handshake message */ + mbedtls_mps_reader *handle; /*!< Reader to retrieve message contents */ + + uint8_t add[8]; /*!< Opaque, additional data to be used for + * checksum calculations. */ + uint8_t addlen; /*!< The length of the additional data. */ +} mbedtls_mps_handshake_in; + +/** + * \brief Attempt to read an incoming message. + * + * \param mps The MPS context to use. + * + * \return A negative error code on failure. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS + * otherwise, indicating which content type was fetched. + * + * \note On success, you can query the type-specific message contents + * using one of mbedtls_mps_read_handshake(), mbedtls_mps_read_alert(), + * or mbedtls_mps_read_application(). + */ +int mbedtls_mps_read( mbedtls_mps *mps ); + +/** + * \brief Check if a message has been read. + * + * \param mps The MPS context to use. + * + * \return #MBEDTLS_ERR_MPS_BLOCKED if MPS is blocked. + * \return #MBEDTLS_MPS_MSG_NONE if no message is available. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS, + * otherwise, indicating the message's record content type. + * + * \note This function doesn't do any processing and + * and only reports if a message is available + * through a prior call to mbedtls_mps_read(). + */ +int mbedtls_mps_read_check( mbedtls_mps const *mps ); + +/** + * \brief Get a handle to the contents of a pending handshake message. + * + * \param mps The MPS context to use. + * \param msg The address to hold the handshake handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_HS. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_in *msg ); + +/** + * \brief Get the contents of a pending application data message. + * + * \param mps The MPS context to use. + * \param rd The address at which to store the read handle + * to be used to access the application data. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_APP. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_application( mbedtls_mps *mps, + mbedtls_mps_reader **rd ); + +/** + * \brief Get the type of a pending alert message. + * + * \param mps The MPS context to use. + * \param type The address to hold the type of the received alert. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_ALERT. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t *type ); + +/** + * \brief Set the options for the current incoming message. + * + * \param mps The MPS context to use. + * \param flags The bitmask indicating if and how the current message + * contributes to the current flight and handshake. + * See the documentation of ::mbedtls_mps_msg_flags for more + * information. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_read_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ); + +/** + * \brief Pause the reading of an incoming handshake message. + * + * When a handshake message has been received, the user of the + * MPS can query its contents through mbedtls_mps_reader_get(), + * using the reader returned from mbedtls_mps_read_handshake(). + * If the handshake message is only partially available - for + * example, because it was fragments on the TLS record layer - + * and the requested content goes beyond the bounds what has + * already been received, this function must be called to pause + * the processing of the handshake message until more data is + * available. (Note: mbedtls_mps_read_consume() must only be + * called if the entire handshake message has been processed, + * and will fail if more data is pending, regardless of whether + * that data belongs to fragments that weren't received yet). + * + * After a successful call to mbedtls_mps_read_pause(), + * continuation can be attempted through subsequent calls to + * mbedtls_mps_read(). If such calls indicate the availability + * of a handshake message, it is guaranteed to be the + * continuation of the handshake message that has been paused. + * Note, however, that handshake fragments might be interleaved + * with messages of other types, and hence the user must be + * prepared to handle other message types, too, when attempting + * to continue the reading. + * + * The recommended way to deal with initiating and continuing + * the reading of a handshake message is to have a single path + * calling mbedtls_mps_read() which deals with unavailability + * of data as well as data of unexpected type, and to jump to + * the concrete handshake message processing routine otherwise. + * This routine should also maintain the state of the processing + * of the handshake message, so that it would pick up the + * processing at the correct point after pausing. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note If this function succeeds, the MPS holds back the reader + * used to fetch the message contents and returns it to the + * MPS user on the next successful reading of a handshake + * message via mbedtls_mps_read(). + */ +int mbedtls_mps_read_pause( mbedtls_mps *mps ); + +/** + * \brief Conclude the reading of an incoming message (of any type). + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_read_consume( mbedtls_mps *mps ); + +/** + * \brief Check which external interfaces (like the underlying + * transport) need to become available in order for the MPS + * to be able to make progress towards fetching a new message. + * + * \param mps The MPS context to use. + * \param flags The pointer ready to receive the bitflag indicating + * the external dependencies. + * + * \return \c 0 on success. In that case, + * \c *flags holds a bitwise OR of some of the following flags: + * - #MBEDTLS_MPS_BLOCK_READ + * The underlying transport must signal incoming data. + * - #MBEDTLS_MPS_BLOCK_WRITE + * The underlying transport must be ready to write data. + * \return A negative error code on failure. + * + * \note #MBEDTLS_MPS_BLOCK_READ need not be set here, as there + * might be more internally buffered data waiting to be + * processed, e.g. if there is more than one records within + * a single datagram. + * + */ +int mbedtls_mps_read_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ); + +/* + * The following function constitutes an abstraction break + * unavoidable by the DTLS standard, so it seems: + * The standard mandates that a HelloVerifyRequest in DTLS + * MUST be sent with the same record sequence number as the + * ClientHello it is replying to. + */ +/** + * \brief Get the sequence number of the record to which the + * currently opened message belongs. + * + * \param mps The MPS context to use. + * \param seq Pointer to write the record sequence number to. + * + * \warning This function constitutes an abstraction break + * and should ONLY be used if it is unavoidable by + * the standard. + * + * \note This function must be called between a pair of + * mbedtls_mps_read() and mbedtls_mps_read_consume() calls. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_get_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ); + +/** + * Write interface + */ + +/* Structure representing an outgoing handshake message. */ +struct mbedtls_mps_handshake_out +{ + /*! The type of the handshake message to be written. + * + * This field must be set by the user before + * calling mbedtls_mps_write_handshake(). */ + mbedtls_mps_stored_hs_type type; + + /*! The length of the handshake message to be written, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the length is determined at write-time. + * In this case, pausing is not possible for the handshake message + * (because the headers for handshake fragments include the total + * length of the handshake message). + * + * This field must be set by the user before + * calling mbedtls_mps_write_handshake(). */ + mbedtls_mps_stored_opt_size_t length; + + mbedtls_writer *handle; /*!< Write-handle to handshake message content. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). Any + * previous value will be ignored and + * overwritten. */ + + uint8_t add[8]; /*!< Read only additional data attached to the + * handshake message. Concretely, this is empty for + * TLS and contains the handshake sequence number + * for DTLS. + * + * This is exposed to allow it to enter + * checksum computations. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). */ + + uint8_t addlen; /*!< The length of the additional data. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). */ +}; + +/* Structure representing an outgoing application data message. */ +struct mbedtls_mps_app_out +{ + uint8_t* app; /*!< Application data buffer. Its content + * may be modified by the application. */ + size_t app_len; /*!< Size of application data buffer. */ + + size_t *written; /*!< Set by the user, indicating the amount + * of the application data buffer that has + * been filled with outgoing data. */ +}; + +/** + * \brief Indicate the contribution of the current outgoing + * message to the flight. + * + * \param mps The MPS context to use. + * \param flags The bitmask indicating if and how the current message + * contributes to the current flight and handshake. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ); + +/** + * \brief Attempt to start writing a handshake message. + * + * \param mps The MPS context ot use. + * \param msg The pointer to a structure which defines the type + * and optionally the length of the handshake message + * to be written (provided by the user), and to which + * the write handle and additional data provided by MPS + * should be written on success. + * See the documentation of mbedtls_mps_handshake_out + * for more information. + * \param cb The callback to use for retransmitting, or \c NULL. + * If \c NULL, MPS internally makes a copy of the message. + * \param cb_ctx The opaque context to be passed to the retransmission + * callback \p cb on retransmission; must be \c NULL if + * \p cb is \c NULL. + * + * \note The question of whether to register a callback or not + * is a speed / space / convenience tradeoff: A raw copy + * of the message is convenient and fast, but increases + * the RAM usage by the size of the message. A callback, + * on the contrary, avoids this RAM overhead, but comes + * at the cost of manually sorting out which information + * is necessary to write the message and to generate and + * remember it prior to message writing in order to have + * a callback which is constant on the callback context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_out *msg, + mbedtls_mps_write_cb_t cb, + mbedtls_mps_write_cb_ctx_t *cb_ctx ); + +/** + * \brief Attempt to start writing application data. + * + * \param mps The MPS context to use. + * \param app The address to hold the outgoing application + * data buffer structure on success. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_application( mbedtls_mps *mps, + mbedtls_writer **app ); + +/** + * \brief Attempt to start writing a non-fatal alert. + * + * \param mps The MPS context to use. + * \param alert_type The type of the alert to be sent. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ); + +/** + * \brief Attempt to start writing a ChangeCipherSpec message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note Even if there is no content to be specified for + * ChangeCipherSpec messages, the writing must currently + * still be explicitly concluded through a call to + * mbedtls_mps_dispatch() in uniformity with the handling + * of the other content types. + * + * Originally, this splitting was mandatory because + * mbedtls_mps_dispatch() might attempt to deliver + * the outgoing message to the underlying transport + * immediately. In that case, we must be able to tell + * apart the following situations: + * (a) The call returned WANT_WRITE because there was still + * data to be flushed, but the underlying transport + * wasn't available. + * (b) The call returned WANT_WRITE because the alert/CCS + * message could be prepared but not yet delivered + * to the underlying transport. + * In case (a), the writing of the alert/CCS hasn't + * commenced, hence we need to call this function again + * for a retry. In case (b), in contrast, the record holding + * the alert/CCS has been prepared and only its delivery + * needs to be retried via mbedtls_mps_flush(). + * + * However, the current version of MPS does never attempt + * immediate delivery of messages to the underlying transport, + * and hence one might omit the explicit call to + * mbedtls_mps_dispatch() in this case. For now, however, + * we keep it for uniformity. + * + */ +int mbedtls_mps_write_ccs( mbedtls_mps *mps ); + +/** + * \brief Pause the writing of an outgoing handshake message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note If this function succeeds, the MPS holds back the writer + * used to write the message contents and returns it to the + * user on the next successful call to mbedtls_mps_write(). + */ +int mbedtls_mps_write_pause( mbedtls_mps *mps ); + +/** + * \brief Conclude the writing of the current outgoing message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This call does not necessarily immediately encrypt and + * deliver the message to the underlying transport. If that + * is desired, additionally mbedtls_mps_flush() must be + * called afterwards. + * + * \note Encryption may be postponed because there's more space + * in the current record. If the current record is full but + * there's more space in the current datagram, the record + * would be decrypted but not yet delivered to the underlying + * transport. + */ +int mbedtls_mps_dispatch( mbedtls_mps *mps ); + +/** + * \brief Enforce that all messages dispatched since the last call + * to this function get encrypted and delivered to the + * underlying transport. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. In this case, all previously dispatched + * messages have been delivered. + * \return #MBEDTLS_ERR_MPS_WANT_WRITE if the underlying transport + * could not yet deliver all messages. In this case, the + * call is remembered and it is guaranteed that no call to + * mbedtls_mps_write() succeeds before all messages have + * been delivered. + * \return Another negative error code otherwise. + * + */ +int mbedtls_mps_flush( mbedtls_mps *mps ); + +/** + * \brief Check which external interfaces need to become + * available in order for the MPS to be able to make + * progress towards starting the writing of a new message. + * + * \param mps The MPS context to use. + * \param flags Pointer ready to receive the bitflag indicating + * the external dependencies. + * + * \return \c 0 on success. In this case, \c *flags holds a + * bitwise OR of some of the following flags: + * - #MBEDTLS_MPS_BLOCK_READ + * The underlying transport must signal incoming data. + * - #MBEDTLS_MPS_BLOCK_WRITE + * The underlying transport must be ready to write data. + * \return A negative error code otherwise. + * + * \note A typical example for this is #MBEDTLS_MPS_BLOCK_WRITE + * being set after a call to mbedtls_mps_flush(). + * + */ +int mbedtls_mps_write_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ); + +/* + * The following function constitutes an abstraction break + * unavoidable by the DTLS standard, so it seems: + * The standard mandates that a HelloVerifyRequest in DTLS + * MUST be sent with the same record sequence number as the + * ClientHello it is replying to. + */ +/** + * \brief Force record sequence number of next record to be written + * (DTLS only). + * + * \param mps The MPS context to use. + * \param seq Buffer holding record sequence number to use next. + * + * \warning This function constitutes an abstraction break + * and should ONLY be used if it is unavoidable by + * the standard. It should almost always be fine to + * let the MPS choose the record sequence number. + * + * \note This function must be called before starting the + * write to which it applies (this is because forcing + * the record sequence number most likely mandates + * the use of a new record when starting the next write, + * while normally the MPS would attempt to merge + * messages of the same content type in the same record). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_force_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ); + + +/** + * Security parameter interface + */ + +/** + * \brief Register the next epoch of security parameters. + * + * \param mps The MPS context to use. + * \param params The address of the new security parameter set to register. + * \param id The address at which to store the identifier through + * which the security parameter set can subsequently be + * identified. + * + * \note The registration of the new security parameter set does + * not yet put it to use for reading or writing. To that end, + * use the functions mbedtls_mps_set_incoming_keys() and + * mbedtls_mps_set_outgoing_keys(), passing the identifier + * this function has written to \p id. +. + * \note The security parameter set \p params must be heap-allocated, + * and calling this function transfers ownership entirely to the + * MPS. In particular, no read, write or deallocation operation + * must be performed on \p params by the user after this function + * has been called. This leads to the following usage flow: + * - Allocate an ::mbedtls_mps_transform_t instance + * from the heap to hold the new security parameters. + * - Initialize and configure the security parameters. + * - Register the security parameters through + * a call to this function. + * - Enable the security parameters for reading + * and/or writing via mbedtls_mps_set_incoming_kets() + * or mbedtls_mps_set_outgoing_keys(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_add_key_material( mbedtls_mps *mps, + mbedtls_mps_transform_t *params, + mbedtls_mps_epoch_id *id ); + +/** + * \brief Set the security parameters for subsequent incoming messages. + * + * \param mps The MPS context to use. + * \param id The identifier of a set of security parameters + * previously registered via mbedtls_mps_add_key_material(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_set_incoming_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ); + +/** + * \brief Set the security parameters for subsequent outgoing messages. + * + * \param mps The MPS context to use. + * \param id The identifier for a set of security parameters + * previously registered via mbedtls_mps_add_key_material(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_set_outgoing_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ); + +/** + * Error handling and shutdown interface + */ + +/** + * \brief Send a fatal alert of the given type + * + * \param mps MPS context + * \param alert_type Type of alert to be sent. + * + * \return \c 0 on success. + * \return A negative error code otherwise. + * + * \note This call blocks the MPS except for mbedtls_mps_flush() + * which might still be called in case this function returns + * #MBEDTLS_ERR_WANT_WRITE, indicating that the alert couldn't + * be delivered. + * After delivery of the fatal alert, the user must free ths MPS. + */ +int mbedtls_mps_send_fatal( mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ); + +/** + * \brief Initiate or proceed with orderly shutdown. + * + * \param mps MPS context + * + * \return 0 on success, nonzero error code otherwise. + * + * \note This call closes the write-side of the connection and + * notifies the peer through an appropriate alert. Afterwards, + * the MPS' write functions are blocked, except for + * mbedtls_mps_flush() which might still be called in + * case this function returns #MBEDTLS_ERR_WANT_WRITE, + * indicating that the notification couldn't be delivered. + */ +int mbedtls_mps_close( mbedtls_mps *mps ); + +mbedtls_mps_connection_state_t mbedtls_mps_connection_state( + mbedtls_mps const *mps, + mbedtls_mps_blocking_reason_t *blocking_reason, + mbedtls_mps_blocking_info_t *blocking_info ); + +#endif /* MBEDTLS_MPS_H */ diff --git a/include/mbedtls/mps/reader.h b/include/mbedtls/mps/reader.h new file mode 100644 index 000000000000..ae701dcdbf7c --- /dev/null +++ b/include/mbedtls/mps/reader.h @@ -0,0 +1,597 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file mps_reader.h + * + * \brief This file defines reader objects, which together with their + * sibling writer objects form the basis for the communication + * between the various layers of the Mbed TLS messaging stack, + * as well as the communication between the messaging stack and + * the (D)TLS handshake protocol implementation. + * + * Readers provide a means of transferring incoming data from + * a 'producer' providing it in chunks of arbitrary size, to + * a 'consumer' which fetches and processes it in chunks of + * again arbitrary, and potentially different, size. + * + * Readers can thus be seen as datagram-to-stream converters, + * and they abstract away the following two tasks from the user: + * 1. The pointer arithmetic of stepping through a producer- + * provided chunk in smaller chunks. + * 2. The merging of incoming data chunks in case the + * consumer requests data in larger chunks than what the + * producer provides. + * + * The basic abstract flow of operation is the following: + * - Initially, the reader is in 'producing mode'. + * - The producer hands an incoming data buffer to the reader, + * moving it from 'producing' to 'consuming' mode. + * - The consumer subsequently fetches and processes the buffer + * content. Once that's done -- or partially done and a consumer's + * request can't be fulfilled -- the producer revokes the reader's + * access to the incoming data buffer, putting the reader back to + * producing mode. + * - The producer subsequently gathers more incoming data and hands + * it to the reader until it switches back to consuming mode + * if enough data is available for the last consumer request to + * be satisfiable. + * - Repeat the above. + * + * The abstract states of the reader from the producer's and + * consumer's perspective are as follows: + * + * - From the perspective of the consumer, the state of the + * reader consists of the following: + * - A byte stream representing (concatenation of) the data + * received through calls to mbedtls_mps_reader_get(), + * - A marker within that byte stream indicating which data + * can be considered processed, and hence need not be retained, + * when the reader is passed back to the producer via + * mbedtls_mps_reader_reclaim(). + * The marker is set via mbedtls_mps_reader_commit() + * which places it at the end of the current byte stream. + * The consumer need not be aware of the distinction between consumer + * and producer mode, because it only interfaces with the reader + * when the latter is in consuming mode. + * + * - From the perspective of the producer, the reader's state is one of: + * - Attached: The reader is in consuming mode. + * - Unset: No incoming data buffer is currently managed by the reader, + * and all previously handed incoming data buffers have been + * fully processed. More data needs to be fed into the reader + * via mbedtls_mps_reader_feed(). + * + * - Accumulating: No incoming data buffer is currently managed by the + * reader, but some data from the previous incoming data + * buffer hasn't been processed yet and is internally + * held back. + * The Attached state belongs to consuming mode, while the Unset and + * Accumulating states belong to producing mode. + * + * Transitioning from the Unset or Accumulating state to Attached is + * done via successful calls to mbedtls_mps_reader_feed(), while + * transitioning from Attached to either Unset or Accumulating (depending + * on what has been processed) is done via mbedtls_mps_reader_reclaim(). + * + * The following diagram depicts the producer-state progression: + * + * +------------------+ reclaim + * | Unset +<-------------------------------------+ get + * +--------|---------+ | +------+ + * | | | | + * | | | | + * | feed +---------+---+--+ | + * +--------------------------------------> <---+ + * | Attached | + * +--------------------------------------> <---+ + * | feed, enough data available +---------+---+--+ | + * | to serve previous consumer request | | | + * | | | | + * +--------+---------+ | +------+ + * +----> Accumulating |<-------------------------------------+ commit + * | +---+--------------+ reclaim, previous read request + * | | couldn't be fulfilled + * | | + * +--------+ + * feed, need more data to serve + * previous consumer request + * | + * | + * producing mode | consuming mode + * | + * + */ + +#ifndef MBEDTLS_MPS_READER_H +#define MBEDTLS_MPS_READER_H + +#include + +#include "common.h" +#include "error.h" + +struct mbedtls_mps_reader; +typedef struct mbedtls_mps_reader mbedtls_mps_reader; + +#define MBEDTLS_ERR_MPS_READER_DATA_LEFT MBEDTLS_MPS_READER_MAKE_ERROR( 0x1 ) /*!< An attempt to reclaim the data buffer from a reader failed because + * the user hasn't yet read and committed all of it. */ +#define MBEDTLS_ERR_MPS_READER_INVALID_ARG MBEDTLS_MPS_READER_MAKE_ERROR( 0x2 ) /*!< The parameter validation failed. */ +#define MBEDTLS_ERR_MPS_READER_NEED_MORE MBEDTLS_MPS_READER_MAKE_ERROR( 0x3 ) /*!< An attempt to move a reader to consuming mode through mbedtls_reader_feed() + * after pausing failed because the provided data is not sufficient to serve the + * the read requests that lead to the pausing. */ +#define MBEDTLS_ERR_MPS_READER_OUT_OF_DATA MBEDTLS_MPS_READER_MAKE_ERROR( 0x5 ) /*!< A read request failed because not enough data is available in the reader. */ +#define MBEDTLS_ERR_MPS_READER_INCONSISTENT_REQUESTS MBEDTLS_MPS_READER_MAKE_ERROR( 0x6 ) /*!< A read request after pausing and reactivating the reader failed because + * the request is not in line with the request made prior to pausing. The user + * must not change it's 'strategy' after pausing and reactivating a reader. */ +#define MBEDTLS_ERR_MPS_READER_OPERATION_UNEXPECTED MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED +#define MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR MBEDTLS_MPS_READER_MAKE_ERROR( 0x69 )/*!< An attempt to reclaim the data buffer from a reader fails because the reader + * has no accumulator it can use to backup the data that hasn't been processed. */ +#define MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL MBEDTLS_MPS_READER_MAKE_ERROR( 0x6a )/*!< An attempt to reclaim the data buffer from a reader fails beacuse the + * accumulator passed to the reader is not large enough to hold both the + * data that hasn't been processed and the excess of the last read-request. */ + +#define MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION MBEDTLS_MPS_READER_MAKE_ERROR( 0x9 ) /*!< The attempted operation violates the bounds of the currently active group. */ +#define MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS MBEDTLS_MPS_READER_MAKE_ERROR( 0xa ) /*!< The extended reader has reached the maximum number of groups, and another + * group cannot be opened. */ + + +/* + * Structure definitions + */ + +struct mbedtls_mps_reader +{ + unsigned char *frag; /*!< The fragment of incoming data managed by + * the reader; it is provided to the reader + * through mbedtls_mps_reader_feed(). The reader + * does not own the fragment and does not + * perform any allocation operations on it, + * but does have read and write access to it. + * + * The reader is in consuming mode if + * and only if \c frag is not \c NULL. */ + mbedtls_mps_stored_size_t frag_len; + /*!< The length of the current fragment. + * Must be 0 if \c frag == \c NULL. */ + mbedtls_mps_stored_size_t commit; + /*!< The offset of the last commit, relative + * to the first byte in the fragment, if + * no accumulator is present. If an accumulator + * is present, it is viewed as a prefix to the + * current fragment, and this variable contains + * an offset from the beginning of the accumulator. + * + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + mbedtls_mps_stored_size_t end; + /*!< The offset of the end of the last chunk + * passed to the user through a call to + * mbedtls_mps_reader_get(), relative to the first + * byte in the fragment, if no accumulator is + * present. If an accumulator is present, it is + * viewed as a prefix to the current fragment, and + * this variable contains an offset from the + * beginning of the accumulator. + * + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + mbedtls_mps_stored_size_t pending; + /*!< The amount of incoming data missing on the + * last call to mbedtls_mps_reader_get(). + * In particular, it is \c 0 if the last call + * was successful. + * If a reader is reclaimed after an + * unsuccessful call to mbedtls_mps_reader_get(), + * this variable is used to have the reader + * remember how much data should be accumulated + * so that the call to mbedtls_mps_reader_get() + * succeeds next time. + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + + /* The accumulator is only needed if we need to be able to pause + * the reader. A few bytes could be saved by moving this to a + * separate struct and using a pointer here. */ + + unsigned char *acc; /*!< The accumulator is used to gather incoming + * data if a read-request via mbedtls_mps_reader_get() + * cannot be served from the current fragment. */ + mbedtls_mps_stored_size_t acc_len; + /*!< The total size of the accumulator. */ + mbedtls_mps_stored_size_t acc_available; + /*!< The number of bytes currently gathered in + * the accumulator. This is both used in + * producing and in consuming mode: + * While producing, it is increased until + * it reaches the value of \c acc_remaining below. + * While consuming, it is used to judge if a + * get request can be served from the + * accumulator or not. + * Must not be larger than \c acc_len. */ + union + { + mbedtls_mps_stored_size_t acc_remaining; + /*!< This indicates the amount of data still + * to be gathered in the accumulator. It is + * only used in producing mode. + * Must be at most acc_len - acc_available. */ + mbedtls_mps_stored_size_t frag_offset; + /*!< If an accumulator is present and in use, this + * field indicates the offset of the current + * fragment from the beginning of the + * accumulator. If no accumulator is present + * or the accumulator is not in use, this is \c 0. + * It is only used in consuming mode. + * Must not be larger than \c acc_available. */ + } acc_share; +}; + +/* + * API organization: + * A reader object is usually prepared and maintained + * by some lower layer and passed for usage to an upper + * layer, and the API naturally splits according to which + * layer is supposed to use the respective functions. + */ + +/* + * Maintenance API (Lower layer) + */ + +/** + * \brief Initialize a reader object + * + * \param reader The reader to be initialized. + * \param acc The buffer to be used as a temporary accumulator + * in case get requests through mbedtls_mps_reader_get() + * exceed the buffer provided by mbedtls_mps_reader_feed(). + * This buffer is owned by the caller and exclusive use + * for reading and writing is given to the reader for the + * duration of the reader's lifetime. It is thus the caller's + * responsibility to maintain (and not touch) the buffer for + * the lifetime of the reader, and to properly zeroize and + * free the memory after the reader has been destroyed. + * \param acc_len The size in Bytes of \p acc. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_init( mbedtls_mps_reader *reader, + unsigned char *acc, + mbedtls_mps_size_t acc_len ); + +/** + * \brief Free a reader object + * + * \param reader The reader to be freed. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_free( mbedtls_mps_reader *reader ); + +/** + * \brief Pass chunk of data for the reader to manage. + * + * \param reader The reader context to use. The reader must be + * in producing mode. + * \param buf The buffer to be managed by the reader. + * \param buflen The size in Bytes of \p buffer. + * + * \return \c 0 on success. In this case, the reader will be + * moved to consuming mode and obtains read access + * of \p buf until mbedtls_mps_reader_reclaim() + * is called. It is the responsibility of the caller + * to ensure that the \p buf persists and is not changed + * between successful calls to mbedtls_mps_reader_feed() + * and mbedtls_mps_reader_reclaim(). + * \return \c MBEDTLS_ERR_MPS_READER_NEED_MORE if more input data is + * required to fulfill a previous request to mbedtls_mps_reader_get(). + * In this case, the reader remains in producing mode and + * takes no ownership of the provided buffer (an internal copy + * is made instead). + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error code on + * different kinds of failures. + */ +int mbedtls_mps_reader_feed( mbedtls_mps_reader *reader, + unsigned char *buf, + mbedtls_mps_size_t buflen ); + +/** + * \brief Reclaim reader's access to the current input buffer. + * + * \param reader The reader context to use. The reader must be + * in consuming mode. + * \param paused If not \c NULL, the integer at address \p paused will be + * modified to indicate whether the reader has been paused + * (value \c 1) or not (value \c 0). Pausing happens if there + * is uncommitted data and a previous request to + * mbedtls_mps_reader_get() has exceeded the bounds of the + * input buffer. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *reader, + int *paused ); + +/* + * Usage API (Upper layer) + */ + +/** + * \brief Request data from the reader. + * + * \param reader The reader context to use. The reader must + * be in consuming mode. + * \param desired The desired amount of data to be read, in Bytes. + * \param buffer The address to store the buffer pointer in. + * This must not be \c NULL. + * \param buflen The address to store the actual buffer + * length in, or \c NULL. + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != \c NULL) or \c desired + * (if \c buflen == \c NULL). The user has read access + * to the buffer and guarantee of stability of the data + * until the next call to mbedtls_mps_reader_reclaim(). + * \return #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA if there is not enough + * data available to serve the get request. In this case, the + * reader remains intact and in consuming mode, and the consumer + * should retry the call after a successful cycle of + * mbedtls_mps_reader_reclaim() and mbedtls_mps_reader_feed(). + * If, after such a cycle, the consumer requests a different + * amount of data, the result is implementation-defined; + * progress is guaranteed only if the same amount of data + * is requested after a mbedtls_mps_reader_reclaim() and + * mbedtls_mps_reader_feed() cycle. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * code for different kinds of failure. + * + * \note Passing \c NULL as \p buflen is a convenient way to + * indicate that fragmentation is not tolerated. + * It's functionally equivalent to passing a valid + * address as buflen and checking \c *buflen == \c desired + * afterwards. + */ +int mbedtls_mps_reader_get( mbedtls_mps_reader *reader, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Mark data obtained from mbedtls_mps_reader_get() as processed. + * + * This call indicates that all data received from prior calls to + * mbedtls_mps_reader_get() has been or will have been + * processed when mbedtls_mps_reader_reclaim() is called, + * and thus need not be backed up. + * + * This function has no user observable effect until + * mbedtls_mps_reader_reclaim() is called. In particular, + * buffers received from mbedtls_mps_reader_get() remain + * valid until mbedtls_mps_reader_reclaim() is called. + * + * \param reader The reader context to use. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_commit( mbedtls_mps_reader *reader ); + +/* + * Interface for extended reader + */ + +struct mbedtls_mps_reader_ext; +typedef struct mbedtls_mps_reader_ext mbedtls_mps_reader_ext; + +#define MBEDTLS_MPS_READER_MAX_GROUPS 4 + +struct mbedtls_mps_reader_ext +{ + unsigned cur_grp; /*!< The 0-based index of the currently active group. + * The group of index 0 always exists and represents + * the entire logical message buffer. */ + mbedtls_mps_stored_size_t grp_end[MBEDTLS_MPS_READER_MAX_GROUPS]; + /*!< The offsets marking the ends of the currently + * active groups. The first cur_grp + 1 entries are + * valid and always weakly descending (subsequent + * groups are subgroups of their predecessors ones). */ + + mbedtls_mps_reader *rd; /*!< Underlying writer object - may be \c NULL. */ + mbedtls_mps_stored_size_t ofs_fetch; + /*!< The offset of the first byte of the next chunk. */ + mbedtls_mps_stored_size_t ofs_commit; + /*!< The offset of first byte beyond + * the last committed chunk. */ +}; + +/** + * \brief Initialize an extended reader object + * + * \param reader The extended reader context to initialize. + * \param size The total size of the logical buffer to + * be managed by the extended reader. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_init_ext( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t size ); + +/** + * \brief Free an extended reader object + * + * \param reader The extended reader context to be freed. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_free_ext( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Fetch a data chunk from an extended reader + * + * \param reader The extended reader to be used. + * \param desired The desired amount of incoming data to be read. + * \param buffer The address at which to store the address + * of the incoming data buffer on success. + * \param buflen The address at which to store the actual + * size of the incoming data buffer on success. + * May be \c NULL (see below). + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != NULL) or \p desired + * (if \c buflen == \c NULL). + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if the read + * request exceeds the bounds of the current group. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + * \note Passing \c NULL as buflen is a convenient way to + * indicate that fragmentation is not tolerated. + * It's functionally equivalent to passing a valid + * address as buflen and checking \c *buflen == \c desired + * afterwards. + * + * + */ +int mbedtls_mps_reader_get_ext( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Signal that all input buffers previously obtained + * from mbedtls_mps_reader_get_ext are fully processed. + * \param reader The extended reader context to use. + * + * This function marks the previously fetched data as fully + * processed and invalidates their respective buffers. + * + * \warning Once this function is called, you must not use the + * pointers corresponding to the committed data anymore. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_commit_ext( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Open a new logical subbuffer. + * + * \param reader The extended reader context to use. + * \param group_size The offset of the end of the subbuffer + * from the end of the last successful fetch. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if + * the new group is not contained in the + * current group. In this case, the extended + * reader is unchanged and hence remains intact. + * This is a very important error condition that + * catches e.g. if the length field for some + * substructure (e.g. an extension within a Hello + * message) claims that substructure to be larger + * than the message itself. + * \return #MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS if the internal + * threshold for the maximum number of groups exceeded. + * This is an internal error, and it should be + * statically verifiable that it doesn't occur. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + */ +int mbedtls_mps_reader_group_open( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t group_size ); + +/** + * \brief Close the most recently opened logical subbuffer. + * + * \param reader The extended reader context to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if + * the current logical subbuffer hasn't been + * fully fetched and committed. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + */ +int mbedtls_mps_reader_group_close( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Attach a reader to an extended reader. + * + * Once a reader has been attached to an extended reader, + * subsequent calls to mbedtls_mps_reader_commit_ext and + * mbedtls_mps_reader_get_ext will be routed through the + * corresponding calls to mbedtls_mps_reader_commit resp. + * mbedtls_mps_reader_get after the extended reader has + * done its bounds checks. + * + * \param rd_ext The extended reader context to use. + * \param rd The reader to bind to the extended reader \p rd_ext. + * + * \return \c 0 on succes. + * \return Another negative error code on failure. + * + */ +int mbedtls_mps_reader_attach( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_reader *rd ); + +/** + * \brief Detach a reader from an extended reader. + * + * \param rd_ext The extended reader context to use. + * + * \return \c 0 on succes. + * \return Another negative error code on failure. + * + */ +int mbedtls_mps_reader_detach( mbedtls_mps_reader_ext *rd_ext ); + +/** + * \brief Check if the extended reader is finished processing + * the logical buffer it was setup with. + * + * \param rd_ext The extended reader context to use. + * + * \return \c 0 if all groups opened via mbedtls_mps_reader_group_open() + * have been closed via mbedtls_mps_reader_group_close(), and + * the entire logical buffer as defined by the \c size + * argument in mbedtls_mps_reader_init_ext() has been fetched + * and committed. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code otherwise. + * + */ +int mbedtls_mps_reader_check_done( mbedtls_mps_reader_ext const *rd_ext ); + +#endif /* MBEDTLS_MPS_READER_H */ diff --git a/include/mbedtls/mps/trace.h b/include/mbedtls/mps/trace.h new file mode 100644 index 000000000000..087ca1f01690 --- /dev/null +++ b/include/mbedtls/mps/trace.h @@ -0,0 +1,187 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file mps_trace.h + * + * \brief Tracing module for MPS + */ + +#ifndef MBEDTLS_MPS_TRACE_H +#define MBEDTLS_MPS_TRACE_H + +#include "common.h" +#include "trace.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_vsnprintf vsnprintf +#endif /* MBEDTLS_PLATFORM_C */ + +/* + * Adapt this to enable/disable tracing output + * from the various layers of the MPS. + */ + +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_1 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_2 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_3 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_4 +#define MBEDTLS_MPS_TRACE_ENABLE_READER +#define MBEDTLS_MPS_TRACE_ENABLE_WRITER + +/* + * To use the existing trace module, only change + * MBEDTLS_MPS_TRACE_ENABLE_XXX above, but don't modify the + * rest of this file. + */ + +typedef enum +{ + MBEDTLS_MPS_TRACE_TYPE_COMMENT, + MBEDTLS_MPS_TRACE_TYPE_CALL, + MBEDTLS_MPS_TRACE_TYPE_ERROR, + MBEDTLS_MPS_TRACE_TYPE_RETURN +} mbedtls_mps_trace_type; + +#define MBEDTLS_MPS_TRACE_BIT_LAYER_1 1 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_2 2 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_3 3 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_4 4 +#define MBEDTLS_MPS_TRACE_BIT_WRITER 5 +#define MBEDTLS_MPS_TRACE_BIT_READER 6 + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_1) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_1 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_1 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_1 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_2) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_2 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_2 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_2 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_3) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_3 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_3 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_3 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_4) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_4 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_4 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_4 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_READER) +#define MBEDTLS_MPS_TRACE_MASK_READER (1u << MBEDTLS_MPS_TRACE_BIT_READER ) +#else +#define MBEDTLS_MPS_TRACE_MASK_READER 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_WRITER) +#define MBEDTLS_MPS_TRACE_MASK_WRITER (1u << MBEDTLS_MPS_TRACE_BIT_WRITER ) +#else +#define MBEDTLS_MPS_TRACE_MASK_WRITER 0 +#endif + +#define MBEDTLS_MPS_TRACE_MASK ( MBEDTLS_MPS_TRACE_MASK_LAYER_1 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_2 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_3 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_4 | \ + MBEDTLS_MPS_TRACE_MASK_READER | \ + MBEDTLS_MPS_TRACE_MASK_WRITER ) + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + +/* We have to avoid globals because E-ACSL chokes on them... + * Wrap everything in stub functions. */ +int mbedtls_mps_trace_get_depth( void ); +void mbedtls_mps_trace_inc_depth( void ); +void mbedtls_mps_trace_dec_depth( void ); + +void mbedtls_mps_trace_color( int id ); +void mbedtls_mps_trace_indent( int level, mbedtls_mps_trace_type ty ); + +void mbedtls_mps_trace_print_msg( int id, int line, const char *format, ... ); + +#define MBEDTLS_MPS_TRACE( type, ... ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + mbedtls_mps_trace_indent( mbedtls_mps_trace_get_depth(), type ); \ + mbedtls_mps_trace_color( mbedtls_mps_trace_id ); \ + mbedtls_mps_trace_print_msg( mbedtls_mps_trace_id, __LINE__, __VA_ARGS__ ); \ + mbedtls_mps_trace_color( 0 ); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_INIT( ... ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_CALL, __VA_ARGS__ ); \ + mbedtls_mps_trace_inc_depth(); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_END( val ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_RETURN, "%d (-%#04x)", \ + (int) (val), -((unsigned)(val)) ); \ + mbedtls_mps_trace_dec_depth(); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_RETURN( val ) \ + do { \ + /* Breaks tail recursion. */ \ + int ret__ = val; \ + MBEDTLS_MPS_TRACE_END( ret__ ); \ + return( ret__ ); \ + } while( 0 ) + +#else /* MBEDTLS_MPS_TRACE */ + +static inline void mps_trace_variable_sink( const char* fmt, ...) +{ + ((void) fmt); +} + +/* Make sure to "use" arguments, to avoid unused variable warnings. */ +#define MBEDTLS_MPS_TRACE( type, ... ) \ + do { ((void) type); mps_trace_variable_sink( __VA_ARGS__ ); } while( 0 ) +#define MBEDTLS_MPS_TRACE_INIT( ... ) \ + do { mps_trace_variable_sink( __VA_ARGS__ ); } while( 0 ) +#define MBEDTLS_MPS_TRACE_END do { } while( 0 ) + +#define MBEDTLS_MPS_TRACE_RETURN( val ) return( val ); + +#endif /* MBEDTLS_MPS_TRACE */ + +#define MBEDTLS_MPS_TRACE_COMMENT(...) \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, __VA_ARGS__ ) +#define MBEDTLS_MPS_TRACE_ERROR(...) \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, __VA_ARGS__ ) + +#endif /* MBEDTLS_MPS_TRACE_H */ diff --git a/include/mbedtls/mps/transform.h b/include/mbedtls/mps/transform.h new file mode 100644 index 000000000000..f9c216b30f39 --- /dev/null +++ b/include/mbedtls/mps/transform.h @@ -0,0 +1,126 @@ +/** + * \file transform.h + * + * \brief Abstraction layer for record protection. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_TRANSFORM_H +#define MBEDTLS_MPS_TRANSFORM_H + +#include +#include + +/* + * \brief Opaque representation of record protection mechanisms. + */ +typedef void mbedtls_mps_transform_t; + +/* + * \brief Structure representing an inclusion of two buffers. + */ +typedef struct +{ + unsigned char *buf; /*!< The parent buffer containing the + * record payload as a sub buffer. */ + size_t buf_len; /*!< The length of the parent buffer. */ + size_t data_offset; /*!< The offset of the payload sub buffer + * from the beginning of the parent buffer. */ + size_t data_len; /*!< The length of the payload sub buffer. + * For more information on its use in the + * Layer 2 context structure, see the + * documentation of ::mps_l2. */ +} mps_l2_bufpair; + +/* + * \brief Structure representing protected and unprotected (D)TLS records. + */ +typedef struct +{ + uint32_t ctr[2]; /*!< The record sequence number. */ + uint16_t epoch; /*!< The epoch to which the record belongs. */ + uint8_t type; /*!< The record content type. */ + uint8_t major_ver; /*!< The major TLS version of the record. */ + uint8_t minor_ver; /*!< The minor TLS version of the record. */ + + mps_l2_bufpair buf; /*!< The record's plaintext or ciphertext, + * surrounded by a parent buffer. */ +} mps_rec; + +typedef int mbedtls_mps_transform_free_t( void *transform ); +extern mbedtls_mps_transform_free_t *mbedtls_mps_transform_free; + +/* + * \brief Encrypt a record using a particular protection mechanism. + * + * \param transform The protection mechanism to use to encrypt the record. + * \param rec The plaintext record to protect. The margin around the + * plaintext buffer must be large enough to hold the + * record expansion, or otherwise the encryption will fail. + * \param f_rng A secure PRNG if needed by the protection mechanism. + * \param p_rng A context to be passed to \p f_rng. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_encrypt_t( + void *transform, mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +extern mbedtls_mps_transform_encrypt_t *mbedtls_mps_transform_encrypt; + +/* + * \brief Decrypt a record using a particular protection mechanism. + * + * \param transform The protection mechanism to use to decrypt the record. + * \param rec The ciphertext record to protect. + * \param f_rng A secure PRNG if needed by the protection mechanism. + * \param p_rng A context to be passed to \p f_rng. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_decrypt_t( void *transform, + mps_rec *rec ); + +extern mbedtls_mps_transform_decrypt_t *mbedtls_mps_transform_decrypt; + +/* + * \brief Obtain the encryption expansion for a record protection mechanism. + * + * \param transform The protection mechanism to use. + * \param pre_exp The address at which to store the pre-expansion during + * encryption. The pre-expansion must be known in advance + * and be independent of the record that's encrypted. + * \param post_exp The address at which to store the maximum post-expansion + * during encryption. The post-expansion may vary from record + * to record, and the value returned by this function must + * be such that encryption always succeeds if at least the + * returned amount of space is available. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_get_expansion_t( void *transform, + size_t *pre_exp, size_t *post_exp ); + +extern mbedtls_mps_transform_get_expansion_t *mbedtls_mps_transform_get_expansion; + +#endif /* MBEDTLS_MPS_TRANSFORM_H */ diff --git a/include/mbedtls/mps/transport.h b/include/mbedtls/mps/transport.h new file mode 100644 index 000000000000..696ba638b908 --- /dev/null +++ b/include/mbedtls/mps/transport.h @@ -0,0 +1,101 @@ +/** + * \file transport.h + * + * \brief Type definitions for the transport layer underlying MPS. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_TRANSPORT_H +#define MBEDTLS_MPS_TRANSPORT_H + +#include +#include + +/** + * \brief Callback type: receive data from the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the receive callback (typically a file + * descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * + * \return The callback must return the number of bytes received, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ + * must be returned when the operation would block. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_mps_recv_t( void *ctx, + unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network, with timeout + * + * \note That callback must block until data is received, or the + * timeout delay expires, or the operation is interrupted by a + * signal. + * + * \param ctx Context for the receive callback (typically a file descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * \param timeout Maximum nomber of millisecondes to wait for data + * 0 means no timeout (potentially waiting forever) + * + * \return The callback must return the number of bytes received, + * or a non-zero error code: + * \c MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * \c MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_mps_recv_timeout_t( void *ctx, + unsigned char *buf, + size_t len, + uint32_t timeout ); + +/** + * \brief Callback type: send data on the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the send callback (typically a file descriptor) + * \param buf Buffer holding the data to send + * \param len Length of the data to send + * + * \return The callback must return the number of bytes sent if any, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_WRITE + * must be returned when the operation would block. + * + * \note The callback is allowed to send fewer bytes than requested. + * It must always return the number of bytes actually sent. + */ +typedef int mbedtls_mps_send_t( void *ctx, + const unsigned char *buf, + size_t len ); + +#endif /* MBEDTLS_MPS_TRANSPORT_H */ diff --git a/include/mbedtls/mps/writer.h b/include/mbedtls/mps/writer.h new file mode 100644 index 000000000000..8b506482d607 --- /dev/null +++ b/include/mbedtls/mps/writer.h @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file writer.h + * + * \brief This file defines writer objects, which together with their + * sibling reader objects form the basis for the communication + * between the various layers of the Mbed TLS messaging stack, + * as well as the communication between the messaging stack and + * the (D)TLS handshake protocol implementation. + * + * Writers provide a means of communication between + * - a 'provider' supplying buffers to hold outgoing data, and + * - a 'consumer' writing data into these buffers. + * Both the size of the data buffers the provider prepares and the size of + * chunks in which the consumer writes the data are variable and may be + * different. It is the writer's responsibility to do the necessary copying + * and pointer arithmetic. + * + * For example, the provider might be the [D]TLS record layer, offering + * to protect and transport data in records of varying size (depending + * on the current configuration and the amount of data left in the current + * datagram, for example), while the consumer would be the handshake logic + * layer which needs to write handshake messages. The size of handshake + * messages are entirely independent of the size of records used to transport + * them, and the writer helps to both split large handshake messages across + * multiple records, and to pack multiple small handshake messages into + * a single record. This example will be elaborated upon in the next paragraph. + * + * Basic flow of operation: + * First, the provider feeds an outgoing data buffer to the writer, transferring + * it from 'providing' to 'consuming' state; in the example, that would be record + * layer providing the plaintext buffer for the next outgoing record. The + * consumer subsequently fetches parts of the buffer and writes data to them, + * which might happen multiple times; in the example, the handshake logic + * layer might request and fill a buffer for each handshake message in the + * current outgoing flight, and these requests would be served from successive + * chunks in the same record plaintext buffer if size permits. Once the consumer + * is done, the provider revokes the writer's access to the data buffer, + * putting the writer back to providing state, and processes the data provided + * in the outgoing data buffer; in the example, that would be the record layer + * encrypting the record and dispatching it to the underlying transport. + * Afterwards, the provider feeds another outgoing data buffer to the writer + * and the cycle starts again. + * In the event that a consumer's request cannot be fulfilled on the basis of + * the outgoing data buffer provided by the provider (in the example, + * the handshake layer might attempt to send a 4KB CRT chain but the current + * record size offers only 2KB), the writer transparently offers a temporary + * 'queue' buffer to hold the data to the consumer. The contents of this queue + * buffer will be gradually split among the next outgoing data buffers when + * the provider subsequently provides them; in the example, the CRT chain would + * be split amont multiple records when the record layer hands more plaintext + * buffers to the writer. The details of this process are left to the writer + * and are opaque both to the consumer and the provider. + * + * Abstract models: + * From the perspective of the consumer, the state of the writer is a + * potentially empty list of output buffers that the writer has provided + * to the consumer. New buffers can be requested through calls to + * mbedtls_writer_get(), while previously obtained output buffers can be + * marked processed through calls to mbedtls_writer_commit(), emptying the + * list of output buffers and invalidating them from the consumer's perspective. + * + */ + +#ifndef MBEDTLS_WRITER_H +#define MBEDTLS_WRITER_H + +#include +#include + +#include "common.h" + +struct mbedtls_writer; +typedef struct mbedtls_writer mbedtls_writer; + +struct mbedtls_writer_ext; +typedef struct mbedtls_writer_ext mbedtls_writer_ext; + +/* + * Error codes returned from the writer. + */ + +/** An attempt was made to reclaim a buffer from the writer, + * but the buffer hasn't been fully used up, yet. */ +#define MBEDTLS_ERR_WRITER_DATA_LEFT MBEDTLS_WRITER_MAKE_ERROR( 0x1 ) +/** The validation of input parameters failed. */ +#define MBEDTLS_ERR_WRITER_INVALID_ARG MBEDTLS_WRITER_MAKE_ERROR( 0x2 ) +/** The provided outgoing data buffer was not large enough to + * hold all queued data that's currently pending to be + * delivered. */ +#define MBEDTLS_ERR_WRITER_NEED_MORE MBEDTLS_WRITER_MAKE_ERROR( 0x3 ) +/** The requested operation is not possible + * in the current state of the writer. */ +#define MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED +/** The remaining amount of space for outgoing data is not + * sufficient to serve the user's request. The current + * outgoing data buffer must be reclaimed, dispatched, + * and a fresh outgoing data buffer must be fed to the + * writer. */ +#define MBEDTLS_ERR_WRITER_OUT_OF_DATA MBEDTLS_WRITER_MAKE_ERROR( 0x5 ) +/** A write-request was issued to the extended writer that + * exceeds the bounds of the most recently added group. */ +#define MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION MBEDTLS_WRITER_MAKE_ERROR( 0x9 ) +/** The extended writer has reached the maximum number of + * groups, and another group cannot be added. */ +#define MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS MBEDTLS_WRITER_MAKE_ERROR( 0xa ) + +/** The identifier to use in mbedtls_writer_reclaim() to + * force the reclamation of the outgoing data buffer even + * if there's space remaining. */ +#define MBEDTLS_WRITER_RECLAIM_FORCE 1 +/** The identifier to use in mbedtls_writer_reclaim() if + * the call should only succeed if the current outgoing data + * buffer has been fully used up. */ +#define MBEDTLS_WRITER_RECLAIM_NO_FORCE 0 + +/** \brief The type of states for the reader. + * + * Possible values are: + * - #MBEDTLS_WRITER_PROVIDING (initial state) + * The writer awaits buffers for holding outgoing + * data to be assigned to it via mbedtls_writer_feed(). + * - #MBEDTLS_WRITER_PRODUCING + * The writer has buffers to serve write requests from. + **/ +typedef unsigned char mbedtls_writer_state_t; +#define MBEDTLS_WRITER_PROVIDING ( (mbedtls_writer_state_t) 0) +#define MBEDTLS_WRITER_CONSUMING ( (mbedtls_writer_state_t) 1) + +struct mbedtls_writer +{ + /** The current buffer to hold outgoing data. */ + unsigned char *out; + /** The queue buffer from which to serve write requests that would + * exceed the current outgoing data buffer's bounds. May be \c NULL. */ + unsigned char *queue; + /** The size in bytes of the outgoing data buffer \c out. */ + mbedtls_mps_stored_size_t out_len; + /** The length of the queue buffer \c queue. */ + mbedtls_mps_stored_size_t queue_len; + + /** The offset from the beginning of the outgoing data buffer indicating + * the amount of data that the user has already finished writing. + * + * Note: When a queue buffer is in use, this may be larger than the length + * of the outgoing data buffer, and is computed as if the outgoing + * data buffer was immediately followed by the queue buffer. + * + * This is only used when the writer is in consuming state, i.e. + * state == MBEDTLS_WRITER_CONSUMING; in this case, its value + * is smaller or equal to out_len + queue_len. + */ + mbedtls_mps_stored_size_t committed; + + /** The offset from the beginning of the outgoing data buffer of the + * end of the last fragment handed to the user. + * + * Note: When a queue buffer is in use, this may be larger than the + * length of the outgoing data buffer, and is computed as if the outgoing + * data buffer was immediately followed by the queue buffer. + * + * This is only used when the writer is in consuming state, + * i.e. state == MBEDTLS_WRITER_CONSUMING; in this case, + * its value is smaller or equal to out_len + queue_len. + */ + mbedtls_mps_stored_size_t end; + + /** In consuming state, this denotes the size of the overlap between the + * queue and the current out buffer, once end > out_len. + * If end < out_len, its value is \c 0. + * In providing state, this denotes the amount of data from the queue that + * has already been copied to some outgoing data buffer. + */ + mbedtls_mps_stored_size_t queue_next; + /** The amount of data within the queue buffer that hasn't been copied to + * some outgoing data buffer yet. This is only used in providing state, and + * if the writer uses a queue (queue != NULL), and in this + * case its value is at most queue_len - queue_next. + */ + mbedtls_mps_stored_size_t queue_remaining; + /** The writer's state. See ::mbedtls_writer_state_t. */ + mbedtls_writer_state_t state; +}; + +/** The type of indices for groups in extended writers. */ +typedef unsigned char mbedtls_writer_ext_grp_index_t; + +/* INTERNAL NOTE: + * + * The value for MBEDTLS_WRITER_MAX_GROUPS needs to be revisited once + * writers are comprehensively used in the message writing functions + * used by the handshake logic layer. Reducing this value saves a few + * bytes in ::mbedtls_writer_ext. + */ +/** The maximum number of nested groups that can be opened in an + * extended writer. */ +#define MBEDTLS_WRITER_MAX_GROUPS ( (mbedtls_writer_ext_grp_index_t) 5 ) + +struct mbedtls_writer_ext +{ + /** The underlying writer object - may be \c NULL. */ + mbedtls_writer *wr; + /** The offsets marking the ends of the currently active groups. + * The first cur_grp + 1 entries are valid and always + * weakly descending (subsequent groups are subgroups of their + * predecessors ones). */ + mbedtls_mps_stored_size_t grp_end[MBEDTLS_WRITER_MAX_GROUPS]; + /** The offset of the first byte of the next chunk. */ + mbedtls_mps_stored_size_t ofs_fetch; + /**< The offset of first byte beyond the last committed chunk. */ + mbedtls_mps_stored_size_t ofs_commit; + /** The 0-based index of the currently active group. + * The group of index 0 always exists and represents + * the entire logical message buffer. */ + mbedtls_writer_ext_grp_index_t cur_grp; +}; + +/** + * \brief Initialize a writer object + * + * \param writer The writer to be initialized. + * \param queue The buffer to be used as dispatch queue if + * buffer provided via mbedtls_writer_feed() + * isn't sufficient. + * \param queue_len The size in Bytes of \p queue. + */ +void mbedtls_writer_init( mbedtls_writer *writer, + unsigned char *queue, + mbedtls_mps_size_t queue_len ); + +/** + * \brief Free a writer object + * + * \param writer The writer to be freed. + */ +void mbedtls_writer_free( mbedtls_writer *writer ); + +/** + * \brief Pass output buffer to the writer. + * + * This function is used to transition the writer + * from providing to consuming state. + * + * \param writer The writer context to be used. + * \param buf The buffer that outgoing data can be written to + * and that the writer should manage. + * \param buflen The length of the outgoing data buffer. + * + * \return \c 0 on success. In this case, the writer is + * in consuming state afterwards. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED if + * the writer is not in providing state. In this case, + * the writer is unmodified and can still be used. + * In particular, the writer stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_NEED_MORE if the provided + * outgoing data buffer was completely filled by data + * that had been internally queued in the writer. + * In this case, the writer stays in consuming state, + * but the content of the output buffer is ready to be + * dispatched in the same way as after a cycle of calls + * to mbedtls_writer_feed(), mbedtls_writer_get(), + * mbedtls_writer_commit(), mbedtls_writer_reclaim(). + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_feed( mbedtls_writer *writer, + unsigned char *buf, + mbedtls_mps_size_t buflen ); + +/** + * \brief Attempt to reclaim output buffer from writer, + * + * This function is used to transition the writer + * from consuming to providing state. + * + * \param writer The writer context to be used. + * \param queued The address at which to store the amount of + * outgoing data that has been queued. May be \c NULL + * if this information is not required. + * \param force Indicates whether the output buffer should + * be reclaimed even if there's space left. + * Must be either #MBEDTLS_WRITER_RECLAIM_FORCE + * or #MBEDTLS_WRITER_RECLAIM_NO_FORCE. + * + * \return \c 0 on success. In this case, the writer is in + * providing state afterwards. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED if + * the writer is not in consuming state. In this case, + * the writer is unmodified and can still be used. + * In particular, the writer stays in providing state. + * \return #MBEDTLS_ERR_WRITER_DATA_LEFT if there is space + * left to be written in the output buffer. + * In this case, the writer stays in consuming state. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + * On success, \c *queued contains the number of bytes that + * have been queued internally in the writer and will be + * written to the next buffer(s) that is fed to the writer. + * + */ +int mbedtls_writer_reclaim( mbedtls_writer *writer, + mbedtls_mps_size_t *queued, + mbedtls_mps_size_t *written, + int force ); + +/** + * \brief Check how many bytes have already been written + * to the current output buffer. + * + * \param writer Writer context + * \param written Pointer to receive amount of data already written. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_bytes_written( mbedtls_writer *writer, + mbedtls_mps_size_t *written ); + +/** + * \brief Signal that all output buffers previously obtained + * from mbedtls_writer_get() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit( mbedtls_writer *writer ); + +/** + * \brief Signal that parts of the output buffers obtained + * from mbedtls_writer_get() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param omit The number of bytes at the end of the last output + * buffer obtained from mbedtls_writer_get() that should + * not be committed. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit_partial( mbedtls_writer *writer, + mbedtls_mps_size_t omit ); + +/** + * \brief Request buffer to hold outbound data. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param desired The desired size of the outgoing data buffer. + * \param buffer The address at which to store the address + * of the outgoing data buffer on success. + * \param buflen The address at which to store the actual + * size of the outgoing data buffer on success. + * May be \c NULL (see below). + * + * \note If \p buflen is \c NULL, the function fails + * if it cannot provide an outgoing data buffer + * of the requested size \p desired. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return #MBEDTLS_ERR_WRITER_OUT_OF_SPACE if there is not + * enough space available to serve the request. + * In this case, the writer remains intact, and + * additional space can be provided by reclaiming + * the current output buffer via mbedtls_writer_reclaim() + * and feeding a new one via mbedtls_writer_feed(). + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_get( mbedtls_writer *writer, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Initialize an extended writer object + * + * \param writer The extended writer context to initialize. + * \param size The total size of the logical buffer to + * be managed by the extended writer. + * + */ +void mbedtls_writer_init_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t size ); + +/** + * \brief Free an extended writer object + * + * \param writer The extended writer context to be freed. + */ +void mbedtls_writer_free_ext( mbedtls_writer_ext *writer ); + +/** + * \brief Request buffer to hold outbound data. + * + * \param writer The extended writer context to use. + * \param desired The desired size of the outgoing data buffer. + * \param buffer The address at which to store the address + * of the outgoing data buffer on success. + * \param buflen The address at which to store the actual + * size of the outgoing data buffer on success. + * May be \c NULL (see below). + * + * \note If \p buflen is \c NULL, the function fails + * if it cannot provide an outgoing data buffer + * of the requested size \p desired. + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != NULL) or \p desired + * (if \c buflen is \c NULL). + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if the write + * request exceeds the bounds of the current group. + * + */ +int mbedtls_writer_get_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Signal that all output buffers previously obtained + * from mbedtls_writer_get_ext() are ready to be dispatched. + * + * \param writer The extended writer context to use. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get_ext() are invalid and must not + * be accessed anymore. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_commit_ext( mbedtls_writer_ext *writer ); + +/** + * \brief Signal that parts of the output buffers obtained + * from mbedtls_writer_get_ext() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param omit The number of bytes at the end of the last output + * buffer obtained from mbedtls_writer_get_ext() that should + * not be committed. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get_ext() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit_partial_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t omit ); + +/** + * \brief Open a new logical subbuffer. + * + * \param writer The extended writer context to use. + * \param group_size The offset of the end of the subbuffer + * from the end of the last successful fetch. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if + * the new group is not contained in the + * current group. In this case, the extended + * writer is unchanged and hence remains intact. + * \return #MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS if the internal + * threshold for the maximum number of groups exceeded. + * This is an internal error, and it should be + * statically verifiable that it doesn't occur. + * \return Another negative error code otherwise. + * + */ +int mbedtls_writer_group_open( mbedtls_writer_ext *writer, + mbedtls_mps_size_t group_size ); + +/** + * \brief Close the most recently opened logical subbuffer. + * + * \param writer The extended writer context to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if + * the current logical subbuffer hasn't been + * fully fetched and committed. + * \return #MBEDTLS_ERR_WRITER_NO_GROUP if there is no + * group opened currently. + * \return Another negative error code otherwise. + * + */ +int mbedtls_writer_group_close( mbedtls_writer_ext *writer ); + +/** + * \brief Attach a writer to an extended writer. + * + * Once a writer has been attached to an extended writer, + * subsequent calls to mbedtls_writer_commit_ext() and + * mbedtls_writer_get_ext() will be routed through the + * corresponding calls to mbedtls_writer_commit() resp. + * mbedtls_writer_get() after the extended writer has + * done its bounds checks. + * + * \param wr_ext The extended writer context to use. + * \param wr The writer to bind to the extended writer \p wr_ext. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_attach( mbedtls_writer_ext *wr_ext, + mbedtls_writer *wr ); +/** + * \brief Detach a writer from an extended writer. + * + * \param wr_ext The extended writer context to use. + * \param committed Address to which to write the number of committed bytes + * May be \c NULL if this information is not needed. + * \param uncommitted Address to which to write the number of uncommitted bytes + * May be \c NULL if this information is not needed. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_detach( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t *committed, + mbedtls_mps_size_t *uncommitted ); + +/** + * \brief Check if the extended writer has finished processing + * the logical buffer it was setup with. + * + * \param writer The extended writer context to use. + * + * \return \c 0 if all groups opened via mbedtls_writer_group_open() + * have been closed via mbedtls_writer_group_close(), + * and the entire logical buffer as defined by the \c size + * argument in mbedtls_writer_init_ext() has been processed. + * \return A negative \c MBEDTLS_ERR_WRITER_XXX error code otherwise. + * + */ +int mbedtls_writer_check_done( mbedtls_writer_ext *writer ); + +/* /\** */ +/* * \brief Get the writer's state */ +/* * */ +/* * \param writer Writer context */ +/* * */ +/* * \return The last state set at a call to mbedtls_writer_commit, */ +/* * or 0 if the reader is used for the first time and hasn't */ +/* * been paused before. */ +/* *\/ */ +/* This has been included in the original MPS API specification, + * but it hasn't been decided yet if we want to keep the state of + * the writing within the writing or leave it to the user to save it + * in an appropriate place, e.g. the handshake structure. + * TODO: Make a decision, and potentially remove this declaration + * if the state is saved elsewhere. + * If this function is needed, the mbedtls_writer_commit + * function should get an additional state argument. */ +/* int mbedtls_writer_state( mbedtls_writer_ext *writer ); */ + +#endif /* MBEDTLS_WRITER_H */ diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 5064ec568917..7e8760b647b6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -33,6 +33,14 @@ #include "mbedtls/ssl_ciphersuites.h" +#if defined(MBEDTLS_SSL_USE_MPS) +#include "mbedtls/mps/mps.h" +#include "mbedtls/mps/layer1.h" +#include "mbedtls/mps/layer2.h" +#include "mbedtls/mps/layer3.h" +#include "mbedtls/mps/allocator.h" +#endif /* MBEDTLS_SSL_USE_MPS */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) #include "mbedtls/x509_crt.h" #include "mbedtls/x509_crl.h" @@ -111,6 +119,7 @@ #define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /** Processing of the ClientHello handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO_CCS -0x7910 /**< Processing of the ClientHello handshake message failed; CCS received instead. */ /** Processing of the ServerHello handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /** Processing of the Certificate handshake message failed. */ @@ -121,6 +130,7 @@ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /** Processing of the ServerHelloDone handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 +#define MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST -0x7B81 /**< Processing of the HelloRetryRequest handshake message failed. */ /** Processing of the ClientKeyExchange handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /** Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. */ @@ -131,8 +141,11 @@ #define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /** Processing of the ChangeCipherSpec handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 +#define MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS -0x7E01 /**< Processing of the Encrypted Extensions handshake message failed. */ /** Processing of the Finished handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80 +#define MBEDTLS_ERR_SSL_BAD_EARLY_DATA -0x7E81 /**< Processing of the Early Data payload failed. */ +#define MBEDTLS_ERR_SSL_BAD_ACK -0x7E82 /**< Processing of the Ack message failed. */ /** Memory allocation failed */ #define MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00 /** Hardware acceleration function returned with error */ @@ -191,6 +204,69 @@ #define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /** Invalid value in SSL config */ #define MBEDTLS_ERR_SSL_BAD_CONFIG -0x5E80 +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_SHARE -0x6781 /**< Problem encountered with the key share provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS -0x6782 /**< Problem encountered with the supported group extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_SHARE -0x6783 /**< Problem encountered with the key share provided by the server. */ +#define MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE -0x6784 /**< The key share provided by the client does not match a group supported by the server. A Hello Retry Request will be needed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_MAX_FRAGMENT_LENGTH_EXT -0x6785 /**< Problem encountered with the max fragment length extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_ALPN_EXT -0x6786 /**< Problem encountered with the ALPN extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVERNAME_EXT -0x6787 /**< Problem encountered with the ServerName extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_PRE_SHARED_KEY_EXT -0x6788 /**< Problem encountered with the Pre-Shared-Key extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_COOKIE_EXT -0x6789 /**< Problem encountered with the cookie extension provided by the client. */ +#define MBEDTLS_ERR_SSL_HRR_REQUIRED -0x6790 /**< Server needs to send a HelloRetryRequest */ +#define MBEDTLS_ERR_SSL_BAD_HS_UNKNOWN_MSG -0x6791 /**< Case where an unknown handshake message was received */ +#define MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR -0x6792 /**< Too many Hello Retry Request messages received */ +#define MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT -0x6793 /**< Problem encountered with the supported versions extension */ +#define MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT -0x6794 /**< Problem encountered with the psk key exchange modes extension */ +#define MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT -0x6795 /**< Missing extension. */ +#define MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET -0x6796 /**< Received NewSessionTicket Post Handshake Message */ +#define MBEDTLS_ERR_SSL_BAD_HS_CID_EXT -0x6797 /**< Received invalid CID extension */ + +#define MBEDTLS_ERR_LAST 0x7F80 /**< This definition points to the last error code to have a correct parsing in error.c */ + + /* List of extensions used in ssl_internal.h / extensions_present in mbedtls_ssl_handshake_params */ +#define MBEDTLS_SSL_EXT_NONE 0 +#define MBEDTLS_SSL_EXT_PRE_SHARED_KEY 1 +#define MBEDTLS_SSL_EXT_KEY_SHARE 2 +#define MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM 4 +#define MBEDTLS_SSL_EXT_SUPPORTED_GROUPS 8 +#define MBEDTLS_SSL_EXT_MAX_FRAGMENT_LENGTH 16 +#define MBEDTLS_SSL_EXT_ALPN 32 +#define MBEDTLS_SSL_EXT_SUPPORTED_VERSION 64 +#define MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES 128 +#define MBEDTLS_SSL_EXT_EARLY_DATA 256 +#define MBEDTLS_SSL_EXT_SERVERNAME 512 +#define MBEDTLS_SSL_EXT_COOKIE 1024 +#define MBEDTLS_SSL_EXT_CID 2048 + + +/* + * TLS 1.3 Key Exchange Modes + * + * Mbed TLS internal identifiers for use with the SSL configuration API + * mbedtls_ssl_conf_tls13_key_exchange(). + */ + +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_NONE 0 +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ( 1u << 0 ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ( 1u << 1 ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ( 1u << 2 ) + +/* Convenience macros for sets of key exchanges. */ +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) + +/* + * Constants from RFC 8446 for TLS 1.3 PSK modes + * + * Those are used in the Pre-Shared Key Exchange Modes extension. + * See Section 4.2.9 in RFC 8446. + */ +#define MBEDTLS_SSL_TLS13_PSK_MODE_PURE 0 /* Pure PSK-based exchange */ +#define MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE 1 /* PSK+ECDHE-based exchange */ /* * Various constants @@ -277,6 +353,29 @@ #define MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED 1 #define MBEDTLS_SSL_CERT_REQ_CA_LIST_DISABLED 0 +#define MBEDTLS_SSL_EARLY_DATA_DISABLED 0 +#define MBEDTLS_SSL_EARLY_DATA_ENABLED 1 + +#define MBEDTLS_SSL_EARLY_DATA_OFF 0 +#define MBEDTLS_SSL_EARLY_DATA_ON 1 + +#define MBEDTLS_SSL_FORCE_RR_CHECK_OFF 0 +#define MBEDTLS_SSL_FORCE_RR_CHECK_ON 1 + +// Flags for DTLS 1.3 unified header format +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_1 1 +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_2 2 +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_3 4 +#define MBEDTLS_SSL_UNIFIED_HDR_CID 8 +#define MBEDTLS_SSL_UNIFIED_HDR_SNR 16 +#define MBEDTLS_SSL_UNIFIED_HDR_LEN 32 +#define MBEDTLS_SSL_UNIFIED_HDR_EPOCH_1 64 +#define MBEDTLS_SSL_UNIFIED_HDR_EPOCH_2 128 + +/* These two constants are used with the mbedtls_ssl_hdr_len() function. */ + +#define MBEDTLS_SSL_DIRECTION_IN 0 +#define MBEDTLS_SSL_DIRECTION_OUT 1 #define MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED 0 #define MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED 1 @@ -382,6 +481,28 @@ #define MBEDTLS_SSL_SIG_RSA 1 #define MBEDTLS_SSL_SIG_ECDSA 3 +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* + * Signature Schemes + * TLS 1.3, Section 4.2.2 + * + * Currently only ECDSA algorithms are implemented + */ + + /* ECDSA algorithms */ + +#define SIGNATURE_ECDSA_SECP256r1_SHA256 0x0403 // 1027 +#define SIGNATURE_ECDSA_SECP384r1_SHA384 0x0503 // 1283 +#define SIGNATURE_ECDSA_SECP521r1_SHA512 0x0603 // 1539 + + /* RSA algorithms */ + +#define SIGNATURE_RSA_PSS_RSAE_SHA256 0x0804 // 2052 + +#define SIGNATURE_NONE 0x0 + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* * Client Certificate Types * RFC 5246 section 7.4.4 plus RFC 4492 section 5.5 @@ -397,45 +518,55 @@ #define MBEDTLS_SSL_MSG_HANDSHAKE 22 #define MBEDTLS_SSL_MSG_APPLICATION_DATA 23 #define MBEDTLS_SSL_MSG_CID 25 +#define MBEDTLS_SSL_MSG_ACK 26 +#define MBEDTLS_SSL_MSG_TLS_CID 25 // OLD CID Implementation #define MBEDTLS_SSL_ALERT_LEVEL_WARNING 1 #define MBEDTLS_SSL_ALERT_LEVEL_FATAL 2 -#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ -#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ -#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ -#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ -#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ -#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ -#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ -#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ -#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ -#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ -#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ -#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ -#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ -#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ -#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ -#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ -#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ -#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ -#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ -#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ -#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ -#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ -#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ -#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ -#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ -#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ +#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ +#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION 109 /* 0x6d -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNOBTAINABLE 111 /* 0x6f -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT_STATUS_RESPONSE 113 /* 0x71 -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT_HASH_VALUE 114 /* 0x72 -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED 116 /* 0x74 -- new in TLS 1.3*/ +#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ #define MBEDTLS_SSL_HS_HELLO_REQUEST 0 #define MBEDTLS_SSL_HS_CLIENT_HELLO 1 #define MBEDTLS_SSL_HS_SERVER_HELLO 2 #define MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST 3 #define MBEDTLS_SSL_HS_NEW_SESSION_TICKET 4 +#define MBEDTLS_SSL_HS_END_OF_EARLY_DATA 5 // NEW IN TLS 1.3 +#define MBEDTLS_SSL_HS_HELLO_RETRY_REQUEST 6 // NEW IN TLS 1.3 (RESERVED) +#define MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION 8 // NEW IN TLS 1.3 #define MBEDTLS_SSL_HS_CERTIFICATE 11 #define MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE 12 #define MBEDTLS_SSL_HS_CERTIFICATE_REQUEST 13 @@ -443,6 +574,9 @@ #define MBEDTLS_SSL_HS_CERTIFICATE_VERIFY 15 #define MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE 16 #define MBEDTLS_SSL_HS_FINISHED 20 +#define MBEDTLS_SSL_HS_KEY_UPDATE 24 // NEW in TLS // NOT USED IN DTLS 1.3 +#define MBEDTLS_SSL_HS_ACK 253 // NEW IN DTLS 1.3 +#define MBEDTLS_SSL_HS_MESSAGE_HASH 254 // NEW IN TLS 1.3 /* * TLS extensions @@ -455,6 +589,8 @@ #define MBEDTLS_TLS_EXT_TRUNCATED_HMAC 4 #define MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 +#define MBEDTLS_TLS_EXT_SUPPORTED_GROUPS 10 // Renamed in TLS 1.3 + #define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS 11 #define MBEDTLS_TLS_EXT_SIG_ALG 13 @@ -468,6 +604,14 @@ #define MBEDTLS_TLS_EXT_SESSION_TICKET 35 + /* TLS 1.3 */ +#define MBEDTLS_TLS_EXT_KEY_SHARES 51 +#define MBEDTLS_TLS_EXT_PRE_SHARED_KEY 41 +#define MBEDTLS_TLS_EXT_EARLY_DATA 42 +#define MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS 43 +#define MBEDTLS_TLS_EXT_COOKIE 44 +#define MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES 45 + /* The value of the CID extension is still TBD as of * draft-ietf-tls-dtls-connection-id-05 * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05). @@ -530,6 +674,7 @@ union mbedtls_ssl_premaster_secret extern "C" { #endif + /* * SSL state machine */ @@ -554,6 +699,25 @@ typedef enum MBEDTLS_SSL_HANDSHAKE_OVER, MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_SSL_HELLO_RETRY_REQUEST, + MBEDTLS_SSL_SECOND_CLIENT_HELLO, + MBEDTLS_SSL_SECOND_SERVER_HELLO, + MBEDTLS_SSL_EARLY_DATA, + MBEDTLS_SSL_END_OF_EARLY_DATA, + MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY, + MBEDTLS_SSL_ENCRYPTED_EXTENSIONS, + MBEDTLS_SSL_HANDSHAKE_FINISH_ACK, + MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET, +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO, + MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED, + MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO, + MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO, + MBEDTLS_SSL_SERVER_CCS_AFTER_HRR, +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + MBEDTLS_SSL_EARLY_APP_DATA +#endif } mbedtls_ssl_states; @@ -695,6 +859,57 @@ typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) +#define MBEDTLS_SSL_EARLY_DATA_NOT_SENT 0 +#define MBEDTLS_SSL_EARLY_DATA_REJECTED 1 +#define MBEDTLS_SSL_EARLY_DATA_ACCEPTED 2 + +/** + * \brief Get information about the use of 0-RTT in a TLS 1.3 handshake + * + * \param ssl The SSL context to query. + * + * \returns #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called + * from the server-side. + * \returns #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called + * prior to completion of the handshake. + * \returns #MBEDTLS_SSL_EARLY_DATA_NOT_SENT if the client has not indicated + * the use of 0-RTT. + * \returns #MBEDTLS_SSL_EARLY_DATA_REJECTED if the client has indicated the use + * of 0-RTT but the server has not accepted it. + * In this situation, the client may want to re-send the 0-RTT data + * as ordinary post-handshake application data via mbedtls_ssl_write(). + * \returns #MBEDTLS_SSL_EARLY_DATA_ACCEPTED if the client has indicated the use + * of 0-RTT and the server has accepted it. + */ +int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +typedef enum +{ + allow_early_data = 1, + allow_dhe_resumption = 2, + allow_psk_resumption = 4, +} mbedtls_ssl_ticket_flags; + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +typedef enum +{ + MBEDTLS_SSL_TLS1_3_CLIENT_EARLY_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET_0, + MBEDTLS_SSL_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET_0, + MBEDTLS_SSL_TLS1_3_EXPORTER_MASTER_SECRET +} mbedtls_ssl_tls1_3_secret_type; +#endif /* MBEDTLS_SSL_EXPORT_KEYS && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) #if defined(MBEDTLS_X509_CRT_PARSE_C) /** @@ -926,6 +1141,15 @@ typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +typedef struct +{ + unsigned char client_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char server_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char exporter_master_secret [ MBEDTLS_MD_MAX_SIZE ]; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + unsigned char resumption_master_secret [ MBEDTLS_MD_MAX_SIZE ]; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +} mbedtls_ssl_tls1_3_application_secrets; #if defined(MBEDTLS_SSL_DTLS_SRTP) #define MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH 255 @@ -980,13 +1204,15 @@ struct mbedtls_ssl_session #if defined(MBEDTLS_HAVE_TIME) mbedtls_time_t start; /*!< starting time */ -#endif +#endif /* MBEDTLS_HAVE_TIME */ int ciphersuite; /*!< chosen ciphersuite */ int compression; /*!< chosen compression */ size_t id_len; /*!< session id length */ unsigned char id[32]; /*!< session identifier */ unsigned char master[48]; /*!< the master secret */ + mbedtls_ssl_tls1_3_application_secrets app_secrets; + #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ @@ -1000,11 +1226,33 @@ struct mbedtls_ssl_session #endif /* MBEDTLS_X509_CRT_PARSE_C */ uint32_t verify_result; /*!< verification result */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + +#if ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && defined(MBEDTLS_SSL_CLI_C) unsigned char *ticket; /*!< RFC 5077 session ticket */ size_t ticket_len; /*!< session ticket length */ uint32_t ticket_lifetime; /*!< ticket lifetime hint */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int minor_ver; /*!< Version information for selecting ticket format */ + unsigned int endpoint : 1; /*!< 0: client, 1: server */ + mbedtls_ssl_ticket_flags ticket_flags; /*!< Ticket flags */ + uint32_t ticket_age_add; /*!< Randomly generated value used to obscure the age of the ticket */ + uint8_t key_len; /*!< PSK key length */ + +#if defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) + unsigned char key[32]; /*!< key (32 byte) */ +#else /* MBEDTLS_SHA512_C */ + unsigned char key[48]; /*!< key (48 byte) */ +#endif /* MBEDTLS_SHA256_C && !MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_CLI_C) + time_t ticket_received; /*!< time ticket was received */ +#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_CLI_C */ + uint32_t max_early_data_size; /*!< max data allowed */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET */ + + #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) int trunc_hmac; /*!< flag for truncated hmac activation */ @@ -1012,7 +1260,18 @@ struct mbedtls_ssl_session #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) int encrypt_then_mac; /*!< flag for EtM activation */ -#endif +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) +/*!< Early data indication: + * 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and + * 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) + */ + int process_early_data; /*!< Indication about using early data or not on the server side */ +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + }; /** @@ -1066,7 +1325,7 @@ struct mbedtls_ssl_config #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) uint8_t trunc_hmac /*bool*/; /*!< negotiate truncated hmac? */ #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) uint8_t session_tickets /*bool*/; /*!< use session tickets? */ #endif #if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) @@ -1117,7 +1376,11 @@ struct mbedtls_ssl_config * Pointers */ - const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + const int* ciphersuite_list[5]; /*!< allowed ciphersuites per version */ +#else + const int* ciphersuite_list[4]; /*!< allowed ciphersuites per version */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /** Callback for printing debug output */ void (*f_dbg)(void *, int, const char *, int, const char *); @@ -1133,6 +1396,16 @@ struct mbedtls_ssl_config int (*f_set_cache)(void *, const mbedtls_ssl_session *); void *p_cache; /*!< context for cache callbacks */ + /* Ephemeral ECC key pair(s) for use with the key share extension + * Provided by the client during the ClientHello, and when used for + * the session copied to the ssl->handshake->ecdh_ctx. + * This structure is only used by the client since he may offer + * multiple key shares to the server. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_ecdh_context keyshare_ctx; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECDH_C && MBEDTLS_SSL_CLI_C */ + #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) /** Callback for setting cert according to SNI extension */ int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); @@ -1143,15 +1416,15 @@ struct mbedtls_ssl_config /** Callback to customize X.509 certificate chain verification */ int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); void *p_vrfy; /*!< context for X.509 verify calllback */ -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) /** Callback to retrieve PSK key from identity */ int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); void *p_psk; /*!< context for PSK callback */ -#endif +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || (defined(MBEDTLS_SSL_COOKIE_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) && defined(MBEDTLS_SSL_SRV_C) /** Callback to create & write a cookie for ClientHello verification */ int (*f_cookie_write)( void *, unsigned char **, unsigned char *, const unsigned char *, size_t ); @@ -1159,18 +1432,27 @@ struct mbedtls_ssl_config int (*f_cookie_check)( void *, const unsigned char *, size_t, const unsigned char *, size_t ); void *p_cookie; /*!< context for the cookie callbacks */ -#endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) - /** Callback to create & write a session ticket */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + unsigned int rr_config; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || ( MBEDTLS_SSL_COOKIE_C && + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ) ) && MBEDTLS_SSL_SRV_C */ + +#if ((defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) ) && defined(MBEDTLS_SSL_SRV_C)) + /* Callback to create and write a session ticket */ int (*f_ticket_write)( void *, const mbedtls_ssl_session *, unsigned char *, const unsigned char *, size_t *, uint32_t * ); /** Callback to parse a session ticket into a session structure */ int (*f_ticket_parse)( void *, mbedtls_ssl_session *, unsigned char *, size_t); void *p_ticket; /*!< context for the ticket callbacks */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || (MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** Callback to export key block and master secret */ int (*f_export_keys)( void *, const unsigned char *, const unsigned char *, size_t, size_t, size_t ); @@ -1181,7 +1463,16 @@ struct mbedtls_ssl_config const unsigned char[32], const unsigned char[32], mbedtls_tls_prf_types ); void *p_export_keys; /*!< context for key export callback */ -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /** Callback to export TLS 1.3 secret */ + int (*f_export_secret)( void *, const unsigned char[32], + mbedtls_ssl_tls1_3_secret_type type, + const unsigned char *, size_t ); + void *p_export_secret; /*!< context for key export callback */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) size_t cid_len; /*!< The length of CIDs for incoming DTLS records. */ @@ -1209,17 +1500,27 @@ struct mbedtls_ssl_config #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - const int *sig_hashes; /*!< allowed signature hashes */ -#endif + const int* sig_hashes; /*!< allowed signature hashes in TLS 1.2 and signature algorithms in TLS 1.3 */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) - const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ -#endif + /* In TLS 1.3 we are re-purposing this curve_list to mean NamedGroup */ + const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + const mbedtls_ecp_group_id* key_shares_curve_list; /*!< curves to send as key shares, as configured by app*/ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_DHM_C) mbedtls_mpi dhm_P; /*!< prime modulus for DHM */ mbedtls_mpi dhm_G; /*!< generator for DHM */ -#endif +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + int key_exchange_modes; /*!< key exchange mode */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -1253,6 +1554,20 @@ struct mbedtls_ssl_config * Its value is non-zero if and only if * \c psk is not \c NULL or \c psk_opaque * is not \c 0. */ + +#if defined(MBEDTLS_ZERO_RTT) + /*!< Early data indication: + * - MBEDTLS_SSL_EARLY_DATA_DISABLED, + * - MBEDTLS_SSL_EARLY_DATA_ENABLED + */ + int early_data_enabled; +#if defined(MBEDTLS_SSL_SRV_C) + /* Max number of bytes of early data acceptable by the server. */ + size_t max_early_data; + /* Callback function for early data processing (server only). */ + int(*early_data_callback)(mbedtls_ssl_context*, const unsigned char*, size_t); +#endif /* MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_ZERO_RTT */ #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ #if defined(MBEDTLS_SSL_ALPN) @@ -1318,8 +1633,49 @@ struct mbedtls_ssl_context */ mbedtls_ssl_transform *transform_in; /*!< current transform params (in) */ mbedtls_ssl_transform *transform_out; /*!< current transform params (in) */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_transform *transform; /*!< negotiated transform params */ mbedtls_ssl_transform *transform_negotiate; /*!< transform params in negotiation */ +#endif /* defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_transform *transform_handshake; + mbedtls_ssl_transform *transform_earlydata; + mbedtls_ssl_transform *transform_application; + +#if defined(MBEDTLS_SSL_USE_MPS) + /* With MPS, we only remember opaque epoch IDs from the handshake + * layer. The transform themselves are managed by MPS. */ + mbedtls_mps_epoch_id epoch_handshake; + mbedtls_mps_epoch_id epoch_earlydata; + mbedtls_mps_epoch_id epoch_application; +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_USE_MPS) + /* MPS structures */ + struct + { + /* TODO: In a context where we use all MPS layers together, + * the references between them should be inlined and + * their configurations consolidated. At the moment, + * we're wasting a bit of memory here. (On the other + * hand, this modularity is very useful for standalone + * testing of the various components). */ + mps_alloc alloc; + mps_l1 l1; + mbedtls_mps_l2 l2; + mps_l3 l3; + mbedtls_mps l4; + } mps; +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Timers @@ -1329,6 +1685,7 @@ struct mbedtls_ssl_context mbedtls_ssl_set_timer_t *f_set_timer; /*!< set timer callback */ mbedtls_ssl_get_timer_t *f_get_timer; /*!< get timer callback */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Record layer (incoming data) */ @@ -1341,6 +1698,7 @@ struct mbedtls_ssl_context unsigned char *in_cid; /*!< The start of the CID; * (the end is marked by in_len). */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *in_len; /*!< two-bytes message length field */ unsigned char *in_iv; /*!< ivlen-byte IV */ unsigned char *in_msg; /*!< message contents (in_iv+ivlen) */ @@ -1349,11 +1707,14 @@ struct mbedtls_ssl_context int in_msgtype; /*!< record header: message type */ size_t in_msglen; /*!< record header: message length */ size_t in_left; /*!< amount of data read so far */ -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - size_t in_buf_len; /*!< length of input buffer */ -#endif #if defined(MBEDTLS_SSL_PROTO_DTLS) uint16_t in_epoch; /*!< DTLS epoch for incoming records */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + uint16_t rec_epoch; /*!< DTLS epoch received */ + uint16_t out_epoch; /*!< DTLS epoch for outgoing records */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + size_t next_record_offset; /*!< offset of the next record in datagram (equal to in_left if none) */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ @@ -1365,6 +1726,23 @@ struct mbedtls_ssl_context size_t in_hslen; /*!< current handshake message length, including the handshake header */ int nb_zero; /*!< # of 0-length encrypted messages */ +#endif /* !MBEDTLS_SSL_USE_MPS */ + + /* The following two variables indicate if and, if yes, + * what kind of alert or warning is pending to be sent. + * They should not be set manually but through the macros + * SSL_PEND_FATAL_ALERT( TYPE ) and SSL_PEND_WARNING( TYPE ) + * defined below. */ + unsigned char send_alert; /*!< Determines if either a fatal error + or a warning should be sent. Values: + - \c 0 if no alert is to be sent. + - #MBEDTLS_SSL_ALERT_LEVEL_FATAL + if a fatal alert is to be sent + - #MBEDTLS_SSL_ALERT_LEVEL_WARNING + if a non-fatal alert is to be sent. */ + unsigned char alert_type; /*!< Type of alert if send_alert != 0 */ + int alert_reason; /*!< The error code to be returned to the + * user once the fatal alert has been sent. */ int keep_current_message; /*!< drop or reuse current message on next call to record layer? */ @@ -1374,6 +1752,7 @@ struct mbedtls_ssl_context * within a single datagram. */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Record layer (outgoing data) */ @@ -1384,6 +1763,7 @@ struct mbedtls_ssl_context unsigned char *out_cid; /*!< The start of the CID; * (the end is marked by in_len). */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *out_len; /*!< two-bytes message length field */ unsigned char *out_iv; /*!< ivlen-byte IV */ unsigned char *out_msg; /*!< message contents (out_iv+ivlen) */ @@ -1391,15 +1771,9 @@ struct mbedtls_ssl_context int out_msgtype; /*!< record header: message type */ size_t out_msglen; /*!< record header: message length */ size_t out_left; /*!< amount of data not yet written */ -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - size_t out_buf_len; /*!< length of output buffer */ -#endif unsigned char cur_out_ctr[8]; /*!< Outgoing record sequence number. */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ -#endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_ZLIB_SUPPORT) unsigned char *compress_buf; /*!< zlib data buffer */ @@ -1407,6 +1781,11 @@ struct mbedtls_ssl_context #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) signed char split_done; /*!< current record already split? */ #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ +#endif /* !MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ /* * PKI layer @@ -1425,6 +1804,10 @@ struct mbedtls_ssl_context const char *alpn_chosen; /*!< negotiated protocol */ #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_PROTO_DTLS) + uint8_t record_numbers_sent[8]; /*send_alert = 1; \ + ssl->alert_reason = (user_return_value); \ + ssl->alert_type = (type); \ + } while( 0 ) +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) #if !defined(MBEDTLS_DEPRECATED_REMOVED) @@ -1619,9 +2040,46 @@ void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ); * the right time(s), which may not be obvious, while REQUIRED always perform * the verification as soon as possible. For example, REQUIRED was protecting * against the "triple handshake" attack even before it was found. + * + * \note In any mode, the signatures of the certificates in CertificateVerify + * messages are always verified. */ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); +/** +* \brief Set the early_data mode +* Default: disabled on server and client +* +* \param ssl SSL context +* \param early_data can be: +* +* MBEDTLS_SSL_EARLY_DATA_DISABLED: early data functionality will not be used +* (default on server) +* (default on client) +* +* MBEDTLS_SSL_EARLY_DATA_ENABLED: early data functionality is enabled and +* may be negotiated in the handshake. Application using +* early data functionality needs to be aware of the +* lack of replay protection of the early data application +* payloads. +* +* \param max_early_data Max number of bytes allowed for early data (server only). +* \param early_data_callback Callback function when early data is received (server +* only). +*/ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) +void mbedtls_ssl_conf_early_data( mbedtls_ssl_config* conf, int early_data, + size_t max_early_data, + int(*early_data_callback)( mbedtls_ssl_context*, + const unsigned char*, + size_t ) ); + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_set_early_data( mbedtls_ssl_context* ssl, const unsigned char* buffer, + size_t len ); +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) /** * \brief Set the verification callback (Optional). @@ -1643,6 +2101,24 @@ void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, void *p_vrfy ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Configure signature algorithms (Optional). + * + * If set, the signature algorithms will be advertised in + * the signature_algorithms extension in the ClientHello of + * TLS/DTLS 1.3. + * + * + * \param conf The SSL configuration to use. + * \param sig_algs A list of signature algorithms with the most preferred algorithm listed first. + * + * Note: sig_algs must be terminated with SIGNATURE_NONE. + */ +void mbedtls_ssl_conf_signature_algorithms( mbedtls_ssl_config *conf, + const int* sig_algs ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_X509_CRT_PARSE_C */ + /** * \brief Set the random number generator callback * @@ -2014,7 +2490,8 @@ void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, * This callback should generate an encrypted and * authenticated ticket for the session and write it to the * output buffer. Here, ticket means the opaque ticket part - * of the NewSessionTicket structure of RFC 5077. + * of the NewSessionTicket structure of RFC 5077 or of a + * TLS 1.3 ticket. * * \param p_ticket Context for the callback * \param session SSL session to be written in the ticket @@ -2034,6 +2511,8 @@ typedef int mbedtls_ssl_ticket_write_t( void *p_ticket, uint32_t *lifetime ); #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** * \brief Callback type: Export key block and master secret * @@ -2095,6 +2574,33 @@ typedef int mbedtls_ssl_export_keys_ext_t( void *p_expkey, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Callback type: Export the client's randbytes + * (ClientHello.random) and TLS 1.3 secrets (client early + * traffic secret, client handshake traffic secret, server + * handshake traffic secret, client application traffic secret + * 0, server application traffic secret 0, exporter master + * secret) used to derive keys. + * Follows the NSS Key Log format + * + * \param p_expsecret Context for the callback + * \param client_random ClientHello.random bytes + * \param type Secret type + * \param secret Pointer to secret + * \param len Secret length + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_secret_t( void *p_expsecret, + const unsigned char client_random[32], + mbedtls_ssl_tls1_3_secret_type type, + const unsigned char *secret, + size_t len ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ /** @@ -2125,7 +2631,7 @@ typedef int mbedtls_ssl_ticket_parse_t( void *p_ticket, unsigned char *buf, size_t len ); -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_SRV_C) /** * \brief Configure SSL session ticket callbacks (server only). * (Default: none.) @@ -2144,9 +2650,11 @@ void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, mbedtls_ssl_ticket_write_t *f_ticket_write, mbedtls_ssl_ticket_parse_t *f_ticket_parse, void *p_ticket ); -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** * \brief Configure key export callback. * (Default: none.) @@ -2176,6 +2684,13 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, void *p_export_keys ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_conf_export_secrets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_secret_t *f_export_secret, + void *p_export_secret ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) @@ -2292,7 +2807,36 @@ typedef int mbedtls_ssl_cookie_check_t( void *ctx, const unsigned char *cookie, size_t clen, const unsigned char *info, size_t ilen ); -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || (defined(MBEDTLS_SSL_COOKIE_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) && defined(MBEDTLS_SSL_SRV_C) + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Configures cookie handling + * (Server only.) + * + * Default: dummy callbacks that fail, in order to force you to + * register working callbacks (and initialize their context). + * + * \warning Disabling return-routability check using cookies allows a + * server to be used for amplification attacks against other hosts. + * Only disable if you known this can't happen in your + * particular environment. + * + * \param conf SSL configuration + * \param f_cookie_write Cookie write callback + * \param f_cookie_check Cookie check callback + * \param p_cookie Context for both callbacks + * \param rr_conf Determines whether a return-routability check is enforced + */ +void mbedtls_ssl_conf_cookies(mbedtls_ssl_config* conf, + mbedtls_ssl_cookie_write_t* f_cookie_write, + mbedtls_ssl_cookie_check_t* f_cookie_check, + void* p_cookie, + unsigned int rr_conf); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) /** * \brief Register callbacks for DTLS cookies * (Server only. DTLS only.) @@ -2325,6 +2869,7 @@ void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, mbedtls_ssl_cookie_write_t *f_cookie_write, mbedtls_ssl_cookie_check_t *f_cookie_check, void *p_cookie ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ /** * \brief Set client's transport-level identification info. @@ -2349,7 +2894,7 @@ int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, const unsigned char *info, size_t ilen ); -#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || (MBEDTLS_SSL_COOKIE_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) /** @@ -2508,6 +3053,9 @@ void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, int (*f_set_cache)(void *, const mbedtls_ssl_session *) ); #endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + #if defined(MBEDTLS_SSL_CLI_C) /** * \brief Request resumption of session (client-side only) @@ -2587,6 +3135,7 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session, * * \return \c 0 if successful. * \return #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small. + * \return #MBEDTLS_ERR_SSL_INTERNAL_ERROR if session is NULL. */ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, unsigned char *buf, @@ -2609,6 +3158,8 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, * \return \c NULL if no session is active. */ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ /** * \brief Set the list of allowed ciphersuites and the preference @@ -2616,17 +3167,36 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co * (Overrides all version-specific lists) * * The ciphersuites array is not copied, and must remain - * valid for the lifetime of the ssl_config. + * valid for the lifetime the SSL configuration. * * Note: The server uses its own preferences * over the preference of the client unless - * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined! + * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined. * - * \param conf SSL configuration - * \param ciphersuites 0-terminated list of allowed ciphersuites + * For TLS 1.2, the notion of ciphersuite determines both + * the key exchange mechanism and the suite of symmetric + * algorithms to be used during and after the handshake. + * + * For TLS 1.3, the notion of ciphersuite only determines + * the suite of symmetric algorithmc to be used during and + * after the handshake. Supported TLS 1.3 key exchange + * mechanisms are configured through the separate API + * mbedtls_ssl_conf_tls13_key_exchange(). + * + * The list of ciphersuites passed to this function may + * contain a mixture of TLS 1.2 and TLS 1.3 ciphersuite + * identifiers. This is useful if negotiation of TLS 1.3 + * should be attempted, but a fallback to TLS 1.2 would + * be tolerated. + * + * \param conf The SSL configuration to modify. + * \param ciphersuites A 0-terminated list of IANA identifiers of supported + * ciphersuites, accessible through \c MBEDTLS_TLS_XXX + * and \c MBEDTLS_TLS1_3_XXX macros defined in + * ssl_ciphersuites.h. */ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, - const int *ciphersuites ); + const int *ciphersuites ); #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_UNEXPECTED_CID_IGNORE 0 @@ -2817,6 +3387,96 @@ int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, mbedtls_pk_context *pk_key ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Set the supported key exchange modes for TLS 1.3 connections. + * + * In (D)TLS 1.2 and earlier, there is a single concept of 'ciphersuite' + * which specifies two separate things simultaneously: + * - The method of key establishment, defining how both parties + * in the communication arrive at a shared secret during the + * initial handshake phase of the protocol. + * - The method of symmetric encryption, defining the set of algorithms + * which, using the keying material established in the handshake, + * provide traffic protection. + * + * Users can specify which ciphersuites to support in (D)TLS versions 1.2 + * and earlier via mbedtls_ssl_conf_ciphersuites(), and should refer to the + * corresponding documentation for more information. + * + * In (D)TLS 1.3, the former ciphersuite concept has been modified to allow + * separate negotiation of key establishment mode and symmetric encryption mode. + * + * In the lingo of (D)TLS 1.3, it is only the latter that is called + * 'ciphersuite', and its configuration continues to be done through + * mbedtls_ssl_conf_ciphersuites(). + * To configure the supported key exchange modes in (D)TLS 1.3, in turn, + * this function should be used. + * + * \param conf + * The SSL configuration the change should apply to. + * \param key_exchange_mode + * A bitwise combination of one or more of the following: + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE + * This flag enables pure-PSK key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE + * This flag enables combined PSK-ECDHE key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA + * This flag enables pure-ECDHE key exchanges. + * + * \note For convenience, the following pre-defined macros are available + * for all combinations of the above: + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL + * Includes all of pure-PSK, PSK-ECDHE and pure-ECDHE. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL + * Includes both pure-PSK and combined PSK-ECDHE key exchanges, + * but excludes pure-ECDHE key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ALL + * Includes both pure-ECDHE and combined PSK-ECDHE key exchanges, + * + * \note If a PSK-based key exchange mode shall be supported, applications + * must also use the APIs mbedtls_ssl_conf_psk() or + * mbedtls_ssl_conf_psk_cb() or mbedtls_ssl_conf_psk_opaque() + * to configure the PSKs to be used. + * + * \note If an ECDHE-based key exchange mode shall be supported, server-side + * applications must also provide a certificate via + * mbedtls_ssl_conf_own_cert(). + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ + +int mbedtls_ssl_conf_tls13_key_exchange( mbedtls_ssl_config* conf, + const int key_exchange_mode ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/** +* \brief Set meta-data for server-provided tickets. +* +* \note This function is used in context of tickets since the +* \p ticket_age_add value is provided by the server-side. +* Furthermore, we also need to record the time the ticket +* was obtained. +* +* \param conf The SSL configuration to use. +* \param ticket_age_add The ticket age add value. +* \param ticket_received The time when the ticket was received. +* +*/ + +#if defined(MBEDTLS_HAVE_TIME) +int mbedtls_ssl_conf_ticket_meta(mbedtls_ssl_config* conf, + const uint32_t ticket_age_add, + const time_t ticket_received); +#else +int mbedtls_ssl_conf_ticket_meta(mbedtls_ssl_config* conf, + const uint32_t ticket_age_add); +#endif /* MBEDTLS_HAVE_TIME */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) /** * \brief Configure a pre-shared key (PSK) and identity @@ -3089,6 +3749,23 @@ void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, const mbedtls_ecp_group_id *curves ); #endif /* MBEDTLS_ECP_C */ +/** +* \brief Set the named groups/curves in order of preference for use +* in the key share extension. +* +* \note This list should be ordered by decreasing preference +* (preferred curve first). +* +* \param conf SSL configuration +* \param curves Ordered list of allowed curves, +* terminated by MBEDTLS_ECP_DP_NONE. +*/ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_ECP_C) +void mbedtls_ssl_conf_key_share_curves(mbedtls_ssl_config* conf, + const mbedtls_ecp_group_id* curve_list); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_CLI_C && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) /** * \brief Set the allowed hashes for signatures during the handshake. @@ -3548,7 +4225,7 @@ void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ); void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ); #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if ((defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined (MBEDTLS_SSL_NEW_SESSION_TICKET) )) && defined(MBEDTLS_SSL_CLI_C)) /** * \brief Enable / Disable session tickets (client only). * (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.) @@ -3560,7 +4237,7 @@ void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split * MBEDTLS_SSL_SESSION_TICKETS_DISABLED) */ void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ); -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || (MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET)) && MBEDTLS_SSL_CLI_C */ #if defined(MBEDTLS_SSL_RENEGOTIATION) /** @@ -3761,6 +4438,19 @@ uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ); */ const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/** +* \brief Return the negotiated key exchange mode id +* +* \param ssl SSL context +* +* \return mbedtls_key_exchange_type_t +*/ +mbedtls_key_exchange_type_t mbedtls_ssl_get_key_exchange(const mbedtls_ssl_context* ssl); + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /** * \brief Return the current SSL version (SSLv3/TLSv1/etc) * @@ -4420,6 +5110,8 @@ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, const unsigned char *random, size_t rlen, unsigned char *dstbuf, size_t dlen ); +int mbedtls_ssl_flush_output(mbedtls_ssl_context* ssl); + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h index 93c32a5edac0..48d5b3b14c92 100644 --- a/include/mbedtls/ssl_ciphersuites.h +++ b/include/mbedtls/ssl_ciphersuites.h @@ -284,6 +284,24 @@ extern "C" { #define MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD /**< TLS 1.2 */ #define MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE /**< TLS 1.2 */ +/* + * Supported ciphersuites (Official IANA names) for TLS / DTLS 1.3 + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_TLS1_3_AES_128_GCM_SHA256 0x1301 +#define MBEDTLS_TLS1_3_AES_256_GCM_SHA384 0x1302 +#define MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256 0x1303 +#define MBEDTLS_TLS1_3_AES_128_CCM_SHA256 0x1304 +#define MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256 0x1305 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +/* Key Exchange Types in TLS 1.3 + * + * Note: When adding a new key exchange algorithm a + * new value needs to be added to the enum list + * below and also the mbedtls_ssl_premaster_secret + * needs to be updated. + */ /* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below */ @@ -293,12 +311,12 @@ typedef enum { MBEDTLS_KEY_EXCHANGE_DHE_RSA, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, - MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_KEY_EXCHANGE_PSK, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_DHE_PSK, MBEDTLS_KEY_EXCHANGE_RSA_PSK, - MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_ECDH_RSA, - MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_ECJPAKE, } mbedtls_key_exchange_type_t; @@ -384,6 +402,7 @@ typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t; /** * \brief This structure is used for storing ciphersuite information + * For alignment, all versions of TLS/DTLS use the same structure. */ struct mbedtls_ssl_ciphersuite_t { @@ -391,7 +410,11 @@ struct mbedtls_ssl_ciphersuite_t const char * name; mbedtls_cipher_type_t cipher; + /* For TLS 1.3 we use this field to populate it with the hash function + * (instead of a MAC). + */ mbedtls_md_type_t mac; + /* In TLS 1.3 we do not make use of this key_exchange field. */ mbedtls_key_exchange_type_t key_exchange; int min_major_ver; @@ -407,6 +430,17 @@ const int *mbedtls_ssl_list_ciphersuites( void ); const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ); const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** +* \brief Returns the size of the hash function output given the ciphersuite +* +* \param ciphersuite mbedtls_ssl_ciphersuite_t +* +* \return Size of output in bytes, -1 in case of error +*/ +unsigned int mbedtls_hash_size_for_ciphersuite(const mbedtls_ssl_ciphersuite_t* ciphersuite); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_PK_C) mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ); mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info ); diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 46ade67b9c4d..06b1fb40ef97 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -79,17 +79,25 @@ #else #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#else /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1 */ #endif /* MBEDTLS_SSL_PROTO_SSL3 */ -#define MBEDTLS_SSL_MIN_VALID_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#define MBEDTLS_SSL_MIN_VALID_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 #define MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 /* Determine maximum supported version */ #define MBEDTLS_SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 +#else #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 #else @@ -105,11 +113,12 @@ #endif /* MBEDTLS_SSL_PROTO_TLS1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* Shorthand for restartable ECC */ #if defined(MBEDTLS_ECP_RESTARTABLE) && \ defined(MBEDTLS_SSL_CLI_C) && \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + (defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) && \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) #define MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED #endif @@ -119,6 +128,19 @@ #define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ #define MBEDTLS_SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ +#define MBEDTLS_SSL_PROC_CHK(f) \ + do { \ + ret = (f); \ + if( ret != 0 ) \ + { \ + if( ret > 0 ) \ + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; \ + goto cleanup; \ + } \ + } while( 0 ) + +#define MBEDTLS_SSL_PROC_CHK_NEG(f) do { if( ( ret = f ) < 0 ) goto cleanup; } while( 0 ) + /* * DTLS retransmission states, see RFC 6347 4.2.4 * @@ -144,6 +166,12 @@ #define MBEDTLS_SSL_COMPRESSION_ADD 0 #endif +#if defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER + /* This macro determines whether CBC is supported. */ #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ ( defined(MBEDTLS_AES_C) || \ @@ -153,6 +181,10 @@ #define MBEDTLS_SSL_SOME_SUITES_USE_CBC #endif +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#define MBEDTLS_SSL_SOME_SUITES_USE_STREAM +#endif + /* This macro determines whether the CBC construct used in TLS 1.0-1.2 (as * opposed to the very different CBC construct used in SSLv3) is supported. */ #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) && \ @@ -162,11 +194,13 @@ #define MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC #endif -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) || \ defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) #define MBEDTLS_SSL_SOME_MODES_USE_MAC #endif +#endif /* TLS <= 1.2 */ + #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) /* Ciphersuites using HMAC */ #if defined(MBEDTLS_SHA512_C) @@ -225,6 +259,12 @@ /* Maximum size in bytes of list in supported elliptic curve ext., RFC 4492 */ #define MBEDTLS_SSL_MAX_CURVE_LIST_LEN 65535 +/* Maximum amount of early data to buffer on the server. */ +#define MBEDTLS_SSL_MAX_EARLY_DATA 1024 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SIGNATURE_SCHEMES_SIZE 20 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* * Check that we obey the standard's message size bounds */ @@ -256,7 +296,7 @@ implicit sequence number. */ #define MBEDTLS_SSL_HEADER_LEN 13 -#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_IN_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) ) #else @@ -265,7 +305,7 @@ + ( MBEDTLS_SSL_CID_IN_LEN_MAX ) ) #endif -#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_OUT_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) ) #else @@ -418,9 +458,38 @@ struct mbedtls_ssl_key_set * server_write_key, in Bytes. */ size_t iv_len; /*!< The length of client_write_iv and * server_write_iv, in Bytes. */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + int epoch; + unsigned char iv[ MBEDTLS_MAX_IV_LENGTH ]; + + /* The [sender]_sn_key is indirectly used to + * encrypt the sequence number in the record layer. + * + * The client_sn_key is used to encrypt the + * sequence number for outgoing transmission. + * server_sn_key is used for incoming payloads. + */ + unsigned char server_sn_key[ MBEDTLS_MAX_KEY_LENGTH ]; + unsigned char client_sn_key[ MBEDTLS_MAX_KEY_LENGTH ]; +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + }; typedef struct mbedtls_ssl_key_set mbedtls_ssl_key_set; +typedef struct +{ + unsigned char binder_key [ MBEDTLS_MD_MAX_SIZE ]; + unsigned char client_early_traffic_secret [ MBEDTLS_MD_MAX_SIZE ]; + unsigned char early_exporter_master_secret[ MBEDTLS_MD_MAX_SIZE ]; +} mbedtls_ssl_tls1_3_early_secrets; + +typedef struct +{ + unsigned char client_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char server_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ]; +} mbedtls_ssl_tls1_3_handshake_secrets; + /* * This structure contains the parameters only needed during handshake. */ @@ -429,6 +498,23 @@ struct mbedtls_ssl_handshake_params /* * Handshake specific crypto variables */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + unsigned int key_exchange; /* Indication of the key exchange algorithm being negotiated*/ + unsigned char key_exchange_modes; /*!< psk key exchange modes */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + int received_signature_schemes_list[MBEDTLS_SIGNATURE_SCHEMES_SIZE]; /*!< Received signature algorithms */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + mbedtls_ecp_curve_info server_preferred_curve; /*!< Preferred curve requested by server (obtained in HelloRetryRequest */ +#if defined(MBEDTLS_SSL_CLI_C) + int hello_retry_requests_received; /*!< Number of Hello Retry Request messages received from the server. */ +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + int hello_retry_requests_sent; /*!< Number of Hello Retry Request messages sent by the server. */ +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + int ccs_sent; /* Number of CCS messages sent */ +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ uint8_t max_major_ver; /*!< max. major version client*/ uint8_t max_minor_ver; /*!< max. minor version client*/ @@ -440,9 +526,9 @@ struct mbedtls_ssl_handshake_params uint8_t sni_authmode; /*!< authmode from SNI callback */ #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) uint8_t new_session_ticket; /*!< use NewSessionTicket? */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS || ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ) */ #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) uint8_t extended_ms; /*!< use Extended Master Secret? */ @@ -494,7 +580,6 @@ struct mbedtls_ssl_handshake_params */ #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) mbedtls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ - #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_key_type_t ecdh_psa_type; uint16_t ecdh_bits; @@ -612,7 +697,7 @@ struct mbedtls_ssl_handshake_params mbedtls_md5_context fin_md5; mbedtls_sha1_context fin_sha1; #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA256_C) #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_hash_operation_t fin_sha256_psa; @@ -627,11 +712,155 @@ struct mbedtls_ssl_handshake_params mbedtls_sha512_context fin_sha512; #endif #endif -#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + /* + * State-local variables used during the processing + * of a specific handshake state. + */ + union + { + /* Outgoing Finished message */ + struct + { + uint8_t preparation_done; + + /* Buffer holding digest of the handshake up to + * but excluding the outgoing finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_out; + + /* Incoming Finished message */ + struct + { + /* Buffer holding digest of the handshake up to but + * excluding the peer's incoming finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_in; + +#if defined(MBEDTLS_SSL_CLI_C) + + /* Client, incoming ServerKeyExchange */ + struct + { + uint8_t preparation_done; + } srv_key_exchange; + + /* Client, incoming ServerHello */ + struct + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_info_seen; +#else + int dummy; +#endif + } srv_hello_in; + + /* Client, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_out; + + /* Client, outgoing Certificate Verify */ + struct + { + uint8_t preparation_done; + } crt_vrfy_out; + + /* Client, outgoing ClientHello */ + struct + { + uint8_t preparation_done; + } cli_hello_out; + +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_in; + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } encrypted_extensions_out; + +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Incoming CertificateVerify */ + struct + { + unsigned char verify_buffer[ 64 + 33 + 1 + MBEDTLS_MD_MAX_SIZE ]; + size_t verify_buffer_len; + } certificate_verify_in; + + /* Outgoing CertificateVerify */ + struct + { + unsigned char handshake_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t handshake_hash_len; + } certificate_verify_out; + + } state_local; unsigned char randbytes[64]; /*!< random bytes */ - unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; - /*!< premaster secret */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ECDSA_C) + unsigned char certificate_request_context_len; + unsigned char* certificate_request_context; +#endif + +#if defined(MBEDTLS_ECDH_C) + /* This is the actual key share list we sent. + * The list configured by the application may + * get modified via the server provided hint + * using the HRR message. + */ + mbedtls_ecp_group_id* key_shares_curve_list; /*!< curves to send as key shares */ +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + // pointer to the pre_shared_key extension + unsigned char* ptr_to_psk_ext; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + union + { + unsigned char early [MBEDTLS_MD_MAX_SIZE]; + unsigned char handshake[MBEDTLS_MD_MAX_SIZE]; + unsigned char app [MBEDTLS_MD_MAX_SIZE]; + } tls1_3_master_secrets; + + mbedtls_ssl_tls1_3_handshake_secrets hs_secrets; +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_tls1_3_early_secrets early_secrets; + + /*!< Early data indication: + 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and + 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) + */ + int early_data; +#endif /* MBEDTLS_ZERO_RTT */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + size_t pmslen; /*!< premaster length */ + unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; /*!< premaster secret */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + int extensions_present; /*!< which extension were present; the */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /** Asynchronous operation context. This field is meant for use by the @@ -755,9 +984,8 @@ struct mbedtls_ssl_transform size_t maclen; /*!< MAC(CBC) len */ size_t taglen; /*!< TAG(AEAD) len */ - unsigned char iv_enc[16]; /*!< IV (encryption) */ - unsigned char iv_dec[16]; /*!< IV (decryption) */ - + unsigned char iv_enc[ MBEDTLS_MAX_IV_LENGTH ]; /*!< IV (encryption) */ + unsigned char iv_dec[ MBEDTLS_MAX_IV_LENGTH ]; /*!< IV (decryption) */ #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) #if defined(MBEDTLS_SSL_PROTO_SSL3) @@ -932,6 +1160,7 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); * * \param ssl SSL context */ + void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL @@ -943,6 +1172,12 @@ void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_handshake_wrapup_tls13( mbedtls_ssl_context *ssl ); +#endif + +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ); + void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); @@ -953,6 +1188,15 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ); void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handshake_client_step(mbedtls_ssl_context* ssl); +int mbedtls_ssl_handshake_server_step(mbedtls_ssl_context* ssl); +void mbedtls_ssl_handshake_wrapup(mbedtls_ssl_context* ssl); + +int mbedtls_ssl_send_fatal_handshake_failure(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl, + int update_checksum ); + /** * \brief Update record layer * @@ -1037,11 +1281,25 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +#if !defined(MBEDTLS_SSL_USE_MPS) MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ); +#endif /* MBEDTLS_SSL_USE_MPS */ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +int mbedtls_ssl_read_certificate_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_certificate_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ); +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL @@ -1056,6 +1314,179 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ); +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) +/* parse early data extension */ +int ssl_parse_encrypted_extensions_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/* + * Helper functions around key exchange modes. + */ +static inline unsigned mbedtls_ssl_conf_tls13_get_key_exchange_modes( mbedtls_ssl_context *ssl ) +{ + return( ssl->conf->key_exchange_modes ); +} + +static inline int mbedtls_ssl_conf_tls13_pure_psk_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_some_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_some_psk_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_tls13_key_exchange_with_psk( mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + return( 1 ); + } + + return( 0 ); +} + +/* + * Helper functions around EarlyData + */ +static inline int mbedtls_ssl_conf_tls13_0rtt_enabled( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + return( 1 ); +#else + ((void) ssl); +#endif /* MBEDTLS_ZERO_RTT */ + + return( 0 ); +} + +int mbedtls_ssl_read_certificate_verify_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_certificate_verify_process(mbedtls_ssl_context* ssl); + +int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform, + int endpoint, + int ciphersuite, + mbedtls_ssl_key_set const *traffic_keys, + mbedtls_ssl_context *ssl /* DEBUG ONLY */ ); + +int mbedtls_ssl_mps_fetch_full_hs_msg( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char **buf, + size_t *buflen ); +int mbedtls_ssl_mps_hs_consume_full_hs_msg( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_mps_remap_error( int ret ); + +int mbedtls_ssl_get_handshake_transcript( mbedtls_ssl_context *ssl, + const mbedtls_md_type_t md, + unsigned char *dst, + size_t dst_len, + size_t *olen ); + + +void mbedtls_ssl_add_hs_msg_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char const *msg, + size_t msg_len ); +void mbedtls_ssl_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + size_t total_hs_len ); + +int mbedtls_ssl_hash_transcript( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_set_inbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); +void mbedtls_ssl_set_outbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); + +int mbedtls_ssl_write_encrypted_extension(mbedtls_ssl_context* ssl); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) +int mbedtls_ssl_write_change_cipher_spec(mbedtls_ssl_context* ssl); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_write_pre_shared_key_ext(mbedtls_ssl_context* ssl, + unsigned char* buf, unsigned char* end, + size_t* olen, + size_t* binder_list_length, + int part ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +int mbedtls_ssl_write_signature_algorithms_ext(mbedtls_ssl_context* ssl, unsigned char* buf, unsigned char* end, size_t* olen); +int mbedtls_ssl_parse_signature_algorithms_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +int mbedtls_ssl_check_signature_scheme(const mbedtls_ssl_context* ssl, int signature_scheme); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_write_early_data_ext(mbedtls_ssl_context* ssl, unsigned char* buf, size_t buflen, size_t* olen); +#endif /* MBEDTLS_ZERO_RTT */ +#if (defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)) +int mbedtls_ssl_parse_supported_groups_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +int mbedtls_ssl_parse_new_session_ticket_server(mbedtls_ssl_context* ssl, unsigned char* buf, size_t len); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_parse_client_psk_identity_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, const mbedtls_ssl_ciphersuite_t *ciphersuite_info ); @@ -1065,36 +1496,92 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ); /** - * Get the first defined PSK by order of precedence: + * Get the first properly defined PSK by order of precedence: * 1. handshake PSK set by \c mbedtls_ssl_set_hs_psk() in the PSK callback * 2. static PSK configured by \c mbedtls_ssl_conf_psk() - * Return a code and update the pair (PSK, PSK length) passed to this function + * Update the pair (PSK, PSK length) passed to the function if they're not null. + * Return whether any PSK was found */ static inline int mbedtls_ssl_get_psk( const mbedtls_ssl_context *ssl, const unsigned char **psk, size_t *psk_len ) { if( ssl->handshake->psk != NULL && ssl->handshake->psk_len > 0 ) { - *psk = ssl->handshake->psk; - *psk_len = ssl->handshake->psk_len; + if( psk != NULL && psk_len != NULL ) + { + *psk = ssl->handshake->psk; + *psk_len = ssl->handshake->psk_len; + } } - else if( ssl->conf->psk != NULL && ssl->conf->psk_len > 0 ) + else if( ssl->conf->psk != NULL && ssl->conf->psk_len > 0 && + ssl->conf->psk_identity != NULL && ssl->conf->psk_identity_len > 0) { - *psk = ssl->conf->psk; - *psk_len = ssl->conf->psk_len; + if( psk != NULL && psk_len != NULL ) + { + *psk = ssl->conf->psk; + *psk_len = ssl->conf->psk_len; + } } else { - *psk = NULL; - *psk_len = 0; + if( psk != NULL && psk_len != NULL ) + { + *psk = NULL; + *psk_len = 0; + } return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); } return( 0 ); } +/* Check if we have any PSK to offer, returns 0 if PSK is available. Assign the + psk and ticket if pointers are present. */ +static inline int mbedtls_ssl_get_psk_to_offer( const mbedtls_ssl_context *ssl, + const unsigned char **psk, size_t *psk_len, + const unsigned char **psk_identity, size_t *psk_identity_len ) +{ + int ptrs_present = 0; + + if( psk != NULL && psk_len != NULL && + psk_identity != NULL && psk_identity_len != NULL ) + { + ptrs_present = 1; + } + + /* Check if a ticket has been configured. */ + if( ssl->session_negotiate != NULL && + ssl->session_negotiate->ticket != NULL ) + { + if( ptrs_present ) + { + *psk = ssl->session_negotiate->key; + *psk_len = ssl->session_negotiate->key_len; + *psk_identity = ssl->session_negotiate->ticket; + *psk_identity_len = ssl->session_negotiate->ticket_len; + } + return( 0 ); + } + + /* Check if an external PSK has been configured. */ + if( ssl->conf->psk != NULL ) + { + if( ptrs_present ) + { + *psk = ssl->conf->psk; + *psk_len = ssl->conf->psk_len; + *psk_identity = ssl->conf->psk_identity; + *psk_identity_len = ssl->conf->psk_identity_len; + } + return( 0 ); + } + + return( 1 ); +} + + #if defined(MBEDTLS_USE_PSA_CRYPTO) /** * Get the first defined opaque PSK by order of precedence: @@ -1200,11 +1687,23 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, uint32_t *flags ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +void mbedtls_ssl_write_wire_version( int major, int minor, int transport, + unsigned char ver[2] ); void mbedtls_ssl_write_version( int major, int minor, int transport, unsigned char ver[2] ); void mbedtls_ssl_read_version( int *major, int *minor, int transport, const unsigned char ver[2] ); +void mbedtls_ssl_remove_hs_psk( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static inline size_t mbedtls_ssl_hdr_len(const mbedtls_ssl_context* ssl) +{ + ((void) ssl); + return(5); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl ) { #if !defined(MBEDTLS_SSL_PROTO_DTLS) @@ -1225,7 +1724,12 @@ static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl ) static inline size_t mbedtls_ssl_out_hdr_len( const mbedtls_ssl_context *ssl ) { +#if !defined(MBEDTLS_SSL_USE_MPS) return( (size_t) ( ssl->out_iv - ssl->out_hdr ) ); +#else + ((void) ssl); + return( 5 ); +#endif /* MBEDTLS_SSL_USE_MPS */ } static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) @@ -1255,6 +1759,25 @@ int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context const *ssl ); void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); #endif +static inline void mbedtls_ssl_handshake_set_state(mbedtls_ssl_context* ssl, + int state) +{ + ssl->state = state; + + /* Note: + * This only works as long as all state-local struct members + * of mbedtls_ssl_hanshake_params::state_local can be initialized + * through zeroization. + * Exceptions must be manually checked for here. + */ + if (state != MBEDTLS_SSL_HANDSHAKE_WRAPUP && + state != MBEDTLS_SSL_HANDSHAKE_OVER && + state != MBEDTLS_SSL_FLUSH_BUFFERS) + { + mbedtls_platform_zeroize(&ssl->handshake->state_local, sizeof(ssl->handshake->state_local)); + } +} + MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ); @@ -1295,6 +1818,19 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, mbedtls_ssl_transform *transform, mbedtls_record *rec ); +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_mps_transform_free_default( void *transform ); +int mbedtls_mps_transform_encrypt_default( + void *transform, mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +int mbedtls_mps_transform_decrypt_default( void *transform, + mps_rec *rec ); +int mbedtls_mps_transform_get_expansion_default( void *transform, + size_t *pre_exp, + size_t *post_exp ); +#endif /* MBEDTLS_SSL_USE_MPS */ + /* Length of the "epoch" field in the record header */ static inline size_t mbedtls_ssl_ep_len( const mbedtls_ssl_context *ssl ) { @@ -1339,6 +1875,9 @@ int mbedtls_ssl_start_renegotiation( mbedtls_ssl_context *ssl ); size_t mbedtls_ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); void mbedtls_ssl_buffering_free( mbedtls_ssl_context *ssl ); void mbedtls_ssl_flight_free( mbedtls_ssl_flight_item *flight ); + +int mbedtls_ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_TEST_HOOKS) @@ -1349,4 +1888,200 @@ int mbedtls_ssl_check_dtls_clihlo_cookie( unsigned char *obuf, size_t buf_len, size_t *olen ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_ECDH_C) +/** + * \brief This function generates an EC key pair and exports its + * in the format used in a TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param olen The address at which to store the number of Bytes written. + * \param buf The destination buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_tls_13_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses the ECDHE parameters in a + * TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDHE context to use. This must be initialized. + * \param buf On input, \c *buf must be the start of the input buffer. + * On output, \c *buf is updated to point to the end of the + * data that has been read. On success, this is the first byte + * past the end of the ServerKeyExchange parameters. + * On error, this is the point at which an error has been + * detected, which is usually not useful except to debug + * failures. + * \param end The end of the input buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + * + */ +int mbedtls_ecdh_read_tls_13_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ); + +/** + * \brief This function generates a public key and exports it + * as a TLS 1.3 KeyShare payload. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, the latter usually by + * mbedtls_ecdh_read_params(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The destination buffer. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The size of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_tls_13_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses and processes the ECDHE payload of a + * TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param buf The pointer to the ClientKeyExchange payload. This must + * be a readable buffer of length \p blen Bytes. + * \param blen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_read_tls_13_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p *buf is updated to point immediately + * after the ECPoint record. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_13_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief This function exports a point as defined in TLS 1.3. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to be exported. This must be initialized. + * \param format The point format to use. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length in Bytes + * of the data written. + * \param buf The target buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the target buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the target buffer + * is too small to hold the exported point. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_write_point( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + + +/** + * \brief This function extracts an elliptic curve group ID from a + * TLS ECParameters record as defined in TLS 1.3. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The address at which to store the group id. + * This must not be \c NULL. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, + size_t len ); + + +/** + * \brief This function exports an elliptic curve as a TLS + * ECParameters record as defined in TLS 1.3. + * + * \param grp The ECP group to be exported. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The buffer to write to. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output + * buffer is too small to hold the exported group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_write_group( const mbedtls_ecp_group *grp, + size_t *olen, + unsigned char *buf, size_t blen ); +#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* ssl_internal.h */ diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h index 8221051b2470..49511e19e9a2 100644 --- a/include/mbedtls/ssl_ticket.h +++ b/include/mbedtls/ssl_ticket.h @@ -48,7 +48,7 @@ extern "C" { /** * \brief Information for session ticket protection */ -typedef struct mbedtls_ssl_ticket_key +typedef struct { unsigned char name[4]; /*!< random key identifier */ uint32_t generation_time; /*!< key generation timestamp (seconds) */ @@ -59,13 +59,15 @@ mbedtls_ssl_ticket_key; /** * \brief Context for session ticket handling functions */ -typedef struct mbedtls_ssl_ticket_context +typedef struct { mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ unsigned char active; /*!< index of the currently active key */ uint32_t ticket_lifetime; /*!< lifetime of tickets in seconds */ - +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_ticket_flags flags; /*!< ticket flags */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /** Callback for getting (pseudo-)random numbers */ int (*f_rng)(void *, unsigned char *, size_t); void *p_rng; /*!< context for the RNG function */ @@ -107,10 +109,10 @@ void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ); * \return 0 if successful, * or a specific MBEDTLS_ERR_XXX error code */ -int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, +int mbedtls_ssl_ticket_setup(mbedtls_ssl_ticket_context* ctx, + int (*f_rng)(void*, unsigned char*, size_t), void* p_rng, mbedtls_cipher_type_t cipher, - uint32_t lifetime ); + uint32_t lifetime); /** * \brief Implementation of the ticket write callback diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index fb0b5e134468..0b1db5637b24 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -114,7 +114,19 @@ set(src_tls ssl_srv.c ssl_ticket.c ssl_tls.c + ssl_tls13_client.c + ssl_tls13_generic.c ssl_tls13_keys.c + ssl_tls13_server.c + mps/allocator.c + mps/trace.c + mps/layer1.c + mps/layer2.c + mps/layer3.c + mps/mps.c + mps/reader.c + mps/writer.c + mps/transform.c ) if(CMAKE_COMPILER_IS_GNUCC) diff --git a/library/Makefile b/library/Makefile index 54b0651dc48d..391065446e0e 100644 --- a/library/Makefile +++ b/library/Makefile @@ -144,6 +144,10 @@ OBJS_CRYPTO= \ version.o \ version_features.o \ xtea.o \ + ssl_tls13_client.o \ + ssl_tls13_generic.o \ + ssl_tls13_server.o \ + ssl_tls13_keys.o \ # This line is intentionally left blank include ../3rdparty/Makefile.inc @@ -174,7 +178,16 @@ OBJS_TLS= \ ssl_ticket.o \ ssl_tls.o \ ssl_tls13_keys.o \ - # This line is intentionally left blank + mps/reader.o \ + mps/writer.o \ + mps/trace.o \ + mps/layer1.o \ + mps/layer2.o \ + mps/layer3.o \ + mps/mps.o \ + mps/allocator.o \ + mps/transform.o \ + # This line is intentionally left blank .SILENT: diff --git a/library/error.c b/library/error.c index afad38904ff0..18434b747aa9 100644 --- a/library/error.c +++ b/library/error.c @@ -434,6 +434,24 @@ const char * mbedtls_high_level_strerr( int error_code ) return( "SSL - No CA Chain is set, but required to operate" ); case -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE): return( "SSL - An unexpected message was received from our peer" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS): + return( "SSL - Processing of the Encrypted Extensions handshake message failed" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR): + return( "SSL - Too many Hello Retry Request messages received" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT): + return( "SSL - Problem encountered with the supported versions extension" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT): + return( "SSL - Problem encountered with the psk key exchange modes extension" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_CID_EXT): + return( "SSL - The CID extension could not be parsed correctly" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT): + return( "SSL - Handshake is missing a required extension" ); + case -(MBEDTLS_ERR_SSL_BAD_EARLY_DATA): + return( "TLS - Processing of the Early Data payload failed." ); + case -(MBEDTLS_ERR_SSL_BAD_ACK): + return( "TLS - Processing of the Ack message failed." ); + case -(MBEDTLS_ERR_SSL_BAD_HS_PRE_SHARED_KEY_EXT): + return( "TLS - Received invalid pre_shared_key extension" ); case -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE): return( "SSL - A fatal alert message was received from our peer" ); case -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED): @@ -442,6 +460,10 @@ const char * mbedtls_high_level_strerr( int error_code ) return( "SSL - The peer notified us that the connection is going to be closed" ); case -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO): return( "SSL - Processing of the ClientHello handshake message failed" ); +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + case -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO_CCS): + return( "SSL - Processing of the ClientHello handshake message failed; CCS received instead" ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ case -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO): return( "SSL - Processing of the ServerHello handshake message failed" ); case -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE): diff --git a/library/mps/allocator.c b/library/mps/allocator.c new file mode 100644 index 000000000000..bc310bac0aa2 --- /dev/null +++ b/library/mps/allocator.c @@ -0,0 +1,123 @@ +/* + * Message Processing Stack, Allocator implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "../../include/mbedtls/mps/allocator.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mps_alloc_init( mps_alloc *ctx, + mbedtls_mps_size_t l1_len ) +{ + ctx->l1_in_len = l1_len; + ctx->l1_out_len = l1_len; + + ctx->l1_in = mbedtls_calloc( 1, l1_len ); + ctx->l1_out = mbedtls_calloc( 1, l1_len ); + if( ctx->l1_in == NULL || ctx->l1_out == NULL ) + { + mbedtls_free( ctx->l1_in ); + mbedtls_free( ctx->l1_out ); + ctx->l1_in = ctx->l1_out = NULL; + return( MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ); + } + + ctx->alloc_state = 0; + return( 0 ); +} + +int mps_alloc_free( mps_alloc *ctx ) +{ + mps_alloc zero = { 0, NULL, 0, NULL, 0 }; + mbedtls_free( ctx->l1_in ); + mbedtls_free( ctx->l1_out ); + *ctx = zero; + return( 0 ); +} + +static int alloc_check_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + if( ( ctx->alloc_state & flag ) != 0 ) + return( 1 ); + else + return( 0 ); +} + +static void alloc_add_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + ctx->alloc_state |= flag; +} + +static void alloc_remove_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + ctx->alloc_state &= ~flag; +} + +int mps_alloc_acquire( mps_alloc *ctx, mps_alloc_type purpose, + unsigned char **buf, + mbedtls_mps_size_t *buflen ) +{ + if( alloc_check_flag( ctx, purpose ) ) + return( MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ); + + switch( purpose ) + { + case MPS_ALLOC_L1_IN: + *buf = ctx->l1_in; + *buflen = ctx->l1_in_len; + break; + + case MPS_ALLOC_L1_OUT: + *buf = ctx->l1_out; + *buflen = ctx->l1_out_len; + break; + + default: + return( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + break; + } + + alloc_add_flag( ctx, purpose ); + return( 0 ); +} + +int mps_alloc_release( mps_alloc* ctx, mps_alloc_type purpose ) +{ + if( alloc_check_flag( ctx, purpose ) == 0 ) + return( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + + if( purpose != MPS_ALLOC_L1_IN && + purpose != MPS_ALLOC_L1_OUT ) + { + return( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } + + alloc_remove_flag( ctx, purpose ); + return( 0 ); +} diff --git a/library/mps/layer1.c b/library/mps/layer1.c new file mode 100644 index 000000000000..4f2249d0b015 --- /dev/null +++ b/library/mps/layer1.c @@ -0,0 +1,1287 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer1.h" +#include "mbedtls/mps/trace.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer1_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_1; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +/* + * GENERAL NOTE ON CODING STYLE + * + * The following code intentionally separates memory loads + * and stores from other operations (arithmetic or branches). + * This leads to the introduction of many local variables + * and significantly increases the C-code line count, but + * should leave the size of generated assembly unchanged. + * + * This reason for this is twofold: + * (1) It could potentially ease verification efforts using + * the VST whose program logic cannot directly reason + * about instructions containing a load or store in + * addition to other operations (e.g. *p = *q or + * tmp = *p + 42). + * (2) Operating on local variables and writing the results + * back to the target contexts on success only + * allows to maintain structure invariants even + * on failure - this in turn has two benefits: + * (2.a) If for some reason an error code is not caught + * and operation continues, functions are nonetheless + * called with sane contexts, reducing the risk + * of dangerous behavior. + * (2.b) Randomized testing is easier if structures + * remain intact even in the face of failing + * and/or non-sensical calls. + * + */ + +MBEDTLS_MPS_STATIC void l1_release_if_set( unsigned char **buf_ptr, + mps_alloc *ctx, + mps_alloc_type purpose ) +{ + if( *buf_ptr == NULL ) + return; + + *buf_ptr = NULL; + mps_alloc_release( ctx, purpose ); +} + +MBEDTLS_MPS_STATIC int l1_acquire_if_unset( unsigned char **buf_ptr, + mbedtls_mps_size_t *buflen, + mps_alloc *ctx, + mps_alloc_type purpose ) +{ + if( *buf_ptr != NULL ) + return( 0 ); + + return( mps_alloc_acquire( ctx, purpose, buf_ptr, buflen ) ); +} + +/* + * + * Stream-based implementation + * + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +/*@ + requires ( p != NULL ); + requires ( recv != NULL ); + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_init_stream_read( mps_l1_stream_read *p, + mps_alloc *ctx, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + mps_l1_stream_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_read = 0, + .bytes_fetched = 0 }; + *p = zero; + p->alloc = ctx; + l1_set_bio_stream_read( p, recv_ctx, recv ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream_read( mps_l1_stream_read *p, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + p->recv = recv; + p->recv_ctx = recv_ctx; +} + +/*@ + requires \valid( p ); + requires ( send != NULL ); + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_init_stream_write( mps_l1_stream_write *p, + mps_alloc *ctx, + void* send_ctx, + mps_l0_send_t *send ) +{ + mps_l1_stream_write const zero = + { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .bytes_written = 0, + .status = MPS_L1_STREAM_STATUS_READY + }; + + *p = zero; + p->alloc = ctx; + l1_set_bio_stream_write( p, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream_write( mps_l1_stream_write *p, + void* send_ctx, + mps_l0_send_t *send ) +{ + p->send = send; + p->send_ctx = send_ctx; +} + +MBEDTLS_MPS_INLINE +void l1_init_stream( mps_l1_stream *p, mps_alloc *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_init_stream_read ( &p->rd, ctx, recv_ctx, recv ); + l1_init_stream_write( &p->wr, ctx, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream( mps_l1_stream *p, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_set_bio_stream_read ( &p->rd, recv_ctx, recv ); + l1_set_bio_stream_write( &p->wr, send_ctx, send ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_free_stream_read( mps_l1_stream_read *p ) +{ + mps_l1_stream_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_read = 0, + .bytes_fetched = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + *p = zero; +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_free_stream_write( mps_l1_stream_write *p ) +{ + mps_l1_stream_write const zero = + { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .bytes_written = 0, + .status = MPS_L1_STREAM_STATUS_READY + }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_stream( mps_l1_stream *p ) +{ + l1_free_stream_read( &p->rd ); + l1_free_stream_write( &p->wr ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_fetch_stream( mps_l1_stream_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ) +{ + int ret; + mbedtls_mps_size_t bl, br, data_need, data_fetched; + unsigned char *read_ptr; + void *recv_ctx; + mps_l0_recv_t *recv; + MBEDTLS_MPS_TRACE_INIT( "l1_fetch_stream, desired %u", (unsigned) len ); + + /* OPTIMIZATION: + * This refers to the potential removal of `buf` from + * the Layer 0 structure. If we do that, we might change + * the allocator's allocation function to only take the + * ID of the allocation, and to add a function querying + * for the pointer on success. This function should be a + * simple getter function returning the corresponding + * field from the allocator, so that the compiler can + * inline the access here. */ + + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + read_ptr = p->buf; + bl = p->buf_len; + if( len > bl ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ); + + br = p->bytes_read; + data_need = br <= len ? len - br : 0; + + recv = p->recv; + recv_ctx = p->recv_ctx; + read_ptr += br; + while( data_need > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "attempt to receive %u", (unsigned) data_need ); + ret = recv( recv_ctx, read_ptr, data_need ); + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_CONN_EOF; + if( ret < 0 ) + break; + MBEDTLS_MPS_TRACE_COMMENT( "got %u", (unsigned) ret ); + + /* TODO: FIX! */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + data_fetched = (mbedtls_mps_size_t) ret; + ret = 0; + + /* Double-check that the external Layer 0 obeys its spec; + * if it doesn't, we'd otherwise underflow data_need. */ + if( data_fetched > data_need ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + data_need -= data_fetched; + read_ptr += data_fetched; + br += data_fetched; + } + p->bytes_read = br; + + if( ret == 0 ) + { + *dst = p->buf; + p->bytes_fetched = len; + } + else + p->bytes_fetched = 0; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_consume_stream( mps_l1_stream_read *p ) +{ + unsigned char *buf; + mbedtls_mps_size_t bf, br, not_yet_fetched; + MBEDTLS_MPS_TRACE_INIT( "l1_consume_stream" ); + + bf = p->bytes_fetched; + br = p->bytes_read; + buf = p->buf; + not_yet_fetched = br - bf; + + p->bytes_fetched = 0; + p->bytes_read = not_yet_fetched; + + /* Note: + * As far as I see, it should never happen that the record-parsing + * Layer 2 client consumes less than what has been read. We might + * therefore consider returning an error on that occasion. On the + * other hand, allowing this use-case makes randomized testing simpler. + */ + if( not_yet_fetched != 0 ) + { + memmove( buf, buf + bf, not_yet_fetched ); + } + else + { + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + p->buf = NULL; + p->buf_len = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_flush_stream( mps_l1_stream_write *p ) +{ + int ret = 0; + unsigned char *buf; + mbedtls_mps_size_t br, bw, data_remaining; + mps_l1_stream_state status; + mps_l0_send_t *send; + void *send_ctx; + MBEDTLS_MPS_TRACE_INIT( "L1 flush stream" ); + + /* Flush is called in the following situations: + * (1) By the user, after data has been dispatched + * successfully, and it should be transferred + * to Layer 0 despite potentially more space + * being available. In this case, the expected + * state is MPS_L1_STREAM_STATUS_READY. + * (2) By mps_l1_write in case a flush is already + * in progress, or if a previous call to + * mps_l1_dispatch and, subsequently, + * l1_check_flush_stream, found a flush necessary. + * In this case the state is MPS_L1_STREAM_STATE_FLUSH. + */ + status = p->status; + + MBEDTLS_MPS_STATE_VALIDATE_RAW( status == MPS_L1_STREAM_STATUS_READY || + status == MPS_L1_STREAM_STATUS_FLUSH, + "Invalid state in l1_flush_stream()" ); + + p->status = MPS_L1_STREAM_STATUS_FLUSH; + br = p->bytes_ready; + bw = p->bytes_written; + + buf = p->buf; + buf += bw; + + send = p->send; + send_ctx = p->send_ctx; + data_remaining = br - bw; + while( data_remaining > 0 ) + { + mbedtls_mps_size_t data_written; + + ret = send( send_ctx, buf, data_remaining ); + if( ret <= 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "send failed with %d", ret ); + /* The underlying transport's send callback should return + * WANT_WRITE instead of 0 if no data can currently be sent. + * Fail with a fatal internal error if this spec is not obeyed. */ + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_BAD_TRANSPORT; + break; + } + + /* TODO: FIX */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + data_written = (mbedtls_mps_size_t) ret; + ret = 0; + + /* Double-check that the external Layer 0 obeys its + * spec to prevent an underflow in data_remaining. */ + if( data_written > data_remaining ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + data_remaining -= data_written; + buf += data_written; + bw += data_written; + } + + if( data_remaining == 0 ) + { + p->bytes_ready = 0; + p->bytes_written = 0; + p->status = MPS_L1_STREAM_STATUS_READY; + } + else + p->bytes_written = bw; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_write_stream( mps_l1_stream_write *p, + unsigned char **dst, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mps_l1_stream_state status; + mbedtls_mps_size_t bl, br, data_remaining; + unsigned char* buf; + MBEDTLS_MPS_TRACE_INIT( "l1_write_stream" ); + + status = p->status; + + /* Check if a flush has been deemed preferable by the + * flushing strategy (implemented in l1_check_flush_stream + * and called at the end of mps_l1_dispatch), or if a flush + * is already in progress but has not yet finished. */ + if( status == MPS_L1_STREAM_STATUS_FLUSH ) + { + ret = l1_flush_stream( p ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* The flush call either succeeded and reset the state + * to MPS_L1_STREAM_STATUS_READY, or it failed either + * fatally or because the underlying transport wasn't + * available, in which case we already returned. + * So assume the state is MPS_L1_STREAM_STATUS READY. */ + MBEDTLS_MPS_ASSERT_RAW( p->status == MPS_L1_STREAM_STATUS_READY, + "Unexpected state are flushing" ); + + /* Make sure a write-buffer is available. */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_OUT ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + br = p->bytes_ready; + bl = p->buf_len; + + buf = p->buf; + buf += br; + data_remaining = bl - br; + + /* The flushing strategy should ensure that we should never + * reach this point if the entire buffer has been dispatched. */ + MBEDTLS_MPS_ASSERT_RAW( data_remaining != 0, + "No data remaining despite flush" ); + + *dst = buf; + *buflen = data_remaining; + p->status = MPS_L1_STREAM_STATUS_WRITE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_write_dependency_stream( mps_l1_stream_write *p ) +{ + mps_l1_stream_state status; + + status = p->status; + if( status == MPS_L1_STREAM_STATUS_FLUSH ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_read_dependency_stream( mps_l1_stream_read *p ) +{ + ((void) p); + return( -1 ); +} + +MBEDTLS_MPS_INLINE +int l1_check_flush_stream( mps_l1_stream_write *p ) +{ + /* + * REMINDER: + * + * Remember to update the E-ACSL invariant + * MPS_L1_STREAM_WRITE_INV_FLUSH_STRATEGY when + * changing the implementation of this function. + * + */ + + mbedtls_mps_size_t bl, br; + br = p->bytes_ready; + bl = p->buf_len; + MBEDTLS_MPS_TRACE_INIT( "l1_check_flush_stream: %u / %u bytes written", + (unsigned) br, (unsigned) bl ); + + /* Several heuristics for flushing are conceivable, + * the simplest one being to immediately flush once + * data is available. + * + * QUESTION: + * Is it more efficient to gather a large buffer of + * outgoing data before calling the underlying stream + * transport, or should this always be done immediately? + */ + if( br > 0 && br >= 4 * bl / 5 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- flush" ); + p->status = MPS_L1_STREAM_STATUS_FLUSH; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- no flush" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_dispatch_stream( mps_l1_stream_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_size_t bl, br, data_remaining; + mps_l1_stream_state status = p->status; + MBEDTLS_MPS_TRACE_INIT( "L1 dispatch %u", (unsigned) len ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( status == MPS_L1_STREAM_STATUS_WRITE, + "Invalid state in l1_dispatch_stream()" ); + + bl = p->buf_len; + br = p->bytes_ready; + data_remaining = br - bl; + if( len > data_remaining ) + { + MBEDTLS_MPS_TRACE_COMMENT( "out of bounds %u > %u", + (unsigned) len, (unsigned) data_remaining ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ); + } + + br += len; + p->bytes_ready = br; + p->status = MPS_L1_STREAM_STATUS_READY; + + if( pending != NULL ) + *pending = br; + + /* + * NOTE: + * + * Currently, a dispatch will *never* immediately + * transmit data to the underlying transport, but + * only do so if, subsequently, another l1_write + * or l1_flush is called. + * The benefit of this is that there's no danger of + * mistakenly omitting critical code if a dispatching + * function fails with the (non-fatal) WANT_WRITE code. + * + * COMMENTS WELCOME + * + */ + + MBEDTLS_MPS_TRACE_RETURN( l1_check_flush_stream( p ) ); +} + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * + * Datagram-based implementation + * + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_INLINE +void l1_init_dgram_read( mps_l1_dgram_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ) +{ + mps_l1_dgram_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .window_base = 0, + .window_len = 0, + .msg_len = 0 }; + *p = zero; + + p->alloc = ctx; + l1_set_bio_dgram_read( p, recv_ctx, recv ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram_read( mps_l1_dgram_read *p, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + p->recv = recv; + p->recv_ctx = recv_ctx; +} + + +MBEDTLS_MPS_INLINE +void l1_init_dgram_write( mps_l1_dgram_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ) +{ + mps_l1_dgram_write const zero = { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .flush = 0 }; + *p = zero; + + p->alloc = ctx; + l1_set_bio_dgram_write( p, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram_write( mps_l1_dgram_write *p, + void* send_ctx, + mps_l0_send_t *send ) +{ + p->send = send; + p->send_ctx = send_ctx; +} + +MBEDTLS_MPS_INLINE +void l1_init_dgram( mps_l1_dgram *p, + mps_alloc *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_init_dgram_read ( &p->rd, ctx, recv_ctx, recv ); + l1_init_dgram_write( &p->wr, ctx, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram( mps_l1_dgram *p, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_set_bio_dgram_read ( &p->rd, recv_ctx, recv ); + l1_set_bio_dgram_write( &p->wr, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram_read( mps_l1_dgram_read *p ) +{ + mps_l1_dgram_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .window_base = 0, + .window_len = 0, + .msg_len = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram_write( mps_l1_dgram_write *p ) +{ + mps_l1_dgram_write const zero = { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .flush = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram( mps_l1_dgram *p ) +{ + l1_free_dgram_read ( &p->rd ); + l1_free_dgram_write( &p->wr ); +} + +/* + * This function ensures that data is available to be + * fetched and processed from the datagram reader. + * + * Specifically, the following is guaranteed on success: + * 1. That the reader has acquired a buffer to hold the Layer 0 data. + * 2. That the reader has received a nonempty datagram from Layer 0. + * + * This function is not part of the L1 API but only used + * as a preparation for the `fetch` function. + */ +MBEDTLS_MPS_INLINE +int l1_ensure_in_dgram( mps_l1_dgram_read *p ) +{ + mbedtls_mps_size_t ml, bl; + unsigned char *buf; + void* recv_ctx; + mps_l0_recv_t *recv; + int ret; + MBEDTLS_MPS_TRACE_INIT( "l1_ensure_in_dgram" ); + + /* 1. Ensure that a buffer is available to receive data */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + buf = p->buf; + bl = p->buf_len; + + /* 2. Ensure that a datagram is available */ + ml = p->msg_len; + if( ml == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Request datagram from underlying transport." ); + /* Q: Will the underlying transport error out + * if the receive buffer is not large enough + * to hold the entire datagram? */ + recv = p->recv; + recv_ctx = p->recv_ctx; + ret = recv( recv_ctx, buf, bl ); + if( ret <= 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* TODO: FIX */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + ml = (mbedtls_mps_size_t) ret; + + /* Double-check that the external Layer 0 obeys its spec. */ + if( ml > bl ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + MBEDTLS_MPS_TRACE_COMMENT( "Obtained datagram of size %u", (unsigned) ml ); + p->msg_len = ml; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_fetch_dgram( mps_l1_dgram_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ) +{ + int ret; + + mbedtls_mps_size_t data_need, data_avail; + mbedtls_mps_size_t wb, wl, ml; + + unsigned char *buf; + + MBEDTLS_MPS_TRACE_INIT( "l1_fetch_dgram, len %u", (unsigned) len ); + + ret = l1_ensure_in_dgram( p ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Datagram length: %u", (unsigned) p->msg_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window base: %u", (unsigned) p->window_base ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window length: %u", (unsigned) p->window_len ); + + wb = p->window_base; + wl = p->window_len; + ml = p->msg_len; + + /* As for the previous `ssl_fetch_input`, the semantics of Layer 1 `fetch` + * is that `fetch N` ensures that, in total, `N` bytes are available. + * Check how many bytes we have already provided to the user and shift + * the pointers by what's remaining. */ + if( wl < len ) + data_need = len - wl; + else + data_need = 0; + + /* Check how many bytes are left in the current datagram. */ + data_avail = ml - ( wb + wl ); + if( data_need > data_avail ) + { + MBEDTLS_MPS_TRACE_ERROR( "Read request goes beyond the datagram boundary - requested %u, available %u", + (unsigned) data_need, (unsigned) data_avail ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ); + } + + wl += data_need; + buf = p->buf; + + p->window_len = wl; + *dst = buf + wb; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_consume_dgram( mps_l1_dgram_read *p ) +{ + int ret; + mbedtls_mps_size_t wl, wb, ml; + + MBEDTLS_MPS_TRACE_INIT( "l1_consume_dgram" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( p->buf != NULL, + "l1_consume_dgram() called, but no datagram available" ); + + wb = p->window_base; + wl = p->window_len; + ml = p->msg_len; + + if( wb + wl == ml ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Reached the end of the datagram." ); + + /* + * Releasing the buffer as soon as a datagram + * has been processed is necessary when we want + * to try to share read and write buffers. But + * even if we don't yet attempt this, calling + * release here is useful to track the usage of the + * buffers. + * + * Note that if this is done, {acquire,release}_buffer + * shouldn't just forward to malloc/free, as this would + * lead to an unnecessarily heavy heap usage. + */ + ret = mps_alloc_release( p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + p->window_base = 0; + p->window_len = 0; + p->msg_len = 0; + p->buf = NULL; + p->buf_len = 0; + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "More data left in the current datagram." ); + p->window_base = wb + wl; + p->window_len = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_write_dependency_dgram( mps_l1_dgram_write *p ) +{ + uint8_t flush; + + flush = p->flush; + if( flush ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_read_dependency_dgram( mps_l1_dgram_read *p ) +{ + unsigned char *buf; + + buf = p->buf; + if( buf == NULL ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_write_dgram( mps_l1_dgram_write *p, + unsigned char **dst, + mbedtls_mps_size_t *dstlen ) +{ + int ret; + unsigned char *buf; + mbedtls_mps_size_t bl, br; + uint8_t flush; + MBEDTLS_MPS_TRACE_INIT( "l1_write_dgram" ); + + flush = p->flush; + if( flush ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Need to flush first" ); + ret = l1_flush_dgram( p ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Flush failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + } + + /* Ensure that a buffer is available to hold them + * outgoing datagram. */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_OUT ); + + bl = p->buf_len; + br = p->bytes_ready; + + buf = p->buf; + buf += p->bytes_ready; + + *dst = buf; + *dstlen = bl - br; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_dispatch_dgram( mps_l1_dgram_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_size_t br; + MBEDTLS_MPS_TRACE_INIT( "l1_dispatch_dgram, length %u", (unsigned) len ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( p->buf != NULL, + "l1_dispatch_dgram() called, but no datagram open" ); + + br = p->bytes_ready; + MBEDTLS_MPS_ASSERT_RAW( len <= p->buf_len - p->bytes_ready, + "l1_dispatch_dgram() length too large" ); + + br += len; + p->bytes_ready = br; + if( pending != NULL ) + *pending = br; + + MBEDTLS_MPS_TRACE_RETURN( l1_check_flush_dgram( p ) ); +} + +MBEDTLS_MPS_INLINE +int l1_check_flush_dgram( mps_l1_dgram_write *p ) +{ + mbedtls_mps_size_t bl, br; + br = p->bytes_ready; + bl = p->buf_len; + MBEDTLS_MPS_TRACE_INIT( "l1_check_flush_dgram: %u / %u bytes written", + (unsigned) br, (unsigned) bl ); + + /* Several heuristics for flushing are conceivable, + * the simplest one being to immediately flush once + * data is available. */ + if( br > 0 && br >= 4 * bl / 5 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- flush" ); + p->flush = 1; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- no flush" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_flush_dgram( mps_l1_dgram_write *p ) +{ + int ret; + void *send_ctx; + mps_l0_send_t *send; + unsigned char *buf; + mbedtls_mps_size_t br; + + MBEDTLS_MPS_TRACE_INIT( "l1_flush_dgram" ); + + buf = p->buf; + if( buf == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "No outgoing datagram open." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Datagram size: %u", (unsigned) p->bytes_ready ); + + br = p->bytes_ready; + + send = p->send; + send_ctx = p->send_ctx; + ret = send( send_ctx, buf, br ); + if( ret <= 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "send failed with %d", ret ); + /* The underlying transport's send callback should return + * WANT_WRITE instead of 0 if no data can currently be sent. + * Fail with a fatal internal error if this spec is not obeyed. */ + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_BAD_TRANSPORT; + + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + if( (size_t) ret != br ) + { + /* Couldn't deliver the datagram to Layer 0 at once. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + } + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + + p->bytes_ready = 0; + p->buf = NULL; + p->buf_len = 0; + + p->flush = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * + * Externally visible layer 1 implementation + * Just a bunch of small wrappers. + * + */ + +/* Q: Generate these functions through a macro? + * Doesn't reduce code-size but eases reading. */ + +int mps_l1_init( mps_l1 *ctx, uint8_t mode, + mps_alloc *alloc, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l1_init, mode %u", (unsigned) mode ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + l1_init_stream( &ctx->raw.stream, alloc, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l1_init_dgram( &ctx->raw.dgram, alloc, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_BOTH) + ctx->mode = mode; +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_BOTH */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l1_set_bio( mps_l1 *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + MBEDTLS_MPS_TRACE_INIT( "mps_l1_set_bio" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + l1_set_bio_stream( &ctx->raw.stream, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l1_set_bio_dgram( &ctx->raw.dgram, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +void mps_l1_free( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + l1_free_stream( &ctx->raw.stream ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + l1_free_dgram( &ctx->raw.dgram ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_fetch( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t desired ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_fetch_stream( &ctx->raw.stream.rd, buf, desired ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_fetch_dgram( &ctx->raw.dgram.rd, buf, desired ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_consume( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_consume_stream( &ctx->raw.stream.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_consume_dgram( &ctx->raw.dgram.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_write( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t *buflen ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_write_stream( &ctx->raw.stream.wr, buf, buflen ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_write_dgram( &ctx->raw.dgram.wr, buf, buflen ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_dispatch( mps_l1 *ctx, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_dispatch_stream( &ctx->raw.stream.wr, len, pending ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_dispatch_dgram( &ctx->raw.dgram.wr, len, pending ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_flush( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_flush_stream( &ctx->raw.stream.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_flush_dgram( &ctx->raw.dgram.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +/* TODO: Will we need this at some point? */ +int UNUSED mps_l1_read_dependency( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_read_dependency_stream( &ctx->raw.stream.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_read_dependency_dgram( &ctx->raw.dgram.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +/* TODO: Will we need this at some point? */ +int UNUSED mps_l1_write_dependency( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_write_dependency_stream( &ctx->raw.stream.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_write_dependency_dgram( &ctx->raw.dgram.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l1_skip( mps_l1 *ctx ) +{ + mps_l1_dgram_read *p; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l1_skip" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( MBEDTLS_MPS_IS_DTLS( mode ), + "mps_l1_skip() only for DTLS." ); + + p = &ctx->raw.dgram.rd; + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + + p->window_base = 0; + p->window_len = 0; + p->msg_len = 0; + p->buf = NULL; + p->buf_len = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer1_internal.h b/library/mps/layer1_internal.h new file mode 100644 index 000000000000..da6751e1a075 --- /dev/null +++ b/library/mps/layer1_internal.h @@ -0,0 +1,154 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_BUFFER_LAYER_INTERNAL_H +#define MBEDTLS_MPS_BUFFER_LAYER_INTERNAL_H + +#include "mbedtls/mps/layer1.h" + +/* + * Allocator related functions + */ + +MBEDTLS_MPS_STATIC void l1_release_if_set( unsigned char **buf_ptr, + mps_alloc *ctx, + mps_alloc_type purpose ); +MBEDTLS_MPS_STATIC int l1_acquire_if_unset( unsigned char **buf_ptr, + mbedtls_mps_size_t *buflen, + mps_alloc *ctx, + mps_alloc_type purpose ); + +/* + * Functions related to stream-based implementation of Layer 1 + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +MBEDTLS_MPS_INLINE void l1_init_stream_read( mps_l1_stream_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_init_stream_write( mps_l1_stream_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_init_stream( mps_l1_stream *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_free_stream_read( mps_l1_stream_read *p ); +MBEDTLS_MPS_INLINE void l1_free_stream_write( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE void l1_free_stream( mps_l1_stream *p ); + +MBEDTLS_MPS_INLINE void l1_set_bio_stream_read( mps_l1_stream_read *p, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_set_bio_stream_write( mps_l1_stream_write *p, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_set_bio_stream( mps_l1_stream *p, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE int l1_fetch_stream( mps_l1_stream_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ); +MBEDTLS_MPS_INLINE int l1_write_stream( mps_l1_stream_write *p, + unsigned char **dst, + mbedtls_mps_size_t *buflen ); + +MBEDTLS_MPS_INLINE int l1_check_flush_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_flush_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_consume_stream( mps_l1_stream_read *p ); +MBEDTLS_MPS_INLINE int l1_dispatch_stream( mps_l1_stream_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +MBEDTLS_MPS_INLINE int l1_write_dependency_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_read_dependency_stream( mps_l1_stream_read *p ); + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Functions related to datagram-based implementation of Layer 1 + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_INLINE void l1_init_dgram_read( mps_l1_dgram_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_init_dgram_write( mps_l1_dgram_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_init_dgram( mps_l1_dgram *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_free_dgram_read( mps_l1_dgram_read *p ); +MBEDTLS_MPS_INLINE void l1_free_dgram_write( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE void l1_free_dgram( mps_l1_dgram *p ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram_write( mps_l1_dgram_write *p, + void *send_ctx, + mps_l0_send_t *send ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram_read( mps_l1_dgram_read *p, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram( mps_l1_dgram *p, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE int l1_fetch_dgram( mps_l1_dgram_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ); +MBEDTLS_MPS_INLINE int l1_consume_dgram( mps_l1_dgram_read *p ); +MBEDTLS_MPS_INLINE int l1_write_dgram( mps_l1_dgram_write *p, + unsigned char **buf, + mbedtls_mps_size_t *buflen ); +MBEDTLS_MPS_INLINE int l1_dispatch_dgram( mps_l1_dgram_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +MBEDTLS_MPS_INLINE int l1_flush_dgram( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE int l1_check_flush_dgram( mps_l1_dgram_write *p ); + +MBEDTLS_MPS_INLINE int l1_ensure_in_dgram( mps_l1_dgram_read *p ); + +MBEDTLS_MPS_INLINE int l1_write_dependency_dgram( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE int l1_read_dependency_dgram( mps_l1_dgram_read *p ); + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_BUFFER_LAYER_INTERNAL */ diff --git a/library/mps/layer2.c b/library/mps/layer2.c new file mode 100644 index 000000000000..6421e07a5ae1 --- /dev/null +++ b/library/mps/layer2.c @@ -0,0 +1,2923 @@ +/* + * Message Processing Stack, Layer 2 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer2.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer2_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_2; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include +#include + + +MBEDTLS_MPS_STATIC +void l2_out_write_version( int major, int minor, + mbedtls_mps_transport_type transport, + unsigned char ver[2] ) +{ + MBEDTLS_MPS_IF_TLS( transport ) + { + ver[0] = (unsigned char) major; + ver[1] = (unsigned char) minor; + } + MBEDTLS_MPS_ELSE_IF_DTLS( transport ) + { + if( minor == MBEDTLS_SSL_MINOR_VERSION_2 ) + --minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + + ver[0] = (unsigned char)( 255 - ( major - 2 ) ); + ver[1] = (unsigned char)( 255 - ( minor - 1 ) ); + } +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +void l2_read_version_tls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ) +{ + *major = ver[0]; + *minor = ver[1]; +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +void l2_read_version_dtls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ) +{ + *major = 255 - ver[0] + 2; + *minor = 255 - ver[1] + 1; + + if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 ) + ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */ +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC +void mps_l2_readers_init( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + cur->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + mbedtls_mps_reader_init( &cur->rd, NULL, 0 ); + } +} + +MBEDTLS_MPS_STATIC +void mps_l2_readers_free( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + cur->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + mbedtls_mps_reader_free( &cur->rd ); + } +} + +/* This functions _assumes_ that there is an active reader (in state internal + * or external) and returns a handle to the reader. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_active( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_INTERNAL || + cur->state == MBEDTLS_MPS_L2_READER_STATE_EXTERNAL ) + { + return( cur ); + } + } + return( NULL ); +} + +MBEDTLS_MPS_STATIC +int mps_l2_readers_close_active( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + return( 0 ); + mbedtls_mps_reader_free( &active->rd ); + active->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + return( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* This function pauses the currently active reader. */ +MBEDTLS_MPS_STATIC +int mps_l2_readers_pause_active( mbedtls_mps_l2 *ctx ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_readers_pause_active" ); + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + active->state = MBEDTLS_MPS_L2_READER_STATE_PAUSED; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* This functions determines + * - Whether there is an active reader in the current Layer 2 implementation + * - If so, whether it's status is internal (record open but not currently + * passed to the user) or external (record open and currently passed to + * the user). + */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_reader_state mps_l2_readers_active_state( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + return( MBEDTLS_MPS_L2_READER_STATE_UNSET ); + return( active->state ); +} + +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_unused( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_UNSET ) + return( cur ); + } + return( NULL ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int mps_l2_readers_accumulator_taken( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_PAUSED ) + return( 1 ); + } + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_INLINE +void mps_l2_reader_slots_changed( mbedtls_mps_l2 *ctx ) +{ + ((void) ctx); + return; +} + +/* This function searches the list of paused readers for one matching the + * record content type passed as an argument. If one exists, it returns that + * reader if it matches the passed epoch, and fails otherwise. If there is + * no reader handling the given content type but an unused reader is available, + * it returns that reader. Otherwise, it fails. */ +MBEDTLS_MPS_INLINE +int mps_l2_find_suitable_slot( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch, + mbedtls_mps_l2_in_internal **dst ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + unsigned char *acc = NULL; + mbedtls_mps_size_t acc_len = 0; + + mbedtls_mps_l2_in_internal *slot = NULL; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_find_suitable_slot(), type %u, epoch %u", + (unsigned) type, (unsigned) epoch ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_PAUSED && + cur->type == type ) + { + /* It is not possible to change the incoming epoch when + * a reader is being paused, hence the epoch of the new + * record must match. Double-check this nonetheless. */ + MBEDTLS_MPS_ASSERT_RAW( cur->epoch == epoch, + "The paused epoch doesn't match the incoming epoch" ); + + *dst = cur; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + } + + if( l2_type_can_be_paused( ctx, type ) != 0 ) + { + if( mps_l2_readers_accumulator_taken( ctx ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The accumulator (size %u) is available", + (unsigned) ctx->io.in.acc_len ); + acc = ctx->io.in.accumulator; + acc_len = ctx->io.in.acc_len; + } + else +#if !defined(MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "The accumulator is not available, and don't allow " + "to open pausable content types without accumulator." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ); + } +#else + { + MBEDTLS_MPS_TRACE_COMMENT( "No accumulator is available, but open nonetheless." ); + } +#endif /* MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR */ + } + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + slot = mps_l2_readers_get_unused( ctx ); + if( slot == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "No free reader available for the incoming record." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); + } + + mbedtls_mps_reader_init( &slot->rd, acc, acc_len ); + slot->type = type; + slot->epoch = epoch; + *dst = slot; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_increment_counter( uint32_t ctr[2] ) +{ + if( ++ctr[1] == 0 && ++ctr[0] == 0 ) + return( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + return( 0 ); +} + +int mps_l2_init( mbedtls_mps_l2 *ctx, mps_l1 *l1, + mbedtls_mps_transport_type mode, + mbedtls_mps_size_t max_read, + mbedtls_mps_size_t max_write, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + /* TODO: Make this more compact; zeroize the Layer 2 + * structure first and then only correct those + * fields where 0 is not proper initialization. */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + unsigned char *queue = NULL, *accumulator = NULL; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + mps_l2_bufpair zero_bufpair = { NULL, 0, 0, 0 }; + MBEDTLS_MPS_TRACE_INIT( "l2_init" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( max_write > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Allocating L2 writer queue of size %u Bytes", + (unsigned) max_write ); + queue = mbedtls_calloc( 1, max_write ); + } + if( max_read > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Allocating L2 reader accumulator of size %u Bytes", + (unsigned) max_read ); + accumulator = mbedtls_calloc( 1, max_read ); + } + + if( ( max_write > 0 && queue == NULL ) || + ( max_read > 0 && accumulator == NULL ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Failed to allocate queue or accumulator." ); + mbedtls_free( queue ); + mbedtls_free( accumulator ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + } +#else + ((void) max_read); + ((void) max_write); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + ctx->conf.l1 = l1; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + ctx->conf.mode = mode; +#else + ((void) mode); + MBEDTLS_MPS_ASSERT_RAW( mode == MBEDTLS_MPS_CONF_MODE, + "Mismatch between compile- and runtime configuration" ); +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + /* TODO: Allow setting an arbitrary version, + * as well as an initially unspecified one. */ + ctx->conf.version = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) + ctx->conf.type_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + ctx->conf.merge_flag = 0; +#endif /* MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + ctx->conf.pause_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + ctx->conf.empty_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) + ctx->conf.max_plain_out = 16384; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) + ctx->conf.max_plain_in = 16384; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) + ctx->conf.max_cipher_in = 16384; +#endif /* !MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + + ctx->conf.f_rng = f_rng; + ctx->conf.p_rng = p_rng; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) + ctx->conf.badmac_limit = 0; +#endif /* !MBEDTLS_MPS_CONF_BADMAC_LIMIT */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) + ctx->conf.anti_replay = MBEDTLS_MPS_ANTI_REPLAY_ENABLED; +#endif /* !MBEDTLS_MPS_CONF_ANTI_REPLAY */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Initialize write-side */ + ctx->io.out.flush = 0; + ctx->io.out.clearing = 0; + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_UNSET; +#if defined(MBEDTLS_MPS_PROTO_TLS) + ctx->io.out.queue = queue; + ctx->io.out.queue_len = max_write; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + ctx->io.out.hdr = NULL; + ctx->io.out.hdr_len = 0; + ctx->io.out.payload = zero_bufpair; + + ctx->io.out.writer.type = MBEDTLS_MPS_MSG_NONE; + ctx->io.out.writer.epoch = MBEDTLS_MPS_EPOCH_NONE; + mbedtls_writer_init( &ctx->io.out.writer.wr, NULL, 0 ); + + /* Initialize read-side */ +#if defined(MBEDTLS_MPS_PROTO_TLS) + ctx->io.in.accumulator = accumulator; + ctx->io.in.acc_len = max_read; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + mps_l2_readers_init( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + ctx->io.in.bad_mac_ctr = 0; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Initialize epochs */ + + memset( &ctx->epochs, 0, sizeof( ctx->epochs ) ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + ctx->epochs.default_in = MBEDTLS_MPS_EPOCH_NONE; + ctx->epochs.default_out = MBEDTLS_MPS_EPOCH_NONE; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_free( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_size_t offset; + ((void) ctx); + MBEDTLS_MPS_TRACE_INIT( "l2_free" ); + + mps_l2_readers_free( ctx ); + mbedtls_writer_free( &ctx->io.out.writer.wr ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + free( ctx->io.in.accumulator ); + free( ctx->io.out.queue ); + + ctx->io.in.accumulator = NULL; + ctx->io.in.acc_len = 0; + ctx->io.out.queue = NULL; + ctx->io.out.queue_len = 0; +#endif /* MBDTLS_MPS_PROTO_TLS */ + + for( offset = 0; offset < MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE; offset++ ) + l2_epoch_free( &ctx->epochs.window[offset] ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_config_version( mbedtls_mps_l2 *ctx, uint8_t ver ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_config_version: %u", (unsigned) ver ); + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + /* TODO: Add check */ + ctx->conf.version = ver; +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* Please consult the documentation of mbedtls_mps_l2 for a basic + * description of the state flow when preparing outgoing records. + * + * This function assumes that no outgoing record is currently being processed + * and prepares L1-owned buffers holding the record header and record plaintext. + * The latter is subsequently fed to the user-facing writer object (not done + * in this function). */ +MBEDTLS_MPS_STATIC +int l2_out_prepare_record( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id ) +{ + int ret; + unsigned char *rec_buf; /* The buffer received from Layer 1 + * to which we write the record. */ + mbedtls_mps_size_t total_sz; /* The total size of rec_buf in bytes. */ + mbedtls_mps_size_t hdr_len; /* The length of the record header. */ + size_t pre_expansion; /* The amount of data (in bytes) that + * the transform protecting the record + * adds in front of the plaintext. */ + size_t post_expansion; /* The amount of data (in bytes) that + * the transform protecting the record + * adds beyond the plaintext. */ + mbedtls_mps_size_t max_plaintext_len; /* The maximum number of plaintext + * bytes that the outgoing record + * can hold. */ + + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_out_prepare, epoch %d", epoch_id ); + + /* Request buffer from Layer 1 to hold entire record. */ + ret = mps_l1_write( l1, &rec_buf, &total_sz ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "l1_write failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* Lookup epoch and get + * - the record header size, and + * - the maximum plaintext-to-ciphertext pre- and post-expansion. + * With this information, the sub-buffer holding the record + * plaintext before encryption can be calculated. */ + + hdr_len = l2_get_header_len( ctx, epoch_id ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Transform expansion:" ); + mbedtls_mps_transform_get_expansion( epoch->transform, + &pre_expansion, + &post_expansion ); + MBEDTLS_MPS_TRACE_COMMENT( "* Pre: %u", (unsigned) pre_expansion ); + MBEDTLS_MPS_TRACE_COMMENT( "* Post: %u", (unsigned) post_expansion ); + +#if defined(MBEDTLS_MPS_TRANSFORM_VALIDATION) + { + /* Detect overflow */ + mbedtls_mps_size_t sum0 = hdr_len; + mbedtls_mps_size_t sum1 = (mbedtls_mps_size_t)( sum0 + pre_expansion ); + mbedtls_mps_size_t sum2 = (mbedtls_mps_size_t)( sum1 + post_expansion ); + + if( sum1 < sum0 || sum2 < sum1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "INTERNAL ERROR on pre- and postexpansion, len %u, pre-expansion %u, post-expansion %u", + (unsigned) hdr_len, (unsigned) pre_expansion, (unsigned) post_expansion ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSFORM ); + } + } +#endif /* MBEDTLS_MPS_TRANSFORM_VALIDATION */ + + /* Check if buffer obtained from Layer 1 is large enough to accomodate + * at least a protected record with plaintext length 1. */ + if( hdr_len + pre_expansion + post_expansion >= total_sz ) + { + mbedtls_mps_size_t bytes_pending; + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space for to hold a non-empty record." ); + MBEDTLS_MPS_TRACE_COMMENT( "Need at least %u ( %u header + %u pre-expansion + " + "%u post-expansion + 1 plaintext ) byte, but have only " + "%u bytes available.", + (unsigned)( hdr_len + pre_expansion + post_expansion + 1 ), + (unsigned) hdr_len, + (unsigned) pre_expansion, + (unsigned) post_expansion, + (unsigned) total_sz ); + + /* Abort the write and remember to flush before the next write. */ + mps_l1_dispatch( l1, 0 /* Abort := Dispatch nothing */, + &bytes_pending ); + ctx->io.out.clearing = 1; + + /* If Layer 1 has no bytes pending but doesn't have enough space + * to allow a record of size 1 to be sent, something must be + * ill-configured. */ + MBEDTLS_MPS_ASSERT_RAW( bytes_pending != 0, + "Layer 1 doesn't have data pending but cannot " + "serve a buffer large enough to hold a non-empty record." ); + + /* We could also return WANT_WRITE here. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + + /* The previous check ensures that the following is >= 1. */ + max_plaintext_len = + (mbedtls_mps_size_t)( total_sz - ( hdr_len + pre_expansion + post_expansion ) ); + + /* Obey maximum plaintext size configured by the user. */ + if( max_plaintext_len > mbedtls_mps_l2_conf_get_max_plain_out( &ctx->conf ) ) + max_plaintext_len = mbedtls_mps_l2_conf_get_max_plain_out( &ctx->conf ); + + /* Dissect L1 record buffer into header, ciphertext and plaintext parts. + * The plaintext sub-buffer can subsequently be fed to the writer which + * then gets passed to the user, i.e. Layer 3. */ + + ctx->io.out.hdr = rec_buf; + ctx->io.out.hdr_len = hdr_len; + + ctx->io.out.payload.buf = rec_buf + hdr_len; + ctx->io.out.payload.buf_len = total_sz - hdr_len; + + ctx->io.out.payload.data_offset = pre_expansion; + ctx->io.out.payload.data_len = max_plaintext_len; + + epoch->usage |= MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN; + + MBEDTLS_MPS_TRACE_COMMENT( "New outgoing record successfully prepared." ); + MBEDTLS_MPS_TRACE_COMMENT( " * Max plaintext size: %u", + (unsigned) ctx->io.out.payload.data_len ); + MBEDTLS_MPS_TRACE_COMMENT( " * Pre expansion: %u", + (unsigned) ctx->io.out.payload.data_offset ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* Please consult the documentation of mbedtls_mps_l2 for a basic description + * of the state flow when preparing outgoing records. + * + * This function assumes that the record header and record plaintext pointers + * are valid ( := obtained from l2_out_prepare ) and some content has been + * written to them (in practice, this will be done through the user-facing + * writer object, but for the purpose of this function this is not important). + * Further, it is assumed that no other resource holds partial ownership of + * these buffers (concretely, again, this means that the writer's access to + * the buffers has already been revoked). It then proceeds to protect the + * record payload via the transform attached to the record's epoch, writes + * the header, and dispatches the final record to Layer 1. */ +MBEDTLS_MPS_STATIC +int l2_out_dispatch_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_rec rec; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + MBEDTLS_MPS_TRACE_INIT( "l2_out_dispatch_record" ); + MBEDTLS_MPS_TRACE_COMMENT( "Plaintext length: %u", + (unsigned) ctx->io.out.payload.data_len ); + + if( ctx->io.out.payload.data_len == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Attempt to dispatch an empty record %u.", + (unsigned) ctx->io.out.writer.type ); + MBEDTLS_MPS_TRACE_COMMENT( "Empty records allowed for type %u: %u", + (unsigned) ctx->io.out.writer.type, + (unsigned) l2_type_empty_allowed( ctx, ctx->io.out.writer.type ) ); + } + + /* Silently ignore empty records if such are not allowed + * for the current record content type. */ + if( ctx->io.out.payload.data_len == 0 && + l2_type_empty_allowed( ctx, ctx->io.out.writer.type ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Empty records are not allowed for type %u -> ignore request.", + ctx->io.out.writer.type ); + + /* dispatch(0) effectively resets the underlying Layer 1. */ + ret = mps_l1_dispatch( l1, 0, NULL ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else + { + mbedtls_mps_l2_epoch_t *epoch; + + /* Step 1: Prepare the record header structure. */ + + /* TODO: Handle the case where the version hasn't been set yet! */ + rec.major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + rec.minor_ver = mbedtls_mps_l2_conf_get_version( &ctx->conf ); + rec.buf = ctx->io.out.payload; + rec.epoch = (uint16_t) ctx->io.out.writer.epoch; + rec.type = ctx->io.out.writer.type; + + MBEDTLS_MPS_TRACE_COMMENT( "Record header fields:" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) rec.epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) rec.type ); + + ret = l2_epoch_lookup( ctx, ctx->io.out.writer.epoch, &epoch ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch lookup failed" ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + l2_out_get_and_update_rec_seq( ctx, epoch, rec.ctr ); + MBEDTLS_MPS_TRACE_COMMENT( "* Sequence number: ( %u << 16 ) + %u", + (unsigned) rec.ctr[0], (unsigned) rec.ctr[1] ); + + /* Step 2: Apply record payload protection. */ + MBEDTLS_MPS_TRACE_COMMENT( "Encrypt record. The plaintext offset is %u.", + (unsigned) rec.buf.data_offset ); + ret = mbedtls_mps_transform_encrypt( epoch->transform, &rec, + ctx->conf.f_rng, + ctx->conf.p_rng ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The record encryption failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + MBEDTLS_MPS_TRACE_COMMENT( "Record type after encryption: %u", + (unsigned) rec.type ); + +#if defined(MBEDTLS_MPS_TRANSFORM_VALIDATION) + /* Double-check that we have calculated the offset of the + * plaintext buffer from the ciphertext buffer correctly + * when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + if( rec.buf.data_offset != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Get non-zero ciphertext offset %u after encryption.", + (unsigned) rec.buf.data_offset ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSFORM ); + } +#endif /* MBEDTLS_MPS_TRANSFORM_VALIDATION */ + + /* Step 3: Write version- and mode-specific header and send record. */ + ret = l2_out_write_protected_record( ctx, &rec ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_ASSERT_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET || + ( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING && + MBEDTLS_MPS_IS_TLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ) ), + "Unexpected writer state at the end of l2_out_dispatch_record()" ); +#else + MBEDTLS_MPS_ASSERT_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET, + "Unexpected writer state at the end of l2_out_dispatch_record()" ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + epoch->usage &= ~MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN; + } + } + + /* Epochs might have been held back because of the pending write. */ + ret = l2_epoch_cleanup( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret = 0; + mps_l2_bufpair const zero_bufpair = { NULL, 0, 0, 0 }; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "Write protected record" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* The record header structure is the same for all versions + * of TLS, including TLS 1.3. The only difference is that in + * TLS 1.3, the record payload needs to be post-processed to + * remove the plaintext padding. + * Note padding is treated entirely separatedly from encryption + * and authentication, while for the use of CBC in earlier versions, + * it was part of CBC, and AEAD didn't allow padding at all. */ + ret = l2_out_write_protected_record_tls( ctx, rec ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + switch( mbedtls_mps_l2_conf_get_version( &ctx->conf ) ) + { + case MBEDTLS_SSL_MINOR_VERSION_2: /* DTLS 1.0 */ + case MBEDTLS_SSL_MINOR_VERSION_3: /* DTLS 1.2 */ + ret = l2_out_write_protected_record_dtls12( ctx, rec ); + + /* TLS-1.3-NOTE: Add DTLS-1.3 here */ + + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Cleanup internal structure for outgoing data. */ + ctx->io.out.hdr = NULL; + ctx->io.out.hdr_len = 0; + ctx->io.out.payload = zero_bufpair; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record_tls( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + uint8_t * const hdr = ctx->io.out.hdr; + mbedtls_mps_size_t const hdr_len = ctx->io.out.hdr_len; + mbedtls_mps_size_t const tls_rec_hdr_len = 5; + mbedtls_mps_size_t const tls_rec_type_offset = 0; + mbedtls_mps_size_t const tls_rec_ver_offset = 1; + mbedtls_mps_size_t const tls_rec_len_offset = 3; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_write_protected_record_tls" ); + + /* Double-check that we have calculated the header length + * correctly when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + MBEDTLS_MPS_ASSERT_RAW( hdr_len == tls_rec_hdr_len, + "Invalid record header length" ); + + /* Header structure is the same for all TLS versions. + * From RFC 5246 - Section 6.2 + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; + */ + + /* Write record content type. */ + MPS_WRITE_UINT8_BE( &rec->type, hdr + tls_rec_type_offset ); + /* Write record version. */ + l2_out_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, + hdr + tls_rec_ver_offset ); + /* Write ciphertext length. */ + MPS_WRITE_UINT16_BE( &rec->buf.data_len, hdr + tls_rec_len_offset ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) rec->type ); + MBEDTLS_MPS_TRACE_COMMENT( "* Version: %u", (unsigned) rec->minor_ver ); + MBEDTLS_MPS_TRACE_RETURN( mps_l1_dispatch( l1, hdr_len + rec->buf.data_len, NULL ) ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + uint8_t * const hdr = ctx->io.out.hdr; + mbedtls_mps_size_t const hdr_len = ctx->io.out.hdr_len; + + /* Header structure the same for DTLS 1.0 and DTLS 1.2. + + From RFC 6347 - Section 4.1 + + struct { + ContentType type; + ProtocolVersion version; + uint16 epoch; + uint48 sequence_number; + uint16 length; + opaque fragment[DTLSPlaintext.length]; + } DTLSPlaintext; + + */ + + mbedtls_mps_size_t const dtls_rec_hdr_len = 13; + + mbedtls_mps_size_t const dtls_rec_type_offset = 0; + mbedtls_mps_size_t const dtls_rec_ver_offset = 1; + mbedtls_mps_size_t const dtls_rec_epoch_offset = 3; + mbedtls_mps_size_t const dtls_rec_seq_offset = 5; + mbedtls_mps_size_t const dtls_rec_len_offset = 11; + + MBEDTLS_MPS_TRACE_INIT( "l2_write_protected_record_dtls12" ); + + /* Double-check that we have calculated the header length + * correctly when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + MBEDTLS_MPS_ASSERT_RAW( hdr_len == dtls_rec_hdr_len, + "Invalid DTLS record header length" ); + + /* Write record content type. */ + MPS_WRITE_UINT8_BE( &rec->type, hdr + dtls_rec_type_offset ); + + /* Write record version. */ + l2_out_write_version( rec->major_ver, + rec->minor_ver, + MBEDTLS_MPS_MODE_DATAGRAM, + hdr + dtls_rec_ver_offset ); + + /* Epoch */ + MPS_WRITE_UINT16_BE( &rec->epoch, hdr + dtls_rec_epoch_offset ); + + /* Record sequence number */ + MPS_WRITE_UINT16_BE( &rec->ctr[0], hdr + dtls_rec_seq_offset ); + MPS_WRITE_UINT32_BE( &rec->ctr[1], hdr + dtls_rec_seq_offset + 2 ); + + /* Write ciphertext length. */ + MPS_WRITE_UINT16_BE( &rec->buf.data_len, hdr + dtls_rec_len_offset ); + + MBEDTLS_MPS_TRACE_COMMENT( "Write protected record -- DISPATCH" ); + MBEDTLS_MPS_TRACE_RETURN( mps_l1_dispatch( l1, hdr_len + rec->buf.data_len, NULL ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +int mps_l2_write_flush( mbedtls_mps_l2 *ctx ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_write_flush, state %u", ctx->io.out.state ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "mps_l2_write_flush() called in unexpected state." ); + + ctx->io.out.flush = 1; + MBEDTLS_MPS_TRACE_RETURN( l2_out_clear_pending( ctx ) ); +} + +/* See the documentation of `clearing` and `flush` in layer2.h + * for more information on the flow of this routine. */ +MBEDTLS_MPS_STATIC +int l2_out_clear_pending( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_out_clear_pending, state %u", (unsigned) ctx->io.out.state ); + + if( ctx->io.out.clearing == 1 ) + { + ret = mps_l1_flush( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + ctx->io.out.clearing = 0; + } + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* Each iteration strictly reduces the size of the + * writer's queue, hence the loop must terminate. */ + while( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING ) + { + mbedtls_mps_epoch_id queued_epoch; + queued_epoch = ctx->io.out.writer.epoch; + + MBEDTLS_MPS_TRACE_COMMENT( "Queued data is pending to be dispatched" ); + + /* Prepare an outgoing record to dispatch the queued data */ + ret = l2_out_prepare_record( ctx, queued_epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ret = l2_out_track_record( ctx ); + if( ret == 0 ) + break; + else if( ret != MBEDTLS_ERR_WRITER_NEED_MORE ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "The prepared record was entirely filled with queued data -> dispatch it" ); + + /* There's more queued data pending, so just deliver the record. */ + ret = l2_out_dispatch_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + MBEDTLS_MPS_TRACE_COMMENT( "Queue clear" ); + + if( ctx->io.out.flush == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A flush was requested requested, state %u", + (unsigned) ctx->io.out.state ); + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ) + { + ret = l2_out_release_and_dispatch( ctx, + MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* NOTE: + * This code is only valid if Layer 1 doesn't attempt partial + * transmissions to the underlying transport; in other words, + * if layer 1 starts sending, it must behave as if `flush` had + * been called, and make sure everything is delivered before + * the next write can be made. + * If this is not satisfied, and e.g. Layer 1 might only clear + * parts of the internal buffers, enough to have free space for + * new outgoing messages, then it might happen that the call + * to l2_out_release_and_dispatch above would return WANT_WRITE, + * thereby terminating this function early, but without having + * informed Layer 1 that it should flush everything. + * + * So: Transmit everything or nothing, but nothing partial. + */ + + /* Epochs might have been held back because of the pending write. */ + ret = l2_epoch_cleanup( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ctx->io.out.clearing = 1; + ctx->io.out.flush = 0; + } + + if( ctx->io.out.clearing == 1 ) + { + ret = mps_l1_flush( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + ctx->io.out.clearing = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_write_start( mbedtls_mps_l2 *ctx, mps_l2_out *out ) +{ + int ret; + uint8_t desired_type; + mbedtls_mps_epoch_id desired_epoch; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_write_start" ); + + /* We must not attempt to write multiple records simultaneously. + * If this happens, the layer most likely forgot to dispatch + * the last outgoing record. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected operation" ); + + /* Check if the requested record content type is valid. */ + desired_type = out->type; + if( l2_type_is_valid( ctx, desired_type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Message type %d is invalid", desired_type ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + /* Check if the requested epoch is valid for writing. */ + desired_epoch = out->epoch; + ret = l2_epoch_check( ctx, desired_epoch, MPS_EPOCH_WRITE_MASK ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Make sure that no data is queueing for dispatching, and that + * all dispatched data has been delivered by Layer 1 in case + * a flush has been requested. + * Please consult the documentation of ::mps_l2 for further information. */ + ret = l2_out_clear_pending( ctx ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "l2_out_clear_pending failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* If l2_out_clear_pending() succeeds, it guarantees that the + * write state is not MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING anymore. + * Hence, it's either INTERNAL or UNSET. */ + + /* + * If an outgoing record has already been prepared but not yet dispatched, + * append to it in case both the requested type and the epoch match. + * + * If they don't match, the current record must be dispatched first before + * a new one can be prepared with the requested type and epoch. + */ + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ) + { + if( ctx->io.out.writer.type == desired_type && + ctx->io.out.writer.epoch == desired_epoch ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Type and epoch match currently open record -> attach." ); + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL; + out->wr = &ctx->io.out.writer.wr; + + MBEDTLS_MPS_TRACE_COMMENT( "* Total size of record buffer: %u Bytes", + (unsigned) out->wr->out_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Committed: %u Bytes", + (unsigned) out->wr->committed ); + MBEDTLS_MPS_TRACE_COMMENT( "* Written: %u Bytes", + (unsigned) out->wr->end ); + MBEDTLS_MPS_TRACE_COMMENT( "* Remaining: %u Bytes", + (unsigned) ( out->wr->out_len - out->wr->committed ) ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Type or epoch doesn't match open record." ); + ret = l2_out_release_and_dispatch( ctx, MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* The old record has been dispatched by now, and we fall through + * to open a new one for the requested type and epoch. */ + } + + /* State must be MBEDTLS_MPS_L2_WRITER_STATE_UNSET when we reach this. */ + + /* Prepare raw buffers from Layer 1 to hold the new record. */ + ret = l2_out_prepare_record( ctx, desired_epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ctx->io.out.writer.type = desired_type; + ctx->io.out.writer.epoch = desired_epoch; + + /* Bind buffers to the writer passed to the user. */ + ret = l2_out_track_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL; + out->wr = &ctx->io.out.writer.wr; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_write_done( mbedtls_mps_l2 *ctx ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_write_done" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected operation" ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL; + + ret = l2_out_release_and_dispatch( ctx, MBEDTLS_WRITER_RECLAIM_NO_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_track_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_out_track_record" ); + + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET ) + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* Depending on whether the record content type is pausable, + * provide a queue to the writer or not. */ + if( l2_type_can_be_paused( ctx, ctx->io.out.writer.type ) ) + { + mbedtls_writer_init( &ctx->io.out.writer.wr, + ctx->io.out.queue, + ctx->io.out.queue_len ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + mbedtls_writer_init( &ctx->io.out.writer.wr, NULL, 0 ); + } + } + + ret = mbedtls_writer_feed( &ctx->io.out.writer.wr, + ctx->io.out.payload.buf + ctx->io.out.payload.data_offset, + ctx->io.out.payload.data_len ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "mbedtls_writer_feed failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_release_record( mbedtls_mps_l2 *ctx, uint8_t force ) +{ + int ret; + mbedtls_mps_size_t bytes_written, bytes_queued; + mbedtls_mps_msg_type_t type; + MBEDTLS_MPS_TRACE_INIT( "l2_out_release_record, force %u, state %u", force, + (unsigned) ctx->io.out.state ); + + ret = mbedtls_writer_reclaim( &ctx->io.out.writer.wr, &bytes_written, + &bytes_queued, force ); + if( force == MBEDTLS_WRITER_RECLAIM_NO_FORCE && + ret == MBEDTLS_ERR_WRITER_DATA_LEFT ) + { + MBEDTLS_MPS_TRACE_COMMENT( "There's space left in the current outgoing record." ); + type = ctx->io.out.writer.type; + + /* Check if records of the given type may be merged. + * E.g., in [D]TLS 1.3 multiple multiple alerts must not + * be placed in a single record. */ + if( l2_type_can_be_merged( ctx, type ) == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Multiple messages of type %u can be merged in a single record.", (unsigned) type ); + /* Here's the place to add a heuristic deciding when to dispatch + * a record even if space is left in the output buffer. For TLS, + * in principle we can go on with as little as a single byte, but + * at least for DTLS a minimum should be fixed. */ + + if( /* HEURISTIC */ 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Postpone dispatching to potentially merge further messages into this record." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_DATA_LEFT ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space remaining to wait for another message oftype %u - dispatch.", (unsigned) type ); + + /* Fall through if heuristic determines that the current record + * should be dispatched albeit spacing being left: fall through */ + } + else + MBEDTLS_MPS_TRACE_COMMENT( "Multiple messages of type %u cannot be merged in a single record.", (unsigned) type ); + + MBEDTLS_MPS_TRACE_COMMENT( "Force reclaim of current record." ); + ret = mbedtls_writer_reclaim( &ctx->io.out.writer.wr, NULL, NULL, + MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Now it's clear that the record should be dispatched */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( bytes_queued > 0 ) + { + /* The writer has queued data */ + MBEDTLS_MPS_TRACE_COMMENT( "The writer has %u bytes of queued data.", + (unsigned) bytes_queued ); + + /* Double-check that the record content type can indeed be paused. */ + if( l2_type_can_be_paused( ctx, ctx->io.out.writer.type ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Content type not pausable -- queue shouldn't" + " have been passed to the writer in the first place" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING; + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + /* No data has been queued */ + MBEDTLS_MPS_TRACE_COMMENT( "The writer has no queued data." ); + + /* The writer is no longer needed. */ + mbedtls_writer_free( &ctx->io.out.writer.wr ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_UNSET; + } + + /* Update internal length field and change the writer state. */ + ctx->io.out.payload.data_len = bytes_written; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_release_and_dispatch( mbedtls_mps_l2 *ctx, uint8_t force ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_out_release_and_dispatch, force %u", force ); + + MBEDTLS_MPS_ASSERT_RAW( ctx->io.out.state == + MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL, + "Unexpected writer state in l2_out_release_and_dispatch()" ); + + /* Attempt to detach the underlying record buffer from the writer. + * This fails if `force` is unset and there is sufficient space + * left in the buffer for more data to be added to the record. */ + ret = l2_out_release_record( ctx, force ); + if( ret != 0 && ret != MBEDTLS_ERR_WRITER_DATA_LEFT ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( ret == 0 ) + { + /* The write-buffer is detached from the writer, hence + * can be dispatched to Layer 1. */ + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch current outgoing record." ); + ret = l2_out_dispatch_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Current record need not yet be dispatched." ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_read_done( mbedtls_mps_l2 *ctx ) +{ + int ret; + mbedtls_mps_transport_type const mode = mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_l2_in_internal *active; +#if defined(MBEDTLS_MPS_PROTO_TLS) + int paused; + int* const paused_ptr = &paused; +#else + int* const paused_ptr = NULL; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_read_done" ); + + /* This only makes sense if the active reader is currently + * on the user-side, i.e. 'external'. Everything else is + * a violation of the API. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_l2_readers_active_state( ctx ) + == MBEDTLS_MPS_L2_READER_STATE_EXTERNAL, + "mbedtls_read_done() called in unexpected state" ); + /* + * Layer 1 has provided the record the contents of which the + * reader manages, so the order of freeing the resources is: + * First retract the reader's access to the buffer, then + * mark it as complete to Layer 1 (retracting our own access). + * + * Outline: + * Attempt to reclaim the record buffer from the active external reader. + * 1a If unsuccessful because data is left, switch the state of the + * active reader from external to internal, but don't do anything else. + * We will hand out the reader again on the next call to read_start. + * This would e.g. happen if there are multiple handshake messages + * within a single record. + * 1b If unsuccessful because no accumulator is present, + * or the accumulator is too small, return a special error code. + * 2 If successful, check if the active reader has been paused. + * 2.1 If no: Unset the active reader and return success. + * This happens when layer 3 acknowledges the end + * of a message at record boundary. + * 2.2 If yes (TLS only): Swap active and paused reader, and return + * success. In this case, when we read a new record of + * matching content type, we'll feed its contents into + * the paused reader until the reader becomes ready to + * be reactivated, and then it'll be made active agaio.in. + */ + + active = mps_l2_readers_get_active( ctx ); + ret = mbedtls_mps_reader_reclaim( &active->rd, paused_ptr ); + if( ret == MBEDTLS_ERR_MPS_READER_DATA_LEFT ) + { + /* 1a */ + MBEDTLS_MPS_TRACE_COMMENT( "There is data remaining in the current incoming record." ); + + /* Check if the content type is configured to allow packing of + * multiple chunks of data in the same record. */ + if( l2_type_can_be_merged( ctx, active->type ) == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Record content type %u does not allow " + "multiple reads from the same record.", + (unsigned) active->type ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + active->state = MBEDTLS_MPS_L2_READER_STATE_INTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) && + ( ( ret == MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ) || + ( ret == MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL ) ) ) + { + /* 1b */ + + if( l2_type_can_be_paused( ctx, active->type ) == 0 ) + { + /* The application should know which types have been configured + * to be pausable, and not attempt to pause a non-pausable type. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION ); + } + + if( ret == MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ) + { +#if !defined(MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR) + /* In this configuration, we shouldn't have opened the read + * port for a pausable record content type in the first + * place when not also providing an accumulator with it. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); +#else + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ); +#endif /* MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR */ + } + + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* 2 */ + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Detached record buffer from reader - " + "release record from Layer 1." ); + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( paused == 0 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + /* 2.1 */ + MBEDTLS_MPS_TRACE_COMMENT( "No pausing - close active reader." ); + MBEDTLS_MPS_TRACE_RETURN( mps_l2_readers_close_active( ctx ) ); + } + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* 2.2 (TLS only) */ + MBEDTLS_MPS_TRACE_COMMENT( "Pause active reader." ); + MBEDTLS_MPS_TRACE_RETURN( mps_l2_readers_pause_active( ctx ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_handle_invalid_record( mbedtls_mps_l2 *ctx, int ret ) +{ + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + /* This function assumes that the mode has been checked + * to be MBEDTLS_MPS_MODE_DATAGRAM and hence omits this check here. */ + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_handle_invalid_record" ); + if( ret == MBEDTLS_ERR_MPS_INVALID_RECORD ) + MBEDTLS_MPS_TRACE_ERROR( "Invalid record header - discard" ); + else if( ret == MBEDTLS_ERR_MPS_REPLAYED_RECORD ) + MBEDTLS_MPS_TRACE_ERROR( "Replayed Record - discard" ); + else /* ret == MBEDTLS_ERR_MPS_INVALID_MAC */ + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record MAC - discard" ); + ctx->io.in.bad_mac_ctr++; + if( mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) != 0 && + ctx->io.in.bad_mac_ctr >= + mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Bad-MAC-limit %u reached.", + (unsigned) mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_MAC ); + } + } + /* Silently discard datagrams containing invalid records. */ + MBEDTLS_MPS_TRACE_RETURN( mps_l1_skip( l1 ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC +int l2_handle_record_content( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + /* The slot we attempt to use to store payload from the new record. */ + mbedtls_mps_l2_in_internal *slot = NULL; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + MBEDTLS_MPS_TRACE_INIT( "l2_handle_record_content" ); + + /* Find a reader to handle the content. + * This can either be a paused reader matching the record content type + * and epoch, or a currently unused reader. */ + ret = mps_l2_find_suitable_slot( ctx, rec->type, rec->epoch, &slot ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Feed record payload into target slot; might be either + * a fresh or a matching paused slot. + * See 3.1.1 and 3.2 in mps_l2_read_start(). */ + ret = mbedtls_mps_reader_feed( &slot->rd, + rec->buf.buf + rec->buf.data_offset, + rec->buf.data_len ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) && + ret == MBEDTLS_ERR_MPS_READER_NEED_MORE ) + { + /* 3.1.1.2 */ + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* As above, it would be ok to return #MBEDTLS_ERR_MPS_WANT_READ here + * because the present code-path is TLS-only, and in TLS we never + * internally buffer more than one record. As we're done + * with the current record, progress can only be made if + * the underlying transport signals more incoming data + * available, which is precisely what #MBEDTLS_ERR_MPS_WANT_READ + * indicates. + * However, if Layer 1 ever changes to request and buffer more + * data than what we asked for, this would need to be reconsidered, + * so it's safer to return MBEDTLS_ERR_MPS_RETRY. + */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* 3.1.1.1 or 3.2 in mps_l2_read_start(). */ + slot->state = MBEDTLS_MPS_L2_READER_STATE_INTERNAL; + mps_l2_reader_slots_changed( ctx ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_read_start( mbedtls_mps_l2 *ctx, mps_l2_in *in ) +{ + int ret; + mbedtls_mps_l2_reader_state current_state; + mbedtls_mps_l2_in_internal *active; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_read_start" ); + + /* + * Outline: + * 1 If the active reader is set and external (i.e., the user of Layer 2 + * has opened a message via mps_l2_read_start() before and not yet closed + * via mps_l2_read_done()), then fail with a state validation error. + * 2 If instead the active reader is set and internal (i.e., from the user's + * perspective no data is open for reading, but internally we've got a + * record open with unprocessed content remaining), ensure that its epoch + * is still valid and make it external in this case (i.e., pass it to the + * user). + * 3 If the active reader is unset (i.e., no record is buffered at the moment), + * attempt to fetch and decrypt a new record from Layer 1. If it succeeds: + * 3.1 (TLS only) Check if there is a paused reader for the incoming + * content type and epoch, that is, a previous record of the same + * type + epoch whose contents haven't been fully processed yet. + * 3.1.1 If yes, feed the new record content into the paused reader, + * that is, merge the records. + * 3.1.1.1 If enough data is ready, activate reader and return. + * 3.1.1.2 If not, keep the reader paused and return WANT_READ. + * 3.1.2 If not, fall back to the case 3.2 + * 3.2 If the paused reader is unset or we come from 3.1.2, + * setup active reader with new record contents and return it. + * Provide an accumulator if and only if the paused reader is unset + * and the record content type is pausable. If the option + * MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR + * is unset, fail if the content type is pausable but the + * accumulator is not available. + */ + + current_state = mps_l2_readers_active_state( ctx ); + + /* * 1 */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + current_state != MBEDTLS_MPS_L2_READER_STATE_EXTERNAL, + "A record is already open and has been passed to the user." ); + + /* 2 */ + if( current_state == MBEDTLS_MPS_L2_READER_STATE_INTERNAL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A record is already open for reading." ); + } + else + { + /* 3 */ + + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + mps_rec rec; + ret = l2_in_fetch_record( ctx, &rec ); + + /* For DTLS, silently discard datagrams containing records + * which have an invalid header field or can't be authenticated. */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) && + ( ret == MBEDTLS_ERR_MPS_REPLAYED_RECORD || + ret == MBEDTLS_ERR_MPS_INVALID_RECORD || + ret == MBEDTLS_ERR_MPS_INVALID_MAC ) ) + { + ret = l2_handle_invalid_record( ctx, ret ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Signal that the processing should be retried." ); + /* We could return MBEDTLS_ERR_MPS_WANT_READ here, indicating that + * progress can _only_ be made through additional data on the + * underlying transport (which is the case here because we have + * discarded the entire underlying datagram, hence progress can + * only be made once another datagram is available). + * However, this non-locally depends on Layer 1 not buffering + * more than one datagram and is hence slightly fragile. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* TLS-1.3-NOTE + * If the server does not support EarlyData is must silently + * ignore the early ApplicationData records that the client + * sends. + * + * This needs the following adaptations to the code: + * - There should be a dynamically configurable option + * to silently discard unauthenticated records. + * - If this option is set and if l2_in_fetch_record() + * returns INVALID_MAC, we should not forward this error + * here but instead call l2_release_record() and return + * MBEDTLS_ERR_MPS_RETRY. Note, however, that we still + * need to update the record counter. + */ + + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Update record sequence numbers and replay protection. + */ + + ret = l2_in_update_counter( ctx, rec.epoch, rec.ctr[0], rec.ctr[1] ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Feed record content in a suitable slot. */ + ret = l2_handle_record_content( ctx, &rec ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + } + + /* If we end up here, there's data available to be returned to + * the caller: It might be more data from an old incoming record + * that hasn't been fully read yet, or data from a newly fetched + * record. */ + + active = mps_l2_readers_get_active( ctx ); + MBEDTLS_MPS_ASSERT_RAW( active != NULL, + "No active reader after l2_handle_record_content()" ); + + /* Check if the record's epoch is a valid epoch for reading. + * + * NOTE: This check MUST even be performed when progressing from + * state INTERNAL to EXTERNAL, i.e. when continuing the reading + * of an already opened record. + * The reason is that there might be epoch + * changes between two handshake messages in TLS 1.3, and in + * this case the check guards against piggy-backing the next + * handshake message -- which should use the new epoch -- in + * the same record as the previous one. */ + + if( l2_epoch_check( ctx, active->epoch, MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Content piggy-backing in record with old epoch." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + in->type = active->type; + in->epoch = active->epoch; + in->rd = &active->rd; + + active->state = MBEDTLS_MPS_L2_READER_STATE_EXTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_release_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_in_release_record" ); + + ret = mps_l1_consume( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_record" ); + + /* + * Remarks regarding record header parsing + * + * There are three major cases: + * 1) TLS, all versions + * 2) DTLS 1.0 and 1.2 (adds sequence number and epoch id) + * 3) DTLS 1.3 + * This is totally different and much more complicated + * than the other cases. The following has to be distinguished: + * 3.1) Active epoch is 0 + * Then a DTLSPlaintext header in the same format + * as for DTLS <= 1.2 is used. + * 3.2) Active epoch is > 0 + * Then a different format with TWO VARIANTS may be used: + * 3.2.1) DTLSCiphertext + * 3.3.3) DTLSShortCiphertext + * In both cases, the record header doesn't contain + * the epoch id and sequence number in full, but only + * some of their lower bits. + * We don't implement DTLS 1.3 record header parsing at the moment, + * as DTLS 1.3 is not yet very mature, but still it's worth being + * aware of the dependencies here: For DTLS 1.3, the record header + * parsing needs access to a) the current epoch, and b) the full list + * of valid epochs and sequence numbers seen so far. + * While this is certainly more than just the version field, + * it's comforting to note that this information is at least + * fully present on Layer 2, so in principle it should be possible + * to implement DTLS 1.3 record header parsing as part of Layer 2. + * + * In any case, what record header parsing should return in *all* cases + * is a synthetic record header structure containing the following data: + * - Record content type + * - Record length + * - Version + * - DTLS: Epoch + * - DTLS: Record sequence number + * + */ + + /* + * Step 1: Read protected record + */ + if( ( ret = l2_in_fetch_protected_record( ctx, rec ) ) != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Step 2: Decrypt and authenticate record + */ + MBEDTLS_MPS_TRACE_COMMENT( "Decrypt and authenticate record for epoch %u", + (unsigned) rec->epoch ); + if( ( ret = l2_epoch_lookup( ctx, rec->epoch, &epoch ) ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch lookup failed with: %d", (int) ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ret = mbedtls_mps_transform_decrypt( epoch->transform, rec ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Decryption failed with: %d", (int) ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* Validate plaintext length */ + if( rec->buf.data_len > mbedtls_mps_l2_conf_get_max_plain_in( &ctx->conf ) ) + { + /* TODO: Release the record */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* + * Validate record content type + * + * This happens after record decryption since the + * record content type is protected in (D)TLS 1.3. + */ + if( l2_type_is_valid( ctx, rec->type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record type received" ); + /* TODO: Release the record? */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* + * Check if the record is empty, and if yes, + * if empty records are allowed for the given content type. + */ + if( rec->buf.data_len == 0 ) + { + if( l2_type_empty_allowed( ctx, rec->type ) == 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + + /* TODO: Should we return WANT_READ here? Is there a reason + * why empty records would be forwarded to the user? + * Their main practical use is to hide inactivity, and to + * that end it's not necessary to make them visible at the + * Layer 2 boundary. */ + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* The record header structure is the same for all versions + * of TLS, including TLS 1.3. The only difference is that in + * TLS 1.3, the record payload needs to be post-processed to + * remove the plaintext padding. + * Note padding is treated entirely separatedly from encryption + * and authentication, while for the use of CBC in earlier versions, + * it was part of CBC, and AEAD didn't allow padding at all. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_tls( ctx, rec ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MBEDTLS_MPS_ASSERT_RAW( + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_2 || + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_3, + "unexpected version" ); + + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_dtls12( ctx, rec ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +MBEDTLS_MPS_STATIC +mbedtls_mps_size_t l2_get_header_len( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_size_t const dtls12_rec_hdr_len = 13; + mbedtls_mps_size_t const tls12_rec_hdr_len = 5; + MBEDTLS_MPS_TRACE_INIT( "l2_get_header_len, %d", epoch ); + + MBEDTLS_MPS_IF_TLS( mode ) + { + MBEDTLS_MPS_TRACE_RETURN( tls12_rec_hdr_len ); + } + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* OPTIMIZATION: + * As long as we're only supporting DTLS 1.0 and 1.2 + * which share the same record header, remove this + * switch to save a few bytes? */ + + MBEDTLS_MPS_ASSERT_RAW( + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_2 || + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_3, + "Unexpected version" ); + + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + MBEDTLS_MPS_TRACE_RETURN( dtls12_rec_hdr_len ); + } +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* This function converts an internal TLS version identifier to + * the version byte used within the record header on the wire. */ +MBEDTLS_MPS_ALWAYS_INLINE +int l2_version_wire_matches_logical( uint8_t wire_version, + int logical_version ) +{ + switch( logical_version ) + { + case MBEDTLS_MPS_L2_VERSION_UNSPECIFIED: + return( 1 ); + case MBEDTLS_SSL_MINOR_VERSION_0: + return( wire_version == 0 ); + case MBEDTLS_SSL_MINOR_VERSION_1: + return( wire_version == 1 ); + case MBEDTLS_SSL_MINOR_VERSION_2: + return( wire_version == 2 ); + case MBEDTLS_SSL_MINOR_VERSION_3: + return( wire_version == 3 ); + /* TLS 1.3 and TLS 1.2 use the same wire-version. */ + case MBEDTLS_SSL_MINOR_VERSION_4: + return( wire_version == 3 ); + + default: + return( 0 ); + } +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record_tls( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + /* Buffer to hold the record header; will be obtained from Layer 1 */ + unsigned char *buf; + /* Header structure is the same for all TLS versions. + * From RFC 5246 - Section 6.2 + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; */ + const mbedtls_mps_size_t tls_rec_hdr_len = 5; + const mbedtls_mps_size_t tls_rec_type_offset = 0; + const mbedtls_mps_size_t tls_rec_ver_offset = 1; + const mbedtls_mps_size_t tls_rec_len_offset = 3; + + /* Record fields */ + uint8_t minor_ver, major_ver; + mbedtls_mps_msg_type_t type; + uint16_t len; + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_tls" ); + + /* + * Fetch TLS record header from Layer 1 + */ + ret = mps_l1_fetch( l1, &buf, tls_rec_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Read header fields + */ + + /* Record content type + * + * We validate the record content type only after deprotection + * since it's protected in TLS 1.3. + * + * TODO: Strictly speaking we need to check that the content type + * is ApplicationData in the case of TLS 1.3. + */ + MPS_READ_UINT8_BE( buf + tls_rec_type_offset, &type ); + l2_read_version_tls( &major_ver, &minor_ver, buf + tls_rec_ver_offset ); + if( major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid major record version %u received, expected %u", + (unsigned) major_ver, (unsigned) MBEDTLS_SSL_MAJOR_VERSION_3 ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* Initially, the server doesn't know which TLS version the client will use + * for its ClientHello message, so Layer 2 must be configurable to allow + * arbitrary TLS versions. This is done through the initial version value + * MBEDTLS_MPS_L2_VERSION_UNSPECIFIED. + * + * Also, for TLS 1.3, the wire-version is still TLS 1.2. + * + * We capture both special cases in a helper function checking whether the + * wire-version matches the configured logical version. */ + if( l2_version_wire_matches_logical( minor_ver, + mbedtls_mps_l2_conf_get_version( &ctx->conf ) ) != 1 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid minor record version %u received, expected %u", + (unsigned) minor_ver, mbedtls_mps_l2_conf_get_version( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* Length */ + MPS_READ_UINT16_BE( buf + tls_rec_len_offset, &len ); + /* TODO: Add length check, at least the architectural bound of 16384 + 2K, + * but preferably a transform-dependent bound that'll catch records + * with overly long plaintext by considering the maximum expansion + * plaintext-to-ciphertext. */ + + /* + * Read record contents from Layer 1 + */ + ret = mps_l1_fetch( l1, &buf, tls_rec_hdr_len + len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Check if record should be ignored */ + if( l2_type_ignore( ctx, type ) == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Silently ignore record of type %u", (unsigned) type ); + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + + /* + * Write target record structure + */ + + /* For TLS-1.3, we must not increment the in_ctr here because (in contrast + * to prior versions of TLS), records may be silently dismissed on + * authentication failure, and in this case the record sequence number + * should stay unmodified. + * + * Instead, postpone updating the incoming record sequence number to the + * point where the record has been successfully authenticated. */ + ret = l2_tls_in_get_epoch_and_counter( ctx, &rec->epoch, rec->ctr ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Record epoch: %u", (unsigned) rec->epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Record number: ( %u << 32 ) + %u ", + (unsigned) rec->ctr[0], (unsigned) rec->ctr[1] ); + + rec->type = type; + rec->major_ver = major_ver; + rec->minor_ver = minor_ver; + + rec->buf.buf = buf + tls_rec_hdr_len; + rec->buf.buf_len = len; + rec->buf.data_offset = 0; + rec->buf.data_len = len; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC +int l2_in_update_counter( mbedtls_mps_l2 *ctx, + uint16_t epoch_id, + uint32_t ctr_hi, + uint32_t ctr_lo ) +{ + int ret; + mbedtls_mps_transport_type const mode = mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_l2_epoch_t *epoch; + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_IF_TLS( mode ) + { + ret = l2_increment_counter( epoch->stats.tls.in_ctr ); + if( ret != 0 ) + return( ret ); + } +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + uint32_t window_top_hi, window_top_lo; + uint32_t window; + uint32_t flag = 1u; + + epoch->stats.dtls.last_seen[0] = ctr_hi; + epoch->stats.dtls.last_seen[1] = ctr_lo; + + if( mbedtls_mps_l2_conf_get_anti_replay( &ctx->conf ) + == MBEDTLS_MPS_ANTI_REPLAY_DISABLED ) + { + return( 0 ); + } + + window_top_hi = epoch->stats.dtls.replay.in_window_top_hi; + window_top_lo = epoch->stats.dtls.replay.in_window_top_lo; + window = epoch->stats.dtls.replay.in_window; + + if( ctr_hi > window_top_hi ) + { + window_top_hi = ctr_hi; + window_top_lo = ctr_lo; + } + else if( ctr_lo > window_top_lo ) + { + /* Update window_top and the contents of the window */ + uint32_t shift = ctr_lo - window_top_lo; + if( shift >= 32 ) + shift = 0; + window <<= shift; + window_top_lo = ctr_lo; + } + else + { + /* Mark that number as seen in the current window */ + uint32_t bit = window_top_lo - ctr_lo; + flag <<= bit; + } + window |= flag; + + epoch->stats.dtls.replay.in_window_top_lo = window_top_lo; + epoch->stats.dtls.replay.in_window_top_hi = window_top_hi; + epoch->stats.dtls.replay.in_window = window; + } +#else /* MBEDTLS_MPS_PROTO_DTLS */ + ((void) ctr_lo); + ((void) ctr_hi); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + return( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_tls_in_get_epoch_and_counter( mbedtls_mps_l2 *ctx, + uint16_t *dst_epoch, + uint32_t dst_ctr[2] ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + mbedtls_mps_epoch_id default_in; + MBEDTLS_MPS_TRACE_INIT( "l2_tls_in_get_epoch_and_counter" ); + + default_in = ctx->epochs.default_in; + ret = l2_epoch_lookup( ctx, default_in, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + dst_ctr[0] = epoch->stats.tls.in_ctr[0]; + dst_ctr[1] = epoch->stats.tls.in_ctr[1]; + *dst_epoch = default_in; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC +int l2_out_get_and_update_rec_seq( mbedtls_mps_l2 *ctx, + mbedtls_mps_l2_epoch_t *epoch, + uint32_t *dst_ctr ) +{ + uint32_t *src_ctr; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + src_ctr = epoch->stats.tls.out_ctr; +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + src_ctr = epoch->stats.dtls.out_ctr; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + dst_ctr[0] = src_ctr[0]; + dst_ctr[1] = src_ctr[1]; + return( l2_increment_counter( src_ctr ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + /* Buffer to hold the DTLS record header; will be obtained from Layer 1 */ + unsigned char *buf; + + /* Header structure the same for DTLS 1.0 and DTLS 1.2. + * From RFC 6347 - Section 4.1 + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 epoch; + * uint48 sequence_number; + * uint16 length; + * opaque fragment[DTLSPlaintext.length]; + * } DTLSPlaintext; */ + + mbedtls_mps_size_t const dtls_rec_hdr_len = 13; + mbedtls_mps_size_t const dtls_rec_type_offset = 0; + mbedtls_mps_size_t const dtls_rec_ver_offset = 1; + mbedtls_mps_size_t const dtls_rec_epoch_offset = 3; + mbedtls_mps_size_t const dtls_rec_seq_offset = 5; + mbedtls_mps_size_t const dtls_rec_len_offset = 11; + + /* Temporaries for record fields. */ + uint8_t type, minor_ver, major_ver; + uint16_t epoch, len; + uint32_t seq_nr[2]; + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_dtls12" ); + + /* + * Fetch DTLS record header from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_rec_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Read and validate header fields + * + * We store individual header fields as soon as they have + * been validated, even if the validation of the rest of + * the header might still fail. This behavior is deliberate + * and documented, and reduces code size by keeping the + * usage scope of variables small. + * + * On the other hand, avoiding the temporaries by working + * directly on the target structure is considered bad style + * because, in theory, a different thread might tamper with + * the target structure during or after validation. + */ + + /* Record content type */ + MPS_READ_UINT8_BE( buf + dtls_rec_type_offset, &type ); + if( l2_type_is_valid( ctx, type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record type received" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + rec->type = type; + + /* Version */ + l2_read_version_dtls( &major_ver, &minor_ver, + buf + dtls_rec_ver_offset ); + if( major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid major record version %u received, expected %u", + (unsigned) major_ver, (unsigned) MBEDTLS_SSL_MAJOR_VERSION_3 ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + if( mbedtls_mps_l2_conf_get_version( &ctx->conf ) != + MBEDTLS_MPS_L2_VERSION_UNSPECIFIED && + mbedtls_mps_l2_conf_get_version( &ctx->conf ) != + minor_ver ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid minor record version %u received, expected %u", + (unsigned) minor_ver, + (unsigned) mbedtls_mps_l2_conf_get_version( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + rec->major_ver = major_ver; + rec->minor_ver = minor_ver; + + /* Epoch */ + MPS_READ_UINT16_BE( buf + dtls_rec_epoch_offset, &epoch ); + ret = l2_epoch_check( ctx, epoch, MPS_EPOCH_READ_MASK ); + if( ret == MBEDTLS_ERR_MPS_INVALID_EPOCH ) + ret = MBEDTLS_ERR_MPS_INVALID_RECORD; + if ( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + rec->epoch = epoch; + + /* Record sequence number */ + MPS_READ_UINT16_BE( buf + dtls_rec_seq_offset, &seq_nr[0] ); + MPS_READ_UINT32_BE( buf + dtls_rec_seq_offset + 2, &seq_nr[1] ); + + if( l2_counter_replay_check( ctx, epoch, seq_nr[0], seq_nr[1] ) != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Replayed record -- ignore" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REPLAYED_RECORD ); + } + rec->ctr[0] = seq_nr[0]; + rec->ctr[1] = seq_nr[1]; + + /* Length */ + MPS_READ_UINT16_BE( buf + dtls_rec_len_offset, &len ); + /* TODO: Add length check, at least the architectural bound of 16384 + 2K, + * but preferably a transform-dependent bound that'll catch records + * with overly long plaintext by considering the maximum expansion + * plaintext-to-ciphertext. */ + + /* + * Read record contents from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_rec_hdr_len + len ); + if( ret == MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ) + { + MBEDTLS_MPS_TRACE_ERROR( "Claimed record length exceeds datagram bounds." ); + ret = MBEDTLS_ERR_MPS_INVALID_RECORD; + } + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + rec->buf.buf = buf + dtls_rec_hdr_len; + rec->buf.buf_len = len; + rec->buf.data_offset = 0; + rec->buf.data_len = len; + + MBEDTLS_MPS_TRACE_COMMENT( "* Record epoch: %u", (unsigned) rec->epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Record number: ( %u << 32 ) + %u", + (unsigned) rec->ctr[0], (unsigned) rec->ctr[1] ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int l2_in_fetch_protected_record_dtls13( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + /* Buffer to hold the DTLS record header; will be obtained from Layer 1 */ + unsigned char *buf; + + /* We need to distinguish DTLSPlaintext records (which are the same + * in DTLS 1.2 and DTLS 1.3) from DTLSCiphertext records specific to + * DTLS 1.3. + * + * Citing the draft 34 of the DTLS 1.3 standard: + * + * ``` + * 4.1. Determining the Header Format + * + * Implementations can distinguish the two header formats by examining + * the first byte: + * - If the first byte is alert(21), handshake(22), or ack(proposed, + * 25), the record MUST be interpreted as a DTLSPlaintext record. + * - If the first byte is any other value, then receivers MUST check to + * see if the leading bits of the first byte are 001. If so, the + * implementation MUST process the record as DTLSCiphertext; the true + * content type will be inside the protected portion. + * - Otherwise, the record MUST be rejected as if it had failed + * deprotection, as described in Section 4.5.2. + * ``` + * + * We implement this in the following way: If the three leading bits of + * the first byte are 001, we continue to parse the DTLS 1.3 specific + * record header. Otherwise, we fall back to parsing the DTLS 1.2 record + * header, via l2_in_fetch_protected_record_dtls12() (this function is + * therefore needed even in DTLS 1.3 only builds). + */ + + /* DTLSCiphertext record header structure: + * + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |0|0|1|C|S|L|E E| + * +-+-+-+-+-+-+-+-+ + * | Connection ID | Legend: + * | (if any, | + * / length as / C - Connection ID (CID) present + * | negotiated) | S - Sequence number length + * +-+-+-+-+-+-+-+-+ L - Length present + * | 8 or 16 bit | E - Epoch + * |Sequence Number| + * +-+-+-+-+-+-+-+-+ + * | 16 bit Length | + * | (if present) | + * +-+-+-+-+-+-+-+-+ + */ + + mbedtls_mps_size_t const dtls_13_stable_hdr_len = 1; + + uint8_t const dtls_13_stable_hdr_magic_mask = + 7u << 5; /* 0b11100000 */ + uint8_t const dtls_13_stable_hdr_cid_mask = + 1u << 4; /* 0b00010000 */ + uint8_t const dtls_13_stable_hdr_seq_nr_mask = + 1u << 3; /* 0b00001000 */ + uint8_t const dtls_13_stable_hdr_length_mask = + 1u << 2; /* 0b00000100 */ + uint8_t const dtls_13_stable_hdr_epoch_mask = + 3u << 0; /* 0x00000011 */ + uint8_t const dtls_13_stable_hdr_magic_bits = + 1u << 5; /* 0b00100000 */ + + mbedtls_mps_size_t hdr_len = 1; + uint8_t stable_hdr_val; + + ((void) dtls_13_stable_hdr_epoch_mask); /* TODO: Implement epoch parsing. */ + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_dtls12" ); + + /* + * Fetch DTLS record header from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_13_stable_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + stable_hdr_val = *buf; + if( ( stable_hdr_val & dtls_13_stable_hdr_magic_mask ) != + dtls_13_stable_hdr_magic_bits ) + { + /* Assume a DTLS 1.2 record header. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_dtls13( ctx, rec ) ); + } + + /* Determine total length of DTLS 1.3 header. */ + + /* Account for CID. */ + if( ( stable_hdr_val & dtls_13_stable_hdr_cid_mask ) != 0 ) + { +#define MPS_FIXED_CID_LEN 4 /* TODO: Make configurable */ + hdr_len += MPS_FIXED_CID_LEN; + } + + /* Account for Sequence Number, 1 or 2 Byte long. */ + hdr_len += 1; + if( ( stable_hdr_val & dtls_13_stable_hdr_seq_nr_mask ) != 0 ) + { + hdr_len++; + } + + /* Account for length */ + if( ( stable_hdr_val & dtls_13_stable_hdr_length_mask ) != 0 ) + { + hdr_len += 2; + } + + /* TODO: Finish */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* Record content type validation */ +MBEDTLS_MPS_STATIC +int l2_type_is_valid( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_type_flag( &ctx->conf ); + /* type <= MBEDTLS_MPS_MSG_MAX == 31 is automatic if flag & mask != 0. */ + return( ( flag & mask ) != 0 ); +} + +/* Check if a valid record content type can be paused. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_type_can_be_paused( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + /* Regardless of the configuration, pausing is only + * allowed for stream transports. */ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_pause_flag( &ctx->conf ); + + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + return( MBEDTLS_MPS_IS_TLS( mode ) && + ( flag & mask ) != 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* Check if a valid record content type allows merging of data. + * This assumes that the provided type is at least valid, + * and in particular smaller than 32. */ +MBEDTLS_MPS_STATIC +int l2_type_can_be_merged( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_merge_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +/* Check if a valid record content type allows empty records. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ +MBEDTLS_MPS_STATIC +int l2_type_empty_allowed( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_empty_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +/* Check if records of a valid record content type should be + * silently ignored. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ +MBEDTLS_MPS_STATIC +int l2_type_ignore( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_ignore_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +MBEDTLS_MPS_STATIC +void l2_epoch_free( mbedtls_mps_l2_epoch_t *epoch ) +{ + if( epoch->transform != NULL ) + { + mbedtls_mps_transform_free( epoch->transform ); + free( epoch->transform ); + } + + memset( epoch, 0, sizeof( mbedtls_mps_l2_epoch_t ) ); +} + +MBEDTLS_MPS_STATIC +void l2_epoch_init( mbedtls_mps_l2_epoch_t *epoch ) +{ + memset( epoch, 0, sizeof( mbedtls_mps_l2_epoch_t ) ); +} + +int mps_l2_epoch_add( mbedtls_mps_l2 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch_id ) +{ + uint8_t next_offset; + mbedtls_mps_l2_epoch_t *epoch; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_epoch_add" ); + + next_offset = ctx->epochs.next; + + if( ctx->epochs.next > MBEDTLS_MPS_EPOCH_MAX ) + { + MBEDTLS_MPS_TRACE_ERROR( "Maximum number %u of epochs reached.", + (unsigned) MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS ); + } + + if( next_offset == MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ) + { + MBEDTLS_MPS_TRACE_ERROR( "The epoch window (size %u) is full.", + (unsigned) MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS ); + } + *epoch_id = ctx->epochs.base + next_offset; + + epoch = &ctx->epochs.window[next_offset]; + l2_epoch_init( epoch ); + epoch->transform = transform; + epoch->usage = MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED; + + ctx->epochs.next++; + + MBEDTLS_MPS_TRACE_COMMENT( "New epoch: %u", (unsigned) *epoch_id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_epoch_usage( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_epoch_usage" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %d", epoch_id ); + MBEDTLS_MPS_TRACE_COMMENT( "* Clear: %u", (unsigned) clear ); + MBEDTLS_MPS_TRACE_COMMENT( "* Set: %u", (unsigned) set ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected state in mps_l2_epoch_usage()" ); + + MBEDTLS_MPS_ASSERT_RAW( ( ( clear & set ) == 0 ) && + ( ( clear | set ) & ~MPS_EPOCH_USAGE_ALL ) == 0, + "Invalid flags in mps_l2_epoch_usage" ); + + clear |= MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED; + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + + /* Silently ignore requests to remove flags for invalid epochs. */ + if( ret == MBEDTLS_ERR_MPS_INVALID_EPOCH && set == 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Old: %04x", (unsigned) epoch->usage ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* In TLS, there's at most one epoch holding read permissions; + * similarly, there's at most one epoch holding write permissions. */ + MBEDTLS_MPS_IF_TLS( mode ) + { + uint8_t offset; + for( offset = 0; offset < ctx->epochs.next; offset++ ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Modify epoch %u usage from %#x to %#x", + (unsigned) offset + ctx->epochs.base, + (unsigned) ctx->epochs.window[offset].usage, + (unsigned) ctx->epochs.window[offset].usage & ~set ); + ctx->epochs.window[offset].usage &= ~set; + } + + if( ( clear & MPS_EPOCH_READ_MASK ) != 0 && + ctx->epochs.default_in == epoch_id ) + { + ctx->epochs.default_in = MBEDTLS_MPS_EPOCH_NONE; + } + if( ( clear & MPS_EPOCH_WRITE_MASK ) != 0 && + ctx->epochs.default_out == epoch_id ) + { + ctx->epochs.default_out = MBEDTLS_MPS_EPOCH_NONE; + } + + if( ( set & MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u the new incoming epoch", + (unsigned) epoch_id ); + ctx->epochs.default_in = epoch_id; + } + if( ( set & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u the new outgoing epoch", + (unsigned) epoch_id ); + ctx->epochs.default_out = epoch_id; + } + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + epoch->usage |= set; + epoch->usage &= ~clear; + MBEDTLS_MPS_TRACE_COMMENT( "* New: %04x", (unsigned) epoch->usage ); + + MBEDTLS_MPS_TRACE_RETURN( l2_epoch_cleanup( ctx ) ); +} + +/* + * This function checks whether an epoch is valid + * and available for reading or writing. + */ +MBEDTLS_MPS_STATIC +int l2_epoch_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint8_t purpose ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_check for epoch %d, purpose %s", + epoch_id, + l2_epoch_usage_to_string( purpose ) ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( ( purpose & epoch->usage ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u has usage %s, but flag from %s is required.", + (unsigned) epoch_id, + l2_epoch_usage_to_string( epoch->usage ), + l2_epoch_usage_to_string( purpose ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * This functions detects and frees epochs that are no longer needed. + */ +#if !defined(MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING) + +MBEDTLS_MPS_STATIC +int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ) +{ + ((void) ctx); + return( 0 ); +} + +#else /* MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING */ + +MBEDTLS_MPS_STATIC +void l2_print_usage( unsigned usage ) +{ +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + if( ( usage & MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch can be used for reading." ); + } + if( ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch can be used for writing." ); + } + if( ( usage & MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Epoch has been added but not yet configured." ); + } + if( ( usage & MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch has an outgoing record open." ); + } +#else + ((void) usage); +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ +} + +MBEDTLS_MPS_STATIC +int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ) +{ + uint8_t shift = 0, offset; + mbedtls_mps_epoch_id max_shift; + + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_cleanup" ); + + /* An epoch is in use if its flags are not empty. */ + for( offset = 0; offset < ctx->epochs.next; offset++ ) + { + unsigned usage = ctx->epochs.window[offset].usage; + + MBEDTLS_MPS_TRACE_COMMENT( "Checking epoch %u at window offset %u, usage %s", + (unsigned)( ctx->epochs.base + offset ), (unsigned) offset, + l2_epoch_usage_to_string( usage ) ); + + if( usage == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "* no longer needed" ); + l2_epoch_free( &ctx->epochs.window[offset] ); + } + else + { + l2_print_usage( usage ); + break; + } + } + + shift = offset; + + if( shift == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Cannot get rid of any epoch." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + max_shift = MBEDTLS_MPS_EPOCH_MAX - + ( ctx->epochs.base + MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + if( shift >= max_shift ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Cannot shift epoch window further." ); + shift = max_shift; + } + + MBEDTLS_MPS_TRACE_COMMENT( "Can get rid of the first %u epochs; clearing.", + (unsigned) shift ); + + ctx->epochs.base += shift; + ctx->epochs.next -= shift; + + MBEDTLS_MPS_TRACE_COMMENT( "* New base: %u", (unsigned) ctx->epochs.base ); + MBEDTLS_MPS_TRACE_COMMENT( "* New next: %u", (unsigned) ctx->epochs.next ); + + /* Shift epochs. */ + for( offset = 0; offset < MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE; offset++ ) + { + if( MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE - offset > shift ) + ctx->epochs.window[offset] = ctx->epochs.window[offset + shift]; + else + l2_epoch_init( &ctx->epochs.window[offset] ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Epoch cleanup done" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING */ + +MBEDTLS_MPS_STATIC +int l2_epoch_lookup( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_l2_epoch_t **epoch ) +{ + uint8_t epoch_offset; + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_lookup" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %d", epoch_id ); + + if( epoch_id == MBEDTLS_MPS_EPOCH_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The epoch is unset." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + else if( epoch_id < ctx->epochs.base ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The epoch %u is below the epoch base %u.", + (unsigned) epoch_id, (unsigned) ctx->epochs.base ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + + epoch_offset = epoch_id - ctx->epochs.base; + MBEDTLS_MPS_TRACE_COMMENT( "* Offset: %u", (unsigned) epoch_offset ); + + if( epoch_offset >= ctx->epochs.next ) + { + MBEDTLS_MPS_TRACE_ERROR( "The epoch is outside the epoch window." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + + if( epoch != NULL ) + *epoch = &ctx->epochs.window[ epoch_offset ]; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * DTLS replay protection + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_counter_replay_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint32_t ctr_hi, + uint32_t ctr_lo ) +{ + int ret; + uint32_t bit; + mbedtls_mps_l2_epoch_t *epoch; + uint32_t window_top_hi, window_top_lo; + uint32_t window; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l2_counter_replay_check, epoch %u", + (unsigned) epoch_id ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + if( mbedtls_mps_l2_conf_get_anti_replay( &ctx->conf ) + == MBEDTLS_MPS_ANTI_REPLAY_DISABLED ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + window_top_hi = epoch->stats.dtls.replay.in_window_top_hi; + window_top_lo = epoch->stats.dtls.replay.in_window_top_lo; + MBEDTLS_MPS_TRACE_COMMENT( "* Window top hi: %u", window_top_hi ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window top lo: %u", window_top_lo ); + MBEDTLS_MPS_TRACE_COMMENT( "* Counter top hi: %u", ctr_hi ); + MBEDTLS_MPS_TRACE_COMMENT( "* Counter top lo: %u", ctr_lo ); + + if( ctr_hi > window_top_hi ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number larger than everything seen so far." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else if( ctr_hi < window_top_hi ) + { + /* Don't maintain window across 32-bit boundaries. */ + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number too old -- drop" ); + MBEDTLS_MPS_TRACE_RETURN( -1 ); + } + else if( ctr_lo > window_top_lo ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + bit = window_top_lo - ctr_lo; + if( bit >= 32 ) + MBEDTLS_MPS_TRACE_RETURN( -1 ); + + /* Bit-reverse the window, so that bits corresponding to fresh + * sequence numbers are set. */ + window = ~epoch->stats.dtls.replay.in_window; + + window >>= bit; + if( ( window & 0x1 ) == 0 ) + MBEDTLS_MPS_TRACE_RETURN( -1 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number within window and not seen so far." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l2_force_next_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_force_next_sequence_number, epoch %u, ctr %u", + (unsigned) epoch_id, (unsigned) ctr ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + MBEDTLS_MPS_IS_DTLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ), + "Sequence number forcing only needed and allowed in DTLS." ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + epoch->stats.dtls.out_ctr[0] = (uint32_t)( ctr >> 32 ); + epoch->stats.dtls.out_ctr[1] = (uint32_t) ctr; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_get_last_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_get_last_sequence_number, epoch %u", + (unsigned) epoch_id ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + MBEDTLS_MPS_IS_DTLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ), + "Sequence number retrieval only needed and allowed in DTLS." ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + *ctr = ((uint64_t) epoch->stats.dtls.last_seen[0]) << 32; + *ctr |= (uint64_t) epoch->stats.dtls.last_seen[1]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer2_internal.h b/library/mps/layer2_internal.h new file mode 100644 index 000000000000..c345faf981ae --- /dev/null +++ b/library/mps/layer2_internal.h @@ -0,0 +1,344 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H +#define MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H + +/* + * Read/Write of (D)TLS versions + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC void l2_read_version_tls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC void l2_read_version_dtls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +MBEDTLS_MPS_STATIC void l2_out_write_version( int major, int minor, + mbedtls_mps_transport_type transport, + unsigned char ver[2] ); + +/* + * Management for readers / input queues + */ + +/* Initialize readers / input queues. */ +MBEDTLS_MPS_STATIC void mps_l2_readers_init( mbedtls_mps_l2 *ctx ); +/* Free readers / input queues. */ +MBEDTLS_MPS_STATIC void mps_l2_readers_free( mbedtls_mps_l2 *ctx ); +/* Get the active reader / input queue, or NULL if there isn't any. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_active( mbedtls_mps_l2 *ctx ); +/* Close the active reader / input queue. */ +MBEDTLS_MPS_STATIC int mps_l2_readers_close_active( mbedtls_mps_l2 *ctx ); +/* Pause the active reader / input queue; this happens if we need more + * than what's currently available, and we need to accumulate more data + * from the respective input stream. */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int mps_l2_readers_pause_active( mbedtls_mps_l2 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +/* Check if data is available in one of the readers / input queues. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_reader_state mps_l2_readers_active_state( mbedtls_mps_l2 *ctx ); +/* Get an unused reader / input queue to manage new incoming data. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_unused( mbedtls_mps_l2 *ctx ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* The implementation currently maintains a single accumulator for all + * readers / input queues. Check whether its currently in use. */ +MBEDTLS_MPS_STATIC +int mps_l2_readers_accumulator_taken( mbedtls_mps_l2 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +/* TODO: Document */ +MBEDTLS_MPS_INLINE +void mps_l2_reader_slots_changed( mbedtls_mps_l2 *ctx ); +/* Match a pair of type and epoch for new incoming data against the set + * of currently opened readers / input streams. If there's a matching one, + * return it. If there's one matching the type but with different epoch, + * fail. */ +MBEDTLS_MPS_INLINE +int mps_l2_find_suitable_slot( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch, + mbedtls_mps_l2_in_internal **dst ); + +/* + * + * Incoming data + * + */ + +/* + * TLS record input queue API + */ + +/* Request a plaintext buffer from the (D)TLS input queue. + * + * The metadata attached to the buffer is: + * - The epoch used to protect the buffer. + * - The TLS record content type of the buffer + * - The record sequence number + * + * The record structure is borrowed to the caller and valid + * until l2_in_release_record() is called. + */ +MBEDTLS_MPS_STATIC int l2_in_fetch_record( mbedtls_mps_l2 *ctx, mps_rec *rec ); + +/* Consume the last buffer received from the TLS input queue. + * + * This function marks the plaintext buffer last received from the + * TLS input queue via l2_in_fetch_record() as processed. The corresponding + * record structure must not be used anymore afterwards. + */ +MBEDTLS_MPS_STATIC int l2_in_release_record( mbedtls_mps_l2 *ctx ); + +/* + * Internal functions of the (D)TLS input queue. + */ + +/* Various record parsing functions + * + * These functions fetch and validate record headers for various TLS/DTLS + * versions from Layer 1 and feed them into the provided record structure. + * + * Checks these functions perform: + * - The epoch is not a valid epoch for incoming records. + * - The record content type is not valid. + * - The length field in the record header exceeds the + * configured maximum record size. + * - The datagram didn't contain as much data after + * the record header as indicated in the record + * header length field. + * - There wasn't enough space remaining in the datagram + * to load a DTLS 1.2 record header. + * - The record sequence number has been seen before, + * so the record is likely duplicated / replayed. + */ + +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record_tls( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ); + +/* TODO */ +MBEDTLS_MPS_STATIC int UNUSED l2_in_fetch_protected_record_dtls13( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +MBEDTLS_MPS_STATIC int l2_handle_invalid_record( mbedtls_mps_l2 *ctx, int ret ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l2_handle_record_content( mbedtls_mps_l2 *ctx, mps_rec *rec ); + +/* + * + * Outgoing data + * + */ + +/* + * TLS record output queue API + */ + +/* Prepare a new plaintext buffer for outgoing data. + * + * The buffer established by this function is mps_l2::io::out::payload, + * which includes the total length of the buffer as well as a field through + * which the caller can signal how much data has actually been written. + * + * The plaintext buffer is borrowed to the caller and valid until + * l2_out_dispatch_record() is called. + */ +MBEDTLS_MPS_STATIC int l2_out_prepare_record( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ); + +/* Dispatch plaintext buffer of outgoing data + * + * After a plaintext buffer has been received from l2_out_prepare_record() + * and filled with outgoing data by the caller, this function transfers it + * to the underlying transport for encryption and dispatch. + */ +MBEDTLS_MPS_STATIC int l2_out_dispatch_record( mbedtls_mps_l2 *ctx ); + +/* + * TLS record output queue internal API + */ + +/* Various record header writing functions */ +MBEDTLS_MPS_STATIC int l2_out_write_protected_record( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_out_write_protected_record_tls( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l2_out_write_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l2_out_release_and_dispatch( mbedtls_mps_l2 *ctx, + uint8_t force ); +MBEDTLS_MPS_STATIC int l2_out_clear_pending( mbedtls_mps_l2 *ctx ); + +MBEDTLS_MPS_STATIC mbedtls_mps_size_t l2_get_header_len( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ); + +/* + * Binding output plaintext buffers to writers + */ + +MBEDTLS_MPS_STATIC int l2_out_track_record( mbedtls_mps_l2 *ctx ); +MBEDTLS_MPS_STATIC int l2_out_release_record( mbedtls_mps_l2 *ctx, + uint8_t force ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_ALWAYS_INLINE +int l2_version_wire_matches_logical( uint8_t wire_version, + int logical_version ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* Configuration related */ +/* OPTIMIZATION: The flexibility of Layer 2 in terms of valid types, + * pausing, merging, and the acceptance of empty records + * is nice for testing, but on a low-profile production build + * targeted at a specific version of [D]TLS, code can be saved + * by implementing the l2_type_can_be_yyy() functions in a + * static way (comparing against a mask / list of types fixed + * at compile-time). */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_type_can_be_paused( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +MBEDTLS_MPS_STATIC int l2_type_can_be_merged( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_is_valid( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_empty_allowed( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_ignore( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); + +/* + * Epoch handling + */ + +/* Print human-readable description of epoch usage flags. */ +MBEDTLS_MPS_STATIC void l2_print_usage( unsigned usage ); + +static inline const char * l2_epoch_usage_to_string( + mbedtls_mps_epoch_usage usage ) +{ + if( ( usage & MPS_EPOCH_READ_MASK ) != 0 && + ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + return( "READ | WRITE" ); + } + else if( ( usage & MPS_EPOCH_READ_MASK ) != 0 ) + return( "READ" ); + else if( ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + return( "WRITE" ); + + return( "NONE" ); +} + +/* Internal macro used to indicate internal usage of an epoch, + * e.g. because data it still pending to be dispatched. + * + * The `reason` parameter may range from 0 to 3. + */ +#define MPS_EPOCH_USAGE_INTERNAL( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( 4 + ( reason ) ) ) ) + +#define MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN \ + MPS_EPOCH_USAGE_INTERNAL( 0 ) +#define MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED \ + MPS_EPOCH_USAGE_INTERNAL( 1 ) + +MBEDTLS_MPS_STATIC void l2_epoch_free( mbedtls_mps_l2_epoch_t *epoch ); +MBEDTLS_MPS_STATIC void l2_epoch_init( mbedtls_mps_l2_epoch_t *epoch ); + +/* Check if an epoch can be used for a given purpose. */ +MBEDTLS_MPS_STATIC int l2_epoch_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch, + uint8_t purpose ); + +/* Lookup the transform associated to an epoch. + * + * The epoch ID is fully untrusted (this function is called + * as part of replay protection for not yet authenticated + * records). + */ +MBEDTLS_MPS_STATIC int l2_epoch_lookup( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_l2_epoch_t **epoch ); + +/* Check if some epochs are no longer needed and can be removed. */ +MBEDTLS_MPS_STATIC int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ); + +/* + * Sequence number handling + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_tls_in_get_epoch_and_counter( mbedtls_mps_l2 *ctx, + uint16_t *dst_epoch, + uint32_t dst_ctr[2] ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC int l2_in_update_counter( mbedtls_mps_l2 *ctx, + uint16_t epoch, + uint32_t ctr_hi, + uint32_t ctr_lo ); + +MBEDTLS_MPS_STATIC int l2_out_get_and_update_rec_seq( mbedtls_mps_l2 *ctx, + mbedtls_mps_l2_epoch_t *epoch, + uint32_t *dst_ctr ); + +MBEDTLS_MPS_STATIC int l2_increment_counter( uint32_t ctr[2] ); + +/* + * DTLS replay protection + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/* This function checks whether the record sequence number represented + * by `ctr_lo` and `ctr_hi` is 'fresh' in the following sense: + * - It hasn't been seen before. + * - It's not too old. + * + * - Returns `0` if the sequence number is fresh. + * - Returns `-1` otherwise. + * + * This function does not update the replay protection window. + */ +MBEDTLS_MPS_STATIC int l2_counter_replay_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch, + uint32_t ctr_hi, + uint32_t ctr_lo ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H */ diff --git a/library/mps/layer3.c b/library/mps/layer3.c new file mode 100644 index 000000000000..268f90b383dc --- /dev/null +++ b/library/mps/layer3.c @@ -0,0 +1,1161 @@ +/* + * Message Processing Stack, Layer 3 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer3.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer3_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_3; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +/* + * Some debug helpers, captured as macros to keep the code readable. + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define L3_DEBUG_TLS_HS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "TLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + } while( 0 ) +#else +#define L3_DEBUG_TLS_HS_HEADER( hdr ) do {} while( 0 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#define L3_DEBUG_DTLS_HS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "DTLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Sequence Nr: %u", (unsigned) (hdr)->seq_nr ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Offset: %u", (unsigned) (hdr)->frag_offset ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Length: %u", (unsigned) (hdr)->frag_len ); \ + } while( 0 ) +#else +#define L3_DEBUG_DTLS_HS_HEADER( hdr ) do {} while( 0 ) +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#define L3_DEBUG_HS_HEADER( hdr, mode ) \ + do \ + { \ + if( MBEDTLS_MPS_IS_TLS( mode ) ) \ + L3_DEBUG_TLS_HS_HEADER(hdr); \ + if( MBEDTLS_MPS_IS_DTLS( mode ) ) \ + L3_DEBUG_DTLS_HS_HEADER(hdr); \ + } while( 0 ) + +#define L3_DEBUG_ALERT( alert ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "Alert, level %u, type %u", \ + (unsigned) (alert)->level, (alert)->type ); \ + } while( 0 ) + +#define L3_DEBUG_IN_STATE( l3 ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "* External state: %u", \ + (unsigned) l3->io.in.state ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Handshake state: %u", \ + (unsigned) l3->io.in.hs.state ); \ + } while( 0 ) + +/* + * Constants and sizes from the [D]TLS standard + */ + +#define MPS_TLS_HS_HDR_SIZE 4 /* The handshake header length in TLS. */ +#define MPS_TLS_ALERT_SIZE 2 /* The length of an Alert message. */ +#define MPS_TLS_ALERT_LEVEL_FATAL 1 /* The 'level' field of a fatal alert. */ +#define MPS_TLS_ALERT_LEVEL_WARNING 2 /* The 'level' field of a warning alert. */ +#define MPS_TLS_CCS_SIZE 1 /* The length of a CCS message. */ +#define MPS_TLS_CCS_VALUE 1 /* The expected value of a valid CCS message. */ + +#define MPS_DTLS_HS_HDR_SIZE 13 /* The handshake header length in DTLS. */ + +/* + * Init & Free API + */ + +int mps_l3_init( mps_l3 *l3, mbedtls_mps_l2 *l2, uint8_t mode ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_init" ); + l3->conf.l2 = l2; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + l3->conf.mode = mode; +#else + MBEDTLS_MPS_ASSERT_RAW( mode == MBEDTLS_MPS_CONF_MODE, "Bad mode" ); +#endif /* !MBEDTLS_MPS_CONF_MODE */ + + l3->io.in.state = MBEDTLS_MPS_MSG_NONE; + l3->io.in.hs.state = MPS_L3_HS_NONE; + l3->io.in.raw_in = NULL; + + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + l3->io.out.hs.state = MPS_L3_HS_NONE; + l3->io.out.raw_out = NULL; + l3->io.out.clearing = 0; + + /* TODO Configure Layer 2 + * - Add allowed record types + * - Configure constraints for merging, pausing, and empty records. */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_free( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_free" ); + ((void) l3); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Reading API + */ + +/* TODO: Will we need this at some point? */ +/* Check if a message is ready to be processed. */ +int UNUSED mps_l3_read_check( mps_l3 *l3 ) +{ + return( l3->io.in.state ); +} + +/* Handles incomplete messages / message headers. + * In DTLS, this is fatal. In TLS, we need to wait for more data. */ +MBEDTLS_MPS_STATIC int l3_incomplete_header( mps_l3 *l3 ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incomplete message header" ); + ret = mps_l2_read_done( l2 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + /* We could return WANT_READ here, because _currently_ no records are + * buffered by Layer 2, hence progress depends on the availability of + * the underlying transport. However, this would need to be reconsidered + * and potentially adapted with any change to Layer 2, so returning + * MBEDTLS_ERR_MPS_RETRY here is safer. */ + return( MBEDTLS_ERR_MPS_RETRY ); + } + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Incomplete message in DTLS -- abort" ); + return( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } +} + +/* Attempt to receive an incoming message from Layer 2. */ +int mps_l3_read( mps_l3 *l3 ) +{ + int ret; + mps_l2_in in; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read" ); + + /* + * Outline: + * 1 If a message is already open for reading, + * do nothing and return its type. + * 2 If no message is currently open for reading, request + * incoming data from the underlying Layer 2 context. + * 3.1 For all content types different from handshake, + * call the type-specific parsing function with the + * reader returned from Layer 2. + * 3.2 For handshake messages, check if an incoming handshake + * message is currently being paused. + * 3.2.1 If no: Parse the TLS/DTLS handshake header from the + * incoming data reader, setup a new extended reader + * with the total message size, and bind it to the incoming + * data reader. + * 3.2.2 If yes (TLS only!) + * Fragmentation of handshake messages across multiple records + * do not require handshake headers within the subsequent records. + * Hence, we can directly bind the incoming data reader to the + * extended reader keeping track of global message bounds. + */ + + /* 1 */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_NONE, + "mps_l3_read() called in unexpected state." ); + + /* 2 */ + /* Request incoming data from Layer 2 context */ + MBEDTLS_MPS_TRACE_COMMENT( "Check for incoming data on Layer 2" ); + + /* TODO: Some compilers complain that `in` could still be + * uninitialized after the call has succeeded. + * I can't figure out what, if anything, is wrong here. + * Need to take a look again at a later point. + * + * For now, just force the initialization. + */ + { + mps_l2_in l2_in_zero = { .type = 0, .epoch = 0, .rd = NULL }; + in = l2_in_zero; + } + + ret = mps_l2_read_start( l2, &in ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Opened incoming datastream" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) in.epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) in.type ); + switch( in.type ) + { + /* Application data */ + case MBEDTLS_MPS_MSG_APP: + MBEDTLS_MPS_TRACE_COMMENT( "-> Application data" ); + break; + + /* Alert data */ + case MBEDTLS_MPS_MSG_ALERT: + MBEDTLS_MPS_TRACE_COMMENT( "-> Alert message" ); + + ret = l3_parse_alert( in.rd, &l3->io.in.alert ); + if( ret == 0 ) + break; /* All good */ + + if( ret != MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Incomplete alert */ + MBEDTLS_MPS_TRACE_RETURN( l3_incomplete_header( l3 ) ); + + /* CCS data */ + case MBEDTLS_MPS_MSG_CCS: + MBEDTLS_MPS_TRACE_COMMENT( "-> CCS message" ); + + /* We don't need to consider #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA + * here because the CCS content type does not allow empty + * records, and hence malicious length-0 records of type CCS + * will already have been silently skipped over (DTLS) or + * lead to failure (TLS) by Layer 2. */ + ret = l3_parse_ccs( in.rd ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + break; + + case MBEDTLS_MPS_MSG_ACK: + /* DTLS-1.3-TODO: Implement */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + + /* Handshake data */ + case MBEDTLS_MPS_MSG_HS: + MBEDTLS_MPS_TRACE_COMMENT( "-> Handshake message" ); + + /* Check if a handshake message is currently being paused. */ + if( l3->io.in.hs.state == MPS_L3_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake message is currently processed" ); + + /* Attempt to fetch and parse handshake header. + * May fail in TLS because of fragmentation. */ + + ret = l3_parse_hs_header( mode, in.rd, &l3->io.in.hs ); + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + /* Incomplete handshake header. */ + MBEDTLS_MPS_TRACE_RETURN( l3_incomplete_header( l3 ) ); + } + else if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Setup the extended reader keeping track of the + * global message bounds. */ + MBEDTLS_MPS_TRACE_COMMENT( + "Setup extended reader for handshake message" ); + } + else + { + /* We should reach this only for paused HS messages in TLS. */ + MBEDTLS_MPS_ASSERT_RAW( MBEDTLS_MPS_IS_TLS( mode ), "" ); + MBEDTLS_MPS_ASSERT_RAW( l3->io.in.hs.state == MPS_L3_HS_PAUSED, + "Invalid Layer 3 handshake state" ); + /* This should never happen, as we don't allow switching + * the incoming epoch while pausing the reading of a + * handshake message. But double-check nonetheless. */ + MBEDTLS_MPS_ASSERT_RAW( l3->io.in.hs.epoch == in.epoch, + "Unexpected epoch" ); + } + + /* Make changes to internal structures only now + * that we know that everything went well. */ + l3->io.in.hs.epoch = in.epoch; + l3->io.in.hs.state = MPS_L3_HS_ACTIVE; + break; + + default: + MBEDTLS_MPS_ASSERT_RAW( 0, "Invalid record content type" ); + break; + } + + l3->io.in.raw_in = in.rd; + l3->io.in.epoch = in.epoch; + l3->io.in.state = in.type; + + L3_DEBUG_IN_STATE( l3 ); + MBEDTLS_MPS_TRACE_RETURN( l3->io.in.state ); +} + +MBEDTLS_MPS_STATIC int l3_read_consume_core( mps_l3 *l3, + mps_l3_hs_state new_hs_state ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + /* Remove reference to the raw reader borrowed from Layer 2 + * before calling mps_l2_read_done(), which invalidates it. */ + l3->io.in.raw_in = NULL; + /* Signal that incoming data is fully processed. */ + res = mps_l2_read_done( l2 ); + if( res != 0 ) + return( res ); + + /* Reset state */ + if( l3->io.in.state == MBEDTLS_MPS_MSG_HS ) + l3->io.in.hs.state = new_hs_state; + l3->io.in.state = MBEDTLS_MPS_MSG_NONE; + return( 0 ); +} + +/* Mark an incoming message as fully processed. */ +int mps_l3_read_consume( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_consume" ); + MBEDTLS_MPS_TRACE_RETURN( l3_read_consume_core( l3, MPS_L3_HS_NONE ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* Pause the processing of an incoming handshake message. */ +int mps_l3_read_pause_handshake( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_pause_handshake" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.in.state == MBEDTLS_MPS_MSG_HS && + l3->io.in.hs.state == MPS_L3_HS_ACTIVE, + "mps_l3_read_pause_handshake() called in unexpected state." ); + MBEDTLS_MPS_TRACE_RETURN( l3_read_consume_core( l3, MPS_L3_HS_PAUSED ) ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Record content type specific parsing functions. + */ + +/* Handshake */ + +MBEDTLS_MPS_STATIC int l3_parse_hs_header( uint8_t mode, mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + if( MBEDTLS_MPS_IS_TLS( mode ) ) + return( l3_parse_hs_header_tls( rd, in ) ); + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l3_parse_hs_header_dtls( rd, in ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_tls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_size_t const tls_hs_hdr_len = 4; + mbedtls_mps_size_t const tls_hs_type_offset = 0; + mbedtls_mps_size_t const tls_hs_length_offset = 1; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_hs_header_tls" ); + + /* From RFC 5246 (TLS 1.2): + * enum { + * ..., (255) + * } HandshakeType; + * struct { + * HandshakeType msg_type; + * uint24 length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + + /* This fails for handshake headers crossing record boundaries. + * It will be caught and handled by the caller. */ + res = mbedtls_mps_reader_get( rd, tls_hs_hdr_len, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE ( tmp + tls_hs_type_offset, &in->type ); + MPS_READ_UINT24_BE( tmp + tls_hs_length_offset, &in->len ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + L3_DEBUG_TLS_HS_HEADER(in); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_dtls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_size_t const dtls_hs_hdr_len = 13; + mbedtls_mps_size_t const dtls_hs_type_offset = 0; + mbedtls_mps_size_t const dtls_hs_len_offset = 1; + mbedtls_mps_size_t const dtls_hs_seq_offset = 4; + mbedtls_mps_size_t const dtls_hs_frag_off_offset = 7; + mbedtls_mps_size_t const dtls_hs_frag_len_offset = 10; + MBEDTLS_MPS_TRACE_INIT( "parse_hs_header_dtls" ); + + /* From RFC 6347 (DTLS 1.2): + * struct { + * HandshakeType msg_type; + * uint24 length; + * uint16 message_seq; + * uint24 fragment_offset; + * uint24 fragment_length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + + res = mbedtls_mps_reader_get( rd, dtls_hs_hdr_len, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE ( tmp + dtls_hs_type_offset, &in->type ); + MPS_READ_UINT24_BE( tmp + dtls_hs_len_offset, &in->len ); + MPS_READ_UINT16_BE( tmp + dtls_hs_seq_offset, &in->seq_nr ); + MPS_READ_UINT24_BE( tmp + dtls_hs_frag_off_offset, &in->frag_offset ); + MPS_READ_UINT24_BE( tmp + dtls_hs_frag_len_offset, &in->frag_len ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* frag_offset + frag_len cannot overflow within uint32_t + * since the summands are 24 bit each. */ + if( in->frag_offset + in->frag_len > in->len ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid handshake header: frag_offset (%u) + frag_len (%u) > len (%u)", + (unsigned)in->frag_offset, + (unsigned)in->frag_len, + (unsigned)in->len ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + L3_DEBUG_DTLS_HS_HEADER(in); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* Alert */ + +MBEDTLS_MPS_STATIC int l3_parse_alert( mbedtls_mps_reader *rd, + mps_l3_alert_in_internal *alert ) +{ + int res; + unsigned char *tmp; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_alert" ); + + /* From RFC 5246 (TLS 1.2): + * enum { warning(1), fatal(2), (255) } AlertLevel; + * enum { close_notify(0), ..., (255) } AlertDescription; + * struct { + * AlertLevel level; + * AlertDescription description; + * } Alert; */ + + /* This may fail for an alert at record boundary. Needs to be + * re-entrant, so no state change before this call. */ + res = mbedtls_mps_reader_get( rd, MPS_TLS_ALERT_SIZE, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE( tmp + 0, &alert->level ); + MPS_READ_UINT8_BE( tmp + 1, &alert->type ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + L3_DEBUG_ALERT(alert); + + if( alert->level != MPS_TLS_ALERT_LEVEL_FATAL && + alert->level != MPS_TLS_ALERT_LEVEL_WARNING ) + { + MBEDTLS_MPS_TRACE_ERROR( "Alert level unknown" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* CCS */ + +MBEDTLS_MPS_STATIC int l3_parse_ccs( mbedtls_mps_reader *rd ) +{ + int res; + unsigned char *tmp; + uint8_t val; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_ccs" ); + + /* From RFC 5246 (TLS 1.2): + * struct { + * enum { change_cipher_spec(1), (255) } type; + * } ChangeCipherSpec; */ + + res = mbedtls_mps_reader_get( rd, MPS_TLS_CCS_SIZE, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE( tmp + 0, &val ); + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + if( val != MPS_TLS_CCS_VALUE ) + { + MBEDTLS_MPS_TRACE_ERROR( "Bad CCS value %u", (unsigned) val ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * API for retrieving read-handles for various content types. + */ + +int mps_l3_read_handshake( mps_l3 *l3, mps_l3_handshake_in *hs ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_handshake" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.in.state == MBEDTLS_MPS_MSG_HS && + l3->io.in.hs.state == MPS_L3_HS_ACTIVE, + "mps_l3_read_handshake() called in unexpected state." ); + + hs->epoch = l3->io.in.epoch; + hs->len = l3->io.in.hs.len; + hs->type = l3->io.in.hs.type; + hs->rd = l3->io.in.raw_in; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + hs->seq_nr = l3->io.in.hs.seq_nr; + hs->frag_offset = l3->io.in.hs.frag_offset; + hs->frag_len = l3->io.in.hs.frag_len; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_app( mps_l3 *l3, mps_l3_app_in *app ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_app" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_APP, + "mps_l3_read_app() called in unexpected state." ); + app->epoch = l3->io.in.epoch; + app->rd = l3->io.in.raw_in; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_alert( mps_l3 *l3, mps_l3_alert_in *alert ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_alert" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_ALERT, + "mps_l3_read_alert() called in unexpected state." ); + alert->epoch = l3->io.in.epoch; + alert->type = l3->io.in.alert.type; + alert->level = l3->io.in.alert.level; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_ccs( mps_l3 *l3, mps_l3_ccs_in *ccs ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_ccs" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_CCS, + "mps_l3_read_appccs() called in unexpected state." ); + ccs->epoch = l3->io.in.epoch; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Writing API + */ + +int mps_l3_flush( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_flush" ); + l3->io.out.clearing = 1; + MBEDTLS_MPS_TRACE_RETURN( l3_check_clear( l3 ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_tls( mps_l3 *l3 ) +{ + int res; + mps_l3_hs_out_internal *hs = &l3->io.out.hs; + /* Skip HS header on continuations */ + if( hs->hdr == NULL ) + return( 0 ); + + MBEDTLS_MPS_ASSERT_RAW( hs->len != MBEDTLS_MPS_SIZE_UNKNOWN, + "HS message length unknown" ); + res = l3_write_hs_header_tls( hs ); + if( res != 0 ) + return( res ); + hs->hdr = NULL; + hs->hdr_len = 0; + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_dtls( mps_l3 *l3 ) +{ + int res; + mps_l3_hs_out_internal *hs = &l3->io.out.hs; + MBEDTLS_MPS_ASSERT_RAW( hs->hdr != NULL && + hs->len != MBEDTLS_MPS_SIZE_UNKNOWN && + hs->frag_len != MBEDTLS_MPS_SIZE_UNKNOWN, + "Incomplete HS header data" ); + res = l3_write_hs_header_dtls( hs ); + if( res != 0 ) + return( res ); + hs->hdr = NULL; + hs->hdr_len = 0; + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr( mps_l3 *l3 ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + return( l3_check_write_hs_hdr_tls( l3 ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l3_check_write_hs_hdr_dtls( l3 ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +#if !defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) +#define L3_ASSERT_FRAG_BOUNDS(a,b,c) do {} while( 0 ) +#else +#define L3_ASSERT_FRAG_BOUNDS(len,frag_offset, frag_len) \ + do { \ + /* If the total length isn't specified, then \ + * then the fragment offset must be 0, and the \ + * fragment length must be unspecified, too. */ \ + MBEDTLS_MPS_ASSERT_RAW( len != MBEDTLS_MPS_SIZE_UNKNOWN || \ + ( frag_offset == 0 && \ + frag_len == MBEDTLS_MPS_SIZE_UNKNOWN ), \ + "Invalid message bounds" ); \ + \ + /* Check that fragment doesn't exceed the total message length. */ \ + if( len != MBEDTLS_MPS_SIZE_UNKNOWN && \ + frag_len != MBEDTLS_MPS_SIZE_UNKNOWN ) \ + { \ + mbedtls_mps_size_t total_len = \ + (mbedtls_mps_size_t) len; \ + mbedtls_mps_size_t end_of_fragment = \ + (mbedtls_mps_size_t)( frag_offset + frag_len ); \ + \ + MBEDTLS_MPS_ASSERT_RAW( end_of_fragment >= frag_offset && \ + end_of_fragment <= total_len, \ + "Invalid fragment bounds" ); \ + } \ + } while( 0 ) +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +int mps_l3_write_handshake( mps_l3 *l3, mps_l3_handshake_out *out ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l3_write_handshake" ); + L3_DEBUG_HS_HEADER(out,mode); + +#if defined(MBEDTLS_MPS_STATE_VALIDATION) + if( l3->io.out.hs.state == MPS_L3_HS_PAUSED && + ( l3->io.out.hs.epoch != out->epoch || + l3->io.out.hs.type != out->type || + l3->io.out.hs.len != out->len ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Inconsistent parameters on continuation." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } +#endif /* MBEDTLS_MPS_STATE_VALIDATION */ + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_HS, out->epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + if( l3->io.out.hs.state == MPS_L3_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake message currently paused" ); + + l3->io.out.hs.epoch = out->epoch; + l3->io.out.hs.len = out->len; + l3->io.out.hs.type = out->type; + + if( MBEDTLS_MPS_IS_TLS( mode ) ) + l3->io.out.hs.hdr_len = MPS_TLS_HS_HDR_SIZE; +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l3->io.out.hs.hdr_len = MPS_DTLS_HS_HDR_SIZE; + l3->io.out.hs.seq_nr = out->seq_nr; + l3->io.out.hs.frag_len = out->frag_len; + l3->io.out.hs.frag_offset = out->frag_offset; + L3_ASSERT_FRAG_BOUNDS(out->len, out->frag_offset, out->frag_len); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MBEDTLS_MPS_TRACE_COMMENT( "Acquire buffer for HS header" ); + res = mbedtls_writer_get( l3->io.out.raw_out, + l3->io.out.hs.hdr_len, + &l3->io.out.hs.hdr, NULL ); + + /* If we're at the end of a record and there's not enough space left for + * a handshake header, abort the write, flush L2, and retry. */ + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space for HS header, flush" ); + /* Remember that we must flush. */ + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Commit the header already now, even though it's not yet written. + * We only commit to writing it at some point. */ + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + /* Remember commit position so we can calculate the message length later. */ + l3->io.out.hs.hdr_offset = l3->io.out.raw_out->committed; + } + + l3->io.out.hs.state = MPS_L3_HS_ACTIVE; + out->wr = l3->io.out.raw_out; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_app( mps_l3 *l3, mps_l3_app_out *app ) +{ + int res; + mbedtls_mps_epoch_id epoch = app->epoch; + MBEDTLS_MPS_TRACE_INIT( "l3_write_app: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_APP, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + app->wr = l3->io.out.raw_out; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_alert( mps_l3 *l3, mps_l3_alert_out *alert ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_epoch_id epoch = alert->epoch; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_write_alert: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_ALERT, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + res = mbedtls_writer_get( l3->io.out.raw_out, 2, &tmp, NULL ); + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + alert->level = &tmp[0]; + alert->type = &tmp[1]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_ccs( mps_l3 *l3, mps_l3_ccs_out *ccs ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_epoch_id epoch = ccs->epoch; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_write_ccs: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_CCS, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + res = mbedtls_writer_get( l3->io.out.raw_out, 1, &tmp, NULL ); + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + *tmp = MPS_TLS_CCS_VALUE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* Pause the writing of an outgoing handshake message (TLS only). */ +int mps_l3_pause_handshake( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_pause_handshake" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.out.state == MBEDTLS_MPS_MSG_HS && + l3->io.out.hs.state == MPS_L3_HS_ACTIVE && + l3->io.out.hs.len != MBEDTLS_MPS_SIZE_UNKNOWN, + "mps_l3_pause_handshake() called in unexpected state." ); + + res = l3_check_write_hs_hdr( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Remove reference to the raw writer borrowed from Layer 2 + * before calling mps_l2_write_done(), which invalidates it. */ + l3->io.out.raw_out = NULL; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Switch to paused state. */ + l3->io.out.hs.state = MPS_L3_HS_PAUSED; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC void l3_autocomplete_hs_length( mps_l3 *l3 ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + + /* Calculate size of handshake message (fragment) */ + mbedtls_mps_size_t committed = l3->io.out.raw_out->committed - + l3->io.out.hs.hdr_offset; + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + if( l3->io.out.hs.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.len = committed; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + if( l3->io.out.hs.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.len = committed; + if( l3->io.out.hs.frag_len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.frag_len = committed; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +} + +int mps_l3_dispatch( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_dispatch" ); + + switch( l3->io.out.state ) + { + case MBEDTLS_MPS_MSG_HS: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch handshake message" ); + MBEDTLS_MPS_ASSERT_RAW( l3->io.out.hs.state == MPS_L3_HS_ACTIVE, "" ); + + /* Fill-in length values that user left unspecified */ + l3_autocomplete_hs_length( l3 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Write handshake header" ); + res = l3_check_write_hs_hdr( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + l3->io.out.hs.state = MPS_L3_HS_NONE; + break; + + case MBEDTLS_MPS_MSG_ALERT: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch alert message" ); + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + break; + + case MBEDTLS_MPS_MSG_CCS: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch CCS message" ); + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + break; + + case MBEDTLS_MPS_MSG_APP: + /* The app data is directly written through the writer. */ + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch application data" ); + break; + + default: + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.out.state != MBEDTLS_MPS_MSG_NONE, + "mps_l2_write_done() called in unexpected state." ); + MBEDTLS_MPS_ASSERT_RAW( 0, "Invalid state in mps_l3_write_done()" ); + break; + } + + /* Remove reference to the raw writer borrowed from Layer 2 + * before calling mps_l2_write_done(), which invalidates it. */ + l3->io.out.raw_out = NULL; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_write_hs_header_tls( mps_l3_hs_out_internal *hs ) + +{ + unsigned char *buf = hs->hdr; + mbedtls_mps_size_t const tls_hs_hdr_len = 4; + mbedtls_mps_size_t const tls_hs_type_offset = 0; + mbedtls_mps_size_t const tls_hs_length_offset = 1; + MBEDTLS_MPS_ASSERT_RAW( buf != NULL, "Invalid buffer" ); + MBEDTLS_MPS_ASSERT_RAW( hs->hdr_len == tls_hs_hdr_len, "Invalid header" ); + + /* From RFC 5246 (TLS 1.2): + * enum { + * ..., (255) + * } HandshakeType; + * struct { + * HandshakeType msg_type; + * uint24 length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; + */ + MPS_WRITE_UINT8_BE ( &hs->type, buf + tls_hs_type_offset ); + MPS_WRITE_UINT24_BE( &hs->len, buf + tls_hs_length_offset ); + + L3_DEBUG_TLS_HS_HEADER(hs); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_write_hs_header_dtls( mps_l3_hs_out_internal *hs ) + +{ + unsigned char *buf = hs->hdr; + mbedtls_mps_size_t const dtls_hs_hdr_len = 13; + mbedtls_mps_size_t const dtls_hs_type_offset = 0; + mbedtls_mps_size_t const dtls_hs_len_offset = 1; + mbedtls_mps_size_t const dtls_hs_seq_offset = 4; + mbedtls_mps_size_t const dtls_hs_frag_off_offset = 7; + mbedtls_mps_size_t const dtls_hs_frag_len_offset = 10; + MBEDTLS_MPS_ASSERT_RAW( buf != NULL, "Invalid buffer" ); + MBEDTLS_MPS_ASSERT_RAW( hs->hdr_len == dtls_hs_hdr_len, "Invalid header" ); + + /* From RFC 6347 (DTLS 1.2): + * struct { + * HandshakeType msg_type; + * uint24 length; + * uint16 message_seq; // New field + * uint24 fragment_offset; // New field + * uint24 fragment_length; // New field + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + MPS_WRITE_UINT8_BE ( &hs->type, buf + dtls_hs_type_offset ); + MPS_WRITE_UINT24_BE( &hs->len, buf + dtls_hs_len_offset ); + MPS_WRITE_UINT16_BE( &hs->seq_nr, buf + dtls_hs_seq_offset ); + MPS_WRITE_UINT24_BE( &hs->frag_offset, buf + dtls_hs_frag_off_offset ); + MPS_WRITE_UINT24_BE( &hs->frag_len, buf + dtls_hs_frag_len_offset ); + + L3_DEBUG_DTLS_HS_HEADER(hs); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Flush Layer 2 if requested. + */ +MBEDTLS_MPS_STATIC int l3_check_clear( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_check_clear" ); + if( l3->io.out.clearing == 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + res = mps_l2_write_flush( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.clearing = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Request a writer for the respective epoch and content type from Layer 2. + * This also keeps track of pursuing ongoing but not yet finished flush calls. + */ +MBEDTLS_MPS_STATIC int l3_prepare_write( mps_l3 *l3, mbedtls_mps_msg_type_t port, + mbedtls_mps_epoch_id epoch ) +{ + int res; + mps_l2_out out; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_prepare_write" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) port ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) epoch ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.out.state == MBEDTLS_MPS_MSG_NONE, + "l3_prepare_write() called in unexpected state." ); + +#if !defined(MPS_L3_ALLOW_INTERLEAVED_SENDING) + if( l3->io.out.hs.state == MPS_L3_HS_PAUSED && port != MBEDTLS_MPS_MSG_HS ) + { + MBEDTLS_MPS_TRACE_ERROR( "Interleaving of outgoing messages is disabled." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_NO_INTERLEAVING ); + } +#endif + + res = l3_check_clear( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + out.epoch = epoch; + out.type = port; + res = mps_l2_write_start( l2, &out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.raw_out = out.wr; + l3->io.out.state = port; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_epoch_add( mps_l3 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ) +{ + return( mps_l2_epoch_add( ctx->conf.l2, transform, epoch ) ); +} + + +int mps_l3_epoch_usage( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ) +{ + return( mps_l2_epoch_usage( ctx->conf.l2, epoch_id, clear, set ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l3_force_next_sequence_number( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ) +{ + return( mps_l2_force_next_sequence_number( ctx->conf.l2, epoch_id, ctr ) ); +} + +int mps_l3_get_last_sequence_number( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ) +{ + return( mps_l2_get_last_sequence_number( ctx->conf.l2, epoch_id, ctr ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer3_internal.h b/library/mps/layer3_internal.h new file mode 100644 index 000000000000..d532cec3f7af --- /dev/null +++ b/library/mps/layer3_internal.h @@ -0,0 +1,73 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H +#define MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H + +#include "mbedtls/mps/layer3.h" + +/* + * Handshake header parsing/writing + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_tls( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_dtls( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr( mps_l3 *l3 ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_tls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); +MBEDTLS_MPS_STATIC int l3_write_hs_header_tls( mps_l3_hs_out_internal *hs ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_dtls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); +MBEDTLS_MPS_STATIC int l3_write_hs_header_dtls( mps_l3_hs_out_internal *hs ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l3_parse_hs_header( uint8_t mode, mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); + +/* + * Other message types + */ + +MBEDTLS_MPS_STATIC int l3_parse_alert( mbedtls_mps_reader *rd, + mps_l3_alert_in_internal *alert ); +MBEDTLS_MPS_STATIC int l3_parse_ccs( mbedtls_mps_reader *rd ); + +/* + * Miscellanious + * + * TODO: Document + */ + +MBEDTLS_MPS_STATIC int l3_prepare_write( mps_l3 *l3, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch ); +MBEDTLS_MPS_STATIC int l3_check_clear( mps_l3 *l3 ); + +#endif /* MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H */ diff --git a/library/mps/mps.c b/library/mps/mps.c new file mode 100644 index 000000000000..51b639c548c4 --- /dev/null +++ b/library/mps/mps.c @@ -0,0 +1,3959 @@ +/* + * Message Processing Stack, (Layer 4) implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/common.h" + +/* Embed all other MPS translation units into here + * for release builds on constrained systems to allow + * inlining and hence significantly smaller code size. */ +#if !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#define MBEDTLS_MPS_TOP_TRANSLATION_UNIT +#include "reader.c" +#include "writer.c" +#include "layer1.c" +#include "layer2.c" +#include "layer3.c" +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS */ + +#include "mbedtls/mps/mps.h" +#include "mbedtls/mps/trace.h" + +#include "mbedtls/platform_util.h" +#include "mbedtls/ssl.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_4; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +/* + * Error state handling + */ + +/* Convenience macro to quit a function by jumping to its + * exit section in case a function call returns an error. */ +#define MPS_CHK( exp ) \ + do \ + { \ + ret = ( exp ); \ + if( ret != 0 ) \ + { \ + if( ret > 0 ) \ + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; \ + goto exit; \ + } \ + } while( 0 ) + +#define MPS_CHK_NEG( exp ) \ + do \ + { \ + ret = ( exp ); \ + if( ret < 0 ) \ + { \ + goto exit; \ + } \ + } while( 0 ) + +/* Convenience macro for the failure handling + * within internal functions. */ +#define MPS_INTERNAL_FAILURE_HANDLER \ + goto exit; /* Silence unused label warnings */ \ + exit: \ + MBEDTLS_MPS_TRACE_RETURN( ret ); + +/* Convenience macro for the failure handling + * within functions at MPS-API boundary, which + * should block the MPS on most errors. */ +#define MPS_API_BOUNDARY_FAILURE_HANDLER \ + goto exit; /* Silence unused label warnings */ \ + exit: \ + ret = mps_generic_failure_handler( mps, ret ); \ + MBEDTLS_MPS_TRACE_RETURN( ret ); \ + +/* Check if the MPS will serve read resp. write API calls. + * It will e.g. reject this if it is blocked after a fatal error, + * or if the user has already sent/received a closure notification. + * See also ::mbedtls_mps_connection_state_t. */ +MBEDTLS_MPS_STATIC int mps_check_read ( mbedtls_mps const *mps ); +MBEDTLS_MPS_STATIC int mps_check_write( mbedtls_mps const *mps ); + +/* Block the MPS, i.e. forbid any further operations. */ +MBEDTLS_MPS_STATIC void mps_block( mbedtls_mps *mps ); + +/* Handlers for incoming closure notifications. */ +MBEDTLS_MPS_STATIC void mps_close_notification_received( mbedtls_mps *mps ); + +/* Handler for incoming fatal alert. */ +MBEDTLS_MPS_STATIC void mps_fatal_alert_received( + mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ); + +/* Failure handler at the end of any public MPS API function. + * This checks the return code and potentially blocks the MPS. */ +MBEDTLS_MPS_STATIC int mps_generic_failure_handler( + mbedtls_mps *mps, int ret ); + +/* Attempt to deliver a pending alert to the underlying Layer 3. */ +MBEDTLS_MPS_STATIC int mps_handle_pending_alert( mbedtls_mps *mps ); + +/* + * Internal flags used to indicate usage of epochs + * + * Layer 3 keeps epochs as long as they are marked as used through + * 'usage flags', maintained separately for reading or writing. + * The DTLS retransmission state machine uses two kinds of read/write + * usage flags each, defined below. + */ + +/* Epochs for incoming messages. */ + +/*! This usage flag is set for the currently active incoming epoch. */ +#define MPS_READ_ACTIVE 0 +/*! This usage flag is set for all epochs of messages of the last incoming flight. + * Such epochs must be kept in order to be able to detect retransmissions. */ +#define MPS_READ_RETRANSMISSION_DETECTION 1 + +/* Epochs for outgoing messages. */ + +/*! This usage flag is set for the currently active outgoing epoch. */ +#define MPS_WRITE_ACTIVE 0 +/*! This usage flag is set for all epochs of messages of the last outgoing flight. + * Such epochs must be kept in order to be able to retransmit the last flight. */ +#define MPS_WRITE_RETRANSMISSION 1 + +/* + * Read/Write preparation functions + * + * These function check if reading/writing is allowed in the current + * handshake state, and performs any necessary preparations such as + * finishing a retransmission. + */ + +/* This function takes care of numerous operations that need to + * be performed before a new incoming message can be fetched: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests, or trigger such if the + * retransmission timer has fired. + */ +MBEDTLS_MPS_STATIC int mps_prepare_read( mbedtls_mps *mps ); + +/* This function takes care of numerous operations that need to + * be performed before a new incoming message can be written: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests. + */ + +#define MPS_PAUSED_HS_FORBIDDEN 0 +#define MPS_PAUSED_HS_ALLOWED 1 + +MBEDTLS_MPS_STATIC int mps_prepare_write( mbedtls_mps *mps, + uint8_t allow_paused_hs ); + +/* This function checks for pending alerts or outgoing handshake messages + * and attempts to dispatch them to Layer 3. In case of pending alerts, + * it also triggers a flush. */ +MBEDTLS_MPS_STATIC int mps_clear_pending( mbedtls_mps *mps, + uint8_t allow_paused_hs ); + +#define MBEDTLS_MPS_ALERT_LEVEL_WARNING 1 +#define MBEDTLS_MPS_ALERT_LEVEL_FATAL 2 +#define MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY 0 + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/* + * Outgoing DTLS handshake message fragmentation. + * + * This is used both for serving a user write-request + * and for outgoing flight retransmission. + */ + +/*! The type of an outgoing handshake message. + * + * Possible values are: + * - #MPS_DTLS_FRAG_OUT_START_USE_L3 + * In this type, the message writer operates on a buffer obtained from + * Layer 3, and only resorts to a separately allocated queue if + * necessary and available. + * This type is used for messages which don't need to be backed + * up for the purpose of retransmission (e.g. because a retransmission + * callback is registered for them); for those, it is desirable to work + * in place on the buffer(s) obtained from Layer 3 as much as possible. + * + * - #MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY + * In this type, the writer operates on a separate queue only. Gradual + * copying and dispatching to fragment buffers from Layer 3 happens only + * after the message has been fully written to the queue. + * This type is used to write messages that need to be backed up for + * retransmission; in this case, the backup buffer functions as the + * queue, so that the user writing the message directly writes it + * it into the backup buffer, avoiding an unnecessary copy. + */ + +typedef uint8_t mps_dtls_outgoing_hs_msg_mode; +#define MPS_DTLS_FRAG_OUT_START_USE_L3 ( (mps_dtls_outgoing_hs_msg_mode) 0 ) +#define MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY ( (mps_dtls_outgoing_hs_msg_mode) 1 ) + +/* + * The API between outgoing fragmentation and the rest of the MPS code. +*/ + +/*! Start a new outgoing handshake message. + * + * - The queue to be used for the underlying writer is provided in \c queue. + * - The write-mode flag \c mode indicates if the handshake data is already + * available and how Layer 3 should be involved when writing the message. + * See the documentation of ::mps_dtls_outgoing_hs_msg_mode for more. + * + * This does not interface with the underlying Layer 3 instance, + * and any error it returns is fatal. + * + * On success, the state of the internal structure representing + * the outgoing handshake message depends on \p mode as follows: + * - If \p mode is #MPS_DTLS_FRAG_OUT_START_USE_L3, the outgoing + * handshake message structure is in state #MBEDTLS_MPS_HS_PAUSED. + * - If \p mode is #MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY, the outgoing + * handshake message structure is in state #MBEDTLS_MPS_HS_ACTIVE. + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_start( + mbedtls_mps_handshake_out_internal *hs, + unsigned char *queue, + mbedtls_mps_size_t queue_len, + mbedtls_mps_msg_metadata *metadata, + mps_dtls_outgoing_hs_msg_mode mode ); + +/*! Move the outgoing handshake message from state #MBEDTLS_MPS_HS_PAUSED + * to state #MBEDTLS_MPS_HS_ACTIVE or #MBEDTLS_MPS_HS_NONE by dispatching + * queued content through Layer 3 (if any). + * + * If there is no outgoing handshake message in state #MBEDTLS_MPS_HS_PAUSED, + * this function returns immediately. + * + * This function might fail with #MBEDTLS_MPS_WANT_READ. + * + * If this function succeeds, the outgoing handshake message is either + * in state #MBEDTLS_MPS_HS_NONE (if it was in state #MBEDTLS_MPS_HS_NONE + * beforehand, or if it was in state #MBEDTLS_MPS_HS_QUEUED) or + * #MBEDTLS_MPS_HS_ACTIVE (if it was in state #MBEDTLS_MPS_HS_ACTIVE + * or #MBEDTLS_MPS_HS_PAUSED). + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_unpause( mbedtls_mps *mps, + uint8_t allow_active_hs ); + +/* The combination of mps_dtls_frag_out_close() and + * mps_dtls_frag_out_dispatch() moves the outgoing handshake + * message structure from state #MBEDTLS_MPS_HS_ACTIVE to state + * #MBEDTLS_MPS_HS_NONE or #MBEDTLS_MPS_HS_PAUSED. + * + * mps_dtls_frag_out_close() revokes the output buffer + * from the user-facing writer. + * + * mps_dtls_frag_out_dispatch() dispatches the next + * fragment to Layer 3. + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_close( mbedtls_mps *mps, + mbedtls_mps_hs_state new_state ); +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_dispatch( mbedtls_mps *mps ); + +/* TODO: Document */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_bind( mbedtls_mps *mps ); + +/* + * State interface for the retransmission state machine + */ + +MBEDTLS_MPS_ALWAYS_INLINE int mps_handshake_state_transition( + mbedtls_mps *mps, + mbedtls_mps_flight_state_t old, + mbedtls_mps_flight_state_t new ); + +MBEDTLS_MPS_ALWAYS_INLINE mbedtls_mps_flight_state_t +mps_get_hs_state( mbedtls_mps *mps ) +{ + /* NOTE: To save RAM, and likely also some code on Thumb due to limited + * immediate address offsets, it should be considered to allocate + * the retransmission state machine only when a handshake is active -- + * in this case, this function should check whether it's present first + * and return MBEDTLS_MPS_FLIGHT_DONE if not. */ + return( mps->dtls.state ); +} + +/* + * Read interface to the retransmission state machine. + */ + +MBEDTLS_MPS_STATIC +int mps_retransmission_finish_incoming_message( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC +int mps_retransmission_pause_incoming_message( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC +int mbedtls_mps_retransmission_handle_incoming_fragment( mbedtls_mps *mps ); + +/* + * Incoming flight retransmission detection + */ + +/* Check whether an incoming handshake message is a + * retransmission from the previous incoming flight. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_check( mbedtls_mps *mps, + mps_l3_handshake_in *hs ); +/* Remember a handshake message in the current incoming flight + * to be able to detect subsequent retransmissions. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_remember( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs_in, + uint8_t seq_nr ); +/* Initialize the structure used to remember incoming flights. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_init( mbedtls_mps *mps ); +/* Free the structure used to remember incoming flights. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_free( mbedtls_mps *mps ); +/* Clear memory of last incoming flight. Used when receiving the + * first message in a new incoming flight, at which point we can + * remove all memory of the last incoming flight. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_forget( mbedtls_mps *mps ); + +/* + * Retransmission timer handling + */ + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_stop( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_update( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_check( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_increase_timeout( + mbedtls_mps *mps ); + +/* + * Sending of outgoing flights. + */ + +MBEDTLS_MPS_STATIC int mps_out_flight_init( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_out_flight_free( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_out_flight_msg_start( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **handle ); +MBEDTLS_MPS_STATIC int mps_out_flight_msg_done( mbedtls_mps *mps ); +MBEDTLS_MPS_ALWAYS_INLINE int mps_out_flight_get_retransmission_handle( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **hdl, size_t offset ); + +/* + * Message retransmission handles + */ + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_init( + mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_free( + mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend_empty( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ); + +/* + * Outgoing flight retransmission + */ + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_retransmit_out( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmit_out_core( mbedtls_mps *mps, + uint8_t mode ); + +/* + * Incoming flight retransmission request + * + * (In DTLS 1.0 and 1.2, this is done by resending the last + * outgoing flight; in DTLS 1.3, it's done using ACK's.) + */ + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission_request( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_request_resend( mbedtls_mps *mps ); + +/* + * Handling of retransmissions / retransmission requests. + */ + +/* Check whether we're currently retransmitting our last outgoing + * flight, or requesting retransmission from the peer, and attempt + * to finish it. */ +MBEDTLS_MPS_STATIC int mps_handle_pending_retransmit( mbedtls_mps *mps ); + +/* + * DTLS reassembly and future message buffering + * + * See also the documentation of ::mbedtls_mps_reassembly in mps.h. + */ + +MBEDTLS_MPS_STATIC int mps_reassembly_init( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_free( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC void mps_bitmask_set( unsigned char *mask, + size_t first_bit, + size_t bitlen ); +MBEDTLS_MPS_STATIC int mps_bitmask_check( unsigned char *mask, size_t len ); + +/* Feed a handshake fragment into the reassembly module, which might + * drop the fragment, buffer it as (part of) a future message, or use + * it for the reassembly of the next handshake message. + * + * This function returns 0 if (parts of) the next handshake message + * are ready to be passed to the user. */ +MBEDTLS_MPS_STATIC int mps_reassembly_feed( mbedtls_mps *mps, mps_l3_handshake_in *hs ); +MBEDTLS_MPS_STATIC int mps_reassembly_get_seq( mbedtls_mps *mps, uint8_t *seq_nr ); + +/* This function indicates whether the next expected + * handshake message has been fully received. */ +MBEDTLS_MPS_STATIC int mps_reassembly_next_msg_complete( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_reassembly_check_and_load( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_read( mbedtls_mps *mps, + mbedtls_mps_handshake_in *in ); +MBEDTLS_MPS_STATIC int mps_reassembly_done( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_pause( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_reassembly_forget( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_recognition_info_match( + mbedtls_mps_recognition_info *info, mps_l3_handshake_in *hs_in ); + +#define MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS 0 +#define MPS_RETRANSMIT_FULL_FLIGHT 1 + +#define MPS_INITIAL_HS_SEQ_NR 0 + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Preparations before a new incoming message can be fetched, + * or a new outgoing message can be prepared. + */ + +MBEDTLS_MPS_STATIC int mps_clear_pending( mbedtls_mps *mps, + uint8_t allow_active_hs ) +{ + int ret = 0; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MBEDTLS_MPS_TRACE_INIT( "mps_clear_pending, allow_active_hs %u", + (unsigned) allow_active_hs ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* If present, dispatch queueing handshake data. */ + MPS_CHK( mps_dtls_frag_out_unpause( mps, allow_active_hs ) ); + } +#else + ((void) allow_active_hs); + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Attempt to send any pending alerts. */ + MPS_CHK( mps_handle_pending_alert( mps ) ); + + /* Note: Once an alert has been sent, no further write operations are + * possible, as the alert was either fatal, or it indicated the + * closure of the write side of the connection. + * Therefore, we can safely handle pending handshake messages + * first before handling the alert. */ + + if( mps->out.flush == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A flush was requested" ); + MPS_CHK( mps_l3_flush( l3 ) ); + mps->out.flush = 0; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_prepare_read( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_prepare_read" ); + + /* Check that MPS isn't blocked or has its reading side closed. */ + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Layer 4 forbids reading while writing. */ + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state == MBEDTLS_MPS_MSG_NONE, + "Reading while writing is forbidden." ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + MBEDTLS_MPS_STATE_VALIDATE( + ! MBEDTLS_MPS_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_PREPARE ), + "Refuse read request when sending flights." ); + + /* Check if the timer expired, and take appropriate action + * (e.g. start a retransmission or send a retransmission + * request). */ + MPS_CHK( mps_retransmission_timer_check( mps ) ); + + /* Check if a retransmission is ongoing (might be one just triggered + * by the previous call to mps_retransmission_timer_check(), or an + * earlier one that hasn't yet completed. */ + MPS_CHK( mps_handle_pending_retransmit( mps ) ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* If a flush is pending, ensure that all outgoing data + * gets delivered before allowing the next read request. + * Do not allow partially sent handshake messages. */ + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + /* Note: At this point, we might still have data dispatched but + * not yet flushed to the underlying transport, which is + * deliberate. + * + * Flushing all dispatched outgoing data on each read would + * not be desirable in case an application protocol is used + * for which multiple messages can fit into a single DTLS-datagram, + * and for which incoming messages might trigger independent + * responses. In this case, a peer might loop on reading a + * message and writing a response, and if space permits, + * it is desirable to handle multiple such read-write + * with a single incoming/outgoing datagram, which + * wouldn't be possible if MPS always flushed outgoing + * data before reading. + * + * When switching from sending to receiving state during + * a handshake, though, a flush is implicit, so subsequent + * reads will only commence once the last outgoing flight + * has been fully delivered. + * + * TODO: If the I/O buffers are shared, all dispatched data + * must be flushed before the next read can commence. + * Implement this! + */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_prepare_write( mbedtls_mps *mps, + uint8_t allow_paused_hs ) +{ + int ret = 0; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_prepare_write" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state == MBEDTLS_MPS_MSG_NONE, + "Write operation already in progress." ); + + /* If a flush is pending, ensure that all outgoing data + * gets delivered before allowing the next write request. */ + MPS_CHK( mps_clear_pending( mps, allow_paused_hs ) ); +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* Reject send requests when receiving flights. + * Note that this does not apply to fatal alerts: + * those are sent through mbedtls_mps_send_fatal() + * which does not call this function. */ + MBEDTLS_MPS_STATE_VALIDATE( + ! MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_RECEIVE ), + "Attempt to send message in an unexpected flight state." ); + + /* In state #MBEDTLS_MPS_FLIGHT_FINALIZE, check if + * the timer has expired and we can wrapup the flight-exchange. */ + MPS_CHK( mps_retransmission_timer_check( mps ) ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Implementation of error and closure handling. + */ + +/* Error/Closure state modifying functions */ + +/* Block the MPS */ +MBEDTLS_MPS_STATIC void mps_block( mbedtls_mps *mps ) +{ + mps->state = MBEDTLS_MPS_STATE_BLOCKED; +} + +/* Handle an error code from an internal library call. */ +MBEDTLS_MPS_STATIC int mps_generic_failure_handler( mbedtls_mps *mps, int ret ) +{ + int flags; + int found = 0; + const char *error_string = NULL; + +#if !defined(MBEDTLS_MPS_ENABLE_TRACE) + ((void) error_string); +#endif + + if( ret == 0 ) + return( 0 ); + +#define MBEDTLS_MPS_ERROR_INFO( err_str, err_code, err_flags ) \ + if( ret == err_code ) \ + { \ + flags = err_flags; \ + error_string = err_str; \ + found = 1; \ + } + + /* Replicates code from above for each MPS error - see error.h. */ + MBEDTLS_ERR_MPS_ERROR_LIST; + + if( found == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Unknown error at MPS boundary: -%#04x", + (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } + +#if defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) + { +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + if( MBEDTLS_MPS_IS_DTLS( mode ) && + MBEDTLS_MPS_ERROR_IS_TLS_ONLY( flags ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "TLS-only error observed in DTLS mode: %s (-%#04x)", + error_string, (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + if( !MBEDTLS_MPS_ERROR_IS_EXTERNAL( flags ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "TLS-only error observed in DTLS mode: %s (-%#04x)", + error_string, (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } + } +#else + ((void) error_string); +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + + if( MBEDTLS_MPS_ERROR_IS_FATAL( flags ) ) + goto fatal; + + /* Error OK and non-fatal */ + return( ret ); + +fatal: + + if( mps->state != MBEDTLS_MPS_STATE_BLOCKED ) + { + /* Remember error and block MPS. */ + MBEDTLS_MPS_TRACE_ERROR( "Blocking MPS after a fatal error" ); + mps->blocking_reason = MBEDTLS_MPS_ERROR_INTERNAL_ERROR; + mps->blocking_info.err = ret; + mps_block( mps ); + } + + return( ret ); +} + +/* Send fatal alert and block MPS. */ +int mbedtls_mps_send_fatal( mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_send_fatal, type %d", alert_type ); + + MPS_CHK( mps_check_write( mps ) ); + + /* Remember the reason for blocking MPS. */ + mps->blocking_reason = MBEDTLS_MPS_ERROR_ALERT_SENT; + mps->blocking_info.alert = alert_type; + + /* Move to blocked state to ensure that no further operations can be + * performed even if something goes wrong when sending the alert. */ + mps_block( mps ); + + /* Attempt to send alert. */ + MBEDTLS_MPS_TRACE_COMMENT( "Pend fatal alert" ); + mps->alert_pending = 1; + MPS_CHK( mbedtls_mps_flush( mps ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +/* React to a fatal alert from the peer. */ +MBEDTLS_MPS_STATIC void mps_fatal_alert_received( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ) +{ + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + case MBEDTLS_MPS_STATE_READ_ONLY: + + mps->blocking_reason = MBEDTLS_MPS_ERROR_ALERT_RECEIVED; + mps->blocking_info.alert = alert_type; + + mps_block( mps ); + break; + } +} + +/* React to a close notification from the peer. */ +MBEDTLS_MPS_STATIC void mps_close_notification_received( mbedtls_mps *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_close_notification_received" ); + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + MBEDTLS_MPS_TRACE_COMMENT( "State transition OPEN -> WRITE-ONLY" ); + mps->state = MBEDTLS_MPS_STATE_WRITE_ONLY; + break; + + case MBEDTLS_MPS_STATE_READ_ONLY: + MBEDTLS_MPS_TRACE_COMMENT( "State transition READ-ONLY -> CLOSED" ); + mps->state = MBEDTLS_MPS_STATE_CLOSED; + break; + } +} + +MBEDTLS_MPS_STATIC int mps_handle_pending_alert( mbedtls_mps *mps ) +{ + int ret; + mps_l3_alert_out alert; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_handle_pending_alert" ); + + if( mps->alert_pending == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No alert pending" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + alert.epoch = mps->out_epoch; + /* This might fail, but we only reset `mps->alert_pending` + * on success, so in this case we'll retry sending the alert + * on a subsequent call to mps_flush(). */ + MPS_CHK( mps_l3_write_alert( l3, &alert ) ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_READ_ONLY, + MBEDTLS_MPS_STATE_CLOSED ) ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Report orderly closure of write-side to peer." ); + *alert.level = MBEDTLS_MPS_ALERT_LEVEL_WARNING; + *alert.type = MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY; + } + else if( mps->state == MBEDTLS_MPS_STATE_BLOCKED && + mps->blocking_reason == MBEDTLS_MPS_ERROR_ALERT_SENT ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Report fatal alert to peer." ); + *alert.level = MBEDTLS_MPS_ALERT_LEVEL_FATAL; + *alert.type = mps->blocking_info.alert; + } + else + MBEDTLS_MPS_ASSERT( 0, "" ); + + MPS_CHK( mps_l3_dispatch( l3 ) ); + + mps->alert_pending = 0; + mps->out.flush = 1; + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* Close the write-side of the MPS and inform the peer. */ +int mbedtls_mps_close( mbedtls_mps *mps ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_close" ); + + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + MBEDTLS_MPS_TRACE_COMMENT( "State transition OPEN -> READ-ONLY" ); + mps->state = MBEDTLS_MPS_STATE_READ_ONLY; + mps->alert_pending = 1; + break; + + case MBEDTLS_MPS_STATE_WRITE_ONLY: + MBEDTLS_MPS_TRACE_COMMENT( "State transition WRITE-ONLY -> CLOSED" ); + mps->state = MBEDTLS_MPS_STATE_CLOSED; + mps->alert_pending = 1; + break; + + case MBEDTLS_MPS_STATE_READ_ONLY: + case MBEDTLS_MPS_STATE_CLOSED: + /* If the write-side has already been closed, just flush to + * make sure the closure alert is being sent. This allows users + * to repeatedly calling mbedtls_mps_close() until it returns 0. */ + break; + + default: + MPS_CHK( MBEDTLS_ERR_MPS_BLOCKED ); + } + + /* Attempt to send the alert - this works regardless + * of whether data is still pending to be delivered; + * in that case, the pending data will be flushed first + * before writing and dispatching the alert. */ + MPS_CHK( mbedtls_mps_flush( mps ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +/* + * Error/Closure state informing functions. + */ + +/* Check if the MPS can be used for reading. */ +MBEDTLS_MPS_STATIC int mps_check_read( mbedtls_mps const *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_check_read, state %d", mps->state ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_OPEN, MBEDTLS_MPS_STATE_READ_ONLY ) ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_ERROR( "Read-side blocked" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BLOCKED ); +} + +/* Check if the MPS can be used for writing. */ +MBEDTLS_MPS_STATIC int mps_check_write( mbedtls_mps const *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_check_write, state %d", mps->state ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_OPEN, MBEDTLS_MPS_STATE_WRITE_ONLY ) ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_ERROR( "Write-side blocked" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BLOCKED ); +} + +/* + * MPS maintenance functions. + */ + +int mbedtls_mps_init( mbedtls_mps *mps, + mps_l3 *l3, + uint8_t mode, + size_t max_write ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_init" ); + + mps->conf.l3 = l3; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + mps->conf.mode = mode; +#else + ((void) mode); + MBEDTLS_MPS_ASSERT( mode == MBEDTLS_MPS_CONF_MODE, + "Protocol passed to mps_l3_init() doesn't match hardcoded protocol." ); +#endif /* !MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) + mps->conf.hs_timeout_max = 16000; +#endif /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) + mps->conf.hs_timeout_min = 250; +#endif /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + + mps->conf.f_get_timer = NULL; + mps->conf.f_set_timer = NULL; + mps->conf.p_timer = NULL; + + mps->in_epoch = MBEDTLS_MPS_EPOCH_NONE; + mps->out_epoch = MBEDTLS_MPS_EPOCH_NONE; + + mps->alert_pending = 0; + mps->state = MBEDTLS_MPS_STATE_OPEN; + mps->blocking_reason = MBEDTLS_MPS_ERROR_UNKNOWN; + + mps->in.state = MBEDTLS_MPS_MSG_NONE; + mps->in.flags = 0; + mps->out.state = MBEDTLS_MPS_MSG_NONE; + mps->out.flush = 0; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps->dtls.io.out.hs.state = MBEDTLS_MPS_HS_NONE; + mps->dtls.state = MBEDTLS_MPS_FLIGHT_DONE; + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_NONE; + + mps_out_flight_init( mps ); + mps_retransmit_in_init( mps ); + mps_reassembly_init( mps ); + + if( max_write > 0 ) + { + unsigned char *queue = NULL; + MBEDTLS_MPS_TRACE_COMMENT( "Alloc L4 %u Byte queue", (unsigned) max_write ); + + queue = calloc( 1, max_write ); + if( queue == NULL ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + + mps->dtls.io.out.hs.queue_len = max_write; + mps->dtls.io.out.hs.queue = queue; + } +#else + ((void) max_write); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +int mbedtls_mps_free( mbedtls_mps *mps ) +{ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps_out_flight_free( mps ); + mps_retransmit_in_free( mps ); + mps_reassembly_free( mps ); + free( mps->dtls.io.out.hs.queue ); +#else + ((void) mps); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + return( 0 ); +} + +/* + * MPS reading functions. + */ + +int mbedtls_mps_read( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_msg_type_t msg; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read" ); + + /* Take care of numerous checks that need to be performed + * before we can fetch a new message: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests, or trigger such if the + * retransmission timer has fired. + */ + MPS_CHK( mps_prepare_read( mps ) ); + + /* Note: In contrast to many other state checks, we deliberately + * tolerate calling mps_read() while a message is already open. + * This is used when it's not clear which handshake message to + * expect next: In this case, the state coordination function can + * peek at the next message's content and call the corresonding + * handler, which in turn doesn't need to know that the message + * has already been opened and may call mps_read() again instead, + * like any other handler function for states where the next + * expected message is unambiguous. */ + if( mps->in.state != MBEDTLS_MPS_MSG_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Msg of type %d already open", mps->in.state ); + MBEDTLS_MPS_TRACE_RETURN( mps->in.state ); + } + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* Check if a future message has been buffered. */ + ret = mps_reassembly_check_and_load( mps ); + if( ret != MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) + { + MPS_CHK( ret ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Fetch a new message (fragment) from Layer 3. */ + MPS_CHK_NEG( mps_l3_read( l3 ) ); + + /* Go through the various message types: + * - Fatal alerts and (non-fatal) closure notifications are handled here, + * while other non-fatal alerts are passed to the user. + * - For DTLS 1.3, ACK messages are passed to and handled by the + * retransmission state machine and are never passed forward to the user. + * - Handshake message fragments are fed to the + * retransmission state machine, which may ... + * (1) pass it through if it's an entire handshake message + * of expected epoch and sequence number. + * (2) trigger retransmission if it's recognized as a + * retransmission from an old flight. + * (3) fetch the contents and add it to the message reassembler, + * in case it's a proper fragment of a handshake message, + * and potentially return the fully reassembled message. + * (4) buffer it if it's a future message and the retransmission + * state machine supports it. + * (5) ignore otherwise. + * In any case, the retransmission state machine will signal + * whether the new fragment leads to a message being deliverable + * to the user or not. + * - Application data messages are always forwarded to the user. + */ + + msg = (unsigned) ret; + ret = 0; + switch( msg ) + { + case MBEDTLS_MPS_MSG_CCS: + { + mps_l3_ccs_in ccs_l3; + MBEDTLS_MPS_TRACE_COMMENT( "CCS message received from L3." ); + + MPS_CHK( mps_l3_read_ccs( l3, &ccs_l3 ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) && + ccs_l3.epoch != mps->in_epoch ) + { + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * CCS messages, however, should always be discarded + * if they're not secured through the current incoming epoch. + */ + + /* The exit handler will retry the read. */ + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->in.state = MBEDTLS_MPS_MSG_CCS; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_CCS ); + } + + case MBEDTLS_MPS_MSG_ALERT: + { + mps_l3_alert_in alert; + + MBEDTLS_MPS_TRACE_COMMENT( "Alert msg received from L3." ); + MPS_CHK( mps_l3_read_alert( l3, &alert ) ); + + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * Alert messages, however, should always be discarded + * if they're not secured through the current incoming epoch. + */ + + MPS_CHK( mps_l3_read_consume( l3 ) ); + + if( alert.epoch != mps->in_epoch ) + { + /* The exit handler will retry the read. */ + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } + + switch( alert.level ) + { + case MBEDTLS_MPS_ALERT_LEVEL_FATAL: + MBEDTLS_MPS_TRACE_COMMENT( "Fatal alert, type %d", alert.type ); + mps_fatal_alert_received( mps, alert.type ); + MPS_CHK( MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED ); + break; + + case MBEDTLS_MPS_ALERT_LEVEL_WARNING: + + MBEDTLS_MPS_TRACE_COMMENT( "Warning, type %d", alert.type ); + + if( alert.type == MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY ) + { + mps_close_notification_received( mps ); + MPS_CHK( MBEDTLS_ERR_MPS_CLOSE_NOTIFY ); + } + mps->in.data.alert = alert.type; + + mps->in.state = MBEDTLS_MPS_MSG_ALERT; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_ALERT ); + break; + + default: + /* Layer 3 checks the level, so this shouldn't happen. */ + MBEDTLS_MPS_ASSERT( 0, "Received invalid alert level from Layer 3." ); + break; + } + + break; + } + + case MBEDTLS_MPS_MSG_ACK: + { + /* 2. ACK messages (DTLS 1.3) + * Not yet implemented. */ + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + break; + } + + case MBEDTLS_MPS_MSG_HS: + { + MBEDTLS_MPS_TRACE_COMMENT( "Received HS fragment from L3" ); + + /* Pass message fragment to retransmission state machine + * and check if it leads to a handshake message being ready + * to be passed to the user. + * + * This is trivial for TLS, in which case handshake messages + * are always forwarded. We keep the call here for uniformity; + * in TLS-only builds the compiler will be able to inline + * and optimize it. + * + * It is the responsibility of the reassembly module to + * deal with the distinction between new messages and + * the continuation of paused ones. + */ +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* In TLS, we transparently forward the data from Layer 3. */ + mps->in.state = MBEDTLS_MPS_MSG_HS; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + ret = mbedtls_mps_retransmission_handle_incoming_fragment( mps ); + /* The retransmission state machine swallows the fragment if ... + * - it's old, or + * - it's from a future message, or + * - it's a fragment of the next handshake message + * which isn't yet fully reassembled. + */ + if( ret == MBEDTLS_ERR_MPS_NO_FORWARD ) + ret = MBEDTLS_ERR_MPS_RETRY; + MPS_CHK( ret ); + + MPS_CHK( mps_reassembly_check_and_load( mps ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + break; + } + + case MBEDTLS_MPS_MSG_APP: + { + mps_l3_app_in app_l3; + MPS_CHK( mps_l3_read_app( l3, &app_l3 ) ); + + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * Application data, however, should always be discarded + * if it's not secured through the current incoming epoch. + */ + + /* TODO: Add DTLS-only guards. */ + if( app_l3.epoch != mps->in_epoch ) + { + /* The exit handler will retry the read. */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } + mps->in.data.app = app_l3.rd; + + mps->in.state = MBEDTLS_MPS_MSG_APP; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_APP ); + } + + default: + MBEDTLS_MPS_ASSERT( 0, "" ); + break; + } + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_check( mbedtls_mps const *mps ) +{ + int ret; + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + return( mps->in.state ); +} + +int mbedtls_mps_read_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_handshake" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_HS, + "mbedtls_mps_read_handshake() must only be called if HS msg is open." ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* TLS */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mps_l3_handshake_in hs_l3; + MPS_CHK( mps_l3_read_handshake( l3, &hs_l3 ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "HS msg: Len %u, Type %u", + (unsigned) hs_l3.len, (unsigned) hs_l3.type ); + + hs->length = hs_l3.len; + hs->type = hs_l3.type; + hs->handle = hs_l3.rd; + hs->addlen = 0; /* No additional data in TLS */ + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MPS_CHK( mps_reassembly_read( mps, hs ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_application( mbedtls_mps *mps, + mbedtls_mps_reader **rd ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_application" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_APP, + "mbedtls_mps_read_application() must only be called if APP msg is open." ); + + *rd = mps->in.data.app; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t *alert_type ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_alert" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_ALERT, + "mbedtls_mps_read_alert() must only be called if Alert msg is open." ); + + *alert_type = mps->in.data.alert; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + int ret = 0; + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_set_flags" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Flags: %02x", (unsigned) flags ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_read_set_flags() must only be called while reading." ); + + /* The logic layer may call this function even for TLS, + * in which case it does nothing. That's to prevent the + * handshake logic code to be cluttered with TLS vs. DTLS + * distinctions. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + mps->in.flags = flags; +#else + ((void) mode); + ((void) flags); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_pause( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_HS, + "mbedtls_mps_read_pause() must only be called if HS msg is open." ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MPS_CHK( mps_l3_read_pause_handshake( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + MPS_CHK( mps_retransmission_pause_incoming_message( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->in.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_consume( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_consume" ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_read_consume() must only be called if HS msg is open." ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + switch( mps->in.state ) + { + case MBEDTLS_MPS_MSG_HS: + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS + * + * Notify the retransmission state machine. + * + * Note that not all handshake messages passed to the user are + * related to an incoming fragment currently opened on Layer 3 + * -- for example, when buffering out-of-order messages, the + * retransmission state machine will serve buffered messages + * from internal copies, and consuming them does not involve any + * interaction with Layer 3. + */ + MPS_CHK( mps_retransmission_finish_incoming_message( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + break; + + case MBEDTLS_MPS_MSG_APP: + MPS_CHK( mps_l3_read_consume( l3 ) ); + break; + + case MBEDTLS_MPS_MSG_CCS: + case MBEDTLS_MPS_MSG_ALERT: + /* Alerts and CCS's are signalled as consumed + * to Layer 3 in mbedtls_mps_read(). */ + break; + + default: + + MBEDTLS_MPS_ASSERT( 0, + "Invalid state in mbedtls_mps_read_consume()" ); + break; + } + + MBEDTLS_MPS_TRACE_COMMENT( "New incoming state: NONE" ); + mps->in.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ) +{ + ((void) mps); + ((void) flags); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +int mbedtls_mps_get_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ) +{ + ((void) mps); + ((void) seq); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +/* + * MPS writing functions. + */ + +int mbedtls_mps_write_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + int ret = 0; + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_set_flags" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Flags: %02x", (unsigned) flags ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_write_set_flags() must only be called while writing." ); + + /* The logic layer may call this function even for TLS, + * in which case it does nothing. That's to prevent the + * handshake logic code to be cluttered with TLS vs. DTLS + * distinctions. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + mps->dtls.io.out.flags = flags; +#else + ((void) mode); + ((void) flags); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_out *hs_new, + mbedtls_mps_write_cb_t cb, + mbedtls_mps_write_cb_ctx_t *cb_ctx ) +{ + /* TODO: + * Currently, when this function returns MPS_WANT_WRITE, + * the user cannot know to what extend the user-facing state of MPS has + * changed: + * - If Layer 4 handshake data is pending to be flushed but the + * underlying transport isn't ready, the function will return + * MPS_WANT_WRITE without having changed the user-facing state of MPS. + * - If Layer 3 handshake data is pending to be flushed, this function + * returns MPS_WANT_WRITE _after_ changing the flight state. + * + * This should be made uniform. + */ + + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_handshake, type %u, length %u", + (unsigned) hs_new->type, (unsigned) hs_new->length ); + + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_ALLOWED ) ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* TLS + * Write a handshake message on Layer 3 and forward the writer. */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + /* TODO: This zero-initialization should not be necessary, but + * some compilers complain if it's omitted, for the following reason: + * At the moment, each layer has its own configuration, and in particular + * its own `mode` identifier. This code-path is guarded by the L4-mode + * being stream, while mps_l3_write_handshake() operates based on the L3-mode. + * If the L4-mode is stream and the L3-mode is datagram, then + * mps_l3_write_handshake() would use some fields of hs_l3 uninitialized, + * which is what the compiler warns about. In a well-formed configuration, + * this should never happen, but the compiler can't reason about it. + * So either we need to silence the compiler by something overhead-generating + * like the zero-initialization below, or some attribute, or we remove + * the duplication of the modes altogether -- which would ultimately + * be the best solution. */ + /* Use per-field initialization to silence annoying compiler warning + * when using the _compliant_ `struct foo bar = { 0 }` zero-initialization... */ + mps_l3_handshake_out hs_l3 = { .epoch = 0, .type = 0, .seq_nr = 0, + .len = 0, .frag_len = 0, .frag_offset = 0, + .wr = NULL }; + + /* Retransmission isn't needed in TLS. */ + ((void) cb); + ((void) cb_ctx); + + hs_l3.epoch = mps->out_epoch; + hs_l3.type = hs_new->type; + hs_l3.len = hs_new->length; + + MPS_CHK( mps_l3_write_handshake( l3, &hs_l3 ) ); + + hs_new->handle = hs_l3.wr; + hs_new->addlen = 0; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* DTLS */ + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + + /* We have to deal with the situation where a flight-exchange finished + * with an outgoing flight of ours, and we attempt to start another one + * while still being unsure whether the peer has received our last + * flight (i.e., we're in state #MBEDTLS_MPS_FLIGHT_FINALIZE). + * + * We are currently ignoring the missing acknowledgement + * and start a new handshake assuming that our peer sees + * the previous one as completed. + * + * This was also the behavior of the previous messaging stack. + * + * TODO: Test this! + */ + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_FINALIZE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Last flight-exchange complete for us, " + "but not necessarily for peer - ignore." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, + MBEDTLS_MPS_FLIGHT_DONE ) ); + } + else if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECVINIT, + MBEDTLS_MPS_FLIGHT_DONE ) ); + } + + /* No `else` because we want to fall through. */ + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_DONE ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No flight-exchange in progress. Start a new one" ); + mps->dtls.seq_nr = MPS_INITIAL_HS_SEQ_NR; + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_DONE, + MBEDTLS_MPS_FLIGHT_SEND ) ); + } + else if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_PREPARE ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_PREPARE, + MBEDTLS_MPS_FLIGHT_SEND ) ); + } + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_ACTIVE || + hs->state == MBEDTLS_MPS_HS_NONE, + "Bad handshake state" ); + + /* Check if a handshake message is currently paused or not. */ + if( hs->state == MBEDTLS_MPS_HS_ACTIVE ) + { + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + MBEDTLS_MPS_TRACE_COMMENT( "Handshake message has been paused - continue" ); + + /* Check consistency of parameters and forward to the user. */ + /* OPTIMIZATION: Consider ignoring the metadata passed on + * continuation calls (and documentin that). */ + if( metadata->len != hs_new->length || + metadata->type != hs_new->type ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Inconsistent parameters on hs message continuation." ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } + } + else /* hs->state == MBEDTLS_MPS_HS_NONE */ + { + mbedtls_mps_retransmission_handle *handle; + unsigned char *queue; + size_t queue_len; + uint8_t write_mode; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No handshake message paused - start a new one." ); + + /* No handshake message is paused -- start a new one. + * + * This differs considerably depending on whether retransmission of + * the new handshake message shall happen on the basis of a raw + * backup or on the basis of a retransmission callback: + * + * - Retransmission via raw backup + * If we have to backup the entire handshake message anyhow, + * we should have it written to its target backup buffer first, + * and only afterwards dispatch that buffer through potentially + * fragmented handhake messages. This is realized here by + * feeding an empty buffer to the message writer passed to the + * user and by registering the message backup buffer as the queue + * for that writer. This way, the user directly writes into the + * backup buffer, and once it's done, actual dispatching is done + * by repeatedly requesting handshake fragments from Layer 3 and + * feed()-ing their contents to the writer until the entire + * queue has been dispatched. + * + * - Retransmission via callback + * If we don't need to backup the message, we follow the same + * strategy as in the rest of MPS of trying to directly perform + * the write on the target record buffer to avoid unnecessary + * allocation and copying. This is done by requesting a new + * handshake fragment from Layer 3 and registering its content + * buffer with the handshake writer passed to the user, alongside + * a queue buffer of size configurable by the user. When the + * user subsequently provides the message contents, it first + * writes into the record buffer and then into the queue + * (if present). + */ + + /* Request to add a new message to the current outgoing flight + * and setup the handle controlling potential retransmissions. */ + + /* This allocates a fresh retransmission handle and sets the + * sequence number for the next outgoing handshake message. */ + MPS_CHK( mps_out_flight_msg_start( mps, &handle ) ); + + /* Remember the handshake message metadata. + * Note that the handshake sequence number has already + * been set through mps_out_flight_msg_start(). */ + handle->metadata.epoch = mps->out_epoch; + handle->metadata.type = hs_new->type; + /* Note: We do support unknown lengths here. In this case, + * we set the actual length later. */ + handle->metadata.len = hs_new->length; + + /* Distinguish between retransmission via raw backup vs. callback. */ + if( cb == NULL ) + { + /* Retransmission via raw backup. */ + size_t backup_len; + unsigned char *backup_buf; + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via raw backup" ); + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW; + + /* Allocate backup buffer to write message to. */ + + if( handle->metadata.len != MBEDTLS_MPS_SIZE_UNKNOWN ) + backup_len = handle->metadata.len; + else + backup_len = MBEDTLS_MPS_MAX_HS_LENGTH; + MBEDTLS_MPS_ASSERT( backup_len <= MBEDTLS_MPS_MAX_HS_LENGTH, + "Bad handshake length" ); + + /* TODO: Switch to allocator interface. */ + backup_buf = mbedtls_calloc( 1, backup_len ); + if( backup_buf == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "Error allocating backup buffer" ); + MPS_CHK( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + } + handle->handle.raw.buf = backup_buf; + handle->handle.raw.len = backup_len; + + write_mode = MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY; + queue = backup_buf; + queue_len = backup_len; + } + else + { + /* Retransmission via callback. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via callback" ); + handle->handle_type = + MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK; + + /* For now, demand that the total length is known. */ + if( handle->metadata.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Retransmission via callback requires known length" ); + MPS_CHK( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); + } + + handle->handle.callback.cb = cb; + handle->handle.callback.ctx = cb_ctx; + + write_mode = MPS_DTLS_FRAG_OUT_START_USE_L3; + queue = hs->queue; + queue_len = hs->queue_len; + } + + /* Setup the structure representing the new handshake message. + * This does not interface with Layer 3. Every error is fatal. */ + MPS_CHK( mps_dtls_frag_out_start( hs, queue, queue_len, + &handle->metadata, write_mode ) ); + /* This can interface with L3 and return WANT_WRITE. */ + MPS_CHK( mps_dtls_frag_out_unpause( mps, MPS_PAUSED_HS_ALLOWED ) ); + } + + /* Add the sequence number to the handshake handle, exposed + * opaquely only to allow it to enter checksum computations. */ + MPS_WRITE_UINT16_BE( &hs->metadata->seq_nr, hs_new->add ); + hs_new->addlen = sizeof( uint16_t ); + hs_new->handle = &hs->wr; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + mps->out.state = MBEDTLS_MPS_MSG_HS; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_application( mbedtls_mps *mps, + mbedtls_writer **app ) +{ + int ret; + mps_l3_app_out out_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_application" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + out_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_app( l3, &out_l3 ) ); + + *app = out_l3.wr; + mps->out.state = MBEDTLS_MPS_MSG_APP; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ) +{ + int ret; + mps_l3_alert_out alert_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_alert" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + alert_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_alert( l3, &alert_l3 ) ); + + *alert_l3.level = MBEDTLS_MPS_ALERT_LEVEL_WARNING; + *alert_l3.type = alert_type; + + mps->out.state = MBEDTLS_MPS_MSG_ALERT; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_ccs( mbedtls_mps *mps ) +{ + int ret; + mps_l3_ccs_out ccs_l3; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + ((void) mode); + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_ccs" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + ccs_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_ccs( l3, &ccs_l3 ) ); + + /* In case of DTLS, add CCS to flight for potential retransmission. */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + mbedtls_mps_retransmission_handle *handle; + + MPS_CHK( mps_out_flight_msg_start( mps, &handle ) ); + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS; + handle->metadata.epoch = mps->out_epoch; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_CCS; + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_pause( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_pause" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MPS_CHK( mps_l3_pause_handshake( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + MBEDTLS_MPS_ASSERT( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_ACTIVE, + "Corrupted HS state" ); + + /* Dispatch the current fragment. */ + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_PAUSED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_dispatch( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_dispatch" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + uint8_t flags; + + if( mps->out.state == MBEDTLS_MPS_MSG_NONE ) + { + MBEDTLS_MPS_TRACE_ERROR( "No message open" ); + MPS_CHK( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + if( mps->out.state != MBEDTLS_MPS_MSG_HS ) + { + /* Everything apart from handshake messages + * is just forwarded to Layer 3. */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + } + else + { + /* Handshake message */ + + MBEDTLS_MPS_ASSERT( + mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_ACTIVE, + "Unexpected handshake state" ); + + /* Wrapup and dispatch the message. */ + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + /* Update outgoing flight state. */ + MPS_CHK( mps_out_flight_msg_done( mps ) ); + } + + /* Update retransmission state machine. */ + flags = mps->dtls.io.out.flags & MBEDTLS_MPS_FLIGHT_MASK; + if( flags == MBEDTLS_MPS_FLIGHT_END || + flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + mps->dtls.wait.retransmit_timeout = + mbedtls_mps_conf_get_hs_timeout_min( &mps->conf ); + + if( flags == MBEDTLS_MPS_FLIGHT_END ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Message finishes the flight, move from SEND to AWAIT." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_AWAIT ) ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Message finishes exchange, move from SEND to FINALIZE." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_FINALIZE ) ); + } + + MPS_CHK( mps_retransmission_timer_update( mps ) ); + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_flush( mbedtls_mps *mps ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_flush" ); + + mps->out.flush = 1; + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_ALLOWED ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ) +{ + ((void) mps); + ((void) flags); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +int mbedtls_mps_force_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ) +{ + ((void) mps); + ((void) seq); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +/* + * MPS security parameter configuration + */ + +int mbedtls_mps_add_key_material( mbedtls_mps *mps, + mbedtls_mps_transform_t *params, + mbedtls_mps_epoch_id *id ) +{ + int ret; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_add_key_material" ); + MPS_CHK( mps_l3_epoch_add( l3, params, id ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_set_incoming_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ) +{ + int ret = 0; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_set_incoming_keys, epoch %d", (int) id ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_NONE, + "Refuse to change incoming keys while reading a message." ); + + if( mps->in_epoch == id ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u already the incoming epoch", (unsigned) id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Clear 'active epoch' usage for old epoch and set it for new. */ + if( mps->in_epoch != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, mps->in_epoch, + MPS_EPOCH_USAGE_READ( MPS_READ_ACTIVE ), 0 ) ); + } + + if( id != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, id, 0, + MPS_EPOCH_USAGE_READ( MPS_READ_ACTIVE ) ) ); + } + + mps->in_epoch = id; + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_set_outgoing_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ) +{ + int ret = 0; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_set_outgoing_keys, epoch %d", (int) id ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_NONE, + "Refuse to change outgoing keys while writing a message." ); + + if( mps->out_epoch == id ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u is already the incoming epoch", (unsigned) id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Clear 'active epoch' usage for old epoch and set it for new. */ + if( mps->out_epoch != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, mps->out_epoch, + MPS_EPOCH_USAGE_WRITE( MPS_WRITE_ACTIVE ), 0 ) ); + } + + if( id != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, id, 0, + MPS_EPOCH_USAGE_WRITE( MPS_WRITE_ACTIVE ) ) ); + } + + mps->out_epoch = id; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +mbedtls_mps_connection_state_t mbedtls_mps_connection_state( + mbedtls_mps const *mps, + mbedtls_mps_blocking_reason_t *blocking_reason, + mbedtls_mps_blocking_info_t *blocking_info ) +{ + if( mps->state == MBEDTLS_MPS_STATE_BLOCKED ) + { + if( blocking_reason != NULL ) + { + *blocking_reason = mps->blocking_reason; + if( blocking_info != NULL ) + *blocking_info = mps->blocking_info; + } + } + + return( mps->state ); +} + +/* + * + * DTLS specific functions + * + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_increase_timeout( mbedtls_mps *mps ) +{ + uint32_t new_timeout, cur_timeout, max_timeout; + uint8_t overflow; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_timer_increase_timeout" ); + + cur_timeout = mps->dtls.wait.retransmit_timeout; + + max_timeout = mbedtls_mps_conf_get_hs_timeout_max( &mps->conf ); + if( cur_timeout >= max_timeout ) + MBEDTLS_MPS_TRACE_RETURN( 0 /* -1 */ ); + + new_timeout = 2 * cur_timeout; + + /* Avoid arithmetic overflow and range overflow */ + overflow = ( new_timeout < cur_timeout ); + if( overflow || new_timeout > max_timeout ) + new_timeout = max_timeout; + + mps->dtls.wait.retransmit_timeout = new_timeout; + MBEDTLS_MPS_TRACE_COMMENT( "Update timeout value to %u milliseonds", + (unsigned) new_timeout ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_update( mbedtls_mps *mps ) +{ + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_set_timer_t * const set_timer = mps->conf.f_set_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_update" ); + + if( set_timer == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No timer configured" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + set_timer( timer_ctx, mps->dtls.wait.retransmit_timeout / 4, + mps->dtls.wait.retransmit_timeout ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_stop( mbedtls_mps *mps ) +{ + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_set_timer_t * const set_timer = mps->conf.f_set_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_stop" ); + + if( set_timer == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No timer configured" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + set_timer( timer_ctx, 0, 0 ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_check( mbedtls_mps *mps ) +{ + int ret = 0; + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_get_timer_t * const get_timer = mps->conf.f_get_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_check" ); + + if( get_timer != NULL && get_timer( timer_ctx ) == 2 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission timer fired" ); + mps_retransmission_timer_stop( mps ); + + /* The retransmission timer is used in various states of the + * flight exchange; check the state and take appropriate action. */ + + switch( mps_get_hs_state( mps ) ) + { + /* When waiting for the first message of the next flight + * from the peer, resend the last outgoing flight. */ + case MBEDTLS_MPS_FLIGHT_AWAIT: + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Trigger retransmission of last outgoing flight." ); + MPS_CHK( mps_trigger_retransmission( mps ) ); + break; + + /* If we have already received some parts of the next + * flight from the peer, send a retransmission request. */ + case MBEDTLS_MPS_FLIGHT_RECEIVE: + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Trigger sending retransmission request to peer." ); + MPS_CHK( mps_trigger_retransmission_request( mps ) ); + break; + + /* After completing the handshake with our last outgoing flight + * we keep backup of the latter for some period of time, in case + * the peer doesn't fully receive it. Once that period has passed + * and the timer fires, wrapup the handshake. */ + case MBEDTLS_MPS_FLIGHT_FINALIZE: + /* TODO: Extract to function, share code + * with mbedtls_mps_write_handshake(). */ + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, MBEDTLS_MPS_FLIGHT_DONE ) ); + break; + + default: + break; + } + } + +exit: + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission( mbedtls_mps *mps ) +{ + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_RESEND; + mps->dtls.wait.resend_offset = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission_request( mbedtls_mps *mps ) +{ + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_RESEND; + mps->dtls.wait.resend_offset = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_handle_pending_retransmit( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_retransmit_state_t state = mps->dtls.retransmit_state; + + if( state == MBEDTLS_MPS_RETRANSMIT_NONE ) + return( 0 ); + + MBEDTLS_MPS_ASSERT( state == MBEDTLS_MPS_RETRANSMIT_RESEND || + state == MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND, + "Bad retransmission state" ); + + if( state == MBEDTLS_MPS_RETRANSMIT_RESEND ) + ret = mps_retransmit_out( mps ); + else /* state == MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND */ + ret = mps_request_resend( mps ); + + MPS_CHK( ret ); + + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_NONE; + MPS_CHK( mps_retransmission_timer_increase_timeout( mps ) ); + MPS_CHK( mps_retransmission_timer_update( mps ) ); + +exit: + return( ret ); +} + +/* + * Incoming flight retransmission detection + */ + +MBEDTLS_MPS_STATIC int mps_recognition_info_match( + mbedtls_mps_recognition_info *info, mps_l3_handshake_in *hs_in ) +{ + if( info->epoch == hs_in->epoch && + info->seq_nr == hs_in->seq_nr ) + { + return( 0 ); + } + return( -1 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_check( mbedtls_mps *mps, + mps_l3_handshake_in *hs ) +{ + uint8_t flight_len, msg_idx; + uint8_t match_idx, match_status; + + mbedtls_mps_recognition_info *info; + uint8_t *status; + + int ret; + + /* + * Please consult the documentation of + * ::mbedtls_mps::dtls::retransmission_detection + * for more information on the retransmission detection + * strategy applied here. + */ + + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_check" ); + MBEDTLS_MPS_TRACE_COMMENT( "Seq Nr: %u", (unsigned) hs->seq_nr ); + MBEDTLS_MPS_TRACE_COMMENT( "Type: %u", (unsigned) hs->type ); + MBEDTLS_MPS_TRACE_COMMENT( "Length: %u", (unsigned) hs->len ); + + /* We only consider handshake fragments with offset 0. */ + if( hs->frag_offset != 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + flight_len = mps->dtls.retransmission_detection.flight_len; + info = &mps->dtls.retransmission_detection.msgs[0]; + match_idx = 0xff; + for( msg_idx=0; msg_idx < flight_len; msg_idx++, info++ ) + { + if( mps_recognition_info_match( info, hs ) == 0 ) + { + match_idx = msg_idx; + break; + } + } + + if( match_idx == 0xff ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission of %u-th message detected", + (unsigned) match_idx ); + + status = &mps->dtls.retransmission_detection.msg_state[match_idx]; + match_status = *status; + if( match_status == MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED ) + { + /* Observed a retransmission - move all messages to 'on hold' + * state to omit triggering multiple retransmissions from a + * single retransmission of the peer. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission active for message" + " - retransmit and put all other messages on hold." ); + + status = &mps->dtls.retransmission_detection.msg_state[0]; + for( msg_idx=0; msg_idx < flight_len; msg_idx++, status++ ) + *status = MBEDTLS_MPS_RETRANSMISSION_DETECTION_ON_HOLD; + + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ); + } + else + { + /* Re-activate retransmission detection for message. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission currently put on hold " + "for this messsage - reactivate." ); + *status = MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_remember( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs_in, + uint8_t seq_nr ) +{ + int ret = 0; + size_t msg_idx; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mbedtls_mps_recognition_info *next_info; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_remember" ); + + /* Currently, we are basing retransmission detection + * on epoch and sequence number only. */ + ((void) hs_in); + + msg_idx = mps->dtls.retransmission_detection.flight_len; + if( msg_idx == MBEDTLS_MPS_MAX_FLIGHT_LENGTH ) + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ); + + next_info = &mps->dtls.retransmission_detection.msgs[ msg_idx ]; + + next_info->epoch = mps->in_epoch; + next_info->seq_nr = seq_nr; + + mps->dtls.retransmission_detection.msg_state[msg_idx] = + MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED; + + mps->dtls.retransmission_detection.flight_len++; + + /* Keep an epoch as long as we might still receive + * retransmissions using that epoch. */ + MPS_CHK( mps_l3_epoch_usage( l3, mps->in_epoch, 0, + MPS_EPOCH_USAGE_READ( + MPS_READ_RETRANSMISSION_DETECTION ) ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_init( mbedtls_mps *mps ) +{ + mps->dtls.retransmission_detection.flight_len = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_free( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t flight_len, msg_idx; + mbedtls_mps_recognition_info *info; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_free" ); + + flight_len = mps->dtls.retransmission_detection.flight_len; + info = &mps->dtls.retransmission_detection.msgs[0]; + + MBEDTLS_MPS_TRACE_COMMENT( "Flight length: %u", (unsigned) flight_len ); + for( msg_idx=0; msg_idx < flight_len; msg_idx++, info++ ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Epoch %u no longer needed for retransmission detection", + (unsigned) info->epoch ); + + MPS_CHK( mps_l3_epoch_usage( l3, info->epoch, + MPS_EPOCH_USAGE_READ( + MPS_READ_RETRANSMISSION_DETECTION ), + 0 ) ); + } + + mps->dtls.retransmission_detection.flight_len = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_forget( mbedtls_mps *mps ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_forget" ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Implementation of reassembly submodule. + */ + +/* + * Mark bits in bitmask (used for DTLS HS reassembly) + */ +MBEDTLS_MPS_STATIC void mps_bitmask_set( unsigned char *mask, size_t first_bit, + size_t bitlen ) +{ + /* Set one bit a time and (tail-)recurse. This is not efficient, + * but short, and this part of the code isn't time critical. */ + size_t first_byte = first_bit >> 3; + size_t byte_frac = first_bit & 0x7; + + if( bitlen-- == 0 ) + return; + + mask += first_byte; + *mask &= ~( 1u << byte_frac ); + + mps_bitmask_set( mask, byte_frac + 1, bitlen ); +} + +/* + * Check that bitmask is full + */ +MBEDTLS_MPS_STATIC int mps_bitmask_check( unsigned char *mask, size_t len ) +{ + /* This function assumes that `mask` points to a bitmask of length + * `len / 8 + 1` Bytes, even if `len % 8 == 0`. */ + size_t byte_len = len / 8 + 1; + while( byte_len != 0 ) + { + uint8_t const cur_byte = *mask; + if( cur_byte != 0x0 ) + return( -1 ); + byte_len--; + mask++; + } + + return( 0 ); +} + +#define L4_DEBUG_DTLS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "DTLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Seq nr: %u", (unsigned) (hdr)->seq_nr ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Offset: %u", (unsigned) (hdr)->frag_offset ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Length: %u", (unsigned) (hdr)->frag_len ); \ + } while( 0 ) + +#define MPS_ASSERT_FLIGHT_STATE_2( a, b ) \ + MBEDTLS_MPS_ASSERT( MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), a, b ), \ + "Unexpected flight state" ) + +MBEDTLS_MPS_STATIC int mps_reassembly_feed( mbedtls_mps *mps, + mps_l3_handshake_in *hs ) +{ + int ret = 0; + uint8_t seq_nr, seq_nr_offset; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_feed" ); + MBEDTLS_MPS_TRACE_COMMENT( "Next seq nr: %u", (unsigned) mps->dtls.seq_nr ); + L4_DEBUG_DTLS_HEADER(hs); + + seq_nr = hs->seq_nr; + seq_nr_offset = seq_nr - mps->dtls.seq_nr; + + /* Check if the sequence number belongs to the window of messages that we're + * currently buffering - in particular, if buffering is disabled, check if + * the fragment belongs to the next handshake message. */ + if( seq_nr < mps->dtls.seq_nr || + seq_nr_offset >= 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ) + { + unsigned char *tmp; + + MBEDTLS_MPS_TRACE_ERROR( "Sequence number %u outside current window [%u,%u]", + (unsigned) seq_nr, (unsigned) mps->dtls.seq_nr, + (unsigned) ( mps->dtls.seq_nr + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ) ); + + /* Layer 3 will error out if we don't fully consume a fragment, + * so fetch and commit it even if we don't consider the contents. */ + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + MPS_CHK( mbedtls_mps_reader_get( hs->rd, hs->frag_len, + &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs->rd ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + /* Check if the message has already been initialized. */ + reassembly = &in->reassembly[ seq_nr_offset ]; + + MBEDTLS_MPS_ASSERT( reassembly->status != MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION, + "Invalid call to mps_reassembly_feed()" ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_NONE ) + { + uint8_t complete_msg; + + /* Sequence number not seen before. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Sequence number %u not seen before - setup reassembly structure.", + (unsigned) seq_nr ); + + reassembly->epoch = hs->epoch; + reassembly->length = hs->len; + reassembly->type = hs->type; + + /* If we receive the next expected HS message in a single fragment, bypass + * reassembly and forward reader from Layer 3. */ + complete_msg = ( hs->frag_offset == 0 ) && ( hs->frag_len == hs->len ); + if( seq_nr_offset == 0 && complete_msg ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Received next handshake message in single fragment." ); + reassembly->status = MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION; + reassembly->data.rd_l3 = hs->rd; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else + { + size_t bitmask_len, msg_len; + unsigned char *bitmask; + unsigned char *buf; + MBEDTLS_MPS_TRACE_COMMENT( "Feed handshake message into reassembler." ); + + /* TODO: If we have received a full fragment, we don't need to + * allocate the bitmask here. */ + + /* For proper fragments of the next expected message, + * or for any fragments (even full ones) belonging + * to future messages, use a reassembly window. */ + + msg_len = hs->len; + /* Slightly overapproximate the size of the bitmask, at the + * benefit of simplifying the call to mps_bitmask_set() below + * as well as the implementation of mps_bitmask_check(). */ + bitmask_len = msg_len / 8 + 2; + buf = mbedtls_calloc( 1, msg_len + bitmask_len ); + bitmask = buf + msg_len; + + if( buf == NULL ) + MPS_CHK( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + + memset( bitmask, 0xFF, bitmask_len ); + mps_bitmask_set( bitmask, msg_len, 8 ); + + reassembly->data.window.bitmask = bitmask; + reassembly->data.window.buf_len = msg_len; + reassembly->data.window.buf = buf; + + reassembly->status = MBEDTLS_MPS_REASSEMBLY_WINDOW; + } + } + else + { + /* Check consistency of parameters across fragments. */ + if( hs->epoch != reassembly->epoch || + hs->type != reassembly->type || + hs->len != reassembly->length ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Inconsistent parameters (%u,%u,%u) != (%u,%u,%u) " + "for fragments of HS msg of sequence number %u", + (unsigned) hs->epoch, (unsigned) hs->type, + (unsigned) hs->len, (unsigned) reassembly->epoch, + (unsigned) reassembly->type, (unsigned) reassembly->length, + (unsigned) seq_nr ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + } + + /* We don't have to check frag_offset and frag_len, + * as this is already done by Layer 3. */ + + /* No `else` because we want to fall through in case the + * initial status was #MPS_REASSEMBLY_NONE. */ + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW ) + { + unsigned char* bitmask = reassembly->data.window.bitmask; + unsigned char *frag_content; + MBEDTLS_MPS_TRACE_COMMENT( "Contribute to ongoing reassembly." ); + + MPS_CHK( mbedtls_mps_reader_get( hs->rd, hs->frag_len, + &frag_content, NULL ) ); + memcpy( reassembly->data.window.buf + hs->frag_offset, + frag_content, hs->frag_len ); + MPS_CHK( mbedtls_mps_reader_commit( hs->rd ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + + if( bitmask != NULL ) + { + /* Add the fragment to the current reassembly window. */ + mps_bitmask_set( bitmask, hs->frag_offset, hs->frag_len ); + + /* Check if message is complete now. */ + if( mps_bitmask_check( bitmask, hs->len ) == 0 ) + { + /* Free bitmask to indicate that the message is complete. */ + MBEDTLS_MPS_TRACE_COMMENT( "Message fully reassembled." ); + reassembly->data.window.bitmask = NULL; + MPS_CHK( mps_reassembly_next_msg_complete( mps ) ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Reassembly incomplete -- need more fragments." ); + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + } + + if( seq_nr_offset != 0 ) + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_free( mbedtls_mps *mps ) +{ + uint8_t idx; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_free" ); + + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + { + mbedtls_mps_msg_reassembly *cur = + &mps->dtls.io.in.incoming.reassembly[idx]; + switch( cur->status ) + { + case MBEDTLS_MPS_REASSEMBLY_WINDOW: + mbedtls_free( cur->data.window.buf ); + break; + default: + break; + } + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_reassembly_init( mbedtls_mps *mps ) +{ + uint8_t idx; + for( idx = 0; idx < 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + { + mps->dtls.io.in.incoming.reassembly[idx].status = + MBEDTLS_MPS_REASSEMBLY_NONE; + } + + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_reassembly_get_seq( mbedtls_mps *mps, + uint8_t *seq_nr ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_get_seq" ); + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, + MBEDTLS_MPS_FLIGHT_RECEIVE ); + + *seq_nr = mps->dtls.seq_nr; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_check_and_load( mbedtls_mps *mps ) +{ + mbedtls_mps_reassembly const * in; + mbedtls_mps_msg_reassembly const * reassembly; + int next_message_complete = 0; + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_check_and_load" ); + + if( ! MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ) + { + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + in = &mps->dtls.io.in.incoming; + reassembly = &in->reassembly[0]; + + switch( reassembly->status ) + { + case MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION: + next_message_complete = 1; + break; + + case MBEDTLS_MPS_REASSEMBLY_WINDOW: + if( reassembly->data.window.bitmask == NULL ) + next_message_complete = 1; + } + + if( next_message_complete == 0 ) + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + + /* Check that message's epoch matches the current incoming epoch. */ + if( reassembly->epoch != mps->in_epoch ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reassembled message isn't protected through current incoming epoch." ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + mps->in.state = MBEDTLS_MPS_MSG_HS; + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_read( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs ) +{ + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly = &in->reassembly[0]; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_read" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + hs->length = reassembly->length; + hs->type = reassembly->type; + MBEDTLS_MPS_TRACE_COMMENT( "Length: %u", (unsigned) hs->length ); + MBEDTLS_MPS_TRACE_COMMENT( "Type: %u", (unsigned) hs->type ); + + /* TODO: Add additional data (sequence number). */ + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Handshake message received as single fragment " + "on Layer 3 - pass on to user." ); + /* The message has been received in a single fragment + * from Layer 3, and we can pass that on to the user. */ + hs->handle = reassembly->data.rd_l3; + } + else if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW && + reassembly->data.window.bitmask == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Fully reassembled handshake messaged" ); + hs->handle = &in->rd; + } + else + { + MBEDTLS_MPS_ASSERT( 0, "Invalid call to mps_reassembly_read()" ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_done( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t idx; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly = &in->reassembly[0]; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_done" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW ) + { + mbedtls_free( reassembly->data.window.buf ); + /* The bitmask is freed as soon as the fragmentation completes. */ + mbedtls_mps_reader_free( &in->rd ); + } + else + { + MPS_CHK( mps_l3_read_consume( l3 ) ); + } + + /* Shift array of reassembly structures. */ + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + in->reassembly[idx] = in->reassembly[idx + 1]; + + reassembly = &in->reassembly[ MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ]; + reassembly->status = MBEDTLS_MPS_REASSEMBLY_NONE; + + if( mps->dtls.seq_nr == MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reached maximum incoming sequence number %u", + (unsigned) MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ); + MPS_CHK( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + } + mps->dtls.seq_nr++; + + MPS_CHK( mps_reassembly_next_msg_complete( mps ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_next_msg_complete( mbedtls_mps *mps ) +{ + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * const reassembly = &in->reassembly[0]; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_next_msg_complete" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW && + reassembly->data.window.bitmask == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Next message already fully available." ); + mbedtls_mps_reader_init( &in->rd, NULL, 0 ); + MPS_CHK( mbedtls_mps_reader_feed( &in->rd, + reassembly->data.window.buf, + reassembly->data.window.buf_len ) ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Next message not yet available." ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_pause( mbedtls_mps *mps ) +{ + int ret = 0; + ((void) mps); + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_pause" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + ret = MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_forget( mbedtls_mps *mps ) +{ + uint8_t idx; + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_forget" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + /* Check that there are no more buffered messages. + * This catches the situation where the peer sends + * more messages than expected. */ +#if MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS > 0 + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + MBEDTLS_MPS_ASSERT( in->reassembly[idx].status == MBEDTLS_MPS_REASSEMBLY_NONE, "" ); +#else + ((void) idx); + ((void) in); + MPS_CHK( 0 ); +#endif + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Outgoing flight retransmission + */ + +MBEDTLS_MPS_STATIC int mps_retransmit_out( mbedtls_mps *mps ) +{ + return( mps_retransmit_out_core( mps, MPS_RETRANSMIT_FULL_FLIGHT ) ); +} + +MBEDTLS_MPS_ALWAYS_INLINE int mps_out_flight_get_retransmission_handle( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **hdl, size_t offset ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_get_transmission_handle, index %u", + (unsigned) offset ); + + MBEDTLS_MPS_ASSERT_RAW( offset < MBEDTLS_MPS_MAX_FLIGHT_LENGTH, + "Invalid retransmission handle index" ); + + *hdl = &mps->dtls.outgoing.backup[ offset ]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_out_core( mbedtls_mps *mps, + uint8_t mode ) +{ + int ret = 0; + uint8_t offset; + mbedtls_mps_retransmission_handle *handle; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_out" ); + + if( mps->dtls.wait.resend_offset == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Start retransmission of last outgoing flight of length %u", + (unsigned) mps->dtls.outgoing.flight_len ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Continue retransmission of last outgoing flight " + "of length %u at message %u.", + (unsigned) mps->dtls.outgoing.flight_len, + (unsigned) mps->dtls.wait.resend_offset ); + } + + offset = mps->dtls.wait.resend_offset; + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &handle, offset ) ); + + while( offset < mps->dtls.outgoing.flight_len ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Retransmitting message %u of last outgoing flight.", + (unsigned) offset ); + + MBEDTLS_MPS_ASSERT( mode == MPS_RETRANSMIT_FULL_FLIGHT || + mode == MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS, + "Invalid flight retransmission mode" ); + + if( mode == MPS_RETRANSMIT_FULL_FLIGHT ) + { + ret = mbedtls_mps_retransmission_handle_resend( mps, handle ); + if( ret != MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED ) + MPS_CHK( ret ); + } + else /* mode == MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS */ + { + ret = mbedtls_mps_retransmission_handle_resend_empty( mps, handle ); + MPS_CHK( ret ); + } + + if( ret == 0 ) + { + /* TODO: Ensure and document some progress guarantee here + * to exclude the possibility of infinite looping! */ + offset++; + handle++; + } + } + + MPS_CHK( mbedtls_mps_flush( mps ) ); + +exit: + mps->dtls.wait.resend_offset = offset; + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/* + * Incoming flight retransmission request + * + * (In DTLS 1.0 and 1.2, this is done by resending the last + * outgoing flight; in DTLS 1.3, it's done using ACK's.) + */ + +MBEDTLS_MPS_STATIC int mps_request_resend( mbedtls_mps *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_request_send" ); + /* TLS-1.3-NOTE: This needs to be handled through ACK's + * in DTLS 1.3. */ + MBEDTLS_MPS_TRACE_RETURN( mps_retransmit_out_core( mps, + MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS ) ); +} + +static inline const char * mps_flight_state_to_string( + mbedtls_mps_flight_state_t state ) +{ + switch( state ) + { + case MBEDTLS_MPS_FLIGHT_AWAIT: + return( "AWAIT" ); + case MBEDTLS_MPS_FLIGHT_SEND: + return( "SEND" ); + case MBEDTLS_MPS_FLIGHT_RECVINIT: + return( "RECVINIT" ); + case MBEDTLS_MPS_FLIGHT_RECEIVE: + return( "RECEIVE" ); + case MBEDTLS_MPS_FLIGHT_FINALIZE: + return( "FINALIZE" ); + case MBEDTLS_MPS_FLIGHT_PREPARE: + return( "PREPARE" ); + case MBEDTLS_MPS_FLIGHT_DONE: + return( "DONE" ); + default: + return( "UNKNOWN" ); + } +} + +MBEDTLS_MPS_INLINE +/* Perform a retransmisison state machine transition and + * all necessary initialization/freeing of internal structures. + * + * The `old` state parameter indicates the expected current state + * of the state machine and is hence redundant in ordinary runs; + * it is passed solely as a safeguard. + */ +int mps_handshake_state_transition( mbedtls_mps *mps, + mbedtls_mps_flight_state_t old, + mbedtls_mps_flight_state_t new ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_handshake_state_transition, old %u (%s), new %u (%s)", + (unsigned) old, mps_flight_state_to_string( old ), + (unsigned) new, mps_flight_state_to_string( new ) ); + + MBEDTLS_MPS_ASSERT( mps_get_hs_state( mps ) == old, + "Mismatch between expected and actual flight state" ); + + if( old == MBEDTLS_MPS_FLIGHT_AWAIT && + new == MBEDTLS_MPS_FLIGHT_RECEIVE ) + { + /* The first message not recognized as a retransmission implicitly + * acknowledges the last outgoing flight. We may therefore forget + * about the last incoming flight and make space for the new one. */ + MPS_CHK( mps_retransmit_in_forget( mps ) ); + + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_DONE && + new == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_DONE && + new == MBEDTLS_MPS_FLIGHT_SEND ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_FINALIZE && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + mps_retransmission_timer_stop( mps ); + MPS_CHK( mps_out_flight_free( mps ) ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECVINIT && + new == MBEDTLS_MPS_FLIGHT_RECEIVE ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + mps->dtls.wait.retransmit_timeout = + mbedtls_mps_conf_get_hs_timeout_min( &mps->conf ); + MPS_CHK( mps_retransmission_timer_update( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECVINIT && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + /* Clear the reassembly module; this fails if we attempt + * to close a flight if there are still some future messages + * buffered; this could happen e.g. if a Client sends its + * ClientKeyExchange immediately after the ClientHello, + * not waiting until it has received the ServerHello, + * and the server receives and buffer the ClientKeyExchange + * before the ClientHello. + * + * TODO: Does this endanger compatibility? */ + MPS_CHK( mps_reassembly_forget( mps ) ); + + /* It is possible that we have already received some handshake + * message fragments from the peer -- delete these. See the + * documentation of mbedtls_mps_retransmission_handle_incoming_fragment() + * for more information on this choice of behavior. */ + MPS_CHK( mps_reassembly_free( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECEIVE && + new == MBEDTLS_MPS_FLIGHT_PREPARE ) + { + /* Clear memory of last outgoing flight. + * NOTE: Logically, we should remove this when switching from state + * #MBEDTLS_MPS_FLIGHT_AWAIT to #MBEDTLS_MPS_FLIGHT_RECEIVE; + * see the corresponding comments in + * \c mbedtls_mps_retransmission_handle_incoming_fragment() + * for more. */ + MPS_CHK( mps_out_flight_free( mps ) ); + + /* As for RECVINIT -> DONE */ + MPS_CHK( mps_reassembly_forget( mps ) ); + MPS_CHK( mps_reassembly_free( mps ) ); + + /* Keep memory of last incoming flight intact. */ + } + else + if( old == MBEDTLS_MPS_FLIGHT_PREPARE && + new == MBEDTLS_MPS_FLIGHT_SEND ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECEIVE && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + MPS_CHK( mps_out_flight_free( mps ) ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + MPS_CHK( mps_reassembly_free( mps ) ); + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_SEND && + new == MBEDTLS_MPS_FLIGHT_AWAIT ) + { + } + else + if( old == MBEDTLS_MPS_FLIGHT_SEND && + new == MBEDTLS_MPS_FLIGHT_FINALIZE ) + { + } + else + { + MBEDTLS_MPS_ASSERT( 0, "Unknown state transition" ); + } + + mps->dtls.state = new; + + MBEDTLS_MPS_TRACE_COMMENT( "State transition from %u to %u done.", + (unsigned) old, (unsigned) new ); + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Main interface to the reading side of the retransmission state machine. + */ + +MBEDTLS_MPS_STATIC +int mbedtls_mps_retransmission_handle_incoming_fragment( mbedtls_mps *mps ) +{ + int ret = 0; + + /* TODO: This zero-initialization should not be necessary, but + * some compilers complain if it's omitted, for the following reason: + * At the moment, each layer has its own configuration, and in particular + * its own `mode` identifier, and if L4 and L3 mode get out of sync, + * we'd use parts of `hs_l3` uninitialized below. */ + /* Use per-field initialization to silence annoying compiler warning + * when using the _compliant_ `struct foo bar = { 0 }` zero-initialization... */ + mps_l3_handshake_in hs_l3 = { .epoch = 0, .type = 0, .len = 0, + .frag_len = 0, .frag_offset = 0, .seq_nr = 0, + .rd = NULL }; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_incoming_fragment" ); + + /* + * When we reach this code-path, the flight state is either + * #MBEDTLS_MPS_FLIGHT_RECEIVE, #MBEDTLS_MPS_FLIGHT_FINALIZE + * #MBEDTLS_MPS_FLIGHT_DONE. We comment on them separately: + * - #MBEDTLS_MPS_FLIGHT_FINALIZE + * In this case, the incoming fragment might either be a + * retransmission from the last incoming flight, or the + * initiation of a new handshake. It is only after we have + * checked that it is not a retransmission that we may + * wrapup the current handshake and start a new one. + * - #MBEDTLS_MPS_FLIGHT_DONE + * In case an entire, non-fragmented handshake message arrives, + * we pass it to the user and switch to receiving state. + * However, if a fragmented message arrives, it's not + * clear how to behave -- concretely, imagine the following DTLS + * scenario: After the initial handshake has completed, the + * client sends multiple ClientHello fragments to the server in order + * to start a renegotiation, but only some reach the server. + * At the same time, the server attempts to start a renegotiation + * by sending a HelloRequest. There are options to deal with that: + * 1 MPS switches to Receiving state silently as soon as it + * receives the first ClientHello fragment(s). Consequently, + * it blocks the server's attempt to send the HelloRequest + * (sending in Receiving state is not allowed). + * This is not optimal because from the server's perspective + * no handshake is in progress, hence it should be possible to + * start a new one via writing a HelloRequest. + * 2 MPS remembers the ClientHello fragments, but does not yet + * switch to Receive state. When the server attempts to send + * the HelloRequest, all buffered fragments are erased and + * MPS switches to send state as if nothing had been received. + * This is not optimal because it will lead to the client + * receiving a HelloRequest when expecting a ServerHello, + * and also to the dropping of the fragments of the ClientHello + * that have already been received. + * While both alternatives have their drawback, variant 2 + * seems preferable because it introduces no problems that + * were not already there beforehand: It might be that Client + * and Server start renegotiation simultaenously and that the + * ClientHello gets lost entirely, leading to the same situation + * as in variant 2. In contrast, variant 1 adds the undesirable + * possibility of the user's perception of the flight state + * getting out of sync with the actual flight state. + */ + + MBEDTLS_MPS_TRACE_COMMENT( "Fetch new fragment from Layer 3" ); + MPS_CHK( mps_l3_read_handshake( l3, &hs_l3 ) ); + + /* 1. Check if the message is recognized as a retransmission + * from an old flight. */ + + if( MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_FINALIZE ) ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Check if the fragment is a retransmission from old flight." ); + ret = mps_retransmit_in_check( mps, &hs_l3 ); + + if( ret == MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ) + { + mbedtls_mps_reader *hs_rd; + unsigned char *tmp; + + /* Message is a retransmission from the last incoming flight. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Retransmission detected - retransmit last flight." ); + + /* Layer 3 will error out if we don't fully consume a fragment, + * so fetch and commit it even if we don't consider the contents. */ + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + hs_rd = hs_l3.rd; + MPS_CHK( mbedtls_mps_reader_get( hs_rd, hs_l3.frag_len, + &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs_rd ) ); + + /* Mark handshake fragment as processed before starting + * the retransmission, which might return WANT_WRITE. */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + + MPS_CHK( mps_trigger_retransmission( mps ) ); + MPS_CHK( mps_handle_pending_retransmit( mps ) ); + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + else + MPS_CHK( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Frag not recognized as a retransmission." ); + + /* Logically, we should also be able to forget about our last + * outgoing flight, because we know that our peer has already + * fully received it. However, in DTLS 1.0 and 1.2, the only + * way to inform the peer that messages from his next flight + * are missing is by retransmitting our own last outgoing + * flight, so we have to keep that until we switch to state + * #MBEDTLS_MPS_FLIGHT_SEND. + * In DTLS 1.3, we can get rid of the last outgoing flight + * already here, which is allows a considerable saving of RAM. + * + * NOTE: What we could do as a remedy is to retransmit + * empty fragments of the messages of the last + * flight in case we want to request a retransmission + * from the peer. This way, we could free the raw + * backup buffers at this point. + */ + + MBEDTLS_MPS_ASSERT( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_AWAIT || + mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_FINALIZE, + "Unexpected flight state" ); + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_AWAIT ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ); + } + else /* if( mps_get_hs_state( mps ) + == MBEDTLS_MPS_FLIGHT_FINALIZE ) */ + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, MBEDTLS_MPS_FLIGHT_DONE ) ); + } + } + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_DONE ) + { + mbedtls_mps_hs_seq_nr_t seq_nr = hs_l3.seq_nr; + + /* Only start handshakes with initial handshake fragments. + * + * This is a heuristic to deal especially with the following situation: + * If a DTLS server receives a proper fragment of a ClientHello message + * without cookie, which is large enough to determine that there's no + * cookie to follow, then the server might send its HelloVerifyRequest + * straight away and reset in order to avoid allocation of state. + * If subsequent later fragments of the ClientHello are still in flight, + * they might be received by the re-started server earlier than the new + * ClientHello that contains the cookie, and they would therefore + * mistakenly be viewed as initiating a new handshake. In particular, + * they would miscalibrate the server's initial handshake sequence number + * to 0, leading to discarding or indefinite buffering of the new + * ClientHello+Cookie, which will have handshake sequence number 1. + * + * To deal with this situation, we only consider initial fragments + * when starting new handshakes. + * + * NOTE: So far, MPS is _not_ DoS resistant in the face of fragmented + * ClientHello's: If a proper fragment of a ClientHello comes in, + * it be fed into a new reassembly structure as for any other message. + * This needs to be changed at some point. */ + if( hs_l3.frag_offset != 0 ) + { + mbedtls_mps_reader *hs_rd; + unsigned char *tmp; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Discard non-initial fragments outside of handshake." ); + + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + hs_rd = hs_l3.rd; + MPS_CHK( mbedtls_mps_reader_get( hs_rd, hs_l3.frag_len, &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs_rd ) ); + + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + + /* DTLS suffers from the following ambiguity: + * For the purpose of DoS mitigation a server receiving + * a cookieless ClientHello may reply with a HelloVerifyRequest + * including a cookie and wait for the client to + * retransmit the ClientHello+Cookie before allocating any state + * and continuing with the actual handshake. In this scenario, + * the second ClientHello and the ServerHello shall have + * sequence number 1 according to Sect 4.2.2 of RFC 6347. + * This is in conflict with the requirement that the server + * must not maintain state after sending its HelloVerifyRequest, + * as initially both the incoming and outgoing handshake sequence + * numbers are 0. + * + * MPS deals with this ambiguity in the same way as the + * previous messaging layer implementation does, by accepting + * any sequence number for an incoming handshake message initiating + * a handshake, and always using the same sequence number for its reply. + */ + mps->dtls.seq_nr = seq_nr; + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_DONE, MBEDTLS_MPS_FLIGHT_RECVINIT ) ); + } + + /* 2. Feed the handshake fragment into the reassembly module. + * + * TLS-1.3-NOTE: In DTLS-1.3, we have to record the record + * sequence number of the incoming fragment + * somewhere to send ACK messages. + * + * To this end, we need to distinguish between handshake fragments that + * belonged to the incoming flight but did not yet allow to complete + * the next handshake message, and those that were dropped because + * they were irrelevant: The former may be ACK'ed, the latter not. + * + * Also, the reassembly module should indicate 'disruption' in the + * flight receival to allow to decide when to ACK the messages received + * so far -- quoting DTLS 1.3 Draft 28: + * + * > Implementations have some discretion about when to + * > generate ACKs, but it is RECOMMENDED that they do so under two + * > circumstances: + * > - When they receive a message or fragment which is out of order, + * > either because it is not the next expected message or because it + * > is not the next piece of the current message. Implementations + * > MUST NOT send ACKs for handshake messages which they discard as + * > out-of-order, because otherwise those messages will not be + * > retransmitted. + * > - When they have received part of a flight and do not immediately + * > receive the rest of the flight (which may be in the same UDP + * > datagram). A reasonable approach here is to set a timer for 1/4 + * > the current retransmit timer value when the first record in the + * > flight is received and then send an ACK when that timer expires. + * + */ + + MBEDTLS_MPS_TRACE_COMMENT( "Feed fragment into reassembly module." ); + ret = mps_reassembly_feed( mps, &hs_l3 ); + if( ret == MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) + { + /* The current fragment didn't lead to the next handshake + * message being ready. That might be because it contributed + * to a future message, or because the next message isn't + * fully reassembled yet. */ + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + else + MPS_CHK( ret ); + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + uint64_t rec_ctr; + + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ); + + /* TODO: Move this logic to Layer 2 -- mirror the sequence + * number when the first operation is the receipt of an + * incoming record. That avoids the abstraction break + * and saves some code. */ + MPS_CHK( mps_l3_get_last_sequence_number( l3, hs_l3.epoch, + &rec_ctr ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "Mirror rec seq nr %u", (unsigned) rec_ctr ); + MPS_CHK( mps_l3_force_next_sequence_number( l3, hs_l3.epoch, + rec_ctr ) ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmission_finish_incoming_message( mbedtls_mps *mps ) +{ + int ret; + uint8_t flags; + uint8_t seq_nr; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_finish_incoming_message" ); + + /* Remember parts of message to detect retransmission. + * Currently, we're only remembering the epoch and the + * sequence number, so we don't need the actual HS handle + * here. This might change in the future. */ + MPS_CHK( mps_reassembly_get_seq( mps, &seq_nr ) ); + MPS_CHK( mps_retransmit_in_remember( mps, NULL, seq_nr ) ); + + /* Inform the buffering submodule that the newest message has been read. */ + MPS_CHK( mps_reassembly_done( mps ) ); + + /* Update retransmission state machine. */ + flags = mps->in.flags & MBEDTLS_MPS_FLIGHT_MASK; + if( flags == MBEDTLS_MPS_FLIGHT_END || + flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + MPS_CHK( mps_retransmission_timer_stop( mps ) ); + } + + if( flags == MBEDTLS_MPS_FLIGHT_END ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg ends flight. -> PREPARE" ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECEIVE, MBEDTLS_MPS_FLIGHT_PREPARE ) ); + } + else if( flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg ends exchange. -> DONE" ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECEIVE, MBEDTLS_MPS_FLIGHT_DONE ) ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg not last in flight. Keep RECEIVE" ); + } + + mps->in.flags = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmission_pause_incoming_message( mbedtls_mps *mps ) +{ + int ret = 0; + MPS_CHK( mps_reassembly_pause( mps ) ); + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_init( mbedtls_mps *mps ) +{ + mps->dtls.io.out.flags = 0; + mps->dtls.outgoing.flight_len = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_out_flight_free( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t idx, flight_len; + mbedtls_mps_retransmission_handle *handle; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_free" ); + + flight_len = mps->dtls.outgoing.flight_len; + handle = &mps->dtls.outgoing.backup[0]; + MBEDTLS_MPS_TRACE_COMMENT( "Flight length: %u", (unsigned) flight_len ); + + for( idx=0; idx < flight_len; idx++, handle++ ) + { + mbedtls_mps_epoch_id cur_epoch = + handle->metadata.epoch; + + MPS_CHK( mps_l3_epoch_usage( l3, cur_epoch, + MPS_EPOCH_USAGE_WRITE( + MPS_WRITE_RETRANSMISSION ), 0 ) ); + + mbedtls_mps_retransmission_handle_free( handle ); + } + + mps->dtls.outgoing.flight_len = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_init( + mbedtls_mps_retransmission_handle *handle ) +{ + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE; +} + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_free( + mbedtls_mps_retransmission_handle *handle ) +{ + switch( handle->handle_type ) + { + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW: + { + unsigned char *buf; + size_t buflen; + + buf = handle->handle.raw.buf; + buflen = handle->handle.raw.len; + mbedtls_platform_zeroize( buf, buflen ); + + free( buf ); + break; + } + default: + break; + } + + mbedtls_platform_zeroize( handle, sizeof( *handle ) ); +} + +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend_empty( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ) +{ + int ret = 0; + mps_l3_handshake_out hs_out_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_resend_empty" ); + + hs_out_l3.epoch = handle->metadata.epoch; + hs_out_l3.frag_len = 0; + hs_out_l3.frag_offset = 0; + hs_out_l3.len = handle->metadata.len; + hs_out_l3.seq_nr = handle->metadata.seq_nr; + hs_out_l3.type = handle->metadata.type; + MPS_CHK( mps_l3_write_handshake( l3, &hs_out_l3 ) ); + /* Don't write anything. */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend( mbedtls_mps *mps, + mbedtls_mps_retransmission_handle *handle ) +{ + int ret = 0; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_resend" ); + + MBEDTLS_MPS_ASSERT( + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW || + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK || + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS, + "Invalid retransmission handle" ); + + switch( handle->handle_type ) + { + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW: + { + unsigned char * backup_buf = handle->handle.raw.buf; + mbedtls_mps_size_t backup_len = handle->handle.raw.len; + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via raw backup" ); + + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + MPS_CHK( mps_dtls_frag_out_start( hs, backup_buf, backup_len, + &handle->metadata, + MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY ) ); + + MPS_CHK( mbedtls_writer_get( &hs->wr, backup_len, &backup_buf, + NULL ) ); + MPS_CHK( mbedtls_writer_commit( &hs->wr ) ); + + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + break; + } + + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK: + { + int cb_unfinished = 0; + mbedtls_mps_write_cb_t const cb = handle->handle.callback.cb; + mbedtls_mps_write_cb_ctx_t* const ctx = handle->handle.callback.ctx; + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via callback" ); + + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_ALLOWED ) ); + + if( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Open new outgoing handshake message." ); + MPS_CHK( mps_dtls_frag_out_start( hs, + hs->queue, + hs->queue_len, + &handle->metadata, + MPS_DTLS_FRAG_OUT_START_USE_L3 ) ); + + /* We now have a message handle in PAUSED state for the + * handshake message to be retransmitted. We handle this + * situation in the same way as the case where the callback + * has been called at least once but didn't yet finish + * the message. */ + ret = MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED; + break; + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission in progress -- continue." ); + } + + /* Call retransmission callback. */ + ret = cb( ctx, &hs->wr ); + if( ret == MBEDTLS_MPS_RETRANSMISSION_CALLBACK_PAUSE ) + cb_unfinished = 1; + else + MPS_CHK( ret ); + + MPS_CHK( mps_dtls_frag_out_close( mps, cb_unfinished == 1 ? + MBEDTLS_MPS_HS_PAUSED : + MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + if( cb_unfinished == 1 ) + ret = MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED; + + break; + } + + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS: + { + mps_l3_ccs_out ccs_l3; + MBEDTLS_MPS_TRACE_COMMENT( "CCS retransmission" ); + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + ccs_l3.epoch = handle->metadata.epoch; + MPS_CHK( mps_l3_write_ccs( l3, &ccs_l3 ) ); + MPS_CHK( mps_l3_dispatch( l3 ) ); + break; + } + } + + MPS_INTERNAL_FAILURE_HANDLER +} + + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_unpause( mbedtls_mps *mps, + uint8_t allow_active_hs ) +{ + int ret; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_unpause" ); + if( mps->dtls.io.out.hs.state != MBEDTLS_MPS_HS_PAUSED && + mps->dtls.io.out.hs.state != MBEDTLS_MPS_HS_QUEUED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake data queueing - skip." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + /* In theory, this could loop indefinitely if max record plaintext size + * is 13 bytes, which should never happen. TODO: Check this. */ + do + { + MBEDTLS_MPS_TRACE_COMMENT( "Fetch frag from L3 to dispatch queued data." ); + + ret = mps_dtls_frag_out_bind( mps ); + if( ret == 0 ) + break; + if( ret != MBEDTLS_ERR_WRITER_NEED_MORE ) + MPS_CHK( ret ); + + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + MBEDTLS_MPS_TRACE_COMMENT( "More data queueing" ); + + } while( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_PAUSED || + mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_QUEUED ); + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_ACTIVE || + hs->state == MBEDTLS_MPS_HS_NONE, + "Unexpected handshake state after clearing" ); + + if( hs->state == MBEDTLS_MPS_HS_ACTIVE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "HS write offset: %u / %u", + (unsigned) hs->offset, (unsigned) hs->metadata->len ); + /* TODO: Think about the classification of this error + * again. Is it always an internal error, or can this + * be triggered by malformed input data as well? */ + MBEDTLS_MPS_ASSERT( allow_active_hs, "Active HS not allowed" ); + MBEDTLS_MPS_TRACE_COMMENT( "HS msg not yet fully written -- keep open" ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_bind( mbedtls_mps *mps ) +{ + int ret; + unsigned char *frag; + mbedtls_mps_size_t frag_len, remaining; + mps_l3_handshake_out l3_hs; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = mps->dtls.io.out.hs.metadata; + + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_bind" ); + + /* Request a new handshake fragment from Layer 3. */ + l3_hs.type = metadata->type; + l3_hs.epoch = metadata->epoch; + l3_hs.seq_nr = metadata->seq_nr; + l3_hs.len = metadata->len; + l3_hs.frag_offset = hs->offset; + l3_hs.frag_len = MBEDTLS_MPS_SIZE_UNKNOWN; + MPS_CHK( mps_l3_write_handshake( l3, &l3_hs ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "Get max len buffer from L3 and feed to writer." ); + + /* Extract buffer for remaining handshake content from + * reader obtained from Layer 3. */ + hs->wr_l3 = l3_hs.wr; + if( metadata->len == MBEDTLS_MPS_SIZE_UNKNOWN ) + remaining = MBEDTLS_MPS_SIZE_MAX; + else + remaining = metadata->len - hs->offset; + MPS_CHK( mbedtls_writer_get( hs->wr_l3, remaining, + &frag, &frag_len ) ); + hs->frag_len = frag_len; + MBEDTLS_MPS_TRACE_COMMENT( "Received len %u buf from L3.", (unsigned) frag_len ); + + /* Feed the buffer into the user-facing writer + * used to write the handshake message. */ + ret = mbedtls_writer_feed( &hs->wr, frag, frag_len ); + if( ret == MBEDTLS_ERR_WRITER_NEED_MORE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L3 buffer too small to dispatch queued data." ); + MPS_CHK( mbedtls_writer_commit( hs->wr_l3 ) ); + MPS_CHK( MBEDTLS_ERR_WRITER_NEED_MORE ); + } + + if( hs->state == MBEDTLS_MPS_HS_QUEUED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Handshake message fully written." ); + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + mbedtls_writer_free( &mps->dtls.io.out.hs.wr ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "New outgoing handshake message state: MBEDTLS_MPS_HS_NONE." ); + + mps->dtls.io.out.hs.state = MBEDTLS_MPS_HS_NONE; + } + else + { + hs->state = MBEDTLS_MPS_HS_ACTIVE; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_close( mbedtls_mps *mps, + mbedtls_mps_hs_state new_state ) +{ + int ret; + mbedtls_mps_size_t frag_len, bytes_queued, remaining; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_close" ); + + /* Revoke the Layer 3 fragment buffer from the writer + * and see how much has been written to it, and how much + * is potentially still pending. */ + MPS_CHK( mbedtls_writer_reclaim( &hs->wr, &frag_len, &bytes_queued, + MBEDTLS_WRITER_RECLAIM_FORCE ) ); + MBEDTLS_MPS_TRACE_COMMENT( "* Fragment length: %u", (unsigned) frag_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Bytes queued: %u", (unsigned) bytes_queued ); + MBEDTLS_MPS_TRACE_COMMENT( "* Total length: %u", (unsigned) metadata->len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Fragment offset: %u", (unsigned) hs->offset ); + + if( hs->wr_l3 != NULL ) + { + MBEDTLS_MPS_ASSERT( frag_len <= hs->frag_len && + frag_len <= (mbedtls_mps_size_t)( metadata->len - hs->offset ), + "Writer claims to have written more data than " + "what's available in current fragment" ); + + remaining = hs->frag_len - frag_len; + + /* Inform Layer 3 about how much has been written, + * and dispatch the fragment. */ + MPS_CHK( mbedtls_writer_commit_partial( hs->wr_l3, remaining ) ); + hs->frag_len = frag_len; + } + else + { + /* TODO: Check whether this is still an assertion even after + * removal of the extended writer. */ + MBEDTLS_MPS_ASSERT( frag_len == 0, "Invalid fragment length" ); + MBEDTLS_MPS_ASSERT( metadata->len == MBEDTLS_MPS_SIZE_UNKNOWN || + (unsigned) metadata->len == bytes_queued, + "Mismatch between HS msg size and amount of data written" ); + + MBEDTLS_MPS_TRACE_COMMENT( "Total HS len: %u", (unsigned) bytes_queued ); + + metadata->len = bytes_queued; + } + + mps->dtls.io.out.hs.state = new_state; + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_dispatch( mbedtls_mps *mps ) +{ + int ret = 0; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + ((void) metadata); + + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_dispatch" ); + + if( mps->dtls.io.out.hs.wr_l3 != NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( " * Seq: %u", (unsigned) metadata->seq_nr ); + MBEDTLS_MPS_TRACE_COMMENT( " * Frag off: %u", (unsigned) hs->offset ); + MBEDTLS_MPS_TRACE_COMMENT( " * Frag len: %u", (unsigned) hs->frag_len ); + MBEDTLS_MPS_TRACE_COMMENT( " * Total len: %u", (unsigned) metadata->len ); + + MPS_CHK( mps_l3_dispatch( l3 ) ); + + hs->offset += hs->frag_len; + hs->wr_l3 = NULL; + hs->frag_len = 0; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_start( mbedtls_mps_handshake_out_internal *hs, + unsigned char *queue, + mbedtls_mps_size_t queue_len, + mbedtls_mps_msg_metadata *metadata, + mps_dtls_outgoing_hs_msg_mode mode ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_start, type %u, length %u", + (unsigned) metadata->type, (unsigned) metadata->len ); + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_NONE, + "Can't start new HS msg while another is still unfinished" ); + + hs->metadata = metadata; + hs->offset = 0; + hs->wr_l3 = NULL; + + mbedtls_writer_init( &hs->wr, queue, queue_len ); + MBEDTLS_MPS_ASSERT( mode == MPS_DTLS_FRAG_OUT_START_USE_L3 || + mode == MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY, + "Invalid handshake message mode" ); + + if( mode == MPS_DTLS_FRAG_OUT_START_USE_L3 ) + { + hs->state = MBEDTLS_MPS_HS_PAUSED; + } + else /* MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY */ + { + /* Feed an empty buffer to serve write requests from the queue only. */ + MPS_CHK( mbedtls_writer_feed( &hs->wr, NULL, 0 ) ); + hs->state = MBEDTLS_MPS_HS_ACTIVE; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_msg_start( mbedtls_mps *mps, + mbedtls_mps_retransmission_handle **handle ) +{ + int ret = 0; + uint8_t cur_flight_len; + mbedtls_mps_retransmission_handle *hdl; + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_msg_start" ); + + MBEDTLS_MPS_TRACE_COMMENT( "Add msg to flight, seq nr %u", + (unsigned) mps->dtls.seq_nr ); + + cur_flight_len = mps->dtls.outgoing.flight_len; + if( cur_flight_len == MBEDTLS_MPS_MAX_FLIGHT_LENGTH ) + { + MBEDTLS_MPS_TRACE_ERROR( "Outgoing flight reached max len %u", + (unsigned) MBEDTLS_MPS_MAX_FLIGHT_LENGTH ); + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ); + } + + mps->dtls.outgoing.flight_len = cur_flight_len + 1; + mps->dtls.io.out.flags = 0; + + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &hdl, + cur_flight_len ) ); + mbedtls_mps_retransmission_handle_init( hdl ); + + hdl->metadata.seq_nr = mps->dtls.seq_nr; + + *handle = hdl; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_msg_done( mbedtls_mps *mps ) +{ + int ret; + uint8_t cur_flight_len; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + mbedtls_mps_retransmission_handle *hdl; + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_msg_done" ); + + /* Add epoch usage for retransmission */ + MPS_CHK( mps_l3_epoch_usage( l3, mps->out_epoch, + 0, MPS_EPOCH_USAGE_WRITE( MPS_WRITE_RETRANSMISSION ) ) ); + + cur_flight_len = mps->dtls.outgoing.flight_len; + MBEDTLS_MPS_ASSERT( cur_flight_len > 0, + "mps_out_flight_msg_done() called with flight length 0" ); + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &hdl, + cur_flight_len - 1 ) ); + + /* Increase handshake sequence number except for the CCS message. */ + if( hdl->handle_type != MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS ) + { + mbedtls_mps_hs_seq_nr_t cur_seq_nr; + cur_seq_nr = mps->dtls.seq_nr; + if( cur_seq_nr == MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reached max seq nr %u", + (unsigned) MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ); + MPS_CHK( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + } + + mps->dtls.seq_nr++; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ diff --git a/library/mps/reader.c b/library/mps/reader.c new file mode 100644 index 000000000000..a29f14c5585b --- /dev/null +++ b/library/mps/reader.c @@ -0,0 +1,716 @@ +/* + * Message Processing Stack, Reader implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "common.h" + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#include "mbedtls/mps/reader.h" +#include "mbedtls/mps/common.h" +#include "mbedtls/mps/trace.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +/* + * GENERAL NOTE ON CODING STYLE + * + * The following code intentionally separates memory loads + * and stores from other operations (arithmetic or branches). + * This leads to the introduction of many local variables + * and significantly increases the C-code line count, but + * should not increase the size of generated assembly. + * + * The reason for this is twofold: + * (1) It will ease verification efforts using the VST + * (Verified Software Toolchain) + * whose program logic cannot directly reason + * about instructions containing a load or store in + * addition to other operations (e.g. *p = *q or + * tmp = *p + 42). + * (2) Operating on local variables and writing the results + * back to the target contexts on success only + * allows to maintain structure invariants even + * on failure - this in turn has two benefits: + * (2.a) If for some reason an error code is not caught + * and operation continues, functions are nonetheless + * called with sane contexts, reducing the risk + * of dangerous behavior. + * (2.b) Randomized testing is easier if structures + * remain intact even in the face of failing + * and/or non-sensical calls. + * Moreover, it might even reduce code-size because + * the compiler need not write back temporary results + * to memory in case of failure. + * + */ + +static inline int mps_reader_is_accumulating( + mbedtls_mps_reader const *rd ) +{ + mbedtls_mps_size_t acc_remaining; + if( rd->acc == NULL ) + return( 0 ); + + acc_remaining = rd->acc_share.acc_remaining; + return( acc_remaining > 0 ); +} + +static inline int mps_reader_is_producing( + mbedtls_mps_reader const *rd ) +{ + unsigned char *frag = rd->frag; + return( frag == NULL ); +} + +static inline int mps_reader_is_consuming( + mbedtls_mps_reader const *rd ) +{ + return( !mps_reader_is_producing( rd ) ); +} + +static inline mbedtls_mps_size_t mps_reader_get_fragment_offset( + mbedtls_mps_reader const *rd ) +{ + unsigned char *acc = rd->acc; + mbedtls_mps_size_t frag_offset; + + if( acc == NULL ) + return( 0 ); + + frag_offset = rd->acc_share.frag_offset; + return( frag_offset ); +} + +static inline mbedtls_mps_size_t mps_reader_serving_from_accumulator( + mbedtls_mps_reader const *rd ) +{ + mbedtls_mps_size_t frag_offset, end; + + frag_offset = mps_reader_get_fragment_offset( rd ); + end = rd->end; + + return( end < frag_offset ); +} + +static inline void mps_reader_zero( mbedtls_mps_reader *rd ) +{ + /* A plain memset() would likely be more efficient, + * but the current way of zeroing makes it harder + * to overlook fields which should not be zero-initialized. + * It's also more suitable for FV efforts since it + * doesn't require reasoning about structs being + * interpreted as unstructured binary blobs. */ + static mbedtls_mps_reader const zero = + { .frag = NULL, + .frag_len = 0, + .commit = 0, + .end = 0, + .pending = 0, + .acc = NULL, + .acc_len = 0, + .acc_available = 0, + .acc_share = { .acc_remaining = 0 } + }; + *rd = zero; +} + +int mbedtls_mps_reader_init( mbedtls_mps_reader *rd, + unsigned char *acc, + mbedtls_mps_size_t acc_len ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_init" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Accumulator size: %u bytes", (unsigned) acc_len ); + mps_reader_zero( rd ); + rd->acc = acc; + rd->acc_len = acc_len; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_free( mbedtls_mps_reader *rd ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_free" ); + mps_reader_zero( rd ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_feed( mbedtls_mps_reader *rd, + unsigned char *new_frag, + mbedtls_mps_size_t new_frag_len ) +{ + mbedtls_mps_size_t copy_to_acc; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_feed" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Fragment length: %u bytes", (unsigned) new_frag_len ); + + if( new_frag == NULL ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_INVALID_ARG ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_producing( rd ), + "mbedtls_mps_reader_feed() requires reader to be in producing mode" ); + + if( mps_reader_is_accumulating( rd ) ) + { + unsigned char *acc = rd->acc; + mbedtls_mps_size_t acc_remaining = rd->acc_share.acc_remaining; + mbedtls_mps_size_t acc_available = rd->acc_available; + + /* Skip over parts of the accumulator that have already been filled. */ + acc += acc_available; + + copy_to_acc = acc_remaining; + if( copy_to_acc > new_frag_len ) + copy_to_acc = new_frag_len; + + /* Copy new contents to accumulator. */ + memcpy( acc, new_frag, copy_to_acc ); + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Copy new data of size %u of %u into accumulator at offset %u", + (unsigned) copy_to_acc, (unsigned) new_frag_len, (unsigned) acc_available ); + + /* Check if, with the new fragment, we have enough data. */ + acc_remaining -= copy_to_acc; + if( acc_remaining > 0 ) + { + /* We need to accumulate more data. Stay in producing mode. */ + acc_available += copy_to_acc; + rd->acc_share.acc_remaining = acc_remaining; + rd->acc_available = acc_available; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_NEED_MORE ); + } + + /* We have filled the accumulator: Move to consuming mode. */ + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Enough data available to serve user request" ); + + /* Remember overlap of accumulator and fragment. */ + rd->acc_share.frag_offset = acc_available; + acc_available += copy_to_acc; + rd->acc_available = acc_available; + } + else /* Not accumulating */ + { + rd->acc_share.frag_offset = 0; + } + + rd->frag = new_frag; + rd->frag_len = new_frag_len; + rd->commit = 0; + rd->end = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + + +int mbedtls_mps_reader_get( mbedtls_mps_reader *rd, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + unsigned char *frag; + mbedtls_mps_size_t frag_len, frag_offset, end, frag_fetched, frag_remaining; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_get" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Bytes requested: %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_get() requires reader to be in consuming mode" ); + + end = rd->end; + frag_offset = mps_reader_get_fragment_offset( rd ); + + /* Check if we're still serving from the accumulator. */ + if( mps_reader_serving_from_accumulator( rd ) ) + { + /* Illustration of supported and unsupported cases: + * + * - Allowed #1 + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +-----v-------v-------------+ + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * - Allowed #2 + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +----------v----------------v + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * - Not allowed #1 (could be served, but we don't actually use it): + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +------v-------------v------+ + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * + * - Not allowed #2 (can't be served with a contiguous buffer): + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end + desired + * | | + * +------v--------------------+ v + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * In case of Allowed #2 we're switching to serve from + * `frag` starting from the next call to mbedtls_mps_reader_get(). + */ + + unsigned char *acc; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Serve the request from the accumulator" ); + if( frag_offset - end < desired ) + { + mbedtls_mps_size_t acc_available; + acc_available = rd->acc_available; + if( acc_available - end != desired ) + { + /* It might be possible to serve some of these situations by + * making additional space in the accumulator, removing those + * parts that have already been committed. + * On the other hand, this brings additional complexity and + * enlarges the code size, while there doesn't seem to be a use + * case where we don't attempt exactly the same `get` calls when + * resuming on a reader than what we tried before pausing it. + * If we believe we adhere to this restricted usage throughout + * the library, this check is a good opportunity to + * validate this. */ + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_INCONSISTENT_REQUESTS ); + } + } + + acc = rd->acc; + acc += end; + + *buffer = acc; + if( buflen != NULL ) + *buflen = desired; + + end += desired; + rd->end = end; + rd->pending = 0; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Attempt to serve the request from the current fragment */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Serve the request from the current fragment." ); + + frag_len = rd->frag_len; + frag_fetched = end - frag_offset; /* The amount of data from the current + * fragment that has already been passed + * to the user. */ + frag_remaining = frag_len - frag_fetched; /* Remaining data in fragment */ + + /* Check if we can serve the read request from the fragment. */ + if( frag_remaining < desired ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There's not enough data in the current fragment " + "to serve the request." ); + /* There's not enough data in the current fragment, + * so either just MBEDTLS_MPS_TRACE_RETURN what we have or fail. */ + if( buflen == NULL ) + { + if( frag_remaining > 0 ) + { + rd->pending = desired - frag_remaining; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Remember to collect %u bytes before re-opening", + (unsigned) rd->pending ); + } + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ); + } + + desired = frag_remaining; + } + + /* There's enough data in the current fragment to serve the + * (potentially modified) read request. */ + + frag = rd->frag; + frag += frag_fetched; + + *buffer = frag; + if( buflen != NULL ) + *buflen = desired; + + end += desired; + rd->end = end; + rd->pending = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_commit( mbedtls_mps_reader *rd ) +{ + mbedtls_mps_size_t end; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_commit" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_commit() requires reader to be in consuming mode" ); + + end = rd->end; + rd->commit = end; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *rd, + int *paused ) +{ + unsigned char *frag, *acc; + mbedtls_mps_size_t pending, commit; + mbedtls_mps_size_t acc_len, frag_offset, frag_len; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_reclaim" ); + + if( paused != NULL ) + *paused = 0; + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_reclaim() requires reader to be in consuming mode" ); + + frag = rd->frag; + acc = rd->acc; + pending = rd->pending; + commit = rd->commit; + frag_len = rd->frag_len; + + frag_offset = mps_reader_get_fragment_offset( rd ); + + if( pending == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No unsatisfied read-request has been logged." ); + + /* Check if there's data left to be consumed. */ + if( commit < frag_offset || commit - frag_offset < frag_len ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There is data left to be consumed." ); + rd->end = commit; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_DATA_LEFT ); + } + + rd->acc_available = 0; + rd->acc_share.acc_remaining = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Fragment has been fully processed and committed." ); + } + else + { + int overflow; + + mbedtls_mps_size_t acc_backup_offset; + mbedtls_mps_size_t acc_backup_len; + mbedtls_mps_size_t frag_backup_offset; + mbedtls_mps_size_t frag_backup_len; + + mbedtls_mps_size_t backup_len; + mbedtls_mps_size_t acc_len_needed; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There has been an unsatisfied read with %u bytes overhead.", + (unsigned) pending ); + + if( acc == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No accumulator present" ); + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ); + } + acc_len = rd->acc_len; + + /* Check if the upper layer has already fetched + * and committed the contents of the accumulator. */ + if( commit < frag_offset ) + { + /* No, accumulator is still being processed. */ + frag_backup_offset = 0; + frag_backup_len = frag_len; + acc_backup_offset = commit; + acc_backup_len = frag_offset - commit; + } + else + { + /* Yes, the accumulator is already processed. */ + frag_backup_offset = commit - frag_offset; + frag_backup_len = frag_len - frag_backup_offset; + acc_backup_offset = 0; + acc_backup_len = 0; + } + + backup_len = acc_backup_len + frag_backup_len; + acc_len_needed = backup_len + pending; + + overflow = 0; + overflow |= ( backup_len < acc_backup_len ); + overflow |= ( acc_len_needed < backup_len ); + + if( overflow || acc_len < acc_len_needed ) + { + /* Except for the different return code, we behave as if + * there hadn't been a call to mbedtls_mps_reader_get() + * since the last commit. */ + rd->end = commit; + rd->pending = 0; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "The accumulator is too small to handle the backup." ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "* Size: %u", (unsigned) acc_len ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "* Needed: %u (%u + %u)", + (unsigned) acc_len_needed, + (unsigned) backup_len, (unsigned) pending ); + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL ); + } + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Fragment backup: %u", (unsigned) frag_backup_len ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Accumulator backup: %u", (unsigned) acc_backup_len ); + + /* Move uncommitted parts from the accumulator to the front + * of the accumulator. */ + memmove( acc, acc + acc_backup_offset, acc_backup_len ); + + /* Copy uncmmitted parts of the current fragment to the + * accumulator. */ + memcpy( acc + acc_backup_len, + frag + frag_backup_offset, frag_backup_len ); + + rd->acc_available = backup_len; + rd->acc_share.acc_remaining = pending; + + if( paused != NULL ) + *paused = 1; + } + + rd->frag = NULL; + rd->frag_len = 0; + + rd->commit = 0; + rd->end = 0; + rd->pending = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Final state: aa %u, al %u, ar %u", + (unsigned) rd->acc_available, (unsigned) rd->acc_len, + (unsigned) rd->acc_share.acc_remaining ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + + +/* + * Implementation of extended reader + */ + +/* TODO: Consider making (some of) these functions inline. */ + +int mbedtls_mps_reader_init_ext( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t size ) +{ + mbedtls_mps_reader_ext zero = { 0, { 0 }, NULL, 0, 0, }; + MBEDTLS_MPS_TRACE_INIT( "reader_init_ext, size %u", (unsigned) size ); + + *rd_ext = zero; + rd_ext->grp_end[0] = size; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_free_ext( mbedtls_mps_reader_ext *rd ) +{ + mbedtls_mps_reader_ext zero = { 0, { 0 }, NULL, 0, 0, }; + MBEDTLS_MPS_TRACE_INIT( "reader_free_ext" ); + *rd = zero; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_get_ext( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mbedtls_mps_size_t logic_avail; + MBEDTLS_MPS_TRACE_INIT( "reader_get_ext %p: desired %u", (void*) rd_ext, (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_get_ext() without underlying reader" ); + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Fetch offset: %u", (unsigned) rd_ext->ofs_fetch ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Group end: %u", + (unsigned) rd_ext->grp_end[rd_ext->cur_grp] ); + logic_avail = rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + if( desired > logic_avail ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Requesting more data (%u) than logically available (%u)", + (unsigned) desired, (unsigned) logic_avail ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + } + + ret = mbedtls_mps_reader_get( rd_ext->rd, desired, buffer, buflen ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( buflen != NULL ) + desired = *buflen; + + rd_ext->ofs_fetch += desired; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_commit_ext( mbedtls_mps_reader_ext *rd_ext ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "reader_commit_ext" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_commit_ext() without underlying reader" ); + + ret = mbedtls_mps_reader_commit( rd_ext->rd ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + rd_ext->ofs_commit = rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_group_open( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t group_size ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "reader_group_open, size %u", (unsigned) group_size ); + + if( rd_ext->cur_grp >= MBEDTLS_MPS_READER_MAX_GROUPS - 1 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS ); + + /* Make sure the new group doesn't exceed the present one */ + if( logic_avail < group_size ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + + /* Add new group */ + rd_ext->cur_grp++; + rd_ext->grp_end[rd_ext->cur_grp] = rd_ext->ofs_fetch + group_size; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_group_close( mbedtls_mps_reader_ext *rd_ext ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "reader_group_close" ); + + /* Ensure that the group is fully exhausted */ + if( logic_avail != 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + + if( rd_ext->cur_grp > 0 ) + rd_ext->cur_grp--; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_attach( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_reader *rd ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_attach" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd == NULL, + "mbedtls_mps_reader_attach() called with already attached ext. reader" ); + + rd_ext->rd = rd; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_detach( mbedtls_mps_reader_ext *rd_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_detach" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_attach() called with already detached ext. reader" ); + + rd_ext->ofs_fetch = rd_ext->ofs_commit; + rd_ext->rd = NULL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_check_done( mbedtls_mps_reader_ext const *rd_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_check_done" ); + if( rd_ext->cur_grp > 0 || + rd_ext->ofs_commit != rd_ext->grp_end[0] ) + { + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/mps/trace.c b/library/mps/trace.c new file mode 100644 index 000000000000..ee8d934502a3 --- /dev/null +++ b/library/mps/trace.c @@ -0,0 +1,127 @@ +/* + * Message Processing Stack, Trace module + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "common.h" + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + +#include "mbedtls/mps/trace.h" +#include + +static int trace_depth = 0; + +#define color_default "\x1B[0m" +#define color_red "\x1B[1;31m" +#define color_green "\x1B[1;32m" +#define color_yellow "\x1B[1;33m" +#define color_blue "\x1B[1;34m" +#define color_magenta "\x1B[1;35m" +#define color_cyan "\x1B[1;36m" +#define color_white "\x1B[1;37m" + +static char const * colors[] = +{ + color_default, + color_green, + color_yellow, + color_magenta, + color_cyan, + color_blue, + color_white +}; + +#define MPS_TRACE_BUF_SIZE 100 + +void mbedtls_mps_trace_print_msg( int id, int line, const char *format, ... ) +{ + int ret; + char str[MPS_TRACE_BUF_SIZE]; + va_list argp; + va_start( argp, format ); + ret = mbedtls_vsnprintf( str, MPS_TRACE_BUF_SIZE, format, argp ); + va_end( argp ); + + if( ret >= 0 && ret < MPS_TRACE_BUF_SIZE ) + { + str[ret] = '\0'; + mbedtls_printf( "[%d|L%d]: %s\n", id, line, str ); + } +} + +int mbedtls_mps_trace_get_depth() +{ + return trace_depth; +} +void mbedtls_mps_trace_dec_depth() +{ + trace_depth--; +} +void mbedtls_mps_trace_inc_depth() +{ + trace_depth++; +} + +void mbedtls_mps_trace_color( int id ) +{ + if( id > (int) ( sizeof( colors ) / sizeof( *colors ) ) ) + return; + printf( "%s", colors[ id ] ); +} + +void mbedtls_mps_trace_indent( int level, mbedtls_mps_trace_type ty ) +{ + if( level > 0 ) + { + while( --level ) + printf( "| " ); + + printf( "| " ); + } + + switch( ty ) + { + case MBEDTLS_MPS_TRACE_TYPE_COMMENT: + mbedtls_printf( "@ " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_CALL: + mbedtls_printf( "+--> " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_ERROR: + mbedtls_printf( "E " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_RETURN: + mbedtls_printf( "< " ); + break; + + default: + break; + } +} + +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/mps/transform.c b/library/mps/transform.c new file mode 100644 index 000000000000..0c8367c4b94a --- /dev/null +++ b/library/mps/transform.c @@ -0,0 +1,28 @@ +/* + * Message Processing Stack, Record Transformation Mechanisms + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/transform.h" + +/* TODO: Use dummy default functions. */ +mbedtls_mps_transform_free_t *mbedtls_mps_transform_free = NULL; +mbedtls_mps_transform_decrypt_t *mbedtls_mps_transform_decrypt = NULL; +mbedtls_mps_transform_encrypt_t *mbedtls_mps_transform_encrypt = NULL; +mbedtls_mps_transform_get_expansion_t *mbedtls_mps_transform_get_expansion = NULL; diff --git a/library/mps/writer.c b/library/mps/writer.c new file mode 100644 index 000000000000..e0154a1ccc1f --- /dev/null +++ b/library/mps/writer.c @@ -0,0 +1,605 @@ +/* + * Message Processing Stack, Writer implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/writer.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/error.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_WRITER; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +void mbedtls_writer_init( mbedtls_writer *wr, + unsigned char *queue, + mbedtls_mps_size_t queue_len ) +{ + mbedtls_writer dst = { .state = MBEDTLS_WRITER_PROVIDING, + .out = NULL, + .queue = queue, + .out_len = 0, + .queue_len = queue_len, + .committed = 0, + .end = 0, + .queue_next = 0, + .queue_remaining = 0 }; + + *wr = dst; +} + +void mbedtls_writer_free( mbedtls_writer *wr ) +{ + mbedtls_writer_init( wr, NULL, 0 ); +} + +int mbedtls_writer_feed( mbedtls_writer *wr, + unsigned char *buf, + mbedtls_mps_size_t buf_len ) +{ + unsigned char *queue; + mbedtls_mps_size_t copy_from_queue; + MBEDTLS_MPS_TRACE_INIT( "writer_feed, buflen %u", + (unsigned) buf_len ); + + /* Feeding is only possible in providing state. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_PROVIDING, + "Attempt to feed output buffer to writer outside providing mode." ); + + /* Check if there is data in the queue pending to be dispatched. */ + queue = wr->queue; + copy_from_queue = 0; + if( queue != NULL ) + { + mbedtls_mps_size_t qa, qr; + qr = wr->queue_remaining; + qa = wr->queue_next; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Queue data pending to be dispatched: %u", + (unsigned) wr->queue_remaining ); + + /* Copy as much data from the queue to + * the provided buffer as possible. */ + copy_from_queue = qr; + if( copy_from_queue > buf_len ) + copy_from_queue = buf_len; + queue += qa; + + if( copy_from_queue != 0 ) + memcpy( buf, queue, copy_from_queue ); + + /* Check if, after the last copy, the entire + * queue has been dispatched. */ + qr -= copy_from_queue; + if( qr > 0 ) + { + /* More data waiting in the queue */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "There are %u bytes remaining in the queue.", + (unsigned) qr ); + + qa += copy_from_queue; + wr->queue_remaining = qr; + wr->queue_next = qa; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_NEED_MORE ); + } + + /* The queue is empty. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Queue is empty" ); + wr->queue_next = 0; + wr->queue_remaining = 0; + + /* NOTE: Currently this returns success if the provided output + * buffer is exactly as big as the remaining queue, + * in which case there is no space left after the + * queue has been copied. Is that intentional? */ + + } + + wr->out = buf; + wr->out_len = buf_len; + wr->committed = copy_from_queue; + wr->end = copy_from_queue; + wr->state = MBEDTLS_WRITER_CONSUMING; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +static inline int mps_writer_fragment_committed( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const committed = wr->committed; + mbedtls_mps_size_t const out_len = wr->out_len; + + return( committed >= out_len ); +} + +static inline int mps_writer_committed_data_in_queue( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const commit = wr->committed; + mbedtls_mps_size_t const out_len = wr->out_len; + mbedtls_mps_size_t const overlap = wr->queue_next; + + return( commit > out_len - overlap ); +} + +static inline void mps_writer_copy_queue_to_fragment( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t queue_size, copy_from_queue; + mbedtls_mps_size_t queue_overlap, commit, out_len; + unsigned char * const queue = wr->queue; + unsigned char * out = wr->out; + + if( !mps_writer_committed_data_in_queue( wr ) ) + return; + + commit = wr->committed; + out_len = wr->out_len; + queue_overlap = wr->queue_next; + + queue_size = commit - ( out_len - queue_overlap ); + copy_from_queue = + queue_size > queue_overlap ? queue_overlap : queue_size; + + if( copy_from_queue != 0 ) + { + out += out_len - queue_overlap; + memcpy( out, queue, copy_from_queue ); + } +} + +int mbedtls_writer_reclaim( mbedtls_writer *wr, + mbedtls_mps_size_t *olen, + mbedtls_mps_size_t *queued, + int force ) +{ + mbedtls_mps_size_t commit, out_len; + MBEDTLS_MPS_TRACE_INIT( "writer_reclaim" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT," * Force reclaim: %u", (unsigned) force ); + + /* Check that the writer is in consuming mode. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_CONSUMING, + "Can't reclaim output buffer outside of consuming mode." ); + + commit = wr->committed; + out_len = wr->out_len; + wr->end = commit; + + if( olen != NULL ) + { + mbedtls_mps_size_t const committed_data_in_frag = + commit > out_len ? out_len : commit; + + *olen = committed_data_in_frag; + } + + /* Copy head of queue to tail of fragment. */ + mps_writer_copy_queue_to_fragment( wr ); + + /* Check if there's space left unused. */ + if( !mps_writer_fragment_committed( wr ) ) + { + if( queued != NULL ) + *queued = 0; + + wr->queue_next = 0; + + if( force == 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_DATA_LEFT ); + } + else + { + wr->queue_remaining = commit - out_len; + if( queued != NULL ) + *queued = wr->queue_remaining; + } + + wr->end = 0; + wr->committed = 0; + wr->out = NULL; + wr->out_len = 0; + wr->state = MBEDTLS_WRITER_PROVIDING; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_bytes_written( mbedtls_writer *wr, + mbedtls_mps_size_t *written ) +{ + mbedtls_mps_size_t commit; + MBEDTLS_MPS_TRACE_INIT( "writer_bytes_written" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_PROVIDING, + "Attempt to feed output buffer to writer outside providing mode." ); + + commit = wr->committed; + *written = commit; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +static inline int mps_writer_queue_in_use( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const end = wr->end; + mbedtls_mps_size_t const out_len = wr->out_len; + mbedtls_mps_size_t const overlap = wr->queue_next; + + return( end > out_len - overlap ); +} + +int mbedtls_writer_get( mbedtls_writer *wr, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + unsigned char *out, *queue; + mbedtls_mps_size_t end, ol, or, ql, qn, qo; + MBEDTLS_MPS_TRACE_INIT( "writer_get, desired %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr->state == MBEDTLS_WRITER_CONSUMING, + "Attempt to request write-buffer outside consuming mode." ); + + out = wr->out; + end = wr->end; + ol = wr->out_len; + qn = wr->queue_next; + + /* Check if we're already serving from the queue */ + if( mps_writer_queue_in_use( wr ) ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "already serving from the queue, attempt to continue" ); + + ql = wr->queue_len; + qo = end - ( ol - qn ); + + if( ql - qo < desired ) + { + if( buflen == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "not enough space remaining in queue" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + desired = ql - qo; + } + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "serving %u bytes from queue", (unsigned) desired ); + + queue = wr->queue; + end += desired; + wr->end = end; + + *buffer = queue + qo; + if( buflen != NULL ) + *buflen = desired; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + or = ol - end; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "%u bytes remaining in output buffer", (unsigned) or ); + if( or < desired ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "need %u, but only %u remains in write buffer", + (unsigned) desired, (unsigned) or ); + + queue = wr->queue; + ql = wr->queue_len; + + /* Out buffer is too small. Attempt to serve from queue if it is + * available and larger than the remaining output buffer. */ + if( queue != NULL && ql > or ) + { + int overflow; + + if( buflen != NULL && desired > ql ) + desired = ql; + + overflow = ( end + desired < end ); + if( overflow || desired > ql ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "queue present but too small, need %u but only got %u", + (unsigned) desired, (unsigned) ql ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + + /* Queue large enough, transition to serving from queue. */ + end += desired; + wr->end = end; + + *buffer = queue; + if( buflen != NULL ) + *buflen = desired; + + /* Remember the overlap between queue and output buffer. */ + wr->queue_next = or; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "served from queue, overlap %u", + (unsigned) wr->queue_next ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* No queue present, so serve only what's available + * in the output buffer, provided the user allows it. */ + if( buflen == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "no queue present" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + + desired = or; + } + + /* We reach this if the request can be served from the output buffer. */ + out += end; + end += desired; + wr->end = end; + + *buffer = out; + if( buflen != NULL) + *buflen = desired; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_commit( mbedtls_writer *wr ) +{ + return( mbedtls_writer_commit_partial( wr, 0 ) ); +} + +int mbedtls_writer_commit_partial( mbedtls_writer *wr, + mbedtls_mps_size_t omit ) +{ + mbedtls_mps_size_t to_be_committed, commit, end; + mbedtls_mps_size_t out_len, queue_overlap; + MBEDTLS_MPS_TRACE_INIT( "writer_commit_partial" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Omit %u bytes", (unsigned) omit ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_CONSUMING, + "Attempt to request write-buffer outside consuming mode." ); + + commit = wr->committed; + end = wr->end; + out_len = wr->out_len; + queue_overlap = wr->queue_next; + + if( omit > end - commit ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_INVALID_ARG ); + + to_be_committed = end - omit; + + if( to_be_committed <= out_len - queue_overlap ) + wr->queue_next = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Last commit: %u", (unsigned) commit ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* End of last fetch: %u", (unsigned) end ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* New commit: %u", (unsigned) to_be_committed ); + + wr->end = to_be_committed; + wr->committed = to_be_committed; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Implementation of extended writer + */ + +/* TODO: Consider making (some of) these functions inline. */ + +void mbedtls_writer_init_ext( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t size ) +{ + mbedtls_writer_ext const writer_ext_zero = + { .wr = NULL, + .grp_end = { 0 }, + .cur_grp = 0, + .ofs_fetch = 0 }; + + *wr_ext = writer_ext_zero; + wr_ext->grp_end[0] = size; +} + +void mbedtls_writer_free_ext( mbedtls_writer_ext *wr_ext ) +{ + mbedtls_writer_init_ext( wr_ext, 0 ); +} + +int mbedtls_writer_get_ext( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mbedtls_mps_size_t logic_avail; + MBEDTLS_MPS_TRACE_INIT( "writer_get_ext: desired %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr != NULL, "No writer attached" ); + + logic_avail = wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "desired %u, logic_avail %u", + (unsigned) desired, (unsigned) logic_avail ); + if( desired > logic_avail ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "bounds violation!" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + ret = mbedtls_writer_get( wr_ext->wr, desired, buffer, buflen ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( buflen != NULL ) + desired = *buflen; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "increase fetch offset from %u to %u", + (unsigned) wr_ext->ofs_fetch, + (unsigned) ( wr_ext->ofs_fetch + desired ) ); + + wr_ext->ofs_fetch += desired; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_commit_ext( mbedtls_writer_ext *wr ) +{ + return( mbedtls_writer_commit_partial_ext( wr, 0 ) ); +} + +int mbedtls_writer_commit_partial_ext( mbedtls_writer_ext *wr, + mbedtls_mps_size_t omit ) +{ + int ret; + mbedtls_mps_size_t ofs_fetch, ofs_commit; + MBEDTLS_MPS_TRACE_INIT( "writer_commit_partial_ext, omit %u", + (unsigned) omit ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr->wr != NULL, "No writer attached" ); + + ofs_fetch = wr->ofs_fetch; + ofs_commit = wr->ofs_commit; + + if( omit > ofs_fetch - ofs_commit ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, "Try to omit %u bytes from commit, but only %u are uncommitted.", + (unsigned) omit, (unsigned)( ofs_fetch - ofs_commit ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + ofs_commit = ofs_fetch - omit; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Forward commit to underlying writer" ); + ret = mbedtls_writer_commit_partial( wr->wr, omit ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ofs_fetch = ofs_commit; + + wr->ofs_fetch = ofs_fetch; + wr->ofs_commit = ofs_commit; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_group_open( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t group_size ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "writer_group_open, size %u", (unsigned) group_size ); + + if( wr_ext->cur_grp >= MBEDTLS_WRITER_MAX_GROUPS - 1 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS ); + + /* Make sure the new group doesn't exceed the present one */ + if( logic_avail < group_size ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + + /* Add new group */ + wr_ext->cur_grp++; + wr_ext->grp_end[wr_ext->cur_grp] = wr_ext->ofs_fetch + group_size; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_group_close( mbedtls_writer_ext *wr_ext ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "writer_group_close" ); + + /* Ensure that the group is fully exhausted */ + if( logic_avail != 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + + if( wr_ext->cur_grp > 0 ) + wr_ext->cur_grp--; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_attach( mbedtls_writer_ext *wr_ext, + mbedtls_writer *wr ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_writer_attach" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr == NULL, "Writer attached" ); + + wr_ext->wr = wr; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_detach( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t *committed, + mbedtls_mps_size_t *uncommitted ) +{ + MBEDTLS_MPS_TRACE_INIT( "writer_check_detach" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr != NULL, "No writer attached" ); + + if( uncommitted != NULL ) + { + *uncommitted = wr_ext->ofs_fetch - wr_ext->ofs_commit; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Uncommitted: %u", + (unsigned) *uncommitted ); + } + if( committed != NULL ) + { + *committed = wr_ext->ofs_commit; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Committed: %u", + (unsigned) *committed ); + } + + wr_ext->ofs_fetch = wr_ext->ofs_commit; + wr_ext->wr = NULL; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_check_done( mbedtls_writer_ext *wr_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "writer_check_done" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Commit: %u", (unsigned) wr_ext->ofs_commit ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Group end: %u", (unsigned) wr_ext->grp_end[0] ); + + if( wr_ext->cur_grp > 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "cur_grp > 0" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + if( wr_ext->grp_end[0] != MBEDTLS_MPS_SIZE_MAX && + wr_ext->ofs_commit != wr_ext->grp_end[0] ) + { + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c index ceec77efb07e..063ea9329807 100644 --- a/library/ssl_ciphersuites.c +++ b/library/ssl_ciphersuites.c @@ -60,6 +60,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All AES-256 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, @@ -75,6 +78,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All CAMELLIA-256 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, @@ -107,6 +113,11 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_AES_128_GCM_SHA256, + MBEDTLS_TLS1_3_AES_128_CCM_SHA256, + MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All CAMELLIA-128 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, @@ -315,6 +326,61 @@ static const int ciphersuite_preference[] = static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS1_3_AES_256_GCM_SHA384, "TLS1-3-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_AES_128_GCM_SHA256, "TLS1-3-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_AES_128_CCM_SHA256, "TLS1-3-AES-128-CCM-SHA256", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, + + { MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, "TLS1-3-AES-128-CCM-8-SHA256", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) && \ + defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, + "TLS1-3-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 // field not used in TLS 1.3 implementation + }, +#endif /* MBEDTLS_CHACHAPOLY_C && MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_CHACHAPOLY_C) && \ defined(MBEDTLS_SHA256_C) && \ defined(MBEDTLS_SSL_PROTO_TLS1_2) @@ -384,6 +450,8 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = #endif /* MBEDTLS_CHACHAPOLY_C && MBEDTLS_SHA256_C && MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) #if defined(MBEDTLS_AES_C) #if defined(MBEDTLS_SHA1_C) @@ -2163,7 +2231,7 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ #endif /* MBEDTLS_ARIA_C */ - +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ { 0, "", MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, @@ -2291,6 +2359,24 @@ int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ) return( cur->id ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +unsigned int mbedtls_hash_size_for_ciphersuite(const mbedtls_ssl_ciphersuite_t* ciphersuite) +{ + /* We assume that the input parameter, ciphersuite, is not NULL. */ + switch( ciphersuite->mac ) + { + case MBEDTLS_MD_SHA256: + return( 32 ); + case MBEDTLS_MD_SHA384: + return( 48 ); + case MBEDTLS_MD_SHA512: + return( 64 ); + default: + return( 0 ); + } +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_PK_C) mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ) { diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 72351c9757c7..42b2eb796bca 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -19,6 +19,8 @@ #include "common.h" +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_PLATFORM_C) @@ -4607,3 +4609,4 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index e47c538888e3..b2f0b7052596 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -58,7 +58,8 @@ #include "mbedtls/oid.h" #endif -static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 /* * Start a timer. @@ -90,6 +91,10 @@ int mbedtls_ssl_check_timer( mbedtls_ssl_context *ssl ) return( 0 ); } +#if !defined(MBEDTLS_SSL_USE_MPS) +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); +#endif /* !MBEDTLS_SSL_USE_MPS */ + #if defined(MBEDTLS_SSL_RECORD_CHECKING) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_parse_record_header( mbedtls_ssl_context const *ssl, @@ -157,9 +162,6 @@ int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl, } #endif /* MBEDTLS_SSL_RECORD_CHECKING */ -#define SSL_DONT_FORCE_FLUSH 0 -#define SSL_FORCE_FLUSH 1 - #if defined(MBEDTLS_SSL_PROTO_DTLS) /* Forward declarations for functions related to message buffering. */ @@ -258,12 +260,15 @@ static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl return( (int) remaining ); } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* * Double the retransmit timeout value, within the allowed range, * returning -1 if the maximum value has already been reached. */ -MBEDTLS_CHECK_RETURN_CRITICAL -static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) +int mbedtls_ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) { uint32_t new_timeout; @@ -298,7 +303,7 @@ static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) return( 0 ); } -static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) +void mbedtls_ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) { ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %lu millisecs", @@ -306,6 +311,8 @@ static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_PROTO_DTLS */ +//#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, const unsigned char *key_enc, const unsigned char *key_dec, @@ -418,7 +425,8 @@ static int ssl_parse_inner_plaintext( unsigned char const *content, static void ssl_extract_add_data_from_record( unsigned char* add_data, size_t *add_data_len, mbedtls_record *rec, - unsigned minor_ver ) + unsigned minor_ver, + size_t taglen ) { /* Quoting RFC 5246 (TLS 1.2): * @@ -437,15 +445,37 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, * * For TLS 1.3, the record sequence number is dropped from the AAD * and encoded within the nonce of the AEAD operation instead. + * Moreover, the additional data involves the length of the TLS + * ciphertext, not the TLS plaintext as in earlier versions. + * Quoting RFC 8446 (TLS 1.3): + * + * additional_data = TLSCiphertext.opaque_type || + * TLSCiphertext.legacy_record_version || + * TLSCiphertext.length + * + * We pass the tag length to this function in order to compute the + * ciphertext length from the inner plaintext length rec->data_len via + * + * TLSCiphertext.length = TLSInnerPlaintext.length + taglen. + * */ unsigned char *cur = add_data; + size_t ad_len_field = rec->data_len; #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) - if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + /* In TLS 1.3, the AAD contains the length of the TLSCiphertext, + * which differs from the length of the TLSInnerPlaintext + * by the length of the authentication tag. */ + ad_len_field += taglen; + } + else #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ { ((void) minor_ver); + ((void) taglen); memcpy( cur, rec->ctr, sizeof( rec->ctr ) ); cur += sizeof( rec->ctr ); } @@ -465,13 +495,13 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, *cur = rec->cid_len; cur++; - MBEDTLS_PUT_UINT16_BE( rec->data_len, cur, 0 ); + MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 ); cur += 2; } else #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ { - MBEDTLS_PUT_UINT16_BE( rec->data_len, cur, 0 ); + MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 ); cur += 2; } @@ -602,6 +632,149 @@ static void ssl_build_record_nonce( unsigned char *dst_iv, } #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_mps_transform_encrypt_default( + void* transform_, + mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ssl_transform *transform = (mbedtls_ssl_transform*) transform_; + mbedtls_record rec_alt; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + return( 0 ); + } + + /* TEMPORARY: + * Convert between different versions of record structure. + * This needs to be uniformized at some point. + */ + + rec_alt.buf = rec->buf.buf; + rec_alt.buf_len = rec->buf.buf_len; + rec_alt.data_len = rec->buf.data_len; + rec_alt.data_offset = rec->buf.data_offset; + rec_alt.type = rec->type; + rec_alt.ctr[0] = ( rec->ctr[0] >> 24 ) & 0xFF; + rec_alt.ctr[1] = ( rec->ctr[0] >> 16 ) & 0xFF; + rec_alt.ctr[2] = ( rec->ctr[0] >> 8 ) & 0xFF; + rec_alt.ctr[3] = ( rec->ctr[0] >> 0 ) & 0xFF; + rec_alt.ctr[4] = ( rec->ctr[1] >> 24 ) & 0xFF; + rec_alt.ctr[5] = ( rec->ctr[1] >> 16 ) & 0xFF; + rec_alt.ctr[6] = ( rec->ctr[1] >> 8 ) & 0xFF; + rec_alt.ctr[7] = ( rec->ctr[1] >> 0 ) & 0xFF; + mbedtls_ssl_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, &rec_alt.ver[0] ); + + ret = mbedtls_ssl_encrypt_buf( NULL, transform, &rec_alt, f_rng, p_rng ); + if( ret != 0 ) + return( ret ); + + rec->buf.data_offset = rec_alt.data_offset; + rec->buf.data_len = rec_alt.data_len; + rec->type = rec_alt.type; + + return( 0 ); +} + +int mbedtls_mps_transform_decrypt_default( void *transform_, mps_rec *rec ) +{ + mbedtls_ssl_transform *transform = (mbedtls_ssl_transform*) transform_; + + int ret; + mbedtls_record rec_alt; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + return( 0 ); + } + + /* TEMPORARY: + * Convert between different versions of record structure. + * This needs to be uniformized at some point. + */ + + rec_alt.buf = rec->buf.buf; + rec_alt.buf_len = rec->buf.buf_len; + rec_alt.data_len = rec->buf.data_len; + rec_alt.data_offset = rec->buf.data_offset; + rec_alt.type = rec->type; + rec_alt.ctr[0] = ( rec->ctr[0] >> 24 ) & 0xFF; + rec_alt.ctr[1] = ( rec->ctr[0] >> 16 ) & 0xFF; + rec_alt.ctr[2] = ( rec->ctr[0] >> 8 ) & 0xFF; + rec_alt.ctr[3] = ( rec->ctr[0] >> 0 ) & 0xFF; + rec_alt.ctr[4] = ( rec->ctr[1] >> 24 ) & 0xFF; + rec_alt.ctr[5] = ( rec->ctr[1] >> 16 ) & 0xFF; + rec_alt.ctr[6] = ( rec->ctr[1] >> 8 ) & 0xFF; + rec_alt.ctr[7] = ( rec->ctr[1] >> 0 ) & 0xFF; + mbedtls_ssl_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, &rec_alt.ver[0] ); + + ret = mbedtls_ssl_decrypt_buf( NULL, transform, &rec_alt ); + if( ret != 0 ) + return( ret ); + + rec->buf.data_offset = rec_alt.data_offset; + rec->buf.data_len = rec_alt.data_len; + rec->type = rec_alt.type; + + return( 0 ); +} + +int mbedtls_mps_transform_get_expansion_default( void *transform_, + size_t *pre_exp, size_t *post_exp ) +{ + mbedtls_ssl_transform * transform = (mbedtls_ssl_transform*) transform_; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + *pre_exp = 0; + *post_exp = 0; + return( 0 ); + } + + /* For the moment copied from mbedtls_ssl_get_record_expansion */ + *pre_exp = transform->ivlen - transform->fixed_ivlen; + switch( mbedtls_cipher_get_cipher_mode( + &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_CHACHAPOLY: + *post_exp = transform->taglen + 1; + break; + + case MBEDTLS_MODE_STREAM: + *post_exp = 0; + break; + + case MBEDTLS_MODE_CBC: + *post_exp = transform->maclen + + mbedtls_cipher_get_block_size( + &transform->cipher_ctx_enc ); + break; + + default: + return( -1 ); + } + + return( 0 ); +} + +int mbedtls_mps_transform_free_default( void *transform_ ) +{ + mbedtls_ssl_transform * transform = (mbedtls_ssl_transform*) transform_; + mbedtls_ssl_transform_free( transform ); + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, mbedtls_ssl_transform *transform, mbedtls_record *rec, @@ -656,15 +829,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ); - if( rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %" MBEDTLS_PRINTF_SIZET - " too large, maximum %" MBEDTLS_PRINTF_SIZET, - rec->data_len, - (size_t) MBEDTLS_SSL_OUT_CONTENT_LEN ) ); - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - } - /* The following two code paths implement the (D)TLSInnerPlaintext * structure present in TLS 1.3 and DTLS 1.2 + CID. * @@ -774,7 +938,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen); ret = mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, add_data_len ); @@ -820,7 +985,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, /* * Encrypt */ -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) if( mode == MBEDTLS_MODE_STREAM ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -845,7 +1010,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } } else -#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_STREAM */ #if defined(MBEDTLS_GCM_C) || \ defined(MBEDTLS_CCM_C) || \ @@ -894,7 +1059,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, * This depends on the TLS version. */ ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", iv, transform->ivlen ); @@ -1066,7 +1232,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } ssl_extract_add_data_from_record( add_data, &add_data_len, - rec, transform->minor_ver ); + rec, transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, @@ -1165,7 +1332,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) if( mode == MBEDTLS_MODE_STREAM ) { padlen = 0; @@ -1186,7 +1353,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } } else -#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_STREAM */ #if defined(MBEDTLS_GCM_C) || \ defined(MBEDTLS_CCM_C) || \ defined(MBEDTLS_CHACHAPOLY_C) @@ -1228,17 +1395,6 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, dynamic_iv = rec->ctr; } - /* Check that there's space for the authentication tag. */ - if( rec->data_len < transform->taglen ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%" MBEDTLS_PRINTF_SIZET - ") < taglen (%" MBEDTLS_PRINTF_SIZET ") ", - rec->data_len, - transform->taglen ) ); - return( MBEDTLS_ERR_SSL_INVALID_MAC ); - } - rec->data_len -= transform->taglen; - /* * Prepare nonce from dynamic and static parts. */ @@ -1252,8 +1408,20 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * Build additional data for AEAD encryption. * This depends on the TLS version. */ + + /* Check that there's space for the authentication tag. */ + if( rec->data_len < transform->taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < taglen (%d) ", + (unsigned) rec->data_len, + (unsigned) transform->taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + rec->data_len -= transform->taglen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", add_data, add_data_len ); @@ -1366,7 +1534,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * Further, we still know that data_len > minlen */ rec->data_len -= transform->maclen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); /* Calculate expected MAC. */ MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, @@ -1621,7 +1790,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, */ rec->data_len -= transform->maclen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); #if defined(MBEDTLS_SSL_PROTO_SSL3) if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) @@ -1743,6 +1913,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, return( 0 ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #undef MAC_NONE #undef MAC_PLAINTEXT #undef MAC_CIPHERTEXT @@ -1858,6 +2030,9 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_ZLIB_SUPPORT */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Fill the input message buffer by appending data to it. * The amount of data already fetched is in ssl->in_left. @@ -2000,7 +2175,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { - if( ssl_double_retransmit_timeout( ssl ) != 0 ) + if( mbedtls_ssl_double_retransmit_timeout( ssl ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); return( MBEDTLS_ERR_SSL_TIMEOUT ); @@ -2090,7 +2265,26 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) return( 0 ); } +#endif /* !MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) +{ + int ret; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +cleanup: + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); + + return( ret); +} +#else /* MBEDTLS_SSL_USE_MPS */ /* * Flush any data not yet written */ @@ -2156,6 +2350,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Functions to handle the DTLS retransmission state machine @@ -2494,7 +2689,7 @@ void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) */ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) { - ssl_reset_retransmit_timeout( ssl ); + mbedtls_ssl_reset_retransmit_timeout( ssl ); mbedtls_ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && @@ -2511,6 +2706,7 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) * Handshake layer functions */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Write (DTLS: or queue) current handshake (including CCS) message. * @@ -2534,6 +2730,12 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) * - ssl->out_msg: the record contents (handshake headers + content) */ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) +{ + return( mbedtls_ssl_write_handshake_msg_ext( ssl, 1 /* update checksum */ ) ); +} + +int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl, + int update_checksum ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; const size_t hs_len = ssl->out_msglen - 4; @@ -2649,8 +2851,11 @@ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_PROTO_DTLS */ /* Update running hashes of handshake messages seen */ - if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST && + update_checksum ) + { ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen ); + } } /* Either send now, or just save to be sent (and resent) later */ @@ -2742,7 +2947,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) /* Skip writing the record content type to after the encryption, * as it may change when using the CID extension. */ - mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + mbedtls_ssl_write_wire_version( ssl->major_ver, ssl->minor_ver, ssl->conf->transport, ssl->out_hdr + 1 ); memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 ); @@ -2758,7 +2963,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) rec.data_offset = ssl->out_msg - rec.buf; memcpy( &rec.ctr[0], ssl->out_ctr, 8 ); - mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + mbedtls_ssl_write_wire_version( ssl->major_ver, ssl->minor_ver, ssl->conf->transport, rec.ver ); rec.type = ssl->out_msgtype; @@ -2871,6 +3076,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -3000,6 +3206,7 @@ static size_t ssl_get_reassembly_buffer_size( size_t msg_len, #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if !defined(MBEDTLS_SSL_USE_MPS) static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ) { return( ( ssl->in_msg[1] << 16 ) | @@ -3096,6 +3303,34 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->handshake != NULL ) + { + const char magic_hrr_string[32] = { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, + 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, + 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, + 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, + 0x33 ,0x9C }; + /* + * If the server responds with the HRR message then a special handling + * with the modified transcript hash is necessary. We compute this hash later. + */ + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_SERVER_HELLO && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ) + 2, + &magic_hrr_string[0], 32 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "--- Special HRR Checksum Processing" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "--- Update Checksum ( ssl_prepare_handshake_record )" ) ); + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + return( 0 ); } @@ -3140,6 +3375,9 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) #endif } +#endif /* !MBEDTLS_SSL_USE_MPS */ + + /* * DTLS anti-replay: RFC 6347 4.1.2.6 * @@ -3475,6 +3713,7 @@ static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ +#if !defined(MBEDTLS_SSL_USE_MPS) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_check_record_type( uint8_t record_type ) { @@ -3799,6 +4038,19 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl, done = 1; } #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + + /* In TLS 1.3, always treat ChangeCipherSpec records + * as unencrypted. The only thing we do with them is + * check the length and content and ignore them. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->transform_in != NULL && + ssl->transform_in->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + if( rec->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + done = 1; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + if( !done && ssl->transform_in != NULL ) { unsigned char const old_msg_type = rec->type; @@ -3830,20 +4082,22 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", rec->buf + rec->data_offset, rec->data_len ); -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) /* We have already checked the record content type * in ssl_parse_record_header(), failing or silently * dropping the record in the case of an unknown type. * - * Since with the use of CIDs, the record content type - * might change during decryption, re-check the record - * content type, but treat a failure as fatal this time. */ + * Since with the use of CIDs or TLS 1.3, the record content type + * might change during decryption, re-check the record content type, + * but treat a failure as fatal this time. */ if( ssl_check_record_type( rec->type ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); return( MBEDTLS_ERR_SSL_INVALID_RECORD ); } -#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID || + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( rec->data_len == 0 ) { @@ -3940,6 +4194,10 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); +#if defined(MBEDTLS_SSL_USE_MPS) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#endif + if( ssl->keep_current_message == 0 ) { do { @@ -4880,6 +5138,19 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); } #endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Ignore ChangeCipherSpec in TLS 1.3 compatibility mode" ) ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); +#else + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ChangeCipherSpec invalid in TLS 1.3 without compatibility mode" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) @@ -4967,6 +5238,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ) { @@ -4990,6 +5262,31 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", level, message )); +#if defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + if( level == MBEDTLS_SSL_ALERT_LEVEL_FATAL ) + { + ret = mbedtls_mps_send_fatal( &ssl->mps.l4, message ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = mbedtls_mps_write_alert( &ssl->mps.l4, message ); + if( ret != 0 ) + return( ret ); + } + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + +#else /* MBEDTLS_SSL_USE_MPS */ + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; ssl->out_msglen = 2; ssl->out_msg[0] = level; @@ -5000,11 +5297,15 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); return( ret ); } - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); return( 0 ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -5101,6 +5402,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + /* Once ssl->out_hdr as the address of the beginning of the * next outgoing record is set, deduce the other pointers. * @@ -5109,6 +5412,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) * and the caller has to make sure there's space for this. */ +#if !defined(MBEDTLS_SSL_USE_MPS) static size_t ssl_transform_get_explicit_iv_len( mbedtls_ssl_transform const *transform ) { @@ -5227,7 +5531,16 @@ void mbedtls_ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ) mbedtls_ssl_update_out_pointers( ssl, NULL /* no transform enabled */ ); mbedtls_ssl_update_in_pointers ( ssl ); } +#endif /* ! MBEDTLS_SSL_USE_MPS */ +#if defined(MBEDTLS_SSL_USE_MPS) +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + /* TODO: Implement */ + ((void) ssl); + return( 0 ); +} +#else /* MBEDTLS_SSL_USE_MPS */ /* * SSL get accessors */ @@ -5235,9 +5548,18 @@ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) { return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); } +#endif /* MBEDTLS_SSL_USE_MPS */ int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Case A: We're currently holding back * a message for further processing. @@ -5289,8 +5611,11 @@ int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: nothing pending" ) ); return( 0 ); -} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) { @@ -5352,6 +5677,8 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) return( (int)( out_hdr_len + transform_expansion ) ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_RENEGOTIATION) /* * Check record counters and renegotiate if they're above the limit. @@ -5385,62 +5712,405 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_RENEGOTIATION */ -/* - * Receive application data decrypted from the SSL layer - */ -int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - if( ssl == NULL || ssl->conf == NULL ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); +/* This function is called from mbedtls_ssl_read() when a handshake message is + * received after the initial handshake. In TLS 1.2, such messages usually + * trigger renegotiations. In (D)TLS 1.3, renegotiation has been replaced + * by a number of specific post-handshake messages. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static int ssl_handle_hs_message_post_handshake_tls12( mbedtls_ssl_context *ssl ); +#endif - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static int ssl_handle_hs_message_post_handshake_tls13( mbedtls_ssl_context *ssl ); +#endif -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) +static int ssl_handle_hs_message_post_handshake( mbedtls_ssl_context *ssl ) +{ + /* Check protocol version and dispatch accordingly. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) { - if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) - return( ret ); + return( ssl_handle_hs_message_post_handshake_tls13( ssl ) ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ - if( ssl->handshake != NULL && - ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) - { - if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) - return( ret ); - } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + if( ssl->minor_ver <= MBEDTLS_SSL_MINOR_VERSION_3 ) + { + return( ssl_handle_hs_message_post_handshake_tls12( ssl ) ); } -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ - /* - * Check if renegotiation is necessary and/or handshake is - * in process. If yes, perform/continue, and fall through - * if an unexpected packet is received while the client - * is waiting for the ServerHello. - * - * (There is no equivalent to the last condition on - * the server-side as it is not treated as within - * a handshake while waiting for the ClientHello - * after a renegotiation request.) - */ + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} -#if defined(MBEDTLS_SSL_RENEGOTIATION) - ret = ssl_check_ctr_renegotiate( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +static int ssl_check_new_session_ticket( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_USE_MPS) + int ret; + mbedtls_mps_handshake_in msg; + ret = mbedtls_mps_read_handshake( &ssl->mps.l4, &msg ); + if( ret != 0 ) return( ret ); - } -#endif - if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + if( msg.type != MBEDTLS_SSL_HS_NEW_SESSION_TICKET ) + return( 0 ); +#else /* MBEDTLS_SSL_USE_MPS */ + if( ( ssl->in_hslen == mbedtls_ssl_hs_hdr_len( ssl ) ) || + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_NEW_SESSION_TICKET ) ) { - ret = mbedtls_ssl_handshake( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { + return( 0 ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket received" ) ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET ); + + return( MBEDTLS_ERR_SSL_WANT_READ ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +static int ssl_handle_hs_message_post_handshake_tls13( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int ret; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received post-handshake message" ) ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ret = ssl_check_new_session_ticket( ssl ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* Fail in all other cases. */ + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static int ssl_handle_hs_message_post_handshake_tls12( mbedtls_ssl_context *ssl ) +{ + /* + * - For client-side, expect SERVER_HELLO_REQUEST. + * - For server-side, expect CLIENT_HELLO. + * - Fail (TLS) or silently drop record (DTLS) in other cases. + */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + return( 0 ); + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + return( 0 ); + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + /* Determine whether renegotiation attempt should be accepted */ + if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == + MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) ) + { + /* + * Accept renegotiation request + */ + + /* DTLS clients need to know renego is server-initiated */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + } +#endif + ret = mbedtls_ssl_start_renegotiation( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation", + ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + /* + * Refuse renegotiation + */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* SSLv3 does not have a "no_renegotiation" warning, so + we send a fatal alert and abort the connection. */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret, msg_type; + size_t data_read; + unsigned char *src; + mbedtls_mps_reader *rd; + + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + goto cleanup; + } + } + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + msg_type = ret; + + if( msg_type == MBEDTLS_MPS_MSG_HS ) + { + ret = ssl_handle_hs_message_post_handshake( ssl ); + if( ret != 0 ) + goto cleanup; + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( msg_type == MBEDTLS_MPS_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ignoring non-fatal non-closure alert" ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( msg_type != MBEDTLS_MPS_MSG_APP ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_application( &ssl->mps.l4, &rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_get( rd, len, &src, &data_read ) ); + memcpy( buf, src, data_read ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + return( data_read ); + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( ret ); +} + +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; + mbedtls_writer *msg; + unsigned char *wr_buf; + mbedtls_mps_size_t wr_buf_len; + + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps.l4, + &msg ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, + &wr_buf, &wr_buf_len ) ); + + if( wr_buf_len < len ) + len = wr_buf_len; + + memcpy( wr_buf, buf, len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, + wr_buf_len - len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + ret = len; + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( ret ); +} + +/* + * Notify the peer that the connection is being closed + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + ret = mbedtls_mps_close( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( 0 ); +} + + +#else /* MBEDTLS_SSL_USE_MPS */ + +/* + * Receive application data decrypted from the SSL layer + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + if( ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + return( ret ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Check if renegotiation is necessary and/or handshake is + * in process. If yes, perform/continue, and fall through + * if an unexpected packet is received while the client + * is waiting for the ServerHello. + * + * (There is no equivalent to the last condition on + * the server-side as it is not treated as within + * a handshake while waiting for the ClientHello + * after a renegotiation request.) + */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ret = ssl_check_ctr_renegotiate( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); return( ret ); } @@ -5483,135 +6153,15 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); - - /* - * - For client-side, expect SERVER_HELLO_REQUEST. - * - For server-side, expect CLIENT_HELLO. - * - Fail (TLS) or silently drop record (DTLS) in other cases. - */ - -#if defined(MBEDTLS_SSL_CLI_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && - ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || - ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + ret = ssl_handle_hs_message_post_handshake( ssl ); + if( ret != 0) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); - - /* With DTLS, drop the packet (probably from last handshake) */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - { - continue; - } -#endif - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } -#endif /* MBEDTLS_SSL_CLI_C */ - -#if defined(MBEDTLS_SSL_SRV_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); - - /* With DTLS, drop the packet (probably from last handshake) */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - { - continue; - } -#endif - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } -#endif /* MBEDTLS_SSL_SRV_C */ - -#if defined(MBEDTLS_SSL_RENEGOTIATION) - /* Determine whether renegotiation attempt should be accepted */ - if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || - ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && - ssl->conf->allow_legacy_renegotiation == - MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) ) - { - /* - * Accept renegotiation request - */ - - /* DTLS clients need to know renego is server-initiated */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && - ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) - { - ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; - } -#endif - ret = mbedtls_ssl_start_renegotiation( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation", - ret ); - return( ret ); - } - } - else -#endif /* MBEDTLS_SSL_RENEGOTIATION */ - { - /* - * Refuse renegotiation - */ - - MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); - -#if defined(MBEDTLS_SSL_PROTO_SSL3) - if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) - { - /* SSLv3 does not have a "no_renegotiation" warning, so - we send a fatal alert and abort the connection. */ - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } - else -#endif /* MBEDTLS_SSL_PROTO_SSL3 */ -#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) - { - if( ( ret = mbedtls_ssl_send_alert_message( ssl, - MBEDTLS_SSL_ALERT_LEVEL_WARNING, - MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) - { - return( ret ); - } - } - else -#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || - MBEDTLS_SSL_PROTO_TLS1_2 */ - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); - } + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_handle_hs_message_post_handshake", + ret ); + return( ret ); } - /* At this point, we don't know whether the renegotiation has been - * completed or not. The cases to consider are the following: - * 1) The renegotiation is complete. In this case, no new record - * has been read yet. - * 2) The renegotiation is incomplete because the client received - * an application data record while awaiting the ServerHello. - * 3) The renegotiation is incomplete because the client received - * a non-handshake, non-application data message while awaiting - * the ServerHello. - * In each of these case, looping will be the proper action: - * - For 1), the next iteration will read a new record and check - * if it's application data. - * - For 2), the loop condition isn't satisfied as application data - * is present, hence continue is the same as break - * - For 3), the loop condition is satisfied and read_record - * will re-deliver the message that was held back by the client - * when expecting the ServerHello. - */ + /* Post-handshake handshake messages are not passed to the user. */ continue; } #if defined(MBEDTLS_SSL_RENEGOTIATION) @@ -5830,12 +6380,19 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_ } #endif - if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) +#if defined(MBEDTLS_ZERO_RTT) + /* TODO: What's the purpose of this check? */ + if( ( ssl->handshake != NULL ) && + ( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_OFF ) ) +#endif /* MBEDTLS_ZERO_RTT */ { - if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); - return( ret ); + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } } } @@ -5878,26 +6435,7 @@ int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) return( 0 ); } -void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) -{ - if( transform == NULL ) - return; - -#if defined(MBEDTLS_ZLIB_SUPPORT) - deflateEnd( &transform->ctx_deflate ); - inflateEnd( &transform->ctx_inflate ); -#endif - - mbedtls_cipher_free( &transform->cipher_ctx_enc ); - mbedtls_cipher_free( &transform->cipher_ctx_dec ); - -#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) - mbedtls_md_free( &transform->md_ctx_enc ); - mbedtls_md_free( &transform->md_ctx_dec ); -#endif - - mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); -} +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -5935,15 +6473,23 @@ static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_DTLS */ -/* - * Convert version numbers to/from wire format - * and, for DTLS, to/from TLS equivalent. - * - * For TLS this is the identity. - * For DTLS, use 1's complement (v -> 255 - v, and then map as follows: - * 1.0 <-> 3.2 (DTLS 1.0 is based on TLS 1.1) - * 1.x <-> 3.x+1 for x != 0 (DTLS 1.2 based on TLS 1.2) - */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + +void mbedtls_ssl_write_wire_version( int major, int minor, int transport, + unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* TLS 1.3 still uses the TLS 1.3 version identifier + * for backwards compatibility. */ + if( minor == MBEDTLS_SSL_MINOR_VERSION_4 ) + minor = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + mbedtls_ssl_write_version( major, minor, transport, ver ); +} + void mbedtls_ssl_write_version( int major, int minor, int transport, unsigned char ver[2] ) { @@ -5988,4 +6534,90 @@ void mbedtls_ssl_read_version( int *major, int *minor, int transport, } } +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) +{ + if( transform == NULL ) + return; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + mbedtls_cipher_free( &transform->cipher_ctx_enc ); + mbedtls_cipher_free( &transform->cipher_ctx_dec ); + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); +#endif + + mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); +} + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SSL_USE_MPS) + +/* + * Send pending fatal alerts or warnings. + */ +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl->send_alert == 0 ) + return( 0 ); + + /* Send alert if requested */ + if( ssl->send_alert == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + ssl->alert_type ) ); + + ret = mbedtls_mps_send_fatal( &ssl->mps.l4, + ssl->alert_type ); + ssl->send_alert = 2; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + if( ret != 0 ) + return( ret ); + } + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + return( ssl->alert_reason ); +} + +#else /* MBEDTLS_SSL_USE_MPS */ + +/* + * Send pending fatal alerts or warnings. + */ +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ) +{ + int ret; + + /* Send alert if requested */ + if( ssl->send_alert != 0 ) + { + ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + ssl->alert_type ); + if( ret != 0 ) + return( ret ); + } + + ssl->send_alert = 0; + ssl->alert_type = 0; + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2efb13cc33c6..0e13b29b7ad3 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -19,6 +19,8 @@ #include "common.h" +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_SRV_C) #if defined(MBEDTLS_PLATFORM_C) @@ -992,7 +994,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, * different uses based on keyUsage, eg if they want to avoid signing * and decrypting with the same RSA key. */ - if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info->key_exchange, MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " @@ -4853,3 +4855,5 @@ int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_SSL_SRV_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c index e0126cc9d1c2..375ac3c32c8d 100644 --- a/library/ssl_ticket.c +++ b/library/ssl_ticket.c @@ -196,7 +196,6 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, * The key_name, iv, and length of encrypted_state are the additional * authenticated data. */ - int mbedtls_ssl_ticket_write( void *p_ticket, const mbedtls_ssl_session *session, unsigned char *start, @@ -360,7 +359,6 @@ int mbedtls_ssl_ticket_parse( void *p_ticket, ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; goto cleanup; } - /* Actually load session */ if( ( ret = mbedtls_ssl_session_load( session, ticket, clear_len ) ) != 0 ) goto cleanup; @@ -400,7 +398,7 @@ void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif - mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); + mbedtls_platform_zeroize( (void*) ctx, sizeof( mbedtls_ssl_ticket_context ) ); } #endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7badec51ae36..e7608c5d6b32 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -230,7 +230,8 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && \ + defined(MBEDTLS_SSL_CLI_C) if( src->ticket != NULL ) { dst->ticket = mbedtls_calloc( 1, src->ticket_len ); @@ -239,7 +240,14 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, memcpy( dst->ticket, src->ticket, src->ticket_len ); } -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET) && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + /* Resumption Key */ + memcpy( dst->key, src->key, src->key_len ); + +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ return( 0 ); } @@ -830,6 +838,208 @@ static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char * #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SHA256_C) +static int ssl_get_handshake_transcript_sha256( mbedtls_ssl_context *ssl, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ + int ret; + mbedtls_sha256_context sha256; + + if( dst_len < 32 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + mbedtls_sha256_init( &sha256 ); + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + if( ( ret = mbedtls_sha256_finish_ret( &sha256, dst ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_finish_ret", ret ); + goto exit; + } + + *olen = 32; + +exit: + + mbedtls_sha256_free( &sha256 ); + return( ret ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int ssl_get_handshake_transcript_sha384( mbedtls_ssl_context *ssl, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ + int ret; + mbedtls_sha512_context sha512; + + if( dst_len < 48 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + mbedtls_sha512_init( &sha512 ); + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + if( ( ret = mbedtls_sha512_finish_ret( &sha512, dst ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_finish_ret", ret ); + goto exit; + } + + *olen = 48; + +exit: + + mbedtls_sha512_free( &sha512 ); + return( ret ); +} +#endif /* MBEDTLS_SHA512_C */ + +static int ssl_hash_transcript_core( mbedtls_ssl_context *ssl, + mbedtls_md_type_t md, + unsigned char *transcript, + size_t len, + size_t *olen ) +{ + int ret; + size_t hash_size; + + if( len < 4 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md, + transcript + 4, + len - 4, + &hash_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 4, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + transcript[0] = MBEDTLS_SSL_HS_MESSAGE_HASH; + transcript[1] = 0; + transcript[2] = 0; + transcript[3] = (unsigned char) hash_size; + + *olen = 4 + hash_size; + return( 0 ); +} + +#if defined(MBEDTLS_SHA256_C) +static int ssl_hash_transcript_sha256( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char transcript[ 32 + 4 ]; + size_t olen; + + ret = ssl_hash_transcript_core( ssl, MBEDTLS_MD_SHA256, + transcript, + sizeof( transcript ), + &olen ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 4, "ssl_hash_transcript_core", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Truncated SHA-256 handshake transcript", + transcript, olen ); + + mbedtls_sha256_starts_ret( &ssl->handshake->fin_sha256, 0 ); + ssl_update_checksum_sha256( ssl, transcript, olen ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int ssl_hash_transcript_sha384( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char transcript[ 48 + 4 ]; + size_t olen; + + ret = ssl_hash_transcript_core( ssl, MBEDTLS_MD_SHA384, + transcript, + sizeof( transcript ), + &olen ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Truncated SHA-384 handshake transcript", + transcript, olen ); + + mbedtls_sha512_starts_ret( &ssl->handshake->fin_sha512, 1 ); + ssl_update_checksum_sha384( ssl, transcript, olen ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA512_C */ + +/* Replace Transcript-Hash(X) by + * Transcript-Hash( message_hash || + * 00 00 Hash.length || + * X ) + */ +int mbedtls_ssl_hash_transcript( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + +#if defined(MBEDTLS_SHA256_C) + ret = ssl_hash_transcript_sha256( ssl ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + ret = ssl_hash_transcript_sha384( ssl ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SHA512_C */ + +exit: + return( 0 ); +} + +int mbedtls_ssl_get_handshake_transcript( mbedtls_ssl_context *ssl, + const mbedtls_md_type_t md, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ +#if defined(MBEDTLS_SHA512_C) + if( md == MBEDTLS_MD_SHA384 ) + { + return( ssl_get_handshake_transcript_sha384( ssl, dst, dst_len, olen ) ); + } + else +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + if( md == MBEDTLS_MD_SHA256 ) + { + return( ssl_get_handshake_transcript_sha256( ssl, dst, dst_len, olen ) ); + } + else +#endif /* MBEDTLS_SHA256_C */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ defined(MBEDTLS_USE_PSA_CRYPTO) MBEDTLS_CHECK_RETURN_CRITICAL @@ -853,6 +1063,7 @@ static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) #endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_SSL_EXPORT_KEYS) static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) { @@ -889,6 +1100,7 @@ static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) return( MBEDTLS_SSL_TLS_PRF_NONE ); } #endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, const unsigned char *secret, size_t slen, @@ -929,7 +1141,7 @@ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) ); } - +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* Type for the TLS PRF */ typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *, const unsigned char *, size_t, @@ -2119,6 +2331,8 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch } #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); @@ -2174,6 +2388,8 @@ static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) } #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + /* * Handshake functions */ @@ -2731,7 +2947,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_ECP_C */ if( mbedtls_ssl_check_cert_usage( chain, - ciphersuite_info, + ciphersuite_info->key_exchange, ! ssl->conf->endpoint, &ssl->session_negotiate->verify_result ) != 0 ) { @@ -3010,6 +3226,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) @@ -3022,7 +3239,7 @@ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; else #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) ssl->handshake->update_checksum = ssl_update_checksum_sha384; @@ -3040,6 +3257,7 @@ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) { #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ @@ -3066,9 +3284,64 @@ void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start_tls13( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_context sha256_debug; +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context sha512_debug; +#endif /* MBEDTLS_SHA512_C */ + unsigned char padbuf[MBEDTLS_MD_MAX_SIZE]; +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (before)", + (unsigned char*) ssl->handshake->fin_sha256.state, 32 ); + mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (after)", ( unsigned char* ) + ssl->handshake->fin_sha256.state, 32 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_init( &sha256_debug ); + mbedtls_sha256_clone( &sha256_debug, &ssl->handshake->fin_sha256 ); + mbedtls_sha256_finish_ret( &sha256_debug, padbuf ); + mbedtls_sha256_free( &sha256_debug ); + MBEDTLS_SSL_DEBUG_BUF( 4, "SHA-256 handshake hash", (unsigned char*) + padbuf, 32 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (before)", (unsigned char*) + ssl->handshake->fin_sha512.state, 48 ); + mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (after)", ( unsigned char* ) + ssl->handshake->fin_sha512.state, 48 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_init( &sha512_debug ); + mbedtls_sha512_starts_ret( &sha512_debug, 1 ); + mbedtls_sha512_clone( &sha512_debug, &ssl->handshake->fin_sha512 ); + mbedtls_sha512_finish_ret( &sha512_debug, padbuf ); + mbedtls_sha512_free( &sha512_debug ); + MBEDTLS_SSL_DEBUG_BUF( 4, "SHA-384 handshake hash", ( unsigned char* ) + padbuf, 48 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +#endif /* MBEDTLS_SHA512_C */ +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ -static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, - const unsigned char *buf, size_t len ) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static void ssl_update_checksum_start_tls12( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) { #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -3105,7 +3378,7 @@ static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SHA256_C) -static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, +static void ssl_update_checksum_sha256_tls12( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -3117,7 +3390,7 @@ static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, #endif #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) -static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, +static void ssl_update_checksum_sha384_tls12( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -3128,6 +3401,106 @@ static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, } #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256_tls13( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_context sha256; + unsigned char padbuf[32]; + +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + if( ( ret = mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, + buf, + len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_update_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state", ( unsigned char* ) + ssl->handshake->fin_sha256.state, 32 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_init( &sha256 ); + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + if( ( ret = mbedtls_sha256_finish_ret( &sha256, + padbuf ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_finish_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake hash", ( unsigned char* ) + padbuf, 32 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + +exit:; +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_free( &sha256 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384_tls13( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_context sha512; + unsigned char padbuf[48]; +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + if( ( ret = mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, + buf, + len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_update_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript hash", ( unsigned char* ) + ssl->handshake->fin_sha512.state, 48 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_init( &sha512 ); + + if( ( ret = mbedtls_sha512_starts_ret( &sha512, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_starts_ret", ret ); + goto exit; + } + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + if( ( ret = mbedtls_sha512_finish_ret( &sha512, padbuf ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_finish_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake hash", ( unsigned char* )padbuf, 48 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + +exit:; +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_free( &sha512); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +} +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_SSL_PROTO_SSL3) static void ssl_calc_finished_ssl( @@ -3450,6 +3823,7 @@ void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) mbedtls_free( ssl->handshake ); ssl->handshake = NULL; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Free the previous transform and switch in the current one */ @@ -3460,6 +3834,7 @@ void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) } ssl->transform = ssl->transform_negotiate; ssl->transform_negotiate = NULL; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) ); } @@ -3733,6 +4108,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) mbedtls_platform_zeroize( buf, hash_len ); return( ret ); } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) { @@ -3745,7 +4121,7 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) mbedtls_md5_starts_ret( &handshake->fin_md5 ); mbedtls_sha1_starts_ret( &handshake->fin_sha1 ); #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA256_C) #if defined(MBEDTLS_USE_PSA_CRYPTO) handshake->fin_sha256_psa = psa_hash_operation_init(); @@ -3764,7 +4140,7 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) mbedtls_sha512_starts_ret( &handshake->fin_sha512, 1 ); #endif #endif -#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ handshake->update_checksum = ssl_update_checksum_start; @@ -3823,13 +4199,17 @@ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_handshake_init( mbedtls_ssl_context *ssl ) { /* Clear old handshake information if present */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform_negotiate ) mbedtls_ssl_transform_free( ssl->transform_negotiate ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + if( ssl->session_negotiate ) mbedtls_ssl_session_free( ssl->session_negotiate ); if( ssl->handshake ) mbedtls_ssl_handshake_free( ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Either the pointers are now NULL or cleared properly and can be freed. * Now allocate missing structures. @@ -3838,6 +4218,14 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) { ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + ssl->transform_handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + ssl->transform_earlydata = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + ssl->transform_application = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( ssl->session_negotiate == NULL ) { @@ -3856,18 +4244,42 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) #endif /* All pointers should exist and can be directly freed without issue */ - if( ssl->handshake == NULL || + if( ssl->handshake == NULL || +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) ssl->transform_negotiate == NULL || - ssl->session_negotiate == NULL ) +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + ssl->transform_handshake == NULL || + ssl->transform_earlydata == NULL || + ssl->transform_application == NULL || +#endif + ssl->session_negotiate == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); mbedtls_free( ssl->handshake ); - mbedtls_free( ssl->transform_negotiate ); - mbedtls_free( ssl->session_negotiate ); - ssl->handshake = NULL; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_free( ssl->transform_negotiate ); ssl->transform_negotiate = NULL; +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#endif + + mbedtls_free( ssl->session_negotiate ); ssl->session_negotiate = NULL; return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -3875,9 +4287,19 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) /* Initialize structures */ mbedtls_ssl_session_init( ssl->session_negotiate ); - mbedtls_ssl_transform_init( ssl->transform_negotiate ); ssl_handshake_params_init( ssl->handshake ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_ssl_transform_init( ssl->transform_negotiate ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_init( ssl->transform_handshake ); + mbedtls_ssl_transform_init( ssl->transform_earlydata ); + mbedtls_ssl_transform_init( ssl->transform_application ); +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -3924,7 +4346,7 @@ static int ssl_cookie_check_dummy( void *ctx, return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); } -#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || MBEDTLS_SSL_COOKIE_C ) && MBEDTLS_SSL_SRV_C */ /* * Initialize an SSL context @@ -3934,38 +4356,178 @@ void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); } -/* - * Setup an SSL context - */ - -int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, - const mbedtls_ssl_config *conf ) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_mps_init( mbedtls_ssl_context *ssl ) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; - size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; - - ssl->conf = conf; - - /* - * Prepare base structures - */ + int ret; - /* Set to NULL in case of an error condition */ - ssl->out_buf = NULL; - -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - ssl->in_buf_len = in_buf_len; -#endif - ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); - if( ssl->in_buf == NULL ) + /* Allocator */ { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", in_buf_len ) ); - ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; - goto error; + /* TODO: At the moment, the allocator doesn't support + * different sizes for the in/out buffers. That's a + * trivial change to the API, but for now, just + * overapproximate. */ + size_t max_size; + if( MBEDTLS_SSL_IN_BUFFER_LEN > MBEDTLS_SSL_OUT_BUFFER_LEN ) + max_size = MBEDTLS_SSL_IN_BUFFER_LEN; + else + max_size = MBEDTLS_SSL_OUT_BUFFER_LEN; + + ret = mps_alloc_init( &ssl->mps.alloc, + (mbedtls_mps_size_t) max_size ); + if( ret != 0 ) + goto exit; } -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + /* Layer 1 */ + ret = mps_l1_init( &ssl->mps.l1, ssl->conf->transport, + &ssl->mps.alloc, + ssl->p_bio, ssl->f_send, + ssl->p_bio, ssl->f_recv ); + if( ret != 0 ) + goto exit; + + /* Layer 2 */ + ret = mps_l2_init( &ssl->mps.l2, &ssl->mps.l1, + ssl->conf->transport, + /* TODO: Use suitable config option */ 4096, + /* TODO: Use suitable config option */ 4096, + /* TODO: Add RNG for < TLS 1.3 */ NULL, + /* TODO: Add RNG for < TLS 1.3 */ NULL ); + if( ret != 0 ) + goto exit; + + /* Layer 3 */ + ret = mps_l3_init( &ssl->mps.l3, &ssl->mps.l2, + ssl->conf->transport ); + if( ret != 0 ) + goto exit; + + /* Layer 4 */ + ret = mbedtls_mps_init( &ssl->mps.l4, &ssl->mps.l3, + ssl->conf->transport, + /* TODO: Use suitable config option */ 4096 ); + if( ret != 0 ) + goto exit; + + /* Register TLS 1.3 content types. + * + * TODO: In a TLS-1.3-only configuration, this could be hardcoded. + */ + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_HS, + MBEDTLS_MPS_SPLIT_ENABLED, + MBEDTLS_MPS_PACK_ENABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_ALERT, + MBEDTLS_MPS_SPLIT_DISABLED, + MBEDTLS_MPS_PACK_DISABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_CCS, + MBEDTLS_MPS_SPLIT_DISABLED, + MBEDTLS_MPS_PACK_DISABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_DROP ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_APP, + MBEDTLS_MPS_SPLIT_ENABLED, + MBEDTLS_MPS_PACK_ENABLED, + MBEDTLS_MPS_EMPTY_ALLOWED, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + + /* Register initial epoch + * + * TODO: This will go away once MPS is setup with a NULL-epoch by default. + */ + { + mbedtls_mps_epoch_id initial_epoch; + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, NULL, &initial_epoch ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, initial_epoch ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, initial_epoch ); + if( ret != 0 ) + goto exit; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_transform_free = mbedtls_mps_transform_free_default; + mbedtls_mps_transform_encrypt = mbedtls_mps_transform_encrypt_default; + mbedtls_mps_transform_decrypt = mbedtls_mps_transform_decrypt_default; + mbedtls_mps_transform_get_expansion = mbedtls_mps_transform_get_expansion_default; +#endif /* MBEDTLS_SSL_USE_MPS */ + +exit: + + if( ret != 0 ) + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + + return( ret ); +} + +static void ssl_mps_free( mbedtls_ssl_context *ssl ) +{ + mbedtls_mps_free( &ssl->mps.l4 ); + mps_l3_free( &ssl->mps.l3 ); + mps_l2_free( &ssl->mps.l2 ); + mps_l1_free( &ssl->mps.l1 ); + mps_alloc_free( &ssl->mps.alloc ); +} +#endif /* MEDTLS_SSL_USE_MPS */ + +/* + * Setup an SSL context + */ + +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if !defined(MBEDTLS_SSL_USE_MPS) + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif /* !MBEDTLS_SSL_USE_MPS */ + + ssl->conf = conf; + + /* + * Prepare base structures + */ + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* Set to NULL in case of an error condition */ + ssl->out_buf = NULL; + +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + ssl->in_buf_len = in_buf_len; +#endif + ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); + if( ssl->in_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", in_buf_len ) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) ssl->out_buf_len = out_buf_len; #endif ssl->out_buf = mbedtls_calloc( 1, out_buf_len ); @@ -3976,7 +4538,41 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, goto error; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_reset_in_out_pointers( ssl ); +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->out_ctr = ssl->out_buf + 3; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_hdr = ssl->in_buf; + ssl->in_ctr = ssl->in_buf + 3; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_ctr = ssl->in_buf; + ssl->in_hdr = ssl->in_buf + 8; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif /* !MBEDTLS_SSL_USE_MPS */ #if defined(MBEDTLS_SSL_DTLS_SRTP) memset( &ssl->dtls_srtp_info, 0, sizeof(ssl->dtls_srtp_info) ); @@ -3985,14 +4581,45 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) goto error; + /* Initialize ticket structure */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + ssl->session_negotiate->ticket = NULL; +#endif /* ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = ssl_mps_init( ssl ); + if( ret != 0 ) + goto error; +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_SRV_C) + if( conf->endpoint == MBEDTLS_SSL_IS_SERVER && + conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED && + conf->max_early_data > 0 ) + { + ssl->early_data_server_buf = mbedtls_calloc( 1, conf->max_early_data ); + ssl->early_data_server_buf_len = conf->max_early_data; + if( ssl->early_data_server_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", conf->max_early_data ) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + } +#endif /* MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_ZERO_RTT */ + return( 0 ); error: - mbedtls_free( ssl->in_buf ); - mbedtls_free( ssl->out_buf ); ssl->conf = NULL; +#if !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_free( ssl->in_buf ); + mbedtls_free( ssl->out_buf ); + #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) ssl->in_buf_len = 0; ssl->out_buf_len = 0; @@ -4011,7 +4638,15 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, ssl->out_len = NULL; ssl->out_iv = NULL; ssl->out_msg = NULL; +#endif /* MBEDTLS_SSL_USE_MPS */ +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) + if( conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_free( ssl->early_data_server_buf ); + ssl->early_data_server_buf = NULL; + } +#endif return( ret ); } @@ -4025,6 +4660,8 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if !defined(MBEDTLS_SSL_USE_MPS) #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) size_t in_buf_len = ssl->in_buf_len; size_t out_buf_len = ssl->out_buf_len; @@ -4032,6 +4669,7 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; #endif +#endif /* !MBEDTLS_SSL_USE_MPS */ #if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \ !defined(MBEDTLS_SSL_SRV_C) @@ -4053,8 +4691,15 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) #endif ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; +#if !defined(MBEDTLS_SSL_USE_MPS) ssl->in_offt = NULL; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_reset_in_out_pointers( ssl ); +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + ssl->out_msg = ssl->out_buf + 13; + ssl->in_msg = ssl->in_buf + 13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ ssl->in_msgtype = 0; ssl->in_msglen = 0; @@ -4081,12 +4726,6 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) ); - ssl->transform_in = NULL; - ssl->transform_out = NULL; - - ssl->session_in = NULL; - ssl->session_out = NULL; - memset( ssl->out_buf, 0, out_buf_len ); #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) @@ -4096,6 +4735,13 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->in_left = 0; memset( ssl->in_buf, 0, in_buf_len ); } +#endif /* !MBEDTLS_SSL_USE_MPS */ + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + ssl->session_in = NULL; + ssl->session_out = NULL; #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( mbedtls_ssl_hw_record_reset != NULL ) @@ -4109,12 +4755,37 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) } #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform ) { mbedtls_ssl_transform_free( ssl->transform ); mbedtls_free( ssl->transform ); ssl->transform = NULL; } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#else + ssl_mps_free( ssl ); + ssl_mps_init( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + ssl->early_data_buf = NULL; + ssl->early_data_len = 0; +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( ssl->session ) { @@ -4237,6 +4908,13 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, ssl->f_send = f_send; ssl->f_recv = f_recv; ssl->f_recv_timeout = f_recv_timeout; + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Update MPS callbacks. */ + mps_l1_set_bio( &ssl->mps.l1, + p_bio, f_send, + p_bio, f_recv ); +#endif /* MBEDTLS_SSL_USE_MPS */ } #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -4276,7 +4954,7 @@ void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, } #endif /* MBEDTLS_SSL_SRV_C */ -#if defined(MBEDTLS_SSL_CLI_C) +#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -4294,10 +4972,9 @@ int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session return( ret ); ssl->handshake->resume = 1; - return( 0 ); } -#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_NEW_SESSION_TICKET */ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, const int *ciphersuites ) @@ -4306,6 +4983,9 @@ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = ciphersuites; conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = ciphersuites; conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = ciphersuites; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = ciphersuites; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, @@ -4315,7 +4995,7 @@ void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, if( major != MBEDTLS_SSL_MAJOR_VERSION_3 ) return; - if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_3 ) + if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_4 ) return; conf->ciphersuite_list[minor] = ciphersuites; @@ -4550,7 +5230,19 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, return( ret ); } -static void ssl_remove_psk( mbedtls_ssl_context *ssl ) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* mbedtls_ssl_conf_tls13_key_exchange( ) allows to set the key exchange mode. */ +int mbedtls_ssl_conf_tls13_key_exchange( mbedtls_ssl_config* conf, + const int key_exchange_mode ) +{ + conf->key_exchange_modes = key_exchange_mode; + return 0; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + +void mbedtls_ssl_remove_hs_psk( mbedtls_ssl_context* ssl ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) if( ! mbedtls_svc_key_id_is_null( ssl->handshake->psk_opaque ) ) @@ -4565,6 +5257,7 @@ static void ssl_remove_psk( mbedtls_ssl_context *ssl ) ssl->handshake->psk_len ); mbedtls_free( ssl->handshake->psk ); ssl->handshake->psk_len = 0; + ssl->handshake->psk = NULL; } } @@ -4575,9 +5268,14 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); if( psk_len > MBEDTLS_PSK_MAX_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "PSK length has exceeded MBEDTLS_PSK_MAX_LEN (%u)", + (unsigned) MBEDTLS_PSK_MAX_LEN ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } - ssl_remove_psk( ssl ); + mbedtls_ssl_remove_hs_psk( ssl ); if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -4596,7 +5294,7 @@ int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; /* Clear opaque/raw PSK + PSK Identity, if present. */ - ssl_conf_remove_psk( conf ); + mbedtls_ssl_remove_hs_psk( ssl ); /* Check and set opaque PSK */ if( mbedtls_svc_key_id_is_null( psk ) ) @@ -4619,7 +5317,7 @@ int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl, ( ssl->handshake == NULL ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - ssl_remove_psk( ssl ); + mbedtls_ssl_remove_hs_psk( ssl ); ssl->handshake->psk_opaque = psk; return( 0 ); } @@ -4724,6 +5422,21 @@ void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, { conf->curve_list = curve_list; } + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* +* Set the named groups for use in a key share extension +*/ +#if defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_key_share_curves( mbedtls_ssl_config* conf, + const mbedtls_ecp_group_id* curve_list ) +{ + conf->key_shares_curve_list = curve_list; +} +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -4997,28 +5710,30 @@ void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, } #endif /* MBEDTLS_SSL_RENEGOTIATION */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) -#if defined(MBEDTLS_SSL_CLI_C) +#if ( ( defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) ) || \ + ( defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) ) void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) { conf->session_tickets = use_tickets; } -#endif +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C ) || MBEDTLS_SSL_NEW_SESSION_TICKET */ -#if defined(MBEDTLS_SSL_SRV_C) -void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, - mbedtls_ssl_ticket_write_t *f_ticket_write, - mbedtls_ssl_ticket_parse_t *f_ticket_parse, - void *p_ticket ) +#if ( ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && \ + defined(MBEDTLS_SSL_SRV_C) ) +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config* conf, + mbedtls_ssl_ticket_write_t* f_ticket_write, + mbedtls_ssl_ticket_parse_t* f_ticket_parse, + void* p_ticket ) { conf->f_ticket_write = f_ticket_write; conf->f_ticket_parse = f_ticket_parse; - conf->p_ticket = p_ticket; + conf->p_ticket = p_ticket; } -#endif -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, mbedtls_ssl_export_keys_t *f_export_keys, void *p_export_keys ) @@ -5034,7 +5749,18 @@ void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, conf->f_export_keys_ext = f_export_keys_ext; conf->p_export_keys = p_export_keys; } -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_conf_export_secrets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_secret_t *f_export_secret, + void *p_export_secret ) +{ + conf->f_export_secret = f_export_secret; + conf->p_export_secret = p_export_secret; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) void mbedtls_ssl_conf_async_private_cb( @@ -5107,6 +5833,8 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) case MBEDTLS_SSL_MINOR_VERSION_3: return( "DTLSv1.2" ); + case MBEDTLS_SSL_MINOR_VERSION_4: + return( "DTLSv1.3" ); default: return( "unknown (DTLS)" ); @@ -5128,11 +5856,23 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) case MBEDTLS_SSL_MINOR_VERSION_3: return( "TLSv1.2" ); + case MBEDTLS_SSL_MINOR_VERSION_4: + return( "TLSv1.3" ); + default: return( "unknown" ); } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +mbedtls_key_exchange_type_t mbedtls_ssl_get_key_exchange( const mbedtls_ssl_context* ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( MBEDTLS_KEY_EXCHANGE_NONE ); + + return ( ssl->handshake->key_exchange ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context *ssl ) { @@ -5298,6 +6038,8 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl ) { if( ssl == NULL ) @@ -5305,6 +6047,8 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co return( ssl->session ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ /* * Define ticket header determining Mbed TLS version @@ -5376,6 +6120,8 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co ( SSL_SERIALIZED_SESSION_CONFIG_ETM << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT ) | \ ( SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT ) ) ) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) static unsigned char ssl_serialized_session_header[] = { MBEDTLS_VERSION_MAJOR, MBEDTLS_VERSION_MINOR, @@ -5396,6 +6142,9 @@ static unsigned char ssl_serialized_session_header[] = { * Note: When updating the format, remember to keep * these version+format bytes. * + * Note: The format below is used by TLS/DTLS versions prior to 1.3. + * The ticket format used in TLS/DTLS 1.3 is shown further below. + * * // In this version, `session_format` determines * // the setting of those compile-time * // configuration options which influence @@ -5417,6 +6166,21 @@ static unsigned char ssl_serialized_session_header[] = { * The order is the same as in the definition of the structure, except * verify_result is put before peer_cert so that all mandatory fields come * together in one block. + * + * For TLS/DTLS 1.3 the ticket contains the following content: + * + * uint64 start_time; + * uint8 ciphersuite[2]; + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * uint8 ticket_flags; + * opaque resumption_key<0..255>; + * opaque ticket<0..2^16>; + * uint64 ticket_received; + * + * Note: The field ticket, and ticket_received + * are only stored on the client-side. + * */ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_session_save( const mbedtls_ssl_session *session, @@ -5427,15 +6191,28 @@ static int ssl_session_save( const mbedtls_ssl_session *session, { unsigned char *p = buf; size_t used = 0; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int minor_ver = 0; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ #if defined(MBEDTLS_HAVE_TIME) uint64_t start; -#endif +#endif /* MBEDTLS_HAVE_TIME */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) size_t cert_len; #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + + if( session == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Ticket format depends on the TLS version negotiated. */ + minor_ver = session->minor_ver; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ if( !omit_header ) { @@ -5453,49 +6230,160 @@ static int ssl_session_save( const mbedtls_ssl_session *session, } } - /* - * Time - */ -#if defined(MBEDTLS_HAVE_TIME) - used += 8; - - if( used <= buf_len ) +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) { - start = (uint64_t) session->start; + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + if( used <= buf_len ) + { + start = (uint64_t) session->start; MBEDTLS_PUT_UINT64_BE( start, p, 0 ); p += 8; } #endif /* MBEDTLS_HAVE_TIME */ - /* - * Basic mandatory fields - */ - used += 2 /* ciphersuite */ - + 1 /* compression */ - + 1 /* id_len */ - + sizeof( session->id ) - + sizeof( session->master ) - + 4; /* verify_result */ + /* + * Basic mandatory fields + */ + used += 2 /* ciphersuite */ + + 4 /* ticket_lifetime */ + + 4 /* ticket_age_add */ + + 1 /* key_len */ + + 1; /* flags */ if( used <= buf_len ) { MBEDTLS_PUT_UINT16_BE( session->ciphersuite, p, 0 ); p += 2; - *p++ = MBEDTLS_BYTE_0( session->compression ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime ) & 0xFF ); - *p++ = MBEDTLS_BYTE_0( session->id_len ); - memcpy( p, session->id, 32 ); - p += 32; - memcpy( p, session->master, 48 ); - p += 48; + *p++ = (unsigned char)( ( session->ticket_age_add >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add ) & 0xFF ); - MBEDTLS_PUT_UINT32_BE( session->verify_result, p, 0 ); - p += 4; + *p++ = (unsigned char)( ( session->ticket_flags ) & 0xFF ); + + *p++ = (unsigned char)( ( session->key_len ) & 0xFF ); + } + + used += session->key_len; + + if( used <= buf_len ) + { + memcpy( p, session->key, session->key_len ); + p += session->key_len; + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* Store ticket itself */ + used += 2 /* ticket length */ + + session->ticket_len; /* ticket */ + + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); + + memcpy( p, session->ticket, session->ticket_len ); + p += session->ticket_len; + } + +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + + if( used <= buf_len ) + { + start = (uint64_t) session->ticket_received; + + *p++ = (unsigned char)( ( start >> 56 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 48 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 40 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 32 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( start ) & 0xFF ); + } +#endif /* MBEDTLS_HAVE_TIME */ + } + +#endif /* MBEDTLS_SSL_CLI_C */ } + else +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + { + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + if( used <= buf_len ) + { + start = (uint64_t) session->start; + + *p++ = (unsigned char)( ( start >> 56 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 48 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 40 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 32 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( start ) & 0xFF ); + } +#endif /* MBEDTLS_HAVE_TIME */ + + /* + * Basic mandatory fields + */ + used += 2 /* ciphersuite */ + + 1 /* compression */ + + 1 /* id_len */ + + sizeof( session->id ) + + sizeof( session->master ) + + 4; /* verify_result */ + + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ciphersuite >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ciphersuite ) & 0xFF ); + + *p++ = (unsigned char)( session->compression & 0xFF ); + + *p++ = (unsigned char)( session->id_len & 0xFF ); + memcpy( p, session->id, 32 ); + p += 32; + + memcpy( p, session->master, 48 ); + p += 48; + + *p++ = (unsigned char)( ( session->verify_result >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result ) & 0xFF ); + } + } +#else + { + return ( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); //TODO::MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL report this error + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Peer's end-entity certificate */ @@ -5544,53 +6432,59 @@ static int ssl_session_save( const mbedtls_ssl_session *session, } #endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ /* * Session ticket if any, plus associated data */ + if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + { #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) - used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */ + used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */ - if( used <= buf_len ) - { - *p++ = MBEDTLS_BYTE_2( session->ticket_len ); - *p++ = MBEDTLS_BYTE_1( session->ticket_len ); - *p++ = MBEDTLS_BYTE_0( session->ticket_len ); + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ticket_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); + + if( session->ticket != NULL ) + { + memcpy( p, session->ticket, session->ticket_len ); + p += session->ticket_len; + } - if( session->ticket != NULL ) - { - memcpy( p, session->ticket, session->ticket_len ); - p += session->ticket_len; + *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime ) & 0xFF ); } - - MBEDTLS_PUT_UINT32_BE( session->ticket_lifetime, p, 0 ); - p += 4; - } #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ - /* - * Misc extension-related info - */ + /* + * Misc extension-related info + */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = session->mfl_code; + if( used <= buf_len ) + *p++ = session->mfl_code; #endif #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF ); + if( used <= buf_len ) + *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF ); #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = MBEDTLS_BYTE_0( session->encrypt_then_mac ); + if( used <= buf_len ) + *p++ = MBEDTLS_BYTE_0( session->encrypt_then_mac ); #endif + } /* Done */ *olen = used; @@ -5626,14 +6520,18 @@ static int ssl_session_load( mbedtls_ssl_session *session, { const unsigned char *p = buf; const unsigned char * const end = buf + len; -#if defined(MBEDTLS_HAVE_TIME) + int minor_ver = 0; +#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SESSION_TICKETS) uint64_t start; -#endif +#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) size_t cert_len; #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ if( !omit_header ) { @@ -5652,49 +6550,161 @@ static int ssl_session_load( mbedtls_ssl_session *session, p += sizeof( ssl_serialized_session_header ); } - /* - * Time - */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + + minor_ver = MBEDTLS_SSL_MINOR_VERSION_4; /* TBD: For testing only */ + session->minor_ver = minor_ver; + + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + #if defined(MBEDTLS_HAVE_TIME) - if( 8 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - start = ( (uint64_t) p[0] << 56 ) | - ( (uint64_t) p[1] << 48 ) | - ( (uint64_t) p[2] << 40 ) | - ( (uint64_t) p[3] << 32 ) | - ( (uint64_t) p[4] << 24 ) | - ( (uint64_t) p[5] << 16 ) | - ( (uint64_t) p[6] << 8 ) | - ( (uint64_t) p[7] ); - p += 8; + session->start = + ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; +#endif /* MBEDTLS_HAVE_TIME */ + + /* 2 bytes for ciphersuite, + * 4 bytes for ticket_lifetime, + * 4 bytes ticket_age_add, + * 1 byte for key_len, + * 1 byte for flags. + */ + + if( 2 + 4 + 4 + 1 + 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ciphersuite = ( p[0] << 8 ) | p[1]; + p += 2; + + session->ticket_lifetime = + ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + + session->ticket_age_add = + ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + + session->ticket_flags = *p++; + + session->key_len = *p++; + + if( session->key_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session->key, p, session->key_len ); + p += session->key_len; + +#if defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( 2 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ticket_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( session->ticket_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ticket = mbedtls_calloc( session->ticket_len, 1 ); + if( session->ticket == NULL ) + { + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + else + { + memcpy( session->ticket, p, session->ticket_len ); + p += session->ticket_len; + } + +#if defined(MBEDTLS_HAVE_TIME) + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->start = (time_t) start; + session->ticket_received = + ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; #endif /* MBEDTLS_HAVE_TIME */ + } +#endif /* MBEDTLS_SSL_CLI_C */ + } + else +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + { + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - /* - * Basic mandatory fields - */ - if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + start = ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; - session->ciphersuite = ( p[0] << 8 ) | p[1]; - p += 2; + session->start = (time_t) start; +#endif /* MBEDTLS_HAVE_TIME */ + + /* + * Basic mandatory fields + */ + if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->compression = *p++; + session->ciphersuite = ( p[0] << 8 ) | p[1]; + p += 2; - session->id_len = *p++; - memcpy( session->id, p, 32 ); - p += 32; + session->compression = *p++; - memcpy( session->master, p, 48 ); - p += 48; + session->id_len = *p++; + memcpy( session->id, p, 32 ); + p += 32; - session->verify_result = ( (uint32_t) p[0] << 24 ) | - ( (uint32_t) p[1] << 16 ) | - ( (uint32_t) p[2] << 8 ) | - ( (uint32_t) p[3] ); - p += 4; + memcpy( session->master, p, 48 ); + p += 48; + + session->verify_result = ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + } +#else + { + return ( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ /* Immediately clear invalid pointer values that have been read, in case * we exit early before we replaced them with valid ones. */ @@ -5709,6 +6719,7 @@ static int ssl_session_load( mbedtls_ssl_session *session, session->ticket = NULL; #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Peer certificate */ @@ -5778,62 +6789,67 @@ static int ssl_session_load( mbedtls_ssl_session *session, #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + /* * Session ticket and associated data */ + if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + { #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) - if( 3 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 3 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; - p += 3; + session->ticket_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; - if( session->ticket_len != 0 ) - { - if( session->ticket_len > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( session->ticket_len != 0 ) + { + if( session->ticket_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket = mbedtls_calloc( 1, session->ticket_len ); - if( session->ticket == NULL ) - return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + session->ticket = mbedtls_calloc( 1, session->ticket_len ); + if( session->ticket == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); - memcpy( session->ticket, p, session->ticket_len ); - p += session->ticket_len; - } + memcpy( session->ticket, p, session->ticket_len ); + p += session->ticket_len; + } - if( 4 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 4 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) | - ( (uint32_t) p[1] << 16 ) | - ( (uint32_t) p[2] << 8 ) | - ( (uint32_t) p[3] ); - p += 4; + session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ - /* - * Misc extension-related info - */ + /* + * Misc extension-related info + */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->mfl_code = *p++; + session->mfl_code = *p++; #endif #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->trunc_hmac = *p++; + session->trunc_hmac = *p++; #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->encrypt_then_mac = *p++; + session->encrypt_then_mac = *p++; #endif + } /* Done, should have consumed entire buffer */ if( p != end ) @@ -5856,6 +6872,26 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session, return( ret ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_mps_remap_error( int ret ) +{ + /* TODO: This should remap _all_ public MPS error codes. */ + + if( ret == MBEDTLS_ERR_MPS_WANT_READ ) + ret = MBEDTLS_ERR_SSL_WANT_READ; + if( ret == MBEDTLS_ERR_MPS_WANT_WRITE ) + ret = MBEDTLS_ERR_SSL_WANT_WRITE; + if( ret == MBEDTLS_ERR_MPS_CONN_EOF ) + ret = MBEDTLS_ERR_SSL_CONN_EOF; + if( ret == MBEDTLS_ERR_MPS_RETRY ) + ret = MBEDTLS_ERR_SSL_WANT_READ; + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Perform a single step of the SSL handshake @@ -5867,6 +6903,10 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) if( ssl == NULL || ssl->conf == NULL ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + #if defined(MBEDTLS_SSL_CLI_C) if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ret = mbedtls_ssl_handshake_client_step( ssl ); @@ -5876,6 +6916,28 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) ret = mbedtls_ssl_handshake_server_step( ssl ); #endif + if( ret != 0 ) + { + int alert_ret; + alert_ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( alert_ret != 0 ) + { + ret = alert_ret; + goto cleanup; + } + } + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + return( ret ); } @@ -5907,9 +6969,27 @@ int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { ret = mbedtls_ssl_handshake_step( ssl ); - if( ret != 0 ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_blocking_reason_t blocking_reason; + mbedtls_mps_blocking_info_t blocking_info; + if( mbedtls_mps_connection_state( &ssl->mps.l4, + &blocking_reason, + &blocking_info ) + == MBEDTLS_MPS_STATE_BLOCKED ) + { + if( blocking_reason == MBEDTLS_MPS_ERROR_ALERT_RECEIVED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "got an alert message, type: [%u:%u]", + (unsigned) MBEDTLS_SSL_ALERT_LEVEL_FATAL, + blocking_info.alert ) ); + } + } +#endif /* MBEDTLS_SSL_USE_MPS */ break; + } } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); @@ -6069,6 +7149,10 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) if( handshake == NULL ) return; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_free( handshake->key_shares_curve_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 ) { @@ -6161,8 +7245,12 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) mbedtls_pk_free( &handshake->peer_pubkey ); #endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) +#if defined(MBEDTLS_SSL_PROTO_DTLS) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) mbedtls_free( handshake->verify_cookie ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_ssl_flight_free( handshake->flight ); mbedtls_ssl_buffering_free( ssl ); #endif @@ -6194,9 +7282,11 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) ssl_clear_peer_cert( session ); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if( defined(MBEDTLS_SSL_SESSION_TICKETS) || ( defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_CLI_C) ) ) + mbedtls_free( session->ticket ); -#endif + +#endif /* MBEDTLS_SSL_SESSION_TICKETS || ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_CLI_C ) */ mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) ); } @@ -6837,6 +7927,12 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> free" ) ); +#if defined(MBEDTLS_SSL_USE_MPS) + + ssl_mps_free( ssl ); + +#else /* MBEDTLS_SSL_USE_MPS */ + if( ssl->out_buf != NULL ) { #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) @@ -6871,20 +7967,40 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) } #endif +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform ) { mbedtls_ssl_transform_free( ssl->transform ); mbedtls_free( ssl->transform ); } +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#endif if( ssl->handshake ) { mbedtls_ssl_handshake_free( ssl ); - mbedtls_ssl_transform_free( ssl->transform_negotiate ); - mbedtls_ssl_session_free( ssl->session_negotiate ); - mbedtls_free( ssl->handshake ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_ssl_transform_free( ssl->transform_negotiate ); mbedtls_free( ssl->transform_negotiate ); +#endif + + mbedtls_ssl_session_free( ssl->session_negotiate ); mbedtls_free( ssl->session_negotiate ); } @@ -6910,10 +8026,22 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) } #endif -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if ( defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || \ + ( defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_SSL_COOKIE_C) ) ) \ + && defined(MBEDTLS_SSL_SRV_C) mbedtls_free( ssl->cli_id ); #endif +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) + if( ssl->early_data_server_buf != NULL ) + { + mbedtls_platform_zeroize( ssl->early_data_server_buf, + ssl->early_data_server_buf_len ); + mbedtls_free( ssl->early_data_server_buf ); + } +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_SRV_C */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); /* Actually clear after last debug message */ @@ -6929,6 +8057,8 @@ void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) } #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) static int ssl_preset_default_hashes[] = { #if defined(MBEDTLS_SHA512_C) MBEDTLS_MD_SHA512, @@ -6945,33 +8075,78 @@ static int ssl_preset_default_hashes[] = { #endif MBEDTLS_MD_NONE }; -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ static int ssl_preset_suiteb_ciphersuites[] = { +#if defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_TLS1_3_AES_128_GCM_SHA256, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_TLS1_3_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_AES_C && MBEDTLS_GCM_C */ 0 }; #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) static int ssl_preset_suiteb_hashes[] = { MBEDTLS_MD_SHA256, MBEDTLS_MD_SHA384, MBEDTLS_MD_NONE }; -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECDSA_C) +static int ssl_preset_suiteb_signature_algorithms_tls13[] = { +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + SIGNATURE_ECDSA_SECP256r1_SHA256, +#endif /* MBEDTLS_SHA256_C && MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + SIGNATURE_ECDSA_SECP384r1_SHA384, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* TBD: This signature algorithm is not yet fully implemented. */ +// SIGNATURE_ECDSA_SECP521r1_SHA512, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + SIGNATURE_RSA_PSS_RSAE_SHA256, +#endif + SIGNATURE_NONE +}; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) MBEDTLS_ECP_DP_SECP256R1, -#endif +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) MBEDTLS_ECP_DP_SECP384R1, -#endif +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ MBEDTLS_ECP_DP_NONE }; -#endif +#endif /* MBEDTLS_ECP_C */ /* * Load default in mbedtls_ssl_config @@ -7076,15 +8251,25 @@ int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = - ssl_preset_suiteb_ciphersuites; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + ssl_preset_suiteb_ciphersuites; #if defined(MBEDTLS_X509_CRT_PARSE_C) conf->cert_profile = &mbedtls_x509_crt_profile_suiteb; #endif #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - conf->sig_hashes = ssl_preset_suiteb_hashes; -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + /* TLS 1.3 re-interprets the signature algorithms + * and therefore we cannot include both. + */ + conf->sig_hashes = ssl_preset_suiteb_hashes; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->sig_hashes = ssl_preset_suiteb_signature_algorithms_tls13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) conf->curve_list = ssl_preset_suiteb_curves; @@ -7105,26 +8290,41 @@ int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, MBEDTLS_SSL_MIN_VALID_MINOR_VERSION; conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + // As a default send key shares for all supported curves +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->key_shares_curve_list = ssl_preset_suiteb_curves; +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ #endif conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = - mbedtls_ssl_list_ciphersuites(); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + mbedtls_ssl_list_ciphersuites( ); #if defined(MBEDTLS_X509_CRT_PARSE_C) conf->cert_profile = &mbedtls_x509_crt_profile_default; #endif #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - conf->sig_hashes = ssl_preset_default_hashes; -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + conf->sig_hashes = ssl_preset_default_hashes; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->sig_hashes = ssl_preset_suiteb_signature_algorithms_tls13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif #if defined(MBEDTLS_ECP_C) conf->curve_list = mbedtls_ecp_grp_id_list(); #endif @@ -7376,6 +8576,10 @@ int mbedtls_ssl_check_curve_tls_id( const mbedtls_ssl_context *ssl, uint16_t tls /* * Check if a hash proposed by the peer is in our list. * Return 0 if we're willing to use it, -1 otherwise. + * + * Assumption: sig_hashes is terminated either with + * SIGNATURE_NONE or with MBEDTLS_MD_NONE and both + * equal 0x0. */ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, mbedtls_md_type_t md ) @@ -7385,8 +8589,8 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, if( ssl->conf->sig_hashes == NULL ) return( -1 ); - for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) - if( *cur == (int) md ) + for( cur = ssl->conf->sig_hashes; *cur != SIGNATURE_NONE; cur++ ) + if( *cur == ( int )md ) return( 0 ); return( -1 ); @@ -7394,10 +8598,10 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_X509_CRT_PARSE_C) -int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, - const mbedtls_ssl_ciphersuite_t *ciphersuite, - int cert_endpoint, - uint32_t *flags ) +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt* cert, + const mbedtls_key_exchange_type_t key_exchange, + int cert_endpoint, + uint32_t* flags ) { int ret = 0; #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) @@ -7419,7 +8623,7 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) { /* Server part of the key exchange */ - switch( ciphersuite->key_exchange ) + switch( key_exchange ) { case MBEDTLS_KEY_EXCHANGE_RSA: case MBEDTLS_KEY_EXCHANGE_RSA_PSK: @@ -7484,7 +8688,9 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, } #endif /* MBEDTLS_X509_CRT_PARSE_C */ -int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context* ssl, int md ) { #if defined(MBEDTLS_SSL_PROTO_TLS1_2) if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) @@ -7525,6 +8731,8 @@ int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -7739,4 +8947,73 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_start_tls13( ssl, buf, len ); + else + ssl_update_checksum_start_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_sha384_tls13( ssl, buf, len ); + else + ssl_update_checksum_sha384_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_sha256_tls13( ssl, buf, len ); + else + ssl_update_checksum_sha256_tls12( ssl, buf, len ); +} + +#elif defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_start_tls13( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha384_tls13( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha256_tls13( ssl, buf, len ); +} + +#elif defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_start_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha384_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha256_tls12( ssl, buf, len ); +} + + +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) \ + && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) */ #endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c new file mode 100644 index 000000000000..53949fa8db0a --- /dev/null +++ b/library/ssl_tls13_client.c @@ -0,0 +1,4567 @@ +/* + * TLS 1.3 client-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS ( https://tls.mbed.org ) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#include "mbedtls/hkdf.h" + +#if defined(MBEDTLS_SSL_CLI_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif + + +#if (defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +static int check_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + +/* + * + * STATE HANDLING: Write Early-Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_write_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_EARLY_DATA_WRITE 0 +#define SSL_EARLY_DATA_SKIP 1 +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_write_early_data_prepare( mbedtls_ssl_context* ssl ); + +/* Write early-data message */ +static int ssl_write_early_data_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the outgoing early-data message. */ +static int ssl_write_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_write_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_writer *msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write early data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_early_data_coordinate( ssl ) ); + if( ret == SSL_EARLY_DATA_WRITE ) + { +#if defined(MBEDTLS_ZERO_RTT) + + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_prepare( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps.l4, + &msg ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_write( + ssl, buf, buf_len, &msg_len ) ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write early-data to message buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +#else /* MBEDTLS_ZERO_RTT */ + ((void) buf); + ((void) buf_len); + ((void) msg); + ((void) msg_len); + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + } + + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write early data" ) ); + return( ret ); +} + +#if defined(MBEDTLS_ZERO_RTT) + +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_WRITE ); +} + +static int ssl_write_early_data_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + /* From RFC 8446: + * "The PSK used to encrypt the + * early data MUST be the first PSK listed in the client's + * 'pre_shared_key' extension." + */ + + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + /* This should never happen: We can only have gone past + * ssl_write_early_data_coordinate() if we have offered a PSK. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret ); + return( ret ); + } + + /* Start the TLS 1.3 key schedule: Set the PSK and derive early secret. */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", ret ); + return( ret ); + } + + /* Derive 0-RTT key material */ + ret = mbedtls_ssl_tls1_3_generate_early_data_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_early_data_keys", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_USE_MPS) + { + mbedtls_ssl_transform *transform_earlydata = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_earlydata == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + return( ret ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_earlydata, + &ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + + /* Activate transform */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to 0-RTT keys for outbound traffic" ) ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_earlydata ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +static int ssl_write_early_data_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + if( ssl->early_data_len > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + else + { + memcpy( buf, ssl->early_data_buf, ssl->early_data_len ); + +#if defined(MBEDTLS_SSL_USE_MPS) + *olen = ssl->early_data_len; + MBEDTLS_SSL_DEBUG_BUF( 3, "Early Data", buf, ssl->early_data_len ); +#else + buf[ssl->early_data_len] = MBEDTLS_SSL_MSG_APPLICATION_DATA; + *olen = ssl->early_data_len + 1; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Early Data", ssl->out_msg, *olen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + return( 0 ); +} + +#else /* MBEDTLS_ZERO_RTT */ + +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_EARLY_DATA_SKIP ); +} + +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_write_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + /* Clear PSK we've used for the 0-RTT. */ + mbedtls_ssl_remove_hs_psk( ssl ); + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + return ( 0 ); +} + + +/* + * + * STATE HANDLING: Write End-of-Early-Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_write_end_of_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_END_OF_EARLY_DATA_WRITE 0 +#define SSL_END_OF_EARLY_DATA_SKIP 1 +static int ssl_write_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ); + +/* Update the state after handling the outgoing end-of-early-data message. */ +static int ssl_write_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_write_end_of_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write EndOfEarlyData" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_end_of_early_data_coordinate( ssl ) ); + if( ret == SSL_END_OF_EARLY_DATA_WRITE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_END_OF_EARLY_DATA; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* EndOfEarlyData message is empty */ + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 0 ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* EndOfEarlyData message is empty */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_END_OF_EARLY_DATA; + ssl->out_msglen = 4; + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else + { + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write EndOfEarlyData" ) ); + return( ret ); +} + +static int ssl_write_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) + { + if( ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_ACCEPTED ) + return( SSL_END_OF_EARLY_DATA_WRITE ); + + /* + * RFC 8446: + * "If the server does not send an "early_data" + * extension in EncryptedExtensions, then the client MUST NOT send an + * EndOfEarlyData message." + */ + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "skip EndOfEarlyData, server rejected" ) ); + } +#endif /* MBEDTLS_ZERO_RTT */ + + return( SSL_END_OF_EARLY_DATA_SKIP ); +} + +static int ssl_write_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ssl_write_end_of_early_data_coordinate( ssl ) != SSL_END_OF_EARLY_DATA_WRITE ) + { + mbedtls_ssl_handshake_set_state( ssl, + MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + size_t hostname_len; + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( ssl ) ) + return; + + if( ssl->hostname == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + hostname_len = strlen( ssl->hostname ); + + if( end < p || (size_t)( end - p ) < hostname_len + 9 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * struct { + * NameType name_type; + * select ( name_type ) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name( 0 ), ( 255 ) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( ( hostname_len + 5 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hostname_len + 5 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( hostname_len + 3 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hostname_len + 3 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, hostname_len ); + + *olen = hostname_len + 9; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +/* + * ssl_write_supported_versions_ext(): + * + * struct { + * ProtocolVersion versions<2..254>; + * } SupportedVersions; + */ + +static void ssl_write_supported_versions_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported version extension" ) ); + + if( end < p || (size_t)( end - p ) < 7 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS ) & 0xFF ); + + /* total length */ + *p++ = 0x00; + *p++ = 3; + + /* length of next field */ + *p++ = 0x2; + + /* This implementation only supports a single TLS version, and only + * advertises a single value. + */ + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "supported version: [%d:%d]", ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) ); + + *olen = 7; +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + +/* + * ssl_write_max_fragment_length_ext(): + * + * enum{ + * 2^9( 1 ), 2^10( 2 ), 2^11( 3 ), 2^12( 4 ), ( 255 ) + * } MaxFragmentLength; + * + */ +static int ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char* end = buf + buflen; + + *olen = 0; + + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + return( 0 ); + } + + if( end < p || (size_t)( end - p ) < 5 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->conf->mfl_code; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Maximum fragment length = %d", ssl->conf->mfl_code ) ); + + *olen = 5; + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + +#if defined(MBEDTLS_SSL_ALPN) +/* + * ssl_write_alpn_ext() structure: + * + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + */ +static int ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + const unsigned char* end, + size_t *olen ) +{ + unsigned char *p = buf; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + { + return( 0 ); + } + + for ( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += (unsigned char)( strlen( *cur ) & 0xFF ) + 1; + + if( end < p || (size_t)( end - p ) < 6 + alpnlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for ( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + *p = (unsigned char)( strlen( *cur ) & 0xFF ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 ( ext_type ) - 2 ( ext_len ) - 2 ( list_len ) */ + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( *olen - 6 ) & 0xFF ); + + /* Extension length = olen - 2 ( ext_type ) - 2 ( ext_len ) */ + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( *olen - 4 ) & 0xFF ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * ssl_write_psk_key_exchange_modes_ext() structure: + * + * enum { psk_ke( 0 ), psk_dhe_ke( 1 ), ( 255 ) } PskKeyExchangeMode; + * + * struct { + * PskKeyExchangeMode ke_modes<1..255>; + * } PskKeyExchangeModes; + */ + +static int ssl_write_psk_key_exchange_modes_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p; + int num_modes = 0; + + /* Skip writing extension if no PSK key exchange mode + * is enabled in the config. */ + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) ) + { + *olen = 0; + return( 0 ); + } + + /* Require 7 bytes of data, otherwise fail, even if extension might be shorter. */ + if( (size_t)( end - buf ) < 7 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Not enough buffer" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding psk_key_exchange_modes extension" ) ); + + /* Extension Type */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES >> 0 ) & 0xFF ); + + /* Skip extension length (2 byte) and PSK mode list length (1 byte) for now. */ + p = buf + 5; + + if( mbedtls_ssl_conf_tls13_pure_psk_enabled( ssl ) ) + { + *p++ = MBEDTLS_SSL_TLS13_PSK_MODE_PURE; + num_modes++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Adding pure PSK key exchange mode" ) ); + } + + if( mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( ssl ) ) + { + *p++ = MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE; + num_modes++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Adding PSK-ECDHE key exchange mode" ) ); + } + + /* Add extension length: PSK mode list length byte + actual PSK mode list length */ + buf[2] = 0; + buf[3] = num_modes + 1; + /* Add PSK mode list length */ + buf[4] = num_modes; + + *olen = p - buf; + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES; + return ( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +/* + * mbedtls_ssl_write_pre_shared_key_ext() structure: + * + * struct { + * opaque identity<1..2^16-1>; + * uint32 obfuscated_ticket_age; + * } PskIdentity; + * + * opaque PskBinderEntry<32..255>; + * + * struct { + * select ( Handshake.msg_type ) { + * + * case client_hello: + * PskIdentity identities<7..2^16-1>; + * PskBinderEntry binders<33..2^16-1>; + * + * case server_hello: + * uint16 selected_identity; + * }; + * + * } PreSharedKeyExtension; + * + * + * part = 0 ==> everything up to the PSK binder list, + * returning the binder list length in `binder_list_length`. + * part = 1 ==> the PSK binder list + */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + +#define SSL_WRITE_PSK_EXT_PARTIAL 0 +#define SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS 1 + +int mbedtls_ssl_write_pre_shared_key_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, unsigned char* end, + size_t *bytes_written, + size_t *total_ext_len, + int part ) +{ + int ret; + unsigned char *p = (unsigned char *) buf; + const mbedtls_ssl_ciphersuite_t *suite_info; + const int *ciphersuites; + int hash_len; + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + *total_ext_len = 0; + *bytes_written = 0; + + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) ) + return( 0 ); + + /* Check if we have any PSKs to offer. If so, return the first. + * + * NOTE: Ultimately, we want to be able to offer multiple PSKs, + * in which case we want to iterate over them here. + * + * As it stands, however, we only ever offer one, chosen + * by the following heuristic: + * - If a ticket has been configured, offer the corresponding PSK. + * - If no ticket has been configured by an external PSK has been + * configured, offer that. + * - Otherwise, skip the PSK extension. + */ + + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip pre_shared_key extensions" ) ); + return( 0 ); + } + + /* + * Ciphersuite list + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + for ( int i = 0; ciphersuites[i] != 0; i++ ) + { + suite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( suite_info == NULL ) + continue; + + /* In this implementation we only add one pre-shared-key extension. */ + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = suite_info; + break; + } + + hash_len = mbedtls_hash_size_for_ciphersuite( suite_info ); + if( hash_len == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + size_t const ext_type_bytes = 2; + size_t const ext_len_bytes = 2; + size_t const psk_identities_len_bytes = 2; + size_t const psk_identity_len_bytes = 2; + size_t const psk_identity_bytes = psk_identity_len; + size_t const obfuscated_ticket_bytes = 4; + size_t const psk_binders_len_bytes = 2; + size_t const psk_binder_len_bytes = 1; + size_t const psk_binder_bytes = hash_len; + + size_t const psk_binder_list_bytes = psk_binders_len_bytes + + psk_binder_len_bytes + + psk_binder_bytes; + + size_t const ext_len = psk_identities_len_bytes + + psk_identity_len_bytes + + psk_identity_bytes + + obfuscated_ticket_bytes + + psk_binder_list_bytes; + + size_t const ext_len_total = ext_type_bytes + + ext_len_bytes + + ext_len; + + if( part == SSL_WRITE_PSK_EXT_PARTIAL ) + { + uint32_t obfuscated_ticket_age = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "client hello, adding pre_shared_key extension, " + "omitting PSK binder list" ) ); + + /* Write extension up to but excluding the PSK binders list + + * The length (excluding the extension header) includes: + * + * - 2 bytes for total length of identities + * - 2 bytes for length of first identity value + * - identity value ( of length len; min( len )>=1 ) + * - 4 bytes for obfuscated_ticket_age + * ... + * - 2 bytes for total length of psk binders + * - 1 byte for length of first psk binder value + * - 32 or 48 bytes (for SHA256/384) for PSK binder value + * ... + * + * Note: Currently we assume we have only one PSK credential + * configured per server. + */ + + /* ext_length + Extension Type ( 2 bytes ) + Extension Length ( 2 bytes ) */ + if( end < p || (size_t)( end - p ) < ext_len_total ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 0 ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len >> 0 ) & 0xFF ); + + /* 2 bytes length field for array of PskIdentity */ + *p++ = (unsigned char)( ( ( psk_identity_len + 4 + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( psk_identity_len + 4 + 2 ) >> 0 ) & 0xFF ); + + /* 2 bytes length field for psk_identity */ + *p++ = (unsigned char)( ( ( psk_identity_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( psk_identity_len ) >> 0 ) & 0xFF ); + + /* actual psk_identity */ + memcpy( p, psk_identity, psk_identity_len ); + p += psk_identity_len; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + /* Calculate obfuscated_ticket_age (omitted for external PSKs). */ + if( ssl->session_negotiate->ticket_age_add > 0 ) + { + /* TODO: Should we somehow fail if TIME is disabled here? + * TODO: Use Mbed TLS' time abstraction? */ +#if defined(MBEDTLS_HAVE_TIME) + time_t now = time( NULL ); + + if( !( ssl->session_negotiate->ticket_received <= now && + now - ssl->session_negotiate->ticket_received < 7 * 86400 * 1000 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket expired" ) ); + /* TBD: We would have to fall back to another PSK */ + return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ); + } + + obfuscated_ticket_age = + (uint32_t)( now - ssl->session_negotiate->ticket_received ) + + ssl->session_negotiate->ticket_age_add; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "obfuscated_ticket_age: %u", + obfuscated_ticket_age ) ); +#endif /* MBEDTLS_HAVE_TIME */ + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* add obfuscated ticket age */ + *p++ = ( obfuscated_ticket_age >> 24 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 16 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 8 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 0 ) & 0xFF; + + *bytes_written = ext_len_total - psk_binder_list_bytes; + *total_ext_len = ext_len_total; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + } + else if( part == SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ) + { + int external_psk; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding PSK binder list" ) ); + + /* 2 bytes length field for array of psk binders */ + *p++ = (unsigned char)( ( ( hash_len + 1 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hash_len + 1 ) >> 0 ) & 0xFF ); + + /* 1 bytes length field for next psk binder */ + *p++ = (unsigned char)( ( hash_len ) & 0xFF ); + + if( ssl->handshake->resume ) + external_psk = 0; + else + external_psk = 1; + + /* Get current state of handshake transcript. */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, suite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_create_psk_binder( ssl, + psk, psk_len, + suite_info->mac, + external_psk, + transcript, p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_create_psk_binder", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + *bytes_written = psk_binder_list_bytes; + } + + return( 0 ); +} + + +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +static int ssl_write_cookie_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + + *olen = 0; + + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no cookie to send; skip extension" ) ); + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + + if( end < p || + (size_t)( end - p ) < ( ssl->handshake->verify_cookie_len + 4 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding cookie extension" ) ); + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( ( ssl->handshake->verify_cookie_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ssl->handshake->verify_cookie_len + 2 ) & 0xFF ); + + /* Cookie Length */ + *p++ = (unsigned char)( ( ssl->handshake->verify_cookie_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ssl->handshake->verify_cookie_len & 0xFF ); + + /* Cookie */ + memcpy( p, ssl->handshake->verify_cookie, ssl->handshake->verify_cookie_len ); + + *olen = ssl->handshake->verify_cookie_len + 6; + + return( 0 ); +} + +#if defined(MBEDTLS_ECDH_C) +/* + + Supported Groups Extension + + In versions of TLS prior to TLS 1.3, this extension was named + 'elliptic_curves' and only contained elliptic curve groups. +*/ + +static int ssl_write_supported_groups_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + unsigned char *elliptic_curve_list = p + 6; + size_t elliptic_curve_len = 0; + const mbedtls_ecp_curve_info *info; +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *grp_id; +#else + ((void) ssl); +#endif + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + return( 0 ); + +#if defined(MBEDTLS_ECP_C) + for ( grp_id = ssl->conf->curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; + grp_id++ ) + { +/* info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); */ +#else + for ( info = mbedtls_ecp_curve_list(); + info->grp_id != MBEDTLS_ECP_DP_NONE; + info++ ) + { +#endif + elliptic_curve_len += 2; + } + + if( elliptic_curve_len == 0 ) + { + /* If we have no curves configured then we are in trouble. */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No curves configured." ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_groups extension" ) ); + + elliptic_curve_len = 0; + +#if defined(MBEDTLS_ECP_C) + for ( grp_id = ssl->conf->curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; + grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + for ( info = mbedtls_ecp_curve_list(); + info->grp_id != MBEDTLS_ECP_DP_NONE; + info++ ) + { +#endif + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Named Curve: %s ( %x )", + mbedtls_ecp_curve_info_from_tls_id( info->tls_id )->name, + info->tls_id ) ); + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_GROUPS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_GROUPS ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len ) ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "Supported groups extension", buf + 4, elliptic_curve_len + 2 ); + + *olen = 6 + elliptic_curve_len; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_GROUPS; + return( 0 ); +} +#endif /* defined(MBEDTLS_ECDH_C) */ + +/* + * Key Shares Extension + * + * enum { + * obsolete_RESERVED(1..22), + * secp256r1(23), secp384r1(24), secp521r1(25), + * obsolete_RESERVED(26..28), + * x25519(29), x448(30), + * + * ffdhe2048(256), ffdhe3072(257), ffdhe4096(258), + * ffdhe6144(259), ffdhe8192(260), + * + * ffdhe_private_use(0x01FC..0x01FF), + * ecdhe_private_use(0xFE00..0xFEFF), + * obsolete_RESERVED(0xFF01..0xFF02), + * (0xFFFF) + * } NamedGroup; + * + * struct { + * NamedGroup group; + * opaque key_exchange<1..2^16-1>; + * } KeyShareEntry; + * + * struct { + * select(role) { + * case client: + * KeyShareEntry client_shares<0..2^16-1>; + * case server: + * KeyShareEntry server_share; + * } + * } KeyShare; + */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) +static int ssl_write_key_shares_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + const mbedtls_ecp_curve_info *info = NULL; + const mbedtls_ecp_group_id *grp_id; + + size_t len; + int ret; + + unsigned char *header = buf; /* Pointer where the header has to go. */ + unsigned char* p = buf + 4 /* Skip header for now */; + + /* TODO: Add bounds checks! Only then remove the next line. */ + ((void) end ); + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding key share extension" ) ); + + /* Use the first entry of the key share list for the share. */ + /* TODO: Further work needed, see #310 */ + grp_id = ssl->handshake->key_shares_curve_list; + if( *grp_id == MBEDTLS_ECP_DP_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Curve list is empty." ) ); + return( MBEDTLS_ERR_SSL_BAD_CONFIG ); + } + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", info->name ) ); + + ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, info->grp_id ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + ret = mbedtls_ecdh_make_tls_13_params( &ssl->handshake->ecdh_ctx, &len, + p+2, end - (p+2), + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_tls_13_params", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDHE: Q ", &ssl->handshake->ecdh_ctx.Q ); + + /* Write length of the key_exchange entry */ + *p++ = (unsigned char)( ( len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( len ) & 0xFF ); + + p += len; + *olen += len + 2; + + /* Write extension header */ + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES ) & 0xFF ); + + /* Write total extension length */ + *header++ = (unsigned char)( ( *olen >> 8 ) & 0xFF ); + *header++ = (unsigned char)( *olen & 0xFF ); + + *olen += 4; /* 4 bytes for fixed header */ + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + return( 0 ); +} + +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ); + +static int ssl_client_hello_prepare( mbedtls_ssl_context* ssl ); +static int ssl_client_hello_write_partial( mbedtls_ssl_context* ssl, + unsigned char* buf, size_t buflen, + size_t* len_without_binders, + size_t* len_with_binders ); + +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; +#if defined(MBEDTLS_SSL_USE_MPS) + size_t len_without_binders; + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#else /* MBEDTLS_SSL_USE_MPS */ + size_t msg_len, len_without_binders; + unsigned char *buf; + size_t len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->handshake->state_local.cli_hello_out.preparation_done == 0 ) + { + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_prepare( ssl ) ); + ssl->handshake->state_local.cli_hello_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CLIENT_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_write_partial( ssl, buf, buf_len, + &len_without_binders, + &msg_len ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, + msg_len ); + ssl->handshake->update_checksum( ssl, buf, len_without_binders ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Patch the PSK binder after updating the HS checksum. */ + { + + size_t dummy0, dummy1; + mbedtls_ssl_write_pre_shared_key_ext( ssl, + buf + len_without_binders, + buf + msg_len, + &dummy0, &dummy1, + SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + len_without_binders, + msg_len - len_without_binders ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare ClientHello message in output buffer, up to + * but excluding the PSK binder list (if present). + * + * In contrast to other handshake writing functions, this + * function returns two length values: Firstly, the length + * of the message up to the binder's list. And secondly, + * the total length of the message including the binders + * list. */ + buf = ssl->out_msg; + len = MBEDTLS_SSL_MAX_CONTENT_LEN; + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_write_partial( ssl, buf, len, + &len_without_binders, + &msg_len ) ); + ssl->out_msglen = msg_len; + + { + unsigned char hs_hdr[4]; + size_t const hs_len = msg_len - 4; + + /* Build HS header for checksum update. */ + hs_hdr[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + hs_hdr[1] = (unsigned char)( hs_len >> 16 ); + hs_hdr[2] = (unsigned char)( hs_len >> 8 ); + hs_hdr[3] = (unsigned char)( hs_len >> 0 ); + + ssl->handshake->update_checksum( ssl, hs_hdr, sizeof( hs_hdr ) ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + 4, len_without_binders - 4 ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Patch the PSK binder after updating the HS checksum. */ + { + + size_t dummy0, dummy1; + mbedtls_ssl_write_pre_shared_key_ext( ssl, + buf + len_without_binders, + buf + len, + &dummy0, &dummy1, + SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + len_without_binders, + msg_len - len_without_binders ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED && + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + + MBEDTLS_SSL_DEBUG_BUF( 3, "ClientHello", ssl->out_msg, ssl->out_msglen ); + + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg_ext( + ssl, 0 /* no checksum update */ ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* NOTE: With the new messaging layer, the postprocessing + * step might come after the dispatching step if the + * latter doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. + * + * Further, once the two calls can be re-ordered, the two + * calls can be consolidated. + */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + return( ret ); +} + +static int ssl_client_hello_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + size_t rand_bytes_len; + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided" ) ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + + rand_bytes_len = 32; + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->handshake->randbytes, rand_bytes_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_generate_random", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + /* Determine whether session id has not been created already */ + if( ssl->session_negotiate->id_len == 0 ) + { + + /* Creating a session id with 32 byte length */ + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "creating session id failed", ret ); + return( ret ); + } + } + + ssl->session_negotiate->id_len = 32; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + return( 0 ); +} + +static int ssl_client_hello_write_partial( mbedtls_ssl_context* ssl, + unsigned char* buf, size_t buflen, + size_t* len_without_binders, + size_t* len_with_binders ) +{ + int ret; + + /* Extensions */ + + /* extension_start + * Used during extension writing where the + * buffer pointer to the beginning of the + * extension list must be kept to write + * the total extension list size in the end. + */ + unsigned char* extension_start; + size_t cur_ext_len; /* Size of the current extension */ + size_t total_ext_len; /* Size of list of extensions */ + + /* Length information */ + size_t rand_bytes_len; + size_t version_len; + + /* Buffer management */ + unsigned char* start = buf; + unsigned char* end = buf + buflen; + + /* Ciphersuite-related variables */ + const int* ciphersuites; + const mbedtls_ssl_ciphersuite_t* ciphersuite_info; + size_t i; /* used to iterate through ciphersuite list */ + /* ciphersuite_start points to the start of the ciphersuite list, i.e. to the length field*/ + unsigned char* ciphersuite_start; + size_t ciphersuite_count; + + /* Keeping track of the included extensions */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + + rand_bytes_len = 32; + + /* NOTE: + * Even for DTLS 1.3, we are writing a TLS handshake header here. + * The actual DTLS 1.3 handshake header is inserted in + * the record writing routine mbedtls_ssl_write_record(). + * + * For cTLS the length, and the version field + * are elided. The random bytes are shorter. + */ + version_len = 2; + + /* With MPS we don't need to write the handshake header. */ +#if !defined(MBEDTLS_SSL_USE_MPS) + { + size_t const tls_hs_hdr_len = 4; + + if( buflen < tls_hs_hdr_len + version_len + rand_bytes_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + buf += tls_hs_hdr_len; + buflen -= tls_hs_hdr_len; + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + if( ssl->conf->max_major_ver == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, " + "consider using mbedtls_ssl_config_defaults()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + ssl->major_ver = ssl->conf->min_major_ver; + ssl->minor_ver = ssl->conf->min_minor_ver; + + /* For TLS 1.3 we use the legacy version number {0x03, 0x03} + * instead of the true version number. + * + * For DTLS 1.3 we use the legacy version number + * {254,253}. + * + * In cTLS the version number is elided. + */ + *buf++ = 0x03; + *buf++ = 0x03; + buflen -= version_len; + + /* Write random bytes */ + memcpy( buf, ssl->handshake->randbytes, rand_bytes_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf, rand_bytes_len ); + + buf += rand_bytes_len; + buflen -= rand_bytes_len; + + /* Versions of TLS before TLS 1.3 supported a + * "session resumption" feature which has been merged with pre-shared + * keys in this version. A client which has a + * cached session ID set by a pre-TLS 1.3 server SHOULD set this + * field to that value. In compatibility mode, + * this field MUST be non-empty, so a client not offering a + * pre-TLS 1.3 session MUST generate a new 32-byte value. This value + * need not be random but SHOULD be unpredictable to avoid + * implementations fixating on a specific value ( also known as + * ossification ). Otherwise, it MUST be set as a zero-length vector + * ( i.e., a zero-valued single byte length field ). + */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( buflen < ( ssl->session_negotiate->id_len + 1 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = (unsigned char)ssl->session_negotiate->id_len; /* write session id length */ + memcpy( buf, ssl->session_negotiate->id, ssl->session_negotiate->id_len ); /* write session id */ + + buf += ssl->session_negotiate->id_len; + buflen -= ssl->session_negotiate->id_len; + + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session id len.: %d", ssl->session_negotiate->id_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", ssl->session_negotiate->id, ssl->session_negotiate->id_len ); +#else + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = 0; /* session id length set to zero */ + buflen -= 1; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* + * Ciphersuite list + * + * This is a list of the symmetric cipher options supported by + * the client, specifically the record protection algorithm + * ( including secret key length ) and a hash to be used with + * HKDF, in descending order of client preference. + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Skip writing ciphersuite length for now */ + ciphersuite_count = 0; + ciphersuite_start = buf; + buf += 2; + buflen -= 2; + + for ( i = 0; ciphersuites[i] != 0; i++ ) + { + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + continue; + + if( ciphersuite_info->min_minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 || + ciphersuite_info->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + continue; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x, %s", + ciphersuites[i], ciphersuite_info->name ) ); + + ciphersuite_count++; + + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = (unsigned char)( ciphersuites[i] >> 8 ); + *buf++ = (unsigned char)( ciphersuites[i] ); + + buflen -= 2; + +#if defined(MBEDTLS_ZERO_RTT) + /* For ZeroRTT we only add a single ciphersuite. */ + break; +#endif /* MBEDTLS_ZERO_RTT */ + } + + /* write ciphersuite length now */ + *ciphersuite_start++ = (unsigned char)( ciphersuite_count*2 >> 8 ); + *ciphersuite_start++ = (unsigned char)( ciphersuite_count*2 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", ciphersuite_count ) ); + + /* For every TLS 1.3 ClientHello, this vector MUST contain exactly + * one byte set to zero, which corresponds to the 'null' compression + * method in prior versions of TLS. + * + * For cTLS this field is elided. + */ + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = 1; + *buf++ = MBEDTLS_SSL_COMPRESS_NULL; + + buflen -= 2; + + /* First write extensions, then the total length */ + extension_start = buf; + total_ext_len = 0; + buf += 2; + + /* Supported Versions Extension is mandatory with TLS 1.3. + * + * For cTLS we only need to provide it if there is more than one version + * and currently there is only one. + */ + ssl_write_supported_versions_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* For TLS / DTLS 1.3 we need to support the use of cookies + * ( if the server provided them ) */ + ssl_write_cookie_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_write_early_data_ext( ssl, buf, (size_t)( end - buf ), + &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /* For PSK-based ciphersuites we don't really need the SNI extension */ + ssl_write_hostname_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* For PSK-based ciphersuites we need the pre-shared-key extension + * and the psk_key_exchange_modes extension. + * + * The pre_shared_key_ext extension MUST be the last extension in the ClientHello. + * Servers MUST check that it is the last extension and otherwise fail the handshake + * with an "illegal_parameter" alert. + */ + + /* Add the psk_key_exchange_modes extension. + */ + ret = ssl_write_psk_key_exchange_modes_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + /* The supported_groups and the key_share extensions are + * REQUIRED for ECDHE ciphersuites. + */ + ret = ssl_write_supported_groups_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* The supported_signature_algorithms extension is REQUIRED for + * certificate authenticated ciphersuites. */ + ret = mbedtls_ssl_write_signature_algorithms_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* We need to send the key shares under three conditions: + * 1 ) A certificate-based ciphersuite is being offered. In this case + * supported_groups and supported_signature extensions have been successfully added. + * 2 ) A PSK-based ciphersuite with ECDHE is offered. In this case the + * psk_key_exchange_modes has been added as the last extension. + * 3 ) Or, in case all ciphers are supported ( which includes #1 and #2 from above ) + */ + + ret = ssl_write_key_shares_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + { + size_t bytes_written; + /* We need to save the pointer to the pre-shared key extension + * because it has to be updated later. */ + ret = mbedtls_ssl_write_pre_shared_key_ext( ssl, buf, end, + &bytes_written, + &cur_ext_len, + SSL_WRITE_PSK_EXT_PARTIAL ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += bytes_written; + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + total_ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", extension_start, total_ext_len ); + + /* Write extension length */ + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len ) & 0xFF ); + + *len_without_binders = buf - start; + *len_with_binders = ( extension_start + total_ext_len ) - start; + return( 0 ); +} + +static int ssl_parse_supported_version_ext( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t len ) +{ + ((void) ssl); + + if( len != 2 || + buf[0] != MBEDTLS_SSL_MAJOR_VERSION_3 || + buf[1] != MBEDTLS_SSL_MINOR_VERSION_4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected version" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* For ticket handling, we need to populate the version + * and the endpoint information into the session structure + * since only session information is available in that API. + */ + ssl->session_negotiate->minor_ver = ssl->minor_ver; + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours ( and len is always 1 ) + */ + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->conf->mfl_code ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * struct { + * opaque identity<1..2^16-1>; + * uint32 obfuscated_ticket_age; + * } PskIdentity; + * + * opaque PskBinderEntry<32..255>; + * + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * PskIdentity identities<7..2^16-1>; + * PskBinderEntry binders<33..2^16-1>; + * case server_hello: + * uint16 selected_identity; + * }; + * + * } PreSharedKeyExtension; + * + */ + +static int ssl_parse_server_psk_identity_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + size_t selected_identity; + + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + + /* Check which PSK we've offered. + * + * NOTE: Ultimately, we want to offer multiple PSKs, and in this + * case, we need to iterate over them here. + */ + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + /* If we haven't offered a PSK, the server must not send + * a PSK identity extension. */ + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( len != (size_t) 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + selected_identity = ( (size_t) buf[0] << 8 ) | (size_t) buf[1]; + + /* We have offered only one PSK, so the only valid choice + * for the server is PSK index 0. + * + * This will change once we support multiple PSKs. */ + if( selected_identity > 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server's chosen PSK identity out of range" ) ); + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* Set the chosen PSK + * + * TODO: We don't have to do this in case we offered 0-RTT and the + * server accepted it, because in this case we've already + * set the handshake PSK. */ + ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret ); + return( ret ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + return( 0 ); +} + +#endif + +#if defined(MBEDTLS_ZERO_RTT) +/* Early Data Extension +* +* struct {} Empty; +* +* struct { +* select (Handshake.msg_type) { +* case new_session_ticket: uint32 max_early_data_size; +* case client_hello: Empty; +* case encrypted_extensions: Empty; +* }; +* } EarlyDataIndication; +* +* This function only handles the case of the EncryptedExtensions message. +*/ +int ssl_parse_encrypted_extensions_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + { + /* The server must not send the EarlyDataIndication if the + * client hasn't indicated the use of 0-RTT. */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( len != 0 ) + { + /* The message must be empty. */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Nothing to parse */ + ((void) buf); + + ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_ACCEPTED; + return( 0 ); +} + +int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ) +{ + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + return( ssl->early_data_status ); +} + +int mbedtls_ssl_set_early_data( mbedtls_ssl_context *ssl, + const unsigned char *buffer, size_t len ) +{ + if( buffer == NULL || len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->early_data_buf = buffer; + ssl->early_data_len = len; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +/* + + ssl_parse_key_shares_ext() verifies whether the information in the extension + is correct and stores the provided key shares. + +*/ + +/* The ssl_parse_key_shares_ext() function is used + * by the client to parse a KeyShare extension in + * a ServerHello message. + * + * The server only provides a single KeyShareEntry. + */ +static int ssl_parse_key_shares_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) { + + int ret = 0; + unsigned char *end = (unsigned char*)buf + len; + unsigned char *start = (unsigned char*)buf; + int named_group; + int i; + const mbedtls_ecp_curve_info *curve_info; + int match_found = 0; + mbedtls_ecp_group_id gid; + + /* Is there a key share available at the server config? */ + /* if( ssl->conf->keyshare_ctx == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no key share context" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + */ + + /* read named group */ + named_group = ( buf[0] << 8 ) | buf[1]; + + /* We need to find out which key share the server had selected from + * those sent out. + */ + + for( i=0; + ssl->handshake->key_shares_curve_list[i] != MBEDTLS_ECP_DP_NONE; + i++ ) { + + gid = ssl->handshake->key_shares_curve_list[i]; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( gid ); + + /* If we find a match then we need to read the key share + * provided by the server and store it alongside the + * respective key share structure. + */ + if( curve_info->tls_id == named_group ) + { + match_found = 1; + + break; + } + } + + if( match_found == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ( ret = mbedtls_ecdh_read_tls_13_params( &ssl->handshake->ecdh_ctx, + ( const unsigned char ** )&start, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_tls_13_params" ), ret ); + return( ret ); + } + + if( check_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "check_ecdh_params() failed!" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + return( ret ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const char **p; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 ( list_len ) + 1 ( name_len ) + 1 ( name ) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + name_len = buf[2]; + if( name_len != list_len - 1 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* Check that the server chosen protocol was in our list and save it */ + for ( p = ssl->conf->alpn_list; *p != NULL; p++ ) + { + if( name_len == strlen( *p ) && + memcmp( buf + 3, *p, name_len ) == 0 ) + { + ssl->alpn_chosen = *p; + return( 0 ); + } + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * + * STATE HANDLING: CertificateRequest + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ); + +/* Coordination: + * Deals with the ambiguity of not knowing if a CertificateRequest + * will be sent. Returns a negative code on failure, or + * - SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST + * - SSL_CERTIFICATE_REQUEST_SKIP + * indicating if a Certificate Request is expected or not. + */ +#define SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST 0 +#define SSL_CERTIFICATE_REQUEST_SKIP 1 +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_certificate_request_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + /* Coordination step + * - Fetch record + * - Make sure it's either a CertificateRequest or a ServerHelloDone + */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_certificate_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ) + { + unsigned char *buf; + size_t buflen; + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_parse( ssl, buf, buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_REQUEST_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + +cleanup: + + /* In the MPS one would close the read-port here to + * ensure there's no overlap of reading and writing. */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + return( ret ); +} + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= skip parse certificate request" ) ); + return( SSL_CERTIFICATE_REQUEST_SKIP ); + } + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + if( ret != MBEDTLS_MPS_MSG_HS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, &msg ) ); + + if( msg.type == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + return( SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ); + + return( SSL_CERTIFICATE_REQUEST_SKIP ); + +cleanup: + return( ret); +} + +#else /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= skip parse certificate request" ) ); + return( SSL_CERTIFICATE_REQUEST_SKIP ); + } + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + ssl->keep_current_message = 1; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + { + return( SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ); + } + + return( SSL_CERTIFICATE_REQUEST_SKIP ); +} + +static int ssl_certificate_request_fetch( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + int ret; + const unsigned char* p; + const unsigned char* ext; + size_t ext_len = 0; + size_t context_len = 0; + + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* + * struct { + * opaque certificate_request_context<0..2^8-1>; + * Extension extensions<2..2^16-1>; + * } CertificateRequest; + */ + + p = buf; + + /* + * Parse certificate_request_context + */ + context_len = (size_t) p[0]; + + /* skip context_len */ + p++; + + /* Fixed length fields are: + * - 1 for length of context + * - 2 for length of extensions + * ----- + * 3 bytes + */ + + if( buflen < (size_t) ( 3 + context_len ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* store context ( if necessary ) */ + if( context_len > 0 ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Certificate Request Context", + p, context_len ); + + ssl->handshake->certificate_request_context = + mbedtls_calloc( context_len, 1 ); + if( ssl->handshake->certificate_request_context == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + memcpy( ssl->handshake->certificate_request_context, p, context_len ); + + /* jump over certificate_request_context */ + p += context_len; + } + + /* + * Parse extensions + */ + ext_len = ( (size_t) p[0] << 8 ) | ( (size_t) p[1] ); + + /* At least one extension needs to be present, + * namely signature_algorithms ext. */ + if( ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* skip total extension length */ + p += 2; + + ext = p; /* jump to extensions */ + while( ext_len ) + { + size_t ext_id = ( ( size_t ) ext[0] << 8 ) | ( ( size_t ) ext[1] ); + size_t ext_size = ( ( size_t ) ext[2] << 8 ) | ( ( size_t ) ext[3] ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "found signature_algorithms extension" ) ); + + if( ( ret = mbedtls_ssl_parse_signature_algorithms_ext( ssl, + ext + 4, (size_t) ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_parse_signature_algorithms_ext", ret ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + ret ); + return( ret ); + } + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "unknown extension found: %d ( ignoring )", ext_id ) ); + break; + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + } + + ssl->client_auth = 1; + return( 0 ); +} +#endif /* ( MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ + + +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CERTIFICATE ); + return( 0 ); +} + +/* + * + * EncryptedExtensions message + * + * The EncryptedExtensions message contains any extensions which + * should be protected, i.e., any which are not needed to establish + * the cryptographic context. + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_encrypted_extensions_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_encrypted_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse encrypted extensions" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_parse( ssl, buf, buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse encrypted extensions" ) ); + return( ret ); + +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_encrypted_extensions_fetch( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + ret = MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} + + +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_encrypted_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + int ret = 0; + size_t ext_len; + const unsigned char *ext; + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension message too short" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + ext_len = ( ( (size_t) buf[0] << 8 ) | ( (size_t) buf[1] ) ); + + buf += 2; /* skip extension length */ + ext = buf; + + /* Checking for an extension length that is too short */ + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension message too short" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + /* Checking for an extension length that is not aligned with the rest of the message */ + if( buflen != 2 + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension lengths misaligned" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "encrypted extensions extensions", ext, ext_len ); + + while( ext_len ) + { + unsigned int ext_id = ( ( (unsigned int) ext[0] << 8 ) | ( (unsigned int) ext[1] ) ); + size_t ext_size = ( ( (size_t) ext[2] << 8 ) | ( (size_t) ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + /* TBD: The client MUST check EncryptedExtensions for the + * presence of any forbidden extensions and if any are found MUST abort + * the handshake with an "illegal_parameter" alert. + */ + + switch( ext_id ) + { + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_max_fragment_length_ext", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_alpn_ext", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found server_name extension" ) ); + + /* The server_name extension should be an empty extension */ + + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_ZERO_RTT) + case MBEDTLS_TLS_EXT_EARLY_DATA: + MBEDTLS_SSL_DEBUG_MSG(3, ( "found early_data extension" )); + + ret = ssl_parse_encrypted_extensions_early_data_ext( + ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_early_data_ext", ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_ZERO_RTT */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + break; + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse encrypted extension" ) ); + + return( ret ); +} + +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST ); + return( 0 ); +} + + +/* + * + * STATE HANDLING: ServerHello + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ); + +/* Fetch and preprocess + * Returns a negative value on failure, and otherwise + * - SSL_SERVER_HELLO_COORDINATE_HELLO or + * - SSL_SERVER_HELLO_COORDINATE_HRR + * to indicate which message is expected and to be parsed next. */ +#define SSL_SERVER_HELLO_COORDINATE_HELLO 0 +#define SSL_SERVER_HELLO_COORDINATE_HRR 1 + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + mbedtls_mps_handshake_in *msg, + unsigned char **buf, + size_t *buflen ); +#else +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ); +#endif + +/* Parse ServerHello */ +static int ssl_server_hello_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_hrr_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +static int ssl_hrr_postprocess( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +/* + * Implementation + */ + +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_in msg; +#endif + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + /* Coordination step + * - Fetch record + * - Make sure it's either a ServerHello or a HRR. + * - Switch processing routine in case of HRR + */ + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK_NEG( ssl_server_hello_coordinate( ssl, &msg, + &buf, &buflen ) ); +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_server_hello_coordinate( ssl, + &buf, &buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Parsing step + * We know what message to expect by now and call + * the respective parsing function. + */ + + if( ret == SSL_SERVER_HELLO_COORDINATE_HELLO ) + { + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_parse( ssl, buf, buflen ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, buflen ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + } + else + { + MBEDTLS_SSL_PROC_CHK( ssl_hrr_parse( ssl, buf, buflen ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_hrr_postprocess( ssl, buf, buflen ) ); + } + + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + return( ret ); +} + +static int ssl_server_hello_is_hrr( unsigned const char *buf ) +{ + const char magic_hrr_string[32] = + { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33 ,0x9C }; + + /* Check whether this message is a HelloRetryRequest ( HRR ) message. + * + * ServerHello and HRR are only distinguished by Random set to the + * special value of the SHA-256 of "HelloRetryRequest". + * + * struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + */ + + if( memcmp( buf + 2, magic_hrr_string, + sizeof( magic_hrr_string ) ) == 0 ) + { + return( 1 ); + } + + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + mbedtls_mps_handshake_in *msg, + unsigned char **buf, + size_t *buflen ) +{ + int ret = 0; + unsigned char *peak; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ret == MBEDTLS_MPS_MSG_CCS ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + msg ) ); + + if( msg->type != MBEDTLS_SSL_HS_SERVER_HELLO ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + ret = mbedtls_mps_reader_get( msg->handle, + msg->length, + &peak, + NULL ); + + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_pause( &ssl->mps.l4 ) ); + ret = MBEDTLS_ERR_SSL_WANT_READ; + } + else + { + if( ssl_server_hello_is_hrr( peak ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received HelloRetryRequest message" ) ); + ret = SSL_SERVER_HELLO_COORDINATE_HRR; + } + else + { + ret = SSL_SERVER_HELLO_COORDINATE_HELLO; + } + + *buf = peak; + *buflen = msg->length; + } + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_read_record( ssl, 0 ) ); + + /* TBD: If we do an HRR, keep track of the number + * of ClientHello's we sent, and fail if it + * exceeds the configured threshold. */ + + if( ( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) || + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + *buf = ssl->in_msg; + *buflen = ssl->in_hslen; + + if( ssl_server_hello_is_hrr( ssl->in_msg + 4 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received HelloRetryRequest message" ) ); + ret = SSL_SERVER_HELLO_COORDINATE_HRR; + } + else + { + ret = SSL_SERVER_HELLO_COORDINATE_HELLO; + } + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_server_hello_session_id_check( mbedtls_ssl_context* ssl, + const unsigned char** buf, + const unsigned char* end ) +{ + size_t buflen = (size_t)( end - *buf ); + size_t recv_id_len; + + if( buflen == 0 ) + return( 1 ); + + recv_id_len = **buf; + *buf += 1; /* skip session id length */ + buflen -= 1; + + /* legacy_session_id_echo */ + if( ssl->session_negotiate->id_len != recv_id_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Mismatch of session id length" ) ); + return( 1 ); + } + + if( buflen < recv_id_len ) + return( 1 ); + + if( memcmp( ssl->session_negotiate->id, *buf, + ssl->session_negotiate->id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unexpected legacy_session_id_echo" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Expected Session ID", + ssl->session_negotiate->id, + ssl->session_negotiate->id_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Received Session ID", *buf, + ssl->session_negotiate->id_len ); + return( 1 ); + } + + *buf += recv_id_len; + buflen -= recv_id_len; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Session ID", + ssl->session_negotiate->id, + ssl->session_negotiate->id_len ); + return( 0 ); +} + +static int ssl_server_hello_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + + int ret; /* return value */ + int i; /* scratch value */ + const unsigned char* msg_end = buf + buflen; /* pointer to the end of the buffer for length checks */ + + size_t ext_len; /* stores length of all extensions */ + unsigned int ext_id; /* id of an extension */ + const unsigned char* ext; /* pointer to an individual extension */ + unsigned int ext_size; /* size of an individual extension */ + + const mbedtls_ssl_ciphersuite_t* suite_info; /* pointer to ciphersuite */ + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t hs_hdr_add = 4; +#else + size_t hs_hdr_add = 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Check for minimal length */ + /* struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + * + * 38 = 32 ( random bytes ) + 2 ( ciphersuite ) + 2 ( version ) + + * 1 ( legacy_compression_method ) + 1 ( minimum for legacy_session_id_echo ) + */ + if( buflen < 38 + hs_hdr_add ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message - min size not reached" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "server hello", buf, buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* skip header */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + /* The version field in the ServerHello must contain 0x303 */ + if( buf[0] != 0x03 || buf[1] != 0x03 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + /* skip version */ + buf += 2; + + /* Internally we use the correct 1.3 version */ + ssl->major_ver = 0x03; + ssl->minor_ver = 0x04; + + /* store server-provided random values */ + memcpy( ssl->handshake->randbytes + 32, buf, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 2, 32 ); + + /* skip random bytes */ + buf += 32; + + if( ssl_server_hello_session_id_check( ssl, &buf, msg_end ) != 0 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* read server-selected ciphersuite, which follows random bytes */ + i = ( buf[0] << 8 ) | buf[1]; + + /* skip ciphersuite */ + buf += 2; + + /* TBD: Check whether we have offered this ciphersuite */ + /* Via the force_ciphersuite version we may have instructed the client */ + /* to use a difference ciphersuite. */ + + /* Configure ciphersuites */ + ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info ); + + ssl->session_negotiate->ciphersuite = i; + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: ( %04x ) - %s", i, suite_info->name ) ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + i = 0; + while ( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + /* Ensure that compression method is set to zero */ + if( buf[0] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* skip compression */ + buf++; + + /* Are we reading beyond the message buffer? */ + if( ( buf + 2 ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ext_len = ( ( buf[0] << 8 ) | ( buf[1] ) ); + buf += 2; /* skip extension length */ + + /* Are we reading beyond the message buffer? */ + if( ( buf + ext_len ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ext = buf; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello extensions", ext, ext_len ); + + while ( ext_len ) + { + ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); + ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_versions extension" ) ); + + ret = ssl_parse_supported_version_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PRE_SHARED_KEY: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found pre_shared_key extension" ) ); + if( ( ret = ssl_parse_server_psk_identity_ext( ssl, ext + 4, (size_t)ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_server_psk_identity_ext" ), ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_KEY_SHARES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found key_shares extension" ) ); + + if( ( ret = ssl_parse_key_shares_ext( ssl, ext + 4, (size_t)ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_key_shares_ext", ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + return( 0 ); +} + + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + /* We need to set the key exchange algorithm based on the + * following rules: + * + * 1 ) IF PRE_SHARED_KEY extension was received + * THEN set MBEDTLS_KEY_EXCHANGE_PSK + * 2 ) IF PRE_SHARED_KEY extension && KEY_SHARE was received + * THEN set MBEDTLS_KEY_EXCHANGE_ECDHE_PSK + * 3 ) IF KEY_SHARES extension was received && SIG_ALG extension received + * THEN set MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA + * ELSE unknown key exchange mechanism. + */ + + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) + { + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_PSK; + else + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_PSK; + } + else if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA; + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unknown key exchange." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* Start the TLS 1.3 key schedule: Set the PSK and derive early secret. + * + * TODO: We don't have to do this in case we offered 0-RTT and the + * server accepted it. In this case, we could skip generating + * the early secret. */ + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", + ret ); + return( ret ); + } + + /* Compute handshake secret */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_master_secret", ret ); + return( ret ); + } + + /* Next evolution in key schedule: Establish handshake secret and + * key material. */ + ret = mbedtls_ssl_tls1_3_generate_handshake_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_handshake_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_handshake = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_handshake == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_handshake, + &ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Switch to new keys for inbound traffic. */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to handshake keys for inbound traffic" ) ); + ssl->session_in = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_platform_zeroize( &traffic_keys, sizeof( traffic_keys ) ); + + return( 0 ); +} + + +static int ssl_hrr_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t buflen ) +{ + int ret; /* return value */ + int i; /* scratch value */ + int found = 0; + const unsigned char* msg_end = buf + buflen; /* pointer to the end of the buffer for length checks */ + + size_t ext_len; /* stores length of all extensions */ + unsigned int ext_id; /* id of an extension */ + const unsigned char* ext; /* pointer to an individual extension */ + unsigned int ext_size; /* size of an individual extension */ + + const mbedtls_ssl_ciphersuite_t* suite_info; /* pointer to ciphersuite */ + +#if defined(MBEDTLS_ECDH_C) + /* Variables for parsing the key_share */ + const mbedtls_ecp_group_id* grp_id; + const mbedtls_ecp_curve_info* info, * curve = NULL; + int tls_id; +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) + size_t cookie_len; + unsigned char *cookie; +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t hs_hdr_add = 0; +#else + size_t hs_hdr_add = 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Check for minimal length */ + /* struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + * + * 38 = 32 ( random bytes ) + 2 ( ciphersuite ) + 2 ( version ) + + * 1 ( legacy_compression_method ) + 1 ( minimum for legacy_session_id_echo ) + */ + if( buflen < 38 + hs_hdr_add ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message - min size not reached" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "hello retry request", buf, buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* skip header */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_BUF( 3, "hello retry request, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + /* The version field must contain 0x303 */ + if( buf[0] != 0x03 || buf[1] != 0x03 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + /* skip version */ + buf += 2; + + /* Internally we use the correct 1.3 version */ + ssl->major_ver = 0x03; + ssl->minor_ver = 0x04; + + /* store server-provided random values */ + memcpy( ssl->handshake->randbytes + 32, buf, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "hello retry request, random bytes", buf + 2, 32 ); + + /* skip random bytes */ + buf += 32; + + if( ssl_server_hello_session_id_check( ssl, &buf, msg_end ) != 0 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* read server-selected ciphersuite, which follows random bytes */ + i = ( buf[0] << 8 ) | buf[1]; + + /* skip ciphersuite */ + buf += 2; + + /* TBD: Check whether we have offered this ciphersuite */ + /* Via the force_ciphersuite version we may have instructed the client */ + /* to use a difference ciphersuite. */ + + /* Configure ciphersuites */ + ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info ); + + ssl->session_negotiate->ciphersuite = i; + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "hello retry request, chosen ciphersuite: ( %04x ) - %s", i, suite_info->name ) ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + i = 0; + while ( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + /* Ensure that compression method is set to zero */ + if( buf[0] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* skip compression */ + buf++; + + /* Are we reading beyond the message buffer? */ + if( ( buf + 2 ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + ext_len = ( ( buf[0] << 8 ) | ( buf[1] ) ); + buf += 2; /* skip extension length */ + + /* Are we reading beyond the message buffer? */ + if( ( buf + ext_len ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + ext = buf; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "hello retry request, total extension length: %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "extensions", ext, ext_len ); + + while ( ext_len ) + { + ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); + ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_COOKIE_C) + case MBEDTLS_TLS_EXT_COOKIE: + + /* Retrieve length field of cookie */ + if( ext_size >= 2 ) + { + cookie = (unsigned char *) ( ext + 4 ); + cookie_len = ( cookie[0] << 8 ) | cookie[1]; + cookie += 2; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + if( ( cookie_len + 2 ) != ext_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie extension", cookie, cookie_len ); + + mbedtls_free( ssl->handshake->verify_cookie ); + + ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len ); + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", cookie_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ssl->handshake->verify_cookie, cookie, cookie_len ); + ssl->handshake->verify_cookie_len = (unsigned char) cookie_len; + break; +#endif /* MBEDTLS_SSL_COOKIE_C */ + + + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_versions extension" ) ); + + ret = ssl_parse_supported_version_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_KEY_SHARES: + + MBEDTLS_SSL_DEBUG_BUF( 3, "key_share extension", ext + 4, ext_size ); + + /* Read selected_group */ + tls_id = ( ( ext[4] << 8 ) | ( ext[5] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group ( %d )", tls_id ) ); + + info = mbedtls_ecp_curve_info_from_tls_id( tls_id ); + + if( info != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group by name ( %s )", info->name ) ); + } + /* + * Upon receipt of this extension in a HelloRetryRequest, the client + * MUST first verify that the selected_group field corresponds to a + * group which was provided in the "supported_groups" extension in the + * original ClientHello. + * + * The supported_group was based on the info in ssl->conf->curve_list. + */ + + for ( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) { + /* In the initial ClientHello we transmitted the key shares based on + * key_shares_curve_list. + */ + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( info->tls_id == tls_id ) + { + /* We found a match */ + found = 1; + break; + } + } + + /* If the server provided a key share that was not sent in the ClientHello + * then the client MUST abort the handshake with an "illegal_parameter" alert. + */ + if( found == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server provided key share that was not sent in ClientHello )" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* + * Client MUST verify that the selected_group + * field does not correspond to a group which was provided in the + * "key_share" extension in the original ClientHello. + */ + found = 0; + for ( grp_id = ssl->handshake->key_shares_curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( info->tls_id == tls_id ) + { + /* We found a match */ + found = 1; + break; + } + } + + /* If the server sent an HRR message with a key share already + * provided in the ClientHello then the client MUST abort the + * handshake with an "illegal_parameter" alert. + */ + if( found == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server sent HRR with a key share already provided in ClientHello )" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* Modify key_shares_curve_list for next ClientHello + * based on info provided by server. For the second + * ClientHello we only send the key share expected + * by the server. + */ + curve = mbedtls_ecp_curve_info_from_tls_id( tls_id ); + + if( curve == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ssl->handshake->key_shares_curve_list[0] = curve->grp_id; + ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE; + + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + /* Jump to next extension */ + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + } + + return( 0 ); +} + +static int ssl_hrr_postprocess( mbedtls_ssl_context* ssl, + const unsigned char* orig_buf, + size_t orig_msg_len ) +{ + int ret = 0; + + ssl->handshake->hello_retry_requests_received++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Compress transcript hash for stateless HRR" ) ); + ret = mbedtls_ssl_hash_transcript( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hash_transcript", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + orig_buf, orig_msg_len ); +#else /* MBEDTLS_SSL_USE_MPS */ + /* Add transcript for HRR */ + ssl->handshake->update_checksum( ssl, orig_buf, orig_msg_len ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_new_session_ticket_fetch( mbedtls_ssl_context* ssl, + unsigned char** dst, + size_t* dstlen ) +{ + *dst = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + *dstlen = ssl->in_hslen - mbedtls_ssl_hs_hdr_len( ssl ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_new_session_ticket_early_data_ext_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t ext_size ) +{ + /* From RFC 8446: + * + * struct { + * select (Handshake.msg_type) { + * case new_session_ticket: uint32 max_early_data_size; + * case client_hello: Empty; + * case encrypted_extensions: Empty; + * }; + * } EarlyDataIndication; + */ + + if( ext_size == 4 && ssl->session != NULL ) + { + ssl->session->max_early_data_size = + ( (uint32_t) buf[0] << 24 ) | ( (uint32_t) buf[1] << 16 ) | + ( (uint32_t) buf[2] << 8 ) | ( (uint32_t) buf[3] ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->max_early_data_size: %u", + ssl->session->max_early_data_size ) ); + ssl->session->ticket_flags |= allow_early_data; + return( 0 ); + } + + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); +} + +static int ssl_new_session_ticket_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buf_remain ) +{ + int ret; + unsigned int ext_id; + size_t ext_size; + + while( buf_remain != 0 ) + { + if( buf_remain < 4 ) + { + /* TODO: Replace with DECODE_ERROR once we have merged 3.0 */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + ext_id = ( ( (unsigned) buf[0] << 8 ) | ( (unsigned) buf[1] ) ); + ext_size = ( ( (size_t) buf[2] << 8 ) | ( (size_t) buf[3] ) ); + + buf += 4; + buf_remain -= 4; + + if( ext_size > buf_remain ) + { + /* TODO: Replace with DECODE_ERROR once we have merged 3.0 */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( ext_id == MBEDTLS_TLS_EXT_EARLY_DATA ) + { + ret = ssl_new_session_ticket_early_data_ext_parse( ssl, buf, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_early_data_ext_parse", ret ); + return( ret ); + } + } + /* Ignore other extensions */ + + buf += ext_size; + buf_remain -= ext_size; + } + + return( 0 ); +} + +static int ssl_new_session_ticket_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ) +{ + int ret; + size_t ticket_len, ext_len; + unsigned char *ticket; + const mbedtls_ssl_ciphersuite_t *suite_info; + size_t used = 0, i = 0; + int hash_length; + size_t ticket_nonce_len; + unsigned char ticket_nonce[256]; + + /* + * struct { + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * opaque ticket_nonce<0..255>; + * opaque ticket<1..2^16-1>; + * Extension extensions<0..2^16-2>; + * } NewSessionTicket; + * + */ + used += 4 /* ticket_lifetime */ + + 4 /* ticket_age_add */ + + 1 /* ticket_nonce length */ + + 2 /* ticket length */ + + 2; /* extension length */ + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + /* Ticket lifetime */ + ssl->session->ticket_lifetime = + ( (unsigned) buf[i] << 24 ) | ( (unsigned) buf[i + 1] << 16 ) | + ( (unsigned) buf[i + 2] << 8 ) | ( (unsigned) buf[i + 3] << 0 ); + i += 4; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->lifetime: %u", + ssl->session->ticket_lifetime ) ); + + /* Ticket Age Add */ + ssl->session->ticket_age_add = + ( (unsigned) buf[i] << 24 ) | + ( (unsigned) buf[i + 1] << 16 ) | + ( (unsigned) buf[i + 2] << 8 ) | + ( (unsigned) buf[i + 3] << 0 ); + i += 4; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_age_add: %u", + ssl->session->ticket_age_add ) ); + + ticket_nonce_len = buf[i]; + i++; + + used += ticket_nonce_len; + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + if( ticket_nonce_len > 0 ) + { + if( ticket_nonce_len > sizeof( ticket_nonce ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket_nonce is too small" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + memcpy( ticket_nonce, &buf[i], ticket_nonce_len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "nonce:", &buf[i], + ticket_nonce_len ); + + } + i += ticket_nonce_len; + + /* Ticket */ + ticket_len = ( (size_t) buf[i] << 8 ) | ( (size_t) buf[i + 1] ); + i += 2; + + used += ticket_len; + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->length: %u", ticket_len ) ); + + /* Check if we previously received a ticket already. */ + if( ssl->session->ticket != NULL || ssl->session->ticket_len > 0 ) + { + mbedtls_free( ssl->session->ticket ); + ssl->session->ticket = NULL; + ssl->session->ticket_len = 0; + } + + if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket, buf + i, ticket_len ); + i += ticket_len; + ssl->session->ticket = ticket; + ssl->session->ticket_len = ticket_len; + + /* Ticket Extension */ + ext_len = ( (size_t) buf[ i + 0 ] << 8 ) | + ( (size_t) buf[ i + 1 ] ); + i += 2; + + used += ext_len; + if( used != buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "ticket->extension", &buf[i], ext_len ); + + ret = ssl_new_session_ticket_extensions_parse( ssl, &buf[i], ext_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_extensions_parse", ret ); + return( ret ); + } + i += ext_len; + + /* Compute PSK based on received nonce and resumption_master_secret + * in the following style: + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session->ciphersuite ); + + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + hash_length = mbedtls_hash_size_for_ciphersuite( suite_info ); + + if( hash_length == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "resumption_master_secret", + ssl->session->app_secrets.resumption_master_secret, + hash_length ); + + /* Computer resumption key + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( suite_info->mac, + ssl->session->app_secrets.resumption_master_secret, + hash_length, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( resumption ), + ticket_nonce, + ticket_nonce_len, + ssl->session->key, + hash_length ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, "Creating the ticket-resumed PSK failed", ret ); + return( ret ); + } + + ssl->session->key_len = hash_length; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Ticket-resumed PSK", ssl->session->key, + ssl->session->key_len ); + +#if defined(MBEDTLS_HAVE_TIME) + /* Store ticket creation time */ + ssl->session->ticket_received = time( NULL ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "ticket", buf, buflen ); + + return( 0 ); +} + +static int ssl_new_session_ticket_postprocess( mbedtls_ssl_context* ssl, int ret ) +{ + ((void ) ssl); + ((void ) ret); + return( 0 ); +} + +/* The ssl_new_session_ticket_process( ) function is used by the + * client to process the NewSessionTicket message, which contains + * the ticket and meta-data provided by the server in a post- + * handshake message. + */ + +static int ssl_new_session_ticket_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char* buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_NEW_SESSION_TICKET, + &buf, &buflen ) ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_postprocess( ssl, ret ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + return( ret ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +/* + * TLS and DTLS 1.3 State Maschine -- client side + */ +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Handshake completed but ssl->handshake is NULL.\n" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); + +#if defined(MBEDTLS_ECP_C) + /* We need to initialize the handshake->key_shares_curve_list. */ + if( ssl->handshake->key_shares_curve_list == NULL ) + { + /* We need to allocate one additional key share for the delimiter. */ + ssl->handshake->key_shares_curve_list = + mbedtls_calloc( 1, sizeof( mbedtls_ecp_group_id* ) * 2 ); + if( ssl->conf->key_shares_curve_list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + memcpy( ssl->handshake->key_shares_curve_list, + ssl->conf->key_shares_curve_list, + sizeof( mbedtls_ecp_group_id ) ); + + /* We need to put a delimiter to the end of the key shares curve list */ + ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE; + } +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + break; + + /* ----- WRITE CLIENT HELLO ----*/ + + case MBEDTLS_SSL_CLIENT_HELLO: + + ret = ssl_client_hello_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_client_hello", ret ); + break; + } + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + break; +#endif /* MBEDTLS_SSL_USE_MPS */ + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE EARLY DATA ----*/ + + case MBEDTLS_SSL_EARLY_APP_DATA: + + ret = ssl_write_early_data_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_early_data_process", ret ); + break; + } + + break; + + /* ----- READ SERVER HELLO ----*/ + + case MBEDTLS_SSL_SERVER_HELLO: + /* In this state the client is expecting a ServerHello + * message but the server could also return a HelloRetryRequest. + * + * Reset extensions we have seen so far. + */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_server_hello_process", ret ); + break; + } + + if( ssl->handshake->hello_retry_requests_received > 0 ) + { + /* If we received the HRR msg then we send another ClientHello */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + /* If not offering early data, the client sends a dummy + * change_cipher_spec record immediately before its + * second flight. This may either be before its second + * ClientHello or before its encrypted handshake flight. + */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + } + break; + + /* ----- WRITE CHANGE_CIPHER_SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE 2nd CLIENT HELLO ----*/ + case MBEDTLS_SSL_SECOND_CLIENT_HELLO: + ret = ssl_client_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_client_hello", ret ); + break; + } + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_SERVER_HELLO ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + break; +#endif /* MBEDTLS_SSL_USE_MPS */ + + break; + + /* ----- READ 2nd SERVER HELLO ----*/ + + case MBEDTLS_SSL_SECOND_SERVER_HELLO: + /* In this state the client is expecting a ServerHello + * message and not the HRR anymore. + */ + /* reset extensions we have seen so far */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_server_hello", ret ); + break; + } + + /* if we received a second HRR we abort */ + if( ssl->handshake->hello_retry_requests_received == 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Too many HelloRetryRequests received from server; I give up." ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return ( MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR ); + } + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + break; + + /* ----- READ ENCRYPTED EXTENSIONS ----*/ + + case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: + + ret = ssl_encrypted_extensions_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypted_extensions_process", ret ); + break; + } + + break; + + /* ----- READ CERTIFICATE REQUEST ----*/ + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_certificate_request_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_certificate_request_process", ret ); + break; + } + + break; + + /* ----- READ SERVER CERTIFICATE ----*/ + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_read_certificate_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_certificate_process", ret ); + break; + } + break; + + /* ----- READ CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_read_certificate_verify_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_certificate_verify_process", ret ); + break; + } + + break; + + /* ----- READ FINISHED ----*/ + + case MBEDTLS_SSL_SERVER_FINISHED: + + ret = mbedtls_ssl_finished_in_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_in_process", ret ); + break; + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_END_OF_EARLY_DATA ); + break; + + /* ----- WRITE END-OF-EARLY-DATA ----*/ + + case MBEDTLS_SSL_END_OF_EARLY_DATA: + + ret = ssl_write_end_of_early_data_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_end_of_early_data_process", ret ); + break; + } + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + + /* ----- WRITE CERTIFICATE ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + + ret = mbedtls_ssl_write_certificate_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_certificate_process", ret ); + break; + } + break; + + /* ----- WRITE CLIENT CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_write_certificate_verify_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_certificate_verify_process", ret ); + break; + } + break; + + /* ----- WRITE CLIENT FINISHED ----*/ + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_finished_out_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_out_process", ret ); + break; + } + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP ); + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for inbound traffic" ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for outbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform ( ssl, ssl->transform_application ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_application ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_wrapup_tls13( ssl ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + break; + + case MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET: + + ret = ssl_new_session_ticket_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_process", ret ); + break; + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + ret = MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET; + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c new file mode 100644 index 000000000000..d1e03cdf5288 --- /dev/null +++ b/library/ssl_tls13_generic.c @@ -0,0 +1,3239 @@ +/* + * Handshake-related functions shared between the TLS/DTLS client + * and server ( ssl_tls13_client.c and ssl_tls13_server.c ). + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS ( https://tls.mbed.org ) + */ + + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#include "mbedtls/ssl_ticket.h" +#include "mbedtls/debug.h" +#include "mbedtls/error.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" +#include "mbedtls/hkdf.h" +#include + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_mps_fetch_full_hs_msg( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + if( msg.type != hs_type ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + ret = mbedtls_mps_reader_get( msg.handle, + msg.length, + buf, + NULL ); + + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_pause( &ssl->mps.l4 ) ); + ret = MBEDTLS_ERR_SSL_WANT_READ; + } + else + { + MBEDTLS_SSL_PROC_CHK( ret ); + + /* *buf already set in mbedtls_mps_reader_get() */ + *buflen = msg.length; + } + +cleanup: + + return( ret ); +} + +int mbedtls_ssl_mps_hs_consume_full_hs_msg( mbedtls_ssl_context *ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +void mbedtls_ssl_add_hs_msg_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char const *msg, + size_t msg_len ) +{ + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, hs_type, msg_len ); + ssl->handshake->update_checksum( ssl, msg, msg_len ); +} + +void mbedtls_ssl_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + size_t total_hs_len ) +{ + unsigned char hs_hdr[4]; + + /* Build HS header for checksum update. */ + hs_hdr[0] = hs_type; + hs_hdr[1] = (unsigned char)( total_hs_len >> 16 ); + hs_hdr[2] = (unsigned char)( total_hs_len >> 8 ); + hs_hdr[3] = (unsigned char)( total_hs_len >> 0 ); + + ssl->handshake->update_checksum( ssl, hs_hdr, sizeof( hs_hdr ) ); +} + +/* + * + * STATE HANDLING: Write ChangeCipherSpec + * + */ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + + /* Main entry point; orchestrates the other functions */ +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ); + +#define SSL_WRITE_CCS_NEEDED 0 +#define SSL_WRITE_CCS_SKIP 1 +static int ssl_write_change_cipher_spec_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_write_change_cipher_spec_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* !MBEDTLS_SSL_USE_MPS */ +static int ssl_write_change_cipher_spec_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_change_cipher_spec_coordinate( ssl ) ); + + if( ret == SSL_WRITE_CCS_NEEDED ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_ccs( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write CCS message */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_postprocess( ssl ) ); + } + else + { + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + return( ret ); +} + +static int ssl_write_change_cipher_spec_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret = SSL_WRITE_CCS_NEEDED; + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ssl->state == MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO ) + { + /* Only transmit the CCS if we have not done so + * earlier already after the HRR. + */ + if( ssl->handshake->hello_retry_requests_sent == 0 ) + ret = SSL_WRITE_CCS_NEEDED; + else + ret = SSL_WRITE_CCS_SKIP; + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_write_change_cipher_spec_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + ((void) ssl); + + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + buf[0] = 1; + *olen = 1; + return( 0 ); +} +#endif /* !MBEDTLS_SSL_USE_MPS */ + +static int ssl_write_change_cipher_spec_postprocess( mbedtls_ssl_context* ssl ) +{ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + switch( ssl->state ) + { + case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + ssl->handshake->ccs_sent++; + break; + + case MBEDTLS_SSL_SERVER_CCS_AFTER_HRR: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + ssl->handshake->ccs_sent++; + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + switch( ssl->state ) + { + case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); + break; + case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + break; + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + break; + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +/* + * mbedtls_ssl_write_signature_algorithms_ext( ) + * + * enum { + * .... + * ecdsa_secp256r1_sha256( 0x0403 ), + * ecdsa_secp384r1_sha384( 0x0503 ), + * ecdsa_secp521r1_sha512( 0x0603 ), + * .... + * } SignatureScheme; + * + * struct { + * SignatureScheme supported_signature_algorithms<2..2^16-2>; + * } SignatureSchemeList; + * + * Only if we handle at least one key exchange that needs signatures. + */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +int mbedtls_ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + size_t sig_alg_len = 0; + const int *md; + unsigned char *sig_alg_list = buf + 6; + + *olen = 0; + + /* Skip the extension on the client if all allowed key exchanges + * are PSK-based. */ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + { + return( 0 ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding signature_algorithms extension" ) ); + + /* + * Determine length of the signature scheme list + */ + for ( md = ssl->conf->sig_hashes; *md != SIGNATURE_NONE; md++ ) + { + sig_alg_len += 2; + } + + if( sig_alg_len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No signature algorithms defined." ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( end < p || (size_t)( end - p ) < sig_alg_len + 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Write signature schemes + */ + + for ( md = ssl->conf->sig_hashes; *md != SIGNATURE_NONE; md++ ) + { + *sig_alg_list++ = (unsigned char)( ( *md >> 8 ) & 0xFF ); + *sig_alg_list++ = (unsigned char)( ( *md ) & 0xFF ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "signature scheme [%x]", *md ) ); + } + + /* + * Write extension header + */ + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + *olen = 6 + sig_alg_len; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM; + return( 0 ); +} + +int mbedtls_ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t buf_len ) +{ + size_t sig_alg_list_size; /* size of receive signature algorithms list */ + const unsigned char *p; /* pointer to individual signature algorithm */ + const unsigned char *end = buf + buf_len; /* end of buffer */ + const int *md_cur; /* iterate through configured signature schemes */ + int signature_scheme; /* store received signature algorithm scheme */ + uint32_t common_idx = 0; /* iterate through received_signature_schemes_list */ + + if( buf_len < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad signature_algorithms extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + sig_alg_list_size = ( ( size_t) buf[0] << 8 ) | ( (size_t) buf[1] ); + if( sig_alg_list_size + 2 != buf_len || + sig_alg_list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad signature_algorithms extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + memset( ssl->handshake->received_signature_schemes_list, + 0, sizeof( ssl->handshake->received_signature_schemes_list ) ); + + for( p = buf + 2; p < end && common_idx + 1 < MBEDTLS_SIGNATURE_SCHEMES_SIZE; p += 2 ) + { + signature_scheme = ( (int) p[0] << 8 ) | ( ( int ) p[1] ); + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "received signature algorithm: 0x%x", signature_scheme ) ); + + for( md_cur = ssl->conf->sig_hashes; *md_cur != SIGNATURE_NONE; md_cur++ ) + { + if( *md_cur == signature_scheme ) + { + ssl->handshake->received_signature_schemes_list[common_idx] = signature_scheme; + common_idx++; + break; + } + } + } + + if( common_idx == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no signature algorithm in common" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + + ssl->handshake->received_signature_schemes_list[common_idx] = SIGNATURE_NONE; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +#if !defined(MBEDTLS_SSL_USE_MPS) +void mbedtls_ssl_set_inbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ + if( ssl->transform_in == transform ) + return; + + ssl->transform_in = transform; + memset( ssl->in_ctr, 0, 8 ); +} + +void mbedtls_ssl_set_outbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ + ssl->transform_out = transform; + memset( ssl->cur_out_ctr, 0, 8 ); +} +#endif /* !MBEDTLS_SSL_USE_MPS */ + +/* + * The ssl_create_verify_structure() creates the verify structure. + * As input, it requires the transcript hash. + * + * The caller has to ensure that the buffer has size at least + * MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE bytes. + */ +static void ssl_create_verify_structure( unsigned char *transcript_hash, + size_t transcript_hash_len, + unsigned char *verify_buffer, + size_t *verify_buffer_len, + int from ) +{ + size_t idx = 0; + + /* RFC 8446, Section 4.4.3: + * + * The digital signature [in the CertificateVerify message] is then + * computed over the concatenation of: + * - A string that consists of octet 32 (0x20) repeated 64 times + * - The context string + * - A single 0 byte which serves as the separator + * - The content to be signed + */ + + uint8_t const verify_padding_val = 0x20; + size_t const verify_padding_len = 64; + + memset( verify_buffer + idx, verify_padding_val, verify_padding_len ); + idx += verify_padding_len; + + if( from == MBEDTLS_SSL_IS_CLIENT ) + { + memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( client_cv ) ); + idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( client_cv ); + } + else + { /* from == MBEDTLS_SSL_IS_SERVER */ + memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( server_cv ) ); + idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( server_cv ); + } + + verify_buffer[idx++] = 0x0; + + memcpy( verify_buffer + idx, transcript_hash, transcript_hash_len ); + idx += transcript_hash_len; + + *verify_buffer_len = idx; +} + +/* + * + * STATE HANDLING: CertificateVerify + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions. */ +int mbedtls_ssl_write_certificate_verify_process( mbedtls_ssl_context* ssl ); + +/* Coordinate: Check whether a certificate verify message should be sent. + * Returns a negative value on failure, and otherwise + * - SSL_WRITE_CERTIFICATE_VERIFY_SKIP + * - SSL_WRITE_CERTIFICATE_VERIFY_SEND + * to indicate if the CertificateVerify message should be sent or not. + */ +#define SSL_WRITE_CERTIFICATE_VERIFY_SKIP 0 +#define SSL_WRITE_CERTIFICATE_VERIFY_SEND 1 +static int ssl_write_certificate_verify_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_verify_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_verify_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_write_certificate_verify_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + /* Coordination step: Check if we need to send a CertificateVerify */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_certificate_verify_coordinate( ssl ) ); + + if( ret == SSL_WRITE_CERTIFICATE_VERIFY_SEND ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare CertificateVerify message in output buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + /* NOTE: With the new messaging layer, the postprocessing + * step might come after the dispatching step if the + * latter doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. + * + * Further, once the two calls can be re-ordered, the two + * calls to ssl_certificate_verify_postprocess( ) can be + * consolidated. */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + return( ret ); +} + +static int ssl_write_certificate_verify_coordinate( mbedtls_ssl_context* ssl ) +{ + int have_own_cert = 1; + int ret; + + if( mbedtls_ssl_tls13_key_exchange_with_psk( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + return( SSL_WRITE_CERTIFICATE_VERIFY_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + if( mbedtls_ssl_own_cert( ssl ) == NULL ) + have_own_cert = 0; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 || + have_own_cert == 0 || + ssl->conf->authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + return( SSL_WRITE_CERTIFICATE_VERIFY_SKIP ); + } + } + + if( have_own_cert == 0 && + ssl->client_auth == 1 && + ssl->conf->authmode != MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Check whether the signature scheme corresponds to the key we are using + */ + if( mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ) != + MBEDTLS_SSL_SIG_ECDSA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Certificate Verify: Only ECDSA signature algorithm is currently supported." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Calculate the transcript hash */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + sizeof( ssl->handshake->state_local.certificate_verify_out.handshake_hash ), + &ssl->handshake->state_local.certificate_verify_out.handshake_hash_len ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake hash", + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + ssl->handshake->state_local.certificate_verify_out.handshake_hash_len); + + return( SSL_WRITE_CERTIFICATE_VERIFY_SEND ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_verify_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t n = 0; + unsigned char verify_buffer[ MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ]; + const int *sig_scheme; /* iterate through configured signature schemes */ + size_t verify_buffer_len; + mbedtls_pk_context *own_key; + size_t own_key_size; + unsigned int md_alg; + int sig_alg; + unsigned char verify_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t verify_hash_len; + unsigned char *p; + const mbedtls_md_info_t *md_info; + /* Verify whether we can use signature algorithm */ + int signature_scheme_client; + +#if defined(MBEDTLS_SSL_USE_MPS) + p = buf; + if( buflen < 2 + MBEDTLS_MD_MAX_SIZE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#else + p = buf + 4; + /* TBD: Check whether the signature fits into the buffer. */ + if( buflen < ( mbedtls_ssl_hs_hdr_len( ssl ) + 2 + MBEDTLS_MD_MAX_SIZE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Create verify structure */ + ssl_create_verify_structure( + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + ssl->handshake->state_local.certificate_verify_out.handshake_hash_len, + verify_buffer, + &verify_buffer_len, + ssl->conf->endpoint ); + + /* + * struct { + * SignatureScheme algorithm; + * opaque signature<0..2^16-1>; + * } CertificateVerify; + */ + + /* Determine size of key */ + own_key = mbedtls_ssl_own_key( ssl ); + if( own_key != NULL) + { + own_key_size = mbedtls_pk_get_bitlen( own_key ); + switch( own_key_size) + { + case 256: + md_alg = MBEDTLS_MD_SHA256; + sig_alg = SIGNATURE_ECDSA_SECP256r1_SHA256; + break; + case 384: + md_alg = MBEDTLS_MD_SHA384; + sig_alg = SIGNATURE_ECDSA_SECP384r1_SHA384; + break; + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown key size: %d bits", + own_key_size ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + signature_scheme_client = SIGNATURE_NONE; + + for( sig_scheme = ssl->handshake->received_signature_schemes_list; + *sig_scheme != SIGNATURE_NONE; sig_scheme++ ) + { + if( *sig_scheme == sig_alg ) + { + signature_scheme_client = *sig_scheme; + break; + } + } + + if( signature_scheme_client == SIGNATURE_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + *(p++) = (unsigned char)( ( signature_scheme_client >> 8 ) & 0xFF ); + *(p++) = (unsigned char)( ( signature_scheme_client >> 0 ) & 0xFF ); + + /* Hash verify buffer with indicated hash function */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ret = mbedtls_md( md_info, verify_buffer, verify_buffer_len, verify_hash ); + if( ret != 0 ) + return( ret ); + + verify_hash_len = mbedtls_md_get_size( md_info ); + MBEDTLS_SSL_DEBUG_BUF( 3, "verify hash", verify_hash, verify_hash_len ); + + if( ( ret = mbedtls_pk_sign( own_key, md_alg, + verify_hash, verify_hash_len, + p + 2, &n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + p[0] = (unsigned char)( n >> 8 ); + p[1] = (unsigned char)( n >> 0 ); + + p += 2 + n; + + *olen = (size_t)( p - buf ); + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_certificate_verify_postprocess( mbedtls_ssl_context* ssl ) +{ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_FINISHED ); + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_FINISHED ); + } + return( 0 ); +} + +/* + * + * STATE HANDLING: Read CertificateVerify + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +int mbedtls_ssl_read_certificate_verify_process( mbedtls_ssl_context* ssl ); + +/* Coordinate: Check whether a certificate verify message is expected. + * Returns a negative value on failure, and otherwise + * - SSL_CERTIFICATE_VERIFY_SKIP + * - SSL_CERTIFICATE_VERIFY_READ + * to indicate if the CertificateVerify message should be present or not. + */ +#define SSL_CERTIFICATE_VERIFY_SKIP 0 +#define SSL_CERTIFICATE_VERIFY_READ 1 +static int ssl_read_certificate_verify_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_verify_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +/* Parse and validate CertificateVerify message + * + * Note: The size of the hash buffer is assumed to be large enough to + * hold the transcript given the selected hash algorithm. + * No bounds-checking is done inside the function. + */ +static int ssl_read_certificate_verify_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen, + unsigned char const* hash, + size_t hashlen ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +/* Update handshake state machine */ +static int ssl_read_certificate_verify_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_read_certificate_verify_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char verify_buffer[ MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ]; + size_t verify_buffer_len; + unsigned char transcript[ MBEDTLS_MD_MAX_SIZE ]; + size_t transcript_len; + + /* Coordination step */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_certificate_verify_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) // TBD: double-check + if( ret == SSL_CERTIFICATE_VERIFY_READ ) + { + unsigned char *buf; + size_t buflen; + + /* Need to calculate the hash of the transcript first + * before reading the message since otherwise it gets + * included in the transcript + */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake hash", transcript, + transcript_len ); + + /* Create verify structure */ + ssl_create_verify_structure( transcript, + transcript_len, + verify_buffer, + &verify_buffer_len, + !ssl->conf->endpoint ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_parse( ssl, buf, buflen, + verify_buffer, + verify_buffer_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_fetch( ssl, &buf, &buflen ) ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_parse( ssl, buf, buflen, + verify_buffer, + verify_buffer_len ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + if( ret == SSL_CERTIFICATE_VERIFY_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state machine and handshake checksum state. + * + * The manual update of the checksum state only needs to be + * done manually here because we couldn't have it done automatically + * when reading the message. + */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_verify_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_read_certificate_verify_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->key_exchange != MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + return( SSL_CERTIFICATE_VERIFY_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + if( ssl->session_negotiate->peer_cert == NULL ) + return( SSL_CERTIFICATE_VERIFY_SKIP ); + + return( SSL_CERTIFICATE_VERIFY_READ ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +} + + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +static int ssl_read_certificate_verify_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen, + unsigned char const* verify_buffer, + size_t verify_buffer_len ) +{ + int ret; + int signature_scheme; + size_t sig_len; + mbedtls_pk_type_t sig_alg; + mbedtls_md_type_t md_alg; + unsigned char verify_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t verify_hash_len; + + void const *opts_ptr = NULL; +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_pk_rsassa_pss_options opts; +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + /* + * struct { + * SignatureScheme algorithm; + * opaque signature<0..2^16-1>; + * } CertificateVerify; + * + */ + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + signature_scheme = ( buf[0] << 8 ) | buf[1]; + + /* We currently only support ECDSA-based signatures */ + switch( signature_scheme ) + { + case SIGNATURE_ECDSA_SECP256r1_SHA256: + md_alg = MBEDTLS_MD_SHA256; + sig_alg = MBEDTLS_PK_ECDSA; + break; + case SIGNATURE_ECDSA_SECP384r1_SHA384: + md_alg = MBEDTLS_MD_SHA384; + sig_alg = MBEDTLS_PK_ECDSA; + break; + case SIGNATURE_ECDSA_SECP521r1_SHA512: + md_alg = MBEDTLS_MD_SHA512; + sig_alg = MBEDTLS_PK_ECDSA; + break; +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + case SIGNATURE_RSA_PSS_RSAE_SHA256: + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Certificate Verify: using RSA" ) ); + md_alg = MBEDTLS_MD_SHA256; + sig_alg = MBEDTLS_PK_RSASSA_PSS; + break; +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Certificate Verify: Unknown signature algorithm." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate Verify: Signature algorithm ( %04x )", + signature_scheme ) ); + + buflen -= 2; + buf += 2; + + /* + * Signature + */ + + /* + * Check the certificate's key type matches the signature alg + */ + if( !mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, sig_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "signature algorithm doesn't match cert key" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + sig_len = ( buf[0] << 8 ) | buf[1]; + buf += 2; + buflen -= 2; + + if( buflen != sig_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Hash verify buffer with indicated hash function */ +#if defined(MBEDTLS_SHA256_C) + if( md_alg == MBEDTLS_MD_SHA256 ) + { + verify_hash_len = 32; + if( ( ret = mbedtls_sha256_ret( verify_buffer, + verify_buffer_len, verify_hash, 0 /* 0 for SHA-256 instead of SHA-224 */ ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_ret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + } + else +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + if( md_alg == MBEDTLS_MD_SHA384 ) + { + verify_hash_len = 48; + if( ( ret = mbedtls_sha512_ret( verify_buffer, + verify_buffer_len, + verify_hash, + 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_ret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + } + else +#endif /* MBEDTLS_SHA512_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Certificate Verify: Unknown signature algorithm." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "verify hash", verify_hash, verify_hash_len ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( sig_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_md_info_t* md_info; + opts.mgf1_hash_id = md_alg; + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + opts.expected_salt_len = mbedtls_md_get_size( md_info ); + opts_ptr = (const void*) &opts; + } +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + if( ( ret = mbedtls_pk_verify_ext( + sig_alg, + opts_ptr, + &ssl->session_negotiate->peer_cert->pk, + md_alg, + verify_hash, + verify_hash_len, + buf, + sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify_ext", ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + +static int ssl_read_certificate_verify_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_FINISHED ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_FINISHED ); + } + + return( 0 ); +} + + + +/* + * + * STATE HANDLING: Outgoing Certificate + * + */ + +/* + * Overview + */ + +/* Main state-handling entry point; orchestrates the other functions. */ +int mbedtls_ssl_write_certificate_process( mbedtls_ssl_context* ssl ); + +/* Check if a certificate should be written, and if yes, + * if it is available. + * Returns a negative error code on failure ( such as no certificate + * being available on the server ), and otherwise + * SSL_WRITE_CERTIFICATE_AVAILABLE or + * SSL_WRITE_CERTIFICATE_SKIP + * indicating that a Certificate message should be written based + * on the configured certificate, or whether it should be silently skipped. + */ + +#define SSL_WRITE_CERTIFICATE_AVAILABLE 0 +#define SSL_WRITE_CERTIFICATE_SKIP 1 +static int ssl_write_certificate_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +/* Write certificate message based on the configured certificate */ +static int ssl_write_certificate_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +/* Update the state after handling the outgoing certificate message. */ +static int ssl_write_certificate_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_write_certificate_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + /* Coordination: Check if we need to send a certificate. */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_certificate_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + if( ret == SSL_WRITE_CERTIFICATE_AVAILABLE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write certificate to message buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + return( ret ); +} + + +static int ssl_write_certificate_coordinate( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + int have_own_cert = 1; +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Switch to handshake traffic keys for outbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + { + int ret; + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#else + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } +#endif /* MBEDTLS_SSL_CLI_C */ + + /* For PSK and ECDHE-PSK ciphersuites there is no certificate to exchange. */ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* The client MUST send a Certificate message if and only + * if the server has requested client authentication via a + * CertificateRequest message. + * + * client_auth indicates whether the server had requested + * client authentication. + */ + if( ssl->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( have_own_cert == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_WRITE_CERTIFICATE_AVAILABLE ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +} + + + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +static int ssl_write_certificate_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + size_t i, n, total_len; + const mbedtls_x509_crt* crt; + unsigned char* start; + + /* TODO: Add bounds checks! Only then remove the next line. */ + ((void) buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* + * Handshake Header is 4 ( before adding DTLS-specific fields, which is done later ) + * Certificate Request Context: 1 byte + * Length of CertificateEntry: 3 bytes + * Length of cert. 1: 2 bytes + * cert_data: n bytes + * Extension: 2 bytes + * Extension value: m bytes + */ + i = 4; +#else /* MBEDTLS_SSL_USE_MPS */ + i = 0; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* empty certificate_request_context with length 0 */ + buf[i] = 0; + /* Skip length of certificate_request_context and + * the length of CertificateEntry + */ + i += 1; + +#if defined(MBEDTLS_SSL_CLI_C) + /* If the server requests client authentication but no suitable + * certificate is available, the client MUST send a + * Certificate message containing no certificates + * ( i.e., with the "certificate_list" field having length 0 ). + * + * authmode indicates whether the client configuration required authentication. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && ( ( mbedtls_ssl_own_cert( ssl ) == NULL ) || ssl->conf->authmode == MBEDTLS_SSL_VERIFY_NONE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write empty client certificate" ) ); + buf[i] = 0; + buf[i + 1] = 0; + buf[i + 2] = 0; + i += 3; + + goto empty_cert; + } +#endif /* MBEDTLS_SSL_CLI_C */ + + start = &buf[i]; + crt = mbedtls_ssl_own_cert( ssl ); + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) ); + + i += 3; + + while ( crt != NULL ) + { + n = crt->raw.len; + if( n > buflen - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + buf[i] = (unsigned char)( n >> 16 ); + buf[i + 1] = (unsigned char)( n >> 8 ); + buf[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( buf + i, crt->raw.p, n ); + i += n; crt = crt->next; + + /* Currently, we don't have any certificate extensions defined. + * Hence, we are sending an empty extension with length zero. + */ + buf[i] = 0; + buf[i + 1] = 0; + i += 2; + } + total_len = &buf[i] - start - 3; + *start++ = (unsigned char)( ( total_len ) >> 16 ); + *start++ = (unsigned char)( ( total_len ) >> 8 ); + *start++ = (unsigned char)( ( total_len ) ); + +#if defined(MBEDTLS_SSL_CLI_C) +empty_cert: +#endif /* MBEDTLS_SSL_CLI_C */ + + *olen = i; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + + +/* Update the state after handling the outgoing certificate message. */ +static int ssl_write_certificate_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); + return( 0 ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_VERIFY ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + + + +/* + * + * STATE HANDLING: Incoming Certificate + * + */ + +/* + * Overview + */ + +/* Main state-handling entry point; orchestrates the other functions. */ +int mbedtls_ssl_read_certificate_process( mbedtls_ssl_context* ssl ); + +/* Coordination: Check if a certificate is expected. + * Returns a negative error code on failure, and otherwise + * SSL_CERTIFICATE_EXPECTED or + * SSL_CERTIFICATE_SKIP + * indicating whether a Certificate message is expected or not. + */ +#define SSL_CERTIFICATE_EXPECTED 0 +#define SSL_CERTIFICATE_SKIP 1 +static int ssl_read_certificate_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +/* Parse certificate chain send by the peer. */ +static int ssl_read_certificate_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +/* Validate certificate chain sent by the peer. */ +static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ); + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +/* Update the state after handling the incoming certificate message. */ +static int ssl_read_certificate_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_read_certificate_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + /* Coordination: + * Check if we expect a certificate, and if yes, + * check if a non-empty certificate has been sent. */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_certificate_coordinate( ssl ) ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_EXPECTED ) + { + unsigned char *buf; + size_t buflen; + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE, buf, buflen ); + + /* Parse the certificate chain sent by the peer. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_parse( ssl, buf, buflen ) ); + /* Validate the certificate chain and set the verification results. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_validate( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_fetch( ssl, &buf, &buflen ) ); + + /* Parse the certificate chain sent by the peer. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_parse( ssl, buf, buflen ) ); + /* Validate the certificate chain and set the verification results. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_validate( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + /* Reading step */ + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + /* mbedtls_ssl_read_record may have sent an alert already. We + let it decide whether to alert. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_read_certificate_coordinate( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + int authmode = ssl->conf->authmode; +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to handshake keys for inbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + { + int ret; + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#else + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + return( SSL_CERTIFICATE_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + ( ( void )authmode ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* If SNI was used, overwrite authentication mode + * from the configuration. */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + /* NOTE: Is it intentional that we set verify_result + * to SKIP_VERIFY on server-side only? */ + ssl->session_negotiate->verify_result = + MBEDTLS_X509_BADCERT_SKIP_VERIFY; + return( SSL_CERTIFICATE_SKIP ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_CERTIFICATE_EXPECTED ); +#endif /* !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +/* Write certificate message based on the configured certificate */ +static int ssl_read_certificate_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ) +{ + int ret; + size_t i, n, certificate_request_context_len; + +#if defined(MBEDTLS_SSL_SRV_C) + int authmode = ssl->conf->authmode; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* read certificate request context length */ + certificate_request_context_len = (size_t) buf[0]; + + /* verify message length */ + if( buflen < 3 + certificate_request_context_len + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* check whether we got an empty certificate message */ + if( memcmp( buf + 1 + certificate_request_context_len , "\0\0\0", 3 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client has no certificate - empty certificate message received" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client certificate required" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED, + MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( buflen < 3 + 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + i = 0; + + /* length information of certificate_request_context */ + certificate_request_context_len = buf[i + 1]; + + /* skip certificate_request_context */ + i += certificate_request_context_len + 1; + + n = ( buf[i + 1] << 8 ) | buf[i + 2]; + + if( buf[i] != 0 || + buflen != ( n + 3 + certificate_request_context_len + 1 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* In case we tried to reuse a session but it failed */ + if( ssl->session_negotiate->peer_cert != NULL ) + { + mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); + mbedtls_free( ssl->session_negotiate->peer_cert ); + } + + if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + sizeof( mbedtls_x509_crt ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc( %d bytes ) failed", + sizeof( mbedtls_x509_crt ) ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_ALLOC_FAILED ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + + i += 3; + + while ( i < buflen ) + { + if( buf[i] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + n = ( ( unsigned int )buf[i + 1] << 8 ) + | ( unsigned int )buf[i + 2]; + i += 3; + + if( n < 128 || i + n > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, + buf + i, n ); + + switch( ret ) + { + case 0: /*ok*/ + case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND: + /* Ignore certificate with an unknown algorithm: maybe a + prior certificate was already trusted. */ + break; + + case MBEDTLS_ERR_X509_ALLOC_FAILED: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_X509_ALLOC_FAILED ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + + case MBEDTLS_ERR_X509_UNKNOWN_VERSION: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, + MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + + default: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_BAD_CERT, + ret ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + } + + i += n; + + /* length information of certificate extensions */ + n = ( buf[i] << 8 ) | buf[i + 1]; + + /* we ignore the certificate extension right now */ + i += 2 + n; + } + + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + int authmode = ssl->conf->authmode; + mbedtls_x509_crt* ca_chain; + mbedtls_x509_crl* ca_crl; + + /* If SNI was used, overwrite authentication mode + * from the configuration. */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif + + /* + * If the client hasn't sent a certificate ( i.e. it sent + * an empty certificate chain ), this is reflected in the peer CRT + * structure being unset. + * Check for that and handle it depending on the + * server's authentication mode. + */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client has no certificate" ) ); + + /* The client was asked for a certificate but didn't send + one. The client should know what's going on, so we + don't send an alert. */ + + /* Note that for authmode == VERIFY_NONE we don't end up in this + * routine in the first place, because ssl_read_certificate_coordinate + * will return CERTIFICATE_SKIP. */ + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + /* NOTE: This happens on client-side only, with the + * server-side case of VERIFY_NONE being handled earlier + * and leading to `ssl->verify_result` being set to + * MBEDTLS_X509_BADCERT_SKIP_VERIFY -- + * is this difference intentional? */ + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_with_profile( + ssl->session_negotiate->peer_cert, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context* pk = &ssl->session_negotiate->peer_cert->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate ( EC key curve )" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, + ssl->handshake->key_exchange, /* ciphersuite_info, */ + !ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate ( usage extensions )" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + /* mbedtls_x509_crt_verify_with_profile is supposed to report a + * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, + * with details encoded in the verification flags. All other kinds + * of error codes, including those from the user provided f_vrfy + * functions, are treated as fatal and lead to a failure of + * ssl_parse_certificate even if verification was optional. */ + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && + ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + { + ret = 0; + } + + if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } + + if( ret != 0 ) + { + /* The certificate may have been rejected for several reasons. + Pick one and send the corresponding alert. Which alert to send + may be a subject of debate in some cases. */ + if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_BAD_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA, ret ); + else + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN, ret ); + } + +#if defined(MBEDTLS_DEBUG_C) + if( ssl->session_negotiate->verify_result != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x", + ssl->session_negotiate->verify_result ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) ); + } +#endif /* MBEDTLS_DEBUG_C */ + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_read_certificate_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_VERIFY ); + } + return( 0 ); +} + +int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform, + int endpoint, + int ciphersuite, + mbedtls_ssl_key_set const *traffic_keys, + mbedtls_ssl_context *ssl /* DEBUG ONLY */ ) +{ + int ret; + mbedtls_cipher_info_t const *cipher_info; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + unsigned char const *key_enc; + unsigned char const *iv_enc; + unsigned char const *key_dec; + unsigned char const *iv_dec; + +#if !defined(MBEDTLS_DEBUG_C) + ssl = NULL; /* make sure we don't use it except for those cases */ + (void) ssl; +#endif + + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite ); + + cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Setup cipher contexts in target transform + */ + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( endpoint == MBEDTLS_SSL_IS_SERVER ) + { + key_enc = traffic_keys->server_write_key; + key_dec = traffic_keys->client_write_key; + iv_enc = traffic_keys->server_write_iv; + iv_dec = traffic_keys->client_write_iv; + } + else +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_CLI_C) + if( endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + key_enc = traffic_keys->client_write_key; + key_dec = traffic_keys->server_write_key; + iv_enc = traffic_keys->client_write_iv; + iv_dec = traffic_keys->server_write_iv; + } + else +#endif /* MBEDTLS_SSL_CLI_C */ + { + /* should not happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( transform->iv_enc, iv_enc, traffic_keys->iv_len ); + memcpy( transform->iv_dec, iv_dec, traffic_keys->iv_len ); + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, + key_enc, cipher_info->key_bitlen, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, + key_dec, cipher_info->key_bitlen, + MBEDTLS_DECRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + /* + * Setup other fields in SSL transform + */ + + if( ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ) != 0 ) + transform->taglen = 8; + else + transform->taglen = 16; + + transform->ivlen = traffic_keys->iv_len; + transform->maclen = 0; + transform->fixed_ivlen = transform->ivlen; + transform->minlen = transform->taglen + 1; + transform->minor_ver = MBEDTLS_SSL_MINOR_VERSION_4; + + return( 0 ); +} + +void mbedtls_ssl_handshake_wrapup_tls13( mbedtls_ssl_context *ssl ) +{ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + + + /* + * Free the previous session and switch in the current one + */ + if( ssl->session ) + { + + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +/* + * + * STATE HANDLING: Outgoing Finished + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions */ +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ); + +static int ssl_finished_out_prepare( mbedtls_ssl_context* ssl ); +static int ssl_finished_out_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_finished_out_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + + +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + if( !ssl->handshake->state_local.finished_out.preparation_done ) + { + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_prepare( ssl ) ); + ssl->handshake->state_local.finished_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + + msg.type = MBEDTLS_SSL_HS_FINISHED; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_FINISHED, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_postprocess( ssl ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_FINISHED; + + /* TODO: This doesn't work if mbedtls_ssl_write_handshake_msg() fails + * because the underlying transport isn't ready. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_postprocess( ssl ) ); + + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + return( ret ); +} + +static int ssl_finished_out_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + + /* Compute transcript of handshake up to now. */ + ret = mbedtls_ssl_tls1_3_calc_finished( ssl, + ssl->handshake->state_local.finished_out.digest, + sizeof( ssl->handshake->state_local.finished_out.digest ), + &ssl->handshake->state_local.finished_out.digest_len, + ssl->conf->endpoint ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "calc_finished failed", ret ); + return( ret ); + } + + return( 0 ); +} + +static int ssl_finished_out_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* Compute resumption_master_secret */ + ret = mbedtls_ssl_tls1_3_generate_resumption_master_secret( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_resumption_master_secret ", ret ); + return ( ret ); + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_FLUSH_BUFFERS ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_key_set traffic_keys; + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_application( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_application", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_generate_application_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_application_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_ssl_tls13_populate_transform( ssl->transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + { + mbedtls_ssl_transform *transform_application = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_application == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_application, + &ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( 0 ); +} + +static int ssl_finished_out_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + unsigned char *p; + size_t finished_len; + +#if defined(MBEDTLS_SSL_USE_MPS) + + p = buf; + finished_len = ssl->handshake->state_local.finished_out.digest_len; + +#else /* MBEDTLS_SSL_USE_MPS */ + + size_t const tls_hs_hdr_len = 4; + finished_len = tls_hs_hdr_len + + ssl->handshake->state_local.finished_out.digest_len; + p = buf + 4; + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Note: Even if DTLS is used, the current message writing functions + * write TLS headers, and it is only at sending time that the actual + * DTLS header is generated. That's why we unconditionally shift by + * 4 bytes here as opposed to mbedtls_ssl_hs_hdr_len( ssl ). */ + + if( buflen < finished_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + memcpy( p, + ssl->handshake->state_local.finished_out.digest, + ssl->handshake->state_local.finished_out.digest_len ); + p += ssl->handshake->state_local.finished_out.digest_len; + + *olen = (size_t)( p - buf ); + + return( 0 ); +} + +/* + * + * STATE HANDLING: Incoming Finished + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions */ +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_finished_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +/* + * Implementation + */ + +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + /* Preprocessing step: Compute handshake digest */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_preprocess( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_FINISHED, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_FINISHED, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_finished_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Postprocessing step: Update state machine */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_postprocess( ssl ) ); + +cleanup: + + /* In the MPS one would close the read-port here to + * ensure there's no overlap of reading and writing. */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_finished_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ) +{ + int ret; + + ret = mbedtls_ssl_tls1_3_calc_finished( ssl, + ssl->handshake->state_local.finished_in.digest, + sizeof( ssl->handshake->state_local.finished_in.digest ), + &ssl->handshake->state_local.finished_in.digest_len, + ssl->conf->endpoint ^ 1 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_calc_finished", ret ); + return( ret ); + } + + return( 0 ); +} + +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + /* Structural validation */ + if( buflen != ssl->handshake->state_local.finished_in.digest_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (self-computed):", + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (received message):", buf, + ssl->handshake->state_local.finished_in.digest_len ); + + /* Semantic validation */ + if( mbedtls_ssl_safer_memcmp( buf, + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + return( 0 ); +} + +#if defined(MBEDTLS_SSL_CLI_C) +static int ssl_finished_in_postprocess_cli( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_ssl_key_set traffic_keys; + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_application( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_application", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_generate_application_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_application_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_application = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_application == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_application, + &ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* Nothing to be done in this case. */ + return( 0 ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + return( ssl_finished_in_postprocess_cli( ssl ) ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +#if defined(MBEDTLS_ZERO_RTT) +void mbedtls_ssl_conf_early_data( mbedtls_ssl_config* conf, int early_data, + size_t max_early_data, + int(*early_data_callback)( mbedtls_ssl_context*, + const unsigned char*, + size_t ) ) +{ +#if !defined(MBEDTLS_SSL_SRV_C) + ( ( void ) early_data_callback ); +#endif /* !MBEDTLS_SSL_SRV_C */ + conf->early_data_enabled = early_data; + +#if defined(MBEDTLS_SSL_SRV_C) + + if( early_data == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + if( max_early_data > MBEDTLS_SSL_MAX_EARLY_DATA ) + max_early_data = MBEDTLS_SSL_MAX_EARLY_DATA; + + conf->max_early_data = max_early_data; + conf->early_data_callback = early_data_callback; + /* Only the server uses the early data callback. + * For the client this parameter is not used. */ + } + else + { + conf->early_data_callback = NULL; + } +#endif +} +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_signature_algorithms( mbedtls_ssl_config *conf, + const int* sig_algs ) +{ + conf->sig_hashes = sig_algs; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* Early Data Extension + * + * struct {} Empty; + * + * struct { + * select ( Handshake.msg_type ) { + * case new_session_ticket: uint32 max_early_data_size; + * case client_hello: Empty; + * case encrypted_extensions: Empty; + * }; + * } EarlyDataIndication; + */ +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_write_early_data_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + + *olen = 0; + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) || + mbedtls_ssl_get_psk_to_offer( ssl, NULL, NULL, NULL, NULL ) != 0 || + ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + return( 0 ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) == 0 ) + return( 0 ); + + if( ssl->conf->key_exchange_modes != + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE || + ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + return( 0 ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding early_data extension" ) ); + /* We're using rejected once we send the EarlyData extension, + and change it to accepted upon receipt of the server extension. */ + ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_REJECTED; + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding early_data extension" ) ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EARLY_DATA >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EARLY_DATA ) & 0xFF ); + + /* Write total extension length */ + *p++ = 0; + *p++ = 0; + + *olen = 4; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + + +#if defined(MBEDTLS_ECDH_C) +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; +#endif + +#define ECDH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) + +static int ecdh_make_tls_13_params_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t grp_len, pt_len; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + if( ( ret = mbedtls_ecp_tls_13_write_group( &ctx->grp, &grp_len, buf, + blen ) ) != 0 ) + return( ret ); + + buf += grp_len; + blen -= grp_len; + + if( ( ret = mbedtls_ecp_tls_13_write_point( &ctx->grp, &ctx->Q, point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +int mbedtls_ecdh_make_tls_13_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_tls_13_params_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_make_params( &ctx->ctx.everest_ecdh, olen, + buf, blen, f_rng, p_rng ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_tls_13_params_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + return( mbedtls_ecp_tls_13_read_point( &ctx->grp, &ctx->Qp, buf, + end - *buf ) ); +} + +int mbedtls_ecdh_read_tls_13_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_group_id grp_id; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( *buf != NULL ); + ECDH_VALIDATE_RET( end != NULL ); + + if( ( ret = mbedtls_ecp_tls_13_read_group_id( &grp_id, buf, end - *buf ) ) + != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_tls_13_params_internal( ctx, buf, end ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_read_params( &ctx->ctx.everest_ecdh, + buf, end) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, + buf, end ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_make_tls_13_public_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + return mbedtls_ecp_tls_13_write_point( &ctx->grp, &ctx->Q, point_format, olen, + buf, blen ); +} + +/* + * Setup and export the client public value + */ +int mbedtls_ecdh_make_tls_13_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_tls_13_public_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_make_public( &ctx->ctx.everest_ecdh, olen, + buf, blen, f_rng, p_rng ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_tls_13_public_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = buf; + + if( ( ret = mbedtls_ecp_tls_13_read_point( &ctx->grp, &ctx->Qp, &p, + blen ) ) != 0 ) + return( ret ); + + if( (size_t)( p - buf ) != blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Parse and import the client's TLS 1.3 public value + */ +int mbedtls_ecdh_read_tls_13_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_tls_13_public_internal( ctx, buf, blen ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_read_public( &ctx->ctx.everest_ecdh, + buf, blen ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, + buf, blen ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_ECP_C) +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) + +int mbedtls_ecp_tls_13_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( buf_len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = ( *( *buf ) << 8 ) | *( *buf+1 ); + *buf += 2; + + if( data_len < 1 || data_len > buf_len - 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return( mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ) ); +} + +int mbedtls_ecp_tls_13_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); + + if( blen < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 2, blen - 2) ) != 0 ) + return( ret ); + + // Length + *buf++ = (unsigned char)( ( *olen >> 8 ) & 0xFF ); + *buf++ = (unsigned char)( ( *olen ) & 0xFF ); + *olen += 2; + + return( 0 ); +} + +/* + * Read a group id from an ECParameters record (TLS 1.3) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_13_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + *grp = curve_info->grp_id; + + return( 0 ); +} + +/* + * Write the ECParameters record corresponding to a group (TLS 1.3) + */ +int mbedtls_ecp_tls_13_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = 2; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + // Two bytes for named curve + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c index 3de6f03fb8aa..782180f07f84 100644 --- a/library/ssl_tls13_keys.c +++ b/library/ssl_tls13_keys.c @@ -23,11 +23,20 @@ #include "mbedtls/hkdf.h" #include "mbedtls/ssl_internal.h" +#include "mbedtls/debug.h" #include "ssl_tls13_keys.h" #include #include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + #define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \ .name = string, @@ -293,7 +302,7 @@ int mbedtls_ssl_tls1_3_evolve_secret( int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; size_t hlen, ilen; unsigned char tmp_secret[ MBEDTLS_MD_MAX_SIZE ] = { 0 }; - unsigned char tmp_input [ MBEDTLS_MD_MAX_SIZE ] = { 0 }; + unsigned char tmp_input [ MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE ] = { 0 }; const mbedtls_md_info_t *md; md = mbedtls_md_info_from_type( hash_alg ); @@ -306,15 +315,14 @@ int mbedtls_ssl_tls1_3_evolve_secret( * on the old secret. */ if( secret_old != NULL ) { - ret = mbedtls_ssl_tls1_3_derive_secret( - hash_alg, - secret_old, hlen, - MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( derived ), - NULL, 0, /* context */ - MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, - tmp_secret, hlen ); - if( ret != 0 ) - goto cleanup; + MBEDTLS_SSL_PROC_CHK( + mbedtls_ssl_tls1_3_derive_secret( + hash_alg, + secret_old, hlen, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( derived ), + NULL, 0, /* context */ + MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + tmp_secret, hlen ) ); } if( input != NULL ) @@ -330,12 +338,10 @@ int mbedtls_ssl_tls1_3_evolve_secret( /* HKDF-Extract takes a salt and input key material. * The salt is the old secret, and the input key material * is the input secret (PSK / ECDHE). */ - ret = mbedtls_hkdf_extract( md, - tmp_secret, hlen, - tmp_input, ilen, - secret_new ); - if( ret != 0 ) - goto cleanup; + MBEDTLS_SSL_PROC_CHK( mbedtls_hkdf_extract( md, + tmp_secret, hlen, + tmp_input, ilen, + secret_new ) ); ret = 0; @@ -346,4 +352,890 @@ int mbedtls_ssl_tls1_3_evolve_secret( return( ret ); } +/* + * + * The following code hasn't been upstreamed yet. + * + */ + +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_tls1_3_derive_early_secrets( + mbedtls_md_type_t md_type, + unsigned char const *early_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_early_secrets *derived_early_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* + * 0 + * | + * v + * PSK -> HKDF-Extract = Early Secret + * | + * +-----> Derive-Secret(., "ext binder" | "res binder", "") + * | = binder_key + * | + * +-----> Derive-Secret(., "c e traffic", ClientHello) + * | = client_early_traffic_secret + * | + * +-----> Derive-Secret(., "e exp master", ClientHello) + * | = early_exporter_master_secret + * v + */ + + /* Create client_early_traffic_secret */ + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_e_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_early_secrets->client_early_traffic_secret, + md_size ); + if( ret != 0 ) + return( ret ); + + /* Create early exporter */ + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( e_exp_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_early_secrets->early_exporter_master_secret, + md_size ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +int mbedtls_ssl_tls1_3_derive_handshake_secrets( + mbedtls_md_type_t md_type, + unsigned char const *handshake_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_handshake_secrets *derived_handshake_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* + * + * Handshake Secret + * | + * +-----> Derive-Secret( ., "c hs traffic", + * | ClientHello...ServerHello ) + * | = client_handshake_traffic_secret + * | + * +-----> Derive-Secret( ., "s hs traffic", + * | ClientHello...ServerHello ) + * | = server_handshake_traffic_secret + * + */ + + /* + * Compute client_handshake_traffic_secret with + * Derive-Secret( ., "c hs traffic", ClientHello...ServerHello ) + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + handshake_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_hs_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_handshake_secrets->client_handshake_traffic_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + /* + * Compute server_handshake_traffic_secret with + * Derive-Secret( ., "s hs traffic", ClientHello...ServerHello ) + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + handshake_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_hs_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_handshake_secrets->server_handshake_traffic_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_derive_application_secrets( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* Generate {client,server}_application_traffic_secret_0 + * + * Master Secret + * | + * +-----> Derive-Secret( ., "c ap traffic", + * | ClientHello...server Finished ) + * | = client_application_traffic_secret_0 + * | + * +-----> Derive-Secret( ., "s ap traffic", + * | ClientHello...Server Finished ) + * | = server_application_traffic_secret_0 + * | + * +-----> Derive-Secret( ., "exp master", + * | ClientHello...server Finished) + * | = exporter_master_secret + * + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_ap_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->client_application_traffic_secret_N, + md_size ); + + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_ap_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->server_application_traffic_secret_N, + md_size ); + + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( exp_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->exporter_master_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_ZERO_RTT) +/* Early Data Key Derivation for TLS 1.3 */ +int mbedtls_ssl_tls1_3_generate_early_data_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "=> mbedtls_ssl_tls1_3_generate_early_data_keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_derive_early_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.early, + transcript, transcript_len, + &ssl->handshake->early_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_early_secrets", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_early_traffic_secret", + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size ); + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_EARLY_TRAFFIC_SECRET, + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + ssl->handshake->early_secrets.client_early_traffic_secret, + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size, keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_generate_early_data_keys" ) ); + return( ret ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +/* mbedtls_ssl_tls1_3_generate_handshake_keys() generates keys necessary for + * protecting the handshake messages, as described in Section 7 of TLS 1.3. */ +int mbedtls_ssl_tls1_3_generate_handshake_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls1_3_generate_handshake_keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_derive_handshake_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.handshake, + transcript, transcript_len, + &ssl->handshake->hs_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_early_secrets", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Client handshake traffic secret", + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + md_size ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Server handshake traffic secret", + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size ); + + /* + * Export client handshake traffic secret + */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + md_size ); + + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET, + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size, + keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + goto exit; + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_handshake write_key", + traffic_keys->client_write_key, + traffic_keys->key_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "server_handshake write_key", + traffic_keys->server_write_key, + traffic_keys->key_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_handshake write_iv", + traffic_keys->client_write_iv, + traffic_keys->iv_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "server_handshake write_iv", + traffic_keys->server_write_iv, + traffic_keys->iv_len); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_generate_handshake_keys" ) ); + +exit: + + return( ret ); +} + +/* Generate application traffic keys since any records following a 1-RTT Finished message + * MUST be encrypted under the application traffic key. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + /* Address at which to store the application secrets */ + mbedtls_ssl_tls1_3_application_secrets * const app_secrets = + &ssl->session_negotiate->app_secrets; + + /* Holding the transcript up to and including the ServerFinished */ + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + /* Variables relating to the hash for the chosen ciphersuite. */ + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + /* Variables relating to the cipher for the chosen ciphersuite. */ + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive application traffic keys" ) ); + + /* Extract basic information about hash and ciphersuite */ + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + /* Compute current handshake transcript. It's the caller's responsiblity + * to call this at the right time, that is, after the ServerFinished. */ + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + /* Compute application secrets from master secret and transcript hash. */ + + ret = mbedtls_ssl_tls1_3_derive_application_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.app, + transcript, transcript_len, + app_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_derive_application_secrets", ret ); + return( ret ); + } + + /* Derive first epoch of IV + Key for application traffic. */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + app_secrets->client_application_traffic_secret_N, + app_secrets->server_application_traffic_secret_N, + md_size, keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Client application traffic secret", + app_secrets->client_application_traffic_secret_N, + md_size ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Server application traffic secret", + app_secrets->server_application_traffic_secret_N, + md_size ); + + /* + * Export client/server application traffic secret 0 + */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET_0, + app_secrets->client_application_traffic_secret_N, md_size ); + + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET_0, + app_secrets->server_application_traffic_secret_N, md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + MBEDTLS_SSL_DEBUG_BUF( 4, "client application_write_key:", + traffic_keys->client_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write key", + traffic_keys->server_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "client application write IV", + traffic_keys->client_write_iv, ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write IV", + traffic_keys->server_write_iv, ivlen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive application traffic keys" ) ); + return( 0 ); +} + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +/* Generate resumption_master_secret for use with the ticket exchange. + * + * This is not integrated with mbedtls_ssl_tls1_3_derive_application_secrets() + * because it uses the transcript hash up to and including ClientFinished. */ +int mbedtls_ssl_tls1_3_derive_resumption_master_secret( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( res_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->resumption_master_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "=> mbedtls_ssl_tls1_3_generate_resumption_master_secret" ) ); + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_resumption_master_secret( md_type, + ssl->handshake->tls1_3_master_secrets.app, + transcript, transcript_len, + &ssl->session_negotiate->app_secrets ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Resumption master secret", + ssl->session_negotiate->app_secrets.resumption_master_secret, + md_size ); + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "<= mbedtls_ssl_tls1_3_generate_resumption_master_secret" ) ); + return( 0 ); +} +#else /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context *ssl ) +{ + ((void) ssl); + return( 0 ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +static int ssl_tls1_3_complete_ephemeral_secret( mbedtls_ssl_context *ssl, + unsigned char *secret, + size_t secret_len, + unsigned char **actual_secret, + size_t *actual_len ) +{ + int ret = 0; + + /* + * Compute ECDHE secret for second stage of secret evolution. + */ +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED) + if( ssl->handshake->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + + ret = mbedtls_ecdh_calc_secret( + &ssl->handshake->ecdh_ctx, + actual_len, secret, secret_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + *actual_secret = secret; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED */ + { + *actual_secret = NULL; + *actual_len = 0; + } + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_key_schedule_stage_handshake( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); +#endif /* MBEDTLS_DEBUG_C */ + + unsigned char *ephemeral; + size_t ephemeral_len; + + unsigned char ecdhe[66]; /* TODO: Magic constant! */ + + /* Finalize calculation of ephemeral input to key schedule, if present. */ + ret = ssl_tls1_3_complete_ephemeral_secret( ssl, + ecdhe, sizeof( ecdhe ), + &ephemeral, + &ephemeral_len ); + if( ret != 0 ) + return( ret ); + + /* + * Compute HandshakeSecret + */ + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + ssl->handshake->tls1_3_master_secrets.early, + ephemeral, ephemeral_len, + ssl->handshake->tls1_3_master_secrets.handshake ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake secret", + ssl->handshake->tls1_3_master_secrets.handshake, md_size ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED) + mbedtls_platform_zeroize( ecdhe, sizeof( ecdhe ) ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED */ + return( 0 ); +} + +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); +#endif /* MBEDTLS_DEBUG_C */ + + /* + * Compute MasterSecret + */ + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + ssl->handshake->tls1_3_master_secrets.handshake, + NULL, 0, + ssl->handshake->tls1_3_master_secrets.app ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Master secret", + ssl->handshake->tls1_3_master_secrets.app, md_size ); + + return( 0 ); +} + +static int ssl_tls1_3_calc_finished_core( mbedtls_md_type_t md_type, + unsigned char const *base_key, + unsigned char const *transcript, + unsigned char *dst ) +{ + const mbedtls_md_info_t* const md = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md ); + unsigned char finished_key[MBEDTLS_MD_MAX_SIZE]; + int ret; + + /* TLS 1.3 Finished message + * + * struct { + * opaque verify_data[Hash.length]; + * } Finished; + * + * verify_data = + * HMAC( finished_key, + * Hash( Handshake Context + + * Certificate* + + * CertificateVerify* ) + * ) + * + * finished_key = + * HKDF-Expand-Label( BaseKey, "finished", "", Hash.length ) + */ + + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( + md_type, base_key, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( finished ), + NULL, 0, + finished_key, md_size ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_md_hmac( md, finished_key, md_size, transcript, md_size, dst ); + if( ret != 0 ) + goto exit; + +exit: + + mbedtls_platform_zeroize( finished_key, sizeof( finished_key ) ); + return( ret ); +} + +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context* ssl, + unsigned char* dst, + size_t dst_len, + size_t *actual_len, + int from ) +{ + int ret; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + unsigned char const *base_key = NULL; + + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; + const mbedtls_md_info_t* const md = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls1_3_calc_finished" ) ); + + if( dst_len < md_size ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_BUF( 4, "handshake hash", transcript, transcript_len ); + + if( from == MBEDTLS_SSL_IS_CLIENT ) + base_key = ssl->handshake->hs_secrets.client_handshake_traffic_secret; + else + base_key = ssl->handshake->hs_secrets.server_handshake_traffic_secret; + + ret = ssl_tls1_3_calc_finished_core( md_type, base_key, transcript, dst ); + if( ret != 0 ) + return( ret ); + *actual_len = md_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "verify_data for finished message", dst, md_size ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_calc_finished" ) ); + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* mbedtls_ssl_tls1_3_create_psk_binder(): + * + * 0 + * | + * v + * PSK -> HKDF-Extract = Early Secret + * | + * +------> Derive-Secret( ., + * | "ext binder" | + * | "res binder", + * | "" ) + * | = binder_key + * ... + */ + +int mbedtls_ssl_tls1_3_create_psk_binder( mbedtls_ssl_context *ssl, + unsigned char const *psk, size_t psk_len, + const mbedtls_md_type_t md_type, + int is_external, + unsigned char const *transcript, + unsigned char *result ) +{ + int ret = 0; + unsigned char binder_key[MBEDTLS_MD_MAX_SIZE]; + unsigned char early_secret[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_info_t const *md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + NULL, /* Old secret */ + psk, psk_len, /* Input */ + early_secret ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + goto exit; + } + + /* + * Compute binder_key with + * + * Derive-Secret( early_secret, "ext binder" | "res binder", "" ) + */ + + if( !is_external ) + { + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( res_binder ), + NULL, 0, MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + binder_key, md_size ); + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Derive Early Secret with 'res binder'" ) ); + } + else + { + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( ext_binder ), + NULL, 0, MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + binder_key, md_size ); + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Derive Early Secret with 'ext binder'" ) ); + } + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_secret", ret ); + goto exit; + } + + /* + * The binding_value is computed in the same way as the Finished message + * but with the BaseKey being the binder_key. + */ + + ret = ssl_tls1_3_calc_finished_core( md_type, binder_key, transcript, result ); + if( ret != 0 ) + goto exit; + + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder", result, md_size ); + +exit: + + mbedtls_platform_zeroize( early_secret, sizeof( early_secret ) ); + mbedtls_platform_zeroize( binder_key, sizeof( binder_key ) ); + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +int mbedtls_ssl_tls1_3_key_schedule_stage_early_data( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher suite info not found" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + NULL, /* Old secret */ + ssl->handshake->psk, + ssl->handshake->psk_len, + ssl->handshake->tls1_3_master_secrets.early ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + return( 0 ); +} + #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h index 7089049ce2c6..254ca3d312ac 100644 --- a/library/ssl_tls13_keys.h +++ b/library/ssl_tls13_keys.h @@ -19,28 +19,44 @@ #if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H) #define MBEDTLS_SSL_TLS1_3_KEYS_H +#include "mbedtls/ssl_internal.h" + +/* The maximum size of the intermediate key material. + * The IKM can be a + * - 0-string of length corresponding to the size of the + * underlying hash function, and hence can be bounded + * in size by MBEDTLS_MD_MAX_SIZE. + * - the PSK, which is bounded in size by MBEDTLS_PREMASTER_SIZE + * - the (EC)DHE, which is bounded in size by MBEDTLS_PREMASTER_SIZE + */ +#define MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE \ + ( MBEDTLS_PREMASTER_SIZE > MBEDTLS_MD_MAX_SIZE ? \ + MBEDTLS_PREMASTER_SIZE : MBEDTLS_MD_MAX_SIZE ) + /* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at * the point of use. See e.g. the definition of mbedtls_ssl_tls1_3_labels_union * below. */ -#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \ - MBEDTLS_SSL_TLS1_3_LABEL( finished , "finished" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( resumption , "resumption" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( exporter , "exporter" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( key , "key" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( iv , "iv" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( res_master , "res master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( exp_master , "exp master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( ext_binder , "ext binder" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( res_binder , "res binder" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( derived , "derived" ) +#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \ + MBEDTLS_SSL_TLS1_3_LABEL( finished , "finished" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( resumption , "resumption" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( exporter , "exporter" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( key , "key" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( iv , "iv" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( res_master , "res master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( exp_master , "exp master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( ext_binder , "ext binder" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( res_binder , "res binder" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( derived , "derived" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( client_cv , "TLS 1.3, client CertificateVerify" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( server_cv , "TLS 1.3, server CertificateVerify" ) #define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \ const unsigned char name [ sizeof(string) - 1 ]; @@ -57,9 +73,12 @@ struct mbedtls_ssl_tls1_3_labels_struct extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels; +#define MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL ) \ + sizeof(mbedtls_ssl_tls1_3_labels.LABEL) + #define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( LABEL ) \ mbedtls_ssl_tls1_3_labels.LABEL, \ - sizeof(mbedtls_ssl_tls1_3_labels.LABEL) + MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL ) #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN \ sizeof( union mbedtls_ssl_tls1_3_labels_union ) @@ -79,6 +98,30 @@ extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels; * is never used with more than 255 Bytes of output. */ #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN 255 +/* Macro to express the length of the verify structure length. + * + * The structure is computed per TLS 1.3 specification as: + * - 64 bytes of octet 32, + * - 33 bytes for the context string + * (which is either "TLS 1.3, client CertificateVerify" + * or "TLS 1.3, server CertificateVerify"), + * - 1 byte for the octet 0x0, which servers as a separator, + * - 32 or 48 bytes for the Transcript-Hash(Handshake Context, Certificate) + * (depending on the size of the transcript_hash) + * + * This results in a total size of + * - 130 bytes for a SHA256-based transcript hash, or + * (64 + 33 + 1 + 32 bytes) + * - 146 bytes for a SHA384-based transcript hash. + * (64 + 33 + 1 + 48 bytes) + * + */ +#define MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ( 64 + \ + 33 + \ + 1 + \ + MBEDTLS_MD_MAX_SIZE \ + ) + /** * \brief The \c HKDF-Expand-Label function from * the TLS 1.3 standard RFC 8446. @@ -198,6 +241,121 @@ int mbedtls_ssl_tls1_3_derive_secret( int ctx_hashed, unsigned char *dstbuf, size_t buflen ); +/** + * \brief Derive TLS 1.3 early data key material from early secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm associated with the PSK for which + * early data key material is being derived. + * \param early_secret The early secret from which the early data key material + * should be derived. This must be a readable buffer whose + * length is the digest size of the hash algorithm + * represented by \p md_size. + * \param transcript The transcript of the handshake so far, calculated with + * respect to \p md_type. This must be a readable buffer + * whose length is the digest size of the hash algorithm + * represented by \p md_size. + * \param derived_early_secrets The address of the structure in which to store + * the early data key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_early_secrets( + mbedtls_md_type_t md_type, + unsigned char const *early_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_early_secrets *derived_early_secrets ); + +/** + * \brief Derive TLS 1.3 handshake key material from handshake secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm used in the handshake for which + * key material is being derived. + * \param handshake_secret The handshake secret from which the handshake key + * material should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the handshake so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param derived_handshake_secrets The address of the structure in which to + * store the handshake key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_handshake_secrets( + mbedtls_md_type_t md_type, + unsigned char const *handshake_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_handshake_secrets *derived_handshake_secrets ); + +/** + * \brief Derive TLS 1.3 application key material from master secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm used in the application for which + * key material is being derived. + * \param master_secret The master secret from which the application key + * material should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the application so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param derived_application_secrets The address of the structure in which to + * store the application key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_application_secrets( + mbedtls_md_type_t md_type, + unsigned char const *master_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +/** + * \brief Derive TLS 1.3 resumption master secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate label. + * + * \param md_type The hash algorithm used in the application for which + * key material is being derived. + * \param application_secret The application secret from which the resumption master + * secret should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the application so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript_len The length of \p transcript in Bytes. + * \param derived_application_secrets The address of the structure in which to + * store the resumption master secret. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_resumption_master_secret( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + /** * \brief Compute the next secret in the TLS 1.3 key schedule * @@ -254,7 +412,8 @@ int mbedtls_ssl_tls1_3_derive_secret( * ephemeral (EC)DH secret). If not \c NULL, this must be * a readable buffer whose size \p input_len Bytes. * If \c NULL, an all \c 0 array will be used instead. - * \param input_len The length of \p input in Bytes. + * \param input_len The length of \p input in Bytes. This must not be + * larger than MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE. * \param secret_new The address of the buffer holding the new secret * on function exit. This must be a writable buffer * whose size matches the output size of the hash @@ -271,4 +430,200 @@ int mbedtls_ssl_tls1_3_evolve_secret( const unsigned char *input, size_t input_len, unsigned char *secret_new ); +/* + * TLS 1.3 key schedule evolutions + * + * Early Data -> Handshake -> Application + * + * Small wrappers around mbedtls_ssl_tls1_3_evolve_secret(). + */ + +/** + * \brief Begin TLS 1.3 key schedule by calculating early secret + * from chosen PSK. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Initial -> Early transition. + * + * In the early stage, mbedtls_ssl_tls1_3_generate_early_data_keys() + * can be used to derive the 0-RTT traffic keys. + * + * \param ssl The SSL context to operate on. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_early_data( + mbedtls_ssl_context *ssl ); + +/** + * \brief Transition into handshake stage of TLS 1.3 key schedule. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Early -> Handshake transition. + * + * In the handshake stage, mbedtls_ssl_tls1_3_generate_handshake_keys() + * can be used to derive the handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in key schedule + * stage \c Early. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_handshake( + mbedtls_ssl_context *ssl ); + +/** + * \brief Transition into application stage of TLS 1.3 key schedule. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Handshake -> Application transition. + * + * In the handshake stage, mbedtls_ssl_tls1_3_generate_application_keys() + * can be used to derive the handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in key schedule + * stage \c Handshake. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ); + +/* + * Convenience functions combining + * + * mbedtls_ssl_tls1_3_key_schedule_stage_xxx() + * + * with + * + * mbedtls_ssl_tls1_3_make_traffic_keys() + * + * Those functions assume that the key schedule has been moved + * to the correct stage via + * + * mbedtls_ssl_tls1_3_key_schedule_stage_xxx(). + */ + +/** + * \brief Compute traffic keys for 0-RTT. + * + * \param ssl The SSL context to operate on. This must be in key schedule stage + * \c Early, see mbedtls_ssl_tls1_3_key_schedule_stage_early_data(). + * \param traffic_keys The address at which to store the 0-RTT traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_early_data_keys( + mbedtls_ssl_context *ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Handshake, see + * mbedtls_ssl_tls1_3_key_schedule_stage_handshake(). + * \param traffic_keys The address at which to store the handshake traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_handshake_keys( + mbedtls_ssl_context* ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 application traffic keys. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Application, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param traffic_keys The address at which to store the application traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context* ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 resumption master secret. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Application, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context* ssl ); + +/** + * \brief Calculate content of TLS 1.3 Finished message. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Handshake, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param dst The address at which to write the Finished content. + * \param dst_len The size of \p dst in bytes. + * \param actual_len The address at which to store the amount of data + * actually written to \p dst upon success. + * \param from The endpoint the Finished message originates from: + * - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message + * - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message + * + * \note Both client and server call this function twice, once to + * generate their own Finished message, and once to verify the + * peer's Finished message. + + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context* ssl, + unsigned char* dst, + size_t dst_len, + size_t *actual_len, + int from ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/** + * \brief Calculate a TLS 1.3 PSK binder + * + * \param ssl The SSL context. This is used for debugging only and may + * be \c NULL if MBEDTLS_DEBUG_C is disabled. + * \param psk The buffer holding the PSK for which to create a binder. + * \param psk_len The size of \p psk in bytes. + * \param md_type The hash algorithm associated to the PSK \p psk. + * \param is_external This indicates whether the PSK \p psk is externally + * provisioned or a resumption PSK: + * - \c 1: Externally provisioned PSK + * - \c 0: Resumption PSK + * \param transcript The handshake transcript up to the point where the + * PSK binder calculation happens. This must be readable, + * and its size must be equal to the digest size of + * the hash algorithm represented by \p md_type. + * \param result The address at which to store the PSK binder on success. + * This must be writable, and its size must be equal to the + * digest size of the hash algorithm represented by \p md_type. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_create_psk_binder( mbedtls_ssl_context *ssl, + unsigned char const *psk, size_t psk_len, + const mbedtls_md_type_t md_type, + int is_external, + unsigned char const *transcript, + unsigned char *result ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + #endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */ diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c new file mode 100644 index 000000000000..69edc49df4ae --- /dev/null +++ b/library/ssl_tls13_server.c @@ -0,0 +1,4551 @@ +/* +* TLSv1.3 server-side functions +* +* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 ( the "License" ); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This file is part of mbed TLS ( https://tls.mbed.org ) +*/ + + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#if defined(MBEDTLS_SSL_SRV_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif /* MBEDTLS_ECP_C */ + +#include "mbedtls/hkdf.h" + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +#include "mbedtls/ssl_ticket.h" +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif /* MBEDTLS_HAVE_TIME */ + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_write_sni_server_ext( + mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + *olen = 0; + + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SERVERNAME ) == 0 ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding server_name extension" ) ); + + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + /* Write total extension length */ + *p++ = 0; + *p++ = 0; + + *olen = 4; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +/* + + Key Shares Extension + + enum { + obsolete_RESERVED( 1..22 ), + secp256r1( 23 ), secp384r1( 24 ), secp521r1( 25 ), + obsolete_RESERVED( 26..28 ), + x25519( 29 ), x448( 30 ), + + ffdhe2048( 256 ), ffdhe3072( 257 ), ffdhe4096( 258 ), + ffdhe6144( 259 ), ffdhe8192( 260 ), + + ffdhe_private_use( 0x01FC..0x01FF ), + ecdhe_private_use( 0xFE00..0xFEFF ), + obsolete_RESERVED( 0xFF01..0xFF02 ), + ( 0xFFFF ) + } NamedGroup; + + struct { + NamedGroup group; + opaque key_exchange<1..2^16-1>; + } KeyShareEntry; + + struct { + select ( role ) { + case client: + KeyShareEntry client_shares<0..2^16-1>; + case server: + KeyShareEntry server_share; + } + } KeyShare; +*/ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) +static int ssl_write_key_shares_ext( + mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf + 4; + unsigned char *header = buf; /* Pointer where the header has to go. */ + size_t len; + int ret; + + const mbedtls_ecp_curve_info *info = NULL; + /* const mbedtls_ecp_group_id *grp_id; */ + + *olen = 0; + + /* TBD: Can we say something about the smallest number of bytes needed for the ecdhe parameters */ + if( end < p || ( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + if( ssl->conf->curve_list == NULL ) + { + /* This should never happen since we previously checked the + * server-supported curves against the client-provided curves. + * We should have returned a HelloRetryRequest instead. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server key share extension: empty curve list" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding key share extension" ) ); + + /* Fetching the agreed curve. */ + info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + + if( info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server key share extension: fetching agreed curve failed" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", info->name ) ); + + if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, info->grp_id ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_make_tls_13_params( &ssl->handshake->ecdh_ctx, &len, + p, end-buf, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_tls_13_params", ret ); + return( ret ); + } + + p += len; + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDHE: Q ", &ssl->handshake->ecdh_ctx.Q ); + + /* Write extension header */ + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES ) & 0xFF ); + + /* Write total extension length */ + *header++ = (unsigned char)( ( ( len ) >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( ( len ) ) & 0xFF ); + + *olen = len + 4; /* 4 bytes for fixed header + length of key share */ + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C && MBEDTLS_ECDSA_C */ + + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +static int check_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif /* MBEDTLS_ECP_C */ + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || ( MBEDTLS_ECDSA_C */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + + +/* + mbedtls_ssl_parse_supported_groups_ext( ) processes the received + supported groups extension and copies the client provided + groups into ssl->handshake->curves. + + Possible response values are: + - MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS + - MBEDTLS_ERR_SSL_ALLOC_FAILED +*/ +int mbedtls_ssl_parse_supported_groups_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) { + + size_t list_size, our_size; + const unsigned char *p; + const mbedtls_ecp_curve_info *curve_info, **curves; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Received supported groups", buf, len ); + + list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( list_size + 2 != len || + list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad supported groups extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + + /* Should never happen unless client duplicates the extension */ + /* if( ssl->handshake->curves != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad supported groups extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + */ + /* Don't allow our peer to make us allocate too much memory, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > MBEDTLS_ECP_DP_MAX ) + our_size = MBEDTLS_ECP_DP_MAX; + + if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_calloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + ssl->handshake->curves = curves; + + p = buf + 2; + while ( list_size > 0 && our_size > 1 ) + { + curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); + + /* + mbedtls_ecp_curve_info_from_tls_id( ) uses the mbedtls_ecp_curve_info + data structure ( defined in ecp.c ), which only includes the list of + curves implemented. Hence, we only add curves that are also supported + and implemented by the server. + */ + + if( curve_info != NULL ) + { + *curves++ = curve_info; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "supported curve: %s", curve_info->name ) ); + + our_size--; + } + + list_size -= 2; + p += 2; + } + + return( 0 ); + +} +#endif /* MBEDTLS_ECDH_C || ( MBEDTLS_ECDSA_C */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +/* + * ssl_parse_key_shares_ext() verifies whether the information in the extension + * is correct and stores the provided key shares. Whether this is an acceptable + * key share depends on the selected ciphersuite. + * + * Possible return values are: + * - 0: Successful processing of the client provided key share extension. + * - MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE: The key share provided by the client + * does not match a group supported by the server. A HelloRetryRequest will + * be needed. + * - Another negative return value for fatal errors. +*/ + +static int ssl_parse_key_shares_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0, final_ret = 0, extensions_available = 1; + unsigned char *end = (unsigned char*)buf + len; + unsigned char *start = (unsigned char*)buf; + unsigned char *old; + + size_t n; + unsigned int ks_entry_size; + + int match_found = 0; + + const mbedtls_ecp_group_id *gid; + + /* Pick the first KeyShareEntry */ + n = ( buf[0] << 8 ) | buf[1]; + + if( n + 2 > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad key share extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + start += 2; + + /* We try to find a suitable key share entry and copy it to the + * handshake context. Later, we have to find out whether we can do + * something with the provided key share or whether we have to + * dismiss it and send a HelloRetryRequest message. */ + + /* + * Ephemeral ECDH parameters: + * + * struct { + * NamedGroup group; + * opaque key_exchange<1..2^16-1>; + * } KeyShareEntry; + */ + + /* Jump over extension length field to the first KeyShareEntry by advancing buf+2 */ + old = start; + while( extensions_available ) + { + ret = mbedtls_ecdh_read_tls_13_params( + &ssl->handshake->ecdh_ctx, + (const unsigned char **) &start, end ); + + if( ret != 0 ) + { + /* For some reason we didn't recognize the key share. We jump + * to the next one + */ + + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_tls_13_params failed " ), ret ); + final_ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_SHARE; + goto skip_parsing_key_share_entry; + } + + /* Does the provided key share match any of our supported groups */ + for ( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + { + /* Currently we only support a single key share */ + /* Hence, we do not need a loop */ + if( ssl->handshake->ecdh_ctx.grp.id == *gid ) + { + match_found = 1; + + ret = check_ecdh_params( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "check_ecdh_params: %d" ), ret ); + final_ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO; + goto skip_parsing_key_share_entry; + } + + break; + } + } + + if( match_found == 0 ) + { + /* A HelloRetryRequest is needed */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } + else + { + final_ret = 0; + goto finish_key_share_parsing; + } + skip_parsing_key_share_entry: + + /* we jump to the next key share entry, if there is one */ + ks_entry_size = ( ( old[2] << 8 ) | ( old[3] ) ); + /* skip named group id + length field + key share entry length */ + start = old + ( ks_entry_size + 4 ); + old = start; + if( start >= end ) + { + /* we reached the end */ + final_ret = MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE; + extensions_available = 0; + } + } + +finish_key_share_parsing: + + if( final_ret == 0 ) + { + /* we found a key share we like */ + return ( 0 ); + } + else { + ( (void ) buf ); + return ( final_ret ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +int mbedtls_ssl_parse_new_session_ticket_server( + mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + unsigned char *ticket_buffer; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + + if( ssl->conf->f_ticket_parse == NULL || + ssl->conf->f_ticket_write == NULL ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) ); + + if( len == 0 ) return( 0 ); + + /* We create a copy of the encrypted ticket since decrypting + * it into the same buffer will wipe-out the original content. + * We do, however, need the original buffer for computing the + * psk binder value. + */ + ticket_buffer = mbedtls_calloc( len,1 ); + + if( ticket_buffer == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket_buffer, buf, len ); + + if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket, ssl->session_negotiate, + ticket_buffer, len ) ) != 0 ) + { + mbedtls_free( ticket_buffer ); + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) ); + else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) ); + else + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_parse", ret ); + + return( ret ); + } + + /* We delete the temporary buffer */ + mbedtls_free( ticket_buffer ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_parse_client_psk_identity_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + unsigned int item_array_length, item_length, sum, length_so_far; + unsigned char server_computed_binder[MBEDTLS_MD_MAX_SIZE]; + const unsigned char *psk = NULL; + unsigned char const * const start = buf; + size_t psk_len = 0; + unsigned char const *end_of_psk_identities; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + uint32_t obfuscated_ticket_age; +#if defined(MBEDTLS_HAVE_TIME) + time_t now; + int64_t diff; +#endif /* MBEDTLS_HAVE_TIME */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* Read length of array of identities */ + item_array_length = ( buf[0] << 8 ) | buf[1]; + length_so_far = item_array_length + 2; + if( length_so_far > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + end_of_psk_identities = buf + length_so_far; + buf += 2; + sum = 2; + while( sum < item_array_length + 2 ) + { + /* Read to psk identity length */ + item_length = ( buf[0] << 8 ) | buf[1]; + sum = sum + 2 + item_length; + + if( sum > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk_identity length mismatch" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Extract pre-shared key identity provided by the client + */ + /* jump to identity value itself */ + buf += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "received psk identity", buf, item_length ); + + if( ssl->conf->f_psk != NULL ) + { + if( ssl->conf->f_psk( ssl->conf->p_psk, ssl, buf, item_length ) != 0 ) + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* Identity is not a big secret since clients send it in the clear, + * but treat it carefully anyway, just in case */ + if( item_length != ssl->conf->psk_identity_len || + mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, buf, item_length ) != 0 ) + { + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* skip obfuscated ticket age */ + /* TBD: Process obfuscated ticket age ( zero for externally configured PSKs?! ) */ + buf = buf + item_length + 4; /* 4 for obfuscated ticket age */; + + mbedtls_ssl_set_hs_psk( ssl, ssl->conf->psk, ssl->conf->psk_len ); + goto psk_parsing_successful; + + } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Check the ticket cache if previous lookup was unsuccessful */ + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + /* copy ticket since it acts as the psk_identity */ + if( ssl->session_negotiate->ticket != NULL ) + { + mbedtls_free( ssl->session_negotiate->ticket ); + } + ssl->session_negotiate->ticket = mbedtls_calloc( 1, item_length ); + if( ssl->session_negotiate->ticket == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", item_length ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + memcpy( ssl->session_negotiate->ticket, buf, item_length ); + ssl->session_negotiate->ticket_len = item_length; + + ret = mbedtls_ssl_parse_new_session_ticket_server( ssl, + ssl->session_negotiate->ticket, + item_length ); + if( ret == 0 ) + { + /* found a match in the ticket cache; everything is OK */ + ssl->handshake->resume = 1; + + /* We put the resumption key into the handshake->psk. + * + * Note: The key in the ticket is already the final PSK, + * i.e., the HKDF-Expand-Label( resumption_master_secret, + * "resumption", + * ticket_nonce, + * Hash.length ) + * function has already been applied. + */ + mbedtls_ssl_set_hs_psk( ssl, ssl->session_negotiate->key, + ssl->session_negotiate->key_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Ticket-resumed PSK:", ssl->session_negotiate->key, + ssl->session_negotiate->key_len ); + + /* obfuscated ticket age follows the identity field, which is + * item_length long, containing the ticket */ + memcpy( &obfuscated_ticket_age, buf+item_length, 4 ); + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "ticket: obfuscated_ticket_age: %u", + obfuscated_ticket_age ) ); + /* + * A server MUST validate that the ticket age for the selected PSK identity + * is within a small tolerance of the time since the ticket was issued. + */ + +#if defined(MBEDTLS_HAVE_TIME) + now = time( NULL ); + + /* Check #1: + * Is the time when the ticket was issued later than now? + */ + + if( now < ssl->session_negotiate->start ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket expired: now=%d, ticket.start=%d", + now, ssl->session_negotiate->start ) ); + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + + /* Check #2: + * Is the ticket expired already? + */ + + if( now - ssl->session_negotiate->start > ssl->session_negotiate->ticket_lifetime ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket expired ( now - ticket.start=%d, "\ + "ticket.ticket_lifetime=%d", + now - ssl->session_negotiate->start, + ssl->session_negotiate->ticket_lifetime ) ); + + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + + /* Check #3: + * Is the ticket age for the selected PSK identity + * (computed by subtracting ticket_age_add from + * PskIdentity.obfuscated_ticket_age modulo 2^32 ) + * within a small tolerance of the time since the + * ticket was issued? + */ + + diff = ( now - ssl->session_negotiate->start ) - + ( obfuscated_ticket_age - ssl->session_negotiate->ticket_age_add ); + + if( diff > MBEDTLS_SSL_TICKET_AGE_TOLERANCE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket age outside tolerance window ( diff=%d )", + diff ) ); + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + if( diff <= MBEDTLS_SSL_EARLY_DATA_MAX_DELAY ) + { + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_ENABLED; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "0-RTT is disabled ( diff=%d exceeds "\ + "MBEDTLS_SSL_EARLY_DATA_MAX_DELAY )", diff ) ); + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_DISABLED; + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + } +#endif /* MBEDTLS_ZERO_RTT */ +#endif /* MBEDTLS_HAVE_TIME */ + + /* TBD: check ALPN, ciphersuite and SNI as well */ + + /* + * If the check failed, the server SHOULD proceed with + * the handshake but reject 0-RTT, and SHOULD NOT take any + * other action that assumes that this ClientHello is fresh. + */ + + /* Disable 0-RTT */ + if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + { +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == + MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_DISABLED; + } +#else + ( ( void )buf ); +#endif /* MBEDTLS_ZERO_RTT */ + } + } + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + } + /* skip the processed identity field and obfuscated ticket age field */ + buf += item_length; + buf += 4; + sum = sum + 4; + } + + if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Session ticket expired." ) ); + return( ret ); + } + + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", buf, item_length ); + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ); + } + + if( length_so_far != sum ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +psk_parsing_successful: + + /* Update the handshake transcript with the CH content up to + * but excluding the PSK binder list. */ + ssl->handshake->update_checksum( ssl, start, + (size_t)( end_of_psk_identities - start ) ); + + buf = end_of_psk_identities; + + /* Get current state of handshake transcript. */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + /* read length of psk binder array */ + item_array_length = ( buf[0] << 8 ) | buf[1]; + length_so_far += item_array_length; + buf += 2; + + sum = 0; + while( sum < item_array_length ) + { + /* Read to psk binder length */ + item_length = buf[0]; + sum = sum + 1 + item_length; + buf += 1; + + if( sum > item_array_length ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk binder length mismatch" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + psk = ssl->handshake->psk; + psk_len = ssl->handshake->psk_len; + + ret = mbedtls_ssl_tls1_3_create_psk_binder( ssl, + psk, psk_len, + ssl->handshake->ciphersuite_info->mac, + !( ssl->handshake->resume == 1 ) /* external PSK */, + transcript, server_computed_binder ); + + /* We do not check for multiple binders */ + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "PSK binder calculation failed." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder ( computed ): ", + server_computed_binder, item_length ); + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder ( received ): ", + buf, item_length ); + + if( mbedtls_ssl_safer_memcmp( server_computed_binder, buf, + item_length ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Received psk binder does not match computed psk binder." ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf += item_length; + + ret = 0; + goto done; + } + + /* No valid PSK binder value found */ + /* TODO: Shouldn't we just fall back to a full handshake in this case? */ + ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO; + +done: + + /* Update the handshake transcript with the binder list. */ + ssl->handshake->update_checksum( ssl, + end_of_psk_identities, + (size_t)( buf - end_of_psk_identities ) ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED*/ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * PskIdentity identities<6..2^16-1>; + * + * case server_hello: + * uint16 selected_identity; + * } + * } PreSharedKeyExtension; + */ + +static int ssl_write_server_pre_shared_key_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = (unsigned char*)buf; + size_t selected_identity; + + *olen = 0; + + if( ssl->handshake->psk == NULL ) + { + /* We shouldn't have called this extension writer unless we've + * chosen to use a PSK. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding pre_shared_key extension" ) ); + + if( end < p || ( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( 2 >> 8 ) & 0xFF ); + *p++ = (unsigned char)( 2 & 0xFF ); + + /* NOTE: This will need to be adjusted once we support multiple PSKs + * being offered by the client. */ + selected_identity = 0; + + /* Write selected_identity */ + *p++ = (unsigned char)( ( selected_identity >> 8 ) & 0xFF ); + *p++ = (unsigned char)( selected_identity & 0xFF ); + + *olen = 6; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "sent selected_identity: %d", selected_identity ) ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +#if defined(MBEDTLS_SSL_COOKIE_C) +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ) +{ + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + mbedtls_free( ssl->cli_id ); + + if( ( ssl->cli_id = mbedtls_calloc( 1, ilen ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->cli_id, info, ilen ); + ssl->cli_id_len = ilen; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) +void mbedtls_ssl_conf_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie, + unsigned int rr_config ) +{ + conf->f_cookie_write = f_cookie_write; + conf->f_cookie_check = f_cookie_check; + conf->p_cookie = p_cookie; + conf->rr_config = rr_config; +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) +static int ssl_parse_cookie_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + size_t cookie_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse cookie extension" ) ); + + if( ssl->conf->f_cookie_check != NULL ) + { + if( len >= 2 ) + { + cookie_len = ( buf[0] << 8 ) | buf[1]; + buf += 2; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( cookie_len + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "Received cookie", buf, cookie_len ); + + if( ssl->conf->f_cookie_check( ssl->conf->p_cookie, + buf, cookie_len, ssl->cli_id, ssl->cli_id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) ); + ssl->handshake->verify_cookie_len = 1; + ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) ); + ssl->handshake->verify_cookie_len = 0; + } + } + else { + /* TBD: Check under what cases this is appropriate */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + + if( ssl->conf->p_sni == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "No SNI callback configured. Skip SNI parsing." ) ); + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Parse ServerName extension" ) ); + + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while ( servername_list_size > 0 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->conf->f_sni( ssl->conf->p_sni, + ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +#if defined(MBEDTLS_ZERO_RTT) +/* + static int ssl_parse_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) + { + ( ( void* )ssl ); + ( ( void* )buf ); + return( 0 ); + } +*/ +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Maximum fragment length = %d", buf[0] ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * ssl_parse_key_exchange_modes_ext( ) structure: + * + * enum { psk_ke( 0 ), psk_dhe_ke( 1 ), ( 255 ) } PskKeyExchangeMode; + * + * struct { + * PskKeyExchangeMode ke_modes<1..255>; + * } PskKeyExchangeModes; + */ + +static int ssl_parse_key_exchange_modes_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t psk_mode_list_len; + unsigned psk_key_exchange_modes = 0; + + /* Read PSK mode list length (1 Byte) */ + psk_mode_list_len = *buf++; + len--; + + /* There's no content after the PSK mode list, to its length + * must match the total length of the extension. */ + if( psk_mode_list_len != len ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* Currently, there are only two PSK modes, so even without looking + * at the content, something's wrong if the list has more than 2 items. */ + if( psk_mode_list_len > 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + while( psk_mode_list_len-- != 0 ) + { + switch( *buf ) + { + case MBEDTLS_SSL_TLS13_PSK_MODE_PURE: + psk_key_exchange_modes |= MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + break; + case MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE: + psk_key_exchange_modes |= MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + break; + default: + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + ssl->handshake->key_exchange_modes = psk_key_exchange_modes; + return ( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + + +/* + * ssl_write_supported_version_ext( ): + * ( as sent by server ) + * + * case server_hello: + * ProtocolVersion selected_version; + */ + +static int ssl_write_supported_version_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + *olen = 0; + + /* With only a single supported version we do not need the ssl structure. */ + ( (void ) ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding supported version extension" ) ); + + if( end < p || (size_t)( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS ) & 0xFF ); + + /* length */ + *p++ = 0x00; + *p++ = 2; + + /* For TLS 1.3 and for DTLS 1.3 we use 0x0304 */ + *p++ = 0x03; + *p++ = 0x04; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "version [%d:%d]", *( p-2 ), *( p-1 ) ) ); + + *olen = 6; + + return( 0 ); +} + + +static int ssl_parse_supported_versions_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len; + int major_ver, minor_ver; + + if( len < 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_versions_ext: Incorrect length" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + + while ( len > 0 ) + { + list_len = buf[0]; + + /* length has to be at least 2 bytes long */ + if( list_len < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_versions_ext: Incorrect length" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + + /* skip length field */ + buf++; + + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, buf ); + + /* In this implementation we only support TLS 1.3 and DTLS 1.3. */ + if( major_ver == MBEDTLS_SSL_MAJOR_VERSION_3 && + minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + /* we found a supported version */ + goto found_version; + } + else + { + /* if no match found, check next entry */ + buf += 2; + len -= 3; + } + } + + /* If we got here then we have no version in common */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS. Supported is [%d:%d]", + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + +found_version: + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Negotiated version. Supported is [%d:%d]", + major_ver, minor_ver ) ); + + /* version in common */ + ssl->major_ver = major_ver; + ssl->minor_ver = minor_ver; + ssl->handshake->max_major_ver = ssl->major_ver; + ssl->handshake->max_minor_ver = ssl->minor_ver; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Store minor version for later use with ticket serialization. */ + ssl->session_negotiate->minor_ver = ssl->minor_ver; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, cur_len, ours_len; + const unsigned char *theirs, *start, *end; + const char **ours; + + /* If ALPN not configured, just ignore the extension */ + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Min length is 2 ( list_len ) + 1 ( name_len ) + 1 ( name ) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* + * Use our order of preference + */ + start = buf + 2; + end = buf + len; + for ( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for ( theirs = start; theirs != end; theirs += cur_len ) + { + /* If the list is well formed, we should get equality first */ + if( theirs > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cur_len = *theirs++; + + /* Empty strings MUST NOT be included */ + if( cur_len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( cur_len == ours_len && + memcmp( theirs, *ours, cur_len ) == 0 ) + { + ssl->alpn_chosen = *ours; + return( 0 ); + } + } + } + + /* If we get there, no match was found */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * + * STATE HANDLING: NewSessionTicket message + * + */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +/* Main state-handling entry point; orchestrates the other functions. */ +static int ssl_write_new_session_ticket_process( mbedtls_ssl_context* ssl ); + +#define SSL_NEW_SESSION_TICKET_SKIP 0 +#define SSL_NEW_SESSION_TICKET_WRITE 1 + +static int ssl_write_new_session_ticket_coordinate( mbedtls_ssl_context* ssl ); + +static int ssl_write_new_session_ticket_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); + +/* Update the state after handling the incoming end of early data message. */ +static int ssl_write_new_session_ticket_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ +static int ssl_write_new_session_ticket_process( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_new_session_ticket_coordinate( ssl ) ); + + if( ret == SSL_NEW_SESSION_TICKET_WRITE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, + MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_new_session_ticket_write( + ssl, buf, buf_len, &msg_len ) ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + MBEDTLS_SSL_PROC_CHK( ssl_write_new_session_ticket_write( ssl, + ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + } + else + { + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + } + +cleanup: + + return( ret ); +} + +static int ssl_write_new_session_ticket_coordinate( mbedtls_ssl_context* ssl ) +{ + /* Check whether the use of session tickets is enabled */ + if( ssl->conf->session_tickets == 0 ) + { + return( SSL_NEW_SESSION_TICKET_SKIP ); + } + + return( SSL_NEW_SESSION_TICKET_WRITE ); +} + + +static int ssl_write_new_session_ticket_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + return( 0 ); +} + +/* This function creates a NewSessionTicket message in the following format: + * + * struct { + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * opaque ticket_nonce<0..255>; + * opaque ticket<1..2^16-1>; + * Extension extensions<0..2^16-2>; + * } NewSessionTicket; + * + * The ticket inside the NewSessionTicket message is an encrypted container + * carrying the necessary information so that the server is later able to + * re-start the communication. + * + * The following fields are placed inside the ticket by the + * f_ticket_write() function: + * + * - creation time (start) + * - flags (flags) + * - lifetime (ticket_lifetime) + * - age add (ticket_age_add) + * - key (key) + * - key length (key_len) + * - ciphersuite (ciphersuite) + * - certificate of the peer (peer_cert) + * + */ +static int ssl_write_new_session_ticket_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t tlen; + size_t ext_len = 0; + unsigned char *p; + unsigned char *end = buf + buflen; + mbedtls_ssl_ciphersuite_t *suite_info; + int hash_length; + unsigned char *ticket_lifetime_ptr; + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t const total_length = 12 + MBEDTLS_SSL_TICKET_NONCE_LENGTH; + p = buf; +#else + size_t const total_length = 16 + MBEDTLS_SSL_TICKET_NONCE_LENGTH; + p = buf + 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write NewSessionTicket msg" ) ); + + /* Do we have space for the fixed length part of the ticket */ + if( buflen < total_length ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer for ticket too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + suite_info = (mbedtls_ssl_ciphersuite_t *) ssl->handshake->ciphersuite_info; + + hash_length = mbedtls_hash_size_for_ciphersuite( suite_info ); + + if( hash_length == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + /* In this code the psk key length equals the length of the hash */ + ssl->session->key_len = hash_length; + ssl->session->ciphersuite = ssl->handshake->ciphersuite_info->id; + + /* Ticket Lifetime + * (write it later) + */ + ticket_lifetime_ptr = p; + p+=4; + + /* Ticket Age Add */ + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, + (unsigned char*) &ssl->session->ticket_age_add, + sizeof( ssl->session->ticket_age_add ) ) != 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to generate ticket" ) ); + return( ret ); + } + + *(p++) = ( ssl->session->ticket_age_add >> 24 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 16 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 8 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_age_add: %u", ssl->session->ticket_age_add ) ); + + /* Ticket Nonce */ + *(p++) = MBEDTLS_SSL_TICKET_NONCE_LENGTH; + + ret = ssl->conf->f_rng( ssl->conf->p_rng, p, + MBEDTLS_SSL_TICKET_NONCE_LENGTH ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "ticket_nonce:", + p, MBEDTLS_SSL_TICKET_NONCE_LENGTH ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "resumption_master_secret", + ssl->session->app_secrets.resumption_master_secret, + hash_length ); + + /* Computer resumption key + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( suite_info->mac, + ssl->session->app_secrets.resumption_master_secret, + hash_length, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( resumption ), + (const unsigned char *) p, + MBEDTLS_SSL_TICKET_NONCE_LENGTH, + ssl->session->key, + hash_length ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, "Creating the ticket-resumed PSK failed", ret ); + return ( ret ); + } + + p += MBEDTLS_SSL_TICKET_NONCE_LENGTH; + + ssl->session->key_len = hash_length; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Ticket-resumed PSK", + ssl->session->key, hash_length ); + + /* Ticket */ + ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, + ssl->session, + p + 2, end, + &tlen, + &ssl->session->ticket_lifetime); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_ticket_write", ret ); + return( ret ); + } + + /* Ticket lifetime */ + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 24 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 16 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 8 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_lifetime: %d", + ssl->session->ticket_lifetime ) ); + + /* Ticket Length */ + p[0] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + p[1] = (unsigned char)( ( tlen >> 0 ) & 0xFF ); + + p += 2 + tlen; + + /* Ticket Extensions + * + * Note: We currently don't have any extensions. + * Set length to zero. + */ + *(p++) = ( ext_len >> 8 ) & 0xFF; + *(p++) = ( ext_len >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket (extension_length): %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket (ticket length): %d", tlen ) ); + + *olen = p - buf; + + MBEDTLS_SSL_DEBUG_BUF( 4, "ticket", buf, *olen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) ); + + return( ret ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +/* + * + * STATE HANDLING: Parse End-of-Early Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_read_end_of_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_END_OF_EARLY_DATA_SKIP 0 +#define SSL_END_OF_EARLY_DATA_EXPECT 1 + +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context* ssl ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the incoming end of early data message. */ +static int ssl_read_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_read_end_of_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse end_of_early_data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_end_of_early_data_coordinate( ssl ) ); + if( ret == SSL_END_OF_EARLY_DATA_EXPECT ) + { +#if defined(MBEDTLS_ZERO_RTT) + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( ssl_end_of_early_data_fetch( ssl ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 0 ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_end_of_early_data_fetch( ssl ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#else /* MBEDTLS_ZERO_RTT */ + + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + + } + + /* Postprocessing step: Update state machine */ + MBEDTLS_SSL_PROC_CHK( ssl_read_end_of_early_data_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse end_of_early_data" ) ); + return( ret ); + +} + +#if defined(MBEDTLS_ZERO_RTT) + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context *ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + if( msg.type != MBEDTLS_SSL_HS_END_OF_EARLY_DATA || + msg.length != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( + "Bad EndOfEarlyData message: Type %u (expect %u), " + "Length %u (expect %u)", + (unsigned) msg.type, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, + (unsigned) msg.length, 0 ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_END_OF_EARLY_DATA || + ssl->in_hslen != 4 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#endif /* MBEDTLS_ZERO_RTT */ + +#if !defined(MBEDTLS_ZERO_RTT) +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_END_OF_EARLY_DATA_SKIP ); +} +#else /* MBEDTLS_ZERO_RTT */ +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_END_OF_EARLY_DATA_SKIP ); + + return( SSL_END_OF_EARLY_DATA_EXPECT ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + return ( 0 ); +} + +/* + * + * STATE HANDLING: Parse Early Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_read_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_EARLY_DATA_SKIP 0 +#define SSL_EARLY_DATA_EXPECT 1 + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_early_data_fetch( mbedtls_ssl_context* ssl, + mbedtls_mps_reader **reader ); +#else +static int ssl_early_data_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +/* Parse early data send by the peer. */ +static int ssl_read_early_data_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the incoming early data message. */ +static int ssl_read_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_read_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse early data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_early_data_coordinate( ssl ) ); + + if( ret == SSL_EARLY_DATA_EXPECT ) + { +#if defined(MBEDTLS_ZERO_RTT) + unsigned char *buf; + size_t buflen; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_reader *rd; +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( ssl_early_data_fetch( ssl, &rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_get( rd, + MBEDTLS_MPS_SIZE_MAX, + &buf, + &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_parse( ssl, buf, buflen ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_early_data_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* No state machine update at this point -- we might receive + * multiple 0-RTT messages. */ + +#else /* MBEDTLS_ZERO_RTT */ + + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + } + else + { + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse early data" ) ); + return( ret ); +} + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_early_data_fetch( mbedtls_ssl_context *ssl, + mbedtls_mps_reader **rd ) +{ + int ret; + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_APP ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_application( &ssl->mps.l4, rd ) ); + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_early_data_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg; + *buflen = ssl->in_hslen; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_ZERO_RTT */ + +#if !defined(MBEDTLS_ZERO_RTT) +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_EARLY_DATA_SKIP ); +} +#else /* MBEDTLS_ZERO_RTT */ +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_EARLY_DATA_SKIP ); + + /* Activate early data transform */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to 0-RTT keys for inbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_earlydata ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + if( ret != MBEDTLS_MPS_MSG_APP ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_EXPECT ); + +cleanup: + + return( ret ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_earlydata ); + + /* Fetching step */ + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + ssl->keep_current_message = 1; + + /* Check for EndOfEarlyData */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_EXPECT ); + +#endif /* MBEDTLS_SSL_USE_MPS */ +} + +static int ssl_read_early_data_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ) +{ + /* Check whether we have enough buffer space. */ + if( buflen <= ssl->conf->max_early_data ) + { + /* TODO: We need to check that we're not receiving more 0-RTT + * than what the ticket allows. */ + + /* copy data to staging area */ + memcpy( ssl->early_data_server_buf, buf, buflen ); + /* execute callback to process application data */ + ssl->conf->early_data_callback( ssl, ssl->early_data_server_buf, + buflen ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer too small (recv %d bytes, buffer %d bytes)", + buflen, ssl->conf->max_early_data ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_END_OF_EARLY_DATA ); + return ( 0 ); +} + + +/* + * + * STATE HANDLING: ClientHello + * + * There are three possible classes of outcomes when parsing the CH: + * + * 1) The CH was well-formed and matched the server's configuration. + * + * In this case, the server progresses to sending its ServerHello. + * + * 2) The CH was well-formed but didn't match the server's configuration. + * + * For example, the client might not have offered a key share which + * the server supports, or the server might require a cookie. + * + * In this case, the server sends a HelloRetryRequest. + * + * 3) The CH was ill-formed + * + * In this case, we abort the handshake. + * + */ + +/* + * Overview + */ + +/* Main entry point from the state machine; orchestrates the otherfunctions. */ +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_client_hello_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_client_hello_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ); + +/* Update the handshake state machine */ +/* TODO: At the moment, this doesn't update the state machine - why? */ +static int ssl_client_hello_postprocess( mbedtls_ssl_context* ssl, + int hrr_required ); + +/* + * Implementation + */ + +#define SSL_CLIENT_HELLO_OK 0 +#define SSL_CLIENT_HELLO_HRR_REQUIRED 1 + +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ) +{ + + int ret = 0; + int hrr_required = SSL_CLIENT_HELLO_OK; + unsigned char* buf = NULL; + size_t buflen = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CLIENT_HELLO, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, + MBEDTLS_SSL_HS_CLIENT_HELLO, buflen ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_client_hello_parse( ssl, buf, buflen ) ); + hrr_required = ret; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK_NEG( ssl_client_hello_parse( ssl, buf, buflen ) ); + hrr_required = ret; + +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "postprocess" ) ); + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_postprocess( ssl, hrr_required ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_client_hello_fetch( mbedtls_ssl_context* ssl, + unsigned char** dst, + size_t* dstlen ) +{ + int ret; + unsigned char* buf; + size_t msg_len; + + if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf = ssl->in_hdr; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, + mbedtls_ssl_hdr_len( ssl ) ); + + /* + * TLS Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 11 DTLS: epoch + record sequence number + * 3 . 4 message length + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, message type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE ) + { +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( buf[0] == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + + if( msg_len != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad CCS message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "CCS, message len.: %d", msg_len ) ); + + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + if( ssl->in_msg[0] == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Change Cipher Spec message received and ignoring it." ) ); + ssl->in_left = 0; + return ( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + else + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 ) + { + return( ret ); + } + return ( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + else +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Spurious message ( maybe alert message )" ) ); + + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, message len.: %d", + ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) ); + + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + + if( msg_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + buf = ssl->in_msg; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, msg_len ); + + /* + * Handshake layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 DTLS only: message seqence number + * 6 . 8 DTLS only: fragment offset + * 9 . 11 DTLS only: fragment length + */ + if( msg_len < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + + /* We don't support fragmentation of ClientHello ( yet? ) */ + if( buf[1] != 0 || + msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + *dst = ssl->in_msg; + *dstlen = msg_len; + return( 0 ); +} + +#endif /* MBEDTLS_SSL_USE_MPS */ + +static void ssl_debug_print_client_hello_exts( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Supported Extensions:" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- KEY_SHARE_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- PSK_KEY_EXCHANGE_MODES_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- PRE_SHARED_KEY_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SIGNATURE_ALGORITHM_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SUPPORTED_GROUPS_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_GROUPS ) >0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SUPPORTED_VERSION_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_VERSION ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#if defined ( MBEDTLS_SSL_SERVER_NAME_INDICATION ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SERVERNAME_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SERVERNAME ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined ( MBEDTLS_SSL_ALPN ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- ALPN_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_ALPN ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_ALPN */ +#if defined ( MBEDTLS_SSL_MAX_FRAGMENT_LENGTH ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- MAX_FRAGMENT_LENGTH_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_MAX_FRAGMENT_LENGTH ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined ( MBEDTLS_SSL_COOKIE_C ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- COOKIE_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_COOKIE ) >0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_COOKIE_C */ +#if defined(MBEDTLS_ZERO_RTT) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- EARLY_DATA_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_ZERO_RTT*/ +} + +static int ssl_client_hello_has_psk_extensions( mbedtls_ssl_context *ssl ) +{ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES ) ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_has_cert_extensions( mbedtls_ssl_context *ssl ) +{ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_GROUPS ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_allows_psk_mode( mbedtls_ssl_context *ssl, + unsigned psk_mode ) +{ + if( ( ssl->handshake->key_exchange_modes & psk_mode ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_allows_pure_psk( mbedtls_ssl_context *ssl ) +{ + return( ssl_client_hello_allows_psk_mode( ssl, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ) ); +} + +static int ssl_client_hello_allows_psk_ecdhe( mbedtls_ssl_context *ssl ) +{ + return( ssl_client_hello_allows_psk_mode( ssl, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) ); +} + +static int ssl_check_psk_key_exchange( mbedtls_ssl_context *ssl ) +{ + if( !ssl_client_hello_has_psk_extensions( ssl ) ) + return( 0 ); + + /* Test whether pure PSK is offered by client and supported by us. */ + if( mbedtls_ssl_conf_tls13_pure_psk_enabled( ssl ) && + ssl_client_hello_allows_pure_psk( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Using a PSK key exchange" ) ); + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_PSK; + return( 1 ); + } + + /* Test whether PSK-ECDHE is offered by client and supported by us. */ + if( mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( ssl ) && + ssl_client_hello_allows_psk_ecdhe( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Using a ECDHE-PSK key exchange" ) ); + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_PSK; + return( 1 ); + } + + /* Can't use PSK */ + return( 0 ); +} + +static int ssl_check_certificate_key_exchange( mbedtls_ssl_context *ssl ) +{ + if( !mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( ssl ) ) + return( 0 ); + + if( !ssl_client_hello_has_cert_extensions( ssl ) ) + return( 0 ); + + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA; + return( 1 ); +} + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_check_use_0rtt_handshake( mbedtls_ssl_context *ssl ) +{ + /* Check if the user has enabled 0-RTT in the config */ + if( !mbedtls_ssl_conf_tls13_0rtt_enabled( ssl ) ) + return( 0 ); + + /* Check if the client has indicated the use of 0-RTT */ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) == 0 ) + return( 0 ); + + /* If the client has indicated the use of 0-RTT but not sent + * the PSK extensions, that's not conformant (and there's no + * way to continue from here). */ + if( !ssl_client_hello_has_psk_extensions( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Client indicated 0-RTT without offering PSK extensions" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Accept 0-RTT */ + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT*/ + +static int ssl_client_hello_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ) +{ + int ret, final_ret = 0, got_common_suite; + size_t i, j; + size_t comp_len, sess_len; + size_t ciph_len, ext_len, ext_len_psk_ext = 0; + unsigned char *orig_buf, *end = buf + buflen; + unsigned char *ciph_offset; + unsigned char *p = NULL; + unsigned char *ext = NULL; + unsigned char *ext_psk_ptr = NULL; + + const int* ciphersuites; + const mbedtls_ssl_ciphersuite_t* ciphersuite_info; + + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_NONE; + + /* TBD: Refactor */ + orig_buf = buf; + + /* + * ClientHello layer: + * 0 . 1 protocol version + * 2 . 33 random bytes ( starting with 4 bytes of Unix time ) + * 34 . 35 session id length ( 1 byte ) + * 35 . 34+x session id + * 35+x . 35+x DTLS only: cookie length ( 1 byte ) + * 36+x . .. DTLS only: cookie + * .. . .. ciphersuite list length ( 2 bytes ) + * .. . .. ciphersuite list + * .. . .. compression alg. list length ( 1 byte ) + * .. . .. compression alg. list + * .. . .. extensions length ( 2 bytes, optional ) + * .. . .. extensions ( optional ) + */ + +#if !defined(MBEDTLS_SSL_USE_MPS) + buf += mbedtls_ssl_hs_hdr_len( ssl ); + buflen -= mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* TBD: Needs to be updated due to mandatory extensions + * Minimal length ( with everything empty and extensions ommitted ) is + * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can + * read at least up to session id length without worrying. + */ + if( buflen < 38 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * We ignore the version field in the ClientHello. + * We use the version field in the extension. + */ + buf += 2; /* skip version */ + + /* + * Save client random + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf, 32 ); + + memcpy( &ssl->handshake->randbytes[0], buf, 32 ); + buf += 32; /* skip random bytes */ + + /* + * Parse session ID + */ + sess_len = buf[0]; + buf++; /* skip session id length */ + + if( sess_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->id_len = sess_len; + + /* Note that this field is echoed even if + * the client's value corresponded to a cached pre-TLS 1.3 session + * which the server has chosen not to resume. A client which + * receives a legacy_session_id_echo field that does not match what + * it sent in the ClientHello MUST abort the handshake with an + * "illegal_parameter" alert. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, session id length ( %d )", sess_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf, sess_len ); + + memcpy( &ssl->session_negotiate->id[0], buf, sess_len ); /* write session id */ + buf += sess_len; + + ciph_len = ( buf[0] << 8 ) | ( buf[1] ); + + /* Length check */ + if( buf + ciph_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* store pointer to ciphersuite list */ + ciph_offset = buf; + + /* skip cipher length */ + buf += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf, ciph_len ); + + /* skip ciphersuites for now */ + buf += ciph_len; + + /* + * For TLS 1.3 we are not using compression. + */ + comp_len = buf[0]; + + if( buf + comp_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf++; /* skip compression length */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, compression", + buf, comp_len ); + + /* Determine whether we are indeed using null compression */ + if( ( comp_len != 1 ) && ( buf[1] == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* skip compression */ + buf++; + + /* + * Check the extension length + */ + if( buf+2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_len = ( buf[0] << 8 ) | ( buf[1] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + buf + 2 + ext_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf += 2; + + ext = buf; + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", ext, ext_len ); + + while( ext_len != 0 ) + { + unsigned int ext_id, ext_size; + + if( ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* The PSK extension must be the last in the ClientHello. + * Fail if we've found it already but haven't yet reached + * the end of the extension block. */ + if( ext_psk_ptr != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_id = ( ( (size_t) ext[0] << 8 ) | ( (size_t) ext[1] << 0 ) ); + ext_size = ( ( (size_t) ext[2] << 8 ) | ( (size_t) ext[3] << 0 ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_servername_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVERNAME_EXT ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SERVERNAME; + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_COOKIE_C) + case MBEDTLS_TLS_EXT_COOKIE: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found cookie extension" ) ); + + ret = ssl_parse_cookie_ext( ssl, ext + 4, ext_size ); + + /* if cookie verification failed then we return a hello retry message */ + if( ret == MBEDTLS_ERR_SSL_HRR_REQUIRED ) + { + final_ret = ret; + } + else if( ret == 0 ) /* cookie extension present and processed succesfully */ + { + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_COOKIE; + } + break; +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PRE_SHARED_KEY: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found pre_shared_key extension" ) ); + /* Delay processing of the PSK identity once we have + * found out which algorithms to use. We keep a pointer + * to the buffer and the size for later processing. + */ + ext_len_psk_ext = ext_size; + ext_psk_ptr = ext + 4; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_ZERO_RTT) + case MBEDTLS_TLS_EXT_EARLY_DATA: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found early_data extension" ) ); + + /* There is nothing really to process with this extension. + + ret = ssl_parse_early_data_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_parse_supported_groups_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + */ + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_EARLY_DATA; + break; +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_SUPPORTED_GROUPS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported group extension" ) ); + + /* Supported Groups Extension + * + * When sent by the client, the "supported_groups" extension + * indicates the named groups which the client supports, + * ordered from most preferred to least preferred. + */ + ret = mbedtls_ssl_parse_supported_groups_ext( ssl, ext + 4, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_parse_supported_groups_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_GROUPS; + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found psk key exchange modes extension" ) ); + + ret = ssl_parse_key_exchange_modes_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_key_exchange_modes_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + case MBEDTLS_TLS_EXT_KEY_SHARES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found key share extension" ) ); + + /* + * Key Share Extension + * + * When sent by the client, the "key_share" extension + * contains the endpoint's cryptographic parameters for + * ECDHE/DHE key establishment methods. + */ + ret = ssl_parse_key_shares_ext( ssl, ext + 4, ext_size ); + if( ret == MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE ) + { + /* We need to send a HelloRetryRequest message + * but we still have to determine the ciphersuite. + * Note: We got the key share - we just didn't like + * the content of it. + */ + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + break; + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_max_fragment_length_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_MAX_FRAGMENT_LENGTH_EXT ); + } + ssl->handshake->extensions_present |= MAX_FRAGMENT_LENGTH_EXTENSION; + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported versions extension" ) ); + + ret = ssl_parse_supported_versions_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_supported_versions_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_VERSION; + break; + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_alpn_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_ALPN_EXT ); + } + ssl->handshake->extensions_present |= ALPN_EXTENSION; + break; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); + + ret = mbedtls_ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_signature_algorithms_server_ext ( %d )", ret ) ); + return( ret ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + } + + /* Update checksum with either + * - The entire content of the CH message, if no PSK extension is present + * - The content up to but excluding the PSK extension, if present. + */ + { + unsigned char *ch_without_psk; + if( ext_psk_ptr == NULL ) + ch_without_psk = ext; + else + ch_without_psk = ext_psk_ptr; + + ssl->handshake->update_checksum( ssl, + orig_buf, + ch_without_psk - orig_buf ); + } + + /* + * Search for a matching ciphersuite + */ + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for ( j = 0, p = ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) + { + for ( i = 0; ciphersuites[i] != 0; i++ ) +#else + for ( i = 0; ciphersuites[i] != 0; i++ ) + { + for ( j = 0, p = ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) +#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */ + { + if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[1] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_ssl_ciphersuite_from_id: should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + goto have_ciphersuite; + /* + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite; + */ + + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, but none of them usable" ) ); + /*mbedtls_ssl_send_fatal_handshake_failure( ssl ); */ + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + /*mbedtls_ssl_send_fatal_handshake_failure( ssl ); */ + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + have_ciphersuite: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", + ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = ciphersuite_info; + + /* List all the extensions we have received */ + ssl_debug_print_client_hello_exts( ssl ); + + /* + * Determine the key exchange algorithm to use. + * There are three types of key exchanges supported in TLS 1.3: + * - (EC)DH with ECDSA, + * - (EC)DH with PSK, + * - plain PSK. + * + * The PSK-based key exchanges may additionally be used with 0-RTT. + * + * Our built-in order of preference is + * 1 ) Plain PSK Mode + * 2 ) (EC)DHE-PSK Mode + * 3 ) Certificate Mode + */ + + ssl->handshake->key_exchange = 0; + + if( !ssl_check_psk_key_exchange( ssl ) && + !ssl_check_certificate_key_exchange( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ClientHello message misses mandatory extensions." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION , + MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +#if defined(MBEDTLS_ZERO_RTT) + ret = ssl_check_use_0rtt_handshake( ssl ); + if( ret != 0 ) + return( ret ); +#endif /* MBEDTLS_ZERO_RTT */ + + /* If we've settled on a PSK-based exchange, parse PSK identity ext */ + if( mbedtls_ssl_tls13_key_exchange_with_psk( ssl ) ) + { + ret = mbedtls_ssl_parse_client_psk_identity_ext( ssl, + ext_psk_ptr, + ext_len_psk_ext ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), + ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_COOKIE_C) + /* If we failed to see a cookie extension, and we required it through the + * configuration settings ( rr_config ), then we need to send a HRR msg. + * Conceptually, this is similiar to having received a cookie that failed + * the verification check. + */ + if( ( ssl->conf->rr_config == MBEDTLS_SSL_FORCE_RR_CHECK_ON ) && + !( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_COOKIE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Cookie extension missing. Need to send a HRR." ) ); + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } +#endif /* MBEDTLS_SSL_COOKIE_C */ + + if( final_ret == MBEDTLS_ERR_SSL_HRR_REQUIRED ) + { + final_ret = SSL_CLIENT_HELLO_HRR_REQUIRED; + + /* + * Create stateless transcript hash for HRR + */ + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Compress transcript hash for stateless HRR" ) ); + ret = mbedtls_ssl_hash_transcript( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hash_transcript", ret ); + return( ret ); + } + } + + return( final_ret ); +} + +static int ssl_client_hello_postprocess( mbedtls_ssl_context* ssl, + int hrr_required ) +{ + int ret = 0; +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_key_set traffic_keys; +#endif /* MBEDTLS_ZERO_RTT */ + + if( ssl->handshake->hello_retry_requests_sent == 0 && + ssl->conf->rr_config == MBEDTLS_SSL_FORCE_RR_CHECK_ON ) + { + hrr_required = SSL_CLIENT_HELLO_HRR_REQUIRED; + } + + if( hrr_required == SSL_CLIENT_HELLO_HRR_REQUIRED ) + { + /* Transmit Hello Retry Request */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HELLO_RETRY_REQUEST ); + return( 0 ); + } + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", ret ); + return( ret ); + } + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Generate 0-RTT keys" ) ); + + ret = mbedtls_ssl_tls1_3_generate_early_data_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_early_data_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_earlydata, ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, &traffic_keys, ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_earlydata = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_earlydata == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_earlydata, + &ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + mbedtls_platform_zeroize( &traffic_keys, sizeof( traffic_keys ) ); + +#endif /* MBEDTLS_ZERO_RTT */ + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + return( 0 ); + +} + + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + *olen = 0; + if( ( ssl->handshake->extensions_present & MAX_FRAGMENT_LENGTH_EXTENSION ) + == 0 ) + { + return( 0 ); + } + + if( ssl->session_negotiate->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t buflen, size_t *olen ) +{ + *olen = 0; + + if( ( ssl->handshake->extensions_present & ALPN_EXTENSION ) == 0 || + ssl->alpn_chosen == NULL ) + { + return( 0 ); + } + + if( buflen < 7 + strlen( ssl->alpn_chosen ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) ); + /* + * 0 . 1 ext identifier + * 2 . 3 ext length + * 4 . 5 protocol list length + * 6 . 6 protocol name length + * 7 . 7+n protocol name + */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + *olen = 7 + strlen( ssl->alpn_chosen ); + + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( *olen - 4 ) & 0xFF ); + + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( *olen - 6 ) & 0xFF ); + + buf[6] = (unsigned char)( ( *olen - 7 ) & 0xFF ); + + memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 ); + return ( 0 ); +} +#endif /* MBEDTLS_SSL_ALPN */ + + + +/* + * + * EncryptedExtensions message + * + * The EncryptedExtensions message contains any extensions which + * should be protected, i.e., any which are not needed to establish + * the cryptographic context. + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ); + +static int ssl_encrypted_extensions_prepare( mbedtls_ssl_context* ssl ); +static int ssl_encrypted_extensions_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ); + + + +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ) +{ + int ret; + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write encrypted extension" ) ); + + if( ssl->handshake->state_local.encrypted_extensions_out.preparation_done == 0 ) + { + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_prepare( ssl ) ); + ssl->handshake->state_local.encrypted_extensions_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION; + + MBEDTLS_SSL_DEBUG_BUF( 3, "EncryptedExtensions", ssl->out_msg, ssl->out_msglen ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + /* NOTE: For the new messaging layer, the postprocessing step + * might come after the dispatching step if the latter + * doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write encrypted extension" ) ); + return( ret ); +} + +static int ssl_encrypted_extensions_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + /* Compute handshake secret */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_master_secret", ret ); + return( ret ); + } + + /* Derive handshake key material */ + ret = mbedtls_ssl_tls1_3_generate_handshake_keys( ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_handshake_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + /* Setup transform from handshake key material */ + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_handshake ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* We're not yet using MPS for all outgoing encrypted handshake messages, + * so we cannot yet remove the old transform generation code in case + * MBEDTLS_SSL_USE_MPS is set. */ + { + mbedtls_ssl_transform *transform_handshake = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_handshake == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_handshake, + &ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * Switch to our negotiated transform and session parameters for outbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + memset( ssl->out_ctr, 0, 8 ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +static int ssl_encrypted_extensions_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t n, enc_ext_len; + unsigned char *p, *end, *len; + + /* If all extensions are disabled then olen is 0. */ + *olen = 0; + + end = buf + buflen; + p = buf; + +#if !defined(MBEDTLS_SSL_USE_MPS) + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Skip HS header */ + p += 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * struct { + * Extension extensions<0..2 ^ 16 - 1>; + * } EncryptedExtensions; + * + */ + + /* Skip extension length; first write extensions, then update length */ + len = p; + p += 2; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ret = ssl_write_sni_server_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_ALPN) + ret = ssl_write_alpn_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ret = ssl_write_max_fragment_length_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ZERO_RTT) + ret = mbedtls_ssl_write_early_data_ext( ssl, p, (size_t)( end - p ), &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_ZERO_RTT */ + + *olen = p - buf; + enc_ext_len = (size_t)( ( p - len ) - 2 ); + + len[0] = (unsigned char)( ( enc_ext_len >> 8 ) & 0xFF ); + len[1] = (unsigned char)( ( enc_ext_len >> 0 ) & 0xFF ); + + return( 0 ); +} + +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST ); + return( 0 ); +} + +/* + * + * HelloRetryRequest message + * + * Servers send this message in response to a ClientHello message when + * the server was able to find an acceptable set of algorithms and groups + * that are mutually supported, but the client's KeyShare did not contain + * an acceptable offer. + * + * We also send this message with DTLS 1.3 to perform a return-routability + * check (and we include a cookie). + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_write_hello_retry_request_process( mbedtls_ssl_context* ssl ); + +static int ssl_write_hello_retry_request_coordinate( mbedtls_ssl_context* ssl ); +static int ssl_write_hello_retry_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_write_hello_retry_request_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_write_hello_retry_request_process( mbedtls_ssl_context *ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_SERVER_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_write( ssl, + ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + return( ret ); +} + + +static int ssl_write_hello_retry_request_coordinate( mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake->hello_retry_requests_sent > 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Too many HRRs" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR ); + } + + return( 0 ); +} + +static int ssl_write_hello_retry_request_postprocess( mbedtls_ssl_context *ssl ) +{ + ssl->handshake->hello_retry_requests_sent++; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CCS_AFTER_HRR ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + return( 0 ); +} + +static int ssl_write_hello_retry_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + unsigned char *p = buf; + unsigned char *end = buf + buflen; + unsigned char *ext_len_byte; + size_t ext_length; + size_t total_ext_len = 0; + unsigned char *extension_start; + const char magic_hrr_string[32] = + { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, + 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, + 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, + 0xE2, 0xC8, 0xA8, 0x33 ,0x9C }; + +#if defined(MBEDTLS_ECDH_C) + const mbedtls_ecp_group_id *gid; + const mbedtls_ecp_curve_info **curve = NULL; +#endif /* MBEDTLS_ECDH_C */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello retry request" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + p = buf; +#else + p = buf + 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random ( with magic value ); + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<0..2^16-1>; + * } ServerHello; --- aka HelloRetryRequest + */ + + + /* For TLS 1.3 we use the legacy version number {0x03, 0x03} + * instead of the true version number. + * + * For DTLS 1.3 we use the legacy version number + * {254,253}. + * + * In cTLS the version number is elided. + */ + *p++ = 0x03; + *p++ = 0x03; + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p - 2, 2 ); + + /* write magic string (as a replacement for the random value) */ + memcpy( p, &magic_hrr_string[0], 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Random bytes in HelloRetryRequest", p, 32 ); + p += 32; + + /* write legacy_session_id_echo */ + *p++ = (unsigned char) ssl->session_negotiate->id_len; + memcpy( p, &ssl->session_negotiate->id[0], ssl->session_negotiate->id_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", p, ssl->session_negotiate->id_len ); + p += ssl->session_negotiate->id_len; + + /* write ciphersuite (2 bytes) */ + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + MBEDTLS_SSL_DEBUG_BUF( 3, "ciphersuite", p-2, 2 ); + + /* write legacy_compression_method (0) */ + *p++ = 0x0; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "legacy compression method: [%d]", *( p-1 ) ) ); + + /* write extensions */ + extension_start = p; + /* Extension starts with a 2 byte length field; we skip it and write it later */ + p += 2; + +#if defined(MBEDTLS_SSL_COOKIE_C) + + /* Cookie Extension + * + * struct { + * opaque cookie<0..2^16-1>; + * } Cookie; + * + */ + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 0 ) & 0xFF ); + + /* Skip writing the extension and the cookie length */ + ext_len_byte = p; + p = p + 4; + + /* If we get here, f_cookie_check is not null */ + if( ssl->conf->f_cookie_write == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, + &p, end, + ssl->cli_id, + ssl->cli_id_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); + return( ret ); + } + + ext_length = ( p - ( ext_len_byte + 4 ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "Cookie", ext_len_byte + 4, ext_length ); + + /* Write extension length */ + *ext_len_byte++ = (unsigned char)( ( ( ext_length + 2 ) >> 8 ) & 0xFF ); + *ext_len_byte++ = (unsigned char)( ( ext_length + 2 ) & 0xFF ); + + /* Write cookie length */ + *ext_len_byte++ = (unsigned char)( ( ext_length >> 8 ) & 0xFF ); + *ext_len_byte = (unsigned char)( ext_length & 0xFF ); + + /* 2 bytes for extension type, + * 2 bytes for extension length field, + * 2 bytes for cookie length */ + total_ext_len += ext_length + 6; +#endif /* MBEDTLS_SSL_COOKIE_C */ + + /* Add supported_version extension */ + if( ( ret = ssl_write_supported_version_ext( ssl, p, end, + &ext_length ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_supported_version_ext", ret ); + return( ret ); + } + + total_ext_len += ext_length; + p += ext_length; + +#if defined(MBEDTLS_ECDH_C) + /* key_share Extension + * + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * KeyShareEntry client_shares<0..2^16-1>; + * + * case hello_retry_request: + * NamedGroup selected_group; + * + * case server_hello: + * KeyShareEntry server_share; + * }; + * } KeyShare; + * + */ + + /* For a pure PSK-based ciphersuite there is no key share to declare. + * Hence, we focus on ECDHE-EDSA and ECDHE-PSK. + */ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 0 ) & 0xFF ); + + ext_len_byte = p; + + /* Write length */ + *p++ = 0; + *p++ = 2; + ext_length = 2; + + for ( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + { + for ( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + { + if( ( *curve )->grp_id == *gid ) + goto curve_matching_done; + } + } + + curve_matching_done: + if( curve == NULL || *curve == NULL ) + { + /* This case should not happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching named group found" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + /* Write selected group */ + *p++ = ( *curve )->tls_id >> 8; + *p++ = ( *curve )->tls_id & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NamedGroup in HRR: %s", (*curve)->name ) ); + + /* 2 bytes for extension_type and 2 bytes for length field */ + total_ext_len += ext_length + 4; + + } +#endif /* MBEDTLS_ECDH_C */ + + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len >> 0 ) & 0xFF ); + + *olen = p - buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello retry request" ) ); + return( 0 ); +} + +/* + * + * STATE HANDLING: ServerHello + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ); + +/* ServerHello handling sub-routines */ +static int ssl_server_hello_prepare( mbedtls_ssl_context* ssl ); +static int ssl_server_hello_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ) { + + int ret = 0; + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + + /* Preprocessing */ + + /* This might lead to ssl_process_server_hello( ) being called multiple + * times. The implementation of ssl_process_server_hello_preprocess( ) + * must either be safe to be called multiple times, or we need to add + * state to omit this call once we're calling ssl_process_server_hello( ) + * multiple times. */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_prepare( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_SERVER_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_write( ssl, buf, buf_len, + &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Postprocess */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Writing */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, &ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + + /* Postprocess */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + + /* NOTE: For the new messaging layer, the postprocessing step + * might come after the dispatching step if the latter + * doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. */ + + /* Dispatch */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + return( ret ); +} + + +/* IMPORTANT: This function can currently be called multiple times + * in case the call to mbedtls_ssl_flush_output( ) that + * follows it in ssl_process_server_hello( ) fails. + * + * Make sure that the preparations in this function + * can safely be repeated multiple times, or add logic + * to ssl_process_server_hello( ) to never call it twice. + */ +static int ssl_server_hello_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->handshake->randbytes + 32, 32 ) ) != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", ssl->handshake->randbytes + 32, 32 ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + + /* Check for session resumption + * + */ + + return( 0 ); +} + +static int ssl_server_hello_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret=0; + /* Extensions */ + + /* extension_start + * Used during extension writing where the + * buffer pointer to the beginning of the + * extension list must be kept to write + * the total extension list size in the end. + */ + unsigned char* extension_start; + size_t cur_ext_len; /* Size of the current extension */ + size_t total_ext_len; /* Size of list of extensions */ + size_t rand_bytes_len; + + /* Buffer management */ + unsigned char* start = buf; + unsigned char* end = buf + buflen; + + rand_bytes_len = 32; + + /* Ensure we have enough room for ServerHello + * up to but excluding the extensions. */ + if( buflen < ( 4+32+2+2+1+ssl->session_negotiate->id_len+1+1 ) ) /* TBD: FIXME */ + { + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* + * TLS 1.3 + * 0 . 0 handshake type + * 1 . 3 handshake length + * + * cTLS + * 0 . 0 handshake type + * + * The header is set by ssl_write_record. + * For DTLS 1.3 the other fields are adjusted. + */ + buf += 4; /* skip handshake type + length */ + buflen -=4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Version */ + *buf++ = (unsigned char)0x3; + *buf++ = (unsigned char)0x3; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [0x3:0x3]" ) ); + buflen -= 2; + + /* Write random bytes */ + memcpy( buf, ssl->handshake->randbytes + 32, rand_bytes_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf, rand_bytes_len ); + + buf += rand_bytes_len; + buflen -= rand_bytes_len; + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + /* Write legacy session id */ + *buf++ = (unsigned char)ssl->session_negotiate->id_len; + buflen--; + memcpy( buf, &ssl->session_negotiate->id[0], ssl->session_negotiate->id_len ); + buf += ssl->session_negotiate->id_len; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session id length ( %d )", ssl->session_negotiate->id_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", ssl->session_negotiate->id, ssl->session_negotiate->id_len ); + buflen -= ssl->session_negotiate->id_len; + + /* write selected ciphersuite ( 2 bytes ) */ + *buf++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *buf++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + buflen -= 2; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s ( id=%d )", mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ), ssl->session_negotiate->ciphersuite ) ); + + /* write legacy_compression_method ( 0 ) */ + *buf++ = 0x0; + buflen--; + + /* First write extensions, then the total length */ + extension_start = buf; + total_ext_len = 0; + buf += 2; + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Only add the pre_shared_key extension if the client provided it in the ClientHello + * and if the key exchange supports PSK + */ + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY && ( + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) ) + { + ret = ssl_write_server_pre_shared_key_ext( ssl, buf, end, + &cur_ext_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_server_pre_shared_key_ext", + ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + /* Only add the key_share extension if the client provided it in the ClientHello + * and if the appropriate key exchange mechanism was selected + */ + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE && ( + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) ) + { + if( ( ret = ssl_write_key_shares_ext( ssl, buf, end, &cur_ext_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_key_shares_ext", ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + } +#endif /* ( MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + /* Add supported_version extension */ + if( ( ret = ssl_write_supported_version_ext( ssl, buf, end, &cur_ext_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_supported_version_ext", ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + MBEDTLS_SSL_DEBUG_BUF( 4, "server hello extensions", extension_start, total_ext_len ); + + /* Write length information */ + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len ) & 0xFF ); + buflen -= 2 + total_ext_len; + + *olen = buf - start; + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello", start, *olen ); + + return( ret ); +} + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + ( (void ) ssl ); + + return( ret ); +} + +/* + * + * STATE HANDLING: CertificateRequest + * + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ); + +/* Coordination: + * Check whether a CertificateRequest message should be written. + * Returns a negative error code on failure, or one of + * - SSL_CERTIFICATE_REQUEST_EXPECT_WRITE or + * - SSL_CERTIFICATE_REQUEST_SKIP + * indicating if the writing of the CertificateRequest + * should be skipped or not. + */ +#define SSL_CERTIFICATE_REQUEST_SEND 0 +#define SSL_CERTIFICATE_REQUEST_SKIP 1 +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + /* Coordination step: Check if we need to send a CertificateRequest */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_certificate_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_REQUEST_SEND ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare CertificateRequest message in output buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_REQUEST_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + return( ret ); +} + + +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int authmode; + + if( ( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) ) + return( SSL_CERTIFICATE_REQUEST_SKIP ); + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + ( ( void )authmode ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; + else +#endif + authmode = ssl->conf->authmode; + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + return( SSL_CERTIFICATE_REQUEST_SKIP ); + + return( SSL_CERTIFICATE_REQUEST_SEND ); + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + +static int ssl_certificate_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t ext_size; + unsigned char* p; + unsigned char* end = buf + buflen; + + p = buf; + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* Skip over handshake header. + * + * NOTE: + * Even for DTLS, we are skipping 4 bytes for the TLS handshake + * header. The actual DTLS handshake header is inserted in + * the record writing routine mbedtls_ssl_write_record( ). + */ + p += 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + if( p + 1 + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* + * + * struct { + * opaque certificate_request_context<0..2^8-1>; + * Extension extensions<2..2^16-1>; + * } CertificateRequest; + * + */ + + /* + * Write certificate_request_context + */ + + /* + * We use a zero length context for the normal handshake + * messages. For post-authentication handshake messages + * this request context would be set to a non-zero value. + */ + *p++ = 0x0; + + /* + * Write extensions + */ + + /* The extensions must contain the signature_algorithms. */ + /* Currently we don't use any other extension */ + ret = mbedtls_ssl_write_signature_algorithms_ext( ssl, p + 2, + end, &ext_size ); + if( ret != 0 ) + return( ret ); + + /* length field for all extensions */ + *p++ = (unsigned char)( ( ext_size >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_size >> 0 ) & 0xFF ); + p += ext_size; + + *olen = p - buf; + + return( ret ); +} + + +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ) +{ + /* next state */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CERTIFICATE ); + return( 0 ); +} + +/* + * TLS and DTLS 1.3 State Maschine -- server side + */ +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); +#endif /* !MBEDTLS_SSL_USE_MPS */ + + switch( ssl->state ) + { + /* start state */ + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->handshake->hello_retry_requests_sent = 0; + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + ssl->handshake->ccs_sent = 0; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + break; + + /* ----- READ CLIENT HELLO ----*/ + + case MBEDTLS_SSL_CLIENT_HELLO: + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + ssl->session_negotiate->minor_ver = ssl->minor_ver; + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + ret = ssl_client_hello_process( ssl ); + if( ret != 0 ) + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_client_hello_process", ret ); + + break; + + /* ----- WRITE EARLY APP DATA ----*/ + case MBEDTLS_SSL_EARLY_APP_DATA: + + ret = ssl_read_early_data_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_read_early_data_process", ret ); + return ( ret ); + } + + break; + + /* ----- WRITE HELLO RETRY REQUEST ----*/ + + case MBEDTLS_SSL_HELLO_RETRY_REQUEST: + + ret = ssl_write_hello_retry_request_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_hello_retry_request", ret ); + return( ret ); + } + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_SERVER_CCS_AFTER_HRR: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- READ 2nd CLIENT HELLO ----*/ + case MBEDTLS_SSL_SECOND_CLIENT_HELLO: + + ret = ssl_client_hello_process( ssl ); + + switch( ret ) + { + case 0: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + break; + case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + break; + case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION, + MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC: + /* Stay in this state */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + ret = 0; + break; + default: + return( ret ); + } + + break; + /* ----- WRITE SERVER HELLO ----*/ + + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + break; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ssl->handshake->ccs_sent > 1 ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO ); + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + } +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process(ssl); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE ENCRYPTED EXTENSIONS ----*/ + + case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: + ret = ssl_encrypted_extensions_process( ssl ); + break; + + /* ----- WRITE CERTIFICATE REQUEST ----*/ + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_certificate_request_process( ssl ); + break; + + /* ----- WRITE SERVER CERTIFICATE ----*/ + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_write_certificate_process( ssl ); + break; + + /* ----- WRITE SERVER CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_write_certificate_verify_process( ssl ); + break; + + /* ----- WRITE FINISHED ----*/ + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_finished_out_process( ssl ); + break; + + /* ----- READ CLIENT CERTIFICATE ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_read_certificate_process( ssl ); + break; + + /* ----- READ CLIENT CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_read_certificate_verify_process( ssl ); + break; + + case MBEDTLS_SSL_END_OF_EARLY_DATA: + ret = ssl_read_end_of_early_data_process( ssl ); + break; + + /* ----- READ FINISHED ----*/ + + case MBEDTLS_SSL_CLIENT_FINISHED: + + ret = mbedtls_ssl_finished_in_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_in_process", ret ); + return( ret ); + } + + /* Compute resumption_master_secret */ + ret = mbedtls_ssl_tls1_3_generate_resumption_master_secret( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_resumption_master_secret ", ret ); + return( ret ); + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP ); + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for all traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform ( ssl, ssl->transform_application ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_application ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_wrapup_tls13( ssl ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET ); + + break; + + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + ret = ssl_write_new_session_ticket_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_new_session_ticket ", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} + +#endif /* MBEDTLS_SSL_SRV_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/programs/fuzz/fuzz_dtlsserver.c b/programs/fuzz/fuzz_dtlsserver.c index 4cde1fe6c762..bea27ab5d581 100644 --- a/programs/fuzz/fuzz_dtlsserver.c +++ b/programs/fuzz/fuzz_dtlsserver.c @@ -89,8 +89,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if( mbedtls_ssl_cookie_setup( &cookie_ctx, dummy_random, &ctr_drbg ) != 0 ) goto exit; - +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ if( mbedtls_ssl_setup( &ssl, &conf ) != 0 ) goto exit; diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c index 5f71ec950260..e187d1154f69 100644 --- a/programs/ssl/dtls_server.c +++ b/programs/ssl/dtls_server.c @@ -245,8 +245,10 @@ int main( void ) goto exit; } +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 4f076602a87e..0c9c9b23a6d3 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -62,6 +62,8 @@ int main( void ) #define DFL_KEY_OPAQUE 0 #define DFL_KEY_PWD "" #define DFL_PSK "" +#define DFL_KEY_EXCHANGE_MODES MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL +#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED #define DFL_PSK_OPAQUE 0 #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -108,6 +110,7 @@ int main( void ) #define DFL_NSS_KEYLOG 0 #define DFL_NSS_KEYLOG_FILE NULL #define DFL_SKIP_CLOSE_NOTIFY 0 +#define DFL_SIG_ALGS NULL #define DFL_QUERY_CONFIG_MODE 0 #define DFL_USE_SRTP 0 #define DFL_SRTP_FORCE_PROFILE 0 @@ -169,11 +172,19 @@ int main( void ) #define USAGE_CID "" #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEX_MODES \ + " key_exchange_modes=%%s default: all\n" \ + " options: psk, psk_dhe, ecdhe_ecdsa, psk_all, all\n" +#else +#define USAGE_KEX_MODES "" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #define USAGE_PSK_RAW \ - " psk=%%s default: \"\" (disabled)\n" \ - " The PSK values are in hex, without 0x.\n" \ - " psk_identity=%%s default: \"Client_identity\"\n" + " psk=%%s default: \"\" (disabled)\n" \ + " The PSK values are in hex, without 0x.\n" \ + " psk_identity=%%s default: \"Client_identity\"\n" #if defined(MBEDTLS_USE_PSA_CRYPTO) #define USAGE_PSK_SLOT \ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \ @@ -209,8 +220,13 @@ int main( void ) #endif /* MBEDTLS_SSL_SESSION_TICKETS */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* Support for EAP-TLS 1.3 has not been implemented yet. */ +#define USAGE_EAP_TLS "" +#else #define USAGE_EAP_TLS \ " eap_tls=%%d default: 0 (disabled)\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #define USAGE_NSS_KEYLOG \ " nss_keylog=%%d default: 0 (disabled)\n" \ " This cannot be used with eap_tls=1\n" @@ -286,6 +302,14 @@ int main( void ) #define USAGE_CURVES "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) +#define USAGE_SIG_ALGS \ + " sig_algs=a,b,c,d default: \"default\" (library default)\n" \ + " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n" +#else +#define USAGE_SIG_ALGS "" +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) #define USAGE_DTLS \ " dtls=%%d default: 0 (TLS)\n" \ @@ -359,6 +383,40 @@ int main( void ) #define USAGE_SERIALIZATION "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_FORCE_VERSION \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, tls1_3, dtls1, dtls1_2, dtls1_3\n" +#else +#define USAGE_FORCE_VERSION \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_EARLY_DATA \ + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), 1 (enabled)\n" +#else +#define USAGE_EARLY_DATA "" +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_NAMED_GROUP \ + " named_groups=%%s default: secp256r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_NAMED_GROUP "" +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEY_SHARE_NAMED_GROUPS \ + " key_share_named_groups=%%s default: secp256r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_KEY_SHARE_NAMED_GROUPS "" +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* USAGE is arbitrarily split to stay under the portable string literal * length limit: 4095 bytes in C99. */ #define USAGE1 \ @@ -419,7 +477,12 @@ int main( void ) USAGE_ETM \ USAGE_REPRODUCIBLE \ USAGE_CURVES \ + USAGE_SIG_ALGS \ USAGE_RECSPLIT \ + USAGE_EARLY_DATA \ + USAGE_KEX_MODES \ + USAGE_NAMED_GROUP \ + USAGE_KEY_SHARE_NAMED_GROUPS \ USAGE_DHMLEN \ "\n" #define USAGE4 \ @@ -438,9 +501,11 @@ int main( void ) USAGE_SERIALIZATION \ " acceptable ciphersuite names:\n" -#define ALPN_LIST_SIZE 10 -#define CURVE_LIST_SIZE 20 +#define ALPN_LIST_SIZE 10 +#define CURVE_LIST_SIZE 20 +#define SIG_ALG_LIST_SIZE 5 +#define NAMED_GROUPS_LIST_SIZE 4 /* * global options @@ -519,6 +584,11 @@ struct options * after renegotiation */ int reproducible; /* make communication reproducible */ int skip_close_notify; /* skip sending the close_notify alert */ + const char *named_groups_string; /* list of named groups */ + const char *key_share_named_groups_string; /* list of named groups */ + int key_exchange_modes; /* supported key exchange modes */ + const char *sig_algs; /* supported signature algorithms */ + int early_data; /* support for early data */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -680,6 +750,10 @@ int main( int argc, char *argv[] ) const char *pers = "ssl_client2"; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + int sig_alg_list[SIG_ALG_LIST_SIZE]; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_USE_PSA_CRYPTO) #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) psa_key_id_t slot = 0; @@ -695,7 +769,22 @@ int main( int argc, char *argv[] ) rng_context_t rng; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ECP_C) + /* list of named groups */ + mbedtls_ecp_group_id named_groups_list[NAMED_GROUPS_LIST_SIZE]; + /* list of named groups for key share*/ + mbedtls_ecp_group_id key_share_named_groups_list[NAMED_GROUPS_LIST_SIZE]; + char *start; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ZERO_RTT) + char early_data[] = "early data test"; +#endif /* MBEDTLS_ZERO_RTT */ + mbedtls_ssl_session saved_session; + unsigned char *session_data = NULL; size_t session_data_len = 0; #if defined(MBEDTLS_TIMING_C) @@ -717,10 +806,14 @@ int main( int argc, char *argv[] ) size_t context_buf_len; #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) unsigned char eap_tls_keymaterial[16]; unsigned char eap_tls_iv[8]; const char* eap_tls_label = "client EAP encryption"; eap_tls_keys eap_tls_keying; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) /*! master keys and master salt for SRTP generated during handshake */ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; @@ -737,7 +830,7 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) - mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) ); + mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) ); #endif #if defined(MBEDTLS_TEST_HOOKS) @@ -750,6 +843,18 @@ int main( int argc, char *argv[] ) mbedtls_net_init( &server_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ECP_C) + memset( (void *) named_groups_list, MBEDTLS_ECP_DP_NONE, sizeof( named_groups_list ) ); + memset( (void *) key_share_named_groups_list, + MBEDTLS_ECP_DP_NONE, + sizeof( key_share_named_groups_list ) ); +#endif /* MBEDTLS_ECP_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + memset( &saved_session, 0, sizeof( mbedtls_ssl_session ) ); rng_init( &rng ); #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -822,6 +927,9 @@ int main( int argc, char *argv[] ) opt.key_opaque = DFL_KEY_OPAQUE; opt.key_pwd = DFL_KEY_PWD; opt.psk = DFL_PSK; + opt.key_exchange_modes = DFL_KEY_EXCHANGE_MODES; + opt.sig_algs = DFL_SIG_ALGS; + opt.early_data = DFL_EARLY_DATA; #if defined(MBEDTLS_USE_PSA_CRYPTO) opt.psk_opaque = DFL_PSK_OPAQUE; #endif @@ -1060,7 +1168,7 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "tickets" ) == 0 ) { opt.tickets = atoi( q ); - if( opt.tickets < 0 || opt.tickets > 2 ) + if( opt.tickets < 0 || opt.tickets > 1 ) goto usage; } else if( strcmp( p, "alpn" ) == 0 ) @@ -1091,6 +1199,10 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "curves" ) == 0 ) opt.curves = q; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + else if( strcmp( p, "sig_algs" ) == 0 ) + opt.sig_algs = q; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ else if( strcmp( p, "etm" ) == 0 ) { switch( atoi( q ) ) @@ -1100,6 +1212,46 @@ int main( int argc, char *argv[] ) default: goto usage; } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ZERO_RTT) + else if( strcmp( p, "early_data" ) == 0 ) + { + switch( atoi( q ) ) + { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + case 1: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + break; + default: goto usage; + } + } +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) + else if( strcmp( p, "named_groups" ) == 0 ) + opt.named_groups_string = q; + else if( strcmp( p, "key_share_named_groups" ) == 0 ) + opt.key_share_named_groups_string = q; +#endif /* MBEDTLS_ECP_C */ + + else if( strcmp( p, "key_exchange_modes" ) == 0 ) + { + if( strcmp( q, "psk" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + else if( strcmp(q, "psk_dhe" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + else if( strcmp(q, "ecdhe_ecdsa" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA; + else if( strcmp( q, "psk_all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL; + else if( strcmp( q, "all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL; + else goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( p, "min_version" ) == 0 ) { if( strcmp( q, "ssl3" ) == 0 ) @@ -1112,6 +1264,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1127,6 +1284,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1170,6 +1332,13 @@ int main( int argc, char *argv[] ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( q, "dtls1" ) == 0 ) { opt.min_version = MBEDTLS_SSL_MINOR_VERSION_2; @@ -1182,6 +1351,14 @@ int main( int argc, char *argv[] ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "dtls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1273,9 +1450,14 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "eap_tls" ) == 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( "Error: eap_tls is not supported in TLS 1.3.\n" ); + goto usage; +#else opt.eap_tls = atoi( q ); if( opt.eap_tls < 0 || opt.eap_tls > 1 ) goto usage; +#endif } else if( strcmp( p, "reproducible" ) == 0 ) { @@ -1531,6 +1713,147 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.named_groups_string != NULL ) + { + p = (char *)opt.named_groups_string; + i = 0; + start = p; + + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0' ) + { + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + } + } + + if( i == 0 ) goto usage; + } + + if( opt.key_share_named_groups_string != NULL ) + { + p = (char *) opt.key_share_named_groups_string; + i = 0; + start = p; + + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0') + { + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + + } + } + + if( i == 0 ) goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + p = (char *) opt.sig_algs; + i = 0; + + /* Leave room for a final NULL in signature algorithm list */ + while( i < SIG_ALG_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( q, "ecdsa_secp256r1_sha256" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP256r1_SHA256; + } + else if( strcmp( q, "ecdsa_secp384r1_sha384" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP384r1_SHA384; + } + else if( strcmp( q, "ecdsa_secp521r1_sha512" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP521r1_SHA512; + } + else + { + mbedtls_printf( "unknown signature algorithm %s\n", q ); + mbedtls_printf( "supported signature algorithms: " ); +#if defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + mbedtls_printf( "ecdsa_secp256r1_sha256 " ); +#endif /* MBEDTLS_SHA256_C && MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + mbedtls_printf( "ecdsa_secp384r1_sha384 " ); +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SHA512_C) + mbedtls_printf( "ecdsa_secp521r1_sha512 " ); +#endif /* MBEDTLS_SHA512_C && MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_ECDSA_C */ + mbedtls_printf( "\n" ); + goto exit; + } + } + + if( i == ( SIG_ALG_LIST_SIZE - 1 ) && *p != '\0' ) + { + mbedtls_printf( "signature algorithm list too long, maximum %d", + SIG_ALG_LIST_SIZE - 1 ); + goto exit; + } + + sig_alg_list[i] = SIGNATURE_NONE; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + /* * 0. Initialize the RNG and the session data */ @@ -1726,6 +2049,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_X509_CRT_PARSE_C) /* The default algorithms profile disables SHA-1, but our tests still rely on it heavily. */ + if( opt.allow_sha1 > 0 ) { crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ); @@ -1737,8 +2061,13 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_verify( &conf, my_verify, NULL ); memset( peer_crt_info, 0, sizeof( peer_crt_info ) ); + #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test_tls13 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) if( opt.cid_enabled == 1 || opt.cid_enabled_renego == 1 ) { @@ -1833,16 +2162,32 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, &eap_tls_keying ); } - else if( opt.nss_keylog != 0 ) - { + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + if( opt.nss_keylog != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_conf_export_secrets_cb( &conf, + nss_keylog_export_tls13, + NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_conf_export_keys_ext_cb( &conf, nss_keylog_export, NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ } #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -1860,6 +2205,11 @@ int main( int argc, char *argv[] ) : MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + // Configure key exchange mode + mbedtls_ssl_conf_tls13_key_exchange( &conf, opt.key_exchange_modes ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_DHM_C) if( opt.dhmlen != DFL_DHMLEN ) mbedtls_ssl_conf_dhm_min_bitlen( &conf, opt.dhmlen ); @@ -1932,12 +2282,26 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_curves(&conf, named_groups_list); + + if( key_share_named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_key_share_curves( &conf, key_share_named_groups_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( opt.curves != NULL && strcmp( opt.curves, "default" ) != 0 ) { mbedtls_ssl_conf_curves( &conf, curve_list ); } -#endif +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + mbedtls_ssl_conf_signature_algorithms( &conf, sig_alg_list ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -1992,6 +2356,12 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_fallback( &conf, opt.fallback ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, NULL ); + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + strlen( early_data ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", @@ -2027,6 +2397,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_set_verify( &ssl, my_verify, NULL ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ + io_ctx.ssl = &ssl; io_ctx.net = &server_fd; mbedtls_ssl_set_bio( &ssl, &io_ctx, send_cb, recv_cb, @@ -2152,7 +2523,9 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) - if( opt.eap_tls != 0 ) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( opt.eap_tls != 0 ) { size_t j = 0; @@ -2201,6 +2574,8 @@ int main( int argc, char *argv[] ) } mbedtls_printf("\n"); } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -2269,61 +2644,11 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_DTLS_SRTP */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ - if( opt.reconnect != 0 ) - { - mbedtls_printf(" . Saving session for reuse..." ); - fflush( stdout ); - - if( opt.reco_mode == 1 ) - { - /* free any previously saved data */ - if( session_data != NULL ) - { - mbedtls_platform_zeroize( session_data, session_data_len ); - mbedtls_free( session_data ); - session_data = NULL; - } - - /* get size of the buffer needed */ - mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), - NULL, 0, &session_data_len ); - session_data = mbedtls_calloc( 1, session_data_len ); - if( session_data == NULL ) - { - mbedtls_printf( " failed\n ! alloc %u bytes for session data\n", - (unsigned) session_data_len ); - ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; - goto exit; - } - - /* actually save session data */ - if( ( ret = mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), - session_data, session_data_len, - &session_data_len ) ) != 0 ) - { - mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n", - (unsigned int) -ret ); - goto exit; - } - } - else - { - if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 ) - { - mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n", - (unsigned int) -ret ); - goto exit; - } - } - mbedtls_printf( " ok\n" ); - - if( opt.reco_mode == 1 ) - { - mbedtls_printf( " [ Saved %u bytes of session data]\n", - (unsigned) session_data_len ); - } - } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_printf( "early data status = %d\n", mbedtls_ssl_get_early_data_status( &ssl ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ #if defined(MBEDTLS_X509_CRT_PARSE_C) /* @@ -2481,6 +2806,17 @@ int main( int argc, char *argv[] ) written += ret; } while( written < len ); + + while( ( ret = mbedtls_ssl_flush_output( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_flush_output returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } } else /* Not stream, so datagram */ { @@ -2587,7 +2923,23 @@ int main( int argc, char *argv[] ) mbedtls_printf( " connection was reset by peer\n" ); ret = 0; goto reconnect; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + case MBEDTLS_ERR_SSL_CONN_EOF: + mbedtls_printf( " connnection eof \n" ); + ret = 0; + goto close_notify; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: + /* We were waiting for application data but got a NewSessionTicket instead. */ + mbedtls_printf( " got ticket.\n" ); + continue; + +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ default: mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret ); @@ -2665,6 +3017,64 @@ int main( int argc, char *argv[] ) ret = 0; } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + if( opt.reconnect != 0 ) + { + mbedtls_printf(" . Saving session for reuse..." ); + fflush( stdout ); + + if( opt.reco_mode == 1 ) + { + /* free any previously saved data */ + if( session_data != NULL ) + { + mbedtls_platform_zeroize( session_data, session_data_len ); + mbedtls_free( session_data ); + session_data = NULL; + } + + /* get size of the buffer needed */ + mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), + NULL, 0, &session_data_len ); + session_data = mbedtls_calloc( 1, session_data_len ); + if( session_data == NULL ) + { + mbedtls_printf( " failed\n ! alloc %u bytes for session data\n", + (unsigned) session_data_len ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + + /* actually save session data */ + if( ( ret = mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), + session_data, session_data_len, + &session_data_len ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n", + (unsigned int) -ret ); + goto exit; + } + } + else + { + if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } + + mbedtls_printf( " ok\n" ); + + if( opt.reco_mode == 1 ) + { + mbedtls_printf( " [ Saved %u bytes of session data]\n", + (unsigned) session_data_len ); + } + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + /* * 7b. Simulate hard reset and reconnect from same port? */ @@ -2898,6 +3308,7 @@ int main( int argc, char *argv[] ) * 9. Reconnect? */ reconnect: +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) if( opt.reconnect != 0 ) { --opt.reconnect; @@ -2941,6 +3352,23 @@ int main( int argc, char *argv[] ) goto exit; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + // Configure key exchange mode to use PSK-ECDHE + if( ( ret = mbedtls_ssl_conf_tls13_key_exchange( &conf, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_conf_tls13_key_exchange returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + strlen( early_data ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + + if( ( ret = mbedtls_net_connect( &server_fd, opt.server_addr, opt.server_port, opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? @@ -2976,8 +3404,15 @@ int main( int argc, char *argv[] ) mbedtls_printf( " ok\n" ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_printf( "early data status, reconnect = %d\n", + mbedtls_ssl_get_early_data_status( &ssl ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + goto send_request; } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ /* * Cleanup and exit @@ -2988,7 +3423,7 @@ int main( int argc, char *argv[] ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); - mbedtls_printf("Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf ); + mbedtls_printf( "Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf ); } #endif diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 6169a377497f..4c2b1f8a8198 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -47,7 +47,7 @@ int main( void ) #include "mbedtls/ssl_cache.h" #endif -#if defined(MBEDTLS_SSL_TICKET_C) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) #include "mbedtls/ssl_ticket.h" #endif @@ -143,6 +143,14 @@ int main( void ) #define DFL_REPRODUCIBLE 0 #define DFL_NSS_KEYLOG 0 #define DFL_NSS_KEYLOG_FILE NULL +#define DFL_SIG_ALGS NULL + +#define DFL_KEY_EXCHANGE_MODES MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL +#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED +#define MAX_NAMED_GROUPS 4 +#define DFL_TICKET_FLAGS 7 /* allow everything */ +#define DFL_TICKET_LIFETIME MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME +#define DFL_RETURN_ROUTABILITY MBEDTLS_SSL_RETURN_ROUTABILITY_DISABLED #define DFL_QUERY_CONFIG_MODE 0 #define DFL_USE_SRTP 0 #define DFL_SRTP_FORCE_PROFILE 0 @@ -234,15 +242,19 @@ int main( void ) #define USAGE_CID "" #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEX_MODES \ + " key_exchange_modes=%%s default: all\n" \ + " options: psk, psk_dhe, ecdhe_ecdsa, psk_all, all\n" +#else +#define USAGE_KEX_MODES "" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #define USAGE_PSK_RAW \ - " psk=%%s default: \"\" (disabled)\n" \ - " The PSK values are in hex, without 0x.\n" \ - " psk_list=%%s default: \"\"\n" \ - " A list of (PSK identity, PSK value) pairs.\n" \ - " The PSK values are in hex, without 0x.\n" \ - " id1,psk1[,id2,psk2[,...]]\n" \ - " psk_identity=%%s default: \"Client_identity\"\n" + " psk=%%s default: \"\" (disabled)\n" \ + " The PSK values are in hex, without 0x.\n" \ + " psk_identity=%%s default: \"Client_identity\"\n" #if defined(MBEDTLS_USE_PSA_CRYPTO) #define USAGE_PSK_SLOT \ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \ @@ -277,17 +289,21 @@ int main( void ) #else #define USAGE_CA_CALLBACK "" #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) #define USAGE_TICKETS \ " tickets=%%d default: 1 (enabled)\n" \ " ticket_timeout=%%d default: 86400 (one day)\n" #else #define USAGE_TICKETS "" -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_EAP_TLS "" +#else #define USAGE_EAP_TLS \ " eap_tls=%%d default: 0 (disabled)\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #define USAGE_NSS_KEYLOG \ " nss_keylog=%%d default: 0 (disabled)\n" \ " This cannot be used with eap_tls=1\n" @@ -364,13 +380,23 @@ int main( void ) #define USAGE_ALPN "" #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) +#define USAGE_COOKIES \ + " cookies=0/1/2/-1 default: 1\n" \ + " 0: disabled, 1: enabled, 2: force return-routability check, -1: library broken\n" +#else +#define USAGE_COOKIES "" +#endif /* MBEDTLS_SSL_COOKIE_C */ +#else #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) #define USAGE_COOKIES \ " cookies=0/1/-1 default: 1 (enabled)\n" \ " 0: disabled, -1: library default (broken)\n" #else #define USAGE_COOKIES "" -#endif +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) #define USAGE_ANTI_REPLAY \ @@ -433,6 +459,24 @@ int main( void ) #define USAGE_ECJPAKE "" #endif +#if defined(MBEDTLS_ZERO_RTT) +#define USAGE_EARLY_DATA \ + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), " \ + " -1 (enabled, unlimited), " \ + " n > 0 (enabled, max. number of bytes sent as 0-RTT = n)\n" +#else +#define USAGE_EARLY_DATA "" +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) +#define USAGE_NAMED_GROUP \ + " named_groups=%%s default: secp256r1, secp384r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_NAMED_GROUP "" +#endif + #if defined(MBEDTLS_ECP_C) #define USAGE_CURVES \ " curves=a,b,c,d default: \"default\" (library default)\n" \ @@ -444,6 +488,14 @@ int main( void ) #define USAGE_CURVES "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) +#define USAGE_SIG_ALGS \ + " sig_algs=a,b,c,d default: \"default\" (library default: ecdsa_secp256r1_sha256)\n" \ + " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n" +#else +#define USAGE_SIG_ALGS "" +#endif + #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) #define USAGE_SERIALIZATION \ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ @@ -512,7 +564,11 @@ int main( void ) USAGE_ALPN \ USAGE_EMS \ USAGE_ETM \ + USAGE_EARLY_DATA \ + USAGE_KEX_MODES \ + USAGE_NAMED_GROUP \ USAGE_CURVES \ + USAGE_SIG_ALGS \ "\n" #define USAGE4 \ USAGE_SSL_ASYNC \ @@ -535,8 +591,29 @@ int main( void ) USAGE_SERIALIZATION \ " acceptable ciphersuite names:\n" +#define USAGE5 \ + " arc4=%%d default: (library default: 0)\n" \ + " allow_sha1=%%d default: 0\n" \ + " min_version=%%s default: (library default: tls1)\n" \ + " max_version=%%s default: (library default: tls1_3)\n" \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, tls1_3, dtls1, dtls1_2, dtls1_3\n" \ + "\n" \ + " version_suites=a,b,c,d,e per-version ciphersuites\n" \ + " in order from ssl3 to tls1_3\n" \ + " default: all enabled\n" \ + " force_ciphersuite= default: all enabled\n" \ + " query_config= return 0 if the specified\n" \ + " configuration macro is defined and 1\n" \ + " otherwise. The expansion of the macro\n" \ + " is printed if it is defined\n" \ + USAGE_SERIALIZATION \ + " acceptable ciphersuite names:\n" + #define ALPN_LIST_SIZE 10 #define CURVE_LIST_SIZE 20 +#define SIG_ALG_LIST_SIZE 5 +#define NAMED_GROUPS_LIST_SIZE 5 #define PUT_UINT64_BE(out_be,in_le,i) \ { \ @@ -606,6 +683,9 @@ struct options int trunc_hmac; /* accept truncated hmac? */ int tickets; /* enable / disable session tickets */ int ticket_timeout; /* session ticket lifetime */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + mbedtls_ssl_ticket_flags ticket_flags; /* ticket flags */ +#endif int cache_max; /* max number of session cache entries */ #if defined(MBEDTLS_HAVE_TIME) int cache_timeout; /* expiration delay of session cache entries*/ @@ -638,6 +718,11 @@ struct options const char *cid_val_renego; /* the CID to use for incoming messages * after renegotiation */ int reproducible; /* make communication reproducible */ + unsigned char key_exchange_modes; /* key exchange modes */ + int early_data; /* support for early data */ + int early_data_max; /* maximum amount of early data */ + const char *named_groups_string; /* list of named groups */ + const char *sig_algs; /* supported signature algorithms */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -949,6 +1034,28 @@ int psk_callback( void *p_info, mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_ZERO_RTT) +/* +* Early data callback. +*/ +int early_data_callback( mbedtls_ssl_context *ssl, + const unsigned char *buffer, size_t len ) +{ + // In this example we don't need access to the SSL structure + ((void) ssl); + char *buffer_to_print; + if( len > 0 && buffer != NULL ) + { + buffer_to_print = mbedtls_calloc( 1, len + 1 ); + memcpy( buffer_to_print, buffer, len ); + buffer_to_print[len] = '\0'; + mbedtls_printf( " %zu bytes early data received: %s\n", len, buffer_to_print ); + mbedtls_free( buffer_to_print ); + } + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + static mbedtls_net_context listen_fd, client_fd; /* Interruption handler to ensure clean exit (for valgrind testing) */ @@ -1300,6 +1407,14 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_COOKIE_C) mbedtls_ssl_cookie_ctx cookie_ctx; #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + /* list of named groups */ + mbedtls_ecp_group_id named_groups_list[NAMED_GROUPS_LIST_SIZE]; + /* list of signature algorithms */ + int sig_alg_list[SIG_ALG_LIST_SIZE]; + char *start; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_x509_crt_profile crt_profile_for_test = mbedtls_x509_crt_profile_default; @@ -1335,7 +1450,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context cache; #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) mbedtls_ssl_ticket_context ticket_ctx; #endif #if defined(SNI_OPTION) @@ -1351,6 +1466,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) unsigned char alloc_buf[MEMORY_HEAP_SIZE]; #endif + #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) unsigned char cid[MBEDTLS_SSL_CID_IN_LEN_MAX]; unsigned char cid_renego[MBEDTLS_SSL_CID_IN_LEN_MAX]; @@ -1369,10 +1485,14 @@ int main( int argc, char *argv[] ) psa_status_t status; #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) unsigned char eap_tls_keymaterial[16]; unsigned char eap_tls_iv[8]; const char* eap_tls_label = "client EAP encryption"; eap_tls_keys eap_tls_keying; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) /*! master keys and master salt for SRTP generated during handshake */ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; @@ -1423,12 +1543,16 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_init( &cache ); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) mbedtls_ssl_ticket_init( &ticket_ctx ); #endif #if defined(MBEDTLS_SSL_ALPN) memset( (void *) alpn_list, 0, sizeof( alpn_list ) ); #endif +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + memset((void *)named_groups_list, MBEDTLS_ECP_DP_NONE, sizeof(named_groups_list)); +#endif + #if defined(MBEDTLS_SSL_COOKIE_C) mbedtls_ssl_cookie_init( &cookie_ctx ); #endif @@ -1462,7 +1586,11 @@ int main( int argc, char *argv[] ) mbedtls_printf( USAGE1 ); mbedtls_printf( USAGE2 ); mbedtls_printf( USAGE3 ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( USAGE5 ); +#else mbedtls_printf( USAGE4 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ list = mbedtls_ssl_list_ciphersuites(); while( *list ) @@ -1504,6 +1632,12 @@ int main( int argc, char *argv[] ) opt.async_private_delay2 = DFL_ASYNC_PRIVATE_DELAY2; opt.async_private_error = DFL_ASYNC_PRIVATE_ERROR; opt.psk = DFL_PSK; + opt.key_exchange_modes = DFL_KEY_EXCHANGE_MODES; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + opt.ticket_flags = DFL_TICKET_FLAGS; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + opt.early_data = DFL_EARLY_DATA; + opt.sig_algs = DFL_SIG_ALGS; #if defined(MBEDTLS_USE_PSA_CRYPTO) opt.psk_opaque = DFL_PSK_OPAQUE; opt.psk_list_opaque = DFL_PSK_LIST_OPAQUE; @@ -1761,6 +1895,47 @@ int main( int argc, char *argv[] ) if( opt.exchanges < 0 ) goto usage; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ZERO_RTT) + else if( strcmp( p, "early_data" ) == 0 ) + { + int early_data_val = atoi( q ); + switch( early_data_val ) + { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + default: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + opt.early_data_max = (size_t) early_data_val; + break; + } + } +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) + else if( strcmp( p, "named_groups" ) == 0 ) + opt.named_groups_string = q; + else if( strcmp( p, "sig_algs" ) == 0 ) + opt.sig_algs = q; +#endif /* MBEDTLS_ECP_C */ + + else if( strcmp( p, "key_exchange_modes" ) == 0 ) + { + if( strcmp( q, "psk" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + else if( strcmp(q, "psk_dhe" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + else if( strcmp(q, "ecdhe_ecdsa" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA; + else if( strcmp( q, "psk_all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL; + else if( strcmp( q, "all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL; + else goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( p, "min_version" ) == 0 ) { if( strcmp( q, "ssl3" ) == 0 ) @@ -1773,6 +1948,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1788,6 +1968,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1831,6 +2016,13 @@ int main( int argc, char *argv[] ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( q, "dtls1" ) == 0 ) { opt.min_version = MBEDTLS_SSL_MINOR_VERSION_2; @@ -1843,6 +2035,14 @@ int main( int argc, char *argv[] ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "dtls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1917,6 +2117,16 @@ int main( int argc, char *argv[] ) if( opt.ticket_timeout < 0 ) goto usage; } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + else if( strcmp( p, "ticket_flags" ) == 0 ) + { + mbedtls_ssl_ticket_flags temp = atoi( q ); + if( ( temp & ( mbedtls_ssl_ticket_flags ) allow_early_data ) || ( temp & ( mbedtls_ssl_ticket_flags ) allow_dhe_resumption ) || ( temp & ( mbedtls_ssl_ticket_flags ) allow_psk_resumption ) ) + { + opt.ticket_flags = temp & ( mbedtls_ssl_ticket_flags ) allow_early_data & ( mbedtls_ssl_ticket_flags ) allow_dhe_resumption & ( mbedtls_ssl_ticket_flags ) allow_psk_resumption; + } else goto usage; + } +#endif else if( strcmp( p, "cache_max" ) == 0 ) { opt.cache_max = atoi( q ); @@ -1934,8 +2144,13 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "cookies" ) == 0 ) { opt.cookies = atoi( q ); - if( opt.cookies < -1 || opt.cookies > 1) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( opt.cookies < -1 || opt.cookies > 2 ) + goto usage; +#else + if( opt.cookies < -1 || opt.cookies > 1 ) goto usage; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } else if( strcmp( p, "anti_replay" ) == 0 ) { @@ -1996,9 +2211,14 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "eap_tls" ) == 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( "Error: eap_tls is not supported in TLS 1.3.\n" ); + goto usage; +#else opt.eap_tls = atoi( q ); if( opt.eap_tls < 0 || opt.eap_tls > 1 ) goto usage; +#endif } else if( strcmp( p, "reproducible" ) == 0 ) { @@ -2217,7 +2437,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) if( mbedtls_test_unhexify( cid, sizeof( cid ), - opt.cid_val, &cid_len ) != 0 ) + opt.cid_val, &cid_len ) != 0 ) { mbedtls_printf( "CID not valid hex\n" ); goto exit; @@ -2231,7 +2451,7 @@ int main( int argc, char *argv[] ) opt.cid_val_renego = opt.cid_val; if( mbedtls_test_unhexify( cid_renego, sizeof( cid_renego ), - opt.cid_val_renego, &cid_renego_len ) != 0 ) + opt.cid_val_renego, &cid_renego_len ) != 0 ) { mbedtls_printf( "CID not valid hex\n" ); goto exit; @@ -2243,7 +2463,7 @@ int main( int argc, char *argv[] ) * Unhexify the pre-shared key and parse the list if any given */ if( mbedtls_test_unhexify( psk, sizeof( psk ), - opt.psk, &psk_len ) != 0 ) + opt.psk, &psk_len ) != 0 ) { mbedtls_printf( "pre-shared key not valid hex\n" ); goto exit; @@ -2315,6 +2535,70 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_ECP_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + p = (char *) opt.sig_algs; + i = 0; + + /* Leave room for a final NULL in signature algorithm list */ + while( i < SIG_ALG_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( q, "ecdsa_secp256r1_sha256" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP256r1_SHA256; + } + else if( strcmp( q, "ecdsa_secp384r1_sha384" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP384r1_SHA384; + } + else if( strcmp( q, "ecdsa_secp521r1_sha512" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP521r1_SHA512; + } + else + { + mbedtls_printf( "unknown signature algorithm %s\n", q ); + mbedtls_printf( "supported signature algorithms: " ); +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + mbedtls_printf( "ecdsa_secp256r1_sha256 " ); +#endif +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + mbedtls_printf( "ecdsa_secp384r1_sha384 " ); +#endif +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + mbedtls_printf( "ecdsa_secp521r1_sha512 " ); +#endif + mbedtls_printf( "\n" ); + goto exit; + } + } + + if( i == ( SIG_ALG_LIST_SIZE - 1 ) && *p != '\0' ) + { + mbedtls_printf( "signature algorithm list too long, maximum %d", + SIG_ALG_LIST_SIZE - 1 ); + goto exit; + } + + sig_alg_list[i] = SIGNATURE_NONE; + } + else + { + /* Configure default signature algorithm */ + sig_alg_list[0] = SIGNATURE_ECDSA_SECP256r1_SHA256; + sig_alg_list[1] = SIGNATURE_NONE; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_SSL_ALPN) if( opt.alpn_string != NULL ) { @@ -2335,6 +2619,54 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_ALPN */ + #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.named_groups_string != NULL ) + { + p = (char *)opt.named_groups_string; + i = 0; + start = p; + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' ) + *p++ = '\0'; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + } + else goto usage; + } + + if( i == 0 ) goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + + /* * 0. Initialize the RNG and the session data */ @@ -2619,7 +2951,11 @@ int main( int argc, char *argv[] ) { crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ); mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test ); + + /* TODO: Check if/why this guard is needed. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test ); +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ } #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -2629,6 +2965,12 @@ int main( int argc, char *argv[] ) if( opt.cert_req_ca_list != DFL_CERT_REQ_CA_LIST ) mbedtls_ssl_conf_cert_req_ca_list( &conf, opt.cert_req_ca_list ); +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_conf_early_data( &conf, opt.early_data, + opt.early_data_max, + early_data_callback ); +#endif /* MBEDTLS_ZERO_RTT */ + #if defined(MBEDTLS_SSL_PROTO_DTLS) if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX ) mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max ); @@ -2720,16 +3062,32 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, &eap_tls_keying ); } - else if( opt.nss_keylog != 0 ) + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + if( opt.nss_keylog != 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_conf_export_secrets_cb( &conf, + nss_keylog_export_tls13, + NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_conf_export_keys_ext_cb( &conf, nss_keylog_export, NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ } #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -2749,6 +3107,11 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_curves( &conf, named_groups_list ); +#endif + if (opt.reproducible) { #if defined(MBEDTLS_HAVE_TIME) @@ -2775,8 +3138,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_cache_get, mbedtls_ssl_cache_set ); #endif - -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) if( opt.tickets == MBEDTLS_SSL_SESSION_TICKETS_ENABLED ) { if( ( ret = mbedtls_ssl_ticket_setup( &ticket_ctx, @@ -2792,9 +3154,49 @@ int main( int argc, char *argv[] ) mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, &ticket_ctx ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Enable use of tickets */ + mbedtls_ssl_conf_session_tickets( &conf, opt.tickets ); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + } -#endif +#endif /* MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) + if( opt.cookies > 0 ) + { + if( ( ret = mbedtls_ssl_cookie_setup( &cookie_ctx, + mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret ); + goto exit; + } + + if( opt.cookies == 1 ) + { + mbedtls_ssl_conf_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &cookie_ctx, MBEDTLS_SSL_FORCE_RR_CHECK_OFF ); + } + + if( opt.cookies == 2 ) + { + mbedtls_ssl_conf_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &cookie_ctx, MBEDTLS_SSL_FORCE_RR_CHECK_ON ); + } + } + else if( opt.cookies == 0 ) // cookie support disabled + { + mbedtls_ssl_conf_cookies( &conf, NULL, NULL, NULL, MBEDTLS_SSL_FORCE_RR_CHECK_OFF ); + } + else +#endif /* MBEDTLS_SSL_COOKIE_C */ + { + ; /* Nothing to do */ + } +#else #if defined(MBEDTLS_SSL_PROTO_DTLS) if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -2807,9 +3209,10 @@ int main( int argc, char *argv[] ) mbedtls_printf( " failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret ); goto exit; } - +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ } else #endif /* MBEDTLS_SSL_COOKIE_C */ @@ -2835,6 +3238,7 @@ int main( int argc, char *argv[] ) #endif } #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite ); @@ -2993,12 +3397,25 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure default name groups */ + if (named_groups_list[0] != MBEDTLS_ECP_DP_NONE) + mbedtls_ssl_conf_curves( &conf, named_groups_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* Configure default curves */ if( opt.curves != NULL && strcmp( opt.curves, "default" ) != 0 ) { mbedtls_ssl_conf_curves( &conf, curve_list ); } -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure default signature algorithms */ + if( opt.sig_algs != NULL && strcmp( opt.sig_algs, "default" ) != 0 ) + { + mbedtls_ssl_conf_signature_algorithms( &conf, sig_alg_list ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -3064,6 +3481,11 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure supported TLS 1.3 key exchange modes. */ + mbedtls_ssl_conf_tls13_key_exchange( &conf, opt.key_exchange_modes ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_DHM_C) /* * Use different group than default DHM group @@ -3188,6 +3610,17 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_read_timeout( &conf, opt.read_timeout ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) + if( ( ret = mbedtls_ssl_set_client_transport_id( &ssl, + client_ip, cliip_len ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } +#endif /* MBEDTLS_SSL_COOKIE_C */ +#else /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -3200,6 +3633,7 @@ int main( int argc, char *argv[] ) } } #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( opt.ecjpake_pw != DFL_ECJPAKE_PW ) @@ -3285,6 +3719,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_get_version( &ssl ), mbedtls_ssl_get_ciphersuite( &ssl ) ); } + if( ( ret = mbedtls_ssl_get_record_expansion( &ssl ) ) >= 0 ) mbedtls_printf( " [ Record expansion is %d ]\n", ret ); else @@ -3337,6 +3772,8 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { size_t j = 0; @@ -3386,6 +3823,8 @@ int main( int argc, char *argv[] ) } mbedtls_printf("\n"); } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -3617,8 +4056,8 @@ int main( int argc, char *argv[] ) */ /* For event-driven IO, wait for socket to become available */ - if( mbedtls_ssl_check_pending( &ssl ) == 0 && - opt.event == 1 /* level triggered IO */ ) + if( opt.event == 1 /* level triggered IO */ && + mbedtls_ssl_check_pending( &ssl ) == 0 ) { #if defined(MBEDTLS_TIMING_C) idle( &client_fd, &timer, MBEDTLS_ERR_SSL_WANT_READ ); @@ -3756,6 +4195,17 @@ int main( int argc, char *argv[] ) } } } + + while( ( ret = mbedtls_ssl_flush_output( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_flush_output returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } } else /* Not stream, so datagram */ { diff --git a/tests/Makefile b/tests/Makefile index 6e232c974eae..c0e371908578 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -74,6 +74,8 @@ endif # constructed by stripping path 'suites/' and extension .data. APPS = $(basename $(subst suites/,,$(wildcard suites/test_suite_*.data))) +# remove test_suite_ssl build from TLS1.3 tests + # Construct executable name by adding OS specific suffix $(EXEXT). BINARIES := $(addsuffix $(EXEXT),$(APPS)) diff --git a/tests/compat.sh b/tests/compat.sh index 560af59d6e57..24497eae57df 100755 --- a/tests/compat.sh +++ b/tests/compat.sh @@ -177,6 +177,9 @@ minor_ver() tls12|dtls12) echo 3 ;; + tls1_3) + echo 4 + ;; *) echo "error: invalid mode: $MODE" >&2 # exiting is no good here, typically called in a subshell @@ -195,6 +198,11 @@ filter() EXCLMODE="$EXCLUDE" fi + if [ `minor_ver "$MODE"` -ge 4 ] + then + EXCLMODE="$EXCLUDE"'\|RC4\|ARCFOUR' + fi + for i in $LIST; do NEW_LIST="$NEW_LIST $( echo "$i" | grep "$FILTER" | grep -v "$EXCLMODE" )" @@ -295,7 +303,7 @@ add_common_ciphersuites() ECDHE-ECDSA-AES128-GCM-SHA256 \ ECDHE-ECDSA-AES256-GCM-SHA384 \ " - fi + fi ;; "RSA") @@ -494,7 +502,7 @@ add_openssl_ciphersuites() ECDHE-ECDSA-ARIA128-GCM-SHA256 \ ECDHE-ECDSA-CHACHA20-POLY1305 \ " - fi + fi ;; "RSA") @@ -879,6 +887,9 @@ setup_arguments() O_MODE="tls1_2" G_PRIO_MODE="+VERS-TLS1.2" ;; + "tls1_3") + G_PRIO_MODE="+VERS-TLS1.3" + ;; "dtls1") G_PRIO_MODE="+VERS-DTLS1.0" G_MODE="-u" @@ -903,7 +914,19 @@ setup_arguments() M_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE arc4=1" O_SERVER_ARGS="-accept $PORT -cipher NULL,ALL -$O_MODE" G_SERVER_ARGS="-p $PORT --http $G_MODE" - G_SERVER_PRIO="NORMAL:${G_PRIO_CCM}+ARCFOUR-128:+NULL:+MD5:+PSK:+DHE-PSK:+ECDHE-PSK:+SHA256:+SHA384:+RSA-PSK:-VERS-TLS-ALL:$G_PRIO_MODE" + + # The default prime for `openssl s_server` depends on the version: + # * OpenSSL <= 1.0.2a: 512-bit + # * OpenSSL 1.0.2b to 1.1.1b: 1024-bit + # * OpenSSL >= 1.1.1c: 2048-bit + # Mbed TLS wants >=1024, so force that for older versions. Don't force + # it for newer versions, which reject a 1024-bit prime. Indifferently + # force it or not for intermediate versions. + case $($OPENSSL_CMD version) in + "OpenSSL 1.0"*) + O_SERVER_ARGS="$O_SERVER_ARGS -dhparam data_files/dhparams.pem" + ;; + esac # The default prime for `openssl s_server` depends on the version: # * OpenSSL <= 1.0.2a: 512-bit @@ -1131,7 +1154,12 @@ run_client() { # run the command and interpret result case $1 in [Oo]pen*) - CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -cipher $2" + if [ `minor_ver "$MODE"` -ge 4 ] + then + CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -ciphersuites $2" + else + CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -cipher $2" + fi log "$CLIENT_CMD" echo "$CLIENT_CMD" > $CLI_OUT printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & @@ -1156,7 +1184,15 @@ run_client() { else G_HOST="localhost" fi - CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 $G_HOST" + + if [ `minor_ver "$MODE"` -ge 4 ] + then + G_CLIENT_PRIO="NONE:${2}:+GROUP-SECP256R1:+GROUP-SECP384R1:+CTYPE-ALL:+ECDHE-ECDSA:+CIPHER-ALL:+MAC-ALL:-SHA1:-AES-128-CBC:+SIGN-ECDSA-SECP256R1-SHA256:+SIGN-ECDSA-SECP384R1-SHA384:+ECDHE-ECDSA:${G_PRIO_MODE}" + CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_CLIENT_PRIO $G_HOST" + else + CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 $G_HOST" + fi + log "$CLIENT_CMD" echo "$CLIENT_CMD" > $CLI_OUT printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & @@ -1335,8 +1371,26 @@ for VERIFY in $VERIFIES; do fi reset_ciphersuites - add_common_ciphersuites - add_openssl_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS1-3-AES-128-GCM-SHA256 \ + TLS1-3-AES-256-GCM-SHA384 \ + TLS1-3-AES-128-CCM-SHA256 \ + TLS1-3-AES-128-CCM-8-SHA256 \ + TLS1-3-CHACHA20-POLY1305-SHA256 \ + " + O_CIPHERS="$O_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + else + add_common_ciphersuites + add_openssl_ciphersuites + fi filter_ciphersuites if [ "X" != "X$M_CIPHERS" ]; then @@ -1361,10 +1415,29 @@ for VERIFY in $VERIFIES; do [Gg]nu*) reset_ciphersuites - add_common_ciphersuites - add_gnutls_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS1-3-AES-128-GCM-SHA256 \ + TLS1-3-AES-256-GCM-SHA384 \ + TLS1-3-AES-128-CCM-SHA256 \ + TLS1-3-AES-128-CCM-8-SHA256 \ + TLS1-3-CHACHA20-POLY1305-SHA256 \ + " + G_CIPHERS="$G_CIPHERS \ + +AES-128-GCM:+SHA256 \ + +AES-256-GCM:+SHA384 \ + +AES-128-CCM:+SHA256 \ + +AES-128-CCM-8:+SHA256 \ + +CHACHA20-POLY1305:+SHA256 \ + " + else + add_common_ciphersuites + add_gnutls_ciphersuites + fi filter_ciphersuites + if [ "X" != "X$M_CIPHERS" ]; then start_server "GnuTLS" for i in $M_CIPHERS; do @@ -1380,16 +1453,33 @@ for VERIFY in $VERIFIES; do done stop_server fi - ;; mbed*) reset_ciphersuites - add_common_ciphersuites - add_openssl_ciphersuites - add_gnutls_ciphersuites - add_mbedtls_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + O_CIPHERS="$O_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + else + add_common_ciphersuites + add_openssl_ciphersuites + add_gnutls_ciphersuites + add_mbedtls_ciphersuites + fi filter_ciphersuites if [ "X" != "X$M_CIPHERS" ]; then diff --git a/tests/dtls13.bash b/tests/dtls13.bash new file mode 100644 index 000000000000..b5d1c4eaacb8 --- /dev/null +++ b/tests/dtls13.bash @@ -0,0 +1,1106 @@ +#!/bin/sh + +# Test various options that are not covered by compat.sh +# +# Here the goal is not to cover every ciphersuite/version, but +# rather specific options (max fragment length, truncated hmac, etc) +# or procedures (session resumption from cache or ticket, renego, etc). +# +# Assumes a build with default options. + +set -u + +# default values, can be overriden by the environment +if [ "$OS" = "Windows_NT" ]; then +: ${P_SRV:=../visualc/VS2010/Debug/ssl_server2.exe} +: ${P_CLI:=../visualc/VS2010/Debug/ssl_client2.exe} +: ${P_PXY:=../visualc/VS2010/Debug/udp_proxy.exe} +#: ${P_SRV:=../programs/ssl/ssl_server2.exe} +#: ${P_CLI:=../programs/ssl/ssl_client2.exe} +#: ${P_PXY:=../programs/test/udp_proxy.exe} +else +: ${P_SRV:=../programs/ssl/ssl_server2} +: ${P_CLI:=../programs/ssl/ssl_client2} +: ${P_PXY:=../programs/test/udp_proxy} +fi +: ${OPENSSL_CMD:=openssl} # OPENSSL would conflict with the build system +: ${GNUTLS_CLI:=gnutls-cli} +: ${GNUTLS_SERV:=gnutls-serv} +: ${MBEDTLS_DEBUG_LEVEL:=debug_level=5} + +O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key" +O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client" +G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key" +G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt" + + + +TESTS=0 +FAILS=0 +SKIPS=0 + +CONFIG_H='../include/mbedtls/config.h' + +MEMCHECK=0 +FILTER='.*' +EXCLUDE='^$' + +print_usage() { + echo "Usage: $0 [options]" + printf " -h|--help\tPrint this help.\n" + printf " -m|--memcheck\tCheck memory leaks and errors.\n" + printf " -f|--filter\tOnly matching tests are executed (default: '$FILTER')\n" + printf " -e|--exclude\tMatching tests are excluded (default: '$EXCLUDE')\n" +} + +get_options() { + while [ $# -gt 0 ]; do + case "$1" in + -f|--filter) + shift; FILTER=$1 + ;; + -e|--exclude) + shift; EXCLUDE=$1 + ;; + -m|--memcheck) + MEMCHECK=1 + ;; + -h|--help) + print_usage + exit 0 + ;; + *) + echo "Unknown argument: '$1'" + print_usage + exit 1 + ;; + esac + shift + done +} + +# skip next test if the flag is not enabled in config.h +requires_config_enabled() { + if grep "^#define $1" $CONFIG_H > /dev/null; then :; else + SKIP_NEXT="YES" + fi +} + +# skip next test if OpenSSL doesn't support FALLBACK_SCSV +requires_openssl_with_fallback_scsv() { + if [ -z "${OPENSSL_HAS_FBSCSV:-}" ]; then + if $OPENSSL_CMD s_client -help 2>&1 | grep fallback_scsv >/dev/null + then + OPENSSL_HAS_FBSCSV="YES" + else + OPENSSL_HAS_FBSCSV="NO" + fi + fi + if [ "$OPENSSL_HAS_FBSCSV" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if GnuTLS isn't available +requires_gnutls() { + if [ -z "${GNUTLS_AVAILABLE:-}" ]; then + if ( which "$GNUTLS_CLI" && which "$GNUTLS_SERV" ) >/dev/null 2>&1; then + GNUTLS_AVAILABLE="YES" + else + GNUTLS_AVAILABLE="NO" + fi + fi + if [ "$GNUTLS_AVAILABLE" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if IPv6 isn't available on this host +requires_ipv6() { + if [ -z "${HAS_IPV6:-}" ]; then + $P_SRV server_addr='::1' > $SRV_OUT 2>&1 & + SRV_PID=$! + sleep 1 + kill $SRV_PID >/dev/null 2>&1 + if grep "NET - Binding of the socket failed" $SRV_OUT >/dev/null; then + HAS_IPV6="NO" + else + HAS_IPV6="YES" + fi + rm -r $SRV_OUT + fi + + if [ "$HAS_IPV6" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip the next test if valgrind is in use +not_with_valgrind() { + if [ "$MEMCHECK" -gt 0 ]; then + SKIP_NEXT="YES" + fi +} + +# multiply the client timeout delay by the given factor for the next test +needs_more_time() { + CLI_DELAY_FACTOR=$1 +} + +# print_name +print_name() { + printf "$1 " + LEN=$(( 72 - `echo "$1" | wc -c` )) + for i in `seq 1 $LEN`; do printf '.'; done + printf ' ' + + TESTS=$(( $TESTS + 1 )) +} + +# fail +fail() { + echo "FAIL" + echo " ! $1" + + mv $SRV_OUT o-srv-${TESTS}.log + mv $CLI_OUT o-cli-${TESTS}.log + if [ -n "$PXY_CMD" ]; then + mv $PXY_OUT o-pxy-${TESTS}.log + fi + echo " ! outputs saved to o-XXX-${TESTS}.log" + + if [ "X${USER:-}" = Xbuildbot -o "X${LOGNAME:-}" = Xbuildbot ]; then + echo " ! server output:" + cat o-srv-${TESTS}.log + echo " ! ========================================================" + echo " ! client output:" + cat o-cli-${TESTS}.log + if [ -n "$PXY_CMD" ]; then + echo " ! ========================================================" + echo " ! proxy output:" + cat o-pxy-${TESTS}.log + fi + echo "" + fi + + FAILS=$(( $FAILS + 1 )) +} + +# is_polar +is_polar() { + echo "$1" | grep 'ssl_server2\|ssl_client2' > /dev/null +} + +# openssl s_server doesn't have -www with DTLS +check_osrv_dtls() { + if echo "$SRV_CMD" | grep 's_server.*-dtls' >/dev/null; then + NEEDS_INPUT=1 + SRV_CMD="$( echo $SRV_CMD | sed s/-www// )" + else + NEEDS_INPUT=0 + fi +} + +# provide input to commands that need it +provide_input() { + if [ $NEEDS_INPUT -eq 0 ]; then + return + fi + + while true; do + echo "HTTP/1.0 200 OK" + sleep 1 + done +} + +# has_mem_err +has_mem_err() { + if ( grep -F 'All heap blocks were freed -- no leaks are possible' "$1" && + grep -F 'ERROR SUMMARY: 0 errors from 0 contexts' "$1" ) > /dev/null + then + return 1 # false: does not have errors + else + return 0 # true: has errors + fi +} + +# wait for server to start: two versions depending on lsof availability +wait_server_start() { + if which lsof >/dev/null 2>&1; then + START_TIME=$( date +%s ) + DONE=0 + + # make a tight loop, server usually takes less than 1 sec to start + if [ "$DTLS" -eq 1 ]; then + while [ $DONE -eq 0 ]; do + if lsof -nbi UDP:"$SRV_PORT" 2>/dev/null | grep UDP >/dev/null + then + DONE=1 + elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then + echo "SERVERSTART TIMEOUT" + echo "SERVERSTART TIMEOUT" >> $SRV_OUT + DONE=1 + fi + done + else + while [ $DONE -eq 0 ]; do + if lsof -nbi TCP:"$SRV_PORT" 2>/dev/null | grep LISTEN >/dev/null + then + DONE=1 + elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then + echo "SERVERSTART TIMEOUT" + echo "SERVERSTART TIMEOUT" >> $SRV_OUT + DONE=1 + fi + done + fi + else + sleep "$START_DELAY" + fi +} + +# wait for client to terminate and set CLI_EXIT +# must be called right after starting the client +wait_client_done() { + CLI_PID=$! + + CLI_DELAY=$(( $DOG_DELAY * $CLI_DELAY_FACTOR )) + CLI_DELAY_FACTOR=1 + + ( sleep $CLI_DELAY; echo "===CLIENT_TIMEOUT===" >> $CLI_OUT; kill $CLI_PID ) & + DOG_PID=$! + + wait $CLI_PID + CLI_EXIT=$? + + kill $DOG_PID >/dev/null 2>&1 + wait $DOG_PID + + echo "EXIT: $CLI_EXIT" >> $CLI_OUT +} + +# check if the given command uses dtls and sets global variable DTLS +detect_dtls() { + if echo "$1" | grep 'dtls=1\|-dtls1\|-u' >/dev/null; then + DTLS=1 + else + DTLS=0 + fi +} + +# Usage: run_test name [-p proxy_cmd] srv_cmd cli_cmd cli_exit [option [...]] +# Options: -s pattern pattern that must be present in server output +# -c pattern pattern that must be present in client output +# -S pattern pattern that must be absent in server output +# -C pattern pattern that must be absent in client output +run_test() { + NAME="$1" + shift 1 + + if echo "$NAME" | grep "$FILTER" | grep -v "$EXCLUDE" >/dev/null; then : + else + SKIP_NEXT="NO" + return + fi + + print_name "$NAME" + + # should we skip? + if [ "X$SKIP_NEXT" = "XYES" ]; then + SKIP_NEXT="NO" + echo "SKIP" + SKIPS=$(( $SKIPS + 1 )) + return + fi + + # does this test use a proxy? + if [ "X$1" = "X-p" ]; then + PXY_CMD="$2" + shift 2 + else + PXY_CMD="" + fi + + # get commands and client output + SRV_CMD="$1" + CLI_CMD="$2" + CLI_EXPECT="$3" + shift 3 + + # fix client port + if [ -n "$PXY_CMD" ]; then + CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$PXY_PORT/g ) + else + CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$SRV_PORT/g ) + fi + + # update DTLS variable + detect_dtls "$SRV_CMD" + + # prepend valgrind to our commands if active + if [ "$MEMCHECK" -gt 0 ]; then + if is_polar "$SRV_CMD"; then + SRV_CMD="valgrind --leak-check=full $SRV_CMD" + fi + if is_polar "$CLI_CMD"; then + CLI_CMD="valgrind --leak-check=full $CLI_CMD" + fi + fi + + TIMES_LEFT=2 + while [ $TIMES_LEFT -gt 0 ]; do + TIMES_LEFT=$(( $TIMES_LEFT - 1 )) + + # run the commands + if [ -n "$PXY_CMD" ]; then + echo "$PXY_CMD" > $PXY_OUT + $PXY_CMD >> $PXY_OUT 2>&1 & + PXY_PID=$! + # assume proxy starts faster than server + fi + + check_osrv_dtls + echo "$SRV_CMD" > $SRV_OUT + provide_input | $SRV_CMD >> $SRV_OUT 2>&1 & + SRV_PID=$! + wait_server_start + + echo "$CLI_CMD" > $CLI_OUT + eval "$CLI_CMD" >> $CLI_OUT 2>&1 & + wait_client_done + + # terminate the server (and the proxy) + kill $SRV_PID + wait $SRV_PID + if [ -n "$PXY_CMD" ]; then + kill $PXY_PID >/dev/null 2>&1 + wait $PXY_PID + fi + + # retry only on timeouts + if grep '===CLIENT_TIMEOUT===' $CLI_OUT >/dev/null; then + printf "RETRY " + else + TIMES_LEFT=0 + fi + done + + # check if the client and server went at least to the handshake stage + # (useful to avoid tests with only negative assertions and non-zero + # expected client exit to incorrectly succeed in case of catastrophic + # failure) + if is_polar "$SRV_CMD"; then + if grep "Performing the SSL/TLS handshake" $SRV_OUT >/dev/null; then :; + else + fail "server or client failed to reach handshake stage" + return + fi + fi + if is_polar "$CLI_CMD"; then + if grep "Performing the SSL/TLS handshake" $CLI_OUT >/dev/null; then :; + else + fail "server or client failed to reach handshake stage" + return + fi + fi + + # check server exit code + if [ $? != 0 ]; then + fail "server fail" + return + fi + + # check client exit code + if [ \( "$CLI_EXPECT" = 0 -a "$CLI_EXIT" != 0 \) -o \ + \( "$CLI_EXPECT" != 0 -a "$CLI_EXIT" = 0 \) ] + then + fail "bad client exit code (expected $CLI_EXPECT, got $CLI_EXIT)" + return + fi + + # check other assertions + # lines beginning with == are added by valgrind, ignore them + while [ $# -gt 0 ] + do + case $1 in + "-s") + if grep -v '^==' $SRV_OUT | grep "$2" >/dev/null; then :; else + fail "-s $2" + return + fi + ;; + + "-c") + if grep -v '^==' $CLI_OUT | grep "$2" >/dev/null; then :; else + fail "-c $2" + return + fi + ;; + + "-S") + if grep -v '^==' $SRV_OUT | grep "$2" >/dev/null; then + fail "-S $2" + return + fi + ;; + + "-C") + if grep -v '^==' $CLI_OUT | grep "$2" >/dev/null; then + fail "-C $2" + return + fi + ;; + + *) + echo "Unknown test: $1" >&2 + exit 1 + esac + shift 2 + done + + # check valgrind's results + if [ "$MEMCHECK" -gt 0 ]; then + if is_polar "$SRV_CMD" && has_mem_err $SRV_OUT; then + fail "Server has memory errors" + return + fi + if is_polar "$CLI_CMD" && has_mem_err $CLI_OUT; then + fail "Client has memory errors" + return + fi + fi + + # if we're here, everything is ok + echo "PASS" + rm -f $SRV_OUT $CLI_OUT $PXY_OUT +} + +cleanup() { + rm -f $CLI_OUT $SRV_OUT $PXY_OUT $SESSION + test -n "${SRV_PID:-}" && kill $SRV_PID >/dev/null 2>&1 + test -n "${PXY_PID:-}" && kill $PXY_PID >/dev/null 2>&1 + test -n "${CLI_PID:-}" && kill $CLI_PID >/dev/null 2>&1 + test -n "${DOG_PID:-}" && kill $DOG_PID >/dev/null 2>&1 + exit 1 +} + +# +# MAIN +# + +if cd $( dirname $0 ); then :; else + echo "cd $( dirname $0 ) failed" >&2 + exit 1 +fi + +get_options "$@" + +# sanity checks, avoid an avalanche of errors +if [ ! -x "$P_SRV" ]; then + echo "Command '$P_SRV' is not an executable file" + exit 1 +fi +if [ ! -x "$P_CLI" ]; then + echo "Command '$P_CLI' is not an executable file" + exit 1 +fi +if [ ! -x "$P_PXY" ]; then + echo "Command '$P_PXY' is not an executable file" + exit 1 +fi +if which $OPENSSL_CMD >/dev/null 2>&1; then :; else + echo "Command '$OPENSSL_CMD' not found" + exit 1 +fi + +# used by watchdog +MAIN_PID="$$" + +# be more patient with valgrind +if [ "$MEMCHECK" -gt 0 ]; then + START_DELAY=3 + DOG_DELAY=30 +else + START_DELAY=1 + DOG_DELAY=10 +fi +CLI_DELAY_FACTOR=1 + +# Pick a "unique" server port in the range 10000-19999, and a proxy port +PORT_BASE="0000$$" +PORT_BASE="$( printf $PORT_BASE | tail -c 4 )" +SRV_PORT="1$PORT_BASE" +PXY_PORT="2$PORT_BASE" +unset PORT_BASE + +# fix commands to use this port, force IPv4 while at it +# +SRV_PORT will be replaced by either $SRV_PORT or $PXY_PORT later +P_SRV="$P_SRV server_addr=127.0.0.1 server_port=$SRV_PORT" +P_CLI="$P_CLI server_addr=127.0.0.1 server_port=+SRV_PORT" +P_PXY="$P_PXY server_addr=127.0.0.1 server_port=$SRV_PORT listen_addr=127.0.0.1 listen_port=$PXY_PORT" +O_SRV="$O_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem" +O_CLI="$O_CLI -connect localhost:+SRV_PORT" +G_SRV="$G_SRV -p $SRV_PORT" +G_CLI="$G_CLI -p +SRV_PORT localhost" + +# Also pick a unique name for intermediate files +SRV_OUT="srv_out.$$" +CLI_OUT="cli_out.$$" +PXY_OUT="pxy_out.$$" +SESSION="session.$$" + +SKIP_NEXT="NO" + +trap cleanup INT TERM HUP + +# --- Default Ciphersuite (DTLS 1.3) --- + +echo "" +echo "*** Default Ciphersuite (PSK, DTLS 1.3) *** " +echo "" + +run_test "PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" + +echo "" +echo "*** Default Ciphersuite (Public Key, DTLS 1.3) *** " +echo "" + +run_test "ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Verifying peer X.509 certificate... ok" + +# ----------------------------------- Plain PSK ---------------------------------- + +echo "" +echo "*** PSK, DTLS 1.3 *** " +echo "" + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_SHA256" + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_GCM_SHA256" + + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_8_SHA256" + + +# - the PSK-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_256_GCM_SHA384" + +# ----------------------------------- PSK-ECDHE ---------------------------------- +echo "" +echo "*** PSK-ECDHE, DTLS 1.3 *** " +echo "" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_GCM_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_8_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_256_GCM_SHA384" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with built-in test certificates +# + server-to-client authentication only +# + server_name extension + +echo "" +echo "*** ECDHE-ECDSA, server auth only with built-in test certificates, DTLS 1.3 ***" +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with built-in test certificates +# + mutual authentication +# + server_name extension + + +echo "" +echo "*** ECDHE-ECDSA, mutual authentication with built-in test certificates, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" + + +echo "" +echo "*** ECDHE-ECDSA, server-only auth. with client sending empty cert, DTLS 1.3 *** " +echo "" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + server asks client for authentication with certificate request message +# + client responds with empty certificate +# + Exchange is successful since the server does not require client authentication + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server accepts the lack of client authentication + +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (empty client certificate)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server accepts the lack of client authentication + +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (empty client certificate)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + server asks client for authentication with certificate request message +# + client responds with empty certificate +# + Exchange fails since the server does requires client authentication + + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server **DOES NOT** accept the lack of client authentication + +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (empty client certificate), failed auth due to missing client-side authentication" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "mbedtls_ssl_parse_certificate() returned -29824 (-0x7480)" \ + -s "client has no certificate" \ + -c "write empty client certificate" + + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server **DOES NOT** accept the lack of client authentication + +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (empty client certificate), failed auth due to missing client-side authentication" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "mbedtls_ssl_parse_certificate() returned -29824 (-0x7480)" \ + -s "client has no certificate" \ + -c "write empty client certificate" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with external SHA384 certificates +# + server-only authentication +# + server_name extension + + +echo "" +echo "*** ECDHE-ECDSA, server auth only with SHA384 certificates, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=certs/server.crt key_file=certs/server.key" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=localhost force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=none key_file=none" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost" \ + -c "signed using : ECDSA with SHA384" \ + -c "EC key size : 384 bits" + + + +# ----------------------------------- Ticket Exchange ---------------------------------- +# +echo "" +echo "*** Ticket Exchange (combination of ECDHE-ECDSA and PSK auth), DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + + + +echo "" +echo "*** ECDHE-ECDSA, server auth only with SHA384 certificates with ticket, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=all tickets=1 ca_file=certs/ca.crt crt_file=certs/server.crt key_file=certs/server.key" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=localhost force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=none key_file=none reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost" \ + -c "signed using : ECDSA with SHA384" \ + -c "EC key size : 384 bits" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + + + +# ----------------------------------- Early Data ---------------------------------- +# +echo "" +echo "*** Early Data *** " +echo "" + +# - the PSK-based ciphersuite exchange is executed +# - AES-256-GCM with SHA384 is negotiated +run_test "TLS_AES_256_GCM_SHA384 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM with SHA256 is negotiated +run_test "TLS_AES_128_CCM_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-GCM with SHA256 is negotiated +run_test "TLS_AES_128_GCM_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM-8 with SHA256 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + + +# ----------------------------------- Cookie / HRR ---------------------------------- +# +echo "" +echo "*** Cookie / HRR, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +# - HRR is initiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa tickets=0 cookies=2" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Cookie extension missing. Need to send a HRR." \ + -s "write hello retry request" \ + -c "received HelloRetryRequest message" \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + + +# Final report +echo "" +echo "------------------------------------------------------------------------" + +echo "" +echo "--- FINAL REPORT ---" +echo "" + +if [ $FAILS = 0 ]; then + printf "PASSED" +else + printf "FAILED" +fi +PASSES=$(( $TESTS - $FAILS )) +echo " ($PASSES / $TESTS tests ($SKIPS skipped))" + +exit $FAILS diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 4705fe88a375..2e3657dae70b 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -2498,6 +2498,52 @@ component_test_malloc_0_null () { tests/ssl-opt.sh -e 'proxy' } +component_test_tls13 () { + msg "build: TLS 1.3 (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_client_only () { + msg "build: TLS 1.3 client-only (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py unset MBEDTLS_SSL_SRV_C + scripts/config.py set MBEDTLS_SSL_CLI_C + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: TLS 1.3 client-only, compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_server_only () { + msg "build: TLS 1.3 server-only (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py set MBEDTLS_SSL_SRV_C + scripts/config.py unset MBEDTLS_SSL_CLI_C + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_rsa_enabled () { + msg "build: TLS 1.3, with RSA (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py set MBEDTLS_RSA_C + scripts/config.py set MBEDTLS_X509_RSASSA_PSS_SUPPORT + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: TLS 1.3 client, OpenSSL server with RSA certificate" + if_build_succeeded tests/ssl-opt.sh --filter "RSA-certificate, OpenSSL server" +} + component_test_aes_fewer_tables () { msg "build: default config with AES_FEWER_TABLES enabled" scripts/config.py set MBEDTLS_AES_FEWER_TABLES diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 7199462ce5af..aca168bf3a1b 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -63,6 +63,7 @@ guess_config_name() { : ${MBEDTLS_TEST_PLATFORM:="$(uname -s | tr -c \\n0-9A-Za-z _)-$(uname -m | tr -c \\n0-9A-Za-z _)"} O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key" +O_SRV_RSA="$OPENSSL_CMD s_server -www -cert data_files/server2.crt -key data_files/server2.key" O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client" G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key" G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt" @@ -436,6 +437,35 @@ requires_gnutls() { fi } +# skip next test if OpenSSL isn't available +requires_openssl() { + if [ -z "${OPENSSL_AVAILABLE:-}" ]; then + if ( which "$OPENSSL_CMD" ) >/dev/null 2>&1; then + OPENSSL_AVAILABLE="YES" + else + OPENSSL_AVAILABLE="NO" + fi + fi + if [ "$OPENSSL_AVAILABLE" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if OpenSSL doesn't support TLS 1.3 +requires_openssl_with_tls1_3() { + if [ -z "${OPENSSL_HAS_TLS1_3:-}" ]; then + if $OPENSSL_CMD s_server -help 2>&1 | grep "\-tls1_3" >/dev/null + then + OPENSSL_HAS_TLS1_3="YES" + else + OPENSSL_HAS_TLS1_3="NO" + fi + fi + if [ "$OPENSSL_HAS_TLS1_3" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + # skip next test if GnuTLS-next isn't available requires_gnutls_next() { if [ -z "${GNUTLS_NEXT_AVAILABLE:-}" ]; then @@ -1520,6 +1550,558 @@ SKIP_NEXT="NO" trap cleanup INT TERM HUP +# +# TLS 1.3 specific tests +# + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, default suite, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, default suite, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-GCM-256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-GCM-256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS1-3-AES-256-GCM-SHA384 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +# Server asks client for authentication with certificate request message, +# client responds with empty certificate +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, empty client certificate, accepted" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + +# - Server does NOT accept the lack of client authentication +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, empty client certificate, rejected" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "empty certificate message received" \ + -s "client has no certificate" \ + -c "write empty client certificate" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3 TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384 with ECDHE-ECDSA (server auth only) with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, client tries early data without PSK, and falls back to 1-RTT" \ + "$P_SRV nbio=2 debug_level=4 force_version=tls1_3" \ + "$P_CLI nbio=2 debug_level=4 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 early_data=1" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -c "<= skip write early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "early data status = 0" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth, HRR enforcing cookie" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa tickets=0 cookies=2" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Cookie extension missing. Need to send a HRR." \ + -s "write hello retry request" \ + -c "received HelloRetryRequest message" \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + + +# configure client to initially sent incorrect group, which will be corrected with HRR from the server +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256 with ECDHE-ECDSA, SRV auth, HRR enforcing group" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1 cookies=1 tickets=0" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1,secp384r1 key_share_named_groups=secp384r1" \ + 0 \ + -s "no matching curve for ECDHE" \ + -s "write hello retry request" \ + -s "NamedGroup in HRR: secp256r1" \ + -s "ECDH curve: secp256r1" \ + -c "received HelloRetryRequest message" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# test early data status - not sent +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - not sent" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 0" \ + +# test early data status - accepted +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - accepted" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 2" \ + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ClientHello message misses mandatory extensions" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=psk" \ + 1 \ + -s "ClientHello message misses mandatory extensions." \ + -s "send alert message" \ + -C "received HelloRetryRequest message" \ + -c "got an alert message, type: \\[2:109]" + +# Test OpenSSL server using RSA certificate +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_X509_RSASSA_PSS_SUPPORT +requires_openssl +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, RSA-certificate, OpenSSL server" \ + "$O_SRV_RSA" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256" \ + 0 \ + -c "Certificate Verify: using RSA" + +# Test OpenSSL server with resumption +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_openssl_with_tls1_3 +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, resumption, OpenSSL server" \ + "$O_SRV" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 reconnect=1 tickets=1" \ + 0 \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -c "skip parse certificate$" + +# Test OpenSSL server with resumption and reject early data +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_openssl_with_tls1_3 +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, reject early data, OpenSSL server" \ + "$O_SRV" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost \ + force_ciphersuite=TLS1-3-AES-128-GCM-256 reconnect=1 tickets=1 \ + early_data=1" \ + 0 \ + -c "=> write early data" \ + -c "=> mbedtls_ssl_tls1_3_generate_early_data_keys" \ + -c "skip EndOfEarlyData, server rejected" \ + -c "early data status, reconnect = 1" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_ALPN +run_test "TLS 1.3, ALPN" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk alpn=abc,1234" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk alpn=1234" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "found alpn extension" \ + -c "found alpn extension" \ + -c "Application Layer Protocol is 1234" \ + -s "Application Layer Protocol is 1234" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS_AES_128_CCM_SHA256, ECDHE-ECDSA, mismatched sig_algs" \ + "$P_SRV nbio=2 debug_level=4 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa sig_algs=ecdsa_secp384r1_sha384" \ + "$P_CLI nbio=2 debug_level=4 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa sig_algs=ecdsa_secp256r1_sha256" \ + 1 \ + -s "found signature_algorithms extension" \ + -c "got an alert message, type: \\[2:40]" + +# +# TLS 1.2 specific tests +# + # Basic test # Checks that: @@ -1549,6 +2131,7 @@ run_test "Default, DTLS" \ -s "Protocol is DTLSv1.2" \ -s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS client auth: required" \ "$P_SRV auth_mode=required" \ "$P_CLI" \ @@ -1558,6 +2141,7 @@ run_test "TLS client auth: required" \ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected client key" \ "$P_SRV auth_mode=required" \ "$P_CLI crt_file=data_files/server5.crt key_file=data_files/server5.key.enc key_pwd=PolarSSLTest" \ @@ -1566,6 +2150,7 @@ run_test "TLS: password protected client key" \ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected server key" \ "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key.enc key_pwd=PolarSSLTest" \ "$P_CLI" \ @@ -1575,6 +2160,7 @@ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_RSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected server key, two certificates" \ "$P_SRV \ key_file=data_files/server5.key.enc key_pwd=PolarSSLTest crt_file=data_files/server5.crt \ @@ -1583,6 +2169,7 @@ run_test "TLS: password protected server key, two certificates" \ 0 requires_config_enabled MBEDTLS_ZLIB_SUPPORT +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Default (compression enabled)" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -1595,6 +2182,7 @@ run_test "Default (compression enabled)" \ -C "error" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CA callback on client" \ "$P_SRV debug_level=3" \ "$P_CLI ca_callback=1 debug_level=3 " \ @@ -1607,6 +2195,7 @@ requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CA callback on server" \ "$P_SRV auth_mode=required" \ "$P_CLI ca_callback=1 debug_level=3 crt_file=data_files/server5.crt \ @@ -1622,6 +2211,7 @@ requires_config_enabled MBEDTLS_USE_PSA_CRYPTO requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Opaque key for client authentication" \ "$P_SRV auth_mode=required crt_file=data_files/server5.crt \ key_file=data_files/server5.key" \ @@ -1769,31 +2359,48 @@ run_test "Opaque psk: server: RSA-PSK not supported" \ # Test ciphersuites which we expect to be fully supported by PSA Crypto # and check that we don't fall back to Mbed TLS' internal crypto primitives. +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CCM +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CCM +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 requires_config_enabled MBEDTLS_ECP_DP_SECP521R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp521r1" requires_config_enabled MBEDTLS_ECP_DP_BP512R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP512r1" requires_config_enabled MBEDTLS_ECP_DP_SECP384R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp384r1" requires_config_enabled MBEDTLS_ECP_DP_BP384R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP384r1" requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp256r1" requires_config_enabled MBEDTLS_ECP_DP_SECP256K1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp256k1" requires_config_enabled MBEDTLS_ECP_DP_BP256R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP256r1" requires_config_enabled MBEDTLS_ECP_DP_SECP224R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp224r1" ## SECP224K1 is buggy via the PSA API ## (https://github.com/Mbed-TLS/mbedtls/issues/3541), @@ -1803,12 +2410,15 @@ run_test_psa_force_curve "secp224r1" #requires_config_enabled MBEDTLS_ECP_DP_SECP224K1_ENABLED #run_test_psa_force_curve "secp224k1" requires_config_enabled MBEDTLS_ECP_DP_SECP192R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp192r1" requires_config_enabled MBEDTLS_ECP_DP_SECP192K1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp192k1" # Test current time in ServerHello requires_config_enabled MBEDTLS_HAVE_TIME +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ServerHello contains gmt_unix_time" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -1817,6 +2427,7 @@ run_test "ServerHello contains gmt_unix_time" \ -F "check_server_hello_time" # Test for uniqueness of IVs in AEAD ciphersuites +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Unique IV in GCM" \ "$P_SRV exchanges=20 debug_level=4" \ "$P_CLI exchanges=20 debug_level=4 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" \ @@ -1825,6 +2436,7 @@ run_test "Unique IV in GCM" \ -U "IV used" # Tests for certificate verification callback +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Configuration-specific CRT verification callback" \ "$P_SRV debug_level=3" \ "$P_CLI context_crt_cb=0 debug_level=3" \ @@ -1835,6 +2447,7 @@ run_test "Configuration-specific CRT verification callback" \ -C "Use context-specific verification callback" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context-specific CRT verification callback" \ "$P_SRV debug_level=3" \ "$P_CLI context_crt_cb=1 debug_level=3" \ @@ -1855,6 +2468,7 @@ requires_config_enabled MBEDTLS_ARC4_C requires_config_enabled MBEDTLS_SHA1_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "RC4: server disabled, client enabled" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -1865,6 +2479,7 @@ requires_config_enabled MBEDTLS_ARC4_C requires_config_enabled MBEDTLS_SHA1_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "RC4: server half, client enabled" \ "$P_SRV arc4=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -1926,6 +2541,7 @@ run_test "SHA-1 explicitly allowed in server certificate" \ "$P_CLI allow_sha1=1" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SHA-256 allowed by default in server certificate" \ "$P_SRV key_file=data_files/server2.key crt_file=data_files/server2-sha256.crt" \ "$P_CLI allow_sha1=0" \ @@ -1942,12 +2558,14 @@ run_test "SHA-1 explicitly allowed in client certificate" \ "$P_CLI key_file=data_files/cli-rsa.key crt_file=data_files/cli-rsa-sha1.crt" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SHA-256 allowed by default in client certificate" \ "$P_SRV auth_mode=required allow_sha1=0" \ "$P_CLI key_file=data_files/cli-rsa.key crt_file=data_files/cli-rsa-sha256.crt" \ 0 # Tests for datagram packing +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, client and server" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1955,6 +2573,7 @@ run_test "DTLS: multiple records in same datagram, client and server" \ -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, client only" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1962,6 +2581,7 @@ run_test "DTLS: multiple records in same datagram, client only" \ -s "next record in same datagram" \ -C "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, server only" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \ @@ -1969,6 +2589,7 @@ run_test "DTLS: multiple records in same datagram, server only" \ -S "next record in same datagram" \ -c "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, neither client nor server" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \ @@ -1978,6 +2599,7 @@ run_test "DTLS: multiple records in same datagram, neither client nor server" # Tests for Truncated HMAC extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client default, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -1986,6 +2608,7 @@ run_test "Truncated HMAC: client default, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client disabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -1994,6 +2617,7 @@ run_test "Truncated HMAC: client disabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2002,6 +2626,7 @@ run_test "Truncated HMAC: client enabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server disabled" \ "$P_SRV debug_level=4 trunc_hmac=0" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2010,6 +2635,7 @@ run_test "Truncated HMAC: client enabled, server disabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client disabled, server enabled" \ "$P_SRV debug_level=4 trunc_hmac=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2018,6 +2644,7 @@ run_test "Truncated HMAC: client disabled, server enabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server enabled" \ "$P_SRV debug_level=4 trunc_hmac=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2025,6 +2652,7 @@ run_test "Truncated HMAC: client enabled, server enabled" \ -S "dumping 'expected mac' (20 bytes)" \ -s "dumping 'expected mac' (10 bytes)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client default, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2033,6 +2661,7 @@ run_test "Truncated HMAC, DTLS: client default, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client disabled, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2041,6 +2670,7 @@ run_test "Truncated HMAC, DTLS: client disabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2049,6 +2679,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server disabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=0" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2057,6 +2688,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server disabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client disabled, server enabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=1" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2065,6 +2697,7 @@ run_test "Truncated HMAC, DTLS: client disabled, server enabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server enabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=1" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2075,6 +2708,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server enabled" \ # Tests for Context serialization requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, CCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2083,6 +2717,7 @@ run_test "Context serialization, client serializes, CCM" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2091,6 +2726,7 @@ run_test "Context serialization, client serializes, ChaChaPoly" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, GCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2100,6 +2736,7 @@ run_test "Context serialization, client serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, with CID" \ "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ @@ -2108,6 +2745,7 @@ run_test "Context serialization, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, CCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2116,6 +2754,7 @@ run_test "Context serialization, server serializes, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2124,6 +2763,7 @@ run_test "Context serialization, server serializes, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, GCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2133,6 +2773,7 @@ run_test "Context serialization, server serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, with CID" \ "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=0 exchanges=2 cid=1 cid_val=beef" \ @@ -2141,6 +2782,7 @@ run_test "Context serialization, server serializes, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, CCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2149,6 +2791,7 @@ run_test "Context serialization, both serialize, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, ChaChaPoly" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2157,6 +2800,7 @@ run_test "Context serialization, both serialize, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, GCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2166,6 +2810,7 @@ run_test "Context serialization, both serialize, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, with CID" \ "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ @@ -2174,6 +2819,7 @@ run_test "Context serialization, both serialize, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, CCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2182,6 +2828,7 @@ run_test "Context serialization, re-init, client serializes, CCM" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2190,6 +2837,7 @@ run_test "Context serialization, re-init, client serializes, ChaChaPoly" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, GCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2199,6 +2847,7 @@ run_test "Context serialization, re-init, client serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, with CID" \ "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=2 exchanges=2 cid=1 cid_val=beef" \ @@ -2207,6 +2856,7 @@ run_test "Context serialization, re-init, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, CCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2215,6 +2865,7 @@ run_test "Context serialization, re-init, server serializes, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2223,6 +2874,7 @@ run_test "Context serialization, re-init, server serializes, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, GCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2232,6 +2884,7 @@ run_test "Context serialization, re-init, server serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, with CID" \ "$P_SRV dtls=1 serialize=2 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=0 exchanges=2 cid=1 cid_val=beef" \ @@ -2240,6 +2893,7 @@ run_test "Context serialization, re-init, server serializes, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, CCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2248,6 +2902,7 @@ run_test "Context serialization, re-init, both serialize, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, ChaChaPoly" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2256,6 +2911,7 @@ run_test "Context serialization, re-init, both serialize, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, GCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2265,6 +2921,7 @@ run_test "Context serialization, re-init, both serialize, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, with CID" \ "$P_SRV dtls=1 serialize=2 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=2 exchanges=2 cid=1 cid_val=beef" \ @@ -2273,6 +2930,7 @@ run_test "Context serialization, re-init, both serialize, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Saving the serialized context to a file" \ "$P_SRV dtls=1 serialize=1 context_file=context_srv.txt" \ "$P_CLI dtls=1 serialize=1 context_file=context_cli.txt" \ @@ -2289,6 +2947,7 @@ rm -f context_cli.txt # changed once the CID extension is implemented. requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli enabled, Srv disabled" \ "$P_SRV debug_level=3 dtls=1 cid=0" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ @@ -2305,6 +2964,7 @@ run_test "Connection ID: Cli enabled, Srv disabled" \ -c "Use of Connection ID was rejected by the server" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli disabled, Srv enabled" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=0" \ @@ -2320,6 +2980,7 @@ run_test "Connection ID: Cli disabled, Srv enabled" \ -s "Use of Connection ID was not offered by client" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef" \ @@ -2340,6 +3001,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=dead" \ @@ -2363,6 +3025,7 @@ run_test "Connection ID, 3D: Cli+Srv enabled, Cli+Srv CID nonempty" \ -s "ignoring unexpected CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY mtu=800" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead" \ @@ -2384,6 +3047,7 @@ run_test "Connection ID, MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead" \ @@ -2407,6 +3071,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -s "ignoring unexpected CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1" \ @@ -2427,6 +3092,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ @@ -2447,6 +3113,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1" \ @@ -2465,6 +3132,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty" \ -C "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2485,6 +3153,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CCM-8 -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2505,6 +3174,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CCM-8" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2525,6 +3195,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CCM-8" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2543,6 +3214,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CCM-8" \ -C "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2563,6 +3235,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CBC" -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2583,6 +3256,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CBC" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2603,6 +3277,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CBC" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2622,6 +3297,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CBC" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate without change of CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef renegotiation=1 renegotiate=1" \ @@ -2637,6 +3313,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate without change of CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate with different CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_val_renego=beef renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_val_renego=dead renegotiation=1 renegotiate=1" \ @@ -2652,6 +3329,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate with different CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate with different CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=dead cid_val_renego=beef renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=beef cid_val_renego=dead renegotiation=1 renegotiate=1" \ @@ -2667,6 +3345,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate with differ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate with different CID" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead cid_val_renego=beef renegotiation=1" \ @@ -2685,6 +3364,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate with different requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate without CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2700,6 +3380,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate without CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate without CID" \ "$P_SRV debug_level=3 dtls=1 dgram_packing=0 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 dgram_packing=0 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2715,6 +3396,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate without CID requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate without CID" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ @@ -2733,6 +3415,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate without CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, CID on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=0 cid_renego=1 cid_val_renego=beef renegotiation=1 renegotiate=1" \ @@ -2746,6 +3429,7 @@ run_test "Connection ID: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, CID on renegotiation" \ "$P_SRV debug_level=3 dtls=1 dgram_packing=0 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 dgram_packing=0 cid=0 cid_renego=1 cid_val_renego=beef renegotiation=1 renegotiate=1" \ @@ -2759,6 +3443,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, CID on renegotiation" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 dgram_packing=1 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ @@ -2775,6 +3460,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli disables on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2791,6 +3477,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli disables on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Cli disables on renegotiation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ @@ -2810,6 +3497,7 @@ run_test "Connection ID, 3D: Cli+Srv enabled, Cli disables on renegotiation" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv disables on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef renegotiation=1 renegotiate=1" \ @@ -2826,6 +3514,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv disables on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Srv disables on renegotiation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ @@ -2876,6 +3565,7 @@ run_test "Connection ID: Cli+Srv enabled, variable buffer lengths, MFL=1024" # Tests for Encrypt-then-MAC extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: default" \ "$P_SRV debug_level=3 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2888,6 +3578,7 @@ run_test "Encrypt then MAC: default" \ -c "using encrypt then mac" \ -s "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, server disabled" \ "$P_SRV debug_level=3 etm=0 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2900,6 +3591,7 @@ run_test "Encrypt then MAC: client enabled, server disabled" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, aead cipher" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-AES-128-GCM-SHA256" \ @@ -2912,6 +3604,7 @@ run_test "Encrypt then MAC: client enabled, aead cipher" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, stream cipher" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -2924,6 +3617,7 @@ run_test "Encrypt then MAC: client enabled, stream cipher" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client disabled, server enabled" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -3022,6 +3716,7 @@ run_test "Extended Master Secret: client enabled, server SSLv3" \ # Tests for FALLBACK_SCSV +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: default" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1" \ @@ -3031,6 +3726,7 @@ run_test "Fallback SCSV: default" \ -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: explicitly disabled" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ @@ -3040,6 +3736,7 @@ run_test "Fallback SCSV: explicitly disabled" \ -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ @@ -3049,6 +3746,7 @@ run_test "Fallback SCSV: enabled" \ -s "inapropriate fallback" \ -c "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, max version" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 fallback=1" \ @@ -3059,6 +3757,7 @@ run_test "Fallback SCSV: enabled, max version" \ -C "is a fatal alert message (msg 86)" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: default, openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ @@ -3067,6 +3766,7 @@ run_test "Fallback SCSV: default, openssl server" \ -C "is a fatal alert message (msg 86)" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ @@ -3076,6 +3776,7 @@ run_test "Fallback SCSV: enabled, openssl server" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1 requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: disabled, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -tls1_1" \ @@ -3085,6 +3786,7 @@ run_test "Fallback SCSV: disabled, openssl client" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1 requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -tls1_1 -fallback_scsv" \ @@ -3093,6 +3795,7 @@ run_test "Fallback SCSV: enabled, openssl client" \ -s "inapropriate fallback" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, max version, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -fallback_scsv" \ @@ -3102,6 +3805,7 @@ run_test "Fallback SCSV: enabled, max version, openssl client" \ # Test sending and receiving empty application data records +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=1" \ "$P_CLI auth_mode=none etm=1 request_size=0 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA" \ @@ -3110,6 +3814,7 @@ run_test "Encrypt then MAC: empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: disabled, empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=0" \ "$P_CLI auth_mode=none etm=0 request_size=0" \ @@ -3117,6 +3822,7 @@ run_test "Encrypt then MAC: disabled, empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC, DTLS: empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=1 dtls=1" \ "$P_CLI auth_mode=none etm=1 request_size=0 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA dtls=1" \ @@ -3125,6 +3831,7 @@ run_test "Encrypt then MAC, DTLS: empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC, DTLS: disabled, empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=0 dtls=1" \ "$P_CLI auth_mode=none etm=0 request_size=0 dtls=1" \ @@ -3165,6 +3872,7 @@ run_test "Fallback SCSV: not in list" \ # Tests for CBC 1/n-1 record splitting +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.2, no splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3174,6 +3882,7 @@ run_test "CBC Record splitting: TLS 1.2, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.1, no splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3183,6 +3892,7 @@ run_test "CBC Record splitting: TLS 1.1, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3201,6 +3911,7 @@ run_test "CBC Record splitting: SSLv3, splitting" \ -s "Read from client: 1 bytes read" \ -s "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0 RC4, no splitting" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -3210,6 +3921,7 @@ run_test "CBC Record splitting: TLS 1.0 RC4, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting disabled" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3219,6 +3931,7 @@ run_test "CBC Record splitting: TLS 1.0, splitting disabled" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting, nbio" \ "$P_SRV nbio=2" \ "$P_CLI nbio=2 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3230,6 +3943,7 @@ run_test "CBC Record splitting: TLS 1.0, splitting, nbio" \ # Tests for Session Tickets +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: basic" \ "$P_SRV debug_level=3 tickets=1" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3244,6 +3958,7 @@ run_test "Session resume using tickets: basic" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: cache disabled" \ "$P_SRV debug_level=3 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3258,6 +3973,7 @@ run_test "Session resume using tickets: cache disabled" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: timeout" \ "$P_SRV debug_level=3 tickets=1 cache_max=0 ticket_timeout=1" \ "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_delay=2" \ @@ -3272,6 +3988,7 @@ run_test "Session resume using tickets: timeout" \ -S "a session has been resumed" \ -C "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: session copy" \ "$P_SRV debug_level=3 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_mode=0" \ @@ -3286,6 +4003,7 @@ run_test "Session resume using tickets: session copy" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3295,6 +4013,7 @@ run_test "Session resume using tickets: openssl server" \ -c "parse new session ticket" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: openssl client" \ "$P_SRV debug_level=3 tickets=1" \ "( $O_CLI -sess_out $SESSION; \ @@ -3309,6 +4028,7 @@ run_test "Session resume using tickets: openssl client" \ # Tests for Session Tickets with DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: basic" \ "$P_SRV debug_level=3 dtls=1 tickets=1" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1" \ @@ -3323,6 +4043,7 @@ run_test "Session resume using tickets, DTLS: basic" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: cache disabled" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1" \ @@ -3337,6 +4058,7 @@ run_test "Session resume using tickets, DTLS: cache disabled" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: timeout" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0 ticket_timeout=1" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_delay=2" \ @@ -3351,6 +4073,7 @@ run_test "Session resume using tickets, DTLS: timeout" \ -S "a session has been resumed" \ -C "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: session copy" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_mode=0" \ @@ -3365,6 +4088,7 @@ run_test "Session resume using tickets, DTLS: session copy" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: openssl server" \ "$O_SRV -dtls1" \ "$P_CLI dtls=1 debug_level=3 tickets=1 reconnect=1" \ @@ -3391,6 +4115,7 @@ run_test "Session resume using tickets, DTLS: openssl client" \ # Tests for Session Resume based on session-ID and cache +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: tickets enabled on client" \ "$P_SRV debug_level=3 tickets=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3405,6 +4130,7 @@ run_test "Session resume using cache: tickets enabled on client" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: tickets enabled on server" \ "$P_SRV debug_level=3 tickets=1" \ "$P_CLI debug_level=3 tickets=0 reconnect=1" \ @@ -3419,6 +4145,7 @@ run_test "Session resume using cache: tickets enabled on server" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: cache_max=0" \ "$P_SRV debug_level=3 tickets=0 cache_max=0" \ "$P_CLI debug_level=3 tickets=0 reconnect=1" \ @@ -3643,6 +4370,7 @@ run_test "Session resume using cache, DTLS: openssl server" \ # Tests for Max Fragment Length extension requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: enabled, default" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -3657,6 +4385,7 @@ run_test "Max fragment length: enabled, default" \ -C "found max_fragment_length extension" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: enabled, default, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3674,6 +4403,7 @@ run_test "Max fragment length: enabled, default, larger message" \ -s "1 bytes read" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length, DTLS: enabled, default, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3693,6 +4423,7 @@ run_test "Max fragment length, DTLS: enabled, default, larger message" \ # content length configuration.) requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: disabled, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3718,6 +4449,7 @@ run_test "Max fragment length, DTLS: disabled, larger message" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: used by client" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3733,6 +4465,7 @@ run_test "Max fragment length: used by client" \ requires_max_content_len 1024 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3748,6 +4481,7 @@ run_test "Max fragment length: client 512, server 1024" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3763,6 +4497,7 @@ run_test "Max fragment length: client 512, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3778,6 +4513,7 @@ run_test "Max fragment length: client 512, server 4096" \ requires_max_content_len 1024 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3793,6 +4529,7 @@ run_test "Max fragment length: client 1024, server 512" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3808,6 +4545,7 @@ run_test "Max fragment length: client 1024, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3823,6 +4561,7 @@ run_test "Max fragment length: client 1024, server 4096" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3838,6 +4577,7 @@ run_test "Max fragment length: client 2048, server 512" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3853,6 +4593,7 @@ run_test "Max fragment length: client 2048, server 1024" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3868,6 +4609,7 @@ run_test "Max fragment length: client 2048, server 4096" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3883,6 +4625,7 @@ run_test "Max fragment length: client 4096, server 512" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3898,6 +4641,7 @@ run_test "Max fragment length: client 4096, server 1024" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3913,6 +4657,7 @@ run_test "Max fragment length: client 4096, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: used by server" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3" \ @@ -3929,6 +4674,7 @@ run_test "Max fragment length: used by server" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: gnutls server" \ "$G_SRV" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3940,6 +4686,7 @@ run_test "Max fragment length: gnutls server" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client, message just fits" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2048" \ @@ -3957,6 +4704,7 @@ run_test "Max fragment length: client, message just fits" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2345" \ @@ -3975,6 +4723,7 @@ run_test "Max fragment length: client, larger message" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: DTLS client, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 max_frag_len=2048 request_size=2345" \ @@ -3992,6 +4741,7 @@ run_test "Max fragment length: DTLS client, larger message" \ # Tests for renegotiation # Renegotiation SCSV always added, regardless of SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: none, for reference" \ "$P_SRV debug_level=3 exchanges=2 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2" \ @@ -4006,6 +4756,7 @@ run_test "Renegotiation: none, for reference" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: client-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4020,6 +4771,7 @@ run_test "Renegotiation: client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4037,6 +4789,7 @@ run_test "Renegotiation: server-initiated" \ # the server did not parse the Signature Algorithm extension. This test is valid only if an MD # algorithm stronger than SHA-1 is enabled in config.h requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: Signature Algorithms parsing, client-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4055,6 +4808,7 @@ run_test "Renegotiation: Signature Algorithms parsing, client-initiated" \ # the server did not parse the Signature Algorithm extension. This test is valid only if an MD # algorithm stronger than SHA-1 is enabled in config.h requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: Signature Algorithms parsing, server-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4070,6 +4824,7 @@ run_test "Renegotiation: Signature Algorithms parsing, server-initiated" \ -S "client hello v3, signature_algorithm ext: 2" # Is SHA-1 negotiated? requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: double" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4108,6 +4863,7 @@ run_test "Renegotiation with max fragment length: client 2048, server 512" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: client-initiated, server-rejected" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=0 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4124,6 +4880,7 @@ run_test "Renegotiation: client-initiated, server-rejected" \ -c "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, default" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=0" \ @@ -4140,6 +4897,7 @@ run_test "Renegotiation: server-initiated, client-rejected, default" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, not enforced" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=-1 auth_mode=optional" \ @@ -4158,6 +4916,7 @@ run_test "Renegotiation: server-initiated, client-rejected, not enforced" \ # delay 2 for 1 alert record + 1 application data record requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, delay 2" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=2 auth_mode=optional" \ @@ -4175,6 +4934,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 2" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, delay 0" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=0 auth_mode=optional" \ @@ -4191,6 +4951,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 0" \ -s "SSL - An unexpected message was received from our peer" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=0 auth_mode=optional" \ @@ -4208,6 +4969,7 @@ run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, just below period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4226,6 +4988,7 @@ run_test "Renegotiation: periodic, just below period" \ # one extra exchange to be able to complete renego requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, just above period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=4 renegotiation=1" \ @@ -4243,6 +5006,7 @@ run_test "Renegotiation: periodic, just above period" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, two times period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=7 renegotiation=1" \ @@ -4260,6 +5024,7 @@ run_test "Renegotiation: periodic, two times period" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, above period, disabled" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=0 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=4 renegotiation=1" \ @@ -4277,6 +5042,7 @@ run_test "Renegotiation: periodic, above period, disabled" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: nbio, client-initiated" \ "$P_SRV debug_level=3 nbio=2 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 nbio=2 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4291,6 +5057,7 @@ run_test "Renegotiation: nbio, client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: nbio, server-initiated" \ "$P_SRV debug_level=3 nbio=2 exchanges=2 renegotiation=1 renegotiate=1 auth_mode=optional" \ "$P_CLI debug_level=3 nbio=2 exchanges=2 renegotiation=1" \ @@ -4305,6 +5072,7 @@ run_test "Renegotiation: nbio, server-initiated" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: openssl server, client-initiated" \ "$O_SRV -www" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4318,6 +5086,7 @@ run_test "Renegotiation: openssl server, client-initiated" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server strict, client-initiated" \ "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4331,6 +5100,7 @@ run_test "Renegotiation: gnutls server strict, client-initiated" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-initiated default" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4344,6 +5114,7 @@ run_test "Renegotiation: gnutls server unsafe, client-initiated default" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-inititated no legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ @@ -4358,6 +5129,7 @@ run_test "Renegotiation: gnutls server unsafe, client-inititated no legacy" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-inititated legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ @@ -4371,6 +5143,7 @@ run_test "Renegotiation: gnutls server unsafe, client-inititated legacy" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, client-initiated" \ "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4385,6 +5158,7 @@ run_test "Renegotiation: DTLS, client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, server-initiated" \ "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \ "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 \ @@ -4400,6 +5174,7 @@ run_test "Renegotiation: DTLS, server-initiated" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, renego_period overflow" \ "$P_SRV debug_level=3 dtls=1 exchanges=4 renegotiation=1 renego_period=18446462598732840962 auth_mode=optional" \ "$P_CLI debug_level=3 dtls=1 exchanges=4 renegotiation=1" \ @@ -4415,6 +5190,7 @@ run_test "Renegotiation: DTLS, renego_period overflow" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, gnutls server, client-initiated" \ "$G_SRV -u --mtu 4096" \ "$P_CLI debug_level=3 dtls=1 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4429,6 +5205,7 @@ run_test "Renegotiation: DTLS, gnutls server, client-initiated" \ # Test for the "secure renegotiation" extension only (no actual renegotiation) requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server strict, client default" \ "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3" \ @@ -4438,6 +5215,7 @@ run_test "Renego ext: gnutls server strict, client default" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server unsafe, client default" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3" \ @@ -4447,6 +5225,7 @@ run_test "Renego ext: gnutls server unsafe, client default" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server unsafe, client break legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 allow_legacy=-1" \ @@ -4456,6 +5235,7 @@ run_test "Renego ext: gnutls server unsafe, client break legacy" \ -C "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client strict, server default" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION localhost" \ @@ -4464,6 +5244,7 @@ run_test "Renego ext: gnutls client strict, server default" \ -s "server hello, secure renegotiation extension" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client unsafe, server default" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -4472,6 +5253,7 @@ run_test "Renego ext: gnutls client unsafe, server default" \ -S "server hello, secure renegotiation extension" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client unsafe, server break legacy" \ "$P_SRV debug_level=3 allow_legacy=-1" \ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -4482,6 +5264,7 @@ run_test "Renego ext: gnutls client unsafe, server break legacy" \ # Tests for silently dropping trailing extra bytes in .der certificates requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: no trailing bytes" \ "$P_SRV crt_file=data_files/server5-der0.crt \ key_file=data_files/server5.key" \ @@ -4490,6 +5273,7 @@ run_test "DER format: no trailing bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with a trailing zero byte" \ "$P_SRV crt_file=data_files/server5-der1a.crt \ key_file=data_files/server5.key" \ @@ -4498,6 +5282,7 @@ run_test "DER format: with a trailing zero byte" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with a trailing random byte" \ "$P_SRV crt_file=data_files/server5-der1b.crt \ key_file=data_files/server5.key" \ @@ -4506,6 +5291,7 @@ run_test "DER format: with a trailing random byte" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 2 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der2.crt \ key_file=data_files/server5.key" \ @@ -4514,6 +5300,7 @@ run_test "DER format: with 2 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 4 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der4.crt \ key_file=data_files/server5.key" \ @@ -4522,6 +5309,7 @@ run_test "DER format: with 4 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 8 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der8.crt \ key_file=data_files/server5.key" \ @@ -4530,6 +5318,7 @@ run_test "DER format: with 8 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 9 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der9.crt \ key_file=data_files/server5.key" \ @@ -4540,6 +5329,7 @@ run_test "DER format: with 9 trailing random bytes" \ # Tests for auth_mode, there are duplicated tests using ca callback for authentication # When updating these tests, modify the matching authentication tests accordingly +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client required" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4550,6 +5340,7 @@ run_test "Authentication: server badcert, client required" \ -c "! mbedtls_ssl_handshake returned" \ -c "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client optional" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4560,6 +5351,7 @@ run_test "Authentication: server badcert, client optional" \ -C "! mbedtls_ssl_handshake returned" \ -C "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server goodcert, client optional, no trusted CA" \ "$P_SRV" \ "$P_CLI debug_level=3 auth_mode=optional ca_file=none ca_path=none" \ @@ -4571,6 +5363,7 @@ run_test "Authentication: server goodcert, client optional, no trusted CA" \ -C "X509 - Certificate verification failed" \ -C "SSL - No CA Chain is set, but required to operate" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server goodcert, client required, no trusted CA" \ "$P_SRV" \ "$P_CLI debug_level=3 auth_mode=required ca_file=none ca_path=none" \ @@ -4589,6 +5382,7 @@ run_test "Authentication: server goodcert, client required, no trusted CA" \ # different means to have the server ignoring the client's supported curve list. requires_config_enabled MBEDTLS_ECP_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server ECDH p256v1, client required, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4599,6 +5393,7 @@ run_test "Authentication: server ECDH p256v1, client required, p256v1 unsuppo -C "bad server certificate (ECDH curve)" # Expect failure at earlier verification stage requires_config_enabled MBEDTLS_ECP_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server ECDH p256v1, client optional, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4608,6 +5403,7 @@ run_test "Authentication: server ECDH p256v1, client optional, p256v1 unsuppo -c "! Certificate verification flags"\ -c "bad server certificate (ECDH curve)" # Expect failure only at ECDH params check +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client none" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4618,6 +5414,7 @@ run_test "Authentication: server badcert, client none" \ -C "! mbedtls_ssl_handshake returned" \ -C "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client SHA256, server required" \ "$P_SRV auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -4627,6 +5424,7 @@ run_test "Authentication: client SHA256, server required" \ -c "Supported Signature Algorithm found: 4," \ -c "Supported Signature Algorithm found: 5," +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client SHA384, server required" \ "$P_SRV auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -4651,6 +5449,7 @@ run_test "Authentication: client has no cert, server required (SSLv3)" \ -c "! mbedtls_ssl_handshake returned" \ -s "No client certification received from the client, but required by the authentication mode" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client has no cert, server required (TLS)" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=none \ @@ -4667,6 +5466,7 @@ run_test "Authentication: client has no cert, server required (TLS)" \ -c "! mbedtls_ssl_handshake returned" \ -s "No client certification received from the client, but required by the authentication mode" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server required" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4720,6 +5520,7 @@ run_test "Authentication: client cert not trusted, server required" \ -c "! mbedtls_ssl_handshake returned" \ -s "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4737,6 +5538,7 @@ run_test "Authentication: client badcert, server optional" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server none" \ "$P_SRV debug_level=3 auth_mode=none" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4754,6 +5556,7 @@ run_test "Authentication: client badcert, server none" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4771,6 +5574,7 @@ run_test "Authentication: client no cert, server optional" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: openssl client no cert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$O_CLI" \ @@ -4781,6 +5585,7 @@ run_test "Authentication: openssl client no cert, server optional" \ -S "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, openssl server optional" \ "$O_SRV -verify 10" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4791,6 +5596,7 @@ run_test "Authentication: client no cert, openssl server optional" \ -c "skip write certificate verify" \ -C "! mbedtls_ssl_handshake returned" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, openssl server required" \ "$O_SRV -Verify 10" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4830,6 +5636,7 @@ MAX_IM_CA='8' # are in place so that the semantics are consistent with the test description. requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c09.pem \ key_file=data_files/dir-maxpath/09.key" \ @@ -4839,6 +5646,7 @@ run_test "Authentication: server max_int chain, client default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4848,6 +5656,7 @@ run_test "Authentication: server max_int+1 chain, client default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client optional" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4858,6 +5667,7 @@ run_test "Authentication: server max_int+1 chain, client optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client none" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4868,6 +5678,7 @@ run_test "Authentication: server max_int+1 chain, client none" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server default" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4877,6 +5688,7 @@ run_test "Authentication: client max_int+1 chain, server default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server optional" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=optional" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4886,6 +5698,7 @@ run_test "Authentication: client max_int+1 chain, server optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server required" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4895,6 +5708,7 @@ run_test "Authentication: client max_int+1 chain, server required" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int chain, server required" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c09.pem \ @@ -4904,6 +5718,7 @@ run_test "Authentication: client max_int chain, server required" \ # Tests for CA list in CertificateRequest messages +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: send CA list in CertificateRequest (default)" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI crt_file=data_files/server6.crt \ @@ -4911,6 +5726,7 @@ run_test "Authentication: send CA list in CertificateRequest (default)" \ 0 \ -s "requested DN" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: do not send CA list in CertificateRequest" \ "$P_SRV debug_level=3 auth_mode=required cert_req_ca_list=0" \ "$P_CLI crt_file=data_files/server6.crt \ @@ -4918,6 +5734,7 @@ run_test "Authentication: do not send CA list in CertificateRequest" \ 0 \ -S "requested DN" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: send CA list in CertificateRequest, client self signed" \ "$P_SRV debug_level=3 auth_mode=required cert_req_ca_list=0" \ "$P_CLI debug_level=3 crt_file=data_files/server5-selfsigned.crt \ @@ -4934,6 +5751,7 @@ run_test "Authentication: send CA list in CertificateRequest, client self sig # When updating these tests, modify the matching authentication tests accordingly requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server badcert, client required" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4946,6 +5764,7 @@ run_test "Authentication, CA callback: server badcert, client required" \ -c "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server badcert, client optional" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4966,6 +5785,7 @@ run_test "Authentication, CA callback: server badcert, client optional" \ requires_config_enabled MBEDTLS_ECP_C requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server ECDH p256v1, client required, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4978,6 +5798,7 @@ run_test "Authentication, CA callback: server ECDH p256v1, client required, p requires_config_enabled MBEDTLS_ECP_C requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server ECDH p256v1, client optional, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4989,6 +5810,7 @@ run_test "Authentication, CA callback: server ECDH p256v1, client optional, p -c "bad server certificate (ECDH curve)" # Expect failure only at ECDH params check requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client SHA256, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -5000,6 +5822,7 @@ run_test "Authentication, CA callback: client SHA256, server required" \ -c "Supported Signature Algorithm found: 5," requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client SHA384, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -5011,6 +5834,7 @@ run_test "Authentication, CA callback: client SHA384, server required" \ -c "Supported Signature Algorithm found: 5," requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client badcert, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -5034,6 +5858,7 @@ run_test "Authentication, CA callback: client badcert, server required" \ # before reading the alert message. requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client cert not trusted, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-selfsigned.crt \ @@ -5053,6 +5878,7 @@ run_test "Authentication, CA callback: client cert not trusted, server requir -s "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client badcert, server optional" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -5074,6 +5900,7 @@ run_test "Authentication, CA callback: client badcert, server optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c09.pem \ key_file=data_files/dir-maxpath/09.key" \ @@ -5085,6 +5912,7 @@ run_test "Authentication, CA callback: server max_int chain, client default" requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int+1 chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -5096,6 +5924,7 @@ run_test "Authentication, CA callback: server max_int+1 chain, client default requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int+1 chain, client optional" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -5108,6 +5937,7 @@ run_test "Authentication, CA callback: server max_int+1 chain, client optiona requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int+1 chain, server optional" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=optional" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -5119,6 +5949,7 @@ run_test "Authentication, CA callback: client max_int+1 chain, server optiona requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int+1 chain, server required" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -5130,6 +5961,7 @@ run_test "Authentication, CA callback: client max_int+1 chain, server require requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int chain, server required" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c09.pem \ @@ -5140,6 +5972,7 @@ run_test "Authentication, CA callback: client max_int chain, server required" # Tests for certificate selection based on SHA version +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.2 -> SHA-2" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5150,6 +5983,7 @@ run_test "Certificate hash: client TLS 1.2 -> SHA-2" \ -c "signed using.*ECDSA with SHA256" \ -C "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1 -> SHA-1" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5160,6 +5994,7 @@ run_test "Certificate hash: client TLS 1.1 -> SHA-1" \ -C "signed using.*ECDSA with SHA256" \ -c "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.0 -> SHA-1" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5170,6 +6005,7 @@ run_test "Certificate hash: client TLS 1.0 -> SHA-1" \ -C "signed using.*ECDSA with SHA256" \ -c "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 1)" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5181,6 +6017,7 @@ run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 1)" \ -c "signed using.*ECDSA with SHA256" \ -C "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 2)" \ "$P_SRV crt_file=data_files/server6.crt \ key_file=data_files/server6.key \ @@ -5194,6 +6031,7 @@ run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 2)" \ # tests for SNI +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: no SNI callback" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ @@ -5203,6 +6041,7 @@ run_test "SNI: no SNI callback" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: matching cert 1" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5213,6 +6052,7 @@ run_test "SNI: matching cert 1" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: matching cert 2" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5223,6 +6063,7 @@ run_test "SNI: matching cert 2" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: no matching cert" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5235,6 +6076,7 @@ run_test "SNI: no matching cert" \ -c "mbedtls_ssl_handshake returned" \ -c "SSL - A fatal alert message was received from our peer" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth no override: optional" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5248,6 +6090,7 @@ run_test "SNI: client auth no override: optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth override: none -> optional" \ "$P_SRV debug_level=3 auth_mode=none \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5261,6 +6104,7 @@ run_test "SNI: client auth override: none -> optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth override: optional -> none" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5274,6 +6118,7 @@ run_test "SNI: client auth override: optional -> none" \ -c "skip write certificate verify" \ -s "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA no override" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5292,6 +6137,7 @@ run_test "SNI: CA no override" \ -s "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA override" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5310,6 +6156,7 @@ run_test "SNI: CA override" \ -S "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA override with CRL" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5330,6 +6177,7 @@ run_test "SNI: CA override with CRL" \ # Tests for SNI and DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, no SNI callback" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ @@ -5339,6 +6187,7 @@ run_test "SNI: DTLS, no SNI callback" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, matching cert 1" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5349,6 +6198,7 @@ run_test "SNI: DTLS, matching cert 1" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, matching cert 2" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5359,6 +6209,7 @@ run_test "SNI: DTLS, matching cert 2" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, no matching cert" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5371,6 +6222,7 @@ run_test "SNI: DTLS, no matching cert" \ -c "mbedtls_ssl_handshake returned" \ -c "SSL - A fatal alert message was received from our peer" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth no override: optional" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5384,6 +6236,7 @@ run_test "SNI: DTLS, client auth no override: optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth override: none -> optional" \ "$P_SRV debug_level=3 auth_mode=none dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5397,6 +6250,7 @@ run_test "SNI: DTLS, client auth override: none -> optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth override: optional -> none" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5410,6 +6264,7 @@ run_test "SNI: DTLS, client auth override: optional -> none" \ -c "skip write certificate verify" \ -s "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA no override" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5428,6 +6283,7 @@ run_test "SNI: DTLS, CA no override" \ -s "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA override" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5446,6 +6302,7 @@ run_test "SNI: DTLS, CA override" \ -S "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA override with CRL" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key dtls=1 \ @@ -5466,6 +6323,7 @@ run_test "SNI: DTLS, CA override with CRL" \ # Tests for non-blocking I/O: exercise a variety of handshake flows +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: basic handshake" \ "$P_SRV nbio=2 tickets=0 auth_mode=none" \ "$P_CLI nbio=2 tickets=0" \ @@ -5474,6 +6332,7 @@ run_test "Non-blocking I/O: basic handshake" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: client auth" \ "$P_SRV nbio=2 tickets=0 auth_mode=required" \ "$P_CLI nbio=2 tickets=0" \ @@ -5482,6 +6341,7 @@ run_test "Non-blocking I/O: client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket" \ "$P_SRV nbio=2 tickets=1 auth_mode=none" \ "$P_CLI nbio=2 tickets=1" \ @@ -5490,6 +6350,7 @@ run_test "Non-blocking I/O: ticket" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + client auth" \ "$P_SRV nbio=2 tickets=1 auth_mode=required" \ "$P_CLI nbio=2 tickets=1" \ @@ -5498,6 +6359,7 @@ run_test "Non-blocking I/O: ticket + client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + client auth + resume" \ "$P_SRV nbio=2 tickets=1 auth_mode=required" \ "$P_CLI nbio=2 tickets=1 reconnect=1" \ @@ -5506,6 +6368,7 @@ run_test "Non-blocking I/O: ticket + client auth + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + resume" \ "$P_SRV nbio=2 tickets=1 auth_mode=none" \ "$P_CLI nbio=2 tickets=1 reconnect=1" \ @@ -5514,6 +6377,7 @@ run_test "Non-blocking I/O: ticket + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: session-id resume" \ "$P_SRV nbio=2 tickets=0 auth_mode=none" \ "$P_CLI nbio=2 tickets=0 reconnect=1" \ @@ -5524,6 +6388,7 @@ run_test "Non-blocking I/O: session-id resume" \ # Tests for event-driven I/O: exercise a variety of handshake flows +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: basic handshake" \ "$P_SRV event=1 tickets=0 auth_mode=none" \ "$P_CLI event=1 tickets=0" \ @@ -5532,6 +6397,7 @@ run_test "Event-driven I/O: basic handshake" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: client auth" \ "$P_SRV event=1 tickets=0 auth_mode=required" \ "$P_CLI event=1 tickets=0" \ @@ -5540,6 +6406,7 @@ run_test "Event-driven I/O: client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket" \ "$P_SRV event=1 tickets=1 auth_mode=none" \ "$P_CLI event=1 tickets=1" \ @@ -5548,6 +6415,7 @@ run_test "Event-driven I/O: ticket" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + client auth" \ "$P_SRV event=1 tickets=1 auth_mode=required" \ "$P_CLI event=1 tickets=1" \ @@ -5556,6 +6424,7 @@ run_test "Event-driven I/O: ticket + client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + client auth + resume" \ "$P_SRV event=1 tickets=1 auth_mode=required" \ "$P_CLI event=1 tickets=1 reconnect=1" \ @@ -5564,6 +6433,7 @@ run_test "Event-driven I/O: ticket + client auth + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + resume" \ "$P_SRV event=1 tickets=1 auth_mode=none" \ "$P_CLI event=1 tickets=1 reconnect=1" \ @@ -5572,6 +6442,7 @@ run_test "Event-driven I/O: ticket + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: session-id resume" \ "$P_SRV event=1 tickets=0 auth_mode=none" \ "$P_CLI event=1 tickets=0 reconnect=1" \ @@ -5580,42 +6451,49 @@ run_test "Event-driven I/O: session-id resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: basic handshake" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=0" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: client auth" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=0" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + client auth" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + client auth + resume" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=1 reconnect=1 skip_close_notify=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + resume" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=1 reconnect=1 skip_close_notify=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: session-id resume" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=0 reconnect=1 skip_close_notify=1" \ @@ -5627,6 +6505,7 @@ run_test "Event-driven I/O, DTLS: session-id resume" \ # within the same datagram as the Finished messages. In this situation, the # server MUST NOT idle on the underlying transport after handshake completion, # because the ApplicationData request has already been queued internally. +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: session-id resume, UDP packing" \ -p "$P_PXY pack=50" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=required" \ @@ -5718,6 +6597,7 @@ run_test "Version check: srv min 1.2, cli max 1.1 -> fail" \ # Tests for ALPN extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: none" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -5730,6 +6610,7 @@ run_test "ALPN: none" \ -C "Application Layer Protocol is" \ -S "Application Layer Protocol is" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: client only" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 alpn=abc,1234" \ @@ -5742,6 +6623,7 @@ run_test "ALPN: client only" \ -c "Application Layer Protocol is (none)" \ -S "Application Layer Protocol is" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: server only" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3" \ @@ -5754,6 +6636,7 @@ run_test "ALPN: server only" \ -C "Application Layer Protocol is" \ -s "Application Layer Protocol is (none)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli1-srv1" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=abc,1234" \ @@ -5766,6 +6649,7 @@ run_test "ALPN: both, common cli1-srv1" \ -c "Application Layer Protocol is abc" \ -s "Application Layer Protocol is abc" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli2-srv1" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=1234,abc" \ @@ -5778,6 +6662,7 @@ run_test "ALPN: both, common cli2-srv1" \ -c "Application Layer Protocol is abc" \ -s "Application Layer Protocol is abc" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli1-srv2" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=1234,abcde" \ @@ -5790,6 +6675,7 @@ run_test "ALPN: both, common cli1-srv2" \ -c "Application Layer Protocol is 1234" \ -s "Application Layer Protocol is 1234" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, no common" \ "$P_SRV debug_level=3 alpn=abc,123" \ "$P_CLI debug_level=3 alpn=1234,abcde" \ @@ -5806,6 +6692,7 @@ run_test "ALPN: both, no common" \ # Tests for keyUsage in leaf certificates, part 1: # server-side certificate/suite selection +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, digitalSignature -> (EC)DHE-RSA" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ds.crt" \ @@ -5814,6 +6701,7 @@ run_test "keyUsage srv: RSA, digitalSignature -> (EC)DHE-RSA" \ -c "Ciphersuite is TLS-[EC]*DHE-RSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, keyEncipherment -> RSA" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ke.crt" \ @@ -5821,6 +6709,7 @@ run_test "keyUsage srv: RSA, keyEncipherment -> RSA" \ 0 \ -c "Ciphersuite is TLS-RSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, keyAgreement -> fail" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ka.crt" \ @@ -5828,6 +6717,7 @@ run_test "keyUsage srv: RSA, keyAgreement -> fail" \ 1 \ -C "Ciphersuite is " +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, digitalSignature -> ECDHE-ECDSA" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ds.crt" \ @@ -5836,6 +6726,7 @@ run_test "keyUsage srv: ECDSA, digitalSignature -> ECDHE-ECDSA" \ -c "Ciphersuite is TLS-ECDHE-ECDSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, keyAgreement -> ECDH-" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -5843,6 +6734,7 @@ run_test "keyUsage srv: ECDSA, keyAgreement -> ECDH-" \ 0 \ -c "Ciphersuite is TLS-ECDH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, keyEncipherment -> fail" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ke.crt" \ @@ -5853,6 +6745,7 @@ run_test "keyUsage srv: ECDSA, keyEncipherment -> fail" \ # Tests for keyUsage in leaf certificates, part 2: # client-side checking of server cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature+KeyEncipherment, RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds_ke.crt" \ @@ -5863,6 +6756,7 @@ run_test "keyUsage cli: DigitalSignature+KeyEncipherment, RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature+KeyEncipherment, DHE-RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds_ke.crt" \ @@ -5873,6 +6767,7 @@ run_test "keyUsage cli: DigitalSignature+KeyEncipherment, DHE-RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5883,6 +6778,7 @@ run_test "keyUsage cli: KeyEncipherment, RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5893,6 +6789,7 @@ run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail" \ -c "Processing of the Certificate handshake message failed" \ -C "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail, soft" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5904,6 +6801,7 @@ run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail, soft" \ -c "Ciphersuite is TLS-" \ -c "! Usage does not match the keyUsage extension" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, DHE-RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5914,6 +6812,7 @@ run_test "keyUsage cli: DigitalSignature, DHE-RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, RSA: fail" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5924,6 +6823,7 @@ run_test "keyUsage cli: DigitalSignature, RSA: fail" \ -c "Processing of the Certificate handshake message failed" \ -C "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, RSA: fail, soft" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5938,6 +6838,7 @@ run_test "keyUsage cli: DigitalSignature, RSA: fail, soft" \ # Tests for keyUsage in leaf certificates, part 3: # server-side checking of client cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, DigitalSignature: OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server2.key \ @@ -5946,6 +6847,7 @@ run_test "keyUsage cli-auth: RSA, DigitalSignature: OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server2.key \ @@ -5954,6 +6856,7 @@ run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (soft)" \ -s "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (hard)" \ "$P_SRV debug_level=1 auth_mode=required" \ "$O_CLI -key data_files/server2.key \ @@ -5962,6 +6865,7 @@ run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (hard)" \ -s "bad certificate (usage extensions)" \ -s "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: ECDSA, DigitalSignature: OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -5970,6 +6874,7 @@ run_test "keyUsage cli-auth: ECDSA, DigitalSignature: OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: ECDSA, KeyAgreement: fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -5980,24 +6885,28 @@ run_test "keyUsage cli-auth: ECDSA, KeyAgreement: fail (soft)" \ # Tests for extendedKeyUsage, part 1: server-side certificate/suite selection +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: serverAuth -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-srv.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: serverAuth,clientAuth -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-srv.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: codeSign,anyEKU -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-cs_any.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: codeSign -> fail" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-cli.crt" \ @@ -6006,6 +6915,7 @@ run_test "extKeyUsage srv: codeSign -> fail" \ # Tests for extendedKeyUsage, part 2: client-side checking of server cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: serverAuth -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-srv.crt" \ @@ -6015,6 +6925,7 @@ run_test "extKeyUsage cli: serverAuth -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: serverAuth,clientAuth -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-srv_cli.crt" \ @@ -6024,6 +6935,7 @@ run_test "extKeyUsage cli: serverAuth,clientAuth -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: codeSign,anyEKU -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-cs_any.crt" \ @@ -6033,6 +6945,7 @@ run_test "extKeyUsage cli: codeSign,anyEKU -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: codeSign -> fail" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-cs.crt" \ @@ -6044,6 +6957,7 @@ run_test "extKeyUsage cli: codeSign -> fail" \ # Tests for extendedKeyUsage, part 3: server-side checking of client cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: clientAuth -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6052,6 +6966,7 @@ run_test "extKeyUsage cli-auth: clientAuth -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: serverAuth,clientAuth -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6060,6 +6975,7 @@ run_test "extKeyUsage cli-auth: serverAuth,clientAuth -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign,anyEKU -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6068,6 +6984,7 @@ run_test "extKeyUsage cli-auth: codeSign,anyEKU -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign -> fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6076,6 +6993,7 @@ run_test "extKeyUsage cli-auth: codeSign -> fail (soft)" \ -s "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign -> fail (hard)" \ "$P_SRV debug_level=1 auth_mode=required" \ "$O_CLI -key data_files/server5.key \ @@ -6086,6 +7004,7 @@ run_test "extKeyUsage cli-auth: codeSign -> fail (hard)" \ # Tests for DHM parameters loading +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM parameters: reference" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6094,6 +7013,7 @@ run_test "DHM parameters: reference" \ -c "value of 'DHM: P ' (2048 bits)" \ -c "value of 'DHM: G ' (2 bits)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM parameters: other parameters" \ "$P_SRV dhm_file=data_files/dhparams.pem" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6104,6 +7024,7 @@ run_test "DHM parameters: other parameters" \ # Tests for DHM client-side size checking +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server default, client default, OK" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6111,6 +7032,7 @@ run_test "DHM size: server default, client default, OK" \ 0 \ -C "DHM prime too short:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server default, client 2048, OK" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6118,6 +7040,7 @@ run_test "DHM size: server default, client 2048, OK" \ 0 \ -C "DHM prime too short:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server 1024, client default, OK" \ "$P_SRV dhm_file=data_files/dhparams.pem" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6176,6 +7099,7 @@ run_test "DHM size: server default, client 2049, rejected" \ # Tests for PSK callback +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: psk, no callback" \ "$P_SRV psk=abc123 psk_identity=foo" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6186,6 +7110,7 @@ run_test "PSK callback: psk, no callback" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6200,6 +7125,7 @@ run_test "PSK callback: opaque psk on client, no callback" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6214,6 +7140,7 @@ run_test "PSK callback: opaque psk on client, no callback, SHA-384" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, EMS" \ "$P_SRV extended_ms=1 debug_level=3 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=1 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6228,6 +7155,7 @@ run_test "PSK callback: opaque psk on client, no callback, EMS" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, SHA-384, EMS" \ "$P_SRV extended_ms=1 debug_level=3 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=1 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6242,6 +7170,7 @@ run_test "PSK callback: opaque psk on client, no callback, SHA-384, EMS" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6256,6 +7185,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6270,6 +7200,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, EMS" \ "$P_SRV debug_level=3 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA extended_ms=1" \ @@ -6285,6 +7216,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, EMS, SHA384" \ "$P_SRV debug_level=3 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 extended_ms=1" \ @@ -6300,6 +7232,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6314,6 +7247,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6328,6 +7262,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, EMS" \ "$P_SRV debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA extended_ms=1" \ @@ -6343,6 +7278,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, EMS, SHA384" \ "$P_SRV debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 extended_ms=1" \ @@ -6358,6 +7294,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static raw PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6372,6 +7309,7 @@ run_test "PSK callback: raw psk on client, mismatching static raw PSK on serv -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static opaque PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6386,6 +7324,7 @@ run_test "PSK callback: raw psk on client, mismatching static opaque PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static opaque PSK on server, raw PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6399,6 +7338,7 @@ run_test "PSK callback: raw psk on client, mismatching static opaque PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, id-matching but wrong raw PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=def psk=abc123 debug_level=3 psk_list=abc,dead,def,beef min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6412,6 +7352,7 @@ run_test "PSK callback: raw psk on client, id-matching but wrong raw PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, matching opaque PSK on server, wrong opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=def psk=beef debug_level=3 psk_list=abc,dead,def,abc123 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6419,6 +7360,7 @@ run_test "PSK callback: raw psk on client, matching opaque PSK on server, wro 1 \ -s "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: no psk, no callback" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6428,6 +7370,7 @@ run_test "PSK callback: no psk, no callback" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: callback overrides other settings" \ "$P_SRV psk=abc123 psk_identity=foo psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6437,6 +7380,7 @@ run_test "PSK callback: callback overrides other settings" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: first id matches" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6446,6 +7390,7 @@ run_test "PSK callback: first id matches" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: second id matches" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6455,6 +7400,7 @@ run_test "PSK callback: second id matches" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: no match" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6464,6 +7410,7 @@ run_test "PSK callback: no match" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: wrong key" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6476,6 +7423,7 @@ run_test "PSK callback: wrong key" \ # Tests for EC J-PAKE requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: client not configured" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -6490,6 +7438,7 @@ run_test "ECJPAKE: client not configured" \ -S "None of the common ciphersuites is usable" requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: server not configured" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 ecjpake_pw=bla \ @@ -6505,6 +7454,7 @@ run_test "ECJPAKE: server not configured" \ -s "None of the common ciphersuites is usable" requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: working, TLS" \ "$P_SRV debug_level=3 ecjpake_pw=bla" \ "$P_CLI debug_level=3 ecjpake_pw=bla \ @@ -6571,6 +7521,7 @@ run_test "ECJPAKE: working, DTLS, nolog" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: SSL3" \ "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=ssl3" \ @@ -6579,6 +7530,7 @@ run_test "Per-version suites: SSL3" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: TLS 1.0" \ "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=tls1 arc4=1" \ @@ -6587,6 +7539,7 @@ run_test "Per-version suites: TLS 1.0" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: TLS 1.1" \ "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=tls1_1" \ @@ -6595,6 +7548,7 @@ run_test "Per-version suites: TLS 1.1" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: TLS 1.2" \ "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=tls12" \ @@ -6604,6 +7558,7 @@ run_test "Per-version suites: TLS 1.2" \ # Test for ClientHello without extensions requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ClientHello without extensions" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -6654,6 +7609,7 @@ run_test "Small client packet SSLv3 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6661,6 +7617,7 @@ run_test "Small client packet TLS 1.0 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1 etm=0 \ @@ -6669,6 +7626,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6677,6 +7635,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6684,6 +7643,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6691,6 +7651,7 @@ run_test "Small client packet TLS 1.0 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6699,6 +7660,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6707,6 +7669,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -6714,6 +7677,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6721,6 +7685,7 @@ run_test "Small client packet TLS 1.1 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6729,6 +7694,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6737,6 +7703,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6744,6 +7711,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6751,6 +7719,7 @@ run_test "Small client packet TLS 1.1 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6759,6 +7728,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6767,6 +7737,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6774,6 +7745,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6781,6 +7753,7 @@ run_test "Small client packet TLS 1.2 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6788,6 +7761,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6796,6 +7770,7 @@ run_test "Small client packet TLS 1.2 BlockCipher larger MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6804,6 +7779,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6811,6 +7787,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6818,6 +7795,7 @@ run_test "Small client packet TLS 1.2 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6826,6 +7804,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6834,6 +7813,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6841,6 +7821,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 AEAD" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6848,6 +7829,7 @@ run_test "Small client packet TLS 1.2 AEAD" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 AEAD shorter tag" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6858,6 +7840,7 @@ run_test "Small client packet TLS 1.2 AEAD shorter tag" \ # Tests for small client packets in DTLS requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0" \ "$P_SRV dtls=1 force_version=dtls1" \ "$P_CLI dtls=1 request_size=1 \ @@ -6866,6 +7849,7 @@ run_test "Small client packet DTLS 1.0" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, without EtM" \ "$P_SRV dtls=1 force_version=dtls1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6875,6 +7859,7 @@ run_test "Small client packet DTLS 1.0, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, truncated hmac" \ "$P_SRV dtls=1 force_version=dtls1 trunc_hmac=1" \ "$P_CLI dtls=1 request_size=1 trunc_hmac=1 \ @@ -6884,6 +7869,7 @@ run_test "Small client packet DTLS 1.0, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, without EtM, truncated MAC" \ "$P_SRV dtls=1 force_version=dtls1 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6892,6 +7878,7 @@ run_test "Small client packet DTLS 1.0, without EtM, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2" \ "$P_SRV dtls=1 force_version=dtls12" \ "$P_CLI dtls=1 request_size=1 \ @@ -6900,6 +7887,7 @@ run_test "Small client packet DTLS 1.2" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, without EtM" \ "$P_SRV dtls=1 force_version=dtls12 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6909,6 +7897,7 @@ run_test "Small client packet DTLS 1.2, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, truncated hmac" \ "$P_SRV dtls=1 force_version=dtls12 trunc_hmac=1" \ "$P_CLI dtls=1 request_size=1 \ @@ -6918,6 +7907,7 @@ run_test "Small client packet DTLS 1.2, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, without EtM, truncated MAC" \ "$P_SRV dtls=1 force_version=dtls12 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6941,6 +7931,7 @@ run_test "Small server packet SSLv3 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1 \ @@ -6948,6 +7939,7 @@ run_test "Small server packet TLS 1.0 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1 etm=0 \ @@ -6956,6 +7948,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6964,6 +7957,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6971,6 +7965,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -6978,6 +7973,7 @@ run_test "Small server packet TLS 1.0 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -6986,6 +7982,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6994,6 +7991,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -7001,6 +7999,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1_1 \ @@ -7008,6 +8007,7 @@ run_test "Small server packet TLS 1.1 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1_1 \ @@ -7016,6 +8016,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7024,6 +8025,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7031,6 +8033,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7038,6 +8041,7 @@ run_test "Small server packet TLS 1.1 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7046,6 +8050,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7054,6 +8059,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7061,6 +8067,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7068,6 +8075,7 @@ run_test "Small server packet TLS 1.2 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7075,6 +8083,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7083,6 +8092,7 @@ run_test "Small server packet TLS 1.2 BlockCipher larger MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7091,6 +8101,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7098,6 +8109,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7105,6 +8117,7 @@ run_test "Small server packet TLS 1.2 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7113,6 +8126,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7121,6 +8135,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7128,6 +8143,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 AEAD" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7135,6 +8151,7 @@ run_test "Small server packet TLS 1.2 AEAD" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 AEAD shorter tag" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7145,6 +8162,7 @@ run_test "Small server packet TLS 1.2 AEAD shorter tag" \ # Tests for small server packets in DTLS requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1" \ "$P_CLI dtls=1 \ @@ -7153,6 +8171,7 @@ run_test "Small server packet DTLS 1.0" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, without EtM" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 etm=0" \ "$P_CLI dtls=1 \ @@ -7162,6 +8181,7 @@ run_test "Small server packet DTLS 1.0, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, truncated hmac" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 trunc_hmac=1" \ "$P_CLI dtls=1 trunc_hmac=1 \ @@ -7171,6 +8191,7 @@ run_test "Small server packet DTLS 1.0, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, without EtM, truncated MAC" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 \ @@ -7179,6 +8200,7 @@ run_test "Small server packet DTLS 1.0, without EtM, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12" \ "$P_CLI dtls=1 \ @@ -7187,6 +8209,7 @@ run_test "Small server packet DTLS 1.2" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, without EtM" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 etm=0" \ "$P_CLI dtls=1 \ @@ -7196,6 +8219,7 @@ run_test "Small server packet DTLS 1.2, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, truncated hmac" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 trunc_hmac=1" \ "$P_CLI dtls=1 \ @@ -7205,6 +8229,7 @@ run_test "Small server packet DTLS 1.2, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, without EtM, truncated MAC" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 \ @@ -7244,6 +8269,7 @@ run_test "Large client packet SSLv3 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \ @@ -7252,6 +8278,7 @@ run_test "Large client packet TLS 1.0 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1 etm=0 recsplit=0 \ @@ -7260,6 +8287,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \ @@ -7269,6 +8297,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 etm=0 recsplit=0 \ @@ -7276,6 +8305,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7283,6 +8313,7 @@ run_test "Large client packet TLS 1.0 StreamCipher" \ 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7291,6 +8322,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7299,6 +8331,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7307,6 +8340,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7315,6 +8349,7 @@ run_test "Large client packet TLS 1.1 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1_1 etm=0 \ @@ -7323,6 +8358,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7331,6 +8367,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7338,6 +8375,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7346,6 +8384,7 @@ run_test "Large client packet TLS 1.1 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7355,6 +8394,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7363,6 +8403,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7371,6 +8412,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7379,6 +8421,7 @@ run_test "Large client packet TLS 1.2 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 etm=0 \ @@ -7386,6 +8429,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7395,6 +8439,7 @@ run_test "Large client packet TLS 1.2 BlockCipher larger MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7403,6 +8448,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7411,6 +8457,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, without EtM, truncated MAC -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7419,6 +8466,7 @@ run_test "Large client packet TLS 1.2 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7427,6 +8475,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7435,6 +8484,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7443,6 +8493,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 AEAD" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7451,6 +8502,7 @@ run_test "Large client packet TLS 1.2 AEAD" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 AEAD shorter tag" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7478,6 +8530,7 @@ run_test "Large server packet SSLv3 BlockCipher" \ -c "16383 bytes read"\ -C "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 recsplit=0 \ @@ -7487,6 +8540,7 @@ run_test "Large server packet TLS 1.0 BlockCipher" \ -c "16383 bytes read"\ -C "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 etm=0 recsplit=0 \ @@ -7497,6 +8551,7 @@ run_test "Large server packet TLS 1.0 BlockCipher, without EtM" \ -C "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 recsplit=0 \ @@ -7508,6 +8563,7 @@ run_test "Large server packet TLS 1.0 BlockCipher truncated MAC" \ -C "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7517,6 +8573,7 @@ run_test "Large server packet TLS 1.0 StreamCipher truncated MAC" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7525,6 +8582,7 @@ run_test "Large server packet TLS 1.0 StreamCipher" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7534,6 +8592,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -7543,6 +8602,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -7551,6 +8611,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 \ @@ -7558,6 +8619,7 @@ run_test "Large server packet TLS 1.1 BlockCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 etm=0 \ @@ -7567,6 +8629,7 @@ run_test "Large server packet TLS 1.1 BlockCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 \ @@ -7576,6 +8639,7 @@ run_test "Large server packet TLS 1.1 BlockCipher truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7584,6 +8648,7 @@ run_test "Large server packet TLS 1.1 BlockCipher, without EtM, truncated MAC -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7591,6 +8656,7 @@ run_test "Large server packet TLS 1.1 StreamCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7600,6 +8666,7 @@ run_test "Large server packet TLS 1.1 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7608,6 +8675,7 @@ run_test "Large server packet TLS 1.1 StreamCipher truncated MAC" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7616,6 +8684,7 @@ run_test "Large server packet TLS 1.1 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7623,6 +8692,7 @@ run_test "Large server packet TLS 1.2 BlockCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 etm=0 \ @@ -7631,6 +8701,7 @@ run_test "Large server packet TLS 1.2 BlockCipher, without EtM" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7639,6 +8710,7 @@ run_test "Large server packet TLS 1.2 BlockCipher larger MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7647,6 +8719,7 @@ run_test "Large server packet TLS 1.2 BlockCipher truncated MAC" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7655,6 +8728,7 @@ run_test "Large server packet TLS 1.2 BlockCipher, without EtM, truncated MAC -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7663,6 +8737,7 @@ run_test "Large server packet TLS 1.2 StreamCipher" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7672,6 +8747,7 @@ run_test "Large server packet TLS 1.2 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7681,6 +8757,7 @@ run_test "Large server packet TLS 1.2 StreamCipher truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7689,6 +8766,7 @@ run_test "Large server packet TLS 1.2 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 AEAD" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7696,6 +8774,7 @@ run_test "Large server packet TLS 1.2 AEAD" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 AEAD shorter tag" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7706,6 +8785,7 @@ run_test "Large server packet TLS 1.2 AEAD shorter tag" \ # Tests for restartable ECC requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, default" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7718,6 +8798,7 @@ run_test "EC restart: TLS, default" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=0" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7730,6 +8811,7 @@ run_test "EC restart: TLS, max_ops=0" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=65535" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7742,6 +8824,7 @@ run_test "EC restart: TLS, max_ops=65535" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7754,6 +8837,7 @@ run_test "EC restart: TLS, max_ops=1000" \ -c "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7771,6 +8855,7 @@ run_test "EC restart: TLS, max_ops=1000, badsign" \ -c "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, auth_mode=optional badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7788,6 +8873,7 @@ run_test "EC restart: TLS, max_ops=1000, auth_mode=optional badsign" \ -C "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, auth_mode=none badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7805,6 +8891,7 @@ run_test "EC restart: TLS, max_ops=1000, auth_mode=none badsign" \ -C "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: DTLS, max_ops=1000" \ "$P_SRV auth_mode=required dtls=1" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7817,6 +8904,7 @@ run_test "EC restart: DTLS, max_ops=1000" \ -c "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000 no client auth" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7828,6 +8916,7 @@ run_test "EC restart: TLS, max_ops=1000 no client auth" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, ECDHE-PSK" \ "$P_SRV psk=abc123" \ "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 \ @@ -7841,6 +8930,7 @@ run_test "EC restart: TLS, max_ops=1000, ECDHE-PSK" \ # Tests of asynchronous private key support in SSL requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=0" \ "$P_SRV \ async_operations=s async_private_delay1=0 async_private_delay2=0" \ @@ -7850,6 +8940,7 @@ run_test "SSL async private: sign, delay=0" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=1" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1" \ @@ -7860,6 +8951,7 @@ run_test "SSL async private: sign, delay=1" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=2" \ "$P_SRV \ async_operations=s async_private_delay1=2 async_private_delay2=2" \ @@ -7883,6 +8975,7 @@ run_test "SSL async private: sign, RSA, TLS 1.1" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, SNI" \ "$P_SRV debug_level=3 \ async_operations=s async_private_delay1=0 async_private_delay2=0 \ @@ -7897,6 +8990,7 @@ run_test "SSL async private: sign, SNI" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, delay=0" \ "$P_SRV \ async_operations=d async_private_delay1=0 async_private_delay2=0" \ @@ -7906,6 +9000,7 @@ run_test "SSL async private: decrypt, delay=0" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, delay=1" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7916,6 +9011,7 @@ run_test "SSL async private: decrypt, delay=1" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt RSA-PSK, delay=0" \ "$P_SRV psk=abc123 \ async_operations=d async_private_delay1=0 async_private_delay2=0" \ @@ -7926,6 +9022,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=0" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt RSA-PSK, delay=1" \ "$P_SRV psk=abc123 \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7937,6 +9034,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=1" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign callback not present" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7950,6 +9048,7 @@ run_test "SSL async private: sign callback not present" \ -s "Successful connection" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt callback not present" \ "$P_SRV debug_level=1 \ async_operations=s async_private_delay1=1 async_private_delay2=1" \ @@ -7964,6 +9063,7 @@ run_test "SSL async private: decrypt callback not present" \ # key1: ECDSA, key2: RSA; use key1 from slot 0 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 0 used with key1" \ "$P_SRV \ async_operations=s async_private_delay1=1 \ @@ -7977,6 +9077,7 @@ run_test "SSL async private: slot 0 used with key1" \ # key1: ECDSA, key2: RSA; use key2 from slot 0 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 0 used with key2" \ "$P_SRV \ async_operations=s async_private_delay2=1 \ @@ -7990,6 +9091,7 @@ run_test "SSL async private: slot 0 used with key2" \ # key1: ECDSA, key2: RSA; use key2 from slot 1 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 1 used with key2" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8003,6 +9105,7 @@ run_test "SSL async private: slot 1 used with key2" \ # key1: ECDSA, key2: RSA; use key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 \ @@ -8013,6 +9116,7 @@ run_test "SSL async private: fall back to transparent key" \ -s "Async sign callback: no key matches this certificate." requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8025,6 +9129,7 @@ run_test "SSL async private: sign, error in start" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, cancel after start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8036,6 +9141,7 @@ run_test "SSL async private: sign, cancel after start" \ -s "Async cancel" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in resume" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8048,6 +9154,7 @@ run_test "SSL async private: sign, error in resume" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, error in start" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8060,6 +9167,7 @@ run_test "SSL async private: decrypt, error in start" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, cancel after start" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8071,6 +9179,7 @@ run_test "SSL async private: decrypt, cancel after start" \ -s "Async cancel" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, error in resume" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8083,6 +9192,7 @@ run_test "SSL async private: decrypt, error in resume" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: cancel after start then operate correctly" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8095,6 +9205,7 @@ run_test "SSL async private: cancel after start then operate correctly" \ -s "Successful connection" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: error in resume then operate correctly" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8107,6 +9218,7 @@ run_test "SSL async private: error in resume then operate correctly" \ # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: cancel after start then fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_error=-2 \ @@ -8125,6 +9237,7 @@ run_test "SSL async private: cancel after start then fall back to transparent # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in resume then fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_error=-3 \ @@ -8141,6 +9254,7 @@ run_test "SSL async private: sign, error in resume then fall back to transpar requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: client-initiated, sign" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8152,6 +9266,7 @@ run_test "SSL async private: renegotiation: client-initiated, sign" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: server-initiated, sign" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8163,6 +9278,7 @@ run_test "SSL async private: renegotiation: server-initiated, sign" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: client-initiated, decrypt" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8175,6 +9291,7 @@ run_test "SSL async private: renegotiation: client-initiated, decrypt" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: server-initiated, decrypt" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8191,6 +9308,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force a non ECC ciphersuite in the client side" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA256" \ @@ -8204,6 +9322,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force a non ECC ciphersuite in the server side" \ "$P_SRV debug_level=3 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA256" \ "$P_CLI debug_level=3" \ @@ -8215,6 +9334,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force an ECC ciphersuite in the client side" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -8228,6 +9348,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force an ECC ciphersuite in the server side" \ "$P_SRV debug_level=3 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ "$P_CLI debug_level=3" \ @@ -8237,6 +9358,7 @@ run_test "Force an ECC ciphersuite in the server side" \ # Tests for DTLS HelloVerifyRequest +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled" \ "$P_SRV dtls=1 debug_level=2" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8248,6 +9370,7 @@ run_test "DTLS cookie: enabled" \ -s "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: disabled" \ "$P_SRV dtls=1 debug_level=2 cookies=0" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8259,6 +9382,7 @@ run_test "DTLS cookie: disabled" \ -S "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: default (failing)" \ "$P_SRV dtls=1 debug_level=2 cookies=-1" \ "$P_CLI dtls=1 debug_level=2 hs_timeout=100-400" \ @@ -8271,6 +9395,7 @@ run_test "DTLS cookie: default (failing)" \ -s "SSL - The requested feature is not available" requires_ipv6 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled, IPv6" \ "$P_SRV dtls=1 debug_level=2 server_addr=::1" \ "$P_CLI dtls=1 debug_level=2 server_addr=::1" \ @@ -8282,6 +9407,7 @@ run_test "DTLS cookie: enabled, IPv6" \ -s "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled, nbio" \ "$P_SRV dtls=1 nbio=2 debug_level=2" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -8296,6 +9422,7 @@ run_test "DTLS cookie: enabled, nbio" \ # Tests for client reconnecting from the same port with DTLS not_with_valgrind # spurious resend +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reference" \ "$P_SRV dtls=1 exchanges=2 read_timeout=20000 hs_timeout=10000-20000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=10000-20000" \ @@ -8305,6 +9432,7 @@ run_test "DTLS client reconnect from same port: reference" \ -S "Client initiated reconnection from same port" not_with_valgrind # spurious resend +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect" \ "$P_SRV dtls=1 exchanges=2 read_timeout=20000 hs_timeout=10000-20000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=10000-20000 reconnect_hard=1" \ @@ -8314,6 +9442,7 @@ run_test "DTLS client reconnect from same port: reconnect" \ -s "Client initiated reconnection from same port" not_with_valgrind # server/client too slow to respond in time (next test has higher timeouts) +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect, nbio, no valgrind" \ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 nbio=2" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-1000 reconnect_hard=1" \ @@ -8322,6 +9451,7 @@ run_test "DTLS client reconnect from same port: reconnect, nbio, no valgrind" -s "Client initiated reconnection from same port" only_with_valgrind # Only with valgrind, do previous test but with higher read_timeout and hs_timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect, nbio, valgrind" \ "$P_SRV dtls=1 exchanges=2 read_timeout=2000 nbio=2 hs_timeout=1500-6000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=1500-3000 reconnect_hard=1" \ @@ -8329,6 +9459,7 @@ run_test "DTLS client reconnect from same port: reconnect, nbio, valgrind" \ -S "The operation timed out" \ -s "Client initiated reconnection from same port" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: no cookies" \ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 cookies=0" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-8000 reconnect_hard=1" \ @@ -8336,6 +9467,7 @@ run_test "DTLS client reconnect from same port: no cookies" \ -s "The operation timed out" \ -S "Client initiated reconnection from same port" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: attacker-injected" \ -p "$P_PXY inject_clihlo=1" \ "$P_SRV dtls=1 exchanges=2 debug_level=1" \ @@ -8347,18 +9479,21 @@ run_test "DTLS client reconnect from same port: attacker-injected" \ # Tests for various cases of client authentication with DTLS # (focused on handshake flows and message parsing) +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: required" \ "$P_SRV dtls=1 auth_mode=required" \ "$P_CLI dtls=1" \ 0 \ -s "Verifying peer X.509 certificate... ok" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: optional, client has no cert" \ "$P_SRV dtls=1 auth_mode=optional" \ "$P_CLI dtls=1 crt_file=none key_file=none" \ 0 \ -s "! Certificate was missing" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: none, client has no cert" \ "$P_SRV dtls=1 auth_mode=none" \ "$P_CLI dtls=1 crt_file=none key_file=none debug_level=2" \ @@ -8366,6 +9501,7 @@ run_test "DTLS client auth: none, client has no cert" \ -c "skip write certificate$" \ -s "! Certificate verification was skipped" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS wrong PSK: badmac alert" \ "$P_SRV dtls=1 psk=abc123 force_ciphersuite=TLS-PSK-WITH-AES-128-GCM-SHA256" \ "$P_CLI dtls=1 psk=abc124" \ @@ -8376,6 +9512,7 @@ run_test "DTLS wrong PSK: badmac alert" \ # Tests for receiving fragmented handshake messages with DTLS requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: no fragmentation (gnutls server)" \ "$G_SRV -u --mtu 2048 -a" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8384,6 +9521,7 @@ run_test "DTLS reassembly: no fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: some fragmentation (gnutls server)" \ "$G_SRV -u --mtu 512" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8392,6 +9530,7 @@ run_test "DTLS reassembly: some fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation (gnutls server)" \ "$G_SRV -u --mtu 128" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8400,6 +9539,7 @@ run_test "DTLS reassembly: more fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation, nbio (gnutls server)" \ "$G_SRV -u --mtu 128" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -8409,6 +9549,7 @@ run_test "DTLS reassembly: more fragmentation, nbio (gnutls server)" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, renego (gnutls server)" \ "$G_SRV -u --mtu 256" \ "$P_CLI debug_level=3 dtls=1 renegotiation=1 renegotiate=1" \ @@ -8423,6 +9564,7 @@ run_test "DTLS reassembly: fragmentation, renego (gnutls server)" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \ "$G_SRV -u --mtu 256" \ "$P_CLI debug_level=3 nbio=2 dtls=1 renegotiation=1 renegotiate=1" \ @@ -8435,6 +9577,7 @@ run_test "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \ -C "error" \ -s "Extra-header:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: no fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 2048" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8442,6 +9585,7 @@ run_test "DTLS reassembly: no fragmentation (openssl server)" \ -C "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: some fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 768" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8449,6 +9593,7 @@ run_test "DTLS reassembly: some fragmentation (openssl server)" \ -c "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 256" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8456,6 +9601,7 @@ run_test "DTLS reassembly: more fragmentation (openssl server)" \ -c "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, nbio (openssl server)" \ "$O_SRV -dtls1 -mtu 256" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -9970,6 +11116,7 @@ run_test "DTLS-SRTP all profiles supported. mki used. gnutls server." \ # Tests for specific things with "unreliable" UDP connection not_with_valgrind # spurious resend due to timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: reference" \ -p "$P_PXY" \ "$P_SRV dtls=1 debug_level=2 hs_timeout=10000-20000" \ @@ -9988,6 +11135,7 @@ run_test "DTLS proxy: reference" \ -c "HTTP/1.0 200 OK" not_with_valgrind # spurious resend due to timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: duplicate every packet" \ -p "$P_PXY duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2 hs_timeout=10000-20000" \ @@ -10001,6 +11149,7 @@ run_test "DTLS proxy: duplicate every packet" \ -s "Extra-header:" \ -c "HTTP/1.0 200 OK" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: duplicate every packet, server anti-replay off" \ -p "$P_PXY duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2 anti_replay=0" \ @@ -10015,6 +11164,7 @@ run_test "DTLS proxy: duplicate every packet, server anti-replay off" \ -s "Extra-header:" \ -c "HTTP/1.0 200 OK" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: multiple records in same datagram" \ -p "$P_PXY pack=50" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ @@ -10023,6 +11173,7 @@ run_test "DTLS proxy: multiple records in same datagram" \ -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: multiple records in same datagram, duplicate every packet" \ -p "$P_PXY pack=50 duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ @@ -10031,6 +11182,7 @@ run_test "DTLS proxy: multiple records in same datagram, duplicate every pack -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, default badmac_limit" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1" \ @@ -10043,6 +11195,7 @@ run_test "DTLS proxy: inject invalid AD record, default badmac_limit" \ -S "too many records with bad MAC" \ -S "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 1" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=1" \ @@ -10055,6 +11208,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 1" \ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 2" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2" \ @@ -10067,6 +11221,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2" \ -S "too many records with bad MAC" \ -S "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2 exchanges=2" \ @@ -10079,6 +11234,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: delay ChangeCipherSpec" \ -p "$P_PXY delay_ccs=1" \ "$P_SRV dtls=1 debug_level=1 dgram_packing=0" \ @@ -10133,6 +11289,7 @@ run_test "DTLS reordering: Buffer out-of-order handshake message fragment on # while keeping the ServerKeyExchange. requires_certificate_authentication requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1300 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next" \ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10156,6 +11313,7 @@ run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling nex requires_certificate_authentication requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 900 requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1299 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg" \ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10224,6 +11382,7 @@ run_test "DTLS reordering: Buffer out-of-order CCS message on server"\ -s "Injecting buffered CCS message" \ -s "Remember CCS message" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer encrypted Finished message" \ -p "$P_PXY delay_ccs=1" \ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10253,6 +11412,7 @@ run_test "DTLS reordering: Buffer encrypted Finished message" \ # handshake, omitting CRTs. requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 190 requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 230 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket" \ -p "$P_PXY delay_srv=NewSessionTicket delay_srv=NewSessionTicket delay_ccs=1" \ "$P_SRV mtu=140 response_size=90 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \ @@ -10267,6 +11427,7 @@ run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragme # Tests for "randomly unreliable connection": try a variety of flows and peers client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10278,6 +11439,7 @@ run_test "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, \"short\" RSA handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none" \ @@ -10288,6 +11450,7 @@ run_test "DTLS proxy: 3d, \"short\" RSA handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none" \ @@ -10297,6 +11460,7 @@ run_test "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, FS, client auth" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=required" \ @@ -10306,6 +11470,7 @@ run_test "DTLS proxy: 3d, FS, client auth" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, FS, ticket" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=1 auth_mode=none" \ @@ -10315,6 +11480,7 @@ run_test "DTLS proxy: 3d, FS, ticket" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=1 auth_mode=required" \ @@ -10324,6 +11490,7 @@ run_test "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, max handshake, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 nbio=2 tickets=1 \ @@ -10365,6 +11532,7 @@ run_test "DTLS proxy: 3d, min handshake, resumption, nbio" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, client-initiated renego" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10380,6 +11548,7 @@ run_test "DTLS proxy: 3d, min handshake, client-initiated renego" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10395,6 +11564,7 @@ run_test "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, server-initiated renego" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10411,6 +11581,7 @@ run_test "DTLS proxy: 3d, min handshake, server-initiated renego" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10433,6 +11604,7 @@ run_test "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \ skip_next_test client_needs_more_time 6 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_SRV -dtls1 -mtu 2048" \ @@ -10443,6 +11615,7 @@ run_test "DTLS proxy: 3d, openssl server" \ skip_next_test # see above client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server, fragmentation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_SRV -dtls1 -mtu 768" \ @@ -10453,6 +11626,7 @@ run_test "DTLS proxy: 3d, openssl server, fragmentation" \ skip_next_test # see above client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_SRV -dtls1 -mtu 768" \ @@ -10463,6 +11637,7 @@ run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \ requires_gnutls client_needs_more_time 6 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_SRV -u --mtu 2048 -a" \ @@ -10474,6 +11649,7 @@ run_test "DTLS proxy: 3d, gnutls server" \ requires_gnutls_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server, fragmentation" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_NEXT_SRV -u --mtu 512" \ @@ -10485,6 +11661,7 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation" \ requires_gnutls_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_NEXT_SRV -u --mtu 512" \ @@ -10494,6 +11671,7 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -c "Extra-header:" requires_config_enabled MBEDTLS_SSL_EXPORT_KEYS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "export keys functionality" \ "$P_SRV eap_tls=1 debug_level=3" \ "$P_CLI eap_tls=1 debug_level=3" \ @@ -10515,7 +11693,6 @@ requires_config_enabled MBEDTLS_MEMORY_BUFFER_ALLOC_C requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH requires_max_content_len 16384 run_tests_memory_after_hanshake - # Final report echo "------------------------------------------------------------------------" diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index dd466037d9a6..cb7b3afe4826 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -291,17 +291,14 @@ ecp_tls_write_read_point:MBEDTLS_ECP_DP_SECP521R1 ECP tls read group #1 (record too short) mbedtls_ecp_tls_read_group:"0313":MBEDTLS_ERR_ECP_BAD_INPUT_DATA:0:0 -ECP tls read group #2 (bad curve_type) -mbedtls_ecp_tls_read_group:"010013":MBEDTLS_ERR_ECP_BAD_INPUT_DATA:0:0 - -ECP tls read group #3 (unknown curve) +ECP tls read group #2 (unknown curve) mbedtls_ecp_tls_read_group:"030010":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:0:0 -ECP tls read group #4 (OK, buffer just fits) +ECP tls read group #3 (OK, buffer just fits) depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED mbedtls_ecp_tls_read_group:"030017":0:256:3 -ECP tls read group #5 (OK, buffer continues) +ECP tls read group #4 (OK, buffer continues) depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED mbedtls_ecp_tls_read_group:"0300180000":0:384:3 diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 023f5fe68539..65242e0a9beb 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1007,6 +1007,7 @@ exit: } /* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ecp_tls_read_group( data_t * buf, int result, int bits, int record_len ) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 0e97e6fed96e..9ae1981a1c8c 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -651,15 +651,19 @@ SSL SET_HOSTNAME memory leak: call ssl_set_hostname twice ssl_set_hostname_twice:"server0":"server1" SSL session serialization: Wrong major version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:1:0:0:0 SSL session serialization: Wrong minor version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:1:0:0 SSL session serialization: Wrong patch version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:0:1:0 SSL session serialization: Wrong config +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:0:0:1 Record crypt, AES-128-CBC, 1.2, SHA-384 @@ -10565,79 +10569,83 @@ depends_on:!MBEDTLS_SHA256_C ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA256:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"7f9998393198a02c8d731ccc2ef90b2c":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE Session serialization, save-load: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:0:"" Session serialization, save-load: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:42:"" Session serialization, save-load: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:1023:"" Session serialization, save-load: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:0:"data_files/server5.crt" Session serialization, save-load: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:42:"data_files/server5.crt" Session serialization, save-load: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:1023:"data_files/server5.crt" Session serialization, load-save: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:0:"" Session serialization, load-save: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:42:"" Session serialization, load-save: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:1023:"" Session serialization, load-save: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:0:"data_files/server5.crt" Session serialization, load-save: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:42:"data_files/server5.crt" Session serialization, load-save: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:1023:"data_files/server5.crt" Session serialization, save buffer size: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:0:"" Session serialization, save buffer size: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:42:"" Session serialization, save buffer size: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:1023:"" Session serialization, save buffer size: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:0:"data_files/server5.crt" Session serialization, save buffer size: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:42:"data_files/server5.crt" Session serialization, save buffer size: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:1023:"data_files/server5.crt" Session serialization, load buffer size: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:0:"" Session serialization, load buffer size: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:42:"" Session serialization, load buffer size: large ticket, no cert @@ -10645,7 +10653,7 @@ depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C ssl_serialize_session_load_buf_size:1023:"" Session serialization, load buffer size: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:0:"data_files/server5.crt" Session serialization, load buffer size: small ticket, cert diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a1e660f28bed..56f3b6def2b0 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -947,10 +947,10 @@ int mbedtls_endpoint_init( mbedtls_endpoint *ep, int endpoint_type, int pk_alg, ret = mbedtls_ssl_setup( &( ep->ssl ), &( ep->conf ) ); TEST_ASSERT( ret == 0 ); -#if defined(MBEDTLS_SSL_PROTO_DTLS) && defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) if( endpoint_type == MBEDTLS_SSL_IS_SERVER && dtls_context != NULL ) mbedtls_ssl_conf_dtls_cookies( &( ep->conf ), NULL, NULL, NULL ); -#endif +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ ret = mbedtls_endpoint_certificate_init( ep, pk_alg ); TEST_ASSERT( ret == 0 ); diff --git a/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln index 3624735119d8..877f494e4082 100644 --- a/visualc/VS2010/mbedTLS.sln +++ b/visualc/VS2010/mbedTLS.sln @@ -699,4 +699,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {57E9027B-90B3-4F05-AE37-187886EC0D53} + EndGlobalSection EndGlobal diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 88ffe1b2ee2d..300c24de6a4f 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -28,17 +28,20 @@ StaticLibrary true Unicode + v142 StaticLibrary true Unicode + v142 StaticLibrary false true Unicode + v142 StaticLibrary @@ -284,6 +287,9 @@ + + + @@ -403,6 +409,18 @@ + + + + + + + + + + + +