blob: a4b47d6c8837fda600c4aab9fa935a20217fe278 [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
Alan Stokes46a1dff2021-12-14 10:56:05 +000022use crate::compos_key_service::Signer;
Alan Stokes183d7d32021-12-08 16:10:45 +000023use 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;
Alan Stokes46a1dff2021-12-14 10:56:05 +000030use std::path::Path;
Alan Stokes183d7d32021-12-08 16:10:45 +000031
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> {
Alan Stokes46a1dff2021-12-14 10:56:05 +000037 base_directory: &'a Path,
Alan Stokes183d7d32021-12-08 16:10:45 +000038 file_digests: Vec<(String, String)>, // (File name, digest in hex)
39}
40
41impl<'a> ArtifactSigner<'a> {
42 /// base_directory specifies the directory under which the artifacts are currently located;
43 /// they will eventually be moved under TARGET_DIRECTORY once they are verified and activated.
Alan Stokes46a1dff2021-12-14 10:56:05 +000044 pub fn new(base_directory: &'a Path) -> Self {
45 Self { base_directory, file_digests: Vec::new() }
Alan Stokes183d7d32021-12-08 16:10:45 +000046 }
47
Alan Stokes46a1dff2021-12-14 10:56:05 +000048 pub fn add_artifact(&mut self, path: &Path) -> Result<()> {
Alan Stokes183d7d32021-12-08 16:10:45 +000049 // The path we store is where the file will be when it is verified, not where it is now.
50 let suffix = path
51 .strip_prefix(&self.base_directory)
52 .context("Artifacts must be under base directory")?;
53 let target_path = Path::new(TARGET_DIRECTORY).join(suffix);
54 let target_path = target_path.to_str().ok_or_else(|| anyhow!("Invalid path"))?;
55
Alan Stokes46a1dff2021-12-14 10:56:05 +000056 let file = File::open(path).with_context(|| format!("Opening {}", path.display()))?;
Alan Stokes183d7d32021-12-08 16:10:45 +000057 let digest = fsverity::measure(file.as_raw_fd())?;
58 let digest = to_hex_string(&digest);
59
60 self.file_digests.push((target_path.to_owned(), digest));
61 Ok(())
62 }
63
64 /// Consume this ArtifactSigner and write details of all its artifacts to the given path,
65 /// with accompanying sigature file.
Alan Stokes46a1dff2021-12-14 10:56:05 +000066 pub fn write_info_and_signature(self, signer: Signer, info_path: &Path) -> Result<()> {
Alan Stokes183d7d32021-12-08 16:10:45 +000067 let mut info = OdsignInfo::new();
68 info.mut_file_hashes().extend(self.file_digests.into_iter());
69 let bytes = info.write_to_bytes()?;
70
Alan Stokes46a1dff2021-12-14 10:56:05 +000071 let signature = signer.sign(&bytes)?;
Alan Stokes183d7d32021-12-08 16:10:45 +000072
Alan Stokes35bac3c2021-12-16 14:37:24 +000073 let mut file =
74 File::create(info_path).with_context(|| format!("Creating {}", info_path.display()))?;
Alan Stokes183d7d32021-12-08 16:10:45 +000075 file.write_all(&bytes)?;
76
77 let mut signature_name = info_path.file_name().unwrap().to_owned();
78 signature_name.push(SIGNATURE_EXTENSION);
79 let signature_path = info_path.with_file_name(&signature_name);
Alan Stokes35bac3c2021-12-16 14:37:24 +000080 let mut signature_file = File::create(&signature_path)
81 .with_context(|| format!("Creating {}", signature_path.display()))?;
Alan Stokes183d7d32021-12-08 16:10:45 +000082 signature_file.write_all(&signature)?;
83
84 Ok(())
85 }
86}
87
88fn to_hex_string(buf: &[u8]) -> String {
89 buf.iter().map(|b| format!("{:02x}", b)).collect()
90}