/src/wolfssl-heapmath/src/ssl_api_dtls.c
Line | Count | Source |
1 | | /* ssl_api_dtls.c |
2 | | * |
3 | | * Copyright (C) 2006-2026 wolfSSL Inc. |
4 | | * |
5 | | * This file is part of wolfSSL. |
6 | | * |
7 | | * wolfSSL is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * wolfSSL is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
20 | | */ |
21 | | |
22 | | #include <wolfssl/wolfcrypt/libwolfssl_sources.h> |
23 | | |
24 | | #if !defined(WOLFSSL_SSL_API_DTLS_INCLUDED) |
25 | | #ifndef WOLFSSL_IGNORE_FILE_WARN |
26 | | #warning ssl_api_dtls.c does not need to be compiled separately from ssl.c |
27 | | #endif |
28 | | #else |
29 | | |
30 | | #ifndef WOLFCRYPT_ONLY |
31 | | |
32 | | #ifdef WOLFSSL_DTLS |
33 | | /* Set the file descriptor for an already connected DTLS object. |
34 | | * |
35 | | * @param [in] ssl SSL/TLS object. |
36 | | * @param [in] fd Connected socket file descriptor. |
37 | | * @return WOLFSSL_SUCCESS on success. |
38 | | * @return BAD_FUNC_ARG when ssl is NULL. |
39 | | */ |
40 | | int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) |
41 | | { |
42 | | int ret; |
43 | | |
44 | | WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); |
45 | | |
46 | | if (ssl == NULL) { |
47 | | return BAD_FUNC_ARG; |
48 | | } |
49 | | |
50 | | ret = wolfSSL_set_fd(ssl, fd); |
51 | | if (ret == WOLFSSL_SUCCESS) |
52 | | ssl->buffers.dtlsCtx.connected = 1; |
53 | | |
54 | | return ret; |
55 | | } |
56 | | #endif |
57 | | |
58 | | /* Determine whether the object is configured for DTLS. |
59 | | * |
60 | | * @param [in] ssl SSL/TLS object. |
61 | | * @return 1 when using DTLS. |
62 | | * @return 0 otherwise, or when ssl is NULL. |
63 | | */ |
64 | | int wolfSSL_dtls(WOLFSSL* ssl) |
65 | 0 | { |
66 | 0 | int dtlsOpt = 0; |
67 | 0 | if (ssl) |
68 | 0 | dtlsOpt = ssl->options.dtls; |
69 | 0 | return dtlsOpt; |
70 | 0 | } |
71 | | |
72 | | #ifndef WOLFSSL_LEANPSK |
73 | | #if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ |
74 | | !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) |
75 | | /* Create a DTLS peer address from a port and IPv4 address string. |
76 | | * |
77 | | * The returned object must be freed with wolfSSL_dtls_free_peer(). |
78 | | * |
79 | | * @param [in] port Port number. |
80 | | * @param [in] ip Dotted-decimal IPv4 address string. |
81 | | * @return Newly allocated peer address on success. |
82 | | * @return NULL on allocation error or when the address is invalid. |
83 | | */ |
84 | | void* wolfSSL_dtls_create_peer(int port, char* ip) |
85 | | { |
86 | | SOCKADDR_IN *addr; |
87 | | addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, |
88 | | DYNAMIC_TYPE_SOCKADDR); |
89 | | if (addr == NULL) { |
90 | | return NULL; |
91 | | } |
92 | | |
93 | | addr->sin_family = AF_INET; |
94 | | addr->sin_port = XHTONS((word16)port); |
95 | | if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { |
96 | | XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); |
97 | | return NULL; |
98 | | } |
99 | | |
100 | | return addr; |
101 | | } |
102 | | |
103 | | /* Free a DTLS peer address created with wolfSSL_dtls_create_peer(). |
104 | | * |
105 | | * @param [in] addr Peer address to free. |
106 | | * @return WOLFSSL_SUCCESS always. |
107 | | */ |
108 | | int wolfSSL_dtls_free_peer(void* addr) |
109 | | { |
110 | | XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); |
111 | | return WOLFSSL_SUCCESS; |
112 | | } |
113 | | #endif |
114 | | |
115 | | #ifdef WOLFSSL_DTLS |
116 | | /* Store a socket address into a socket address holder, resizing as needed. |
117 | | * |
118 | | * A NULL or zero-length peer frees the holder's buffer. An address that fits |
119 | | * the buffer already there is copied over it rather than reallocated: |
120 | | * EmbedSendTo reads peer.sa without taking peerLock, so freeing it on every |
121 | | * update would widen that race rather than leave it as it is. |
122 | | * |
123 | | * The record layer promotes a pending peer through this while already holding |
124 | | * peerLock, so it takes no lock of its own. |
125 | | * |
126 | | * @param [in, out] sockAddr Socket address holder. |
127 | | * @param [in] peer Socket address data, may be NULL to free. |
128 | | * @param [in] peerSz Length of socket address data in bytes. |
129 | | * @param [in] heap Heap hint for dynamic memory allocation. |
130 | | * @return WOLFSSL_SUCCESS on success. |
131 | | * @return WOLFSSL_FAILURE on allocation error. |
132 | | */ |
133 | | int wolfssl_local_SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, |
134 | | unsigned int peerSz, void* heap) |
135 | | { |
136 | | if (peer == NULL || peerSz == 0) { |
137 | | if (sockAddr->sa != NULL) |
138 | | XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); |
139 | | sockAddr->sa = NULL; |
140 | | sockAddr->sz = 0; |
141 | | sockAddr->bufSz = 0; |
142 | | return WOLFSSL_SUCCESS; |
143 | | } |
144 | | |
145 | | if (peerSz > sockAddr->bufSz) { |
146 | | if (sockAddr->sa != NULL) |
147 | | XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); |
148 | | sockAddr->sa = |
149 | | (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); |
150 | | if (sockAddr->sa == NULL) { |
151 | | sockAddr->sz = 0; |
152 | | sockAddr->bufSz = 0; |
153 | | return WOLFSSL_FAILURE; |
154 | | } |
155 | | sockAddr->bufSz = peerSz; |
156 | | } |
157 | | XMEMCPY(sockAddr->sa, peer, peerSz); |
158 | | sockAddr->sz = peerSz; |
159 | | return WOLFSSL_SUCCESS; |
160 | | } |
161 | | #endif |
162 | | |
163 | | /* Set the DTLS peer address on the object. |
164 | | * |
165 | | * @param [in] ssl SSL/TLS object. |
166 | | * @param [in] peer Peer socket address, may be NULL to clear. |
167 | | * @param [in] peerSz Length of peer address in bytes. |
168 | | * @return WOLFSSL_SUCCESS on success. |
169 | | * @return WOLFSSL_FAILURE when ssl is NULL or on error. |
170 | | * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. |
171 | | */ |
172 | | int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) |
173 | 0 | { |
174 | | #ifdef WOLFSSL_DTLS |
175 | | int ret; |
176 | | |
177 | | if (ssl == NULL) |
178 | | return WOLFSSL_FAILURE; |
179 | | #ifdef WOLFSSL_RW_THREADED |
180 | | if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) |
181 | | return WOLFSSL_FAILURE; |
182 | | #endif |
183 | | ret = wolfssl_local_SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, |
184 | | ssl->heap); |
185 | | if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) |
186 | | ssl->buffers.dtlsCtx.userSet = 1; |
187 | | else |
188 | | ssl->buffers.dtlsCtx.userSet = 0; |
189 | | #ifdef WOLFSSL_RW_THREADED |
190 | | if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) |
191 | | ret = WOLFSSL_FAILURE; |
192 | | #endif |
193 | | return ret; |
194 | | #else |
195 | 0 | (void)ssl; |
196 | 0 | (void)peer; |
197 | 0 | (void)peerSz; |
198 | 0 | return WOLFSSL_NOT_IMPLEMENTED; |
199 | 0 | #endif |
200 | 0 | } |
201 | | |
202 | | #if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) |
203 | | /* Set the pending DTLS peer address on the object. |
204 | | * |
205 | | * Used with connection ID to stage a change of peer address. |
206 | | * |
207 | | * @param [in] ssl SSL/TLS object. |
208 | | * @param [in] peer Peer socket address. |
209 | | * @param [in] peerSz Length of peer address in bytes. |
210 | | * @return WOLFSSL_SUCCESS on success. |
211 | | * @return WOLFSSL_FAILURE when ssl is NULL or on error. |
212 | | * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. |
213 | | */ |
214 | | int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) |
215 | | { |
216 | | #ifdef WOLFSSL_DTLS |
217 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
218 | | |
219 | | if (ssl == NULL) |
220 | | return WOLFSSL_FAILURE; |
221 | | #ifdef WOLFSSL_RW_THREADED |
222 | | if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) |
223 | | return WOLFSSL_FAILURE; |
224 | | #endif |
225 | | if (ssl->buffers.dtlsCtx.peer.sa != NULL && |
226 | | ssl->buffers.dtlsCtx.peer.sz == peerSz && |
227 | | sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, |
228 | | (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, |
229 | | (XSOCKLENT)peerSz)) { |
230 | | /* Already the current peer. */ |
231 | | if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { |
232 | | /* Clear any other pendingPeer */ |
233 | | XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, |
234 | | DYNAMIC_TYPE_SOCKADDR); |
235 | | ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; |
236 | | ssl->buffers.dtlsCtx.pendingPeer.sz = 0; |
237 | | ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; |
238 | | } |
239 | | ret = WOLFSSL_SUCCESS; |
240 | | } |
241 | | else { |
242 | | ret = wolfssl_local_SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, |
243 | | peer, peerSz, ssl->heap); |
244 | | } |
245 | | if (ret == WOLFSSL_SUCCESS) |
246 | | ssl->buffers.dtlsCtx.processingPendingRecord = 0; |
247 | | #ifdef WOLFSSL_RW_THREADED |
248 | | if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) |
249 | | ret = WOLFSSL_FAILURE; |
250 | | #endif |
251 | | return ret; |
252 | | #else |
253 | | (void)ssl; |
254 | | (void)peer; |
255 | | (void)peerSz; |
256 | | return WOLFSSL_NOT_IMPLEMENTED; |
257 | | #endif |
258 | | } |
259 | | #endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ |
260 | | |
261 | | /* Get a copy of the DTLS peer address from the object. |
262 | | * |
263 | | * @param [in] ssl SSL/TLS object. |
264 | | * @param [out] peer Buffer to hold the peer address. |
265 | | * @param [in, out] peerSz In: size of buffer. Out: length of address. |
266 | | * @return WOLFSSL_SUCCESS on success. |
267 | | * @return WOLFSSL_FAILURE when ssl is NULL or the buffer is too small. |
268 | | * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. |
269 | | */ |
270 | | int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) |
271 | 0 | { |
272 | | #ifdef WOLFSSL_DTLS |
273 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
274 | | if (ssl == NULL) |
275 | | return WOLFSSL_FAILURE; |
276 | | #ifdef WOLFSSL_RW_THREADED |
277 | | if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) |
278 | | return WOLFSSL_FAILURE; |
279 | | #endif |
280 | | if (peer != NULL && peerSz != NULL |
281 | | && *peerSz >= ssl->buffers.dtlsCtx.peer.sz |
282 | | && ssl->buffers.dtlsCtx.peer.sa != NULL) { |
283 | | *peerSz = ssl->buffers.dtlsCtx.peer.sz; |
284 | | XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); |
285 | | ret = WOLFSSL_SUCCESS; |
286 | | } |
287 | | #ifdef WOLFSSL_RW_THREADED |
288 | | if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) |
289 | | ret = WOLFSSL_FAILURE; |
290 | | #endif |
291 | | return ret; |
292 | | #else |
293 | 0 | (void)ssl; |
294 | 0 | (void)peer; |
295 | 0 | (void)peerSz; |
296 | 0 | return WOLFSSL_NOT_IMPLEMENTED; |
297 | 0 | #endif |
298 | 0 | } |
299 | | |
300 | | /* Get a pointer to the DTLS peer address stored on the object. |
301 | | * |
302 | | * @param [in] ssl SSL/TLS object. |
303 | | * @param [out] peer Pointer to the stored peer address. |
304 | | * @param [out] peerSz Length of the peer address in bytes. |
305 | | * @return WOLFSSL_SUCCESS on success. |
306 | | * @return WOLFSSL_FAILURE when an argument is NULL. |
307 | | * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in or threaded. |
308 | | */ |
309 | | int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, |
310 | | unsigned int* peerSz) |
311 | 0 | { |
312 | | #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) |
313 | | if (ssl == NULL) |
314 | | return WOLFSSL_FAILURE; |
315 | | |
316 | | if (peer == NULL || peerSz == NULL) |
317 | | return WOLFSSL_FAILURE; |
318 | | |
319 | | *peer = ssl->buffers.dtlsCtx.peer.sa; |
320 | | *peerSz = ssl->buffers.dtlsCtx.peer.sz; |
321 | | return WOLFSSL_SUCCESS; |
322 | | #else |
323 | 0 | (void)ssl; |
324 | 0 | (void)peer; |
325 | 0 | (void)peerSz; |
326 | 0 | return WOLFSSL_NOT_IMPLEMENTED; |
327 | 0 | #endif |
328 | 0 | } |
329 | | |
330 | | #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) |
331 | | |
332 | | /* Enable DTLS over SCTP mode on the context. |
333 | | * |
334 | | * @param [in] ctx SSL/TLS context object. |
335 | | * @return WOLFSSL_SUCCESS on success. |
336 | | * @return BAD_FUNC_ARG when ctx is NULL. |
337 | | */ |
338 | | int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) |
339 | | { |
340 | | WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); |
341 | | |
342 | | if (ctx == NULL) |
343 | | return BAD_FUNC_ARG; |
344 | | |
345 | | ctx->dtlsSctp = 1; |
346 | | return WOLFSSL_SUCCESS; |
347 | | } |
348 | | |
349 | | /* Enable DTLS over SCTP mode on the object. |
350 | | * |
351 | | * @param [in] ssl SSL/TLS object. |
352 | | * @return WOLFSSL_SUCCESS on success. |
353 | | * @return BAD_FUNC_ARG when ssl is NULL. |
354 | | */ |
355 | | int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) |
356 | | { |
357 | | WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); |
358 | | |
359 | | if (ssl == NULL) |
360 | | return BAD_FUNC_ARG; |
361 | | |
362 | | ssl->options.dtlsSctp = 1; |
363 | | return WOLFSSL_SUCCESS; |
364 | | } |
365 | | |
366 | | #endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ |
367 | | |
368 | | #if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ |
369 | | defined(WOLFSSL_DTLS) |
370 | | |
371 | | /* Set the DTLS path MTU on the context. |
372 | | * |
373 | | * @param [in] ctx SSL/TLS context object. |
374 | | * @param [in] newMtu Maximum transmission unit in bytes. |
375 | | * @return WOLFSSL_SUCCESS on success. |
376 | | * @return BAD_FUNC_ARG when ctx is NULL or newMtu is too large. |
377 | | */ |
378 | | int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) |
379 | | { |
380 | | if (ctx == NULL || newMtu > MAX_RECORD_SIZE) |
381 | | return BAD_FUNC_ARG; |
382 | | |
383 | | ctx->dtlsMtuSz = newMtu; |
384 | | return WOLFSSL_SUCCESS; |
385 | | } |
386 | | |
387 | | /* Set the DTLS path MTU on the object. |
388 | | * |
389 | | * @param [in] ssl SSL/TLS object. |
390 | | * @param [in] newMtu Maximum transmission unit in bytes. |
391 | | * @return WOLFSSL_SUCCESS on success. |
392 | | * @return BAD_FUNC_ARG when ssl is NULL. |
393 | | * @return WOLFSSL_FAILURE when newMtu is too large. |
394 | | */ |
395 | | int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) |
396 | | { |
397 | | if (ssl == NULL) |
398 | | return BAD_FUNC_ARG; |
399 | | |
400 | | if (newMtu > MAX_RECORD_SIZE) { |
401 | | ssl->error = BAD_FUNC_ARG; |
402 | | return WOLFSSL_FAILURE; |
403 | | } |
404 | | |
405 | | ssl->dtlsMtuSz = newMtu; |
406 | | return WOLFSSL_SUCCESS; |
407 | | } |
408 | | |
409 | | #ifdef OPENSSL_EXTRA |
410 | | /* Set the DTLS path MTU on the object. |
411 | | * |
412 | | * Maps to the compatibility API SSL_set_mtu. Same as wolfSSL_dtls_set_mtu() |
413 | | * but returns only success or failure. |
414 | | * |
415 | | * @param [in] ssl SSL/TLS object. |
416 | | * @param [in] mtu Maximum transmission unit in bytes. |
417 | | * @return WOLFSSL_SUCCESS on success. |
418 | | * @return WOLFSSL_FAILURE on error. |
419 | | */ |
420 | | int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) |
421 | | { |
422 | | if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) |
423 | | return WOLFSSL_SUCCESS; |
424 | | else |
425 | | return WOLFSSL_FAILURE; |
426 | | } |
427 | | #endif /* OPENSSL_EXTRA */ |
428 | | |
429 | | #endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ |
430 | | |
431 | | #ifdef WOLFSSL_SRTP |
432 | | |
433 | | static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { |
434 | | /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits |
435 | | * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ |
436 | | {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, |
437 | | (((128 + 112) * 2) / 8) }, |
438 | | /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits |
439 | | * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ |
440 | | {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, |
441 | | (((128 + 112) * 2) / 8) }, |
442 | | /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ |
443 | | {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, |
444 | | /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ |
445 | | {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, |
446 | | /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits |
447 | | * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ |
448 | | {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, |
449 | | /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits |
450 | | * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ |
451 | | {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, |
452 | | }; |
453 | | |
454 | | /* Find an SRTP protection profile by name or by id. |
455 | | * |
456 | | * @param [in] profile_str Profile name, or NULL to search by id. |
457 | | * @param [in] profile_str_len Length of profile name in bytes. |
458 | | * @param [in] id Profile id to search for when name is NULL. |
459 | | * @return Matching SRTP protection profile on success. |
460 | | * @return NULL when no profile matches. |
461 | | */ |
462 | | static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( |
463 | | const char* profile_str, word32 profile_str_len, unsigned long id) |
464 | | { |
465 | | int i; |
466 | | const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; |
467 | | for (i=0; |
468 | | i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); |
469 | | i++) { |
470 | | if (profile_str != NULL) { |
471 | | word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); |
472 | | if (srtp_profile_len == profile_str_len && |
473 | | XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) |
474 | | == 0) { |
475 | | profile = &gSrtpProfiles[i]; |
476 | | break; |
477 | | } |
478 | | } |
479 | | else if (id != 0 && gSrtpProfiles[i].id == id) { |
480 | | profile = &gSrtpProfiles[i]; |
481 | | break; |
482 | | } |
483 | | } |
484 | | return profile; |
485 | | } |
486 | | |
487 | | /* Select SRTP protection profiles from a colon-separated name list. |
488 | | * |
489 | | * @param [out] id Bitmask of selected profile ids. |
490 | | * @param [in] profile_str Colon-separated list of SRTP profile names. |
491 | | * @return WOLFSSL_SUCCESS on success. |
492 | | * @return WOLFSSL_FAILURE when profile_str is NULL. |
493 | | */ |
494 | | static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) |
495 | | { |
496 | | const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; |
497 | | const char *current, *next = NULL; |
498 | | word32 length = 0, current_length; |
499 | | |
500 | | *id = 0; /* reset destination ID's */ |
501 | | |
502 | | if (profile_str == NULL) { |
503 | | return WOLFSSL_FAILURE; |
504 | | } |
505 | | |
506 | | /* loop on end of line or colon ":" */ |
507 | | next = profile_str; |
508 | | length = (word32)XSTRLEN(profile_str); |
509 | | do { |
510 | | current = next; |
511 | | next = XSTRSTR(current, ":"); |
512 | | if (next) { |
513 | | current_length = (word32)(next - current); |
514 | | ++next; /* ++ needed to skip ':' */ |
515 | | } else { |
516 | | current_length = (word32)XSTRLEN(current); |
517 | | } |
518 | | if (current_length < length) |
519 | | length = current_length; |
520 | | profile = DtlsSrtpFindProfile(current, current_length, 0); |
521 | | if (profile != NULL) { |
522 | | *id |= (1 << profile->id); /* selected bit based on ID */ |
523 | | } |
524 | | } while (next != NULL); |
525 | | return WOLFSSL_SUCCESS; |
526 | | } |
527 | | |
528 | | /* Set the SRTP protection profiles for DTLS on the context. |
529 | | * |
530 | | * @param [in] ctx SSL/TLS context object. |
531 | | * @param [in] profile_str Colon-separated list of SRTP profile names. |
532 | | * @return 0 on success, to match OpenSSL. |
533 | | * @return 1 on error, to match OpenSSL. |
534 | | */ |
535 | | int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) |
536 | | { |
537 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
538 | | if (ctx != NULL) { |
539 | | ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); |
540 | | } |
541 | | |
542 | | if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { |
543 | | ret = 1; |
544 | | } else { |
545 | | ret = 0; |
546 | | } |
547 | | |
548 | | return ret; |
549 | | } |
550 | | |
551 | | /* Set the SRTP protection profiles for DTLS on the object. |
552 | | * |
553 | | * @param [in] ssl SSL/TLS object. |
554 | | * @param [in] profile_str Colon-separated list of SRTP profile names. |
555 | | * @return 0 on success, to match OpenSSL. |
556 | | * @return 1 on error, to match OpenSSL. |
557 | | */ |
558 | | int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) |
559 | | { |
560 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
561 | | if (ssl != NULL) { |
562 | | ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); |
563 | | } |
564 | | |
565 | | if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { |
566 | | ret = 1; |
567 | | } else { |
568 | | ret = 0; |
569 | | } |
570 | | |
571 | | return ret; |
572 | | } |
573 | | |
574 | | /* Get the SRTP protection profile selected for the object. |
575 | | * |
576 | | * @param [in] ssl SSL/TLS object. |
577 | | * @return Selected SRTP protection profile on success. |
578 | | * @return NULL when ssl is NULL or none is selected. |
579 | | */ |
580 | | const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( |
581 | | WOLFSSL* ssl) |
582 | | { |
583 | | const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; |
584 | | if (ssl) { |
585 | | profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); |
586 | | } |
587 | | return profile; |
588 | | } |
589 | | #ifndef NO_WOLFSSL_STUB |
590 | | /* Get the list of SRTP protection profiles set on the object. |
591 | | * |
592 | | * Not implemented - stub. |
593 | | * |
594 | | * @param [in] ssl SSL/TLS object. |
595 | | * @return NULL always. |
596 | | */ |
597 | | WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( |
598 | | WOLFSSL* ssl) |
599 | | { |
600 | | /* Not yet implemented - should return list of available SRTP profiles |
601 | | * ssl->dtlsSrtpProfiles */ |
602 | | (void)ssl; |
603 | | return NULL; |
604 | | } |
605 | | #endif |
606 | | |
607 | | #define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" |
608 | | |
609 | | /* Export the DTLS-SRTP keying material for the object. |
610 | | * |
611 | | * When out is NULL, the length required is returned in olen. |
612 | | * |
613 | | * @param [in] ssl SSL/TLS object. |
614 | | * @param [out] out Buffer to hold keying material. May be NULL. |
615 | | * @param [in, out] olen In: size of buffer. Out: length of keying material. |
616 | | * @return WOLFSSL_SUCCESS on success. |
617 | | * @return BAD_FUNC_ARG when ssl or olen is NULL. |
618 | | * @return EXT_MISSING when DTLS-SRTP is not in use. |
619 | | * @return LENGTH_ONLY_E when out is NULL and olen has been set. |
620 | | * @return BUFFER_E when the buffer is too small. |
621 | | */ |
622 | | int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, |
623 | | unsigned char* out, size_t* olen) |
624 | | { |
625 | | const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; |
626 | | |
627 | | if (ssl == NULL || olen == NULL) { |
628 | | return BAD_FUNC_ARG; |
629 | | } |
630 | | |
631 | | profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); |
632 | | if (profile == NULL) { |
633 | | WOLFSSL_MSG("Not using DTLS SRTP"); |
634 | | return EXT_MISSING; |
635 | | } |
636 | | if (out == NULL) { |
637 | | *olen = (size_t)profile->kdfBits; |
638 | | return WC_NO_ERR_TRACE(LENGTH_ONLY_E); |
639 | | } |
640 | | |
641 | | if (*olen < (size_t)profile->kdfBits) { |
642 | | return BUFFER_E; |
643 | | } |
644 | | |
645 | | return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, |
646 | | DTLS_SRTP_KEYING_MATERIAL_LABEL, |
647 | | XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); |
648 | | } |
649 | | |
650 | | #endif /* WOLFSSL_SRTP */ |
651 | | |
652 | | #ifdef WOLFSSL_DTLS_DROP_STATS |
653 | | |
654 | | /* Get the DTLS dropped-record statistics for the object. |
655 | | * |
656 | | * @param [in] ssl SSL/TLS object. |
657 | | * @param [out] macDropCount Number of records dropped on MAC failure. |
658 | | * @param [out] replayDropCount Number of records dropped as replays. |
659 | | * @return WOLFSSL_SUCCESS on success. |
660 | | * @return BAD_FUNC_ARG when ssl is NULL. |
661 | | */ |
662 | | int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, |
663 | | word32* macDropCount, word32* replayDropCount) |
664 | | { |
665 | | int ret; |
666 | | |
667 | | WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); |
668 | | |
669 | | if (ssl == NULL) |
670 | | ret = BAD_FUNC_ARG; |
671 | | else { |
672 | | ret = WOLFSSL_SUCCESS; |
673 | | if (macDropCount != NULL) |
674 | | *macDropCount = ssl->macDropCount; |
675 | | if (replayDropCount != NULL) |
676 | | *replayDropCount = ssl->replayDropCount; |
677 | | } |
678 | | |
679 | | WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); |
680 | | return ret; |
681 | | } |
682 | | |
683 | | #endif /* WOLFSSL_DTLS_DROP_STATS */ |
684 | | |
685 | | #if defined(WOLFSSL_MULTICAST) |
686 | | |
687 | | /* Set the multicast member id on the context and enable multicast. |
688 | | * |
689 | | * @param [in] ctx SSL/TLS context object. |
690 | | * @param [in] id Multicast member id. |
691 | | * @return WOLFSSL_SUCCESS on success. |
692 | | * @return BAD_FUNC_ARG when ctx is NULL or id is out of range. |
693 | | */ |
694 | | int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) |
695 | | { |
696 | | int ret = 0; |
697 | | |
698 | | WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); |
699 | | |
700 | | if (ctx == NULL || id > WOLFSSL_MAX_8BIT) |
701 | | ret = BAD_FUNC_ARG; |
702 | | |
703 | | if (ret == 0) { |
704 | | ctx->haveEMS = 0; |
705 | | ctx->haveMcast = 1; |
706 | | ctx->mcastID = (byte)id; |
707 | | #ifndef WOLFSSL_USER_IO |
708 | | ctx->CBIORecv = EmbedReceiveFromMcast; |
709 | | #endif /* WOLFSSL_USER_IO */ |
710 | | |
711 | | ret = WOLFSSL_SUCCESS; |
712 | | } |
713 | | WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); |
714 | | return ret; |
715 | | } |
716 | | |
717 | | /* Get the maximum number of multicast peers supported. |
718 | | * |
719 | | * @return Maximum number of multicast peers. |
720 | | */ |
721 | | int wolfSSL_mcast_get_max_peers(void) |
722 | | { |
723 | | return WOLFSSL_MULTICAST_PEERS; |
724 | | } |
725 | | |
726 | | #ifdef WOLFSSL_DTLS |
727 | | /* Determine the next highwater mark from the current sequence number. |
728 | | * |
729 | | * @param [in] cur Current sequence number. |
730 | | * @param [in] first First highwater threshold. |
731 | | * @param [in] second Second highwater threshold. |
732 | | * @param [in] high Maximum highwater threshold. |
733 | | * @return Next highwater mark, or 0 when cur is at or above high. |
734 | | */ |
735 | | static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, |
736 | | word32 second, word32 high) |
737 | | { |
738 | | word32 newCur = 0; |
739 | | |
740 | | if (cur < first) |
741 | | newCur = first; |
742 | | else if (cur < second) |
743 | | newCur = second; |
744 | | else if (cur < high) |
745 | | newCur = high; |
746 | | |
747 | | return newCur; |
748 | | } |
749 | | #endif /* WOLFSSL_DTLS */ |
750 | | |
751 | | /* Set the master secret and derived keys directly on the object. |
752 | | * |
753 | | * Used with multicast to install externally derived keys. |
754 | | * |
755 | | * @param [in, out] ssl SSL/TLS object. |
756 | | * @param [in] epoch DTLS epoch to use. |
757 | | * @param [in] preMasterSecret Pre-master secret data. |
758 | | * @param [in] preMasterSz Length of pre-master secret in bytes. |
759 | | * @param [in] clientRandom Client random data (RAN_LEN bytes). |
760 | | * @param [in] serverRandom Server random data (RAN_LEN bytes). |
761 | | * @param [in] suite Cipher suite bytes (2). |
762 | | * @return WOLFSSL_SUCCESS on success. |
763 | | * @return WOLFSSL_FATAL_ERROR on error, including invalid arguments and a |
764 | | * failure to allocate the pre-master secret. The specific code is |
765 | | * recorded in ssl->error and can be read with wolfSSL_get_error(). |
766 | | */ |
767 | | int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, |
768 | | const byte* preMasterSecret, word32 preMasterSz, |
769 | | const byte* clientRandom, const byte* serverRandom, |
770 | | const byte* suite) |
771 | | { |
772 | | int ret = 0; |
773 | | |
774 | | WOLFSSL_ENTER("wolfSSL_set_secret"); |
775 | | |
776 | | if (ssl == NULL || preMasterSecret == NULL || |
777 | | preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || |
778 | | clientRandom == NULL || serverRandom == NULL || suite == NULL) { |
779 | | |
780 | | ret = BAD_FUNC_ARG; |
781 | | } |
782 | | |
783 | | /* The handshake arrays are released once the handshake resources are |
784 | | * freed, so a reused object may not have them any more. */ |
785 | | if (ret == 0 && ssl->arrays == NULL) { |
786 | | WOLFSSL_MSG("Handshake arrays not available"); |
787 | | ret = BAD_FUNC_ARG; |
788 | | } |
789 | | |
790 | | if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { |
791 | | ssl->arrays->preMasterSz = ENCRYPT_LEN; |
792 | | ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, |
793 | | DYNAMIC_TYPE_SECRET); |
794 | | if (ssl->arrays->preMasterSecret == NULL) { |
795 | | ret = MEMORY_E; |
796 | | } |
797 | | } |
798 | | |
799 | | if (ret == 0) { |
800 | | XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); |
801 | | XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, |
802 | | ENCRYPT_LEN - preMasterSz); |
803 | | ssl->arrays->preMasterSz = preMasterSz; |
804 | | XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); |
805 | | XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); |
806 | | ssl->options.cipherSuite0 = suite[0]; |
807 | | ssl->options.cipherSuite = suite[1]; |
808 | | |
809 | | ret = SetCipherSpecs(ssl); |
810 | | } |
811 | | |
812 | | if (ret == 0) |
813 | | ret = MakeTlsMasterSecret(ssl); |
814 | | |
815 | | if (ret == 0) { |
816 | | ssl->keys.encryptionOn = 1; |
817 | | ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); |
818 | | } |
819 | | |
820 | | if (ret == 0) { |
821 | | if (ssl->options.dtls) { |
822 | | #ifdef WOLFSSL_DTLS |
823 | | WOLFSSL_DTLS_PEERSEQ* peerSeq; |
824 | | int i; |
825 | | |
826 | | ssl->keys.dtls_epoch = epoch; |
827 | | for (i = 0, peerSeq = ssl->keys.peerSeq; |
828 | | i < WOLFSSL_DTLS_PEERSEQ_SZ; |
829 | | i++, peerSeq++) { |
830 | | |
831 | | peerSeq->nextEpoch = epoch; |
832 | | peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; |
833 | | peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; |
834 | | peerSeq->nextSeq_lo = 0; |
835 | | peerSeq->nextSeq_hi = 0; |
836 | | XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); |
837 | | XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); |
838 | | peerSeq->highwaterMark = UpdateHighwaterMark(0, |
839 | | ssl->ctx->mcastFirstSeq, |
840 | | ssl->ctx->mcastSecondSeq, |
841 | | ssl->ctx->mcastMaxSeq); |
842 | | } |
843 | | #else |
844 | | (void)epoch; |
845 | | #endif |
846 | | } |
847 | | FreeHandshakeResources(ssl); |
848 | | ret = WOLFSSL_SUCCESS; |
849 | | } |
850 | | else { |
851 | | if (ssl) |
852 | | ssl->error = ret; |
853 | | ret = WOLFSSL_FATAL_ERROR; |
854 | | } |
855 | | WOLFSSL_LEAVE("wolfSSL_set_secret", ret); |
856 | | return ret; |
857 | | } |
858 | | |
859 | | #ifdef WOLFSSL_DTLS |
860 | | |
861 | | /* Add or remove a peer from the multicast peer list. |
862 | | * |
863 | | * @param [in] ssl SSL/TLS object. |
864 | | * @param [in] peerId Peer id to add or remove. |
865 | | * @param [in] sub 0 to add the peer, non-zero to remove it. |
866 | | * @return WOLFSSL_SUCCESS on success. |
867 | | * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. |
868 | | * @return WOLFSSL_FATAL_ERROR when the peer list is full. |
869 | | */ |
870 | | int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) |
871 | | { |
872 | | WOLFSSL_DTLS_PEERSEQ* p = NULL; |
873 | | int ret = WOLFSSL_SUCCESS; |
874 | | int i; |
875 | | |
876 | | WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); |
877 | | if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) |
878 | | return BAD_FUNC_ARG; |
879 | | |
880 | | if (!sub) { |
881 | | /* Make sure it isn't already present, while keeping the first |
882 | | * open spot. */ |
883 | | for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { |
884 | | if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) |
885 | | p = &ssl->keys.peerSeq[i]; |
886 | | if (ssl->keys.peerSeq[i].peerId == peerId) { |
887 | | WOLFSSL_MSG("Peer ID already in multicast peer list."); |
888 | | p = NULL; |
889 | | } |
890 | | } |
891 | | |
892 | | if (p != NULL) { |
893 | | XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); |
894 | | p->peerId = peerId; |
895 | | p->highwaterMark = UpdateHighwaterMark(0, |
896 | | ssl->ctx->mcastFirstSeq, |
897 | | ssl->ctx->mcastSecondSeq, |
898 | | ssl->ctx->mcastMaxSeq); |
899 | | } |
900 | | else { |
901 | | WOLFSSL_MSG("No room in peer list."); |
902 | | ret = WOLFSSL_FATAL_ERROR; |
903 | | } |
904 | | } |
905 | | else { |
906 | | for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { |
907 | | if (ssl->keys.peerSeq[i].peerId == peerId) |
908 | | p = &ssl->keys.peerSeq[i]; |
909 | | } |
910 | | |
911 | | if (p != NULL) { |
912 | | p->peerId = INVALID_PEER_ID; |
913 | | } |
914 | | else { |
915 | | WOLFSSL_MSG("Peer not found in list."); |
916 | | } |
917 | | } |
918 | | |
919 | | WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); |
920 | | return ret; |
921 | | } |
922 | | |
923 | | /* Determine whether a multicast peer is known and active. |
924 | | * |
925 | | * @param [in] ssl SSL/TLS object. |
926 | | * @param [in] peerId Peer id to look up. |
927 | | * @return 1 when the peer is in the list with a non-zero sequence number. |
928 | | * @return 0 when the peer is not known or has not sent data. |
929 | | * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. |
930 | | */ |
931 | | int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) |
932 | | { |
933 | | int known = 0; |
934 | | int i; |
935 | | |
936 | | WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); |
937 | | |
938 | | if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { |
939 | | return BAD_FUNC_ARG; |
940 | | } |
941 | | |
942 | | for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { |
943 | | if (ssl->keys.peerSeq[i].peerId == peerId) { |
944 | | if (ssl->keys.peerSeq[i].nextSeq_hi || |
945 | | ssl->keys.peerSeq[i].nextSeq_lo) { |
946 | | |
947 | | known = 1; |
948 | | } |
949 | | break; |
950 | | } |
951 | | } |
952 | | |
953 | | WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); |
954 | | return known; |
955 | | } |
956 | | |
957 | | /* Set the multicast highwater callback and thresholds on the context. |
958 | | * |
959 | | * @param [in] ctx SSL/TLS context object. |
960 | | * @param [in] maxSeq Maximum sequence number threshold. |
961 | | * @param [in] first First sequence number threshold. |
962 | | * @param [in] second Second sequence number threshold. |
963 | | * @param [in] cb Highwater callback. |
964 | | * @return WOLFSSL_SUCCESS on success. |
965 | | * @return BAD_FUNC_ARG when an argument is NULL or thresholds are invalid. |
966 | | */ |
967 | | int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, |
968 | | word32 first, word32 second, |
969 | | CallbackMcastHighwater cb) |
970 | | { |
971 | | if (ctx == NULL || (second && first > second) || |
972 | | first > maxSeq || second > maxSeq || cb == NULL) { |
973 | | |
974 | | return BAD_FUNC_ARG; |
975 | | } |
976 | | |
977 | | ctx->mcastHwCb = cb; |
978 | | ctx->mcastFirstSeq = first; |
979 | | ctx->mcastSecondSeq = second; |
980 | | ctx->mcastMaxSeq = maxSeq; |
981 | | |
982 | | return WOLFSSL_SUCCESS; |
983 | | } |
984 | | |
985 | | /* Set the user context passed to the multicast highwater callback. |
986 | | * |
987 | | * @param [in] ssl SSL/TLS object. |
988 | | * @param [in] ctx User context for the highwater callback. |
989 | | * @return WOLFSSL_SUCCESS on success. |
990 | | * @return BAD_FUNC_ARG when ssl or ctx is NULL. |
991 | | */ |
992 | | int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) |
993 | | { |
994 | | if (ssl == NULL || ctx == NULL) |
995 | | return BAD_FUNC_ARG; |
996 | | |
997 | | ssl->mcastHwCbCtx = ctx; |
998 | | |
999 | | return WOLFSSL_SUCCESS; |
1000 | | } |
1001 | | |
1002 | | #endif /* WOLFSSL_DTLS */ |
1003 | | |
1004 | | #endif /* WOLFSSL_MULTICAST */ |
1005 | | |
1006 | | #endif /* WOLFSSL_LEANPSK */ |
1007 | | |
1008 | | #ifndef NO_TLS |
1009 | | #ifdef WOLFSSL_MULTICAST |
1010 | | |
1011 | | /* Read application data from a multicast DTLS object. |
1012 | | * |
1013 | | * @param [in] ssl SSL/TLS object. |
1014 | | * @param [out] id Peer id the data was received from. May be NULL. |
1015 | | * @param [out] data Buffer to hold the data read. |
1016 | | * @param [in] sz Size of the buffer in bytes. |
1017 | | * @return Number of bytes read on success. |
1018 | | * @return BAD_FUNC_ARG when ssl is NULL or sz is negative. |
1019 | | * @return Negative value on error. |
1020 | | */ |
1021 | | int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) |
1022 | | { |
1023 | | int ret = 0; |
1024 | | |
1025 | | WOLFSSL_ENTER("wolfSSL_mcast_read"); |
1026 | | |
1027 | | if ((ssl == NULL) || (sz < 0)) |
1028 | | return BAD_FUNC_ARG; |
1029 | | |
1030 | | ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); |
1031 | | if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) |
1032 | | *id = ssl->keys.curPeerId; |
1033 | | return ret; |
1034 | | } |
1035 | | |
1036 | | #endif /* WOLFSSL_MULTICAST */ |
1037 | | #endif /* !NO_TLS */ |
1038 | | |
1039 | | #ifdef WOLFSSL_DTLS |
1040 | | /* Get the DTLS MAC secret for the requested side and epoch. |
1041 | | * |
1042 | | * @param [in] ssl SSL/TLS object. |
1043 | | * @param [in] verify 1 for the verify (read) secret, 0 for the write one. |
1044 | | * @param [in] epochOrder Epoch order: PEER_ORDER, PREV_ORDER or CUR_ORDER. |
1045 | | * @return MAC secret on success. |
1046 | | * @return NULL when ssl is NULL, AEAD-only build, or epoch order is unknown. |
1047 | | */ |
1048 | | const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) |
1049 | | { |
1050 | | #ifndef WOLFSSL_AEAD_ONLY |
1051 | | Keys* keys = NULL; |
1052 | | |
1053 | | (void)epochOrder; |
1054 | | |
1055 | | if (ssl == NULL) |
1056 | | return NULL; |
1057 | | |
1058 | | #ifdef HAVE_SECURE_RENEGOTIATION |
1059 | | switch (epochOrder) { |
1060 | | case PEER_ORDER: |
1061 | | if (IsDtlsMsgSCRKeys(ssl)) |
1062 | | keys = &ssl->secure_renegotiation->tmp_keys; |
1063 | | else |
1064 | | keys = &ssl->keys; |
1065 | | break; |
1066 | | case PREV_ORDER: |
1067 | | keys = &ssl->keys; |
1068 | | break; |
1069 | | case CUR_ORDER: |
1070 | | if (DtlsUseSCRKeys(ssl)) |
1071 | | keys = &ssl->secure_renegotiation->tmp_keys; |
1072 | | else |
1073 | | keys = &ssl->keys; |
1074 | | break; |
1075 | | default: |
1076 | | WOLFSSL_MSG("Unknown epoch order"); |
1077 | | return NULL; |
1078 | | } |
1079 | | #else |
1080 | | keys = &ssl->keys; |
1081 | | #endif |
1082 | | |
1083 | | if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || |
1084 | | (ssl->options.side == WOLFSSL_SERVER_END && verify) ) |
1085 | | return keys->client_write_MAC_secret; |
1086 | | else |
1087 | | return keys->server_write_MAC_secret; |
1088 | | #else |
1089 | | (void)ssl; |
1090 | | (void)verify; |
1091 | | (void)epochOrder; |
1092 | | |
1093 | | return NULL; |
1094 | | #endif |
1095 | | } |
1096 | | #endif /* WOLFSSL_DTLS */ |
1097 | | |
1098 | | /* Get whether the DTLS object is using non-blocking I/O. |
1099 | | * |
1100 | | * @param [in] ssl SSL/TLS object. |
1101 | | * @return 1 when non-blocking I/O is enabled. |
1102 | | * @return 0 when disabled or not a DTLS object. |
1103 | | * @return WOLFSSL_FAILURE when ssl is NULL. |
1104 | | */ |
1105 | | int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) |
1106 | 0 | { |
1107 | 0 | int useNb = 0; |
1108 | |
|
1109 | 0 | if (ssl == NULL) |
1110 | 0 | return WOLFSSL_FAILURE; |
1111 | | |
1112 | 0 | WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); |
1113 | 0 | if (ssl->options.dtls) { |
1114 | | #ifdef WOLFSSL_DTLS |
1115 | | useNb = ssl->options.dtlsUseNonblock; |
1116 | | #endif |
1117 | 0 | } |
1118 | 0 | else { |
1119 | 0 | WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " |
1120 | 0 | "DEPRECATED for non-DTLS use."); |
1121 | 0 | } |
1122 | 0 | return useNb; |
1123 | 0 | } |
1124 | | |
1125 | | #ifndef WOLFSSL_LEANPSK |
1126 | | |
1127 | | /* Set whether the DTLS object uses non-blocking I/O. |
1128 | | * |
1129 | | * @param [in] ssl SSL/TLS object. |
1130 | | * @param [in] nonblock 1 to use non-blocking I/O, 0 otherwise. |
1131 | | */ |
1132 | | void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) |
1133 | 0 | { |
1134 | 0 | (void)nonblock; |
1135 | |
|
1136 | 0 | WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); |
1137 | |
|
1138 | 0 | if (ssl == NULL) |
1139 | 0 | return; |
1140 | | |
1141 | 0 | if (ssl->options.dtls) { |
1142 | | #ifdef WOLFSSL_DTLS |
1143 | | ssl->options.dtlsUseNonblock = (nonblock != 0); |
1144 | | #endif |
1145 | 0 | } |
1146 | 0 | else { |
1147 | 0 | WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " |
1148 | 0 | "DEPRECATED for non-DTLS use."); |
1149 | 0 | } |
1150 | 0 | } |
1151 | | |
1152 | | #ifdef WOLFSSL_DTLS |
1153 | | |
1154 | | /* Get the current DTLS receive timeout, in seconds. |
1155 | | * |
1156 | | * @param [in] ssl SSL/TLS object. |
1157 | | * @return Current timeout in seconds, or 0 when ssl is NULL. |
1158 | | */ |
1159 | | int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) |
1160 | | { |
1161 | | int timeout = 0; |
1162 | | if (ssl) |
1163 | | timeout = ssl->dtls_timeout; |
1164 | | |
1165 | | WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout", timeout); |
1166 | | return timeout; |
1167 | | } |
1168 | | |
1169 | | #ifdef WOLFSSL_DTLS13 |
1170 | | |
1171 | | /* Determine whether a short receive timeout should be used. |
1172 | | * |
1173 | | * Recommended to be at most 1/4 of wolfSSL_dtls_get_current_timeout(). |
1174 | | * |
1175 | | * @param [in] ssl SSL/TLS object. |
1176 | | * @return 1 when a short timeout should be used. |
1177 | | * @return 0 otherwise, or when ssl is NULL. |
1178 | | */ |
1179 | | int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) |
1180 | | { |
1181 | | return ssl != NULL && ssl->dtls13FastTimeout; |
1182 | | } |
1183 | | |
1184 | | /* Set whether a DTLS 1.3 connection sends acks immediately on a disruption. |
1185 | | * |
1186 | | * Sending more acks may increase traffic but can speed up the handshake. |
1187 | | * |
1188 | | * @param [in] ssl SSL/TLS object. |
1189 | | * @param [in] value Non-zero to send more acks, 0 otherwise. |
1190 | | */ |
1191 | | void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) |
1192 | | { |
1193 | | if (ssl != NULL) |
1194 | | ssl->options.dtls13SendMoreAcks = !!value; |
1195 | | } |
1196 | | #endif /* WOLFSSL_DTLS13 */ |
1197 | | |
1198 | | /* Get the time left until the next DTLS timeout. |
1199 | | * |
1200 | | * @param [in] ssl SSL/TLS object. |
1201 | | * @param [out] timeleft Time left until the next timeout. |
1202 | | * @return 0 always. |
1203 | | */ |
1204 | | int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) |
1205 | | { |
1206 | | if (ssl && timeleft) { |
1207 | | XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); |
1208 | | timeleft->tv_sec = ssl->dtls_timeout; |
1209 | | } |
1210 | | return 0; |
1211 | | } |
1212 | | |
1213 | | #ifndef NO_WOLFSSL_STUB |
1214 | | /* Handle a DTLS timeout. |
1215 | | * |
1216 | | * Not implemented - stub for OpenSSL compatibility. |
1217 | | * |
1218 | | * @param [in] ssl SSL/TLS object. |
1219 | | * @return 0 always. |
1220 | | */ |
1221 | | int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) |
1222 | | { |
1223 | | WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); |
1224 | | (void)ssl; |
1225 | | return 0; |
1226 | | } |
1227 | | |
1228 | | /* Set the initial DTLS timeout duration. |
1229 | | * |
1230 | | * Not implemented - stub for OpenSSL compatibility. |
1231 | | * |
1232 | | * @param [in] ssl SSL/TLS object. |
1233 | | * @param [in] duration_ms Initial timeout duration in milliseconds. |
1234 | | */ |
1235 | | void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, |
1236 | | word32 duration_ms) |
1237 | | { |
1238 | | WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); |
1239 | | (void)ssl; |
1240 | | (void)duration_ms; |
1241 | | } |
1242 | | #endif |
1243 | | |
1244 | | /* Set the initial DTLS receive timeout, in seconds, on the object. |
1245 | | * |
1246 | | * @param [in] ssl SSL/TLS object. |
1247 | | * @param [in] timeout Initial timeout in seconds. |
1248 | | * @return WOLFSSL_SUCCESS on success. |
1249 | | * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or greater than |
1250 | | * the maximum timeout. |
1251 | | */ |
1252 | | int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) |
1253 | | { |
1254 | | if (ssl == NULL || timeout < 0) |
1255 | | return BAD_FUNC_ARG; |
1256 | | |
1257 | | if (timeout > ssl->dtls_timeout_max) { |
1258 | | WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " |
1259 | | "max"); |
1260 | | return BAD_FUNC_ARG; |
1261 | | } |
1262 | | |
1263 | | ssl->dtls_timeout_init = timeout; |
1264 | | ssl->dtls_timeout = timeout; |
1265 | | |
1266 | | return WOLFSSL_SUCCESS; |
1267 | | } |
1268 | | |
1269 | | /* Set the maximum DTLS receive timeout, in seconds, on the object. |
1270 | | * |
1271 | | * @param [in] ssl SSL/TLS object. |
1272 | | * @param [in] timeout Maximum timeout in seconds. |
1273 | | * @return WOLFSSL_SUCCESS on success. |
1274 | | * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or less than |
1275 | | * the initial timeout. |
1276 | | */ |
1277 | | int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) |
1278 | | { |
1279 | | if (ssl == NULL || timeout < 0) |
1280 | | return BAD_FUNC_ARG; |
1281 | | |
1282 | | if (timeout < ssl->dtls_timeout_init) { |
1283 | | WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); |
1284 | | return BAD_FUNC_ARG; |
1285 | | } |
1286 | | |
1287 | | ssl->dtls_timeout_max = timeout; |
1288 | | |
1289 | | return WOLFSSL_SUCCESS; |
1290 | | } |
1291 | | |
1292 | | /* Process a DTLS timeout, retransmitting messages as needed. |
1293 | | * |
1294 | | * @param [in] ssl SSL/TLS object. |
1295 | | * @return WOLFSSL_SUCCESS on success. |
1296 | | * @return WOLFSSL_FATAL_ERROR when ssl is NULL, not DTLS, or on error. |
1297 | | */ |
1298 | | int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) |
1299 | | { |
1300 | | int result = WOLFSSL_SUCCESS; |
1301 | | WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); |
1302 | | |
1303 | | if (ssl == NULL || !ssl->options.dtls) |
1304 | | return WOLFSSL_FATAL_ERROR; |
1305 | | |
1306 | | #ifdef WOLFSSL_DTLS13 |
1307 | | if (IsAtLeastTLSv1_3(ssl->version)) { |
1308 | | result = Dtls13RtxTimeout(ssl); |
1309 | | if (result < 0) { |
1310 | | if (result == WC_NO_ERR_TRACE(WANT_WRITE)) |
1311 | | ssl->dtls13SendingAckOrRtx = 1; |
1312 | | ssl->error = result; |
1313 | | WOLFSSL_ERROR(result); |
1314 | | return WOLFSSL_FATAL_ERROR; |
1315 | | } |
1316 | | |
1317 | | return WOLFSSL_SUCCESS; |
1318 | | } |
1319 | | #endif /* WOLFSSL_DTLS13 */ |
1320 | | |
1321 | | /* Do we have any 1.2 messages stored? */ |
1322 | | if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { |
1323 | | if (DtlsMsgPoolTimeout(ssl) < 0){ |
1324 | | ssl->error = SOCKET_ERROR_E; |
1325 | | WOLFSSL_ERROR(ssl->error); |
1326 | | result = WOLFSSL_FATAL_ERROR; |
1327 | | } |
1328 | | else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { |
1329 | | ssl->error = result; |
1330 | | WOLFSSL_ERROR(result); |
1331 | | result = WOLFSSL_FATAL_ERROR; |
1332 | | } |
1333 | | else { |
1334 | | /* Reset return value to success */ |
1335 | | result = WOLFSSL_SUCCESS; |
1336 | | } |
1337 | | } |
1338 | | |
1339 | | WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout", result); |
1340 | | return result; |
1341 | | } |
1342 | | |
1343 | | /* Retransmit all stored DTLS handshake messages. |
1344 | | * |
1345 | | * @param [in] ssl SSL/TLS object. |
1346 | | * @return WOLFSSL_SUCCESS on success. |
1347 | | * @return WOLFSSL_FATAL_ERROR when ssl is NULL or on error. |
1348 | | */ |
1349 | | int wolfSSL_dtls_retransmit(WOLFSSL* ssl) |
1350 | | { |
1351 | | WOLFSSL_ENTER("wolfSSL_dtls_retransmit"); |
1352 | | |
1353 | | if (ssl == NULL) |
1354 | | return WOLFSSL_FATAL_ERROR; |
1355 | | |
1356 | | if (!ssl->options.handShakeDone) { |
1357 | | int result; |
1358 | | #ifdef WOLFSSL_DTLS13 |
1359 | | if (IsAtLeastTLSv1_3(ssl->version)) |
1360 | | result = Dtls13DoScheduledWork(ssl); |
1361 | | else |
1362 | | #endif |
1363 | | result = DtlsMsgPoolSend(ssl, 0); |
1364 | | if (result < 0) { |
1365 | | ssl->error = result; |
1366 | | WOLFSSL_ERROR(result); |
1367 | | return WOLFSSL_FATAL_ERROR; |
1368 | | } |
1369 | | } |
1370 | | |
1371 | | return WOLFSSL_SUCCESS; |
1372 | | } |
1373 | | |
1374 | | #ifdef WOLFSSL_DTLS13 |
1375 | | /* Is this object the kind the scheduled-work API operates on? |
1376 | | * |
1377 | | * A write-dup pair parks the read side's scheduled work in the shared WriteDup |
1378 | | * struct, and only wolfSSL_write() reconciles it back onto the write side. |
1379 | | * Such applications already have a working drain and are deliberately out of |
1380 | | * scope here, on either side of the pair. |
1381 | | */ |
1382 | | static int Dtls13ScheduledWorkObject(WOLFSSL* ssl) |
1383 | | { |
1384 | | if (!ssl->options.dtls || !IsAtLeastTLSv1_3(ssl->version)) |
1385 | | return 0; |
1386 | | #ifdef HAVE_WRITE_DUP |
1387 | | if (ssl->dupWrite != NULL) |
1388 | | return 0; |
1389 | | #endif |
1390 | | |
1391 | | return 1; |
1392 | | } |
1393 | | |
1394 | | /* Is there any point running the scheduled work now? |
1395 | | * |
1396 | | * While the handshake runs, wolfSSL_connect()/wolfSSL_accept() and |
1397 | | * wolfSSL_dtls_retransmit() already drive it. Kept separate from the object |
1398 | | * check above so the pump can tell a caller error, which it reports, from |
1399 | | * simply having nothing to do yet, which it does not. |
1400 | | */ |
1401 | | static int Dtls13ScheduledWorkReady(WOLFSSL* ssl) |
1402 | | { |
1403 | | return Dtls13ScheduledWorkObject(ssl) && ssl->options.handShakeDone; |
1404 | | } |
1405 | | |
1406 | | /* Can a key update be sent right now? |
1407 | | * |
1408 | | * DTLS must not have two in flight, so not while one of ours is still |
1409 | | * unacknowledged. This governs both an update we scheduled ourselves and |
1410 | | * answering one the peer asked for, because Tls13UpdateKeys() silently drops |
1411 | | * the former in that state. Both entry points ask this same question: the |
1412 | | * predicate must not report work the pump then declines or discards, or a |
1413 | | * drain loop over the pair never terminates and the caller is misled about |
1414 | | * what was done. |
1415 | | */ |
1416 | | static int Dtls13CanSendKeyUpdate(WOLFSSL* ssl) |
1417 | | { |
1418 | | return !ssl->dtls13WaitKeyUpdateAck; |
1419 | | } |
1420 | | |
1421 | | /* Check whether the object has DTLS 1.3 work waiting to be sent. |
1422 | | * |
1423 | | * Only meaningful with WOLFSSL_RW_THREADED, where the read path does not |
1424 | | * transmit. The answer is advisory: it can change as soon as it is returned, |
1425 | | * and wolfSSL_dtls13_do_scheduled_work() is safe to call regardless. |
1426 | | * |
1427 | | * Reports only work that wolfSSL_dtls13_do_scheduled_work() can carry out, so |
1428 | | * that a drain loop over the pair terminates. |
1429 | | * |
1430 | | * @param [in] ssl SSL/TLS object. |
1431 | | * @return 1 when there is work to send, or when it could not be determined. |
1432 | | * @return 0 when there is nothing to do, or ssl is not supported here. |
1433 | | */ |
1434 | | int wolfSSL_dtls13_pending_work(WOLFSSL* ssl) |
1435 | | { |
1436 | | int pending = 0; |
1437 | | |
1438 | | WOLFSSL_ENTER("wolfSSL_dtls13_pending_work"); |
1439 | | |
1440 | | if (ssl == NULL || !Dtls13ScheduledWorkReady(ssl)) |
1441 | | return 0; |
1442 | | |
1443 | | /* A record this API built but could only write in part. The pump retries |
1444 | | * it, so a drain loop has to be told the retry is still owed. */ |
1445 | | if (ssl->buffers.outputBuffer.length > 0 && ssl->dtls13SendingAckOrRtx) |
1446 | | pending = 1; |
1447 | | |
1448 | | /* dtls13WaitKeyUpdateAck deliberately does not count as work: it says we |
1449 | | * are waiting on the peer, not that we have anything to send. */ |
1450 | | if (!pending && (ssl->dtls13DoKeyUpdate || ssl->options.sendKeyUpdate) && |
1451 | | Dtls13CanSendKeyUpdate(ssl)) { |
1452 | | pending = 1; |
1453 | | } |
1454 | | |
1455 | | if (!pending) { |
1456 | | #ifdef WOLFSSL_RW_THREADED |
1457 | | if (wc_LockMutex(&ssl->dtls13Rtx.mutex) != 0) { |
1458 | | /* Report work rather than nothing, so a drain loop calls the pump |
1459 | | * and surfaces the error instead of stopping silently. */ |
1460 | | return 1; |
1461 | | } |
1462 | | #endif |
1463 | | pending = ssl->dtls13Rtx.sendAcks || ssl->dtls13Rtx.retransmit; |
1464 | | #ifdef WOLFSSL_RW_THREADED |
1465 | | (void)wc_UnLockMutex(&ssl->dtls13Rtx.mutex); |
1466 | | #endif |
1467 | | } |
1468 | | |
1469 | | WOLFSSL_LEAVE("wolfSSL_dtls13_pending_work", pending); |
1470 | | |
1471 | | return pending; |
1472 | | } |
1473 | | |
1474 | | /* Send any DTLS 1.3 work that was scheduled while reading. |
1475 | | * |
1476 | | * Covers pending ACKs, retransmissions and key updates, including the |
1477 | | * KeyUpdate response a peer asked for. With WOLFSSL_RW_THREADED the read path |
1478 | | * never transmits, because doing so would race the write thread over the |
1479 | | * output buffer and the sending key schedule, so this work is only performed |
1480 | | * from the write side. An application that reads without writing has to call |
1481 | | * this or those messages are never sent, and the peer keeps retransmitting |
1482 | | * what it is waiting to have acknowledged. |
1483 | | * |
1484 | | * Call it from the same thread used for writing. Calling it concurrently with |
1485 | | * a write on another thread has the same effect as two concurrent writes. |
1486 | | * |
1487 | | * Not for write-dup applications: those park the read side's work in the |
1488 | | * shared WriteDup struct, which only wolfSSL_write() reconciles, so they |
1489 | | * already have a drain and get WOLFSSL_FATAL_ERROR here rather than a call |
1490 | | * that quietly does nothing. |
1491 | | * |
1492 | | * Note that a key update started from our own side still needs the peer's ACK |
1493 | | * to be processed before it completes, and that processing rotates the sending |
1494 | | * keys, so it cannot run here. |
1495 | | * |
1496 | | * A send that only wrote part of a record reports WANT_WRITE through |
1497 | | * wolfSSL_get_error(). The record is held and the next call sends the rest, |
1498 | | * so that is a retry rather than a reason to stop draining. |
1499 | | * |
1500 | | * @param [in] ssl SSL/TLS object. |
1501 | | * @return WOLFSSL_SUCCESS on success, including when there was nothing to do. |
1502 | | * @return WOLFSSL_FATAL_ERROR when ssl is NULL, unsupported, or on error. |
1503 | | */ |
1504 | | int wolfSSL_dtls13_do_scheduled_work(WOLFSSL* ssl) |
1505 | | { |
1506 | | int ret; |
1507 | | |
1508 | | WOLFSSL_ENTER("wolfSSL_dtls13_do_scheduled_work"); |
1509 | | |
1510 | | if (ssl == NULL) |
1511 | | return WOLFSSL_FATAL_ERROR; |
1512 | | |
1513 | | /* Rejecting the object is a usage error, not something that happened to |
1514 | | * the connection, so leave ssl->error alone. It is sticky: SendData() |
1515 | | * only clears it for WANT_WRITE, WC_PENDING_E and the DTLS MAC/decrypt |
1516 | | * cases, and wolfSSL_write() skips the write-dup drain entirely while it |
1517 | | * is set, so recording one here would disable the very drain a write-dup |
1518 | | * application relies on. */ |
1519 | | #ifdef HAVE_WRITE_DUP |
1520 | | if (ssl->dupWrite != NULL) { |
1521 | | WOLFSSL_MSG("Write dup objects drain through wolfSSL_write"); |
1522 | | WOLFSSL_LEAVE("wolfSSL_dtls13_do_scheduled_work", WOLFSSL_FATAL_ERROR); |
1523 | | return WOLFSSL_FATAL_ERROR; |
1524 | | } |
1525 | | #endif |
1526 | | |
1527 | | if (!Dtls13ScheduledWorkObject(ssl)) { |
1528 | | WOLFSSL_MSG("Not a DTLS 1.3 object this API handles"); |
1529 | | WOLFSSL_LEAVE("wolfSSL_dtls13_do_scheduled_work", WOLFSSL_FATAL_ERROR); |
1530 | | return WOLFSSL_FATAL_ERROR; |
1531 | | } |
1532 | | |
1533 | | if (!Dtls13ScheduledWorkReady(ssl)) |
1534 | | return WOLFSSL_SUCCESS; |
1535 | | |
1536 | | /* An earlier call may have left a record only partly written. Retry it |
1537 | | * first: the request that produced it has already been consumed, so |
1538 | | * nothing else would send it, and every other caller of |
1539 | | * Dtls13DoScheduledWork() pairs it with this same flush. Only a record |
1540 | | * this API built is retried here, which is what dtls13SendingAckOrRtx |
1541 | | * marks, so a partly written application record is left to the |
1542 | | * wolfSSL_write() the caller has to repeat anyway. */ |
1543 | | if (ssl->buffers.outputBuffer.length > 0 && ssl->dtls13SendingAckOrRtx) { |
1544 | | ret = SendBuffered(ssl); |
1545 | | if (ret != 0) { |
1546 | | ssl->error = ret; |
1547 | | WOLFSSL_ERROR(ret); |
1548 | | return WOLFSSL_FATAL_ERROR; |
1549 | | } |
1550 | | ssl->dtls13SendingAckOrRtx = 0; |
1551 | | } |
1552 | | |
1553 | | ret = Dtls13DoScheduledWork(ssl); |
1554 | | if (ret < 0) { |
1555 | | ssl->error = ret; |
1556 | | WOLFSSL_ERROR(ret); |
1557 | | return WOLFSSL_FATAL_ERROR; |
1558 | | } |
1559 | | |
1560 | | /* Answer a KeyUpdate the peer requested. The read path defers this the |
1561 | | * same way, and SendData() is otherwise the only thing that clears it. |
1562 | | * Skip it while one of ours is still unacknowledged: DTLS must not have |
1563 | | * two KeyUpdates in flight, and Dtls13DoScheduledWork() above may have |
1564 | | * just started one. */ |
1565 | | if (ssl->options.sendKeyUpdate && Dtls13CanSendKeyUpdate(ssl)) { |
1566 | | /* Drop the request before sending, as SendData() does. DTLS commits |
1567 | | * the record to the retransmit queue and consumes the handshake |
1568 | | * number on WANT_WRITE as well, and sets dtls13WaitKeyUpdateAck |
1569 | | * unconditionally, so the update is under way from that point on. |
1570 | | * Leaving the request set would send a second one once the peer |
1571 | | * acknowledges the first. */ |
1572 | | ssl->options.sendKeyUpdate = 0; |
1573 | | /* Mark the record as ours so a short write is retried by the flush |
1574 | | * above rather than waiting for a retransmission timer. */ |
1575 | | ssl->dtls13SendingAckOrRtx = 1; |
1576 | | ret = SendTls13KeyUpdate(ssl); |
1577 | | if (ret != 0) { |
1578 | | /* Keep the mark only while there is something left to send, so a |
1579 | | * failure that wrote nothing does not leave it standing. */ |
1580 | | ssl->dtls13SendingAckOrRtx = |
1581 | | (ssl->buffers.outputBuffer.length > 0); |
1582 | | ssl->error = ret; |
1583 | | WOLFSSL_ERROR(ret); |
1584 | | return WOLFSSL_FATAL_ERROR; |
1585 | | } |
1586 | | ssl->dtls13SendingAckOrRtx = 0; |
1587 | | } |
1588 | | |
1589 | | WOLFSSL_LEAVE("wolfSSL_dtls13_do_scheduled_work", WOLFSSL_SUCCESS); |
1590 | | |
1591 | | return WOLFSSL_SUCCESS; |
1592 | | } |
1593 | | #endif /* WOLFSSL_DTLS13 */ |
1594 | | |
1595 | | #endif /* DTLS */ |
1596 | | #endif /* LEANPSK */ |
1597 | | |
1598 | | #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) |
1599 | | |
1600 | | /* Set the DTLS cookie secret used to generate HelloVerifyRequest cookies. |
1601 | | * |
1602 | | * When secret is NULL a new secret is randomly generated. The object's RNG |
1603 | | * must be initialized. This is not an SSL function. |
1604 | | * |
1605 | | * @param [in] ssl SSL/TLS object. |
1606 | | * @param [in] secret Cookie secret data, or NULL to generate one. |
1607 | | * @param [in] secretSz Length of secret in bytes, 0 to use the default. |
1608 | | * @return 0 on success. |
1609 | | * @return BAD_FUNC_ARG when ssl is NULL or secret is set with size 0. |
1610 | | * @return MEMORY_ERROR on allocation failure. |
1611 | | */ |
1612 | | int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, |
1613 | | const byte* secret, word32 secretSz) |
1614 | | { |
1615 | | int ret = 0; |
1616 | | |
1617 | | WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); |
1618 | | |
1619 | | if (ssl == NULL) { |
1620 | | WOLFSSL_MSG("need a SSL object"); |
1621 | | return BAD_FUNC_ARG; |
1622 | | } |
1623 | | |
1624 | | if (secret != NULL && secretSz == 0) { |
1625 | | WOLFSSL_MSG("can't have a new secret without a size"); |
1626 | | return BAD_FUNC_ARG; |
1627 | | } |
1628 | | |
1629 | | /* If secretSz is 0, use the default size. */ |
1630 | | if (secretSz == 0) |
1631 | | secretSz = COOKIE_SECRET_SZ; |
1632 | | |
1633 | | if (secretSz != ssl->buffers.dtlsCookieSecret.length) { |
1634 | | byte* newSecret; |
1635 | | |
1636 | | if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { |
1637 | | ForceZero(ssl->buffers.dtlsCookieSecret.buffer, |
1638 | | ssl->buffers.dtlsCookieSecret.length); |
1639 | | XFREE(ssl->buffers.dtlsCookieSecret.buffer, |
1640 | | ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); |
1641 | | } |
1642 | | |
1643 | | newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); |
1644 | | if (newSecret == NULL) { |
1645 | | ssl->buffers.dtlsCookieSecret.buffer = NULL; |
1646 | | ssl->buffers.dtlsCookieSecret.length = 0; |
1647 | | WOLFSSL_MSG("couldn't allocate new cookie secret"); |
1648 | | return MEMORY_ERROR; |
1649 | | } |
1650 | | ssl->buffers.dtlsCookieSecret.buffer = newSecret; |
1651 | | ssl->buffers.dtlsCookieSecret.length = secretSz; |
1652 | | #ifdef WOLFSSL_CHECK_MEM_ZERO |
1653 | | wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", |
1654 | | ssl->buffers.dtlsCookieSecret.buffer, |
1655 | | ssl->buffers.dtlsCookieSecret.length); |
1656 | | #endif |
1657 | | } |
1658 | | |
1659 | | /* If the supplied secret is NULL, randomly generate a new secret. */ |
1660 | | if (secret == NULL) { |
1661 | | ret = wc_RNG_GenerateBlock(ssl->rng, |
1662 | | ssl->buffers.dtlsCookieSecret.buffer, secretSz); |
1663 | | } |
1664 | | else |
1665 | | XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); |
1666 | | |
1667 | | WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); |
1668 | | return ret; |
1669 | | } |
1670 | | |
1671 | | struct chGoodDisableReadCbCtx { |
1672 | | ClientHelloGoodCb userCb; |
1673 | | void* userCtx; |
1674 | | }; |
1675 | | |
1676 | | /* ClientHello good callback that stops reading. |
1677 | | * |
1678 | | * Wraps the user's callback so that reading is disabled once a ClientHello |
1679 | | * with a valid cookie has been received. Used by wolfDTLS_accept_stateless(). |
1680 | | * |
1681 | | * @param [in] ssl SSL/TLS object. |
1682 | | * @param [in] ctx Context with user callback and its context. |
1683 | | * @return 0 on success or when no user callback set. |
1684 | | * @return Value returned by the user callback when negative. |
1685 | | */ |
1686 | | static int chGoodDisableReadCB(WOLFSSL* ssl, void* ctx) |
1687 | | { |
1688 | | struct chGoodDisableReadCbCtx* cb = (struct chGoodDisableReadCbCtx*)ctx; |
1689 | | int ret = 0; |
1690 | | if (cb->userCb != NULL) |
1691 | | ret = cb->userCb(ssl, cb->userCtx); |
1692 | | if (ret >= 0) |
1693 | | wolfSSL_SSLDisableRead(ssl); |
1694 | | return ret; |
1695 | | } |
1696 | | |
1697 | | /** |
1698 | | * Statelessly listen for a connection |
1699 | | * @param ssl The ssl object to use for listening to connections |
1700 | | * @return WOLFSSL_SUCCESS - ClientHello containing a valid cookie was received |
1701 | | * The connection can be continued with wolfSSL_accept |
1702 | | * WOLFSSL_FAILURE - The I/O layer returned WANT_READ. This is either |
1703 | | * because there is no data to read and we are using |
1704 | | * non-blocking sockets or we sent a cookie request |
1705 | | * and we are waiting for a reply. The user should |
1706 | | * call wolfDTLS_accept_stateless again after data |
1707 | | * becomes available in the I/O layer. |
1708 | | * WOLFSSL_FATAL_ERROR - A fatal error occurred. The ssl object should |
1709 | | * be free'd and allocated again to continue. |
1710 | | */ |
1711 | | int wolfDTLS_accept_stateless(WOLFSSL* ssl) |
1712 | | { |
1713 | | byte disableRead; |
1714 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); |
1715 | | struct chGoodDisableReadCbCtx cb; |
1716 | | |
1717 | | WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); |
1718 | | |
1719 | | if (ssl == NULL) |
1720 | | return WOLFSSL_FATAL_ERROR; |
1721 | | |
1722 | | /* Save this to restore it later */ |
1723 | | disableRead = (byte)ssl->options.disableRead; |
1724 | | cb.userCb = ssl->chGoodCb; |
1725 | | cb.userCtx = ssl->chGoodCtx; |
1726 | | |
1727 | | /* Register our own callback so that we can disable reading */ |
1728 | | if (wolfDTLS_SetChGoodCb(ssl, chGoodDisableReadCB, &cb) != WOLFSSL_SUCCESS) |
1729 | | return WOLFSSL_FATAL_ERROR; |
1730 | | |
1731 | | ssl->options.returnOnGoodCh = 1; |
1732 | | ret = wolfSSL_accept(ssl); |
1733 | | ssl->options.returnOnGoodCh = 0; |
1734 | | /* restore user options */ |
1735 | | ssl->options.disableRead = disableRead; |
1736 | | (void)wolfDTLS_SetChGoodCb(ssl, cb.userCb, cb.userCtx); |
1737 | | if (ret == WOLFSSL_SUCCESS) { |
1738 | | WOLFSSL_MSG("should not happen. maybe the user called " |
1739 | | "wolfDTLS_accept_stateless instead of wolfSSL_accept"); |
1740 | | } |
1741 | | else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ) || |
1742 | | ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) { |
1743 | | ssl->error = 0; |
1744 | | if (ssl->options.dtlsStateful) |
1745 | | ret = WOLFSSL_SUCCESS; |
1746 | | else |
1747 | | ret = WOLFSSL_FAILURE; |
1748 | | } |
1749 | | else { |
1750 | | ret = WOLFSSL_FATAL_ERROR; |
1751 | | } |
1752 | | return ret; |
1753 | | } |
1754 | | |
1755 | | /* Set the callback to call when a ClientHello with a valid cookie is received. |
1756 | | * |
1757 | | * WC_NO_INLINE: wolfDTLS_accept_stateless passes the address of a stack-local |
1758 | | * context here; the restore call before return clears it again. Preventing |
1759 | | * inlining hides that cross-frame assignment from GCC's -Wdangling-pointer |
1760 | | * analysis, which otherwise flags a false positive on GCC 14+. |
1761 | | * |
1762 | | * @param [in] ssl SSL/TLS object. |
1763 | | * @param [in] cb Callback to call. NULL to clear. |
1764 | | * @param [in] user_ctx Context to pass to the callback. |
1765 | | * @return WOLFSSL_SUCCESS on success. |
1766 | | * @return BAD_FUNC_ARG when ssl is NULL. |
1767 | | */ |
1768 | | WC_NO_INLINE |
1769 | | int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx) |
1770 | | { |
1771 | | WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); |
1772 | | |
1773 | | if (ssl == NULL) |
1774 | | return BAD_FUNC_ARG; |
1775 | | |
1776 | | ssl->chGoodCb = cb; |
1777 | | ssl->chGoodCtx = user_ctx; |
1778 | | |
1779 | | return WOLFSSL_SUCCESS; |
1780 | | } |
1781 | | |
1782 | | /* Set a secondary DTLS 1.2 cookie secret used only when verifying a received |
1783 | | * HelloVerifyRequest cookie, and only if the primary secret (set by |
1784 | | * wolfSSL_DTLS_SetCookieSecret()) fails to verify it. |
1785 | | * |
1786 | | * This supports an application-driven cookie-secret rotation on a stateless |
1787 | | * server: after rotating the primary secret, install the previous secret here |
1788 | | * so that cookies already issued under it are still accepted for an overlap |
1789 | | * window. It is never used to issue cookies. |
1790 | | * |
1791 | | * This is the DTLS 1.2 counterpart of wolfSSL_set_hrr_cookie_secret_secondary() |
1792 | | * (which covers the DTLS 1.3 HelloRetryRequest cookie); the two cookie |
1793 | | * mechanisms keep separate secrets, so a server that handles both versions sets |
1794 | | * both secondary secrets. |
1795 | | * |
1796 | | * @param [in] ssl SSL/TLS object. |
1797 | | * @param [in] secret Secondary secret to verify cookies against. A value |
1798 | | * of NULL (or a secretSz of 0) clears any previously set |
1799 | | * secondary secret. |
1800 | | * @param [in] secretSz Size of secret data in bytes. |
1801 | | * @return 0 on success. |
1802 | | * @return BAD_FUNC_ARG when ssl is NULL. |
1803 | | * @return MEMORY_ERROR on allocation failure. |
1804 | | */ |
1805 | | int wolfSSL_DTLS_SetCookieSecretSecondary(WOLFSSL* ssl, |
1806 | | const byte* secret, word32 secretSz) |
1807 | | { |
1808 | | byte* newSecret; |
1809 | | |
1810 | | WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecretSecondary"); |
1811 | | |
1812 | | if (ssl == NULL) { |
1813 | | WOLFSSL_MSG("need a SSL object"); |
1814 | | return BAD_FUNC_ARG; |
1815 | | } |
1816 | | |
1817 | | /* Clear any existing secondary secret. */ |
1818 | | if (ssl->buffers.dtlsCookieSecretSecondary.buffer != NULL) { |
1819 | | ForceZero(ssl->buffers.dtlsCookieSecretSecondary.buffer, |
1820 | | ssl->buffers.dtlsCookieSecretSecondary.length); |
1821 | | XFREE(ssl->buffers.dtlsCookieSecretSecondary.buffer, |
1822 | | ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); |
1823 | | ssl->buffers.dtlsCookieSecretSecondary.buffer = NULL; |
1824 | | ssl->buffers.dtlsCookieSecretSecondary.length = 0; |
1825 | | } |
1826 | | |
1827 | | /* A NULL/empty secret just clears the secondary secret. */ |
1828 | | if (secret == NULL || secretSz == 0) { |
1829 | | WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecretSecondary", 0); |
1830 | | return 0; |
1831 | | } |
1832 | | |
1833 | | newSecret = (byte*)XMALLOC(secretSz, ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); |
1834 | | if (newSecret == NULL) { |
1835 | | WOLFSSL_MSG("couldn't allocate secondary cookie secret"); |
1836 | | return MEMORY_ERROR; |
1837 | | } |
1838 | | XMEMCPY(newSecret, secret, secretSz); |
1839 | | ssl->buffers.dtlsCookieSecretSecondary.buffer = newSecret; |
1840 | | ssl->buffers.dtlsCookieSecretSecondary.length = secretSz; |
1841 | | #ifdef WOLFSSL_CHECK_MEM_ZERO |
1842 | | wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecretSecondary secret", |
1843 | | ssl->buffers.dtlsCookieSecretSecondary.buffer, |
1844 | | ssl->buffers.dtlsCookieSecretSecondary.length); |
1845 | | #endif |
1846 | | |
1847 | | WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecretSecondary", 0); |
1848 | | return 0; |
1849 | | } |
1850 | | |
1851 | | #endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ |
1852 | | |
1853 | | #endif /* !WOLFCRYPT_ONLY */ |
1854 | | |
1855 | | #endif /* !WOLFSSL_SSL_API_DTLS_INCLUDED */ |