• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_channel_credentials, grpc_server_credentials,
12     grpc_ssl_client_certificate_request_type, grpc_ssl_server_certificate_config,
13 };
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         (&mut *(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             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         let credentials = 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             grpcio_sys::grpc_ssl_server_credentials_create_with_options(opt)
194         };
195 
196         ServerCredentials { creds: credentials }
197     }
198 }
199 
200 impl Drop for ServerCredentialsBuilder {
drop(&mut self)201     fn drop(&mut self) {
202         for pair in self.key_cert_pairs.drain(..) {
203             unsafe {
204                 CString::from_raw(pair.cert_chain as *mut _);
205                 let s = CString::from_raw(pair.private_key as *mut _);
206                 clear_key_securely(&mut s.into_bytes_with_nul());
207             }
208         }
209     }
210 }
211 
212 /// Server-side SSL credentials.
213 ///
214 /// Use [`ServerCredentialsBuilder`] to build a [`ServerCredentials`].
215 pub struct ServerCredentials {
216     creds: *mut grpc_server_credentials,
217 }
218 
219 unsafe impl Send for ServerCredentials {}
220 
221 impl ServerCredentials {
frow_raw(creds: *mut grpc_server_credentials) -> ServerCredentials222     pub(crate) unsafe fn frow_raw(creds: *mut grpc_server_credentials) -> ServerCredentials {
223         ServerCredentials { creds }
224     }
225 
as_mut_ptr(&mut self) -> *mut grpc_server_credentials226     pub fn as_mut_ptr(&mut self) -> *mut grpc_server_credentials {
227         self.creds
228     }
229 }
230 
231 impl Drop for ServerCredentials {
drop(&mut self)232     fn drop(&mut self) {
233         unsafe {
234             grpc_sys::grpc_server_credentials_release(self.creds);
235         }
236     }
237 }
238 
239 /// [`ChannelCredentials`] factory in order to configure the properties.
240 pub struct ChannelCredentialsBuilder {
241     root: Option<CString>,
242     cert_key_pair: Option<(CString, CString)>,
243 }
244 
245 impl ChannelCredentialsBuilder {
246     /// Initialize a new [`ChannelCredentialsBuilder`].
new() -> ChannelCredentialsBuilder247     pub fn new() -> ChannelCredentialsBuilder {
248         ChannelCredentialsBuilder {
249             root: None,
250             cert_key_pair: None,
251         }
252     }
253 
254     /// Set the PEM encoded server root certificate to verify server's identity.
root_cert(mut self, cert: Vec<u8>) -> ChannelCredentialsBuilder255     pub fn root_cert(mut self, cert: Vec<u8>) -> ChannelCredentialsBuilder {
256         self.root = Some(CString::new(cert).unwrap());
257         self
258     }
259 
260     /// Set the PEM encoded client side certificate and key.
cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ChannelCredentialsBuilder261     pub fn cert(mut self, cert: Vec<u8>, mut private_key: Vec<u8>) -> ChannelCredentialsBuilder {
262         if private_key.capacity() == private_key.len() {
263             let mut nil_key = Vec::with_capacity(private_key.len() + 1);
264             nil_key.extend_from_slice(&private_key);
265             clear_key_securely(&mut private_key);
266             private_key = nil_key;
267         }
268         self.cert_key_pair = Some((
269             CString::new(cert).unwrap(),
270             CString::new(private_key).unwrap(),
271         ));
272         self
273     }
274 
275     /// Finalize the [`ChannelCredentialsBuilder`] and build the [`ChannelCredentials`].
build(mut self) -> ChannelCredentials276     pub fn build(mut self) -> ChannelCredentials {
277         let root_ptr = self
278             .root
279             .take()
280             .map_or_else(ptr::null_mut, CString::into_raw);
281         let (cert_ptr, key_ptr) = self.cert_key_pair.take().map_or_else(
282             || (ptr::null_mut(), ptr::null_mut()),
283             |(cert, key)| (cert.into_raw(), key.into_raw()),
284         );
285 
286         let mut pair = grpcio_sys::grpc_ssl_pem_key_cert_pair {
287             private_key: key_ptr,
288             cert_chain: cert_ptr,
289         };
290         let creds = unsafe {
291             if cert_ptr.is_null() {
292                 grpcio_sys::grpc_ssl_credentials_create_ex(
293                     root_ptr,
294                     ptr::null_mut(),
295                     ptr::null_mut(),
296                     ptr::null_mut(),
297                 )
298             } else {
299                 grpcio_sys::grpc_ssl_credentials_create_ex(
300                     root_ptr,
301                     &mut pair,
302                     ptr::null_mut(),
303                     ptr::null_mut(),
304                 )
305             }
306         };
307 
308         if !root_ptr.is_null() {
309             unsafe {
310                 self.root = Some(CString::from_raw(root_ptr));
311             }
312         }
313 
314         if !cert_ptr.is_null() {
315             unsafe {
316                 let cert = CString::from_raw(cert_ptr);
317                 let key = CString::from_raw(key_ptr);
318                 self.cert_key_pair = Some((cert, key));
319             }
320         }
321 
322         ChannelCredentials { creds }
323     }
324 }
325 
326 impl Drop for ChannelCredentialsBuilder {
drop(&mut self)327     fn drop(&mut self) {
328         if let Some((_, key)) = self.cert_key_pair.take() {
329             clear_key_securely(&mut key.into_bytes_with_nul());
330         }
331     }
332 }
333 
334 /// Client-side SSL credentials.
335 ///
336 /// Use [`ChannelCredentialsBuilder`] or [`ChannelCredentials::google_default_credentials`] to
337 /// build a [`ChannelCredentials`].
338 pub struct ChannelCredentials {
339     creds: *mut grpc_channel_credentials,
340 }
341 
342 impl ChannelCredentials {
as_mut_ptr(&mut self) -> *mut grpc_channel_credentials343     pub fn as_mut_ptr(&mut self) -> *mut grpc_channel_credentials {
344         self.creds
345     }
346 
347     /// Try to build a [`ChannelCredentials`] to authenticate with Google OAuth credentials.
google_default_credentials() -> Result<ChannelCredentials>348     pub fn google_default_credentials() -> Result<ChannelCredentials> {
349         // Initialize the runtime here. Because this is an associated method
350         // that can be called before construction of an `Environment`, we
351         // need to call this here too.
352         unsafe {
353             grpc_sys::grpc_init();
354         }
355         let creds = unsafe { grpc_sys::grpc_google_default_credentials_create(ptr::null_mut()) };
356         if creds.is_null() {
357             Err(Error::GoogleAuthenticationFailed)
358         } else {
359             Ok(ChannelCredentials { creds })
360         }
361     }
362 }
363 
364 impl Drop for ChannelCredentials {
drop(&mut self)365     fn drop(&mut self) {
366         unsafe { grpc_sys::grpc_channel_credentials_release(self.creds) }
367     }
368 }
369