1 /* 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 use crate::compos_key; 21 use crate::fsverity; 22 use anyhow::{anyhow, Context, Result}; 23 use odsign_proto::odsign_info::OdsignInfo; 24 use protobuf::Message; 25 use std::fs::File; 26 use std::io::Write; 27 use std::os::unix::io::AsFd; 28 use std::path::Path; 29 30 const TARGET_DIRECTORY: &str = "/data/misc/apexdata/com.android.art/dalvik-cache"; 31 const SIGNATURE_EXTENSION: &str = ".signature"; 32 33 /// Accumulates and then signs information about generated artifacts. 34 pub struct ArtifactSigner<'a> { 35 base_directory: &'a Path, 36 file_digests: Vec<(String, String)>, // (File name, digest in hex) 37 } 38 39 impl<'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. new(base_directory: &'a Path) -> Self42 pub fn new(base_directory: &'a Path) -> Self { 43 Self { base_directory, file_digests: Vec::new() } 44 } 45 add_artifact(&mut self, path: &Path) -> Result<()>46 pub fn add_artifact(&mut self, path: &Path) -> Result<()> { 47 // The path we store is where the file will be when it is verified, not where it is now. 48 let suffix = path 49 .strip_prefix(self.base_directory) 50 .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 54 let file = File::open(path).with_context(|| format!("Opening {}", path.display()))?; 55 let digest = fsverity::measure(file.as_fd())?; 56 let digest = hex::encode(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. write_info_and_signature(self, info_path: &Path) -> Result<()>64 pub fn write_info_and_signature(self, info_path: &Path) -> Result<()> { 65 let mut info = OdsignInfo::new(); 66 info.file_hashes.extend(self.file_digests); 67 let bytes = info.write_to_bytes()?; 68 69 let signature = compos_key::sign(&bytes)?; 70 71 let mut file = 72 File::create(info_path).with_context(|| format!("Creating {}", info_path.display()))?; 73 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); 78 let mut signature_file = File::create(&signature_path) 79 .with_context(|| format!("Creating {}", signature_path.display()))?; 80 signature_file.write_all(&signature)?; 81 82 Ok(()) 83 } 84 } 85