Select one of the symbols to view example projects that use it.
 
Outline
...
...
...
...
#define NX_SECURE_SOURCE_CODE
#include "nx_secure_tls.h"
...
_nx_secure_tls_send_record(NX_SECURE_TLS_SESSION *, NX_PACKET *, UCHAR, ULONG)
Files
loading...
CodeScopeSTM32 Libraries and Samplesnetxduonx_secure/src/nx_secure_tls_send_record.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**************************************************************************/ /* */ /* Copyright (c) Microsoft Corporation. All rights reserved. */ /* */ /* This software is licensed under the Microsoft Software License */ /* Terms for Microsoft Azure RTOS. Full text of the license can be */ /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ /* and in the root directory of this software. */ /* */... /**************************************************************************/ ... /**************************************************************************/ /**************************************************************************/ /** */ /** NetX Secure Component */ /** */ /** Transport Layer Security (TLS) */ /** */... /**************************************************************************/ /**************************************************************************/ #define NX_SECURE_SOURCE_CODE #include "nx_secure_tls.h" ... /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _nx_secure_tls_send_record PORTABLE C */ /* 6.1.8 */ /* AUTHOR */ /* */ /* Timothy Stapko, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function encapsulates the TLS record layer send */ /* functionality. The incoming packet data is wrapped in */ /* a TLS record, which includes a header and footer (for */ /* encrypted data). Also, all encryption of application */ /* data is handled here. */ /* */ /* INPUT */ /* */ /* tls_session Pointer to TLS session */ /* send_packet Packet data to send */ /* record_type TLS record type */ /* wait_option Suspension option */ /* */ /* OUTPUT */ /* */ /* status Record send status */ /* */ /* CALLS */ /* */ /* _nx_secure_tls_record_hash_calculate Calculate hash of record */ /* _nx_secure_tls_record_hash_initialize Initialize hash of record */ /* _nx_secure_tls_record_hash_update Update hash of record */ /* _nx_secure_tls_record_payload_encrypt Encrypt payload */ /* _nx_secure_tls_session_iv_size_get Get IV size for this session. */ /* nx_packet_data_append Append data to packet */ /* nx_tcp_socket_send Send packet */ /* tx_mutex_get Get protection mutex */ /* tx_mutex_put Put protection mutex */ /* */ /* CALLED BY */ /* */ /* _nx_secure_tls_client_handshake TLS client state machine */ /* _nx_secure_tls_send_handshake_record Send TLS handshake record */ /* _nx_secure_tls_server_handshake TLS server state machine */ /* _nx_secure_tls_session_end End of a session */ /* _nx_secure_tls_session_receive_records */ /* Receive TLS records */ /* _nx_secure_tls_session_send Send session packet */ /* */ /* RELEASE HISTORY */ /* */ /* DATE NAME DESCRIPTION */ /* */ /* 05-19-2020 Timothy Stapko Initial Version 6.0 */ /* 09-30-2020 Timothy Stapko Modified comment(s), and */ /* fixed race condition for */ /* multithread transmission, */ /* resulting in version 6.1 */ /* 06-02-2021 Timothy Stapko Modified comment(s), */ /* resulting in version 6.1.7 */ /* 08-02-2021 Timothy Stapko Modified comment(s), */ /* used wait forever on */ /* transmission mutex, */ /* resulting in version 6.1.8 */ /* */... /**************************************************************************/ UINT _nx_secure_tls_send_record(NX_SECURE_TLS_SESSION *tls_session, NX_PACKET *send_packet, UCHAR record_type, ULONG wait_option) { UINT status; UINT message_length; UCHAR *mac_secret; UCHAR *record_header; UCHAR record_hash[NX_SECURE_TLS_MAX_HASH_SIZE]; UINT hash_length; UCHAR *hash_data; ULONG hash_data_length; ULONG length; USHORT iv_size = 0; NX_PACKET *current_packet; /* Length of the data in the packet. */ length = send_packet -> nx_packet_length; if ((tls_session -> nx_secure_tls_tcp_socket) && (tls_session -> nx_secure_tls_tcp_socket -> nx_tcp_socket_ip_ptr) && (tx_thread_identify() == &(tls_session -> nx_secure_tls_tcp_socket -> nx_tcp_socket_ip_ptr -> nx_ip_thread))) { /* No wait is allowed for IP thread to avoid dead lock. */ wait_option = 0; }if ((tls_session -> nx_secure_tls_tcp_socket) && (tls_session -> nx_secure_tls_tcp_socket -> nx_tcp_socket_ip_ptr) && (tx_thread_identify() == &(tls_session -> nx_secure_tls_tcp_socket -> nx_tcp_socket_ip_ptr -> nx_ip_thread))) { ... } tx_mutex_put(&_nx_secure_tls_protection); /* Get transmit mutex first. */ status = tx_mutex_get(&(tls_session -> nx_secure_tls_session_transmit_mutex), TX_WAIT_FOREVER); tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER); if (status) { /* Unable to send due to another thread is still transmitting. */ return(NX_SECURE_TLS_TRANSMIT_LOCKED); }if (status) { ... } /* See if this is an active session, we need to account for the IV if the session cipher uses one. TLS 1.3 does not use an explicit IV so don't add it.*//* ... */ if (tls_session -> nx_secure_tls_local_session_active #if (NX_SECURE_TLS_TLS_1_3_ENABLED) && !tls_session->nx_secure_tls_1_3 #endif ) { /* Get the size of the IV used by the session cipher. */ status = _nx_secure_tls_session_iv_size_get(tls_session, &iv_size); if (status != NX_SUCCESS) { tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(status); }if (status != NX_SUCCESS) { ... } /* Ensure there is enough room for the IV data. */ if ((ULONG)(send_packet -> nx_packet_prepend_ptr - send_packet -> nx_packet_data_start) < iv_size) { /* Return an invalid packet error. */ tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(NX_SECURE_TLS_INVALID_PACKET); }if ((ULONG)(send_packet -> nx_packet_prepend_ptr - send_packet -> nx_packet_data_start) < iv_size) { ... } /* Back off the pointer to the point before the IV data allocation (can be 0). Increases length since we are moving the prepend pointer. *//* ... */ send_packet -> nx_packet_prepend_ptr -= iv_size; send_packet -> nx_packet_length += iv_size; }if (tls_session -> nx_secure_tls_local_session_active #if (NX_SECURE_TLS_TLS_1_3_ENABLED) && !tls_session->nx_secure_tls_1_3 #endif) { ... } /* Ensure there is enough room for the record header. */ if ((ULONG)(send_packet -> nx_packet_prepend_ptr - send_packet -> nx_packet_data_start) < NX_SECURE_TLS_RECORD_HEADER_SIZE) { /* Return an invalid packet error. */ tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(NX_SECURE_TLS_INVALID_PACKET); }if ((ULONG)(send_packet -> nx_packet_prepend_ptr - send_packet -> nx_packet_data_start) < NX_SECURE_TLS_RECORD_HEADER_SIZE) { ... } /* Get a pointer to our record header which is now right after the prepend pointer. */ record_header = send_packet -> nx_packet_prepend_ptr - NX_SECURE_TLS_RECORD_HEADER_SIZE; /* Build the TLS record header. */ record_header[0] = record_type; /* Set the version number. */ record_header[1] = (UCHAR)((tls_session -> nx_secure_tls_protocol_version & 0xFF00) >> 8); record_header[2] = (UCHAR)(tls_session -> nx_secure_tls_protocol_version & 0x00FF); /* Set the length of the record prior to hashing and encryption - this is because the hashing is done on the record as if it were not encrypted so any additional padding or IVs, etc. added to the length would invalidate the hash. We update the length following the encryption below. *//* ... */ message_length = length; record_header[3] = (UCHAR)((length & 0xFF00) >> 8); record_header[4] = (UCHAR)(length & 0x00FF); /* If the session is active, hash and encrypt the record payload using the session keys and chosen ciphersuite. *//* ... */ if (tls_session -> nx_secure_tls_local_session_active) { /*************************************************************************************************************/ if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL) { /* Likely internal error since at this point ciphersuite negotiation was theoretically completed. */ tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(NX_SECURE_TLS_UNKNOWN_CIPHERSUITE); }if (tls_session -> nx_secure_tls_session_ciphersuite == NX_NULL) { ... } #if (NX_SECURE_TLS_TLS_1_3_ENABLED) /* TLS 1.3 records have the record type appended in a single byte. */ if(tls_session->nx_secure_tls_1_3) { /* If in a TLS 1.3 encrypted session, write the message type to the end. */ status = nx_packet_data_append(send_packet, (UCHAR*)(&record_type), 1, tls_session -> nx_secure_tls_packet_pool, wait_option); if(status != NX_SUCCESS) { tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(status); }if (status != NX_SUCCESS) { ... } /* Record header type is APPLICATION DATA for all TLS 1.3 encrypted records. */ record_type = NX_SECURE_TLS_APPLICATION_DATA; record_header[0] = record_type; }if (tls_session->nx_secure_tls_1_3) { ... } /* ... */#endif /* TLS 1.3 does uses AEAD instead of per-record hash MACs. */ if ( #if (NX_SECURE_TLS_TLS_1_3_ENABLED) !tls_session->nx_secure_tls_1_3 && #endif tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash -> nx_crypto_operation) { /***** HASHING *****/ /* Select our proper MAC secret for hashing. */ if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER) { /* If we are a server, we need to use the client's MAC secret. */ mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_server_write_mac_secret; }if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_SERVER) { ... } else { /* We are a client, so use the server's MAC secret. */ mac_secret = tls_session -> nx_secure_tls_key_material.nx_secure_tls_client_write_mac_secret; }else { ... } /* Account for large records that exceed the packet size and are chained in multiple packets such as large certificate messages with multiple certificates. tls_session->nx_secure_hash_mac_metadata_area is persistent across the following calls, so it's important to not do anything that might change the contents of that buffer until the hash is calculated after the loop! *//* ... */ current_packet = send_packet; /* Initialize the hash routine with our MAC secret, sequence number, and header. */ status = _nx_secure_tls_record_hash_initialize(tls_session, tls_session -> nx_secure_tls_local_sequence_number, record_header, 5, &hash_length, mac_secret); /* Check return from hash routine initialization. */ if (status != NX_SUCCESS) { tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(status); }if (status != NX_SUCCESS) { ... } /* Start the hash data after the header and IV. */ hash_data = current_packet -> nx_packet_prepend_ptr + iv_size; hash_data_length = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr) - iv_size; /* Walk packet chain. */ do { /* Update the hash with the data. */ status = _nx_secure_tls_record_hash_update(tls_session, hash_data, (UINT)hash_data_length); /* Advance the packet pointer to the next packet in the chain. */ current_packet = current_packet -> nx_packet_next; if (current_packet != NX_NULL) { hash_data = current_packet -> nx_packet_prepend_ptr; hash_data_length = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr); }if (current_packet != NX_NULL) { ... } ...} while (current_packet != NX_NULL); /* Generate the hash on the plaintext data. */ _nx_secure_tls_record_hash_calculate(tls_session, record_hash, &hash_length); /* Release the protection before suspending on nx_packet_data_append. */ tx_mutex_put(&_nx_secure_tls_protection); /* Append the hash to the plaintext data in the last packet before encryption. */ status = nx_packet_data_append(send_packet, record_hash, hash_length, tls_session -> nx_secure_tls_packet_pool, wait_option); #ifdef NX_SECURE_KEY_CLEAR NX_SECURE_MEMSET(record_hash, 0, sizeof(record_hash)); #endif /* NX_SECURE_KEY_CLEAR */ /* Get the protection after nx_packet_data_append. */ tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER); }if (#if (NX_SECURE_TLS_TLS_1_3_ENABLED) !tls_session->nx_secure_tls_1_3 && #endif tls_session -> nx_secure_tls_session_ciphersuite -> nx_secure_tls_hash -> nx_crypto_operation) { ... } ... /*************************************************************************************************************/ /***** ENCRYPTION *****/ status = _nx_secure_tls_record_payload_encrypt(tls_session, send_packet, tls_session -> nx_secure_tls_local_sequence_number, record_type); if (status != NX_SUCCESS) { tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(status); }if (status != NX_SUCCESS) { ... } ... /*************************************************************************************************************/ /* Increment the sequence number. */ if ((tls_session -> nx_secure_tls_local_sequence_number[0] + 1) == 0) { /* Check for overflow of the 32-bit number. */ tls_session -> nx_secure_tls_local_sequence_number[1]++; }if ((tls_session -> nx_secure_tls_local_sequence_number[0] + 1) == 0) { ... } tls_session -> nx_secure_tls_local_sequence_number[0]++; }if (tls_session -> nx_secure_tls_local_session_active) { ... } /* The encryption above may have changed the payload length, so get the length from the packet and use it to update the record header. *//* ... */ message_length = send_packet -> nx_packet_length; /* Set the length of the record. */ record_header[3] = (UCHAR)((message_length & 0xFF00) >> 8); record_header[4] = (UCHAR)(message_length & 0x00FF); /* Adjust packet length */ send_packet -> nx_packet_prepend_ptr -= NX_SECURE_TLS_RECORD_HEADER_SIZE; send_packet -> nx_packet_length += NX_SECURE_TLS_RECORD_HEADER_SIZE; /* Release the protection before suspending on nx_tcp_socket_send. */ tx_mutex_put(&_nx_secure_tls_protection); /* Send the TCP packet(s) containing our record. */ status = nx_tcp_socket_send(tls_session -> nx_secure_tls_tcp_socket, send_packet, wait_option); #ifdef NX_SECURE_KEY_CLEAR if (tls_session -> nx_secure_tls_local_session_active) { /* Clear all data in chained packet. */ current_packet = send_packet; while (current_packet) { NX_SECURE_MEMSET(current_packet -> nx_packet_prepend_ptr, 0, (ULONG)current_packet -> nx_packet_append_ptr - (ULONG)current_packet -> nx_packet_prepend_ptr); current_packet = current_packet -> nx_packet_next; }while (current_packet) { ... } }if (tls_session -> nx_secure_tls_local_session_active) { ... } /* ... */#endif /* NX_SECURE_KEY_CLEAR */ /* Get the protection after nx_tcp_socket_send. */ tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER); /* Release transmit mutex. */ tx_mutex_put(&(tls_session -> nx_secure_tls_session_transmit_mutex)); return(status); }{ ... }