mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
pvattest: Use hybrid keys
Allow the creation of Attestation requests using 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:
committed by
Steffen Eiden
parent
fc853f3259
commit
9dca2d3181
@@ -5,7 +5,10 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum, ValueHint};
|
||||
use utils::{CertificateOptions, DeprecatedVerbosityOptions};
|
||||
use utils::{
|
||||
AutoOrExplicit, AutoOrExplicitParser, CertificateOptions, DeprecatedVerbosityOptions,
|
||||
HkdVersion, ValueEnumDisplay, ValueEnumFromStr,
|
||||
};
|
||||
|
||||
/// create, perform, and verify attestation measurements
|
||||
///
|
||||
@@ -67,6 +70,29 @@ pub enum Command {
|
||||
Version,
|
||||
}
|
||||
|
||||
/// Secure Execution attestation version for CLI
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, ValueEnumDisplay, ValueEnumFromStr)]
|
||||
pub enum AttVersion {
|
||||
#[value(name = "1")]
|
||||
/// Version 1 - uses traditional cryptographic keys
|
||||
V1,
|
||||
#[value(name = "2")]
|
||||
/// Version 2 - uses hybrid (post-quantum) cryptographic keys
|
||||
V2,
|
||||
}
|
||||
|
||||
pub type AttVersionSelection = AutoOrExplicit<AttVersion>;
|
||||
pub type AttVersionSelectionParser = AutoOrExplicitParser<AttVersion>;
|
||||
|
||||
impl From<AttVersion> for HkdVersion {
|
||||
fn from(val: AttVersion) -> Self {
|
||||
match val {
|
||||
AttVersion::V1 => Self::Classical,
|
||||
AttVersion::V2 => Self::Hybrid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct CreateAttOpt {
|
||||
#[command(flatten)]
|
||||
@@ -94,6 +120,10 @@ pub struct CreateAttOpt {
|
||||
value_delimiter = ','
|
||||
)]
|
||||
pub add_data: Vec<AttAddFlags>,
|
||||
|
||||
/// Specify the Attestation Request version to use.
|
||||
#[arg(long = "att-version", value_name = "VERSION", default_value_t = AttVersionSelection::Explicit(AttVersion::V1), value_parser = AttVersionSelectionParser::default())]
|
||||
pub att_version: AttVersionSelection,
|
||||
}
|
||||
|
||||
#[derive(Debug, ValueEnum, Clone, Copy)]
|
||||
|
||||
@@ -12,7 +12,7 @@ pub use check::check;
|
||||
pub use create::create;
|
||||
pub use verify::verify;
|
||||
|
||||
pub const CMD_FN: &[&str] = &["+create", "+verify"];
|
||||
pub const CMD_FN: &[&str] = &["+create", "+verify", "+quantumsafe"];
|
||||
// s390 branch
|
||||
#[cfg(target_arch = "s390x")]
|
||||
mod uv_cmd {
|
||||
|
||||
@@ -10,7 +10,7 @@ use pv::attest::{AttestationFlags, AttestationMeasAlg, AttestationRequest, Attes
|
||||
use pv::misc::{create_file, write_file};
|
||||
use pv::request::{HostKey, ReqEncrCtx, Request, SymKey, SymKeyType};
|
||||
|
||||
use crate::cli::{AttAddFlags, CreateAttOpt};
|
||||
use crate::cli::{AttAddFlags, AttVersion, AttVersionSelection, CreateAttOpt};
|
||||
use crate::exchange::{ExchangeFormatRequest, ExchangeFormatVersion};
|
||||
|
||||
fn flags(cli_flags: &[AttAddFlags]) -> AttestationFlags {
|
||||
@@ -26,18 +26,54 @@ fn flags(cli_flags: &[AttAddFlags]) -> AttestationFlags {
|
||||
att_flags
|
||||
}
|
||||
|
||||
/// Auto-detect the attestation version based on the host keys.
|
||||
///
|
||||
/// Returns Two if any host key is a hybrid key, otherwise returns V1.
|
||||
fn auto_detect_version(host_keys: &[HostKey]) -> AttestationVersion {
|
||||
let use_hybrid_keys = host_keys.iter().any(|k: &HostKey| k.is_hybrid());
|
||||
if use_hybrid_keys {
|
||||
AttestationVersion::Two
|
||||
} else {
|
||||
AttestationVersion::One
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AttVersion> for AttestationVersion {
|
||||
fn from(value: AttVersion) -> Self {
|
||||
match value {
|
||||
AttVersion::V1 => Self::One,
|
||||
AttVersion::V2 => Self::Two,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine the attestation version to use.
|
||||
///
|
||||
/// If an explicit version is provided via CLI, use that.
|
||||
/// Otherwise, auto-detect based on the host key types.
|
||||
fn determine_version(
|
||||
cli_version: AttVersionSelection,
|
||||
host_keys: &[HostKey],
|
||||
) -> AttestationVersion {
|
||||
match cli_version {
|
||||
AttVersionSelection::Auto => auto_detect_version(host_keys),
|
||||
AttVersionSelection::Explicit(att_version) => att_version.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(opt: &CreateAttOpt) -> Result<ExitCode> {
|
||||
let att_version = AttestationVersion::One;
|
||||
let hkds = opt
|
||||
.certificate_args
|
||||
.get_verified_hkds_new("attestation request", opt.att_version.map(|v| v.into()))?;
|
||||
|
||||
let att_version = determine_version(opt.att_version, &hkds);
|
||||
let meas_alg = AttestationMeasAlg::HmacSha512;
|
||||
|
||||
let mut arcb = AttestationRequest::new(att_version, meas_alg, flags(&opt.add_data))?;
|
||||
debug!("Generated Attestation request");
|
||||
|
||||
// Add host-key documents
|
||||
opt.certificate_args
|
||||
.get_verified_hkds("attestation request")?
|
||||
.into_iter()
|
||||
.for_each(|k| arcb.add_hostkey(HostKey::V1(k)));
|
||||
hkds.into_iter().for_each(|k| arcb.add_hostkey(k));
|
||||
debug!("Added all host-keys");
|
||||
|
||||
let encr_ctx =
|
||||
|
||||
@@ -11,6 +11,8 @@ use pv::request::MagicValue;
|
||||
use pv::uv::{AttestationCmd, ConfigUid};
|
||||
use zerocopy::{BigEndian, ByteOrder, FromBytes, Immutable, IntoBytes, KnownLayout, U32, U64};
|
||||
|
||||
use crate::additional;
|
||||
|
||||
const INV_EXCHANGE_FMT_ERROR_TEXT: &str = "The input has not the correct format:";
|
||||
|
||||
#[repr(C)]
|
||||
@@ -99,10 +101,18 @@ impl ExchangeFormatV1Hdr {
|
||||
let measurement_entry = Entry::from_exp(Some(measurement));
|
||||
let exp_add = match additional {
|
||||
0 => None,
|
||||
size => Some(size),
|
||||
size => {
|
||||
if size > AttestationCmd::ADDITIONAL_MAX_SIZE {
|
||||
bail!(
|
||||
"Additional data size ({}) exceeds maximum allowed size ({})",
|
||||
size,
|
||||
AttestationCmd::ADDITIONAL_MAX_SIZE
|
||||
);
|
||||
}
|
||||
Some(size)
|
||||
}
|
||||
};
|
||||
// TODO min and max size check?
|
||||
let additional_entry = Entry::from_exp(exp_add); //, AttestationCmd::ADDITIONAL_MAX_SIZE, &mut offset);
|
||||
let additional_entry = Entry::from_exp(exp_add);
|
||||
let user_entry = Entry::from_none();
|
||||
let cuid_entry = Entry::from_none();
|
||||
|
||||
@@ -530,7 +540,6 @@ impl ExchangeFormatResponse {
|
||||
"{INV_EXCHANGE_FMT_ERROR_TEXT} Contains no attestation request.",
|
||||
))?;
|
||||
|
||||
// TODO remove unwrap
|
||||
let measurement = hdr.measurement.read(reader)?.data().ok_or(anyhow!(
|
||||
"{INV_EXCHANGE_FMT_ERROR_TEXT} Contains no attestation response (Measurement missing).",
|
||||
))?;
|
||||
@@ -693,6 +702,50 @@ mod test {
|
||||
ExchangeFormatRequest::new(ARCB.to_vec(), 0, ADDITIONAL.len() as u32).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_additional_data_size_validation() {
|
||||
// Test for TODO 1 fix: Additional data size validation
|
||||
let arcb = ARCB.to_vec();
|
||||
|
||||
// Test with valid size at maximum
|
||||
let result = ExchangeFormatV1Hdr::new_request(
|
||||
&arcb,
|
||||
MEASUREMENT.len() as u32,
|
||||
AttestationCmd::ADDITIONAL_MAX_SIZE,
|
||||
);
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Maximum additional data size should be accepted"
|
||||
);
|
||||
|
||||
// Test with size exceeding maximum
|
||||
let result = ExchangeFormatV1Hdr::new_request(
|
||||
&arcb,
|
||||
MEASUREMENT.len() as u32,
|
||||
AttestationCmd::ADDITIONAL_MAX_SIZE + 1,
|
||||
);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Additional data size exceeding maximum should fail"
|
||||
);
|
||||
|
||||
if let Err(e) = result {
|
||||
let error_msg = e.to_string();
|
||||
assert!(
|
||||
error_msg.contains("exceeds maximum"),
|
||||
"Error should mention exceeding maximum: {}",
|
||||
error_msg
|
||||
);
|
||||
}
|
||||
|
||||
// Test with zero size (no additional data)
|
||||
let result = ExchangeFormatV1Hdr::new_request(&arcb, MEASUREMENT.len() as u32, 0);
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Zero additional data size should be accepted"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn min_req() {
|
||||
test_read_write_request(
|
||||
|
||||
Reference in New Issue
Block a user