apple_security/os/macos/
identity.rs

1//! OSX specific extensions to identity functionality.
2use core_foundation::array::CFArray;
3use core_foundation::base::TCFType;
4use apple_security_sys::identity::SecIdentityCreateWithCertificate;
5use std::ptr;
6
7use crate::base::Result;
8use crate::certificate::SecCertificate;
9use crate::cvt;
10use crate::identity::SecIdentity;
11use crate::os::macos::keychain::SecKeychain;
12
13/// An extension trait adding OSX specific functionality to `SecIdentity`.
14pub trait SecIdentityExt {
15    /// Creates an identity corresponding to a certificate, looking in the
16    /// provided keychains for the corresponding private key.
17    ///
18    /// To search the default keychains, use an empty slice for `keychains`.
19    ///
20    /// <https://developer.apple.com/documentation/security/1401160-secidentitycreatewithcertificate>
21    fn with_certificate(
22        keychains: &[SecKeychain],
23        certificate: &SecCertificate,
24    ) -> Result<SecIdentity>;
25}
26
27impl SecIdentityExt for SecIdentity {
28    fn with_certificate(keychains: &[SecKeychain], certificate: &SecCertificate) -> Result<Self> {
29        let keychains = CFArray::from_CFTypes(keychains);
30        unsafe {
31            let mut identity = ptr::null_mut();
32            cvt(SecIdentityCreateWithCertificate(
33                if keychains.len() > 0 {keychains.as_CFTypeRef()} else {ptr::null()},
34                certificate.as_concrete_TypeRef(),
35                &mut identity,
36            ))?;
37            Ok(Self::wrap_under_create_rule(identity))
38        }
39    }
40}
41
42#[cfg(test)]
43mod test {
44    use tempfile::tempdir;
45
46    use super::*;
47    use crate::identity::SecIdentity;
48    use crate::os::macos::certificate::SecCertificateExt;
49    use crate::os::macos::import_export::ImportOptions;
50    use crate::os::macos::keychain::CreateOptions;
51    use crate::os::macos::test::identity;
52    use crate::test;
53
54    #[test]
55    fn certificate() {
56        let dir = p!(tempdir());
57        let identity = identity(dir.path());
58        let certificate = p!(identity.certificate());
59        assert_eq!("foobar.com", p!(certificate.common_name()));
60    }
61
62    #[test]
63    fn private_key() {
64        let dir = p!(tempdir());
65        let identity = identity(dir.path());
66        p!(identity.private_key());
67    }
68
69    #[test]
70    fn with_certificate() {
71        let dir = p!(tempdir());
72
73        let mut keychain = p!(CreateOptions::new()
74            .password("foobar")
75            .create(dir.path().join("test.keychain")));
76
77        let key = include_bytes!("../../../test/server.key");
78        p!(ImportOptions::new()
79            .filename("server.key")
80            .keychain(&mut keychain)
81            .import(key));
82
83        let cert = test::certificate();
84        p!(SecIdentity::with_certificate(&[keychain], &cert));
85    }
86}