• 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::{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