openssl/openssl
BIO
Active contributors: Matt Caswell, Tomas Mraz, Pauli, Richard Levitte, Bob Beck
Purpose
BIO is OpenSSL's I/O abstraction. A single BIO_* API works over files, sockets, in-memory buffers, base64 wrappers, encryption wrappers, ASN.1 wrappers, SSL connections, and chains of any of the above. Every API in OpenSSL that does I/O takes a BIO * rather than a FILE * or a file descriptor.
The abstraction predates the project; it has been load-bearing since the SSLeay era and is used by libssl to interface with the network.
Directory layout
crypto/bio/
├── bio_lib.c -- the BIO core (read/write/ctrl dispatch, BIO chains)
├── bio_meth.c -- BIO_METHOD allocator (custom BIO types)
├── bio_addr.c -- BIO_ADDR (sockaddr abstraction)
├── bio_dump.c -- hexdump helper
├── bio_print.c -- BIO_printf
├── bio_sock.c, bio_sock2.c -- socket helpers
├── bio_err.c -- BIO_R_* reasons
├── bf_*.c -- filter BIOs (bf_buff.c, bf_lbuf.c, bf_nbio.c, bf_null.c, bf_prefix.c, bf_readbuff.c)
├── bss_*.c -- source/sink BIOs (bss_acpt.c, bss_bio.c, bss_conn.c, bss_core.c, bss_dgram.c, bss_dgram_pair.c, bss_fd.c, bss_file.c, bss_log.c, bss_mem.c, bss_null.c, bss_sock.c)
└── bio_local.hKey abstractions
| Type | What it is |
|---|---|
BIO |
A single I/O endpoint or filter. Has read, write, ctrl, callback function pointers. |
BIO_METHOD |
A vtable. Each BIO instance points at its method. |
BIO_ADDR |
An OS-independent socket address. |
BIO_ADDRINFO |
Result of a BIO_lookup_ex. |
| Chain of BIOs | BIO_push(top, next) makes top filter into next. |
A short cheatsheet of common types:
BIO_method_*() returning a method |
Source/sink/filter | What it does |
|---|---|---|
BIO_s_mem |
source/sink | In-memory buffer |
BIO_s_file |
source/sink | FILE * |
BIO_s_fd |
source/sink | Raw file descriptor |
BIO_s_socket |
source/sink | TCP socket |
BIO_s_accept |
source | Listening TCP socket |
BIO_s_connect |
source | Connect to a host |
BIO_s_datagram |
source/sink | UDP socket |
BIO_s_dgram_pair |
source/sink | Connected pair of in-memory datagram BIOs (used by QUIC tests) |
BIO_s_null |
source/sink | /dev/null-like |
BIO_s_bio |
source/sink | Half of a BIO pair (BIO_new_bio_pair) |
BIO_s_core |
source/sink | A BIO whose I/O is delegated through provider upcalls (FIPS) |
BIO_f_buffer |
filter | Buffered I/O |
BIO_f_base64 |
filter | Base64 encode/decode |
BIO_f_cipher |
filter | EVP_CIPHER wrapping |
BIO_f_md |
filter | EVP_MD passthrough |
BIO_f_ssl |
filter | TLS/DTLS |
BIO_f_zlib / BIO_f_zstd / BIO_f_brotli |
filter | Compression |
How chains work
A BIO chain is a singly-linked list. Reads/writes pass through filters until they reach a source/sink:
graph LR
App[Application] --> B64[BIO_f_base64]
B64 --> Buf[BIO_f_buffer]
Buf --> File[BIO_s_file]To build that chain:
BIO *out = BIO_new_file("out.b64", "wb");
BIO *b64 = BIO_new(BIO_f_base64());
BIO *buf = BIO_new(BIO_f_buffer());
BIO_push(b64, BIO_push(buf, out));
BIO_write(b64, plaintext, len);
BIO_free_all(b64);BIO_free_all walks the chain.
How libssl uses BIO
A TLS connection has one or two BIOs underneath it (SSL_set_bio for symmetric, SSL_set_rbio + SSL_set_wbio for asymmetric). The TLS state machine reads ciphertext from rbio, processes it, and writes plaintext to a buffer the application reads via SSL_read. Conversely, SSL_write puts plaintext into the SSL object, which encrypts and writes ciphertext to wbio.
For DTLS, BIO_s_datagram provides the per-datagram framing. For QUIC, BIO_s_dgram_pair and BIO_s_datagram (or the application's own custom BIO) feed UDP packets.
ctrl
Most knobs on a BIO are exercised through BIO_ctrl(bio, cmd, larg, parg). The numeric cmd constants are in include/openssl/bio.h.in (BIO_C_*). Convenience wrappers exist for common operations:
BIO_set_close(bio, mode)— set whether the underlying resource is closed on free.BIO_get_fd(bio, &fd)— extract the underlying fd from a fd-/socket-based BIO.BIO_seek(bio, off),BIO_tell(bio)— for seekable types.BIO_pending(bio),BIO_wpending(bio)— bytes waiting to be read/written.BIO_set_nbio(bio, n)— switch to non-blocking.BIO_get_mem_ptr(bio, &bm)— read the underlyingBUF_MEM *of aBIO_s_mem.
Custom BIOs
Applications can build their own source/sink or filter BIOs:
BIO_METHOD *bm = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "mybio");
BIO_meth_set_write_ex(bm, my_write);
BIO_meth_set_read_ex(bm, my_read);
BIO_meth_set_ctrl(bm, my_ctrl);
BIO_meth_set_create(bm, my_create);
BIO_meth_set_destroy(bm, my_destroy);
BIO *b = BIO_new(bm);Provider-side BIOs (BIO_s_core)
When a provider needs to do I/O (e.g. read keying material from a file), libcrypto passes it a "core BIO" that delegates back to a real BIO in libcrypto via the dispatch table. This lets the FIPS provider read files via libcrypto without statically linking the file/stream code into fips.so. See providers/common/bio_prov.c.
Datagram BIOs and DTLS/QUIC
BIO_s_datagram (bss_dgram.c) wraps a UDP socket and adds:
- MTU discovery (via
BIO_CTRL_DGRAM_QUERY_MTU). - Per-packet peer addressing (via
BIO_dgram_set_peer/BIO_ADDR). - ICMP "destination unreachable" handling.
BIO_s_dgram_pair (bss_dgram_pair.c) is two in-memory datagram BIOs connected back-to-back, used by tests and the QUIC tserver harness. BIO_s_dgram_mem is its single-ended cousin.
Logging and debugging
BIO_f_prefix (bf_prefix.c) prepends a prefix to every line. bio_dump.c formats hex dumps. The trace facility (see how-to-contribute/debugging) writes through a BIO.
Integration points
libssluses BIO as its only transport. SSL_BIO is itself a filter BIO.crypto/cms/,crypto/pkcs7/,crypto/pem/use BIO chains for streaming I/O of multi-megabyte signed/encrypted blobs.crypto/http/builds its HTTP request/response on top of BIO_s_connect or a caller-supplied BIO.apps/consumes BIOs everywhere —bio_in,bio_out,bio_errinapps/openssl.care the program-wide stdin/out/err BIOs.
Entry points for modification
- New BIO type: add
bss_<name>.c(source/sink) orbf_<name>.c(filter), expose aBIO_METHOD *BIO_<x>(void)function. - New ctrl command: extend the
BIO_C_*enum inbio.h.in, add the helper, route it in the relevant BIO method. - Touching socket portability:
bio_sock.c,bio_sock2.c, pluscrypto/bio/bio_addr.c. Be mindful of the Windows / VMS / Unix split.
Documentation
doc/man3/BIO_*.pod— the API.doc/man3/BIO_new.pod,BIO_s_mem.pod,BIO_f_buffer.pod, etc.doc/man7/bio.pod— concepts.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.