Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade rustls and tokio-rustls #175

Merged
merged 2 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup | Install NASM (Windows)
uses: ilammy/setup-nasm@v1
if: matrix.os == 'windows-latest'

- name: Setup | Install toolchain
run: |
rustup toolchain install stable --profile minimal
rustup toolchain install nightly --profile minimal
rustup update --no-self-update stable
rustup update --no-self-update nightly
rustup set profile minimal

- name: Setup | Install cargo-fuzz
run: |
Expand Down Expand Up @@ -101,8 +106,9 @@ jobs:
- name: Setup | Install toolchain
run: |
# 1.66 is the Minimum Supported Rust Version (MSRV) for imap-flow.
rustup toolchain install 1.66 --profile minimal
rustup toolchain install nightly --profile minimal
rustup update --no-self-update 1.66
rustup update --no-self-update nightly
rustup set profile minimal

- name: Setup | Cache dependencies
uses: Swatinem/[email protected]
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ bounded-static = "0.5.0"
bytes = "1.5.0"
imap-codec = { version = "2.0.0", features = ["quirk_crlf_relaxed", "bounded-static"] }
imap-types = { version = "2.0.0" }
rustls = { version = "0.21.11", optional = true }
rustls = { version = "0.23.1", optional = true }
thiserror = "1.0.49"
tokio = { version = "1.32.0", optional = true, features = ["io-util", "macros", "net"] }
tokio-rustls = { version = "0.24.1", optional = true }
tokio-rustls = { version = "0.26.0", optional = true }
tracing = "0.1.40"

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ allow-git = [
]

[licenses]
allow = [ "Apache-2.0", "MIT", "Unicode-DFS-2016", "ISC", "OpenSSL" ]
allow = [ "Apache-2.0", "BSD-3-Clause", "MIT", "Unicode-DFS-2016", "ISC", "OpenSSL" ]

[[licenses.clarify]]
name = "ring"
Expand Down
6 changes: 3 additions & 3 deletions proxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ colored = "2.0.4"
imap-codec = { version = "2.0.0", features = ["bounded-static", "quirk_crlf_relaxed", "ext_id"] }
imap-flow = { path = ".." }
imap-types = { version = "2.0.0", features = ["bounded-static", "ext_id"] }
rustls = "0.21.7"
once_cell = "1.19.0"
rustls-native-certs = "0.7.0"
rustls-pemfile = "2.0.0-alpha.1"
serde = { version = "1.0.171", features = ["derive"] }
thiserror = "1.0.49"
tokio = { version = "1.28", features = ["full"] }
tokio-rustls = "0.24.1"
tokio-rustls = "0.26.0"
toml = "0.8.2"
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
webpki-roots = "0.25.2"
43 changes: 19 additions & 24 deletions proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,30 @@ use imap_types::{
extensions::idle::IdleDone,
response::{Code, Status},
};
use rustls::{ClientConfig, OwnedTrustAnchor, RootCertStore, ServerName};
use once_cell::sync::Lazy;
use thiserror::Error;
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::{TlsAcceptor, TlsConnector};
use tokio_rustls::{
rustls::{pki_types::ServerName, ClientConfig, RootCertStore, ServerConfig},
TlsAcceptor, TlsConnector,
};
use tracing::{error, info, trace};

use crate::{
config::{Bind, Connect, Identity, Service},
util::{self, ControlFlow, IdentityError},
};

static ROOT_CERT_STORE: Lazy<RootCertStore> = Lazy::new(|| {
let mut root_store = RootCertStore::empty();

for cert in rustls_native_certs::load_native_certs().unwrap() {
root_store.add(cert).unwrap();
}

root_store
});

const LITERAL_ACCEPT_TEXT: &str = "proxy: Literal accepted by proxy";
const LITERAL_REJECT_TEXT: &str = "proxy: Literal rejected by proxy";
const COMMAND_REJECTED_TEXT: &str = "proxy: Command rejected by server";
Expand All @@ -35,7 +48,7 @@ pub enum ProxyError {
#[error(transparent)]
Identity(#[from] IdentityError),
#[error(transparent)]
Tls(#[from] rustls::Error),
Tls(#[from] tokio_rustls::rustls::Error),
}

pub trait State: Send + 'static {}
Expand Down Expand Up @@ -84,8 +97,7 @@ impl Proxy<BoundState> {
}
};

let mut config = rustls::ServerConfig::builder()
.with_safe_defaults()
let mut config = ServerConfig::builder()
.with_no_client_auth()
// Note: The name is misleading. We provide the full chain here.
.with_single_cert(certificate_chain, leaf_key)?;
Expand Down Expand Up @@ -134,25 +146,8 @@ impl Proxy<ClientAcceptedState> {
let proxy_to_server = match self.service.connect {
Connect::Tls { ref host, .. } => {
let config = {
let root_store = {
let mut root_store = RootCertStore::empty();

root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(
|ta| {
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
},
));

root_store
};

let mut config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_root_certificates(ROOT_CERT_STORE.clone())
.with_no_client_auth();

// See <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>
Expand All @@ -162,7 +157,7 @@ impl Proxy<ClientAcceptedState> {
};

let connector = TlsConnector::from(Arc::new(config));
let dnsname = ServerName::try_from(host.as_str()).unwrap();
let dnsname = ServerName::try_from(host.clone()).unwrap();

info!(?server_addr_port, "Starting TLS with server");
Stream::tls(connector.connect(dnsname, stream_to_server).await?.into())
Expand Down
14 changes: 8 additions & 6 deletions proxy/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use imap_types::{
Greeting, Status, StatusBody, Tagged,
},
};
use rustls::{Certificate, PrivateKey};
use thiserror::Error;
use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
use tracing::warn;

pub enum ControlFlow {
Expand Down Expand Up @@ -144,9 +144,9 @@ pub enum IdentityError {
UnexpectedKeyCount { path: String, found: usize },
}

pub fn load_certificate_chain_pem<P: AsRef<Path>>(
pub fn load_certificate_chain_pem<'a, P: AsRef<Path>>(
path: P,
) -> Result<Vec<Certificate>, IdentityError> {
) -> Result<Vec<CertificateDer<'a>>, IdentityError> {
let display_path = path.as_ref().display().to_string();

let mut reader = BufReader::new(File::open(path).map_err(|error| IdentityError::Io {
Expand All @@ -156,7 +156,7 @@ pub fn load_certificate_chain_pem<P: AsRef<Path>>(

rustls_pemfile::certs(&mut reader)
.map(|res| {
res.map(|der| Certificate(der.to_vec()))
res.map(|der| CertificateDer::from(der.to_vec()))
.map_err(|source| IdentityError::Io {
source,
path: display_path.clone(),
Expand All @@ -165,7 +165,7 @@ pub fn load_certificate_chain_pem<P: AsRef<Path>>(
.collect()
}

pub fn load_leaf_key_pem<P: AsRef<Path>>(path: P) -> Result<PrivateKey, IdentityError> {
pub fn load_leaf_key_pem<'a, P: AsRef<Path>>(path: P) -> Result<PrivateKeyDer<'a>, IdentityError> {
let display_path = path.as_ref().display().to_string();

let mut reader = BufReader::new(File::open(&path).map_err(|source| IdentityError::Io {
Expand All @@ -180,7 +180,9 @@ pub fn load_leaf_key_pem<P: AsRef<Path>>(path: P) -> Result<PrivateKey, Identity
source,
path: display_path.clone(),
})?;
keys.push(PrivateKey(key.secret_pkcs8_der().to_vec()));
keys.push(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
key.secret_pkcs8_der().to_vec(),
)));
}

match keys.len() {
Expand Down
Loading