secure_env/ios.rs
1use crate::{
2 error::{SecureEnvError, SecureEnvResult},
3 KeyOps, SecureEnvironmentOps,
4};
5use p256::{ecdsa::Signature, elliptic_curve::group::GroupEncoding};
6use security_framework::{
7 access_control::{ProtectionMode, SecAccessControl},
8 item::{ItemClass, ItemSearchOptions, KeyClass, Location, SearchResult},
9 key::{Algorithm, GenerateKeyOptions, KeyType, SecKey, Token},
10 passwords_options::AccessControlOptions,
11};
12
13/// Unit struct that can be used to create and get keypairs by id
14///
15/// # Examples
16///
17/// ## Generate a keypair
18///
19/// ```
20/// use secure_env::{SecureEnvironment, SecureEnvironmentOps};
21///
22/// let key = SecureEnvironment::generate_keypair("my-unique-id").unwrap();
23/// ```
24///
25/// ## Get a keypair from the keychain
26///
27/// ```
28/// use secure_env::{SecureEnvironment, SecureEnvironmentOps};
29///
30/// {
31/// SecureEnvironment::generate_keypair("my-unique-id").unwrap();
32/// }
33///
34/// let key = SecureEnvironment::get_keypair_by_id("my-unique-id").unwrap();
35/// ```
36#[derive(Debug, Clone, Eq, PartialEq, Copy)]
37pub struct SecureEnvironment;
38
39impl SecureEnvironmentOps<Key> for SecureEnvironment {
40 fn generate_keypair(id: impl Into<String>, backed_by_biometrics: bool) -> SecureEnvResult<Key> {
41 // Create a dictionary with the following options:
42 let mut opts = GenerateKeyOptions::default();
43
44 // Set the key type to `ec` (Elliptic Curve)
45 let opts = opts.set_key_type(KeyType::ec());
46
47 // Set the a token of `SecureEnclave`.
48 // Meaning Apple will store the key in a secure element
49 let opts = opts.set_token(Token::SecureEnclave);
50
51 let opts = if backed_by_biometrics {
52 // Set the access control so that biometrics via LocalAuthentication.framework is required
53 let access_control = SecAccessControl::create_with_protection(
54 Some(ProtectionMode::AccessibleWhenUnlockedThisDeviceOnly),
55 AccessControlOptions::BIOMETRY_CURRENT_SET.bits(),
56 )
57 .map_err(|_| {
58 SecureEnvError::UnableToGenerateKey(
59 "Unable to create access control flags".to_owned(),
60 )
61 })?;
62
63 opts.set_access_control(access_control)
64 } else {
65 opts
66 };
67
68 // Store the key in the keychain
69 let opts = opts.set_location(Location::DataProtectionKeychain);
70
71 // Give the key a label so we can retrieve it later
72 // with the `SecureEnvironment::get_keypair_by_id` method
73 let opts = opts.set_label(id);
74
75 let dict = opts.to_dictionary();
76
77 // Generate a key using the dictionary
78 // This also passes along any information the OS provides when an error occurs
79 let key = SecKey::generate(dict)
80 .map_err(|e| SecureEnvError::UnableToGenerateKey(e.to_string()))?;
81
82 Ok(Key(key))
83 }
84
85 fn get_keypair_by_id(id: impl Into<String>) -> SecureEnvResult<Key> {
86 let id = id.into();
87
88 let search_result = ItemSearchOptions::new()
89 // Search by the provided label
90 .label(&id)
91 // Load the reference, not the actual data
92 .load_refs(true)
93 // Looking for a `Key` instance
94 .class(ItemClass::key())
95 // We want access to the private key
96 .key_class(KeyClass::private())
97 // Limit to 1 output key
98 .limit(1)
99 // Search the keychain
100 .search()
101 .map_err(|_| {
102 SecureEnvError::UnableToGetKeyPairById(format!(
103 "Key reference with id: '{id}' not found."
104 ))
105 })?;
106
107 let result = search_result
108 .first()
109 .ok_or(SecureEnvError::UnableToGetKeyPairById(format!(
110 "Key reference with id: '{id}' not found."
111 )))?;
112
113 match result {
114 SearchResult::Ref(r) => match r {
115 security_framework::item::Reference::Key(k) => Ok(Key(k.to_owned())),
116 _ => Err(SecureEnvError::UnableToGetKeyPairById(
117 "Found Reference, but not of key instance".to_owned(),
118 )),
119 },
120 _ => Err(SecureEnvError::UnableToGetKeyPairById(
121 "Did not find search reference".to_owned(),
122 )),
123 }
124 }
125}
126
127/// Key structure which allows for signing and retrieval of the public key
128///
129/// # Examples
130///
131/// ## Get the public Key
132///
133/// ```
134/// use secure_env::{SecureEnvironment, SecureEnvironmentOps, Key, KeyOps};
135///
136/// let key = SecureEnvironment::generate_keypair("documentation-public-key-token").unwrap();
137/// let public_key_bytes = key.get_public_key().unwrap();
138///
139/// assert_eq!(public_key_bytes.len(), 33);
140/// ```
141///
142/// ## Sign a message
143///
144/// ```
145/// use secure_env::{SecureEnvironment, SecureEnvironmentOps, Key, KeyOps};
146///
147/// let key = SecureEnvironment::generate_keypair("documentation-sign-key-token").unwrap();
148/// let signature = key.sign(b"Hello World").unwrap();
149///
150/// assert_eq!(signature.len(), 64);
151/// ```
152///
153/// ## Verify the signed message with `askar_crypto`
154///
155/// ```
156/// use secure_env::{SecureEnvironment, SecureEnvironmentOps, Key, KeyOps};
157/// use askar_crypto::{alg::p256::P256KeyPair, repr::KeyPublicBytes};
158///
159/// let msg = b"Hello World!";
160/// let key = SecureEnvironment::generate_keypair("my-test-sign-key").unwrap();
161///
162/// let public_key = key.get_public_key().unwrap();
163/// let signature = key.sign(b"Hello World!").unwrap();
164///
165/// let verify_key = P256KeyPair::from_public_bytes(&public_key).unwrap();
166/// let is_signature_valid = verify_key.verify_signature(msg, &signature);
167///
168/// assert!(is_signature_valid);
169/// ```
170#[derive(Debug, Clone, Eq, PartialEq)]
171pub struct Key(SecKey);
172
173impl KeyOps for Key {
174 fn get_public_key(&self) -> SecureEnvResult<Vec<u8>> {
175 // Retrieve the internal representation of the public key of the `SecKey`
176 let public_key = self
177 .0
178 .public_key()
179 .ok_or(SecureEnvError::UnableToGetPublicKey(
180 "No public key reference found on the internal `SecKey`".to_owned(),
181 ))?;
182
183 // Convert the public key reference to the `sec1` format in bytes
184 let sec1_bytes = public_key
185 .external_representation()
186 .ok_or(SecureEnvError::UnableToGetPublicKey(
187 "Could not create an external representation for the public key on the `SecKey`"
188 .to_owned(),
189 ))?
190 .to_vec();
191
192 // Instantiate a P256 public key from the `sec1` bytes
193 let public_key = p256::PublicKey::from_sec1_bytes(&sec1_bytes)
194 .map_err(|e| SecureEnvError::UnableToGetPublicKey(e.to_string()))?;
195
196 // Get the affine point of the public key and convert this into a byte representation
197 let public_key = public_key.as_affine().to_bytes().to_vec();
198
199 Ok(public_key)
200 }
201
202 /**
203 *
204 * Signing is an operation that requires authentication. Make sure to manually authenticate
205 * before calling this operation
206 *
207 */
208 fn sign(&self, msg: &[u8]) -> SecureEnvResult<Vec<u8>> {
209 // Sign the message with the `der` format
210 let der_sig = self
211 .0
212 .create_signature(Algorithm::ECDSASignatureMessageX962SHA256, msg)
213 .map_err(|e| SecureEnvError::UnableToCreateSignature(e.to_string()))?;
214
215 // Convert the `ASN.1 der` format signature
216 let signature = Signature::from_der(&der_sig)
217 .map_err(|e| SecureEnvError::UnableToCreateSignature(e.to_string()))?;
218
219 // Convert the signature to a byte representation
220 let signature = signature.to_vec();
221
222 Ok(signature)
223 }
224}