1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #include "bsl_log_internal.h"
18 #include "bsl_err_internal.h"
19 #include "tls_binlog_id.h"
20 #include "bsl_log.h"
21 #include "hitls_error.h"
22 #include "hitls_type.h"
23 #include "tls.h"
24 #include "alert.h"
25 #include "app.h"
26 #include "conn_common.h"
27 #include "hs.h"
28 #include "hs_ctx.h"
29 #include "record.h"
30
HITLS_GetMaxWriteSize(const HITLS_Ctx * ctx,uint32_t * len)31 int32_t HITLS_GetMaxWriteSize(const HITLS_Ctx *ctx, uint32_t *len)
32 {
33 if (ctx == NULL || len == NULL) {
34 return HITLS_NULL_INPUT;
35 }
36
37 return APP_GetMaxWriteSize(ctx, len);
38 }
39
WriteEventInIdleState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)40 static int32_t WriteEventInIdleState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
41 {
42 (void)ctx;
43 (void)data;
44 (void)dataLen;
45 (void)writeLen;
46 return HITLS_CM_LINK_UNESTABLISHED;
47 }
48
WriteEventInTransportingState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)49 static int32_t WriteEventInTransportingState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
50 {
51 int32_t ret;
52 int32_t alertRet;
53
54 do {
55 #if defined(HITLS_TLS_PROTO_DTLS12) && defined(HITLS_BSL_UIO_UDP)
56 /* In UDP scenarios, the 2MSL timer expires */
57 ret = HS_CheckAndProcess2MslTimeout(ctx);
58 if (ret != HITLS_SUCCESS) {
59 return ret;
60 }
61 #endif
62 ret = APP_Write(ctx, data, dataLen, writeLen);
63 if (ret == HITLS_SUCCESS) {
64 /* The message is sent successfully */
65 break;
66 }
67
68 if (!ALERT_GetFlag(ctx)) {
69 /* Failed to send a message but no alert is displayed */
70 break;
71 }
72
73 if (ALERT_HaveExceeded(ctx, MAX_ALERT_COUNT)) {
74 /* If multiple consecutive alerts exist, the link is abnormal and needs to be disconnected */
75 ALERT_Send(ctx, ALERT_LEVEL_FATAL, ALERT_UNEXPECTED_MESSAGE);
76 }
77
78 alertRet = AlertEventProcess(ctx);
79 if (alertRet != HITLS_SUCCESS) {
80 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16546, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
81 "AlertEventProcess fail", 0, 0, 0, 0);
82 /* If the alert fails to be sent, a response is returned to the user */
83 return alertRet;
84 }
85
86 /* If fatal alert or close_notify has been processed, the link must be disconnected. */
87 if (ctx->state == CM_STATE_ALERTED) {
88 break;
89 }
90 } while (ret != HITLS_SUCCESS);
91
92 return ret;
93 }
94
WriteEventInHandshakingState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)95 static int32_t WriteEventInHandshakingState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
96 {
97 // The link is being established. Therefore, the link establishment is triggered first. If the link is successfully
98 // established, the message is directly sent.
99 int32_t ret = CommonEventInHandshakingState(ctx);
100 if (ret != HITLS_SUCCESS) {
101 return ret;
102 }
103
104 return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
105 }
106
WriteEventInRenegotiationState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)107 static int32_t WriteEventInRenegotiationState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
108 {
109 #ifdef HITLS_TLS_FEATURE_RENEGOTIATION
110 int32_t ret;
111 if (ctx->recCtx->pendingData != NULL) {
112 // Send the app data first.
113 return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
114 }
115 do {
116 /* If an unexpected message is received, the system ignores the return value and continues to establish a link.
117 * Otherwise, the system returns the return value to the user for processing */
118 ret = CommonEventInRenegotiationState(ctx);
119 } while (ret == HITLS_REC_NORMAL_RECV_UNEXPECT_MSG && ctx->state != CM_STATE_ALERTED);
120 if (ret != HITLS_SUCCESS) {
121 if (ctx->negotiatedInfo.isRenegotiation || (ret != HITLS_REC_NORMAL_RECV_BUF_EMPTY)) {
122 /* If an error is returned during renegotiation, the error code must be sent to the user */
123 return ret;
124 }
125 /* The scenario is that the HITLS server initiates renegotiation, but the peer end does not respond with the
126 * client hello message. In this case,the app message needs to be sent to the peer end to prevent message
127 * blocking
128 */
129 }
130
131 return WriteEventInTransportingState(ctx, data, dataLen, writeLen);
132 #else
133 (void)ctx;
134 (void)data;
135 (void)dataLen;
136 (void)writeLen;
137 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15583, BSL_LOG_LEVEL_FATAL, BSL_LOG_BINLOG_TYPE_RUN,
138 "invalid conn states %d", CM_STATE_RENEGOTIATION, NULL, NULL, NULL);
139 return HITLS_INTERNAL_EXCEPTION;
140 #endif
141 }
142
WriteEventInAlertedState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)143 static int32_t WriteEventInAlertedState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
144 {
145 (void)ctx;
146 (void)data;
147 (void)dataLen;
148 (void)writeLen;
149 // Directly return a message indicating that the link status is abnormal.
150 return HITLS_CM_LINK_FATAL_ALERTED;
151 }
152
WriteEventInClosedState(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)153 static int32_t WriteEventInClosedState(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
154 {
155 if ((ctx->shutdownState & HITLS_SENT_SHUTDOWN) == 0) {
156 ALERT_CleanInfo(ctx);
157 int ret = APP_Write(ctx, data, dataLen, writeLen);
158 if (ret == HITLS_SUCCESS || ret == HITLS_REC_NORMAL_IO_BUSY) {
159 return ret;
160 }
161 // There is no alert message to be processed.
162 if (ALERT_GetFlag(ctx) == false) {
163 return ret;
164 }
165
166 int32_t alertRet = AlertEventProcess(ctx);
167 if (alertRet != HITLS_SUCCESS) {
168 return alertRet;
169 }
170 return ret;
171 }
172 // Directly return a message indicating that the link status is abnormal.
173 return HITLS_CM_LINK_CLOSED;
174 }
175 #ifdef HITLS_TLS_FEATURE_PHA
CommonCheckPostHandshakeAuth(TLS_Ctx * ctx)176 int32_t CommonCheckPostHandshakeAuth(TLS_Ctx *ctx)
177 {
178 if (!ctx->isClient && ctx->phaState == PHA_PENDING && ctx->state == CM_STATE_TRANSPORTING) {
179 ChangeConnState(ctx, CM_STATE_HANDSHAKING);
180 return HS_CheckPostHandshakeAuth(ctx);
181 }
182 return HITLS_SUCCESS;
183 }
184 #endif
HITLS_WritePreporcess(HITLS_Ctx * ctx)185 static int32_t HITLS_WritePreporcess(HITLS_Ctx *ctx)
186 {
187 int32_t ret = HITLS_SUCCESS;
188 /* Process the unsent alert message first, and then enter the corresponding state processing function based on the
189 * processing result */
190 if (GetConnState(ctx) == CM_STATE_ALERTING) {
191 ret = CommonEventInAlertingState(ctx);
192 if (ret != HITLS_SUCCESS) {
193 /* If the alert message fails to be sent, the system returns the message to the user for processing */
194 return ret;
195 }
196 }
197
198 #ifdef HITLS_TLS_FEATURE_PHA
199 return CommonCheckPostHandshakeAuth(ctx);
200 #else
201 return ret;
202 #endif
203 }
204
HITLS_Write(HITLS_Ctx * ctx,const uint8_t * data,uint32_t dataLen,uint32_t * writeLen)205 int32_t HITLS_Write(HITLS_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint32_t *writeLen)
206 {
207 if (ctx == NULL || data == NULL || dataLen == 0 || writeLen == NULL) {
208 return HITLS_NULL_INPUT;
209 }
210 ctx->allowAppOut = false;
211
212 int32_t ret = HITLS_WritePreporcess(ctx);
213 if (ret != HITLS_SUCCESS) {
214 return ret;
215 }
216
217 WriteEventProcess writeEventProcess[CM_STATE_END] = {
218 WriteEventInIdleState,
219 WriteEventInHandshakingState,
220 WriteEventInTransportingState,
221 WriteEventInRenegotiationState,
222 NULL,
223 WriteEventInAlertedState,
224 WriteEventInClosedState
225 };
226
227 if ((GetConnState(ctx) >= CM_STATE_END) || (GetConnState(ctx) == CM_STATE_ALERTING)) {
228 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID16548, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
229 "internal exception occurs", 0, 0, 0, 0);
230 /* If the alert message is sent successfully, the system switches to another state. Otherwise, an internal
231 * exception occurs */
232 return HITLS_INTERNAL_EXCEPTION;
233 }
234
235 WriteEventProcess proc = writeEventProcess[GetConnState(ctx)];
236
237 ret = proc(ctx, data, dataLen, writeLen);
238 if (ret != HITLS_SUCCESS) {
239 *writeLen = 0;
240 }
241 return ret;
242 }
243