Files
s390-tools/rust/pvebc/src/ebc_utils.rs
Finn Callies c04a0919f6 rust: Add new tool pvebc
Add pvebc tool for parsing and verifying EBC Add-Secret-Request structures

Introduce pvebc, a CLI tool that parses and verifies the integrity of
Add-Secret-Request (ASR) structures used in Early Boot Customization for
SEL guests.

The tool processes an integrity-protected ASR structure consisting of:
 - toc.asr: Meta secret that links to toc.pol via relative filepath and
   SHA512 hash, integrity-protected by its AES GCM authentication tag
 - toc.pol: Policy file containing AES GCM authentication tags (last 16
   bytes) of all user-provided ASRs
 - User ASRs: Individual Add-Secret-Requests containing encrypted secrets

This structure guarantees:
 - Prevents ASR removal: toc.pol lists all expected ASR authentication tags
 - Prevents ASR insertion: Unlisted ASRs are rejected
 - Prevents ASR modification: AES GCM authentication tags provide
   cryptographic integrity
 - Prevents toc.pol tampering: toc.asr's integrity protection secures the
   link

The tool verifies completeness by checking that all ASRs listed in toc.pol
are present and their AES GCM authentication tags match. This prevents
attackers from removing, inserting, or modifying ASRs during transport over
unsecured channels.

After verification, pvebc adds all ASRs to the Ultravisor (UV), which
decrypts them using the guest's secret key and makes them available to
the guest during early boot.

Assisted-by: IBM Bob:1.0.1
Acked-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 13:46:31 +02:00

55 lines
1.5 KiB
Rust

// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
use anyhow::{bail, Context, Result};
use pv_core::misc::open_file;
use std::{io::Read, path::Path};
/// Length of the MAC tag in bytes (last 16 bytes of AddSecretRequest files)
pub const MAC_TAG_LEN: usize = 16;
/// Opens a file and returns a boxed reader
pub fn get_reader_from_filepath<P: AsRef<Path>>(filepath: P) -> Result<Box<dyn Read>> {
Ok(Box::new(open_file(filepath)?))
}
/// Get reader from &Path with additional context on error
pub fn get_reader(filepath: &Path) -> Result<Box<dyn Read>> {
get_reader_from_filepath(filepath)
.with_context(|| format!("unable to get reader from {:?}", filepath))
}
/// Read all data from a reader into a Vec<u8>
pub fn get_data(rd_in: &mut Box<dyn Read>) -> Result<Vec<u8>> {
let mut data_in = Vec::new();
rd_in
.read_to_end(&mut data_in)
.context("Cannot read input file")?;
Ok(data_in)
}
/// Extract the MAC tag (last 16 bytes) from an AddSecretRequest file
///
/// # Errors
///
/// Returns an error if:
/// - The file cannot be read
/// - The file is smaller than MAC_TAG_LEN bytes
pub fn get_mac_tag(filepath: &Path) -> Result<Vec<u8>> {
let mut rd_in = get_reader(filepath)?;
let data_in = get_data(&mut rd_in)?;
if data_in.len() < MAC_TAG_LEN {
bail!(
"File {:?} too small to contain MAC tag (expected at least {} bytes, got {})",
filepath,
MAC_TAG_LEN,
data_in.len()
);
}
Ok(data_in[data_in.len() - MAC_TAG_LEN..].to_vec())
}