11//!secure connection over TLS
22
33use crate :: error:: Error as HttpError ;
4- use std:: io;
4+ use std:: fs:: File ;
5+ use std:: io:: { self , BufReader } ;
6+ use std:: path:: Path ;
7+
8+ #[ cfg( feature = "native-tls" ) ]
9+ use std:: io:: prelude:: * ;
10+
11+ #[ cfg( feature = "rust-tls" ) ]
12+ use crate :: error:: ParseErr ;
513
614#[ cfg( not( any( feature = "native-tls" , feature = "rust-tls" ) ) ) ]
715compile_error ! ( "one of the `native-tls` or `rust-tls` features must be enabled" ) ;
@@ -50,14 +58,18 @@ impl<S: io::Read + io::Write> io::Write for Conn<S> {
5058
5159///client configuration
5260pub struct Config {
61+ #[ cfg( feature = "native-tls" ) ]
62+ extra_root_certs : Vec < native_tls:: Certificate > ,
5363 #[ cfg( feature = "rust-tls" ) ]
5464 client_config : std:: sync:: Arc < rustls:: ClientConfig > ,
5565}
5666
5767impl Default for Config {
5868 #[ cfg( feature = "native-tls" ) ]
5969 fn default ( ) -> Self {
60- Config { }
70+ Config {
71+ extra_root_certs : vec ! [ ] ,
72+ }
6173 }
6274
6375 #[ cfg( feature = "rust-tls" ) ]
@@ -74,18 +86,53 @@ impl Default for Config {
7486}
7587
7688impl Config {
89+ #[ cfg( feature = "native-tls" ) ]
90+ pub fn add_root_cert_file_pem ( & mut self , file_path : & Path ) -> Result < & mut Self , HttpError > {
91+ let f = File :: open ( file_path) ?;
92+ let f = BufReader :: new ( f) ;
93+ let mut pem_crt = vec ! [ ] ;
94+ for line in f. lines ( ) {
95+ let line = line?;
96+ let is_end_cert = line. contains ( "-----END" ) ;
97+ pem_crt. append ( & mut line. into_bytes ( ) ) ;
98+ pem_crt. push ( b'\n' ) ;
99+ if is_end_cert {
100+ let crt = native_tls:: Certificate :: from_pem ( & pem_crt) ?;
101+ self . extra_root_certs . push ( crt) ;
102+ pem_crt. clear ( ) ;
103+ }
104+ }
105+ Ok ( self )
106+ }
107+
77108 #[ cfg( feature = "native-tls" ) ]
78109 pub fn connect < H , S > ( & self , hostname : H , stream : S ) -> Result < Conn < S > , HttpError >
79110 where
80111 H : AsRef < str > ,
81112 S : io:: Read + io:: Write ,
82113 {
83- let connector = native_tls:: TlsConnector :: new ( ) ?;
114+ let mut connector_builder = native_tls:: TlsConnector :: builder ( ) ;
115+ for crt in self . extra_root_certs . iter ( ) {
116+ connector_builder. add_root_certificate ( ( * crt) . clone ( ) ) ;
117+ }
118+ let connector = connector_builder. build ( ) ?;
84119 let stream = connector. connect ( hostname. as_ref ( ) , stream) ?;
85120
86121 Ok ( Conn { stream } )
87122 }
88123
124+ #[ cfg( feature = "rust-tls" ) ]
125+ pub fn add_root_cert_file_pem ( & mut self , file_path : & Path ) -> Result < & mut Self , HttpError > {
126+ let f = File :: open ( file_path) ?;
127+ let mut f = BufReader :: new ( f) ;
128+ let config = std:: sync:: Arc :: make_mut ( & mut self . client_config ) ;
129+ let _ = config
130+ . root_store
131+ . add_pem_file ( & mut f)
132+ . map_err ( |_| HttpError :: from ( ParseErr :: Invalid ) ) ?;
133+ Ok ( self )
134+ }
135+
89136 #[ cfg( feature = "rust-tls" ) ]
90137 pub fn connect < H , S > ( & self , hostname : H , stream : S ) -> Result < Conn < S > , HttpError >
91138 where
0 commit comments