* 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 "bsl_log_internal.h"
#include "tls_binlog_id.h"
#include "bsl_log.h"
#include "hitls_error.h"
#include "hitls_type.h"
#include "tls.h"
#include "alert.h"
#include "app.h"
#include "conn_common.h"
#include "hs.h"
#include "hs_ctx.h"
#include "record.h"
int32_t HITLS_GetMaxWriteSize(const HITLS_Ctx *ctx, uint32_t *len)
{
if (ctx == NULL || len == NULL) {
return HITLS_NULL_INPUT;
}
return APP_GetMaxWriteSize(ctx, len);
}
static int32_t WriteEventInIdleState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
(void)ctx;
(void)data;
(void)dataLen;
(void)writeLen;
return HITLS_CM_LINK_UNESTABLISHED;
}
static int32_t WriteEventInTransportingState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
int32_t ret;
int32_t alertRet;
do {
#if defined(HITLS_TLS_PROTO_DTLS12) && defined(HITLS_BSL_UIO_UDP)
ret = HS_CheckAndProcess2MslTimeout(ctx);
if (ret != HITLS_SUCCESS) {
return ret;
}
#endif
ret = APP_Write(ctx, data, dataLen, writeLen);
if (ret == HITLS_SUCCESS) {
break;
}
if (!ALERT_GetFlag(ctx)) {
break;
}
#ifdef HITLS_TLS_PROTO_DFX_ALERT_NUMBER
if (ALERT_HaveExceeded(ctx, MAX_ALERT_COUNT)) {
ALERT_Send(ctx, ALERT_LEVEL_FATAL, ALERT_UNEXPECTED_MESSAGE);
}
#endif
alertRet = AlertEventProcess(ctx);
if (alertRet != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16546, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"AlertEventProcess fail", 0, 0, 0, 0);
return alertRet;
}
if (ctx->state == CM_STATE_ALERTED) {
break;
}
} while (ret != HITLS_SUCCESS);
return ret;
}
static int32_t WriteEventInHandshakingState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
int32_t ret = CommonEventInHandshakingState(ctx);
if (ret != HITLS_SUCCESS) {
return ret;
}
return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
}
static int32_t WriteEventInRenegotiationState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
#ifdef HITLS_TLS_FEATURE_RENEGOTIATION
int32_t ret;
if (ctx->recCtx->pendingData != NULL) {
return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
}
do {
* Otherwise, the system returns the return value to the user for processing */
ret = CommonEventInRenegotiationState(ctx);
} while (ret == HITLS_REC_NORMAL_RECV_UNEXPECT_MSG && ctx->state != CM_STATE_ALERTED);
if (ret != HITLS_SUCCESS) {
if (ctx->negotiatedInfo.isRenegotiation || (ret != HITLS_REC_NORMAL_RECV_BUF_EMPTY)) {
return ret;
}
* client hello message. In this case,the app message needs to be sent to the peer end to prevent message
* blocking
*/
}
return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
#else
(void)ctx;
(void)data;
(void)dataLen;
(void)writeLen;
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15583, BSL_LOG_LEVEL_FATAL, BSL_LOG_BINLOG_TYPE_RUN,
"invalid conn states %d", CM_STATE_RENEGOTIATION, NULL, NULL, NULL);
return HITLS_INTERNAL_EXCEPTION;
#endif
}
static int32_t WriteEventInAlertedState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
(void)ctx;
(void)data;
(void)dataLen;
(void)writeLen;
return HITLS_CM_LINK_FATAL_ALERTED;
}
#ifdef HITLS_TLS_PROTO_CLOSE_STATE
static int32_t WriteEventInClosedState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
if ((ctx->shutdownState & HITLS_SENT_SHUTDOWN) == 0) {
ALERT_CleanInfo(ctx);
int ret = APP_Write(ctx, data, dataLen, writeLen);
if (ret == HITLS_SUCCESS || ret == HITLS_REC_NORMAL_IO_BUSY) {
return ret;
}
if (ALERT_GetFlag(ctx) == false) {
return ret;
}
int32_t alertRet = AlertEventProcess(ctx);
if (alertRet != HITLS_SUCCESS) {
return alertRet;
}
return ret;
}
return HITLS_CM_LINK_CLOSED;
}
#endif
#ifdef HITLS_TLS_FEATURE_PHA
int32_t CommonCheckPostHandshakeAuth(TLS_Ctx *ctx)
{
if (!ctx->isClient && ctx->phaState == PHA_PENDING && ctx->state == CM_STATE_TRANSPORTING) {
ChangeConnState(ctx, CM_STATE_HANDSHAKING);
return HS_CheckPostHandshakeAuth(ctx);
}
return HITLS_SUCCESS;
}
#endif
static int32_t HITLS_WritePreporcess(HITLS_Ctx *ctx)
{
int32_t ret = HITLS_SUCCESS;
* processing result */
if (GetConnState(ctx) == CM_STATE_ALERTING) {
ret = CommonEventInAlertingState(ctx);
if (ret != HITLS_SUCCESS) {
return ret;
}
}
#ifdef HITLS_TLS_FEATURE_PHA
return CommonCheckPostHandshakeAuth(ctx);
#else
return ret;
#endif
}
int32_t HITLS_Write(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
{
if (ctx == NULL || data == NULL || dataLen == 0 || writeLen == NULL) {
return HITLS_NULL_INPUT;
}
ctx->allowAppOut = false;
int32_t ret = HITLS_WritePreporcess(ctx);
if (ret != HITLS_SUCCESS) {
return ret;
}
WriteEventProcess writeEventProcess[CM_STATE_END] = {
WriteEventInIdleState,
WriteEventInHandshakingState,
WriteEventInTransportingState,
WriteEventInRenegotiationState,
NULL,
WriteEventInAlertedState,
#ifdef HITLS_TLS_PROTO_CLOSE_STATE
WriteEventInClosedState
#endif
};
if ((GetConnState(ctx) >= CM_STATE_END) || (GetConnState(ctx) == CM_STATE_ALERTING)) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16548, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"internal exception occurs", 0, 0, 0, 0);
* exception occurs */
return HITLS_INTERNAL_EXCEPTION;
}
WriteEventProcess proc = writeEventProcess[GetConnState(ctx)];
ret = proc(ctx, data, dataLen, writeLen);
if (ret != HITLS_SUCCESS) {
*writeLen = 0;
}
return ret;
}