Skip to content

Commit

Permalink
adds support for rsa in put_asymmetric_key
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo committed Nov 22, 2023
1 parent e607110 commit e857db8
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 7 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ tiny_http = { version = "0.12", optional = true }

[dev-dependencies]
ed25519-dalek = "2"
num-bigint = { version = "0.8.2", features = ["i128", "prime", "zeroize"], default-features = false, package = "num-bigint-dig" }
once_cell = "1"
p256 = { version = "0.13", features = ["ecdsa"] }

Expand Down
87 changes: 85 additions & 2 deletions src/asymmetric/commands/put_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ use crate::{
object,
response::Response,
};
use serde::{Deserialize, Serialize};
use serde::{de, Deserialize, Serialize};
use std::{fmt, marker::PhantomData};

/// Request parameters for `command::put_asymmetric_key`
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Debug)]
pub(crate) struct PutAsymmetricKeyCommand {
/// Common parameters to all put object commands
pub params: object::put::Params,

/// Serialized object
pub data: Vec<u8>,

/// Serialized second parameter
/// This is only used for RSA.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub extra_data: Vec<u8>,
}

impl Command for PutAsymmetricKeyCommand {
Expand All @@ -33,3 +39,80 @@ pub(crate) struct PutAsymmetricKeyResponse {
impl Response for PutAsymmetricKeyResponse {
const COMMAND_CODE: command::Code = command::Code::PutAsymmetricKey;
}

impl<'de> Deserialize<'de> for PutAsymmetricKeyCommand {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
#[doc(hidden)]
struct Visitor<'de> {
marker: PhantomData<PutAsymmetricKeyCommand>,
lifetime: PhantomData<&'de ()>,
}
impl<'de> de::Visitor<'de> for Visitor<'de> {
type Value = PutAsymmetricKeyCommand;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "struct PutAsymmetricKeyCommand")
}

#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let params = match de::SeqAccess::next_element::<object::put::Params>(&mut seq)? {
Some(v) => v,
None => {
return Err(de::Error::invalid_length(
0usize,
&"struct PutAsymmetricKeyCommand with 3 elements",
));
}
};

let data = match de::SeqAccess::next_element::<Vec<u8>>(&mut seq)? {
Some(v) => v,
None => {
return Err(de::Error::invalid_length(
1usize,
&"struct PutAsymmetricKeyCommand with 3 elements",
));
}
};

let extra_data = if params.algorithm.rsa().is_some() {
match de::SeqAccess::next_element::<Vec<u8>>(&mut seq)? {
Some(v) => v,
None => {
return Err(de::Error::invalid_length(
2usize,
&"struct PutAsymmetricKeyCommand with 3 elements",
));
}
}
} else {
Vec::new()
};

Ok(PutAsymmetricKeyCommand {
params,
data,
extra_data,
})
}
}

#[doc(hidden)]
const FIELDS: &'static [&'static str] = &["params", "data", "extra_data"];

Check failure on line 107 in src/asymmetric/commands/put_key.rs

View workflow job for this annotation

GitHub Actions / clippy

constants have by default a `'static` lifetime

Check failure on line 107 in src/asymmetric/commands/put_key.rs

View workflow job for this annotation

GitHub Actions / clippy

constants have by default a `'static` lifetime
de::Deserializer::deserialize_struct(
deserializer,
"PutAsymmetricKeyCommand",
FIELDS,
Visitor {
marker: PhantomData::<PutAsymmetricKeyCommand>,
lifetime: PhantomData,
},
)
}
}
8 changes: 7 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ impl Client {
where
K: Into<Vec<u8>>,
{
let data = key_bytes.into();
let mut data = key_bytes.into();
let mut extra_data = Vec::new();

if data.len() != algorithm.key_len() {
fail!(
Expand All @@ -567,6 +568,10 @@ impl Client {
);
}

if algorithm.is_rsa() {
extra_data = data.split_off(algorithm.key_len() / 2);
}

Ok(self
.send_command(PutAsymmetricKeyCommand {
params: object::put::Params {
Expand All @@ -577,6 +582,7 @@ impl Client {
algorithm: algorithm.into(),
},
data,
extra_data,
})?
.key_id)
}
Expand Down
11 changes: 10 additions & 1 deletion src/mockhsm/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,18 @@ fn list_objects(state: &State, cmd_data: &[u8]) -> response::Message {

/// Put an existing asymmetric key into the HSM
fn put_asymmetric_key(state: &mut State, cmd_data: &[u8]) -> response::Message {
let PutAsymmetricKeyCommand { params, data } = deserialize(cmd_data)
let PutAsymmetricKeyCommand {
params,
data,
extra_data,
} = deserialize(cmd_data)
.unwrap_or_else(|e| panic!("error parsing Code::PutAsymmetricKey: {e:?}"));

let mut buf = data.clone();
if !extra_data.is_empty() {
buf.extend_from_slice(&extra_data);
}

state.objects.put(
params.id,
object::Type::AsymmetricKey,
Expand Down
14 changes: 13 additions & 1 deletion src/mockhsm/object/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
use crate::{algorithm::Algorithm, asymmetric, authentication, hmac, opaque, wrap};
use ecdsa::elliptic_curve::sec1::ToEncodedPoint;
use ed25519_dalek as ed25519;
use num_traits::cast::FromPrimitive;
use rand_core::{OsRng, RngCore};
use rsa::traits::PublicKeyParts;
use rsa::{traits::PublicKeyParts, BigUint};

/// Loaded instances of a cryptographic primitives in the MockHsm
#[derive(Debug)]
Expand Down Expand Up @@ -53,6 +54,17 @@ impl Payload {
assert_eq!(data.len(), ed25519::SECRET_KEY_LENGTH);
Payload::Ed25519Key(ed25519::SigningKey::try_from(data).unwrap())
}
asymmetric::Algorithm::Rsa2048
| asymmetric::Algorithm::Rsa3072
| asymmetric::Algorithm::Rsa4096 => {
assert_eq!(data.len(), asymmetric_alg.key_len());
let exp = BigUint::from_u64(65537).expect("invalid static exponent");
let p = BigUint::from_bytes_be(&data[..asymmetric_alg.key_len() / 2]);
let q = BigUint::from_bytes_be(&data[asymmetric_alg.key_len() / 2..]);

let key = rsa::RsaPrivateKey::from_p_q(p, q, exp).unwrap();
Payload::RsaKey(key)
}
_ => {
panic!("MockHsm doesn't support this asymmetric algorithm: {asymmetric_alg:?}")
}
Expand Down

0 comments on commit e857db8

Please sign in to comment.