/src/wolfssl/src/ssl_api_rw.c
Line | Count | Source |
1 | | /* ssl_api_rw.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_RW_INCLUDED) |
25 | | #ifndef WOLFSSL_IGNORE_FILE_WARN |
26 | | #warning ssl_api_rw.c does not need to be compiled separately from ssl.c |
27 | | #endif |
28 | | #else |
29 | | |
30 | | #ifndef WOLFCRYPT_ONLY |
31 | | |
32 | | #ifndef NO_TLS |
33 | | |
34 | | #if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_TLS13) |
35 | | /* Take over the TLS 1.3 work delegated by the read side. |
36 | | * |
37 | | * The read side of a write duplicate cannot send, so it records what needs to |
38 | | * be sent in the write duplicate object. Move that state across to the SSL |
39 | | * object of the write side. |
40 | | * |
41 | | * Must be called with ssl->dupWrite->dupMutex held. |
42 | | * |
43 | | * @param [in, out] ssl SSL/TLS object of the write side. |
44 | | * @return 0 on success. |
45 | | * @return Negative on error. |
46 | | */ |
47 | | static int wolfssl_write_dup_take_tls13_work(WOLFSSL* ssl) |
48 | | { |
49 | | int ret = 0; |
50 | | |
51 | | if (IsAtLeastTLSv1_3(ssl->version)) { |
52 | | /* TLS 1.3: if the read side received a KeyUpdate(update_requested) |
53 | | * it cannot respond; send the response from here. */ |
54 | | ssl->keys.keyUpdateRespond |= ssl->dupWrite->keyUpdateRespond; |
55 | | ssl->dupWrite->keyUpdateRespond = 0; |
56 | | #ifdef WOLFSSL_POST_HANDSHAKE_AUTH |
57 | | ssl->postHandshakeAuthPending |= |
58 | | ssl->dupWrite->postHandshakeAuthPending; |
59 | | ssl->dupWrite->postHandshakeAuthPending = 0; |
60 | | if (ssl->postHandshakeAuthPending) { |
61 | | /* Take ownership of the delegated auth state. */ |
62 | | CertReqCtx** tail = &ssl->dupWrite->postHandshakeCertReqCtx; |
63 | | while (*tail != NULL) { |
64 | | tail = &(*tail)->next; |
65 | | } |
66 | | *tail = ssl->certReqCtx; |
67 | | ssl->certReqCtx = ssl->dupWrite->postHandshakeCertReqCtx; |
68 | | ssl->dupWrite->postHandshakeCertReqCtx = NULL; |
69 | | FreeHandshakeHashes(ssl); |
70 | | ssl->hsHashes = ssl->dupWrite->postHandshakeHashState; |
71 | | ssl->dupWrite->postHandshakeHashState = NULL; |
72 | | ssl->options.sendVerify = ssl->dupWrite->postHandshakeSendVerify; |
73 | | ssl->options.sigAlgo = ssl->dupWrite->postHandshakeSigAlgo; |
74 | | ssl->options.hashAlgo = ssl->dupWrite->postHandshakeHashAlgo; |
75 | | #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) |
76 | | ssl->options.peerSha1CertOk = |
77 | | (ssl->dupWrite->postHandshakeSha1CertOk != 0) ? 1 : 0; |
78 | | #endif |
79 | | } |
80 | | #endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ |
81 | | #ifdef WOLFSSL_DTLS13 |
82 | | if (ssl->options.dtls) { |
83 | | /* Schedule key update to be sent. */ |
84 | | if (ssl->keys.keyUpdateRespond) { |
85 | | ssl->dtls13DoKeyUpdate = 1; |
86 | | } |
87 | | |
88 | | /* Copy over ACKs */ |
89 | | ssl->dtls13Rtx.sendAcks |= ssl->dupWrite->sendAcks; |
90 | | if (ssl->dupWrite->sendAcks) { |
91 | | /* Insert each record number so the |
92 | | * ACK message is properly ordered. */ |
93 | | struct Dtls13RecordNumber* rn; |
94 | | for (rn = ssl->dupWrite->sendAckList; rn != NULL; |
95 | | rn = rn->next) { |
96 | | ret = Dtls13RtxAddAck(ssl, rn->epoch, rn->seq); |
97 | | if (ret != 0) { |
98 | | break; |
99 | | } |
100 | | } |
101 | | /* Clear only on success so no ACKs get dropped */ |
102 | | if (ret == 0) { |
103 | | rn = ssl->dupWrite->sendAckList; |
104 | | ssl->dupWrite->sendAckList = NULL; |
105 | | ssl->dupWrite->sendAcks = 0; |
106 | | while (rn != NULL) { |
107 | | struct Dtls13RecordNumber* next = rn->next; |
108 | | XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG); |
109 | | rn = next; |
110 | | } |
111 | | } |
112 | | } |
113 | | |
114 | | /* Remove KeyUpdate record from RTX list. */ |
115 | | if (ssl->dupWrite->keyUpdateAcked) { |
116 | | Dtls13RtxRemoveRecord(ssl, ssl->dupWrite->keyUpdateEpoch, |
117 | | ssl->dupWrite->keyUpdateSeq); |
118 | | } |
119 | | /* Store if KeyUpdate was ACKed. */ |
120 | | ssl->dtls13KeyUpdateAcked |= ssl->dupWrite->keyUpdateAcked; |
121 | | ssl->dupWrite->keyUpdateAcked = 0; |
122 | | } |
123 | | #endif /* WOLFSSL_DTLS13 */ |
124 | | } |
125 | | |
126 | | return ret; |
127 | | } |
128 | | |
129 | | /* Perform the TLS 1.3 work delegated by the read side. |
130 | | * |
131 | | * Must be called after ssl->dupWrite->dupMutex has been released, as the work |
132 | | * performed here sends records. |
133 | | * |
134 | | * @param [in, out] ssl SSL/TLS object of the write side. |
135 | | * @return 0 on success. |
136 | | * @return WOLFSSL_FATAL_ERROR on error. Call wolfSSL_get_error() for the |
137 | | * reason. |
138 | | */ |
139 | | static int wolfssl_write_dup_do_tls13_work(WOLFSSL* ssl) |
140 | | { |
141 | | int ret = 0; |
142 | | |
143 | | if (IsWriteClosed(ssl)) { |
144 | | WOLFSSL_MSG("Dropping delegated responses after close_notify"); |
145 | | #ifdef WOLFSSL_POST_HANDSHAKE_AUTH |
146 | | ssl->postHandshakeAuthPending = 0; |
147 | | #endif |
148 | | ssl->keys.keyUpdateRespond = 0; |
149 | | #ifdef WOLFSSL_DTLS13 |
150 | | ssl->dtls13DoKeyUpdate = 0; |
151 | | #endif |
152 | | } |
153 | | |
154 | | if (IsAtLeastTLSv1_3(ssl->version)) { |
155 | | #ifdef WOLFSSL_POST_HANDSHAKE_AUTH |
156 | | /* Read side received a CertificateRequest but couldn't write; |
157 | | * send Certificate+CertificateVerify+Finished from the write |
158 | | * side. */ |
159 | | if (ssl->postHandshakeAuthPending) { |
160 | | /* reset handshake states */ |
161 | | ssl->postHandshakeAuthPending = 0; |
162 | | ssl->postHandshakeAuthPublish = 1; |
163 | | ssl->options.clientState = CLIENT_HELLO_COMPLETE; |
164 | | ssl->options.connectState = FIRST_REPLY_DONE; |
165 | | ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; |
166 | | ssl->options.processReply = 0; /* doProcessInit */ |
167 | | if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) { |
168 | | if ((ssl->error != WC_NO_ERR_TRACE(WANT_WRITE)) && |
169 | | (ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E))) { |
170 | | WOLFSSL_MSG("Post-handshake auth send failed"); |
171 | | ssl->error = POST_HAND_AUTH_ERROR; |
172 | | } |
173 | | ret = WOLFSSL_FATAL_ERROR; |
174 | | } |
175 | | } |
176 | | #endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ |
177 | | |
178 | | if (ret == 0) { |
179 | | #ifdef WOLFSSL_DTLS13 |
180 | | if (ssl->options.dtls) { |
181 | | if (ssl->dtls13KeyUpdateAcked) { |
182 | | ret = DoDtls13KeyUpdateAck(ssl); |
183 | | } |
184 | | ssl->dtls13KeyUpdateAcked = 0; |
185 | | if (ret == 0) { |
186 | | ret = Dtls13DoScheduledWork(ssl); |
187 | | } |
188 | | } |
189 | | else |
190 | | #endif /* WOLFSSL_DTLS13 */ |
191 | | { |
192 | | /* keyUpdateRespond is cleared in SendTls13KeyUpdate. */ |
193 | | if (ssl->keys.keyUpdateRespond) { |
194 | | /* RFC 9846 Section 4.7.3: a sender that would exceed the |
195 | | * key update limit "MUST NOT send its own KeyUpdate ... |
196 | | * and SHOULD instead ignore the 'update_requested' flag". |
197 | | * The read side delegated this response without seeing the |
198 | | * cap - it never sends KeyUpdates, so its count is not the |
199 | | * one that matters - so the check belongs here, on the |
200 | | * side that actually sends and owns the counter. */ |
201 | | if (Tls13KeyUpdateLimitReached(ssl)) { |
202 | | WOLFSSL_MSG("Key update limit reached; ignoring " |
203 | | "delegated update_requested"); |
204 | | ssl->keys.keyUpdateRespond = 0; |
205 | | } |
206 | | else { |
207 | | ret = Tls13UpdateKeys(ssl); |
208 | | } |
209 | | } |
210 | | } |
211 | | |
212 | | if (ret != 0) { |
213 | | ssl->error = ret; |
214 | | ret = WOLFSSL_FATAL_ERROR; |
215 | | } |
216 | | } |
217 | | } |
218 | | |
219 | | return ret; |
220 | | } |
221 | | #endif /* HAVE_WRITE_DUP && WOLFSSL_TLS13 */ |
222 | | |
223 | | #ifdef HAVE_WRITE_DUP |
224 | | /* Settle the write duplicate state before application data is sent. |
225 | | * |
226 | | * Takes over the work the read side delegated and surfaces any error it |
227 | | * recorded. Both are held under ssl->dupWrite->dupMutex, so they are collected |
228 | | * with the lock held and acted on once it has been released. |
229 | | * |
230 | | * @param [in, out] ssl SSL/TLS object of the write side. |
231 | | * @return 0 when the write may proceed. |
232 | | * @return BAD_MUTEX_E when the write duplicate could not be locked. |
233 | | * @return WOLFSSL_FATAL_ERROR on error. Call wolfSSL_get_error() for the |
234 | | * reason. |
235 | | */ |
236 | | static int wolfssl_write_dup_prepare(WOLFSSL* ssl) |
237 | | { |
238 | | int ret = 0; |
239 | | |
240 | | /* Lock ssl->dupWrite to gather what needs to be done. */ |
241 | | if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { |
242 | | ret = BAD_MUTEX_E; |
243 | | } |
244 | | else { |
245 | | int dupErr = ssl->dupWrite->dupErr; /* local copy */ |
246 | | |
247 | | #ifdef WOLFSSL_TLS13 |
248 | | ret = wolfssl_write_dup_take_tls13_work(ssl); |
249 | | #endif /* WOLFSSL_TLS13 */ |
250 | | wc_UnLockMutex(&ssl->dupWrite->dupMutex); |
251 | | |
252 | | /* An error from the read side takes precedence over one hit while |
253 | | * taking over its work. */ |
254 | | if (dupErr != 0) { |
255 | | WOLFSSL_MSG("Write dup error from other side"); |
256 | | ret = dupErr; |
257 | | } |
258 | | |
259 | | if (ret != 0) { |
260 | | ssl->error = ret; |
261 | | ret = WOLFSSL_FATAL_ERROR; |
262 | | } |
263 | | #ifdef WOLFSSL_TLS13 |
264 | | else { |
265 | | /* Do the work delegated by the read side. */ |
266 | | ret = wolfssl_write_dup_do_tls13_work(ssl); |
267 | | } |
268 | | #endif /* WOLFSSL_TLS13 */ |
269 | | } |
270 | | |
271 | | return ret; |
272 | | } |
273 | | #endif /* HAVE_WRITE_DUP */ |
274 | | |
275 | | /* Write application data to the peer. |
276 | | * |
277 | | * Performs the handshake when it has not completed. When a write duplicate is |
278 | | * in use, work delegated by the read side, such as sending a key update, is |
279 | | * done here first. |
280 | | * |
281 | | * @param [in, out] ssl SSL/TLS object. |
282 | | * @param [in] data Application data to write. |
283 | | * @param [in] sz Length of data in bytes. |
284 | | * @return Number of bytes written on success. |
285 | | * @return BAD_FUNC_ARG when ssl or data is NULL. |
286 | | * @return WRITE_DUP_WRITE_E when called on the read side of a write |
287 | | * duplicate. |
288 | | * @return BAD_MUTEX_E when the write duplicate could not be locked. Neither |
289 | | * of those two sets ssl->error. |
290 | | * @return WOLFSSL_FATAL_ERROR when the handshake or write fails. Call |
291 | | * wolfSSL_get_error() for the reason. |
292 | | */ |
293 | | static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) |
294 | 0 | { |
295 | 0 | int ret = 0; |
296 | |
|
297 | 0 | WOLFSSL_ENTER("wolfSSL_write_internal"); |
298 | | |
299 | | /* Validate parameters. Nothing on the way to the send reports zero, so ret |
300 | | * doubles as the "keep going" flag. */ |
301 | 0 | if ((ssl == NULL) || (data == NULL)) { |
302 | 0 | ret = BAD_FUNC_ARG; |
303 | 0 | } |
304 | |
|
305 | | #ifdef WOLFSSL_QUIC |
306 | | if ((ret == 0) && (WOLFSSL_IS_QUIC(ssl))) { |
307 | | WOLFSSL_MSG("SSL_write() on QUIC not allowed"); |
308 | | ret = BAD_FUNC_ARG; |
309 | | } |
310 | | #endif |
311 | |
|
312 | | #ifdef HAVE_WRITE_DUP |
313 | | if ((ret == 0) && (ssl->dupSide == READ_DUP_SIDE)) { |
314 | | WOLFSSL_MSG("Read dup side cannot write"); |
315 | | ret = WRITE_DUP_WRITE_E; |
316 | | } |
317 | | /* Only enter special dupWrite logic when error is cleared. This will help |
318 | | * with handling async data and other edge case errors. */ |
319 | | if ((ret == 0) && (ssl->dupWrite != NULL) && (ssl->error == 0)) { |
320 | | ret = wolfssl_write_dup_prepare(ssl); |
321 | | } |
322 | | #endif |
323 | |
|
324 | 0 | if (ret == 0) { |
325 | 0 | #ifdef HAVE_ERRNO_H |
326 | 0 | errno = 0; |
327 | 0 | #endif |
328 | |
|
329 | | #ifdef OPENSSL_EXTRA |
330 | | if (ssl->CBIS != NULL) { |
331 | | ssl->CBIS(ssl, WOLFSSL_CB_WRITE, WOLFSSL_SUCCESS); |
332 | | ssl->cbmode = WOLFSSL_CB_WRITE; |
333 | | } |
334 | | #endif |
335 | 0 | ret = SendData(ssl, data, sz); |
336 | |
|
337 | 0 | WOLFSSL_LEAVE("wolfSSL_write_internal", ret); |
338 | |
|
339 | 0 | if (ret < 0) { |
340 | 0 | ret = WOLFSSL_FATAL_ERROR; |
341 | 0 | } |
342 | 0 | } |
343 | |
|
344 | 0 | return ret; |
345 | 0 | } |
346 | | |
347 | | /* Write application data to the peer. |
348 | | * |
349 | | * @param [in, out] ssl SSL/TLS object. |
350 | | * @param [in] data Application data to write. |
351 | | * @param [in] sz Length of data in bytes. |
352 | | * @return Number of bytes written on success. |
353 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. |
354 | | * @return WOLFSSL_FATAL_ERROR when the write fails. Call |
355 | | * wolfSSL_get_error() for the reason. |
356 | | */ |
357 | | WOLFSSL_ABI |
358 | | int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) |
359 | 0 | { |
360 | 0 | int ret; |
361 | |
|
362 | 0 | WOLFSSL_ENTER("wolfSSL_write"); |
363 | | |
364 | | /* Validate parameter. */ |
365 | 0 | if (sz < 0) { |
366 | 0 | ret = BAD_FUNC_ARG; |
367 | 0 | } |
368 | 0 | else { |
369 | 0 | ret = wolfSSL_write_internal(ssl, data, (size_t)sz); |
370 | 0 | } |
371 | |
|
372 | 0 | return ret; |
373 | 0 | } |
374 | | |
375 | | /* Inject data into the input buffer as if it was received from the peer. |
376 | | * |
377 | | * Used when the application reads the transport itself. |
378 | | * |
379 | | * @param [in, out] ssl SSL/TLS object. |
380 | | * @param [in] data Data to inject. |
381 | | * @param [in] sz Length of data in bytes. |
382 | | * @return WOLFSSL_SUCCESS on success. |
383 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is not positive. |
384 | | * @return BUFFER_ERROR when the input buffer lengths are inconsistent. |
385 | | * @return APP_DATA_READY when the input buffer must be grown while there is |
386 | | * application data left to read. |
387 | | * @return Negative error code from growing the input buffer, such as |
388 | | * MEMORY_E. |
389 | | */ |
390 | | int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) |
391 | 0 | { |
392 | 0 | int ret = WOLFSSL_SUCCESS; |
393 | 0 | int usedLength = 0; |
394 | 0 | int maxLength = 0; |
395 | 0 | bufferStatic* in = NULL; |
396 | |
|
397 | 0 | WOLFSSL_ENTER("wolfSSL_inject"); |
398 | | |
399 | | /* Validate parameters. */ |
400 | 0 | if ((ssl == NULL) || (data == NULL) || (sz <= 0)) { |
401 | 0 | ret = BAD_FUNC_ARG; |
402 | 0 | } |
403 | |
|
404 | 0 | if (ret == WOLFSSL_SUCCESS) { |
405 | 0 | in = &ssl->buffers.inputBuffer; |
406 | | |
407 | | /* Order the unsigned fields first. Subtracting a larger value wraps |
408 | | * and can land back in the positive int range. */ |
409 | 0 | if ((in->idx > in->length) || (in->length > in->bufferSize)) { |
410 | 0 | ret = BUFFER_ERROR; |
411 | 0 | } |
412 | 0 | else { |
413 | 0 | usedLength = (int)(in->length - in->idx); |
414 | | /* Free space past all buffered data, where new data is appended. */ |
415 | 0 | maxLength = (int)(in->bufferSize - in->length); |
416 | |
|
417 | 0 | if ((usedLength < 0) || (maxLength < 0)) { |
418 | 0 | ret = BUFFER_ERROR; |
419 | 0 | } |
420 | 0 | } |
421 | 0 | } |
422 | |
|
423 | 0 | if ((ret == WOLFSSL_SUCCESS) && (sz > maxLength)) { |
424 | | /* Need to make space */ |
425 | 0 | if (ssl->buffers.clearOutputBuffer.length > 0) { |
426 | | /* clearOutputBuffer points into so reallocating inputBuffer |
427 | | * will invalidate clearOutputBuffer and lose app data */ |
428 | 0 | WOLFSSL_MSG( |
429 | 0 | "Can't inject while there is application data to read"); |
430 | 0 | ret = APP_DATA_READY; |
431 | 0 | } |
432 | 0 | else { |
433 | | /* Compacts the unconsumed data, leaving idx 0 and length |
434 | | * usedLength. */ |
435 | 0 | int growRet = GrowInputBuffer(ssl, sz, usedLength); |
436 | |
|
437 | 0 | if (growRet < 0) { |
438 | 0 | ret = growRet; |
439 | 0 | } |
440 | 0 | } |
441 | 0 | } |
442 | |
|
443 | 0 | if (ret == WOLFSSL_SUCCESS) { |
444 | 0 | XMEMCPY(in->buffer + in->length, data, (size_t)sz); |
445 | 0 | in->length += (word32)sz; |
446 | 0 | } |
447 | |
|
448 | 0 | return ret; |
449 | 0 | } |
450 | | |
451 | | /* Write application data to the peer and return the number of bytes written. |
452 | | * |
453 | | * @param [in, out] ssl SSL/TLS object. |
454 | | * @param [in] data Application data to write. |
455 | | * @param [in] sz Length of data in bytes. |
456 | | * @param [out] wr Number of bytes written. May be NULL. |
457 | | * @return WOLFSSL_SUCCESS on success. |
458 | | * @return BAD_FUNC_ARG when ssl is NULL. |
459 | | * @return WOLFSSL_FAILURE when the write fails. Call wolfSSL_get_error() for |
460 | | * the reason. |
461 | | */ |
462 | | int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) |
463 | 0 | { |
464 | 0 | int ret; |
465 | |
|
466 | 0 | if (wr != NULL) { |
467 | 0 | *wr = 0; |
468 | 0 | } |
469 | | |
470 | | /* Validate parameter, matching wolfSSL_read_ex() and the rest of the |
471 | | * file. Reported as an error code rather than the 0 used for "nothing |
472 | | * was written", which a caller cannot tell from a short write. */ |
473 | 0 | if (ssl == NULL) { |
474 | 0 | ret = BAD_FUNC_ARG; |
475 | 0 | } |
476 | 0 | else { |
477 | 0 | ret = wolfSSL_write_internal(ssl, data, sz); |
478 | 0 | if (ret >= 0) { |
479 | 0 | if (wr != NULL) { |
480 | 0 | *wr = (size_t)ret; |
481 | 0 | } |
482 | | |
483 | | /* handle partial write cases, if not set then a partial write is |
484 | | * considered a failure case, or if set and ret is 0 then is a |
485 | | * fail */ |
486 | 0 | if ((ret == 0) && (ssl->options.partialWrite)) { |
487 | 0 | ret = 0; |
488 | 0 | } |
489 | 0 | else if (((size_t)ret < sz) && (!ssl->options.partialWrite)) { |
490 | 0 | ret = 0; |
491 | 0 | } |
492 | 0 | else { |
493 | | /* wrote out all application data, or wrote out 1 byte or more |
494 | | * with partial write flag set */ |
495 | 0 | ret = 1; |
496 | 0 | } |
497 | 0 | } |
498 | 0 | else { |
499 | 0 | ret = 0; |
500 | 0 | } |
501 | 0 | } |
502 | |
|
503 | 0 | return ret; |
504 | 0 | } |
505 | | |
506 | | /* Read application data from the peer. |
507 | | * |
508 | | * Performs the handshake when it has not completed. |
509 | | * |
510 | | * @param [in, out] ssl SSL/TLS object. |
511 | | * @param [out] data Buffer to hold application data. |
512 | | * @param [in] sz Length of buffer in bytes. |
513 | | * @param [in] peek When 1, data is not removed from the input buffer. |
514 | | * @return Number of bytes read on success. |
515 | | * @return 0 when the peer has closed the connection. |
516 | | * @return BAD_FUNC_ARG when ssl or data is NULL. |
517 | | * @return WRITE_DUP_READ_E when called on the write side of a write |
518 | | * duplicate. ssl->error is not set for it. |
519 | | * @return WOLFSSL_FATAL_ERROR when the handshake or read fails. Call |
520 | | * wolfSSL_get_error() for the reason. |
521 | | */ |
522 | | static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) |
523 | 0 | { |
524 | 0 | int ret = 0; |
525 | | /* A separate flag is needed rather than gating on ret: the OpenSSL |
526 | | * shutdown simulation below reports WOLFSSL_FAILURE, which is zero. */ |
527 | 0 | int done = 0; |
528 | |
|
529 | 0 | WOLFSSL_ENTER("wolfSSL_read_internal"); |
530 | | |
531 | | /* Validate parameters. */ |
532 | 0 | if ((ssl == NULL) || (data == NULL)) { |
533 | 0 | ret = BAD_FUNC_ARG; |
534 | 0 | done = 1; |
535 | 0 | } |
536 | |
|
537 | | #ifdef WOLFSSL_QUIC |
538 | | if ((!done) && (WOLFSSL_IS_QUIC(ssl))) { |
539 | | WOLFSSL_MSG("SSL_read() on QUIC not allowed"); |
540 | | ret = BAD_FUNC_ARG; |
541 | | done = 1; |
542 | | } |
543 | | #endif |
544 | | #if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) |
545 | | /* This additional logic is meant to simulate following openSSL behavior: |
546 | | * After bidirectional SSL_shutdown complete, SSL_read returns 0 and |
547 | | * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. |
548 | | * This behavior is used to know the disconnect of the underlying |
549 | | * transport layer. |
550 | | * |
551 | | * In this logic, CBIORecv is called with a read size of 0 to check the |
552 | | * transport layer status. It also returns WOLFSSL_FAILURE so that |
553 | | * SSL_read does not return a positive number on failure. |
554 | | */ |
555 | | |
556 | | /* make sure bidirectional TLS shutdown completes */ |
557 | | if ((!done) && ((ssl->error == WOLFSSL_ERROR_SYSCALL) || |
558 | | (ssl->options.shutdownDone))) { |
559 | | /* ask the underlying transport the connection is closed */ |
560 | | if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) |
561 | | == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_CONN_CLOSE)) |
562 | | { |
563 | | ssl->options.isClosed = 1; |
564 | | ssl->error = WOLFSSL_ERROR_ZERO_RETURN; |
565 | | } |
566 | | ret = WOLFSSL_FAILURE; |
567 | | done = 1; |
568 | | } |
569 | | #endif |
570 | |
|
571 | | #ifdef HAVE_WRITE_DUP |
572 | | if ((!done) && (ssl->dupWrite != NULL) && |
573 | | (ssl->dupSide == WRITE_DUP_SIDE)) { |
574 | | WOLFSSL_MSG("Write dup side cannot read"); |
575 | | ret = WRITE_DUP_READ_E; |
576 | | done = 1; |
577 | | } |
578 | | #endif |
579 | |
|
580 | 0 | if (!done) { |
581 | 0 | #ifdef HAVE_ERRNO_H |
582 | 0 | errno = 0; |
583 | 0 | #endif |
584 | |
|
585 | 0 | ret = ReceiveData(ssl, (byte*)data, sz, peek); |
586 | |
|
587 | | #ifdef HAVE_WRITE_DUP |
588 | | if (ssl->dupWrite != NULL) { |
589 | | if ((ssl->error != 0) && |
590 | | (ssl->error != WC_NO_ERR_TRACE(WANT_READ)) |
591 | | #ifdef WOLFSSL_HAVE_HS_SUSPEND |
592 | | && !IsHsSuspendErr(ssl->error) |
593 | | #endif |
594 | | ) { |
595 | | int notifyErr; |
596 | | |
597 | | WOLFSSL_MSG("Notifying write side of fatal read error"); |
598 | | notifyErr = NotifyWriteSide(ssl, ssl->error); |
599 | | if (notifyErr < 0) { |
600 | | ret = ssl->error = notifyErr; |
601 | | } |
602 | | } |
603 | | } |
604 | | #endif |
605 | |
|
606 | 0 | WOLFSSL_LEAVE("wolfSSL_read_internal", ret); |
607 | |
|
608 | 0 | if (ret < 0) { |
609 | 0 | ret = WOLFSSL_FATAL_ERROR; |
610 | 0 | } |
611 | 0 | } |
612 | |
|
613 | 0 | return ret; |
614 | 0 | } |
615 | | |
616 | | /* Read application data from the peer without removing it. |
617 | | * |
618 | | * The same data is returned by the next call to wolfSSL_read(). |
619 | | * |
620 | | * @param [in, out] ssl SSL/TLS object. |
621 | | * @param [out] data Buffer to hold application data. |
622 | | * @param [in] sz Length of buffer in bytes. |
623 | | * @return Number of bytes read on success. |
624 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. |
625 | | * @return WOLFSSL_FATAL_ERROR when the read fails. |
626 | | */ |
627 | | int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) |
628 | 0 | { |
629 | 0 | int ret; |
630 | |
|
631 | 0 | WOLFSSL_ENTER("wolfSSL_peek"); |
632 | | |
633 | | /* Validate parameter. */ |
634 | 0 | if (sz < 0) { |
635 | 0 | ret = BAD_FUNC_ARG; |
636 | 0 | } |
637 | 0 | else { |
638 | 0 | ret = wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); |
639 | 0 | } |
640 | |
|
641 | 0 | return ret; |
642 | 0 | } |
643 | | |
644 | | /* Read application data from the peer. |
645 | | * |
646 | | * @param [in, out] ssl SSL/TLS object. |
647 | | * @param [out] data Buffer to hold application data. |
648 | | * @param [in] sz Length of buffer in bytes. |
649 | | * @return Number of bytes read on success. |
650 | | * @return 0 when the peer has closed the connection. |
651 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. |
652 | | * @return WOLFSSL_FATAL_ERROR when the read fails. Call wolfSSL_get_error() |
653 | | * for the reason. |
654 | | */ |
655 | | WOLFSSL_ABI |
656 | | int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) |
657 | 0 | { |
658 | 0 | int ret; |
659 | |
|
660 | 0 | WOLFSSL_ENTER("wolfSSL_read"); |
661 | | |
662 | | /* Validate parameters. */ |
663 | 0 | if (sz < 0) { |
664 | 0 | ret = BAD_FUNC_ARG; |
665 | 0 | } |
666 | | #ifdef OPENSSL_EXTRA |
667 | | else if (ssl == NULL) { |
668 | | ret = BAD_FUNC_ARG; |
669 | | } |
670 | | #endif |
671 | 0 | else { |
672 | | #ifdef OPENSSL_EXTRA |
673 | | if (ssl->CBIS != NULL) { |
674 | | ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); |
675 | | ssl->cbmode = WOLFSSL_CB_READ; |
676 | | } |
677 | | #endif |
678 | 0 | ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); |
679 | 0 | } |
680 | |
|
681 | 0 | return ret; |
682 | 0 | } |
683 | | |
684 | | /* Read application data from the peer and report whether any was read. |
685 | | * |
686 | | * @param [in, out] ssl SSL/TLS object. |
687 | | * @param [out] data Buffer to hold application data. |
688 | | * @param [in] sz Length of buffer in bytes. |
689 | | * @param [out] rd Number of bytes read. May be NULL. Only set when |
690 | | * data was read. |
691 | | * @return 1 when application data was read. |
692 | | * @return 0 when no application data was read. Call wolfSSL_get_error() for |
693 | | * the reason. |
694 | | * @return BAD_FUNC_ARG when ssl is NULL. |
695 | | */ |
696 | | int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) |
697 | 0 | { |
698 | 0 | int ret; |
699 | | |
700 | | /* Validate parameter. Checked unconditionally so the guarded branch does |
701 | | * not leave a standalone block. */ |
702 | 0 | if (ssl == NULL) { |
703 | 0 | ret = BAD_FUNC_ARG; |
704 | 0 | } |
705 | 0 | else { |
706 | | #ifdef OPENSSL_EXTRA |
707 | | if (ssl->CBIS != NULL) { |
708 | | ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); |
709 | | ssl->cbmode = WOLFSSL_CB_READ; |
710 | | } |
711 | | #endif |
712 | 0 | ret = wolfSSL_read_internal(ssl, data, sz, FALSE); |
713 | |
|
714 | 0 | if ((ret > 0) && (rd != NULL)) { |
715 | 0 | *rd = (size_t)ret; |
716 | 0 | } |
717 | |
|
718 | 0 | ret = (ret > 0) ? 1 : 0; |
719 | 0 | } |
720 | |
|
721 | 0 | return ret; |
722 | 0 | } |
723 | | |
724 | | #ifndef WOLFSSL_LEANPSK |
725 | | |
726 | | /* Write application data to the peer with socket flags. |
727 | | * |
728 | | * Flags are set on the socket for the write and restored afterwards. |
729 | | * |
730 | | * @param [in, out] ssl SSL/TLS object. |
731 | | * @param [in] data Application data to write. |
732 | | * @param [in] sz Length of data in bytes. |
733 | | * @param [in] flags Flags to pass to the send call. |
734 | | * @return Number of bytes written on success. |
735 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. |
736 | | * @return WOLFSSL_FATAL_ERROR when the write fails. |
737 | | */ |
738 | | int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) |
739 | 0 | { |
740 | 0 | int ret; |
741 | |
|
742 | 0 | WOLFSSL_ENTER("wolfSSL_send"); |
743 | | |
744 | | /* Validate parameters. */ |
745 | 0 | if ((ssl == NULL) || (data == NULL) || (sz < 0)) { |
746 | 0 | ret = BAD_FUNC_ARG; |
747 | 0 | } |
748 | 0 | else { |
749 | 0 | int oldFlags = ssl->wflags; |
750 | |
|
751 | 0 | ssl->wflags = flags; |
752 | 0 | ret = wolfSSL_write(ssl, data, sz); |
753 | 0 | ssl->wflags = oldFlags; |
754 | |
|
755 | 0 | WOLFSSL_LEAVE("wolfSSL_send", ret); |
756 | 0 | } |
757 | |
|
758 | 0 | return ret; |
759 | 0 | } |
760 | | |
761 | | /* Read application data from the peer with socket flags. |
762 | | * |
763 | | * Flags are set on the socket for the read and restored afterwards. |
764 | | * |
765 | | * @param [in, out] ssl SSL/TLS object. |
766 | | * @param [out] data Buffer to hold application data. |
767 | | * @param [in] sz Length of buffer in bytes. |
768 | | * @param [in] flags Flags to pass to the recv call. |
769 | | * @return Number of bytes read on success. |
770 | | * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. |
771 | | * @return WOLFSSL_FATAL_ERROR when the read fails. |
772 | | */ |
773 | | int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) |
774 | 0 | { |
775 | 0 | int ret; |
776 | |
|
777 | 0 | WOLFSSL_ENTER("wolfSSL_recv"); |
778 | | |
779 | | /* Validate parameters. */ |
780 | 0 | if ((ssl == NULL) || (data == NULL) || (sz < 0)) { |
781 | 0 | ret = BAD_FUNC_ARG; |
782 | 0 | } |
783 | 0 | else { |
784 | 0 | int oldFlags = ssl->rflags; |
785 | |
|
786 | 0 | ssl->rflags = flags; |
787 | 0 | ret = wolfSSL_read(ssl, data, sz); |
788 | 0 | ssl->rflags = oldFlags; |
789 | |
|
790 | 0 | WOLFSSL_LEAVE("wolfSSL_recv", ret); |
791 | 0 | } |
792 | |
|
793 | 0 | return ret; |
794 | 0 | } |
795 | | #endif |
796 | | |
797 | | static int wolfssl_shutdown_internal(WOLFSSL* ssl, int allowInInit); |
798 | | |
799 | | /* Send a user_canceled alert to the peer and shut down the connection. |
800 | | * |
801 | | * @param [in, out] ssl SSL/TLS object. |
802 | | * @return WOLFSSL_SUCCESS on success. |
803 | | * @return WOLFSSL_SHUTDOWN_NOT_DONE when the shutdown is not complete. |
804 | | * @return WOLFSSL_FAILURE when ssl is NULL or sending the alert fails. |
805 | | */ |
806 | | int wolfSSL_SendUserCanceled(WOLFSSL* ssl) |
807 | 0 | { |
808 | 0 | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
809 | 0 | WOLFSSL_ENTER("wolfSSL_SendUserCanceled"); |
810 | |
|
811 | 0 | if (ssl != NULL) { |
812 | 0 | ssl->error = SendAlert(ssl, alert_warning, user_canceled); |
813 | 0 | if (ssl->error < 0) { |
814 | 0 | WOLFSSL_ERROR(ssl->error); |
815 | 0 | } |
816 | 0 | else { |
817 | | /* RFC 9846: user_canceled must be followed by close_notify. Quiet |
818 | | * shutdown suppresses a standalone close_notify, but the alert just |
819 | | * sent obligates the paired close_notify, so clear quiet shutdown |
820 | | * across this shutdown call to guarantee it is sent, then restore |
821 | | * the caller's setting. */ |
822 | 0 | int quietShutdown = ssl->options.quietShutdown; |
823 | 0 | ssl->options.quietShutdown = 0; |
824 | | /* RFC 8446 Section 6.1: user_canceled cancels a handshake in |
825 | | * progress, so shut down even when it never completed. */ |
826 | 0 | ret = wolfssl_shutdown_internal(ssl, 1); |
827 | 0 | if (quietShutdown) { |
828 | 0 | if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) { |
829 | | /* The close_notify is still in the output buffer. Leave |
830 | | * quiet shutdown off so the caller's retry of |
831 | | * wolfSSL_shutdown() flushes it, and have that call give |
832 | | * the setting back once the flush reaches a decision. */ |
833 | 0 | ssl->options.quietShutdownRestore = 1; |
834 | 0 | } |
835 | 0 | else { |
836 | 0 | ssl->options.quietShutdown = 1; |
837 | 0 | } |
838 | 0 | } |
839 | 0 | } |
840 | 0 | } |
841 | |
|
842 | 0 | WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); |
843 | |
|
844 | 0 | return ret; |
845 | 0 | } |
846 | | |
847 | | /* Flush an alert still sitting in the output buffer. |
848 | | * |
849 | | * A previous call may have left the close_notify alert buffered when the |
850 | | * transport reported WANT_WRITE. Get it out before doing anything else. |
851 | | * |
852 | | * @param [in, out] ssl SSL/TLS object. |
853 | | * @param [in, out] ret Result for wolfSSL_shutdown() to return. Set only on |
854 | | * the paths that reach a decision; on the others it is |
855 | | * left as the caller initialized it. Returning 0 while |
856 | | * assigning WOLFSSL_SHUTDOWN_NOT_DONE would break the |
857 | | * caller: it treats an undecided result as "no |
858 | | * close_notify can ever be sent" and converts it to a |
859 | | * failure. Every path here that reports "call again" |
860 | | * therefore returns 1. |
861 | | * @return 1 when no later step of the shutdown may run. |
862 | | * @return 0 when the caller carries on with the rest of the shutdown. The |
863 | | * result may already have been decided: the exchange can complete |
864 | | * here, and the steps that follow then leave it alone. |
865 | | */ |
866 | | static int wolfssl_shutdown_flush_alert(WOLFSSL* ssl, int* ret) |
867 | 0 | { |
868 | 0 | int done = 0; |
869 | |
|
870 | 0 | if ((ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) && |
871 | 0 | (ssl->buffers.outputBuffer.length > 0)) { |
872 | 0 | int rc = SendBuffered(ssl); |
873 | |
|
874 | 0 | if (rc != 0) { |
875 | 0 | ssl->error = rc; |
876 | | /* for error tracing */ |
877 | 0 | if (rc != WC_NO_ERR_TRACE(WANT_WRITE)) { |
878 | 0 | WOLFSSL_ERROR(rc); |
879 | 0 | } |
880 | | /* The reason has been traced above - don't trace the return |
881 | | * value as well. */ |
882 | 0 | *ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); |
883 | 0 | done = 1; |
884 | 0 | } |
885 | 0 | else { |
886 | 0 | ssl->error = WOLFSSL_ERROR_NONE; |
887 | | /* we succeeded in sending the alert now */ |
888 | 0 | if (ssl->options.sentNotify) { |
889 | | /* just after we send the alert, if we didn't receive the |
890 | | * alert from the other peer yet, return |
891 | | * WOLFSSL_SHUTDOWN_NOT_DONE */ |
892 | 0 | if (!ssl->options.closeNotify) { |
893 | 0 | *ret = WOLFSSL_SHUTDOWN_NOT_DONE; |
894 | 0 | done = 1; |
895 | 0 | } |
896 | 0 | else { |
897 | 0 | ssl->options.shutdownDone = 1; |
898 | 0 | *ret = WOLFSSL_SUCCESS; |
899 | 0 | } |
900 | 0 | } |
901 | 0 | } |
902 | 0 | } |
903 | |
|
904 | 0 | return done; |
905 | 0 | } |
906 | | |
907 | | /* Send the close_notify alert to the peer. |
908 | | * |
909 | | * Not being able to send it right away is not an error - the alert is left in |
910 | | * the output buffer and goes out eventually. |
911 | | * |
912 | | * @param [in, out] ssl SSL/TLS object. |
913 | | * @param [in, out] ret Result for wolfSSL_shutdown() to return. Set only on |
914 | | * the paths that reach a decision; on the others it is |
915 | | * left as the caller initialized it. As in |
916 | | * wolfssl_shutdown_flush_alert(), a path that reports |
917 | | * "call again" must return 1 - the caller reads an |
918 | | * undecided result as "no close_notify can ever be |
919 | | * sent" and turns it into a failure. |
920 | | * @return 1 when no later step of the shutdown may run. |
921 | | * @return 0 when the caller carries on with the rest of the shutdown. The |
922 | | * result may already have been decided: the exchange can complete |
923 | | * here, and the steps that follow then leave it alone. |
924 | | */ |
925 | | static int wolfssl_shutdown_send_close_notify(WOLFSSL* ssl, int* ret) |
926 | 0 | { |
927 | 0 | int done = 0; |
928 | | |
929 | | /* try to send close notify, not an error if can't */ |
930 | 0 | if ((!ssl->options.isClosed) && (!ssl->options.connReset) && |
931 | 0 | (!ssl->options.sentNotify)) { |
932 | 0 | ssl->error = SendAlert(ssl, alert_warning, close_notify); |
933 | | |
934 | | /* the alert is now sent or sitting in the buffer, |
935 | | * where will be sent eventually */ |
936 | 0 | if ((ssl->error == 0) || |
937 | 0 | (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE))) { |
938 | 0 | ssl->options.sentNotify = 1; |
939 | 0 | } |
940 | |
|
941 | 0 | if (ssl->error < 0) { |
942 | 0 | WOLFSSL_ERROR(ssl->error); |
943 | | /* The reason has been traced above - don't trace the return |
944 | | * value as well. */ |
945 | 0 | *ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); |
946 | 0 | done = 1; |
947 | 0 | } |
948 | 0 | else if (ssl->options.closeNotify) { |
949 | 0 | *ret = WOLFSSL_SUCCESS; |
950 | 0 | ssl->options.shutdownDone = 1; |
951 | 0 | } |
952 | 0 | else { |
953 | 0 | *ret = WOLFSSL_SHUTDOWN_NOT_DONE; |
954 | 0 | done = 1; |
955 | 0 | } |
956 | 0 | } |
957 | |
|
958 | 0 | return done; |
959 | 0 | } |
960 | | |
961 | | /* Wait for the peer's close_notify alert to complete a bidirectional shutdown. |
962 | | * |
963 | | * Called when this side has sent its close_notify but has not seen the |
964 | | * peer's, i.e. wolfSSL_shutdown() called again. |
965 | | * |
966 | | * @param [in, out] ssl SSL/TLS object. |
967 | | * @return WOLFSSL_SUCCESS when the shutdown is complete. |
968 | | * @return WOLFSSL_SHUTDOWN_NOT_DONE when the peer's alert has not arrived. |
969 | | * @return WOLFSSL_FATAL_ERROR on error. Call wolfSSL_get_error() for the |
970 | | * reason. |
971 | | */ |
972 | | static int wolfssl_shutdown_recv_close_notify(WOLFSSL* ssl) |
973 | 0 | { |
974 | 0 | int ret; |
975 | | |
976 | | /* If there is still buffered application data waiting to be read, do not |
977 | | * process incoming records here. clearOutputBuffer.buffer points into |
978 | | * inputBuffer, and ProcessReply() may call GrowInputBuffer(), which frees |
979 | | * and reallocates inputBuffer. Require the pending data to be drained |
980 | | * first. */ |
981 | 0 | if (ssl->buffers.clearOutputBuffer.length > 0) { |
982 | 0 | WOLFSSL_MSG("Pending application data, read it before shutdown"); |
983 | 0 | ret = WOLFSSL_SHUTDOWN_NOT_DONE; |
984 | 0 | } |
985 | 0 | else { |
986 | 0 | if (ssl->error == WC_NO_ERR_TRACE(SSL_SHUTDOWN_ALREADY_DONE_E)) |
987 | 0 | ssl->error = WOLFSSL_ERROR_NONE; |
988 | 0 | ret = ProcessReply(ssl); |
989 | 0 | if ((ret == WC_NO_ERR_TRACE(ZERO_RETURN)) || |
990 | 0 | (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E))) { |
991 | | /* simulate OpenSSL behavior */ |
992 | 0 | ssl->options.shutdownDone = 1; |
993 | | /* Clear error */ |
994 | 0 | ssl->error = WOLFSSL_ERROR_NONE; |
995 | 0 | ret = WOLFSSL_SUCCESS; |
996 | 0 | } |
997 | 0 | else if ((ret < 0) && (ret != WC_NO_ERR_TRACE(APP_DATA_READY))) { |
998 | | /* Retry would process the same bad record again, error out. */ |
999 | 0 | ssl->error = ret; |
1000 | 0 | WOLFSSL_ERROR(ret); |
1001 | 0 | ret = WOLFSSL_FATAL_ERROR; |
1002 | 0 | } |
1003 | 0 | else if (ssl->error == WOLFSSL_ERROR_NONE) { |
1004 | 0 | ret = WOLFSSL_SHUTDOWN_NOT_DONE; |
1005 | 0 | } |
1006 | 0 | else { |
1007 | 0 | WOLFSSL_ERROR(ssl->error); |
1008 | 0 | ret = WOLFSSL_FATAL_ERROR; |
1009 | 0 | } |
1010 | 0 | } |
1011 | |
|
1012 | 0 | return ret; |
1013 | 0 | } |
1014 | | |
1015 | | /* Shut the connection down by exchanging close_notify alerts with the peer. |
1016 | | * |
1017 | | * Call repeatedly while WOLFSSL_SHUTDOWN_NOT_DONE is returned to complete a |
1018 | | * bidirectional shutdown. |
1019 | | * |
1020 | | * @param [in, out] ssl SSL/TLS object. |
1021 | | * @return WOLFSSL_SUCCESS when the shutdown is complete. |
1022 | | * @return WOLFSSL_SHUTDOWN_NOT_DONE when the peer's close_notify has not |
1023 | | * been received yet. |
1024 | | * @return SSL_SHUTDOWN_ALREADY_DONE_E when the connection was already closed |
1025 | | * and WOLFSSL_SHUTDOWNONCE is defined. |
1026 | | * @return WOLFSSL_FATAL_ERROR when ssl is NULL or on error. Call |
1027 | | * wolfSSL_get_error() for the reason. |
1028 | | * |
1029 | | * SOCKET_PEER_CLOSED_E is reported when the connection was already |
1030 | | * closed or reset and no close_notify was ever sent, so the exchange |
1031 | | * can never complete. That covers this side closing by sending a fatal |
1032 | | * alert as much as the peer going away, and it is only used when no |
1033 | | * more specific error has been recorded. Under OPENSSL_EXTRA |
1034 | | * wolfSSL_get_error() reports it as WOLFSSL_ERROR_SYSCALL, so a locally |
1035 | | * aborted connection surfaces as a syscall error. This case used to return 0, |
1036 | | * which is WOLFSSL_SHUTDOWN_NOT_DONE under WOLFSSL_ERROR_CODE_OPENSSL, |
1037 | | * so a caller looping while the result is 0 never terminated. |
1038 | | * |
1039 | | * Recording it also appends to the OpenSSL error queue where one is built in |
1040 | | * (WOLFSSL_HAVE_ERROR_QUEUE, which OPENSSL_ALL, OPENSSL_EXTRA, WOLFSSL_NGINX |
1041 | | * and WOLFSSL_HAPROXY all enable), so an application that inspects the queue |
1042 | | * after tearing down an already-aborted connection now finds an entry where |
1043 | | * it previously found none. Clear it with wolfSSL_ERR_clear_error() if |
1044 | | * leftover entries matter to the caller. |
1045 | | */ |
1046 | | WOLFSSL_ABI |
1047 | | int wolfSSL_shutdown(WOLFSSL* ssl) |
1048 | 0 | { |
1049 | 0 | return wolfssl_shutdown_internal(ssl, 0); |
1050 | 0 | } |
1051 | | |
1052 | | /* Whether the handshake failed outright rather than being still in flight. |
1053 | | * WANT_READ/WANT_WRITE and a handshake suspend error (pending async |
1054 | | * operation, non-blocking OCSP/CRL lookup or deferred chain verify callback) |
1055 | | * mean it can still continue, anything else recorded in ssl->error means it |
1056 | | * cannot. |
1057 | | * |
1058 | | * @param [in] ssl SSL/TLS object. |
1059 | | * @return 1 when the handshake has failed, 0 when it can still progress. |
1060 | | */ |
1061 | | static int wolfssl_handshake_failed(const WOLFSSL* ssl) |
1062 | 0 | { |
1063 | 0 | return (ssl->error != 0) && |
1064 | 0 | (ssl->error != WC_NO_ERR_TRACE(WANT_READ)) && |
1065 | 0 | (ssl->error != WC_NO_ERR_TRACE(WANT_WRITE)) |
1066 | | #ifdef WOLFSSL_HAVE_HS_SUSPEND |
1067 | | /* The handshake resumes off this error, which sending the alert |
1068 | | * would overwrite. */ |
1069 | | && !IsHsSuspendErr(ssl->error) |
1070 | | #endif |
1071 | | #ifdef WOLFSSL_CERT_SETUP_CB |
1072 | | /* The certificate setup callback asked to be called again. Positive |
1073 | | * value, so no WC_NO_ERR_TRACE(). */ |
1074 | | && (ssl->error != WOLFSSL_ERROR_WANT_X509_LOOKUP) |
1075 | | #endif |
1076 | 0 | ; |
1077 | 0 | } |
1078 | | |
1079 | | /* Body of wolfSSL_shutdown(). |
1080 | | * |
1081 | | * @param [in, out] ssl SSL/TLS object. |
1082 | | * @param [in] allowInInit Whether to shut down a handshake that has not |
1083 | | * completed. |
1084 | | */ |
1085 | | static int wolfssl_shutdown_internal(WOLFSSL* ssl, int allowInInit) |
1086 | 0 | { |
1087 | 0 | int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); |
1088 | |
|
1089 | 0 | WOLFSSL_ENTER("wolfSSL_shutdown"); |
1090 | | |
1091 | | /* Validate parameter. */ |
1092 | 0 | if (ssl == NULL) { |
1093 | 0 | ret = WOLFSSL_FATAL_ERROR; |
1094 | 0 | } |
1095 | | /* close_notify only means anything on an established connection. OpenSSL |
1096 | | * fails here with SSL_R_SHUTDOWN_WHILE_IN_INIT and sends nothing. Gate on |
1097 | | * handShakeDone, not handShakeState, so a renegotiation in flight does not |
1098 | | * block shutdown. A handshake that already failed is not in flight - the |
1099 | | * caller is tearing down and the peer still has to be told, otherwise it |
1100 | | * sees a truncated connection instead of an alert. Once sentNotify is set |
1101 | | * the shutdown is already under way - wolfSSL_SendUserCanceled() may have |
1102 | | * started it - and the retry that flushes a buffered close_notify has to |
1103 | | * get through. */ |
1104 | 0 | else if ((!allowInInit) && (!ssl->options.handShakeDone) && |
1105 | 0 | (!ssl->options.sentNotify) && (!wolfssl_handshake_failed(ssl))) { |
1106 | 0 | WOLFSSL_MSG("Shutdown called before the handshake completed"); |
1107 | | /* Queue NOT_READY_ERROR but leave ssl->error alone. ssl->error is a |
1108 | | * single slot that also gates handshake progress and drives |
1109 | | * wolfssl_handshake_failed() above, so writing it here would abort |
1110 | | * the in-flight handshake and make this guard skip itself on the |
1111 | | * next call. The queued error is what OpenSSL reports for |
1112 | | * SSL_R_SHUTDOWN_WHILE_IN_INIT, and it is separate from the retry |
1113 | | * state either way. */ |
1114 | 0 | WOLFSSL_ERROR(NOT_READY_ERROR); |
1115 | 0 | ret = WOLFSSL_FATAL_ERROR; |
1116 | 0 | } |
1117 | 0 | else if (ssl->options.quietShutdown) { |
1118 | 0 | WOLFSSL_MSG("quiet shutdown, no close notify sent"); |
1119 | 0 | ret = WOLFSSL_SUCCESS; |
1120 | 0 | } |
1121 | 0 | else { |
1122 | 0 | int done; |
1123 | | |
1124 | | /* Try to flush the buffer first, it might contain the alert */ |
1125 | 0 | done = wolfssl_shutdown_flush_alert(ssl, &ret); |
1126 | 0 | if (!done) { |
1127 | 0 | done = wolfssl_shutdown_send_close_notify(ssl, &ret); |
1128 | 0 | } |
1129 | |
|
1130 | | #ifdef WOLFSSL_SHUTDOWNONCE |
1131 | | if ((!done) && |
1132 | | ((ssl->options.isClosed) || (ssl->options.connReset))) { |
1133 | | /* Shutdown has already occurred. |
1134 | | * Caller is free to ignore this error. */ |
1135 | | ret = SSL_SHUTDOWN_ALREADY_DONE_E; |
1136 | | done = 1; |
1137 | | } |
1138 | | #endif |
1139 | | |
1140 | | /* wolfSSL_shutdown called again for bidirectional shutdown */ |
1141 | 0 | if ((!done) && (ssl->options.sentNotify) && |
1142 | 0 | (!ssl->options.closeNotify)) { |
1143 | 0 | ret = wolfssl_shutdown_recv_close_notify(ssl); |
1144 | 0 | } |
1145 | 0 | else if ((!done) && (!ssl->options.sentNotify) && |
1146 | 0 | (ret != WOLFSSL_SUCCESS)) { |
1147 | | /* No close_notify was sent and the exchange has not completed by |
1148 | | * other means, so it never will. Record why when nothing else |
1149 | | * has, so the caller is not left with a failure and no error to |
1150 | | * query, but keep any more specific error already set. |
1151 | | * |
1152 | | * A send can report failure without setting sentNotify and still |
1153 | | * leave the shutdown complete: SendAlert() returns a positive |
1154 | | * value when a QUIC send_alert callback fails, which is neither |
1155 | | * the success nor the negative-error case the helper checks, and |
1156 | | * the peer's close_notify may already have arrived. Leave a |
1157 | | * success decided above alone. |
1158 | | * |
1159 | | * One case is left out: being called again once the exchange has |
1160 | | * completed, with both notifies seen. Nothing has gone wrong |
1161 | | * there, so no error is recorded, and the call still reports |
1162 | | * failure. Only reachable where wolfSSL_clear() below is not |
1163 | | * compiled in to reset the flags after a success. */ |
1164 | 0 | WOLFSSL_MSG("Connection closed before close_notify was sent"); |
1165 | 0 | if (ssl->error == WOLFSSL_ERROR_NONE) { |
1166 | 0 | ssl->error = SOCKET_PEER_CLOSED_E; |
1167 | | /* Trace it as the other failing paths here do - recording the |
1168 | | * error without this leaves nothing in the error trace. */ |
1169 | 0 | WOLFSSL_ERROR(ssl->error); |
1170 | 0 | } |
1171 | 0 | ret = WOLFSSL_FATAL_ERROR; |
1172 | 0 | } |
1173 | 0 | } |
1174 | | |
1175 | | /* wolfSSL_SendUserCanceled() turned quiet shutdown off so that the |
1176 | | * close_notify it left in the output buffer could be flushed here. Give |
1177 | | * the caller's setting back once the flush has reached a decision. */ |
1178 | 0 | if ((ssl != NULL) && ssl->options.quietShutdownRestore && |
1179 | 0 | (ssl->error != WC_NO_ERR_TRACE(WANT_WRITE))) { |
1180 | 0 | ssl->options.quietShutdownRestore = 0; |
1181 | 0 | ssl->options.quietShutdown = 1; |
1182 | 0 | } |
1183 | |
|
1184 | | #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) |
1185 | | /* reset WOLFSSL structure state for possible reuse */ |
1186 | | if (ret == WOLFSSL_SUCCESS) { |
1187 | | if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { |
1188 | | WOLFSSL_MSG("could not clear WOLFSSL"); |
1189 | | ret = WOLFSSL_FATAL_ERROR; |
1190 | | } |
1191 | | } |
1192 | | #endif |
1193 | |
|
1194 | 0 | WOLFSSL_LEAVE("wolfSSL_shutdown", ret); |
1195 | |
|
1196 | 0 | return ret; |
1197 | 0 | } |
1198 | | #endif /* !NO_TLS */ |
1199 | | |
1200 | | /* Get the number of bytes of decrypted application data ready to be read. |
1201 | | * |
1202 | | * TODO This ssl parameter needs to be changed to const once our ABI checker |
1203 | | * stops flagging qualifier additions as ABI breaking. |
1204 | | * |
1205 | | * @param [in] ssl SSL/TLS object. |
1206 | | * @return Number of buffered application data bytes. |
1207 | | * @return WOLFSSL_FAILURE when ssl is NULL. |
1208 | | */ |
1209 | | WOLFSSL_ABI |
1210 | | int wolfSSL_pending(WOLFSSL* ssl) |
1211 | 0 | { |
1212 | 0 | int ret; |
1213 | |
|
1214 | 0 | WOLFSSL_ENTER("wolfSSL_pending"); |
1215 | | |
1216 | | /* Validate parameter. */ |
1217 | 0 | if (ssl == NULL) { |
1218 | 0 | ret = WOLFSSL_FAILURE; |
1219 | 0 | } |
1220 | 0 | else { |
1221 | 0 | ret = (int)ssl->buffers.clearOutputBuffer.length; |
1222 | 0 | } |
1223 | |
|
1224 | 0 | return ret; |
1225 | 0 | } |
1226 | | |
1227 | | /* Determine whether there is application data available to read. |
1228 | | * |
1229 | | * @param [in] ssl SSL/TLS object. |
1230 | | * @return 1 when there is data buffered. |
1231 | | * @return 0 when there is no data buffered. |
1232 | | * @return WOLFSSL_FAILURE when ssl is NULL. |
1233 | | */ |
1234 | | int wolfSSL_has_pending(const WOLFSSL* ssl) |
1235 | 0 | { |
1236 | 0 | int ret = 0; |
1237 | |
|
1238 | 0 | WOLFSSL_ENTER("wolfSSL_has_pending"); |
1239 | | |
1240 | | /* Validate parameter. */ |
1241 | 0 | if (ssl == NULL) { |
1242 | 0 | ret = WOLFSSL_FAILURE; |
1243 | 0 | } |
1244 | 0 | else if (ssl->buffers.clearOutputBuffer.length > 0) { |
1245 | 0 | ret = 1; |
1246 | 0 | } |
1247 | | #ifdef WOLFSSL_TLS_READ_AHEAD |
1248 | | /* Read-ahead can leave undecrypted data buffered while the socket itself |
1249 | | * has no more data. This may be a complete record or only a partial one |
1250 | | * (e.g. a coalesced read that pulled a record plus the head of the next), |
1251 | | * so a non-zero return does not guarantee wolfSSL_read() will yield |
1252 | | * application data without another socket read. Report it so a |
1253 | | * select()/poll() loop keeps draining until wolfSSL_read() reports |
1254 | | * WANT_READ, instead of stalling on buffered data. */ |
1255 | | else if (ssl->buffers.inputBuffer.length > ssl->buffers.inputBuffer.idx) { |
1256 | | ret = 1; |
1257 | | } |
1258 | | #elif defined(WOLFSSL_DTLS) |
1259 | | /* A DTLS read takes a whole datagram, which can hold more records. They |
1260 | | * may carry no application data, so wolfSSL_read() can still WANT_READ. */ |
1261 | | else if (ssl->options.dtls && |
1262 | | ssl->buffers.inputBuffer.length > ssl->buffers.inputBuffer.idx) { |
1263 | | ret = 1; |
1264 | | } |
1265 | | #endif |
1266 | |
|
1267 | 0 | return ret; |
1268 | 0 | } |
1269 | | |
1270 | | #ifndef USE_WINDOWS_API |
1271 | | #if !defined(NO_WRITEV) && !defined(NO_TLS) |
1272 | | |
1273 | | /* Write the data described by an array of iovecs to the peer. |
1274 | | * |
1275 | | * Simulates writev semantics, doesn't actually do block at a time though |
1276 | | * because of SSL_write behavior and because front adds may be small. The |
1277 | | * segments are gathered into one buffer and written as a single call. |
1278 | | * |
1279 | | * @param [in, out] ssl SSL/TLS object. |
1280 | | * @param [in] iov Array of buffers to write. |
1281 | | * @param [in] iovcnt Number of entries in iov. |
1282 | | * @return Number of bytes written on success. |
1283 | | * @return BAD_FUNC_ARG when ssl is NULL, iovcnt is negative, or iov is |
1284 | | * NULL with a non-zero iovcnt. |
1285 | | * @return BUFFER_E when the total length of the segments overflows. |
1286 | | * @return MEMORY_ERROR when the gather buffer cannot be allocated. |
1287 | | * @return WOLFSSL_FATAL_ERROR when the write fails. Call wolfSSL_get_error() |
1288 | | * for the reason. |
1289 | | */ |
1290 | | int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt) |
1291 | 0 | { |
1292 | | #ifdef WOLFSSL_SMALL_STACK |
1293 | | byte staticBuffer[1]; /* force heap usage */ |
1294 | | #else |
1295 | 0 | byte staticBuffer[FILE_BUFFER_SIZE]; |
1296 | 0 | #endif |
1297 | 0 | byte* myBuffer = staticBuffer; |
1298 | 0 | int dynamic = 0; |
1299 | 0 | size_t sending = 0; |
1300 | 0 | size_t idx = 0; |
1301 | 0 | int i; |
1302 | 0 | int ret = 0; |
1303 | |
|
1304 | 0 | WOLFSSL_ENTER("wolfSSL_writev"); |
1305 | | |
1306 | | /* Validate parameters before anything is read from the object. */ |
1307 | 0 | if ((ssl == NULL) || ((iov == NULL) && (iovcnt != 0)) || (iovcnt < 0)) { |
1308 | 0 | ret = BAD_FUNC_ARG; |
1309 | 0 | } |
1310 | | |
1311 | | /* Total up the length being sent, checking for overflow. */ |
1312 | 0 | for (i = 0; (ret == 0) && (i < iovcnt); i++) { |
1313 | 0 | if (!WC_SAFE_SUM_UNSIGNED(size_t, sending, iov[i].iov_len, sending)) { |
1314 | 0 | ret = BUFFER_E; |
1315 | 0 | } |
1316 | 0 | } |
1317 | | |
1318 | | /* Gather into the stack buffer, or the heap when it doesn't fit. Small |
1319 | | * stack builds have a one byte buffer, so always take the heap. */ |
1320 | 0 | if ((ret == 0) && (sending > sizeof(staticBuffer))) { |
1321 | 0 | myBuffer = (byte*)XMALLOC(sending, ssl->heap, DYNAMIC_TYPE_WRITEV); |
1322 | 0 | if (myBuffer == NULL) { |
1323 | 0 | ret = MEMORY_ERROR; |
1324 | 0 | } |
1325 | 0 | else { |
1326 | 0 | dynamic = 1; |
1327 | 0 | } |
1328 | 0 | } |
1329 | |
|
1330 | 0 | if (ret == 0) { |
1331 | | /* The loop below writes exactly the span that is read, but the |
1332 | | * compiler cannot see that. When wolfSSL_write_internal() is inlined |
1333 | | * here, the warning is reported against the SendData() call inside |
1334 | | * it rather than against the call below, and a diagnostic pragma |
1335 | | * only applies at the line the warning is reported on - so the one |
1336 | | * below cannot reach it. A definite store does. Do not remove: it is |
1337 | | * what keeps -Wmaybe-uninitialized quiet on builds that inline this, |
1338 | | * such as a powerpc64 cross build at -O2. */ |
1339 | 0 | myBuffer[0] = 0; |
1340 | |
|
1341 | 0 | for (i = 0; i < iovcnt; i++) { |
1342 | 0 | XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len); |
1343 | 0 | idx += iov[i].iov_len; |
1344 | 0 | } |
1345 | | |
1346 | | /* Covers the warning when it is reported against the call itself |
1347 | | * instead, which is where it lands when there is no inlining. */ |
1348 | 0 | PRAGMA_GCC_DIAG_PUSH |
1349 | 0 | PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") |
1350 | 0 | ret = wolfSSL_write_internal(ssl, myBuffer, sending); |
1351 | 0 | PRAGMA_GCC_DIAG_POP |
1352 | 0 | } |
1353 | | |
1354 | | /* Only set when the allocation above succeeded, so ssl is not NULL. */ |
1355 | 0 | if (dynamic) { |
1356 | 0 | XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV); |
1357 | 0 | } |
1358 | |
|
1359 | 0 | return ret; |
1360 | 0 | } |
1361 | | #endif |
1362 | | #endif |
1363 | | |
1364 | | #ifdef OPENSSL_EXTRA |
1365 | | /* Get the I/O operation the SSL/TLS object is waiting on. |
1366 | | * |
1367 | | * @param [in] ssl SSL/TLS object. |
1368 | | * @return WOLFSSL_READING when waiting for the transport to be readable. |
1369 | | * @return WOLFSSL_WRITING when waiting for the transport to be writable. |
1370 | | * @return WOLFSSL_NOTHING when not waiting on the transport or ssl is NULL. |
1371 | | */ |
1372 | | int wolfSSL_want(WOLFSSL* ssl) |
1373 | | { |
1374 | | int rw_state = WOLFSSL_NOTHING; |
1375 | | |
1376 | | if (ssl != NULL) { |
1377 | | if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) { |
1378 | | rw_state = WOLFSSL_READING; |
1379 | | } |
1380 | | else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) { |
1381 | | rw_state = WOLFSSL_WRITING; |
1382 | | } |
1383 | | } |
1384 | | |
1385 | | return rw_state; |
1386 | | } |
1387 | | #endif |
1388 | | |
1389 | | /* Determine whether the last operation is waiting for the transport to be |
1390 | | * readable. |
1391 | | * |
1392 | | * @param [in] ssl SSL/TLS object. |
1393 | | * @return 1 when the current error is want read. |
1394 | | * @return 0 otherwise, including when ssl is NULL. |
1395 | | */ |
1396 | | int wolfSSL_want_read(WOLFSSL* ssl) |
1397 | 0 | { |
1398 | 0 | int ret = 0; |
1399 | |
|
1400 | 0 | WOLFSSL_ENTER("wolfSSL_want_read"); |
1401 | |
|
1402 | 0 | if ((ssl != NULL) && (ssl->error == WC_NO_ERR_TRACE(WANT_READ))) { |
1403 | 0 | ret = 1; |
1404 | 0 | } |
1405 | |
|
1406 | 0 | return ret; |
1407 | 0 | } |
1408 | | |
1409 | | /* Determine whether the last operation is waiting for the transport to be |
1410 | | * writable. |
1411 | | * |
1412 | | * @param [in] ssl SSL/TLS object. |
1413 | | * @return 1 when the current error is want write. |
1414 | | * @return 0 otherwise, including when ssl is NULL. |
1415 | | */ |
1416 | | int wolfSSL_want_write(WOLFSSL* ssl) |
1417 | 0 | { |
1418 | 0 | int ret = 0; |
1419 | |
|
1420 | 0 | WOLFSSL_ENTER("wolfSSL_want_write"); |
1421 | |
|
1422 | 0 | if ((ssl != NULL) && (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE))) { |
1423 | 0 | ret = 1; |
1424 | 0 | } |
1425 | |
|
1426 | 0 | return ret; |
1427 | 0 | } |
1428 | | |
1429 | | /* Get the shutdown state of the connection. |
1430 | | * |
1431 | | * @param [in] ssl SSL/TLS object. |
1432 | | * @return Bit set of WOLFSSL_SENT_SHUTDOWN and WOLFSSL_RECEIVED_SHUTDOWN. |
1433 | | * @return 0 when ssl is NULL or no close_notify has been sent or received. |
1434 | | */ |
1435 | | int wolfSSL_get_shutdown(const WOLFSSL* ssl) |
1436 | 0 | { |
1437 | 0 | int isShutdown = 0; |
1438 | |
|
1439 | 0 | WOLFSSL_ENTER("wolfSSL_get_shutdown"); |
1440 | |
|
1441 | 0 | if (ssl != NULL) { |
1442 | | #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) |
1443 | | if (ssl->options.shutdownDone) { |
1444 | | /* The SSL object was possibly cleared with wolfSSL_clear after |
1445 | | * a successful shutdown. Simulate a response for a full |
1446 | | * bidirectional shutdown. */ |
1447 | | isShutdown = WOLFSSL_SENT_SHUTDOWN | WOLFSSL_RECEIVED_SHUTDOWN; |
1448 | | } |
1449 | | else |
1450 | | #endif |
1451 | 0 | { |
1452 | | /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * |
1453 | | * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ |
1454 | 0 | if (ssl->options.sentNotify) { |
1455 | 0 | isShutdown |= WOLFSSL_SENT_SHUTDOWN; |
1456 | 0 | } |
1457 | 0 | if ((ssl->options.closeNotify) || (ssl->options.connReset)) { |
1458 | 0 | isShutdown |= WOLFSSL_RECEIVED_SHUTDOWN; |
1459 | 0 | } |
1460 | 0 | } |
1461 | 0 | } |
1462 | |
|
1463 | 0 | WOLFSSL_LEAVE("wolfSSL_get_shutdown", isShutdown); |
1464 | 0 | return isShutdown; |
1465 | 0 | } |
1466 | | |
1467 | | #endif /* !WOLFCRYPT_ONLY */ |
1468 | | |
1469 | | #endif /* !WOLFSSL_SSL_API_RW_INCLUDED */ |