mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust/pv_core: Support for listing Retrievable Secrets
Add support for listing retrievable secrets in the List Secrets UVC. Acked-by: Marc Hartmayer <marc@linux.ibm.com> Reviewed-by: Christoph Schlameuss <schlameuss@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:
committed by
Jan Höppner
parent
01cd81ecf5
commit
4af137f4fa
@@ -32,6 +32,8 @@ pub mod misc {
|
||||
/// [`crate::uv::UvCmd`]
|
||||
pub mod uv {
|
||||
pub use crate::uvdevice::attest::AttestationCmd;
|
||||
pub use crate::uvdevice::retr_secret::RetrievableSecret;
|
||||
pub use crate::uvdevice::retr_secret::{AesSizes, AesXtsSizes, EcCurves, HmacShaSizes};
|
||||
pub use crate::uvdevice::secret::{AddCmd, ListCmd, LockCmd, RetrieveCmd};
|
||||
pub use crate::uvdevice::secret_list::{ListableSecretType, SecretEntry, SecretId, SecretList};
|
||||
pub use crate::uvdevice::{ConfigUid, UvCmd, UvDevice, UvDeviceInfo, UvFlags, UvcSuccess};
|
||||
|
||||
@@ -25,6 +25,7 @@ mod info;
|
||||
mod test;
|
||||
pub(crate) use ffi::uv_ioctl;
|
||||
pub mod attest;
|
||||
pub mod retr_secret;
|
||||
pub mod secret;
|
||||
pub mod secret_list;
|
||||
|
||||
|
||||
399
rust/pv_core/src/uvdevice/retr_secret.rs
Normal file
399
rust/pv_core/src/uvdevice/retr_secret.rs
Normal file
@@ -0,0 +1,399 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::uv::{ListableSecretType, RetrieveCmd};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Allowed sizes for AES keys
|
||||
#[non_exhaustive]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum AesSizes {
|
||||
/// 128 bit key
|
||||
Bits128,
|
||||
/// 192 bit key
|
||||
Bits192,
|
||||
/// 256 bit key
|
||||
Bits256,
|
||||
}
|
||||
|
||||
impl AesSizes {
|
||||
/// Construct the key-size from the bit-size.
|
||||
///
|
||||
/// Returns [`None`] if the bit-size is not supported.
|
||||
pub fn from_bits(bits: u32) -> Option<Self> {
|
||||
match bits {
|
||||
128 => Some(Self::Bits128),
|
||||
192 => Some(Self::Bits192),
|
||||
256 => Some(Self::Bits256),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the bit-size for the key-type
|
||||
const fn bit_size(&self) -> u32 {
|
||||
match self {
|
||||
Self::Bits128 => 128,
|
||||
Self::Bits192 => 192,
|
||||
Self::Bits256 => 256,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AesSizes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.bit_size())
|
||||
}
|
||||
}
|
||||
|
||||
/// Allowed sizes for AES-XTS keys
|
||||
#[non_exhaustive]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum AesXtsSizes {
|
||||
/// Two AES 128 bit keys
|
||||
Bits128,
|
||||
/// Two AES 256 bit keys
|
||||
Bits256,
|
||||
}
|
||||
|
||||
impl AesXtsSizes {
|
||||
/// Construct the key-size from the bit-size.
|
||||
///
|
||||
/// It's a key containing two keys; bit-size is half the number of bits it has
|
||||
/// Returns [`None`] if the bit-size is not supported.
|
||||
pub fn from_bits(bits: u32) -> Option<Self> {
|
||||
match bits {
|
||||
128 => Some(Self::Bits128),
|
||||
256 => Some(Self::Bits256),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the bit-size for the key-type
|
||||
///
|
||||
/// It's a key containing two keys: bit-size is half the number of bits it has
|
||||
const fn bit_size(&self) -> u32 {
|
||||
match self {
|
||||
Self::Bits128 => 128,
|
||||
Self::Bits256 => 256,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AesXtsSizes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.bit_size())
|
||||
}
|
||||
}
|
||||
|
||||
/// Allowed sizes for HMAC-SHA keys
|
||||
#[non_exhaustive]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum HmacShaSizes {
|
||||
/// SHA 256 bit
|
||||
Sha256,
|
||||
/// SHA 512 bit
|
||||
Sha512,
|
||||
}
|
||||
|
||||
impl HmacShaSizes {
|
||||
/// Construct the key-size from the sha-size.
|
||||
///
|
||||
/// FW expects maximum resistance keys (double the SHA size).
|
||||
/// The `sha_size` is half of the number of bits in the key
|
||||
/// Returns [`None`] if the `sha_size` is not supported.
|
||||
pub fn from_sha_size(sha_size: u32) -> Option<Self> {
|
||||
match sha_size {
|
||||
256 => Some(Self::Sha256),
|
||||
512 => Some(Self::Sha512),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the sha-size for the key-type
|
||||
///
|
||||
/// FW expects maximum resistance keys (double the SHA size).
|
||||
/// The `sha_size` is half of the number of bits in the key
|
||||
const fn sha_size(&self) -> u32 {
|
||||
match self {
|
||||
Self::Sha256 => 256,
|
||||
Self::Sha512 => 512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for HmacShaSizes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.sha_size())
|
||||
}
|
||||
}
|
||||
|
||||
/// Allowed curves for EC private keys
|
||||
#[non_exhaustive]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum EcCurves {
|
||||
/// secp256r1 or prime256v1 curve
|
||||
Secp256R1,
|
||||
/// secp384p1 curve
|
||||
Secp384R1,
|
||||
/// secp521r1 curve
|
||||
Secp521R1,
|
||||
/// ed25519 curve
|
||||
Ed25519,
|
||||
/// ed448 curve
|
||||
Ed448,
|
||||
}
|
||||
|
||||
impl EcCurves {
|
||||
const fn exp_size(&self) -> usize {
|
||||
match self {
|
||||
Self::Secp256R1 => 32,
|
||||
Self::Secp384R1 => 48,
|
||||
Self::Secp521R1 => 80,
|
||||
Self::Ed25519 => 32,
|
||||
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
|
||||
impl Display for EcCurves {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Secp256R1 => write!(f, "SECP256R1"),
|
||||
Self::Secp384R1 => write!(f, "SECP384R1"),
|
||||
Self::Secp521R1 => write!(f, "SECP521R1"),
|
||||
Self::Ed25519 => write!(f, "ED25519"),
|
||||
Self::Ed448 => write!(f, "ED448"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrievable Secret types
|
||||
#[non_exhaustive]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum RetrievableSecret {
|
||||
/// Plain-text secret
|
||||
PlainText,
|
||||
/// Protected AES key
|
||||
Aes(AesSizes),
|
||||
/// Protected AES-XTS key
|
||||
AesXts(AesXtsSizes),
|
||||
/// Protected HMAC-SHA key
|
||||
HmacSha(HmacShaSizes),
|
||||
/// Protected EC-private key
|
||||
Ec(EcCurves),
|
||||
}
|
||||
|
||||
// The names have to stay constant, otherwise the PEM contains invalid/unknown types
|
||||
impl Display for RetrievableSecret {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Alternate representation: Omit sizes/curves
|
||||
if f.alternate() {
|
||||
match self {
|
||||
Self::PlainText => write!(f, "PLAINTEXT"),
|
||||
Self::Aes(_) => write!(f, "AES-KEY"),
|
||||
Self::AesXts(_) => write!(f, "AES-XTS-KEY"),
|
||||
Self::HmacSha(_) => write!(f, "HMAC-SHA-KEY"),
|
||||
Self::Ec(_) => write!(f, "EC-PRIVATE-KEY"),
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
Self::PlainText => write!(f, "PLAINTEXT"),
|
||||
Self::Aes(s) => write!(f, "AES-{s}-KEY"),
|
||||
Self::AesXts(s) => write!(f, "AES-XTS-{s}-KEY"),
|
||||
Self::HmacSha(s) => write!(f, "HMAC-SHA-{s}-KEY"),
|
||||
Self::Ec(c) => write!(f, "EC-{c}-PRIVATE-KEY"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RetrievableSecret {
|
||||
/// Report expected input types
|
||||
pub fn expected(&self) -> String {
|
||||
match self {
|
||||
Self::PlainText => format!("less than {}", RetrieveCmd::MAX_SIZE),
|
||||
Self::Aes(_) => "128, 192, or 256".to_string(),
|
||||
Self::AesXts(_) => "128 or 256".to_string(),
|
||||
Self::HmacSha(_) => "256 or 512".to_string(),
|
||||
Self::Ec(_) => "secp256r1, secp384r1, secp521r1, ed25519, or ed448".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RetrievableSecret> for u16 {
|
||||
fn from(value: &RetrievableSecret) -> Self {
|
||||
match value {
|
||||
RetrievableSecret::PlainText => ListableSecretType::PLAINTEXT,
|
||||
RetrievableSecret::Aes(AesSizes::Bits128) => ListableSecretType::AES_128_KEY,
|
||||
RetrievableSecret::Aes(AesSizes::Bits192) => ListableSecretType::AES_192_KEY,
|
||||
RetrievableSecret::Aes(AesSizes::Bits256) => ListableSecretType::AES_256_KEY,
|
||||
RetrievableSecret::AesXts(AesXtsSizes::Bits128) => ListableSecretType::AES_128_XTS_KEY,
|
||||
RetrievableSecret::AesXts(AesXtsSizes::Bits256) => ListableSecretType::AES_256_XTS_KEY,
|
||||
RetrievableSecret::HmacSha(HmacShaSizes::Sha256) => {
|
||||
ListableSecretType::HMAC_SHA_256_KEY
|
||||
}
|
||||
RetrievableSecret::HmacSha(HmacShaSizes::Sha512) => {
|
||||
ListableSecretType::HMAC_SHA_512_KEY
|
||||
}
|
||||
RetrievableSecret::Ec(EcCurves::Secp256R1) => ListableSecretType::ECDSA_P256_KEY,
|
||||
RetrievableSecret::Ec(EcCurves::Secp384R1) => ListableSecretType::ECDSA_P384_KEY,
|
||||
RetrievableSecret::Ec(EcCurves::Secp521R1) => ListableSecretType::ECDSA_P521_KEY,
|
||||
RetrievableSecret::Ec(EcCurves::Ed25519) => ListableSecretType::ECDSA_ED25519_KEY,
|
||||
RetrievableSecret::Ec(EcCurves::Ed448) => ListableSecretType::ECDSA_ED448_KEY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// serializes to: <secret type nb> (String name)
|
||||
impl Serialize for RetrievableSecret {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let id: u16 = self.into();
|
||||
serializer.serialize_str(&format!("{id} ({self})"))
|
||||
}
|
||||
}
|
||||
|
||||
/// deserializes from the secret type nb only
|
||||
impl<'de> Deserialize<'de> for RetrievableSecret {
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct RetrSecretVisitor;
|
||||
impl<'de> serde::de::Visitor<'de> for RetrSecretVisitor {
|
||||
type Value = RetrievableSecret;
|
||||
|
||||
fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.write_str(
|
||||
"a retrievable secret type: `<number> (String name)` number in [3,10]|[17,21]",
|
||||
)
|
||||
}
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
let (n, _) = s.split_once(' ').ok_or(serde::de::Error::invalid_value(
|
||||
serde::de::Unexpected::Str(s),
|
||||
&self,
|
||||
))?;
|
||||
let id: u16 = n.parse().map_err(|_| {
|
||||
serde::de::Error::invalid_value(serde::de::Unexpected::Str(n), &self)
|
||||
})?;
|
||||
let listable: ListableSecretType = id.into();
|
||||
match listable {
|
||||
ListableSecretType::Retrievable(r) => Ok(r),
|
||||
_ => Err(serde::de::Error::invalid_value(
|
||||
serde::de::Unexpected::Unsigned(id.into()),
|
||||
&self,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
de.deserialize_str(RetrSecretVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn retr_serde_plain() {
|
||||
let retr = RetrievableSecret::PlainText;
|
||||
assert_tokens(&retr, &[Token::Str("3 (PLAINTEXT)")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retr_serde_aes() {
|
||||
let retr = RetrievableSecret::Aes(AesSizes::Bits192);
|
||||
assert_tokens(&retr, &[Token::Str("5 (AES-192-KEY)")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retr_serde_aes_xts() {
|
||||
let retr = RetrievableSecret::AesXts(AesXtsSizes::Bits128);
|
||||
assert_tokens(&retr, &[Token::Str("7 (AES-XTS-128-KEY)")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retr_serde_hmac() {
|
||||
let retr = RetrievableSecret::HmacSha(HmacShaSizes::Sha256);
|
||||
assert_tokens(&retr, &[Token::Str("9 (HMAC-SHA-256-KEY)")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retr_serde_es() {
|
||||
let retr = RetrievableSecret::Ec(EcCurves::Secp521R1);
|
||||
assert_tokens(&retr, &[Token::Str("19 (EC-SECP521R1-PRIVATE-KEY)")]);
|
||||
}
|
||||
|
||||
// Ensure that the string representation of the retrievable types stay constant, or PEM will have
|
||||
// different, incompatible types
|
||||
#[test]
|
||||
fn stable_type_names() {
|
||||
assert_eq!("PLAINTEXT", RetrievableSecret::PlainText.to_string());
|
||||
assert_eq!(
|
||||
"AES-128-KEY",
|
||||
RetrievableSecret::Aes(AesSizes::Bits128).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"AES-192-KEY",
|
||||
RetrievableSecret::Aes(AesSizes::Bits192).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"AES-256-KEY",
|
||||
RetrievableSecret::Aes(AesSizes::Bits256).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"AES-XTS-128-KEY",
|
||||
RetrievableSecret::AesXts(AesXtsSizes::Bits128).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"AES-XTS-256-KEY",
|
||||
RetrievableSecret::AesXts(AesXtsSizes::Bits256).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"HMAC-SHA-256-KEY",
|
||||
RetrievableSecret::HmacSha(HmacShaSizes::Sha256).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"HMAC-SHA-512-KEY",
|
||||
RetrievableSecret::HmacSha(HmacShaSizes::Sha512).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"EC-SECP256R1-PRIVATE-KEY",
|
||||
RetrievableSecret::Ec(EcCurves::Secp256R1).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"EC-SECP384R1-PRIVATE-KEY",
|
||||
RetrievableSecret::Ec(EcCurves::Secp384R1).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"EC-SECP521R1-PRIVATE-KEY",
|
||||
RetrievableSecret::Ec(EcCurves::Secp521R1).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"EC-ED25519-PRIVATE-KEY",
|
||||
RetrievableSecret::Ec(EcCurves::Ed25519).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
"EC-ED448-PRIVATE-KEY",
|
||||
RetrievableSecret::Ec(EcCurves::Ed448).to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,14 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::assert_size;
|
||||
use crate::{misc::to_u16, uv::ListCmd, uvdevice::UvCmd, Error, Result};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use crate::{
|
||||
assert_size,
|
||||
misc::to_u16,
|
||||
uv::{AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListCmd, RetrievableSecret},
|
||||
uvdevice::UvCmd,
|
||||
Error, Result,
|
||||
};
|
||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use std::{
|
||||
fmt::Display,
|
||||
@@ -18,7 +23,7 @@ use zerocopy::{AsBytes, FromBytes, FromZeroes, U16, U32};
|
||||
///
|
||||
/// (de)serializes itself in/from a hex-string
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Debug, Clone)]
|
||||
#[derive(PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Debug, Clone, Default)]
|
||||
pub struct SecretId([u8; Self::ID_SIZE]);
|
||||
assert_size!(SecretId, SecretId::ID_SIZE);
|
||||
|
||||
@@ -94,11 +99,11 @@ impl SecretEntry {
|
||||
/// Create a new entry for a [`SecretList`].
|
||||
///
|
||||
/// The content of this entry will very likely not represent the status of the guest in the
|
||||
/// Ultravisor. Use of [`SecretList::decode`] in any non-test environments is encuraged.
|
||||
/// Ultravisor. Use of [`SecretList::decode`] in any non-test environments is encouraged.
|
||||
pub fn new(index: u16, stype: ListableSecretType, id: SecretId, secret_len: u32) -> Self {
|
||||
Self {
|
||||
index: index.into(),
|
||||
stype: stype.into(),
|
||||
stype: U16::new(stype.into()),
|
||||
len: secret_len.into(),
|
||||
res_8: 0,
|
||||
id,
|
||||
@@ -117,7 +122,7 @@ impl SecretEntry {
|
||||
|
||||
/// Returns the secret type of this [`SecretEntry`].
|
||||
pub fn stype(&self) -> ListableSecretType {
|
||||
self.stype.into()
|
||||
self.stype.get().into()
|
||||
}
|
||||
|
||||
/// Returns a reference to the id of this [`SecretEntry`].
|
||||
@@ -146,7 +151,7 @@ impl SecretEntry {
|
||||
|
||||
impl Display for SecretEntry {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let stype: ListableSecretType = self.stype.into();
|
||||
let stype: ListableSecretType = self.stype.get().into();
|
||||
writeln!(f, "{} {}:", self.index, stype)?;
|
||||
write!(f, " ")?;
|
||||
for b in self.id.as_ref() {
|
||||
@@ -298,51 +303,115 @@ fn ser_u16<S: Serializer>(v: &U16<BigEndian>, ser: S) -> Result<S::Ok, S::Error>
|
||||
pub enum ListableSecretType {
|
||||
/// Association Secret
|
||||
Association,
|
||||
/// Retrievable key
|
||||
Retrievable(RetrievableSecret),
|
||||
|
||||
/// Invalid secret type, that should never appear in a list
|
||||
///
|
||||
/// 0 is reserved
|
||||
/// 1 is Null secret, with no id and not listable
|
||||
/// 1 is Null secret, with no id and not list-able
|
||||
Invalid(u16),
|
||||
/// Unknown secret type
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
impl ListableSecretType {
|
||||
/// UV type id for an association secret
|
||||
pub const ASSOCIATION: u16 = 0x0002;
|
||||
/// UV type id for a null secret
|
||||
pub const NULL: u16 = 0x0001;
|
||||
const RESERVED_0: u16 = 0x0000;
|
||||
/// UV secret-type id for a null secret
|
||||
pub const NULL: u16 = 0x0001;
|
||||
/// UV secret-type id for an association secret
|
||||
pub const ASSOCIATION: u16 = 0x0002;
|
||||
/// UV secret-type id for a plain text secret
|
||||
pub const PLAINTEXT: u16 = 0x0003;
|
||||
/// UV secret-type id for an aes-128-key secret
|
||||
pub const AES_128_KEY: u16 = 0x0004;
|
||||
/// UV secret-type id for an aes-192-key secret
|
||||
pub const AES_192_KEY: u16 = 0x0005;
|
||||
/// UV secret-type id for an aes-256-key secret
|
||||
pub const AES_256_KEY: u16 = 0x0006;
|
||||
/// UV secret-type id for an aes-xts-128-key secret
|
||||
pub const AES_128_XTS_KEY: u16 = 0x0007;
|
||||
/// UV secret-type id for an aes-xts-256-key secret
|
||||
pub const AES_256_XTS_KEY: u16 = 0x0008;
|
||||
/// UV secret-type id for an hmac-sha-256-key secret
|
||||
pub const HMAC_SHA_256_KEY: u16 = 0x0009;
|
||||
/// UV secret-type id for an hmac-sha-512-key secret
|
||||
pub const HMAC_SHA_512_KEY: u16 = 0x000a;
|
||||
// 0x000b - 0x0010 reserved
|
||||
/// UV secret-type id for an ecdsa-p256-private-key secret
|
||||
pub const ECDSA_P256_KEY: u16 = 0x0011;
|
||||
/// UV secret-type id for an ecdsa-p384-private-key secret
|
||||
pub const ECDSA_P384_KEY: u16 = 0x0012;
|
||||
/// UV secret-type id for an ecdsa-p521-private-key secret
|
||||
pub const ECDSA_P521_KEY: u16 = 0x0013;
|
||||
/// UV secret-type id for an ed25519-private-key secret
|
||||
pub const ECDSA_ED25519_KEY: u16 = 0x0014;
|
||||
/// UV secret-type id for an ed448-private-key secret
|
||||
pub const ECDSA_ED448_KEY: u16 = 0x0015;
|
||||
}
|
||||
|
||||
impl Display for ListableSecretType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Association => write!(f, "Association"),
|
||||
Self::Invalid(n) => write!(f, "Invalid({n})"),
|
||||
Self::Unknown(n) => write!(f, "Unknown({n})"),
|
||||
Self::Invalid(n) => write!(f, "Invalid(0x{n:04x})"),
|
||||
Self::Unknown(n) => write!(f, "Unknown(0x{n:04x})"),
|
||||
Self::Retrievable(r) => write!(f, "{r}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U16<BigEndian>> for ListableSecretType {
|
||||
fn from(value: U16<BigEndian>) -> Self {
|
||||
match value.get() {
|
||||
impl<O: ByteOrder> From<U16<O>> for ListableSecretType {
|
||||
fn from(value: U16<O>) -> Self {
|
||||
value.get().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for ListableSecretType {
|
||||
fn from(value: u16) -> Self {
|
||||
match value {
|
||||
Self::RESERVED_0 => Self::Invalid(Self::RESERVED_0),
|
||||
Self::NULL => Self::Invalid(Self::NULL),
|
||||
Self::ASSOCIATION => Self::Association,
|
||||
Self::PLAINTEXT => Self::Retrievable(RetrievableSecret::PlainText),
|
||||
Self::AES_128_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits128)),
|
||||
Self::AES_192_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits192)),
|
||||
Self::AES_256_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits256)),
|
||||
Self::AES_128_XTS_KEY => {
|
||||
Self::Retrievable(RetrievableSecret::AesXts(AesXtsSizes::Bits128))
|
||||
}
|
||||
Self::AES_256_XTS_KEY => {
|
||||
Self::Retrievable(RetrievableSecret::AesXts(AesXtsSizes::Bits256))
|
||||
}
|
||||
Self::HMAC_SHA_256_KEY => {
|
||||
Self::Retrievable(RetrievableSecret::HmacSha(HmacShaSizes::Sha256))
|
||||
}
|
||||
Self::HMAC_SHA_512_KEY => {
|
||||
Self::Retrievable(RetrievableSecret::HmacSha(HmacShaSizes::Sha512))
|
||||
}
|
||||
Self::ECDSA_P256_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp256R1)),
|
||||
Self::ECDSA_P384_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp384R1)),
|
||||
Self::ECDSA_P521_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp521R1)),
|
||||
Self::ECDSA_ED25519_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Ed25519)),
|
||||
Self::ECDSA_ED448_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Ed448)),
|
||||
n => Self::Unknown(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ListableSecretType> for U16<BigEndian> {
|
||||
impl<O: ByteOrder> From<ListableSecretType> for U16<O> {
|
||||
fn from(value: ListableSecretType) -> Self {
|
||||
Self::new(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ListableSecretType> for u16 {
|
||||
fn from(value: ListableSecretType) -> Self {
|
||||
match value {
|
||||
ListableSecretType::Association => ListableSecretType::ASSOCIATION,
|
||||
ListableSecretType::Invalid(n) | ListableSecretType::Unknown(n) => n,
|
||||
ListableSecretType::Retrievable(r) => (&r).into(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,8 +432,8 @@ where
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if s.len() != SecretId::ID_SIZE * 2 + 2 {
|
||||
return Err(serde::de::Error::invalid_length(s.len(), &self));
|
||||
if s.len() != SecretId::ID_SIZE * 2 + "0x".len() {
|
||||
return Err(serde::de::Error::invalid_length(s.len() - 2, &self));
|
||||
}
|
||||
let nb = s.strip_prefix("0x").ok_or_else(|| {
|
||||
serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)
|
||||
@@ -385,7 +454,6 @@ mod test {
|
||||
|
||||
use super::*;
|
||||
use std::io::{BufReader, BufWriter, Cursor};
|
||||
|
||||
#[test]
|
||||
fn dump_secret_entry() {
|
||||
const EXP: &[u8] = &[
|
||||
@@ -516,4 +584,47 @@ mod test {
|
||||
)],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secret_list_ser() {
|
||||
let list = SecretList {
|
||||
total_num_secrets: 0x112,
|
||||
secrets: vec![SecretEntry {
|
||||
index: 1.into(),
|
||||
stype: 2.into(),
|
||||
len: 32.into(),
|
||||
res_8: 0,
|
||||
id: SecretId::from([0; 32]),
|
||||
}],
|
||||
};
|
||||
|
||||
assert_ser_tokens(
|
||||
&list,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "SecretList",
|
||||
len: 2,
|
||||
},
|
||||
Token::String("total_num_secrets"),
|
||||
Token::U64(0x112),
|
||||
Token::String("secrets"),
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Struct {
|
||||
name: "SecretEntry",
|
||||
len: (4),
|
||||
},
|
||||
Token::String("index"),
|
||||
Token::U16(1),
|
||||
Token::String("stype"),
|
||||
Token::U16(2),
|
||||
Token::String("len"),
|
||||
Token::U32(32),
|
||||
Token::String("id"),
|
||||
Token::String("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
Token::StructEnd,
|
||||
Token::SeqEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user