* 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_CLIENT
#include <string.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_list.h"
#include "hs_ctx.h"
#include "hitls_error.h"
#include "hitls_cert_type.h"
#include "tls.h"
#include "hs.h"
#include "hs_extensions.h"
#include "hs_common.h"
#include "rec.h"
#include "parse_common.h"
#include "parse_extensions.h"
#include "custom_extensions.h"
static int32_t ParseServerPointFormats(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->havePointFormats == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15193, BINGLOG_STR("ServerPointFormats"));
}
uint8_t pointFormatsSize = 0;
int32_t ret = ParseOneByteLengthField(pkt, &pointFormatsSize, &msg->pointFormats);
if (ret == HITLS_PARSE_INVALID_MSG_LEN) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15194, BINGLOG_STR("ServerPointFormats"));
} else if (ret == HITLS_MEMALLOC_FAIL) {
return ParseErrorProcess(pkt->ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID15196,
BINGLOG_STR("pointFormats malloc fail."), ALERT_UNKNOWN);
}
if ((pkt->bufLen != *pkt->bufOffset) || (pointFormatsSize == 0u)) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15195, BINGLOG_STR("ServerPointFormats"));
}
msg->havePointFormats = true;
msg->pointFormatsSize = pointFormatsSize;
return HITLS_SUCCESS;
}
#ifdef HITLS_TLS_PROTO_TLS13
static int32_t ParseServerPreShareKey(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveSelectedIdentity == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15156, BINGLOG_STR("pre_shared_key"));
}
int32_t ret = ParseBytesToUint16(pkt, &msg->selectedIdentity);
if (ret != HITLS_SUCCESS || pkt->bufLen != *pkt->bufOffset) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15157, BINGLOG_STR("pre_shared_key"));
}
msg->haveSelectedIdentity = true;
return HITLS_SUCCESS;
}
int32_t ParseServerKeyShare(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveKeyShare == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15158, BINGLOG_STR("ServerKeyShare"));
}
int32_t ret = ParseBytesToUint16(pkt, &msg->keyShare.group);
if (ret != HITLS_SUCCESS) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15159, BINGLOG_STR("ServerKeyShare"));
}
if (pkt->bufLen == *pkt->bufOffset) {
msg->haveKeyShare = true;
return HITLS_SUCCESS;
}
uint16_t keyExchangeSize = 0;
ret = ParseTwoByteLengthField(pkt, &keyExchangeSize, &msg->keyShare.keyExchange);
if (ret == HITLS_PARSE_INVALID_MSG_LEN) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID16202, BINGLOG_STR("ServerKeyShare"));
} else if (ret == HITLS_MEMALLOC_FAIL) {
return ParseErrorProcess(pkt->ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID16984,
BINGLOG_STR("ServerKeyShare"), ALERT_INTERNAL_ERROR);
}
if ((pkt->bufLen != *pkt->bufOffset) || (keyExchangeSize == 0u)) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15160, BINGLOG_STR("ServerKeyShare"));
}
msg->keyShare.keyExchangeSize = keyExchangeSize;
msg->haveKeyShare = true;
return HITLS_SUCCESS;
}
int32_t ParseServerCookie(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveCookie == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15162, BINGLOG_STR("cookie"));
}
int32_t ret = ParseExCookie(pkt->buf, pkt->bufLen, &msg->cookie, &msg->cookieLen);
if (ret != HITLS_SUCCESS) {
return ret;
}
msg->haveCookie = true;
return HITLS_SUCCESS;
}
static int32_t ParseServerSupportedVersions(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveSupportedVersion == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15164, BINGLOG_STR("ServerSupportedVersions"));
}
int32_t ret = ParseBytesToUint16(pkt, &msg->supportedVersion);
if (ret != HITLS_SUCCESS || pkt->bufLen != *pkt->bufOffset) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16985, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"ParseBytesToUint16 fail, ret %d", ret, 0, 0, 0);
BSL_ERR_PUSH_ERROR(HITLS_PARSE_INVALID_MSG_LEN);
return HITLS_PARSE_INVALID_MSG_LEN;
}
msg->haveSupportedVersion = true;
return HITLS_SUCCESS;
}
#endif
#ifdef HITLS_TLS_FEATURE_EXTENDED_MASTER_SECRET
static int32_t ParseServerExtMasterSecret(ParsePacket *pkt, ServerHelloMsg *msg)
{
return ParseEmptyExtension(pkt->ctx, HS_EX_TYPE_EXTENDED_MASTER_SECRET, pkt->bufLen,
&msg->haveExtendedMasterSecret);
}
#endif
#ifdef HITLS_TLS_FEATURE_ALPN
int32_t ParseServerSelectedAlpnProtocol(
ParsePacket *pkt, bool *haveSelectedAlpn, uint8_t **alpnSelected, uint16_t *alpnSelectedSize)
{
if (*haveSelectedAlpn == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15197, BINGLOG_STR("selected alpn protocol"));
}
uint16_t selectedAlpnListLen = 0;
uint8_t selectedAlpnLen = 0;
int32_t ret = ParseBytesToUint16(pkt, &selectedAlpnListLen);
if (ret != HITLS_SUCCESS) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15198, BINGLOG_STR("alpn"));
}
uint32_t offset = *pkt->bufOffset;
ret = ParseBytesToUint8(pkt, &selectedAlpnLen);
if (ret != HITLS_SUCCESS) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID16253, BINGLOG_STR("alpn"));
}
* is returned */
if (((selectedAlpnListLen * sizeof(uint8_t)) != (pkt->bufLen - sizeof(uint16_t))) || (selectedAlpnLen == 0)) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15199, BINGLOG_STR("alpn"));
}
* name, and returns a handshake message error */
if (selectedAlpnLen != selectedAlpnListLen - sizeof(uint8_t)) {
return ParseErrorProcess(pkt->ctx, HITLS_MSG_HANDLE_ALPN_UNRECOGNIZED, BINLOG_ID16121,
BINGLOG_STR("the number of Protocol in ALPN extensions is incorrect."), ALERT_DECODE_ERROR);
}
*alpnSelected = (uint8_t *)BSL_SAL_Calloc(selectedAlpnLen + 1, sizeof(uint8_t));
if (*alpnSelected == NULL) {
return ParseErrorProcess(pkt->ctx, HITLS_MEMALLOC_FAIL, BINLOG_ID15200,
BINGLOG_STR("selected alpn proto malloc fail."), ALERT_UNKNOWN);
}
memcpy(*alpnSelected, &pkt->buf[offset], selectedAlpnLen + 1);
*alpnSelectedSize = selectedAlpnLen + 1;
*haveSelectedAlpn = true;
return HITLS_SUCCESS;
}
#endif
#ifdef HITLS_TLS_FEATURE_SNI
* @brief server hello ServerName extension item
*
* @param ctx [IN] TLS context
* @param buf [IN] message buffer
* @param bufLen [IN] message length
* @param msg [OUT] Parsed message
*
* @retval HITLS_SUCCESS parsed successfully.
* @retval HITLS_PARSE_INVALID_MSG_LEN The message length is incorrect.
* @retval HITLS_MEMALLOC_FAIL Memory application failed.
* @retval HITLS_PARSE_DUPLICATE_EXTENSIVE_MSG Extended message
*/
static int32_t ParseServerServerName(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveServerName == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15202, BINGLOG_STR("ServerName"));
}
* When the server decides to receive server_name, the server should include an extension of type "server_name" in
* the (extended) server hello. The'extension_data' field for this extension should be empty
*/
if (pkt->bufLen != 0) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15203, BINGLOG_STR("ServerName"));
}
msg->haveServerName = true;
return HITLS_SUCCESS;
}
#endif
#if defined(HITLS_TLS_PROTO_TLS_BASIC) || defined(HITLS_TLS_PROTO_DTLS12)
static int32_t ParseServerSecRenegoInfo(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveSecRenego == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15204, BINGLOG_STR("renegotiation info"));
}
uint8_t secRenegoInfoSize = 0;
uint8_t *secRenegoInfo = NULL;
int32_t ret = ParseSecRenegoInfo(pkt->ctx, pkt->buf, pkt->bufLen, &secRenegoInfo, &secRenegoInfoSize);
if (ret != HITLS_SUCCESS) {
return ret;
}
msg->secRenegoInfo = secRenegoInfo;
msg->secRenegoInfoSize = secRenegoInfoSize;
msg->haveSecRenego = true;
return HITLS_SUCCESS;
}
#endif
#ifdef HITLS_TLS_FEATURE_SESSION_TICKET
static int32_t ParseServerTicket(ParsePacket *pkt, ServerHelloMsg *msg)
{
if (msg->haveTicket == true) {
return ParseDupExtProcess(pkt->ctx, BINLOG_ID15964, BINGLOG_STR("ticket"));
}
#ifdef HITLS_TLS_FEATURE_SESSION_CUSTOM_TICKET
if (pkt->ctx->config.tlsConfig.sessionTicketExtCb != NULL) {
int32_t ret = pkt->ctx->config.tlsConfig.sessionTicketExtCb(pkt->ctx, pkt->buf, pkt->bufLen,
pkt->ctx->config.tlsConfig.sessionTicketExtCbArg);
if (ret == 0) {
return ParseErrorProcess(pkt->ctx, HITLS_PARSE_SESSION_TICKET_FAIL, BINLOG_ID17378,
BINGLOG_STR("parse ticket extension failed."), ALERT_HANDSHAKE_FAILURE);
}
}
#endif
if (pkt->bufLen != 0) {
return ParseErrorExtLengthProcess(pkt->ctx, BINLOG_ID15965, BINGLOG_STR("tiket"));
}
msg->haveTicket = true;
return HITLS_SUCCESS;
}
#endif
#ifdef HITLS_TLS_FEATURE_ETM
static int32_t ParseServerEncryptThenMac(ParsePacket *pkt, ServerHelloMsg *msg)
{
return ParseEmptyExtension(pkt->ctx, HS_EX_TYPE_ENCRYPT_THEN_MAC, pkt->bufLen, &msg->haveEncryptThenMac);
}
#endif
* @brief Parses the extended message from server
*
* @param ctx [IN] TLS context
* @param extMsgType [IN] Extended message type
* @param buf [IN] message buffer
* @param extMsgLen [IN] Extended message length
* @param msg [OUT] Structure of the parsed extended message
*
* @retval HITLS_SUCCESS parsed successfully.
* @retval HITLS_PARSE_INVALID_MSG_LEN The message length is incorrect.
* @retval HITLS_MEMALLOC_FAIL Memory application failed.
* @retval HITLS_PARSE_DUPLICATE_EXTENSIVE_MSG Extended message
* @retval HITLS_PARSE_UNSUPPORTED_EXTENSION: unsupported extended field
*/
static int32_t ParseServerExBody(TLS_Ctx *ctx, uint16_t extMsgType, const uint8_t *buf, uint32_t extMsgLen,
ServerHelloMsg *msg)
{
uint32_t bufOffset = 0u;
ParsePacket pkt = {.ctx = ctx, .buf = buf, .bufLen = extMsgLen, .bufOffset = &bufOffset};
switch (extMsgType) {
case HS_EX_TYPE_POINT_FORMATS:
return ParseServerPointFormats(&pkt, msg);
#ifdef HITLS_TLS_FEATURE_SNI
case HS_EX_TYPE_SERVER_NAME:
return ParseServerServerName(&pkt, msg);
#endif
#ifdef HITLS_TLS_FEATURE_EXTENDED_MASTER_SECRET
case HS_EX_TYPE_EXTENDED_MASTER_SECRET:
return ParseServerExtMasterSecret(&pkt, msg);
#endif
#ifdef HITLS_TLS_FEATURE_ALPN
case HS_EX_TYPE_APP_LAYER_PROTOCOLS:
return ParseServerSelectedAlpnProtocol(
&pkt, &msg->haveSelectedAlpn, &msg->alpnSelected, &msg->alpnSelectedSize);
#endif
#ifdef HITLS_TLS_PROTO_TLS13
case HS_EX_TYPE_KEY_SHARE:
return ParseServerKeyShare(&pkt, msg);
case HS_EX_TYPE_PRE_SHARED_KEY:
return ParseServerPreShareKey(&pkt, msg);
case HS_EX_TYPE_COOKIE:
return ParseServerCookie(&pkt, msg);
case HS_EX_TYPE_SUPPORTED_VERSIONS:
return ParseServerSupportedVersions(&pkt, msg);
#endif
case HS_EX_TYPE_RENEGOTIATION_INFO:
#if defined(HITLS_TLS_PROTO_TLS_BASIC) || defined(HITLS_TLS_PROTO_DTLS12)
return ParseServerSecRenegoInfo(&pkt, msg);
#else
return HITLS_SUCCESS;
#endif
#ifdef HITLS_TLS_FEATURE_SESSION_TICKET
case HS_EX_TYPE_SESSION_TICKET:
return ParseServerTicket(&pkt, msg);
#endif
#ifdef HITLS_TLS_FEATURE_ETM
case HS_EX_TYPE_ENCRYPT_THEN_MAC:
return ParseServerEncryptThenMac(&pkt, msg);
#endif
case HS_EX_TYPE_SUPPORTED_GROUPS:
return HITLS_SUCCESS;
#ifdef HITLS_TLS_FEATURE_RECORD_SIZE_LIMIT
case HS_EX_TYPE_RECORD_SIZE_LIMIT:
return ParseRecordSizeLimit(pkt.ctx, pkt.buf, extMsgLen, &msg->haveRecordSizeLimit, &msg->recordSizeLimit);
#endif
default:
break;
}
#ifdef HITLS_TLS_FEATURE_CUSTOM_EXTENSION
if (IsParseNeedCustomExtensions(CUSTOM_EXT_FROM_CTX(ctx), extMsgType,
HITLS_EX_TYPE_TLS1_2_SERVER_HELLO | HITLS_EX_TYPE_TLS1_3_SERVER_HELLO | HITLS_EX_TYPE_HELLO_RETRY_REQUEST)) {
return ParseCustomExtensions(pkt.ctx, pkt.buf + *pkt.bufOffset, extMsgType, extMsgLen,
HITLS_EX_TYPE_TLS1_2_SERVER_HELLO | HITLS_EX_TYPE_TLS1_3_SERVER_HELLO | HITLS_EX_TYPE_HELLO_RETRY_REQUEST,
NULL, 0);
}
#endif
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15205, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"unknown extension message type:%d len:%lu in server hello message.", extMsgType, extMsgLen, 0, 0);
return ParseErrorProcess(pkt.ctx, HITLS_PARSE_UNSUPPORTED_EXTENSION, 0, NULL, ALERT_UNSUPPORTED_EXTENSION);
}
int32_t ParseServerExtension(TLS_Ctx *ctx, const uint8_t *buf, uint32_t bufLen, ServerHelloMsg *msg)
{
uint32_t bufOffset = 0u;
#ifdef HITLS_TLS_FEATURE_CUSTOM_EXTENSION
uint32_t customExtSeenMask = 0;
#endif
ParsePacket pkt = {.ctx = ctx, .buf = buf, .bufLen = bufLen, .bufOffset = &bufOffset};
while (bufOffset < bufLen) {
uint32_t extMsgLen = 0u;
uint16_t extMsgType = HS_EX_TYPE_END;
uint32_t extensionId = 0;
int32_t ret = CheckForDuplicateExtension(&pkt, &extMsgType, &extMsgLen, &extensionId, msg->extensionTypeMask);
if (ret != HITLS_SUCCESS) {
return ret;
}
#ifdef HITLS_TLS_FEATURE_CUSTOM_EXTENSION
if (extensionId == HS_EX_TYPE_ID_UNRECOGNIZED) {
ret = CheckForDuplicateCustomExtension(ctx, extMsgType,
HITLS_EX_TYPE_TLS1_2_SERVER_HELLO | HITLS_EX_TYPE_TLS1_3_SERVER_HELLO |
HITLS_EX_TYPE_HELLO_RETRY_REQUEST, &customExtSeenMask, NULL);
if (ret != HITLS_SUCCESS) {
return ret;
}
}
#endif
if (extensionId != HS_EX_TYPE_ID_UNRECOGNIZED
#ifdef HITLS_TLS_FEATURE_CUSTOM_EXTENSION
|| !IsParseNeedCustomExtensions(CUSTOM_EXT_FROM_CTX(ctx), extMsgType,
HITLS_EX_TYPE_TLS1_2_SERVER_HELLO | HITLS_EX_TYPE_TLS1_3_SERVER_HELLO |
HITLS_EX_TYPE_HELLO_RETRY_REQUEST)
#endif
) {
if (!GetExtensionFlagValue(ctx, extensionId)) {
BSL_ERR_PUSH_ERROR(HITLS_MSG_HANDLE_UNSUPPORT_EXTENSION_TYPE);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17330, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"client did not send but get extension type %u.", extensionId, 0, 0, 0);
ctx->method.sendAlert(ctx, ALERT_LEVEL_FATAL, ALERT_UNSUPPORTED_EXTENSION);
return HITLS_MSG_HANDLE_UNSUPPORT_EXTENSION_TYPE;
}
msg->extensionTypeMask |= 1ULL << extensionId;
}
ret = ParseServerExBody(ctx, extMsgType, &buf[bufOffset], extMsgLen, msg);
if (ret != HITLS_SUCCESS) {
return ret;
}
bufOffset += extMsgLen;
}
if (bufOffset != bufLen) {
return ParseErrorProcess(ctx, HITLS_PARSE_INVALID_MSG_LEN, BINLOG_ID15201,
BINGLOG_STR("parse extension failed."), ALERT_DECODE_ERROR);
}
return HITLS_SUCCESS;
}
void CleanServerHelloExtension(ServerHelloMsg *msg)
{
if (msg == NULL) {
return;
}
BSL_SAL_FREE(msg->pointFormats);
#ifdef HITLS_TLS_FEATURE_ALPN
BSL_SAL_FREE(msg->alpnSelected);
#endif
#if defined(HITLS_TLS_PROTO_TLS_BASIC) || defined(HITLS_TLS_PROTO_DTLS12)
BSL_SAL_FREE(msg->secRenegoInfo);
#endif
#ifdef HITLS_TLS_PROTO_TLS13
BSL_SAL_FREE(msg->cookie);
BSL_SAL_FREE(msg->keyShare.keyExchange);
#endif
}
#endif