mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
pvimg: info: Improve JSON output
Improve JSON output and implement deserialization. Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Marc Hartmayer <marc@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
012025595f
commit
87966251c4
@@ -10,6 +10,7 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.95", features = ["std"] }
|
||||
base64 = "0.22.1"
|
||||
clap = { version ="4.5", features = ["derive", "wrap_help"]}
|
||||
deku = "0.18"
|
||||
deku_derive = "0.18"
|
||||
|
||||
@@ -31,10 +31,16 @@ pub fn info(opt: &InfoArgs) -> Result<OwnExitCode> {
|
||||
let key =
|
||||
SymKey::try_from_data(hdr.key_type(), read_file(key_path, "Reading key")?.into())?;
|
||||
let decrypted_hdr = hdr.decrypt(&key)?;
|
||||
SeH::Decrypted(decrypted_hdr)
|
||||
SeH::DecryptedSeHdr {
|
||||
se_hdr: decrypted_hdr,
|
||||
verified: true,
|
||||
}
|
||||
} else {
|
||||
warn!("WARNING: The Secure Execution header integrity and authenticity was not verified. Specify '--hdr-key' to authenticate it. Do not trust the data without verification.");
|
||||
SeH::Encrypted(hdr)
|
||||
SeH::SeHdr {
|
||||
se_hdr: hdr,
|
||||
verified: false,
|
||||
}
|
||||
};
|
||||
|
||||
match opt.format {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
use deku::{ctx::Endian, DekuRead, DekuWrite};
|
||||
use pv::request::Zeroize;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::serializing::ser_lower_hex;
|
||||
use super::serializing::serde_hex_left_padded_u64;
|
||||
use crate::pv_utils::error::Error;
|
||||
|
||||
pub const PSW32_ADDR_MASK: u64 = 0x000000007fffffff;
|
||||
@@ -14,12 +14,12 @@ pub const PSW_MASK_BA: u64 = 0x0000000080000000;
|
||||
pub const PSW_MASK_EA: u64 = 0x0000000100000000;
|
||||
pub const PSW_MASK_BIT_12: u64 = 0x08000000000000;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct PSW {
|
||||
#[serde(serialize_with = "ser_lower_hex")]
|
||||
#[serde(with = "serde_hex_left_padded_u64", rename = "mask_hex")]
|
||||
pub mask: u64,
|
||||
#[serde(serialize_with = "ser_lower_hex")]
|
||||
#[serde(with = "serde_hex_left_padded_u64", rename = "addr_hex")]
|
||||
pub addr: u64,
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ impl Zeroize for PSW {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct ShortPsw(u64);
|
||||
|
||||
@@ -135,4 +135,19 @@ mod tests {
|
||||
let new_psw: PSW = short_psw.into();
|
||||
assert_eq!(new_psw, psw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn psw_json_roundtrip() {
|
||||
let psw = PSW {
|
||||
addr: 0x1234567890abcdef,
|
||||
mask: 0xfedcba0987654321,
|
||||
};
|
||||
let json = serde_json::to_string(&psw).expect("should serialize");
|
||||
assert_eq!(
|
||||
json,
|
||||
"{\"mask_hex\":\"fedcba0987654321\",\"addr_hex\":\"1234567890abcdef\"}"
|
||||
);
|
||||
let deserialized: PSW = serde_json::from_str(&json).expect("should deserialize");
|
||||
assert_eq!(psw, deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use pv::{
|
||||
},
|
||||
static_assert,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use super::hdr_v1::{SeHdrBinV1, SeHdrDataV1};
|
||||
use super::{PlaintextControlFlagsV1, SecretControlFlagsV1};
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
misc::PAGESIZE,
|
||||
pv_utils::{
|
||||
error::{Error, Result},
|
||||
serializing::{ser_hex, serialize_to_bytes},
|
||||
serializing::{serde_hex_array, serialize_to_bytes},
|
||||
uvdata::{
|
||||
AeadCipherTrait, AeadDataTrait, AeadPlainDataTrait, KeyExchangeTrait, UvDataPlainTrait,
|
||||
UvDataTrait,
|
||||
@@ -35,7 +35,7 @@ use crate::{
|
||||
|
||||
#[repr(u32)]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(
|
||||
endian = "endian",
|
||||
id_type = "u32",
|
||||
@@ -47,26 +47,37 @@ pub enum SeHdrVersion {
|
||||
V1 = 0x100,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SeH {
|
||||
Decrypted(SeHdrPlain),
|
||||
Encrypted(SeHdr),
|
||||
DecryptedSeHdr {
|
||||
verified: bool,
|
||||
#[serde(flatten)]
|
||||
se_hdr: SeHdrPlain,
|
||||
},
|
||||
SeHdr {
|
||||
verified: bool,
|
||||
#[serde(flatten)]
|
||||
se_hdr: SeHdr,
|
||||
},
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct SeHdrCommon {
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "magic_hex")]
|
||||
pub magic: [u8; 8],
|
||||
pub version: SeHdrVersion,
|
||||
}
|
||||
static_assert!(::std::mem::size_of::<SeHdrCommon>() == 12);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct SeHdrCommonWithSize {
|
||||
#[serde(with = "serde_hex_array", rename = "magic_hex")]
|
||||
pub magic: [u8; 8],
|
||||
pub version: SeHdrVersion,
|
||||
pub sehs: u32,
|
||||
@@ -85,7 +96,7 @@ impl SeHdrCommon {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "Endian::Big")]
|
||||
/// Secure Execution header structure
|
||||
pub struct SeHdr {
|
||||
@@ -97,7 +108,7 @@ pub struct SeHdr {
|
||||
pub data: SeHdrVersioned,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "Endian::Big")]
|
||||
/// Plain data Secure Execution header structure
|
||||
pub struct SeHdrPlain {
|
||||
@@ -109,7 +120,7 @@ pub struct SeHdrPlain {
|
||||
}
|
||||
|
||||
#[enum_dispatch(AeadCipherTrait, AeadDataTrait, KeyExchangeTrait)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[deku(ctx = "_endian: Endian, version: SeHdrVersion", id = "version")]
|
||||
pub enum SeHdrVersioned {
|
||||
@@ -123,7 +134,7 @@ pub enum SeHdrVersioned {
|
||||
KeyExchangeTrait,
|
||||
KeyExchangeBuilderTrait
|
||||
)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[deku(ctx = "_endian: Endian, version: SeHdrVersion", id = "version")]
|
||||
pub enum SeHdrData {
|
||||
@@ -382,7 +393,7 @@ impl AeadCipherTrait for SeHdrPlain {
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use super::SeHdr;
|
||||
use super::*;
|
||||
use crate::error::Error;
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,7 +14,7 @@ use pv::request::{
|
||||
random_array, Aes256XtsKey, Confidential, EcPubKeyCoord, Encrypt, Keyslot, SymKey, SymKeyType,
|
||||
Zeroize, SHA_512_HASH_LEN,
|
||||
};
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::keys::phkh_v1;
|
||||
use crate::{
|
||||
@@ -31,7 +31,8 @@ use crate::{
|
||||
},
|
||||
serializing::{
|
||||
bytesize, bytesize_confidential, confidential_read_slice, confidential_write_slice,
|
||||
ser_hex, ser_hex_confidential, ser_lower_hex, serialize_to_bytes,
|
||||
serde_base64, serde_hex_array, serde_hex_confidential_array, serde_hex_left_padded_u64,
|
||||
serialize_to_bytes,
|
||||
},
|
||||
try_copy_slice_to_array,
|
||||
uvdata::{
|
||||
@@ -49,27 +50,28 @@ struct HdrSizesV1 {
|
||||
pub sea: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct SeHdrAadV1 {
|
||||
#[deku(assert = "*sehs <= SeHdrDataV1::MAX_SIZE.try_into().unwrap()")]
|
||||
pub sehs: u32,
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "iv_hex")]
|
||||
pub iv: [u8; SymKeyType::AES_256_GCM_IV_LEN],
|
||||
#[serde(skip)]
|
||||
res1: u32,
|
||||
#[deku(assert = "*nks <= (*sehs).into()", update = "self.keyslots.len()")]
|
||||
pub nks: u64,
|
||||
#[deku(assert = "*sea <= (*sehs).into()")]
|
||||
pub sea: u64,
|
||||
pub nep: u64,
|
||||
#[serde(serialize_with = "ser_lower_hex")]
|
||||
#[serde(with = "serde_hex_left_padded_u64", rename = "pcf_hex")]
|
||||
pub pcf: u64,
|
||||
pub cust_pub_key: EcPubKeyCoordV1,
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "pld_hex")]
|
||||
pub pld: [u8; SHA_512_HASH_LEN],
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "ald_hex")]
|
||||
pub ald: [u8; SHA_512_HASH_LEN],
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "tld_hex")]
|
||||
pub tld: [u8; SHA_512_HASH_LEN],
|
||||
#[deku(count = "nks")]
|
||||
pub keyslots: Vec<BinaryKeySlotV1>,
|
||||
@@ -104,27 +106,30 @@ impl KeyExchangeTrait for SeHdrAadV1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct SeHdrConfV1 {
|
||||
#[serde(serialize_with = "ser_hex_confidential")]
|
||||
#[serde(with = "serde_hex_confidential_array", rename = "cck_hex")]
|
||||
#[deku(
|
||||
reader = "confidential_read_slice(deku::reader, endian)",
|
||||
writer = "confidential_write_slice(cck, deku::writer, endian)"
|
||||
)]
|
||||
cck: Confidential<[u8; 32]>,
|
||||
#[serde(serialize_with = "ser_hex_confidential")]
|
||||
#[serde(with = "serde_hex_confidential_array", rename = "xts_hex")]
|
||||
#[deku(
|
||||
reader = "confidential_read_slice(deku::reader, endian)",
|
||||
writer = "confidential_write_slice(xts, deku::writer, endian)"
|
||||
)]
|
||||
xts: Aes256XtsKey,
|
||||
psw: PSW,
|
||||
#[serde(serialize_with = "ser_lower_hex")]
|
||||
#[serde(with = "serde_hex_left_padded_u64", rename = "scf_hex")]
|
||||
pub scf: u64,
|
||||
#[serde(skip)]
|
||||
#[deku(assert_eq = "0")]
|
||||
noi: u32,
|
||||
#[serde(skip)]
|
||||
res2: u32,
|
||||
#[serde(skip)]
|
||||
#[deku(count = "noi")]
|
||||
opt_items: Vec<u8>,
|
||||
}
|
||||
@@ -141,27 +146,41 @@ impl Zeroize for SeHdrConfV1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Debug, Clone, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Default, PartialEq, Eq, Debug, Clone, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct SeHdrTagV1 {
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "tag_hex")]
|
||||
tag: [u8; SymKeyType::AES_256_GCM_TAG_LEN],
|
||||
}
|
||||
|
||||
fn ser_confidential_confv1<S: Serializer>(
|
||||
encrypted: &Confidential<SeHdrConfV1>,
|
||||
ser: S,
|
||||
) -> std::result::Result<S::Ok, S::Error> {
|
||||
encrypted.value().serialize(ser)
|
||||
mod ser_confidential_confv1 {
|
||||
use pv::request::Confidential;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use super::SeHdrConfV1;
|
||||
|
||||
pub fn serialize<S: Serializer>(
|
||||
encrypted: &Confidential<SeHdrConfV1>,
|
||||
ser: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
encrypted.value().serialize(ser)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<Confidential<SeHdrConfV1>, D::Error> {
|
||||
let conf = SeHdrConfV1::deserialize(deserializer)?;
|
||||
Ok(Confidential::new(conf))
|
||||
}
|
||||
}
|
||||
|
||||
/// Secure Execution Header definition
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "big")]
|
||||
pub struct SeHdrDataV1 {
|
||||
#[serde(flatten)]
|
||||
pub aad: SeHdrAadV1,
|
||||
#[serde(flatten, serialize_with = "ser_confidential_confv1")]
|
||||
#[serde(flatten, with = "ser_confidential_confv1")]
|
||||
#[deku(
|
||||
reader = "confidential_read_sehdrconf_v1(deku::reader)",
|
||||
writer = "confidential_write_sehdrconf_v1(data, deku::writer)"
|
||||
@@ -439,14 +458,14 @@ impl SeHdrPubBuilderTrait for SeHdrDataV1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "big")]
|
||||
pub struct SeHdrBinV1 {
|
||||
#[serde(flatten)]
|
||||
pub aad: SeHdrAadV1,
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_base64", rename = "cipher_data_b64")]
|
||||
#[deku(bytes_read = "aad.sea")]
|
||||
pub data: Vec<u8>,
|
||||
pub cipher_data: Vec<u8>,
|
||||
#[serde(flatten)]
|
||||
pub tag: SeHdrTagV1,
|
||||
}
|
||||
@@ -512,7 +531,7 @@ impl AeadDataTrait for SeHdrBinV1 {
|
||||
}
|
||||
|
||||
fn data(&self) -> Vec<u8> {
|
||||
self.data.to_owned()
|
||||
self.cipher_data.to_owned()
|
||||
}
|
||||
|
||||
fn tag(&self) -> Vec<u8> {
|
||||
@@ -667,4 +686,93 @@ mod tests {
|
||||
.expect("should not fail");
|
||||
assert!(matches!(builder.build(), Err(Error::InvalidSeHdr)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_se_hdr_tag_v1_json() {
|
||||
let tag = SeHdrTagV1 {
|
||||
tag: [0x42; SymKeyType::AES_256_GCM_TAG_LEN],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&tag).expect("should serialize");
|
||||
assert_eq!(json, "{\"tag_hex\":\"42424242424242424242424242424242\"}");
|
||||
let deserialized: SeHdrTagV1 = serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(tag, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_se_hdr_conf_v1_json() {
|
||||
let conf = SeHdrConfV1 {
|
||||
cck: Confidential::new([0x11; 32]),
|
||||
xts: Confidential::new([0x22; SymKeyType::AES_256_XTS_KEY_LEN]),
|
||||
psw: PSW {
|
||||
addr: 0x1000,
|
||||
mask: 0x2000,
|
||||
},
|
||||
scf: 0x42,
|
||||
noi: 0,
|
||||
res2: 0,
|
||||
opt_items: vec![],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&conf).expect("should serialize");
|
||||
assert_eq!(json, "{\"cck_hex\":\"1111111111111111111111111111111111111111111111111111111111111111\",\"xts_hex\":\"22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222\",\"psw\":{\"mask_hex\":\"0000000000002000\",\"addr_hex\":\"0000000000001000\"},\"scf_hex\":\"0000000000000042\"}");
|
||||
let deserialized: SeHdrConfV1 = serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(conf, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_se_hdr_aad_v1_json() {
|
||||
let aad = SeHdrAadV1 {
|
||||
sehs: 1024,
|
||||
iv: [0x33; SymKeyType::AES_256_GCM_IV_LEN],
|
||||
res1: 0,
|
||||
nks: 2,
|
||||
sea: 512,
|
||||
nep: 10,
|
||||
pcf: 0x100,
|
||||
cust_pub_key: EcPubKeyCoordV1 { coord: [0x44; 160] },
|
||||
pld: [0x55; SHA_512_HASH_LEN],
|
||||
ald: [0x66; SHA_512_HASH_LEN],
|
||||
tld: [0x77; SHA_512_HASH_LEN],
|
||||
keyslots: vec![],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&aad).expect("should serialize");
|
||||
assert_eq!(json, "{\"sehs\":1024,\"iv_hex\":\"333333333333333333333333\",\"nks\":2,\"sea\":512,\"nep\":10,\"pcf_hex\":\"0000000000000100\",\"cust_pub_key\":{\"coord_hex\":\"44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\"},\"pld_hex\":\"55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555\",\"ald_hex\":\"66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\",\"tld_hex\":\"77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777\",\"keyslots\":[]}");
|
||||
let deserialized: SeHdrAadV1 = serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(aad, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_se_hdr_bin_v1_json() {
|
||||
let bin = SeHdrBinV1 {
|
||||
aad: SeHdrAadV1 {
|
||||
sehs: 1024,
|
||||
iv: [0x33; SymKeyType::AES_256_GCM_IV_LEN],
|
||||
res1: 0,
|
||||
nks: 0,
|
||||
sea: 64,
|
||||
nep: 10,
|
||||
pcf: 0x100,
|
||||
cust_pub_key: EcPubKeyCoordV1 { coord: [0x44; 160] },
|
||||
pld: [0x55; SHA_512_HASH_LEN],
|
||||
ald: [0x66; SHA_512_HASH_LEN],
|
||||
tld: [0x77; SHA_512_HASH_LEN],
|
||||
keyslots: vec![],
|
||||
},
|
||||
cipher_data: vec![0x88; 64],
|
||||
tag: SeHdrTagV1 {
|
||||
tag: [0x99; SymKeyType::AES_256_GCM_TAG_LEN],
|
||||
},
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&bin).expect("should serialize");
|
||||
assert_eq!(json, "{\"sehs\":1024,\"iv_hex\":\"333333333333333333333333\",\"nks\":0,\"sea\":64,\"nep\":10,\"pcf_hex\":\"0000000000000100\",\"cust_pub_key\":{\"coord_hex\":\"44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\"},\"pld_hex\":\"55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555\",\"ald_hex\":\"66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\",\"tld_hex\":\"77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777\",\"keyslots\":[],\"cipher_data_b64\":\"iIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiA==\",\"tag_hex\":\"99999999999999999999999999999999\"}");
|
||||
let deserialized: SeHdrBinV1 = serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(bin, deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ use openssl::{
|
||||
pkey::{PKey, PKeyRef, Public},
|
||||
};
|
||||
use pv::{request::EcPubKeyCoord, static_assert};
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
pv_utils::{serializing::ser_hex, try_copy_slice_to_array},
|
||||
pv_utils::{serializing::serde_hex_array, try_copy_slice_to_array},
|
||||
};
|
||||
|
||||
/// Try to hash the public EC key.
|
||||
@@ -28,10 +28,10 @@ pub fn phkh_v1<T: AsRef<PKeyRef<Public>>>(key: T) -> Result<[u8; 32]> {
|
||||
try_copy_slice_to_array(&binding)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
pub struct EcPubKeyCoordV1 {
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "coord_hex")]
|
||||
pub coord: [u8; 160],
|
||||
}
|
||||
|
||||
@@ -68,18 +68,18 @@ impl TryFrom<EcPubKeyCoordV1> for PKey<Public> {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, DekuRead, DekuWrite, Serialize)]
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, DekuRead, DekuWrite, Serialize, Deserialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
/// Binary key slot v1
|
||||
pub struct BinaryKeySlotV1 {
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "phkh_hex")]
|
||||
/// Public host key hash
|
||||
pub phkh: [u8; 32],
|
||||
/// Wrapper key
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "wrpk_hex")]
|
||||
pub wrpk: [u8; 32],
|
||||
/// Tag
|
||||
#[serde(serialize_with = "ser_hex")]
|
||||
#[serde(with = "serde_hex_array", rename = "kst_hex")]
|
||||
pub kst: [u8; 16],
|
||||
}
|
||||
static_assert!(size_of::<BinaryKeySlotV1>() == 80);
|
||||
@@ -97,3 +97,44 @@ impl TryFrom<Vec<u8>> for BinaryKeySlotV1 {
|
||||
Ok(bin)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod serde_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn roundtrip_ecpubkey_json() {
|
||||
let key = EcPubKeyCoordV1 { coord: [0x42; 160] };
|
||||
|
||||
let json = serde_json::to_string(&key).expect("should serialize");
|
||||
assert_eq!(json,
|
||||
"{\"coord_hex\":\"42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242\"}");
|
||||
let deserialized: EcPubKeyCoordV1 =
|
||||
serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(key, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_keyslots_json() {
|
||||
let keyslots = vec![
|
||||
BinaryKeySlotV1 {
|
||||
phkh: [0x01; 32],
|
||||
wrpk: [0x02; 32],
|
||||
kst: [0x03; 16],
|
||||
},
|
||||
BinaryKeySlotV1 {
|
||||
phkh: [0x03; 32],
|
||||
wrpk: [0x04; 32],
|
||||
kst: [0x05; 16],
|
||||
},
|
||||
];
|
||||
|
||||
let json = serde_json::to_string(&keyslots).expect("should serialize");
|
||||
assert_eq!(json, "[{\"phkh_hex\":\"0101010101010101010101010101010101010101010101010101010101010101\",\"wrpk_hex\":\"0202020202020202020202020202020202020202020202020202020202020202\",\"kst_hex\":\"03030303030303030303030303030303\"},{\"phkh_hex\":\"0303030303030303030303030303030303030303030303030303030303030303\",\"wrpk_hex\":\"0404040404040404040404040404040404040404040404040404040404040404\",\"kst_hex\":\"05050505050505050505050505050505\"}]");
|
||||
let deserialized: Vec<BinaryKeySlotV1> =
|
||||
serde_json::from_str(&json).expect("should deserialize");
|
||||
|
||||
assert_eq!(keyslots, deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,37 +2,132 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use std::fmt::LowerHex;
|
||||
|
||||
use deku::{
|
||||
reader::Reader, writer::Writer, DekuContainerRead, DekuContainerWrite, DekuError, DekuReader,
|
||||
DekuWriter,
|
||||
};
|
||||
use pv::request::{Confidential, Zeroize};
|
||||
use serde::{Serialize, Serializer};
|
||||
use utils::HexSlice;
|
||||
|
||||
use crate::pv_utils::error::Result;
|
||||
|
||||
pub fn ser_hex<A: AsRef<[u8]>, S: Serializer>(
|
||||
data: A,
|
||||
ser: S,
|
||||
) -> std::result::Result<S::Ok, S::Error> {
|
||||
HexSlice::from(data.as_ref()).serialize(ser)
|
||||
pub mod serde_hex_left_padded_u64 {
|
||||
use std::fmt::LowerHex;
|
||||
|
||||
use serde::Deserializer;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer, B: LowerHex>(
|
||||
data: &B,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
format!("{data:016x}").serialize(serializer)
|
||||
}
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
|
||||
let s = String::deserialize(deserializer)?;
|
||||
u64::from_str_radix(&s, 16).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ser_lower_hex<S: Serializer, B: LowerHex>(
|
||||
data: &B,
|
||||
ser: S,
|
||||
) -> std::result::Result<S::Ok, S::Error> {
|
||||
format!("{data:#018x}").serialize(ser)
|
||||
pub mod serde_hex_array {
|
||||
use std::result::Result;
|
||||
|
||||
use pv::misc::{decode_hex, encode_hex};
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
use crate::pv_utils::try_copy_slice_to_array;
|
||||
|
||||
pub fn serialize<S: Serializer, const COUNT: usize>(
|
||||
data: &[u8; COUNT],
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_str(&encode_hex(data))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn deserialize<'de, D: Deserializer<'de>, const COUNT: usize>(
|
||||
deserializer: D,
|
||||
) -> Result<[u8; COUNT], D::Error> {
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let decoded = decode_hex(s).map_err(serde::de::Error::custom)?;
|
||||
|
||||
try_copy_slice_to_array(&decoded).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ser_hex_confidential<S: Serializer, const COUNT: usize>(
|
||||
data: &Confidential<[u8; COUNT]>,
|
||||
ser: S,
|
||||
) -> std::result::Result<S::Ok, S::Error> {
|
||||
ser_hex(data.value(), ser)
|
||||
pub mod serde_hex_confidential_array {
|
||||
use std::result::Result;
|
||||
|
||||
use pv::request::Confidential;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
use super::serde_hex_array;
|
||||
|
||||
pub fn serialize<S: Serializer, const COUNT: usize>(
|
||||
data: &Confidential<[u8; COUNT]>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
serde_hex_array::serialize(data.value(), serializer)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn deserialize<'de, D: Deserializer<'de>, const COUNT: usize>(
|
||||
deserializer: D,
|
||||
) -> Result<Confidential<[u8; COUNT]>, D::Error> {
|
||||
Ok(Confidential::new(serde_hex_array::deserialize(
|
||||
deserializer,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod serde_base64 {
|
||||
use base64::prelude::*;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S, B>(bytes: B, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
let b64 = BASE64_STANDARD.encode(bytes.as_ref());
|
||||
serializer.serialize_str(&b64)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
BASE64_STANDARD.decode(&s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod serde_base64_array {
|
||||
use base64::prelude::*;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
use crate::pv_utils::try_copy_slice_to_array;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn serialize<S, const N: usize>(bytes: &[u8; N], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let b64 = BASE64_STANDARD.encode(bytes);
|
||||
serializer.serialize_str(&b64)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn deserialize<'de, D, const COUNT: usize>(deserializer: D) -> Result<[u8; COUNT], D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let decoded = BASE64_STANDARD
|
||||
.decode(&s)
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
try_copy_slice_to_array(&decoded).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a slice into a confidential array of type [`T`] and length [`N`].
|
||||
@@ -146,4 +241,102 @@ mod tests {
|
||||
assert_eq!(test.test.value()[0], 0x0f010203);
|
||||
assert_eq!(test.to_bytes().unwrap().as_slice(), &DATA);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_base64() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestStruct {
|
||||
#[serde(with = "super::serde_base64")]
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
let original = TestStruct {
|
||||
data: vec![1, 2, 3, 4, 5],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&original).unwrap();
|
||||
assert!(json.contains("AQIDBAU="));
|
||||
|
||||
let deserialized: TestStruct = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(original, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_base64_with_array() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestStruct {
|
||||
#[serde(with = "super::serde_base64_array")]
|
||||
data: [u8; 5],
|
||||
}
|
||||
|
||||
let original = TestStruct {
|
||||
data: [1, 2, 3, 4, 5],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&original).unwrap();
|
||||
assert!(json.contains("AQIDBAU="));
|
||||
|
||||
let deserialized: TestStruct = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(original, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_hex_array() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestStruct {
|
||||
#[serde(with = "super::serde_hex_array")]
|
||||
data: [u8; 5],
|
||||
}
|
||||
|
||||
let original = TestStruct {
|
||||
data: [1, 2, 3, 4, 5],
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&original).unwrap();
|
||||
assert!(json.contains("0102030405"));
|
||||
assert_eq!(&json, r#"{"data":"0102030405"}"#);
|
||||
|
||||
let deserialized: TestStruct = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(original, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_hex_array_invalid_length() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestStruct {
|
||||
#[serde(with = "super::serde_hex_array")]
|
||||
data: [u8; 5],
|
||||
}
|
||||
|
||||
// Try to deserialize with wrong length (3 bytes instead of 5)
|
||||
let json = r#"{"data":"010203"}"#;
|
||||
let result: Result<TestStruct, _> = serde_json::from_str(json);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("Expected size 5"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_base64_array_invalid_length() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestStruct {
|
||||
#[serde(with = "super::serde_base64_array")]
|
||||
data: [u8; 5],
|
||||
}
|
||||
|
||||
// Try to deserialize with wrong length (3 bytes instead of 5)
|
||||
let json = r#"{"data":"AQID"}"#; // Base64 for [1, 2, 3]
|
||||
let result: Result<TestStruct, _> = serde_json::from_str(json);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("Expected size 5"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user