Skip to content

Commit 335a373

Browse files
jen20LucioFranco
authored andcommitted
feat(transport): Add support client mTLS (#77)
This commit adds a simple API for specifying the TLS certificate a GRPC client will present (via the same `Identity` wrapper as a server cert is configured). It also adds an API to specify which CA certificate client TLS certificates will be validated against for servers.
1 parent 9079e0f commit 335a373

File tree

11 files changed

+354
-51
lines changed

11 files changed

+354
-51
lines changed

tonic-examples/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ path = "src/tls/client.rs"
4444
name = "tls-server"
4545
path = "src/tls/server.rs"
4646

47+
[[bin]]
48+
name = "tls-client-auth-server"
49+
path = "src/tls_client_auth/server.rs"
50+
51+
[[bin]]
52+
name = "tls-client-auth-client"
53+
path = "src/tls_client_auth/client.rs"
54+
4755
[dependencies]
4856
tonic = { path = "../tonic", features = ["rustls"] }
4957
bytes = "0.4"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCiiWrmzpENsI+c
3+
Cz4aBpG+Pl8WOsrByfZx/ZnJdCZHO3MTYE6sCLhYssf0ygAEEGxvmkd4cxmfCfgf
4+
xuT8u+D7Y5zQSoymkbWdU6/9jbNY6Ovtc+a96I1LGXOKROQw6KR3PuqLpUqEOJiB
5+
l03qK+HMU0g56G1n31Od7HkJsDRvtePqy3I3LgpdcRps23sk46tCzZzhyfqIQ7Qf
6+
J5qZx93tA+pfy+Xtb9XIUTIWKIp1/uyfh8Fp8HA0c9zJCSZzJOX2j3GH1TYqkVgP
7+
egI2lhmdXhP5Q8vdhwy0UJaL28RJXA6UAg0tPZeWJe6pux9JiA81sI6My+Krrw8D
8+
yibkGTTbAgMBAAECggEANCQhRym9HsclSsnQgkjZOE6J8nep08EWbjsMurOoE/He
9+
WLjshAPIH6w6uSyUFLmwD51OkDVcYsiv8IG9s9YRtpOeGrPPqx/TQ0U1kAGFJ2CR
10+
Tvt/aizQJudjSVgQXCBFontsgp/j58bAJdKEDDtHlGSjJvCJKGlcSa0ypwj/yVXt
11+
frjROJNYzw9gMM7fN/IKF/cysdXSeLl/Q9RnHVIfC3jOFJutsILCK8+PC51dM8Fl
12+
IOjmPmiZ080yV8RBcMRECwl53vLOE3OOpR3ZijfNCY1KU8zWi1oELJ1o6f4+cBye
13+
7WPgFEoBew5XHXZ+ke8rh8cc0wth7ZTcC+xC/456AQKBgQDQr2EzBwXxYLF8qsN1
14+
R4zlzXILLdZN8a4bKfrS507/Gi1gDBHzfvbE7HfljeqrAkbKMdKNkbz3iS85SguH
15+
jsM047xUGJg0PAcwBLHUedlSn1xDDcDHW6X8ginpA2Zz1+WAlhNz6XurA1wnjZmS
16+
VcPxopH7QsuFCclqtt14MbBQ6QKBgQDHY3jcAVfQF+yhQ0YyM6GPLN342aTplgyJ
17+
yz4uWVMeXacU4QzqGbf2L2hc9M2L28Xb37RWC3Q/by0vUefiC6qxRt+GJdRsOuQj
18+
2F1uUibeWtAWp249fcfvxjLib276J+Eit18LI0s0mNR3ekK4GcjSe4NwSq5IrU8e
19+
pBreet3dIwKBgQCxVuil4WkGd+I8jC0v5A7zVsR8hYZhlGkdgm45fgHevdMjlP5I
20+
S3PPYxh8hj6O9o9L0k0Yq2nHfdgYujjUCNkQgBuR55iogv6kqsioRKgPE4fnH6/c
21+
eqCy1bZh4tbUyPqqbF65mQfUCzXsEuQXvDSYiku+F0Q2mVuGCUJpmug3yQKBgEd3
22+
LeCdUp4xlQ0QEd74hpXM3RrO178pmwDgqj7uoU4m/zYKnBhkc3137I406F+SvE5c
23+
1kRpApeh/64QS27IA7xazM9GS+cnDJKUgJiENY5JOoCELo03wiv8/EwQ6NQc6yMI
24+
WrahRdlqVe0lEzjtdP+MacYb3nAKPmubIk5P96nFAoGAFAyrKpFTyXbNYBTw9Rab
25+
TG6q7qkn+YTHN3+k4mo9NGGwZ3pXvmrKMYCIRhLMbqzsmTbFqCPPIxKsrmf8QYLh
26+
xHYQjrCkbZ0wZdcdeV6yFSDsF218nF/12ZPE7CBOQMfZTCKFNWGL97uIVcmR6K5G
27+
ojTkOvaUnwQtSFhNuzyr23I=
28+
-----END PRIVATE KEY-----
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDCTCCAfGgAwIBAgIQYbE9d1Rft5h4ku7FSAvWdzANBgkqhkiG9w0BAQsFADAn
3+
MSUwIwYDVQQDExxUb25pYyBFeGFtcGxlIENsaWVudCBSb290IENBMB4XDTE5MTAx
4+
NDEyMzkzNloXDTI0MTAxMjEyMzkzNlowEjEQMA4GA1UEAxMHY2xpZW50MTCCASIw
5+
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKJaubOkQ2wj5wLPhoGkb4+XxY6
6+
ysHJ9nH9mcl0Jkc7cxNgTqwIuFiyx/TKAAQQbG+aR3hzGZ8J+B/G5Py74PtjnNBK
7+
jKaRtZ1Tr/2Ns1jo6+1z5r3ojUsZc4pE5DDopHc+6oulSoQ4mIGXTeor4cxTSDno
8+
bWffU53seQmwNG+14+rLcjcuCl1xGmzbeyTjq0LNnOHJ+ohDtB8nmpnH3e0D6l/L
9+
5e1v1chRMhYoinX+7J+HwWnwcDRz3MkJJnMk5faPcYfVNiqRWA96AjaWGZ1eE/lD
10+
y92HDLRQlovbxElcDpQCDS09l5Yl7qm7H0mIDzWwjozL4quvDwPKJuQZNNsCAwEA
11+
AaNGMEQwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAfBgNVHSME
12+
GDAWgBQV1YOR+Jpl1fbujvWLSBEoRvsDhTANBgkqhkiG9w0BAQsFAAOCAQEAfTPu
13+
KeHXmyVTSCUrYQ1X5Mu7VzfZlRbhoytHOw7bYGgwaFwQj+ZhlPt8nFC22/bEk4IV
14+
AoCOli0WyPIB7Lx52dZ+v9JmYOK6ca2Aa/Dkw8Q+M3XA024FQWq3nZ6qANKC32/9
15+
Nk+xOcb1Qd/11stpTkRf2Oj7F7K4GnlFbY6iMyNW+RFXGKEbL5QAJDTDPIT8vw1x
16+
oYeNPwmC042uEboCZPNXmuctiK9Wt1TAxjZT/cwdIBGGJ+xrW72abfJGs7bUcJfc
17+
O4r9V0xVv+X0iKWTW0fwd9qjNfiEP1tFCcZb2XsNQPe/DlQZ+h98P073tZEsWI/G
18+
KJrFspGX8vOuSdIeqw==
19+
-----END CERTIFICATE-----
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvpRVRx7joJVf3
3+
dIcDih5lY0Z+Y2MoDX83iwNF4QTfMibULyXffOnC5XcvayS/W8ToxaLweNE2bIwa
4+
krl3K+R/4tdI9ZguSgHFBMRCNp33ZDGxD01XHduETXXdHXxKufxLNjCFtAWwM+GF
5+
KbYzEdeyMmV9yYc3ihW3mg+7rzaUwU+hK7LjhTi/YW7TJF53UGIkEQuPKYUfBCha
6+
01CWAJTJDI7hrH7asfIG690Wm3uWNj2wsFVk2ZtyRIis2aQOE4tknG3yTKjnLGBH
7+
L+DQ+2UljuVyHi1pwCVN+zvoG/0RiiHWs6kW/zAompoxWhWPucKgssjC/JsWVKKp
8+
TpfOfEy7AgMBAAECggEAFclTQKaWT+054Q7KJG1AYfETcF/hj7lE213Z1RQZJ5ov
9+
6MfEWdlDoZIW24HduAKpBPpmwI8r3CVQp4cljBucpyQ68ejMrIkveQGjWlct9t6t
10+
rzmnrTOd4+Y7xWZ/4UD6g1XAZQU0Y2u8AGlxGRqQd6D6p8SUihYNpY1tgCk2ivLO
11+
znGZau0Gdt2f6Pv9C0cy5R2832a+3V1X9oCeeXVP8kM1dBKbWQTVxhYaxJxMZifn
12+
qfJi3sjEJZZ05NEFKwKpYx7gUEtC1d/zvvL/VSjihcyCYk728jr40uoeBpBUiUsR
13+
G0N1/xGNGHuRAGFjQSyrACtz1hRSPFmTyRhr6vrRGQKBgQDOFWKl6HjVB/WZ6ZC+
14+
BXMhUvCKz99lrOO1TbDAI8Tn26D+OSXhywXWPf++HhTZuND460I+79rPH+tJiFw4
15+
Y5z9JFce0MYPNcd/K7JBiV7zBBYof40UbBw8Eff7mWLaOXtI9uwItRXRBs+fIPRM
16+
eCgVUid7pe//oAQ8npcmQEVxjwKBgQDaMEmrTo0+RpT3sS1m9pCQc2LjiKmhWP1L
17+
N/IxZn5Ey9Ao+ibVIQzb69HMUBJ1EZGNZZkEcCguWICIov8rO10xIrD3m9rWgAVg
18+
HlVFlcSTrg0/3cVd26msJKW4pjKA/GmYVhP8o027Zy5KtZ/2jJCh2UjSLsY+acEq
19+
+Qr972BEFQKBgHOwAZ7NL/e27iKmwUBK4uSUIMBsDSaQtYtzv4M9ES5vVqMgBaoJ
20+
RI+OYmChlmban0T9HEUkdJrNelHfIJXvJZPdsKJ15JlpQUKcjwbHTOvzIVU+tT3/
21+
qqH2HFW7N4j1t8WwB7Sjo0miHy9fWoUK9sVxRwTclCvV8krtZEBu2Az1AoGAGZoU
22+
6t76v9X0YOQPWceQywJfFifRD7ercQoNhzJpmpT3xfckW1nXcm7HXVv/7nCzTY4g
23+
WF74uAd2fZHysxXyJ3PUpBlLomO/PboRc2rReCqyL05MfGjsDeD2+SW3Q19a3J8t
24+
FTXsRxMiYW3SaVGxHuyqGM+YP3aVTf+PBKD0AMkCgYEAyKtuxwBjPjO1pyOn195e
25+
UY2oaZq4PfaK04Eu5uCmOD2vBcgJWZ8VJNXPlRL5vlCx9LrLB9vJDyXgSurqJAH6
26+
M8/7tR/xlyMix+Jq47209kfOXMMdSGf55/xERmN6vPuhLtPwtj0ZduJzq6gwnlvs
27+
gG29TwA5xp9S4A1amFSrJBo=
28+
-----END PRIVATE KEY-----
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDCjCCAfKgAwIBAgIRAKD72aj29NawAKPAQkcm7QcwDQYJKoZIhvcNAQELBQAw
3+
JzElMCMGA1UEAxMcVG9uaWMgRXhhbXBsZSBDbGllbnQgUm9vdCBDQTAeFw0xOTEw
4+
MTQxMjM5MzZaFw0yNDEwMTIxMjM5MzZaMBIxEDAOBgNVBAMTB2NsaWVudDIwggEi
5+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvpRVRx7joJVf3dIcDih5lY0Z+
6+
Y2MoDX83iwNF4QTfMibULyXffOnC5XcvayS/W8ToxaLweNE2bIwakrl3K+R/4tdI
7+
9ZguSgHFBMRCNp33ZDGxD01XHduETXXdHXxKufxLNjCFtAWwM+GFKbYzEdeyMmV9
8+
yYc3ihW3mg+7rzaUwU+hK7LjhTi/YW7TJF53UGIkEQuPKYUfBCha01CWAJTJDI7h
9+
rH7asfIG690Wm3uWNj2wsFVk2ZtyRIis2aQOE4tknG3yTKjnLGBHL+DQ+2UljuVy
10+
Hi1pwCVN+zvoG/0RiiHWs6kW/zAompoxWhWPucKgssjC/JsWVKKpTpfOfEy7AgMB
11+
AAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0j
12+
BBgwFoAUFdWDkfiaZdX27o71i0gRKEb7A4UwDQYJKoZIhvcNAQELBQADggEBAF5F
13+
2A3V2GGZo7AdztxWaPd6Nu/8VbQWGEeZeWFpQEloNiur96KDcndXXrS6GAyL31d9
14+
vfV2IA2yrB/2przFVRjfNnTj7+xNEtp23iMW8qhMIeHQs1IYu+HqHWDPEJfphTPd
15+
4Tu5M+ciE7KSZgPsV15piPgst2dqDvghBqxE6t3UnR1wQ5b3wWCt1O9NO+obeV9a
16+
1lzlYw2NjdHxmrqXLS9I5eYqEo3JtRQrOu3LUd7LqdlEO0jHMaxblxTgwJDoj/9C
17+
CnXp3sNewqsNHW17dsKavMJ2LFXukqLjonvz8NjxeetD09OzMEsg8Tx/1nOQPUBw
18+
rtVdBkQ/TxiNTlTtdZc=
19+
-----END CERTIFICATE-----
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDGzCCAgOgAwIBAgIRAMNWpWRu6Q1txEYUyrkyXKEwDQYJKoZIhvcNAQELBQAw
3+
JzElMCMGA1UEAxMcVG9uaWMgRXhhbXBsZSBDbGllbnQgUm9vdCBDQTAeFw0xOTEw
4+
MTQxMjM5MzZaFw0yOTEwMTExMjM5MzZaMCcxJTAjBgNVBAMTHFRvbmljIEV4YW1w
5+
bGUgQ2xpZW50IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
6+
AQCv8Nj4XJbMI0wWUvLbmCf7IEvJFnomodGnDurh8Y5AGMPJ8cGdZC1yo2Lgah+D
7+
IhXdsd72Wp7MhdntJAyPrMCDBfDrFiuj6YHDgt3OhPQSYl7EWG7QjFK3B2sp1K5D
8+
h16G5zfwUKDj9Jp3xuPGuqNFQHL02nwbhtDilqHvaTfOJKVjsFCoU8Z77mfwXSwn
9+
sPXpPB7oOO4mWfAtcwU11rTMiHFSGFlFhgbHULU/y90DcpfRQEpEiBoiK13gkyoP
10+
zHT9WAg3Pelwb6K7c7kJ7mp4axhbf7MkwFhDQIjbBWqus2Eu3b0mf86ALfDbAaNC
11+
wBi8xbNH2vWaDjiwLDY5uMZDAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwICBDAPBgNV
12+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQV1YOR+Jpl1fbujvWLSBEoRvsDhTANBgkq
13+
hkiG9w0BAQsFAAOCAQEAaXmM29TYkFUzZUsV7TSonAK560BjxDmbg0GJSUgLEFUJ
14+
wpKqa9UKOSapG45LEeR2wwAmVWDJomJplkuvTD/KOabAbZKyPEfp+VMCaBUnILQF
15+
Cxv5m7kQ3wmPS/rEL8FD809UGowW9cYqnZzUy5i/r263rx0k3OPjkkZN66Mh6+3H
16+
ibNdaxf7ITO0JVb/Ohq9vLC9qf7ujiB1atMdJwkOWsZrLJXLygpx/D0/UhBT4fFH
17+
OlyVOmuR27qaMbPgOs2l8DznkJY/QUfnET8iOQhFgb0Dt/Os4PYFhSDRIrgl5dJ7
18+
L/zZVQfZYpdxlBHJlDC1/NzVQl/1MgDnSgPGStZKPQ==
19+
-----END CERTIFICATE-----
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
pub mod pb {
2+
tonic::include_proto!("grpc.examples.echo");
3+
}
4+
5+
use pb::{client::EchoClient, EchoRequest};
6+
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};
7+
8+
#[tokio::main]
9+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
10+
let server_root_ca_cert = tokio::fs::read("tonic-examples/data/tls/ca.pem").await?;
11+
let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);
12+
let client_cert = tokio::fs::read("tonic-examples/data/tls/client1.pem").await?;
13+
let client_key = tokio::fs::read("tonic-examples/data/tls/client1.key").await?;
14+
let client_identity = Identity::from_pem(client_cert, client_key);
15+
16+
let tls = ClientTlsConfig::with_openssl()
17+
.domain_name("localhost")
18+
.ca_certificate(server_root_ca_cert)
19+
.identity(client_identity)
20+
.clone();
21+
22+
let channel = Channel::from_static("http://[::1]:50051")
23+
.tls_config(&tls)
24+
.clone()
25+
.channel();
26+
27+
let mut client = EchoClient::new(channel);
28+
29+
let request = tonic::Request::new(EchoRequest {
30+
message: "hello".into(),
31+
});
32+
33+
let response = client.unary_echo(request).await?;
34+
35+
println!("RESPONSE={:?}", response);
36+
37+
Ok(())
38+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
pub mod pb {
2+
tonic::include_proto!("grpc.examples.echo");
3+
}
4+
5+
use std::collections::VecDeque;
6+
7+
use pb::{EchoRequest, EchoResponse};
8+
use tonic::transport::{Certificate, Identity, Server, ServerTlsConfig};
9+
use tonic::{Request, Response, Status};
10+
11+
type EchoResult<T> = Result<Response<T>, Status>;
12+
type Stream = VecDeque<Result<EchoResponse, Status>>;
13+
14+
#[derive(Default)]
15+
pub struct EchoServer;
16+
17+
#[tonic::async_trait]
18+
impl pb::server::Echo for EchoServer {
19+
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
20+
let message = request.into_inner().message;
21+
Ok(Response::new(EchoResponse { message }))
22+
}
23+
24+
type ServerStreamingEchoStream = Stream;
25+
type BidirectionalStreamingEchoStream = Stream;
26+
}
27+
28+
#[tokio::main]
29+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
30+
let cert = tokio::fs::read("tonic-examples/data/tls/server.pem").await?;
31+
let key = tokio::fs::read("tonic-examples/data/tls/server.key").await?;
32+
let server_identity = Identity::from_pem(cert, key);
33+
34+
let client_ca_cert = tokio::fs::read("tonic-examples/data/tls/client_ca.pem").await?;
35+
let client_ca_cert = Certificate::from_pem(client_ca_cert);
36+
37+
let addr = "[::1]:50051".parse().unwrap();
38+
let server = EchoServer::default();
39+
40+
let tls = ServerTlsConfig::with_rustls()
41+
.identity(server_identity)
42+
.client_ca_root(client_ca_cert)
43+
.clone();
44+
45+
Server::builder()
46+
.tls_config(&tls)
47+
.clone()
48+
.serve(addr, pb::server::EchoServer::new(server))
49+
.await?;
50+
51+
Ok(())
52+
}

tonic/src/transport/endpoint.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::channel::Channel;
22
#[cfg(feature = "tls")]
33
use super::{
44
service::TlsConnector,
5-
tls::{Certificate, TlsProvider},
5+
tls::{Certificate, Identity, TlsProvider},
66
};
77
use bytes::Bytes;
88
use http::uri::{InvalidUriBytes, Uri};
@@ -212,6 +212,7 @@ pub struct ClientTlsConfig {
212212
provider: TlsProvider,
213213
domain: Option<String>,
214214
cert: Option<Certificate>,
215+
identity: Option<Identity>,
215216
#[cfg(feature = "openssl")]
216217
openssl_raw: Option<openssl1::ssl::SslConnector>,
217218
#[cfg(feature = "rustls")]
@@ -223,6 +224,9 @@ impl fmt::Debug for ClientTlsConfig {
223224
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224225
f.debug_struct("ClientTlsConfig")
225226
.field("provider", &self.provider)
227+
.field("domain", &self.domain)
228+
.field("cert", &self.cert)
229+
.field("identity", &self.identity)
226230
.finish()
227231
}
228232
}
@@ -246,6 +250,7 @@ impl ClientTlsConfig {
246250
provider,
247251
domain: None,
248252
cert: None,
253+
identity: None,
249254
#[cfg(feature = "openssl")]
250255
openssl_raw: None,
251256
#[cfg(feature = "rustls")]
@@ -265,6 +270,12 @@ impl ClientTlsConfig {
265270
self
266271
}
267272

273+
/// Sets the client identity to present to the server.
274+
pub fn identity(&mut self, identity: Identity) -> &mut Self {
275+
self.identity = Some(identity);
276+
self
277+
}
278+
268279
/// Use options specified by the given `SslConnector` to configure TLS.
269280
///
270281
/// This overrides all other TLS options set via other means.
@@ -294,12 +305,20 @@ impl ClientTlsConfig {
294305
match self.provider {
295306
#[cfg(feature = "openssl")]
296307
TlsProvider::OpenSsl => match &self.openssl_raw {
297-
None => TlsConnector::new_with_openssl_cert(self.cert.clone(), domain),
308+
None => TlsConnector::new_with_openssl_cert(
309+
self.cert.clone(),
310+
self.identity.clone(),
311+
domain,
312+
),
298313
Some(r) => TlsConnector::new_with_openssl_raw(r.clone(), domain),
299314
},
300315
#[cfg(feature = "rustls")]
301316
TlsProvider::Rustls => match &self.rustls_raw {
302-
None => TlsConnector::new_with_rustls_cert(self.cert.clone(), domain),
317+
None => TlsConnector::new_with_rustls_cert(
318+
self.cert.clone(),
319+
self.identity.clone(),
320+
domain,
321+
),
303322
Some(c) => TlsConnector::new_with_rustls_raw(c.clone(), domain),
304323
},
305324
}

tonic/src/transport/server.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::service::{layer_fn, BoxedIo, ServiceBuilderExt};
55
use super::{
66
service::TlsAcceptor,
77
tls::{Identity, TlsProvider},
8+
Certificate,
89
};
910
use crate::body::BoxBody;
1011
use futures_core::Stream;
@@ -225,6 +226,7 @@ impl fmt::Debug for Server {
225226
pub struct ServerTlsConfig {
226227
provider: TlsProvider,
227228
identity: Option<Identity>,
229+
client_ca_root: Option<Certificate>,
228230
#[cfg(feature = "openssl")]
229231
openssl_raw: Option<openssl1::ssl::SslAcceptor>,
230232
#[cfg(feature = "rustls")]
@@ -260,6 +262,7 @@ impl ServerTlsConfig {
260262
ServerTlsConfig {
261263
provider,
262264
identity: None,
265+
client_ca_root: None,
263266
#[cfg(feature = "openssl")]
264267
openssl_raw: None,
265268
#[cfg(feature = "rustls")]
@@ -273,6 +276,12 @@ impl ServerTlsConfig {
273276
self
274277
}
275278

279+
/// Sets a certificate against which to validate client TLS certificates.
280+
pub fn client_ca_root(&mut self, cert: Certificate) -> &mut Self {
281+
self.client_ca_root = Some(cert);
282+
self
283+
}
284+
276285
/// Use options specified by the given `SslAcceptor` to configure TLS.
277286
///
278287
/// This overrides all other TLS options set via other means.
@@ -298,12 +307,18 @@ impl ServerTlsConfig {
298307
match self.provider {
299308
#[cfg(feature = "openssl")]
300309
TlsProvider::OpenSsl => match &self.openssl_raw {
301-
None => TlsAcceptor::new_with_openssl_identity(self.identity.clone().unwrap()),
310+
None => TlsAcceptor::new_with_openssl_identity(
311+
self.identity.clone().unwrap(),
312+
self.client_ca_root.clone(),
313+
),
302314
Some(acceptor) => TlsAcceptor::new_with_openssl_raw(acceptor.clone()),
303315
},
304316
#[cfg(feature = "rustls")]
305317
TlsProvider::Rustls => match &self.rustls_raw {
306-
None => TlsAcceptor::new_with_rustls_identity(self.identity.clone().unwrap()),
318+
None => TlsAcceptor::new_with_rustls_identity(
319+
self.identity.clone().unwrap(),
320+
self.client_ca_root.clone(),
321+
),
307322
Some(config) => TlsAcceptor::new_with_rustls_raw(config.clone()),
308323
},
309324
}

0 commit comments

Comments
 (0)