/*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ /** */ /** NetX Secure Component */ /** */ /** Transport Layer Security (TLS) */ /** */ /**************************************************************************/ /**************************************************************************/ #define NX_SECURE_SOURCE_CODE #include "nx_secure_tls.h" #ifdef NX_SECURE_ENABLE_DTLS #include "nx_secure_dtls.h" #endif /* NX_SECURE_ENABLE_DTLS */ /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _nx_secure_tls_handshake_hash_update PORTABLE C */ /* 6.1.9 */ /* AUTHOR */ /* */ /* Timothy Stapko, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function updates the hash function states with handshake */ /* messages, both generated by this host and received from a remote */ /* host. This is needed for the TLS Finished message handshake hash. */ /* */ /* INPUT */ /* */ /* tls_session TLS control block */ /* data Data to be hashed */ /* length Data length */ /* */ /* OUTPUT */ /* */ /* status Completion status */ /* */ /* CALLS */ /* */ /* [nx_crypto_operation] Hash update functions */ /* */ /* CALLED BY */ /* */ /* _nx_secure_dtls_send_clienthello Send ClientHello */ /* _nx_secure_dtls_send_handshake_record Send DTLS handshake record */ /* _nx_secure_dtls_server_handshake DTLS server state machine */ /* _nx_secure_tls_send_clienthello Send ClientHello */ /* _nx_secure_tls_send_handshake_record Send TLS handshake record */ /* _nx_secure_tls_server_handshake TLS server state machine */ /* */ /* RELEASE HISTORY */ /* */ /* DATE NAME DESCRIPTION */ /* */ /* 05-19-2020 Timothy Stapko Initial Version 6.0 */ /* 09-30-2020 Timothy Stapko Modified comment(s), */ /* resulting in version 6.1 */ /* 10-15-2021 Timothy Stapko Modified comment(s), fixed */ /* compilation issue with */ /* TLS 1.3 and disabling TLS */ /* server, */ /* resulting in version 6.1.9 */ /* */ /**************************************************************************/ UINT _nx_secure_tls_handshake_hash_update(NX_SECURE_TLS_SESSION *tls_session, UCHAR *data, UINT length) { UINT status = NX_NOT_SUCCESSFUL; const NX_CRYPTO_METHOD *method_ptr; #if (NX_SECURE_TLS_TLS_1_3_ENABLED) UINT hash_length; USHORT hello_retry_process = 0; #endif #if (NX_SECURE_TLS_TLS_1_3_ENABLED) if(tls_session->nx_secure_tls_1_3) { /* Hash handshake record using ciphersuite hash routine. */ if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL) { /* Set the hash method to the default of SHA-256 if no ciphersuite is available. */ method_ptr = tls_session -> nx_secure_tls_crypto_table->nx_secure_tls_handshake_hash_sha256_method; } else { /* The handshake transcript hash in TLS 1.3 uses the hash routine associated with the chosen ciphersuite. */ method_ptr = tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash; } /* Generate the "transcript hash" for the point in the handshake where this message falls. * This is needed for TLS 1.3 key generation which uses the hash of all previous handshake * messages at multiple points during the handshake. Instead of saving the entirety of the * handshake messages, just generate a hash when each record is hashed. */ if (method_ptr -> nx_crypto_operation != NX_NULL) { status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, data, length, NX_NULL, NX_NULL, 0, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size, NX_NULL, NX_NULL); /* See if we have recieved or are sending a hello retry message - we need to process the hash differently. */ #ifndef NX_SECURE_TLS_SERVER_DISABLED if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER) { hello_retry_process = (tls_session -> nx_secure_tls_server_state == NX_SECURE_TLS_SERVER_STATE_SEND_HELLO_RETRY); } #endif #ifndef NX_SECURE_TLS_CLIENT_DISABLED if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT) { hello_retry_process = (tls_session -> nx_secure_tls_client_state == NX_SECURE_TLS_CLIENT_STATE_HELLO_RETRY); } #endif /* Modify message buffer - replace message with hash used for HelloRetryRequest processing. */ if ((status == NX_SUCCESS) && (hello_retry_process) && (data[0] == NX_SECURE_TLS_CLIENT_HELLO) && (length > NX_SECURE_TLS_HANDSHAKE_HEADER_SIZE)) { /* ClientHello1 is replaced with "message_hash || 00 00 Hash.length || Hash(ClientHello1)"*/ status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_CALCULATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, NX_NULL, 0, NX_NULL, data + 4, /* Reuse input buffer since the input will not be used anymore. */ NX_SECURE_TLS_MAX_HASH_SIZE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size, NX_NULL, NX_NULL); /* Initialize handshake HASH again. */ if (status == NX_SUCCESS) { status = _nx_secure_tls_handshake_hash_init(tls_session); } if (status == NX_SUCCESS) { hash_length = method_ptr -> nx_crypto_ICV_size_in_bits >> 3; data[0] = NX_SECURE_TLS_MESSAGE_HASH & 0xFF; data[1] = 0; data[2] = 0; data[3] = hash_length & 0xFF; status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, data, hash_length + 4, NX_NULL, NX_NULL, 0, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size, NX_NULL, NX_NULL); } } } return(status); } #endif /* Hash this handshake message. We do not hash HelloRequest messages, but since only the server will send them, we do not worry about them here because these are only messages received from the client at this point. Hashes include the handshake layer header but not the record layer header. */ #if (NX_SECURE_TLS_TLS_1_2_ENABLED) #ifdef NX_SECURE_ENABLE_DTLS if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_2 || tls_session -> nx_secure_tls_protocol_version == NX_SECURE_DTLS_VERSION_1_2) #else if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_2) #endif /* NX_SECURE_ENABLE_DTLS */ { /* Hash is determined by ciphersuite in TLS 1.2. Default is SHA-256. */ method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_sha256_method; if (method_ptr -> nx_crypto_operation != NX_NULL) { status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, data, length, NX_NULL, NX_NULL, 0, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha256_metadata_size, NX_NULL, NX_NULL); if (status != NX_CRYPTO_SUCCESS) { return(status); } } } #endif #if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED) #ifdef NX_SECURE_ENABLE_DTLS if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_0 || tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_1 || tls_session -> nx_secure_tls_protocol_version == NX_SECURE_DTLS_VERSION_1_0) #else if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_0 || tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_1) #endif /* NX_SECURE_ENABLE_DTLS */ { /* TLS 1.0 and 1.1 use both MD5 and SHA-1. */ method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_md5_method; if (method_ptr -> nx_crypto_operation != NX_NULL) { status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, data, length, NX_NULL, NX_NULL, 0, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_md5_metadata_size, NX_NULL, NX_NULL); if (status != NX_CRYPTO_SUCCESS) { return(status); } } method_ptr = tls_session -> nx_secure_tls_crypto_table -> nx_secure_tls_handshake_hash_sha1_method; if (method_ptr -> nx_crypto_operation != NX_NULL) { status = method_ptr -> nx_crypto_operation(NX_CRYPTO_HASH_UPDATE, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_handler, (NX_CRYPTO_METHOD*)method_ptr, NX_NULL, 0, data, length, NX_NULL, NX_NULL, 0, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata, tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_sha1_metadata_size, NX_NULL, NX_NULL); if (status != NX_CRYPTO_SUCCESS) { return(status); } } } #endif return(status); }