1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Secure Component */
16 /** */
17 /** Datagram Transport Layer Security (DTLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_dtls.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_secure_dtls_session_end PORTABLE C */
31 /* 6.3.0 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function ends an active DTLS session by sending the DTLS */
39 /* CloseNotify alert to the remote host, then waiting for the response */
40 /* CloseNotify before returning. */
41 /* */
42 /* INPUT */
43 /* */
44 /* dtls_session DTLS session control block */
45 /* wait_option Indicates how long the caller */
46 /* should wait for the response */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* status Completion status */
51 /* */
52 /* CALLS */
53 /* */
54 /* _nx_secure_dtls_packet_allocate Allocate internal DTLS packet */
55 /* _nx_secure_tls_send_alert Generate the CloseNotify */
56 /* _nx_secure_dtls_send_record Send the CloseNotify */
57 /* _nx_secure_dtls_session_reset Clear out the session */
58 /* _nx_secure_dtls_session_receive Receive DTLS data */
59 /* nx_secure_tls_packet_release Release packet */
60 /* tx_mutex_get Get protection mutex */
61 /* tx_mutex_put Put protection mutex */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
72 /* 09-30-2020 Timothy Stapko Modified comment(s), */
73 /* released packet securely, */
74 /* resulting in version 6.1 */
75 /* 01-31-2022 Timothy Stapko Modified comment(s), */
76 /* fixed out-of-order handling,*/
77 /* resulting in version 6.1.10 */
78 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
79 /* handled close notify packet,*/
80 /* resulting in version 6.3.0 */
81 /* */
82 /**************************************************************************/
_nx_secure_dtls_session_end(NX_SECURE_DTLS_SESSION * dtls_session,UINT wait_option)83 UINT _nx_secure_dtls_session_end(NX_SECURE_DTLS_SESSION *dtls_session, UINT wait_option)
84 {
85 #ifdef NX_SECURE_ENABLE_DTLS
86 UINT status;
87 UINT error_status;
88 NX_PACKET *send_packet;
89 NX_PACKET *incoming_packet;
90 NX_PACKET *tmp_ptr;
91 NX_SECURE_TLS_SESSION *tls_session;
92
93 /* Get reference to internal TLS state. */
94 tls_session = &dtls_session -> nx_secure_dtls_tls_session;
95
96 /* Get the protection. */
97 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
98
99 /* Release packets in queue. */
100 while (tls_session -> nx_secure_record_queue_header)
101 {
102 tmp_ptr = tls_session -> nx_secure_record_queue_header;
103 tls_session -> nx_secure_record_queue_header = tmp_ptr -> nx_packet_queue_next;
104 tmp_ptr -> nx_packet_queue_next = NX_NULL;
105 nx_secure_tls_packet_release(tmp_ptr);
106 }
107 if (tls_session -> nx_secure_record_decrypted_packet)
108 {
109 nx_secure_tls_packet_release(tls_session -> nx_secure_record_decrypted_packet);
110 tls_session -> nx_secure_record_decrypted_packet = NX_NULL;
111 }
112
113 /* If the remote session is already finished, don't try to send. */
114 if(!dtls_session -> nx_secure_dtls_tls_session.nx_secure_tls_remote_session_active)
115 {
116 /* Reset the TLS state so this socket can be reused. */
117 tx_mutex_put(&_nx_secure_tls_protection);
118 status = _nx_secure_dtls_session_reset(dtls_session);
119 return(status);
120 }
121
122
123 /* Release the protection before suspending on nx_packet_allocate. */
124 tx_mutex_put(&_nx_secure_tls_protection);
125
126 /* Allocate a packet for our close-notify alert. */
127 status = _nx_secure_dtls_packet_allocate(dtls_session, tls_session -> nx_secure_tls_packet_pool, &send_packet, wait_option);
128
129 /* Check for errors in allocating packet. */
130 if (status != NX_SUCCESS)
131 {
132 _nx_secure_dtls_session_reset(dtls_session);
133 return(status);
134 }
135
136 /* Get the protection after nx_packet_allocate. */
137 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
138
139 /* A close-notify alert shuts down the TLS session cleanly. */
140 _nx_secure_tls_send_alert(tls_session, send_packet, NX_SECURE_TLS_ALERT_CLOSE_NOTIFY, NX_SECURE_TLS_ALERT_LEVEL_WARNING);
141
142 /* Finally, send the alert record to the remote host. */
143 status = _nx_secure_dtls_send_record(dtls_session, send_packet, NX_SECURE_TLS_ALERT, wait_option);
144
145 if (status)
146 {
147 /* Failed to send, release the packet. */
148 nx_secure_tls_packet_release(send_packet);
149 _nx_secure_dtls_session_reset(dtls_session);
150 tx_mutex_put(&_nx_secure_tls_protection);
151 return(status);
152 }
153
154 /* Release the protection. */
155 tx_mutex_put(&_nx_secure_tls_protection);
156
157 /* See if we received the CloseNotify, or if we need to wait. */
158 if(tls_session -> nx_secure_tls_received_alert_level != NX_SECURE_TLS_ALERT_LEVEL_WARNING ||
159 tls_session -> nx_secure_tls_received_alert_value != NX_SECURE_TLS_ALERT_CLOSE_NOTIFY)
160 {
161 while (status == NX_SUCCESS)
162 {
163 /* Wait for the CloseNotify response. */
164
165 status = _nx_secure_dtls_session_receive(dtls_session, &incoming_packet, wait_option);
166
167 if (status == NX_SUCCESS)
168 {
169
170 /* Release the packet. */
171 nx_secure_tls_packet_release(incoming_packet);
172 }
173 }
174 }
175
176 /* Save error status for return below. */
177 error_status = status;
178
179 /* Reset the TLS state so this socket can be reused. */
180 status = _nx_secure_dtls_session_reset(dtls_session);
181
182 if(error_status != NX_SECURE_TLS_ALERT_RECEIVED && error_status != NX_SECURE_TLS_CLOSE_NOTIFY_RECEIVED)
183 {
184 status = error_status;
185 }
186
187 return(status);
188 #else
189 NX_PARAMETER_NOT_USED(dtls_session);
190 NX_PARAMETER_NOT_USED(wait_option);
191
192 return(NX_NOT_SUPPORTED);
193 #endif /* NX_SECURE_ENABLE_DTLS */
194 }
195
196