1 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2 
3 use std::error::Error as StdError;
4 use std::ffi::CString;
5 use std::{mem, ptr};
6 
7 use crate::error::{Error, Result};
8 use crate::grpc_sys::grpc_ssl_certificate_config_reload_status::{self, *};
9 use crate::grpc_sys::grpc_ssl_client_certificate_request_type::*;
10 use crate::grpc_sys::{
11     self, grpc_ssl_client_certificate_request_type, grpc_ssl_server_certificate_config,
12 };
13 use crate::{ChannelCredentials, ServerCredentials};
14 
15 #[repr(u32)]
16 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
17 pub enum CertificateRequestType {
18     /// Server does not request client certificate.
19     ///
20     /// The certificate presented by the client is not checked by the server at
21     /// all. (A client may present a self signed or signed certificate or not
22     /// present a certificate at all and any of those option would be accepted)
23     DontRequestClientCertificate = GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE as u32,
24     /// Server requests client certificate but does not enforce that the client
25     /// presents a certificate.
26     ///
27     /// If the client presents a certificate, the client authentication is left to
28     /// the application (the necessary metadata will be available to the
29     /// application via authentication context properties, see grpc_auth_context).
30     ///
31     /// The client's key certificate pair must be valid for the SSL connection to
32     /// be established.
33     RequestClientCertificateButDontVerify =
34         GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY as u32,
35     /// Server requests client certificate but does not enforce that the client
36     /// presents a certificate.
37     ///
38     /// If the client presents a certificate, the client authentication is done by
39     /// the gRPC framework. (For a successful connection the client needs to either
40     /// present a certificate that can be verified against the root certificate
41     /// configured by the server or not present a certificate at all)
42     ///
43     /// The client's key certificate pair must be valid for the SSL connection to
44     /// be established.
45     RequestClientCertificateAndVerify = GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY as u32,
46     /// Server requests client certificate and enforces that the client presents a
47     /// certificate.
48     ///
49     /// If the client presents a certificate, the client authentication is left to
50     /// the application (the necessary metadata will be available to the
51     /// application via authentication context properties, see grpc_auth_context).
52     ///
53     /// The client's key certificate pair must be valid for the SSL connection to
54     /// be established.
55     RequestAndRequireClientCertificateButDontVerify =
56         GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY as u32,
57     /// Server requests client certificate and enforces that the client presents a
58     /// certificate.
59     ///
60     /// The certificate presented by the client is verified by the gRPC framework.
61     /// (For a successful connection the client needs to present a certificate that
62     /// can be verified against the root certificate configured by the server)
63     ///
64     /// The client's key certificate pair must be valid for the SSL connection to
65     /// be established.
66     RequestAndRequireClientCertificateAndVerify =
67         GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY as u32,
68 }
69 
70 /// Traits to retrieve updated SSL server certificates, private keys, and trusted CAs
71 /// (for client authentication).
72 pub trait ServerCredentialsFetcher {
73     /// Retrieves updated credentials.
74     ///
75     /// The method will be called during server initialization and every time a new
76     /// connection is about to be accepted. When returning `None` or error, gRPC
77     /// will continue to use the previous certificates returned by the method. If no
78     /// valid credentials is returned during initialization, the server will fail to start.
fetch(&self) -> std::result::Result<Option<ServerCredentialsBuilder>, Box<dyn StdError>>79     fn fetch(&self) -> std::result::Result<Option<ServerCredentialsBuilder>, Box<dyn StdError>>;
80 }
81 
82 impl CertificateRequestType {
83     #[inline]
to_native(self) -> grpc_ssl_client_certificate_request_type84     pub(crate) fn to_native(self) -> grpc_ssl_client_certificate_request_type {
85         unsafe { mem::transmute(self) }
86     }
87 }
88 
clear_key_securely(key: &mut [u8])89 fn clear_key_securely(key: &mut [u8]) {
90     unsafe {
91         for b in key {
92             ptr::write_volatile(b, 0)
93         }
94     }
95 }
96 
server_cert_fetcher_wrapper( user_data: *mut std::os::raw::c_void, config: *mut *mut grpc_ssl_server_certificate_config, ) -> grpc_ssl_certificate_config_reload_status97 pub(crate) unsafe extern "C" fn server_cert_fetcher_wrapper(
98     user_data: *mut std::os::raw::c_void,
99     config: *mut *mut grpc_ssl_server_certificate_config,
100 ) -> grpc_ssl_certificate_config_reload_status {
101     if user_data.is_null() {
102         panic!("fetcher user_data must be set up!");
103     }
104     let f: &mut dyn ServerCredentialsFetcher =
105         (*(user_data as *mut Box<dyn ServerCredentialsFetcher>)).as_mut();
106     let result = f.fetch();
107     match result {
108         Ok(Some(builder)) => {
109             let new_config = builder.build_config();
110             *config = new_config;
111         }
112         Ok(None) => {
113             return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED;
114         }
115         Err(e) => {
116             warn!("cert_fetcher met error: {}", e);
117             return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL;
118         }
119     }
120     GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW
121 }
122 
123 /// [`ServerCredentials`] factory in order to configure the properties.
124 pub struct ServerCredentialsBuilder {
125     root: Option<CString>,
126     key_cert_pairs: Vec<grpcio_sys::grpc_ssl_pem_key_cert_pair>,
127     cer_request_type: CertificateRequestType,
128 }
129 
130 impl ServerCredentialsBuilder {
131     /// Initialize a new [`ServerCredentialsBuilder`].
new() -> ServerCredentialsBuilder132     pub fn new() -> ServerCredentialsBuilder {
133         ServerCredentialsBuilder {
134             root: None,
135             key_cert_pairs: vec![],
136             cer_request_type: CertificateRequestType::DontRequestClientCertificate,
137         }
138     }
139 
140     /// Set the PEM encoded client root certificate to verify client's identity. If
141     /// `force_client_auth` is set to `true`, the authenticity of client check will be enforced.
root_cert<S: Into<Vec<u8>>>( mut self, cert: S, cer_request_type: CertificateRequestType, ) -> ServerCredentialsBuilder142     pub fn root_cert<S: Into<Vec<u8>>>(
143         mut self,
144         cert: S,
145         cer_request_type: CertificateRequestType,
146     ) -> ServerCredentialsBuilder {
147         self.root = Some(CString::new(cert).unwrap());
148         self.cer_request_type = cer_request_type;
149         self
150     }
151 
152     /// Add a PEM encoded server side certificate and key.
add_cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ServerCredentialsBuilder153     pub fn add_cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ServerCredentialsBuilder {
154         if private_key.capacity() == private_key.len() {
155             let mut nil_key = Vec::with_capacity(private_key.len() + 1);
156             nil_key.extend_from_slice(&private_key);
157             clear_key_securely(&mut private_key);
158             private_key = nil_key;
159         }
160         self.key_cert_pairs
161             .push(grpcio_sys::grpc_ssl_pem_key_cert_pair {
162                 private_key: CString::new(private_key).unwrap().into_raw(),
163                 cert_chain: CString::new(cert).unwrap().into_raw(),
164             });
165         self
166     }
167 
168     /// Finalize the [`ServerCredentialsBuilder`] and build the
169     /// [`*mut grpcio_sys::bindings::grpc_ssl_server_certificate_config`].
build_config(mut self) -> *mut grpcio_sys::grpc_ssl_server_certificate_config170     unsafe fn build_config(mut self) -> *mut grpcio_sys::grpc_ssl_server_certificate_config {
171         let root_cert = self
172             .root
173             .take()
174             .map_or_else(ptr::null_mut, CString::into_raw);
175         let cfg = grpcio_sys::grpc_ssl_server_certificate_config_create(
176             root_cert,
177             self.key_cert_pairs.as_ptr(),
178             self.key_cert_pairs.len(),
179         );
180         if !root_cert.is_null() {
181             drop(CString::from_raw(root_cert));
182         }
183         cfg
184     }
185 
186     /// Finalize the [`ServerCredentialsBuilder`] and build the [`ServerCredentials`].
build(self) -> ServerCredentials187     pub fn build(self) -> ServerCredentials {
188         unsafe {
189             let opt = grpcio_sys::grpc_ssl_server_credentials_create_options_using_config(
190                 self.cer_request_type.to_native(),
191                 self.build_config(),
192             );
193             let credentials = grpcio_sys::grpc_ssl_server_credentials_create_with_options(opt);
194             ServerCredentials::from_raw(credentials)
195         }
196     }
197 }
198 
199 impl Drop for ServerCredentialsBuilder {
drop(&mut self)200     fn drop(&mut self) {
201         for pair in self.key_cert_pairs.drain(..) {
202             unsafe {
203                 drop(CString::from_raw(pair.cert_chain as *mut _));
204                 let s = CString::from_raw(pair.private_key as *mut _);
205                 clear_key_securely(&mut s.into_bytes_with_nul());
206             }
207         }
208     }
209 }
210 
211 impl ServerCredentials {
212     /// Creates the credentials using a certificate config fetcher. Use this
213     /// method to reload the certificates and keys of the SSL server without
214     /// interrupting the operation of the server. Initial certificate config will be
215     /// fetched during server initialization.
with_fetcher( fetcher: Box<dyn ServerCredentialsFetcher + Send + Sync>, cer_request_type: CertificateRequestType, ) -> Self216     pub fn with_fetcher(
217         fetcher: Box<dyn ServerCredentialsFetcher + Send + Sync>,
218         cer_request_type: CertificateRequestType,
219     ) -> Self {
220         let fetcher_wrap = Box::new(fetcher);
221         let fetcher_wrap_ptr = Box::into_raw(fetcher_wrap);
222         unsafe {
223             let opt = grpcio_sys::grpc_ssl_server_credentials_create_options_using_config_fetcher(
224                 cer_request_type.to_native(),
225                 Some(server_cert_fetcher_wrapper),
226                 fetcher_wrap_ptr as _,
227             );
228             let mut creds = ServerCredentials::from_raw(
229                 grpcio_sys::grpc_ssl_server_credentials_create_with_options(opt),
230             );
231             creds._fetcher = Some(Box::from_raw(fetcher_wrap_ptr));
232             creds
233         }
234     }
235 }
236 
237 /// [`ChannelCredentials`] factory in order to configure the properties.
238 pub struct ChannelCredentialsBuilder {
239     root: Option<CString>,
240     cert_key_pair: Option<(CString, CString)>,
241 }
242 
243 impl ChannelCredentialsBuilder {
244     /// Initialize a new [`ChannelCredentialsBuilder`].
new() -> ChannelCredentialsBuilder245     pub fn new() -> ChannelCredentialsBuilder {
246         ChannelCredentialsBuilder {
247             root: None,
248             cert_key_pair: None,
249         }
250     }
251 
252     /// Set the PEM encoded server root certificate to verify server's identity.
root_cert(mut self, cert: Vec<u8>) -> ChannelCredentialsBuilder253     pub fn root_cert(mut self, cert: Vec<u8>) -> ChannelCredentialsBuilder {
254         self.root = Some(CString::new(cert).unwrap());
255         self
256     }
257 
258     /// Set the PEM encoded client side certificate and key.
cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ChannelCredentialsBuilder259     pub fn cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ChannelCredentialsBuilder {
260         if private_key.capacity() == private_key.len() {
261             let mut nil_key = Vec::with_capacity(private_key.len() + 1);
262             nil_key.extend_from_slice(&private_key);
263             clear_key_securely(&mut private_key);
264             private_key = nil_key;
265         }
266         self.cert_key_pair = Some((
267             CString::new(cert).unwrap(),
268             CString::new(private_key).unwrap(),
269         ));
270         self
271     }
272 
273     /// Finalize the [`ChannelCredentialsBuilder`] and build the [`ChannelCredentials`].
build(mut self) -> ChannelCredentials274     pub fn build(mut self) -> ChannelCredentials {
275         let root_ptr = self
276             .root
277             .take()
278             .map_or_else(ptr::null_mut, CString::into_raw);
279         let (cert_ptr, key_ptr) = self.cert_key_pair.take().map_or_else(
280             || (ptr::null_mut(), ptr::null_mut()),
281             |(cert, key)| (cert.into_raw(), key.into_raw()),
282         );
283 
284         let mut pair = grpcio_sys::grpc_ssl_pem_key_cert_pair {
285             private_key: key_ptr,
286             cert_chain: cert_ptr,
287         };
288         let creds = unsafe {
289             if cert_ptr.is_null() {
290                 grpcio_sys::grpc_ssl_credentials_create_ex(
291                     root_ptr,
292                     ptr::null_mut(),
293                     ptr::null_mut(),
294                     ptr::null_mut(),
295                 )
296             } else {
297                 grpcio_sys::grpc_ssl_credentials_create_ex(
298                     root_ptr,
299                     &mut pair,
300                     ptr::null_mut(),
301                     ptr::null_mut(),
302                 )
303             }
304         };
305 
306         if !root_ptr.is_null() {
307             unsafe {
308                 self.root = Some(CString::from_raw(root_ptr));
309             }
310         }
311 
312         if !cert_ptr.is_null() {
313             unsafe {
314                 let cert = CString::from_raw(cert_ptr);
315                 let key = CString::from_raw(key_ptr);
316                 self.cert_key_pair = Some((cert, key));
317             }
318         }
319 
320         ChannelCredentials { creds }
321     }
322 }
323 
324 impl Drop for ChannelCredentialsBuilder {
drop(&mut self)325     fn drop(&mut self) {
326         if let Some((_, key)) = self.cert_key_pair.take() {
327             clear_key_securely(&mut key.into_bytes_with_nul());
328         }
329     }
330 }
331 
332 impl ChannelCredentials {
333     /// Try to build a [`ChannelCredentials`] to authenticate with Google OAuth credentials.
google_default_credentials() -> Result<ChannelCredentials>334     pub fn google_default_credentials() -> Result<ChannelCredentials> {
335         // Initialize the runtime here. Because this is an associated method
336         // that can be called before construction of an `Environment`, we
337         // need to call this here too.
338         unsafe {
339             grpc_sys::grpc_init();
340         }
341         let creds = unsafe { grpc_sys::grpc_google_default_credentials_create(ptr::null_mut()) };
342         if creds.is_null() {
343             Err(Error::GoogleAuthenticationFailed)
344         } else {
345             Ok(ChannelCredentials { creds })
346         }
347     }
348 }
349