apple_security_framework/
import_export.rs1use std::ptr;
4
5use core_foundation::{
6 array::CFArray,
7 base::{CFType, TCFType},
8 data::CFData,
9 dictionary::CFDictionary,
10 string::CFString,
11};
12use security_framework_sys::import_export::*;
13
14#[cfg(target_os = "macos")]
15use crate::os::macos::access::SecAccess;
16#[cfg(target_os = "macos")]
17use crate::os::macos::keychain::SecKeychain;
18use crate::{
19 base::Result, certificate::SecCertificate, cvt, identity::SecIdentity, trust::SecTrust,
20};
21
22#[non_exhaustive]
24pub struct ImportedIdentity {
25 pub label: Option<String>,
27
28 pub key_id: Option<Vec<u8>>,
30
31 pub trust: Option<SecTrust>,
33
34 pub cert_chain: Option<Vec<SecCertificate>>,
36
37 pub identity: Option<SecIdentity>,
39}
40
41#[derive(Default)]
43pub struct Pkcs12ImportOptions {
44 passphrase: Option<CFString>,
45 #[cfg(target_os = "macos")]
46 keychain: Option<SecKeychain>,
47 #[cfg(target_os = "macos")]
48 access: Option<SecAccess>,
49}
50
51#[cfg(target_os = "macos")]
52impl crate::Pkcs12ImportOptionsInternals for Pkcs12ImportOptions {
53 #[inline(always)]
54 fn keychain(&mut self, keychain: SecKeychain) -> &mut Self {
55 self.keychain = Some(keychain);
56 self
57 }
58
59 #[inline(always)]
60 fn access(&mut self, access: SecAccess) -> &mut Self {
61 self.access = Some(access);
62 self
63 }
64}
65
66impl Pkcs12ImportOptions {
67 #[inline(always)]
69 #[must_use]
70 pub fn new() -> Self {
71 Self::default()
72 }
73
74 #[inline]
78 pub fn passphrase(&mut self, passphrase: &str) -> &mut Self {
79 self.passphrase = Some(CFString::new(passphrase));
80 self
81 }
82
83 pub fn import(&self, pkcs12_data: &[u8]) -> Result<Vec<ImportedIdentity>> {
85 unsafe {
86 let pkcs12_data = CFData::from_buffer(pkcs12_data);
87
88 let mut options = vec![];
89
90 if let Some(ref passphrase) = self.passphrase {
91 options.push((
92 CFString::wrap_under_get_rule(kSecImportExportPassphrase),
93 passphrase.as_CFType(),
94 ));
95 }
96
97 self.import_setup(&mut options);
98
99 let options = CFDictionary::from_CFType_pairs(&options);
100
101 let mut raw_items = ptr::null();
102 cvt(SecPKCS12Import(
103 pkcs12_data.as_concrete_TypeRef(),
104 options.as_concrete_TypeRef(),
105 &mut raw_items,
106 ))?;
107 let raw_items =
108 CFArray::<CFDictionary<CFString, *const _>>::wrap_under_create_rule(raw_items);
109
110 let mut items = vec![];
111
112 for raw_item in &raw_items {
113 let label = raw_item
114 .find(kSecImportItemLabel)
115 .map(|label| CFString::wrap_under_get_rule((*label).cast()).to_string());
116 let key_id = raw_item
117 .find(kSecImportItemKeyID)
118 .map(|key_id| CFData::wrap_under_get_rule((*key_id).cast()).to_vec());
119 let trust = raw_item
120 .find(kSecImportItemTrust)
121 .map(|trust| SecTrust::wrap_under_get_rule(*trust as *mut _));
122 let cert_chain = raw_item
123 .find(kSecImportItemCertChain.cast())
124 .map(|cert_chain| {
125 CFArray::<SecCertificate>::wrap_under_get_rule((*cert_chain).cast())
126 .iter()
127 .map(|c| c.clone())
128 .collect()
129 });
130 let identity = raw_item
131 .find(kSecImportItemIdentity)
132 .map(|identity| SecIdentity::wrap_under_get_rule(*identity as *mut _));
133
134 items.push(ImportedIdentity {
135 label,
136 key_id,
137 trust,
138 cert_chain,
139 identity,
140 });
141 }
142
143 Ok(items)
144 }
145 }
146
147 #[cfg(target_os = "macos")]
148 fn import_setup(&self, options: &mut Vec<(CFString, CFType)>) {
149 unsafe {
150 if let Some(ref keychain) = self.keychain {
151 options.push((
152 CFString::wrap_under_get_rule(kSecImportExportKeychain),
153 keychain.as_CFType(),
154 ));
155 }
156
157 if let Some(ref access) = self.access {
158 options.push((
159 CFString::wrap_under_get_rule(kSecImportExportAccess),
160 access.as_CFType(),
161 ));
162 }
163 }
164 }
165
166 #[cfg(not(target_os = "macos"))]
167 fn import_setup(&self, _: &mut Vec<(CFString, CFType)>) {}
168}
169
170#[cfg(test)]
171mod test {
172 use super::*;
173
174 #[test]
175 fn missing_passphrase() {
176 let data = include_bytes!("../test/server.p12");
177 assert!(Pkcs12ImportOptions::new().import(data).is_err());
178 }
179}