pub struct Bio { /* private fields */ }Expand description
Shared ownership wrapper around a BIO*.
Used where OpenSSL takes ownership of a BIO (e.g. SSL_set_bio) or where
the same BIO must be reachable from multiple Rust values. Implemented with
BIO_up_ref / BIO_free.
Implementations§
Source§impl Bio
impl Bio
Sourcepub fn new_pair() -> Result<(Self, Self), ErrorStack>
pub fn new_pair() -> Result<(Self, Self), ErrorStack>
Create a linked in-memory BIO pair suitable for in-process TLS.
Returns (bio1, bio2) where data written to bio1 is readable from
bio2 and vice-versa. Pass each half to crate::ssl::Ssl::set_bio_duplex on
the client and server Ssl objects respectively.
§Errors
Returns Err if OpenSSL fails to allocate the pair.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 // ── Key pair and self-signed certificate ───────────────────────────────────
16
17 let mut kgen = KeygenCtx::new(c"ED25519")?;
18 let priv_key = kgen.generate()?;
19 let pub_key = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(priv_key.clone());
20
21 let mut name = X509NameOwned::new()?;
22 name.add_entry_by_txt(c"CN", b"localhost")?;
23
24 let cert = X509Builder::new()?
25 .set_version(2)?
26 .set_serial_number(1)?
27 .set_not_before_offset(0)?
28 .set_not_after_offset(86400)?
29 .set_subject_name(&name)?
30 .set_issuer_name(&name)?
31 .set_public_key(&pub_key)?
32 .sign(&priv_key, None)?
33 .build();
34
35 // ── Server context ─────────────────────────────────────────────────────────
36
37 let server_ctx = SslCtx::new_server()?;
38 server_ctx.set_min_proto_version(TlsVersion::Tls13)?;
39 server_ctx.use_certificate(&cert)?;
40 server_ctx.use_private_key(&priv_key)?;
41 server_ctx.check_private_key()?;
42
43 // ── Client context ─────────────────────────────────────────────────────────
44
45 let client_ctx = SslCtx::new_client()?;
46 client_ctx.set_min_proto_version(TlsVersion::Tls13)?;
47 // Skip certificate verification for this self-signed example.
48 client_ctx.set_verify(SslVerifyMode::NONE);
49
50 // ── SSL objects ────────────────────────────────────────────────────────────
51
52 let mut client = client_ctx.new_ssl()?;
53 let mut server = server_ctx.new_ssl()?;
54
55 client.set_connect_state();
56 client.set_hostname(c"localhost")?;
57 server.set_accept_state();
58
59 // ── In-process BIO pair ────────────────────────────────────────────────────
60 // Data written to client_bio is readable from server_bio and vice-versa.
61
62 let (client_bio, server_bio) = Bio::new_pair()?;
63 client.set_bio_duplex(client_bio);
64 server.set_bio_duplex(server_bio);
65
66 // ── Drive the handshake ────────────────────────────────────────────────────
67 // Alternate between client and server until both report success.
68
69 let mut client_done = false;
70 let mut server_done = false;
71
72 for step in 0..20 {
73 if !client_done {
74 match client.connect() {
75 Ok(()) => {
76 client_done = true;
77 println!("Client handshake done at step {step}");
78 }
79 Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
80 Err(e) => return Err(format!("client error: {e}").into()),
81 }
82 }
83 if !server_done {
84 match server.accept() {
85 Ok(()) => {
86 server_done = true;
87 println!("Server handshake done at step {step}");
88 }
89 Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
90 Err(e) => return Err(format!("server error: {e}").into()),
91 }
92 }
93 if client_done && server_done {
94 break;
95 }
96 }
97 assert!(client_done && server_done, "handshake did not complete");
98
99 // ── Inspect the peer certificate on the client ─────────────────────────────
100
101 if let Some(peer_cert) = client.peer_certificate() {
102 if let Some(subject) = peer_cert.subject_name().to_string() {
103 println!("Server cert subject: {subject}");
104 }
105 }
106
107 // ── Application data exchange ──────────────────────────────────────────────
108
109 let request = b"GET / HTTP/1.0\r\n\r\n";
110 let response = b"HTTP/1.0 200 OK\r\n\r\nHello, TLS!";
111
112 let written = client.write(request)?;
113 assert_eq!(written, request.len());
114
115 let mut rbuf = [0u8; 64];
116 let n = server.read(&mut rbuf)?;
117 assert_eq!(&rbuf[..n], request);
118 println!("Server received: {:?}", std::str::from_utf8(&rbuf[..n])?);
119
120 let written = server.write(response)?;
121 assert_eq!(written, response.len());
122
123 let n = client.read(&mut rbuf)?;
124 assert_eq!(&rbuf[..n], response);
125 println!("Client received: {:?}", std::str::from_utf8(&rbuf[..n])?);
126
127 println!("In-process TLS 1.3 round-trip: OK");
128
129 Ok(())
130}Sourcepub fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>
Read bytes from the BIO into buf.
Returns the number of bytes actually read, which may be less than
buf.len() if fewer bytes are available.
§Errors
Returns Err on I/O error or EOF (when BIO_read returns -1).
Sourcepub fn read_ex(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>
pub fn read_ex(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>
Read bytes from the BIO, reporting the exact number of bytes read.
On success returns the number of bytes placed into buf.
§Errors
Returns Err if BIO_read_ex reports failure (returns 0).
Sourcepub fn write(&mut self, buf: &[u8]) -> Result<usize, ErrorStack>
pub fn write(&mut self, buf: &[u8]) -> Result<usize, ErrorStack>
Write buf into the BIO.
Returns the number of bytes actually written.
§Errors
Returns Err on I/O error (when BIO_write returns -1).
Sourcepub fn push(self, next: Bio) -> Bio
pub fn push(self, next: Bio) -> Bio
Append next after self in the BIO chain.
Ownership of next is transferred into the chain; it must not be
freed separately. Returns self with the chain extended.
Corresponds to BIO_push(self, next).
Sourcepub fn pop(&mut self) -> Option<Bio>
pub fn pop(&mut self) -> Option<Bio>
Remove self from its chain and return the rest of the chain.
After this call self is a standalone BIO. Returns None if self
was the only (or last) element in the chain.
Corresponds to BIO_pop(self).
Sourcepub fn next(&self) -> Option<BorrowedBio<'_>>
pub fn next(&self) -> Option<BorrowedBio<'_>>
Return a borrowed view of the next BIO in the chain without consuming self.
The returned BorrowedBio is valid for the lifetime of self and does
not free the underlying pointer when dropped.
Returns None if self is the last (or only) BIO in the chain.
Corresponds to BIO_next(self).
Sourcepub fn pending(&self) -> usize
pub fn pending(&self) -> usize
Return the number of bytes available for reading from the BIO.
Corresponds to the BIO_pending C macro, implemented via
BIO_ctrl(b, BIO_CTRL_PENDING, 0, NULL).
For a mem BIO this is the number of unread bytes in the buffer. For other BIO types the value is type-specific.
Sourcepub fn wpending(&self) -> usize
pub fn wpending(&self) -> usize
Return the number of bytes still to be written (pending in the write buffer).
Corresponds to the BIO_wpending C macro, implemented via
BIO_ctrl(b, BIO_CTRL_WPENDING, 0, NULL).
For most BIO types this is 0 (writes are synchronous). For filter BIOs it reflects bytes buffered but not yet flushed downstream.
Sourcepub fn find_type(&self, bio_type: c_int) -> Option<BorrowedBio<'_>>
pub fn find_type(&self, bio_type: c_int) -> Option<BorrowedBio<'_>>
Search the chain for the first BIO of the given bio_type.
bio_type is one of the BIO_TYPE_* integer constants from OpenSSL
(e.g. BIO_TYPE_MEM = 8, BIO_TYPE_BIO = 19).
Returns a borrowed view of the matching BIO, or None if none is found.
Corresponds to BIO_find_type(self, bio_type).
§Errors
Returns None if no BIO of the requested type exists in the chain.