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 /** Transport Layer Security (TLS) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_tls.h"
25
26 /**************************************************************************/
27 /* */
28 /* FUNCTION RELEASE */
29 /* */
30 /* _nx_secure_tls_send_newsessionticket PORTABLE C */
31 /* 6.1 */
32 /* AUTHOR */
33 /* */
34 /* Timothy Stapko, Microsoft Corporation */
35 /* */
36 /* DESCRIPTION */
37 /* */
38 /* This function generates a NewSessionTicket message for a TLS Server.*/
39 /* The message contains data used to generate a PSK that can be used */
40 /* for session resumption should the same client attempt another */
41 /* connection within the lifespan of the ticket. */
42 /* */
43 /* INPUT */
44 /* */
45 /* tls_session TLS control block */
46 /* send_packet Packet used to send message */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* status Completion status */
51 /* */
52 /* CALLS */
53 /* */
54 /* NX_RAND Generate ticket data */
55 /* */
56 /* CALLED BY */
57 /* */
58 /* _nx_secure_tls_server_handshake TLS server state machine */
59 /* */
60 /* RELEASE HISTORY */
61 /* */
62 /* DATE NAME DESCRIPTION */
63 /* */
64 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
65 /* 09-30-2020 Timothy Stapko Modified comment(s), */
66 /* verified memcpy use cases, */
67 /* resulting in version 6.1 */
68 /* */
69 /**************************************************************************/
70 #if (NX_SECURE_TLS_TLS_1_3_ENABLED)
_nx_secure_tls_send_newsessionticket(NX_SECURE_TLS_SESSION * tls_session,NX_PACKET * send_packet)71 UINT _nx_secure_tls_send_newsessionticket(NX_SECURE_TLS_SESSION *tls_session, NX_PACKET *send_packet)
72 {
73 UINT status = NX_SUCCESS;
74 UINT length;
75 UINT lifetime;
76 UINT age_add;
77 UINT nonce;
78 UINT nonce_len;
79 UINT ticket_len;
80 UCHAR *ticket;
81 UINT extensions_len;
82 UCHAR *packet_buffer;
83
84 /* From RFC 8446:
85 struct {
86 uint32 ticket_lifetime;
87 uint32 ticket_age_add;
88 opaque ticket_nonce<0..255>;
89 opaque ticket<1..2^16-1>;
90 Extension extensions<0..2^16-2>;
91 } NewSessionTicket;
92
93 | 4 | 4 | 1 | <nonce_len> | 2 | <ticket_len> | 2 | <extensions_len> |
94 | lifetime | age add | nonce_len | nonce | ticket_len | ticket | extensions_len | extensions |
95
96 ticket_lifetime: Indicates the lifetime in seconds as a 32-bit
97 unsigned integer in network byte order from the time of ticket
98 issuance. Servers MUST NOT use any value greater than
99 604800 seconds (7 days). The value of zero indicates that the
100 ticket should be discarded immediately. Clients MUST NOT cache
101 tickets for longer than 7 days, regardless of the ticket_lifetime,
102 and MAY delete tickets earlier based on local policy. A server
103 MAY treat a ticket as valid for a shorter period of time than what
104 is stated in the ticket_lifetime.
105
106 ticket_age_add: A securely generated, random 32-bit value that is
107 used to obscure the age of the ticket that the client includes in
108 the "pre_shared_key" extension. The client-side ticket age is
109 added to this value modulo 2^32 to obtain the value that is
110 transmitted by the client. The server MUST generate a fresh value
111 for each ticket it sends.
112
113 ticket_nonce: A per-ticket value that is unique across all tickets
114 issued on this connection.
115
116 ticket: The value of the ticket to be used as the PSK identity. The
117 ticket itself is an opaque label. It MAY be either a database
118 lookup key or a self-encrypted and self-authenticated value.
119
120 extensions: A set of extension values for the ticket. The
121 "Extension" format is defined in Section 4.2. Clients MUST ignore
122 unrecognized extensions.
123
124 The sole extension currently defined for NewSessionTicket is
125 "early_data", indicating that the ticket may be used to send 0-RTT
126 data (Section 4.2.10). It contains the following value:
127
128 max_early_data_size: The maximum amount of 0-RTT data that the
129 client is allowed to send when using this ticket, in bytes. Only
130 Application Data payload (i.e., plaintext but not padding or the
131 inner content type byte) is counted. A server receiving more than
132 max_early_data_size bytes of 0-RTT data SHOULD terminate the
133 connection with an "unexpected_message" alert. Note that servers
134 that reject early data due to lack of cryptographic material will
135 be unable to differentiate padding from content, so clients
136 SHOULD NOT depend on being able to send large quantities of
137 padding in early data records.
138
139 The PSK associated with the ticket is computed as:
140
141 HKDF-Expand-Label(resumption_master_secret,
142 "resumption", ticket_nonce, Hash.length)
143
144
145 */
146
147 NX_PARAMETER_NOT_USED(tls_session);
148
149 if (((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_append_ptr)) < 13u)
150 {
151
152 /* Packet buffer too small. */
153 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
154 }
155
156 length = 0;
157 packet_buffer = send_packet -> nx_packet_append_ptr;
158
159 /* First, the ticket lifetime in ms - 604800 is the maximum. */
160 lifetime = 604800;
161 packet_buffer[length] = (UCHAR)((lifetime & 0xFF000000) >> 24);
162 packet_buffer[length + 1] = (UCHAR)((lifetime & 0x00FF0000) >> 16);
163 packet_buffer[length + 2] = (UCHAR)((lifetime & 0x0000FF00) >> 8);
164 packet_buffer[length + 3] = (UCHAR) (lifetime & 0x000000FF);
165 length += 4;
166
167 /* The age_add is a cryptographically secure random 32-bit number. */
168 age_add = (UINT)NX_RAND();
169 packet_buffer[length] = (UCHAR)((age_add & 0xFF000000) >> 24);
170 packet_buffer[length + 1] = (UCHAR)((age_add & 0x00FF0000) >> 16);
171 packet_buffer[length + 2] = (UCHAR)((age_add & 0x0000FF00) >> 8);
172 packet_buffer[length + 3] = (UCHAR) (age_add & 0x000000FF);
173 length += 4;
174
175
176 /* Set up the nonce - 4 bytes of random data. */
177 nonce = (UINT)NX_RAND();
178 nonce_len = 4;
179
180 /* Add in the nonce length. */
181 packet_buffer[length] = (UCHAR)(nonce_len & 0xFF);
182 length += 1;
183
184 /* Nonces are currently max 32 bits */
185 packet_buffer[length] = (UCHAR)((nonce & 0xFF000000) >> 24);
186 packet_buffer[length + 1] = (UCHAR)((nonce & 0x00FF0000) >> 16);
187 packet_buffer[length + 2] = (UCHAR)((nonce & 0x0000FF00) >> 8);
188 packet_buffer[length + 3] = (UCHAR) (nonce & 0x000000FF);
189 length += nonce_len;
190
191
192 /* Now for the ticket ID itself. 16-bit length with the ticket being a label
193 used as the PSK identity. */
194 ticket = (UCHAR *)("NewSessionTicket");
195 ticket_len = sizeof("NewSessionTicket");
196
197 if (((ULONG)(send_packet -> nx_packet_data_end) - (ULONG)(send_packet -> nx_packet_append_ptr)) < (17u + ticket_len))
198 {
199
200 /* Packet buffer too small. */
201 return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
202 }
203
204 /* Insert ticket length. */
205 packet_buffer[length] = (UCHAR)((ticket_len & 0xFF00) >> 8);
206 packet_buffer[length + 1] = (UCHAR)(ticket_len & 0x00FF);
207 length += 2;
208
209 /* Copy in ticket. */
210 NX_SECURE_MEMCPY(&packet_buffer[length], ticket, ticket_len); /* Use case of memcpy is verified. */
211 length += ticket_len;
212
213 /* Add in extensions if available. */
214 extensions_len = 0;
215 packet_buffer[length] = (UCHAR)((extensions_len & 0xFF00) >> 8);
216 packet_buffer[length + 1] = (UCHAR) (extensions_len & 0x00FF);
217 length += 2;
218
219 /* Adjust the packet into which we just wrote the finished hash. */
220 send_packet -> nx_packet_append_ptr = send_packet -> nx_packet_append_ptr + length;
221 send_packet -> nx_packet_length = send_packet -> nx_packet_length + length;
222
223 return(status);
224 }
225
226 #endif
227