1 use bitflags::bitflags;
2 use foreign_types::ForeignTypeRef;
3 use libc::{c_int, c_uint, c_ulong, time_t};
4 use std::net::IpAddr;
5 
6 use crate::error::ErrorStack;
7 #[cfg(any(ossl102, boringssl))]
8 use crate::x509::X509PurposeId;
9 use crate::{cvt, cvt_p};
10 use openssl_macros::corresponds;
11 
12 bitflags! {
13     /// Flags used to check an `X509` certificate.
14     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
15     #[repr(transparent)]
16     pub struct X509CheckFlags: c_uint {
17         const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT as _;
18         const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _;
19         const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS as _;
20         const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS as _;
21         const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS as _;
22         /// Requires OpenSSL 1.1.0 or newer.
23         #[cfg(any(ossl110))]
24         const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT;
25 
26         #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")]
27         const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _;
28     }
29 }
30 
31 bitflags! {
32     /// Flags used to verify an `X509` certificate chain.
33     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
34     #[repr(transparent)]
35     pub struct X509VerifyFlags: c_ulong {
36         const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK as _;
37         const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME as _;
38         const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK as _;
39         const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL as _;
40         const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL as _;
41         const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT as _;
42         const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS as _;
43         const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK as _;
44         const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY as _;
45         const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY as _;
46         const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP as _;
47         const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY as _;
48         const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT as _;
49         const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS as _;
50         const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE as _;
51         #[cfg(any(ossl102, boringssl))]
52         const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST as _;
53         #[cfg(ossl102)]
54         const SUITEB_128_LOS_ONLY = ffi::X509_V_FLAG_SUITEB_128_LOS_ONLY;
55         #[cfg(ossl102)]
56         const SUITEB_192_LOS = ffi::X509_V_FLAG_SUITEB_128_LOS;
57         #[cfg(ossl102)]
58         const SUITEB_128_LOS = ffi::X509_V_FLAG_SUITEB_192_LOS;
59         #[cfg(any(ossl102, boringssl))]
60         const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN as _;
61         #[cfg(any(ossl110, boringssl))]
62         const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS as _;
63         #[cfg(any(ossl110, boringssl))]
64         const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME as _;
65     }
66 }
67 
68 foreign_type_and_impl_send_sync! {
69     type CType = ffi::X509_VERIFY_PARAM;
70     fn drop = ffi::X509_VERIFY_PARAM_free;
71 
72     /// Adjust parameters associated with certificate verification.
73     pub struct X509VerifyParam;
74     /// Reference to `X509VerifyParam`.
75     pub struct X509VerifyParamRef;
76 }
77 
78 impl X509VerifyParam {
79     /// Create an X509VerifyParam
80     #[corresponds(X509_VERIFY_PARAM_new)]
new() -> Result<X509VerifyParam, ErrorStack>81     pub fn new() -> Result<X509VerifyParam, ErrorStack> {
82         unsafe {
83             ffi::init();
84             cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam)
85         }
86     }
87 }
88 
89 impl X509VerifyParamRef {
90     /// Set the host flags.
91     #[corresponds(X509_VERIFY_PARAM_set_hostflags)]
set_hostflags(&mut self, hostflags: X509CheckFlags)92     pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) {
93         unsafe {
94             ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits());
95         }
96     }
97 
98     /// Set verification flags.
99     #[corresponds(X509_VERIFY_PARAM_set_flags)]
set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack>100     pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
101         unsafe {
102             cvt(ffi::X509_VERIFY_PARAM_set_flags(
103                 self.as_ptr(),
104                 flags.bits(),
105             ))
106             .map(|_| ())
107         }
108     }
109 
110     /// Clear verification flags.
111     #[corresponds(X509_VERIFY_PARAM_clear_flags)]
clear_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack>112     pub fn clear_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
113         unsafe {
114             cvt(ffi::X509_VERIFY_PARAM_clear_flags(
115                 self.as_ptr(),
116                 flags.bits(),
117             ))
118             .map(|_| ())
119         }
120     }
121 
122     /// Gets verification flags.
123     #[corresponds(X509_VERIFY_PARAM_get_flags)]
flags(&mut self) -> X509VerifyFlags124     pub fn flags(&mut self) -> X509VerifyFlags {
125         let bits = unsafe { ffi::X509_VERIFY_PARAM_get_flags(self.as_ptr()) };
126         X509VerifyFlags::from_bits_retain(bits)
127     }
128 
129     /// Set the expected DNS hostname.
130     #[corresponds(X509_VERIFY_PARAM_set1_host)]
set_host(&mut self, host: &str) -> Result<(), ErrorStack>131     pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> {
132         unsafe {
133             // len == 0 means "run strlen" :(
134             let raw_host = if host.is_empty() { "\0" } else { host };
135             cvt(ffi::X509_VERIFY_PARAM_set1_host(
136                 self.as_ptr(),
137                 raw_host.as_ptr() as *const _,
138                 host.len(),
139             ))
140             .map(|_| ())
141         }
142     }
143 
144     /// Set the expected email address.
145     #[corresponds(X509_VERIFY_PARAM_set1_email)]
set_email(&mut self, email: &str) -> Result<(), ErrorStack>146     pub fn set_email(&mut self, email: &str) -> Result<(), ErrorStack> {
147         unsafe {
148             // len == 0 means "run strlen" :(
149             let raw_email = if email.is_empty() { "\0" } else { email };
150             cvt(ffi::X509_VERIFY_PARAM_set1_email(
151                 self.as_ptr(),
152                 raw_email.as_ptr() as *const _,
153                 email.len(),
154             ))
155             .map(|_| ())
156         }
157     }
158 
159     /// Set the expected IPv4 or IPv6 address.
160     #[corresponds(X509_VERIFY_PARAM_set1_ip)]
set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack>161     pub fn set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack> {
162         unsafe {
163             let mut buf = [0; 16];
164             let len = match ip {
165                 IpAddr::V4(addr) => {
166                     buf[..4].copy_from_slice(&addr.octets());
167                     4
168                 }
169                 IpAddr::V6(addr) => {
170                     buf.copy_from_slice(&addr.octets());
171                     16
172                 }
173             };
174             cvt(ffi::X509_VERIFY_PARAM_set1_ip(
175                 self.as_ptr(),
176                 buf.as_ptr() as *const _,
177                 len,
178             ))
179             .map(|_| ())
180         }
181     }
182 
183     /// Set the verification time, where time is of type time_t, traditionaly defined as seconds since the epoch
184     #[corresponds(X509_VERIFY_PARAM_set_time)]
set_time(&mut self, time: time_t)185     pub fn set_time(&mut self, time: time_t) {
186         unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), time) }
187     }
188 
189     /// Set the verification depth
190     #[corresponds(X509_VERIFY_PARAM_set_depth)]
set_depth(&mut self, depth: c_int)191     pub fn set_depth(&mut self, depth: c_int) {
192         unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) }
193     }
194 
195     /// Sets the authentication security level to auth_level
196     #[corresponds(X509_VERIFY_PARAM_set_auth_level)]
197     #[cfg(ossl110)]
set_auth_level(&mut self, lvl: c_int)198     pub fn set_auth_level(&mut self, lvl: c_int) {
199         unsafe { ffi::X509_VERIFY_PARAM_set_auth_level(self.as_ptr(), lvl) }
200     }
201 
202     /// Gets the current authentication security level
203     #[corresponds(X509_VERIFY_PARAM_get_auth_level)]
204     #[cfg(ossl110)]
auth_level(&self) -> i32205     pub fn auth_level(&self) -> i32 {
206         unsafe { ffi::X509_VERIFY_PARAM_get_auth_level(self.as_ptr()) }
207     }
208 
209     /// Sets the verification purpose
210     #[corresponds(X509_VERIFY_PARAM_set_purpose)]
211     #[cfg(any(ossl102, boringssl))]
set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack>212     pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
213         unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) }
214     }
215 }
216