Fix GENERAL AUTHENTICATE for agreement mechanisms

This commit is contained in:
Sosthène Guédon
2024-03-01 14:29:40 +01:00
committed by Nicolas Stalder
parent c1f16e6605
commit 441202f7b0
4 changed files with 129 additions and 16 deletions
+13 -10
View File
@@ -16,6 +16,7 @@ macro_rules! enum_subset {
) => {
$(#[$outer])*
#[repr(u8)]
#[derive(Clone, Copy)]
$vis enum $name {
$(
$var,
@@ -46,9 +47,9 @@ macro_rules! enum_subset {
}
}
impl PartialEq<$sup> for $name {
fn eq(&self, other: &$sup) -> bool {
match (self,other) {
impl<T: Copy + Into<$sup>> PartialEq<T> for $name {
fn eq(&self, other: &T) -> bool {
match (self,(*other).into()) {
$(
| ($name::$var, $sup::$var)
)* => true,
@@ -57,6 +58,8 @@ macro_rules! enum_subset {
}
}
impl Eq for $name {}
impl TryFrom<u8> for $name {
type Error = ::iso7816::Status;
fn try_from(tag: u8) -> ::core::result::Result<Self, Self::Error> {
@@ -84,7 +87,7 @@ pub enum SecurityCondition {
pub struct RetiredIndex(u8);
crate::enum_u8! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum KeyReference {
GlobalPin = 0x00,
SecureMessaging = 0x04,
@@ -148,14 +151,14 @@ macro_rules! impl_use_security_condition {
}
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum AttestKeyReference: KeyReference {
PivAuthentication,
}
}
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum AsymmetricKeyReference: KeyReference {
// SecureMessaging,
PivAuthentication,
@@ -187,7 +190,7 @@ enum_subset! {
}
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum GenerateKeyReference: AsymmetricKeyReference {
// SecureMessaging,
PivAuthentication,
@@ -198,7 +201,7 @@ enum_subset! {
}
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum ChangeReferenceKeyReference: KeyReference {
GlobalPin,
ApplicationPin,
@@ -207,7 +210,7 @@ enum_subset! {
}
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum VerifyKeyReference: KeyReference {
GlobalPin,
ApplicationPin,
@@ -220,7 +223,7 @@ enum_subset! {
enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub enum AuthenticateKeyReference: KeyReference {
SecureMessaging,
PivAuthentication,
+64 -3
View File
@@ -11,7 +11,7 @@ extern crate log;
delog::generate_macros!();
pub mod commands;
use commands::piv_types::Algorithms;
use commands::piv_types::{Algorithms, RsaAlgorithms};
pub use commands::{Command, YubicoPivExtension};
use commands::{GeneralAuthenticate, PutData, ResetRetryCounter};
pub mod constants;
@@ -592,7 +592,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
self.admin_challenge(auth.algorithm, data, reply)
}
SecureMessaging => Err(Status::FunctionNotSupported),
_ => self.sign_challenge(
PivAuthentication | CardAuthentication | DigitalSignature => self.sign_challenge(
auth.algorithm,
auth.key_reference.try_into().map_err(|_| {
if cfg!(debug_assertions) {
@@ -600,7 +600,24 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
panic!("Failed to convert key reference: {:?}", auth.key_reference);
} else {
error!("Failed to convert key reference: {:?}", auth.key_reference);
Status::UnspecifiedNonpersistentExecutionError
Status::UnspecifiedPersistentExecutionError
}
})?,
data,
reply,
),
KeyManagement | Retired01 | Retired02 | Retired03 | Retired04 | Retired05
| Retired06 | Retired07 | Retired08 | Retired09 | Retired10 | Retired11
| Retired12 | Retired13 | Retired14 | Retired15 | Retired16 | Retired17
| Retired18 | Retired19 | Retired20 => self.agreement_challenge(
auth.algorithm,
auth.key_reference.try_into().map_err(|_| {
if cfg!(debug_assertions) {
// To find errors more easily in tests and fuzzing but not crash in production
panic!("Failed to convert key reference: {:?}", auth.key_reference);
} else {
error!("Failed to convert key reference: {:?}", auth.key_reference);
Status::UnspecifiedPersistentExecutionError
}
})?,
data,
@@ -610,6 +627,50 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
}
}
pub fn agreement_challenge<const R: usize>(
&mut self,
requested_alg: Algorithms,
key_ref: AsymmetricKeyReference,
data: derp::Input<'_>,
mut reply: Reply<'_, R>,
) -> Result {
let Some(KeyWithAlg { alg, id }) = self.state.persistent.keys.asymetric_for_reference(key_ref) else {
warn!("Attempt to use unset key");
return Err(Status::ConditionsOfUseNotSatisfied);
};
if alg != requested_alg {
warn!("Bad algorithm: {:?}", requested_alg);
return Err(Status::IncorrectP1OrP2Parameter);
}
let rsa_alg: RsaAlgorithms = alg.try_into().map_err(|_| {
warn!("Tried to perform agreement on a challenge with a non-rsa algorithm");
Status::ConditionsOfUseNotSatisfied
})?;
let response = try_syscall!(self.trussed.decrypt(
rsa_alg.mechanism(),
id,
data.as_slice_less_safe(),
&[],
&[],
&[]
))
.map_err(|_err| {
warn!("Failed to decrypt challenge: {:?}", _err);
Status::IncorrectDataParameter
})?
.plaintext
.ok_or_else(|| {
warn!("Failed to decrypt challenge, no plaintext");
Status::IncorrectDataParameter
})?;
reply.expand(&[0x82])?;
reply.append_len(response.len())?;
reply.expand(&response)?;
Ok(())
}
pub fn sign_challenge<const R: usize>(
&mut self,
requested_alg: Algorithms,
+51 -2
View File
@@ -19,6 +19,7 @@ macro_rules! enum_u8 {
) => {
$(#[$outer])*
#[repr(u8)]
#[derive(Clone, Copy)]
$vis enum $name {
$(
$var = $num,
@@ -42,6 +43,17 @@ macro_rules! enum_u8 {
*self as u8 == *other
}
}
impl<T: Into<$name> + Copy> PartialEq<T> for $name {
fn eq(&self, other: &T) -> bool {
let other: $name = (*other).into();
matches!((self,other), $(
| ($name::$var, $name::$var)
)*)
}
}
impl Eq for $name {}
}
}
@@ -70,7 +82,7 @@ impl TryFrom<&[u8]> for Puk {
}
enum_u8! {
#[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)]
#[derive(Debug,Deserialize,Serialize)]
// As additional reference, see:
// https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15
//
@@ -109,7 +121,7 @@ enum_u8! {
}
crate::container::enum_subset! {
#[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)]
#[derive(Debug,Deserialize,Serialize)]
pub enum AsymmetricAlgorithms: Algorithms {
Rsa2048,
Rsa4096,
@@ -165,6 +177,43 @@ impl AsymmetricAlgorithms {
}
}
macro_rules! impl_use_try_into {
($sup:ident => {$(($from:ident, $into:ident)),*}) => {
$(
impl TryFrom<$from> for $into {
type Error = iso7816::Status;
fn try_from(v: $from) -> core::result::Result<$into, iso7816::Status> {
let sup: $sup = v.into();
sup.try_into()
}
}
)*
};
}
crate::container::enum_subset! {
#[derive(Debug,Deserialize,Serialize)]
pub enum RsaAlgorithms: Algorithms {
Rsa2048,
Rsa4096,
}
}
impl RsaAlgorithms {
pub fn mechanism(self) -> Mechanism {
match self {
Self::Rsa2048 => Mechanism::Rsa2048Pkcs,
Self::Rsa4096 => Mechanism::Rsa4096Pkcs,
}
}
}
impl_use_try_into!(
Algorithms => {
(AsymmetricAlgorithms, RsaAlgorithms)
}
);
/// TODO:
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct CryptographicAlgorithmTemplate<'a> {
+1 -1
View File
@@ -38,7 +38,7 @@ pub enum TouchPolicy {
}
crate::container::enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub enum AdministrationAlgorithm: Algorithms {
Tdes,
Aes256