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_cert_verify_callback, SSL_CTX_set_cipher_list, 31 SSL_CTX_set_ciphersuites, SSL_CTX_up_ref, SSL_CTX_use_certificate_chain_file, 32 SSL_CTX_use_certificate_file, SSL_CTX, 33 }; 34 use crate::util::c_openssl::foreign::{Foreign, ForeignRef}; 35 use crate::util::c_openssl::{cert_verify, check_ptr, check_ret, ssl_init}; 36 use crate::util::config::tls::DefaultCertVerifier; 37 38 const SSL_CTRL_SET_MIN_PROTO_VERSION: c_int = 123; 39 const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124; 40 const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98; 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:!SHA1:!CBC", 96 )?; 97 builder.set_sigalgs_list()?; 98 99 Ok(builder) 100 } 101 102 /// Creates a `SslContextBuilder` from a `SSL_CTX`. from_ptr(ptr: *mut SSL_CTX) -> Self103 pub(crate) fn from_ptr(ptr: *mut SSL_CTX) -> Self { 104 SslContextBuilder(SslContext(ptr)) 105 } 106 107 /// Creates a `*mut SSL_CTX` from a `SSL_CTX`. as_ptr_mut(&mut self) -> *mut SSL_CTX108 pub(crate) fn as_ptr_mut(&mut self) -> *mut SSL_CTX { 109 self.0 .0 110 } 111 112 /// Builds a `SslContext`. build(self) -> SslContext113 pub(crate) fn build(self) -> SslContext { 114 self.0 115 } 116 set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>117 pub(crate) fn set_min_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> { 118 let ptr = self.as_ptr_mut(); 119 120 check_ret(unsafe { 121 SSL_CTX_ctrl( 122 ptr, 123 SSL_CTRL_SET_MIN_PROTO_VERSION, 124 version.0 as c_long, 125 ptr::null_mut(), 126 ) 127 } as c_int) 128 .map(|_| ()) 129 } 130 set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack>131 pub(crate) fn set_max_proto_version(&mut self, version: SslVersion) -> Result<(), ErrorStack> { 132 let ptr = self.as_ptr_mut(); 133 134 check_ret(unsafe { 135 SSL_CTX_ctrl( 136 ptr, 137 SSL_CTRL_SET_MAX_PROTO_VERSION, 138 version.0 as c_long, 139 ptr::null_mut(), 140 ) 141 } as c_int) 142 .map(|_| ()) 143 } 144 145 /// Loads trusted root certificates from a file.\ 146 /// Uses to Set default locations for trusted CA certificates. 147 /// 148 /// 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>,149 pub(crate) fn set_ca_file<P>(&mut self, file: P) -> Result<(), ErrorStack> 150 where 151 P: AsRef<Path>, 152 { 153 let file = Self::get_c_file(file)?; 154 let ptr = self.as_ptr_mut(); 155 check_ret(unsafe { 156 SSL_CTX_load_verify_locations(ptr, file.as_ptr() as *const _, ptr::null()) 157 }) 158 .map(|_| ()) 159 } 160 161 /// Sets the list of supported ciphers for protocols before `TLSv1.3`. set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack>162 pub(crate) fn set_cipher_list(&mut self, list: &str) -> Result<(), ErrorStack> { 163 let list = match CString::new(list) { 164 Ok(cstr) => cstr, 165 Err(_) => return Err(ErrorStack::get()), 166 }; 167 let ptr = self.as_ptr_mut(); 168 169 check_ret(unsafe { SSL_CTX_set_cipher_list(ptr, list.as_ptr() as *const _) }).map(|_| ()) 170 } 171 172 /// Sets the list of supported ciphers for the `TLSv1.3` protocol. set_cipher_suites(&mut self, list: &str) -> Result<(), ErrorStack>173 pub(crate) fn set_cipher_suites(&mut self, list: &str) -> Result<(), ErrorStack> { 174 let list = match CString::new(list) { 175 Ok(cstr) => cstr, 176 Err(_) => return Err(ErrorStack::get()), 177 }; 178 let ptr = self.as_ptr_mut(); 179 180 check_ret(unsafe { SSL_CTX_set_ciphersuites(ptr, list.as_ptr() as *const _) }).map(|_| ()) 181 } 182 183 /// Loads a leaf certificate from a file. 184 /// 185 /// Only a single certificate will be loaded - use `add_extra_chain_cert` to 186 /// add the remainder of the certificate chain, or 187 /// `set_certificate_chain_file` to load the entire chain from a 188 /// single file. set_certificate_file<P>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> where P: AsRef<Path>,189 pub(crate) fn set_certificate_file<P>( 190 &mut self, 191 file: P, 192 file_type: SslFiletype, 193 ) -> Result<(), ErrorStack> 194 where 195 P: AsRef<Path>, 196 { 197 let file = Self::get_c_file(file)?; 198 let ptr = self.as_ptr_mut(); 199 check_ret(unsafe { 200 SSL_CTX_use_certificate_file(ptr, file.as_ptr() as *const _, file_type.as_raw()) 201 }) 202 .map(|_| ()) 203 } 204 205 /// Loads a certificate chain from file into ctx. 206 /// The certificates must be in PEM format and must be sorted starting with 207 /// the subject's certificate (actual client or server certificate), 208 /// followed by intermediate CA certificates if applicable, and ending 209 /// at the highest level (root) CA. set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack> where P: AsRef<Path>,210 pub(crate) fn set_certificate_chain_file<P>(&mut self, file: P) -> Result<(), ErrorStack> 211 where 212 P: AsRef<Path>, 213 { 214 let file = Self::get_c_file(file)?; 215 let ptr = self.as_ptr_mut(); 216 check_ret(unsafe { SSL_CTX_use_certificate_chain_file(ptr, file.as_ptr() as *const _) }) 217 .map(|_| ()) 218 } 219 get_c_file<P>(file: P) -> Result<CString, ErrorStack> where P: AsRef<Path>,220 pub(crate) fn get_c_file<P>(file: P) -> Result<CString, ErrorStack> 221 where 222 P: AsRef<Path>, 223 { 224 let path = match file.as_ref().as_os_str().to_str() { 225 Some(path) => path, 226 None => return Err(ErrorStack::get()), 227 }; 228 match CString::new(path) { 229 Ok(path) => Ok(path), 230 Err(_) => Err(ErrorStack::get()), 231 } 232 } 233 234 /// Sets the protocols to sent to the server for Application Layer Protocol 235 /// Negotiation (ALPN). set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack>236 pub(crate) fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { 237 assert!(protocols.len() <= c_uint::max_value() as usize); 238 239 let ptr = self.as_ptr_mut(); 240 match unsafe { SSL_CTX_set_alpn_protos(ptr, protocols.as_ptr(), protocols.len() as c_uint) } 241 { 242 0 => Ok(()), 243 _ => Err(ErrorStack::get()), 244 } 245 } 246 set_verify(&mut self, mode: c_int)247 pub(crate) fn set_verify(&mut self, mode: c_int) { 248 let ptr = self.as_ptr_mut(); 249 unsafe { SSL_CTX_set_verify(ptr, mode, None) }; 250 } 251 set_cert_verify_callback(&mut self, verifier: *const DefaultCertVerifier)252 pub(crate) fn set_cert_verify_callback(&mut self, verifier: *const DefaultCertVerifier) { 253 let ptr = self.as_ptr_mut(); 254 unsafe { 255 SSL_CTX_set_cert_verify_callback(ptr, cert_verify, verifier as *mut c_void); 256 } 257 } 258 set_cert_store(&mut self, cert_store: X509Store)259 pub(crate) fn set_cert_store(&mut self, cert_store: X509Store) { 260 let ptr = self.as_ptr_mut(); 261 unsafe { 262 SSL_CTX_set_cert_store(ptr, cert_store.as_ptr()); 263 mem::forget(cert_store); 264 } 265 } 266 cert_store_mut(&mut self) -> &mut X509StoreRef267 pub(crate) fn cert_store_mut(&mut self) -> &mut X509StoreRef { 268 let ptr = self.as_ptr_mut(); 269 unsafe { X509StoreRef::from_ptr_mut(SSL_CTX_get_cert_store(ptr)) } 270 } 271 set_sigalgs_list(&mut self) -> Result<(), ErrorStack>272 pub(crate) fn set_sigalgs_list(&mut self) -> Result<(), ErrorStack> { 273 // Allowed signature algorithms: 274 // ecdsa_secp256r1_sha256 (0x0403) 275 // ecdsa_secp384r1_sha384 (0x0503) 276 // ecdsa_secp521r1_sha512 (0x0603) 277 // ed25519 (0x0807) 278 // ed448 (0x0808) 279 // rsa_pss_pss_sha256 (0x0809) 280 // rsa_pss_pss_sha384 (0x080a) 281 // rsa_pss_pss_sha512 (0x080b) 282 // rsa_pss_rsae_sha256 (0x0804) 283 // rsa_pss_rsae_sha384 (0x0805) 284 // rsa_pss_rsae_sha512 (0x0806) 285 // rsa_pkcs1_sha256 (0x0401) 286 // rsa_pkcs1_sha384 (0x0501) 287 // rsa_pkcs1_sha512 (0x0601) 288 // SHA256 DSA (0x0402) 289 // SHA384 DSA (0x0502) 290 // SHA512 DSA (0x0602) 291 const SUPPORT_SIGNATURE_ALGORITHMS: &str = "\ 292 ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:\ 293 ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:\ 294 rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:\ 295 rsa_pss_rsae_sha512:rsa_pkcs1_sha256:rsa_pkcs1_sha384:rsa_pkcs1_sha512:DSA+SHA256:DSA+SHA384:DSA+SHA512"; 296 let list = match CString::new(SUPPORT_SIGNATURE_ALGORITHMS) { 297 Ok(cstr) => cstr, 298 Err(_) => return Err(ErrorStack::get()), 299 }; 300 301 let ptr = self.as_ptr_mut(); 302 303 check_ret(unsafe { 304 SSL_CTX_ctrl( 305 ptr, 306 SSL_CTRL_SET_SIGALGS_LIST, 307 0, 308 list.as_ptr() as *const c_void as *mut c_void, 309 ) 310 } as c_int) 311 .map(|_| ()) 312 } 313 } 314