mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Add a new tool called 'pvimg' that can be used to create and inspect
Secure Execution images. It has several subcommands:
+ create: create an IBM Secure Execution image (genprotimg compatible
sytnax) and C-'genprotimg' is going to be replaced by a
symlink to this subcommand.
+ test: test various aspects of an existing Secure Execution image
+ info: print information about an existing Secure Execution
image (experimental API!)
+ version: print version and exit
As mentioned above, the 'genprotimg' tool is now a symbolic link to the
'pvimg create' subcommand and the CLI is backward compatible with the
original genprotimg CLI, with the following exceptions:
- '-v' increases the verbosity instead of showing the version
- '-V' is now deprecated in favor of '-v'
- an existing output file is no longer silently overwritten, but there
is a new flag '--overwrite' to get the original behavior
- experimental options are no longer described in the help
- the commands '--cert ...' and '--root-ca' are now mutually exclusive
- to '--no-verify'
- there is now a component check, e.g. it checks if the specified
Linux kernel looks like a raw binary s390x kernel. These checks can be
disabled by using the new command line flag '--no-component-check'
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
123 lines
3.6 KiB
Rust
123 lines
3.6 KiB
Rust
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright IBM Corp. 2024
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use anyhow::Result;
|
|
use log::{info, warn};
|
|
use pv::{
|
|
misc::{open_file, read_certs, read_file},
|
|
FileAccessErrorType, PvCoreError,
|
|
};
|
|
use pvimg::{
|
|
error::{Error, OwnExitCode, PvError},
|
|
uvdata::{KeyExchangeTrait, SeHdr, UvKeyHashesV1},
|
|
};
|
|
use utils::HexSlice;
|
|
|
|
use crate::{cli::TestArgs, log_println};
|
|
|
|
/// Returns `Ok(true)` if at least one of the hashes is included.
|
|
fn hdr_test_target_hashes(hdr: &SeHdr, key_hashes: &Path) -> Result<bool> {
|
|
let file = open_file(key_hashes).map_err(|err| match err {
|
|
PvCoreError::FileAccess {
|
|
ref ty,
|
|
ref path,
|
|
ref source,
|
|
} if matches!(ty, FileAccessErrorType::Open)
|
|
&& source.kind() == std::io::ErrorKind::NotFound
|
|
&& *path == PathBuf::from(UvKeyHashesV1::SYS_UV_KEYS_ALL) =>
|
|
{
|
|
Error::UnavailableQueryUvKeyHashesSupport { source: err }
|
|
}
|
|
err => Error::PvCore(err),
|
|
})?;
|
|
let hashes = UvKeyHashesV1::read_from_io(file)?;
|
|
let mut contains = hdr.contains_hash(&hashes.pchkh);
|
|
if contains {
|
|
log_println!(
|
|
" ✓ Host key hash {:#} is included",
|
|
HexSlice::from(&hashes.pchkh)
|
|
);
|
|
}
|
|
if hdr.contains_hash(&hashes.pbhkh) {
|
|
log_println!(
|
|
" ✓ Backup host key hash {:#} is included",
|
|
HexSlice::from(&hashes.pbhkh)
|
|
);
|
|
contains = true;
|
|
};
|
|
|
|
for hash in hashes.res {
|
|
if hdr.contains_hash(&hash) {
|
|
log_println!(" ✓ Key hash {:#} is included", HexSlice::from(&hash));
|
|
contains = true;
|
|
}
|
|
}
|
|
|
|
if !contains {
|
|
warn!(" ✘ None of the key hashes is included");
|
|
}
|
|
Ok(contains)
|
|
}
|
|
|
|
/// Returns `Ok(true)` if at least one of the given public key of the host key
|
|
/// documents was used for the image creation or if no host key document was
|
|
/// specified.
|
|
fn hdr_test_hkd<P>(hdr: &SeHdr, host_key_documents: &[P]) -> Result<bool>
|
|
where
|
|
P: AsRef<Path>,
|
|
{
|
|
if host_key_documents.is_empty() {
|
|
return Ok(true);
|
|
}
|
|
|
|
let mut result = false;
|
|
for path in host_key_documents {
|
|
let hkd_path = path.as_ref();
|
|
let hkd_data = read_file(hkd_path, "host key document")?;
|
|
let certs = read_certs(&hkd_data)?;
|
|
if certs.is_empty() {
|
|
return Err(PvError::NoHkdInFile(hkd_path.display().to_string()).into());
|
|
}
|
|
|
|
if certs.len() != 1 {
|
|
warn!("The host key document in '{}' contains more than one certificate! Only the first certificate will be used.",
|
|
hkd_path.display());
|
|
}
|
|
|
|
// Panic: len is == 1 -> unwrap will succeed/not panic
|
|
let cert = certs.first().unwrap();
|
|
if hdr.contains(cert.public_key()?)? {
|
|
result = true;
|
|
log_println!(" ✓ Host key document '{}' is included", hkd_path.display());
|
|
} else {
|
|
log_println!(
|
|
" ✘ Host key document '{}' is not included",
|
|
hkd_path.display()
|
|
);
|
|
}
|
|
}
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn test(opt: &TestArgs) -> Result<OwnExitCode> {
|
|
info!("Testing a Secure Execution image");
|
|
|
|
let mut input = open_file(&opt.input.path)?;
|
|
SeHdr::seek_sehdr(&mut input, None)?;
|
|
let hdr = SeHdr::try_from_io(input)?;
|
|
|
|
let mut success = hdr_test_hkd(&hdr, &opt.host_key_documents)?;
|
|
if let Some(path) = &opt.key_hashes {
|
|
success = hdr_test_target_hashes(&hdr, path)? && success;
|
|
}
|
|
|
|
Ok(if success {
|
|
OwnExitCode::Success
|
|
} else {
|
|
OwnExitCode::GenericError
|
|
})
|
|
}
|