Files
s390-tools/rust/pvimg/src/pv_utils/uvdata.rs
T
Timo Keller 89577c2f8c pvimg: Use hybrid keys
Allow the creation of SE images using 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>
2026-07-28 11:00:00 +02:00

201 lines
6.1 KiB
Rust

// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2024
use enum_dispatch::enum_dispatch;
use pv::request::openssl::pkey::{PKey, Public};
use pv::request::{decrypt_aead, encrypt_aead, Confidential, SymKey, SymKeyType};
use super::se_hdr::{SeHdrBinV1, SeHdrBinV2, SeHdrData, SeHdrVersioned};
use crate::pv_utils::error::{Error, Result};
use crate::pv_utils::serializing::deserialize_from_bytes;
/// Trait to be used for Authenticated Encryption with Associated Data (AEAD)
/// data structures.
#[enum_dispatch]
pub trait AeadCipherTrait {
/// Returns the AEAD key type used by the data structure.
fn aead_key_type(&self) -> SymKeyType;
/// Returns the AEAD tag size used by the data structure.
fn aead_tag_size(&self) -> usize;
/// Returns the initialization vector (IV) used for AEAD
/// encryption/decryption.
fn iv(&self) -> &[u8];
}
/// Trait to be used for AEAD cipher data
#[enum_dispatch]
pub trait AeadDataTrait {
/// Returns the authenticated associated data.
fn aad(&self) -> Result<Vec<u8>>;
/// Returns the encrypted data.
fn data(&self) -> Vec<u8>;
/// Returns the tag data.
fn tag(&self) -> Vec<u8>;
}
/// Trait to be used for AEAD plaintext data
#[enum_dispatch]
pub trait AeadPlainDataTrait {
/// Returns the authenticated associated data.
fn aad(&self) -> Result<Vec<u8>>;
/// Returns the unencrypted data.
fn data(&self) -> Result<Confidential<Vec<u8>>>;
/// Returns the tag data.
fn tag(&self) -> Vec<u8>;
}
/// Key exchange related methods
pub trait KeyExchangeTrait {
type TargetKeyType;
type PrivateKeyType: ToOwned;
/// Checks if a public target key was used.
///
/// # Errors
///
/// This function will return an error if the public key cannot be converted
/// into a hash.
fn contains<K>(&self, key: K) -> Result<bool>
where
K: AsRef<Self::TargetKeyType>;
/// Checks if the hash of a public key was used.
fn contains_hash<H: AsRef<[u8]>>(&self, hash: H) -> bool;
/// Returns the public key from the party (e.g. guest owner) that is stored
/// in the data structed.
///
/// # Errors
///
/// This function will return an error if the public key cannot be
/// reconstructed.
fn cust_pub_key(&mut self) -> Result<PKey<Public>>;
/// Returns the key type of the exchanged key.
fn key_type(&self) -> SymKeyType;
// TODO Implement it
// /// Derive the key.
// ///
// /// # Errors
// ///
// /// This function will return an error if there is no customer public key is
// /// available or the key derivations fails.
// fn derive_key<K>(&mut self, other_priv_key: K) -> Result<SymKey> where
// K: AsRef<Self::PrivateKeyType>{
// match self.key_type() {
// SymKeyType::Aes256Gcm =>
// match Self::TargetKeyType {
// PKeyRef::<Public> => {todo!()},
// HybridPKey => {todo!()},
// }
// _ => unreachable!("BUG"),
// }
// }
}
/// Trait to be used for plain UV data.
#[enum_dispatch]
pub trait UvDataPlainTrait:
AeadPlainDataTrait + AeadCipherTrait + KeyExchangeTrait + Clone
{
/// Returned type by [`Self::encrypt`].
type C: UvDataTrait;
/// Encrypt the plain data.
///
/// # Errors
///
/// This function will return an error if the passed `key` has the wrong
/// key type or the encryption fails.
fn encrypt(&self, key: &SymKey) -> Result<Self::C>
where
<Self as UvDataPlainTrait>::C: for<'a> deku::DekuContainerRead<'a>,
{
if key.key_type() != self.aead_key_type() {
return Err(Error::UnexpectedKeyType {
given: self.key_type().to_string(),
expected: self.aead_key_type().to_string(),
});
}
let aad = self.aad().map_err(|err| match err {
Error::Deku(_) => Error::InvalidSeHdr,
err => err,
})?;
let unecrypted_data = self.data().map_err(|err| match err {
Error::Deku(_) => Error::InvalidSeHdr,
err => err,
})?;
let iv = self.iv();
let result = encrypt_aead(key, iv, &aad, unecrypted_data.value())?;
Self::C::try_from_data(&result.into_buf())
}
/// Parses and converts the data into an instance of [`Self`] if possible.
///
/// # Errors
///
/// This function will return an error if the data could not parsed or
/// converted.
fn try_from_data<'a>(data: &'a [u8]) -> Result<Self>
where
Self: deku::DekuContainerRead<'a> + Sized,
{
deserialize_from_bytes(data)
}
}
/// Trait to be used for (cipher) UV data.
#[enum_dispatch]
pub trait UvDataTrait: AeadDataTrait + AeadCipherTrait + KeyExchangeTrait + Clone {
/// Returned type by [`Self::decrypt`].
type P: UvDataPlainTrait;
/// Decrypt the UV data.
///
/// # Errors
///
/// This function will return an error if the passed `key` has the wrong key
/// type or the decryption fails.
fn decrypt(&self, key: &SymKey) -> Result<Self::P>
where
<Self as UvDataTrait>::P: for<'a> deku::DekuContainerRead<'a>,
{
if key.key_type() != self.aead_key_type() {
return Err(Error::UnexpectedKeyType {
given: key.key_type().to_string(),
expected: self.aead_key_type().to_string(),
});
}
let tag_size = self.aead_tag_size();
let aad = self.aad()?;
let unecrypted_data = self.data();
let iv = self.iv();
let tag = self.tag();
assert_eq!(tag.len(), tag_size);
let result = decrypt_aead(key, iv, &aad, &unecrypted_data, &tag)?;
Self::P::try_from_data(result.into_buf().value())
}
/// Parses and converts the data into an instance of [`Self`] if possible.
///
/// # Errors
///
/// This function will return an error if the data could not parsed or
/// converted.
fn try_from_data<'a>(data: &'a [u8]) -> Result<Self>
where
Self: deku::DekuContainerRead<'a> + Sized,
{
deserialize_from_bytes(data)
}
}