1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 //! Module used to interact with keymint secure storage data.
17 use crate::keybox;
18 use crate::keymaster_attributes;
19 use alloc::{format, string::String, vec::Vec};
20 use kmr_common::{
21 crypto::{self, KeyMaterial},
22 km_err, try_to_vec, vec_try, vec_try_with_capacity,
23 wire::keymint,
24 wire::AttestationIdInfo,
25 Error,
26 };
27 use kmr_ta::device::{
28 RetrieveAttestationIds, RetrieveCertSigningInfo, SigningAlgorithm, SigningKeyType,
29 };
30 use log::info;
31 use protobuf::{self, Message};
32 use storage::{OpenMode, Port, SecureFile, Session};
33
34 #[cfg(feature = "soft_attestation_fallback")]
35 mod software;
36
37 /// Name of file holding attestation device ID information; matches the `kAttestationIdsFileName`
38 /// value in `secure_storage_manager.cpp` for back-compatibility.
39 const KM_ATTESTATION_ID_FILENAME: &str = "AttestationIds";
40
41 /// Filename prefix for files holding attestation keys and certificates; matches the
42 /// `kAttestKeyCertPrefix` value in `secure_storage_manager.cpp` for back-compatibility.
43 const KM_ATTESTATION_KEY_CERT_PREFIX: &str = "AttestKeyCert";
44
45 /// Maximum size of each attestation certificate
46 const MAX_CERT_SIZE: usize = 2048;
47 /// Maximum number of attestation certificates
48 const MAX_CERT_CHAIN_LEN: usize = 3;
49
50 /// Return the filename for the file holding attestation keys and certificates for the specified
51 /// signing algorithm.
get_key_slot_file_name(algorithm: SigningAlgorithm) -> String52 fn get_key_slot_file_name(algorithm: SigningAlgorithm) -> String {
53 let suffix = match algorithm {
54 SigningAlgorithm::Ec => "ec",
55 SigningAlgorithm::Rsa => "rsa",
56 };
57 format!("{}.{}", KM_ATTESTATION_KEY_CERT_PREFIX, suffix)
58 }
59
60 // `session` and `secure_file` are of type `Option` because close() takes self by value, so this was
61 // needed for the `Drop` implementation. The intent though is that they should always be populated
62 // on a OpenSecureFile object; which is `OpenSecureFile::new` behavior.
63 struct OpenSecureFile {
64 session: Option<Session>,
65 secure_file: Option<SecureFile>,
66 }
67
68 impl OpenSecureFile {
69 /// Opens a secure storage session and creates the requested file
new(file_name: &str) -> Result<Self, Error>70 fn new(file_name: &str) -> Result<Self, Error> {
71 let mut session = Session::new(Port::TamperProof, true).map_err(|e| {
72 km_err!(SecureHwCommunicationFailed, "couldn't create storage session: {:?}", e)
73 })?;
74 let secure_file = session.open_file(file_name, OpenMode::Create).map_err(|e| {
75 km_err!(SecureHwCommunicationFailed, "couldn't create file {}: {:?}", file_name, e)
76 })?;
77 Ok(OpenSecureFile { session: Some(session), secure_file: Some(secure_file) })
78 }
79
80 /// Writes provided data in the previously opened file
write_all(&mut self, data: &[u8]) -> Result<(), Error>81 fn write_all(&mut self, data: &[u8]) -> Result<(), Error> {
82 // Even though we are handling the case when secure_file and session are None, this is not
83 // expected; if an OpenSecureFile object exists its `secure_file` and `session` elements
84 // shall be populated.
85 let session =
86 self.session.as_mut().ok_or(km_err!(UnknownError, "session shouldn't ever be None"))?;
87 let file = self
88 .secure_file
89 .as_mut()
90 .ok_or(km_err!(UnknownError, "secure_file shouldn't ever be None"))?;
91 session.write_all(file, data).map_err(|e| {
92 km_err!(SecureHwCommunicationFailed, "failed to write data; received error: {:?}", e)
93 })
94 }
95
96 /// Close the session and file handlers by taking ownership and letting the value be dropped
97 #[cfg(test)]
close(self)98 fn close(self) {}
99 }
100
101 impl Drop for OpenSecureFile {
drop(&mut self)102 fn drop(&mut self) {
103 // Even though we are handling the case when secure_file and session are None, this is not
104 // expected; if an OpenSecureFile object exists its `secure_file` and `session` elements
105 // shall be populated.
106 if let Some(file) = self.secure_file.take() {
107 file.close();
108 }
109 if let Some(session) = self.session.take() {
110 session.close();
111 }
112 }
113 }
114
115 /// Creates an empty attestation IDs file
create_attestation_id_file() -> Result<OpenSecureFile, Error>116 fn create_attestation_id_file() -> Result<OpenSecureFile, Error> {
117 OpenSecureFile::new(KM_ATTESTATION_ID_FILENAME)
118 }
119
120 /// Creates and empty attestation key/certificates file for the given algorithm
create_attestation_key_file(algorithm: SigningAlgorithm) -> Result<OpenSecureFile, Error>121 fn create_attestation_key_file(algorithm: SigningAlgorithm) -> Result<OpenSecureFile, Error> {
122 let file_name = get_key_slot_file_name(algorithm);
123 OpenSecureFile::new(&file_name)
124 }
125
write_protobuf_to_attestation_key_file( algorithm: SigningAlgorithm, attestation_key_data: keymaster_attributes::AttestationKey, ) -> Result<(), Error>126 fn write_protobuf_to_attestation_key_file(
127 algorithm: SigningAlgorithm,
128 attestation_key_data: keymaster_attributes::AttestationKey,
129 ) -> Result<(), Error> {
130 let serialized_buffer = attestation_key_data.write_to_bytes().map_err(|e| {
131 km_err!(SecureHwCommunicationFailed, "couldn't serialize attestationKey: {:?}", e)
132 })?;
133 let mut file = create_attestation_key_file(algorithm)?;
134 file.write_all(&serialized_buffer).map_err(|e| {
135 km_err!(SecureHwCommunicationFailed, "failed to provision attestation key file: {:?}", e)
136 })?;
137 Ok(())
138 }
139
140 /// Unwraps a keybox wrapped key and uses it to provision the key on the device.
set_wrapped_attestation_key( algorithm: SigningAlgorithm, key_data: &[u8], ) -> Result<(), Error>141 pub(crate) fn set_wrapped_attestation_key(
142 algorithm: SigningAlgorithm,
143 key_data: &[u8],
144 ) -> Result<(), Error> {
145 let unwrapped_key = keybox::keybox_unwrap(key_data)?;
146 provision_attestation_key_file(algorithm, &unwrapped_key)
147 }
148
149 /// Tries to read the file containing the attestation key and certificates and only replaces the key
150 /// section. If the file doesn't exist it will create it and save the provided key.
provision_attestation_key_file( algorithm: SigningAlgorithm, key_data: &[u8], ) -> Result<(), Error>151 pub(crate) fn provision_attestation_key_file(
152 algorithm: SigningAlgorithm,
153 key_data: &[u8],
154 ) -> Result<(), Error> {
155 let mut attestation_key = read_attestation_key_content(algorithm)?;
156 attestation_key.set_key(try_to_vec(key_data)?);
157
158 write_protobuf_to_attestation_key_file(algorithm, attestation_key)
159 }
160
161 /// Tries to read the file containing the attestation key and certificates and adds a certificate to
162 /// it if there is still space left on the certificate section. If the file doesn't exist it will
163 /// create it and save the provided certificate.
append_attestation_cert_chain( algorithm: SigningAlgorithm, cert_data: &[u8], ) -> Result<(), Error>164 pub(crate) fn append_attestation_cert_chain(
165 algorithm: SigningAlgorithm,
166 cert_data: &[u8],
167 ) -> Result<(), Error> {
168 if cert_data.is_empty() {
169 return Err(km_err!(InvalidInputLength, "received a certificate of length 0"));
170 }
171
172 if cert_data.len() > MAX_CERT_SIZE {
173 return Err(km_err!(
174 InvalidArgument,
175 "certificate is too big. Size: {}, max size {}",
176 cert_data.len(),
177 MAX_CERT_SIZE
178 ));
179 }
180
181 let mut attestation_key_data = read_attestation_key_content(algorithm)?;
182 let cert_chain_len = attestation_key_data.get_certs().len();
183
184 if cert_chain_len >= MAX_CERT_CHAIN_LEN {
185 return Err(km_err!(
186 InvalidArgument,
187 "cannot accept more certificates, {} already provisioned",
188 cert_chain_len
189 ));
190 }
191
192 let mut cert = keymaster_attributes::AttestationCert::new();
193 cert.set_content(try_to_vec(cert_data)?);
194 attestation_key_data.mut_certs().push(cert);
195
196 write_protobuf_to_attestation_key_file(algorithm, attestation_key_data)
197 }
198
199 /// Tries to read the file containing the attestation key delete only the certificate section.
clear_attestation_cert_chain(algorithm: SigningAlgorithm) -> Result<(), Error>200 pub(crate) fn clear_attestation_cert_chain(algorithm: SigningAlgorithm) -> Result<(), Error> {
201 let mut attestation_key_data = read_attestation_key_content(algorithm)?;
202 if attestation_key_data.get_certs().is_empty() {
203 // No certs found, nothing to delete.
204 return Ok(());
205 }
206 attestation_key_data.clear_certs();
207 write_protobuf_to_attestation_key_file(algorithm, attestation_key_data)?;
208 // Checking that the certificates were indeed deleted
209 let attestation_key_data = read_attestation_key_content(algorithm)?;
210 let cert_chain_len = attestation_key_data.get_certs().len();
211 if cert_chain_len != 0 {
212 log::error!("Couldn't delete all certificates, found {}", cert_chain_len);
213 return Err(km_err!(
214 UnknownError,
215 "couldn't delete all certificates, found {}",
216 cert_chain_len
217 ));
218 }
219 Ok(())
220 }
221
222 /// Creates a new attestation IDs file and saves the provided data there
223 #[allow(clippy::too_many_arguments)]
provision_attestation_id_file( brand: &[u8], product: &[u8], device: &[u8], serial: &[u8], imei: &[u8], meid: &[u8], manufacturer: &[u8], model: &[u8], maybe_imei2: Option<&[u8]>, ) -> Result<(), Error>224 pub(crate) fn provision_attestation_id_file(
225 brand: &[u8],
226 product: &[u8],
227 device: &[u8],
228 serial: &[u8],
229 imei: &[u8],
230 meid: &[u8],
231 manufacturer: &[u8],
232 model: &[u8],
233 maybe_imei2: Option<&[u8]>,
234 ) -> Result<(), Error> {
235 let mut file = create_attestation_id_file()?;
236
237 let mut attestation_ids = keymaster_attributes::AttestationIds::new();
238
239 if !brand.is_empty() {
240 attestation_ids.set_brand(try_to_vec(brand)?);
241 }
242 if !device.is_empty() {
243 attestation_ids.set_device(try_to_vec(device)?);
244 }
245 if !product.is_empty() {
246 attestation_ids.set_product(try_to_vec(product)?);
247 }
248 if !serial.is_empty() {
249 attestation_ids.set_serial(try_to_vec(serial)?);
250 }
251 if !imei.is_empty() {
252 attestation_ids.set_imei(try_to_vec(imei)?);
253 }
254 if !meid.is_empty() {
255 attestation_ids.set_meid(try_to_vec(meid)?);
256 }
257 if !manufacturer.is_empty() {
258 attestation_ids.set_manufacturer(try_to_vec(manufacturer)?);
259 }
260 if !model.is_empty() {
261 attestation_ids.set_model(try_to_vec(model)?);
262 }
263 match maybe_imei2 {
264 Some(imei2) if !imei2.is_empty() => {
265 attestation_ids.set_second_imei(try_to_vec(imei2)?);
266 }
267 _ => (),
268 }
269
270 let serialized_buffer = attestation_ids.write_to_bytes().map_err(|e| {
271 km_err!(SecureHwCommunicationFailed, "couldn't serialize attestationIds: {:?}", e)
272 })?;
273
274 file.write_all(&serialized_buffer).map_err(|e| {
275 km_err!(SecureHwCommunicationFailed, "failed to provision attestation IDs file: {:?}", e)
276 })?;
277
278 Ok(())
279 }
280
281 /// Delete all attestation IDs from secure storage.
delete_attestation_ids() -> Result<(), Error>282 pub(crate) fn delete_attestation_ids() -> Result<(), Error> {
283 let mut session = Session::new(Port::TamperProof, true).map_err(|e| {
284 km_err!(SecureHwCommunicationFailed, "failed to connect to storage port: {:?}", e)
285 })?;
286 session.remove(KM_ATTESTATION_ID_FILENAME).map_err(|e| {
287 km_err!(SecureHwCommunicationFailed, "failed to delete attestation IDs file: {:?}", e)
288 })?;
289 Ok(())
290 }
291
292 /// Return the contents of the specified file in secure storage.
get_file_contents(file_name: &str) -> Result<Option<Vec<u8>>, Error>293 fn get_file_contents(file_name: &str) -> Result<Option<Vec<u8>>, Error> {
294 let mut session = Session::new(Port::TamperProof, true).map_err(|e| {
295 km_err!(SecureHwCommunicationFailed, "failed to connect to storage port: {:?}", e)
296 })?;
297 // Distinguishing between file not found and other errors, so we can match c++ behavior when
298 // retrieving attestation IDs on unprovisioned devices.
299 let file = match session.open_file(file_name, OpenMode::Open) {
300 Ok(file) => file,
301 Err(storage::Error::Code(trusty_sys::Error::NotFound)) => return Ok(None),
302 Err(e) => {
303 return Err(km_err!(
304 SecureHwCommunicationFailed,
305 "failed to open '{}': {:?}",
306 file_name,
307 e
308 ));
309 }
310 };
311 let size = session.get_size(&file).map_err(|e| {
312 km_err!(SecureHwCommunicationFailed, "failed to get size for '{}': {:?}", file_name, e)
313 })?;
314 let mut buffer = vec_try![0; size]?;
315 let content = session.read_all(&file, buffer.as_mut_slice()).map_err(|e| {
316 km_err!(SecureHwCommunicationFailed, "failed to read '{}': {:?}", file_name, e)
317 })?;
318 let total_size = content.len();
319 buffer.resize(total_size, 0);
320 Ok(Some(buffer))
321 }
322
323 /// Retrieve the attestation ID information from secure storage.
read_attestation_ids() -> Result<AttestationIdInfo, Error>324 pub(crate) fn read_attestation_ids() -> Result<AttestationIdInfo, Error> {
325 // Retrieving attestation IDs from file. If the file is not found (device not provisioned) we
326 // will return an empty AttestationIdInfo info to match the c++ code behavior
327 let content = match get_file_contents(KM_ATTESTATION_ID_FILENAME) {
328 Ok(Some(file_contents)) => file_contents,
329 Ok(None) => return Ok(AttestationIdInfo::default()),
330 Err(e) => return Err(e),
331 };
332 let mut attestation_ids_pb: keymaster_attributes::AttestationIds =
333 Message::parse_from_bytes(content.as_slice())
334 .map_err(|e| km_err!(UnknownError, "failed to parse attestation IDs proto: {:?}", e))?;
335
336 let brand = attestation_ids_pb.take_brand();
337 let device = attestation_ids_pb.take_device();
338 let product = attestation_ids_pb.take_product();
339 let serial = attestation_ids_pb.take_serial();
340 let imei = attestation_ids_pb.take_imei();
341 let meid = attestation_ids_pb.take_meid();
342 let manufacturer = attestation_ids_pb.take_manufacturer();
343 let model = attestation_ids_pb.take_model();
344
345 let imei2 = if attestation_ids_pb.has_second_imei() {
346 // A second IMEI has been explicitly provisioned, so use that.
347 attestation_ids_pb.take_second_imei()
348 } else if cfg!(feature = "auto_second_imei") {
349 // No second IMEI has been explicitly provisioned, but dual-SIM devices typically ship with
350 // two sequential IMEIs, so treat (IMEI+1) as the second IMEI.
351 kmr_common::tag::increment_imei(&imei)
352 } else {
353 Vec::new()
354 };
355
356 Ok(AttestationIdInfo { brand, device, product, serial, imei, imei2, meid, manufacturer, model })
357 }
358
359 /// Retrieve that attestation key information for the specified signing algorithm.
360 /// Returns an empty protobuf when file is not found to match c++ behavior
read_attestation_key_content( key_type: SigningAlgorithm, ) -> Result<keymaster_attributes::AttestationKey, Error>361 fn read_attestation_key_content(
362 key_type: SigningAlgorithm,
363 ) -> Result<keymaster_attributes::AttestationKey, Error> {
364 let file_name = get_key_slot_file_name(key_type);
365 let pb = match get_file_contents(&file_name)? {
366 Some(content) => Message::parse_from_bytes(content.as_slice())
367 .map_err(|e| km_err!(UnknownError, "failed to parse attestation key proto: {:?}", e))?,
368 None => keymaster_attributes::AttestationKey::new(),
369 };
370 Ok(pb)
371 }
372
373 /// Tries to parse an EC private key as a SEC1 private EC key. If that fails, it tries to parse it
374 /// as a PKCS#8 encoded key.
import_ec_key(key_buffer: &[u8]) -> Result<KeyMaterial, Error>375 fn import_ec_key(key_buffer: &[u8]) -> Result<KeyMaterial, Error> {
376 match crypto::ec::import_sec1_private_key(key_buffer) {
377 Ok(key_material) => Ok(key_material),
378 Err(e) => {
379 info!("couldn't parse as sec1 ECPrivateKey, will try as PKCS#8. Error {:?}", e);
380 crypto::ec::import_pkcs8_key(key_buffer)
381 }
382 }
383 }
384
385 /// Tries to parse an RSA key as a PKCS#1 encoded key. If that fails, it tries to parse it as a
386 /// PKCS#8 one.
import_rsa_key(key_buffer: &[u8]) -> Result<KeyMaterial, Error>387 fn import_rsa_key(key_buffer: &[u8]) -> Result<KeyMaterial, Error> {
388 match crypto::rsa::import_pkcs1_key(key_buffer) {
389 Ok((key_material, _, _)) => Ok(key_material),
390 Err(e) => {
391 info!("couldn't parse PKCS#1 RSA key, will try as PKCS#8. Error {:?}", e);
392 let (key_material, _, _) = crypto::rsa::import_pkcs8_key(key_buffer)?;
393 Ok(key_material)
394 }
395 }
396 }
397
398 /// Retrieve the specified attestation key from the file in secure storage.
read_attestation_key(key_type: SigningKeyType) -> Result<KeyMaterial, Error>399 pub(crate) fn read_attestation_key(key_type: SigningKeyType) -> Result<KeyMaterial, Error> {
400 let mut attestation_key_pb: keymaster_attributes::AttestationKey =
401 read_attestation_key_content(key_type.algo_hint)?;
402
403 if !(attestation_key_pb.has_key()) {
404 return Err(km_err!(UnknownError, "attestation Key file found but it had no key"));
405 }
406 let key_buffer = attestation_key_pb.take_key();
407
408 match key_type.algo_hint {
409 SigningAlgorithm::Ec => import_ec_key(&key_buffer),
410 SigningAlgorithm::Rsa => import_rsa_key(&key_buffer),
411 }
412 }
413
get_cert_chain(key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error>414 pub(crate) fn get_cert_chain(key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error> {
415 let mut attestation_certs_pb: keymaster_attributes::AttestationKey =
416 read_attestation_key_content(key_type.algo_hint)?;
417 let certs = attestation_certs_pb.take_certs();
418
419 let num_certs = certs.len();
420 if num_certs == 0 {
421 return Err(km_err!(UnknownError, "attestation Key file found but it had no certs"));
422 }
423 let mut certificates = vec_try_with_capacity!(num_certs)?;
424 for mut cert in certs {
425 let certificate = keymint::Certificate { encoded_certificate: cert.take_content() };
426 certificates.push(certificate);
427 }
428 Ok(certificates)
429 }
430
431 /// Implementation of attestation ID retrieval trait based on protobuf-encoded data in a file in
432 /// secure storage.
433 pub struct AttestationIds;
434
435 impl RetrieveAttestationIds for AttestationIds {
get(&self) -> Result<AttestationIdInfo, Error>436 fn get(&self) -> Result<AttestationIdInfo, Error> {
437 read_attestation_ids()
438 }
439
440 /// Destroy all attestation IDs associated with the device.
destroy_all(&mut self) -> Result<(), Error>441 fn destroy_all(&mut self) -> Result<(), Error> {
442 delete_attestation_ids()
443 }
444 }
445
446 /// Implementation of attestation signing key retrieval trait based on data held in files in secure
447 /// storage.
448 pub struct CertSignInfo;
449
450 impl RetrieveCertSigningInfo for CertSignInfo {
signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error>451 fn signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error> {
452 let result = read_attestation_key(key_type);
453 #[cfg(feature = "soft_attestation_fallback")]
454 if let Err(e) = result {
455 info!("failed to read attestation key ({:?}), fall back to test key", e);
456 let fake = software::CertSignInfo::new();
457 return fake.signing_key(key_type);
458 }
459 result
460 }
461
cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error>462 fn cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error> {
463 let result = get_cert_chain(key_type);
464 #[cfg(feature = "soft_attestation_fallback")]
465 if let Err(e) = result {
466 info!("failed to read attestation chain ({:?}), fall back to test chain", e);
467 let fake = software::CertSignInfo::new();
468 return fake.cert_chain(key_type);
469 }
470 result
471 }
472 }
473
474 #[allow(dead_code)]
475 #[cfg(test)]
476 mod tests {
477 use super::*;
478 use alloc::vec;
479 use core::iter::zip;
480 use kmr_common::wire::AttestationIdInfo;
481 use kmr_ta::device::{SigningAlgorithm, SigningKey, SigningKeyType};
482 use test::{expect, expect_eq};
483
484 // Generated by:
485 // openssl genpkey -out rsakey2.key -outform DER -algorithm RSA -pkeyopt rsa_keygen_bits:2048
486 // openssl pkcs8 -topk8 -in rsakey2.key -outform der -nocrypt -out rsakey.key
487 const RSA_KEY: &'static [u8] = include_bytes!("rsakey.key");
488 // Generated by:
489 // openssl ecparam -name prime256v1 -genkey -outform der -out eckey2.key
490 // openssl pkcs8 -topk8 -in eckey2.key -outform der -nocrypt -out eckey.key
491 const EC_KEY: &'static [u8] = include_bytes!("eckey.key");
492 // Generated by:
493 // openssl genpkey -out rsakey2.key -outform DER -algorithm RSA -pkeyopt rsa_keygen_bits:2048
494 const RSA_KEY_PKCS1: &'static [u8] = include_bytes!("rsakeyrfc3447.key");
495 // Generated by:
496 // openssl ecparam -name prime256v1 -genkey -outform der -out eckey2.key
497 const EC_PRIVATE_KEY_SEC1: &'static [u8] = include_bytes!("eckeysec1.key");
498
delete_key_file(algorithm: SigningAlgorithm)499 fn delete_key_file(algorithm: SigningAlgorithm) {
500 let file_name = get_key_slot_file_name(algorithm);
501 let mut session =
502 Session::new(Port::TamperProof, true).expect("Couldn't connect to storage");
503 session.remove(&file_name).expect("Couldn't delete attestation file.");
504 }
505
check_key_file_exists(algorithm: SigningAlgorithm) -> bool506 fn check_key_file_exists(algorithm: SigningAlgorithm) -> bool {
507 let mut session =
508 Session::new(Port::TamperProof, true).expect("Couldn't connect to storage");
509 let file_name = get_key_slot_file_name(algorithm);
510 session.open_file(&file_name, OpenMode::Open).is_ok()
511 }
512
delete_attestation_id_file()513 fn delete_attestation_id_file() {
514 let mut session =
515 Session::new(Port::TamperProof, true).expect("Couldn't connect to storage");
516 session.remove(KM_ATTESTATION_ID_FILENAME).expect("Couldn't delete attestation IDs file.");
517 }
518
check_attestation_id_file_exists() -> bool519 fn check_attestation_id_file_exists() -> bool {
520 let mut session =
521 Session::new(Port::TamperProof, true).expect("Couldn't connect to storage");
522 session.open_file(KM_ATTESTATION_ID_FILENAME, OpenMode::Open).is_ok()
523 }
524
compare_attestation_ids(lhs: &AttestationIdInfo, rhs: &AttestationIdInfo)525 fn compare_attestation_ids(lhs: &AttestationIdInfo, rhs: &AttestationIdInfo) {
526 expect_eq!(lhs.brand, rhs.brand, "brand doesn't match");
527 expect_eq!(lhs.device, rhs.device, "device doesn't match");
528 expect_eq!(lhs.product, rhs.product, "product doesn't match");
529 expect_eq!(lhs.serial, rhs.serial, "serial doesn't match");
530 expect_eq!(lhs.imei, rhs.imei, "imei doesn't match");
531 expect_eq!(lhs.meid, rhs.meid, "meid doesn't match");
532 expect_eq!(lhs.manufacturer, rhs.manufacturer, "manufacturer doesn't match");
533 expect_eq!(lhs.model, rhs.model, "model doesn't match");
534 expect_eq!(lhs.imei2, rhs.imei2, "imei2 doesn't match");
535 }
536
read_certificates_test(algorithm: SigningAlgorithm)537 fn read_certificates_test(algorithm: SigningAlgorithm) {
538 let mut file =
539 create_attestation_key_file(algorithm).expect("Couldn't create attestation key file");
540 let mut key_cert = keymaster_attributes::AttestationKey::new();
541 let certs_data = [[b'a'; 2048], [b'\0'; 2048], [b'c'; 2048]];
542
543 let mut certs = protobuf::RepeatedField::<keymaster_attributes::AttestationCert>::new();
544
545 for cert_data in certs_data.iter() {
546 let mut cert = keymaster_attributes::AttestationCert::new();
547 cert.set_content(cert_data.to_vec());
548 certs.push(cert);
549 }
550
551 key_cert.set_certs(certs);
552
553 let serialized_buffer = key_cert.write_to_bytes().expect("Couldn't serialize certs");
554
555 file.write_all(&serialized_buffer).unwrap();
556 file.close();
557
558 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: algorithm };
559 let certs = get_cert_chain(key_type).expect("Couldn't get certificates from storage");
560 delete_key_file(algorithm);
561
562 expect_eq!(certs.len(), 3, "Didn't recover all certificates");
563 for (cert, cert_data) in zip(certs.iter(), certs_data.iter()) {
564 expect_eq!(cert.encoded_certificate, cert_data.to_vec(), "Wrong certificate retrieved");
565 }
566
567 // Trying now using just a raw protobuf with same data
568 let field_header = [18, 131, 16, 10, 128, 16];
569 let mut raw_protobuf = Vec::new();
570 for cert_data in certs_data.iter() {
571 raw_protobuf.extend_from_slice(&field_header);
572 raw_protobuf.extend_from_slice(cert_data);
573 }
574
575 let mut file =
576 create_attestation_key_file(algorithm).expect("Couldn't create attestation key file");
577 file.write_all(&raw_protobuf).unwrap();
578 file.close();
579
580 let certs_comp = get_cert_chain(key_type).expect("Couldn't get certificates from storage");
581
582 expect_eq!(certs, certs_comp, "Retrieved certificates didn't match");
583
584 delete_key_file(algorithm);
585 }
586
587 // This test should be run manually as it writes to storage.
588 // #[test]
read_ec_rsa_certificates()589 fn read_ec_rsa_certificates() {
590 read_certificates_test(SigningAlgorithm::Rsa);
591 read_certificates_test(SigningAlgorithm::Ec);
592 }
593
get_test_key_data(algorithm: SigningAlgorithm) -> &'static [u8]594 fn get_test_key_data(algorithm: SigningAlgorithm) -> &'static [u8] {
595 match algorithm {
596 SigningAlgorithm::Rsa => RSA_KEY,
597 SigningAlgorithm::Ec => EC_KEY,
598 }
599 }
600
get_non_pkcs8_test_key_data(algorithm: SigningAlgorithm) -> &'static [u8]601 fn get_non_pkcs8_test_key_data(algorithm: SigningAlgorithm) -> &'static [u8] {
602 match algorithm {
603 SigningAlgorithm::Rsa => RSA_KEY_PKCS1,
604 SigningAlgorithm::Ec => EC_PRIVATE_KEY_SEC1,
605 }
606 }
607
get_test_attestation_key(algorithm: SigningAlgorithm) -> Result<KeyMaterial, Error>608 fn get_test_attestation_key(algorithm: SigningAlgorithm) -> Result<KeyMaterial, Error> {
609 let key_buffer = get_test_key_data(algorithm);
610 let key = match algorithm {
611 SigningAlgorithm::Ec => crypto::ec::import_pkcs8_key(key_buffer)?,
612 SigningAlgorithm::Rsa => {
613 let (key_material, _key_size, _exponent) =
614 crypto::rsa::import_pkcs8_key(key_buffer)?;
615 key_material
616 }
617 };
618 Ok(key)
619 }
620
621 // This test should be run manually as it writes to storage.
622 // #[test]
multiple_attestation_calls_work()623 fn multiple_attestation_calls_work() {
624 let ec_test_key =
625 get_test_attestation_key(SigningAlgorithm::Ec).expect("Couldn't get test key");
626 let rsa_test_key =
627 get_test_attestation_key(SigningAlgorithm::Rsa).expect("Couldn't get test key");
628
629 provision_attestation_key_file(SigningAlgorithm::Ec, EC_KEY)
630 .expect("Couldn't provision key");
631 provision_attestation_key_file(SigningAlgorithm::Rsa, RSA_KEY)
632 .expect("Couldn't provision key");
633 provision_attestation_key_file(SigningAlgorithm::Rsa, &[0])
634 .expect("Couldn't provision key");
635 provision_attestation_key_file(SigningAlgorithm::Ec, &[0, 0])
636 .expect("Couldn't provision key");
637 provision_attestation_key_file(SigningAlgorithm::Ec, EC_KEY)
638 .expect("Couldn't provision key");
639 provision_attestation_key_file(SigningAlgorithm::Rsa, RSA_KEY)
640 .expect("Couldn't provision key");
641
642 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: SigningAlgorithm::Ec };
643 let read_ec_test_key =
644 read_attestation_key(key_type).expect("Couldn't read key from storage");
645
646 let key_type =
647 SigningKeyType { which: SigningKey::Batch, algo_hint: SigningAlgorithm::Rsa };
648 let read_rsa_test_key =
649 read_attestation_key(key_type).expect("Couldn't read key from storage");
650
651 delete_key_file(SigningAlgorithm::Ec);
652 delete_key_file(SigningAlgorithm::Rsa);
653
654 expect_eq!(ec_test_key, read_ec_test_key, "Provisioned key doesn't match original one");
655 expect_eq!(rsa_test_key, read_rsa_test_key, "Provisioned key doesn't match original one");
656 }
657
read_key_test(algorithm: SigningAlgorithm)658 fn read_key_test(algorithm: SigningAlgorithm) {
659 let test_key = get_test_key_data(algorithm);
660
661 provision_attestation_key_file(algorithm, test_key).expect("Couldn't provision key");
662
663 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: algorithm };
664 let att_key = read_attestation_key(key_type).expect("Couldn't read key from storage");
665
666 delete_key_file(algorithm);
667
668 // Trying now using just a raw protobuf with same data
669 let key_header = match algorithm {
670 SigningAlgorithm::Rsa => [10, 191, 9],
671 SigningAlgorithm::Ec => [10, 138, 1],
672 };
673 let mut raw_protobuf = Vec::new();
674 raw_protobuf.extend_from_slice(&key_header);
675 raw_protobuf.extend_from_slice(&test_key);
676
677 let mut file =
678 create_attestation_key_file(algorithm).expect("Couldn't create attestation key file");
679 file.write_all(&raw_protobuf).unwrap();
680 file.close();
681
682 let att_key_comp = read_attestation_key(key_type).expect("Couldn't read key from storage");
683
684 expect_eq!(att_key, att_key_comp);
685
686 delete_key_file(algorithm);
687 }
688
689 // This test should be run manually as it writes to storage.
690 // #[test]
read_ec_rsa_key()691 fn read_ec_rsa_key() {
692 read_key_test(SigningAlgorithm::Rsa);
693 read_key_test(SigningAlgorithm::Ec);
694 }
695
read_non_pkcs8_key_test(algorithm: SigningAlgorithm)696 fn read_non_pkcs8_key_test(algorithm: SigningAlgorithm) {
697 let test_key = get_non_pkcs8_test_key_data(algorithm);
698
699 provision_attestation_key_file(algorithm, test_key).expect("Couldn't provision key");
700
701 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: algorithm };
702 let att_key = read_attestation_key(key_type);
703 expect!(att_key.is_ok(), "Couldn't read a non-pkcs8 key from storage");
704
705 delete_key_file(algorithm);
706 }
707
708 // This test should be run manually as it writes to storage.
709 // #[test]
read_sec1_private_ec_key()710 fn read_sec1_private_ec_key() {
711 read_non_pkcs8_key_test(SigningAlgorithm::Ec);
712 }
713
714 // This test should be run manually as it writes to storage.
715 // #[test]
read_pkcs1_rsa_key()716 fn read_pkcs1_rsa_key() {
717 read_non_pkcs8_key_test(SigningAlgorithm::Rsa);
718 }
719
720 // This test should be run manually as it writes to storage.
721 // #[test]
unprovisioned_keys_certs_reads_produces_error()722 fn unprovisioned_keys_certs_reads_produces_error() {
723 if check_key_file_exists(SigningAlgorithm::Ec) {
724 delete_key_file(SigningAlgorithm::Ec);
725 }
726 if check_key_file_exists(SigningAlgorithm::Rsa) {
727 delete_key_file(SigningAlgorithm::Rsa);
728 }
729 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: SigningAlgorithm::Ec };
730 expect!(read_attestation_key(key_type).is_err(), "Shouldn't be able to read a key");
731 let key_type =
732 SigningKeyType { which: SigningKey::Batch, algo_hint: SigningAlgorithm::Rsa };
733 expect!(read_attestation_key(key_type).is_err(), "Shouldn't be able to read a key");
734 }
735
736 // This test should be run manually as it writes to storage.
737 // #[test]
provision_certs_test()738 fn provision_certs_test() {
739 provision_certs_test_impl(SigningAlgorithm::Ec, true);
740 provision_certs_test_impl(SigningAlgorithm::Rsa, true);
741 provision_certs_test_impl(SigningAlgorithm::Ec, false);
742 provision_certs_test_impl(SigningAlgorithm::Rsa, false);
743 }
744
provision_certs_test_impl(algorithm: SigningAlgorithm, key_first: bool)745 fn provision_certs_test_impl(algorithm: SigningAlgorithm, key_first: bool) {
746 if check_key_file_exists(algorithm) {
747 delete_key_file(algorithm);
748 }
749 let test_key = get_test_key_data(algorithm);
750 if key_first {
751 provision_attestation_key_file(algorithm, test_key).expect("Couldn't provision key");
752 }
753 let cert1 = [b'a'; 2048].as_slice();
754 let cert2 = [b'b'; 2048].as_slice();
755 let cert3 = [b'c'; 2048].as_slice();
756 let certs = [cert1, cert2, cert3];
757 for cert_data in certs.iter() {
758 append_attestation_cert_chain(algorithm, cert_data)
759 .expect("Couldn't provision certificate");
760 }
761 expect!(
762 append_attestation_cert_chain(algorithm, cert3).is_err(),
763 "Shouldn't be able to add more certificates"
764 );
765 if !key_first {
766 provision_attestation_key_file(algorithm, test_key).expect("Couldn't provision key");
767 }
768 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: algorithm };
769 let read_test_key = read_attestation_key(key_type).expect("Couldn't read attestation key");
770 //Getting test key data on a format that can be compared with the key in storage
771 let test_key = get_test_attestation_key(algorithm).expect("Couldn't get test key");
772 expect_eq!(test_key, read_test_key, "Test keys didn't match");
773
774 let read_certs = get_cert_chain(key_type).expect("Couldn't get certificates from storage");
775 expect_eq!(read_certs.len(), 3, "Didn't get all certificates back");
776 for (cert, read_cert) in certs.iter().zip(read_certs.iter()) {
777 expect_eq!(cert, &read_cert.encoded_certificate, "got wrong certificate back");
778 }
779 delete_key_file(algorithm);
780 }
781
clear_certificate_chain_works_when_unprovisioned_impl(algorithm: SigningAlgorithm)782 fn clear_certificate_chain_works_when_unprovisioned_impl(algorithm: SigningAlgorithm) {
783 if check_key_file_exists(algorithm) {
784 delete_key_file(algorithm);
785 }
786 clear_attestation_cert_chain(algorithm).expect("couldn't clear certificate chain");
787 expect!(
788 check_key_file_exists(algorithm) == false,
789 "Shouldn't have created a file if it didn't existed originally"
790 );
791 }
792
793 // This test should be run manually as it writes to storage.
794 // #[test]
clear_certificate_chain_works_when_unprovisioned()795 fn clear_certificate_chain_works_when_unprovisioned() {
796 clear_certificate_chain_works_when_unprovisioned_impl(SigningAlgorithm::Ec);
797 clear_certificate_chain_works_when_unprovisioned_impl(SigningAlgorithm::Rsa);
798 }
799
clear_certificate_chain_works_impl(algorithm: SigningAlgorithm)800 fn clear_certificate_chain_works_impl(algorithm: SigningAlgorithm) {
801 if check_key_file_exists(algorithm) {
802 delete_key_file(algorithm);
803 }
804 let test_key = get_test_key_data(algorithm);
805 provision_attestation_key_file(algorithm, test_key).expect("Couldn't provision key");
806 let cert = [b'a'; 2048].as_slice();
807 append_attestation_cert_chain(algorithm, cert).expect("Couldn't provision certificate");
808
809 let key_type = SigningKeyType { which: SigningKey::Batch, algo_hint: algorithm };
810 let read_certs = get_cert_chain(key_type).expect("Couldn't get certificates from storage");
811 expect_eq!(read_certs.len(), 1, "Didn't get all certificates back");
812
813 clear_attestation_cert_chain(algorithm).expect("couldn't clear certificate chain");
814
815 expect!(get_cert_chain(key_type).is_err(), "Certificates were not deleted");
816
817 let read_test_key = read_attestation_key(key_type).expect("Couldn't read attestation key");
818 //Getting test key data on a format that can be compared with the key in storage
819 let test_key = get_test_attestation_key(algorithm).expect("Couldn't get test key");
820 expect_eq!(test_key, read_test_key, "Test keys didn't match");
821
822 delete_key_file(algorithm);
823 }
824
825 // This test should be run manually as it writes to storage.
826 // #[test]
clear_certificate_chain_works()827 fn clear_certificate_chain_works() {
828 clear_certificate_chain_works_impl(SigningAlgorithm::Ec);
829 clear_certificate_chain_works_impl(SigningAlgorithm::Rsa);
830 }
831
832 // This test should be run manually as it writes to storage.
833 // #[test]
unprovisioned_attestation_ids_do_not_error()834 fn unprovisioned_attestation_ids_do_not_error() {
835 if check_attestation_id_file_exists() {
836 delete_attestation_id_file();
837 }
838 let attestation_ids =
839 read_attestation_ids().expect("Couldn't read attestation IDs when unprovisioned");
840
841 expect_eq!(attestation_ids.brand.len(), 0, "brand should be empty");
842 expect_eq!(attestation_ids.device.len(), 0, "device should be empty");
843 expect_eq!(attestation_ids.product.len(), 0, "product should be empty");
844 expect_eq!(attestation_ids.serial.len(), 0, "serial should be empty");
845 expect_eq!(attestation_ids.imei.len(), 0, "imei should be empty");
846 expect_eq!(attestation_ids.meid.len(), 0, "meid should be empty");
847 expect_eq!(attestation_ids.manufacturer.len(), 0, "manufacturer should be empty");
848 expect_eq!(attestation_ids.model.len(), 0, "model should be empty");
849 expect_eq!(attestation_ids.imei2.len(), 0, "imei2 should be empty");
850 }
851
852 // This test should be run manually as it writes to storage.
853 // #[test]
single_attestation_id_field()854 fn single_attestation_id_field() {
855 let mut file = create_attestation_id_file().expect("Couldn't create attestation id file");
856
857 let mut attestation_ids = keymaster_attributes::AttestationIds::new();
858 let brand = b"new brand";
859
860 attestation_ids.set_brand(brand.to_vec());
861
862 let serialized_buffer =
863 attestation_ids.write_to_bytes().expect("Couldn't serialize attestationIds");
864
865 file.write_all(&serialized_buffer).unwrap();
866 file.close();
867
868 let attestation_ids_info =
869 read_attestation_ids().expect("Couldn't read attestation IDs from storage");
870
871 delete_attestation_id_file();
872 expect_eq!(
873 check_attestation_id_file_exists(),
874 false,
875 "Couldn't delete attestation IDs file"
876 );
877
878 expect_eq!(attestation_ids_info.brand, brand.to_vec(), "brand doesn't match");
879 expect_eq!(attestation_ids_info.device.len(), 0, "shouldn't have a device");
880 expect_eq!(attestation_ids_info.product.len(), 0, "shouldn't have a product");
881 expect_eq!(attestation_ids_info.serial.len(), 0, "shouldn't have a serial");
882 expect_eq!(attestation_ids_info.imei.len(), 0, "shouldn't have a imei");
883 expect_eq!(attestation_ids_info.meid.len(), 0, "shouldn't have a meid");
884 expect_eq!(attestation_ids_info.manufacturer.len(), 0, "shouldn't have a manufacturer");
885 expect_eq!(attestation_ids_info.model.len(), 0, "shouldn't have a model");
886 expect_eq!(attestation_ids_info.imei2.len(), 0, "shouldn't have a model");
887
888 // Now using a raw protobuf
889 let raw_protobuf = [10, 9, 110, 101, 119, 32, 98, 114, 97, 110, 100];
890
891 let mut file = create_attestation_id_file().expect("Couldn't create attestation id file");
892 file.write_all(&raw_protobuf).unwrap();
893 file.close();
894
895 let attestation_ids_comp = read_attestation_ids()
896 .expect("Couldn't read comparison set of attestation IDs from storage");
897
898 compare_attestation_ids(&attestation_ids_info, &attestation_ids_comp);
899
900 delete_attestation_id_file();
901 expect_eq!(
902 check_attestation_id_file_exists(),
903 false,
904 "Couldn't delete attestation IDs file"
905 );
906 }
907
908 // This test should be run manually as it writes to storage.
909 // #[test]
test_provision_attestation_id_file()910 fn test_provision_attestation_id_file() {
911 let brand = b"unknown brand";
912 let product = b"";
913 let device = b"my brand new device";
914 let serial = vec![b'9'; 64];
915 let imei = b" ";
916 let meid = b"\0";
917 let manufacturer = b"manufacturer #$%%^";
918 let model = b"working one";
919 let imei2 = b"0";
920
921 assert!(provision_attestation_id_file(
922 brand,
923 product,
924 device,
925 &serial,
926 imei,
927 meid,
928 manufacturer,
929 model,
930 Some(imei2)
931 )
932 .is_ok());
933
934 let attestation_ids_info =
935 read_attestation_ids().expect("Couldn't read attestation IDs from storage");
936
937 delete_attestation_id_file();
938 expect_eq!(
939 check_attestation_id_file_exists(),
940 false,
941 "Couldn't delete attestation IDs file"
942 );
943
944 expect_eq!(attestation_ids_info.brand, brand.to_vec(), "brand doesn't match");
945 expect_eq!(attestation_ids_info.device, device.to_vec(), "device doesn't match");
946 expect_eq!(attestation_ids_info.product, product.to_vec(), "product doesn't match");
947 expect_eq!(attestation_ids_info.serial, serial, "serial doesn't match");
948 expect_eq!(attestation_ids_info.imei, imei.to_vec(), "imei doesn't match");
949 expect_eq!(attestation_ids_info.meid, meid.to_vec(), "meid doesn't match");
950 expect_eq!(
951 attestation_ids_info.manufacturer,
952 manufacturer.to_vec(),
953 "manufacturer doesn't match"
954 );
955 expect_eq!(attestation_ids_info.model, model.to_vec(), "model doesn't match");
956 expect_eq!(attestation_ids_info.imei2, imei2.to_vec(), "imei2 doesn't match");
957 }
958
959 #[test]
test_provision_attestation_id_file_imei2_none()960 fn test_provision_attestation_id_file_imei2_none() {
961 let brand = b"unknown brand";
962 let product = b"";
963 let device = b"my brand new device";
964 let serial = vec![b'9'; 64];
965 let imei = b"000000123456782";
966 let meid = b"\0";
967 let manufacturer = b"manufacturer #$%%^";
968 let model = b"working one";
969 let expected_imei2 = b"123456790";
970
971 assert!(provision_attestation_id_file(
972 brand,
973 product,
974 device,
975 &serial,
976 imei,
977 meid,
978 manufacturer,
979 model,
980 None
981 )
982 .is_ok());
983
984 let attestation_ids_info =
985 read_attestation_ids().expect("Couldn't read attestation IDs from storage");
986
987 delete_attestation_id_file();
988 expect_eq!(
989 check_attestation_id_file_exists(),
990 false,
991 "Couldn't delete attestation IDs file"
992 );
993
994 expect_eq!(attestation_ids_info.brand, brand.to_vec(), "brand doesn't match");
995 expect_eq!(attestation_ids_info.device, device.to_vec(), "device doesn't match");
996 expect_eq!(attestation_ids_info.product, product.to_vec(), "product doesn't match");
997 expect_eq!(attestation_ids_info.serial, serial, "serial doesn't match");
998 expect_eq!(attestation_ids_info.imei, imei.to_vec(), "imei doesn't match");
999 expect_eq!(attestation_ids_info.meid, meid.to_vec(), "meid doesn't match");
1000 expect_eq!(
1001 attestation_ids_info.manufacturer,
1002 manufacturer.to_vec(),
1003 "manufacturer doesn't match"
1004 );
1005 expect_eq!(attestation_ids_info.model, model.to_vec(), "model doesn't match");
1006 expect_eq!(attestation_ids_info.imei2, expected_imei2.to_vec(), "imei2 doesn't match");
1007 }
1008
1009 // This test should be run manually as it writes to storage.
1010 // #[test]
all_attestation_id_fields()1011 fn all_attestation_id_fields() {
1012 let mut file = create_attestation_id_file().expect("Couldn't create attestation id file");
1013 let mut attestation_ids = keymaster_attributes::AttestationIds::new();
1014 let brand = b"unknown brand";
1015 let device = b"my brand new device";
1016 let product = b"";
1017 let serial = vec![b'9'; 64];
1018 let imei = b" ";
1019 let meid = b"\0";
1020 let manufacturer = b"manufacturer #$%%^";
1021 let model = b"working one";
1022 let imei2 = b"0";
1023
1024 attestation_ids.set_brand(brand.to_vec());
1025 attestation_ids.set_device(device.to_vec());
1026 attestation_ids.set_product(product.to_vec());
1027 attestation_ids.set_serial(serial.clone());
1028 attestation_ids.set_imei(imei.to_vec());
1029 attestation_ids.set_meid(meid.to_vec());
1030 attestation_ids.set_manufacturer(manufacturer.to_vec());
1031 attestation_ids.set_model(model.to_vec());
1032 attestation_ids.set_second_imei(imei2.to_vec());
1033
1034 let serialized_buffer =
1035 attestation_ids.write_to_bytes().expect("Couldn't serialize attestationIds");
1036
1037 file.write_all(&serialized_buffer).unwrap();
1038 file.close();
1039
1040 let attestation_ids_info =
1041 read_attestation_ids().expect("Couldn't read attestation IDs from storage");
1042
1043 delete_attestation_id_file();
1044 expect_eq!(
1045 check_attestation_id_file_exists(),
1046 false,
1047 "Couldn't delete attestation IDs file"
1048 );
1049
1050 expect_eq!(attestation_ids_info.brand, brand.to_vec(), "brand doesn't match");
1051 expect_eq!(attestation_ids_info.device, device.to_vec(), "device doesn't match");
1052 expect_eq!(attestation_ids_info.product, product.to_vec(), "product doesn't match");
1053 expect_eq!(attestation_ids_info.serial, serial, "serial doesn't match");
1054 expect_eq!(attestation_ids_info.imei, imei.to_vec(), "imei doesn't match");
1055 expect_eq!(attestation_ids_info.meid, meid.to_vec(), "meid doesn't match");
1056 expect_eq!(
1057 attestation_ids_info.manufacturer,
1058 manufacturer.to_vec(),
1059 "manufacturer doesn't match"
1060 );
1061 expect_eq!(attestation_ids_info.model, model.to_vec(), "model doesn't match");
1062 expect_eq!(attestation_ids_info.imei2, imei2.to_vec(), "imei2 doesn't match");
1063
1064 // Now trying the same from a raw protobuf
1065 let raw_protobuf = [
1066 10, 13, 117, 110, 107, 110, 111, 119, 110, 32, 98, 114, 97, 110, 100, 18, 19, 109, 121,
1067 32, 98, 114, 97, 110, 100, 32, 110, 101, 119, 32, 100, 101, 118, 105, 99, 101, 26, 0,
1068 34, 64, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
1069 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
1070 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
1071 42, 1, 32, 50, 1, 0, 58, 18, 109, 97, 110, 117, 102, 97, 99, 116, 117, 114, 101, 114,
1072 32, 35, 36, 37, 37, 94, 66, 11, 119, 111, 114, 107, 105, 110, 103, 32, 111, 110, 101,
1073 74, 1, 48,
1074 ];
1075
1076 let mut file = create_attestation_id_file().expect("Couldn't create attestation id file");
1077 file.write_all(&raw_protobuf).unwrap();
1078 file.close();
1079
1080 let attestation_ids_comp = read_attestation_ids()
1081 .expect("Couldn't read comparison set of attestation IDs from storage");
1082
1083 compare_attestation_ids(&attestation_ids_info, &attestation_ids_comp);
1084
1085 delete_attestation_id_file();
1086 expect_eq!(
1087 check_attestation_id_file_exists(),
1088 false,
1089 "Couldn't delete attestation IDs file"
1090 );
1091 }
1092
1093 // This test should be run manually as it writes to storage.
1094 // #[test]
delete_attestation_ids_file()1095 fn delete_attestation_ids_file() {
1096 let mut file = create_attestation_id_file().expect("Couldn't create attestation id file");
1097 let raw_protobuf = [10, 9, 110, 101, 119, 32, 98, 114, 97, 110, 100];
1098 file.write_all(&raw_protobuf).unwrap();
1099 file.close();
1100
1101 expect!(check_attestation_id_file_exists(), "Couldn't create attestation IDs file");
1102 expect!(delete_attestation_ids().is_ok(), "Couldn't delete attestation IDs file");
1103 expect_eq!(
1104 check_attestation_id_file_exists(),
1105 false,
1106 "Attestation IDs file was not deleted"
1107 );
1108 }
1109
1110 #[test]
protobuf_lib_version()1111 fn protobuf_lib_version() {
1112 // We are generating the protobuf rust files out of tree because we cannot do it in-tree yet
1113 // Because the version of the tool used to autogenerate the files has to match the protobuf
1114 // library version, we check it here.
1115 expect_eq!("2.27.1", protobuf::VERSION, "autogenerated files version mistmatch");
1116 }
1117 }
1118