| //! 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::identity::SecIdentity; |
| 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)); |
| } |
| } |