SSL_READ(3)
π SSL_READ(3) β your girl's guide to reading bytes off a TLS connection π
okay so real talk, this is the SSL_READ(3) manual page from the Library Functions Manual, and it's literally about SSL_read_ex, SSL_read, SSL_peek_ex, and SSL_peek β the whole squad that pulls bytes out of a TLS connection. grab a strawberry drink bestie, we're going in π
β¨ NAME β¨
SSL_read_ex, SSL_read, SSL_peek_ex, SSL_peek β read bytes from a TLS connection π¦
πΈ SYNOPSIS πΈ
okay so first things first, you gotta pull in the library. it says library βlibsslβ libcrypto and:
#include <openssl/ssl.h>
then the four icons themselves:
int
SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
int
SSL_read(SSL *ssl, void *buf, int num);
int
SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
int
SSL_peek(SSL *ssl, void *buf, int num);
like, look at them. so uniform. so clean. main character energy honestly π
π DESCRIPTION π
okay so SSL_read_ex() and SSL_read() try to read num bytes from the specified ssl into the buffer buf. and on success, SSL_read_ex() stores the number of bytes actually read into *readbytes (because you deserve to know the receipts, bestie π
).
now SSL_peek_ex() and SSL_peek() are literally identical to SSL_read_ex() and SSL_read() respectively, EXCEPT β and this is the vibe β no bytes are removed from the underlying BIO during the read. so a subsequent call to SSL_read_ex() or SSL_read() will yield at least the same bytes once again. it's giving "look but don't touch" π
and for the rest of this page, SSL_read_ex(), SSL_read(), SSL_peek_ex(), and SSL_peek() all get called the "read functions". a little group name, cute, we love a collective noun π«Ά
so, if necessary, a read function will negotiate a TLS session, if that wasn't already explicitly done by SSL_connect(3) or SSL_accept(3). and if the peer requests a re-negotiation? it will be performed transparently during the read function operation. like it just happens behind the scenes, no drama. the behaviour of the read functions depends on the underlying BIO tho β important π―
for that transparent negotiation to actually succeed, the ssl must have been initialized to client or server mode. this is done by calling SSL_set_connect_state(3) or SSL_set_accept_state(3) before the first call to a read function. do not skip this step bestie, I'm begging π
π§ how the read functions actually work (the record tea) β
okay so the read functions work based on the TLS records. the data are received in records β with a maximum record size of 16kB β and only when a record has been completely received can it be processed (decrypted and checked for integrity). no partial processing, no cutting corners, she's thorough π
so, therefore:
- data that was not retrieved at the last read call can still be buffered inside the TLS layer, and will be retrieved on the next read call.
- if
numis higher than the number of bytes buffered, the read functions will return with the bytes buffered. - if no more bytes are in the buffer, the read functions will trigger the processing of the next record.
- only when the record has been received and processed completely will the read functions return reporting success.
- at most the contents of the record will be returned.
and here's the part that lowkey trips people up: as the size of a TLS record may exceed the maximum packet size of the underlying transport (e.g., TCP), it may be necessary to read several packets from the transport layer before the record is complete and the read call can succeed. so yeah, one read call β one packet. iykyk π
π blocking vs non-blocking BIOs π
if the underlying BIO is blocking: a read function will only return once the read operation has been finished or an error occurred β except when a renegotiation takes place, in which case an SSL_ERROR_WANT_READ may occur. this behavior can be controlled with the SSL_MODE_AUTO_RETRY flag of the SSL_CTX_set_mode(3) call. noted. written down. memorized β¨
if the underlying BIO is non-blocking: a read function will also return when the underlying BIO could not satisfy the needs of the function to continue the operation. in that case, a call to SSL_get_error(3) with the return value of the read function will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
and because at any time a re-negotiation is possible, a read function may also cause write operations. yes, a read function writing. she contains multitudes π the calling process must then repeat the call after taking appropriate action to satisfy the needs of the read function. and that action depends on the underlying BIO:
- when using a non-blocking socket, nothing is to be done β but
select(2)can be used to check for the required condition. - when using a buffering
BIO, like aBIOpair, data must be written into or retrieved out of theBIObefore being able to continue.
π the pending-bytes cheat code π
SSL_pending(3) can be used to find out whether there are buffered bytes available for immediate retrieval. in that case a read function can be called without blocking or actually receiving new data from the underlying socket. obsessed with her, honestly π₯
β οΈ ok important rule bestie: when a read function operation has to be repeated because ofSSL_ERROR_WANT_READorSSL_ERROR_WANT_WRITE, it must be repeated with the same arguments. same args, every time. no switching it up mid-retry π
π RETURN VALUES π
SSL_read_ex() and SSL_peek_ex() return 1 for success or 0 for failure.
- success means one or more application data bytes have been read from the SSL connection π
- failure means no bytes could be read from the SSL connection.
and failures can be retryable (e.g. we are waiting for more bytes to be delivered by the network) or non-retryable (e.g. a fatal network error). in the event of a failure, call SSL_get_error(3) to find out the reason, which indicates whether the call is retryable or not. she'll tell you the truth π«Ά
for SSL_read() and SSL_peek(), the following return values can occur:
>0β the read operation was successful. the return value is the number of bytes actually read from the TLS connection. slay π0β the read operation was not successful. the reason may either be a clean shutdown due to a "close notify" alert sent by the peer (in which case theSSL_RECEIVED_SHUTDOWNflag in thesslshutdown state is set β seeSSL_shutdown(3)andSSL_set_shutdown(3)). it is also possible that the peer simply shut down the underlying transport and the shutdown is incomplete. callSSL_get_error(3)with the return value to find out whether an error occurred or the connection was shut down cleanly (SSL_ERROR_ZERO_RETURN). π<0β the read operation was not successful, because either an error occurred or action must be taken by the calling process. callSSL_get_error(3)with the return value to find out the reason. π
π¦ SEE ALSO π¦
the whole friend group, in alphabetical order because we're classy:
BIO_new(3), ssl(3), SSL_accept(3), SSL_connect(3), SSL_CTX_new(3), SSL_CTX_set_mode(3), SSL_get_error(3), SSL_pending(3), SSL_set_connect_state(3), SSL_set_shutdown(3), SSL_shutdown(3), SSL_write(3)
π HISTORY π
SSL_read() appeared in SSLeay 0.4 or earlier. SSL_peek() first appeared in SSLeay 0.6.6. both functions have been available since OpenBSD 2.4. like, ancient. elders. icons. periodt π
SSL_read_ex() and SSL_peek_ex() first appeared in OpenSSL 1.1.1 and have been available since OpenBSD 7.1. the newer girls on the block, and they ate π
and that's the page bestie!! this one's from Debian, dated June 8, 2025, and it's the SSL_READ(3) page from the Library Functions Manual β go forth, read your bytes, repeat your calls with the same arguments, and remember: SSL_get_error(3) is always there for you ππβ¨
π¦ where this page comes from
- alpine 3.24: libressl-doc 4.3.1-r0 Β· custom
- arch rolling: libressl 4.4.0-1 Β· ISC AND custom:OpenSSL
- Copyright (c) 2000, 2001, 2008, 2016 The OpenSSL Project
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms