TLS_READ(3)

πŸ“¦ version 4.1.0, in opensuse-leap 16.0

πŸ’… TLS_READ(3) β€” use a TLS connection πŸ’…

okay bestie, welcome to the Library Functions Manual page for TLS_READ(3) β€” this is the whole group chat for using a TLS connection: reading, writing, handshaking, checking errors, and closing things out. no cap, every detail is staying. 🫢


🌸 NAME 🌸

tls_read, tls_write, tls_handshake, tls_error, tls_close β€” use a TLS connection. πŸ’–

✨ SYNOPSIS ✨

#include <tls.h>

ssize_t
tls_read(struct tls *ctx, void *buf, size_t buflen);

ssize_t
tls_write(struct tls *ctx, const void *buf, size_t buflen);

int
tls_handshake(struct tls *ctx);

const char *
tls_error(struct tls *ctx);

int
tls_close(struct tls *ctx);

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so here’s the vibe check on each one:

  • tls_read() β€” reads buflen bytes of data from the socket into buf. it returns the amount of data read. πŸ’–
  • tls_write() β€” writes buflen bytes of data from buf to the socket. it returns the amount of data written. ✨
  • tls_handshake() β€” explicitly performs the TLS handshake. it is only necessary to call this function if you need to guarantee that the handshake has completed, because both tls_read() and tls_write() automatically perform the TLS handshake when necessary. no extra handshaking needed otherwise, iykyk. 🫢
  • tls_error() β€” may be used to retrieve a string containing more information about the most recent error relating to a context. πŸŽ€
  • tls_close() β€” closes a connection after use. only the TLS layer will be shut down, and the caller is responsible for closing the file descriptors, unless the connection was established using tls_connect(3) or tls_connect_servername(3). after closing the connection, ctx can be passed to tls_free(3). πŸ’…

🌈 RETURN VALUES 🌈

  • tls_read() and tls_write() return a size on success or -1 on error. πŸ“
  • tls_handshake() and tls_close() return 0 on success or -1 on error. ✨

the tls_read(), tls_write(), tls_handshake(), and tls_close() functions also have two special return values:

  • TLS_WANT_POLLIN β€” the underlying read file descriptor needs to be readable in order to continue. πŸ‘€
  • TLS_WANT_POLLOUT β€” the underlying write file descriptor needs to be writeable in order to continue. ✍️

in the case of blocking file descriptors, the same function call should be repeated immediately. in the case of non-blocking file descriptors, the same function call should be repeated when the required condition has been met. πŸ”

callers of these functions cannot rely on the value of the global errno. to prevent mishandling of error conditions, tls_read(), tls_write(), tls_handshake(), and tls_close() all explicitly clear errno. 🚨

tls_error() returns NULL if no error occurred with ctx during or since the last call to tls_handshake(), tls_read(), tls_write(), tls_close(), or tls_reset(3) involving ctx, or if memory allocation failed while trying to assemble the string describing the most recent error related to ctx. 😭

🧚 EXAMPLES 🧚

the following example demonstrates how to handle TLS writes on a blocking file descriptor:

...
while (len > 0) {
        ssize_t ret;

        ret = tls_write(ctx, buf, len);
        if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
                continue;
        if (ret == -1)
                errx(1, "tls_write: %s", tls_error(ctx));
        buf += ret;
        len -= ret;
}
...

the following example demonstrates how to handle TLS writes on a non-blocking file descriptor using poll(2):

...
pfd[0].fd = fd;
pfd[0].events = POLLIN|POLLOUT;
while (len > 0) {
        nready = poll(pfd, 1, 0);
        if (nready == -1)
                err(1, "poll");
        if ((pfd[0].revents & (POLLERR|POLLNVAL)))
                errx(1, "bad fd %d", pfd[0].fd);
        if ((pfd[0].revents & (pfd[0].events|POLLHUP))) {
                ssize_t ret;

                ret = tls_write(ctx, buf, len);
                if (ret == TLS_WANT_POLLIN)
                        pfd[0].events = POLLIN;
                else if (ret == TLS_WANT_POLLOUT)
                        pfd[0].events = POLLOUT;
                else if (ret == -1)
                        errx(1, "tls_write: %s", tls_error(ctx));
                else {
                        buf += ret;
                        len -= ret;
                }
        }
}
...

πŸŽ€ SEE ALSO πŸŽ€

tls_accept_socket(3), tls_configure(3), tls_conn_version(3), tls_connect(3), tls_init(3), tls_ocsp_process_response(3) β€” go read those too, bestie. πŸ’–

⭐ HISTORY ⭐

  • tls_read(), tls_write(), tls_error(), and tls_close() appeared in OpenBSD 5.6 and got their final names in OpenBSD 5.7. πŸ‘‘
  • tls_handshake() appeared in OpenBSD 5.9. πŸ¦‹

πŸ’œ AUTHORS πŸ’œ

Joel Sing <jsing@openbsd.org> with contributions from Bob Beck <beck@openbsd.org>. iconic. πŸ’…

πŸ’€ CAVEATS πŸ’€

okay bestie, this is the important warning part: the function tls_error() returns an internal pointer. it must not be freed by the application, or a double free error will occur. the pointer will become invalid when the next error occurs with ctx. consequently, if the application may need the message at a later time, it has to copy the string before calling the next libtls function involving ctx, or a segmentation fault or read access to unintended data is the likely result. 😭

πŸ’– that’s the whole page, bestie β€” brought to you by Debian, dated September 18, 2023. now go handle those TLS connections with main character energy. periodt. πŸŽ€βœ¨

πŸ“¦ where this page comes from
  • opensuse-leap 16.0: libressl-devel-doc 4.1.0-bp160.1.1 Β· OpenSSL
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms