Authenticate file w/ fs-verity digest in hex
An input directory is configured by a build manifest file. With this
change, authfs starts to use the fs-verity digest in the manifest to
authenticate the corresponding file.
Although we're not using it, this change also makes it possible to
specify a known fs-verity digest to a remote file from the command line
(and deprecate the fake support of signature verification by the given
certificate).
Since we no longer derive fs-verity digest from the first chunk of a
Merkle tree, some relevant functions are deleted.
Bug: 206869687
Test: atest AuthFsHostTest ComposHostTestCases
Test: atest authfs_device_test_src_lib
Change-Id: Ibb5c246fb0d29aeafde187555f8d72c0282a65c7
diff --git a/authfs/src/fsverity/verifier.rs b/authfs/src/fsverity/verifier.rs
index 17a0a2a..61b8e13 100644
--- a/authfs/src/fsverity/verifier.rs
+++ b/authfs/src/fsverity/verifier.rs
@@ -18,17 +18,12 @@
use std::io;
use super::common::{build_fsverity_digest, merkle_tree_height, FsverityError};
-use super::sys::{FS_VERITY_HASH_ALG_SHA256, FS_VERITY_MAGIC};
-use crate::auth::Authenticator;
use crate::common::{divide_roundup, CHUNK_SIZE};
use crate::crypto::{CryptoError, Sha256Hasher};
use crate::file::{ChunkBuffer, ReadByChunk};
const ZEROS: [u8; CHUNK_SIZE as usize] = [0u8; CHUNK_SIZE as usize];
-// The size of `struct fsverity_formatted_digest` in Linux with SHA-256.
-const SIZE_OF_FSVERITY_FORMATTED_DIGEST_SHA256: usize = 12 + Sha256Hasher::HASH_SIZE;
-
type HashBuffer = [u8; Sha256Hasher::HASH_SIZE];
fn hash_with_padding(chunk: &[u8], pad_to: usize) -> Result<HashBuffer, CryptoError> {
@@ -116,21 +111,6 @@
}))
}
-fn build_fsverity_formatted_digest(
- root_hash: &HashBuffer,
- file_size: u64,
-) -> Result<[u8; SIZE_OF_FSVERITY_FORMATTED_DIGEST_SHA256], CryptoError> {
- let digest = build_fsverity_digest(root_hash, file_size)?;
- // Little-endian byte representation of fsverity_formatted_digest from linux/fsverity.h
- // Not FFI-ed as it seems easier to deal with the raw bytes manually.
- let mut formatted_digest = [0u8; SIZE_OF_FSVERITY_FORMATTED_DIGEST_SHA256];
- formatted_digest[0..8].copy_from_slice(FS_VERITY_MAGIC);
- formatted_digest[8..10].copy_from_slice(&(FS_VERITY_HASH_ALG_SHA256 as u16).to_le_bytes());
- formatted_digest[10..12].copy_from_slice(&(Sha256Hasher::HASH_SIZE as u16).to_le_bytes());
- formatted_digest[12..].copy_from_slice(&digest);
- Ok(formatted_digest)
-}
-
pub struct VerifiedFileReader<F: ReadByChunk, M: ReadByChunk> {
chunked_file: F,
file_size: u64,
@@ -139,11 +119,10 @@
}
impl<F: ReadByChunk, M: ReadByChunk> VerifiedFileReader<F, M> {
- pub fn new<A: Authenticator>(
- authenticator: &A,
+ pub fn new(
chunked_file: F,
file_size: u64,
- sig: Option<&[u8]>,
+ expected_digest: &[u8],
merkle_tree: M,
) -> Result<VerifiedFileReader<F, M>, FsverityError> {
let mut buf = [0u8; CHUNK_SIZE as usize];
@@ -157,12 +136,11 @@
}
}
let root_hash = Sha256Hasher::new()?.update(&buf[..])?.finalize()?;
- let formatted_digest = build_fsverity_formatted_digest(&root_hash, file_size)?;
- let valid = authenticator.verify(sig, &formatted_digest)?;
- if valid {
+ if expected_digest == build_fsverity_digest(&root_hash, file_size)? {
+ // Once verified, use the root_hash for verification going forward.
Ok(VerifiedFileReader { chunked_file, file_size, merkle_tree, root_hash })
} else {
- Err(FsverityError::BadSignature)
+ Err(FsverityError::InvalidDigest)
}
}
}
@@ -183,7 +161,6 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::auth::FakeAuthenticator;
use crate::file::ReadByChunk;
use anyhow::Result;
use authfs_fsverity_metadata::{parse_fsverity_metadata, FSVerityMetadata};
@@ -245,13 +222,11 @@
let file_reader = LocalFileReader::new(File::open(content_path)?)?;
let file_size = file_reader.len();
let metadata = parse_fsverity_metadata(File::open(metadata_path)?)?;
- let authenticator = FakeAuthenticator::always_succeed();
Ok((
VerifiedFileReader::new(
- &authenticator,
file_reader,
file_size,
- metadata.signature.clone().as_deref(),
+ &metadata.digest.clone(),
MerkleTreeReader { metadata },
)?,
file_size,
@@ -312,21 +287,4 @@
assert!(file_reader.read_chunk(last_index, &mut buf).is_ok());
Ok(())
}
-
- #[test]
- fn invalid_signature() -> Result<()> {
- let authenticator = FakeAuthenticator::always_fail();
- let file_reader = LocalFileReader::new(File::open("testdata/input.4m")?)?;
- let file_size = file_reader.len();
- let metadata = parse_fsverity_metadata(File::open("testdata/input.4m.fsv_meta")?)?;
- assert!(VerifiedFileReader::new(
- &authenticator,
- file_reader,
- file_size,
- metadata.signature.clone().as_deref(),
- MerkleTreeReader { metadata },
- )
- .is_err());
- Ok(())
- }
}