/* * This file is part of the openHiTLS project. * * openHiTLS is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * * http://license.coscl.org.cn/MulanPSL2 * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ #include "hitls_build.h" #ifdef HITLS_TLS_HOST_SERVER #include "securec.h" #include "tls_binlog_id.h" #include "bsl_log_internal.h" #include "bsl_log.h" #include "bsl_sal.h" #include "bsl_err_internal.h" #include "bsl_bytes.h" #include "hitls_error.h" #include "hitls_config.h" #include "hs_msg.h" #include "hs.h" #include "parse_common.h" #include "parse_extensions.h" #include "parse_msg.h" #define SINGLE_CIPHER_SUITE_SIZE 2u /* Length of the signature cipher suite */ #ifdef HITLS_TLS_CONNECTION_INFO_NEGOTIATION static int32_t StoreClientCipherSuites(TLS_Ctx *ctx, ClientHelloMsg *msg) { uint32_t scsvCount = 0; scsvCount += msg->haveEmptyRenegoScsvCipher ? 1 : 0; scsvCount += msg->haveFallBackScsvCipher ? 1 : 0; if (scsvCount == msg->cipherSuitesSize) { BSL_SAL_FREE(ctx->peerInfo.cipherSuites); ctx->peerInfo.cipherSuitesSize = 0; return HITLS_SUCCESS; } uint32_t tmpSize = 0; BSL_SAL_FREE(ctx->peerInfo.cipherSuites); uint32_t peerCipherSuitesSize = ((uint32_t)msg->cipherSuitesSize - scsvCount) * sizeof(uint16_t); ctx->peerInfo.cipherSuites = (uint16_t *)BSL_SAL_Malloc(peerCipherSuitesSize); if (ctx->peerInfo.cipherSuites == NULL) { BSL_SAL_FREE(msg->cipherSuites); ctx->peerInfo.cipherSuitesSize = 0; return ParseErrorProcess(ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID16237, BINGLOG_STR("peer cipherSuites dump fail"), ALERT_UNKNOWN); } for (uint16_t index = 0u; index < msg->cipherSuitesSize; index++) { if (msg->cipherSuites[index] == TLS_EMPTY_RENEGOTIATION_INFO_SCSV || msg->cipherSuites[index] == TLS_FALLBACK_SCSV) { continue; } ctx->peerInfo.cipherSuites[tmpSize] = msg->cipherSuites[index]; tmpSize += 1; } ctx->peerInfo.cipherSuitesSize = (uint16_t)tmpSize; return HITLS_SUCCESS; } #endif /** * @brief Parse the cipher suite list of Client Hello messages. * * @param pkt [IN] parse context * @param msg [OUT] Client Hello Structure * * @retval HITLS_SUCCESS parsed successfully. * @retval HITLS_MEMALLOC_FAIL Memory application failed. * @retval HITLS_PARSE_INVALID_MSG_LEN The message length is incorrect. */ static int32_t ParseClientHelloCipherSuites(ParsePacket *pkt, ClientHelloMsg *msg) { uint16_t cipherSuitesLen = 0; int32_t ret = ParseBytesToUint16(pkt, &cipherSuitesLen); const char *logStr = BINGLOG_STR("parse cipherSuites failed."); if (ret != HITLS_SUCCESS) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15700, logStr, ALERT_DECODE_ERROR); } if (((uint32_t)cipherSuitesLen > (pkt->bufLen - *pkt->bufOffset)) || (cipherSuitesLen % SINGLE_CIPHER_SUITE_SIZE) != 0u) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15342, logStr, ALERT_DECODE_ERROR); } if (cipherSuitesLen == 0u) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15701, logStr, ALERT_ILLEGAL_PARAMETER); } msg->cipherSuitesSize = cipherSuitesLen / SINGLE_CIPHER_SUITE_SIZE; BSL_SAL_FREE(msg->cipherSuites); msg->cipherSuites = (uint16_t *)BSL_SAL_Malloc(((uint32_t)msg->cipherSuitesSize) * sizeof(uint16_t)); if (msg->cipherSuites == NULL) { return ParseErrorProcess(pkt->ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID15702, BINGLOG_STR("cipherSuites malloc fail"), ALERT_UNKNOWN); } /* Parse the cipher suite */ for (uint16_t index = 0u; index < msg->cipherSuitesSize; index++) { msg->cipherSuites[index] = BSL_ByteToUint16(&pkt->buf[*pkt->bufOffset]); *pkt->bufOffset += sizeof(uint16_t); BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15703, BSL_LOG_LEVEL_INFO, BSL_LOG_BINLOG_TYPE_RUN, "got cipher suite from client:0x%x.", msg->cipherSuites[index], 0, 0, 0); if (msg->cipherSuites[index] == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { msg->haveEmptyRenegoScsvCipher = true; } if (msg->cipherSuites[index] == TLS_FALLBACK_SCSV) { msg->haveFallBackScsvCipher = true; } } #ifdef HITLS_TLS_CONNECTION_INFO_NEGOTIATION ret = StoreClientCipherSuites(pkt->ctx, msg); #endif return ret; } /** * @brief List of compression methods for parsing Client Hello messages * * @param pkt [IN] parse context * @param msg [OUT] Client Hello Structure * * @retval HITLS_SUCCESS parsed successfully. * @retval HITLS_PARSE_INVALID_MSG_LEN The message length is incorrect. * @retval HITLS_MEMALLOC_FAIL Memory application failed. */ static int32_t ParseClientHelloCompressionMethods(ParsePacket *pkt, ClientHelloMsg *msg) { uint8_t compressionMethodsLen = 0; const char *logStr = BINGLOG_STR("parse compressionMethod failed."); int32_t ret = ParseBytesToUint8(pkt, &compressionMethodsLen); if (ret != HITLS_SUCCESS) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15704, logStr, ALERT_DECODE_ERROR); } if ((compressionMethodsLen > (pkt->bufLen - *pkt->bufOffset)) || (compressionMethodsLen == 0u)) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15705, logStr, ALERT_DECODE_ERROR); } ret = ParseBytesToArray(pkt, &msg->compressionMethods, compressionMethodsLen); if (ret == HITLS_MEMALLOC_FAIL) { return ParseErrorProcess(pkt->ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID16146, BINGLOG_STR("compressionMethods malloc fail."), ALERT_UNKNOWN); } msg->compressionMethodsSize = compressionMethodsLen; for (uint32_t i = 0; i < compressionMethodsLen; i++) { if (msg->compressionMethods[i] == 0u) { return HITLS_SUCCESS; } } return ParseErrorProcess(pkt->ctx, HITLS_MSG_HANDLE_INVALID_COMPRESSION_METHOD, BINLOG_ID16238, logStr, ALERT_DECODE_ERROR); } /** * @brief Parse the Client Hello extension messages. * * @param pkt [IN] parse context * @param msg [OUT] Client Hello Structure * * @retval HITLS_SUCCESS parsed successfully. * @retval HITLS_PARSE_INVALID_MSG_LEN The message length is incorrect. * @retval HITLS_PARSE_DUPLICATE_EXTENSIVE_MSG Extended message */ static int32_t ParseClientHelloExtensions(ParsePacket *pkt, ClientHelloMsg *msg) { uint16_t exMsgLen = 0; const char *logStr = BINGLOG_STR("parse extension length failed."); int32_t ret = ParseBytesToUint16(pkt, &exMsgLen); if (ret != HITLS_SUCCESS) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15707, logStr, ALERT_DECODE_ERROR); } if (exMsgLen != (pkt->bufLen - *pkt->bufOffset)) { return ParseErrorProcess(pkt->ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15708, logStr, ALERT_DECODE_ERROR); } if (exMsgLen == 0u) { return HITLS_SUCCESS; } return ParseClientExtension(pkt->ctx, &pkt->buf[*pkt->bufOffset], exMsgLen, msg); } int32_t ParseClientHello(TLS_Ctx *ctx, const uint8_t *data, uint32_t len, HS_Msg *hsMsg) { ClientHelloMsg *msg = &hsMsg->body.clientHello; uint32_t bufOffset = 0; ParsePacket pkt = {.ctx = ctx, .buf = data, .bufLen = len, .bufOffset = &bufOffset}; /* Parse the version number. The version number occupies two bytes */ int32_t ret = ParseVersion(&pkt, &msg->version); if (ret != HITLS_SUCCESS) { return ret; } ctx->negotiatedInfo.clientVersion = msg->version; /* Parse the random number. The random number occupies 32 bytes */ ret = ParseRandom(&pkt, msg->randomValue, HS_RANDOM_SIZE); if (ret != HITLS_SUCCESS) { return ret; } ret = ParseSessionId(&pkt, &msg->sessionIdSize, &msg->sessionId); if (ret != HITLS_SUCCESS) { return ret; } #ifdef HITLS_TLS_PROTO_DTLS12 if (IS_SUPPORT_DATAGRAM(ctx->config.tlsConfig.originVersionMask)) { /* Cookies need to be parsed in DTLS */ ret = ParseCookie(&pkt, &msg->cookieLen, &msg->cookie); if (ret != HITLS_SUCCESS) { return ret; } } #endif /* Parse the cipher suite. After the parsing is complete, update the msg->cipherSuitesSize and msg->cipherSuites */ ret = ParseClientHelloCipherSuites(&pkt, msg); if (ret != HITLS_SUCCESS) { return ret; } /* Parse compression method */ ret = ParseClientHelloCompressionMethods(&pkt, msg); if (ret != HITLS_SUCCESS) { return ret; } if (len == bufOffset) { return HITLS_SUCCESS; } return ParseClientHelloExtensions(&pkt, msg); } void CleanClientHello(ClientHelloMsg *msg) { // The value of msg->refCnt is not 0, indicating that the ClientHelloMsg resource is hosted in the hrr scenario if (msg == NULL || msg->refCnt != 0) { return; } BSL_SAL_FREE(msg->sessionId); BSL_SAL_FREE(msg->cookie); BSL_SAL_FREE(msg->cipherSuites); BSL_SAL_FREE(msg->compressionMethods); CleanClientHelloExtension(msg); return; } #endif /* HITLS_TLS_HOST_SERVER */