* 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 "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
#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);
}
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;
int32_t ret = ParseExtensionCommon(pkt, &exMsgLen);
if (ret != HITLS_SUCCESS) {
return ret;
}
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};
int32_t ret = ParseVersion(&pkt, &msg->version);
if (ret != HITLS_SUCCESS) {
return ret;
}
ctx->negotiatedInfo.clientVersion = msg->version;
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)) {
ret = ParseCookie(&pkt, &msg->cookieLen, &msg->cookie);
if (ret != HITLS_SUCCESS) {
return ret;
}
}
#endif
ret = ParseClientHelloCipherSuites(&pkt, msg);
if (ret != HITLS_SUCCESS) {
return ret;
}
ret = ParseClientHelloCompressionMethods(&pkt, msg);
if (ret != HITLS_SUCCESS) {
return ret;
}
if (len == bufOffset) {
return HITLS_SUCCESS;
}
return ParseClientHelloExtensions(&pkt, msg);
}
void CleanClientHello(ClientHelloMsg *msg)
{
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);
BSL_SAL_FREE(msg->extensionBuff);
CleanClientHelloExtension(msg);
}
#endif