| 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, awslc))] |
| 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, awslc))] |
| 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, awslc))] |
| 60 | const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN as _; |
| 61 | #[cfg (any(ossl110, boringssl, awslc))] |
| 62 | const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS as _; |
| 63 | #[cfg (any(ossl110, boringssl, awslc))] |
| 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)] |
| 81 | pub fn new() -> Result<X509VerifyParam, ErrorStack> { |
| 82 | unsafe { |
| 83 | ffi::init(); |
| 84 | cvt_p(ffi::X509_VERIFY_PARAM_new()).map(op:X509VerifyParam) |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl X509VerifyParamRef { |
| 90 | /// Set the host flags. |
| 91 | #[corresponds (X509_VERIFY_PARAM_set_hostflags)] |
| 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)] |
| 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)] |
| 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)] |
| 124 | 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)] |
| 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)] |
| 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)] |
| 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)] |
| 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)] |
| 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)] |
| 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)] |
| 205 | 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, awslc))] |
| 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 | |