• 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_long, 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 use crate::util::c_openssl::ffi::ssl::{
29     SSL_CTX_ctrl, SSL_CTX_load_verify_locations, SSL_CTX_new, SSL_CTX_set_alpn_protos,
30     SSL_CTX_set_cert_store, SSL_CTX_set_cipher_list, SSL_CTX_set_ciphersuites, SSL_CTX_up_ref,
31     SSL_CTX_use_certificate_chain_file, SSL_CTX_use_certificate_file, SSL_CTX,
32 };
33 use crate::util::c_openssl::foreign::{Foreign, ForeignRef};
34 use crate::util::c_openssl::x509::{X509Ref, X509};
35 use crate::util::c_openssl::{check_ptr, check_ret, ssl_init};
36 
37 const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
38 
39 const SSL_CTRL_SET_MIN_PROTO_VERSION: c_int = 123;
40 const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124;
41 
42 foreign_type!(
43     type CStruct = SSL_CTX;
44     fn drop = SSL_CTX_free;
45     pub(crate) struct SslContext;
46     pub(crate) struct SslContextRef;
47 );
48 
49 impl SslContext {
builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack>50     pub(crate) fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
51         SslContextBuilder::new(method)
52     }
53 }
54 
55 // TODO: add useful info here.
56 impl fmt::Debug for SslContext {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result57     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
58         write!(fmt, "SslContext")
59     }
60 }
61 
62 impl Clone for SslContext {
clone(&self) -> Self63     fn clone(&self) -> Self {
64         (**self).to_owned()
65     }
66 }
67 
68 impl ToOwned for SslContextRef {
69     type Owned = SslContext;
70 
to_owned(&self) -> Self::Owned71     fn to_owned(&self) -> Self::Owned {
72         unsafe {
73             SSL_CTX_up_ref(self.as_ptr());
74             SslContext::from_ptr(self.as_ptr())
75         }
76     }
77 }
78 
79 pub(crate) const SSL_VERIFY_NONE: c_int = 0;
80 pub(crate) const SSL_VERIFY_PEER: c_int = 1;
81 
82 /// A builder for `SslContext`.
83 pub(crate) struct SslContextBuilder(SslContext);
84 
85 impl SslContextBuilder {
new(method: SslMethod) -> Result<Self, ErrorStack>86     pub(crate) fn new(method: SslMethod) -> Result<Self, ErrorStack> {
87         ssl_init();
88 
89         let ptr = check_ptr(unsafe { SSL_CTX_new(method.as_ptr()) })?;
90         check_ret(unsafe { SSL_CTX_set_default_verify_paths(ptr) })?;
91 
92         let mut builder = Self::from_ptr(ptr);
93         builder.set_verify(SSL_VERIFY_PEER);
94         builder.set_cipher_list(
95             "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK",
96         )?;
97 
98         Ok(builder)
99     }
100 
101     /// Creates a `SslContextBuilder` from a `SSL_CTX`.
from_ptr(ptr: *mut SSL_CTX) -> Self102     pub(crate) fn from_ptr(ptr: *mut SSL_CTX) -> Self {
103         SslContextBuilder(SslContext(ptr))
104     }
105 
106     /// Creates a `*mut SSL_CTX` from a `SSL_CTX`.
as_ptr_mut(&mut self) -> *mut SSL_CTX107     pub(crate) fn as_ptr_mut(&mut self) -> *mut SSL_CTX {
108         self.0 .0
109     }
110 
111     /// Builds a `SslContext`.
build(self) -> SslContext112     pub(crate) fn build(self) -> SslContext {
113         self.0
114     }
115 
set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>116     pub(crate) fn set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> {
117         let ptr = self.as_ptr_mut();
118 
119         check_ret(unsafe {
120             SSL_CTX_ctrl(
121                 ptr,
122                 SSL_CTRL_SET_MIN_PROTO_VERSION,
123                 version.0 as c_long,
124                 ptr::null_mut(),
125             )
126         } as c_int)
127         .map(|_| ())
128     }
129 
set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>130     pub(crate) fn set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> {
131         let ptr = self.as_ptr_mut();
132 
133         check_ret(unsafe {
134             SSL_CTX_ctrl(
135                 ptr,
136                 SSL_CTRL_SET_MAX_PROTO_VERSION,
137                 version.0 as c_long,
138                 ptr::null_mut(),
139             )
140         } as c_int)
141         .map(|_| ())
142     }
143 
144     /// Loads trusted root certificates from a file.\
145     /// Uses to Set default locations for trusted CA certificates.
146     ///
147     /// 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>,148     pub(crate) fn set_ca_file<P>(&mut self, file: P) -> Result<(), ErrorStack>
149     where
150         P: AsRef<Path>,
151     {
152         let path = match file.as_ref().as_os_str().to_str() {
153             Some(path) => path,
154             None => return Err(ErrorStack::get()),
155         };
156         let file = match CString::new(path) {
157             Ok(path) => path,
158             Err(_) => return Err(ErrorStack::get()),
159         };
160         let ptr = self.as_ptr_mut();
161 
162         check_ret(unsafe {
163             SSL_CTX_load_verify_locations(ptr, file.as_ptr() as *const _, ptr::null())
164         })
165         .map(|_| ())
166     }
167 
168     /// Sets the list of supported ciphers for protocols before `TLSv1.3`.
set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack>169     pub(crate) fn set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack> {
170         let list = match CString::new(list) {
171             Ok(cstr) => cstr,
172             Err(_) => return Err(ErrorStack::get()),
173         };
174         let ptr = self.as_ptr_mut();
175 
176         check_ret(unsafe { SSL_CTX_set_cipher_list(ptr, list.as_ptr() as *const _) }).map(|_| ())
177     }
178 
179     /// Sets the list of supported ciphers for the `TLSv1.3` protocol.
set_cipher_suites(&mut self, list: &str) -> Result<(), ErrorStack>180     pub(crate) fn set_cipher_suites(&mut self, list: &str) -> Result<(), ErrorStack> {
181         let list = match CString::new(list) {
182             Ok(cstr) => cstr,
183             Err(_) => return Err(ErrorStack::get()),
184         };
185         let ptr = self.as_ptr_mut();
186 
187         check_ret(unsafe { SSL_CTX_set_ciphersuites(ptr, list.as_ptr() as *const _) }).map(|_| ())
188     }
189 
190     /// Loads a leaf certificate from a file.
191     ///
192     /// Only a single certificate will be loaded - use `add_extra_chain_cert` to
193     /// add the remainder of the certificate chain, or
194     /// `set_certificate_chain_file` to load the entire chain from a
195     /// single file.
set_certificate_file<P>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> where P: AsRef<Path>,196     pub(crate) fn set_certificate_file<P>(
197         &mut self,
198         file: P,
199         file_type: SslFiletype,
200     ) -> Result<(), ErrorStack>
201     where
202         P: AsRef<Path>,
203     {
204         let path = match file.as_ref().as_os_str().to_str() {
205             Some(path) => path,
206             None => return Err(ErrorStack::get()),
207         };
208         let file = match CString::new(path) {
209             Ok(path) => path,
210             Err(_) => return Err(ErrorStack::get()),
211         };
212         let ptr = self.as_ptr_mut();
213 
214         check_ret(unsafe {
215             SSL_CTX_use_certificate_file(ptr, file.as_ptr() as *const _, file_type.as_raw())
216         })
217         .map(|_| ())
218     }
219 
220     /// Loads a certificate chain from file into ctx.
221     /// The certificates must be in PEM format and must be sorted starting with
222     /// the subject's certificate (actual client or server certificate),
223     /// followed by intermediate CA certificates if applicable, and ending
224     /// at the highest level (root) CA.
set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack> where P: AsRef<Path>,225     pub(crate) fn set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack>
226     where
227         P: AsRef<Path>,
228     {
229         let path = match file.as_ref().as_os_str().to_str() {
230             Some(path) => path,
231             None => return Err(ErrorStack::get()),
232         };
233         let file = match CString::new(path) {
234             Ok(path) => path,
235             Err(_) => return Err(ErrorStack::get()),
236         };
237         let ptr = self.as_ptr_mut();
238 
239         check_ret(unsafe { SSL_CTX_use_certificate_chain_file(ptr, file.as_ptr() as *const _) })
240             .map(|_| ())
241     }
242 
243     /// Sets the protocols to sent to the server for Application Layer Protocol
244     /// Negotiation (ALPN).
set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack>245     pub(crate) fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
246         assert!(protocols.len() <= c_uint::max_value() as usize);
247 
248         let ptr = self.as_ptr_mut();
249         match unsafe { SSL_CTX_set_alpn_protos(ptr, protocols.as_ptr(), protocols.len() as c_uint) }
250         {
251             0 => Ok(()),
252             _ => Err(ErrorStack::get()),
253         }
254     }
255 
set_verify(&mut self, mode: c_int)256     pub(crate) fn set_verify(&mut self, mode: c_int) {
257         let ptr = self.as_ptr_mut();
258         unsafe { SSL_CTX_set_verify(ptr, mode, None) };
259     }
260 
set_cert_store(&mut self, cert_store: X509Store)261     pub(crate) fn set_cert_store(&mut self, cert_store: X509Store) {
262         let ptr = self.as_ptr_mut();
263         unsafe {
264             SSL_CTX_set_cert_store(ptr, cert_store.as_ptr());
265             mem::forget(cert_store);
266         }
267     }
268 
cert_store_mut(&mut self) -> &mut X509StoreRef269     pub(crate) fn cert_store_mut(&mut self) -> &mut X509StoreRef {
270         let ptr = self.as_ptr_mut();
271         unsafe { X509StoreRef::from_ptr_mut(SSL_CTX_get_cert_store(ptr)) }
272     }
273 }
274