blob: 76da00a73b2070d466896361e7d2be2eceddbc48 [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
Alan Stokes16fb8552022-02-10 15:07:27 +000020use crate::compos_key;
Alan Stokes183d7d32021-12-08 16:10:45 +000021use crate::fsverity;
22use anyhow::{anyhow, Context, Result};
23use odsign_proto::odsign_info::OdsignInfo;
24use protobuf::Message;
25use std::fs::File;
26use std::io::Write;
Victor Hsieh4333d522022-08-26 11:27:08 -070027use std::os::unix::io::AsFd;
Alan Stokes46a1dff2021-12-14 10:56:05 +000028use std::path::Path;
Alan Stokes183d7d32021-12-08 16:10:45 +000029
30const TARGET_DIRECTORY: &str = "/data/misc/apexdata/com.android.art/dalvik-cache";
31const SIGNATURE_EXTENSION: &str = ".signature";
32
33/// Accumulates and then signs information about generated artifacts.
34pub struct ArtifactSigner<'a> {
Alan Stokes46a1dff2021-12-14 10:56:05 +000035 base_directory: &'a Path,
Alan Stokes183d7d32021-12-08 16:10:45 +000036 file_digests: Vec<(String, String)>, // (File name, digest in hex)
37}
38
39impl<'a> ArtifactSigner<'a> {
40 /// base_directory specifies the directory under which the artifacts are currently located;
41 /// they will eventually be moved under TARGET_DIRECTORY once they are verified and activated.
Alan Stokes46a1dff2021-12-14 10:56:05 +000042 pub fn new(base_directory: &'a Path) -> Self {
43 Self { base_directory, file_digests: Vec::new() }
Alan Stokes183d7d32021-12-08 16:10:45 +000044 }
45
Alan Stokes46a1dff2021-12-14 10:56:05 +000046 pub fn add_artifact(&mut self, path: &Path) -> Result<()> {
Alan Stokes183d7d32021-12-08 16:10:45 +000047 // The path we store is where the file will be when it is verified, not where it is now.
48 let suffix = path
Chris Wailes9b866f02022-11-16 15:17:16 -080049 .strip_prefix(self.base_directory)
Alan Stokes183d7d32021-12-08 16:10:45 +000050 .context("Artifacts must be under base directory")?;
51 let target_path = Path::new(TARGET_DIRECTORY).join(suffix);
52 let target_path = target_path.to_str().ok_or_else(|| anyhow!("Invalid path"))?;
53
Alan Stokes46a1dff2021-12-14 10:56:05 +000054 let file = File::open(path).with_context(|| format!("Opening {}", path.display()))?;
Victor Hsieh4333d522022-08-26 11:27:08 -070055 let digest = fsverity::measure(file.as_fd())?;
Alan Stokes183d7d32021-12-08 16:10:45 +000056 let digest = to_hex_string(&digest);
57
58 self.file_digests.push((target_path.to_owned(), digest));
59 Ok(())
60 }
61
62 /// Consume this ArtifactSigner and write details of all its artifacts to the given path,
63 /// with accompanying sigature file.
Alan Stokes16fb8552022-02-10 15:07:27 +000064 pub fn write_info_and_signature(self, info_path: &Path) -> Result<()> {
Alan Stokes183d7d32021-12-08 16:10:45 +000065 let mut info = OdsignInfo::new();
James Farrellf6935592023-08-15 20:01:56 +000066 info.file_hashes.extend(self.file_digests);
Alan Stokes183d7d32021-12-08 16:10:45 +000067 let bytes = info.write_to_bytes()?;
68
Alan Stokes16fb8552022-02-10 15:07:27 +000069 let signature = compos_key::sign(&bytes)?;
Alan Stokes183d7d32021-12-08 16:10:45 +000070
Alan Stokes35bac3c2021-12-16 14:37:24 +000071 let mut file =
72 File::create(info_path).with_context(|| format!("Creating {}", info_path.display()))?;
Alan Stokes183d7d32021-12-08 16:10:45 +000073 file.write_all(&bytes)?;
74
75 let mut signature_name = info_path.file_name().unwrap().to_owned();
76 signature_name.push(SIGNATURE_EXTENSION);
77 let signature_path = info_path.with_file_name(&signature_name);
Alan Stokes35bac3c2021-12-16 14:37:24 +000078 let mut signature_file = File::create(&signature_path)
79 .with_context(|| format!("Creating {}", signature_path.display()))?;
Alan Stokes183d7d32021-12-08 16:10:45 +000080 signature_file.write_all(&signature)?;
81
82 Ok(())
83 }
84}
85
86fn to_hex_string(buf: &[u8]) -> String {
87 buf.iter().map(|b| format!("{:02x}", b)).collect()
88}