• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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