WIP: Implement key generation

This commit is contained in:
Sosthène Guédon
2024-03-01 14:29:40 +01:00
committed by Nicolas Stalder
parent aa91b2b0bd
commit f4c128498c
5 changed files with 102 additions and 44 deletions
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,