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