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