Skip to content

Commit

Permalink
oaep: implement mockhsm backend for decrypt_oaep
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo committed Jun 28, 2024
1 parent 865d03c commit aefadfe
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 13 deletions.
132 changes: 121 additions & 11 deletions src/mockhsm/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ use crate::{
opaque::{self, commands::*},
otp,
response::{self, Response},
rsa::{self, pkcs1::commands::*, pss::commands::*},
rsa::{
self, mgf,
oaep::{commands::*, DecryptedData},
pkcs1::commands::*,
pss::commands::*,
},
serialization::deserialize,
session::{self, commands::*},
template,
Expand All @@ -29,10 +34,10 @@ use ::ecdsa::{
hazmat::SignPrimitive,
};
use ::hmac::{Hmac, Mac};
use ::rsa::{pkcs1v15, pss, RsaPrivateKey};
use ::rsa::{oaep::Oaep, pkcs1v15, pss, traits::PaddingScheme, RsaPrivateKey};
use digest::{
const_oid::AssociatedOid, crypto_common::OutputSizeUser, typenum::Unsigned, Digest,
FixedOutputReset,
FixedOutput, FixedOutputReset, Output, Reset,
};
use rand_core::{OsRng, RngCore};
use sha1::Sha1;
Expand Down Expand Up @@ -130,6 +135,7 @@ pub(crate) fn session_message(
Code::VerifyHmac => verify_hmac(state, &command.data),
Code::SignPss => sign_pss(state, &command.data),
Code::SignPkcs1 => sign_pkcs1v15(state, &command.data),
Code::DecryptOaep => decrypt_oaep(state, &command.data),
unsupported => panic!("unsupported command type: {unsupported:?}"),
};

Expand Down Expand Up @@ -207,10 +213,10 @@ fn device_info() -> response::Message {
Algorithm::Wrap(wrap::Algorithm::Aes128Ccm),
Algorithm::Opaque(opaque::Algorithm::Data),
Algorithm::Opaque(opaque::Algorithm::X509Certificate),
Algorithm::Mgf(rsa::mgf::Algorithm::Sha1),
Algorithm::Mgf(rsa::mgf::Algorithm::Sha256),
Algorithm::Mgf(rsa::mgf::Algorithm::Sha384),
Algorithm::Mgf(rsa::mgf::Algorithm::Sha512),
Algorithm::Mgf(mgf::Algorithm::Sha1),
Algorithm::Mgf(mgf::Algorithm::Sha256),
Algorithm::Mgf(mgf::Algorithm::Sha384),
Algorithm::Mgf(mgf::Algorithm::Sha512),
Algorithm::Template(template::Algorithm::Ssh),
Algorithm::YubicoOtp(otp::Algorithm::Aes128),
Algorithm::Authentication(authentication::Algorithm::YubicoAes),
Expand Down Expand Up @@ -740,16 +746,16 @@ fn sign_pss(state: &State, cmd_data: &[u8]) -> response::Message {
{
if let Payload::RsaKey(private_key) = &obj.payload {
let signature = match command.mgf1_hash_alg {
rsa::mgf::Algorithm::Sha1 => {
mgf::Algorithm::Sha1 => {
sign_pss_digest::<Sha1>(private_key, command.digest.as_ref())
}
rsa::mgf::Algorithm::Sha256 => {
mgf::Algorithm::Sha256 => {
sign_pss_digest::<Sha256>(private_key, command.digest.as_ref())
}
rsa::mgf::Algorithm::Sha384 => {
mgf::Algorithm::Sha384 => {
sign_pss_digest::<Sha384>(private_key, command.digest.as_ref())
}
rsa::mgf::Algorithm::Sha512 => {
mgf::Algorithm::Sha512 => {
sign_pss_digest::<Sha512>(private_key, command.digest.as_ref())
}
};
Expand Down Expand Up @@ -843,3 +849,107 @@ fn verify_hmac(state: &State, cmd_data: &[u8]) -> response::Message {
device::ErrorKind::ObjectNotFound.into()
}
}

#[derive(Clone)]
struct FixedHashDigest<D: OutputSizeUser> {
fixed: GenericArray<u8, D::OutputSize>,
}

impl<D: OutputSizeUser> OutputSizeUser for FixedHashDigest<D> {
type OutputSize = D::OutputSize;
fn output_size() -> usize {
D::output_size()
}
}

impl<D: OutputSizeUser> FixedOutput for FixedHashDigest<D> {
fn finalize_into(self, out: &mut Output<Self>) {
out.clone_from_slice(self.fixed.as_slice())
}
}

impl<D: OutputSizeUser> digest::Update for FixedHashDigest<D> {
fn update(&mut self, _data: &[u8]) {}
}

impl<D: OutputSizeUser> Reset for FixedHashDigest<D> {
fn reset(&mut self) {
unimplemented!()
}
}

impl<D: OutputSizeUser> FixedOutputReset for FixedHashDigest<D> {
fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
out.clone_from_slice(self.fixed.as_slice())
}
}

fn decrypt_oaep(state: &State, cmd_data: &[u8]) -> response::Message {
let command: DecryptOaepCommand = deserialize(cmd_data)
.unwrap_or_else(|e| panic!("error parsing Code::DecryptOaepCommand: {e:?}"));

if let Some(obj) = state
.objects
.get(command.key_id, object::Type::AsymmetricKey)
{
if let Payload::RsaKey(private_key) = &obj.payload {
let plaintext = match command.mgf1_hash_alg {
mgf::Algorithm::Sha1 => {
let oaep = Oaep {
digest: Box::new(FixedHashDigest::<Sha1> {
fixed: GenericArray::clone_from_slice(command.label_hash.as_slice()),
}),
mgf_digest: Box::new(Sha1::new()),
label: None,
};
oaep.decrypt(Some(&mut OsRng), &private_key, &command.data)
}
mgf::Algorithm::Sha256 => {
let oaep = Oaep {
digest: Box::new(FixedHashDigest::<Sha256> {
fixed: GenericArray::clone_from_slice(command.label_hash.as_slice()),
}),
mgf_digest: Box::new(Sha256::new()),
label: None,
};
oaep.decrypt(Some(&mut OsRng), &private_key, &command.data)
}
mgf::Algorithm::Sha384 => {
let oaep = Oaep {
digest: Box::new(FixedHashDigest::<Sha384> {
fixed: GenericArray::clone_from_slice(command.label_hash.as_slice()),
}),
mgf_digest: Box::new(Sha384::new()),
label: None,
};
oaep.decrypt(Some(&mut OsRng), &private_key, &command.data)
}
mgf::Algorithm::Sha512 => {
let oaep = Oaep {
digest: Box::new(FixedHashDigest::<Sha512> {
fixed: GenericArray::clone_from_slice(command.label_hash.as_slice()),
}),
mgf_digest: Box::new(Sha512::new()),
label: None,
};
oaep.decrypt(Some(&mut OsRng), &private_key, &command.data)
}
};

let plaintext = if let Ok(plaintext) = plaintext {
plaintext
} else {
debug!("decrypt failed");
return device::ErrorKind::InvalidData.into();
};

DecryptOaepResponse(DecryptedData(plaintext)).serialize()
} else {
debug!("not an Rsa key: {:?}", obj.algorithm());
device::ErrorKind::InvalidCommand.into()
}
} else {
debug!("no such object ID: {:?}", command.key_id);
device::ErrorKind::ObjectNotFound.into()
}
}
2 changes: 1 addition & 1 deletion src/rsa/oaep/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Command for DecryptOaepCommand {

/// RSA OAEP decrypted data
#[derive(Serialize, Deserialize, Debug)]
pub struct DecryptOaepResponse(rsa::oaep::DecryptedData);
pub struct DecryptOaepResponse(pub(crate) rsa::oaep::DecryptedData);

impl Response for DecryptOaepResponse {
const COMMAND_CODE: command::Code = command::Code::DecryptOaep;
Expand Down
1 change: 0 additions & 1 deletion tests/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Integration tests for YubiHSM 2 commands

pub mod blink_device;
#[cfg(not(feature = "mockhsm"))]
pub mod decrypt_oaep;
pub mod delete_object;
pub mod device_info;
Expand Down

0 comments on commit aefadfe

Please sign in to comment.