blob: bfd886e16bc2747c8d23a1ce4943d7830889709b [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Support for generating and signing an info file listing names and digests of generated
//! artifacts.
use crate::compos_key;
use crate::fsverity;
use anyhow::{anyhow, Context, Result};
use odsign_proto::odsign_info::OdsignInfo;
use protobuf::Message;
use std::fs::File;
use std::io::Write;
use std::os::unix::io::AsFd;
use std::path::Path;
const TARGET_DIRECTORY: &str = "/data/misc/apexdata/com.android.art/dalvik-cache";
const SIGNATURE_EXTENSION: &str = ".signature";
/// Accumulates and then signs information about generated artifacts.
pub struct ArtifactSigner<'a> {
base_directory: &'a Path,
file_digests: Vec<(String, String)>, // (File name, digest in hex)
}
impl<'a> ArtifactSigner<'a> {
/// base_directory specifies the directory under which the artifacts are currently located;
/// they will eventually be moved under TARGET_DIRECTORY once they are verified and activated.
pub fn new(base_directory: &'a Path) -> Self {
Self { base_directory, file_digests: Vec::new() }
}
pub fn add_artifact(&mut self, path: &Path) -> Result<()> {
// The path we store is where the file will be when it is verified, not where it is now.
let suffix = path
.strip_prefix(self.base_directory)
.context("Artifacts must be under base directory")?;
let target_path = Path::new(TARGET_DIRECTORY).join(suffix);
let target_path = target_path.to_str().ok_or_else(|| anyhow!("Invalid path"))?;
let file = File::open(path).with_context(|| format!("Opening {}", path.display()))?;
let digest = fsverity::measure(file.as_fd())?;
let digest = hex::encode(digest);
self.file_digests.push((target_path.to_owned(), digest));
Ok(())
}
/// Consume this ArtifactSigner and write details of all its artifacts to the given path,
/// with accompanying sigature file.
pub fn write_info_and_signature(self, info_path: &Path) -> Result<()> {
let mut info = OdsignInfo::new();
info.file_hashes.extend(self.file_digests);
let bytes = info.write_to_bytes()?;
let signature = compos_key::sign(&bytes)?;
let mut file =
File::create(info_path).with_context(|| format!("Creating {}", info_path.display()))?;
file.write_all(&bytes)?;
let mut signature_name = info_path.file_name().unwrap().to_owned();
signature_name.push(SIGNATURE_EXTENSION);
let signature_path = info_path.with_file_name(&signature_name);
let mut signature_file = File::create(&signature_path)
.with_context(|| format!("Creating {}", signature_path.display()))?;
signature_file.write_all(&signature)?;
Ok(())
}
}