//! 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`. /// /// fn with_certificate( keychains: &[SecKeychain], certificate: &SecCertificate, ) -> Result; } impl SecIdentityExt for SecIdentity { fn with_certificate(keychains: &[SecKeychain], certificate: &SecCertificate) -> Result { 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)); } }