blob: 3d5c2081724a0e8761900372638db44b2cc8ea7d [file]
// Copyright 2026 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use bssl_x509::params::Trust;
use crate::tests::dumb_server_client;
#[cfg(unix)]
#[test]
fn stdio() {
use std::io::{Read, Write};
use crate::io::sync_io::{NoAsync, StdIoWithReactor};
let (mut server_conn, mut client_conn) = dumb_server_client().unwrap();
let (server_rx, server_tx) = std::io::pipe().unwrap();
let (client_rx, client_tx) = std::io::pipe().unwrap();
let server_rx = StdIoWithReactor::new(server_rx, NoAsync);
let server_tx = StdIoWithReactor::new(server_tx, NoAsync);
let client_rx = StdIoWithReactor::new(client_rx, NoAsync);
let client_tx = StdIoWithReactor::new(client_tx, NoAsync);
server_conn.set_split_io(client_rx, server_tx).unwrap();
client_conn.set_split_io(server_rx, client_tx).unwrap();
let thread = std::thread::spawn(move || {
let mut message = [0; 21];
// Use `std::io::Read::read_exact`
server_conn.read_exact(&mut message).unwrap();
assert_eq!(message, *b"BoringSSL is awesome!");
// Use `std::io::Write::write_all`
server_conn.write_all(b"Oh yeah definitely!").unwrap();
server_conn.established().unwrap().sync_shutdown().unwrap();
// Calling shutdown the second time does not do anything.
server_conn.established().unwrap().sync_shutdown().unwrap();
});
// Use `std::io::Write::write_all`
client_conn.write_all(b"BoringSSL is awesome!").unwrap();
let mut message = [0; 19];
// Use `std::io::Read::read_exact`
client_conn.read_exact(&mut message).unwrap();
assert_eq!(message, *b"Oh yeah definitely!");
let mut message = [0; 1];
// We might race with the peer closing, so let's just try to read something
// out and we do not care the status of the read in the end.
let _ = client_conn.read(&mut message);
thread.join().unwrap();
}
#[cfg(feature = "std")]
#[test]
fn high_level_sync() -> Result<(), crate::errors::Error> {
use crate::context::TlsContextBuilder;
use crate::credentials::{Certificate, TlsCredentialBuilder};
use crate::tests::{CA, RSA_SERVER_CERT, RSA_SERVER_KEY};
use bssl_x509::certificates::X509Certificate;
use bssl_x509::keys::PrivateKey;
use bssl_x509::store::X509StoreBuilder;
use std::io::{Read, Write};
let ca = Certificate::parse_one_from_pem(CA, None)?;
let server_cert = Certificate::parse_one_from_pem(RSA_SERVER_CERT, None)?;
let server_key = PrivateKey::from_pem(RSA_SERVER_KEY, || unreachable!())?;
let mut server_ctx_builder = TlsContextBuilder::new_tls();
let server_cred = {
let mut builder = TlsCredentialBuilder::new();
builder
.with_certificate_chain(&[server_cert, ca])?
.with_private_key(server_key)?;
builder.build()
};
server_ctx_builder.with_credential(server_cred.unwrap())?;
let mut builder = TlsContextBuilder::new_tls();
let ca = X509Certificate::parse_one_from_pem(CA)?;
let store = {
let mut store = X509StoreBuilder::new();
store.set_trust(Trust::SslServer)?.add_cert(ca)?;
store.build()
};
builder.with_certificate_store(&store);
let connector = builder.build_connector();
let acceptor = server_ctx_builder.build_acceptor();
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let server_thread = std::thread::spawn(move || {
let (stream, _) = listener.accept().unwrap();
let mut tls_stream = acceptor.accept(stream).unwrap();
let mut buf = [0; 5];
tls_stream.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"hello");
tls_stream.write_all(b"world").unwrap();
tls_stream.flush().unwrap();
});
let stream = std::net::TcpStream::connect(addr).unwrap();
let mut tls_stream = connector.connect("www.google.com", stream).unwrap();
tls_stream.write_all(b"hello").unwrap();
tls_stream.flush().unwrap();
let mut buf = [0; 5];
tls_stream.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"world");
server_thread.join().unwrap();
Ok(())
}
#[cfg(unix)]
#[test]
fn abrupt_transport_eof_is_unexpected_eof() {
use std::io::Read;
use crate::ReceiveBuffer;
use crate::errors::{Error, IoError};
use crate::io::sync_io::{NoAsync, StdIoWithReactor};
let (mut server_conn, mut client_conn) = dumb_server_client().unwrap();
let (server_rx, server_tx) = std::io::pipe().unwrap();
let (client_rx, client_tx) = std::io::pipe().unwrap();
let server_rx = StdIoWithReactor::new(server_rx, NoAsync);
let server_tx = StdIoWithReactor::new(server_tx, NoAsync);
let client_rx = StdIoWithReactor::new(client_rx, NoAsync);
let client_tx = StdIoWithReactor::new(client_tx, NoAsync);
server_conn.set_split_io(client_rx, server_tx).unwrap();
client_conn.set_split_io(server_rx, client_tx).unwrap();
let thread = std::thread::spawn(move || {
server_conn.accept().unwrap();
// Drop the server connection abruptly without sending close_notify.
drop(server_conn);
});
client_conn.connect().unwrap();
thread.join().unwrap();
// At the connection level, `sync_read` must report `Err(Error::Io(IoError::EndOfStream))`,
// not `Ok(IoStatus::EndOfStream)`.
let mut buf = [0u8; 16];
let mut recv_buf = ReceiveBuffer::new(&mut buf);
assert!(matches!(
client_conn.poll_read(&mut recv_buf),
Err(Error::Io(IoError::EndOfStream))
));
// Through `std::io::Read`, this translates into `io::ErrorKind::UnexpectedEof`.
let err = Read::read(&mut client_conn, &mut buf).unwrap_err();
assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
}