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