Skip to content

Commit 6c6de6b

Browse files
committed
account: support default client w/ custom root
1 parent aee2e80 commit 6c6de6b

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ categories = ["web-programming", "api-bindings"]
1515
default = ["aws-lc-rs", "hyper-rustls"]
1616
aws-lc-rs = ["dep:aws-lc-rs", "hyper-rustls?/aws-lc-rs", "rcgen/aws_lc_rs"]
1717
fips = ["aws-lc-rs", "aws-lc-rs?/fips"]
18-
hyper-rustls = ["dep:hyper", "dep:hyper-rustls", "dep:hyper-util"]
18+
hyper-rustls = ["dep:hyper", "dep:hyper-rustls", "dep:hyper-util", "dep:rustls"]
1919
rcgen = ["dep:rcgen"]
2020
ring = ["dep:ring", "hyper-rustls?/ring", "rcgen/ring"]
2121
time = ["dep:time"]
@@ -35,6 +35,7 @@ hyper-rustls = { version = "0.27.7", default-features = false, features = ["http
3535
hyper-util = { version = "0.1.5", features = ["client", "client-legacy", "http1", "http2", "tokio"], optional = true }
3636
rcgen = { version = "0.14", default-features = false, features = ["pem"], optional = true }
3737
ring = { version = "0.17", features = ["std"], optional = true }
38+
rustls = { version = "0.23", default-features = false, optional = true }
3839
rustls-pki-types = "1.1.0"
3940
serde = { version = "1.0.104", features = ["derive"] }
4041
serde_json = "1.0.78"

src/account.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(feature = "hyper-rustls")]
2+
use std::path::Path;
13
use std::sync::Arc;
24
#[cfg(feature = "time")]
35
use std::time::{Duration, SystemTime};
@@ -6,6 +8,12 @@ use base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine};
68
use http::header::LOCATION;
79
#[cfg(feature = "time")]
810
use http::{Method, Request};
11+
#[cfg(feature = "hyper-rustls")]
12+
use rustls::RootCertStore;
13+
#[cfg(feature = "hyper-rustls")]
14+
use rustls_pki_types::CertificateDer;
15+
#[cfg(feature = "hyper-rustls")]
16+
use rustls_pki_types::pem::PemObject;
917
use rustls_pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
1018
use serde::de::DeserializeOwned;
1119
use serde::{Deserialize, Serialize};
@@ -48,6 +56,26 @@ impl Account {
4856
})
4957
}
5058

59+
/// Create an account builder with an HTTP client configured using a custom root CA
60+
///
61+
/// This is useful if your ACME server uses a testing PKI and not a certificate
62+
/// chain issued by a publicly trusted CA.
63+
#[cfg(feature = "hyper-rustls")]
64+
pub fn builder_with_root(pem_path: impl AsRef<Path>) -> Result<AccountBuilder, Error> {
65+
let root_der = match CertificateDer::from_pem_file(pem_path) {
66+
Ok(root_der) => root_der,
67+
Err(err) => return Err(Error::Other(err.into())),
68+
};
69+
70+
let mut roots = RootCertStore::empty();
71+
match roots.add(root_der) {
72+
Ok(()) => Ok(AccountBuilder {
73+
http: Box::new(DefaultClient::with_roots(roots)?),
74+
}),
75+
Err(err) => Err(Error::Other(err.into())),
76+
}
77+
}
78+
5179
/// Create an account builder with the given HTTP client
5280
pub fn builder_with_http(http: Box<dyn HttpClient>) -> AccountBuilder {
5381
AccountBuilder { http }

src/lib.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ use httpdate::HttpDate;
2323
#[cfg(feature = "hyper-rustls")]
2424
use hyper::body::Incoming;
2525
#[cfg(feature = "hyper-rustls")]
26+
use hyper_rustls::HttpsConnectorBuilder;
27+
#[cfg(feature = "hyper-rustls")]
28+
use hyper_rustls::builderstates::WantsSchemes;
29+
#[cfg(feature = "hyper-rustls")]
2630
use hyper_util::client::legacy::Client as HyperClient;
2731
#[cfg(feature = "hyper-rustls")]
2832
use hyper_util::client::legacy::connect::{Connect, HttpConnector};
@@ -195,18 +199,29 @@ struct DefaultClient(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Bo
195199
#[cfg(feature = "hyper-rustls")]
196200
impl DefaultClient {
197201
fn try_new() -> Result<Self, Error> {
198-
Ok(Self(
199-
HyperClient::builder(TokioExecutor::new()).build(
200-
hyper_rustls::HttpsConnectorBuilder::new()
201-
.try_with_platform_verifier()
202-
.map_err(|e| Error::Other(Box::new(e)))?
203-
.https_only()
204-
.enable_http1()
205-
.enable_http2()
206-
.build(),
202+
Ok(Self::new(
203+
hyper_rustls::HttpsConnectorBuilder::new()
204+
.try_with_platform_verifier()
205+
.map_err(|e| Error::Other(Box::new(e)))?,
206+
))
207+
}
208+
209+
fn with_roots(roots: rustls::RootCertStore) -> Result<Self, Error> {
210+
Ok(Self::new(
211+
hyper_rustls::HttpsConnectorBuilder::new().with_tls_config(
212+
rustls::ClientConfig::builder()
213+
.with_root_certificates(roots)
214+
.with_no_client_auth(),
207215
),
208216
))
209217
}
218+
219+
fn new(builder: HttpsConnectorBuilder<WantsSchemes>) -> Self {
220+
Self(
221+
HyperClient::builder(TokioExecutor::new())
222+
.build(builder.https_only().enable_http1().enable_http2().build()),
223+
)
224+
}
210225
}
211226

212227
#[cfg(feature = "hyper-rustls")]

0 commit comments

Comments
 (0)