blob: 54b8d7acb45bd9e0c32c5ca1e17c2bb8f1d9006c [file] [log] [blame]
Alan Stokes183d7d32021-12-08 16:10:45 +00001/*
2 * Copyright (C) 2021 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
17//! Support for generating and signing an info file listing names and digests of generated
18//! artifacts.
19
20#![allow(dead_code)] // Will be used soon
21
22use crate::compos_key_service::CompOsKeyService;
23use crate::fsverity;
24use anyhow::{anyhow, Context, Result};
25use odsign_proto::odsign_info::OdsignInfo;
26use protobuf::Message;
27use std::fs::File;
28use std::io::Write;
29use std::os::unix::io::AsRawFd;
30use std::path::{Path, PathBuf};
31
32const TARGET_DIRECTORY: &str = "/data/misc/apexdata/com.android.art/dalvik-cache";
33const SIGNATURE_EXTENSION: &str = ".signature";
34
35/// Accumulates and then signs information about generated artifacts.
36pub struct ArtifactSigner<'a> {
37 key_blob: Vec<u8>,
38 key_service: &'a CompOsKeyService,
39 base_directory: PathBuf,
40 file_digests: Vec<(String, String)>, // (File name, digest in hex)
41}
42
43impl<'a> ArtifactSigner<'a> {
44 /// base_directory specifies the directory under which the artifacts are currently located;
45 /// they will eventually be moved under TARGET_DIRECTORY once they are verified and activated.
46 pub fn new(
47 key_blob: Vec<u8>,
48 key_service: &'a CompOsKeyService,
49 base_directory: PathBuf,
50 ) -> Self {
51 ArtifactSigner { key_blob, key_service, base_directory, file_digests: Vec::new() }
52 }
53
54 pub fn add_artifact(&mut self, path: PathBuf) -> Result<()> {
55 // The path we store is where the file will be when it is verified, not where it is now.
56 let suffix = path
57 .strip_prefix(&self.base_directory)
58 .context("Artifacts must be under base directory")?;
59 let target_path = Path::new(TARGET_DIRECTORY).join(suffix);
60 let target_path = target_path.to_str().ok_or_else(|| anyhow!("Invalid path"))?;
61
62 let file = File::open(&path)?;
63 let digest = fsverity::measure(file.as_raw_fd())?;
64 let digest = to_hex_string(&digest);
65
66 self.file_digests.push((target_path.to_owned(), digest));
67 Ok(())
68 }
69
70 /// Consume this ArtifactSigner and write details of all its artifacts to the given path,
71 /// with accompanying sigature file.
72 pub fn write_info_and_signature(self, info_path: &Path) -> Result<()> {
73 let mut info = OdsignInfo::new();
74 info.mut_file_hashes().extend(self.file_digests.into_iter());
75 let bytes = info.write_to_bytes()?;
76
77 let signature = self.key_service.sign(&self.key_blob, &bytes)?;
78
79 let mut file = File::create(info_path)?;
80 file.write_all(&bytes)?;
81
82 let mut signature_name = info_path.file_name().unwrap().to_owned();
83 signature_name.push(SIGNATURE_EXTENSION);
84 let signature_path = info_path.with_file_name(&signature_name);
85 let mut signature_file = File::create(&signature_path)?;
86 signature_file.write_all(&signature)?;
87
88 Ok(())
89 }
90}
91
92fn to_hex_string(buf: &[u8]) -> String {
93 buf.iter().map(|b| format!("{:02x}", b)).collect()
94}