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::{ffi, fmt, ptr, str}; 15 use std::net::IpAddr; 16 17 use libc::{c_int, c_long, c_uint}; 18 19 use super::bio::BioSlice; 20 use super::error::{error_get_lib, error_get_reason, ErrorStack}; 21 use super::ffi::err::{ERR_clear_error, ERR_peek_last_error}; 22 use super::ffi::pem::PEM_read_bio_X509; 23 use super::ffi::x509::{ 24 d2i_X509, X509_STORE_add_cert, X509_STORE_free, X509_STORE_new, X509_VERIFY_PARAM_free, 25 X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_set_hostflags, 26 X509_verify_cert_error_string, STACK_X509, X509_STORE, X509_VERIFY_PARAM, 27 }; 28 use super::foreign::{Foreign, ForeignRef}; 29 use super::stack::Stackof; 30 use super::{check_ptr, check_ret, ssl_init}; 31 use crate::util::c_openssl::ffi::x509::{X509_free, C_X509}; 32 #[cfg(feature = "c_openssl_3_0")] 33 use super::ffi::x509::X509_STORE_load_path; 34 #[cfg(feature = "c_openssl_3_0")] 35 use std::ffi::CString; 36 37 foreign_type!( 38 type CStruct = C_X509; 39 fn drop = X509_free; 40 pub(crate) struct X509; 41 pub(crate) struct X509Ref; 42 ); 43 44 const ERR_LIB_PEM: c_int = 9; 45 const PEM_R_NO_START_LINE: c_int = 108; 46 47 impl X509 { from_pem(pem: &[u8]) -> Result<X509, ErrorStack>48 pub(crate) fn from_pem(pem: &[u8]) -> Result<X509, ErrorStack> { 49 ssl_init(); 50 let bio = BioSlice::from_byte(pem)?; 51 let ptr = check_ptr(unsafe { 52 PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()) 53 })?; 54 Ok(X509::from_ptr(ptr)) 55 } 56 from_der(der: &[u8]) -> Result<X509, ErrorStack>57 pub(crate) fn from_der(der: &[u8]) -> Result<X509, ErrorStack> { 58 ssl_init(); 59 let len = 60 ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; 61 let ptr = check_ptr(unsafe { d2i_X509(ptr::null_mut(), &mut der.as_ptr(), len) })?; 62 Ok(X509::from_ptr(ptr)) 63 } 64 65 /// Deserializes a list of PEM-formatted certificates. stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack>66 pub(crate) fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> { 67 unsafe { 68 ssl_init(); 69 let bio = BioSlice::from_byte(pem)?; 70 71 let mut certs = vec![]; 72 loop { 73 let r = PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); 74 if r.is_null() { 75 let err = ERR_peek_last_error(); 76 if error_get_lib(err) == ERR_LIB_PEM 77 && error_get_reason(err) == PEM_R_NO_START_LINE 78 { 79 ERR_clear_error(); 80 break; 81 } 82 83 return Err(ErrorStack::get()); 84 } else { 85 certs.push(X509(r)); 86 } 87 } 88 Ok(certs) 89 } 90 } 91 } 92 93 impl Stackof for X509 { 94 type StackType = STACK_X509; 95 } 96 97 #[derive(Copy, Clone, PartialEq, Eq)] 98 pub(crate) struct X509VerifyResult(c_int); 99 100 impl X509VerifyResult { error_string(&self) -> &'static str101 fn error_string(&self) -> &'static str { 102 ssl_init(); 103 unsafe { 104 let s = X509_verify_cert_error_string(self.0 as c_long); 105 str::from_utf8(ffi::CStr::from_ptr(s).to_bytes()).unwrap_or("") 106 } 107 } 108 from_raw(err: c_int) -> X509VerifyResult109 pub(crate) fn from_raw(err: c_int) -> X509VerifyResult { 110 X509VerifyResult(err) 111 } 112 } 113 114 impl fmt::Display for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result115 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 116 fmt.write_str(self.error_string()) 117 } 118 } 119 120 #[cfg(test)] 121 impl fmt::Debug for X509VerifyResult { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result122 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 123 fmt.debug_struct("X509VerifyResult") 124 .field("code", &self.0) 125 .field("error", &self.error_string()) 126 .finish() 127 } 128 } 129 130 foreign_type!( 131 type CStruct = X509_STORE; 132 fn drop = X509_STORE_free; 133 pub(crate) struct X509Store; 134 pub(crate) struct X509StoreRef; 135 ); 136 137 impl X509Store { new() -> Result<X509Store, ErrorStack>138 pub(crate) fn new() -> Result<X509Store, ErrorStack> { 139 ssl_init(); 140 Ok(X509Store(check_ptr(unsafe { X509_STORE_new() })?)) 141 } 142 } 143 144 impl X509StoreRef { add_cert(&mut self, cert: X509) -> Result<(), ErrorStack>145 pub(crate) fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { 146 check_ret(unsafe { X509_STORE_add_cert(self.as_ptr(), cert.as_ptr()) }).map(|_| ()) 147 } 148 149 #[cfg(feature = "c_openssl_3_0")] add_path(&mut self, path: String) -> Result<(), ErrorStack>150 pub(crate) fn add_path(&mut self, path: String) -> Result<(), ErrorStack> { 151 let p_slice: &str = &path; 152 let path = match CString::new(p_slice) { 153 Ok(cstr) => cstr, 154 Err(_) => return Err(ErrorStack::get()), 155 }; 156 check_ret(unsafe { X509_STORE_load_path(self.as_ptr(), path.as_ptr() as *const _) }).map(|_| ()) 157 } 158 } 159 160 foreign_type!( 161 type CStruct = X509_VERIFY_PARAM; 162 fn drop = X509_VERIFY_PARAM_free; 163 pub(crate) struct X509VerifyParam; 164 pub(crate) struct X509VerifyParamRef; 165 ); 166 167 pub(crate) const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; 168 169 impl X509VerifyParamRef { set_hostflags(&mut self, hostflags: c_uint)170 pub(crate) fn set_hostflags(&mut self, hostflags: c_uint) { 171 unsafe { 172 X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags); 173 } 174 } 175 set_host(&mut self, host: &str) -> Result<(), ErrorStack>176 pub(crate) fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { 177 let c_host = if host.is_empty() { "\0" } else { host }; 178 check_ret(unsafe { 179 // Must ensure name is NUL-terminated when namelen == 0. 180 X509_VERIFY_PARAM_set1_host(self.as_ptr(), c_host.as_ptr() as *const _, host.len()) 181 }) 182 .map(|_| ()) 183 } 184 set_ip(&mut self, ip_addr: IpAddr) -> Result<(), ErrorStack>185 pub(crate) fn set_ip(&mut self, ip_addr: IpAddr) -> Result<(), ErrorStack> { 186 let mut v = [0u8; 16]; 187 let len = match ip_addr { 188 IpAddr::V4(addr) => { 189 v[..4].copy_from_slice(&addr.octets()); 190 4 191 } 192 IpAddr::V6(addr) => { 193 v.copy_from_slice(&addr.octets()); 194 16 195 } 196 }; 197 check_ret(unsafe { X509_VERIFY_PARAM_set1_ip(self.as_ptr(), v.as_ptr() as *const _, len) }) 198 .map(|_| ()) 199 } 200 } 201