mod common;
pub use common::{CertVerdict, CertVerify, ProtocolVersion, VerifyCallback};
pub(crate) mod pc_roots;
pub(crate) mod client_auth;
pub(crate) use client_auth::{cipher_names_to_ids, parse_pinned_pubkey};
#[cfg(feature = "rustls-tls")]
mod rustls;
#[cfg(feature = "rustls-tls")]
use rustls as backend;
#[cfg(all(feature = "purecrypto-tls", not(feature = "rustls-tls")))]
mod purecrypto;
#[cfg(all(feature = "purecrypto-tls", not(feature = "rustls-tls")))]
use purecrypto as backend;
#[cfg(not(any(feature = "purecrypto-tls", feature = "rustls-tls")))]
compile_error!(
"rsurl: no TLS backend enabled. Enable either `purecrypto-tls` \
(default) or `rustls-tls`."
);
#[cfg(any(feature = "purecrypto-tls", feature = "rustls-tls"))]
pub use backend::{
connect_over, connect_over_tls, connect_over_with_alpn, load_roots_from_dir,
load_roots_from_file, RootCertStore, TlsConn, TlsOpts, TlsStream,
};
pub(crate) fn reject_pipelined_plaintext(
proto: &str,
buffer_empty: bool,
) -> crate::error::Result<()> {
if buffer_empty {
Ok(())
} else {
Err(crate::error::Error::BadResponse(format!(
"{proto}: server pipelined plaintext before the TLS handshake (STARTTLS injection)"
)))
}
}
#[cfg(feature = "rustls-tls")]
pub(crate) fn build_client_engine(
sni: &str,
opts: &mut TlsOpts,
) -> crate::error::Result<crate::proto::tls::RustlsEngine> {
Ok(crate::proto::tls::RustlsEngine(backend::build_client_conn(
sni, opts,
)?))
}
#[cfg(all(feature = "purecrypto-tls", not(feature = "rustls-tls")))]
pub(crate) fn build_client_engine(
sni: &str,
opts: &mut TlsOpts,
) -> crate::error::Result<crate::proto::tls::PurecryptoEngine> {
crate::proto::tls::PurecryptoEngine::new(backend::build_client_conn(sni, opts)?)
}
#[cfg(feature = "rustls-tls")]
pub(crate) type ClientEngine = crate::proto::tls::RustlsEngine;
#[cfg(all(feature = "purecrypto-tls", not(feature = "rustls-tls")))]
pub(crate) type ClientEngine = crate::proto::tls::PurecryptoEngine;
#[cfg(test)]
mod tests {
use super::reject_pipelined_plaintext;
use crate::error::Error;
#[test]
fn pipelined_guard_passes_on_empty_buffer() {
assert!(reject_pipelined_plaintext("imap", true).is_ok());
}
#[test]
fn pipelined_guard_rejects_buffered_plaintext() {
match reject_pipelined_plaintext("pop3", false) {
Err(Error::BadResponse(m)) => {
assert!(m.contains("pop3"));
assert!(m.contains("STARTTLS injection"));
}
other => panic!("expected BadResponse, got {other:?}"),
}
}
}