pvimg/create-sehdr: Use hybrid keys

Allow the creation of SE headers with hybrid (=quantum safe) keys. This
results in using the headers in version 2 (0x200).

Co-developed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Timo Keller <tkeller@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Timo Keller
2026-07-21 14:29:56 +02:00
committed by Steffen Eiden
parent 89577c2f8c
commit fc853f3259
2 changed files with 118 additions and 26 deletions

View File

@@ -148,10 +148,9 @@ mod tests {
use zerocopy::IntoBytes;
use super::*;
use crate::crypto::SymKey;
use crate::get_test_asset;
use crate::req::header::RequestHdr;
use crate::req::{Aad, HostKey, Keyslot, ReqEncrCtx};
use crate::request::SymKey;
use crate::req::{Aad, HybridPKey, Keyslot};
use crate::test_utils::*;
static TEST_MAGIC: [u8; 8] = 0x12345689abcdef00u64.to_be_bytes();
@@ -187,6 +186,37 @@ mod tests {
assert_eq!(&aad, &aad_exp);
}
#[test]
fn encr_build_aad_v2() {
let (cust_key, host_key1, host_key2) = get_test_keys_hybrid();
let ks = Keyslot::new(HostKey::V2(HybridPKey::new(host_key1, host_key2).unwrap()));
let ctx = ReqEncrCtx::new_aes_256(
Some([0x11; 12]),
Some(cust_key),
Some(SymKey::Aes256([0x17; 32].into())),
)
.unwrap();
let v = [0x55; 8];
let aad = Aad::Plain(&v);
let aad = ctx
.build_aad(0x200, &vec![aad, Aad::Ks(&ks)], 16, Some(TEST_MAGIC))
.unwrap();
let aad_exp = vec![
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // progr
0, 0, 2, 0, // vers
0, 0, 6, 232, // size
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
1, // nks
0, 0, 0, 0, // res
0, 0, 0, 16, // sea
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // aad
];
// only compare non-randomized part
assert_eq!(aad[..aad_exp.len()], aad_exp);
}
#[test]
fn encr_build_aad_nks_no() {
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
@@ -210,6 +240,21 @@ mod tests {
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
assert!(matches!(aad, Err(Error::ManyHostkeys)));
}
#[test]
fn encr_build_aad_nks_many_v2() {
let (_, host_key1, host_key2) = get_test_keys_hybrid();
let host_key = HostKey::V2(HybridPKey::new(host_key1, host_key2).unwrap());
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
let ks: Vec<Keyslot> = (0..257).map(|_| Keyslot::new(host_key.clone())).collect();
let mut aad = Vec::<Aad>::new();
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
assert!(matches!(aad, Err(Error::ManyHostkeys)));
}
#[test]
fn encr_build_aad_nks() {
let (_, host_key) = get_test_keys();
@@ -229,6 +274,25 @@ mod tests {
assert_eq!(aad.get(39).unwrap(), &3u8);
}
#[test]
fn encr_build_aad_nks_v2() {
let (_, host_key1, host_key2) = get_test_keys_hybrid();
let host_key = HostKey::V2(HybridPKey::new(host_key1, host_key2).unwrap());
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
let ks = [
Keyslot::new(host_key.clone()),
Keyslot::new(host_key.clone()),
Keyslot::new(host_key),
];
let mut aad = Vec::<Aad>::new();
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC)).unwrap();
assert_eq!(aad.get(39).unwrap(), &3u8);
}
#[test]
fn req_hdr() {
let hdr = RequestHdr::new(0x200, 22, [0x11; 12], 15, 44, None);

View File

@@ -10,11 +10,11 @@ use std::path::PathBuf;
use std::str::FromStr;
use anyhow::{anyhow, Context, Error};
use clap::{Parser, ValueHint};
use log::{info, warn};
use pv::misc::{decode_hex, open_file, read_certs, read_file, try_parse_u64};
use pv::request::SymKeyType;
use pv::{Error as PvError, Result};
use clap::{Parser, ValueEnum, ValueHint};
use log::info;
use pv::misc::{decode_hex, open_file, read_file, read_hkd, try_parse_u64};
use pv::request::{HostKey, SymKeyType};
use pv::Result;
use pvimg::misc::PSW;
use pvimg::secured_comp::{ComponentTrait, Layout, SecuredComponentBuilder};
use pvimg::uvdata::{BuilderTrait, SeHdrBuilder, SeHdrControlFlags, SeHdrVersion, SeTarget};
@@ -87,6 +87,38 @@ impl Display for ComponentArg {
}
}
/// SE-header version selection
#[derive(Debug, Clone, Copy, ValueEnum)]
enum SeHdrVersionArg {
/// SE-header version 1
#[value(name = "1")]
V1,
/// SE-header version 2
#[value(name = "2")]
V2,
}
impl From<SeHdrVersionArg> for SeHdrVersion {
fn from(arg: SeHdrVersionArg) -> Self {
match arg {
SeHdrVersionArg::V1 => SeHdrVersion::V1,
SeHdrVersionArg::V2 => SeHdrVersion::V2,
}
}
}
impl SeHdrVersionArg {
/// Detect the SE header version from the keys.
/// Returns V2 if any key is hybrid, otherwise V1.
pub fn detect<K: AsRef<[HostKey]>>(keys: K) -> Self {
if keys.as_ref().iter().any(|k| !k.is_hybrid()) {
Self::V1
} else {
Self::V2
}
}
}
/// Create a Secure Execution header.
#[derive(Parser, Debug)]
pub struct Args {
@@ -129,6 +161,10 @@ pub struct Args {
#[arg(short, long)]
pub output: PathBuf,
/// SE-header version to build
#[arg(long, value_enum)]
version: Option<SeHdrVersionArg>,
#[clap(flatten)]
pub verbosity: VerbosityOptions,
}
@@ -203,34 +239,26 @@ fn main() -> anyhow::Result<()> {
info!("\n# Creating Secure Execution Header");
let addr = args.psw_addr;
let mask = args.psw_mask;
let version = SeHdrVersion::V1;
let mut builder = SeHdrBuilder::new(version, PSW { addr, mask }, secure_comp_builer.finish()?)?;
let mut target_pub_keys = vec![];
for hkd_path in args.host_key_documents {
info!(
"Use the file '{}' as a host key document",
hkd_path.display()
);
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! All keys will be used.",
hkd_path.display());
}
for cert in &certs {
target_pub_keys.push(cert.public_key()?);
}
let cert = read_hkd(&hkd_path)?;
target_pub_keys.push(cert);
}
builder.add_hostkeys(&target_pub_keys)?;
let version: SeHdrVersion = args
.version
.unwrap_or(SeHdrVersionArg::detect(&target_pub_keys))
.into();
let target = SeTarget::from_se_hdr_version(version);
let pcf = SeHdrControlFlags::from_u64(try_parse_u64(&args.pcf, "pcf")?, target, true);
let scf = SeHdrControlFlags::from_u64(try_parse_u64(&args.scf, "scf")?, target, false);
info!("SE-header version ...: {}", version);
let mut builder = SeHdrBuilder::new(version, PSW { addr, mask }, secure_comp_builer.finish()?)?;
builder.add_hostkeys(&target_pub_keys)?;
info!(
"PSW addr ............: {addr:#018x}\n\
PSW mask ............: {mask:#018x}\n\