Allow TLS client config to be overridden
See: https://docs.rs/rustls/latest/rustls/struct.ClientConfig.html
This commit is contained in:
committed by
Martin Algesten
parent
bbfd125025
commit
2e3a75166d
@@ -1,5 +1,7 @@
|
||||
use std::io::Read;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(feature = "tls")]
|
||||
use std::fmt;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use qstring::QString;
|
||||
@@ -46,6 +48,8 @@ pub struct Request {
|
||||
pub(crate) timeout_write: u64,
|
||||
pub(crate) redirects: u32,
|
||||
pub(crate) proxy: Option<crate::proxy::Proxy>,
|
||||
#[cfg(feature = "tls")]
|
||||
pub(crate) tls_config: Option<TLSClientConfig>,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for Request {
|
||||
@@ -554,4 +558,31 @@ impl Request {
|
||||
self.proxy = Some(proxy);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the TLS client config to use for the connection.
|
||||
///
|
||||
/// See [`ClientConfig`](https://docs.rs/rustls/latest/rustls/struct.ClientConfig.html).
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// let tls_config = std::sync::Arc::new(rustls::ClientConfig::new());
|
||||
/// let req = ureq::post("https://cool.server")
|
||||
/// .set_tls_config(tls_config.clone());
|
||||
/// ```
|
||||
#[cfg(feature = "tls")]
|
||||
pub fn set_tls_config(&mut self, tls_config: Arc<rustls::ClientConfig>) -> &mut Request {
|
||||
self.tls_config = Some(TLSClientConfig(tls_config));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TLSClientConfig(pub(crate) Arc<rustls::ClientConfig>);
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
impl fmt::Debug for TLSClientConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TLSClientConfig").finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,9 @@ pub(crate) fn connect_https(unit: &Unit) -> Result<Stream, Error> {
|
||||
|
||||
let sni = webpki::DNSNameRef::try_from_ascii_str(hostname)
|
||||
.map_err(|err| Error::DnsFailed(err.to_string()))?;
|
||||
let sess = rustls::ClientSession::new(&*TLS_CONF, sni);
|
||||
let tls_conf: &Arc<rustls::ClientConfig> =
|
||||
unit.tls_config.as_ref().map(|c| &c.0).unwrap_or(&*TLS_CONF);
|
||||
let sess = rustls::ClientSession::new(&tls_conf, sni);
|
||||
|
||||
let sock = connect_host(unit, hostname, port)?;
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ use crate::header;
|
||||
use crate::stream::{self, connect_https, connect_test, Stream};
|
||||
use crate::Proxy;
|
||||
use crate::{Error, Header, Request, Response};
|
||||
#[cfg(feature = "tls")]
|
||||
use crate::request::TLSClientConfig;
|
||||
|
||||
use crate::pool::DEFAULT_HOST;
|
||||
|
||||
@@ -31,6 +33,8 @@ pub(crate) struct Unit {
|
||||
pub timeout_write: u64,
|
||||
pub method: String,
|
||||
pub proxy: Option<Proxy>,
|
||||
#[cfg(feature = "tls")]
|
||||
pub tls_config: Option<TLSClientConfig>,
|
||||
}
|
||||
|
||||
impl Unit {
|
||||
@@ -89,6 +93,8 @@ impl Unit {
|
||||
timeout_write: req.timeout_write,
|
||||
method: req.method.clone(),
|
||||
proxy: req.proxy.clone(),
|
||||
#[cfg(feature = "tls")]
|
||||
tls_config: req.tls_config.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,3 +45,96 @@ fn agent_set_cookie() {
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
const BADSSL_CLIENT_CERT_PEM: &'static str = r#"Bag Attributes
|
||||
localKeyID: 41 C3 6C 33 C7 E3 36 DD EA 4A 1F C0 B7 23 B8 E6 9C DC D8 0F
|
||||
subject=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Certificate
|
||||
|
||||
issuer=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Root Certificate Authority
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEqDCCApCgAwIBAgIUK5Ns4y2CzosB/ZoFlaxjZqoBTIIwDQYJKoZIhvcNAQEL
|
||||
BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
|
||||
DVNhbiBGcmFuY2lzY28xDzANBgNVBAoMBkJhZFNTTDExMC8GA1UEAwwoQmFkU1NM
|
||||
IENsaWVudCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTExMjcwMDE5
|
||||
NTdaFw0yMTExMjYwMDE5NTdaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
|
||||
Zm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wx
|
||||
IjAgBgNVBAMMGUJhZFNTTCBDbGllbnQgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDHN18R6x5Oz+u6SOXLoxIscz5GHR6cDcCLgyPa
|
||||
x2XfXHdJs+h6fTy61WGM+aXEhR2SIwbj5997s34m0MsbvkJrFmn0LHK1fuTLCihE
|
||||
EmxGdCGZA9xrwxFYAkEjP7D8v7cAWRMipYF/JP7VU7xNUo+QSkZ0sOi9k6bNkABK
|
||||
L3+yP6PqAzsBoKIN5lN/YRLrppsDmk6nrRDo4R3CD+8JQl9quEoOmL22Pc/qpOjL
|
||||
1jgOIFSE5y3gwbzDlfCYoAL5V+by1vu0yJShTTK8oo5wvphcFfEHaQ9w5jFg2htd
|
||||
q99UER3BKuNDuL+zejqGQZCWb0Xsk8S5WBuX8l3Brrg5giqNAgMBAAGjLTArMAkG
|
||||
A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMAsGA1UdDwQEAwIF4DANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAZBauLzFSOijkDadcippr9C6laHebb0oRS54xAV70E9k5GxfR
|
||||
/E2EMuQ8X+miRUMXxKquffcDsSxzo2ac0flw94hDx3B6vJIYvsQx9Lzo95Im0DdT
|
||||
DkHFXhTlv2kjQwFVnEsWYwyGpHMTjanvNkO7sBP9p1bN1qTE3QAeyMZNKWJk5xPl
|
||||
U298ERar6tl3Z2Cl8mO6yLhrq4ba6iPGw08SENxzuAJW+n8r0rq7EU+bMg5spgT1
|
||||
CxExzG8Bb0f98ZXMklpYFogkcuH4OUOFyRodotrotm3iRbuvZNk0Zz7N5n1oLTPl
|
||||
bGPMwBcqaGXvK62NlaRkwjnbkPM4MYvREM0bbAgZD2GHyANBTso8bdWvhLvmoSjs
|
||||
FSqJUJp17AZ0x/ELWZd69v2zKW9UdPmw0evyVR19elh/7dmtF6wbewc4N4jxQnTq
|
||||
IItuhIWKWB9edgJz65uZ9ubQWjXoa+9CuWcV/1KxuKCbLHdZXiboLrKm4S1WmMYW
|
||||
d0sJm95H9mJzcLyhLF7iX2kK6K9ug1y02YCVXBC9WGZc2x6GMS7lDkXSkJFy3EWh
|
||||
CmfxkmFGwOgwKt3Jd1pF9ftcSEMhu4WcMgxi9vZr9OdkJLxmk033sVKI/hnkPaHw
|
||||
g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4=
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
localKeyID: 41 C3 6C 33 C7 E3 36 DD EA 4A 1F C0 B7 23 B8 E6 9C DC D8 0F
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAxzdfEeseTs/rukjly6MSLHM+Rh0enA3Ai4Mj2sdl31x3SbPo
|
||||
en08utVhjPmlxIUdkiMG4+ffe7N+JtDLG75CaxZp9CxytX7kywooRBJsRnQhmQPc
|
||||
a8MRWAJBIz+w/L+3AFkTIqWBfyT+1VO8TVKPkEpGdLDovZOmzZAASi9/sj+j6gM7
|
||||
AaCiDeZTf2ES66abA5pOp60Q6OEdwg/vCUJfarhKDpi9tj3P6qToy9Y4DiBUhOct
|
||||
4MG8w5XwmKAC+Vfm8tb7tMiUoU0yvKKOcL6YXBXxB2kPcOYxYNobXavfVBEdwSrj
|
||||
Q7i/s3o6hkGQlm9F7JPEuVgbl/Jdwa64OYIqjQIDAQABAoIBAFUQf7fW/YoJnk5c
|
||||
8kKRzyDL1Lt7k6Zu+NiZlqXEnutRQF5oQ8yJzXS5yH25296eOJI+AqMuT28ypZtN
|
||||
bGzcQOAZIgTxNcnp9Sf9nlPyyekLjY0Y6PXaxX0e+VFj0N8bvbiYUGNq6HCyC15r
|
||||
8uvRZRvnm04YfEj20zLTWkxTG+OwJ6ZNha1vfq8z7MG5JTsZbP0g7e/LrEb3wI7J
|
||||
Zu9yHQUzq23HhfhpmLN/0l89YLtOaS8WNq4QvKYgZapw/0G1wWoWW4Y2/UpAxZ9r
|
||||
cqTBWSpCSCCgyWjiNhPbSJWfe/9J2bcanITLcvCLlPWGAHy1wpo9iBH57y7S+7YS
|
||||
3yi7lgECgYEA8lwaRIChc38tmtQCNPtai/7uVDdeJe0uv8Jsg04FTF8KMYcD0V1g
|
||||
+T7rUPA+rTHwv8uAGLdzl4NW5Qryw18rDY+UivnaZkEdEsnlo3fc8MSQF78dDHCX
|
||||
nwmHfOmBnBoSbLl+W5ByHkJRHOnX+8qKq9ePNFUMf/hZNYuma9BCFBUCgYEA0m2p
|
||||
VDn12YdhFUUBIH91aD5cQIsBhkHFU4vqW4zBt6TsJpFciWbrBrTeRzeDou59aIsn
|
||||
zGBrLMykOY+EwwRku9KTVM4U791Z/NFbH89GqyUaicb4or+BXw5rGF8DmzSsDo0f
|
||||
ixJ9TVD5DmDi3c9ZQ7ljrtdSxPdA8kOoYPFsApkCgYEA08uZSPQAI6aoe/16UEK4
|
||||
Rk9qhz47kHlNuVZ27ehoyOzlQ5Lxyy0HacmKaxkILOLPuUxljTQEWAv3DAIdVI7+
|
||||
WMN41Fq0eVe9yIWXoNtGwUGFirsA77YVSm5RcN++3GQMZedUfUAl+juKFvJkRS4j
|
||||
MTkXdGw+mDa3/wsjTGSa2mECgYABO6NCWxSVsbVf6oeXKSgG9FaWCjp4DuqZErjM
|
||||
0IZSDSVVFIT2SSQXZffncuvSiJMziZ0yFV6LZKeRrsWYXu44K4Oxe4Oj5Cgi0xc1
|
||||
mIFRf2YoaIIMchLP+8Wk3ummfyiC7VDB/9m8Gj1bWDX8FrrvKqbq31gcz1YSFVNn
|
||||
PgLkAQKBgFzG8NdL8os55YcjBcOZMUs5QTKiQSyZM0Abab17k9JaqsU0jQtzeFsY
|
||||
FTiwh2uh6l4gdO/dGC/P0Vrp7F05NnO7oE4T+ojDzVQMnFpCBeL7x08GfUQkphEG
|
||||
m0Wqhhi8/24Sy934t5Txgkfoltg8ahkx934WjP6WWRnSAu+cf+vW
|
||||
-----END RSA PRIVATE KEY-----
|
||||
"#;
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
#[test]
|
||||
fn tls_client_certificate() {
|
||||
let agent = ureq::Agent::default().build();
|
||||
|
||||
let mut tls_config = rustls::ClientConfig::new();
|
||||
|
||||
let certs =
|
||||
rustls::internal::pemfile::certs(&mut BADSSL_CLIENT_CERT_PEM.clone().as_bytes()).unwrap();
|
||||
let key =
|
||||
rustls::internal::pemfile::rsa_private_keys(&mut BADSSL_CLIENT_CERT_PEM.clone().as_bytes())
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
tls_config.set_single_client_cert(certs, key).unwrap();
|
||||
tls_config
|
||||
.root_store
|
||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||
|
||||
let resp = agent
|
||||
.get("https://client.badssl.com/")
|
||||
.set_tls_config(std::sync::Arc::new(tls_config))
|
||||
.call();
|
||||
|
||||
assert_eq!(resp.status(), 200);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user