summaryrefslogtreecommitdiff
path: root/vendor/security-framework/src
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/security-framework/src
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/security-framework/src')
-rw-r--r--vendor/security-framework/src/access_control.rs81
-rw-r--r--vendor/security-framework/src/authorization.rs815
-rw-r--r--vendor/security-framework/src/base.rs88
-rw-r--r--vendor/security-framework/src/certificate.rs320
-rw-r--r--vendor/security-framework/src/cipher_suite.rs246
-rw-r--r--vendor/security-framework/src/dlsym.rs50
-rw-r--r--vendor/security-framework/src/identity.rs83
-rw-r--r--vendor/security-framework/src/import_export.rs174
-rw-r--r--vendor/security-framework/src/item.rs793
-rw-r--r--vendor/security-framework/src/key.rs398
-rw-r--r--vendor/security-framework/src/lib.rs93
-rw-r--r--vendor/security-framework/src/os/macos/access.rs14
-rw-r--r--vendor/security-framework/src/os/macos/certificate.rs267
-rw-r--r--vendor/security-framework/src/os/macos/certificate_oids.rs32
-rw-r--r--vendor/security-framework/src/os/macos/code_signing.rs486
-rw-r--r--vendor/security-framework/src/os/macos/digest_transform.rs194
-rw-r--r--vendor/security-framework/src/os/macos/encrypt_transform.rs254
-rw-r--r--vendor/security-framework/src/os/macos/identity.rs85
-rw-r--r--vendor/security-framework/src/os/macos/import_export.rs344
-rw-r--r--vendor/security-framework/src/os/macos/item.rs47
-rw-r--r--vendor/security-framework/src/os/macos/key.rs38
-rw-r--r--vendor/security-framework/src/os/macos/keychain.rs281
-rw-r--r--vendor/security-framework/src/os/macos/keychain_item.rs26
-rw-r--r--vendor/security-framework/src/os/macos/mod.rs52
-rw-r--r--vendor/security-framework/src/os/macos/passwords.rs525
-rw-r--r--vendor/security-framework/src/os/macos/secure_transport.rs647
-rw-r--r--vendor/security-framework/src/os/macos/transform.rs54
-rw-r--r--vendor/security-framework/src/os/mod.rs4
-rw-r--r--vendor/security-framework/src/passwords.rs337
-rw-r--r--vendor/security-framework/src/passwords_options.rs130
-rw-r--r--vendor/security-framework/src/policy.rs100
-rw-r--r--vendor/security-framework/src/random.rs39
-rw-r--r--vendor/security-framework/src/secure_transport.rs1843
-rw-r--r--vendor/security-framework/src/trust.rs393
-rw-r--r--vendor/security-framework/src/trust_settings.rs305
35 files changed, 0 insertions, 9638 deletions
diff --git a/vendor/security-framework/src/access_control.rs b/vendor/security-framework/src/access_control.rs
deleted file mode 100644
index dfaa4541..00000000
--- a/vendor/security-framework/src/access_control.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-//! Access Control support.
-
-use std::ptr::{self, null};
-
-use core_foundation::string::CFString;
-use core_foundation::base::{TCFType, CFOptionFlags, kCFAllocatorDefault};
-use security_framework_sys::access_control::{
- SecAccessControlGetTypeID, SecAccessControlCreateWithFlags,
- kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
- kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
- kSecAttrAccessibleWhenUnlocked,
- kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
- kSecAttrAccessibleAfterFirstUnlock
-};
-use security_framework_sys::base::{SecAccessControlRef, errSecParam};
-use crate::base::{Error, Result};
-
-declare_TCFType! {
- /// A type representing sec access control settings.
- SecAccessControl, SecAccessControlRef
-}
-impl_TCFType!(
- SecAccessControl,
- SecAccessControlRef,
- SecAccessControlGetTypeID
-);
-
-unsafe impl Sync for SecAccessControl {}
-unsafe impl Send for SecAccessControl {}
-
-/// Specify when an item is available.
-pub enum ProtectionMode {
- /// The data in the keychain can only be accessed when the device is
- /// unlocked. Only available if a passcode is set on the device.
- AccessibleWhenPasscodeSetThisDeviceOnly,
- ///The data in the keychain item can be accessed only while the device is
- /// unlocked by the user.
- AccessibleWhenUnlockedThisDeviceOnly,
- /// The data in the keychain item can be accessed only while the device is
- /// unlocked by the user.
- AccessibleWhenUnlocked,
- /// The data in the keychain item cannot be accessed after a restart until
- /// the device has been unlocked once by the user.
- AccessibleAfterFirstUnlockThisDeviceOnly,
- /// The data in the keychain item cannot be accessed after a restart until
- /// the device has been unlocked once by the user.
- AccessibleAfterFirstUnlock,
-}
-
-impl SecAccessControl {
- /// Create `AccessControl` object from flags
- pub fn create_with_flags(flags: CFOptionFlags) -> Result<Self> {
- Self::create_with_protection(None, flags)
- }
-
- /// Create `AccessControl` object from a protection value and flags.
- pub fn create_with_protection(protection: Option<ProtectionMode>, flags: CFOptionFlags) -> Result<Self> {
- let protection_val = protection.map(|v| {
- match v {
- ProtectionMode::AccessibleWhenPasscodeSetThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) },
- ProtectionMode::AccessibleWhenUnlockedThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenUnlockedThisDeviceOnly) },
- ProtectionMode::AccessibleWhenUnlocked => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenUnlocked) },
- ProtectionMode::AccessibleAfterFirstUnlockThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) },
- ProtectionMode::AccessibleAfterFirstUnlock => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleAfterFirstUnlock) },
- }
- });
- unsafe {
- let access_control = SecAccessControlCreateWithFlags(
- kCFAllocatorDefault,
- protection_val.map(|v| v.as_CFTypeRef()).unwrap_or(null()),
- flags,
- ptr::null_mut(),
- );
- if access_control.is_null() {
- Err(Error::from_code(errSecParam))
- } else {
- Ok(Self::wrap_under_create_rule(access_control))
- }
- }
- }
-}
diff --git a/vendor/security-framework/src/authorization.rs b/vendor/security-framework/src/authorization.rs
deleted file mode 100644
index 762addb6..00000000
--- a/vendor/security-framework/src/authorization.rs
+++ /dev/null
@@ -1,815 +0,0 @@
-//! Authorization Services support.
-
-/// # Potential improvements
-///
-/// * When generic specialization stabilizes prevent copying from `CString`
-/// arguments.
-/// * `AuthorizationCopyRightsAsync`
-/// * Provide constants for well known item names
-
-use crate::base::{Error, Result};
-#[cfg(all(target_os = "macos", feature = "job-bless"))]
-use core_foundation::base::Boolean;
-use core_foundation::base::{CFTypeRef, TCFType};
-use core_foundation::bundle::CFBundleRef;
-use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
-#[cfg(all(target_os = "macos", feature = "job-bless"))]
-use core_foundation::error::CFError;
-#[cfg(all(target_os = "macos", feature = "job-bless"))]
-use core_foundation::error::CFErrorRef;
-use core_foundation::string::{CFString, CFStringRef};
-use security_framework_sys::authorization as sys;
-use security_framework_sys::base::errSecConversionError;
-use std::ffi::{CStr, CString};
-use std::fs::File;
-use std::mem::MaybeUninit;
-use std::os::raw::c_void;
-use std::ptr::addr_of;
-use std::marker::PhantomData;
-use sys::AuthorizationExternalForm;
-
-macro_rules! optional_str_to_cfref {
- ($string:ident) => {{
- $string
- .map(CFString::new)
- .map_or(std::ptr::null(), |cfs| cfs.as_concrete_TypeRef())
- }};
-}
-
-macro_rules! cstring_or_err {
- ($x:expr) => {{
- CString::new($x).map_err(|_| Error::from_code(errSecConversionError))
- }};
-}
-
-bitflags::bitflags! {
- /// The flags used to specify authorization options.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct Flags: sys::AuthorizationFlags {
- /// An empty flag set that you use as a placeholder when you don't want
- /// any of the other flags.
- const DEFAULTS = sys::kAuthorizationFlagDefaults;
-
- /// A flag that permits user interaction as needed.
- const INTERACTION_ALLOWED = sys::kAuthorizationFlagInteractionAllowed;
-
- /// A flag that permits the Security Server to attempt to grant the
- /// rights requested.
- const EXTEND_RIGHTS = sys::kAuthorizationFlagExtendRights;
-
- /// A flag that permits the Security Server to grant rights on an
- /// individual basis.
- const PARTIAL_RIGHTS = sys::kAuthorizationFlagPartialRights;
-
- /// A flag that instructs the Security Server to revoke authorization.
- const DESTROY_RIGHTS = sys::kAuthorizationFlagDestroyRights;
-
- /// A flag that instructs the Security Server to preauthorize the rights
- /// requested.
- const PREAUTHORIZE = sys::kAuthorizationFlagPreAuthorize;
- }
-}
-
-impl Default for Flags {
- #[inline(always)]
- fn default() -> Flags {
- Flags::DEFAULTS
- }
-}
-
-/// Information about an authorization right or the environment.
-#[repr(C)]
-pub struct AuthorizationItem(sys::AuthorizationItem);
-
-impl AuthorizationItem {
- /// The required name of the authorization right or environment data.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- #[must_use] pub fn name(&self) -> &str {
- unsafe {
- CStr::from_ptr(self.0.name)
- .to_str()
- .expect("AuthorizationItem::name failed to convert &str to CStr")
- }
- }
-
- /// The information pertaining to the name field. Do not rely on NULL
- /// termination of string data.
- #[inline]
- #[must_use] pub fn value(&self) -> Option<&[u8]> {
- if self.0.value.is_null() {
- return None;
- }
-
- let value =
- unsafe { std::slice::from_raw_parts(self.0.value as *const u8, self.0.valueLength) };
-
- Some(value)
- }
-}
-
-/// A set of authorization items returned and owned by the Security Server.
-#[derive(Debug)]
-#[repr(C)]
-pub struct AuthorizationItemSet<'a> {
- inner: *const sys::AuthorizationItemSet,
- phantom: PhantomData<&'a sys::AuthorizationItemSet>,
-}
-
-impl<'a> Drop for AuthorizationItemSet<'a> {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- sys::AuthorizationFreeItemSet(self.inner as *mut sys::AuthorizationItemSet);
- }
- }
-}
-
-/// Used by `AuthorizationItemSetBuilder` to store data pointed to by
-/// `sys::AuthorizationItemSet`.
-#[derive(Debug)]
-pub struct AuthorizationItemSetStorage {
- /// The layout of this is a little awkward because of the requirements of
- /// Apple's APIs. `items` contains pointers to data owned by `names` and
- /// `values`, so we must not modify them once `items` has been set up.
- names: Vec<CString>,
- values: Vec<Option<Vec<u8>>>,
- items: Vec<sys::AuthorizationItem>,
-
- /// Must not be given to APIs which would attempt to modify it.
- ///
- /// See `AuthorizationItemSet` for sets owned by the Security Server which
- /// are writable.
- pub set: sys::AuthorizationItemSet,
-}
-
-impl Default for AuthorizationItemSetStorage {
- #[inline]
- fn default() -> Self {
- AuthorizationItemSetStorage {
- names: Vec::new(),
- values: Vec::new(),
- items: Vec::new(),
- set: sys::AuthorizationItemSet {
- count: 0,
- items: std::ptr::null_mut(),
- },
- }
- }
-}
-
-/// A convenience `AuthorizationItemSetBuilder` builder which enabled you to use
-/// rust types. All names and values passed in will be copied.
-#[derive(Debug, Default)]
-pub struct AuthorizationItemSetBuilder {
- storage: AuthorizationItemSetStorage,
-}
-
-// Stores AuthorizationItems contiguously, and their items separately
-impl AuthorizationItemSetBuilder {
- /// Creates a new `AuthorizationItemSetStore`, which simplifies creating
- /// owned vectors of `AuthorizationItem`s.
- #[inline(always)]
- #[must_use]
- pub fn new() -> AuthorizationItemSetBuilder {
- Default::default()
- }
-
- /// Adds an `AuthorizationItem` with the name set to a right and an empty
- /// value.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn add_right<N: Into<Vec<u8>>>(mut self, name: N) -> Result<Self> {
- self.storage.names.push(cstring_or_err!(name)?);
- self.storage.values.push(None);
- Ok(self)
- }
-
- /// Adds an `AuthorizationItem` with arbitrary data.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn add_data<N, V>(mut self, name: N, value: V) -> Result<Self>
- where
- N: Into<Vec<u8>>,
- V: Into<Vec<u8>>,
- {
- self.storage.names.push(cstring_or_err!(name)?);
- self.storage.values.push(Some(value.into()));
- Ok(self)
- }
-
- /// Adds an `AuthorizationItem` with NULL terminated string data.
- ///
- /// If `name` or `value` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn add_string<N, V>(mut self, name: N, value: V) -> Result<Self>
- where
- N: Into<Vec<u8>>,
- V: Into<Vec<u8>>,
- {
- self.storage.names.push(cstring_or_err!(name)?);
- self.storage
- .values
- .push(Some(cstring_or_err!(value)?.to_bytes().to_vec()));
- Ok(self)
- }
-
- /// Creates the `sys::AuthorizationItemSet`, and gives you ownership of the
- /// data it points to.
- #[must_use]
- pub fn build(mut self) -> AuthorizationItemSetStorage {
- self.storage.items = self
- .storage
- .names
- .iter()
- .zip(self.storage.values.iter())
- .map(|(n, v)| sys::AuthorizationItem {
- name: n.as_ptr(),
- value: v
- .as_ref()
- .map_or(std::ptr::null_mut(), |v| v.as_ptr() as *mut c_void),
- valueLength: v.as_ref().map_or(0, |v| v.len()),
- flags: 0,
- })
- .collect();
-
- self.storage.set = sys::AuthorizationItemSet {
- count: self.storage.items.len() as u32,
- items: self.storage.items.as_ptr() as *mut sys::AuthorizationItem,
- };
-
- self.storage
- }
-}
-
-/// Used by `Authorization::set_item` to define the rules of he right.
-#[derive(Copy, Clone)]
-pub enum RightDefinition<'a> {
- /// The dictionary will contain the keys and values that define the rules.
- FromDictionary(&'a CFDictionary<CFStringRef, CFTypeRef>),
-
- /// The specified right's rules will be duplicated.
- FromExistingRight(&'a str),
-}
-
-/// A wrapper around `AuthorizationCreate` and functions which operate on an
-/// `AuthorizationRef`.
-#[derive(Debug)]
-pub struct Authorization {
- handle: sys::AuthorizationRef,
- free_flags: Flags,
-}
-
-impl TryFrom<AuthorizationExternalForm> for Authorization {
- type Error = Error;
-
- /// Internalizes the external representation of an authorization reference.
- #[cold]
- fn try_from(external_form: AuthorizationExternalForm) -> Result<Self> {
- let mut handle = MaybeUninit::<sys::AuthorizationRef>::uninit();
-
- let status = unsafe {
- sys::AuthorizationCreateFromExternalForm(&external_form, handle.as_mut_ptr())
- };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from_code(status));
- }
-
- let auth = Authorization {
- handle: unsafe { handle.assume_init() },
- free_flags: Flags::default(),
- };
-
- Ok(auth)
- }
-}
-
-impl Authorization {
- /// Creates an authorization object which has no environment or associated
- /// rights.
- #[inline]
- #[allow(clippy::should_implement_trait)]
- pub fn default() -> Result<Self> {
- Self::new(None, None, Default::default())
- }
-
- /// Creates an authorization reference and provides an option to authorize
- /// or preauthorize rights.
- ///
- /// `rights` should be the names of the rights you want to create.
- ///
- /// `environment` is used when authorizing or preauthorizing rights. Not
- /// used in OS X v10.2 and earlier. In macOS 10.3 and later, you can pass
- /// icon or prompt data to be used in the authentication dialog box. In
- /// macOS 10.4 and later, you can also pass a user name and password in
- /// order to authorize a user without user interaction.
- #[allow(clippy::unnecessary_cast)]
- pub fn new(
- // FIXME: this should have been by reference
- rights: Option<AuthorizationItemSetStorage>,
- environment: Option<AuthorizationItemSetStorage>,
- flags: Flags,
- ) -> Result<Self> {
- let rights_ptr = rights.as_ref().map_or(std::ptr::null(), |r| {
- addr_of!(r.set) as *const sys::AuthorizationItemSet
- });
-
- let env_ptr = environment.as_ref().map_or(std::ptr::null(), |e| {
- addr_of!(e.set) as *const sys::AuthorizationItemSet
- });
-
- let mut handle = MaybeUninit::<sys::AuthorizationRef>::uninit();
-
- let status = unsafe {
- sys::AuthorizationCreate(rights_ptr, env_ptr, flags.bits(), handle.as_mut_ptr())
- };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from_code(status));
- }
-
- Ok(Authorization {
- handle: unsafe { handle.assume_init() },
- free_flags: Default::default(),
- })
- }
-
- /// Internalizes the external representation of an authorization reference.
- #[deprecated(since = "2.0.1", note = "Please use the TryFrom trait instead")]
- pub fn from_external_form(external_form: sys::AuthorizationExternalForm) -> Result<Self> {
- external_form.try_into()
- }
-
- /// By default the rights acquired will be retained by the Security Server.
- /// Use this to ensure they are destroyed and to prevent shared rights'
- /// continued used by other processes.
- #[inline(always)]
- pub fn destroy_rights(mut self) {
- self.free_flags = Flags::DESTROY_RIGHTS;
- }
-
- /// Retrieve's the right's definition as a dictionary. Use `right_exists`
- /// if you want to avoid retrieving the dictionary.
- ///
- /// `name` can be a wildcard right name.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn get_right<T: Into<Vec<u8>>>(name: T) -> Result<CFDictionary<CFString, CFTypeRef>> {
- let name = cstring_or_err!(name)?;
- let mut dict = MaybeUninit::<CFDictionaryRef>::uninit();
-
- let status = unsafe { sys::AuthorizationRightGet(name.as_ptr(), dict.as_mut_ptr()) };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from_code(status));
- }
-
- let dict = unsafe { CFDictionary::wrap_under_create_rule(dict.assume_init()) };
-
- Ok(dict)
- }
-
- /// Checks if a right exists within the policy database. This is the same as
- /// `get_right`, but avoids a dictionary allocation.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn right_exists<T: Into<Vec<u8>>>(name: T) -> Result<bool> {
- let name = cstring_or_err!(name)?;
-
- let status = unsafe { sys::AuthorizationRightGet(name.as_ptr(), std::ptr::null_mut()) };
-
- Ok(status == sys::errAuthorizationSuccess)
- }
-
- /// Removes a right from the policy database.
- ///
- /// `name` cannot be a wildcard right name.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn remove_right<T: Into<Vec<u8>>>(&self, name: T) -> Result<()> {
- let name = cstring_or_err!(name)?;
-
- let status = unsafe { sys::AuthorizationRightRemove(self.handle, name.as_ptr()) };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from_code(status));
- }
-
- Ok(())
- }
-
- /// Creates or updates a right entry in the policy database. Your process
- /// must have a code signature in order to be able to add rights to the
- /// authorization database.
- ///
- /// `name` cannot be a wildcard right.
- ///
- /// `definition` can be either a `CFDictionaryRef` containing keys defining
- /// the rules or a `CFStringRef` representing the name of another right
- /// whose rules you wish to duplicaate.
- ///
- /// `description` is a key which can be used to look up localized
- /// descriptions.
- ///
- /// `bundle` will be used to get localizations from if not the main bundle.
- ///
- /// `localeTableName` will be used to get localizations if provided.
- ///
- /// If `name` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn set_right<T: Into<Vec<u8>>>(
- &self,
- name: T,
- definition: RightDefinition<'_>,
- description: Option<&str>,
- bundle: Option<CFBundleRef>,
- locale: Option<&str>,
- ) -> Result<()> {
- let name = cstring_or_err!(name)?;
-
- let definition_cfstring: CFString;
- let definition_ref = match definition {
- RightDefinition::FromDictionary(def) => def.as_CFTypeRef(),
- RightDefinition::FromExistingRight(def) => {
- definition_cfstring = CFString::new(def);
- definition_cfstring.as_CFTypeRef()
- }
- };
-
- let status = unsafe {
- sys::AuthorizationRightSet(
- self.handle,
- name.as_ptr(),
- definition_ref,
- optional_str_to_cfref!(description),
- bundle.unwrap_or(std::ptr::null_mut()),
- optional_str_to_cfref!(locale),
- )
- };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from_code(status));
- }
-
- Ok(())
- }
-
- /// An authorization plugin can store the results of an authentication
- /// operation by calling the `SetContextValue` function. You can then
- /// retrieve this supporting data, such as the user name.
- ///
- /// `tag` should specify the type of data the Security Server should return.
- /// If `None`, all available information is retreieved.
- ///
- /// If `tag` isn't convertable to a `CString` it will return
- /// Err(errSecConversionError).
- pub fn copy_info<T: Into<Vec<u8>>>(&self, tag: Option<T>) -> Result<AuthorizationItemSet<'_>> {
- let tag_with_nul: CString;
-
- let tag_ptr = match tag {
- Some(tag) => {
- tag_with_nul = cstring_or_err!(tag)?;
- tag_with_nul.as_ptr()
- }
- None => std::ptr::null(),
- };
-
- let mut inner = MaybeUninit::<*mut sys::AuthorizationItemSet>::uninit();
-
- let status =
- unsafe { sys::AuthorizationCopyInfo(self.handle, tag_ptr, inner.as_mut_ptr()) };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from(status));
- }
-
- let set = AuthorizationItemSet {
- inner: unsafe { inner.assume_init() },
- phantom: PhantomData,
- };
-
- Ok(set)
- }
-
- /// Creates an external representation of an authorization reference so that
- /// you can transmit it between processes.
- pub fn make_external_form(&self) -> Result<sys::AuthorizationExternalForm> {
- let mut external_form = MaybeUninit::<sys::AuthorizationExternalForm>::uninit();
-
- let status =
- unsafe { sys::AuthorizationMakeExternalForm(self.handle, external_form.as_mut_ptr()) };
-
- if status != sys::errAuthorizationSuccess {
- return Err(Error::from(status));
- }
-
- Ok(unsafe { external_form.assume_init() })
- }
-
- /// Runs an executable tool with root privileges.
- /// Discards executable's output
- #[cfg(target_os = "macos")]
- #[inline(always)]
- pub fn execute_with_privileges<P, S, I>(
- &self,
- command: P,
- arguments: I,
- flags: Flags,
- ) -> Result<()>
- where
- P: AsRef<std::path::Path>,
- I: IntoIterator<Item = S>,
- S: AsRef<std::ffi::OsStr>,
- {
- use std::os::unix::ffi::OsStrExt;
-
- let arguments = arguments
- .into_iter().flat_map(|a| CString::new(a.as_ref().as_bytes()))
- .collect::<Vec<_>>();
- self.execute_with_privileges_internal(command.as_ref().as_os_str().as_bytes(), &arguments, flags, false)?;
- Ok(())
- }
-
- /// Runs an executable tool with root privileges,
- /// and returns a `File` handle to its communication pipe
- #[cfg(target_os = "macos")]
- #[inline(always)]
- pub fn execute_with_privileges_piped<P, S, I>(
- &self,
- command: P,
- arguments: I,
- flags: Flags,
- ) -> Result<File>
- where
- P: AsRef<std::path::Path>,
- I: IntoIterator<Item = S>,
- S: AsRef<std::ffi::OsStr>,
- {
- use std::os::unix::ffi::OsStrExt;
-
- let arguments = arguments
- .into_iter().flat_map(|a| CString::new(a.as_ref().as_bytes()))
- .collect::<Vec<_>>();
- Ok(self.execute_with_privileges_internal(command.as_ref().as_os_str().as_bytes(), &arguments, flags, true)?.unwrap())
- }
-
- /// Submits the executable for the given label as a `launchd` job.
- #[cfg(all(target_os = "macos", feature = "job-bless"))]
- pub fn job_bless(&self, label: &str) -> Result<(), CFError> {
- #[link(name = "ServiceManagement", kind = "framework")]
- extern "C" {
- static kSMDomainSystemLaunchd: CFStringRef;
-
- fn SMJobBless(
- domain: CFStringRef,
- executableLabel: CFStringRef,
- auth: sys::AuthorizationRef,
- error: *mut CFErrorRef,
- ) -> Boolean;
- }
-
- unsafe {
- let mut error = std::ptr::null_mut();
- SMJobBless(
- kSMDomainSystemLaunchd,
- CFString::new(label).as_concrete_TypeRef(),
- self.handle,
- &mut error,
- );
- if !error.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
-
- Ok(())
- }
- }
-
- // Runs an executable tool with root privileges.
- #[cfg(target_os = "macos")]
- fn execute_with_privileges_internal(
- &self,
- command: &[u8],
- arguments: &[CString],
- flags: Flags,
- make_pipe: bool,
- ) -> Result<Option<File>> {
- use std::os::unix::io::{FromRawFd, RawFd};
-
- let c_cmd = cstring_or_err!(command)?;
-
- let mut c_args = arguments.iter().map(|a| a.as_ptr() as _).collect::<Vec<_>>();
- c_args.push(std::ptr::null_mut());
-
- let mut pipe: *mut libc::FILE = std::ptr::null_mut();
-
- let status = unsafe {
- sys::AuthorizationExecuteWithPrivileges(
- self.handle,
- c_cmd.as_ptr(),
- flags.bits(),
- c_args.as_ptr(),
- if make_pipe { &mut pipe } else { std::ptr::null_mut() },
- )
- };
-
- crate::cvt(status)?;
- Ok(if make_pipe {
- if pipe.is_null() {
- return Err(Error::from_code(32)); // EPIPE?
- }
- Some(unsafe { File::from_raw_fd(libc::fileno(pipe) as RawFd) })
- } else {
- None
- })
- }
-}
-
-impl Drop for Authorization {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- sys::AuthorizationFree(self.handle, self.free_flags.bits());
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_create_default_authorization() {
- Authorization::default().unwrap();
- }
-
- #[test]
- fn test_create_allowed_authorization() -> Result<()> {
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.hdd.smart")?
- .add_right("system.login.done")?
- .build();
-
- Authorization::new(Some(rights), None, Flags::EXTEND_RIGHTS).unwrap();
-
- Ok(())
- }
-
- #[test]
- fn test_create_then_destroy_allowed_authorization() -> Result<()> {
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.hdd.smart")?
- .add_right("system.login.done")?
- .build();
-
- let auth = Authorization::new(Some(rights), None, Flags::EXTEND_RIGHTS).unwrap();
- auth.destroy_rights();
-
- Ok(())
- }
-
- #[test]
- fn test_create_authorization_requiring_interaction() -> Result<()> {
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.privilege.admin")?
- .build();
-
- let error = Authorization::new(Some(rights), None, Flags::EXTEND_RIGHTS).unwrap_err();
-
- assert_eq!(error.code(), sys::errAuthorizationInteractionNotAllowed);
-
- Ok(())
- }
-
- fn create_credentials_env() -> Result<AuthorizationItemSetStorage> {
- let set = AuthorizationItemSetBuilder::new()
- .add_string("username", std::env::var("USER").expect("You must set the USER environment variable"))?
- .add_string("password", std::env::var("PASSWORD").expect("You must set the PASSWORD environment varible"))?
- .build();
-
- Ok(set)
- }
-
- #[test]
- fn test_create_authorization_with_bad_credentials() -> Result<()> {
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.privilege.admin")?
- .build();
-
- let env = AuthorizationItemSetBuilder::new()
- .add_string("username", "Tim Apple")?
- .add_string("password", "butterfly")?
- .build();
-
- let error =
- Authorization::new(Some(rights), Some(env), Flags::INTERACTION_ALLOWED).unwrap_err();
-
- assert_eq!(error.code(), sys::errAuthorizationDenied);
-
- Ok(())
- }
-
- #[test]
- fn test_create_authorization_with_credentials() -> Result<()> {
- if std::env::var_os("PASSWORD").is_none() {
- return Ok(());
- }
-
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.privilege.admin")?
- .build();
-
- let env = create_credentials_env()?;
-
- Authorization::new(Some(rights), Some(env), Flags::EXTEND_RIGHTS).unwrap();
-
- Ok(())
- }
-
- #[test]
- fn test_query_authorization_database() -> Result<()> {
- assert!(Authorization::right_exists("system.hdd.smart")?);
- assert!(!Authorization::right_exists("EMPTY")?);
-
- let dict = Authorization::get_right("system.hdd.smart").unwrap();
-
- let key = CFString::from_static_string("class");
- assert!(dict.contains_key(&key));
-
- let invalid_key = CFString::from_static_string("EMPTY");
- assert!(!dict.contains_key(&invalid_key));
-
- Ok(())
- }
-
- /// This test will only pass if its process has a valid code signature.
- #[test]
- fn test_modify_authorization_database() -> Result<()> {
- if std::env::var_os("PASSWORD").is_none() {
- return Ok(());
- }
-
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("config.modify.")?
- .build();
-
- let env = create_credentials_env()?;
-
- let auth = Authorization::new(Some(rights), Some(env), Flags::EXTEND_RIGHTS).unwrap();
-
- assert!(!Authorization::right_exists("TEST_RIGHT")?);
-
- auth.set_right(
- "TEST_RIGHT",
- RightDefinition::FromExistingRight("system.hdd.smart"),
- None,
- None,
- None,
- )
- .unwrap();
-
- assert!(Authorization::right_exists("TEST_RIGHT")?);
-
- auth.remove_right("TEST_RIGHT").unwrap();
-
- assert!(!Authorization::right_exists("TEST_RIGHT")?);
-
- Ok(())
- }
-
- /// This test will succeed if authorization popup is approved.
- #[test]
- fn test_execute_with_privileges() -> Result<()> {
- if std::env::var_os("PASSWORD").is_none() {
- return Ok(());
- }
-
- let rights = AuthorizationItemSetBuilder::new()
- .add_right("system.privilege.admin")?
- .build();
-
- let auth = Authorization::new(
- Some(rights),
- None,
- Flags::DEFAULTS
- | Flags::INTERACTION_ALLOWED
- | Flags::PREAUTHORIZE
- | Flags::EXTEND_RIGHTS,
- )?;
-
- let file = auth.execute_with_privileges_piped("/bin/ls", ["/"], Flags::DEFAULTS)?;
-
- use std::io::{self, BufRead};
- for line in io::BufReader::new(file).lines() {
- let _ = line.unwrap();
- }
-
- Ok(())
- }
-}
diff --git a/vendor/security-framework/src/base.rs b/vendor/security-framework/src/base.rs
deleted file mode 100644
index e790d95c..00000000
--- a/vendor/security-framework/src/base.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-//! Support types for other modules.
-
-use core_foundation::string::CFString;
-use core_foundation_sys::base::OSStatus;
-use std::error;
-use std::fmt;
-use std::num::NonZeroI32;
-use std::result;
-
-/// A `Result` type commonly returned by functions.
-pub type Result<T, E = Error> = result::Result<T, E>;
-
-/// A Security Framework error.
-#[derive(Copy, Clone)]
-pub struct Error(NonZeroI32);
-
-impl fmt::Debug for Error {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("Error");
- builder.field("code", &self.0);
- if let Some(message) = self.message() {
- builder.field("message", &message);
- }
- builder.finish()
- }
-}
-
-impl Error {
- /// Creates a new `Error` from a status code.
- /// The code must not be zero
- #[inline]
- #[must_use]
- pub fn from_code(code: OSStatus) -> Self {
- Self(NonZeroI32::new(code).unwrap_or_else(|| NonZeroI32::new(1).unwrap()))
- }
-
- /// Returns a string describing the current error, if available.
- #[inline(always)]
- #[must_use]
- pub fn message(self) -> Option<String> {
- self.inner_message()
- }
-
- #[cold]
- fn inner_message(self) -> Option<String> {
- use core_foundation::base::TCFType;
- use security_framework_sys::base::SecCopyErrorMessageString;
- use std::ptr;
-
- unsafe {
- let s = SecCopyErrorMessageString(self.code(), ptr::null_mut());
- if s.is_null() {
- None
- } else {
- Some(CFString::wrap_under_create_rule(s).to_string())
- }
- }
- }
-
- /// Returns the code of the current error.
- #[inline(always)]
- #[must_use]
- pub fn code(self) -> OSStatus {
- self.0.get() as _
- }
-}
-
-impl From<OSStatus> for Error {
- #[inline(always)]
- #[must_use]
- fn from(code: OSStatus) -> Self {
- Self::from_code(code)
- }
-}
-
-impl fmt::Display for Error {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- if let Some(message) = self.message() {
- write!(fmt, "{message}")
- } else {
- write!(fmt, "error code {}", self.code())
- }
- }
-}
-
-impl error::Error for Error {}
diff --git a/vendor/security-framework/src/certificate.rs b/vendor/security-framework/src/certificate.rs
deleted file mode 100644
index 15fa297f..00000000
--- a/vendor/security-framework/src/certificate.rs
+++ /dev/null
@@ -1,320 +0,0 @@
-//! Certificate support.
-
-use core_foundation::array::{CFArray, CFArrayRef};
-use core_foundation::base::{TCFType, ToVoid};
-use core_foundation::data::CFData;
-use core_foundation::dictionary::CFMutableDictionary;
-use core_foundation::string::CFString;
-use core_foundation_sys::base::kCFAllocatorDefault;
-#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use security_framework_sys::base::{errSecNotTrusted, errSecSuccess};
-use security_framework_sys::base::{errSecParam, SecCertificateRef};
-use security_framework_sys::certificate::*;
-use security_framework_sys::keychain_item::SecItemDelete;
-use std::fmt;
-use std::ptr;
-
-use crate::base::{Error, Result};
-use crate::cvt;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use crate::key;
-#[cfg(target_os = "macos")]
-use crate::os::macos::keychain::SecKeychain;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::base::FromVoid;
-#[cfg(any(feature = "OSX_10_13", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::error::{CFError, CFErrorRef};
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::number::CFNumber;
-#[cfg(feature = "serial-number-bigint")]
-use num_bigint::BigUint;
-use security_framework_sys::item::kSecValueRef;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use std::ops::Deref;
-
-declare_TCFType! {
- /// A type representing a certificate.
- SecCertificate, SecCertificateRef
-}
-impl_TCFType!(SecCertificate, SecCertificateRef, SecCertificateGetTypeID);
-
-unsafe impl Sync for SecCertificate {}
-unsafe impl Send for SecCertificate {}
-
-impl fmt::Debug for SecCertificate {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.debug_struct("SecCertificate")
- .field("subject", &self.subject_summary())
- .finish()
- }
-}
-
-impl SecCertificate {
- /// Creates a `SecCertificate` from DER encoded certificate data.
- pub fn from_der(der_data: &[u8]) -> Result<Self> {
- let der_data = CFData::from_buffer(der_data);
- unsafe {
- let certificate =
- SecCertificateCreateWithData(kCFAllocatorDefault, der_data.as_concrete_TypeRef());
- if certificate.is_null() {
- Err(Error::from_code(errSecParam))
- } else {
- Ok(Self::wrap_under_create_rule(certificate))
- }
- }
- }
-
- /// Returns DER encoded data describing this certificate.
- #[must_use]
- pub fn to_der(&self) -> Vec<u8> {
- unsafe {
- let der_data = SecCertificateCopyData(self.0);
- CFData::wrap_under_create_rule(der_data).to_vec()
- }
- }
-
- /// Adds a certificate to a keychain.
- #[cfg(target_os="macos")]
- pub fn add_to_keychain(&self, keychain: Option<SecKeychain>) -> Result<()> {
- let kch = match keychain {
- Some(kch) => kch,
- _ => SecKeychain::default()?,
- };
- cvt(unsafe {
- SecCertificateAddToKeychain(self.as_CFTypeRef() as *mut _, kch.as_CFTypeRef() as *mut _)
- })
- }
-
- /// Returns a human readable summary of this certificate.
- #[must_use]
- pub fn subject_summary(&self) -> String {
- unsafe {
- let summary = SecCertificateCopySubjectSummary(self.0);
- CFString::wrap_under_create_rule(summary).to_string()
- }
- }
-
- /// Returns a vector of email addresses for the subject of the certificate.
- pub fn email_addresses(&self) -> Result<Vec<String>, Error> {
- let mut array: CFArrayRef = ptr::null();
- unsafe {
- cvt(SecCertificateCopyEmailAddresses(
- self.as_concrete_TypeRef(),
- &mut array,
- ))?;
-
- let array = CFArray::<CFString>::wrap_under_create_rule(array);
- Ok(array.into_iter().map(|p| p.to_string()).collect())
- }
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Returns DER encoded X.509 distinguished name of the certificate issuer.
- #[must_use]
- pub fn issuer(&self) -> Vec<u8> {
- unsafe {
- let issuer = SecCertificateCopyNormalizedIssuerSequence(self.0);
- CFData::wrap_under_create_rule(issuer).to_vec()
- }
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Returns DER encoded X.509 distinguished name of the certificate subject.
- #[must_use]
- pub fn subject(&self) -> Vec<u8> {
- unsafe {
- let subject = SecCertificateCopyNormalizedSubjectSequence(self.0);
- CFData::wrap_under_create_rule(subject).to_vec()
- }
- }
-
- #[cfg(any(feature = "OSX_10_13", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Returns DER encoded serial number of the certificate.
- pub fn serial_number_bytes(&self) -> Result<Vec<u8>, CFError> {
- unsafe {
- let mut error: CFErrorRef = ptr::null_mut();
- let serial_number = SecCertificateCopySerialNumberData(self.0, &mut error);
- if error.is_null() {
- Ok(CFData::wrap_under_create_rule(serial_number).to_vec())
- } else {
- Err(CFError::wrap_under_create_rule(error))
- }
- }
- }
-
- /// Use `BigUint::from_bytes_be(serial_number_bytes())` instead
- #[deprecated(note = "use serial_number_bytes()")]
- #[cfg(feature = "serial-number-bigint")]
- pub fn serial_number(&self) -> Result<BigUint, CFError> {
- Ok(BigUint::from_bytes_be(&self.serial_number_bytes()?))
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Returns DER encoded subjectPublicKeyInfo of certificate if available. This can be used
- /// for certificate pinning.
- pub fn public_key_info_der(&self) -> Result<Option<Vec<u8>>> {
- // Imported from TrustKit
- // https://github.com/datatheorem/TrustKit/blob/master/TrustKit/Pinning/TSKSPKIHashCache.m
- let public_key = self.public_key()?;
- Ok(self.pk_to_der(public_key))
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- #[must_use]
- fn pk_to_der(&self, public_key: key::SecKey) -> Option<Vec<u8>> {
- use security_framework_sys::item::kSecAttrKeyType;
- use security_framework_sys::item::kSecAttrKeySizeInBits;
-
- let public_key_attributes = public_key.attributes();
- let public_key_type = public_key_attributes
- .find(unsafe { kSecAttrKeyType }.cast::<std::os::raw::c_void>())?;
- let public_keysize = public_key_attributes
- .find(unsafe { kSecAttrKeySizeInBits }.cast::<std::os::raw::c_void>())?;
- let public_keysize = unsafe { CFNumber::from_void(*public_keysize.deref()) };
- let public_keysize_val = public_keysize.to_i64()? as u32;
- let hdr_bytes = get_asn1_header_bytes(
- unsafe { CFString::wrap_under_get_rule(*public_key_type.deref() as _) },
- public_keysize_val,
- )?;
- let public_key_data = public_key.external_representation()?;
- let mut out = Vec::with_capacity(hdr_bytes.len() + public_key_data.len() as usize);
- out.extend_from_slice(hdr_bytes);
- out.extend_from_slice(public_key_data.bytes());
- Some(out)
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Get public key from certificate
- pub fn public_key(&self) -> Result<key::SecKey> {
- use crate::policy::SecPolicy;
- use crate::trust::SecTrust;
- use std::slice::from_ref;
-
- let policy = SecPolicy::create_x509();
- let mut trust = SecTrust::create_with_certificates(from_ref(self), from_ref(&policy))?;
- #[allow(deprecated)]
- #[cfg(not(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))]
- trust.evaluate()?;
- #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- cvt(match trust.evaluate_with_error() {
- Ok(_) => errSecSuccess,
- Err(_) => errSecNotTrusted,
- })?;
- trust.copy_public_key()
- }
-
- /// Translates to `SecItemDelete`, passing in the `SecCertificateRef`
- pub fn delete(&self) -> Result<(), Error> {
- let query = CFMutableDictionary::from_CFType_pairs(&[(
- unsafe { kSecValueRef }.to_void(),
- self.to_void(),
- )]);
-
- cvt(unsafe { SecItemDelete(query.as_concrete_TypeRef()) })
- }
-}
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-fn get_asn1_header_bytes(pkt: CFString, ksz: u32) -> Option<&'static [u8]> {
- use security_framework_sys::item::kSecAttrKeyTypeRSA;
- use security_framework_sys::item::kSecAttrKeyTypeECSECPrimeRandom;
-
- if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeRSA) } && ksz == 2048 {
- return Some(&RSA_2048_ASN1_HEADER);
- }
- if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeRSA) } && ksz == 4096 {
- return Some(&RSA_4096_ASN1_HEADER);
- }
- if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeECSECPrimeRandom) }
- && ksz == 256
- {
- return Some(&EC_DSA_SECP_256_R1_ASN1_HEADER);
- }
- if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeECSECPrimeRandom) }
- && ksz == 384
- {
- return Some(&EC_DSA_SECP_384_R1_ASN1_HEADER);
- }
- None
-}
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-const RSA_2048_ASN1_HEADER: [u8; 24] = [
- 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
-];
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-const RSA_4096_ASN1_HEADER: [u8; 24] = [
- 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
-];
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-const EC_DSA_SECP_256_R1_ASN1_HEADER: [u8; 26] = [
- 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
-];
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-const EC_DSA_SECP_384_R1_ASN1_HEADER: [u8; 23] = [
- 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
- 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00,
-];
-
-#[cfg(test)]
-mod test {
- use crate::test::certificate;
- #[cfg(feature = "serial-number-bigint")]
- use num_bigint::BigUint;
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- use x509_parser::prelude::*;
-
- #[test]
- fn subject_summary() {
- let cert = certificate();
- assert_eq!("foobar.com", cert.subject_summary());
- }
-
- #[test]
- fn email_addresses() {
- let cert = certificate();
- assert_eq!(Vec::<String>::new(), cert.email_addresses().unwrap());
- }
-
- #[test]
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- fn issuer() {
- let cert = certificate();
- let issuer = cert.issuer();
- let (_, name) = X509Name::from_der(&issuer).unwrap();
- let name_str = name.to_string_with_registry(oid_registry()).unwrap();
- assert_eq!(
- "C=US, ST=CALIFORNIA, L=PALO ALTO, O=FOOBAR LLC, OU=DEV LAND, CN=FOOBAR.COM",
- name_str
- );
- }
-
- #[test]
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- fn subject() {
- let cert = certificate();
- let subject = cert.subject();
- let (_, name) = X509Name::from_der(&subject).unwrap();
- let name_str = name.to_string_with_registry(oid_registry()).unwrap();
- assert_eq!(
- "C=US, ST=CALIFORNIA, L=PALO ALTO, O=FOOBAR LLC, OU=DEV LAND, CN=FOOBAR.COM",
- name_str
- );
- }
-
- #[test]
- #[cfg(feature = "serial-number-bigint")]
- #[allow(deprecated)]
- fn serial_number() {
- let cert = certificate();
- let serial_number = cert.serial_number().unwrap();
- assert_eq!(BigUint::from(16452297291294946383_u128), serial_number);
- }
-}
diff --git a/vendor/security-framework/src/cipher_suite.rs b/vendor/security-framework/src/cipher_suite.rs
deleted file mode 100644
index 4462b5e5..00000000
--- a/vendor/security-framework/src/cipher_suite.rs
+++ /dev/null
@@ -1,246 +0,0 @@
-//! Cipher Suites supported by Secure Transport
-
-use security_framework_sys::cipher_suite::*;
-
-macro_rules! make_suites {
- ($($suite:ident),+) => {
- /// TLS cipher suites.
- #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
- pub struct CipherSuite(SSLCipherSuite);
-
- #[allow(missing_docs)]
- impl CipherSuite {
- $(
- pub const $suite: Self = Self($suite);
- )+
-
- #[inline(always)]
- #[must_use]
- pub fn from_raw(raw: SSLCipherSuite) -> Self {
- Self(raw)
- }
-
- #[inline(always)]
- #[must_use]
- pub fn to_raw(&self) -> SSLCipherSuite {
- self.0
- }
- }
- }
-}
-
-make_suites! {
- // The commented out ones up here are aliases of the matching TLS suites
- SSL_NULL_WITH_NULL_NULL,
- SSL_RSA_WITH_NULL_MD5,
- SSL_RSA_WITH_NULL_SHA,
- SSL_RSA_EXPORT_WITH_RC4_40_MD5,
- SSL_RSA_WITH_RC4_128_MD5,
- SSL_RSA_WITH_RC4_128_SHA,
- SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
- SSL_RSA_WITH_IDEA_CBC_SHA,
- SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
- SSL_RSA_WITH_DES_CBC_SHA,
- //SSL_RSA_WITH_3DES_EDE_CBC_SHA,
- SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
- SSL_DH_DSS_WITH_DES_CBC_SHA,
- //SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA,
- SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
- SSL_DH_RSA_WITH_DES_CBC_SHA,
- //SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA,
- SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
- SSL_DHE_DSS_WITH_DES_CBC_SHA,
- //SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
- SSL_DHE_RSA_WITH_DES_CBC_SHA,
- //SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,
- //SSL_DH_anon_WITH_RC4_128_MD5,
- SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
- SSL_DH_anon_WITH_DES_CBC_SHA,
- //SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
- SSL_FORTEZZA_DMS_WITH_NULL_SHA,
- SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,
-
- /* TLS addenda using AES, per RFC 3268 */
- TLS_RSA_WITH_AES_128_CBC_SHA,
- TLS_DH_DSS_WITH_AES_128_CBC_SHA,
- TLS_DH_RSA_WITH_AES_128_CBC_SHA,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_DH_anon_WITH_AES_128_CBC_SHA,
- TLS_RSA_WITH_AES_256_CBC_SHA,
- TLS_DH_DSS_WITH_AES_256_CBC_SHA,
- TLS_DH_RSA_WITH_AES_256_CBC_SHA,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- TLS_DH_anon_WITH_AES_256_CBC_SHA,
-
- /* ECDSA addenda, RFC 4492 */
- TLS_ECDH_ECDSA_WITH_NULL_SHA,
- TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
- TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
- TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_NULL_SHA,
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- TLS_ECDH_RSA_WITH_NULL_SHA,
- TLS_ECDH_RSA_WITH_RC4_128_SHA,
- TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
- TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
- TLS_ECDHE_RSA_WITH_NULL_SHA,
- TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- TLS_ECDH_anon_WITH_NULL_SHA,
- TLS_ECDH_anon_WITH_RC4_128_SHA,
- TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
- TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
- TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
-
- /* TLS 1.2 addenda, RFC 5246 */
-
- /* Initial state. */
- TLS_NULL_WITH_NULL_NULL,
-
- /* Server provided RSA certificate for key exchange. */
- TLS_RSA_WITH_NULL_MD5,
- TLS_RSA_WITH_NULL_SHA,
- TLS_RSA_WITH_RC4_128_MD5,
- TLS_RSA_WITH_RC4_128_SHA,
- TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- //TLS_RSA_WITH_AES_128_CBC_SHA,
- //TLS_RSA_WITH_AES_256_CBC_SHA,
- TLS_RSA_WITH_NULL_SHA256,
- TLS_RSA_WITH_AES_128_CBC_SHA256,
- TLS_RSA_WITH_AES_256_CBC_SHA256,
-
- /* Server-authenticated (and optionally client-authenticated) Diffie-Hellman. */
- TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
- TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
- TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- //TLS_DH_DSS_WITH_AES_128_CBC_SHA,
- //TLS_DH_RSA_WITH_AES_128_CBC_SHA,
- //TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
- //TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- //TLS_DH_DSS_WITH_AES_256_CBC_SHA,
- //TLS_DH_RSA_WITH_AES_256_CBC_SHA,
- //TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
- //TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
- TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
- TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
- TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
-
- /* Completely anonymous Diffie-Hellman */
- TLS_DH_anon_WITH_RC4_128_MD5,
- TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
- //TLS_DH_anon_WITH_AES_128_CBC_SHA,
- //TLS_DH_anon_WITH_AES_256_CBC_SHA,
- TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- TLS_DH_anon_WITH_AES_256_CBC_SHA256,
-
- /* Addendum from RFC 4279, TLS PSK */
-
- TLS_PSK_WITH_RC4_128_SHA,
- TLS_PSK_WITH_3DES_EDE_CBC_SHA,
- TLS_PSK_WITH_AES_128_CBC_SHA,
- TLS_PSK_WITH_AES_256_CBC_SHA,
- TLS_DHE_PSK_WITH_RC4_128_SHA,
- TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
- TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
- TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
- TLS_RSA_PSK_WITH_RC4_128_SHA,
- TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
- TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
- TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
-
- /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
-
- TLS_PSK_WITH_NULL_SHA,
- TLS_DHE_PSK_WITH_NULL_SHA,
- TLS_RSA_PSK_WITH_NULL_SHA,
-
- /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
- for TLS. */
- TLS_RSA_WITH_AES_128_GCM_SHA256,
- TLS_RSA_WITH_AES_256_GCM_SHA384,
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
- TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
- TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
- TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
- TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
- TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
- TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
- TLS_DH_anon_WITH_AES_128_GCM_SHA256,
- TLS_DH_anon_WITH_AES_256_GCM_SHA384,
-
- /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
- TLS_PSK_WITH_AES_128_GCM_SHA256,
- TLS_PSK_WITH_AES_256_GCM_SHA384,
- TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
- TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
- TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
- TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
-
- TLS_PSK_WITH_AES_128_CBC_SHA256,
- TLS_PSK_WITH_AES_256_CBC_SHA384,
- TLS_PSK_WITH_NULL_SHA256,
- TLS_PSK_WITH_NULL_SHA384,
-
- TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
- TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
- TLS_DHE_PSK_WITH_NULL_SHA256,
- TLS_DHE_PSK_WITH_NULL_SHA384,
-
- TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
- TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
- TLS_RSA_PSK_WITH_NULL_SHA256,
- TLS_RSA_PSK_WITH_NULL_SHA384,
-
-
- /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
- HMAC SHA-256/384. */
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
- TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
- TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
-
- /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
- SHA-256/384 and AES Galois Counter Mode (GCM) */
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
-
- /* RFC 5746 - Secure Renegotiation */
- TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
- /*
- * Tags for SSL 2 cipher kinds which are not specified
- * for SSL 3.
- */
- SSL_RSA_WITH_RC2_CBC_MD5,
- SSL_RSA_WITH_IDEA_CBC_MD5,
- SSL_RSA_WITH_DES_CBC_MD5,
- SSL_RSA_WITH_3DES_EDE_CBC_MD5,
- SSL_NO_SUCH_CIPHERSUITE
-}
diff --git a/vendor/security-framework/src/dlsym.rs b/vendor/security-framework/src/dlsym.rs
deleted file mode 100644
index d3229298..00000000
--- a/vendor/security-framework/src/dlsym.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// dlsym.rs is taken from mio
-// https://github.com/carllerche/mio/blob/master/src/sys/unix/dlsym.rs
-
-use std::marker;
-use std::mem;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-use libc;
-
-macro_rules! dlsym {
- (fn $name:ident($($t:ty),*) -> $ret:ty) => (
- #[allow(bad_style)]
- static $name: $crate::dlsym::DlSym<unsafe extern fn($($t),*) -> $ret> =
- $crate::dlsym::DlSym {
- name: concat!(stringify!($name), "\0"),
- addr: ::std::sync::atomic::AtomicUsize::new(0),
- _marker: ::std::marker::PhantomData,
- };
- )
-}
-
-pub struct DlSym<F> {
- pub name: &'static str,
- pub addr: AtomicUsize,
- pub _marker: marker::PhantomData<F>,
-}
-
-impl<F> DlSym<F> {
- pub fn get(&self) -> Option<&F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
- unsafe {
- if self.addr.load(Ordering::SeqCst) == 0 {
- self.addr.store(fetch(self.name), Ordering::SeqCst);
- }
- if self.addr.load(Ordering::SeqCst) == 1 {
- None
- } else {
- mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
- }
- }
- }
-}
-
-unsafe fn fetch(name: &str) -> usize {
- assert_eq!(name.as_bytes()[name.len() - 1], 0);
- match libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize {
- 0 => 1,
- n => n,
- }
-}
diff --git a/vendor/security-framework/src/identity.rs b/vendor/security-framework/src/identity.rs
deleted file mode 100644
index 33775251..00000000
--- a/vendor/security-framework/src/identity.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! Identity support.
-
-use core_foundation::base::TCFType;
-use core_foundation::base::ToVoid;
-use core_foundation::dictionary::CFMutableDictionary;
-use security_framework_sys::base::SecIdentityRef;
-use security_framework_sys::identity::{SecIdentityCopyCertificate, SecIdentityCopyPrivateKey, SecIdentityGetTypeID};
-use security_framework_sys::item::kSecValueRef;
-use security_framework_sys::keychain_item::SecItemDelete;
-use std::fmt;
-use std::ptr;
-
-use crate::base::Error;
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::key::SecKey;
-
-declare_TCFType! {
- /// A type representing an identity.
- ///
- /// Identities are a certificate paired with the corresponding private key.
- SecIdentity, SecIdentityRef
-}
-impl_TCFType!(SecIdentity, SecIdentityRef, SecIdentityGetTypeID);
-
-unsafe impl Sync for SecIdentity {}
-unsafe impl Send for SecIdentity {}
-
-impl fmt::Debug for SecIdentity {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("SecIdentity");
- if let Ok(cert) = self.certificate() {
- builder.field("certificate", &cert);
- }
- if let Ok(key) = self.private_key() {
- builder.field("private_key", &key);
- }
- builder.finish()
- }
-}
-
-impl SecIdentity {
- /// Returns the certificate corresponding to this identity.
- pub fn certificate(&self) -> Result<SecCertificate> {
- unsafe {
- let mut certificate = ptr::null_mut();
- cvt(SecIdentityCopyCertificate(self.0, &mut certificate))?;
- Ok(SecCertificate::wrap_under_create_rule(certificate))
- }
- }
-
- /// Returns the private key corresponding to this identity.
- pub fn private_key(&self) -> Result<SecKey> {
- unsafe {
- let mut key = ptr::null_mut();
- cvt(SecIdentityCopyPrivateKey(self.0, &mut key))?;
- Ok(SecKey::wrap_under_create_rule(key))
- }
- }
-
- /// Translates to `SecItemDelete`, passing in the `SecIdentityRef`
- pub fn delete(&self) -> Result<(), Error> {
- let query = CFMutableDictionary::from_CFType_pairs(&[(
- unsafe { kSecValueRef }.to_void(),
- self.to_void(),
- )]);
-
- cvt(unsafe { SecItemDelete(query.as_concrete_TypeRef()) })
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::SecIdentity;
-
- #[test]
- fn identity_has_send_bound() {
- fn assert_send<T: Send>() {}
- assert_send::<SecIdentity>();
- }
-}
diff --git a/vendor/security-framework/src/import_export.rs b/vendor/security-framework/src/import_export.rs
deleted file mode 100644
index 378a2d5b..00000000
--- a/vendor/security-framework/src/import_export.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-//! Security Framework type import/export support.
-
-use core_foundation::array::CFArray;
-use core_foundation::base::{CFType, TCFType};
-use core_foundation::data::CFData;
-use core_foundation::dictionary::CFDictionary;
-use core_foundation::string::CFString;
-use security_framework_sys::import_export::*;
-use std::ptr;
-
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::identity::SecIdentity;
-#[cfg(target_os = "macos")]
-use crate::os::macos::access::SecAccess;
-#[cfg(target_os = "macos")]
-use crate::os::macos::keychain::SecKeychain;
-use crate::trust::SecTrust;
-
-/// Information about an imported identity.
-pub struct ImportedIdentity {
- /// The label of the identity.
- pub label: Option<String>,
- /// The ID of the identity. Typically the SHA-1 hash of the public key.
- pub key_id: Option<Vec<u8>>,
- /// A `SecTrust` object set up to validate this identity.
- pub trust: Option<SecTrust>,
- /// A certificate chain validating this identity.
- pub cert_chain: Option<Vec<SecCertificate>>,
- /// The identity itself.
- pub identity: Option<SecIdentity>,
- _p: (),
-}
-
-/// A builder type to import an identity from PKCS#12 formatted data.
-#[derive(Default)]
-pub struct Pkcs12ImportOptions {
- passphrase: Option<CFString>,
- #[cfg(target_os = "macos")]
- keychain: Option<SecKeychain>,
- #[cfg(target_os = "macos")]
- access: Option<SecAccess>,
-}
-
-#[cfg(target_os = "macos")]
-impl crate::Pkcs12ImportOptionsInternals for Pkcs12ImportOptions {
- #[inline(always)]
- fn keychain(&mut self, keychain: SecKeychain) -> &mut Self {
- self.keychain = Some(keychain);
- self
- }
-
- #[inline(always)]
- fn access(&mut self, access: SecAccess) -> &mut Self {
- self.access = Some(access);
- self
- }
-}
-
-impl Pkcs12ImportOptions {
- /// Creates a new builder with default options.
- #[inline(always)]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Specifies the passphrase to be used to decrypt the data.
- ///
- /// This must be specified, as unencrypted PKCS#12 data is not supported.
- #[inline]
- pub fn passphrase(&mut self, passphrase: &str) -> &mut Self {
- self.passphrase = Some(CFString::new(passphrase));
- self
- }
-
- /// Imports identities from PKCS#12 encoded data.
- pub fn import(&self, pkcs12_data: &[u8]) -> Result<Vec<ImportedIdentity>> {
- unsafe {
- let pkcs12_data = CFData::from_buffer(pkcs12_data);
-
- let mut options = vec![];
-
- if let Some(ref passphrase) = self.passphrase {
- options.push((
- CFString::wrap_under_get_rule(kSecImportExportPassphrase),
- passphrase.as_CFType(),
- ));
- }
-
- self.import_setup(&mut options);
-
- let options = CFDictionary::from_CFType_pairs(&options);
-
- let mut raw_items = ptr::null();
- cvt(SecPKCS12Import(
- pkcs12_data.as_concrete_TypeRef(),
- options.as_concrete_TypeRef(),
- &mut raw_items,
- ))?;
- let raw_items = CFArray::<CFDictionary<CFString, *const _>>::wrap_under_create_rule(raw_items);
-
- let mut items = vec![];
-
- for raw_item in &raw_items {
- let label = raw_item
- .find(kSecImportItemLabel)
- .map(|label| CFString::wrap_under_get_rule((*label).cast()).to_string());
- let key_id = raw_item
- .find(kSecImportItemKeyID)
- .map(|key_id| CFData::wrap_under_get_rule((*key_id).cast()).to_vec());
- let trust = raw_item
- .find(kSecImportItemTrust)
- .map(|trust| SecTrust::wrap_under_get_rule(*trust as *mut _));
- let cert_chain = raw_item.find(kSecImportItemCertChain.cast()).map(
- |cert_chain| {
- CFArray::<SecCertificate>::wrap_under_get_rule((*cert_chain).cast())
- .iter()
- .map(|c| c.clone())
- .collect()
- },
- );
- let identity = raw_item
- .find(kSecImportItemIdentity)
- .map(|identity| SecIdentity::wrap_under_get_rule(*identity as *mut _));
-
- items.push(ImportedIdentity {
- label,
- key_id,
- trust,
- cert_chain,
- identity,
- _p: (),
- });
- }
-
- Ok(items)
- }
- }
-
- #[cfg(target_os = "macos")]
- fn import_setup(&self, options: &mut Vec<(CFString, CFType)>) {
- unsafe {
- if let Some(ref keychain) = self.keychain {
- options.push((
- CFString::wrap_under_get_rule(kSecImportExportKeychain),
- keychain.as_CFType(),
- ));
- }
-
- if let Some(ref access) = self.access {
- options.push((
- CFString::wrap_under_get_rule(kSecImportExportAccess),
- access.as_CFType(),
- ));
- }
- }
- }
-
- #[cfg(not(target_os = "macos"))]
- fn import_setup(&self, _: &mut Vec<(CFString, CFType)>) {}
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn missing_passphrase() {
- let data = include_bytes!("../test/server.p12");
- assert!(Pkcs12ImportOptions::new().import(data).is_err());
- }
-}
diff --git a/vendor/security-framework/src/item.rs b/vendor/security-framework/src/item.rs
deleted file mode 100644
index 55425ade..00000000
--- a/vendor/security-framework/src/item.rs
+++ /dev/null
@@ -1,793 +0,0 @@
-//! Support to search for items in a keychain.
-
-use core_foundation::array::CFArray;
-use core_foundation::base::{CFType, TCFType, ToVoid};
-use core_foundation::boolean::CFBoolean;
-use core_foundation::data::CFData;
-use core_foundation::date::CFDate;
-use core_foundation::dictionary::{CFDictionary, CFMutableDictionary};
-use core_foundation::number::CFNumber;
-use core_foundation::string::CFString;
-use core_foundation_sys::base::{CFCopyDescription, CFGetTypeID, CFRelease, CFTypeRef};
-use core_foundation_sys::string::CFStringRef;
-use security_framework_sys::item::*;
-use security_framework_sys::keychain_item::{SecItemAdd, SecItemCopyMatching};
-use std::collections::HashMap;
-use std::fmt;
-use std::ptr;
-
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::identity::SecIdentity;
-use crate::key::SecKey;
-#[cfg(target_os = "macos")]
-use crate::os::macos::keychain::SecKeychain;
-
-/// Specifies the type of items to search for.
-#[derive(Debug, Copy, Clone)]
-pub struct ItemClass(CFStringRef);
-
-impl ItemClass {
- /// Look for `SecKeychainItem`s corresponding to generic passwords.
- #[inline(always)]
- #[must_use]
- pub fn generic_password() -> Self {
- unsafe { Self(kSecClassGenericPassword) }
- }
-
- /// Look for `SecKeychainItem`s corresponding to internet passwords.
- #[inline(always)]
- #[must_use]
- pub fn internet_password() -> Self {
- unsafe { Self(kSecClassInternetPassword) }
- }
-
- /// Look for `SecCertificate`s.
- #[inline(always)]
- #[must_use]
- pub fn certificate() -> Self {
- unsafe { Self(kSecClassCertificate) }
- }
-
- /// Look for `SecKey`s.
- #[inline(always)]
- #[must_use]
- pub fn key() -> Self {
- unsafe { Self(kSecClassKey) }
- }
-
- /// Look for `SecIdentity`s.
- #[inline(always)]
- #[must_use]
- pub fn identity() -> Self {
- unsafe { Self(kSecClassIdentity) }
- }
-
- #[inline]
- fn to_value(self) -> CFType {
- unsafe { CFType::wrap_under_get_rule(self.0.cast()) }
- }
-}
-
-/// Specifies the type of keys to search for.
-#[derive(Debug, Copy, Clone)]
-pub struct KeyClass(CFStringRef);
-
-impl KeyClass {
- /// `kSecAttrKeyClassPublic`
- #[inline(always)]
- #[must_use] pub fn public() -> Self {
- unsafe { Self(kSecAttrKeyClassPublic) }
- }
- /// `kSecAttrKeyClassPrivate`
- #[inline(always)]
- #[must_use] pub fn private() -> Self {
- unsafe { Self(kSecAttrKeyClassPrivate) }
- }
- /// `kSecAttrKeyClassSymmetric`
- #[inline(always)]
- #[must_use] pub fn symmetric() -> Self {
- unsafe { Self(kSecAttrKeyClassSymmetric) }
- }
-
- #[inline]
- fn to_value(self) -> CFType {
- unsafe { CFType::wrap_under_get_rule(self.0.cast()) }
- }
-}
-
-/// Specifies the number of results returned by a search
-#[derive(Debug, Copy, Clone)]
-pub enum Limit {
- /// Always return all results
- All,
-
- /// Return up to the specified number of results
- Max(i64),
-}
-
-impl Limit {
- #[inline]
- fn to_value(self) -> CFType {
- match self {
- Self::All => unsafe { CFString::wrap_under_get_rule(kSecMatchLimitAll).into_CFType() },
- Self::Max(l) => CFNumber::from(l).into_CFType(),
- }
- }
-}
-
-impl From<i64> for Limit {
- #[inline]
- fn from(limit: i64) -> Self {
- Self::Max(limit)
- }
-}
-
-/// A builder type to search for items in keychains.
-#[derive(Default)]
-pub struct ItemSearchOptions {
- #[cfg(target_os = "macos")]
- keychains: Option<CFArray<SecKeychain>>,
- #[cfg(not(target_os = "macos"))]
- keychains: Option<CFArray<CFType>>,
- case_insensitive: Option<bool>,
- class: Option<ItemClass>,
- key_class: Option<KeyClass>,
- load_refs: bool,
- load_attributes: bool,
- load_data: bool,
- limit: Option<Limit>,
- trusted_only: Option<bool>,
- label: Option<CFString>,
- service: Option<CFString>,
- subject: Option<CFString>,
- account: Option<CFString>,
- access_group: Option<CFString>,
- pub_key_hash: Option<CFData>,
- app_label: Option<CFData>,
-}
-
-#[cfg(target_os = "macos")]
-impl crate::ItemSearchOptionsInternals for ItemSearchOptions {
- #[inline]
- fn keychains(&mut self, keychains: &[SecKeychain]) -> &mut Self {
- self.keychains = Some(CFArray::from_CFTypes(keychains));
- self
- }
-}
-
-impl ItemSearchOptions {
- /// Creates a new builder with default options.
- #[inline(always)]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Search only for items of the specified class.
- #[inline(always)]
- pub fn class(&mut self, class: ItemClass) -> &mut Self {
- self.class = Some(class);
- self
- }
-
- /// Whether search for an item should be case insensitive or not.
- #[inline(always)]
- pub fn case_insensitive(&mut self, case_insensitive: Option<bool>) -> &mut Self {
- self.case_insensitive = case_insensitive;
- self
- }
-
- /// Search only for keys of the specified class. Also sets self.class to
- /// `ItemClass::key()`.
- #[inline(always)]
- pub fn key_class(&mut self, key_class: KeyClass) -> &mut Self {
- self.class(ItemClass::key());
- self.key_class = Some(key_class);
- self
- }
-
- /// Load Security Framework objects (`SecCertificate`, `SecKey`, etc) for
- /// the results.
- #[inline(always)]
- pub fn load_refs(&mut self, load_refs: bool) -> &mut Self {
- self.load_refs = load_refs;
- self
- }
-
- /// Load Security Framework object attributes for
- /// the results.
- #[inline(always)]
- pub fn load_attributes(&mut self, load_attributes: bool) -> &mut Self {
- self.load_attributes = load_attributes;
- self
- }
-
- /// Load Security Framework objects data for
- /// the results.
- #[inline(always)]
- pub fn load_data(&mut self, load_data: bool) -> &mut Self {
- self.load_data = load_data;
- self
- }
-
- /// Limit the number of search results.
- ///
- /// If this is not called, the default limit is 1.
- #[inline(always)]
- pub fn limit<T: Into<Limit>>(&mut self, limit: T) -> &mut Self {
- self.limit = Some(limit.into());
- self
- }
-
- /// Search for an item with the given label.
- #[inline(always)]
- pub fn label(&mut self, label: &str) -> &mut Self {
- self.label = Some(CFString::new(label));
- self
- }
-
- /// Whether untrusted certificates should be returned.
- #[inline(always)]
- pub fn trusted_only(&mut self, trusted_only: Option<bool>) -> &mut Self {
- self.trusted_only = trusted_only;
- self
- }
-
- /// Search for an item with the given service.
- #[inline(always)]
- pub fn service(&mut self, service: &str) -> &mut Self {
- self.service = Some(CFString::new(service));
- self
- }
-
- /// Search for an item with exactly the given subject.
- #[inline(always)]
- pub fn subject(&mut self, subject: &str) -> &mut Self {
- self.subject = Some(CFString::new(subject));
- self
- }
-
- /// Search for an item with the given account.
- #[inline(always)]
- pub fn account(&mut self, account: &str) -> &mut Self {
- self.account = Some(CFString::new(account));
- self
- }
-
- /// Search for an item with a specific access group.
- pub fn access_group(&mut self, access_group: &str) -> &mut Self {
- self.access_group = Some(CFString::new(access_group));
- self
- }
-
- /// Sets `kSecAttrAccessGroup` to `kSecAttrAccessGroupToken`
- #[inline(always)]
- pub fn access_group_token(&mut self) -> &mut Self {
- self.access_group = unsafe { Some(CFString::wrap_under_get_rule(kSecAttrAccessGroupToken)) };
- self
- }
-
- /// Search for a certificate with the given public key hash.
- ///
- /// This is only compatible with [`ItemClass::certificate`], to search for
- /// a key by public key hash use [`ItemSearchOptions::application_label`]
- /// instead.
- #[inline(always)]
- pub fn pub_key_hash(&mut self, pub_key_hash: &[u8]) -> &mut Self {
- self.pub_key_hash = Some(CFData::from_buffer(pub_key_hash));
- self
- }
-
- /// Search for a key with the given public key hash.
- ///
- /// This is only compatible with [`ItemClass::key`], to search for a
- /// certificate by the public key hash use [`ItemSearchOptions::pub_key_hash`]
- /// instead.
- #[inline(always)]
- pub fn application_label(&mut self, app_label: &[u8]) -> &mut Self {
- self.app_label = Some(CFData::from_buffer(app_label));
- self
- }
-
- /// Search for objects.
- pub fn search(&self) -> Result<Vec<SearchResult>> {
- unsafe {
- let mut params = vec![];
-
- if let Some(ref keychains) = self.keychains {
- params.push((
- CFString::wrap_under_get_rule(kSecMatchSearchList),
- keychains.as_CFType(),
- ));
- }
-
- if let Some(class) = self.class {
- params.push((CFString::wrap_under_get_rule(kSecClass), class.to_value()));
- }
-
- if let Some(case_insensitive) = self.case_insensitive {
- params.push((
- CFString::wrap_under_get_rule(kSecMatchCaseInsensitive),
- CFBoolean::from(case_insensitive).as_CFType()
- ));
- }
-
- if let Some(key_class) = self.key_class {
- params.push((CFString::wrap_under_get_rule(kSecAttrKeyClass), key_class.to_value()));
- }
-
- if self.load_refs {
- params.push((
- CFString::wrap_under_get_rule(kSecReturnRef),
- CFBoolean::true_value().into_CFType(),
- ));
- }
-
- if self.load_attributes {
- params.push((
- CFString::wrap_under_get_rule(kSecReturnAttributes),
- CFBoolean::true_value().into_CFType(),
- ));
- }
-
- if self.load_data {
- params.push((
- CFString::wrap_under_get_rule(kSecReturnData),
- CFBoolean::true_value().into_CFType(),
- ));
- }
-
- if let Some(limit) = self.limit {
- params.push((
- CFString::wrap_under_get_rule(kSecMatchLimit),
- limit.to_value(),
- ));
- }
-
- if let Some(ref label) = self.label {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrLabel),
- label.as_CFType(),
- ));
- }
-
- if let Some(ref trusted_only) = self.trusted_only {
- params.push((
- CFString::wrap_under_get_rule(kSecMatchTrustedOnly),
- if *trusted_only { CFBoolean::true_value().into_CFType() } else { CFBoolean::false_value().into_CFType() },
- ));
- }
-
- if let Some(ref service) = self.service {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrService),
- service.as_CFType(),
- ));
- }
-
- #[cfg(target_os = "macos")]
- {
- if let Some(ref subject) = self.subject {
- params.push((
- CFString::wrap_under_get_rule(kSecMatchSubjectWholeString),
- subject.as_CFType(),
- ));
- }
- }
-
- if let Some(ref account) = self.account {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrAccount),
- account.as_CFType(),
- ));
- }
-
- if let Some(ref access_group) = self.access_group {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrAccessGroup),
- access_group.as_CFType(),
- ));
- }
-
- if let Some(ref pub_key_hash) = self.pub_key_hash {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrPublicKeyHash),
- pub_key_hash.as_CFType(),
- ));
- }
-
- if let Some(ref app_label) = self.app_label {
- params.push((
- CFString::wrap_under_get_rule(kSecAttrApplicationLabel),
- app_label.as_CFType(),
- ));
- }
-
- let params = CFDictionary::from_CFType_pairs(&params);
-
- let mut ret = ptr::null();
- cvt(SecItemCopyMatching(params.as_concrete_TypeRef(), &mut ret))?;
- if ret.is_null() {
- // SecItemCopyMatching returns NULL if no load_* was specified,
- // causing a segfault.
- return Ok(vec![]);
- }
- let type_id = CFGetTypeID(ret);
-
- let mut items = vec![];
-
- if type_id == CFArray::<CFType>::type_id() {
- let array: CFArray<CFType> = CFArray::wrap_under_create_rule(ret as *mut _);
- for item in array.iter() {
- items.push(get_item(item.as_CFTypeRef()));
- }
- } else {
- items.push(get_item(ret));
- // This is a bit janky, but get_item uses wrap_under_get_rule
- // which bumps the refcount but we want create semantics
- CFRelease(ret);
- }
-
- Ok(items)
- }
- }
-}
-
-unsafe fn get_item(item: CFTypeRef) -> SearchResult {
- let type_id = CFGetTypeID(item);
-
- if type_id == CFData::type_id() {
- let data = CFData::wrap_under_get_rule(item as *mut _);
- let mut buf = Vec::new();
- buf.extend_from_slice(data.bytes());
- return SearchResult::Data(buf);
- }
-
- if type_id == CFDictionary::<*const u8, *const u8>::type_id() {
- return SearchResult::Dict(CFDictionary::wrap_under_get_rule(item as *mut _));
- }
-
- #[cfg(target_os = "macos")]
- {
- use crate::os::macos::keychain_item::SecKeychainItem;
- if type_id == SecKeychainItem::type_id() {
- return SearchResult::Ref(Reference::KeychainItem(
- SecKeychainItem::wrap_under_get_rule(item as *mut _),
- ));
- }
- }
-
- let reference = if type_id == SecCertificate::type_id() {
- Reference::Certificate(SecCertificate::wrap_under_get_rule(item as *mut _))
- } else if type_id == SecKey::type_id() {
- Reference::Key(SecKey::wrap_under_get_rule(item as *mut _))
- } else if type_id == SecIdentity::type_id() {
- Reference::Identity(SecIdentity::wrap_under_get_rule(item as *mut _))
- } else {
- panic!("Got bad type from SecItemCopyMatching: {type_id}");
- };
-
- SearchResult::Ref(reference)
-}
-
-/// An enum including all objects whose references can be returned from a search.
-/// Note that generic _Keychain Items_, such as passwords and preferences, do
-/// not have specific object types; they are modeled using dictionaries and so
-/// are available directly as search results in variant `SearchResult::Dict`.
-#[derive(Debug)]
-pub enum Reference {
- /// A `SecIdentity`.
- Identity(SecIdentity),
- /// A `SecCertificate`.
- Certificate(SecCertificate),
- /// A `SecKey`.
- Key(SecKey),
- /// A `SecKeychainItem`.
- ///
- /// Only defined on OSX
- #[cfg(target_os = "macos")]
- KeychainItem(crate::os::macos::keychain_item::SecKeychainItem),
- #[doc(hidden)]
- __NonExhaustive,
-}
-
-/// An individual search result.
-pub enum SearchResult {
- /// A reference to the Security Framework object, if asked for.
- Ref(Reference),
- /// A dictionary of data about the Security Framework object, if asked for.
- Dict(CFDictionary),
- /// The Security Framework object as bytes, if asked for.
- Data(Vec<u8>),
- /// An unknown representation of the Security Framework object.
- Other,
-}
-
-impl fmt::Debug for SearchResult {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Self::Ref(ref reference) => fmt
- .debug_struct("SearchResult::Ref")
- .field("reference", reference)
- .finish(),
- Self::Data(ref buf) => fmt
- .debug_struct("SearchResult::Data")
- .field("data", buf)
- .finish(),
- Self::Dict(_) => {
- let mut debug = fmt.debug_struct("SearchResult::Dict");
- for (k, v) in self.simplify_dict().unwrap() {
- debug.field(&k, &v);
- }
- debug.finish()
- }
- Self::Other => write!(fmt, "SearchResult::Other"),
- }
- }
-}
-
-impl SearchResult {
- /// If the search result is a `CFDict`, simplify that to a
- /// `HashMap<String, String>`. This transformation isn't
- /// comprehensive, it only supports `CFString`, `CFDate`, and `CFData`
- /// value types.
- #[must_use]
- pub fn simplify_dict(&self) -> Option<HashMap<String, String>> {
- match *self {
- Self::Dict(ref d) => unsafe {
- let mut retmap = HashMap::new();
- let (keys, values) = d.get_keys_and_values();
- for (k, v) in keys.iter().zip(values.iter()) {
- let keycfstr = CFString::wrap_under_get_rule((*k).cast());
- let val: String = match CFGetTypeID(*v) {
- cfstring if cfstring == CFString::type_id() => {
- format!("{}", CFString::wrap_under_get_rule((*v).cast()))
- }
- cfdata if cfdata == CFData::type_id() => {
- let buf = CFData::wrap_under_get_rule((*v).cast());
- let mut vec = Vec::new();
- vec.extend_from_slice(buf.bytes());
- format!("{}", String::from_utf8_lossy(&vec))
- }
- cfdate if cfdate == CFDate::type_id() => format!(
- "{}",
- CFString::wrap_under_create_rule(CFCopyDescription(*v))
- ),
- _ => String::from("unknown"),
- };
- retmap.insert(format!("{keycfstr}"), val);
- }
- Some(retmap)
- },
- _ => None,
- }
- }
-}
-
-/// Builder-pattern struct for specifying options for `add_item` (`SecAddItem`
-/// wrapper).
-///
-/// When finished populating options, call `to_dictionary()` and pass the
-/// resulting `CFDictionary` to `add_item`.
-pub struct ItemAddOptions {
- /// The value (by ref or data) of the item to add, required.
- pub value: ItemAddValue,
- /// Optional kSecAttrAccount attribute.
- pub account_name: Option<CFString>,
- /// Optional kSecAttrAccessGroup attribute.
- pub access_group: Option<CFString>,
- /// Optional kSecAttrComment attribute.
- pub comment: Option<CFString>,
- /// Optional kSecAttrDescription attribute.
- pub description: Option<CFString>,
- /// Optional kSecAttrLabel attribute.
- pub label: Option<CFString>,
- /// Optional kSecAttrService attribute.
- pub service: Option<CFString>,
- /// Optional keychain location.
- pub location: Option<Location>,
-}
-
-impl ItemAddOptions {
- /// Specifies the item to add.
- #[must_use]
- pub fn new(value: ItemAddValue) -> Self {
- Self{ value, label: None, location: None, service: None, account_name: None, comment: None, description: None, access_group: None }
- }
-
- /// Specifies the `kSecAttrAccount` attribute.
- pub fn set_account_name(&mut self, account_name: impl AsRef<str>) -> &mut Self {
- self.account_name = Some(account_name.as_ref().into());
- self
- }
- /// Specifies the `kSecAttrAccessGroup` attribute.
- pub fn set_access_group(&mut self, access_group: impl AsRef<str>) -> &mut Self {
- self.access_group = Some(access_group.as_ref().into());
- self
- }
- /// Specifies the `kSecAttrComment` attribute.
- pub fn set_comment(&mut self, comment: impl AsRef<str>) -> &mut Self {
- self.comment = Some(comment.as_ref().into());
- self
- }
- /// Specifies the `kSecAttrDescription` attribute.
- pub fn set_description(&mut self, description: impl AsRef<str>) -> &mut Self {
- self.description = Some(description.as_ref().into());
- self
- }
- /// Specifies the `kSecAttrLabel` attribute.
- pub fn set_label(&mut self, label: impl AsRef<str>) -> &mut Self {
- self.label = Some(label.as_ref().into());
- self
- }
- /// Specifies which keychain to add the item to.
- pub fn set_location(&mut self, location: Location) -> &mut Self {
- self.location = Some(location);
- self
- }
- /// Specifies the `kSecAttrService` attribute.
- pub fn set_service(&mut self, service: impl AsRef<str>) -> &mut Self {
- self.service = Some(service.as_ref().into());
- self
- }
- /// Populates a `CFDictionary` to be passed to
- pub fn to_dictionary(&self) -> CFDictionary {
- let mut dict = CFMutableDictionary::from_CFType_pairs(&[]);
-
- let class_opt = match &self.value {
- ItemAddValue::Ref(ref_) => ref_.class(),
- ItemAddValue::Data { class, .. } => Some(*class),
- };
- if let Some(class) = class_opt {
- dict.add(&unsafe { kSecClass }.to_void(), &class.0.to_void());
- }
-
- let value_pair = match &self.value {
- ItemAddValue::Ref(ref_) => (unsafe { kSecValueRef }.to_void(), ref_.ref_()),
- ItemAddValue::Data { data, .. } => (unsafe { kSecValueData }.to_void(), data.to_void()),
- };
- dict.add(&value_pair.0, &value_pair.1);
-
- if let Some(location) = &self.location {
- match location {
- #[cfg(any(feature = "OSX_10_15", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- Location::DataProtectionKeychain => {
- dict.add(
- &unsafe { kSecUseDataProtectionKeychain }.to_void(),
- &CFBoolean::true_value().to_void(),
- );
- }
- #[cfg(target_os = "macos")]
- Location::DefaultFileKeychain => {}
- #[cfg(target_os = "macos")]
- Location::FileKeychain(keychain) => {
- dict.add(&unsafe { kSecUseKeychain }.to_void(), &keychain.to_void());
- },
- }
- }
- if let Some(account_name) = &self.account_name {
- dict.add(&unsafe { kSecAttrAccount }.to_void(), &account_name.to_void());
- }
- if let Some(access_group) = &self.access_group {
- dict.add(&unsafe { kSecAttrAccessGroup }.to_void(), &access_group.to_void());
- }
- if let Some(comment) = &self.comment {
- dict.add(&unsafe { kSecAttrComment }.to_void(), &comment.to_void());
- }
- if let Some(description) = &self.description {
- dict.add(&unsafe { kSecAttrDescription }.to_void(), &description.to_void());
- }
- if let Some(label) = &self.label {
- dict.add(&unsafe { kSecAttrLabel }.to_void(), &label.to_void());
- }
- if let Some(service) = &self.service {
- dict.add(&unsafe { kSecAttrService }.to_void(), &service.to_void());
- }
-
- dict.to_immutable()
- }
-}
-
-/// Value of an item to add to the keychain.
-pub enum ItemAddValue {
- /// Pass item by Ref (kSecValueRef)
- Ref(AddRef),
- /// Pass item by Data (kSecValueData)
- Data {
- /// The item class (kSecClass).
- class: ItemClass,
- /// The item data.
- data: CFData,
- },
-}
-
-/// Type of Ref to add to the keychain.
-pub enum AddRef {
- /// `SecKey`
- Key(SecKey),
- /// `SecIdentity`
- Identity(SecIdentity),
- /// `SecCertificate`
- Certificate(SecCertificate),
-}
-
-impl AddRef {
- fn class(&self) -> Option<ItemClass> {
- match self {
- AddRef::Key(_) => Some(ItemClass::key()),
- // kSecClass should not be specified when adding a SecIdentityRef:
- // https://developer.apple.com/forums/thread/25751
- AddRef::Identity(_) => None,
- AddRef::Certificate(_) => Some(ItemClass::certificate()),
- }
- }
- fn ref_(&self) -> CFTypeRef {
- match self {
- AddRef::Key(key) => key.as_CFTypeRef(),
- AddRef::Identity(id) => id.as_CFTypeRef(),
- AddRef::Certificate(cert) => cert.as_CFTypeRef(),
- }
- }
-}
-
-/// Which keychain to add an item to.
-///
-/// <https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains>
-pub enum Location {
- /// Store the item in the newer DataProtectionKeychain. This is the only
- /// keychain on iOS. On macOS, this is the newer and more consistent
- /// keychain implementation. Keys stored in the Secure Enclave _must_ use
- /// this keychain.
- ///
- /// This keychain requires the calling binary to be codesigned with
- /// entitlements for the KeychainAccessGroups it is supposed to
- /// access.
- #[cfg(any(feature = "OSX_10_15", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- DataProtectionKeychain,
- /// Store the key in the default file-based keychain. On macOS, defaults to
- /// the Login keychain.
- #[cfg(target_os = "macos")]
- DefaultFileKeychain,
- /// Store the key in a specific file-based keychain.
- #[cfg(target_os = "macos")]
- FileKeychain(crate::os::macos::keychain::SecKeychain),
-}
-
-/// Translates to `SecItemAdd`. Use `ItemAddOptions` to build an `add_params`
-/// `CFDictionary`.
-pub fn add_item(add_params: CFDictionary) -> Result<()> {
- cvt(unsafe { SecItemAdd(add_params.as_concrete_TypeRef(), std::ptr::null_mut()) })
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn find_nothing() {
- assert!(ItemSearchOptions::new().search().is_err());
- }
-
- #[test]
- fn limit_two() {
- let results = ItemSearchOptions::new()
- .class(ItemClass::certificate())
- .limit(2)
- .search()
- .unwrap();
- assert_eq!(results.len(), 2);
- }
-
- #[test]
- fn limit_all() {
- let results = ItemSearchOptions::new()
- .class(ItemClass::certificate())
- .limit(Limit::All)
- .search()
- .unwrap();
- assert!(results.len() >= 2);
- }
-}
diff --git a/vendor/security-framework/src/key.rs b/vendor/security-framework/src/key.rs
deleted file mode 100644
index a244de8c..00000000
--- a/vendor/security-framework/src/key.rs
+++ /dev/null
@@ -1,398 +0,0 @@
-//! Encryption key support
-
-use crate::cvt;
-use core_foundation::{
- base::TCFType, string::{CFStringRef, CFString},
- dictionary::CFMutableDictionary,
-};
-use core_foundation::base::ToVoid;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::boolean::CFBoolean;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::data::CFData;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::dictionary::CFDictionary;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::number::CFNumber;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use core_foundation::error::{CFError, CFErrorRef};
-
-use security_framework_sys::{
- item::{kSecAttrKeyTypeRSA, kSecValueRef},
- keychain_item::SecItemDelete
-};
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use security_framework_sys::{item::{
- kSecAttrIsPermanent, kSecAttrLabel, kSecAttrKeyType,
- kSecAttrKeySizeInBits, kSecPrivateKeyAttrs, kSecAttrAccessControl
-}};
-#[cfg(target_os="macos")]
-use security_framework_sys::item::{
- kSecAttrKeyType3DES, kSecAttrKeyTypeDSA, kSecAttrKeyTypeAES,
- kSecAttrKeyTypeDES, kSecAttrKeyTypeRC4, kSecAttrKeyTypeCAST,
-};
-
-use security_framework_sys::key::SecKeyGetTypeID;
-use security_framework_sys::base::SecKeyRef;
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub use security_framework_sys::key::Algorithm;
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use security_framework_sys::key::{
- SecKeyCopyAttributes, SecKeyCopyExternalRepresentation,
- SecKeyCreateSignature, SecKeyCreateRandomKey,
- SecKeyCopyPublicKey,
-};
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use security_framework_sys::item::kSecAttrApplicationLabel;
-use std::fmt;
-
-
-use crate::base::Error;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use crate::item::Location;
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-use crate::access_control::SecAccessControl;
-/// Types of `SecKey`s.
-#[derive(Debug, Copy, Clone)]
-pub struct KeyType(CFStringRef);
-
-#[allow(missing_docs)]
-impl KeyType {
- #[inline(always)]
- #[must_use]
- pub fn rsa() -> Self {
- unsafe { Self(kSecAttrKeyTypeRSA) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn dsa() -> Self {
- unsafe { Self(kSecAttrKeyTypeDSA) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn aes() -> Self {
- unsafe { Self(kSecAttrKeyTypeAES) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn des() -> Self {
- unsafe { Self(kSecAttrKeyTypeDES) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn triple_des() -> Self {
- unsafe { Self(kSecAttrKeyType3DES) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn rc4() -> Self {
- unsafe { Self(kSecAttrKeyTypeRC4) }
- }
-
- #[cfg(target_os = "macos")]
- #[inline(always)]
- #[must_use]
- pub fn cast() -> Self {
- unsafe { Self(kSecAttrKeyTypeCAST) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn ec() -> Self {
- use security_framework_sys::item::kSecAttrKeyTypeEC;
-
- unsafe { Self(kSecAttrKeyTypeEC) }
- }
-
- pub(crate) fn to_str(self) -> CFString {
- unsafe { CFString::wrap_under_get_rule(self.0) }
- }
-}
-
-declare_TCFType! {
- /// A type representing an encryption key.
- SecKey, SecKeyRef
-}
-impl_TCFType!(SecKey, SecKeyRef, SecKeyGetTypeID);
-
-unsafe impl Sync for SecKey {}
-unsafe impl Send for SecKey {}
-
-impl SecKey {
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Translates to `SecKeyCreateRandomKey`
- /// `GenerateKeyOptions` provides a helper to create an attribute
- /// `CFDictionary`.
- pub fn generate(attributes: CFDictionary) -> Result<Self, CFError> {
- let mut error: CFErrorRef = ::std::ptr::null_mut();
- let sec_key = unsafe { SecKeyCreateRandomKey(attributes.as_concrete_TypeRef(), &mut error)};
- if !error.is_null() {
- Err(unsafe { CFError::wrap_under_create_rule(error) })
- } else {
- Ok(unsafe { SecKey::wrap_under_create_rule(sec_key) })
- }
- }
-
- /// Returns the programmatic identifier for the key. For keys of class
- /// kSecAttrKeyClassPublic and kSecAttrKeyClassPrivate, the value is the
- /// hash of the public key.
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- pub fn application_label(&self) -> Option<Vec<u8>> {
- self.attributes()
- .find(unsafe { kSecAttrApplicationLabel.to_void() })
- .map(|v| unsafe { CFData::wrap_under_get_rule(v.cast()) }.to_vec())
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Translates to `SecKeyCopyAttributes`
- #[must_use]
- pub fn attributes(&self) -> CFDictionary {
- let pka = unsafe { SecKeyCopyAttributes(self.to_void() as _) };
- unsafe { CFDictionary::wrap_under_create_rule(pka) }
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Translates to `SecKeyCopyExternalRepresentation`
- #[must_use]
- pub fn external_representation(&self) -> Option<CFData> {
- let mut error: CFErrorRef = ::std::ptr::null_mut();
- let data = unsafe { SecKeyCopyExternalRepresentation(self.to_void() as _, &mut error) };
- if data.is_null() {
- return None;
- }
- Some(unsafe { CFData::wrap_under_create_rule(data) })
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Translates to `SecKeyCopyPublicKey`
- #[must_use]
- pub fn public_key(&self) -> Option<Self> {
- let pub_seckey = unsafe { SecKeyCopyPublicKey(self.0.cast()) };
- if pub_seckey.is_null() {
- return None;
- }
-
- Some(unsafe { SecKey::wrap_under_create_rule(pub_seckey) })
- }
-
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- /// Creates the cryptographic signature for a block of data using a private
- /// key and specified algorithm.
- pub fn create_signature(&self, algorithm: Algorithm, input: &[u8]) -> Result<Vec<u8>, CFError> {
- let mut error: CFErrorRef = std::ptr::null_mut();
-
- let output = unsafe {
- SecKeyCreateSignature(
- self.as_concrete_TypeRef(),
- algorithm.into(),
- CFData::from_buffer(input).as_concrete_TypeRef(),
- &mut error,
- )
- };
-
- if !error.is_null() {
- Err(unsafe { CFError::wrap_under_create_rule(error) })
- } else {
- let output = unsafe { CFData::wrap_under_create_rule(output) };
- Ok(output.to_vec())
- }
- }
-
- /// Verifies the cryptographic signature for a block of data using a public
- /// key and specified algorithm.
- #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- pub fn verify_signature(&self, algorithm: Algorithm, signed_data: &[u8], signature: &[u8]) -> Result<bool, CFError> {
- use security_framework_sys::key::SecKeyVerifySignature;
- let mut error: CFErrorRef = std::ptr::null_mut();
-
- let valid = unsafe {
- SecKeyVerifySignature(
- self.as_concrete_TypeRef(),
- algorithm.into(),
- CFData::from_buffer(signed_data).as_concrete_TypeRef(),
- CFData::from_buffer(signature).as_concrete_TypeRef(),
- &mut error,
- )
- };
-
- if !error.is_null() {
- return Err(unsafe { CFError::wrap_under_create_rule(error) })?;
- }
- Ok(valid != 0)
- }
-
- /// Translates to `SecItemDelete`, passing in the `SecKeyRef`
- pub fn delete(&self) -> Result<(), Error> {
- let query = CFMutableDictionary::from_CFType_pairs(&[(
- unsafe { kSecValueRef }.to_void(),
- self.to_void(),
- )]);
-
- cvt(unsafe { SecItemDelete(query.as_concrete_TypeRef()) })
- }
-}
-
-/// Where to generate the key.
-pub enum Token {
- /// Generate the key in software, compatible with all `KeyType`s.
- Software,
- /// Generate the key in the Secure Enclave such that the private key is not
- /// extractable. Only compatible with `KeyType::ec()`.
- SecureEnclave,
-}
-
-/// Helper for creating `CFDictionary` attributes for `SecKey::generate`
-/// Recommended reading:
-/// <https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains>
-#[derive(Default)]
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub struct GenerateKeyOptions {
- /// kSecAttrKeyType
- pub key_type: Option<KeyType>,
- /// kSecAttrKeySizeInBits
- pub size_in_bits: Option<u32>,
- /// kSecAttrLabel
- pub label: Option<String>,
- /// kSecAttrTokenID
- pub token: Option<Token>,
- /// Which keychain to store the key in, if any.
- pub location: Option<Location>,
- /// Access control
- pub access_control: Option<SecAccessControl>,
-}
-
-#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-impl GenerateKeyOptions {
- /// Set `key_type`
- pub fn set_key_type(&mut self, key_type: KeyType) -> &mut Self {
- self.key_type = Some(key_type);
- self
- }
- /// Set `size_in_bits`
- pub fn set_size_in_bits(&mut self, size_in_bits: u32) -> &mut Self {
- self.size_in_bits = Some(size_in_bits);
- self
- }
- /// Set `label`
- pub fn set_label(&mut self, label: impl Into<String>) -> &mut Self {
- self.label = Some(label.into());
- self
- }
- /// Set `token`
- pub fn set_token(&mut self, token: Token) -> &mut Self {
- self.token = Some(token);
- self
- }
- /// Set `location`
- pub fn set_location(&mut self, location: Location) -> &mut Self {
- self.location = Some(location);
- self
- }
- /// Set `access_control`
- pub fn set_access_control(&mut self, access_control: SecAccessControl) -> &mut Self {
- self.access_control = Some(access_control);
- self
- }
-
- /// Collect options into a `CFDictioanry`
- pub fn to_dictionary(&self) -> CFDictionary {
- #[cfg(target_os = "macos")]
- use security_framework_sys::item::kSecUseKeychain;
- use security_framework_sys::item::{
- kSecAttrTokenID, kSecAttrTokenIDSecureEnclave, kSecPublicKeyAttrs,
- };
-
- let is_permanent = CFBoolean::from(self.location.is_some());
- let mut private_attributes = CFMutableDictionary::from_CFType_pairs(&[(
- unsafe { kSecAttrIsPermanent }.to_void(),
- is_permanent.to_void(),
- )]);
- if let Some(access_control) = &self.access_control {
- private_attributes.set(unsafe { kSecAttrAccessControl }.to_void(), access_control.to_void());
- }
-
- let public_attributes = CFMutableDictionary::from_CFType_pairs(&[(
- unsafe { kSecAttrIsPermanent }.to_void(),
- is_permanent.to_void(),
- )]);
-
- let key_type = self.key_type.unwrap_or_else(KeyType::rsa).to_str();
-
- let size_in_bits = self.size_in_bits.unwrap_or(match () {
- _ if key_type == KeyType::rsa().to_str() => 2048,
- _ if key_type == KeyType::ec().to_str() => 256,
- _ => 256,
- });
- let size_in_bits = CFNumber::from(size_in_bits as i32);
-
- let mut attribute_key_values = vec![
- (unsafe { kSecAttrKeyType }.to_void(), key_type.to_void()),
- (
- unsafe { kSecAttrKeySizeInBits }.to_void(),
- size_in_bits.to_void(),
- ),
- (
- unsafe { kSecPrivateKeyAttrs }.to_void(),
- private_attributes.to_void(),
- ),
- (
- unsafe { kSecPublicKeyAttrs }.to_void(),
- public_attributes.to_void(),
- ),
- ];
- let label = self.label.as_deref().map(CFString::new);
- if let Some(label) = &label {
- attribute_key_values.push((unsafe { kSecAttrLabel }.to_void(), label.to_void()));
- }
-
- #[cfg(target_os = "macos")]
- match &self.location {
- #[cfg(feature = "OSX_10_15")]
- Some(Location::DataProtectionKeychain) => {
- use security_framework_sys::item::kSecUseDataProtectionKeychain;
- attribute_key_values.push((
- unsafe { kSecUseDataProtectionKeychain }.to_void(),
- CFBoolean::true_value().to_void(),
- ));
- }
- Some(Location::FileKeychain(keychain)) => {
- attribute_key_values.push((
- unsafe { kSecUseKeychain }.to_void(),
- keychain.as_concrete_TypeRef().to_void(),
- ));
- }
- _ => {}
- }
-
- match self.token.as_ref().unwrap_or(&Token::Software) {
- Token::Software => {},
- Token::SecureEnclave => {
- attribute_key_values.push((
- unsafe { kSecAttrTokenID }.to_void(),
- unsafe { kSecAttrTokenIDSecureEnclave }.to_void(),
- ));
- }
- }
-
- CFMutableDictionary::from_CFType_pairs(&attribute_key_values).to_immutable()
- }
-}
-
-impl fmt::Debug for SecKey {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.debug_struct("SecKey").finish_non_exhaustive()
- }
-}
diff --git a/vendor/security-framework/src/lib.rs b/vendor/security-framework/src/lib.rs
deleted file mode 100644
index 81631afe..00000000
--- a/vendor/security-framework/src/lib.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//! Wrappers around the OSX Security Framework.
-#![warn(missing_docs)]
-#![allow(non_upper_case_globals)]
-#![allow(clippy::manual_non_exhaustive)] // MSRV
-#![allow(clippy::bad_bit_mask)] // bitflags
-
-#[macro_use]
-extern crate core_foundation;
-
-use core_foundation_sys::base::OSStatus;
-use security_framework_sys::base::errSecSuccess;
-
-use crate::base::{Error, Result};
-#[cfg(target_os = "macos")]
-use crate::os::macos::access::SecAccess;
-#[cfg(target_os = "macos")]
-use crate::os::macos::keychain::SecKeychain;
-
-#[cfg(test)]
-macro_rules! p {
- ($e:expr) => {
- match $e {
- Ok(s) => s,
- Err(e) => panic!("{:?}", e),
- }
- };
-}
-
-#[cfg(all(not(feature = "OSX_10_13"), any(feature = "alpn", feature = "session-tickets")))]
-#[macro_use]
-mod dlsym;
-
-pub mod access_control;
-#[cfg(target_os = "macos")]
-pub mod authorization;
-pub mod base;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod certificate;
-pub mod cipher_suite;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod identity;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod import_export;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod item;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod key;
-pub mod os;
-pub mod passwords;
-pub mod passwords_options;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod policy;
-pub mod random;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod secure_transport;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
-pub mod trust;
-#[cfg(target_os = "macos")]
-pub mod trust_settings;
-
-#[cfg(target_os = "macos")]
-trait Pkcs12ImportOptionsInternals {
- fn keychain(&mut self, keychain: SecKeychain) -> &mut Self;
- fn access(&mut self, access: SecAccess) -> &mut Self;
-}
-
-#[cfg(target_os = "macos")]
-trait ItemSearchOptionsInternals {
- fn keychains(&mut self, keychains: &[SecKeychain]) -> &mut Self;
-}
-
-trait AsInner {
- type Inner;
- fn as_inner(&self) -> Self::Inner;
-}
-
-#[inline(always)]
-fn cvt(err: OSStatus) -> Result<()> {
- match err {
- errSecSuccess => Ok(()),
- err => Err(Error::from_code(err)),
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::certificate::SecCertificate;
-
- pub fn certificate() -> SecCertificate {
- let certificate = include_bytes!("../test/server.der");
- p!(SecCertificate::from_der(certificate))
- }
-}
diff --git a/vendor/security-framework/src/os/macos/access.rs b/vendor/security-framework/src/os/macos/access.rs
deleted file mode 100644
index 1c41d85d..00000000
--- a/vendor/security-framework/src/os/macos/access.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//! Access functionality.
-
-use core_foundation::base::TCFType;
-use security_framework_sys::access::SecAccessGetTypeID;
-use security_framework_sys::base::SecAccessRef;
-
-declare_TCFType! {
- /// A type representing access settings.
- SecAccess, SecAccessRef
-}
-impl_TCFType!(SecAccess, SecAccessRef, SecAccessGetTypeID);
-
-unsafe impl Sync for SecAccess {}
-unsafe impl Send for SecAccess {}
diff --git a/vendor/security-framework/src/os/macos/certificate.rs b/vendor/security-framework/src/os/macos/certificate.rs
deleted file mode 100644
index b50ee52d..00000000
--- a/vendor/security-framework/src/os/macos/certificate.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-//! OSX specific extensions to certificate functionality.
-
-use core_foundation::array::{CFArray, CFArrayIterator};
-use core_foundation::base::TCFType;
-use core_foundation::base::ToVoid;
-use core_foundation::data::CFData;
-use core_foundation::dictionary::CFDictionary;
-use core_foundation::error::CFError;
-use core_foundation::string::CFString;
-use security_framework_sys::certificate::*;
-use std::os::raw::c_void;
-use std::ptr;
-
-use crate::base::Error;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::key::SecKey;
-use crate::os::macos::certificate_oids::CertificateOid;
-use crate::os::macos::digest_transform::{Builder, DigestType};
-
-/// An extension trait adding OSX specific functionality to `SecCertificate`.
-pub trait SecCertificateExt {
- /// Returns the common name associated with the certificate.
- fn common_name(&self) -> Result<String, Error>;
-
- /// Returns the public key associated with the certificate.
- #[cfg_attr(not(feature = "OSX_10_14"), deprecated(note = "Uses deprecated SecCertificateCopyPublicKey. Enable OSX_10_14 feature to avoid it"))]
- fn public_key(&self) -> Result<SecKey, Error>;
-
- /// Returns the set of properties associated with the certificate.
- ///
- /// The `keys` argument can optionally be used to filter the properties loaded to an explicit
- /// subset.
- fn properties(&self, keys: Option<&[CertificateOid]>)
- -> Result<CertificateProperties, CFError>;
-
- /// Returns the SHA-256 fingerprint of the certificate.
- fn fingerprint(&self) -> Result<[u8; 32], CFError> { unimplemented!() }
-}
-
-impl SecCertificateExt for SecCertificate {
- fn common_name(&self) -> Result<String, Error> {
- unsafe {
- let mut string = ptr::null();
- cvt(SecCertificateCopyCommonName(
- self.as_concrete_TypeRef(),
- &mut string,
- ))?;
- Ok(CFString::wrap_under_create_rule(string).to_string())
- }
- }
-
- #[cfg(feature = "OSX_10_14")]
- fn public_key(&self) -> Result<SecKey, Error> {
- unsafe {
- let key = SecCertificateCopyKey(self.as_concrete_TypeRef());
- if key.is_null() {
- return Err(Error::from_code(-26275));
- }
- Ok(SecKey::wrap_under_create_rule(key))
- }
- }
-
- #[cfg(not(feature = "OSX_10_14"))]
- fn public_key(&self) -> Result<SecKey, Error> {
- #[allow(deprecated)]
- unsafe {
- let mut key = ptr::null_mut();
- cvt(SecCertificateCopyPublicKey(
- self.as_concrete_TypeRef(),
- &mut key,
- ))?;
- Ok(SecKey::wrap_under_create_rule(key))
- }
- }
-
- fn properties(
- &self,
- keys: Option<&[CertificateOid]>,
- ) -> Result<CertificateProperties, CFError> {
- unsafe {
- let keys = keys.map(|oids| {
- let oids = oids.iter().map(|oid| oid.to_str()).collect::<Vec<_>>();
- CFArray::from_CFTypes(&oids)
- });
-
- let keys = match keys {
- Some(ref keys) => keys.as_concrete_TypeRef(),
- None => ptr::null_mut(),
- };
-
- let mut error = ptr::null_mut();
-
- let dictionary = SecCertificateCopyValues(self.as_concrete_TypeRef(), keys, &mut error);
-
- if error.is_null() {
- Ok(CertificateProperties(CFDictionary::wrap_under_create_rule(
- dictionary,
- )))
- } else {
- Err(CFError::wrap_under_create_rule(error))
- }
- }
- }
-
- /// Returns the SHA-256 fingerprint of the certificate.
- fn fingerprint(&self) -> Result<[u8; 32], CFError> {
- let data = CFData::from_buffer(&self.to_der());
- let hash = Builder::new()
- .type_(DigestType::sha2())
- .length(256)
- .execute(&data)?;
- Ok(hash.bytes().try_into().unwrap())
- }
-}
-
-/// Properties associated with a certificate.
-pub struct CertificateProperties(CFDictionary);
-
-impl CertificateProperties {
- /// Retrieves a specific property identified by its OID.
- #[must_use] pub fn get(&self, oid: CertificateOid) -> Option<CertificateProperty> {
- unsafe {
- self.0.find(oid.as_ptr().cast::<c_void>()).map(|value| {
- CertificateProperty(CFDictionary::wrap_under_get_rule(*value as *mut _))
- })
- }
- }
-}
-
-/// A property associated with a certificate.
-pub struct CertificateProperty(CFDictionary);
-
-impl CertificateProperty {
- /// Returns the label of this property.
- #[must_use]
- pub fn label(&self) -> CFString {
- unsafe {
- CFString::wrap_under_get_rule((*self.0.get(kSecPropertyKeyLabel.to_void())).cast())
- }
- }
-
- /// Returns an enum of the underlying data for this property.
- #[must_use]
- pub fn get(&self) -> PropertyType {
- unsafe {
- let type_ =
- CFString::wrap_under_get_rule(*self.0.get(kSecPropertyKeyType.to_void()) as *mut _);
- let value = self.0.get(kSecPropertyKeyValue.to_void());
-
- if type_ == CFString::wrap_under_get_rule(kSecPropertyTypeSection) {
- PropertyType::Section(PropertySection(CFArray::wrap_under_get_rule(
- (*value).cast(),
- )))
- } else if type_ == CFString::wrap_under_get_rule(kSecPropertyTypeString) {
- PropertyType::String(CFString::wrap_under_get_rule((*value).cast()))
- } else {
- PropertyType::__Unknown
- }
- }
- }
-}
-
-/// A "section" property.
-///
-/// Sections are sequences of other properties.
-pub struct PropertySection(CFArray<CFDictionary>);
-
-impl PropertySection {
- /// Returns an iterator over the properties in this section.
- #[inline(always)]
- #[must_use]
- pub fn iter(&self) -> PropertySectionIter<'_> {
- PropertySectionIter(self.0.iter())
- }
-}
-
-impl<'a> IntoIterator for &'a PropertySection {
- type IntoIter = PropertySectionIter<'a>;
- type Item = CertificateProperty;
-
- #[inline(always)]
- fn into_iter(self) -> PropertySectionIter<'a> {
- self.iter()
- }
-}
-
-/// An iterator over the properties in a section.
-pub struct PropertySectionIter<'a>(CFArrayIterator<'a, CFDictionary>);
-
-impl<'a> Iterator for PropertySectionIter<'a> {
- type Item = CertificateProperty;
-
- #[inline]
- fn next(&mut self) -> Option<CertificateProperty> {
- self.0.next().map(|t| CertificateProperty(t.clone()))
- }
-
- #[inline(always)]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.0.size_hint()
- }
-}
-
-/// An enum of the various types of properties.
-pub enum PropertyType {
- /// A section.
- Section(PropertySection),
- /// A string.
- String(CFString),
- #[doc(hidden)]
- __Unknown,
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::test::certificate;
- use std::collections::HashMap;
-
- #[test]
- fn common_name() {
- let certificate = certificate();
- assert_eq!("foobar.com", p!(certificate.common_name()));
- }
-
- #[test]
- #[allow(deprecated)]
- fn public_key() {
- let certificate = certificate();
- p!(certificate.public_key());
- }
-
- #[test]
- fn fingerprint() {
- let certificate = certificate();
- let fingerprint = p!(certificate.fingerprint());
- assert_eq!(
- "af9dd180a326ae08b37e6398f9262f8b9d4c55674a233a7c84975024f873655d",
- hex::encode(fingerprint)
- );
- }
-
- #[test]
- fn signature_algorithm() {
- let certificate = certificate();
- let properties = certificate
- .properties(Some(&[CertificateOid::x509_v1_signature_algorithm()]))
- .unwrap();
- let value = properties
- .get(CertificateOid::x509_v1_signature_algorithm())
- .unwrap();
- let section = match value.get() {
- PropertyType::Section(section) => section,
- _ => panic!(),
- };
- let properties = section
- .iter()
- .map(|p| (p.label().to_string(), p.get()))
- .collect::<HashMap<_, _>>();
- let algorithm = match properties["Algorithm"] {
- PropertyType::String(ref s) => s.to_string(),
- _ => panic!(),
- };
- assert_eq!(algorithm, "1.2.840.113549.1.1.5");
- }
-}
diff --git a/vendor/security-framework/src/os/macos/certificate_oids.rs b/vendor/security-framework/src/os/macos/certificate_oids.rs
deleted file mode 100644
index d820afe4..00000000
--- a/vendor/security-framework/src/os/macos/certificate_oids.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//! OIDs associated with certificate properties.
-use core_foundation::base::TCFType;
-use core_foundation::string::CFString;
-use core_foundation_sys::string::CFStringRef;
-use security_framework_sys::certificate_oids::kSecOIDX509V1SignatureAlgorithm;
-
-/// An identifier of a property of a certificate.
-#[derive(Copy, Clone)]
-pub struct CertificateOid(CFStringRef);
-
-#[allow(missing_docs)]
-impl CertificateOid {
- #[inline(always)]
- #[must_use]
- pub fn x509_v1_signature_algorithm() -> Self {
- unsafe { Self(kSecOIDX509V1SignatureAlgorithm) }
- }
-
- /// Returns the underlying raw pointer corresponding to this OID.
- #[inline(always)]
- #[must_use]
- pub fn as_ptr(&self) -> CFStringRef {
- self.0
- }
-
- /// Returns the string representation of the OID.
- #[inline]
- #[must_use]
- pub fn to_str(&self) -> CFString {
- unsafe { CFString::wrap_under_get_rule(self.0) }
- }
-}
diff --git a/vendor/security-framework/src/os/macos/code_signing.rs b/vendor/security-framework/src/os/macos/code_signing.rs
deleted file mode 100644
index b42917c1..00000000
--- a/vendor/security-framework/src/os/macos/code_signing.rs
+++ /dev/null
@@ -1,486 +0,0 @@
-//! Code signing services.
-
-use std::{fmt::Debug, mem::MaybeUninit, str::FromStr};
-
-use core_foundation::{
- base::{TCFType, TCFTypeRef, ToVoid},
- data::CFDataRef,
- dictionary::CFMutableDictionary,
- number::CFNumber,
- string::{CFString, CFStringRef},
- url::CFURL,
-};
-use libc::pid_t;
-use security_framework_sys::code_signing::{
- kSecCSBasicValidateOnly, kSecCSCheckAllArchitectures, kSecCSCheckGatekeeperArchitectures,
- kSecCSCheckNestedCode, kSecCSCheckTrustedAnchors, kSecCSConsiderExpiration,
- kSecCSDoNotValidateExecutable, kSecCSDoNotValidateResources, kSecCSEnforceRevocationChecks,
- kSecCSFullReport, kSecCSNoNetworkAccess, kSecCSQuickCheck, kSecCSReportProgress,
- kSecCSRestrictSidebandData, kSecCSRestrictSymlinks, kSecCSRestrictToAppLike,
- kSecCSSingleThreaded, kSecCSStrictValidate, kSecCSUseSoftwareSigningCert, kSecCSValidatePEH,
- kSecGuestAttributeAudit, kSecGuestAttributePid, SecCodeCheckValidity,
- SecCodeCopyGuestWithAttributes, SecCodeCopyPath, SecCodeCopySelf, SecCodeGetTypeID, SecCodeRef,
- SecRequirementCreateWithString, SecRequirementGetTypeID, SecRequirementRef,
- SecStaticCodeCheckValidity, SecStaticCodeCreateWithPath, SecStaticCodeGetTypeID,
- SecStaticCodeRef,
-};
-
-use crate::{cvt, Result};
-
-bitflags::bitflags! {
-
- /// Values that can be used in the flags parameter to most code signing
- /// functions.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct Flags: u32 {
- /// Use the default behaviour.
- const NONE = 0;
-
- /// For multi-architecture (universal) Mach-O programs, validate all
- /// architectures included.
- const CHECK_ALL_ARCHITECTURES = kSecCSCheckAllArchitectures;
-
- /// Do not validate the contents of the main executable.
- const DO_NOT_VALIDATE_EXECUTABLE = kSecCSDoNotValidateExecutable;
-
- /// Do not validate the presence and contents of all bundle resources
- /// if any.
- const DO_NOT_VALIDATE_RESOURCES = kSecCSDoNotValidateResources;
-
- /// Do not validate either the main executable or the bundle resources,
- /// if any.
- const BASIC_VALIDATE_ONLY = kSecCSBasicValidateOnly;
-
- /// For code in bundle form, locate and recursively check embedded code.
- const CHECK_NESTED_CODE = kSecCSCheckNestedCode;
-
- /// Perform additional checks to ensure the validity of code in bundle
- /// form.
- const STRICT_VALIDATE = kSecCSStrictValidate;
-
- /// Apple have not documented this flag.
- const FULL_REPORT = kSecCSFullReport;
-
- /// Apple have not documented this flag.
- const CHECK_GATEKEEPER_ARCHITECTURES = kSecCSCheckGatekeeperArchitectures;
-
- /// Apple have not documented this flag.
- const RESTRICT_SYMLINKS = kSecCSRestrictSymlinks;
-
- /// Apple have not documented this flag.
- const RESTRICT_TO_APP_LIKE = kSecCSRestrictToAppLike;
-
- /// Apple have not documented this flag.
- const RESTRICT_SIDEBAND_DATA = kSecCSRestrictSidebandData;
-
- /// Apple have not documented this flag.
- const USE_SOFTWARE_SIGNING_CERT = kSecCSUseSoftwareSigningCert;
-
- /// Apple have not documented this flag.
- const VALIDATE_PEH = kSecCSValidatePEH;
-
- /// Apple have not documented this flag.
- const SINGLE_THREADED = kSecCSSingleThreaded;
-
- /// Apple have not documented this flag.
- const QUICK_CHECK = kSecCSQuickCheck;
-
- /// Apple have not documented this flag.
- const CHECK_TRUSTED_ANCHORS = kSecCSCheckTrustedAnchors;
-
- /// Apple have not documented this flag.
- const REPORT_PROGRESS = kSecCSReportProgress;
-
- /// Apple have not documented this flag.
- const NO_NETWORK_ACCESS = kSecCSNoNetworkAccess;
-
- /// Apple have not documented this flag.
- const ENFORCE_REVOCATION_CHECKS = kSecCSEnforceRevocationChecks;
-
- /// Apple have not documented this flag.
- const CONSIDER_EXPIRATION = kSecCSConsiderExpiration;
- }
-}
-
-impl Default for Flags {
- #[inline(always)]
- fn default() -> Self {
- Self::NONE
- }
-}
-
-/// A helper to create guest attributes, which are normally passed as a
-/// `CFDictionary` with varying types.
-pub struct GuestAttributes {
- inner: CFMutableDictionary,
-}
-
-impl GuestAttributes {
- // Not implemented:
- // - architecture
- // - canonical
- // - dynamic code
- // - dynamic code info plist
- // - hash
- // - mach port
- // - sub-architecture
-
- /// Creates a new, empty `GuestAttributes`. You must add values to it in
- /// order for it to be of any use.
- #[must_use]
- pub fn new() -> Self {
- Self {
- inner: CFMutableDictionary::new(),
- }
- }
-
- /// The guest's audit token.
- pub fn set_audit_token(&mut self, token: CFDataRef) {
- let key = unsafe { CFString::wrap_under_get_rule(kSecGuestAttributeAudit) };
- self.inner.add(&key.as_CFTypeRef(), &token.to_void());
- }
-
- /// The guest's pid.
- pub fn set_pid(&mut self, pid: pid_t) {
- let key = unsafe { CFString::wrap_under_get_rule(kSecGuestAttributePid) };
- let pid = CFNumber::from(pid);
- self.inner.add(&key.as_CFTypeRef(), &pid.as_CFTypeRef());
- }
-
- /// Support for arbirtary guest attributes.
- pub fn set_other<V: ToVoid<V>>(&mut self, key: CFStringRef, value: V) {
- self.inner.add(&key.as_void_ptr(), &value.to_void());
- }
-}
-
-impl Default for GuestAttributes {
- fn default() -> Self {
- Self::new()
- }
-}
-
-declare_TCFType! {
- /// A code object representing signed code running on the system.
- SecRequirement, SecRequirementRef
-}
-impl_TCFType!(SecRequirement, SecRequirementRef, SecRequirementGetTypeID);
-
-impl FromStr for SecRequirement {
- type Err = crate::base::Error;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let text = CFString::new(s);
- let mut requirement = MaybeUninit::uninit();
-
- unsafe {
- cvt(SecRequirementCreateWithString(
- text.as_concrete_TypeRef(),
- 0,
- requirement.as_mut_ptr(),
- ))?;
-
- Ok(Self::wrap_under_create_rule(requirement.assume_init()))
- }
- }
-}
-
-declare_TCFType! {
- /// A code object representing signed code running on the system.
- SecCode, SecCodeRef
-}
-impl_TCFType!(SecCode, SecCodeRef, SecCodeGetTypeID);
-
-impl Debug for SecCode {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str("SecCode")
- }
-}
-
-impl SecCode {
- /// Retrieves the code object for the code making the call.
- pub fn for_self(flags: Flags) -> Result<Self> {
- let mut code = MaybeUninit::uninit();
-
- unsafe {
- cvt(SecCodeCopySelf(flags.bits(), code.as_mut_ptr()))?;
- Ok(Self::wrap_under_create_rule(code.assume_init()))
- }
- }
-
- /// Performs dynamic validation of signed code.
- pub fn check_validity(&self, flags: Flags, requirement: &SecRequirement) -> Result<()> {
- unsafe {
- cvt(SecCodeCheckValidity(
- self.as_concrete_TypeRef(),
- flags.bits(),
- requirement.as_concrete_TypeRef(),
- ))
- }
- }
-
- /// Asks a code host to identify one of its guests given
- /// the type and value of specific attributes of the guest code.
- ///
- /// If `host` is `None` then the code signing root of trust (currently, the
- // system kernel) should be used as the code host.
- pub fn copy_guest_with_attribues(
- host: Option<&SecCode>,
- attrs: &GuestAttributes,
- flags: Flags,
- ) -> Result<SecCode> {
- let mut code = MaybeUninit::uninit();
-
- let host = match host {
- Some(host) => host.as_concrete_TypeRef(),
- None => std::ptr::null_mut(),
- };
-
- unsafe {
- cvt(SecCodeCopyGuestWithAttributes(
- host,
- attrs.inner.as_concrete_TypeRef(),
- flags.bits(),
- code.as_mut_ptr(),
- ))?;
-
- Ok(SecCode::wrap_under_create_rule(code.assume_init()))
- }
- }
-
- /// Retrieves the location on disk of signed code, given a code or static
- /// code object.
- pub fn path(&self, flags: Flags) -> Result<CFURL> {
- let mut url = MaybeUninit::uninit();
-
- // The docs say we can pass a SecCodeRef instead of a SecStaticCodeRef.
- unsafe {
- cvt(SecCodeCopyPath(
- self.as_CFTypeRef() as _,
- flags.bits(),
- url.as_mut_ptr(),
- ))?;
-
- Ok(CFURL::wrap_under_create_rule(url.assume_init()))
- }
- }
-}
-
-declare_TCFType! {
- /// A static code object representing signed code on disk.
- SecStaticCode, SecStaticCodeRef
-}
-impl_TCFType!(SecStaticCode, SecStaticCodeRef, SecStaticCodeGetTypeID);
-
-impl SecStaticCode {
- /// Creates a static code object representing the code at a specified file
- /// system path.
- pub fn from_path(path: &CFURL, flags: Flags) -> Result<Self> {
- let mut code = MaybeUninit::uninit();
-
- unsafe {
- cvt(SecStaticCodeCreateWithPath(
- path.as_concrete_TypeRef(),
- flags.bits(),
- code.as_mut_ptr(),
- ))?;
-
- Ok(Self::wrap_under_create_rule(code.assume_init()))
- }
- }
-
- /// Retrieves the location on disk of signed code, given a code or static
- /// code object.
- pub fn path(&self, flags: Flags) -> Result<CFURL> {
- let mut url = MaybeUninit::uninit();
-
- // The docs say we can pass a SecCodeRef instead of a SecStaticCodeRef.
- unsafe {
- cvt(SecCodeCopyPath(
- self.as_concrete_TypeRef(),
- flags.bits(),
- url.as_mut_ptr(),
- ))?;
-
- Ok(CFURL::wrap_under_create_rule(url.assume_init()))
- }
- }
-
- /// Performs dynamic validation of signed code.
- pub fn check_validity(&self, flags: Flags, requirement: &SecRequirement) -> Result<()> {
- unsafe {
- cvt(SecStaticCodeCheckValidity(
- self.as_concrete_TypeRef(),
- flags.bits(),
- requirement.as_concrete_TypeRef(),
- ))
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use core_foundation::data::CFData;
- use libc::{c_uint, c_void, KERN_SUCCESS};
-
- #[test]
- fn path_to_static_code_and_back() {
- let path = CFURL::from_path("/bin/bash", false).unwrap();
- let code = SecStaticCode::from_path(&path, Flags::NONE).unwrap();
- assert_eq!(code.path(Flags::NONE).unwrap(), path);
- }
-
- #[test]
- fn self_to_path() {
- let path = CFURL::from_path(std::env::current_exe().unwrap(), false).unwrap();
- let code = SecCode::for_self(Flags::NONE).unwrap();
- assert_eq!(code.path(Flags::NONE).unwrap(), path);
- }
-
- #[test]
- fn bash_is_signed_by_apple() {
- let path = CFURL::from_path("/bin/bash", false).unwrap();
- let code = SecStaticCode::from_path(&path, Flags::NONE).unwrap();
- let requirement: SecRequirement = "anchor apple".parse().unwrap();
- code.check_validity(Flags::NONE, &requirement).unwrap();
- }
-
- #[cfg(target_arch = "aarch64")]
- #[test]
- fn self_is_not_signed_by_apple() {
- let code = SecCode::for_self(Flags::NONE).unwrap();
- let requirement: SecRequirement = "anchor apple".parse().unwrap();
-
- assert_eq!(
- code.check_validity(Flags::NONE, &requirement)
- .unwrap_err()
- .code(),
- // "code failed to satisfy specified code requirement(s)"
- -67050
- );
- }
-
- #[cfg(not(target_arch = "aarch64"))]
- #[test]
- fn self_is_not_signed_by_apple() {
- let code = SecCode::for_self(Flags::NONE).unwrap();
- let requirement: SecRequirement = "anchor apple".parse().unwrap();
-
- assert_eq!(
- code.check_validity(Flags::NONE, &requirement)
- .unwrap_err()
- .code(),
- // "code object is not signed at all"
- -67062
- );
- }
-
- #[test]
- fn copy_kernel_guest_with_launchd_pid() {
- let mut attrs = GuestAttributes::new();
- attrs.set_pid(1);
-
- assert_eq!(
- SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE)
- .unwrap()
- .path(Flags::NONE)
- .unwrap()
- .get_string()
- .to_string(),
- "file:///sbin/launchd"
- );
- }
-
- #[test]
- fn copy_current_guest_with_launchd_pid() {
- let host_code = SecCode::for_self(Flags::NONE).unwrap();
-
- let mut attrs = GuestAttributes::new();
- attrs.set_pid(1);
-
- assert_eq!(
- SecCode::copy_guest_with_attribues(Some(&host_code), &attrs, Flags::NONE)
- .unwrap_err()
- .code(),
- // "host has no guest with the requested attributes"
- -67065
- );
- }
-
- #[test]
- fn copy_kernel_guest_with_unmatched_pid() {
- let mut attrs = GuestAttributes::new();
- attrs.set_pid(999_999_999);
-
- assert_eq!(
- SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE)
- .unwrap_err()
- .code(),
- // "UNIX[No such process]"
- 100003
- );
- }
-
- #[test]
- fn copy_kernel_guest_with_current_token() {
- let mut token: [u8; 32] = [0; 32];
- let mut token_len = 32u32;
-
- enum OpaqueTaskName {}
-
- extern "C" {
- fn mach_task_self() -> *const OpaqueTaskName;
- fn task_info(
- task_name: *const OpaqueTaskName,
- task_flavor: u32,
- out: *mut c_void,
- out_len: *mut u32,
- ) -> i32;
- }
-
- const TASK_AUDIT_TOKEN: c_uint = 15;
-
- let result = unsafe {
- task_info(
- mach_task_self(),
- TASK_AUDIT_TOKEN,
- token.as_mut_ptr().cast::<c_void>(),
- &mut token_len,
- )
- };
-
- assert_eq!(result, KERN_SUCCESS);
-
- let token_data = CFData::from_buffer(&token);
-
- let mut attrs = GuestAttributes::new();
- attrs.set_audit_token(token_data.as_concrete_TypeRef());
-
- assert_eq!(
- SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE)
- .unwrap()
- .path(Flags::NONE)
- .unwrap()
- .to_path()
- .unwrap(),
- std::env::current_exe().unwrap()
- );
- }
-
- #[test]
- fn copy_kernel_guest_with_unmatched_token() {
- let token: [u8; 32] = [0; 32];
- let token_data = CFData::from_buffer(&token);
-
- let mut attrs = GuestAttributes::new();
- attrs.set_audit_token(token_data.as_concrete_TypeRef());
-
- assert_eq!(
- SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE)
- .unwrap_err()
- .code(),
- // "UNIX[No such process]"
- 100003
- );
- }
-}
diff --git a/vendor/security-framework/src/os/macos/digest_transform.rs b/vendor/security-framework/src/os/macos/digest_transform.rs
deleted file mode 100644
index c086ed1a..00000000
--- a/vendor/security-framework/src/os/macos/digest_transform.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-//! Digest Transform support
-
-use core_foundation::base::{CFIndex, TCFType};
-use core_foundation::data::CFData;
-use core_foundation::error::CFError;
-use core_foundation::string::CFString;
-use core_foundation_sys::base::CFTypeRef;
-use core_foundation_sys::data::CFDataRef;
-use core_foundation_sys::string::CFStringRef;
-use security_framework_sys::digest_transform::*;
-use security_framework_sys::transform::kSecTransformInputAttributeName;
-use std::ptr;
-
-use crate::os::macos::transform::SecTransform;
-
-#[derive(Debug, Copy, Clone)]
-/// A type of digest.
-pub struct DigestType(CFStringRef);
-
-#[allow(missing_docs)]
-impl DigestType {
- #[inline(always)]
- #[must_use]
- pub fn hmac_md5() -> Self {
- unsafe { Self(kSecDigestHMACMD5) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn hmac_sha1() -> Self {
- unsafe { Self(kSecDigestHMACSHA1) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn hmac_sha2() -> Self {
- unsafe { Self(kSecDigestHMACSHA2) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn md2() -> Self {
- unsafe { Self(kSecDigestMD2) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn md4() -> Self {
- unsafe { Self(kSecDigestMD4) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn md5() -> Self {
- unsafe { Self(kSecDigestMD5) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn sha1() -> Self {
- unsafe { Self(kSecDigestSHA1) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn sha2() -> Self {
- unsafe { Self(kSecDigestSHA2) }
- }
-
- #[inline(always)]
- fn to_type(self) -> CFTypeRef {
- self.0 as CFTypeRef
- }
-}
-
-/// A builder for digest transform operations.
-pub struct Builder {
- digest_type: Option<DigestType>,
- digest_length: Option<CFIndex>,
- hmac_key: Option<CFData>,
-}
-
-impl Default for Builder {
- #[inline(always)]
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl Builder {
- /// Returns a new builder with default settings.
- #[inline(always)]
- #[must_use]
- pub fn new() -> Self {
- Self {
- digest_type: None,
- digest_length: None,
- hmac_key: None,
- }
- }
-
- /// Sets the type of digest to perform.
- ///
- /// If not set, an appropriate digest will be selected for you.
- #[inline]
- pub fn type_(&mut self, digest_type: DigestType) -> &mut Self {
- self.digest_type = Some(digest_type);
- self
- }
-
- /// Sets the output length of the digest.
- ///
- /// If not set, an appropriate length will be selected for you. Some digest
- /// types only support specific output lengths.
- #[inline]
- pub fn length(&mut self, digest_length: CFIndex) -> &mut Self {
- self.digest_length = Some(digest_length);
- self
- }
-
- /// Sets the key used for HMAC digests.
- ///
- /// Only applies to `HmacMd5`, `HmacSha1`, and `HmacSha2` digests.
- #[inline]
- pub fn hmac_key(&mut self, hmac_key: CFData) -> &mut Self {
- self.hmac_key = Some(hmac_key);
- self
- }
-
- /// Computes the digest of the data.
- pub fn execute(&self, data: &CFData) -> Result<CFData, CFError> {
- unsafe {
- let digest_type = match self.digest_type {
- Some(ref digest_type) => digest_type.to_type(),
- None => ptr::null(),
- };
-
- let digest_length = self.digest_length.unwrap_or(0);
-
- let mut error = ptr::null_mut();
- let transform = SecDigestTransformCreate(digest_type, digest_length, &mut error);
- if transform.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
- let mut transform = SecTransform::wrap_under_create_rule(transform);
-
- if let Some(ref hmac_key) = self.hmac_key {
- let key = CFString::wrap_under_get_rule(kSecDigestHMACKeyAttribute);
- transform.set_attribute(&key, hmac_key)?;
- }
-
- let key = CFString::wrap_under_get_rule(kSecTransformInputAttributeName);
- transform.set_attribute(&key, data)?;
-
- let result = transform.execute()?;
- Ok(CFData::wrap_under_get_rule(
- result.as_CFTypeRef() as CFDataRef
- ))
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn md5() {
- let data = CFData::from_buffer("The quick brown fox jumps over the lazy dog".as_bytes());
- let hash = Builder::new()
- .type_(DigestType::md5())
- .execute(&data)
- .unwrap();
- assert_eq!(
- hex::encode(hash.bytes()),
- "9e107d9d372bb6826bd81d3542a419d6"
- );
- }
-
- #[test]
- fn hmac_sha1() {
- let data = CFData::from_buffer("The quick brown fox jumps over the lazy dog".as_bytes());
- let key = CFData::from_buffer(b"key");
- let hash = Builder::new()
- .type_(DigestType::hmac_sha1())
- .hmac_key(key)
- .execute(&data)
- .unwrap();
- assert_eq!(
- hex::encode(hash.bytes()),
- "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
- );
- }
-}
diff --git a/vendor/security-framework/src/os/macos/encrypt_transform.rs b/vendor/security-framework/src/os/macos/encrypt_transform.rs
deleted file mode 100644
index 7b9736da..00000000
--- a/vendor/security-framework/src/os/macos/encrypt_transform.rs
+++ /dev/null
@@ -1,254 +0,0 @@
-//! Encryption and Decryption transform support.
-
-use core_foundation::base::TCFType;
-use core_foundation::data::CFData;
-use core_foundation::error::CFError;
-use core_foundation::string::CFString;
-use core_foundation_sys::data::CFDataRef;
-use core_foundation_sys::string::CFStringRef;
-use security_framework_sys::encrypt_transform::*;
-use security_framework_sys::transform::kSecTransformInputAttributeName;
-use std::ptr;
-
-use crate::key::SecKey;
-use crate::os::macos::transform::SecTransform;
-
-#[derive(Debug, Copy, Clone)]
-/// The padding scheme to use for encryption.
-pub struct Padding(CFStringRef);
-
-impl Padding {
- /// Do not pad.
- #[inline(always)]
- #[must_use]
- pub fn none() -> Self {
- unsafe { Self(kSecPaddingNoneKey) }
- }
-
- /// Use PKCS#1 padding.
- #[inline(always)]
- #[must_use]
- pub fn pkcs1() -> Self {
- unsafe { Self(kSecPaddingPKCS1Key) }
- }
-
- /// Use PKCS#5 padding.
- #[inline(always)]
- #[must_use]
- pub fn pkcs5() -> Self {
- unsafe { Self(kSecPaddingPKCS5Key) }
- }
-
- /// Use PKCS#7 padding.
- #[inline(always)]
- #[must_use]
- pub fn pkcs7() -> Self {
- unsafe { Self(kSecPaddingPKCS7Key) }
- }
-
- /// Use OAEP padding.
- #[inline(always)]
- #[must_use]
- pub fn oaep() -> Self {
- unsafe { Self(kSecPaddingOAEPKey) }
- }
-
- #[inline]
- fn to_str(self) -> CFString {
- unsafe { CFString::wrap_under_get_rule(self.0) }
- }
-}
-
-/// The cipher mode to use.
-///
-/// Only applies to AES encryption.
-#[derive(Debug, Copy, Clone)]
-pub struct Mode(CFStringRef);
-
-#[allow(missing_docs)]
-impl Mode {
- #[inline(always)]
- #[must_use]
- pub fn none() -> Self {
- unsafe { Self(kSecModeNoneKey) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn ecb() -> Self {
- unsafe { Self(kSecModeECBKey) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn cbc() -> Self {
- unsafe { Self(kSecModeCBCKey) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn cfb() -> Self {
- unsafe { Self(kSecModeCFBKey) }
- }
-
- #[inline(always)]
- #[must_use]
- pub fn ofb() -> Self {
- unsafe { Self(kSecModeOFBKey) }
- }
-
- fn to_str(self) -> CFString {
- unsafe { CFString::wrap_under_get_rule(self.0) }
- }
-}
-
-/// A builder for encryption and decryption transform operations.
-#[derive(Default)]
-pub struct Builder {
- padding: Option<Padding>,
- mode: Option<Mode>,
- iv: Option<CFData>,
-}
-
-impl Builder {
- /// Creates a new `Builder` with a default configuration.
- #[inline(always)]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Selects the padding scheme to use.
- ///
- /// If not set, an appropriate scheme will be selected for you.
- #[inline(always)]
- pub fn padding(&mut self, padding: Padding) -> &mut Self {
- self.padding = Some(padding);
- self
- }
-
- /// Selects the encryption mode to use.
- ///
- /// If not set, an appropriate mode will be selected for you.
- #[inline(always)]
- pub fn mode(&mut self, mode: Mode) -> &mut Self {
- self.mode = Some(mode);
- self
- }
-
- /// Sets the initialization vector to use.
- ///
- /// If not set, an appropriate value will be supplied for you.
- #[inline(always)]
- pub fn iv(&mut self, iv: CFData) -> &mut Self {
- self.iv = Some(iv);
- self
- }
-
- /// Encrypts data with a provided key.
- pub fn encrypt(&self, key: &SecKey, data: &CFData) -> Result<CFData, CFError> {
- unsafe {
- let mut error = ptr::null_mut();
- let transform = SecEncryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
- if transform.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
- let transform = SecTransform::wrap_under_create_rule(transform);
-
- self.finish(transform, data)
- }
- }
-
- /// Decrypts data with a provided key.
- pub fn decrypt(&self, key: &SecKey, data: &CFData) -> Result<CFData, CFError> {
- unsafe {
- let mut error = ptr::null_mut();
- let transform = SecDecryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
- if transform.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
- let transform = SecTransform::wrap_under_create_rule(transform);
-
- self.finish(transform, data)
- }
- }
-
- fn finish(&self, mut transform: SecTransform, data: &CFData) -> Result<CFData, CFError> {
- unsafe {
- if let Some(ref padding) = self.padding {
- let key = CFString::wrap_under_get_rule(kSecPaddingKey);
- transform.set_attribute(&key, &padding.to_str())?;
- }
-
- if let Some(ref mode) = self.mode {
- let key = CFString::wrap_under_get_rule(kSecEncryptionMode);
- transform.set_attribute(&key, &mode.to_str())?;
- }
-
- if let Some(ref iv) = self.iv {
- let key = CFString::wrap_under_get_rule(kSecIVKey);
- transform.set_attribute(&key, iv)?;
- }
-
- let key = CFString::wrap_under_get_rule(kSecTransformInputAttributeName);
- transform.set_attribute(&key, data)?;
-
- let result = transform.execute()?;
- Ok(CFData::wrap_under_get_rule(
- result.as_CFTypeRef() as CFDataRef
- ))
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use hex::FromHex;
-
- use super::*;
- use crate::os::macos::item::KeyType;
- use crate::os::macos::key::SecKeyExt;
-
- #[test]
- fn cbc_mmt_256() {
- // test 9
- let key = "87725bd43a45608814180773f0e7ab95a3c859d83a2130e884190e44d14c6996";
- let iv = "e49651988ebbb72eb8bb80bb9abbca34";
- let ciphertext = "5b97a9d423f4b97413f388d9a341e727bb339f8e18a3fac2f2fb85abdc8f135deb30054a\
- 1afdc9b6ed7da16c55eba6b0d4d10c74e1d9a7cf8edfaeaa684ac0bd9f9d24ba674955c7\
- 9dc6be32aee1c260b558ff07e3a4d49d24162011ff254db8be078e8ad07e648e6bf56793\
- 76cb4321a5ef01afe6ad8816fcc7634669c8c4389295c9241e45fff39f3225f7745032da\
- eebe99d4b19bcb215d1bfdb36eda2c24";
- let plaintext = "bfe5c6354b7a3ff3e192e05775b9b75807de12e38a626b8bf0e12d5fff78e4f1775aa7d79\
- 2d885162e66d88930f9c3b2cdf8654f56972504803190386270f0aa43645db187af41fcea\
- 639b1f8026ccdd0c23e0de37094a8b941ecb7602998a4b2604e69fc04219585d854600e0a\
- d6f99a53b2504043c08b1c3e214d17cde053cbdf91daa999ed5b47c37983ba3ee254bc5c7\
- 93837daaa8c85cfc12f7f54f699f";
-
- let key = Vec::<u8>::from_hex(key).unwrap();
- let key = CFData::from_buffer(&key);
- let key = SecKey::from_data(KeyType::aes(), &key).unwrap();
-
- let iv = Vec::<u8>::from_hex(iv).unwrap();
-
- let ciphertext = Vec::<u8>::from_hex(ciphertext).unwrap();
-
- let plaintext = Vec::<u8>::from_hex(plaintext).unwrap();
-
- let decrypted = Builder::new()
- .padding(Padding::none())
- .iv(CFData::from_buffer(&iv))
- .decrypt(&key, &CFData::from_buffer(&ciphertext))
- .unwrap();
-
- assert_eq!(plaintext, decrypted.bytes());
-
- let encrypted = Builder::new()
- .padding(Padding::none())
- .iv(CFData::from_buffer(&iv))
- .encrypt(&key, &CFData::from_buffer(&plaintext))
- .unwrap();
-
- assert_eq!(ciphertext, encrypted.bytes());
- }
-}
diff --git a/vendor/security-framework/src/os/macos/identity.rs b/vendor/security-framework/src/os/macos/identity.rs
deleted file mode 100644
index 0f8da464..00000000
--- a/vendor/security-framework/src/os/macos/identity.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-//! OSX specific extensions to identity functionality.
-use core_foundation::array::CFArray;
-use core_foundation::base::TCFType;
-use security_framework_sys::identity::SecIdentityCreateWithCertificate;
-use std::ptr;
-
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::identity::SecIdentity;
-use crate::os::macos::keychain::SecKeychain;
-
-/// An extension trait adding OSX specific functionality to `SecIdentity`.
-pub trait SecIdentityExt {
- /// Creates an identity corresponding to a certificate, looking in the
- /// provided keychains for the corresponding private key.
- ///
- /// To search the default keychains, use an empty slice for `keychains`.
- ///
- /// <https://developer.apple.com/documentation/security/1401160-secidentitycreatewithcertificate>
- fn with_certificate(
- keychains: &[SecKeychain],
- certificate: &SecCertificate,
- ) -> Result<SecIdentity>;
-}
-
-impl SecIdentityExt for SecIdentity {
- fn with_certificate(keychains: &[SecKeychain], certificate: &SecCertificate) -> Result<Self> {
- let keychains = CFArray::from_CFTypes(keychains);
- unsafe {
- let mut identity = ptr::null_mut();
- cvt(SecIdentityCreateWithCertificate(
- if keychains.len() > 0 {keychains.as_CFTypeRef()} else {ptr::null()},
- certificate.as_concrete_TypeRef(),
- &mut identity,
- ))?;
- Ok(Self::wrap_under_create_rule(identity))
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use tempfile::tempdir;
-
- use super::*;
- use crate::os::macos::certificate::SecCertificateExt;
- use crate::os::macos::import_export::ImportOptions;
- use crate::os::macos::keychain::CreateOptions;
- use crate::os::macos::test::identity;
- use crate::test;
-
- #[test]
- fn certificate() {
- let dir = p!(tempdir());
- let identity = identity(dir.path());
- let certificate = p!(identity.certificate());
- assert_eq!("foobar.com", p!(certificate.common_name()));
- }
-
- #[test]
- fn private_key() {
- let dir = p!(tempdir());
- let identity = identity(dir.path());
- p!(identity.private_key());
- }
-
- #[test]
- fn with_certificate() {
- let dir = p!(tempdir());
-
- let mut keychain = p!(CreateOptions::new()
- .password("foobar")
- .create(dir.path().join("test.keychain")));
-
- let key = include_bytes!("../../../test/server.key");
- p!(ImportOptions::new()
- .filename("server.key")
- .keychain(&mut keychain)
- .import(key));
-
- let cert = test::certificate();
- p!(SecIdentity::with_certificate(&[keychain], &cert));
- }
-}
diff --git a/vendor/security-framework/src/os/macos/import_export.rs b/vendor/security-framework/src/os/macos/import_export.rs
deleted file mode 100644
index 830d9483..00000000
--- a/vendor/security-framework/src/os/macos/import_export.rs
+++ /dev/null
@@ -1,344 +0,0 @@
-//! OSX specific extensions to import/export functionality.
-
-use core_foundation::array::CFArray;
-use core_foundation::base::{CFType, TCFType};
-use core_foundation::data::CFData;
-use core_foundation::string::CFString;
-use security_framework_sys::base::errSecSuccess;
-use security_framework_sys::import_export::*;
-use std::ptr;
-use std::str::FromStr;
-
-use crate::base::{Error, Result};
-use crate::certificate::SecCertificate;
-use crate::identity::SecIdentity;
-use crate::import_export::Pkcs12ImportOptions;
-use crate::key::SecKey;
-use crate::os::macos::access::SecAccess;
-use crate::os::macos::keychain::SecKeychain;
-
-/// An extension trait adding OSX specific functionality to `Pkcs12ImportOptions`.
-pub trait Pkcs12ImportOptionsExt {
- /// Specifies the keychain in which to import the identity.
- ///
- /// If this is not called, the default keychain will be used.
- fn keychain(&mut self, keychain: SecKeychain) -> &mut Self;
-
- /// Specifies the access control to be associated with the identity.
- fn access(&mut self, access: SecAccess) -> &mut Self;
-}
-
-impl Pkcs12ImportOptionsExt for Pkcs12ImportOptions {
- #[inline(always)]
- fn keychain(&mut self, keychain: SecKeychain) -> &mut Self {
- crate::Pkcs12ImportOptionsInternals::keychain(self, keychain)
- }
-
- #[inline(always)]
- fn access(&mut self, access: SecAccess) -> &mut Self {
- crate::Pkcs12ImportOptionsInternals::access(self, access)
- }
-}
-
-/// A builder type to import Security Framework types from serialized formats.
-#[derive(Default)]
-pub struct ImportOptions<'a> {
- filename: Option<CFString>,
- passphrase: Option<CFType>,
- secure_passphrase: bool,
- no_access_control: bool,
- alert_title: Option<CFString>,
- alert_prompt: Option<CFString>,
- items: Option<&'a mut SecItems>,
- keychain: Option<SecKeychain>,
-}
-
-impl<'a> ImportOptions<'a> {
- /// Creates a new builder with default options.
- #[inline(always)]
- #[must_use]
- pub fn new() -> ImportOptions<'a> {
- ImportOptions::default()
- }
-
- /// Sets the filename from which the imported data came.
- ///
- /// The extension of the file will used as a hint for parsing.
- #[inline]
- pub fn filename(&mut self, filename: &str) -> &mut ImportOptions<'a> {
- self.filename = Some(CFString::from_str(filename).unwrap());
- self
- }
-
- /// Sets the passphrase to be used to decrypt the imported data.
- #[inline]
- pub fn passphrase(&mut self, passphrase: &str) -> &mut ImportOptions<'a> {
- self.passphrase = Some(CFString::from_str(passphrase).unwrap().into_CFType());
- self
- }
-
- /// Sets the passphrase to be used to decrypt the imported data.
- #[inline]
- pub fn passphrase_bytes(&mut self, passphrase: &[u8]) -> &mut ImportOptions<'a> {
- self.passphrase = Some(CFData::from_buffer(passphrase).into_CFType());
- self
- }
-
- /// If set, the user will be prompted to imput the passphrase used to
- /// decrypt the imported data.
- #[inline(always)]
- pub fn secure_passphrase(&mut self, secure_passphrase: bool) -> &mut ImportOptions<'a> {
- self.secure_passphrase = secure_passphrase;
- self
- }
-
- /// If set, imported items will have no access controls imposed on them.
- #[inline(always)]
- pub fn no_access_control(&mut self, no_access_control: bool) -> &mut ImportOptions<'a> {
- self.no_access_control = no_access_control;
- self
- }
-
- /// Sets the title of the alert popup used with the `secure_passphrase`
- /// option.
- #[inline]
- pub fn alert_title(&mut self, alert_title: &str) -> &mut ImportOptions<'a> {
- self.alert_title = Some(CFString::from_str(alert_title).unwrap());
- self
- }
-
- /// Sets the prompt of the alert popup used with the `secure_passphrase`
- /// option.
- #[inline]
- pub fn alert_prompt(&mut self, alert_prompt: &str) -> &mut ImportOptions<'a> {
- self.alert_prompt = Some(CFString::from_str(alert_prompt).unwrap());
- self
- }
-
- /// Sets the object into which imported items will be placed.
- #[inline(always)]
- pub fn items(&mut self, items: &'a mut SecItems) -> &mut ImportOptions<'a> {
- self.items = Some(items);
- self
- }
-
- /// Sets the keychain into which items will be imported.
- ///
- /// This must be specified to import `SecIdentity`s.
- #[inline]
- pub fn keychain(&mut self, keychain: &SecKeychain) -> &mut ImportOptions<'a> {
- self.keychain = Some(keychain.clone());
- self
- }
-
- /// Imports items from serialized data.
- pub fn import(&mut self, data: &[u8]) -> Result<()> {
- let data = CFData::from_buffer(data);
- let data = data.as_concrete_TypeRef();
-
- let filename = match self.filename {
- Some(ref filename) => filename.as_concrete_TypeRef(),
- None => ptr::null(),
- };
-
- let mut key_params = SecItemImportExportKeyParameters {
- version: SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
- flags: 0,
- passphrase: ptr::null(),
- alertTitle: ptr::null(),
- alertPrompt: ptr::null(),
- accessRef: ptr::null_mut(),
- keyUsage: ptr::null_mut(),
- keyAttributes: ptr::null(),
- };
-
- if let Some(ref passphrase) = self.passphrase {
- key_params.passphrase = passphrase.as_CFTypeRef();
- }
-
- if self.secure_passphrase {
- key_params.flags |= kSecKeySecurePassphrase;
- }
-
- if self.no_access_control {
- key_params.flags |= kSecKeyNoAccessControl;
- }
-
- if let Some(ref alert_title) = self.alert_title {
- key_params.alertTitle = alert_title.as_concrete_TypeRef();
- }
-
- if let Some(ref alert_prompt) = self.alert_prompt {
- key_params.alertPrompt = alert_prompt.as_concrete_TypeRef();
- }
-
- let keychain = match self.keychain {
- Some(ref keychain) => keychain.as_concrete_TypeRef(),
- None => ptr::null_mut(),
- };
-
- let mut raw_items = ptr::null();
- let items_ref = match self.items {
- Some(_) => std::ptr::addr_of_mut!(raw_items),
- None => ptr::null_mut(),
- };
-
- unsafe {
- let ret = SecItemImport(
- data,
- filename,
- ptr::null_mut(),
- ptr::null_mut(),
- 0,
- &key_params,
- keychain,
- items_ref,
- );
- if ret != errSecSuccess {
- return Err(Error::from_code(ret));
- }
-
- if let Some(ref mut items) = self.items {
- let raw_items = CFArray::<CFType>::wrap_under_create_rule(raw_items);
- for item in raw_items.iter() {
- let type_id = item.type_of();
- if type_id == SecCertificate::type_id() {
- items.certificates.push(SecCertificate::wrap_under_get_rule(
- item.as_CFTypeRef() as *mut _,
- ));
- } else if type_id == SecIdentity::type_id() {
- items.identities.push(SecIdentity::wrap_under_get_rule(
- item.as_CFTypeRef() as *mut _,
- ));
- } else if type_id == SecKey::type_id() {
- items
- .keys
- .push(SecKey::wrap_under_get_rule(item.as_CFTypeRef() as *mut _));
- } else {
- panic!("Got bad type from SecItemImport: {type_id}");
- }
- }
- }
- }
-
- Ok(())
- }
-}
-
-/// A type which holds items imported from serialized data.
-///
-/// Pass a reference to `ImportOptions::items`.
-#[derive(Default)]
-pub struct SecItems {
- /// Imported certificates.
- pub certificates: Vec<SecCertificate>,
- /// Imported identities.
- pub identities: Vec<SecIdentity>,
- /// Imported keys.
- pub keys: Vec<SecKey>,
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::import_export::*;
- use crate::os::macos::keychain;
- use tempfile::tempdir;
-
- #[test]
- fn certificate() {
- let data = include_bytes!("../../../test/server.der");
- let mut items = SecItems::default();
- ImportOptions::new()
- .filename("server.der")
- .items(&mut items)
- .import(data)
- .unwrap();
- assert_eq!(1, items.certificates.len());
- assert_eq!(0, items.identities.len());
- assert_eq!(0, items.keys.len());
- }
-
- #[test]
- fn key() {
- let data = include_bytes!("../../../test/server.key");
- let mut items = SecItems::default();
- ImportOptions::new()
- .filename("server.key")
- .items(&mut items)
- .import(data)
- .unwrap();
- assert_eq!(0, items.certificates.len());
- assert_eq!(0, items.identities.len());
- assert_eq!(1, items.keys.len());
- }
-
- #[test]
- fn identity() {
- let dir = tempdir().unwrap();
- let keychain = keychain::CreateOptions::new()
- .password("password")
- .create(dir.path().join("identity.keychain"))
- .unwrap();
-
- let data = include_bytes!("../../../test/server.p12");
- let mut items = SecItems::default();
- ImportOptions::new()
- .filename("server.p12")
- .passphrase("password123")
- .items(&mut items)
- .keychain(&keychain)
- .import(data)
- .unwrap();
- assert_eq!(1, items.identities.len());
- assert_eq!(0, items.certificates.len());
- assert_eq!(0, items.keys.len());
- }
-
- #[test]
- #[ignore] // since it requires manual intervention
- fn secure_passphrase_identity() {
- let dir = tempdir().unwrap();
- let keychain = keychain::CreateOptions::new()
- .password("password")
- .create(dir.path().join("identity.keychain"))
- .unwrap();
-
- let data = include_bytes!("../../../test/server.p12");
- let mut items = SecItems::default();
- ImportOptions::new()
- .filename("server.p12")
- .secure_passphrase(true)
- .alert_title("alert title")
- .alert_prompt("alert prompt")
- .items(&mut items)
- .keychain(&keychain)
- .import(data)
- .unwrap();
- assert_eq!(1, items.identities.len());
- assert_eq!(0, items.certificates.len());
- assert_eq!(0, items.keys.len());
- }
-
- #[test]
- fn pkcs12_import() {
- use super::Pkcs12ImportOptionsExt;
-
- let dir = tempdir().unwrap();
- let keychain = keychain::CreateOptions::new()
- .password("password")
- .create(dir.path().join("pkcs12_import"))
- .unwrap();
-
- let data = include_bytes!("../../../test/server.p12");
- let identities = p!(Pkcs12ImportOptions::new()
- .passphrase("password123")
- .keychain(keychain)
- .import(data));
- assert_eq!(1, identities.len());
- assert_eq!(
- hex::encode(identities[0].key_id.as_ref().unwrap()),
- "ed6492936dcc8907e397e573b36e633458dc33f1"
- );
- }
-}
diff --git a/vendor/security-framework/src/os/macos/item.rs b/vendor/security-framework/src/os/macos/item.rs
deleted file mode 100644
index 18a4d2e8..00000000
--- a/vendor/security-framework/src/os/macos/item.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-//! OSX specific functionality for items.
-use crate::item::ItemSearchOptions;
-use crate::os::macos::keychain::SecKeychain;
-use crate::ItemSearchOptionsInternals;
-
-// Moved to crate::Key
-pub use crate::key::KeyType;
-
-/// An extension trait adding OSX specific functionality to `ItemSearchOptions`.
-pub trait ItemSearchOptionsExt {
- /// Search within the specified keychains.
- ///
- /// If this is not called, the default keychain will be searched.
- fn keychains(&mut self, keychains: &[SecKeychain]) -> &mut Self;
-}
-
-impl ItemSearchOptionsExt for ItemSearchOptions {
- #[inline(always)]
- fn keychains(&mut self, keychains: &[SecKeychain]) -> &mut Self {
- ItemSearchOptionsInternals::keychains(self, keychains)
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::item::*;
- use crate::os::macos::certificate::SecCertificateExt;
- use crate::os::macos::item::ItemSearchOptionsExt;
- use crate::os::macos::test::keychain;
- use tempfile::tempdir;
-
- #[test]
- fn find_certificate() {
- let dir = p!(tempdir());
- let keychain = keychain(dir.path());
- let results = p!(ItemSearchOptions::new()
- .keychains(&[keychain])
- .class(ItemClass::certificate())
- .search());
- assert_eq!(1, results.len());
- let certificate = match results[0] {
- SearchResult::Ref(Reference::Certificate(ref cert)) => cert,
- _ => panic!("expected certificate"),
- };
- assert_eq!("foobar.com", p!(certificate.common_name()));
- }
-}
diff --git a/vendor/security-framework/src/os/macos/key.rs b/vendor/security-framework/src/os/macos/key.rs
deleted file mode 100644
index f6a20e93..00000000
--- a/vendor/security-framework/src/os/macos/key.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! OSX specific functionality for keys.
-use core_foundation::base::TCFType;
-use core_foundation::data::CFData;
-use core_foundation::dictionary::CFDictionary;
-use core_foundation::error::CFError;
-use core_foundation::string::CFString;
-use security_framework_sys::item::kSecAttrKeyType;
-use security_framework_sys::key::SecKeyCreateFromData;
-use std::ptr;
-
-use crate::key::{KeyType, SecKey};
-
-/// An extension trait adding OSX specific functionality to `SecKey`.
-pub trait SecKeyExt {
- /// Creates a new `SecKey` from a buffer containing key data.
- fn from_data(key_type: KeyType, key_data: &CFData) -> Result<SecKey, CFError>;
-}
-
-impl SecKeyExt for SecKey {
- fn from_data(key_type: KeyType, key_data: &CFData) -> Result<Self, CFError> {
- unsafe {
- let key = CFString::wrap_under_get_rule(kSecAttrKeyType);
- let dict = CFDictionary::from_CFType_pairs(&[(key, key_type.to_str())]);
-
- let mut err = ptr::null_mut();
- let key = SecKeyCreateFromData(
- dict.as_concrete_TypeRef(),
- key_data.as_concrete_TypeRef(),
- &mut err,
- );
- if key.is_null() {
- Err(CFError::wrap_under_create_rule(err))
- } else {
- Ok(Self::wrap_under_create_rule(key))
- }
- }
- }
-}
diff --git a/vendor/security-framework/src/os/macos/keychain.rs b/vendor/security-framework/src/os/macos/keychain.rs
deleted file mode 100644
index bce5e00a..00000000
--- a/vendor/security-framework/src/os/macos/keychain.rs
+++ /dev/null
@@ -1,281 +0,0 @@
-//! Keychain support.
-
-use core_foundation::base::{Boolean, TCFType};
-use security_framework_sys::base::{errSecSuccess, SecKeychainRef};
-use security_framework_sys::keychain::*;
-use std::ffi::CString;
-use std::os::raw::c_void;
-use std::os::unix::ffi::OsStrExt;
-use std::path::Path;
-use std::ptr;
-
-use crate::base::{Error, Result};
-use crate::cvt;
-use crate::os::macos::access::SecAccess;
-
-pub use security_framework_sys::keychain::SecPreferencesDomain;
-
-declare_TCFType! {
- /// A type representing a keychain.
- SecKeychain, SecKeychainRef
-}
-impl_TCFType!(SecKeychain, SecKeychainRef, SecKeychainGetTypeID);
-
-unsafe impl Sync for SecKeychain {}
-unsafe impl Send for SecKeychain {}
-
-impl SecKeychain {
- /// Creates a `SecKeychain` object corresponding to the user's default
- /// keychain.
- #[inline]
- #[allow(clippy::should_implement_trait)]
- pub fn default() -> Result<Self> {
- unsafe {
- let mut keychain = ptr::null_mut();
- cvt(SecKeychainCopyDefault(&mut keychain))?;
- Ok(Self::wrap_under_create_rule(keychain))
- }
- }
-
- /// Creates a `SecKeychain` object corresponding to the user's default
- /// keychain for the given domain.
- pub fn default_for_domain(domain: SecPreferencesDomain) -> Result<Self> {
- unsafe {
- let mut keychain = ptr::null_mut();
- cvt(SecKeychainCopyDomainDefault(domain, &mut keychain))?;
- Ok(Self::wrap_under_create_rule(keychain))
- }
- }
-
- /// Opens a keychain from a file.
- pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
- let path_name = [
- path.as_ref().as_os_str().as_bytes(),
- std::slice::from_ref(&0)
- ].concat();
-
- unsafe {
- let mut keychain = ptr::null_mut();
- cvt(SecKeychainOpen(path_name.as_ptr().cast(), &mut keychain))?;
- Ok(Self::wrap_under_create_rule(keychain))
- }
- }
-
- /// Unlocks the keychain.
- ///
- /// If a password is not specified, the user will be prompted to enter it.
- pub fn unlock(&mut self, password: Option<&str>) -> Result<()> {
- let (len, ptr, use_password) = match password {
- Some(password) => (password.len(), password.as_ptr().cast(), true),
- None => (0, ptr::null(), false),
- };
-
- unsafe {
- cvt(SecKeychainUnlock(
- self.as_concrete_TypeRef(),
- len as u32,
- ptr,
- Boolean::from(use_password),
- ))
- }
- }
-
- /// Sets settings of the keychain.
- #[inline]
- pub fn set_settings(&mut self, settings: &KeychainSettings) -> Result<()> {
- unsafe {
- cvt(SecKeychainSetSettings(
- self.as_concrete_TypeRef(),
- &settings.0,
- ))
- }
- }
-
- #[cfg(target_os = "macos")]
- /// Disables the user interface for keychain services functions that
- /// automatically display a user interface.
- pub fn disable_user_interaction() -> Result<KeychainUserInteractionLock> {
- let code = unsafe { SecKeychainSetUserInteractionAllowed(0u8) };
-
- if code != errSecSuccess {
- Err(Error::from_code(code))
- } else {
- Ok(KeychainUserInteractionLock)
- }
- }
-
- #[cfg(target_os = "macos")]
- /// Indicates whether keychain services functions that normally display a
- /// user interaction are allowed to do so.
- pub fn user_interaction_allowed() -> Result<bool> {
- let mut state: Boolean = 0;
- let code = unsafe { SecKeychainGetUserInteractionAllowed(&mut state) };
-
- if code != errSecSuccess {
- Err(Error::from_code(code))
- } else {
- Ok(state != 0)
- }
- }
-}
-
-/// A builder type to create new keychains.
-#[derive(Default)]
-pub struct CreateOptions {
- password: Option<String>,
- prompt_user: bool,
- access: Option<SecAccess>,
-}
-
-impl CreateOptions {
- /// Creates a new builder with default options.
- #[inline(always)]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Sets the password to be used to protect the keychain.
- #[inline]
- pub fn password(&mut self, password: &str) -> &mut Self {
- self.password = Some(password.into());
- self
- }
-
- /// If set, the user will be prompted to provide a password used to
- /// protect the keychain.
- #[inline(always)]
- pub fn prompt_user(&mut self, prompt_user: bool) -> &mut Self {
- self.prompt_user = prompt_user;
- self
- }
-
- /// Sets the access control applied to the keychain.
- #[inline(always)]
- pub fn access(&mut self, access: SecAccess) -> &mut Self {
- self.access = Some(access);
- self
- }
-
- /// Creates a new keychain at the specified location on the filesystem.
- pub fn create<P: AsRef<Path>>(&self, path: P) -> Result<SecKeychain> {
- unsafe {
- let path_name = path.as_ref().as_os_str().as_bytes();
- // FIXME
- let path_name = CString::new(path_name).unwrap();
-
- let (password, password_len) = match self.password {
- Some(ref password) => (password.as_ptr().cast::<c_void>(), password.len() as u32),
- None => (ptr::null(), 0),
- };
-
- let access = match self.access {
- Some(ref access) => access.as_concrete_TypeRef(),
- None => ptr::null_mut(),
- };
-
- let mut keychain = ptr::null_mut();
- cvt(SecKeychainCreate(
- path_name.as_ptr(),
- password_len,
- password,
- Boolean::from(self.prompt_user),
- access,
- &mut keychain,
- ))?;
-
- Ok(SecKeychain::wrap_under_create_rule(keychain))
- }
- }
-}
-
-/// Settings associated with a `SecKeychain`.
-pub struct KeychainSettings(SecKeychainSettings);
-
-impl KeychainSettings {
- /// Creates a new `KeychainSettings` with default settings.
- #[inline]
- #[must_use]
- pub fn new() -> Self {
- Self(SecKeychainSettings {
- version: SEC_KEYCHAIN_SETTINGS_VERS1,
- lockOnSleep: 0,
- useLockInterval: 0,
- lockInterval: i32::max_value() as u32,
- })
- }
-
- /// If set, the keychain will automatically lock when the computer sleeps.
- ///
- /// Defaults to `false`.
- #[inline(always)]
- pub fn set_lock_on_sleep(&mut self, lock_on_sleep: bool) {
- self.0.lockOnSleep = Boolean::from(lock_on_sleep);
- }
-
- /// Sets the interval of time in seconds after which the keychain is
- /// automatically locked.
- ///
- /// Defaults to `None`.
- pub fn set_lock_interval(&mut self, lock_interval: Option<u32>) {
- match lock_interval {
- Some(lock_interval) => {
- self.0.useLockInterval = 1;
- self.0.lockInterval = lock_interval;
- }
- None => {
- self.0.useLockInterval = 0;
- self.0.lockInterval = i32::max_value() as u32;
- }
- }
- }
-}
-
-impl Default for KeychainSettings {
- #[inline(always)]
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[cfg(target_os = "macos")]
-#[must_use = "The user interaction is disabled for the lifetime of the returned object"]
-/// Automatically re-enables user interaction.
-pub struct KeychainUserInteractionLock;
-
-#[cfg(target_os = "macos")]
-impl Drop for KeychainUserInteractionLock {
- #[inline(always)]
- fn drop(&mut self) {
- unsafe { SecKeychainSetUserInteractionAllowed(1u8) };
- }
-}
-
-#[cfg(test)]
-mod test {
- use tempfile::tempdir;
-
- use super::*;
-
- #[test]
- fn create_options() {
- let dir = tempdir().unwrap();
-
- let mut keychain = CreateOptions::new()
- .password("foobar")
- .create(dir.path().join("test.keychain"))
- .unwrap();
-
- keychain.set_settings(&KeychainSettings::new()).unwrap();
- }
-
- #[test]
- fn disable_user_interaction() {
- assert!(SecKeychain::user_interaction_allowed().unwrap());
- {
- let _lock = SecKeychain::disable_user_interaction().unwrap();
- assert!(!SecKeychain::user_interaction_allowed().unwrap());
- }
- assert!(SecKeychain::user_interaction_allowed().unwrap());
- }
-}
diff --git a/vendor/security-framework/src/os/macos/keychain_item.rs b/vendor/security-framework/src/os/macos/keychain_item.rs
deleted file mode 100644
index fd7b452a..00000000
--- a/vendor/security-framework/src/os/macos/keychain_item.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//! Keychain item support.
-
-use core_foundation::base::TCFType;
-use security_framework_sys::base::SecKeychainItemRef;
-use security_framework_sys::keychain_item::SecKeychainItemGetTypeID;
-use std::fmt;
-
-declare_TCFType! {
- /// A type representing a keychain item.
- SecKeychainItem, SecKeychainItemRef
-}
-impl_TCFType!(
- SecKeychainItem,
- SecKeychainItemRef,
- SecKeychainItemGetTypeID
-);
-
-unsafe impl Sync for SecKeychainItem {}
-unsafe impl Send for SecKeychainItem {}
-
-impl fmt::Debug for SecKeychainItem {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.debug_struct("SecKeychainItem").finish_non_exhaustive()
- }
-}
diff --git a/vendor/security-framework/src/os/macos/mod.rs b/vendor/security-framework/src/os/macos/mod.rs
deleted file mode 100644
index 3e468fc3..00000000
--- a/vendor/security-framework/src/os/macos/mod.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-//! OSX specific extensions.
-
-pub mod access;
-pub mod certificate;
-pub mod certificate_oids;
-pub mod code_signing;
-pub mod digest_transform;
-pub mod encrypt_transform;
-pub mod identity;
-pub mod import_export;
-pub mod item;
-pub mod key;
-pub mod keychain;
-pub mod keychain_item;
-pub mod passwords;
-pub mod secure_transport;
-pub mod transform;
-
-#[cfg(test)]
-pub mod test {
- use crate::identity::SecIdentity;
- use crate::item::{ItemClass, ItemSearchOptions, Reference, SearchResult};
- use crate::os::macos::item::ItemSearchOptionsExt;
- use crate::os::macos::keychain::SecKeychain;
- use std::fs::File;
- use std::io::prelude::*;
- use std::path::Path;
-
- #[must_use] pub fn identity(dir: &Path) -> SecIdentity {
- // FIXME https://github.com/rust-lang/rust/issues/30018
- let keychain = keychain(dir);
- let mut items = p!(ItemSearchOptions::new()
- .class(ItemClass::identity())
- .keychains(&[keychain])
- .search());
- match items.pop().unwrap() {
- SearchResult::Ref(Reference::Identity(identity)) => identity,
- _ => panic!("expected identity"),
- }
- }
-
- #[must_use] pub fn keychain(dir: &Path) -> SecKeychain {
- let path = dir.join("server.keychain");
- let mut file = p!(File::create(&path));
- p!(file.write_all(include_bytes!("../../../test/server.keychain")));
- drop(file);
-
- let mut keychain = p!(SecKeychain::open(&path));
- p!(keychain.unlock(Some("password123")));
- keychain
- }
-}
diff --git a/vendor/security-framework/src/os/macos/passwords.rs b/vendor/security-framework/src/os/macos/passwords.rs
deleted file mode 100644
index 8587a3c5..00000000
--- a/vendor/security-framework/src/os/macos/passwords.rs
+++ /dev/null
@@ -1,525 +0,0 @@
-//! Password support.
-
-use crate::os::macos::keychain::SecKeychain;
-use crate::os::macos::keychain_item::SecKeychainItem;
-use core_foundation::array::CFArray;
-use core_foundation::base::TCFType;
-pub use security_framework_sys::keychain::{SecAuthenticationType, SecProtocolType};
-use security_framework_sys::keychain::{
- SecKeychainAddGenericPassword, SecKeychainAddInternetPassword, SecKeychainFindGenericPassword,
- SecKeychainFindInternetPassword,
-};
-use security_framework_sys::keychain_item::{
- SecKeychainItemDelete, SecKeychainItemFreeContent, SecKeychainItemModifyAttributesAndData,
-};
-use std::fmt;
-use std::fmt::Write;
-use std::ops::Deref;
-use std::ptr;
-use std::slice;
-
-use crate::base::Result;
-use crate::cvt;
-
-/// Password slice. Use `.as_ref()` to get `&[u8]` or `.to_owned()` to get `Vec<u8>`
-pub struct SecKeychainItemPassword {
- data: *const u8,
- data_len: usize,
-}
-
-impl fmt::Debug for SecKeychainItemPassword {
- #[cold]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for _ in 0..self.data_len {
- f.write_char('•')?;
- }
- Ok(())
- }
-}
-
-impl AsRef<[u8]> for SecKeychainItemPassword {
- #[inline]
- fn as_ref(&self) -> &[u8] {
- unsafe { slice::from_raw_parts(self.data, self.data_len) }
- }
-}
-
-impl Deref for SecKeychainItemPassword {
- type Target = [u8];
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- self.as_ref()
- }
-}
-
-impl Drop for SecKeychainItemPassword {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- SecKeychainItemFreeContent(ptr::null_mut(), self.data as *mut _);
- }
- }
-}
-
-impl SecKeychainItem {
- /// Modify keychain item in-place, replacing its password with the given one
- pub fn set_password(&mut self, password: &[u8]) -> Result<()> {
- unsafe {
- cvt(SecKeychainItemModifyAttributesAndData(
- self.as_CFTypeRef() as *mut _,
- ptr::null(),
- password.len() as u32,
- password.as_ptr().cast(),
- ))?;
- }
- Ok(())
- }
-
- /// Delete this item from its keychain
- #[inline]
- pub fn delete(self) {
- unsafe {
- SecKeychainItemDelete(self.as_CFTypeRef() as *mut _);
- }
- }
-}
-
-/// Find a generic password.
-///
-/// The underlying system supports passwords with 0 values, so this
-/// returns a vector of bytes rather than a string.
-///
-/// * `keychains` is an array of keychains to search or None to search
-/// the default keychain.
-/// * `service` is the name of the service to search for.
-/// * `account` is the name of the account to search for.
-pub fn find_generic_password(
- keychains: Option<&[SecKeychain]>,
- service: &str,
- account: &str,
-) -> Result<(SecKeychainItemPassword, SecKeychainItem)> {
- let keychains_or_none = keychains.map(CFArray::from_CFTypes);
-
- let keychains_or_null = match keychains_or_none {
- None => ptr::null(),
- Some(ref keychains) => keychains.as_CFTypeRef(),
- };
-
- let mut data_len = 0;
- let mut data = ptr::null_mut();
- let mut item = ptr::null_mut();
-
- unsafe {
- cvt(SecKeychainFindGenericPassword(
- keychains_or_null,
- service.len() as u32,
- service.as_ptr().cast(),
- account.len() as u32,
- account.as_ptr().cast(),
- &mut data_len,
- &mut data,
- &mut item,
- ))?;
- Ok((
- SecKeychainItemPassword {
- data: data as *const _,
- data_len: data_len as usize,
- },
- SecKeychainItem::wrap_under_create_rule(item),
- ))
- }
-}
-
-/// * `keychains` is an array of keychains to search or None to search
-/// the default keychain.
-/// * `server`: server name.
-/// * `security_domain`: security domain. This parameter is optional.
-/// * `account`: account name.
-/// * `path`: the path.
-/// * `port`: The TCP/IP port number.
-/// * `protocol`: The protocol associated with this password.
-/// * `authentication_type`: The authentication scheme used.
-#[allow(clippy::too_many_arguments)]
-pub fn find_internet_password(
- keychains: Option<&[SecKeychain]>,
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
-) -> Result<(SecKeychainItemPassword, SecKeychainItem)> {
- let keychains_or_none = keychains.map(CFArray::from_CFTypes);
-
- let keychains_or_null = match keychains_or_none {
- None => ptr::null(),
- Some(ref keychains) => keychains.as_CFTypeRef(),
- };
-
- let mut data_len = 0;
- let mut data = ptr::null_mut();
- let mut item = ptr::null_mut();
-
- unsafe {
- cvt(SecKeychainFindInternetPassword(
- keychains_or_null,
- server.len() as u32,
- server.as_ptr().cast(),
- security_domain.map_or(0, |s| s.len() as u32),
- security_domain
- .map_or(ptr::null(), |s| s.as_ptr().cast()),
- account.len() as u32,
- account.as_ptr().cast(),
- path.len() as u32,
- path.as_ptr().cast(),
- port.unwrap_or(0),
- protocol,
- authentication_type,
- &mut data_len,
- &mut data,
- &mut item,
- ))?;
- Ok((
- SecKeychainItemPassword {
- data: data as *const _,
- data_len: data_len as usize,
- },
- SecKeychainItem::wrap_under_create_rule(item),
- ))
- }
-}
-
-impl SecKeychain {
- /// Find application password in this keychain
- #[inline]
- pub fn find_generic_password(
- &self,
- service: &str,
- account: &str,
- ) -> Result<(SecKeychainItemPassword, SecKeychainItem)> {
- find_generic_password(Some(&[self.clone()]), service, account)
- }
-
- /// Find internet password in this keychain
- #[inline]
- #[allow(clippy::too_many_arguments)]
- pub fn find_internet_password(
- &self,
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
- ) -> Result<(SecKeychainItemPassword, SecKeychainItem)> {
- find_internet_password(
- Some(&[self.clone()]),
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- )
- }
-
- /// Update existing or add new internet password
- #[allow(clippy::too_many_arguments)]
- pub fn set_internet_password(
- &self,
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
- password: &[u8],
- ) -> Result<()> {
- match self.find_internet_password(
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- ) {
- Ok((_, mut item)) => item.set_password(password),
- _ => self.add_internet_password(
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- password,
- ),
- }
- }
-
- /// Set a generic password.
- ///
- /// * `keychain_opt` is the keychain to use or None to use the default
- /// keychain.
- /// * `service` is the associated service name for the password.
- /// * `account` is the associated account name for the password.
- /// * `password` is the password itself.
- pub fn set_generic_password(
- &self,
- service: &str,
- account: &str,
- password: &[u8],
- ) -> Result<()> {
- match self.find_generic_password(service, account) {
- Ok((_, mut item)) => item.set_password(password),
- _ => self.add_generic_password(service, account, password),
- }
- }
-
- /// Add application password to the keychain, without checking if it exists already
- ///
- /// See `set_generic_password()`
- #[inline]
- pub fn add_generic_password(
- &self,
- service: &str,
- account: &str,
- password: &[u8],
- ) -> Result<()> {
- unsafe {
- cvt(SecKeychainAddGenericPassword(
- self.as_CFTypeRef() as *mut _,
- service.len() as u32,
- service.as_ptr().cast(),
- account.len() as u32,
- account.as_ptr().cast(),
- password.len() as u32,
- password.as_ptr().cast(),
- ptr::null_mut(),
- ))?;
- }
- Ok(())
- }
-
- /// Add internet password to the keychain, without checking if it exists already
- ///
- /// See `set_internet_password()`
- #[inline]
- #[allow(clippy::too_many_arguments)]
- pub fn add_internet_password(
- &self,
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
- password: &[u8],
- ) -> Result<()> {
- unsafe {
- cvt(SecKeychainAddInternetPassword(
- self.as_CFTypeRef() as *mut _,
- server.len() as u32,
- server.as_ptr().cast(),
- security_domain.map_or(0, |s| s.len() as u32),
- security_domain
- .map_or(ptr::null(), |s| s.as_ptr().cast()),
- account.len() as u32,
- account.as_ptr().cast(),
- path.len() as u32,
- path.as_ptr().cast(),
- port.unwrap_or(0),
- protocol,
- authentication_type,
- password.len() as u32,
- password.as_ptr().cast(),
- ptr::null_mut(),
- ))?;
- }
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::os::macos::keychain::CreateOptions;
- use tempfile::tempdir;
- use tempfile::TempDir;
-
- fn temp_keychain_setup(name: &str) -> (TempDir, SecKeychain) {
- let dir = tempdir().expect("TempDir::new");
- let keychain = CreateOptions::new()
- .password("foobar")
- .create(dir.path().join(name.to_string() + ".keychain"))
- .expect("create keychain");
-
- (dir, keychain)
- }
-
- fn temp_keychain_teardown(dir: TempDir) {
- dir.close().expect("temp dir close");
- }
-
- #[test]
- fn missing_password_temp() {
- let (dir, keychain) = temp_keychain_setup("missing_password");
- let keychains = vec![keychain];
-
- let service = "temp_this_service_does_not_exist";
- let account = "this_account_is_bogus";
- let found = find_generic_password(Some(&keychains), service, account);
-
- assert!(found.is_err());
-
- temp_keychain_teardown(dir);
- }
-
- #[test]
- #[cfg(feature = "default_keychain_tests")]
- fn missing_password_default() {
- let service = "default_this_service_does_not_exist";
- let account = "this_account_is_bogus";
- let found = find_generic_password(None, service, account);
-
- assert!(found.is_err());
- }
-
- #[test]
- fn round_trip_password_temp() {
- let (dir, keychain) = temp_keychain_setup("round_trip_password");
-
- let service = "test_round_trip_password_temp";
- let account = "temp_this_is_the_test_account";
- let password = String::from("deadbeef").into_bytes();
-
- keychain
- .set_generic_password(service, account, &password)
- .expect("set_generic_password");
- let (found, item) = keychain
- .find_generic_password(service, account)
- .expect("find_generic_password");
- assert_eq!(found.to_owned(), password);
-
- item.delete();
-
- temp_keychain_teardown(dir);
- }
-
- #[test]
- #[cfg(feature = "default_keychain_tests")]
- fn round_trip_password_default() {
- let service = "test_round_trip_password_default";
- let account = "this_is_the_test_account";
- let password = String::from("deadbeef").into_bytes();
-
- SecKeychain::default()
- .expect("default keychain")
- .set_generic_password(service, account, &password)
- .expect("set_generic_password");
- let (found, item) =
- find_generic_password(None, service, account).expect("find_generic_password");
- assert_eq!(&*found, &password[..]);
-
- item.delete();
- }
-
- #[test]
- fn change_password_temp() {
- let (dir, keychain) = temp_keychain_setup("change_password");
- let keychains = vec![keychain];
-
- let service = "test_change_password_temp";
- let account = "this_is_the_test_account";
- let pw1 = String::from("password1").into_bytes();
- let pw2 = String::from("password2").into_bytes();
-
- keychains[0]
- .set_generic_password(service, account, &pw1)
- .expect("set_generic_password1");
- let (found, _) = find_generic_password(Some(&keychains), service, account)
- .expect("find_generic_password1");
- assert_eq!(found.as_ref(), &pw1[..]);
-
- keychains[0]
- .set_generic_password(service, account, &pw2)
- .expect("set_generic_password2");
- let (found, item) = find_generic_password(Some(&keychains), service, account)
- .expect("find_generic_password2");
- assert_eq!(&*found, &pw2[..]);
-
- item.delete();
-
- temp_keychain_teardown(dir);
- }
-
- #[test]
- #[cfg(feature = "default_keychain_tests")]
- fn change_password_default() {
- let service = "test_change_password_default";
- let account = "this_is_the_test_account";
- let pw1 = String::from("password1").into_bytes();
- let pw2 = String::from("password2").into_bytes();
-
- SecKeychain::default()
- .expect("default keychain")
- .set_generic_password(service, account, &pw1)
- .expect("set_generic_password1");
- let (found, _) =
- find_generic_password(None, service, account).expect("find_generic_password1");
- assert_eq!(found.to_owned(), pw1);
-
- SecKeychain::default()
- .expect("default keychain")
- .set_generic_password(service, account, &pw2)
- .expect("set_generic_password2");
- let (found, item) =
- find_generic_password(None, service, account).expect("find_generic_password2");
- assert_eq!(found.to_owned(), pw2);
-
- item.delete();
- }
-
- #[test]
- fn cross_keychain_corruption_temp() {
- let (dir1, keychain1) = temp_keychain_setup("cross_corrupt1");
- let (dir2, keychain2) = temp_keychain_setup("cross_corrupt2");
- let keychains1 = vec![keychain1.clone()];
- let keychains2 = vec![keychain2.clone()];
- let both_keychains = vec![keychain1, keychain2];
-
- let service = "temp_this_service_does_not_exist";
- let account = "this_account_is_bogus";
- let password = String::from("deadbeef").into_bytes();
-
- // Make sure this password doesn't exist in either keychain.
- let found = find_generic_password(Some(&both_keychains), service, account);
- assert!(found.is_err());
-
- // Set a password in one keychain.
- keychains1[0]
- .set_generic_password(service, account, &password)
- .expect("set_generic_password");
-
- // Make sure it's found in that keychain.
- let (found, item) = find_generic_password(Some(&keychains1), service, account)
- .expect("find_generic_password1");
- assert_eq!(found.to_owned(), password);
-
- // Make sure it's _not_ found in the other keychain.
- let found = find_generic_password(Some(&keychains2), service, account);
- assert!(found.is_err());
-
- // Cleanup.
- item.delete();
-
- temp_keychain_teardown(dir1);
- temp_keychain_teardown(dir2);
- }
-}
diff --git a/vendor/security-framework/src/os/macos/secure_transport.rs b/vendor/security-framework/src/os/macos/secure_transport.rs
deleted file mode 100644
index 7d01f066..00000000
--- a/vendor/security-framework/src/os/macos/secure_transport.rs
+++ /dev/null
@@ -1,647 +0,0 @@
-//! OSX specific extensions to Secure Transport functionality.
-
-use core_foundation::array::CFArray;
-use core_foundation::base::TCFType;
-use security_framework_sys::secure_transport::*;
-use std::ptr;
-use std::slice;
-
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::secure_transport::{MidHandshakeSslStream, SslContext};
-use crate::{cvt, AsInner};
-
-/// An extension trait adding OSX specific functionality to the `SslContext`
-/// type.
-pub trait SslContextExt {
- /// Returns the DER encoded data specifying the parameters used for
- /// Diffie-Hellman key exchange.
- fn diffie_hellman_params(&self) -> Result<Option<&[u8]>>;
-
- /// Sets the parameters used for Diffie-Hellman key exchange, in the
- /// DER format used by OpenSSL.
- ///
- /// If a cipher suite which uses Diffie-Hellman key exchange is selected,
- /// parameters will automatically be generated if none are provided with
- /// this method, but this process can take up to 30 seconds.
- ///
- /// This can only be called on server-side sessions.
- fn set_diffie_hellman_params(&mut self, dh_params: &[u8]) -> Result<()>;
-
- /// Returns the certificate authorities used to validate client
- /// certificates.
- fn certificate_authorities(&self) -> Result<Option<Vec<SecCertificate>>>;
-
- /// Sets the certificate authorities used to validate client certificates,
- /// replacing any that are already present.
- fn set_certificate_authorities(&mut self, certs: &[SecCertificate]) -> Result<()>;
-
- /// Adds certificate authorities used to validate client certificates.
- fn add_certificate_authorities(&mut self, certs: &[SecCertificate]) -> Result<()>;
-
- /// If enabled, server identity changes are allowed during renegotiation.
- ///
- /// It is disabled by default to protect against triple handshake attacks.
- ///
- /// Requires the `OSX_10_11` (or greater) feature.
- #[cfg(feature = "OSX_10_11")]
- fn allow_server_identity_change(&self) -> Result<bool>;
-
- /// If enabled, server identity changes are allowed during renegotiation.
- ///
- /// It is disabled by default to protect against triple handshake attacks.
- ///
- /// Requires the `OSX_10_11` (or greater) feature.
- #[cfg(feature = "OSX_10_11")]
- fn set_allow_server_identity_change(&mut self, value: bool) -> Result<()>;
-
- /// If enabled, fallback countermeasures will be used during negotiation.
- ///
- /// It should be enabled when renegotiating with a peer with a lower
- /// maximum protocol version due to an earlier failure to connect.
- ///
- /// Requires the `OSX_10_10` (or greater) feature.
- #[cfg(feature = "OSX_10_10")]
- fn fallback(&self) -> Result<bool>;
-
- /// If enabled, fallback countermeasures will be used during negotiation.
- ///
- /// It should be enabled when renegotiating with a peer with a lower
- /// maximum protocol version due to an earlier failure to connect.
- ///
- /// Requires the `OSX_10_10` (or greater) feature.
- #[cfg(feature = "OSX_10_10")]
- fn set_fallback(&mut self, value: bool) -> Result<()>;
-
- /// If enabled, the handshake process will pause and return when the client
- /// hello is recieved to support server name identification.
- ///
- /// Requires the `OSX_10_11` (or greater) feature.
- #[cfg(feature = "OSX_10_11")]
- fn break_on_client_hello(&self) -> Result<bool>;
-
- /// If enabled, the handshake process will pause and return when the client
- /// hello is recieved to support server name identification.
- ///
- /// Requires the `OSX_10_11` (or greater) feature.
- #[cfg(feature = "OSX_10_11")]
- fn set_break_on_client_hello(&mut self, value: bool) -> Result<()>;
-}
-
-macro_rules! impl_options {
- ($($(#[$a:meta])* const $opt:ident: $get:ident & $set:ident,)*) => {
- $(
- $(#[$a])*
- #[inline]
- fn $set(&mut self, value: bool) -> Result<()> {
- unsafe {
- cvt(SSLSetSessionOption(self.as_inner(),
- $opt,
- value as ::core_foundation::base::Boolean))
- }
- }
-
- $(#[$a])*
- #[inline]
- fn $get(&self) -> Result<bool> {
- let mut value = 0;
- unsafe { cvt(SSLGetSessionOption(self.as_inner(), $opt, &mut value))?; }
- Ok(value != 0)
- }
- )*
- }
-}
-
-impl SslContextExt for SslContext {
- fn diffie_hellman_params(&self) -> Result<Option<&[u8]>> {
- unsafe {
- let mut ptr = ptr::null();
- let mut len = 0;
- cvt(SSLGetDiffieHellmanParams(
- self.as_inner(),
- &mut ptr,
- &mut len,
- ))?;
- if ptr.is_null() {
- Ok(None)
- } else {
- Ok(Some(slice::from_raw_parts(ptr.cast::<u8>(), len)))
- }
- }
- }
-
- fn set_diffie_hellman_params(&mut self, dh_params: &[u8]) -> Result<()> {
- unsafe {
- cvt(SSLSetDiffieHellmanParams(
- self.as_inner(),
- dh_params.as_ptr().cast(),
- dh_params.len(),
- ))
- }
- }
-
- fn certificate_authorities(&self) -> Result<Option<Vec<SecCertificate>>> {
- unsafe {
- let mut raw_certs = ptr::null();
- cvt(SSLCopyCertificateAuthorities(
- self.as_inner(),
- &mut raw_certs,
- ))?;
- if raw_certs.is_null() {
- Ok(None)
- } else {
- let certs = CFArray::<SecCertificate>::wrap_under_create_rule(raw_certs)
- .iter()
- .map(|c| c.clone())
- .collect();
- Ok(Some(certs))
- }
- }
- }
-
- fn set_certificate_authorities(&mut self, certs: &[SecCertificate]) -> Result<()> {
- unsafe {
- let certs = CFArray::from_CFTypes(certs);
- cvt(SSLSetCertificateAuthorities(
- self.as_inner(),
- certs.as_CFTypeRef(),
- 1,
- ))
- }
- }
-
- fn add_certificate_authorities(&mut self, certs: &[SecCertificate]) -> Result<()> {
- unsafe {
- let certs = CFArray::from_CFTypes(certs);
- cvt(SSLSetCertificateAuthorities(
- self.as_inner(),
- certs.as_CFTypeRef(),
- 0,
- ))
- }
- }
-
- impl_options! {
- #[cfg(feature = "OSX_10_11")]
- const kSSLSessionOptionAllowServerIdentityChange: allow_server_identity_change & set_allow_server_identity_change,
- #[cfg(feature = "OSX_10_10")]
- const kSSLSessionOptionFallback: fallback & set_fallback,
- #[cfg(feature = "OSX_10_11")]
- const kSSLSessionOptionBreakOnClientHello: break_on_client_hello & set_break_on_client_hello,
- }
-}
-
-/// An extension trait adding OSX specific functionality to the
-/// `MidHandshakeSslStream` type.
-pub trait MidHandshakeSslStreamExt {
- /// Returns `true` iff `break_on_client_hello` was set and the handshake
- /// has progressed to that point.
- ///
- /// Requires the `OSX_10_11` (or greater) feature.
- #[cfg(feature = "OSX_10_11")]
- fn client_hello_received(&self) -> bool;
-}
-
-impl<S> MidHandshakeSslStreamExt for MidHandshakeSslStream<S> {
- #[cfg(feature = "OSX_10_11")]
- fn client_hello_received(&self) -> bool {
- self.error().code() == errSSLClientHelloReceived
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::io::prelude::*;
- use std::net::{TcpListener, TcpStream};
- use std::thread;
- use tempfile::tempdir;
-
- use super::*;
- use crate::cipher_suite::CipherSuite;
- use crate::os::macos::test::identity;
- use crate::secure_transport::*;
- use crate::test::certificate;
-
- #[test]
- fn server_client() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(ctx.handshake(stream));
-
- let mut buf = [0; 12];
- p!(stream.read(&mut buf));
- assert_eq!(&buf[..], b"hello world!");
- });
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_break_on_server_auth(true));
- let stream = p!(TcpStream::connect(("localhost", port)));
-
- let stream = match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(err) => panic!("unexpected error {err:?}"),
- };
-
- assert!(stream.server_auth_completed());
- let mut peer_trust = p!(stream.context().peer_trust2()).unwrap();
- p!(peer_trust.set_anchor_certificates(&[certificate()]));
- p!(peer_trust.evaluate_with_error());
-
- let mut stream = p!(stream.handshake());
- p!(stream.write_all(b"hello world!"));
-
- handle.join().unwrap();
- }
-
- #[test]
- #[ignore]
- fn server_client_builders() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let identity = identity(dir.path());
- let builder = ServerBuilder::new(&identity, &[]);
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(builder.handshake(stream));
-
- let mut buf = [0; 12];
- p!(stream.read(&mut buf));
- assert_eq!(&buf[..], b"hello world!");
- });
-
- let stream = p!(TcpStream::connect(("localhost", port)));
- let mut stream = p!(ClientBuilder::new()
- .anchor_certificates(&[certificate()])
- .handshake("foobar.com", stream));
-
- p!(stream.write_all(b"hello world!"));
-
- handle.join().unwrap();
- }
-
- #[test]
- fn client_bad_cert() {
- let _ = env_logger::try_init();
-
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
-
- let stream = p!(listener.accept()).0;
- let _ = ctx.handshake(stream);
- });
-
- let stream = p!(TcpStream::connect(("localhost", port)));
- assert!(ClientBuilder::new()
- .handshake("foobar.com", stream)
- .is_err());
-
- handle.join().unwrap();
- }
-
- #[test]
- #[ignore]
- fn client() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(ctx.handshake(stream));
-
- let mut buf = [0; 12];
- p!(stream.read(&mut buf));
- assert_eq!(&buf[..], b"hello world!");
- });
-
- let stream = p!(TcpStream::connect(("localhost", port)));
- let mut stream = p!(ClientBuilder::new()
- .anchor_certificates(&[certificate()])
- .handshake("foobar.com", stream));
- p!(stream.write_all(b"hello world!"));
-
- handle.join().unwrap();
- }
-
- #[test]
- fn negotiated_cipher() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
- p!(ctx.set_enabled_ciphers(&[
- CipherSuite::TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
- CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- ]));
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(ctx.handshake(stream));
- assert_eq!(
- CipherSuite::TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
- p!(stream.context().negotiated_cipher())
- );
- let mut buf = [0; 1];
- p!(stream.read(&mut buf));
- });
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_break_on_server_auth(true));
- p!(ctx.set_enabled_ciphers(&[
- CipherSuite::TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
- CipherSuite::TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
- ]));
- let stream = p!(TcpStream::connect(("localhost", port)));
-
- let stream = match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(err) => panic!("unexpected error {err:?}"),
- };
-
- let mut stream = p!(stream.handshake());
- assert_eq!(
- CipherSuite::TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
- p!(stream.context().negotiated_cipher())
- );
- p!(stream.write(&[0]));
-
- handle.join().unwrap();
- }
-
- #[test]
- fn dh_params() {
- let params = include_bytes!("../../../test/dhparam.der");
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- assert!(p!(ctx.diffie_hellman_params()).is_none());
- p!(ctx.set_diffie_hellman_params(params));
- assert_eq!(p!(ctx.diffie_hellman_params()).unwrap(), &params[..]);
- }
-
- #[test]
- fn try_authenticate_no_cert() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
- p!(ctx.set_client_side_authenticate(SslAuthenticate::TRY));
- let cert = certificate();
- p!(ctx.add_certificate_authorities(&[cert]));
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(ctx.handshake(stream));
- let mut buf = [0; 1];
- p!(stream.read(&mut buf));
- });
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_break_on_server_auth(true));
- let stream = p!(TcpStream::connect(("localhost", port)));
-
- let stream = match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(err) => panic!("unexpected error {err:?}"),
- };
-
- let mut stream = p!(stream.handshake());
- p!(stream.write(&[0]));
-
- handle.join().unwrap();
- }
-
- #[test]
- fn always_authenticate_no_cert() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
- p!(ctx.set_client_side_authenticate(SslAuthenticate::ALWAYS));
-
- let stream = p!(listener.accept()).0;
-
- match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Failure(_)) => {}
- Err(err) => panic!("unexpected error {err:?}"),
- }
- });
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_break_on_server_auth(true));
- let stream = p!(TcpStream::connect(("localhost", port)));
-
- let stream = match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(err) => panic!("unexpected error {err:?}"),
- };
-
- match stream.handshake() {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Failure(_)) => {}
- Err(err) => panic!("unexpected error {err:?}"),
- }
-
- handle.join().unwrap();
- }
-
- #[test]
- fn always_authenticate_with_cert() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
- p!(ctx.set_client_side_authenticate(SslAuthenticate::ALWAYS));
-
- let stream = p!(listener.accept()).0;
-
- match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Failure(_)) => {}
- Err(err) => panic!("unexpected error {err:?}"),
- }
- });
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_break_on_server_auth(true));
- let dir = p!(tempdir());
- let identity = identity(dir.path());
- p!(ctx.set_certificate(&identity, &[]));
- let stream = p!(TcpStream::connect(("localhost", port)));
-
- let stream = match ctx.handshake(stream) {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(err) => panic!("unexpected error {err:?}"),
- };
-
- match stream.handshake() {
- Ok(_) => panic!("unexpected success"),
- Err(HandshakeError::Failure(_)) => {}
- Err(err) => panic!("unexpected error {err:?}"),
- }
-
- handle.join().unwrap();
- }
-
- #[test]
- fn certificate_authorities() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- assert!(p!(ctx.certificate_authorities()).is_none());
- p!(ctx.set_certificate_authorities(&[certificate()]));
- assert_eq!(p!(ctx.certificate_authorities()).unwrap().len(), 1);
- }
-
- #[test]
- #[ignore]
- fn close() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let identity = identity(dir.path());
- let builder = ServerBuilder::new(&identity, &[]);
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(builder.handshake(stream));
- p!(stream.close());
- });
-
- let stream = p!(TcpStream::connect(("localhost", port)));
- let mut stream = p!(ClientBuilder::new()
- .anchor_certificates(&[certificate()])
- .handshake("foobar.com", stream));
-
- let mut buf = [0; 1];
- assert_eq!(p!(stream.read(&mut buf)), 0);
- p!(stream.close());
-
- p!(handle.join());
- }
-
- #[test]
- #[ignore]
- fn short_read() {
- let listener = p!(TcpListener::bind("localhost:0"));
- let port = p!(listener.local_addr()).port();
-
- let handle = thread::spawn(move || {
- let dir = p!(tempdir());
-
- let identity = identity(dir.path());
- let builder = ServerBuilder::new(&identity, &[]);
-
- let stream = p!(listener.accept()).0;
- let mut stream = p!(builder.handshake(stream));
-
- stream.write_all(b"hello").unwrap();
- // make sure stream doesn't close
- stream
- });
-
- let stream = p!(TcpStream::connect(("localhost", port)));
- let mut stream = p!(ClientBuilder::new()
- .anchor_certificates(&[certificate()])
- .handshake("foobar.com", stream));
-
- let mut b = [0; 1];
- stream.read_exact(&mut b).unwrap();
- assert_eq!(stream.context().buffered_read_size().unwrap(), 4);
- let mut b = [0; 5];
- let read = stream.read(&mut b).unwrap();
- assert_eq!(read, 4);
-
- p!(handle.join());
- }
-}
diff --git a/vendor/security-framework/src/os/macos/transform.rs b/vendor/security-framework/src/os/macos/transform.rs
deleted file mode 100644
index d03bc1f7..00000000
--- a/vendor/security-framework/src/os/macos/transform.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-//! Transform support
-
-use core_foundation::base::{CFType, TCFType};
-use core_foundation::error::CFError;
-use core_foundation::string::CFString;
-use security_framework_sys::transform::*;
-use std::ptr;
-
-declare_TCFType! {
- /// A type representing a transform.
- SecTransform, SecTransformRef
-}
-impl_TCFType!(SecTransform, SecTransformRef, SecTransformGetTypeID);
-
-unsafe impl Sync for SecTransform {}
-unsafe impl Send for SecTransform {}
-
-impl SecTransform {
- /// Sets an attribute of the transform.
- pub fn set_attribute<T>(&mut self, key: &CFString, value: &T) -> Result<(), CFError>
- where
- T: TCFType,
- {
- unsafe {
- let mut error = ptr::null_mut();
- SecTransformSetAttribute(
- self.0,
- key.as_concrete_TypeRef(),
- value.as_CFTypeRef(),
- &mut error,
- );
- if !error.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
-
- Ok(())
- }
- }
-
- /// Executes the transform.
- ///
- /// The return type depends on the type of transform.
- pub fn execute(&mut self) -> Result<CFType, CFError> {
- unsafe {
- let mut error = ptr::null_mut();
- let result = SecTransformExecute(self.0, &mut error);
- if result.is_null() {
- return Err(CFError::wrap_under_create_rule(error));
- }
-
- Ok(CFType::wrap_under_create_rule(result))
- }
- }
-}
diff --git a/vendor/security-framework/src/os/mod.rs b/vendor/security-framework/src/os/mod.rs
deleted file mode 100644
index ec7e38b3..00000000
--- a/vendor/security-framework/src/os/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//! OS specific extensions.
-
-#[cfg(target_os = "macos")]
-pub mod macos;
diff --git a/vendor/security-framework/src/passwords.rs b/vendor/security-framework/src/passwords.rs
deleted file mode 100644
index 0e83f432..00000000
--- a/vendor/security-framework/src/passwords.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-//! Support for password entries in the keychain. Works on both iOS and macOS.
-//!
-//! If you want the extended keychain facilities only available on macOS, use the
-//! version of these functions in the macOS extensions module.
-
-use crate::base::Result;
-use crate::passwords_options::PasswordOptions;
-use crate::{cvt, Error};
-use core_foundation::base::TCFType;
-use core_foundation::boolean::CFBoolean;
-use core_foundation::data::CFData;
-use core_foundation::dictionary::CFDictionary;
-use core_foundation::string::CFString;
-use core_foundation_sys::base::{CFGetTypeID, CFRelease, CFTypeRef};
-use core_foundation_sys::data::CFDataRef;
-use security_framework_sys::base::{errSecDuplicateItem, errSecParam};
-use security_framework_sys::item::{kSecReturnData, kSecValueData};
-use security_framework_sys::keychain::{SecAuthenticationType, SecProtocolType};
-use security_framework_sys::keychain_item::{
- SecItemAdd, SecItemCopyMatching, SecItemDelete, SecItemUpdate,
-};
-
-/// Set a generic password for the given service and account.
-/// Creates or updates a keychain entry.
-pub fn set_generic_password(service: &str, account: &str, password: &[u8]) -> Result<()> {
- let mut options = PasswordOptions::new_generic_password(service, account);
- set_password_internal(&mut options, password)
-}
-
-/// Get the generic password for the given service and account. If no matching
-/// keychain entry exists, fails with error code `errSecItemNotFound`.
-pub fn get_generic_password(service: &str, account: &str) -> Result<Vec<u8>> {
- let mut options = PasswordOptions::new_generic_password(service, account);
- options.query.push((
- unsafe { CFString::wrap_under_get_rule(kSecReturnData) },
- CFBoolean::from(true).into_CFType(),
- ));
- let params = CFDictionary::from_CFType_pairs(&options.query);
- let mut ret: CFTypeRef = std::ptr::null();
- cvt(unsafe { SecItemCopyMatching(params.as_concrete_TypeRef(), &mut ret) })?;
- get_password_and_release(ret)
-}
-
-/// Delete the generic password keychain entry for the given service and account.
-/// If none exists, fails with error code `errSecItemNotFound`.
-pub fn delete_generic_password(service: &str, account: &str) -> Result<()> {
- let options = PasswordOptions::new_generic_password(service, account);
- let params = CFDictionary::from_CFType_pairs(&options.query);
- cvt(unsafe { SecItemDelete(params.as_concrete_TypeRef()) })
-}
-
-/// Set an internet password for the given endpoint parameters.
-/// Creates or updates a keychain entry.
-#[allow(clippy::too_many_arguments)]
-pub fn set_internet_password(
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
- password: &[u8],
-) -> Result<()> {
- let mut options = PasswordOptions::new_internet_password(
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- );
- set_password_internal(&mut options, password)
-}
-
-/// Get the internet password for the given endpoint parameters. If no matching
-/// keychain entry exists, fails with error code `errSecItemNotFound`.
-pub fn get_internet_password(
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
-) -> Result<Vec<u8>> {
- let mut options = PasswordOptions::new_internet_password(
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- );
- options.query.push((
- unsafe { CFString::wrap_under_get_rule(kSecReturnData) },
- CFBoolean::from(true).into_CFType(),
- ));
- let params = CFDictionary::from_CFType_pairs(&options.query);
- let mut ret: CFTypeRef = std::ptr::null();
- cvt(unsafe { SecItemCopyMatching(params.as_concrete_TypeRef(), &mut ret) })?;
- get_password_and_release(ret)
-}
-
-/// Delete the internet password for the given endpoint parameters.
-/// If none exists, fails with error code `errSecItemNotFound`.
-pub fn delete_internet_password(
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
-) -> Result<()> {
- let options = PasswordOptions::new_internet_password(
- server,
- security_domain,
- account,
- path,
- port,
- protocol,
- authentication_type,
- );
- let params = CFDictionary::from_CFType_pairs(&options.query);
- cvt(unsafe { SecItemDelete(params.as_concrete_TypeRef()) })
-}
-
-// This starts by trying to create the password with the given query params.
-// If the creation attempt reveals that one exists, its password is updated.
-fn set_password_internal(options: &mut PasswordOptions, password: &[u8]) -> Result<()> {
- let query_len = options.query.len();
- options.query.push((
- unsafe { CFString::wrap_under_get_rule(kSecValueData) },
- CFData::from_buffer(password).into_CFType(),
- ));
-
- let params = CFDictionary::from_CFType_pairs(&options.query);
- let mut ret = std::ptr::null();
- let status = unsafe { SecItemAdd(params.as_concrete_TypeRef(), &mut ret) };
- if status == errSecDuplicateItem {
- let params = CFDictionary::from_CFType_pairs(&options.query[0..query_len]);
- let update = CFDictionary::from_CFType_pairs(&options.query[query_len..]);
- cvt(unsafe { SecItemUpdate(params.as_concrete_TypeRef(), update.as_concrete_TypeRef()) })
- } else {
- cvt(status)
- }
-}
-
-// Having retrieved a password entry, this copies and returns the password.
-//
-// # Safety
-// The data element passed in is assumed to have been returned from a Copy
-// call, so it's released after we are done with it.
-fn get_password_and_release(data: CFTypeRef) -> Result<Vec<u8>> {
- if !data.is_null() {
- let type_id = unsafe { CFGetTypeID(data) };
- if type_id == CFData::type_id() {
- let val = unsafe { CFData::wrap_under_create_rule(data as CFDataRef) };
- let mut vec = Vec::new();
- if val.len() > 0 {
- vec.extend_from_slice(val.bytes());
- }
- return Ok(vec);
- }
- // unexpected: we got a reference to some other type.
- // Release it to make sure there's no leak, but
- // we can't return the password in this case.
- unsafe { CFRelease(data) };
- }
- Err(Error::from_code(errSecParam))
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use security_framework_sys::base::errSecItemNotFound;
-
- #[test]
- fn missing_generic() {
- let name = "a string not likely to already be in the keychain as service or account";
- let result = delete_generic_password(name, name);
- match result {
- Ok(()) => (), // this is ok because the name _might_ be in the keychain
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!("missing_generic: delete failed with status: {}", err.code()),
- };
- let result = get_generic_password(name, name);
- match result {
- Ok(bytes) => panic!("missing_generic: get returned {bytes:?}"),
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!("missing_generic: get failed with status: {}", err.code()),
- };
- let result = delete_generic_password(name, name);
- match result {
- Ok(()) => panic!("missing_generic: second delete found a password"),
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!("missing_generic: delete failed with status: {}", err.code()),
- };
- }
-
- #[test]
- fn roundtrip_generic() {
- let name = "roundtrip_generic";
- set_generic_password(name, name, name.as_bytes()).expect("set_generic_password");
- let pass = get_generic_password(name, name).expect("get_generic_password");
- assert_eq!(name.as_bytes(), pass);
- delete_generic_password(name, name).expect("delete_generic_password");
- }
-
- #[test]
- fn update_generic() {
- let name = "update_generic";
- set_generic_password(name, name, name.as_bytes()).expect("set_generic_password");
- let alternate = "update_generic_alternate";
- set_generic_password(name, name, alternate.as_bytes()).expect("set_generic_password");
- let pass = get_generic_password(name, name).expect("get_generic_password");
- assert_eq!(pass, alternate.as_bytes());
- delete_generic_password(name, name).expect("delete_generic_password");
- }
-
- #[test]
- fn missing_internet() {
- let name = "a string not likely to already be in the keychain as service or account";
- let (server, domain, account, path, port, protocol, auth) = (
- name,
- None,
- name,
- "/",
- Some(8080u16),
- SecProtocolType::HTTP,
- SecAuthenticationType::Any,
- );
- let result = delete_internet_password(server, domain, account, path, port, protocol, auth);
- match result {
- Ok(()) => (), // this is ok because the name _might_ be in the keychain
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!(
- "missing_internet: delete failed with status: {}",
- err.code()
- ),
- };
- let result = get_internet_password(server, domain, account, path, port, protocol, auth);
- match result {
- Ok(bytes) => panic!("missing_internet: get returned {bytes:?}"),
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!("missing_internet: get failed with status: {}", err.code()),
- };
- let result = delete_internet_password(server, domain, account, path, port, protocol, auth);
- match result {
- Ok(()) => panic!("missing_internet: second delete found a password"),
- Err(err) if err.code() == errSecItemNotFound => (),
- Err(err) => panic!(
- "missing_internet: delete failed with status: {}",
- err.code()
- ),
- };
- }
-
- #[test]
- fn roundtrip_internet() {
- let name = "roundtrip_internet";
- let (server, domain, account, path, port, protocol, auth) = (
- name,
- None,
- name,
- "/",
- Some(8080u16),
- SecProtocolType::HTTP,
- SecAuthenticationType::Any,
- );
- set_internet_password(
- server,
- domain,
- account,
- path,
- port,
- protocol,
- auth,
- name.as_bytes(),
- )
- .expect("set_internet_password");
- let pass = get_internet_password(server, domain, account, path, port, protocol, auth)
- .expect("get_internet_password");
- assert_eq!(name.as_bytes(), pass);
- delete_internet_password(server, domain, account, path, port, protocol, auth)
- .expect("delete_internet_password");
- }
-
- #[test]
- fn update_internet() {
- let name = "update_internet";
- let (server, domain, account, path, port, protocol, auth) = (
- name,
- None,
- name,
- "/",
- Some(8080u16),
- SecProtocolType::HTTP,
- SecAuthenticationType::Any,
- );
-
- // cleanup after failed test
- let _ = delete_internet_password(server, domain, account, path, port, protocol, auth);
-
- set_internet_password(
- server,
- domain,
- account,
- path,
- port,
- protocol,
- auth,
- name.as_bytes(),
- )
- .expect("set_internet_password");
- let alternate = "alternate_internet_password";
- set_internet_password(
- server,
- domain,
- account,
- path,
- port,
- protocol,
- auth,
- alternate.as_bytes(),
- )
- .expect("set_internet_password");
- let pass = get_internet_password(server, domain, account, path, port, protocol, auth)
- .expect("get_internet_password");
- assert_eq!(pass, alternate.as_bytes());
- delete_internet_password(server, domain, account, path, port, protocol, auth)
- .expect("delete_internet_password");
- }
-}
diff --git a/vendor/security-framework/src/passwords_options.rs b/vendor/security-framework/src/passwords_options.rs
deleted file mode 100644
index 7d85d01c..00000000
--- a/vendor/security-framework/src/passwords_options.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-//! Support for password options, to be used with the passwords module
-
-use core_foundation::{string::CFString, base::{CFType, TCFType, CFOptionFlags}, number::CFNumber};
-use security_framework_sys::{keychain::{SecProtocolType, SecAuthenticationType}, access_control::*};
-use security_framework_sys::item::{
- kSecAttrAccessControl, kSecAttrAccount, kSecAttrAuthenticationType, kSecAttrPath, kSecAttrPort, kSecAttrProtocol,
- kSecAttrSecurityDomain, kSecAttrServer, kSecAttrService, kSecClass, kSecClassGenericPassword,
- kSecClassInternetPassword,
-};
-use crate::access_control::SecAccessControl;
-
-/// `PasswordOptions` constructor
-pub struct PasswordOptions {
- /// query built for the keychain request
- pub query: Vec<(CFString, CFType)>,
-}
-
-bitflags::bitflags! {
- /// The option flags used to configure the evaluation of a `SecAccessControl`.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct AccessControlOptions: CFOptionFlags {
- /** Constraint to access an item with either biometry or passcode. */
- const USER_PRESENCE = kSecAccessControlUserPresence;
- #[cfg(feature = "OSX_10_13")]
- /** Constraint to access an item with Touch ID for any enrolled fingers, or Face ID. */
- const BIOMETRY_ANY = kSecAccessControlBiometryAny;
- #[cfg(feature = "OSX_10_13")]
- /** Constraint to access an item with Touch ID for currently enrolled fingers, or from Face ID with the currently enrolled user. */
- const BIOMETRY_CURRENT_SET = kSecAccessControlBiometryCurrentSet;
- /** Constraint to access an item with a passcode. */
- const DEVICE_PASSCODE = kSecAccessControlDevicePasscode;
- #[cfg(feature = "OSX_10_15")]
- /** Constraint to access an item with a watch. */
- const WATCH = kSecAccessControlWatch;
- /** Indicates that at least one constraint must be satisfied. */
- const OR = kSecAccessControlOr;
- /** Indicates that all constraints must be satisfied. */
- const AND = kSecAccessControlAnd;
- /** Enable a private key to be used in signing a block of data or verifying a signed block. */
- const PRIVATE_KEY_USAGE = kSecAccessControlPrivateKeyUsage;
- /** Option to use an application-provided password for data encryption key generation. */
- const APPLICATION_PASSWORD = kSecAccessControlApplicationPassword;
- }
-}
-
-impl PasswordOptions {
- /// Create a new generic password options
- /// Generic passwords are identified by service and account. They have other
- /// attributes, but this interface doesn't allow specifying them.
- #[must_use] pub fn new_generic_password(service: &str, account: &str) -> Self {
- let query = vec![
- (
- unsafe { CFString::wrap_under_get_rule(kSecClass) },
- unsafe { CFString::wrap_under_get_rule(kSecClassGenericPassword).into_CFType() },
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrService) },
- CFString::from(service).into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) },
- CFString::from(account).into_CFType(),
- ),
- ];
- Self { query }
- }
-
- /// Create a new internet password options
- /// Internet passwords are identified by a number of attributes.
- /// They can have others, but this interface doesn't allow specifying them.
- #[must_use] pub fn new_internet_password(
- server: &str,
- security_domain: Option<&str>,
- account: &str,
- path: &str,
- port: Option<u16>,
- protocol: SecProtocolType,
- authentication_type: SecAuthenticationType,
- ) -> Self {
- let mut query = vec![
- (
- unsafe { CFString::wrap_under_get_rule(kSecClass) },
- unsafe { CFString::wrap_under_get_rule(kSecClassInternetPassword) }.into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrServer) },
- CFString::from(server).into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrPath) },
- CFString::from(path).into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrAccount) },
- CFString::from(account).into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrProtocol) },
- CFNumber::from(protocol as i32).into_CFType(),
- ),
- (
- unsafe { CFString::wrap_under_get_rule(kSecAttrAuthenticationType) },
- CFNumber::from(authentication_type as i32).into_CFType(),
- ),
- ];
- if let Some(domain) = security_domain {
- query.push((
- unsafe { CFString::wrap_under_get_rule(kSecAttrSecurityDomain) },
- CFString::from(domain).into_CFType(),
- ));
- }
- if let Some(port) = port {
- query.push((
- unsafe { CFString::wrap_under_get_rule(kSecAttrPort) },
- CFNumber::from(i32::from(port)).into_CFType(),
- ));
- }
- Self { query }
- }
-
- /// Add access control to the password
- pub fn set_access_control_options(&mut self, options: AccessControlOptions) {
- self.query.push((
- unsafe { CFString::wrap_under_get_rule(kSecAttrAccessControl) },
- SecAccessControl::create_with_flags(options.bits())
- .unwrap()
- .into_CFType(),
- ));
- }
-}
diff --git a/vendor/security-framework/src/policy.rs b/vendor/security-framework/src/policy.rs
deleted file mode 100644
index f70a97c5..00000000
--- a/vendor/security-framework/src/policy.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-//! Security Policies support.
-use core_foundation::base::CFOptionFlags;
-use core_foundation::base::TCFType;
-use core_foundation::string::CFString;
-use security_framework_sys::base::errSecParam;
-use security_framework_sys::base::SecPolicyRef;
-use security_framework_sys::policy::*;
-use std::fmt;
-use std::ptr;
-
-use crate::secure_transport::SslProtocolSide;
-use crate::Error;
-
-declare_TCFType! {
- /// A type representing a certificate validation policy.
- SecPolicy, SecPolicyRef
-}
-impl_TCFType!(SecPolicy, SecPolicyRef, SecPolicyGetTypeID);
-
-unsafe impl Sync for SecPolicy {}
-unsafe impl Send for SecPolicy {}
-
-impl fmt::Debug for SecPolicy {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.debug_struct("SecPolicy").finish()
- }
-}
-
-bitflags::bitflags! {
- /// The flags used to specify revocation policy options.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct RevocationPolicy: CFOptionFlags {
- /// Perform revocation checking using OCSP (Online Certificate Status Protocol).
- const OCSP_METHOD = kSecRevocationOCSPMethod;
- /// Perform revocation checking using the CRL (Certification Revocation List) method.
- const CRL_METHOD = kSecRevocationCRLMethod;
- /// Prefer CRL revocation checking over OCSP; by default, OCSP is preferred.
- const PREFER_CRL = kSecRevocationPreferCRL;
- /// Require a positive response to pass the policy.
- const REQUIRE_POSITIVE_RESPONSE = kSecRevocationRequirePositiveResponse;
- /// Consult only locally cached replies; do not use network access.
- const NETWORK_ACCESS_DISABLED = kSecRevocationNetworkAccessDisabled;
- /// Perform either OCSP or CRL checking.
- const USE_ANY_METHOD_AVAILABLE = kSecRevocationUseAnyAvailableMethod;
- }
-}
-
-impl SecPolicy {
- /// Creates a `SecPolicy` for evaluating SSL certificate chains.
- ///
- /// The side which you are evaluating should be provided (i.e. pass `SslSslProtocolSide::SERVER` if
- /// you are a client looking to validate a server's certificate chain).
- pub fn create_ssl(protocol_side: SslProtocolSide, hostname: Option<&str>) -> Self {
- let hostname = hostname.map(CFString::new);
- let hostname = hostname
- .as_ref()
- .map(|s| s.as_concrete_TypeRef())
- .unwrap_or(ptr::null_mut());
- let is_server = protocol_side == SslProtocolSide::SERVER;
- unsafe {
- let policy = SecPolicyCreateSSL(is_server as _, hostname);
- Self::wrap_under_create_rule(policy)
- }
- }
-
- /// Creates a `SecPolicy` for checking revocation of certificates.
- ///
- /// If you do not specify this policy creating a `SecTrust` object, the system defaults
- /// will be used during evaluation.
- pub fn create_revocation(options: RevocationPolicy) -> crate::Result<Self> {
- let policy = unsafe { SecPolicyCreateRevocation(options.bits()) };
-
- if policy.is_null() {
- Err(Error::from_code(errSecParam))
- } else {
- Ok(unsafe { Self::wrap_under_create_rule(policy) })
- }
- }
-
- /// Returns a policy object for the default X.509 policy.
- #[must_use]
- pub fn create_x509() -> Self {
- unsafe {
- let policy = SecPolicyCreateBasicX509();
- Self::wrap_under_create_rule(policy)
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::policy::SecPolicy;
- use crate::secure_transport::SslProtocolSide;
-
- #[test]
- fn create_ssl() {
- SecPolicy::create_ssl(SslProtocolSide::SERVER, Some("certifi.org"));
- }
-}
diff --git a/vendor/security-framework/src/random.rs b/vendor/security-framework/src/random.rs
deleted file mode 100644
index 7bd7f614..00000000
--- a/vendor/security-framework/src/random.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//! Randomness support.
-
-use security_framework_sys::random::{SecRandomCopyBytes, SecRandomRef, kSecRandomDefault};
-use std::io;
-
-/// A source of random data.
-pub struct SecRandom(SecRandomRef);
-
-unsafe impl Sync for SecRandom {}
-unsafe impl Send for SecRandom {}
-
-impl Default for SecRandom {
- #[inline(always)]
- fn default() -> Self {
- unsafe { Self(kSecRandomDefault) }
- }
-}
-
-impl SecRandom {
- /// Fills the buffer with cryptographically secure random bytes.
- pub fn copy_bytes(&self, buf: &mut [u8]) -> io::Result<()> {
- if unsafe { SecRandomCopyBytes(self.0, buf.len(), buf.as_mut_ptr().cast()) } == 0 {
- Ok(())
- } else {
- Err(io::Error::last_os_error())
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn basic() {
- let mut buf = [0; 10];
- SecRandom::default().copy_bytes(&mut buf).unwrap();
- }
-}
diff --git a/vendor/security-framework/src/secure_transport.rs b/vendor/security-framework/src/secure_transport.rs
deleted file mode 100644
index a4e7cb7f..00000000
--- a/vendor/security-framework/src/secure_transport.rs
+++ /dev/null
@@ -1,1843 +0,0 @@
-//! SSL/TLS encryption support using Secure Transport.
-//!
-//! # Examples
-//!
-//! To connect as a client to a server with a certificate trusted by the system:
-//!
-//! ```rust
-//! use std::io::prelude::*;
-//! use std::net::TcpStream;
-//! use security_framework::secure_transport::ClientBuilder;
-//!
-//! let stream = TcpStream::connect("google.com:443").unwrap();
-//! let mut stream = ClientBuilder::new().handshake("google.com", stream).unwrap();
-//!
-//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
-//! let mut page = vec![];
-//! stream.read_to_end(&mut page).unwrap();
-//! println!("{}", String::from_utf8_lossy(&page));
-//! ```
-//!
-//! To connect to a server with a certificate that's *not* trusted by the
-//! system, specify the root certificates for the server's chain to the
-//! `ClientBuilder`:
-//!
-//! ```rust,no_run
-//! use std::io::prelude::*;
-//! use std::net::TcpStream;
-//! use security_framework::secure_transport::ClientBuilder;
-//!
-//! # let root_cert = unsafe { std::mem::zeroed() };
-//! let stream = TcpStream::connect("my_server.com:443").unwrap();
-//! let mut stream = ClientBuilder::new()
-//! .anchor_certificates(&[root_cert])
-//! .handshake("my_server.com", stream)
-//! .unwrap();
-//!
-//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
-//! let mut page = vec![];
-//! stream.read_to_end(&mut page).unwrap();
-//! println!("{}", String::from_utf8_lossy(&page));
-//! ```
-//!
-//! For more advanced configuration, the `SslContext` type can be used directly.
-//!
-//! To run a server:
-//!
-//! ```rust,no_run
-//! use std::net::TcpListener;
-//! use std::thread;
-//! use security_framework::secure_transport::{SslContext, SslProtocolSide, SslConnectionType};
-//!
-//! // Create a TCP listener and start accepting on it.
-//! let mut listener = TcpListener::bind("0.0.0.0:443").unwrap();
-//!
-//! for stream in listener.incoming() {
-//! let stream = stream.unwrap();
-//! thread::spawn(move || {
-//! // Create a new context configured to operate on the server side of
-//! // a traditional SSL/TLS session.
-//! let mut ctx = SslContext::new(SslProtocolSide::SERVER, SslConnectionType::STREAM)
-//! .unwrap();
-//!
-//! // Install the certificate chain that we will be using.
-//! # let identity = unsafe { std::mem::zeroed() };
-//! # let intermediate_cert = unsafe { std::mem::zeroed() };
-//! # let root_cert = unsafe { std::mem::zeroed() };
-//! ctx.set_certificate(identity, &[intermediate_cert, root_cert]).unwrap();
-//!
-//! // Perform the SSL/TLS handshake and get our stream.
-//! let mut stream = ctx.handshake(stream).unwrap();
-//! });
-//! }
-//!
-//! ```
-#[allow(unused_imports)]
-use core_foundation::array::{CFArray, CFArrayRef};
-
-use core_foundation::base::{Boolean, TCFType};
-#[cfg(feature = "alpn")]
-use core_foundation::string::CFString;
-use core_foundation_sys::base::{kCFAllocatorDefault, OSStatus};
-use std::os::raw::c_void;
-
-#[allow(unused_imports)]
-use security_framework_sys::base::{
- errSecBadReq, errSecIO, errSecNotTrusted, errSecSuccess, errSecTrustSettingDeny,
- errSecUnimplemented,
-};
-
-use security_framework_sys::secure_transport::*;
-use std::any::Any;
-use std::cmp;
-use std::fmt;
-use std::io;
-use std::io::prelude::*;
-use std::marker::PhantomData;
-use std::panic::{self, AssertUnwindSafe};
-use std::ptr;
-use std::result;
-use std::slice;
-
-use crate::base::{Error, Result};
-use crate::certificate::SecCertificate;
-use crate::cipher_suite::CipherSuite;
-use crate::identity::SecIdentity;
-use crate::import_export::Pkcs12ImportOptions;
-use crate::policy::SecPolicy;
-use crate::trust::SecTrust;
-use crate::{cvt, AsInner};
-use security_framework_sys::base::errSecParam;
-
-/// Specifies a side of a TLS session.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct SslProtocolSide(SSLProtocolSide);
-
-impl SslProtocolSide {
- /// The server side of the session.
- pub const SERVER: Self = Self(kSSLServerSide);
-
- /// The client side of the session.
- pub const CLIENT: Self = Self(kSSLClientSide);
-}
-
-/// Specifies the type of TLS session.
-#[derive(Debug, Copy, Clone)]
-pub struct SslConnectionType(SSLConnectionType);
-
-impl SslConnectionType {
- /// A traditional TLS stream.
- pub const STREAM: Self = Self(kSSLStreamType);
-
- /// A DTLS session.
- pub const DATAGRAM: Self = Self(kSSLDatagramType);
-}
-
-/// An error or intermediate state after a TLS handshake attempt.
-#[derive(Debug)]
-pub enum HandshakeError<S> {
- /// The handshake failed.
- Failure(Error),
- /// The handshake was interrupted midway through.
- Interrupted(MidHandshakeSslStream<S>),
-}
-
-impl<S> From<Error> for HandshakeError<S> {
- #[inline(always)]
- fn from(err: Error) -> Self {
- Self::Failure(err)
- }
-}
-
-/// An error or intermediate state after a TLS handshake attempt.
-#[derive(Debug)]
-pub enum ClientHandshakeError<S> {
- /// The handshake failed.
- Failure(Error),
- /// The handshake was interrupted midway through.
- Interrupted(MidHandshakeClientBuilder<S>),
-}
-
-impl<S> From<Error> for ClientHandshakeError<S> {
- #[inline(always)]
- fn from(err: Error) -> Self {
- Self::Failure(err)
- }
-}
-
-/// An SSL stream midway through the handshake process.
-#[derive(Debug)]
-pub struct MidHandshakeSslStream<S> {
- stream: SslStream<S>,
- error: Error,
-}
-
-impl<S> MidHandshakeSslStream<S> {
- /// Returns a shared reference to the inner stream.
- #[inline(always)]
- #[must_use]
- pub fn get_ref(&self) -> &S {
- self.stream.get_ref()
- }
-
- /// Returns a mutable reference to the inner stream.
- #[inline(always)]
- pub fn get_mut(&mut self) -> &mut S {
- self.stream.get_mut()
- }
-
- /// Returns a shared reference to the `SslContext` of the stream.
- #[inline(always)]
- #[must_use]
- pub fn context(&self) -> &SslContext {
- self.stream.context()
- }
-
- /// Returns a mutable reference to the `SslContext` of the stream.
- #[inline(always)]
- pub fn context_mut(&mut self) -> &mut SslContext {
- self.stream.context_mut()
- }
-
- /// Returns `true` iff `break_on_server_auth` was set and the handshake has
- /// progressed to that point.
- #[inline(always)]
- #[must_use]
- pub fn server_auth_completed(&self) -> bool {
- self.error.code() == errSSLPeerAuthCompleted
- }
-
- /// Returns `true` iff `break_on_cert_requested` was set and the handshake
- /// has progressed to that point.
- #[inline(always)]
- #[must_use]
- pub fn client_cert_requested(&self) -> bool {
- self.error.code() == errSSLClientCertRequested
- }
-
- /// Returns `true` iff the underlying stream returned an error with the
- /// `WouldBlock` kind.
- #[inline(always)]
- #[must_use]
- pub fn would_block(&self) -> bool {
- self.error.code() == errSSLWouldBlock
- }
-
- /// Returns the error which caused the handshake interruption.
- #[inline(always)]
- #[must_use]
- pub fn error(&self) -> &Error {
- &self.error
- }
-
- /// Restarts the handshake process.
- #[inline(always)]
- pub fn handshake(self) -> result::Result<SslStream<S>, HandshakeError<S>> {
- self.stream.handshake()
- }
-}
-
-/// An SSL stream midway through the handshake process.
-#[derive(Debug)]
-pub struct MidHandshakeClientBuilder<S> {
- stream: MidHandshakeSslStream<S>,
- domain: Option<String>,
- certs: Vec<SecCertificate>,
- trust_certs_only: bool,
- danger_accept_invalid_certs: bool,
-}
-
-impl<S> MidHandshakeClientBuilder<S> {
- /// Returns a shared reference to the inner stream.
- #[inline(always)]
- #[must_use]
- pub fn get_ref(&self) -> &S {
- self.stream.get_ref()
- }
-
- /// Returns a mutable reference to the inner stream.
- #[inline(always)]
- pub fn get_mut(&mut self) -> &mut S {
- self.stream.get_mut()
- }
-
- /// Returns the error which caused the handshake interruption.
- #[inline(always)]
- #[must_use]
- pub fn error(&self) -> &Error {
- self.stream.error()
- }
-
- /// Restarts the handshake process.
- pub fn handshake(self) -> result::Result<SslStream<S>, ClientHandshakeError<S>> {
- let MidHandshakeClientBuilder {
- stream,
- domain,
- certs,
- trust_certs_only,
- danger_accept_invalid_certs,
- } = self;
-
- let mut result = stream.handshake();
- loop {
- let stream = match result {
- Ok(stream) => return Ok(stream),
- Err(HandshakeError::Interrupted(stream)) => stream,
- Err(HandshakeError::Failure(err)) => {
- return Err(ClientHandshakeError::Failure(err))
- }
- };
-
- if stream.would_block() {
- let ret = MidHandshakeClientBuilder {
- stream,
- domain,
- certs,
- trust_certs_only,
- danger_accept_invalid_certs,
- };
- return Err(ClientHandshakeError::Interrupted(ret));
- }
-
- if stream.server_auth_completed() {
- if danger_accept_invalid_certs {
- result = stream.handshake();
- continue;
- }
- let mut trust = match stream.context().peer_trust2()? {
- Some(trust) => trust,
- None => {
- result = stream.handshake();
- continue;
- }
- };
- trust.set_anchor_certificates(&certs)?;
- trust.set_trust_anchor_certificates_only(self.trust_certs_only)?;
- let policy = SecPolicy::create_ssl(SslProtocolSide::SERVER, domain.as_deref());
- trust.set_policy(&policy)?;
- trust.evaluate_with_error().map_err(|error| {
- #[cfg(feature = "log")]
- log::warn!("SecTrustEvaluateWithError: {}", error.to_string());
- Error::from_code(error.code() as _)
- })?;
- result = stream.handshake();
- continue;
- }
-
- let err = Error::from_code(stream.error().code());
- return Err(ClientHandshakeError::Failure(err));
- }
- }
-}
-
-/// Specifies the state of a TLS session.
-#[derive(Debug, PartialEq, Eq)]
-pub struct SessionState(SSLSessionState);
-
-impl SessionState {
- /// The session has not yet started.
- pub const IDLE: Self = Self(kSSLIdle);
-
- /// The session is in the handshake process.
- pub const HANDSHAKE: Self = Self(kSSLHandshake);
-
- /// The session is connected.
- pub const CONNECTED: Self = Self(kSSLConnected);
-
- /// The session has been terminated.
- pub const CLOSED: Self = Self(kSSLClosed);
-
- /// The session has been aborted due to an error.
- pub const ABORTED: Self = Self(kSSLAborted);
-}
-
-/// Specifies a server's requirement for client certificates.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct SslAuthenticate(SSLAuthenticate);
-
-impl SslAuthenticate {
- /// Do not request a client certificate.
- pub const NEVER: Self = Self(kNeverAuthenticate);
-
- /// Require a client certificate.
- pub const ALWAYS: Self = Self(kAlwaysAuthenticate);
-
- /// Request but do not require a client certificate.
- pub const TRY: Self = Self(kTryAuthenticate);
-}
-
-/// Specifies the state of client certificate processing.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct SslClientCertificateState(SSLClientCertificateState);
-
-impl SslClientCertificateState {
- /// A client certificate has not been requested or sent.
- pub const NONE: Self = Self(kSSLClientCertNone);
-
- /// A client certificate has been requested but not recieved.
- pub const REQUESTED: Self = Self(kSSLClientCertRequested);
- /// A client certificate has been received and successfully validated.
- pub const SENT: Self = Self(kSSLClientCertSent);
-
- /// A client certificate has been received but has failed to validate.
- pub const REJECTED: Self = Self(kSSLClientCertRejected);
-}
-
-/// Specifies protocol versions.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct SslProtocol(SSLProtocol);
-
-impl SslProtocol {
- /// No protocol has been or should be negotiated or specified; use the default.
- pub const UNKNOWN: Self = Self(kSSLProtocolUnknown);
-
- /// The SSL 3.0 protocol is preferred, though SSL 2.0 may be used if the peer does not support
- /// SSL 3.0.
- pub const SSL3: Self = Self(kSSLProtocol3);
-
- /// The TLS 1.0 protocol is preferred, though lower versions may be used
- /// if the peer does not support TLS 1.0.
- pub const TLS1: Self = Self(kTLSProtocol1);
-
- /// The TLS 1.1 protocol is preferred, though lower versions may be used
- /// if the peer does not support TLS 1.1.
- pub const TLS11: Self = Self(kTLSProtocol11);
-
- /// The TLS 1.2 protocol is preferred, though lower versions may be used
- /// if the peer does not support TLS 1.2.
- pub const TLS12: Self = Self(kTLSProtocol12);
-
- /// The TLS 1.3 protocol is preferred, though lower versions may be used
- /// if the peer does not support TLS 1.3.
- pub const TLS13: Self = Self(kTLSProtocol13);
-
- /// Only the SSL 2.0 protocol is accepted.
- pub const SSL2: Self = Self(kSSLProtocol2);
-
- /// The `DTLSv1` protocol is preferred.
- pub const DTLS1: Self = Self(kDTLSProtocol1);
-
- /// Only the SSL 3.0 protocol is accepted.
- pub const SSL3_ONLY: Self = Self(kSSLProtocol3Only);
-
- /// Only the TLS 1.0 protocol is accepted.
- pub const TLS1_ONLY: Self = Self(kTLSProtocol1Only);
-
- /// All supported TLS/SSL versions are accepted.
- pub const ALL: Self = Self(kSSLProtocolAll);
-}
-
-declare_TCFType! {
- /// A Secure Transport SSL/TLS context object.
- SslContext, SSLContextRef
-}
-
-impl_TCFType!(SslContext, SSLContextRef, SSLContextGetTypeID);
-
-impl fmt::Debug for SslContext {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("SslContext");
- if let Ok(state) = self.state() {
- builder.field("state", &state);
- }
- builder.finish()
- }
-}
-
-unsafe impl Sync for SslContext {}
-unsafe impl Send for SslContext {}
-
-impl AsInner for SslContext {
- type Inner = SSLContextRef;
-
- #[inline(always)]
- fn as_inner(&self) -> SSLContextRef {
- self.0
- }
-}
-
-macro_rules! impl_options {
- ($($(#[$a:meta])* const $opt:ident: $get:ident & $set:ident,)*) => {
- $(
- $(#[$a])*
- #[inline(always)]
- pub fn $set(&mut self, value: bool) -> Result<()> {
- unsafe { cvt(SSLSetSessionOption(self.0, $opt, value as Boolean)) }
- }
-
- $(#[$a])*
- #[inline]
- pub fn $get(&self) -> Result<bool> {
- let mut value = 0;
- unsafe { cvt(SSLGetSessionOption(self.0, $opt, &mut value))?; }
- Ok(value != 0)
- }
- )*
- }
-}
-
-impl SslContext {
- /// Creates a new `SslContext` for the specified side and type of SSL
- /// connection.
- #[inline]
- pub fn new(side: SslProtocolSide, type_: SslConnectionType) -> Result<Self> {
- unsafe {
- let ctx = SSLCreateContext(kCFAllocatorDefault, side.0, type_.0);
- Ok(Self(ctx))
- }
- }
-
- /// Sets the fully qualified domain name of the peer.
- ///
- /// This will be used on the client side of a session to validate the
- /// common name field of the server's certificate. It has no effect if
- /// called on a server-side `SslContext`.
- ///
- /// It is *highly* recommended to call this method before starting the
- /// handshake process.
- #[inline]
- pub fn set_peer_domain_name(&mut self, peer_name: &str) -> Result<()> {
- unsafe {
- // SSLSetPeerDomainName doesn't need a null terminated string
- cvt(SSLSetPeerDomainName(
- self.0,
- peer_name.as_ptr().cast(),
- peer_name.len(),
- ))
- }
- }
-
- /// Returns the peer domain name set by `set_peer_domain_name`.
- pub fn peer_domain_name(&self) -> Result<String> {
- unsafe {
- let mut len = 0;
- cvt(SSLGetPeerDomainNameLength(self.0, &mut len))?;
- let mut buf = vec![0; len];
- cvt(SSLGetPeerDomainName(
- self.0,
- buf.as_mut_ptr().cast(),
- &mut len,
- ))?;
- Ok(String::from_utf8(buf).unwrap())
- }
- }
-
- /// Sets the certificate to be used by this side of the SSL session.
- ///
- /// This must be called before the handshake for server-side connections,
- /// and can be used on the client-side to specify a client certificate.
- ///
- /// The `identity` corresponds to the leaf certificate and private
- /// key, and the `certs` correspond to extra certificates in the chain.
- pub fn set_certificate(
- &mut self,
- identity: &SecIdentity,
- certs: &[SecCertificate],
- ) -> Result<()> {
- let mut arr = vec![identity.as_CFType()];
- arr.extend(certs.iter().map(|c| c.as_CFType()));
- let certs = CFArray::from_CFTypes(&arr);
-
- unsafe { cvt(SSLSetCertificate(self.0, certs.as_concrete_TypeRef())) }
- }
-
- /// Sets the peer ID of this session.
- ///
- /// A peer ID is an opaque sequence of bytes that will be used by Secure
- /// Transport to identify the peer of an SSL session. If the peer ID of
- /// this session matches that of a previously terminated session, the
- /// previous session can be resumed without requiring a full handshake.
- #[inline]
- pub fn set_peer_id(&mut self, peer_id: &[u8]) -> Result<()> {
- unsafe { cvt(SSLSetPeerID(self.0, peer_id.as_ptr().cast(), peer_id.len())) }
- }
-
- /// Returns the peer ID of this session.
- pub fn peer_id(&self) -> Result<Option<&[u8]>> {
- unsafe {
- let mut ptr = ptr::null();
- let mut len = 0;
- cvt(SSLGetPeerID(self.0, &mut ptr, &mut len))?;
- if ptr.is_null() {
- Ok(None)
- } else {
- Ok(Some(slice::from_raw_parts(ptr.cast(), len)))
- }
- }
- }
-
- /// Returns the list of ciphers that are supported by Secure Transport.
- pub fn supported_ciphers(&self) -> Result<Vec<CipherSuite>> {
- unsafe {
- let mut num_ciphers = 0;
- cvt(SSLGetNumberSupportedCiphers(self.0, &mut num_ciphers))?;
- let mut ciphers = vec![0; num_ciphers];
- cvt(SSLGetSupportedCiphers(
- self.0,
- ciphers.as_mut_ptr(),
- &mut num_ciphers,
- ))?;
- Ok(ciphers.iter().map(|c| CipherSuite::from_raw(*c)).collect())
- }
- }
-
- /// Returns the list of ciphers that are eligible to be used for
- /// negotiation.
- pub fn enabled_ciphers(&self) -> Result<Vec<CipherSuite>> {
- unsafe {
- let mut num_ciphers = 0;
- cvt(SSLGetNumberEnabledCiphers(self.0, &mut num_ciphers))?;
- let mut ciphers = vec![0; num_ciphers];
- cvt(SSLGetEnabledCiphers(
- self.0,
- ciphers.as_mut_ptr(),
- &mut num_ciphers,
- ))?;
- Ok(ciphers.iter().map(|c| CipherSuite::from_raw(*c)).collect())
- }
- }
-
- /// Sets the list of ciphers that are eligible to be used for negotiation.
- pub fn set_enabled_ciphers(&mut self, ciphers: &[CipherSuite]) -> Result<()> {
- let ciphers = ciphers.iter().map(|c| c.to_raw()).collect::<Vec<_>>();
- unsafe {
- cvt(SSLSetEnabledCiphers(
- self.0,
- ciphers.as_ptr(),
- ciphers.len(),
- ))
- }
- }
-
- /// Returns the cipher being used by the session.
- #[inline]
- pub fn negotiated_cipher(&self) -> Result<CipherSuite> {
- unsafe {
- let mut cipher = 0;
- cvt(SSLGetNegotiatedCipher(self.0, &mut cipher))?;
- Ok(CipherSuite::from_raw(cipher))
- }
- }
-
- /// Sets the requirements for client certificates.
- ///
- /// Should only be called on server-side sessions.
- #[inline]
- pub fn set_client_side_authenticate(&mut self, auth: SslAuthenticate) -> Result<()> {
- unsafe { cvt(SSLSetClientSideAuthenticate(self.0, auth.0)) }
- }
-
- /// Returns the state of client certificate processing.
- #[inline]
- pub fn client_certificate_state(&self) -> Result<SslClientCertificateState> {
- let mut state = 0;
-
- unsafe {
- cvt(SSLGetClientCertificateState(self.0, &mut state))?;
- }
- Ok(SslClientCertificateState(state))
- }
-
- /// Returns the `SecTrust` object corresponding to the peer.
- ///
- /// This can be used in conjunction with `set_break_on_server_auth` to
- /// validate certificates which do not have roots in the default set.
- pub fn peer_trust2(&self) -> Result<Option<SecTrust>> {
- // Calling SSLCopyPeerTrust on an idle connection does not seem to be well defined,
- // so explicitly check for that
- if self.state()? == SessionState::IDLE {
- return Err(Error::from_code(errSecBadReq));
- }
-
- unsafe {
- let mut trust = ptr::null_mut();
- cvt(SSLCopyPeerTrust(self.0, &mut trust))?;
- if trust.is_null() {
- Ok(None)
- } else {
- Ok(Some(SecTrust::wrap_under_create_rule(trust)))
- }
- }
- }
-
- /// Returns the state of the session.
- #[inline]
- pub fn state(&self) -> Result<SessionState> {
- unsafe {
- let mut state = 0;
- cvt(SSLGetSessionState(self.0, &mut state))?;
- Ok(SessionState(state))
- }
- }
-
- /// Returns the protocol version being used by the session.
- #[inline]
- pub fn negotiated_protocol_version(&self) -> Result<SslProtocol> {
- unsafe {
- let mut version = 0;
- cvt(SSLGetNegotiatedProtocolVersion(self.0, &mut version))?;
- Ok(SslProtocol(version))
- }
- }
-
- /// Returns the maximum protocol version allowed by the session.
- #[inline]
- pub fn protocol_version_max(&self) -> Result<SslProtocol> {
- unsafe {
- let mut version = 0;
- cvt(SSLGetProtocolVersionMax(self.0, &mut version))?;
- Ok(SslProtocol(version))
- }
- }
-
- /// Sets the maximum protocol version allowed by the session.
- #[inline]
- pub fn set_protocol_version_max(&mut self, max_version: SslProtocol) -> Result<()> {
- unsafe { cvt(SSLSetProtocolVersionMax(self.0, max_version.0)) }
- }
-
- /// Returns the minimum protocol version allowed by the session.
- #[inline]
- pub fn protocol_version_min(&self) -> Result<SslProtocol> {
- unsafe {
- let mut version = 0;
- cvt(SSLGetProtocolVersionMin(self.0, &mut version))?;
- Ok(SslProtocol(version))
- }
- }
-
- /// Sets the minimum protocol version allowed by the session.
- #[inline]
- pub fn set_protocol_version_min(&mut self, min_version: SslProtocol) -> Result<()> {
- unsafe { cvt(SSLSetProtocolVersionMin(self.0, min_version.0)) }
- }
-
- /// Returns the set of protocols selected via ALPN if it succeeded.
- #[cfg(feature = "alpn")]
- pub fn alpn_protocols(&self) -> Result<Vec<String>> {
- let mut array: CFArrayRef = ptr::null();
- unsafe {
- #[cfg(feature = "OSX_10_13")]
- {
- cvt(SSLCopyALPNProtocols(self.0, &mut array))?;
- }
-
- #[cfg(not(feature = "OSX_10_13"))]
- {
- dlsym! { fn SSLCopyALPNProtocols(SSLContextRef, *mut CFArrayRef) -> OSStatus }
- if let Some(f) = SSLCopyALPNProtocols.get() {
- cvt(f(self.0, &mut array))?;
- } else {
- return Err(Error::from_code(errSecUnimplemented));
- }
- }
-
- if array.is_null() {
- return Ok(vec![]);
- }
-
- let array = CFArray::<CFString>::wrap_under_create_rule(array);
- Ok(array.into_iter().map(|p| p.to_string()).collect())
- }
- }
-
- /// Configures the set of protocols use for ALPN.
- ///
- /// This is only used for client-side connections.
- #[cfg(feature = "alpn")]
- pub fn set_alpn_protocols(&mut self, protocols: &[&str]) -> Result<()> {
- // When CFMutableArray is added to core-foundation and IntoIterator trait
- // is implemented for CFMutableArray, the code below should directly collect
- // into a CFMutableArray.
- let protocols = CFArray::from_CFTypes(
- &protocols
- .iter()
- .map(|proto| CFString::new(proto))
- .collect::<Vec<_>>(),
- );
-
- #[cfg(feature = "OSX_10_13")]
- {
- unsafe { cvt(SSLSetALPNProtocols(self.0, protocols.as_concrete_TypeRef())) }
- }
- #[cfg(not(feature = "OSX_10_13"))]
- {
- dlsym! { fn SSLSetALPNProtocols(SSLContextRef, CFArrayRef) -> OSStatus }
- if let Some(f) = SSLSetALPNProtocols.get() {
- unsafe { cvt(f(self.0, protocols.as_concrete_TypeRef())) }
- } else {
- Err(Error::from_code(errSecUnimplemented))
- }
- }
- }
-
- /// Sets whether the client sends the `SessionTicket` extension in its `ClientHello`.
- ///
- /// On its own, this will just cause the client to send an empty `SessionTicket` extension on
- /// every connection. [`SslContext::set_peer_id`] must also be used to key the session
- /// ticket returned by the server.
- ///
- /// [`SslContext::set_peer_id`]: #method.set_peer_id
- #[cfg(feature = "session-tickets")]
- pub fn set_session_tickets_enabled(&mut self, enabled: bool) -> Result<()> {
- #[cfg(feature = "OSX_10_13")]
- {
- unsafe { cvt(SSLSetSessionTicketsEnabled(self.0, enabled as Boolean)) }
- }
- #[cfg(not(feature = "OSX_10_13"))]
- {
- dlsym! { fn SSLSetSessionTicketsEnabled(SSLContextRef, Boolean) -> OSStatus }
- if let Some(f) = SSLSetSessionTicketsEnabled.get() {
- unsafe { cvt(f(self.0, enabled as Boolean)) }
- } else {
- Err(Error::from_code(errSecUnimplemented))
- }
- }
- }
-
- /// Sets whether a protocol is enabled or not.
- ///
- /// # Note
- ///
- /// On OSX this is a deprecated API in favor of `set_protocol_version_max` and
- /// `set_protocol_version_min`, although if you're working with OSX 10.8 or before you may have
- /// to use this API instead.
- #[cfg(target_os = "macos")]
- #[deprecated(note = "use `set_protocol_version_max`")]
- pub fn set_protocol_version_enabled(
- &mut self,
- protocol: SslProtocol,
- enabled: bool,
- ) -> Result<()> {
- unsafe {
- cvt(SSLSetProtocolVersionEnabled(
- self.0,
- protocol.0,
- Boolean::from(enabled),
- ))
- }
- }
-
- /// Returns the number of bytes which can be read without triggering a
- /// `read` call in the underlying stream.
- #[inline]
- pub fn buffered_read_size(&self) -> Result<usize> {
- unsafe {
- let mut size = 0;
- cvt(SSLGetBufferedReadSize(self.0, &mut size))?;
- Ok(size)
- }
- }
-
- impl_options! {
- /// If enabled, the handshake process will pause and return instead of
- /// automatically validating a server's certificate.
- const kSSLSessionOptionBreakOnServerAuth: break_on_server_auth & set_break_on_server_auth,
- /// If enabled, the handshake process will pause and return after
- /// the server requests a certificate from the client.
- const kSSLSessionOptionBreakOnCertRequested: break_on_cert_requested & set_break_on_cert_requested,
- /// If enabled, the handshake process will pause and return instead of
- /// automatically validating a client's certificate.
- const kSSLSessionOptionBreakOnClientAuth: break_on_client_auth & set_break_on_client_auth,
- /// If enabled, TLS false start will be performed if an appropriate
- /// cipher suite is negotiated.
- ///
- const kSSLSessionOptionFalseStart: false_start & set_false_start,
- /// If enabled, 1/n-1 record splitting will be enabled for TLS 1.0
- /// connections using block ciphers to mitigate the BEAST attack.
- ///
- const kSSLSessionOptionSendOneByteRecord: send_one_byte_record & set_send_one_byte_record,
- }
-
- fn into_stream<S>(self, stream: S) -> Result<SslStream<S>>
- where
- S: Read + Write,
- {
- unsafe {
- let ret = SSLSetIOFuncs(self.0, read_func::<S>, write_func::<S>);
- if ret != errSecSuccess {
- return Err(Error::from_code(ret));
- }
-
- let stream = Connection {
- stream,
- err: None,
- panic: None,
- };
- let stream = Box::into_raw(Box::new(stream));
- let ret = SSLSetConnection(self.0, stream.cast());
- if ret != errSecSuccess {
- let _conn = Box::from_raw(stream);
- return Err(Error::from_code(ret));
- }
-
- Ok(SslStream {
- ctx: self,
- _m: PhantomData,
- })
- }
- }
-
- /// Performs the SSL/TLS handshake.
- pub fn handshake<S>(self, stream: S) -> result::Result<SslStream<S>, HandshakeError<S>>
- where
- S: Read + Write,
- {
- self.into_stream(stream)
- .map_err(HandshakeError::Failure)
- .and_then(SslStream::handshake)
- }
-}
-
-struct Connection<S> {
- stream: S,
- err: Option<io::Error>,
- panic: Option<Box<dyn Any + Send>>,
-}
-
-// the logic here is based off of libcurl's
-#[cold]
-fn translate_err(e: &io::Error) -> OSStatus {
- match e.kind() {
- io::ErrorKind::NotFound => errSSLClosedGraceful,
- io::ErrorKind::ConnectionReset => errSSLClosedAbort,
- io::ErrorKind::WouldBlock |
- io::ErrorKind::NotConnected => errSSLWouldBlock,
- _ => errSecIO,
- }
-}
-
-unsafe extern "C" fn read_func<S>(
- connection: SSLConnectionRef,
- data: *mut c_void,
- data_length: *mut usize,
-) -> OSStatus
-where
- S: Read,
-{
- let conn: &mut Connection<S> = &mut *(connection as *mut _);
- let data = slice::from_raw_parts_mut(data.cast::<u8>(), *data_length);
- let mut start = 0;
- let mut ret = errSecSuccess;
-
- while start < data.len() {
- match panic::catch_unwind(AssertUnwindSafe(|| conn.stream.read(&mut data[start..]))) {
- Ok(Ok(0)) => {
- ret = errSSLClosedNoNotify;
- break;
- }
- Ok(Ok(len)) => start += len,
- Ok(Err(e)) => {
- ret = translate_err(&e);
- conn.err = Some(e);
- break;
- }
- Err(e) => {
- ret = errSecIO;
- conn.panic = Some(e);
- break;
- }
- }
- }
-
- *data_length = start;
- ret
-}
-
-unsafe extern "C" fn write_func<S>(
- connection: SSLConnectionRef,
- data: *const c_void,
- data_length: *mut usize,
-) -> OSStatus
-where
- S: Write,
-{
- let conn: &mut Connection<S> = &mut *(connection as *mut _);
- let data = slice::from_raw_parts(data as *mut u8, *data_length);
- let mut start = 0;
- let mut ret = errSecSuccess;
-
- while start < data.len() {
- match panic::catch_unwind(AssertUnwindSafe(|| conn.stream.write(&data[start..]))) {
- Ok(Ok(0)) => {
- ret = errSSLClosedNoNotify;
- break;
- }
- Ok(Ok(len)) => start += len,
- Ok(Err(e)) => {
- ret = translate_err(&e);
- conn.err = Some(e);
- break;
- }
- Err(e) => {
- ret = errSecIO;
- conn.panic = Some(e);
- break;
- }
- }
- }
-
- *data_length = start;
- ret
-}
-
-/// A type implementing SSL/TLS encryption over an underlying stream.
-pub struct SslStream<S> {
- ctx: SslContext,
- _m: PhantomData<S>,
-}
-
-impl<S: fmt::Debug> fmt::Debug for SslStream<S> {
- #[cold]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.debug_struct("SslStream")
- .field("context", &self.ctx)
- .field("stream", self.get_ref())
- .finish()
- }
-}
-
-impl<S> Drop for SslStream<S> {
- fn drop(&mut self) {
- unsafe {
- let mut conn = ptr::null();
- let ret = SSLGetConnection(self.ctx.0, &mut conn);
- assert!(ret == errSecSuccess);
- let _ = Box::<Connection<S>>::from_raw(conn as *mut _);
- }
- }
-}
-
-impl<S> SslStream<S> {
- fn handshake(mut self) -> result::Result<Self, HandshakeError<S>> {
- match unsafe { SSLHandshake(self.ctx.0) } {
- errSecSuccess => Ok(self),
- reason @ errSSLPeerAuthCompleted
- | reason @ errSSLClientCertRequested
- | reason @ errSSLWouldBlock
- | reason @ errSSLClientHelloReceived => {
- Err(HandshakeError::Interrupted(MidHandshakeSslStream {
- stream: self,
- error: Error::from_code(reason),
- }))
- }
- err => {
- self.check_panic();
- Err(HandshakeError::Failure(Error::from_code(err)))
- }
- }
- }
-
- /// Returns a shared reference to the inner stream.
- #[inline(always)]
- #[must_use]
- pub fn get_ref(&self) -> &S {
- &self.connection().stream
- }
-
- /// Returns a mutable reference to the underlying stream.
- #[inline(always)]
- pub fn get_mut(&mut self) -> &mut S {
- &mut self.connection_mut().stream
- }
-
- /// Returns a shared reference to the `SslContext` of the stream.
- #[inline(always)]
- #[must_use]
- pub fn context(&self) -> &SslContext {
- &self.ctx
- }
-
- /// Returns a mutable reference to the `SslContext` of the stream.
- #[inline(always)]
- pub fn context_mut(&mut self) -> &mut SslContext {
- &mut self.ctx
- }
-
- /// Shuts down the connection.
- pub fn close(&mut self) -> result::Result<(), io::Error> {
- unsafe {
- let ret = SSLClose(self.ctx.0);
- if ret == errSecSuccess {
- Ok(())
- } else {
- Err(self.get_error(ret))
- }
- }
- }
-
- fn connection(&self) -> &Connection<S> {
- unsafe {
- let mut conn = ptr::null();
- let ret = SSLGetConnection(self.ctx.0, &mut conn);
- assert!(ret == errSecSuccess);
-
- &mut *(conn as *mut Connection<S>)
- }
- }
-
- fn connection_mut(&mut self) -> &mut Connection<S> {
- unsafe {
- let mut conn = ptr::null();
- let ret = SSLGetConnection(self.ctx.0, &mut conn);
- assert!(ret == errSecSuccess);
-
- &mut *(conn as *mut Connection<S>)
- }
- }
-
- #[cold]
- fn check_panic(&mut self) {
- let conn = self.connection_mut();
- if let Some(err) = conn.panic.take() {
- panic::resume_unwind(err);
- }
- }
-
- #[cold]
- fn get_error(&mut self, ret: OSStatus) -> io::Error {
- self.check_panic();
-
- if let Some(err) = self.connection_mut().err.take() {
- err
- } else {
- io::Error::new(io::ErrorKind::Other, Error::from_code(ret))
- }
- }
-}
-
-impl<S: Read + Write> Read for SslStream<S> {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- // Below we base our return value off the amount of data read, so a
- // zero-length buffer might cause us to erroneously interpret this
- // request as an error. Instead short-circuit that logic and return
- // `Ok(0)` instead.
- if buf.is_empty() {
- return Ok(0);
- }
-
- // If some data was buffered but not enough to fill `buf`, SSLRead
- // will try to read a new packet. This is bad because there may be
- // no more data but the socket is remaining open (e.g HTTPS with
- // Connection: keep-alive).
- let buffered = self.context().buffered_read_size().unwrap_or(0);
- let to_read = if buffered > 0 {
- cmp::min(buffered, buf.len())
- } else {
- buf.len()
- };
-
- unsafe {
- let mut nread = 0;
- let ret = SSLRead(self.ctx.0, buf.as_mut_ptr().cast(), to_read, &mut nread);
- // SSLRead can return an error at the same time it returns the last
- // chunk of data (!)
- if nread > 0 {
- return Ok(nread);
- }
-
- match ret {
- errSSLClosedGraceful | errSSLClosedAbort | errSSLClosedNoNotify => Ok(0),
- // this error isn't fatal
- errSSLPeerAuthCompleted => self.read(buf),
- _ => Err(self.get_error(ret)),
- }
- }
- }
-}
-
-impl<S: Read + Write> Write for SslStream<S> {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- // Like above in read, short circuit a 0-length write
- if buf.is_empty() {
- return Ok(0);
- }
- unsafe {
- let mut nwritten = 0;
- let ret = SSLWrite(
- self.ctx.0,
- buf.as_ptr().cast(),
- buf.len(),
- &mut nwritten,
- );
- // just to be safe, base success off of nwritten rather than ret
- // for the same reason as in read
- if nwritten > 0 {
- Ok(nwritten)
- } else {
- Err(self.get_error(ret))
- }
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- self.connection_mut().stream.flush()
- }
-}
-
-/// A builder type to simplify the creation of client side `SslStream`s.
-#[derive(Debug)]
-pub struct ClientBuilder {
- identity: Option<SecIdentity>,
- certs: Vec<SecCertificate>,
- chain: Vec<SecCertificate>,
- protocol_min: Option<SslProtocol>,
- protocol_max: Option<SslProtocol>,
- trust_certs_only: bool,
- use_sni: bool,
- danger_accept_invalid_certs: bool,
- danger_accept_invalid_hostnames: bool,
- whitelisted_ciphers: Vec<CipherSuite>,
- blacklisted_ciphers: Vec<CipherSuite>,
- #[cfg(feature = "alpn")]
- alpn: Option<Vec<String>>,
- #[cfg(feature = "session-tickets")]
- enable_session_tickets: bool,
-}
-
-impl Default for ClientBuilder {
- #[inline(always)]
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl ClientBuilder {
- /// Creates a new builder with default options.
- #[inline]
- #[must_use]
- pub fn new() -> Self {
- Self {
- identity: None,
- certs: Vec::new(),
- chain: Vec::new(),
- protocol_min: None,
- protocol_max: None,
- trust_certs_only: false,
- use_sni: true,
- danger_accept_invalid_certs: false,
- danger_accept_invalid_hostnames: false,
- whitelisted_ciphers: Vec::new(),
- blacklisted_ciphers: Vec::new(),
- #[cfg(feature = "alpn")]
- alpn: None,
- #[cfg(feature = "session-tickets")]
- enable_session_tickets: false,
- }
- }
-
- /// Specifies the set of root certificates to trust when
- /// verifying the server's certificate.
- #[inline]
- pub fn anchor_certificates(&mut self, certs: &[SecCertificate]) -> &mut Self {
- self.certs = certs.to_owned();
- self
- }
-
- /// Add the certificate the set of root certificates to trust
- /// when verifying the server's certificate.
- #[inline]
- pub fn add_anchor_certificate(&mut self, certs: &SecCertificate) -> &mut Self {
- self.certs.push(certs.to_owned());
- self
- }
-
- /// Specifies whether to trust the built-in certificates in addition
- /// to specified anchor certificates.
- #[inline(always)]
- pub fn trust_anchor_certificates_only(&mut self, only: bool) -> &mut Self {
- self.trust_certs_only = only;
- self
- }
-
- /// Specifies whether to trust invalid certificates.
- ///
- /// # Warning
- ///
- /// You should think very carefully before using this method. If invalid
- /// certificates are trusted, *any* certificate for *any* site will be
- /// trusted for use. This includes expired certificates. This introduces
- /// significant vulnerabilities, and should only be used as a last resort.
- #[inline(always)]
- pub fn danger_accept_invalid_certs(&mut self, noverify: bool) -> &mut Self {
- self.danger_accept_invalid_certs = noverify;
- self
- }
-
- /// Specifies whether to use Server Name Indication (SNI).
- #[inline(always)]
- pub fn use_sni(&mut self, use_sni: bool) -> &mut Self {
- self.use_sni = use_sni;
- self
- }
-
- /// Specifies whether to verify that the server's hostname matches its certificate.
- ///
- /// # Warning
- ///
- /// You should think very carefully before using this method. If hostnames are not verified,
- /// *any* valid certificate for *any* site will be trusted for use. This introduces significant
- /// vulnerabilities, and should only be used as a last resort.
- #[inline(always)]
- pub fn danger_accept_invalid_hostnames(
- &mut self,
- danger_accept_invalid_hostnames: bool,
- ) -> &mut Self {
- self.danger_accept_invalid_hostnames = danger_accept_invalid_hostnames;
- self
- }
-
- /// Set a whitelist of enabled ciphers. Any ciphers not whitelisted will be disabled.
- pub fn whitelist_ciphers(&mut self, whitelisted_ciphers: &[CipherSuite]) -> &mut Self {
- self.whitelisted_ciphers = whitelisted_ciphers.to_owned();
- self
- }
-
- /// Set a blacklist of disabled ciphers. Blacklisted ciphers will be disabled.
- pub fn blacklist_ciphers(&mut self, blacklisted_ciphers: &[CipherSuite]) -> &mut Self {
- self.blacklisted_ciphers = blacklisted_ciphers.to_owned();
- self
- }
-
- /// Use the specified identity as a SSL/TLS client certificate.
- pub fn identity(&mut self, identity: &SecIdentity, chain: &[SecCertificate]) -> &mut Self {
- self.identity = Some(identity.clone());
- self.chain = chain.to_owned();
- self
- }
-
- /// Configure the minimum protocol that this client will support.
- #[inline(always)]
- pub fn protocol_min(&mut self, min: SslProtocol) -> &mut Self {
- self.protocol_min = Some(min);
- self
- }
-
- /// Configure the minimum protocol that this client will support.
- #[inline(always)]
- pub fn protocol_max(&mut self, max: SslProtocol) -> &mut Self {
- self.protocol_max = Some(max);
- self
- }
-
- /// Configures the set of protocols used for ALPN.
- #[cfg(feature = "alpn")]
- pub fn alpn_protocols(&mut self, protocols: &[&str]) -> &mut Self {
- self.alpn = Some(protocols.iter().map(|s| s.to_string()).collect());
- self
- }
-
- /// Configures the use of the RFC 5077 `SessionTicket` extension.
- ///
- /// Defaults to `false`.
- #[cfg(feature = "session-tickets")]
- #[inline(always)]
- pub fn enable_session_tickets(&mut self, enable: bool) -> &mut Self {
- self.enable_session_tickets = enable;
- self
- }
-
- /// Initiates a new SSL/TLS session over a stream connected to the specified domain.
- ///
- /// If both SNI and hostname verification are disabled, the value of `domain` will be ignored.
- pub fn handshake<S>(
- &self,
- domain: &str,
- stream: S,
- ) -> result::Result<SslStream<S>, ClientHandshakeError<S>>
- where
- S: Read + Write,
- {
- // the logic for trust validation is in MidHandshakeClientBuilder::connect, so run all
- // of the handshake logic through that.
- let stream = MidHandshakeSslStream {
- stream: self.ctx_into_stream(domain, stream)?,
- error: Error::from(errSecSuccess),
- };
-
- let certs = self.certs.clone();
- let stream = MidHandshakeClientBuilder {
- stream,
- domain: if self.danger_accept_invalid_hostnames {
- None
- } else {
- Some(domain.to_string())
- },
- certs,
- trust_certs_only: self.trust_certs_only,
- danger_accept_invalid_certs: self.danger_accept_invalid_certs,
- };
- stream.handshake()
- }
-
- fn ctx_into_stream<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>>
- where
- S: Read + Write,
- {
- let mut ctx = SslContext::new(SslProtocolSide::CLIENT, SslConnectionType::STREAM)?;
-
- if self.use_sni {
- ctx.set_peer_domain_name(domain)?;
- }
- if let Some(ref identity) = self.identity {
- ctx.set_certificate(identity, &self.chain)?;
- }
- #[cfg(feature = "alpn")]
- {
- if let Some(ref alpn) = self.alpn {
- ctx.set_alpn_protocols(&alpn.iter().map(|s| &**s).collect::<Vec<_>>())?;
- }
- }
- #[cfg(feature = "session-tickets")]
- {
- if self.enable_session_tickets {
- // We must use the domain here to ensure that we go through certificate validation
- // again rather than resuming the session if the domain changes.
- ctx.set_peer_id(domain.as_bytes())?;
- ctx.set_session_tickets_enabled(true)?;
- }
- }
- ctx.set_break_on_server_auth(true)?;
- self.configure_protocols(&mut ctx)?;
- self.configure_ciphers(&mut ctx)?;
-
- ctx.into_stream(stream)
- }
-
- fn configure_protocols(&self, ctx: &mut SslContext) -> Result<()> {
- if let Some(min) = self.protocol_min {
- ctx.set_protocol_version_min(min)?;
- }
- if let Some(max) = self.protocol_max {
- ctx.set_protocol_version_max(max)?;
- }
- Ok(())
- }
-
- fn configure_ciphers(&self, ctx: &mut SslContext) -> Result<()> {
- let mut ciphers = if self.whitelisted_ciphers.is_empty() {
- ctx.enabled_ciphers()?
- } else {
- self.whitelisted_ciphers.clone()
- };
-
- if !self.blacklisted_ciphers.is_empty() {
- ciphers.retain(|cipher| !self.blacklisted_ciphers.contains(cipher));
- }
-
- ctx.set_enabled_ciphers(&ciphers)?;
- Ok(())
- }
-}
-
-/// A builder type to simplify the creation of server-side `SslStream`s.
-#[derive(Debug)]
-pub struct ServerBuilder {
- identity: SecIdentity,
- certs: Vec<SecCertificate>,
-}
-
-impl ServerBuilder {
- /// Creates a new `ServerBuilder` which will use the specified identity
- /// and certificate chain for handshakes.
- #[must_use]
- pub fn new(identity: &SecIdentity, certs: &[SecCertificate]) -> Self {
- Self {
- identity: identity.clone(),
- certs: certs.to_owned(),
- }
- }
-
- /// Creates a new `ServerBuilder` which will use the identity
- /// from the given PKCS #12 data.
- ///
- /// This operation fails if PKCS #12 file contains zero or more than one identity.
- ///
- /// This is a shortcut for the most common operation.
- pub fn from_pkcs12(pkcs12_der: &[u8], passphrase: &str) -> Result<Self> {
- let mut identities: Vec<(SecIdentity, Vec<SecCertificate>)> = Pkcs12ImportOptions::new()
- .passphrase(passphrase)
- .import(pkcs12_der)?
- .into_iter()
- .filter_map(|idendity| {
- let certs = idendity.cert_chain.unwrap_or_default();
- idendity.identity.map(|identity| (identity, certs))
- })
- .collect();
- if identities.len() == 1 {
- let (identity, certs) = identities.pop().unwrap();
- Ok(ServerBuilder::new(&identity, &certs))
- } else {
- // This error code is not really helpful
- Err(Error::from_code(errSecParam))
- }
- }
-
- /// Create a SSL context for lower-level stream initialization.
- pub fn new_ssl_context(&self) -> Result<SslContext> {
- let mut ctx = SslContext::new(SslProtocolSide::SERVER, SslConnectionType::STREAM)?;
- ctx.set_certificate(&self.identity, &self.certs)?;
- Ok(ctx)
- }
-
- /// Initiates a new SSL/TLS session over a stream.
- pub fn handshake<S>(&self, stream: S) -> Result<SslStream<S>>
- where
- S: Read + Write,
- {
- match self.new_ssl_context()?.handshake(stream) {
- Ok(stream) => Ok(stream),
- Err(HandshakeError::Interrupted(stream)) => Err(*stream.error()),
- Err(HandshakeError::Failure(err)) => Err(err),
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::io::prelude::*;
- use std::net::TcpStream;
-
- use super::*;
-
- #[test]
- fn server_builder_from_pkcs12() {
- let pkcs12_der = include_bytes!("../test/server.p12");
- ServerBuilder::from_pkcs12(pkcs12_der, "password123").unwrap();
- }
-
- #[test]
- fn connect() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- p!(ctx.handshake(stream));
- }
-
- #[test]
- fn connect_bad_domain() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("foobar.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- match ctx.handshake(stream) {
- Ok(_) => panic!("expected failure"),
- Err(_) => {}
- }
- }
-
- #[test]
- fn load_page() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- let mut stream = p!(ctx.handshake(stream));
- p!(stream.write_all(b"GET / HTTP/1.0\r\n\r\n"));
- p!(stream.flush());
- let mut buf = vec![];
- p!(stream.read_to_end(&mut buf));
- println!("{}", String::from_utf8_lossy(&buf));
- }
-
- #[test]
- fn client_no_session_ticket_resumption() {
- for _ in 0..2 {
- let stream = p!(TcpStream::connect("google.com:443"));
-
- // Manually handshake here.
- let stream = MidHandshakeSslStream {
- stream: ClientBuilder::new()
- .ctx_into_stream("google.com", stream)
- .unwrap(),
- error: Error::from(errSecSuccess),
- };
-
- let mut result = stream.handshake();
-
- if let Err(HandshakeError::Interrupted(stream)) = result {
- assert!(stream.server_auth_completed());
- result = stream.handshake();
- } else {
- panic!("Unexpectedly skipped server auth");
- }
-
- assert!(result.is_ok());
- }
- }
-
- #[test]
- #[cfg(feature = "session-tickets")]
- fn client_session_ticket_resumption() {
- // The first time through this loop, we should do a full handshake. The second time, we
- // should immediately finish the handshake without breaking on server auth.
- for i in 0..2 {
- let stream = p!(TcpStream::connect("google.com:443"));
- let mut builder = ClientBuilder::new();
- builder.enable_session_tickets(true);
-
- // Manually handshake here.
- let stream = MidHandshakeSslStream {
- stream: builder.ctx_into_stream("google.com", stream).unwrap(),
- error: Error::from(errSecSuccess),
- };
-
- let mut result = stream.handshake();
-
- if let Err(HandshakeError::Interrupted(stream)) = result {
- assert!(stream.server_auth_completed());
- assert_eq!(
- i, 0,
- "Session ticket resumption did not work, server auth was not skipped"
- );
- result = stream.handshake();
- } else {
- assert_eq!(i, 1, "Unexpectedly skipped server auth");
- }
-
- assert!(result.is_ok());
- }
- }
-
- #[test]
- #[cfg(feature = "alpn")]
- fn client_alpn_accept() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- p!(ctx.set_alpn_protocols(&vec!["h2"]));
- let stream = p!(TcpStream::connect("google.com:443"));
- let stream = ctx.handshake(stream).unwrap();
- assert_eq!(vec!["h2"], stream.context().alpn_protocols().unwrap());
- }
-
- #[test]
- #[cfg(feature = "alpn")]
- fn client_alpn_reject() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- p!(ctx.set_alpn_protocols(&vec!["h2c"]));
- let stream = p!(TcpStream::connect("google.com:443"));
- let stream = ctx.handshake(stream).unwrap();
- assert!(stream.context().alpn_protocols().is_err());
- }
-
- #[test]
- fn client_no_anchor_certs() {
- let stream = p!(TcpStream::connect("google.com:443"));
- assert!(ClientBuilder::new()
- .trust_anchor_certificates_only(true)
- .handshake("google.com", stream)
- .is_err());
- }
-
- #[test]
- fn client_bad_domain() {
- let stream = p!(TcpStream::connect("google.com:443"));
- assert!(ClientBuilder::new()
- .handshake("foobar.com", stream)
- .is_err());
- }
-
- #[test]
- fn client_bad_domain_ignored() {
- let stream = p!(TcpStream::connect("google.com:443"));
- ClientBuilder::new()
- .danger_accept_invalid_hostnames(true)
- .handshake("foobar.com", stream)
- .unwrap();
- }
-
- #[test]
- fn connect_no_verify_ssl() {
- let stream = p!(TcpStream::connect("expired.badssl.com:443"));
- let mut builder = ClientBuilder::new();
- builder.danger_accept_invalid_certs(true);
- builder.handshake("expired.badssl.com", stream).unwrap();
- }
-
- #[test]
- fn load_page_client() {
- let stream = p!(TcpStream::connect("google.com:443"));
- let mut stream = p!(ClientBuilder::new().handshake("google.com", stream));
- p!(stream.write_all(b"GET / HTTP/1.0\r\n\r\n"));
- p!(stream.flush());
- let mut buf = vec![];
- p!(stream.read_to_end(&mut buf));
- println!("{}", String::from_utf8_lossy(&buf));
- }
-
- #[test]
- #[cfg_attr(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"), ignore)] // FIXME what's going on with ios?
- fn cipher_configuration() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- let ciphers = p!(ctx.enabled_ciphers());
- let ciphers = ciphers
- .iter()
- .enumerate()
- .filter_map(|(i, c)| if i % 2 == 0 { Some(*c) } else { None })
- .collect::<Vec<_>>();
- p!(ctx.set_enabled_ciphers(&ciphers));
- assert_eq!(ciphers, p!(ctx.enabled_ciphers()));
- }
-
- #[test]
- fn test_builder_whitelist_ciphers() {
- let stream = p!(TcpStream::connect("google.com:443"));
-
- let ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- assert!(p!(ctx.enabled_ciphers()).len() > 1);
-
- let ciphers = p!(ctx.enabled_ciphers());
- let cipher = ciphers.first().unwrap();
- let stream = p!(ClientBuilder::new()
- .whitelist_ciphers(&[*cipher])
- .ctx_into_stream("google.com", stream));
-
- assert_eq!(1, p!(stream.context().enabled_ciphers()).len());
- }
-
- #[test]
- #[cfg_attr(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"), ignore)] // FIXME same issue as cipher_configuration
- fn test_builder_blacklist_ciphers() {
- let stream = p!(TcpStream::connect("google.com:443"));
-
- let ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- let num = p!(ctx.enabled_ciphers()).len();
- assert!(num > 1);
-
- let ciphers = p!(ctx.enabled_ciphers());
- let cipher = ciphers.first().unwrap();
- let stream = p!(ClientBuilder::new()
- .blacklist_ciphers(&[*cipher])
- .ctx_into_stream("google.com", stream));
-
- assert_eq!(num - 1, p!(stream.context().enabled_ciphers()).len());
- }
-
- #[test]
- fn idle_context_peer_trust() {
- let ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- assert!(ctx.peer_trust2().is_err());
- }
-
- #[test]
- fn peer_id() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::SERVER,
- SslConnectionType::STREAM
- ));
- assert!(p!(ctx.peer_id()).is_none());
- p!(ctx.set_peer_id(b"foobar"));
- assert_eq!(p!(ctx.peer_id()), Some(&b"foobar"[..]));
- }
-
- #[test]
- fn peer_domain_name() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- assert_eq!("", p!(ctx.peer_domain_name()));
- p!(ctx.set_peer_domain_name("foobar.com"));
- assert_eq!("foobar.com", p!(ctx.peer_domain_name()));
- }
-
- #[test]
- #[should_panic(expected = "blammo")]
- fn write_panic() {
- struct ExplodingStream(TcpStream);
-
- impl Read for ExplodingStream {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
- }
- }
-
- impl Write for ExplodingStream {
- fn write(&mut self, _: &[u8]) -> io::Result<usize> {
- panic!("blammo");
- }
-
- fn flush(&mut self) -> io::Result<()> {
- self.0.flush()
- }
- }
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- let _ = ctx.handshake(ExplodingStream(stream));
- }
-
- #[test]
- #[should_panic(expected = "blammo")]
- fn read_panic() {
- struct ExplodingStream(TcpStream);
-
- impl Read for ExplodingStream {
- fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
- panic!("blammo");
- }
- }
-
- impl Write for ExplodingStream {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- self.0.flush()
- }
- }
-
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- let _ = ctx.handshake(ExplodingStream(stream));
- }
-
- #[test]
- fn zero_length_buffers() {
- let mut ctx = p!(SslContext::new(
- SslProtocolSide::CLIENT,
- SslConnectionType::STREAM
- ));
- p!(ctx.set_peer_domain_name("google.com"));
- let stream = p!(TcpStream::connect("google.com:443"));
- let mut stream = ctx.handshake(stream).unwrap();
- assert_eq!(stream.write(b"").unwrap(), 0);
- assert_eq!(stream.read(&mut []).unwrap(), 0);
- }
-}
diff --git a/vendor/security-framework/src/trust.rs b/vendor/security-framework/src/trust.rs
deleted file mode 100644
index 79181d9f..00000000
--- a/vendor/security-framework/src/trust.rs
+++ /dev/null
@@ -1,393 +0,0 @@
-//! Trust evaluation support.
-
-use core_foundation::array::CFArray;
-#[cfg(target_os = "macos")]
-use core_foundation::array::CFArrayRef;
-use core_foundation::base::TCFType;
-use core_foundation::data::CFData;
-use core_foundation::date::CFDate;
-use core_foundation_sys::base::{Boolean, CFIndex};
-
-use security_framework_sys::trust::*;
-use std::ptr;
-
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-use crate::key::SecKey;
-use crate::policy::SecPolicy;
-use core_foundation::error::{CFError, CFErrorRef};
-
-/// The result of trust evaluation.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct TrustResult(SecTrustResultType);
-
-impl TrustResult {
- /// An invalid setting or result.
- pub const INVALID: Self = Self(kSecTrustResultInvalid);
-
- /// You may proceed.
- pub const PROCEED: Self = Self(kSecTrustResultProceed);
-
- /// Indicates a denial by the user, do not proceed.
- pub const DENY: Self = Self(kSecTrustResultDeny);
-
- /// The certificate is implicitly trusted.
- pub const UNSPECIFIED: Self = Self(kSecTrustResultUnspecified);
-
- /// Indicates a trust policy failure that the user can override.
- pub const RECOVERABLE_TRUST_FAILURE: Self = Self(kSecTrustResultRecoverableTrustFailure);
-
- /// Indicates a trust policy failure that the user cannot override.
- pub const FATAL_TRUST_FAILURE: Self = Self(kSecTrustResultFatalTrustFailure);
-
- /// An error not related to trust validation.
- pub const OTHER_ERROR: Self = Self(kSecTrustResultOtherError);
-}
-
-impl TrustResult {
- /// Returns true if the result is "successful" - specifically `PROCEED` or `UNSPECIFIED`.
- #[inline]
- #[must_use]
- pub fn success(self) -> bool {
- matches!(self, Self::PROCEED | Self::UNSPECIFIED)
- }
-}
-
-declare_TCFType! {
- /// A type representing a trust evaluation for a certificate.
- SecTrust, SecTrustRef
-}
-impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
-
-unsafe impl Sync for SecTrust {}
-unsafe impl Send for SecTrust {}
-
-#[cfg(target_os = "macos")]
-bitflags::bitflags! {
- /// The option flags used to configure the evaluation of a `SecTrust`.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct TrustOptions: SecTrustOptionFlags {
- /// Allow expired certificates (except for the root certificate).
- const ALLOW_EXPIRED = kSecTrustOptionAllowExpired;
- /// Allow CA certificates as leaf certificates.
- const LEAF_IS_CA = kSecTrustOptionLeafIsCA;
- /// Allow network downloads of CA certificates.
- const FETCH_ISSUER_FROM_NET = kSecTrustOptionFetchIssuerFromNet;
- /// Allow expired root certificates.
- const ALLOW_EXPIRED_ROOT = kSecTrustOptionAllowExpiredRoot;
- /// Require a positive revocation check for each certificate.
- const REQUIRE_REVOCATION_PER_CERT = kSecTrustOptionRequireRevPerCert;
- /// Use TrustSettings instead of anchors.
- const USE_TRUST_SETTINGS = kSecTrustOptionUseTrustSettings;
- /// Treat properly self-signed certificates as anchors implicitly.
- const IMPLICIT_ANCHORS = kSecTrustOptionImplicitAnchors;
- }
-}
-
-impl SecTrust {
- /// Creates a `SecTrustRef` that is configured with a certificate chain, for validating
- /// that chain against a collection of policies.
- pub fn create_with_certificates(
- certs: &[SecCertificate],
- policies: &[SecPolicy],
- ) -> Result<Self> {
- let cert_array = CFArray::from_CFTypes(certs);
- let policy_array = CFArray::from_CFTypes(policies);
- let mut trust = ptr::null_mut();
- unsafe {
- cvt(SecTrustCreateWithCertificates(
- cert_array.as_CFTypeRef(),
- policy_array.as_CFTypeRef(),
- &mut trust,
- ))?;
- Ok(Self(trust))
- }
- }
-
- /// Sets the date and time against which the certificates in this trust object
- /// are verified.
- #[inline]
- pub fn set_trust_verify_date(&mut self, date: &CFDate) -> Result<()> {
- unsafe { cvt(SecTrustSetVerifyDate(self.0, date.as_concrete_TypeRef())) }
- }
-
- /// Sets additional anchor certificates used to validate trust.
- pub fn set_anchor_certificates(&mut self, certs: &[SecCertificate]) -> Result<()> {
- let certs = CFArray::from_CFTypes(certs);
-
- unsafe {
- cvt(SecTrustSetAnchorCertificates(
- self.0,
- certs.as_concrete_TypeRef(),
- ))
- }
- }
-
- /// Retrieves the anchor (root) certificates stored by macOS
- #[cfg(target_os = "macos")]
- pub fn copy_anchor_certificates() -> Result<Vec<SecCertificate>> {
- let mut array: CFArrayRef = ptr::null();
-
- unsafe {
- cvt(SecTrustCopyAnchorCertificates(&mut array))?;
- }
-
- if array.is_null() {
- return Ok(vec![]);
- }
-
- let array = unsafe { CFArray::<SecCertificate>::wrap_under_create_rule(array) };
- Ok(array.into_iter().map(|c| c.clone()).collect())
- }
-
- /// If set to `true`, only the certificates specified by
- /// `set_anchor_certificates` will be trusted, but not globally trusted
- /// certificates.
- #[inline]
- pub fn set_trust_anchor_certificates_only(&mut self, only: bool) -> Result<()> {
- unsafe { cvt(SecTrustSetAnchorCertificatesOnly(self.0, Boolean::from(only))) }
- }
-
- /// Sets the policy used to evaluate trust.
- #[inline]
- pub fn set_policy(&mut self, policy: &SecPolicy) -> Result<()> {
- unsafe { cvt(SecTrustSetPolicies(self.0, policy.as_CFTypeRef())) }
- }
-
- /// Sets option flags for customizing evaluation of a trust object.
- #[cfg(target_os = "macos")]
- #[inline]
- pub fn set_options(&mut self, options: TrustOptions) -> Result<()> {
- unsafe { cvt(SecTrustSetOptions(self.0, options.bits())) }
- }
-
- /// Indicates whether this trust object is permitted to
- /// fetch missing intermediate certificates from the network.
- pub fn get_network_fetch_allowed(&mut self) -> Result<bool> {
- let mut allowed = 0;
-
- unsafe { cvt(SecTrustGetNetworkFetchAllowed(self.0, &mut allowed))? };
-
- Ok(allowed != 0)
- }
-
- /// Specifies whether this trust object is permitted to
- /// fetch missing intermediate certificates from the network.
- #[inline]
- pub fn set_network_fetch_allowed(&mut self, allowed: bool) -> Result<()> {
- unsafe { cvt(SecTrustSetNetworkFetchAllowed(self.0, allowed as u8)) }
- }
-
- /// Attaches Online Certificate Status Protocol (OSCP) response data
- /// to this trust object.
- pub fn set_trust_ocsp_response<I: Iterator<Item = impl AsRef<[u8]>>>(
- &mut self,
- ocsp_response: I,
- ) -> Result<()> {
- let response: Vec<CFData> = ocsp_response
- .into_iter()
- .map(|bytes| CFData::from_buffer(bytes.as_ref()))
- .collect();
-
- let response = CFArray::from_CFTypes(&response);
-
- unsafe { cvt(SecTrustSetOCSPResponse(self.0, response.as_CFTypeRef())) }
- }
-
- /// Attaches signed certificate timestamp data to this trust object.
- #[cfg(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- pub fn set_signed_certificate_timestamps<I: Iterator<Item = impl AsRef<[u8]>>>(
- &mut self,
- scts: I,
- ) -> Result<()> {
- let scts: Vec<CFData> = scts
- .into_iter()
- .map(|bytes| CFData::from_buffer(bytes.as_ref()))
- .collect();
-
- let scts = CFArray::from_CFTypes(&scts);
-
- unsafe { cvt(SecTrustSetSignedCertificateTimestamps(self.0, scts.as_concrete_TypeRef())) }
- }
-
- /// Returns the public key for a leaf certificate after it has been evaluated.
- #[inline]
- pub fn copy_public_key(&mut self) -> Result<SecKey> {
- unsafe {
- Ok(SecKey::wrap_under_create_rule(SecTrustCopyPublicKey(
- self.0,
- )))
- }
- }
-
- /// Evaluates trust.
- #[deprecated(note = "use evaluate_with_error")]
- pub fn evaluate(&self) -> Result<TrustResult> {
- #[allow(deprecated)]
- unsafe {
- let mut result = kSecTrustResultInvalid;
- cvt(SecTrustEvaluate(self.0, &mut result))?;
- Ok(TrustResult(result))
- }
- }
-
- /// Evaluates trust. Requires macOS 10.14 or iOS, otherwise it just calls `evaluate()`
- pub fn evaluate_with_error(&self) -> Result<(), CFError> {
- #[cfg(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))]
- unsafe {
- let mut error: CFErrorRef = ::std::ptr::null_mut();
- if !SecTrustEvaluateWithError(self.0, &mut error) {
- assert!(!error.is_null());
- let error = CFError::wrap_under_create_rule(error);
- return Err(error);
- }
- Ok(())
- }
- #[cfg(not(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))]
- #[allow(deprecated)]
- {
- use security_framework_sys::base::errSecNotTrusted;
- use security_framework_sys::base::errSecTrustSettingDeny;
-
- let code = match self.evaluate() {
- Ok(res) if res.success() => return Ok(()),
- Ok(TrustResult::DENY) => errSecTrustSettingDeny,
- Ok(_) => errSecNotTrusted,
- Err(err) => err.code(),
- };
- Err(cferror_from_osstatus(code))
- }
- }
-
- /// Returns the number of certificates in an evaluated certificate chain.
- ///
- /// Note: evaluate must first be called on the `SecTrust`.
- #[inline(always)]
- #[must_use]
- pub fn certificate_count(&self) -> CFIndex {
- unsafe { SecTrustGetCertificateCount(self.0) }
- }
-
- /// Returns a specific certificate from the certificate chain used to evaluate trust.
- ///
- /// Note: evaluate must first be called on the `SecTrust`.
- #[deprecated(note = "deprecated by Apple")]
- #[must_use]
- pub fn certificate_at_index(&self, ix: CFIndex) -> Option<SecCertificate> {
- #[allow(deprecated)]
- unsafe {
- if self.certificate_count() <= ix {
- None
- } else {
- let certificate = SecTrustGetCertificateAtIndex(self.0, ix);
- Some(SecCertificate::wrap_under_get_rule(certificate.cast()))
- }
- }
- }
-}
-
-#[cfg(not(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))]
-extern "C" {
- fn CFErrorCreate(allocator: core_foundation_sys::base::CFAllocatorRef, domain: core_foundation_sys::string::CFStringRef, code: CFIndex, userInfo: core_foundation_sys::dictionary::CFDictionaryRef) -> CFErrorRef;
-}
-
-#[cfg(not(any(feature = "OSX_10_14", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))]
-fn cferror_from_osstatus(code: core_foundation_sys::base::OSStatus) -> CFError {
- unsafe {
- let error = CFErrorCreate(ptr::null_mut(), core_foundation_sys::error::kCFErrorDomainOSStatus, code as _, ptr::null_mut());
- assert!(!error.is_null());
- CFError::wrap_under_create_rule(error)
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::policy::SecPolicy;
- use crate::secure_transport::SslProtocolSide;
- use crate::test::certificate;
- use crate::trust::SecTrust;
-
- #[test]
- #[allow(deprecated)]
- fn create_with_certificates() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- assert!(!trust.evaluate().unwrap().success());
- }
-
- #[test]
- fn create_with_certificates_new() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- assert!(trust.evaluate_with_error().is_err());
- }
-
- #[test]
- #[allow(deprecated)]
- fn certificate_count_and_at_index() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- trust.evaluate().unwrap();
-
- let count = trust.certificate_count();
- assert_eq!(count, 1);
-
- let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
- assert_eq!(cert_bytes, certificate().to_der());
- }
-
- #[test]
- #[allow(deprecated)]
- fn certificate_count_and_at_index_new() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- assert!(trust.evaluate_with_error().is_err());
-
- let count = trust.certificate_count();
- assert_eq!(count, 1);
-
- let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
- assert_eq!(cert_bytes, certificate().to_der());
- }
-
- #[test]
- #[allow(deprecated)]
- fn certificate_at_index_out_of_bounds() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
-
- let trust = SecTrust::create_with_certificates(&[cert.clone()], &[ssl_policy.clone()]).unwrap();
- trust.evaluate().unwrap();
- assert!(trust.certificate_at_index(1).is_none());
-
- let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- assert!(trust.evaluate_with_error().is_err());
- assert!(trust.certificate_at_index(1).is_none());
- }
-
- #[test]
- #[allow(deprecated)]
- fn set_policy() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
- let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- trust.set_policy(&ssl_policy).unwrap();
- assert!(!trust.evaluate().unwrap().success());
- }
-
- #[test]
- fn set_policy_new() {
- let cert = certificate();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
- let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
- let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
- trust.set_policy(&ssl_policy).unwrap();
- assert!(trust.evaluate_with_error().is_err());
- }
-}
diff --git a/vendor/security-framework/src/trust_settings.rs b/vendor/security-framework/src/trust_settings.rs
deleted file mode 100644
index 8ccdedc2..00000000
--- a/vendor/security-framework/src/trust_settings.rs
+++ /dev/null
@@ -1,305 +0,0 @@
-//! Querying trust settings.
-
-use core_foundation::array::{CFArray, CFArrayRef};
-use core_foundation::base::{CFIndex, TCFType};
-use core_foundation::dictionary::CFDictionary;
-use core_foundation::number::CFNumber;
-use core_foundation::string::CFString;
-
-use core_foundation_sys::base::CFTypeRef;
-use security_framework_sys::base::errSecNoTrustSettings;
-use security_framework_sys::base::errSecSuccess;
-use security_framework_sys::trust_settings::*;
-
-use std::ptr;
-
-use crate::base::Error;
-use crate::base::Result;
-use crate::certificate::SecCertificate;
-use crate::cvt;
-
-/// Which set of trust settings to query
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(u32)]
-pub enum Domain {
- /// Per-user trust settings
- User = kSecTrustSettingsDomainUser,
- /// Locally administered, system-wide trust settings
- Admin = kSecTrustSettingsDomainAdmin,
- /// System trust settings
- System = kSecTrustSettingsDomainSystem,
-}
-
-impl From<Domain> for SecTrustSettingsDomain {
- #[inline]
- fn from(domain: Domain) -> SecTrustSettingsDomain {
- match domain {
- Domain::User => kSecTrustSettingsDomainUser,
- Domain::Admin => kSecTrustSettingsDomainAdmin,
- Domain::System => kSecTrustSettingsDomainSystem,
- }
- }
-}
-
-/// Trust settings for a specific certificate in a specific domain
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum TrustSettingsForCertificate {
- /// Not used
- Invalid,
-
- /// This is a root certificate and is trusted, either explicitly or
- /// implicitly.
- TrustRoot,
-
- /// This is a non-root certificate but is explicitly trusted.
- TrustAsRoot,
-
- /// Cert is explicitly distrusted.
- Deny,
-
- /// Neither trusted nor distrusted.
- Unspecified,
-}
-
-impl TrustSettingsForCertificate {
- /// Create from `kSecTrustSettingsResult*` constant
- fn new(value: i64) -> Self {
- if value < 0 || value > i64::from(u32::max_value()) {
- return Self::Invalid;
- }
- match value as u32 {
- kSecTrustSettingsResultTrustRoot => Self::TrustRoot,
- kSecTrustSettingsResultTrustAsRoot => Self::TrustAsRoot,
- kSecTrustSettingsResultDeny => Self::Deny,
- kSecTrustSettingsResultUnspecified => Self::Unspecified,
- _ => Self::Invalid,
- }
- }
-}
-
-/// Allows access to the certificates and their trust settings in a given domain.
-pub struct TrustSettings {
- domain: Domain,
-}
-
-impl TrustSettings {
- /// Create a new `TrustSettings` for the given domain.
- ///
- /// You can call `iter()` to discover the certificates with settings in this domain.
- ///
- /// Then you can call `tls_trust_settings_for_certificate()` with a given certificate
- /// to learn what the aggregate trust setting for that certificate within this domain.
- #[inline(always)]
- #[must_use]
- pub fn new(domain: Domain) -> Self {
- Self { domain }
- }
-
- /// Create an iterator over the certificates with settings in this domain.
- /// This produces an empty iterator if there are no such certificates.
- pub fn iter(&self) -> Result<TrustSettingsIter> {
- let array = unsafe {
- let mut array_ptr: CFArrayRef = ptr::null_mut();
-
- // SecTrustSettingsCopyCertificates returns errSecNoTrustSettings
- // if no items have trust settings in the given domain. We map
- // that to an empty TrustSettings iterator.
- match SecTrustSettingsCopyCertificates(self.domain.into(), &mut array_ptr) {
- errSecNoTrustSettings => CFArray::from_CFTypes(&[]),
- errSecSuccess => CFArray::<SecCertificate>::wrap_under_create_rule(array_ptr),
- err => return Err(Error::from_code(err)),
- }
- };
-
- Ok(TrustSettingsIter { index: 0, array })
- }
-
- ///set trust settings to ""always trust this root certificate regardless of use.".
- /// Sets the trust settings for the provided certificate to "always trust this root certificate
- /// regardless of use."
- ///
- /// This method configures the trust settings for the specified certificate, indicating that it should
- /// always be trusted as a TLS root certificate, regardless of its usage.
- ///
- /// If successful, the trust settings are updated for the certificate in the given domain. If the
- /// certificate had no previous trust settings in the domain, new trust settings are created. If the
- /// certificate had existing trust settings, they are replaced with the new settings.
- ///
- /// It is not possible to modify per-user trust settings when not running in a GUI
- /// environment, if you try it will return error `2070: errSecInternalComponent`
- #[cfg(target_os="macos")]
- pub fn set_trust_settings_always(&self, cert: &SecCertificate) -> Result<()> {
- let domain = self.domain;
- let trust_settings: CFTypeRef = ptr::null_mut();
- cvt(unsafe {
- SecTrustSettingsSetTrustSettings(
- cert.as_CFTypeRef() as *mut _,
- domain.into(),
- trust_settings,
- )
- })
- }
-
- /// Returns the aggregate trust setting for the given certificate.
- ///
- /// This tells you whether the certificate should be trusted as a TLS
- /// root certificate.
- ///
- /// If the certificate has no trust settings in the given domain, the
- /// `errSecItemNotFound` error is returned.
- ///
- /// If the certificate has no specific trust settings for TLS in the
- /// given domain `None` is returned.
- ///
- /// Otherwise, the specific trust settings are aggregated and returned.
- pub fn tls_trust_settings_for_certificate(&self, cert: &SecCertificate)
- -> Result<Option<TrustSettingsForCertificate>> {
- let trust_settings = unsafe {
- let mut array_ptr: CFArrayRef = ptr::null_mut();
- let cert_ptr = cert.as_CFTypeRef() as *mut _;
- cvt(SecTrustSettingsCopyTrustSettings(cert_ptr,
- self.domain.into(),
- &mut array_ptr))?;
- CFArray::<CFDictionary>::wrap_under_create_rule(array_ptr)
- };
-
- for settings in trust_settings.iter() {
- // Reject settings for non-SSL policies
- let is_not_ssl_policy = {
- let policy_name_key = CFString::from_static_string("kSecTrustSettingsPolicyName");
- let ssl_policy_name = CFString::from_static_string("sslServer");
-
- let maybe_name: Option<CFString> = settings
- .find(policy_name_key.as_CFTypeRef().cast())
- .map(|name| unsafe { CFString::wrap_under_get_rule((*name).cast()) });
-
- matches!(maybe_name, Some(ref name) if name != &ssl_policy_name)
- };
-
- if is_not_ssl_policy {
- continue;
- }
-
- // Evaluate "effective trust settings" for this usage constraint.
- let maybe_trust_result = {
- let settings_result_key = CFString::from_static_string("kSecTrustSettingsResult");
- settings
- .find(settings_result_key.as_CFTypeRef().cast())
- .map(|num| unsafe { CFNumber::wrap_under_get_rule((*num).cast()) })
- .and_then(|num| num.to_i64())
- };
-
- // "Note that an empty Trust Settings array means "always trust this cert,
- // with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot"."
- let trust_result = TrustSettingsForCertificate::new(maybe_trust_result
- .unwrap_or_else(|| i64::from(kSecTrustSettingsResultTrustRoot)));
-
- match trust_result {
- TrustSettingsForCertificate::Unspecified |
- TrustSettingsForCertificate::Invalid => { continue; },
- _ => return Ok(Some(trust_result)),
- }
- }
-
- // There were no more specific settings. This might mean the certificate
- // is to be trusted anyway (since, eg, it's in system store), but leave
- // the caller to make this decision.
- Ok(None)
- }
-}
-
-/// Iterator over certificates.
-pub struct TrustSettingsIter {
- array: CFArray<SecCertificate>,
- index: CFIndex,
-}
-
-impl Iterator for TrustSettingsIter {
- type Item = SecCertificate;
-
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- if self.index >= self.array.len() {
- None
- } else {
- let cert = self.array.get(self.index).unwrap();
- self.index += 1;
- Some(cert.clone())
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let left = (self.array.len() as usize).saturating_sub(self.index as usize);
- (left, Some(left))
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::test::certificate;
-
- fn list_for_domain(domain: Domain) {
- println!("--- domain: {domain:?}");
- let ts = TrustSettings::new(domain);
- let iterator = ts.iter().unwrap();
-
- for (i, cert) in iterator.enumerate() {
- println!("cert({i:?}) = {cert:?}");
- println!(" settings = {:?}", ts.tls_trust_settings_for_certificate(&cert));
- }
- println!("---");
- }
-
- #[test]
- fn list_for_user() {
- list_for_domain(Domain::User);
- }
-
- #[test]
- fn list_for_system() {
- list_for_domain(Domain::System);
- }
-
- #[test]
- fn list_for_admin() {
- list_for_domain(Domain::Admin);
- }
-
- #[test]
- fn test_system_certs_are_present() {
- let system = TrustSettings::new(Domain::System).iter().unwrap().count();
-
- // 168 at the time of writing
- assert!(system > 100);
- }
-
- #[test]
- fn test_isrg_root_exists_and_is_trusted() {
- let ts = TrustSettings::new(Domain::System);
- assert_eq!(
- ts.iter()
- .unwrap()
- .find(|cert| cert.subject_summary() == "ISRG Root X1")
- .and_then(|cert| ts.tls_trust_settings_for_certificate(&cert).unwrap()),
- None
- );
- // ^ this is a case where None means "always trust", according to Apple docs:
- //
- // "Note that an empty Trust Settings array means "always trust this cert,
- // with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot"."
- }
-
- #[test]
- fn test_unknown_cert_is_not_trusted() {
- let ts = TrustSettings::new(Domain::System);
- let cert = certificate();
- assert_eq!(ts.tls_trust_settings_for_certificate(&cert)
- .err()
- .unwrap()
- .message(),
- Some("The specified item could not be found in the keychain.".into()));
- }
-}
-