mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Fix GENERAL AUTHENTICATE for agreement mechanisms
This commit is contained in:
committed by
Nicolas Stalder
parent
c1f16e6605
commit
441202f7b0
+13
-10
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user