• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use core::{fmt, mem, ptr};
15 use std::ffi::CString;
16 use std::path::Path;
17 
18 use libc::{c_int, c_uint, c_void};
19 
20 use super::filetype::SslFiletype;
21 use super::method::SslMethod;
22 use super::version::SslVersion;
23 use crate::c_openssl::ffi::ssl::{
24     SSL_CTX_free, SSL_CTX_get_cert_store, SSL_CTX_set_default_verify_paths, SSL_CTX_set_verify,
25 };
26 use crate::c_openssl::x509::{X509Store, X509StoreRef};
27 use crate::util::c_openssl::error::ErrorStack;
28 #[cfg(feature = "__c_openssl")]
29 use crate::util::c_openssl::ffi::ssl::SSL_CTX_ctrl;
30 use crate::util::c_openssl::ffi::ssl::{
31     SSL_CTX_load_verify_locations, SSL_CTX_new, SSL_CTX_set_alpn_protos, SSL_CTX_set_cert_store,
32     SSL_CTX_set_cert_verify_callback, SSL_CTX_set_cipher_list, SSL_CTX_up_ref,
33     SSL_CTX_use_certificate_chain_file, SSL_CTX_use_certificate_file, SSL_CTX,
34 };
35 #[cfg(feature = "c_boringssl")]
36 use crate::util::c_openssl::ffi::ssl::{
37     SSL_CTX_set1_sigalgs_list, SSL_CTX_set_max_proto_version, SSL_CTX_set_min_proto_version,
38 };
39 use crate::util::c_openssl::foreign::{Foreign, ForeignRef};
40 use crate::util::c_openssl::{cert_verify, check_ptr, check_ret, ssl_init};
41 use crate::util::config::tls::DefaultCertVerifier;
42 
43 #[cfg(feature = "__c_openssl")]
44 const SSL_CTRL_SET_MIN_PROTO_VERSION: c_int = 123;
45 #[cfg(feature = "__c_openssl")]
46 const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124;
47 #[cfg(feature = "__c_openssl")]
48 const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98;
49 
50 foreign_type!(
51     type CStruct = SSL_CTX;
52     fn drop = SSL_CTX_free;
53     pub(crate) struct SslContext;
54     pub(crate) struct SslContextRef;
55 );
56 
57 impl SslContext {
builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack>58     pub(crate) fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
59         SslContextBuilder::new(method)
60     }
61 }
62 
63 // TODO: add useful info here.
64 impl fmt::Debug for SslContext {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result65     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
66         write!(fmt, "SslContext")
67     }
68 }
69 
70 impl Clone for SslContext {
clone(&self) -> Self71     fn clone(&self) -> Self {
72         (**self).to_owned()
73     }
74 }
75 
76 impl ToOwned for SslContextRef {
77     type Owned = SslContext;
78 
to_owned(&self) -> Self::Owned79     fn to_owned(&self) -> Self::Owned {
80         unsafe {
81             SSL_CTX_up_ref(self.as_ptr());
82             SslContext::from_ptr(self.as_ptr())
83         }
84     }
85 }
86 
87 pub(crate) const SSL_VERIFY_NONE: c_int = 0;
88 pub(crate) const SSL_VERIFY_PEER: c_int = 1;
89 
90 /// A builder for `SslContext`.
91 pub(crate) struct SslContextBuilder(SslContext);
92 
93 impl SslContextBuilder {
new(method: SslMethod) -> Result<Self, ErrorStack>94     pub(crate) fn new(method: SslMethod) -> Result<Self, ErrorStack> {
95         ssl_init();
96 
97         let ptr = check_ptr(unsafe { SSL_CTX_new(method.as_ptr()) })?;
98         check_ret(unsafe { SSL_CTX_set_default_verify_paths(ptr) })?;
99 
100         let mut builder = Self::from_ptr(ptr);
101         builder.set_verify(SSL_VERIFY_PEER);
102         builder.set_cipher_list(
103             "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK:!SHA1:!CBC",
104         )?;
105         builder.set_sigalgs_list()?;
106 
107         Ok(builder)
108     }
109 
110     /// Creates a `SslContextBuilder` from a `SSL_CTX`.
from_ptr(ptr: *mut SSL_CTX) -> Self111     pub(crate) fn from_ptr(ptr: *mut SSL_CTX) -> Self {
112         SslContextBuilder(SslContext(ptr))
113     }
114 
115     /// Creates a `*mut SSL_CTX` from a `SSL_CTX`.
as_ptr_mut(&mut self) -> *mut SSL_CTX116     pub(crate) fn as_ptr_mut(&mut self) -> *mut SSL_CTX {
117         self.0 .0
118     }
119 
120     /// Builds a `SslContext`.
build(self) -> SslContext121     pub(crate) fn build(self) -> SslContext {
122         self.0
123     }
124 
set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>125     pub(crate) fn set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> {
126         let ptr = self.as_ptr_mut();
127 
128         #[cfg(feature = "__c_openssl")]
129         return check_ret(unsafe {
130             SSL_CTX_ctrl(
131                 ptr,
132                 SSL_CTRL_SET_MIN_PROTO_VERSION,
133                 version.0 as libc::c_long,
134                 ptr::null_mut(),
135             )
136         } as c_int)
137         .map(|_| ());
138 
139         #[cfg(feature = "c_boringssl")]
140         return check_ret(
141             unsafe { SSL_CTX_set_min_proto_version(ptr, version.0 as libc::c_ushort) } as c_int,
142         )
143         .map(|_| ());
144     }
145 
set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>146     pub(crate) fn set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> {
147         let ptr = self.as_ptr_mut();
148 
149         #[cfg(feature = "__c_openssl")]
150         return check_ret(unsafe {
151             SSL_CTX_ctrl(
152                 ptr,
153                 SSL_CTRL_SET_MAX_PROTO_VERSION,
154                 version.0 as libc::c_long,
155                 ptr::null_mut(),
156             )
157         } as c_int)
158         .map(|_| ());
159         #[cfg(feature = "c_boringssl")]
160         return check_ret(
161             unsafe { SSL_CTX_set_max_proto_version(ptr, version.0 as libc::c_ushort) } as c_int,
162         )
163         .map(|_| ());
164     }
165 
166     /// Loads trusted root certificates from a file.\
167     /// Uses to Set default locations for trusted CA certificates.
168     ///
169     /// The file should contain a sequence of PEM-formatted CA certificates.
set_ca_file<P>(&mut self, file: P) -> Result<(), ErrorStack> where P: AsRef<Path>,170     pub(crate) fn set_ca_file<P>(&mut self, file: P) -> Result<(), ErrorStack>
171     where
172         P: AsRef<Path>,
173     {
174         let file = Self::get_c_file(file)?;
175         let ptr = self.as_ptr_mut();
176         check_ret(unsafe {
177             SSL_CTX_load_verify_locations(ptr, file.as_ptr() as *const _, ptr::null())
178         })
179         .map(|_| ())
180     }
181 
182     /// Sets the list of supported ciphers for protocols before `TLSv1.3`.
set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack>183     pub(crate) fn set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack> {
184         let list = match CString::new(list) {
185             Ok(cstr) => cstr,
186             Err(_) => return Err(ErrorStack::get()),
187         };
188         let ptr = self.as_ptr_mut();
189 
190         check_ret(unsafe { SSL_CTX_set_cipher_list(ptr, list.as_ptr() as *const _) }).map(|_| ())
191     }
192 
193     /// Loads a leaf certificate from a file.
194     ///
195     /// Only a single certificate will be loaded - use `add_extra_chain_cert` to
196     /// add the remainder of the certificate chain, or
197     /// `set_certificate_chain_file` to load the entire chain from a
198     /// single file.
set_certificate_file<P>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> where P: AsRef<Path>,199     pub(crate) fn set_certificate_file<P>(
200         &mut self,
201         file: P,
202         file_type: SslFiletype,
203     ) -> Result<(), ErrorStack>
204     where
205         P: AsRef<Path>,
206     {
207         let file = Self::get_c_file(file)?;
208         let ptr = self.as_ptr_mut();
209         check_ret(unsafe {
210             SSL_CTX_use_certificate_file(ptr, file.as_ptr() as *const _, file_type.as_raw())
211         })
212         .map(|_| ())
213     }
214 
215     /// Loads a certificate chain from file into ctx.
216     /// The certificates must be in PEM format and must be sorted starting with
217     /// the subject's certificate (actual client or server certificate),
218     /// followed by intermediate CA certificates if applicable, and ending
219     /// at the highest level (root) CA.
set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack> where P: AsRef<Path>,220     pub(crate) fn set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack>
221     where
222         P: AsRef<Path>,
223     {
224         let file = Self::get_c_file(file)?;
225         let ptr = self.as_ptr_mut();
226         check_ret(unsafe { SSL_CTX_use_certificate_chain_file(ptr, file.as_ptr() as *const _) })
227             .map(|_| ())
228     }
229 
get_c_file<P>(file: P) -> Result<CString, ErrorStack> where P: AsRef<Path>,230     pub(crate) fn get_c_file<P>(file: P) -> Result<CString, ErrorStack>
231     where
232         P: AsRef<Path>,
233     {
234         let path = match file.as_ref().as_os_str().to_str() {
235             Some(path) => path,
236             None => return Err(ErrorStack::get()),
237         };
238         match CString::new(path) {
239             Ok(path) => Ok(path),
240             Err(_) => Err(ErrorStack::get()),
241         }
242     }
243 
244     /// Sets the protocols to sent to the server for Application Layer Protocol
245     /// Negotiation (ALPN).
set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack>246     pub(crate) fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
247         assert!(protocols.len() <= c_uint::max_value() as usize);
248 
249         let ptr = self.as_ptr_mut();
250         match unsafe { SSL_CTX_set_alpn_protos(ptr, protocols.as_ptr(), protocols.len() as c_uint) }
251         {
252             0 => Ok(()),
253             _ => Err(ErrorStack::get()),
254         }
255     }
256 
set_verify(&mut self, mode: c_int)257     pub(crate) fn set_verify(&mut self, mode: c_int) {
258         let ptr = self.as_ptr_mut();
259         unsafe { SSL_CTX_set_verify(ptr, mode, None) };
260     }
261 
set_cert_verify_callback(&mut self, verifier: *const DefaultCertVerifier)262     pub(crate) fn set_cert_verify_callback(&mut self, verifier: *const DefaultCertVerifier) {
263         let ptr = self.as_ptr_mut();
264         unsafe {
265             SSL_CTX_set_cert_verify_callback(ptr, cert_verify, verifier as *mut c_void);
266         }
267     }
268 
set_cert_store(&mut self, cert_store: X509Store)269     pub(crate) fn set_cert_store(&mut self, cert_store: X509Store) {
270         let ptr = self.as_ptr_mut();
271         unsafe {
272             SSL_CTX_set_cert_store(ptr, cert_store.as_ptr());
273             mem::forget(cert_store);
274         }
275     }
276 
cert_store_mut(&mut self) -> &mut X509StoreRef277     pub(crate) fn cert_store_mut(&mut self) -> &mut X509StoreRef {
278         let ptr = self.as_ptr_mut();
279         unsafe { X509StoreRef::from_ptr_mut(SSL_CTX_get_cert_store(ptr)) }
280     }
281 
set_sigalgs_list(&mut self) -> Result<(), ErrorStack>282     pub(crate) fn set_sigalgs_list(&mut self) -> Result<(), ErrorStack> {
283         // Allowed signature algorithms:
284         // ecdsa_secp256r1_sha256 (0x0403)
285         // ecdsa_secp384r1_sha384 (0x0503)
286         // ecdsa_secp521r1_sha512 (0x0603)
287         // ed25519 (0x0807)
288         // ed448 (0x0808)
289         // rsa_pss_pss_sha256 (0x0809)
290         // rsa_pss_pss_sha384 (0x080a)
291         // rsa_pss_pss_sha512 (0x080b)
292         // rsa_pss_rsae_sha256 (0x0804)
293         // rsa_pss_rsae_sha384 (0x0805)
294         // rsa_pss_rsae_sha512 (0x0806)
295         // rsa_pkcs1_sha256 (0x0401)
296         // rsa_pkcs1_sha384 (0x0501)
297         // rsa_pkcs1_sha512 (0x0601)
298         // SHA256 DSA (0x0402)
299         // SHA384 DSA (0x0502)
300         // SHA512 DSA (0x0602)
301         const SUPPORT_SIGNATURE_ALGORITHMS: &str = "\
302         ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:\
303         rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:\
304         rsa_pss_rsae_sha512:rsa_pkcs1_sha256:rsa_pkcs1_sha384:rsa_pkcs1_sha512";
305         let list = match CString::new(SUPPORT_SIGNATURE_ALGORITHMS) {
306             Ok(cstr) => cstr,
307             Err(_) => return Err(ErrorStack::get()),
308         };
309 
310         let ptr = self.as_ptr_mut();
311         #[cfg(feature = "__c_openssl")]
312         return check_ret(unsafe {
313             SSL_CTX_ctrl(
314                 ptr,
315                 SSL_CTRL_SET_SIGALGS_LIST,
316                 0,
317                 list.as_ptr() as *const c_void as *mut c_void,
318             )
319         } as c_int)
320         .map(|_| ());
321         #[cfg(feature = "c_boringssl")]
322         return check_ret(unsafe {
323             SSL_CTX_set1_sigalgs_list(ptr, list.as_ptr() as *const c_void as *mut c_void)
324         } as c_int)
325         .map(|_| ());
326     }
327 }
328