mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
WIP: Implement key generation
This commit is contained in:
committed by
Nicolas Stalder
parent
aa91b2b0bd
commit
f4c128498c
+3
-3
@@ -15,7 +15,7 @@ use crate::state::TouchPolicy;
|
||||
pub use crate::{
|
||||
container::{
|
||||
self as containers, AttestKeyReference, AuthenticateKeyReference,
|
||||
ChangeReferenceKeyReference, GenerateAsymmetricKeyReference, VerifyKeyReference,
|
||||
ChangeReferenceKeyReference, AsymmetricKeyReference, VerifyKeyReference,
|
||||
},
|
||||
piv_types, Pin, Puk,
|
||||
};
|
||||
@@ -58,7 +58,7 @@ pub enum Command<'l> {
|
||||
GeneralAuthenticate(GeneralAuthenticate),
|
||||
/// Store a data object / container.
|
||||
PutData(PutData),
|
||||
GenerateAsymmetric(GenerateAsymmetricKeyReference),
|
||||
GenerateAsymmetric(AsymmetricKeyReference),
|
||||
|
||||
/* Yubico commands */
|
||||
YkExtension(YubicoPivExtension),
|
||||
@@ -327,7 +327,7 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
}
|
||||
|
||||
(0x00, Instruction::GenerateAsymmetricKeyPair, 0x00, p2) => {
|
||||
Self::GenerateAsymmetric(GenerateAsymmetricKeyReference::try_from(p2)?)
|
||||
Self::GenerateAsymmetric(AsymmetricKeyReference::try_from(p2)?)
|
||||
}
|
||||
// (0x00, 0x01, 0x10, 0x00)
|
||||
(0x00, Instruction::Unknown(0x01), 0x00, 0x00) => {
|
||||
|
||||
+2
-2
@@ -132,8 +132,8 @@ enum_subset! {
|
||||
|
||||
enum_subset! {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum GenerateAsymmetricKeyReference: KeyReference {
|
||||
SecureMessaging,
|
||||
pub enum AsymmetricKeyReference: KeyReference {
|
||||
// SecureMessaging,
|
||||
PivAuthentication,
|
||||
DigitalSignature,
|
||||
KeyManagement,
|
||||
|
||||
+25
-26
@@ -12,7 +12,7 @@ delog::generate_macros!();
|
||||
|
||||
pub mod commands;
|
||||
use commands::containers::KeyReference;
|
||||
use commands::GeneralAuthenticate;
|
||||
use commands::{AsymmetricKeyReference, GeneralAuthenticate};
|
||||
pub use commands::{Command, YubicoPivExtension};
|
||||
pub mod constants;
|
||||
pub mod container;
|
||||
@@ -23,7 +23,7 @@ mod dispatch;
|
||||
pub mod piv_types;
|
||||
pub mod state;
|
||||
|
||||
pub use piv_types::{Pin, Puk};
|
||||
pub use piv_types::{AsymmetricAlgorithms, Pin, Puk};
|
||||
|
||||
#[cfg(feature = "virtual")]
|
||||
pub mod vpicc;
|
||||
@@ -126,6 +126,10 @@ where
|
||||
self.load()?
|
||||
.general_authenticate(authenticate, command.data(), reply)
|
||||
}
|
||||
Command::GenerateAsymmetric(reference) => {
|
||||
self.load()?
|
||||
.generate_asymmetric_keypair(reference, command.data(), reply)
|
||||
}
|
||||
Command::YkExtension(yk_command) => {
|
||||
self.yubico_piv_extension(command.data(), yk_command, reply)
|
||||
}
|
||||
@@ -595,9 +599,9 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn generate_asymmetric_keypair<const R: usize, const C: usize>(
|
||||
pub fn generate_asymmetric_keypair<const R: usize>(
|
||||
&mut self,
|
||||
reference: AsymmetricKeyReference,
|
||||
data: &[u8],
|
||||
reply: &mut Data<R>,
|
||||
) -> Result {
|
||||
@@ -629,37 +633,32 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
|
||||
// TODO: iterate on this, don't expect tags..
|
||||
let input = derp::Input::from(data);
|
||||
// let (mechanism, parameter) = input.read_all(derp::Error::Read, |input| {
|
||||
let (mechanism, _pin_policy, _touch_policy) = input
|
||||
let mechanism_data = input
|
||||
.read_all(derp::Error::Read, |input| {
|
||||
derp::nested(input, 0xac, |input| {
|
||||
let mechanism = derp::expect_tag_and_get_value(input, 0x80)?;
|
||||
// let parameter = derp::expect_tag_and_get_value(input, 0x81)?;
|
||||
let pin_policy = derp::expect_tag_and_get_value(input, 0xaa)?;
|
||||
let touch_policy = derp::expect_tag_and_get_value(input, 0xab)?;
|
||||
// Ok((mechanism.as_slice_less_safe(), parameter.as_slice_less_safe()))
|
||||
Ok((
|
||||
mechanism.as_slice_less_safe(),
|
||||
pin_policy.as_slice_less_safe(),
|
||||
touch_policy.as_slice_less_safe(),
|
||||
))
|
||||
derp::expect_tag_and_get_value(input, 0x80)
|
||||
.map(|input| input.as_slice_less_safe())
|
||||
})
|
||||
})
|
||||
.map_err(|_e| {
|
||||
info!("error parsing GenerateAsymmetricKeypair: {:?}", &_e);
|
||||
warn!("error parsing GenerateAsymmetricKeypair: {:?}", &_e);
|
||||
Status::IncorrectDataParameter
|
||||
})?;
|
||||
|
||||
// if mechanism != &[0x11] {
|
||||
// HA! patch in Ed255
|
||||
if mechanism != [0x22] {
|
||||
return Err(Status::InstructionNotSupportedOrInvalid);
|
||||
}
|
||||
let [mechanism] = mechanism_data else {
|
||||
warn!("Mechanism of len not 1: {mechanism_data:02x?}");
|
||||
return Err(Status::IncorrectDataParameter);
|
||||
};
|
||||
|
||||
let parsed_mechanism: AsymmetricAlgorithms = (*mechanism).try_into().map_err(|_| {
|
||||
warn!("Unknown mechanism: {mechanism:x}");
|
||||
Status::IncorrectDataParameter
|
||||
})?;
|
||||
|
||||
// ble policy
|
||||
|
||||
if let Some(key) = self.state.persistent.keys.authentication_key {
|
||||
syscall!(self.trussed.delete(key));
|
||||
}
|
||||
// if let Some(key) = self.state.persistent.keys.authentication_key {
|
||||
// // syscall!(self.trussed.delete(key));
|
||||
// }
|
||||
|
||||
// let key = syscall!(self.trussed.generate_p256_private_key(
|
||||
// let key = syscall!(self.trussed.generate_p256_private_key(
|
||||
@@ -686,7 +685,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
|
||||
// )?
|
||||
// .signature;
|
||||
// blocking::dbg!(&signature);
|
||||
self.state.persistent.keys.authentication_key = Some(key);
|
||||
// self.state.persistent.keys.authentication_key = Some(key);
|
||||
self.state.persistent.save(self.trussed);
|
||||
|
||||
// let public_key = syscall!(self.trussed.derive_p256_public_key(
|
||||
|
||||
+27
-1
@@ -92,7 +92,7 @@ impl TryFrom<&[u8]> for Puk {
|
||||
}
|
||||
|
||||
enum_u8! {
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)]
|
||||
// As additional reference, see:
|
||||
// https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15
|
||||
//
|
||||
@@ -129,6 +129,32 @@ enum_u8! {
|
||||
P384Sha384 = 0xF4,
|
||||
}
|
||||
}
|
||||
|
||||
crate::container::enum_subset! {
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)]
|
||||
pub enum AsymmetricAlgorithms: Algorithms {
|
||||
Rsa2048,
|
||||
Rsa4096,
|
||||
P256,
|
||||
|
||||
// Not supported
|
||||
// Rsa1024 = 0x6,
|
||||
// Rsa3072 = 0xE0,
|
||||
// P384 = 0x14,
|
||||
// P521 = 0x15,
|
||||
|
||||
// non-standard! in piv-go though!
|
||||
// Ed255_prev = 0x22,
|
||||
// https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15
|
||||
// non-standard!
|
||||
// Ed25519 = 0xE2,
|
||||
// X25519 = 0xE3,
|
||||
// Ed448 = 0xE4,
|
||||
// X448 = 0xE5,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO:
|
||||
#[derive(Clone, Copy, Default, Eq, PartialEq)]
|
||||
pub struct CryptographicAlgorithmTemplate<'a> {
|
||||
|
||||
+45
-12
@@ -12,8 +12,8 @@ use trussed::{
|
||||
types::{KeyId, KeySerialization, Location, Mechanism, PathBuf},
|
||||
};
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::piv_types::Algorithms;
|
||||
use crate::{constants::*, piv_types::AsymmetricAlgorithms};
|
||||
use crate::{container::AsymmetricKeyReference, piv_types::Algorithms};
|
||||
|
||||
use crate::{Pin, Puk};
|
||||
|
||||
@@ -166,29 +166,43 @@ impl ManagementAlgorithm {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct ManagementKey {
|
||||
pub struct KeyWithAlg<A> {
|
||||
pub id: KeyId,
|
||||
pub alg: ManagementAlgorithm,
|
||||
pub alg: A,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Keys {
|
||||
// 9a "PIV Authentication Key" (YK: PIV Authentication)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub authentication_key: Option<KeyId>,
|
||||
pub authentication_key: Option<KeyWithAlg<AsymmetricAlgorithms>>,
|
||||
// 9b "PIV Card Application Administration Key" (YK: PIV Management)
|
||||
pub management_key: ManagementKey,
|
||||
pub management_key: KeyWithAlg<ManagementAlgorithm>,
|
||||
// 9c "Digital Signature Key" (YK: Digital Signature)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub signature_key: Option<KeyId>,
|
||||
pub signature_key: Option<KeyWithAlg<AsymmetricAlgorithms>>,
|
||||
// 9d "Key Management Key" (YK: Key Management)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub encryption_key: Option<KeyId>,
|
||||
pub encryption_key: Option<KeyWithAlg<AsymmetricAlgorithms>>,
|
||||
// 9e "Card Authentication Key" (YK: Card Authentication)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pinless_authentication_key: Option<KeyId>,
|
||||
pub pinless_authentication_key: Option<KeyWithAlg<AsymmetricAlgorithms>>,
|
||||
// 0x82..=0x95 (130-149)
|
||||
pub retired_keys: [Option<KeyId>; 20],
|
||||
pub retired_keys: [Option<KeyWithAlg<AsymmetricAlgorithms>>; 20],
|
||||
}
|
||||
|
||||
impl Keys {
|
||||
pub fn asymetric_for_reference(
|
||||
&self,
|
||||
key: AsymmetricKeyReference,
|
||||
) -> &Option<KeyWithAlg<AsymmetricAlgorithms>> {
|
||||
match key {
|
||||
AsymmetricKeyReference::PivAuthentication => &self.authentication_key,
|
||||
AsymmetricKeyReference::DigitalSignature => &self.signature_key,
|
||||
AsymmetricKeyReference::KeyManagement => &self.authentication_key,
|
||||
AsymmetricKeyReference::CardAuthentication => &self.authentication_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
@@ -466,14 +480,33 @@ impl Persistent {
|
||||
))
|
||||
.key;
|
||||
let old_management_key = self.keys.management_key.id;
|
||||
self.keys.management_key = ManagementKey { id, alg };
|
||||
self.keys.management_key = KeyWithAlg { id, alg };
|
||||
self.save(client);
|
||||
syscall!(client.delete(old_management_key));
|
||||
}
|
||||
|
||||
pub fn set_asymmetric_key(
|
||||
&mut self,
|
||||
_key: AsymmetricKeyReference,
|
||||
_id: KeyId,
|
||||
_alg: AsymmetricAlgorithms,
|
||||
_client: &mut impl trussed::Client,
|
||||
) -> Result<Option<KeyWithAlg<AsymmetricAlgorithms>>, Status> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn generate_asymmetric_key(
|
||||
&mut self,
|
||||
_key: AsymmetricKeyReference,
|
||||
_alg: AsymmetricAlgorithms,
|
||||
_client: &mut impl trussed::Client,
|
||||
) -> Result<KeyId, Status> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn initialize(client: &mut impl trussed::Client) -> Self {
|
||||
info!("initializing PIV state");
|
||||
let management_key = ManagementKey {
|
||||
let management_key = KeyWithAlg {
|
||||
id: syscall!(client.unsafe_inject_key(
|
||||
YUBICO_DEFAULT_MANAGEMENT_KEY_ALG.mechanism(),
|
||||
YUBICO_DEFAULT_MANAGEMENT_KEY,
|
||||
|
||||
Reference in New Issue
Block a user