* 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"
#include "tls_binlog_id.h"
#include "bsl_log_internal.h"
#include "bsl_log.h"
#include "bsl_err_internal.h"
#include "hitls_error.h"
#include "hitls.h"
#include "rec.h"
#include "tls.h"
#include "hs.h"
#include "hs_ctx.h"
#include "hs_common.h"
#include "hs_dtls_timer.h"
#include "parse.h"
#include "hs_state_recv.h"
#include "hs_state_send.h"
#include "bsl_errno.h"
#include "bsl_uio.h"
#ifdef HITLS_TLS_FEATURE_INDICATOR
#include "indicator.h"
#endif
#include "transcript_hash.h"
#include "recv_process.h"
static int32_t HandshakeDone(TLS_Ctx *ctx)
{
(void)ctx;
int32_t ret = HITLS_SUCCESS;
#ifdef HITLS_TLS_FEATURE_FLIGHT
* the handshake is complete */
if (ctx->config.tlsConfig.isFlightTransmitEnable) {
ret = BSL_UIO_Ctrl(ctx->uio, BSL_UIO_FLUSH, 0, NULL);
if (ret == BSL_UIO_IO_BUSY) {
return HITLS_REC_NORMAL_IO_BUSY;
}
if (ret != BSL_SUCCESS) {
BSL_ERR_PUSH_ERROR(HITLS_REC_ERR_IO_EXCEPTION);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16109, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"fail to send the CCS and Finish message of server in bUio.", 0, 0, 0, 0);
return HITLS_REC_ERR_IO_EXCEPTION;
}
}
#endif
#if defined(HITLS_TLS_PROTO_DTLS12) && defined(HITLS_BSL_UIO_SCTP)
if (!BSL_UIO_GetUioChainTransportType(ctx->uio, BSL_UIO_SCTP)) {
return HITLS_SUCCESS;
}
bool isBuffEmpty = false;
ret = BSL_UIO_Ctrl(ctx->uio, BSL_UIO_SCTP_SND_BUFF_IS_EMPTY, sizeof(isBuffEmpty), &isBuffEmpty);
if (ret != BSL_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17188, BSL_LOG_LEVEL_FATAL, BSL_LOG_BINLOG_TYPE_RUN,
"SCTP_SND_BUFF_IS_EMPTY fail, ret %d", ret, 0, 0, 0);
return HITLS_UIO_SCTP_IS_SND_BUF_EMPTY_FAIL;
}
if (isBuffEmpty != true) {
return HITLS_REC_NORMAL_IO_BUSY;
}
if (!ctx->negotiatedInfo.isRenegotiation && ctx->userRenego) {
return HITLS_SUCCESS;
}
ret = HS_ActiveSctpAuthKey(ctx);
if (ret != HITLS_SUCCESS) {
return ret;
}
ret = HS_DeletePreviousSctpAuthKey(ctx);
#endif
return ret;
}
bool IsHsSendState(HITLS_HandshakeState state)
{
switch (state) {
case TRY_SEND_HELLO_REQUEST:
case TRY_SEND_CLIENT_HELLO:
case TRY_SEND_HELLO_VERIFY_REQUEST:
case TRY_SEND_HELLO_RETRY_REQUEST:
case TRY_SEND_SERVER_HELLO:
case TRY_SEND_ENCRYPTED_EXTENSIONS:
case TRY_SEND_CERTIFICATE:
case TRY_SEND_SERVER_KEY_EXCHANGE:
case TRY_SEND_CERTIFICATE_REQUEST:
case TRY_SEND_SERVER_HELLO_DONE:
case TRY_SEND_CLIENT_KEY_EXCHANGE:
case TRY_SEND_CERTIFICATE_VERIFY:
case TRY_SEND_NEW_SESSION_TICKET:
case TRY_SEND_CHANGE_CIPHER_SPEC:
case TRY_SEND_END_OF_EARLY_DATA:
case TRY_SEND_FINISH:
case TRY_SEND_KEY_UPDATE:
return true;
default:
break;
}
return false;
}
static bool IsHsRecvState(HITLS_HandshakeState state)
{
switch (state) {
case TRY_RECV_CLIENT_HELLO:
case TRY_RECV_HELLO_VERIFY_REQUEST:
case TRY_RECV_SERVER_HELLO:
case TRY_RECV_ENCRYPTED_EXTENSIONS:
case TRY_RECV_CERTIFICATE:
case TRY_RECV_SERVER_KEY_EXCHANGE:
case TRY_RECV_CERTIFICATE_REQUEST:
case TRY_RECV_SERVER_HELLO_DONE:
case TRY_RECV_CLIENT_KEY_EXCHANGE:
case TRY_RECV_CERTIFICATE_VERIFY:
case TRY_RECV_NEW_SESSION_TICKET:
case TRY_RECV_END_OF_EARLY_DATA:
case TRY_RECV_FINISH:
case TRY_RECV_KEY_UPDATE:
case TRY_RECV_HELLO_REQUEST:
return true;
default:
break;
}
return false;
}
int32_t HS_DoHandshake(TLS_Ctx *ctx)
{
int32_t ret = HITLS_SUCCESS;
HS_Ctx *hsCtx = ctx->hsCtx;
#ifdef HITLS_TLS_FEATURE_INDICATOR
int32_t eventType = (ctx->isClient) ? INDICATE_EVENT_STATE_CONNECT_EXIT : INDICATE_EVENT_STATE_ACCEPT_EXIT;
#endif
while (hsCtx->state != TLS_CONNECTED) {
if (IsHsSendState(hsCtx->state)) {
ret = HS_SendMsgProcess(ctx);
} else if (IsHsRecvState(hsCtx->state)) {
ret = HS_RecvMsgProcess(ctx);
} else {
BSL_ERR_PUSH_ERROR(HITLS_MSG_HANDLE_STATE_ILLEGAL);
BSL_LOG_BINLOG_VARLEN(BINLOG_ID15884, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Handshake state unable to process, current state is %s.", HS_GetStateStr(hsCtx->state));
ret = HITLS_MSG_HANDLE_STATE_ILLEGAL;
}
if (ret != HITLS_SUCCESS) {
#ifdef HITLS_TLS_FEATURE_INDICATOR
INDICATOR_StatusIndicate(ctx, eventType, ret);
#endif
return ret;
}
}
#ifdef HITLS_TLS_FEATURE_INDICATOR
INDICATOR_StatusIndicate(ctx, INDICATE_EVENT_HANDSHAKE_DONE, INDICATE_VALUE_SUCCESS);
#endif
ret = HandshakeDone(ctx);
if (ret != HITLS_SUCCESS) {
#ifdef HITLS_TLS_FEATURE_INDICATOR
INDICATOR_StatusIndicate(ctx, eventType, ret);
#endif
return ret;
}
#ifdef HITLS_TLS_FEATURE_INDICATOR
INDICATOR_StatusIndicate(ctx, eventType, INDICATE_VALUE_SUCCESS);
#endif
return HITLS_SUCCESS;
}
#ifdef HITLS_TLS_FEATURE_KEY_UPDATE
int32_t HS_CheckKeyUpdateState(TLS_Ctx *ctx, uint32_t updateType)
{
if (ctx->negotiatedInfo.version != HITLS_VERSION_TLS13) {
return HITLS_MSG_HANDLE_UNSUPPORT_VERSION;
}
if (ctx->state != CM_STATE_TRANSPORTING) {
return HITLS_MSG_HANDLE_STATE_ILLEGAL;
}
if (updateType != HITLS_UPDATE_REQUESTED && updateType != HITLS_UPDATE_NOT_REQUESTED) {
return HITLS_MSG_HANDLE_ILLEGAL_KEY_UPDATE_TYPE;
}
return HITLS_SUCCESS;
}
#endif
#if defined(HITLS_TLS_PROTO_DTLS12) && defined(HITLS_BSL_UIO_UDP)
int32_t HS_CheckAndProcess2MslTimeout(TLS_Ctx *ctx)
{
if (!BSL_UIO_GetUioChainTransportType(ctx->uio, BSL_UIO_UDP)) {
return HITLS_SUCCESS;
}
bool isTimeout = false;
int32_t ret = HS_IsTimeout(ctx, &isTimeout);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17189, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"HS_IsTimeout fail", 0, 0, 0, 0);
return ret;
}
if (isTimeout) {
REC_RetransmitListClean(ctx->recCtx);
}
return HITLS_SUCCESS;
}
#endif
#ifdef HITLS_TLS_FEATURE_PHA
int32_t HS_CheckPostHandshakeAuth(TLS_Ctx *ctx)
{
int32_t ret = HS_Init(ctx);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17190, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"CONN_Init fail", 0, 0, 0, 0);
return ret;
}
HS_ChangeState(ctx, TRY_SEND_CERTIFICATE_REQUEST);
SAL_CRYPT_DigestFree(ctx->hsCtx->verifyCtx->hashCtx);
ctx->hsCtx->verifyCtx->hashCtx = SAL_CRYPT_DigestCopy(ctx->phaHash);
if (ctx->hsCtx->verifyCtx->hashCtx == NULL) {
BSL_ERR_PUSH_ERROR(HITLS_CRYPT_ERR_DIGEST);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16179, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"pha hash copy error: digest copy fail.", 0, 0, 0, 0);
return HITLS_CRYPT_ERR_DIGEST;
}
return HITLS_SUCCESS;
}
#endif