rust/pv: User-data signing and verifying

Add the ability to generate signed user-data and to verify the
signature.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Steffen Eiden
2024-01-30 12:55:56 +01:00
committed by Jan Höppner
parent f36c34038b
commit 34bef977e8
11 changed files with 798 additions and 3 deletions

View File

@@ -21,6 +21,7 @@ use std::convert::TryInto;
/// An AES256-key that will purge itself out of the memory when going out of scope
///
pub type Aes256Key = Secret<[u8; 32]>;
pub(crate) const AES_256_GCM_TAG_SIZE: usize = 16;
/// Types of symmetric keys, to specify during construction.
///
@@ -182,7 +183,7 @@ pub fn encrypt_aes(key: &SymKey, iv: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
///
/// This function will return an error if the data could not be encrypted by OpenSSL.
pub fn encrypt_aes_gcm(key: &SymKey, iv: &[u8], aad: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
let mut tag = vec![0xff; 16];
let mut tag = vec![0xff; AES_256_GCM_TAG_SIZE];
let encr = match key {
SymKey::Aes256(key) => encrypt_aead(
Cipher::aes_256_gcm(),

View File

@@ -38,6 +38,36 @@ pub enum Error {
#[error("Verifying signatures is only supported for EC and RSA keys")]
UnsupportedVerificationKey,
#[error("Provided binary request is too small")]
BinRequestSmall,
#[error("No Config UID found: {0}")]
NoCuid(String),
// errors from request types
#[error("Customer Communication Key must be 32 bytes long")]
CckSize,
#[error("Invalid {0} user-data for signing provided. Max {} bytes allowed", .0.max())]
AsrcbInvSgnUserData(UserDataType),
#[error("Unsupported user data signing key provided. Only EC(secp521r1) and RSA(2048 & 3072 bit) are supported")]
BinAsrcbUnsupportedUserDataSgnKey,
#[error("No user-key for verification provided and user-data is signed")]
BinAsrcbNoUserDataSgnKey,
#[error("Input does not contain an add-secret request version 1")]
BinAsrcbInvVersion,
#[error("Provided user-data key type ({key}) does not match with the user-data ({kind})")]
AsrcbUserDataKeyMismatch { key: String, kind: UserDataType },
#[error(
"The user-defined request signature could not be verified with the provided certificate"
)]
AsrcbUserDataSgnFail,
// errors from other crates
#[error(transparent)]
PvCore(#[from] pv_core::Error),
@@ -96,3 +126,5 @@ macro_rules! bail_hkd_verify {
};
}
pub(crate) use bail_hkd_verify;
use crate::request::uvsecret::UserDataType;

View File

@@ -65,7 +65,7 @@ pub mod request {
pub use crate::crypto::{hash, hkdf_rfc_5869};
pub use crate::crypto::{sign_msg, verify_signature};
pub use crate::crypto::{Aes256Key, SymKey, SymKeyType};
pub use crate::req::{Aad, Encrypt, Keyslot, ReqEncrCtx, Request};
pub use crate::req::{Aad, BinReqValues, Encrypt, Keyslot, ReqEncrCtx, Request};
pub use crate::secret::{Secret, Zeroize};
pub use crate::verify::{CertVerifier, HkdVerifier, NoVerifyHkd};
@@ -83,6 +83,7 @@ pub mod request {
asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion},
ext_secret::ExtSecret,
guest_secret::GuestSecret,
user_data::verify_asrcb_and_get_user_data,
};
pub use pv_core::request::uvsecret::AddSecretMagic;
pub use pv_core::request::uvsecret::UserDataType;

View File

@@ -2,6 +2,7 @@
//
// Copyright IBM Corp. 2023
use crate::crypto::AES_256_GCM_TAG_SIZE;
use crate::misc::to_u32;
use crate::request::{
derive_key, encrypt_aes, encrypt_aes_gcm, gen_ec_key, random_array, SymKey, SymKeyType,
@@ -14,6 +15,8 @@ use openssl::hash::{hash, MessageDigest};
use openssl::pkey::{PKey, PKeyRef, Private, Public};
use pv_core::request::{RequestMagic, RequestVersion};
use std::convert::TryInto;
use std::mem::size_of;
use utils::assert_size;
use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U32};
/// Encrypt a _secret_ using self and a given private key.
@@ -322,6 +325,7 @@ struct RequestHdr {
reserved28: u32,
sea: U32<BigEndian>,
}
assert_size!(RequestHdr, 48);
impl RequestHdr {
fn new(rqvn: u32, rql: u32, iv: [u8; 12], nks: u8, sea: u32, magic: Option<[u8; 8]>) -> Self {
@@ -380,6 +384,67 @@ pub trait Request {
fn add_hostkey(&mut self, hostkey: PKey<Public>);
}
/// A struct to represent some parts of a binary/encrypted request.
#[derive(Debug)]
#[allow(unused)]
#[allow(clippy::len_without_is_empty)]
pub struct BinReqValues<'a> {
iv: &'a [u8],
aad: &'a [u8],
req_dep_aad: &'a [u8],
encr: &'a [u8],
tag: &'a [u8],
version: u32,
len: usize,
}
impl<'a> BinReqValues<'a> {
pub(crate) const TAG_LEN: usize = AES_256_GCM_TAG_SIZE;
/// Get the locations from this request.
///
/// Does minimal sanity test, just tests to prevent panics.
/// `req` may be larger than the actual request.
pub fn get(req: &'a [u8]) -> Result<Self> {
let hdr = RequestHdr::read_from_prefix(req).ok_or(Error::BinRequestSmall)?;
let rql = hdr.rql.get() as usize;
let sea = hdr.sea.get() as usize;
if rql < req.len() || sea + Self::TAG_LEN > rql {
return Err(Error::BinRequestSmall);
}
let aad_size = rql - sea - Self::TAG_LEN;
if aad_size < size_of::<RequestHdr>() {
return Err(Error::BinRequestSmall);
}
let iv = &req[0x10..0x1c];
let aad = &req[..aad_size];
let req_dep_aad = &req[size_of::<RequestHdr>()..aad_size];
let encr = &req[aad_size..(aad_size + sea)];
let tag = &req[rql - Self::TAG_LEN..];
Ok(Self {
iv,
aad,
req_dep_aad,
encr,
tag,
version: hdr.rqvn.get(),
len: rql,
})
}
/// Returns the version of this [`BinReqValues`].
pub fn version(&self) -> u32 {
self.version
}
/// Returns the length of this [`BinReqValues`].
pub fn len(&self) -> usize {
self.len
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -10,3 +10,4 @@
pub mod asrcb;
pub mod ext_secret;
pub mod guest_secret;
pub mod user_data;

View File

@@ -176,6 +176,10 @@ pub struct AddSecretRequest {
}
impl AddSecretRequest {
#[allow(unused)]
/// Offset of the user-data in the add-secret request in bytes
pub(super) const V1_USER_DATA_OFFS: usize = 0x218;
/// Create a new add-secret request.
///
/// The request has no extension secret, no configuration UID, no host-keys,

View File

@@ -0,0 +1,612 @@
#![allow(unused)]
use crate::{
crypto::{sign_msg, verify_signature},
req::BinReqValues,
request::{
openssl::{
pkey::{PKey, Private},
MessageDigest,
},
uvsecret::{AddSecretRequest, AddSecretVersion},
RequestMagic,
},
Error, Result,
};
use openssl::{
nid::Nid,
pkey::{HasParams, HasPublic, Id, PKeyRef, Public},
};
use pv_core::request::uvsecret::AddSecretMagic;
use pv_core::request::uvsecret::UserDataType;
use utils::assert_size;
use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U16};
/// User data.
///
/// User defined data can be:
/// - 512 bytes arbitrary data
/// - 256 bytes arbitrary data + EC(secp521r1) signature
/// ```none
/// LAYOUT
/// |------------------------|
/// | user-data (256) |
/// | ec signature (139) |
/// | reserved (5) |
/// | signature size (2) (BE)|
/// | reserved (110) |
/// |------------------------|
/// ```
/// - 256 bytes arbitrary data + RSA2048 signature
/// ```none
/// LAYOUT
/// |---------------------|
/// | user-data (256) |
/// | rsa signature (256) |
/// |---------------------|
/// ```
/// - 128 bytes arbitrary data + RSA3072 signature
/// ```none
/// LAYOUT
/// |---------------------|
/// | user-data (128) |
/// | rsa signature (384) |
/// |---------------------|
/// ```
///
/// Ensures that the data+signature fits into 512 bytes
/// must be created via functions!
#[derive(Debug, Clone)]
pub(super) enum UserData {
Null,
Unsigned(Vec<u8>),
Signed(SignedUserData),
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
struct EcUserData {
data: [u8; 256],
signature: [u8; EC_SIGN_MAX_SIZE],
res_18b: [u8; 5],
sgn_size: U16<BigEndian>,
res_192: [u8; 110],
}
assert_size!(EcUserData, USER_DATA_SIZE);
const USER_DATA_SIZE: usize = 0x200;
const EC_SIGN_MAX_SIZE: usize = 139;
impl EcUserData {
// Sets the signature to this data.
//
//# Panic
// Panics if `sgn` is longer than 139 bytes
fn set_signature(&mut self, sgn: &[u8]) {
debug_assert!(sgn.len() <= EC_SIGN_MAX_SIZE);
self.signature.fill(0);
self.signature[..sgn.len()].copy_from_slice(sgn);
self.res_18b.fill(0);
self.sgn_size = (sgn.len() as u16).into();
self.res_192.fill(0);
}
}
#[derive(Debug, Clone)]
pub(super) struct SignedUserData {
sign_key: PKey<Private>,
data: Vec<u8>,
}
impl UserData {
const USER_DATA_SIZE: usize = 0x200;
fn user_data_type<P: HasPublic>(sign_key: &PKeyRef<P>) -> Result<UserDataType> {
fn check_curve<P: HasParams>(pkey: &PKeyRef<P>) -> Result<bool> {
let nid = pkey.ec_key()?.group().curve_name();
match nid {
Some(nid) => Ok(nid == Nid::SECP521R1),
None => Ok(false),
}
}
match sign_key.id() {
Id::EC if check_curve(sign_key)? => Ok(UserDataType::SgnEcSECP521R1),
Id::RSA if sign_key.rsa()?.size() == 2048 / 8 => Ok(UserDataType::SgnRsa2048),
Id::RSA if sign_key.rsa()?.size() == 3072 / 8 => Ok(UserDataType::SgnRsa3072),
_ => Err(Error::BinAsrcbUnsupportedUserDataSgnKey),
}
}
pub(super) fn magic(&self) -> RequestMagic {
let magic: AddSecretMagic = self.data_type().into();
magic.get()
}
/// Creates new user data
///
/// Verifies that the provided data + signature fits into 512 bytes
///
/// #Error
/// An error is reported if the provided data and the signature would not fit into 512 bytes
/// An error is reported if the key is not of type RSA (2048|3072) or EC(specp521r1)
pub(super) fn new(sign_key: Option<PKey<Private>>, data: Vec<u8>) -> Result<Self> {
let sign_key = match sign_key {
None => {
return match data.len() > UserDataType::Unsigned.max() {
true => Err(Error::AsrcbInvSgnUserData(UserDataType::Unsigned)),
false => Ok(Self::Unsigned(data)),
};
}
Some(skey) => skey,
};
let kind = Self::user_data_type(&sign_key)?;
// does the data fit into the arbitrary buffer?
if data.len() > kind.max() {
return Err(Error::AsrcbInvSgnUserData(kind));
}
Ok(Self::Signed(SignedUserData { sign_key, data }))
}
/// Signs data in buf, writes signature to buf+user_data_offset+sign_offset if applicable.
///
/// Uses [`MessageDigest::sha512`] as digest. Does not modify the abritary user data buffer.
///
/// * buf: user data buffer, must be at least 512 bytes long
///
/// # Panic
/// panics if `buf` is smaller than 512 bytes
///
/// # Errors
/// Returns an error if signature could not be calculated.
/// It is considered no error if no signature is required by user data type
pub(super) fn sign(&self, buf: &mut [u8], user_data_offset: usize) -> Result<()> {
// get signing info or return if no signature is required
let signed_data = match self {
UserData::Null | UserData::Unsigned(_) => return Ok(()),
UserData::Signed(s) => s,
};
debug_assert!(buf.len() >= USER_DATA_SIZE);
// clear the signature area
let sgn_offset = user_data_offset + self.data_type().max();
buf[sgn_offset..user_data_offset + USER_DATA_SIZE].fill(0);
// calculate signature
let sgn = sign_msg(&signed_data.sign_key, MessageDigest::sha512(), buf)?;
// insert signature
if let UserDataType::SgnEcSECP521R1 = self.data_type() {
// Panic: will not panic buffer is 512+ bytes long
let buf_ec = EcUserData::mut_from_prefix(&mut buf[user_data_offset..]).unwrap();
buf_ec.set_signature(&sgn);
} else {
// Panic: will not panic buffer is 512+ bytes long
buf[sgn_offset..sgn_offset + sgn.len()].copy_from_slice(&sgn);
}
Ok(())
}
fn data_type(&self) -> UserDataType {
match self {
Self::Null => UserDataType::Null,
Self::Unsigned(_) => UserDataType::Unsigned,
Self::Signed(data) => Self::user_data_type(&data.sign_key).unwrap(),
}
}
/// returns a slice for the abitraty user data as first tuple part if User data is available
/// the second part contains a vector, created on the fly, which contains enough zeros to fill
/// the missing bytes to fill 512 bytes of space or None if the first slice already contains
/// 512 bytes
pub(super) fn data(&self) -> (Option<&[u8]>, Option<Vec<u8>>) {
let buf = match self {
UserData::Null => None,
UserData::Unsigned(d) => Some(d),
UserData::Signed(SignedUserData { data, .. }) => Some(data),
};
let remaining_size = Self::USER_DATA_SIZE - buf.map(|b| b.len()).unwrap_or(0);
let remaining = match remaining_size > 0 {
true => Some(vec![0; remaining_size]),
false => None,
};
(buf.map(|b| b.as_ref()), remaining)
}
}
fn format_vrfy_key(key: &PKeyRef<Public>) -> String {
let id = key.id();
match key.rsa() {
Ok(key) => format!("RSA {}", key.size() * 8),
Err(_) if id == Id::EC => "EC".to_string(),
Err(_) => "Unknown".to_string(),
}
}
fn check_key_format(kind: UserDataType, key: &PKeyRef<Public>) -> Result<()> {
let other_kind =
UserData::user_data_type(key).map_err(|_| Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(key),
kind,
})?;
if other_kind == kind {
Ok(())
} else {
Err(Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(key),
kind,
})
}
}
/// Verify the user data contained in the add-secret request.
///
/// First checks that the provided data contains a sound add-secret request.
/// Then performs the inverse action that happened during the add-secret generation with user-data
/// signature:
/// - extract and replace the signature with zeros
/// - verify the signature of the request until, but not including the request tag
///
/// # Returns
///
/// Extracrted user-data if available
///
/// #Errors
///
/// returns an error if
/// - No sound add-secret request presented
/// - Sinned user-data indicated, but no key provided
/// - Another keytype provided than indicated in the request
/// - Signature could not be verified by the provided key
/// - any OpenSSL error that might happen during the verification process
pub fn verify_asrcb_and_get_user_data(
mut asrcb: Vec<u8>,
key: Option<PKey<Public>>,
) -> Result<Option<Vec<u8>>> {
// check that the provided buffer contains an Add Secret request
let magic = AddSecretMagic::try_from_bytes(&asrcb)?;
let req = BinReqValues::get(&asrcb)?;
if req.version() != AddSecretVersion::One as u32 {
return Err(Error::BinAsrcbInvVersion);
}
//preventing the two lines after the truncate from panicking
let req_len = req.len();
if asrcb.len() < req_len
|| req_len < AddSecretRequest::V1_USER_DATA_OFFS + UserData::USER_DATA_SIZE
{
return Err(pv_core::Error::NoAsrcb.into());
}
// forget the tag (and all additional data that might be behind the tag)
asrcb.truncate(req_len - BinReqValues::TAG_LEN);
// get a mutable refrenence on the 512 bytes of user data
let (_, user_data) = asrcb.split_at_mut(AddSecretRequest::V1_USER_DATA_OFFS);
let user_data = &mut user_data[..UserData::USER_DATA_SIZE];
// depending on the user_data_type do:
// Null -> exit w/o user data
// Unsigned -> exit return all user data
// Signed ->
// - check that provided key matches user data keytype
// - extract user data& signature
let (key, user_data) = match (key, magic.kind()) {
(_, UserDataType::Null) => return Ok(None),
(None, UserDataType::Unsigned) => return Ok(Some(user_data.to_vec())),
(Some(key), UserDataType::Unsigned) => {
return Err(Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(&key),
kind: UserDataType::Unsigned,
})
}
(Some(key), _) => {
check_key_format(magic.kind(), &key)?;
(key, VerifiedUserData::new(user_data, magic.kind()))
}
(None, _) => return Err(Error::BinAsrcbNoUserDataSgnKey),
};
match verify_signature(&key, MessageDigest::sha512(), &asrcb, user_data.signature())? {
false => Err(Error::AsrcbUserDataSgnFail),
true => Ok(Some(user_data.into())),
}
}
// Internal representation of the 512 bytes of user-data, signing-algorithm agnostic
struct VerifiedUserData {
data: Vec<u8>,
signature: Vec<u8>,
}
impl VerifiedUserData {
/// Reads user-data from buf depending on the indicated user data type.
/// Overwrites the signature in the buf with zeros.
///
/// #Panics
/// Panics it provided buffer is smaller that 512 bytes or kind is Null or Unsigned
fn new(buf: &mut [u8], kind: UserDataType) -> Self {
assert!(buf.len() >= 0x200);
let (ret, sgn) = match kind {
UserDataType::SgnEcSECP521R1 => {
let EcUserData {
data,
signature,
sgn_size,
..
} = EcUserData::mut_from_prefix(buf).unwrap();
let data_len: usize = data.len();
let data = data.to_vec();
let mut signature = signature.to_vec();
signature.truncate(sgn_size.get() as usize);
(Self { data, signature }, &mut buf[data_len..])
}
UserDataType::SgnRsa2048 => (
Self {
data: buf[..0x100].to_vec(),
signature: buf[0x100..].to_vec(),
},
&mut buf[0x100..],
),
UserDataType::SgnRsa3072 => (
Self {
data: buf[..0x80].to_vec(),
signature: buf[0x80..].to_vec(),
},
&mut buf[0x80..],
),
UserDataType::Null => unreachable!(),
UserDataType::Unsigned => unreachable!(),
};
//overwrite signature field with zeros
sgn.fill(0);
ret
}
fn signature(&self) -> &[u8] {
self.signature.as_ref()
}
}
impl From<VerifiedUserData> for Vec<u8> {
fn from(value: VerifiedUserData) -> Self {
value.data
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{get_test_asset, test_utils::get_test_keys};
#[test]
fn sign_null() {
let mut buf = vec![17; 0x200];
let user_data = UserData::Null;
let (data, _) = user_data.data();
assert!(data.is_none());
user_data.sign(&mut buf, 0).unwrap();
// sign should not touch the buffer
assert_eq!(buf, vec![17; 0x200]);
}
#[test]
fn sign_unsigned() {
let user_data = UserData::Unsigned(vec![0x11; 0x200]);
let (data, _) = user_data.data();
assert_eq!(data.unwrap(), &[0x11; 0x200]);
let mut buf = vec![17; 0x200];
user_data.sign(&mut buf, 0).unwrap();
// sign should not touch the buffer
assert_eq!(buf, vec![17; 0x200]);
}
#[test]
fn sign_rsa2048() {
let rsa = get_test_asset!("keys/rsa2048key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let mut buf = vec![0x17; 0x200];
let user_data = UserData::new(Some(rsa.clone()), vec![0x11; 0x100]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x100].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnRsa2048);
let res = verify_signature(
&rsa,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_rsa3072() {
let rsa = get_test_asset!("keys/rsa3072key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let mut buf = vec![0x17; 0x200];
let user_data = UserData::new(Some(rsa.clone()), vec![0x11; 0x80]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x80].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnRsa3072);
let res = verify_signature(
&rsa,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_rsa4096_fail() {
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let user_data = UserData::new(Some(rsa.clone()), vec![]);
assert!(matches!(
user_data.unwrap_err(),
Error::BinAsrcbUnsupportedUserDataSgnKey
));
}
#[test]
fn sign_ec() {
let (ec, _) = get_test_keys();
let mut buf = vec![0x11; 0x200];
let user_data = UserData::new(Some(ec.clone()), vec![0x11; 0x80]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x80].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let buf_ec = EcUserData::mut_from(&mut buf).unwrap();
let EcUserData {
data,
signature,
res_18b,
sgn_size,
res_192,
} = buf_ec;
assert_eq!(data, &[0x11u8; 256]);
assert_ne!(signature, &[0u8; 139]);
assert_eq!(res_18b, &[0u8; 5]);
assert!(sgn_size.get() <= 139);
assert_eq!(res_192, &[0u8; 110]);
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnEcSECP521R1);
let res = verify_signature(
&ec,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_ec_fail() {
let ec = get_test_asset!("keys/ecsecp256k1.pem");
let ec = PKey::private_key_from_pem(ec).unwrap();
let user_data = UserData::new(Some(ec.clone()), vec![]);
assert!(matches!(
user_data.unwrap_err(),
Error::BinAsrcbUnsupportedUserDataSgnKey
));
}
#[test]
fn check_format() {
let (_, ec) = get_test_keys();
check_key_format(UserDataType::SgnEcSECP521R1, &ec).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &ec);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
let rsa = get_test_asset!("keys/rsa2048key.pub.pem");
let rsa = PKey::public_key_from_pem(rsa).unwrap();
check_key_format(UserDataType::SgnRsa2048, &rsa).unwrap();
let rsa = get_test_asset!("keys/rsa3072key.pub.pem");
let rsa = PKey::public_key_from_pem(rsa).unwrap();
check_key_format(UserDataType::SgnRsa3072, &rsa).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &rsa);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let rsa = PKey::public_key_from_pem(&rsa.public_key_to_pem().unwrap()).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &rsa);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
}
#[test]
fn kind() {
let (ec, _) = get_test_keys();
let kind = UserData::user_data_type(&ec).unwrap();
assert_eq!(kind, UserDataType::SgnEcSECP521R1);
let rsa = get_test_asset!("keys/rsa2048key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap();
assert_eq!(kind, UserDataType::SgnRsa2048);
let rsa = get_test_asset!("keys/rsa3072key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap();
assert_eq!(kind, UserDataType::SgnRsa3072);
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap_err();
assert!(matches!(kind, Error::BinAsrcbUnsupportedUserDataSgnKey));
}
#[test]
fn new() {
let (ec, _) = get_test_keys();
let user_data = UserData::new(
Some(ec.clone()),
vec![1; UserDataType::SgnEcSECP521R1.max()],
)
.unwrap();
assert!(matches!(user_data, UserData::Signed(_)));
let user_data = UserData::new(Some(ec), vec![1; UserDataType::SgnEcSECP521R1.max() + 1]);
assert!(matches!(
user_data,
Err(Error::AsrcbInvSgnUserData(UserDataType::SgnEcSECP521R1))
));
let user_data = UserData::new(None, vec![1; UserDataType::Unsigned.max()]).unwrap();
assert!(matches!(user_data, UserData::Unsigned(_)));
let user_data = UserData::new(None, vec![1; UserDataType::Unsigned.max() + 1]);
assert!(matches!(
user_data,
Err(Error::AsrcbInvSgnUserData(UserDataType::Unsigned))
));
}
#[test]
fn data() {
let (ec, _) = get_test_keys();
let data_in = vec![1; UserDataType::SgnEcSECP521R1.max()];
let user_data = UserData::new(Some(ec.clone()), data_in.clone()).unwrap();
let exp_pad = Some(vec![0; UserData::USER_DATA_SIZE - data_in.len()]);
let (data_out, pad) = user_data.data();
assert_eq!(data_out, Some(data_in.as_ref()));
assert_eq!(pad, exp_pad);
let data_in = vec![1; UserDataType::SgnEcSECP521R1.max() - 1];
let user_data = UserData::new(Some(ec.clone()), data_in.clone()).unwrap();
let exp_pad = Some(vec![0; UserData::USER_DATA_SIZE - data_in.len()]);
let (data_out, pad) = user_data.data();
assert_eq!(data_out, Some(data_in.as_ref()));
assert_eq!(pad, exp_pad);
}
}

View File

@@ -5,7 +5,10 @@ use pv::{
get_test_asset,
request::{
openssl::pkey::{PKey, Public},
uvsecret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
uvsecret::{
verify_asrcb_and_get_user_data, AddSecretFlags, AddSecretRequest, AddSecretVersion,
ExtSecret, GuestSecret,
},
BootHdrTags, ReqEncrCtx, Request, SymKey,
},
test_utils::get_test_keys,
@@ -153,3 +156,12 @@ fn null_none_default_cuid_seven() {
let exp = get_test_asset!("exp/asrcb/null_none_default_cuid_seven");
assert_eq!(asrcb, exp);
}
#[test]
fn verify_no_user_data() {
let req = get_test_asset!("exp/asrcb/null_none_default_ncuid_one");
assert!(matches!(
verify_asrcb_and_get_user_data(req.to_vec(), None),
Ok(None)
))
}

View File

@@ -0,0 +1,8 @@
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIAiQERmhEIwksExNpW2CsaQeFPKFEN6PIdMWUiX3Mu7FoAcGBSuBBAAK
oUQDQgAEO9U+NDdHcIZ59RzTq/6lDH2RA7sEyRlvFVQsj7feiuXh4Q4qeZNCb2sn
s7Hd1lUjFexH+Cp97/ggwSa3q2y/0Q==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
io4wIYBrX/SPmp7tQvWI18Ike/IDtA==
-----END PRIVATE KEY-----

View File

@@ -67,6 +67,13 @@ impl AddSecretMagic {
let kind = UserDataType::try_from(kind)?;
Ok(Self::from(kind))
}
/// Returns the [`UserDataType`] of this [`AddSecretMagic`].
pub fn kind(&self) -> UserDataType {
// Panic: Will never panic. The value is cheched during construcion of the object for
// beeing one of the enum values.
self.kind.get().try_into().unwrap()
}
}
/// Types of (non architectured) user data for an add-secret request