Add code to bulk-sign artifacts
This isn't wired up yet - we need to be able to iterate over AuthFs
directories, but that's coming soon.
Import the OdsignInfo proto, which contains the map of filenames and
digests, and provide a way to build it from a set of artifact files
and write it along with its signature.
Also remove the old Signer trait (which is unused), and a couple of
small refactorings.
Bug: 161471326
Test: Builds
Change-Id: I37fccb1f2ca4fa1ea3006185d9f805d668252e2a
diff --git a/compos/Android.bp b/compos/Android.bp
index b9fcfff..783ba22 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -50,6 +50,8 @@
"liblog_rust",
"libminijail_rust",
"libnix",
+ "libodsign_proto_rust",
+ "libprotobuf",
"libring",
"libscopeguard",
],
diff --git a/compos/src/artifact_signer.rs b/compos/src/artifact_signer.rs
new file mode 100644
index 0000000..54b8d7a
--- /dev/null
+++ b/compos/src/artifact_signer.rs
@@ -0,0 +1,94 @@
+/*
+ * 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.
+
+#![allow(dead_code)] // Will be used soon
+
+use crate::compos_key_service::CompOsKeyService;
+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::AsRawFd;
+use std::path::{Path, PathBuf};
+
+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> {
+ key_blob: Vec<u8>,
+ key_service: &'a CompOsKeyService,
+ base_directory: PathBuf,
+ 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(
+ key_blob: Vec<u8>,
+ key_service: &'a CompOsKeyService,
+ base_directory: PathBuf,
+ ) -> Self {
+ ArtifactSigner { key_blob, key_service, base_directory, file_digests: Vec::new() }
+ }
+
+ pub fn add_artifact(&mut self, path: PathBuf) -> 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)?;
+ let digest = fsverity::measure(file.as_raw_fd())?;
+ let digest = to_hex_string(&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.mut_file_hashes().extend(self.file_digests.into_iter());
+ let bytes = info.write_to_bytes()?;
+
+ let signature = self.key_service.sign(&self.key_blob, &bytes)?;
+
+ let mut file = File::create(info_path)?;
+ 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)?;
+ signature_file.write_all(&signature)?;
+
+ Ok(())
+ }
+}
+
+fn to_hex_string(buf: &[u8]) -> String {
+ buf.iter().map(|b| format!("{:02x}", b)).collect()
+}
diff --git a/compos/src/compos_key_service.rs b/compos/src/compos_key_service.rs
index 4a1566d..f6caac9 100644
--- a/compos/src/compos_key_service.rs
+++ b/compos/src/compos_key_service.rs
@@ -77,7 +77,7 @@
})
}
- pub fn do_generate(&self) -> Result<CompOsKeyData> {
+ pub fn generate(&self) -> Result<CompOsKeyData> {
let key_descriptor = BLOB_KEY_DESCRIPTOR;
let key_parameters =
[PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST, KEY_SIZE, EXPONENT, NO_AUTH_REQUIRED];
@@ -97,11 +97,11 @@
}
}
- pub fn do_verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
+ pub fn verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
let mut data = [0u8; 32];
self.random.fill(&mut data).context("No random data")?;
- let signature = self.do_sign(key_blob, &data)?;
+ let signature = self.sign(key_blob, &data)?;
let public_key =
signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key);
@@ -110,7 +110,7 @@
Ok(())
}
- pub fn do_sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
+ pub fn sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
let key_descriptor = KeyDescriptor { blob: Some(key_blob.to_vec()), ..BLOB_KEY_DESCRIPTOR };
let operation_parameters = [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST];
let forced = false;
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 0a15876..19f2f47 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -24,7 +24,7 @@
use std::default::Default;
use std::env;
use std::path::PathBuf;
-use std::sync::{Arc, RwLock};
+use std::sync::RwLock;
use crate::compilation::{compile_cmd, odrefresh, CompilerOutput};
use crate::compos_key_service::CompOsKeyService;
@@ -50,7 +50,7 @@
dex2oat_path: PathBuf::from(DEX2OAT_PATH),
odrefresh_path: PathBuf::from(ODREFRESH_PATH),
key_service: CompOsKeyService::new()?,
- key_blob: Arc::new(RwLock::new(Vec::new())),
+ key_blob: RwLock::new(Vec::new()),
};
Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
}
@@ -59,7 +59,7 @@
dex2oat_path: PathBuf,
odrefresh_path: PathBuf,
key_service: CompOsKeyService,
- key_blob: Arc<RwLock<Vec<u8>>>,
+ key_blob: RwLock<Vec<u8>>,
}
impl CompOsService {
@@ -69,7 +69,7 @@
fsverity_digest: &fsverity::Sha256Digest,
) -> Vec<u8> {
let formatted_digest = fsverity::to_formatted_digest(fsverity_digest);
- self.key_service.do_sign(key_blob, &formatted_digest[..]).unwrap_or_else(|e| {
+ self.key_service.sign(key_blob, &formatted_digest[..]).unwrap_or_else(|e| {
warn!("Failed to sign the fsverity digest, returning empty signature. Error: {}", e);
Vec::new()
})
@@ -189,12 +189,12 @@
fn generateSigningKey(&self) -> BinderResult<CompOsKeyData> {
self.key_service
- .do_generate()
+ .generate()
.map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
}
fn verifySigningKey(&self, key_blob: &[u8], public_key: &[u8]) -> BinderResult<bool> {
- Ok(if let Err(e) = self.key_service.do_verify(key_blob, public_key) {
+ Ok(if let Err(e) = self.key_service.verify(key_blob, public_key) {
warn!("Signing key verification failed: {}", e.to_string());
false
} else {
@@ -208,7 +208,7 @@
Err(new_binder_exception(ExceptionCode::ILLEGAL_STATE, "Key is not initialized"))
} else {
self.key_service
- .do_sign(key, data)
+ .sign(key, data)
.map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
}
}
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index fc00039..9347905 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -16,11 +16,11 @@
//! A tool to start a standalone compsvc server that serves over RPC binder.
+mod artifact_signer;
mod compilation;
mod compos_key_service;
mod compsvc;
mod fsverity;
-mod signer;
use android_system_virtualmachineservice::{
aidl::android::system::virtualmachineservice::IVirtualMachineService::{
diff --git a/compos/src/signer.rs b/compos/src/signer.rs
deleted file mode 100644
index 9ff1477..0000000
--- a/compos/src/signer.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-use anyhow::Result;
-
-/// Provides the ability to cryptographically sign messages.
-pub trait Signer: Send + Sync {
- /// Sign the supplied data. The result is a raw signature over the input data.
- fn sign(&self, data: &[u8]) -> Result<Vec<u8>>;
-}