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 #ifdef NX_SECURE_ENABLE_DTLS
26 #include "nx_packet.h"
27 #include "nx_udp.h"
28
29 /**************************************************************************/
30 /* */
31 /* FUNCTION RELEASE */
32 /* */
33 /* _nx_secure_dtls_client_handshake PORTABLE C */
34 /* 6.1.12 */
35 /* AUTHOR */
36 /* */
37 /* Timothy Stapko, Microsoft Corporation */
38 /* */
39 /* DESCRIPTION */
40 /* */
41 /* This function runs the DTLS Client mode state machine. It processes */
42 /* an incoming handshake record and takes appropriate action to */
43 /* advance the DTLS Client handshake. */
44 /* */
45 /* INPUT */
46 /* */
47 /* dtls_session DTLS control block */
48 /* packet_buffer Pointer into record buffer */
49 /* data_length Length of data */
50 /* wait_option Controls timeout actions */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* status Completion status */
55 /* */
56 /* CALLS */
57 /* */
58 /* _nx_secure_dtls_allocate_handshake_packet */
59 /* Allocate DTLS handshake packet*/
60 /* _nx_secure_dtls_packet_allocate Allocate internal DTLS packet */
61 /* _nx_secure_dtls_process_handshake_header */
62 /* Process handshake header */
63 /* _nx_secure_dtls_process_helloverifyrequest */
64 /* Process HelloVerifyRequest */
65 /* _nx_secure_dtls_retransmit_queue_flush */
66 /* Flush retransmit queue */
67 /* _nx_secure_dtls_send_clienthello Send ClientHello */
68 /* _nx_secure_dtls_send_handshake_record Send DTLS handshake record */
69 /* _nx_secure_dtls_send_record Send DTLS records */
70 /* _nx_secure_tls_generate_keys Generate session keys */
71 /* _nx_secure_tls_generate_premaster_secret */
72 /* Generate premaster secret */
73 /* _nx_secure_tls_handshake_hash_update Update Finished hash */
74 /* _nx_secure_tls_process_certificate_request */
75 /* Process certificate request */
76 /* _nx_secure_tls_process_finished Process Finished message */
77 /* _nx_secure_tls_process_remote_certificate */
78 /* Process remote certificate */
79 /* _nx_secure_tls_process_server_key_exchange */
80 /* Process ServerKeyExchange */
81 /* _nx_secure_tls_process_serverhello Process ServerHello */
82 /* _nx_secure_tls_send_certificate Send DTLS certificate */
83 /* _nx_secure_tls_send_certificate_verify */
84 /* Send certificate verify */
85 /* _nx_secure_tls_send_changecipherspec Send ChangeCipherSpec */
86 /* _nx_secure_tls_send_client_key_exchange */
87 /* Send ClientKeyExchange */
88 /* _nx_secure_tls_send_finished Send Finished message */
89 /* _nx_secure_tls_session_keys_set Set session keys */
90 /* nx_secure_tls_packet_release Release packet */
91 /* tx_mutex_get Get protection mutex */
92 /* tx_mutex_put Put protection mutex */
93 /* */
94 /* CALLED BY */
95 /* */
96 /* _nx_secure_dtls_process_record Process DTLS record data */
97 /* */
98 /* RELEASE HISTORY */
99 /* */
100 /* DATE NAME DESCRIPTION */
101 /* */
102 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
103 /* 09-30-2020 Timothy Stapko Modified comment(s), */
104 /* verified memcpy use cases, */
105 /* verified memmove use cases, */
106 /* released packet securely, */
107 /* fixed certificate buffer */
108 /* allocation, */
109 /* resulting in version 6.1 */
110 /* 12-31-2020 Timothy Stapko Modified comment(s), */
111 /* improved buffer length */
112 /* verification, added null */
113 /* pointer checking, */
114 /* resulting in version 6.1.3 */
115 /* 01-31-2022 Timothy Stapko Modified comment(s), */
116 /* fixed out-of-order handling,*/
117 /* resulting in version 6.1.10 */
118 /* 07-29-2022 Yuxin Zhou Modified comment(s), */
119 /* removed duplicated alert, */
120 /* resulting in version 6.1.12 */
121 /* */
122 /**************************************************************************/
_nx_secure_dtls_client_handshake(NX_SECURE_DTLS_SESSION * dtls_session,UCHAR * packet_buffer,UINT data_length,ULONG wait_option)123 UINT _nx_secure_dtls_client_handshake(NX_SECURE_DTLS_SESSION *dtls_session, UCHAR *packet_buffer,
124 UINT data_length, ULONG wait_option)
125 {
126 #ifndef NX_SECURE_TLS_CLIENT_DISABLED
127 UINT status;
128 USHORT message_type = NX_SECURE_TLS_INVALID_MESSAGE;
129 UINT header_bytes;
130 UINT message_length;
131 UCHAR *data_start = NX_NULL;
132 NX_PACKET *send_packet = NX_NULL;
133 NX_PACKET_POOL *packet_pool;
134 UINT message_seq;
135 UINT fragment_offset;
136 UINT fragment_length;
137 UCHAR *fragment_buffer;
138 NX_SECURE_TLS_SESSION *tls_session;
139
140 /* Basic state machine for handshake:
141 * 1. We have received a handshake message, now process the header.
142 * 2. Then process the message itself and populate the TLS socket structure.
143 * 3. Follow up with whatever actions are needed.
144 */
145
146 /* Get a reference to the internal TLS state for ease of use. */
147 tls_session = &dtls_session -> nx_secure_dtls_tls_session;
148
149 /* Use the TLS packet buffer for fragment processing. */
150 fragment_buffer = tls_session->nx_secure_tls_packet_buffer;
151
152 while (data_length > 0)
153 {
154 header_bytes = data_length;
155
156 /* First, process the handshake message to get our state and any data therein. */
157 status = _nx_secure_dtls_process_handshake_header(packet_buffer, &message_type, &header_bytes,
158 &message_length, &message_seq, &fragment_offset, &fragment_length);
159
160 if (status == NX_SUCCESS)
161 {
162
163 /* Out-of-order plus fragmentation:
164 * - If message sequence > current message sequence
165 * - New message
166 * - If message_sequence <= current message sequence
167 * - If fragment_length < message length, we have a fragment
168 * - Once fragment is reassembled, check message sequence for repeats
169 */
170
171 /* If we see a repeated message sequence, assume an unnecessary retransmission and ignore. */
172 if (message_seq < dtls_session -> nx_secure_dtls_remote_handshake_sequence)
173 {
174 /* Re-transmitted message. */
175 return(NX_SUCCESS);
176 }
177
178 /* Check the fragment_length with the lenght of packet buffer. */
179 if ((header_bytes + fragment_length) > data_length)
180 {
181 return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
182 }
183
184 /* Check available area of buffer. */
185 if ((fragment_offset + fragment_length) > tls_session -> nx_secure_tls_packet_buffer_size ||
186 (header_bytes + message_length) > tls_session -> nx_secure_tls_packet_buffer_size)
187 {
188 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
189 }
190
191 /* If this message sequence isn't what we expect, continue reading packets. */
192 if(message_seq != dtls_session -> nx_secure_dtls_expected_handshake_sequence)
193 {
194 return(NX_SECURE_TLS_OUT_OF_ORDER_MESSAGE);
195 }
196
197 /* If we have a new sequence number, we have a new record (may be fragmented). Unless
198 the sequence number is 0, which means it is the first record. */
199 if (message_seq > dtls_session -> nx_secure_dtls_remote_handshake_sequence || (message_seq == 0 && fragment_offset == 0))
200 {
201 /* New record starting, reset the fragment length and handshake sequence number. */
202 dtls_session -> nx_secure_dtls_remote_handshake_sequence = message_seq;
203 dtls_session -> nx_secure_dtls_fragment_length = message_length;
204 }
205
206 if (fragment_length > dtls_session -> nx_secure_dtls_fragment_length)
207 {
208 return(NX_SECURE_TLS_INVALID_PACKET);
209 }
210
211 /* When we receive a message fragment, subtract it from the current fragment length. */
212 dtls_session -> nx_secure_dtls_fragment_length -= fragment_length;
213
214 /* Copy the fragment data (minus the header) into the reassembly buffer. */
215 NX_SECURE_MEMCPY(&fragment_buffer[fragment_offset], &packet_buffer[header_bytes], fragment_length); /* Use case of memcpy is verified. */
216
217 /* If we still have fragments to add, just return success. */
218 if (dtls_session -> nx_secure_dtls_fragment_length > 0)
219 {
220 return(NX_SUCCESS);
221 }
222 else
223 {
224 /* At beginning of handshake, reset the expected sequence number. */
225 if (message_seq == 0)
226 {
227 dtls_session -> nx_secure_dtls_expected_handshake_sequence = 0;
228 }
229
230 /* If the recontructed message has a sequence not equal to the expected, it's
231 a retransmission we need to ignore. */
232 if (message_seq != dtls_session -> nx_secure_dtls_expected_handshake_sequence)
233 {
234 return(NX_SUCCESS);
235 }
236
237 /* Our next expected handshake message sequence number is 1 greater than this one. */
238 dtls_session -> nx_secure_dtls_expected_handshake_sequence = message_seq + 1;
239
240 /* Put the header into the packet buffer, adjusting the fields to create a seam-less
241 * DTLS record. */
242 NX_SECURE_MEMMOVE(&fragment_buffer[header_bytes], fragment_buffer, message_length); /* Use case of memmove is verified. */
243
244 /* Reconstruct the header in the fragment buffer so we can hash the
245 reconstructed record as if it were never fragmented. */
246
247 /* Type. */
248 fragment_buffer[0] = (UCHAR)message_type;
249
250 /* Length. */
251 fragment_buffer[1] = (UCHAR)(message_length >> 16);
252 fragment_buffer[2] = (UCHAR)(message_length >> 8);
253 fragment_buffer[3] = (UCHAR)(message_length);
254
255 /* Sequence. */
256 fragment_buffer[4] = (UCHAR)(message_seq >> 8);
257 fragment_buffer[5] = (UCHAR)(message_seq);
258
259 /* Fragment offset is now 0. */
260 fragment_buffer[6] = 0;
261 fragment_buffer[7] = 0;
262 fragment_buffer[8] = 0;
263
264 /* Fragment length is now == message length. */
265 fragment_buffer[9] = (UCHAR)(message_length >> 16);
266 fragment_buffer[10] = (UCHAR)(message_length >> 8);
267 fragment_buffer[11] = (UCHAR)(message_length);
268
269 /* We have a reassembled DTLS record, use that for the handshake. */
270 data_start = fragment_buffer;
271 }
272 }
273
274 if (status != NX_SECURE_TLS_SUCCESS)
275 {
276 return(status);
277 }
278
279 /* Allocate a packet for all send operations. */
280 packet_pool = tls_session -> nx_secure_tls_packet_pool;
281
282 /* Hash this handshake message. We do not hash HelloRequest messages.
283 Hashes include the handshake layer header but not the record layer header. */
284 if (message_type != NX_SECURE_TLS_HELLO_REQUEST && message_type != NX_SECURE_TLS_FINISHED &&
285 message_type != NX_SECURE_TLS_HELLO_VERIFY_REQUEST)
286 {
287 _nx_secure_tls_handshake_hash_update(tls_session, data_start, message_length + header_bytes);
288 }
289
290 /* Reduce total length by the size of this fragment. */
291 data_length -= (fragment_length + header_bytes);
292 data_start += header_bytes;
293
294 /* Process the message itself information from the header. */
295 switch (message_type)
296 {
297 case NX_SECURE_TLS_HELLO_VERIFY_REQUEST:
298 /* Initial DTLS message from server, contains a cookie for later transmissions. */
299 status = _nx_secure_dtls_process_helloverifyrequest(dtls_session, data_start, message_length);
300
301 if (status)
302 {
303
304 /* This is the end of a flight, clear out the transmit queue. */
305 _nx_secure_dtls_retransmit_queue_flush(dtls_session);
306 }
307 break;
308 case NX_SECURE_TLS_SERVER_HELLO:
309 /* Server has responded to our ClientHello. */
310 status = _nx_secure_tls_process_serverhello(tls_session, data_start, message_length);
311 break;
312 case NX_SECURE_TLS_CERTIFICATE_MSG:
313 /* Server has sent its certificate message. */
314 status = _nx_secure_tls_process_remote_certificate(tls_session, data_start, message_length, message_length);
315 break;
316 case NX_SECURE_TLS_SERVER_HELLO_DONE:
317 /* Server has responded to our ClientHello. */
318 /* A ServerHelloDone does not contain any data - it simply changes state. */
319 tls_session -> nx_secure_tls_client_state = NX_SECURE_TLS_CLIENT_STATE_SERVERHELLO_DONE;
320
321 /* This is the end of a flight, clear out the transmit queue. */
322 _nx_secure_dtls_retransmit_queue_flush(dtls_session);
323 break;
324 case NX_SECURE_TLS_SERVER_KEY_EXCHANGE:
325 /* Server has sent a key exchange message, used for certain ciphersuites (DH and PSK mainly). */
326 status = _nx_secure_tls_process_server_key_exchange(tls_session, data_start, message_length);
327 break;
328 case NX_SECURE_TLS_CERTIFICATE_REQUEST:
329 /* Server has requested we provide a client certificate. */
330 status = _nx_secure_tls_process_certificate_request(tls_session, data_start, message_length);
331 break;
332 case NX_SECURE_TLS_FINISHED:
333 /* Final handshake message from the server, process it (verify the server handshake hash). */
334 status = _nx_secure_tls_process_finished(tls_session, data_start, message_length);
335
336 /* This is the end of a flight, clear out the transmit queue. */
337 _nx_secure_dtls_retransmit_queue_flush(dtls_session);
338 break;
339 case NX_SECURE_TLS_HELLO_REQUEST:
340 /* Server has requested we restart the session. If we are in the middle of a handshake already
341 * (session is not active) then ignore. If we are in an active session, we can choose to
342 * send a ClientHello (start the handshake again) or send a no_renegotiation alert. */
343
344 /* A HelloRequest does not contain any data - it simply changes state. */
345 tls_session -> nx_secure_tls_client_state = NX_SECURE_TLS_CLIENT_STATE_HELLO_REQUEST;
346 break;
347 case NX_SECURE_TLS_CERTIFICATE_VERIFY:
348 case NX_SECURE_TLS_CLIENT_KEY_EXCHANGE:
349 case NX_SECURE_TLS_CLIENT_HELLO:
350 case NX_SECURE_TLS_INVALID_MESSAGE:
351 case NX_SECURE_TLS_CERTIFICATE_URL:
352 case NX_SECURE_TLS_CERTIFICATE_STATUS:
353 default:
354 /* The message received was not a valid TLS server handshake message, send alert and return. */
355 status = NX_SECURE_TLS_UNEXPECTED_MESSAGE;
356 break;
357 }
358
359 /* Check for errors in processing messages. */
360 if (status != NX_SECURE_TLS_SUCCESS)
361 {
362
363 return(status);
364 }
365
366 /* Now take any actions based on state set in the message processing. */
367 switch (tls_session -> nx_secure_tls_client_state)
368 {
369 case NX_SECURE_TLS_CLIENT_STATE_IDLE:
370 /* Client isn't doing anything right now. */
371 break;
372 case NX_SECURE_TLS_CLIENT_STATE_ERROR:
373 case NX_SECURE_TLS_CLIENT_STATE_ALERT_SENT:
374 /* This means an error was encountered at some point in processing a valid message. At this point
375 the alert was sent, so just return a status indicating as much. */
376 return(NX_SECURE_TLS_HANDSHAKE_FAILURE);
377 break;
378 case NX_SECURE_TLS_CLIENT_STATE_HELLO_REQUEST:
379 /* Server sent a hello request, indicating it wants to restart the handshake process with a new ClientHello. */
380 if (tls_session -> nx_secure_tls_local_session_active)
381 {
382 /* Respond to the HelloRequest with a "no_renegotiation" alert since we don't want to restart the handshake. */
383 status = NX_SECURE_TLS_NO_RENEGOTIATION_ERROR;
384 }
385 /* If we are still in a handshake (session is not active) then ignore the message. */
386 break;
387 case NX_SECURE_TLS_CLIENT_STATE_HELLO_VERIFY:
388
389 /* Get ClientHello packet from header of transmit queue. */
390 send_packet = dtls_session -> nx_secure_dtls_transmit_sent_head;
391 if ((send_packet == NX_NULL) || (send_packet -> nx_packet_queue_next != ((NX_PACKET *)NX_DRIVER_TX_DONE)))
392 {
393
394 /* Invalid packet. */
395 status = NX_INVALID_PACKET;
396 break;
397 }
398
399 /* Clear the transmit queue. */
400 dtls_session -> nx_secure_dtls_transmit_sent_head = NX_NULL;
401 dtls_session -> nx_secure_dtls_transmit_sent_tail = NX_NULL;
402 dtls_session -> nx_secure_dtls_transmit_sent_count = 0;
403
404 /* Reset the packet. */
405 send_packet -> nx_packet_prepend_ptr += sizeof(NX_UDP_HEADER);
406 send_packet -> nx_packet_length -= sizeof(NX_UDP_HEADER);
407 send_packet -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
408
409 _nx_secure_dtls_send_clienthello(dtls_session, send_packet);
410
411 status = _nx_secure_dtls_send_handshake_record(dtls_session, send_packet, NX_SECURE_TLS_CLIENT_HELLO, wait_option, 1);
412 break;
413 case NX_SECURE_TLS_CLIENT_STATE_SERVERHELLO:
414 /* We processed a serverhello above. Don't do anything right now. */
415 break;
416 case NX_SECURE_TLS_CLIENT_STATE_SERVER_CERTIFICATE:
417 /* Processed a server certificate above. Here, we extract the public key and do any verification
418 we want - the TLS implementation will verify certificate authenticity by checking the issuer
419 signature, but any other verification will be done by the caller via a callback. */
420 break;
421 case NX_SECURE_TLS_CLIENT_STATE_SERVER_KEY_EXCHANGE:
422 break;
423 case NX_SECURE_TLS_CLIENT_STATE_CERTIFICATE_REQUEST:
424 /* Set flag to send CertificateVerify once we have received ServerHelloDone. */
425 tls_session -> nx_secure_tls_client_certificate_requested = 1;
426 break;
427 case NX_SECURE_TLS_CLIENT_STATE_SERVERHELLO_DONE:
428 /* We received a ServerHelloDone, meaning we now have all the information we need to generate
429 our key material. First check if the server requested our client certificate. */
430
431 if (tls_session -> nx_secure_tls_client_certificate_requested)
432 {
433
434 /* The server has requested a client certificate. Provide that certificate to the server here. */
435 status = _nx_secure_dtls_allocate_handshake_packet(dtls_session, packet_pool, &send_packet, wait_option);
436
437 if (status != NX_SUCCESS)
438 {
439 break;
440 }
441
442 _nx_secure_tls_send_certificate(tls_session, send_packet, wait_option);
443
444 status = _nx_secure_dtls_send_handshake_record(dtls_session, send_packet, NX_SECURE_TLS_CERTIFICATE_MSG, wait_option, 1);
445
446 if (status != NX_SUCCESS)
447 {
448 break;
449 }
450 }
451
452 /* Now, generate the pre-master secret that is used to generate keys for our session. */
453 status = _nx_secure_tls_generate_premaster_secret(tls_session, NX_SECURE_DTLS);
454 if (status != NX_SUCCESS)
455 {
456 break;
457 }
458
459 /* We have received and processed a ServerHelloDone. Now respond to the client appropriately. */
460 status = _nx_secure_dtls_allocate_handshake_packet(dtls_session, packet_pool, &send_packet, wait_option);
461
462 if (status != NX_SUCCESS)
463 {
464 break;
465 }
466
467 /* Generate and send the ClientKeyExchange message. */
468 _nx_secure_tls_send_client_key_exchange(tls_session, send_packet);
469 status = _nx_secure_dtls_send_handshake_record(dtls_session, send_packet, NX_SECURE_TLS_CLIENT_KEY_EXCHANGE, wait_option, 1);
470
471 if (status != NX_SUCCESS)
472 {
473 break;
474 }
475
476 /* After sending ClientKeyExchange, we need to send a CertificateVerify message if the
477 server has requested a certificate. */
478 if (tls_session -> nx_secure_tls_client_certificate_requested)
479 {
480 /* We can now clear the flag since this is the last specific certificate message sent. */
481 tls_session -> nx_secure_tls_client_certificate_requested = 0;
482
483 /* Allocate packet for CertificateVerify. */
484 status = _nx_secure_dtls_allocate_handshake_packet(dtls_session, packet_pool, &send_packet, wait_option);
485
486 if (status != NX_SUCCESS)
487 {
488 break;
489 }
490
491 _nx_secure_tls_send_certificate_verify(tls_session, send_packet);
492
493 status = _nx_secure_dtls_send_handshake_record(dtls_session, send_packet, NX_SECURE_TLS_CERTIFICATE_VERIFY, wait_option, 1);
494
495 if (status != NX_SUCCESS)
496 {
497 break;
498 }
499 }
500
501 /* Generate our key material from the data collected thus far and put it all into our
502 socket structure. Don't call generate keys before sending the client_key_exchange message
503 since it needs the pre-master secret and this call clears it out (for security). */
504 status = _nx_secure_tls_generate_keys(tls_session);
505
506 if (status != NX_SUCCESS)
507 {
508 break;
509 }
510
511 /* Release the protection before suspending on nx_packet_allocate. */
512 tx_mutex_put(&_nx_secure_tls_protection);
513
514 /* We have received everything we need to complete the handshake. Keys have been
515 * generated above. Now end the handshake with a ChangeCipherSpec (indicating following
516 * messages are encrypted) and the encrypted Finished message. */
517 status = _nx_secure_dtls_packet_allocate(dtls_session, packet_pool, &send_packet, wait_option);
518
519 /* Get the protection after nx_packet_allocate. */
520 tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
521
522 if (status != NX_SUCCESS)
523 {
524 break;
525 }
526
527 /* ChangeCipherSpec is NOT a handshake message, so send as a normal TLS record. */
528 _nx_secure_tls_send_changecipherspec(tls_session, send_packet);
529 status = _nx_secure_dtls_send_record(dtls_session, send_packet, NX_SECURE_TLS_CHANGE_CIPHER_SPEC, wait_option);
530
531 if (status != NX_SUCCESS)
532 {
533 /* Release packet on send error. */
534 nx_secure_tls_packet_release(send_packet);
535 break;
536 }
537 /* The local session is now active since we sent the changecipherspec message.
538 NOTE: Do not set this flag until after the changecipherspec message has been passed to the send record
539 routine - this flag causes encryption and hashing to happen on records. ChangeCipherSpec should be the last
540 un-encrypted/un-hashed record sent. */
541
542 /* For DTLS, reset sequence number and advance epoch right after CCS message is sent. */
543 NX_SECURE_MEMSET(tls_session -> nx_secure_tls_local_sequence_number, 0, sizeof(tls_session -> nx_secure_tls_local_sequence_number));
544
545 status = _nx_secure_tls_session_keys_set(tls_session, NX_SECURE_TLS_KEY_SET_LOCAL);
546
547 if (status != NX_SUCCESS)
548 {
549 break;
550 }
551
552 /* Advance the DTLS epoch - all messages after the ChangeCipherSpec are in a new epoch. */
553 dtls_session -> nx_secure_dtls_local_epoch = (USHORT)(dtls_session -> nx_secure_dtls_local_epoch + 1);
554
555 /* We can now send our finished message, which will be encrypted using the chosen ciphersuite. */
556 status = _nx_secure_dtls_allocate_handshake_packet(dtls_session, packet_pool, &send_packet, wait_option);
557
558 if (status != NX_SUCCESS)
559 {
560 break;
561 }
562
563 /* Generate and send the finished message, which completes the handshake. */
564 _nx_secure_tls_send_finished(tls_session, send_packet);
565 status = _nx_secure_dtls_send_handshake_record(dtls_session, send_packet, NX_SECURE_TLS_FINISHED, wait_option, 1);
566
567 break;
568 case NX_SECURE_TLS_CLIENT_STATE_HANDSHAKE_FINISHED:
569 /* We processed a server finished message, completing the handshake. Verify all is good and if so,
570 continue to the encrypted session. */
571 break;
572 default:
573 status = NX_SECURE_TLS_INVALID_STATE;
574 }
575
576 /* If we have an error at this point, we have experienced a problem in sending
577 handshake messages, which is some type of internal issue. */
578 if (status != NX_SUCCESS)
579 {
580
581 return(status);
582 }
583
584 /* Advance the buffer pointer past the fragment. */
585 packet_buffer += (fragment_length + header_bytes);
586 } /* End while. */
587 return(NX_SUCCESS);
588 #else /* TLS Client disabled. */
589
590 /* We don't use the parameters since this is an error case. */
591 NX_PARAMETER_NOT_USED(packet_buffer);
592 NX_PARAMETER_NOT_USED(wait_option);
593 NX_PARAMETER_NOT_USED(data_length);
594
595 /* If TLS Client is disabled and we are in the client state machine, something is wrong... */
596 dtls_session -> nx_secure_dtls_tls_session.nx_secure_tls_server_state = NX_SECURE_TLS_SERVER_STATE_ERROR;
597 return(NX_SECURE_TLS_INVALID_STATE);
598 #endif
599 }
600 #endif /* NX_SECURE_ENABLE_DTLS */
601
602