rust/pv: Fix padding of retrievable private keys

Fix the padding of keys that are smaller than the architected slot for
the retrievable key. Previously the keys where appended with zeros.
However, processing software expects a left-padding.
Affected key types:
  * Ed448
  * SecP521

While at it, fix documentation in the retrievable key struct.

Fixes: fd024387d7 ("rust/pv: Retrievable secrets support")
Acked-by: Ingo Franzki <ifranzki@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
2025-01-21 13:03:18 +01:00
committed by Jan Höppner
parent 7bd159de1d
commit 26d2e2d786
3 changed files with 55 additions and 30 deletions
+3
View File
@@ -117,6 +117,9 @@ pub enum Error {
exp: String,
},
#[error("Invalid data from OpenSSL")]
InvalSslData,
// errors from other crates
#[error(transparent)]
PvCore(#[from] pv_core::Error),
+50 -21
View File
@@ -21,7 +21,7 @@ use byteorder::BigEndian;
use openssl::{
hash::MessageDigest,
nid::Nid,
pkey::{Id, PKey, Private},
pkey::{Id, PKey, PKeyRef, Private},
};
use pv_core::static_assert;
use serde::{Deserialize, Serialize};
@@ -61,7 +61,7 @@ pub enum GuestSecret {
name: String,
/// SHA256 hash of [`GuestSecret::RetrievableKey::name`]
id: SecretId,
/// Confidential actual retrievable secret (32 bytes)
/// Confidential actual retrievable secret
#[serde(skip)]
secret: Confidential<Vec<u8>>,
},
@@ -293,20 +293,26 @@ fn hmac_sha(key: Confidential<Vec<u8>>) -> Result<RetrKeyInfo> {
/// Get an EC-private-key
fn ec(key: PKey<Private>) -> Result<RetrKeyInfo> {
let (key, nid) = match key.id() {
Id::EC => {
let ec_key = key.ec_key()?;
let key = ec_key.private_key().to_vec();
let nid = ec_key.group().curve_name().unwrap_or(Nid::UNDEF);
(key, nid)
// reads & left-pads Edward EC keys
fn pad_ed_key(pkey: &PKeyRef<Private>, curve: &EcCurves) -> Result<Vec<u8>> {
let raw_key = pkey.raw_private_key()?;
match raw_key.len().cmp(&curve.exp_key_size()) {
std::cmp::Ordering::Less => {
let mut key = Vec::with_capacity(curve.exp_key_size());
key.extend_from_slice(&vec![0u8; curve.exp_key_size() - raw_key.len()]);
key.extend_from_slice(&raw_key);
Ok(key)
}
std::cmp::Ordering::Equal => Ok(raw_key),
std::cmp::Ordering::Greater => Err(Error::InvalSslData),
}
// ED keys are not handled via the EC struct in OpenSSL.
id @ (Id::ED25519 | Id::ED448) => {
let key = key.raw_private_key()?;
let nid = Nid::from_raw(id.as_raw());
(key, nid)
}
_ => (vec![], Nid::UNDEF),
}
let nid = match key.id() {
Id::EC => key.ec_key()?.group().curve_name().unwrap_or(Nid::UNDEF),
id @ (Id::ED25519 | Id::ED448) => Nid::from_raw(id.as_raw()),
_ => Nid::UNDEF,
};
let kind = match nid {
@@ -327,7 +333,16 @@ fn ec(key: PKey<Private>) -> Result<RetrKeyInfo> {
}
};
let key = kind.resize_raw_key(key);
let key = match key.id() {
Id::EC => key
.ec_key()?
.private_key()
.to_vec_padded(kind.exp_key_size() as i32)?,
// ED keys are not handled via the EC struct in OpenSSL.
Id::ED25519 | Id::ED448 => pad_ed_key(&key, &kind)?,
_ => unreachable!(),
};
Ok((RetrievableSecret::Ec(kind), key.into()))
}
@@ -484,16 +499,19 @@ mod test {
assert_eq!(secret, exp);
}
#[track_caller]
fn gen_ec(nid: Nid) -> PKey<Private> {
let group = EcGroup::from_curve_name(nid).unwrap();
let key = EcKey::generate(&group).unwrap();
PKey::from_ec_key(key).unwrap()
}
#[track_caller]
fn test_ec(grp: Nid, exp_kind: EcCurves, exp_len: usize) {
let key = match grp {
NID_ED25519 => PKey::generate_ed25519().unwrap(),
NID_ED448 => PKey::generate_ed448().unwrap(),
nid => {
let group = EcGroup::from_curve_name(nid).unwrap();
let key = EcKey::generate(&group).unwrap();
PKey::from_ec_key(key).unwrap()
}
nid => gen_ec(nid),
};
let (kind, key) = ec(key).unwrap();
@@ -510,6 +528,17 @@ mod test {
test_ec(NID_ED448, EcCurves::Ed448, 64);
}
#[test]
fn retr_ec_pad() {
let pkey = PKey::generate_ed448().unwrap();
let (_, key) = ec(pkey).unwrap();
assert_eq!(key.value()[..7], [0; 7]);
let pkey = gen_ec(Nid::SECP521R1);
let (_, key) = ec(pkey).unwrap();
assert_eq!(key.value()[..14], [0; 14]);
}
#[test]
fn asc_parse() {
let id = [
+2 -9
View File
@@ -146,7 +146,8 @@ pub enum EcCurves {
}
impl EcCurves {
const fn exp_size(&self) -> usize {
/// Returns the expected key-byte-size for this curve.
pub const fn exp_key_size(&self) -> usize {
match self {
Self::Secp256R1 => 32,
Self::Secp384R1 => 48,
@@ -155,14 +156,6 @@ impl EcCurves {
Self::Ed448 => 64,
}
}
/// Resizes the raw key to the expected size.
///
/// See [`Vec::resize`]
pub fn resize_raw_key(&self, mut raw: Vec<u8>) -> Vec<u8> {
raw.resize(self.exp_size(), 0);
raw
}
}
// The names have to stay constant, otherwise the PEM contains invalid types