From 1b23557101d16d7162ccfa5c3bd972149c9262b9 Mon Sep 17 00:00:00 2001
From: Paul Vorobyev
Date: Sun, 28 Jul 2024 21:22:26 +0000
Subject: [PATCH 1/4] Add TLS 1.2 support via configuration
---
Cargo.lock | 2 +-
Cargo.toml | 2 +-
src/client.rs | 25 +++++++++++++++++++------
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 3afe4a81..4529d9cc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,7 +4,7 @@ version = 3
[[package]]
name = "a2"
-version = "0.10.0"
+version = "0.10.1"
dependencies = [
"argparse",
"base64",
diff --git a/Cargo.toml b/Cargo.toml
index 29bdaeeb..6edc63b3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "a2"
-version = "0.10.0"
+version = "0.10.1"
authors = [
"Harry Bairstow ",
"Julius de Bruijn ",
diff --git a/src/client.rs b/src/client.rs
index 9da3c8d4..535317d4 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -69,6 +69,9 @@ pub struct ClientConfig {
pub request_timeout_secs: Option,
/// The timeout for idle sockets being kept alive
pub pool_idle_timeout_secs: Option,
+ /// We use TLS 1.3 by default, setting this to `true` overrides it to use TLS 1.2.
+ /// Defaults to `false`.
+ pub use_tls_12_override: bool,
}
impl Default for ClientConfig {
@@ -77,6 +80,7 @@ impl Default for ClientConfig {
endpoint: Endpoint::Production,
request_timeout_secs: Some(DEFAULT_REQUEST_TIMEOUT_SECS),
pool_idle_timeout_secs: Some(600),
+ use_tls_12_override: false,
}
}
}
@@ -130,6 +134,7 @@ impl ClientBuilder {
endpoint,
request_timeout_secs,
pool_idle_timeout_secs,
+ use_tls_12_override: _,
},
signer,
connector,
@@ -188,7 +193,7 @@ impl Client {
let Some((cert, pkey)) = pkcs.cert.zip(pkcs.pkey) else {
return Err(Error::InvalidCertificate);
};
- let connector = client_cert_connector(&cert.to_pem()?, &pkey.private_key_to_pem_pkcs8()?)?;
+ let connector = client_cert_connector(&cert.to_pem()?, &pkey.private_key_to_pem_pkcs8()?, &config)?;
Ok(Self::builder().connector(connector).config(config).build())
}
@@ -197,7 +202,7 @@ impl Client {
/// key, extracted from the provider client certificate you obtain from your
/// [Apple developer account](https://developer.apple.com/account/)
pub fn certificate_parts(cert_pem: &[u8], key_pem: &[u8], config: ClientConfig) -> Result {
- let connector = client_cert_connector(cert_pem, key_pem)?;
+ let connector = client_cert_connector(cert_pem, key_pem, &config)?;
Ok(Self::builder().config(config).connector(connector).build())
}
@@ -309,7 +314,11 @@ fn default_connector() -> HyperConnector {
.build()
}
-fn client_cert_connector(mut cert_pem: &[u8], mut key_pem: &[u8]) -> Result {
+fn client_cert_connector(
+ mut cert_pem: &[u8],
+ mut key_pem: &[u8],
+ client_config: &ClientConfig,
+) -> Result {
let private_key_error = || io::Error::new(io::ErrorKind::InvalidData, "private key");
let key = rustls_pemfile::pkcs8_private_keys(&mut key_pem)
@@ -320,9 +329,13 @@ fn client_cert_connector(mut cert_pem: &[u8], mut key_pem: &[u8]) -> Result, _> = rustls_pemfile::certs(&mut cert_pem).collect();
let cert_chain = cert_chain.map_err(|_| private_key_error())?;
- let config = rustls::client::ClientConfig::builder()
- .with_webpki_roots()
- .with_client_auth_cert(cert_chain, key.into())?;
+ let config = if client_config.use_tls_12_override {
+ rustls::client::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS12])
+ } else {
+ rustls::client::ClientConfig::builder()
+ }
+ .with_webpki_roots()
+ .with_client_auth_cert(cert_chain, key.into())?;
Ok(HttpsConnectorBuilder::new()
.with_tls_config(config)
From 4ea1a63cd15832b47c45cf6ddcdcda8e86f99d21 Mon Sep 17 00:00:00 2001
From: Paul Vorobyev
Date: Sun, 28 Jul 2024 21:38:39 +0000
Subject: [PATCH 2/4] Add certificate_resolver method
---
Cargo.lock | 2 +-
Cargo.toml | 2 +-
src/client.rs | 25 +++++++++++++++++++++++++
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 4529d9cc..c18bd858 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,7 +4,7 @@ version = 3
[[package]]
name = "a2"
-version = "0.10.1"
+version = "0.10.2"
dependencies = [
"argparse",
"base64",
diff --git a/Cargo.toml b/Cargo.toml
index 6edc63b3..8c639b6c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "a2"
-version = "0.10.1"
+version = "0.10.2"
authors = [
"Harry Bairstow ",
"Julius de Bruijn ",
diff --git a/src/client.rs b/src/client.rs
index 535317d4..c838633a 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -16,8 +16,10 @@ use hyper_rustls::{ConfigBuilderExt, HttpsConnector, HttpsConnectorBuilder};
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::client::legacy::Client as HttpClient;
use hyper_util::rt::TokioExecutor;
+use rustls::client::ResolvesClientCert;
use std::convert::Infallible;
use std::io::Read;
+use std::sync::Arc;
use std::time::Duration;
use std::{fmt, io};
@@ -198,6 +200,29 @@ impl Client {
Ok(Self::builder().connector(connector).config(config).build())
}
+ /// Create a connection to APNs using the provider client certificate which
+ /// you obtain from your [Apple developer
+ /// account](https://developer.apple.com/account/), chosen dynamically via
+ /// the rustls `ResolvesClientCert` trait. Prefer certificate() over this; use
+ /// this if you're using a key management service and don't have the private
+ /// key available.
+ pub fn certificate_resolver(
+ client_auth_cert_resolver: Arc,
+ config: ClientConfig,
+ ) -> Result {
+ let tls_config = rustls::client::ClientConfig::builder()
+ .with_webpki_roots()
+ .with_client_cert_resolver(client_auth_cert_resolver);
+
+ let connector = HttpsConnectorBuilder::new()
+ .with_tls_config(tls_config)
+ .https_only()
+ .enable_http2()
+ .build();
+
+ Ok(Self::builder().connector(connector).config(config).build())
+ }
+
/// Create a connection to APNs using the raw PEM-formatted certificate and
/// key, extracted from the provider client certificate you obtain from your
/// [Apple developer account](https://developer.apple.com/account/)
From f7379d9196d46ab1e51757211983b8ec25aca97b Mon Sep 17 00:00:00 2001
From: Paul Vorobyev
Date: Sun, 28 Jul 2024 22:03:24 +0000
Subject: [PATCH 3/4] Use TLS 1.2 support
---
src/client.rs | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/client.rs b/src/client.rs
index c838633a..26ee2e93 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -94,6 +94,14 @@ impl ClientConfig {
..Default::default()
}
}
+
+ pub fn get_tls_config_builder(&self) -> rustls::ConfigBuilder {
+ if self.use_tls_12_override {
+ rustls::client::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS12])
+ } else {
+ rustls::client::ClientConfig::builder()
+ }
+ }
}
#[derive(Debug, Clone)]
@@ -210,7 +218,8 @@ impl Client {
client_auth_cert_resolver: Arc,
config: ClientConfig,
) -> Result {
- let tls_config = rustls::client::ClientConfig::builder()
+ let tls_config = config
+ .get_tls_config_builder()
.with_webpki_roots()
.with_client_cert_resolver(client_auth_cert_resolver);
@@ -354,13 +363,10 @@ fn client_cert_connector(
let cert_chain: Result, _> = rustls_pemfile::certs(&mut cert_pem).collect();
let cert_chain = cert_chain.map_err(|_| private_key_error())?;
- let config = if client_config.use_tls_12_override {
- rustls::client::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS12])
- } else {
- rustls::client::ClientConfig::builder()
- }
- .with_webpki_roots()
- .with_client_auth_cert(cert_chain, key.into())?;
+ let config = client_config
+ .get_tls_config_builder()
+ .with_webpki_roots()
+ .with_client_auth_cert(cert_chain, key.into())?;
Ok(HttpsConnectorBuilder::new()
.with_tls_config(config)
From c021479dc2373ca4fb35373dea46c96b74d7cf43 Mon Sep 17 00:00:00 2001
From: Paul Vorobyev
Date: Sun, 28 Jul 2024 22:10:55 +0000
Subject: [PATCH 4/4] pub use ResolvesClientcert
---
src/client.rs | 2 +-
src/lib.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/client.rs b/src/client.rs
index 26ee2e93..c060d766 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -16,7 +16,7 @@ use hyper_rustls::{ConfigBuilderExt, HttpsConnector, HttpsConnectorBuilder};
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::client::legacy::Client as HttpClient;
use hyper_util::rt::TokioExecutor;
-use rustls::client::ResolvesClientCert;
+pub use rustls::client::ResolvesClientCert;
use std::convert::Infallible;
use std::io::Read;
use std::sync::Arc;
diff --git a/src/lib.rs b/src/lib.rs
index 513fac04..c87b841b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -131,6 +131,6 @@ pub use crate::request::notification::{
pub use crate::response::{ErrorBody, ErrorReason, Response};
-pub use crate::client::{Client, ClientConfig, Endpoint};
+pub use crate::client::{Client, ClientConfig, Endpoint, ResolvesClientCert};
pub use crate::error::Error;