mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
89577c2f8c
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>
201 lines
6.1 KiB
Rust
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)
|
|
}
|
|
}
|