/*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * Copyright (c) 2025-present Eclipse ThreadX Contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ /** */ /** NetX Secure Component */ /** */ /** Datagram Transport Layer Security (DTLS) */ /** */ /**************************************************************************/ /**************************************************************************/ #define NX_SECURE_SOURCE_CODE #include "nx_secure_dtls.h" /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _nx_secure_dtls_server_create PORTABLE C */ /* 6.4.3 */ /* AUTHOR */ /* */ /* Timothy Stapko, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function creates an instance of a DTLS server to handle */ /* incoming DTLS requests on a particular UDP port. Due to the fact */ /* that UDP is stateless, DTLS requests from multiple clients can come */ /* in on a single port while other DTLS sessions are active. Thus, the */ /* server is needed to maintain active sessions and properly route */ /* incoming messages to the proper handler. */ /* */ /* The session buffer parameter is used to hold the control blocks for */ /* all the possible simultaneous DTLS sessions for the DTLS server. It */ /* should be allocated with a size that is an even multiple of the */ /* size of the NX_SECURE_DTLS_SESSION control block structure. */ /* */ /* To calculate the necessary metadata size, the API */ /* nx_secure_tls_metadata_size_calculate may be used. */ /* */ /* INPUT */ /* */ /* server_ptr DTLS server control block */ /* ip_ptr Pointer to IP instance */ /* port Server port */ /* timeout Timeout value */ /* session_buffer DTLS sessions buffer */ /* session_buffer_size Size of DTLS sessions buffer */ /* crypto_table Crypto table */ /* crypto_metadata_buffer Encryption metadata buffer */ /* crypto_metadata_size Encryption metadata size */ /* packet_reassembly_buffer DTLS reassembly buffer */ /* packet_reassembly_buffer_size Size of reassembly buffer */ /* connect_notify Callback for new connections */ /* receive_notify Callback for received data */ /* */ /* OUTPUT */ /* */ /* status Completion status */ /* */ /* CALLS */ /* */ /* _nx_secure_dtls_session_create Initialize DTLS control block */ /* nx_udp_socket_create Set up UDP socket */ /* tx_mutex_get Get protection mutex */ /* tx_mutex_put Put protection mutex */ /* */ /* CALLED BY */ /* */ /* Application Code */ /* */ /**************************************************************************/ UINT _nx_secure_dtls_server_create(NX_SECURE_DTLS_SERVER *server_ptr, NX_IP *ip_ptr, UINT port, ULONG timeout, VOID *session_buffer, UINT session_buffer_size, const NX_SECURE_TLS_CRYPTO *crypto_table, VOID *crypto_metadata_buffer, ULONG crypto_metadata_size, UCHAR *packet_reassembly_buffer, UINT packet_reassembly_buffer_size, UINT (*connect_notify)(NX_SECURE_DTLS_SESSION *dtls_session, NXD_ADDRESS *ip_address, UINT port), UINT (*receive_notify)(NX_SECURE_DTLS_SESSION *dtls_session)) { #ifdef NX_SECURE_ENABLE_DTLS UINT status; UINT i; NX_SECURE_DTLS_SESSION *current_session; ULONG session_metadata_size; UINT session_pkt_buffer_size; UCHAR *session_pkt_buffer; UCHAR *session_metadata; UINT num_sessions; NX_SECURE_DTLS_SERVER *tail_ptr; /* Figure out number of sessions. */ num_sessions = session_buffer_size / sizeof(NX_SECURE_DTLS_SESSION); /* Check sessions buffer size. */ if(num_sessions == 0) { return(NX_INVALID_PARAMETERS); } /* Set server parameters. */ server_ptr->nx_dtls_server_ip_ptr = ip_ptr; server_ptr->nx_dtls_server_listen_port = port; server_ptr->nx_dtls_server_sessions_count = num_sessions; server_ptr->nx_dtls_server_timeout = timeout; /* Set up session buffer. */ server_ptr->nx_dtls_server_sessions = (NX_SECURE_DTLS_SESSION*)session_buffer; /* Setup per-session packet buffer. */ session_pkt_buffer_size = packet_reassembly_buffer_size / num_sessions; session_pkt_buffer = packet_reassembly_buffer; /* Get our per-session metadata. */ session_metadata = crypto_metadata_buffer; session_metadata_size = crypto_metadata_size / num_sessions; /* Set up UDP socket. */ status = nx_udp_socket_create(ip_ptr, &(server_ptr->nx_dtls_server_udp_socket), "DTLS Server", NX_IP_NORMAL, NX_FRAGMENT_OKAY, timeout, 8192); /* Store a pointer to our DTLS server instance in our UDP socket. This enables the receive callback to access the right server. */ server_ptr->nx_dtls_server_udp_socket.nx_udp_socket_reserved_ptr = server_ptr; if(status != NX_SUCCESS) { return(status); } /* Assign callbacks. */ server_ptr->nx_secure_dtls_receive_notify = receive_notify; server_ptr->nx_secure_dtls_connect_notify = connect_notify; /* Reset the protocol version override. */ server_ptr -> nx_dtls_server_protocol_version_override = 0; /* Initialize sessions. */ for(i = 0; i < num_sessions; ++i) { /* Get the current session. */ current_session = &(server_ptr->nx_dtls_server_sessions[i]); /* Initialize each DTLS session - don't add remote certificate data here. */ status = _nx_secure_dtls_session_create(current_session, crypto_table, session_metadata, session_metadata_size, session_pkt_buffer, session_pkt_buffer_size, 0, NX_NULL, 0); if(status != NX_SUCCESS) { /* Delete the created UDP socket. */ nx_udp_socket_delete(&(server_ptr->nx_dtls_server_udp_socket)); return(status); } /* Assign the parent server instance. */ current_session->nx_secure_dtls_server_parent = server_ptr; /* Assign other parameters. */ current_session->nx_secure_dtls_local_port = port; current_session->nx_secure_dtls_udp_socket = &(server_ptr->nx_dtls_server_udp_socket); /* Advance metadata buffer. */ session_metadata = &session_metadata[session_metadata_size]; /* Advance packet buffer. */ session_pkt_buffer = &session_pkt_buffer[session_pkt_buffer_size]; } /* Get the protection. */ tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER); /* Place the new DTLS server control block on the list of created DTLS server. */ if (_nx_secure_dtls_server_created_ptr) { /* Pickup tail pointer. */ tail_ptr = _nx_secure_dtls_server_created_ptr -> nx_dtls_server_created_previous; /* Place the new DTLS server control block in the list. */ _nx_secure_dtls_server_created_ptr -> nx_dtls_server_created_previous = server_ptr; tail_ptr -> nx_dtls_server_created_next = server_ptr; /* Setup this DTLS server's created links. */ server_ptr -> nx_dtls_server_created_previous = tail_ptr; server_ptr -> nx_dtls_server_created_next = _nx_secure_dtls_server_created_ptr; } else { /* The created DTLS server list is empty. Add DTLS server control block to empty list. */ _nx_secure_dtls_server_created_ptr = server_ptr; server_ptr -> nx_dtls_server_created_previous = server_ptr; server_ptr -> nx_dtls_server_created_next = server_ptr; } _nx_secure_dtls_server_created_count++; /* Release the protection. */ tx_mutex_put(&_nx_secure_tls_protection); return(NX_SUCCESS); #else NX_PARAMETER_NOT_USED(server_ptr); NX_PARAMETER_NOT_USED(ip_ptr); NX_PARAMETER_NOT_USED(port); NX_PARAMETER_NOT_USED(timeout); NX_PARAMETER_NOT_USED(session_buffer); NX_PARAMETER_NOT_USED(session_buffer_size); NX_PARAMETER_NOT_USED(crypto_table); NX_PARAMETER_NOT_USED(crypto_metadata_buffer); NX_PARAMETER_NOT_USED(crypto_metadata_size); NX_PARAMETER_NOT_USED(packet_reassembly_buffer); NX_PARAMETER_NOT_USED(packet_reassembly_buffer_size); NX_PARAMETER_NOT_USED(connect_notify); NX_PARAMETER_NOT_USED(receive_notify); return(NX_NOT_SUPPORTED); #endif /* NX_SECURE_ENABLE_DTLS */ }