Skip to content

Commit

Permalink
implement put credential method
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo committed Sep 8, 2023
1 parent e34b133 commit f7c4374
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 4 deletions.
5 changes: 5 additions & 0 deletions src/apdu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ pub enum Ins {
/// YubiHSM Auth // List credentials
ListCredentials,

/// YubiHSM Auth // Put credential
PutCredential,

/// Other/unrecognized instruction codes
Other(u8),
}
Expand All @@ -233,6 +236,7 @@ impl Ins {
Ins::GetSerial => 0xf8,
Ins::GetMetadata => 0xf7,
// Yubihsm auth
Ins::PutCredential => 0x01,
Ins::Calculate => 0x03,
Ins::GetHostChallenge => 0x04,
Ins::ListCredentials => 0x05,
Expand All @@ -244,6 +248,7 @@ impl Ins {
impl From<u8> for Ins {
fn from(code: u8) -> Self {
match code {
0x01 => Ins::PutCredential,
0x03 => Ins::Calculate,
0x04 => Ins::GetHostChallenge,
0x05 => Ins::ListCredentials,
Expand Down
5 changes: 5 additions & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ pub(crate) const TAG_PROTECTED_MGM: u8 = 0x89;
// YubiHSM Auth
pub(crate) const TAG_LABEL: u8 = 0x71;
pub(crate) const TAG_PW: u8 = 0x73;
pub(crate) const TAG_ALGO: u8 = 0x74;
pub(crate) const TAG_KEY_ENC: u8 = 0x75;
pub(crate) const TAG_KEY_MAC: u8 = 0x76;
pub(crate) const TAG_CONTEXT: u8 = 0x77;
pub(crate) const TAG_TOUCH: u8 = 0x7a;
pub(crate) const TAG_MGMKEY: u8 = 0x7b;
38 changes: 36 additions & 2 deletions src/hsmauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ pub(crate) const KEY_SIZE: usize = 16;
/// Password to authenticate to the Yubikey HSM Auth Applet has a max length of 16
pub(crate) const PW_LEN: usize = 16;

/// Management key used to manipulate secrets (add/delete)
pub struct MgmKey(pub [u8; PW_LEN]);

impl Default for MgmKey {
fn default() -> Self {
// https://docs.yubico.com/yesdk/users-manual/application-yubihsm-auth/commands/change-management-key.html
// The default value of the management key is all zeros:
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Self([0; PW_LEN])
}
}

/// Label associated with a secret on the Yubikey.
#[derive(Clone)]
pub struct Label(pub(crate) Vec<u8>);
Expand Down Expand Up @@ -116,6 +128,27 @@ impl HsmAuth {
Transaction::new(&mut self.client.card)?.list_credentials(self.client.version)
}

/// Put credential
pub fn put_credential(
&mut self,
mgmkey: Option<MgmKey>,
label: Label,
password: &[u8],
enc_key: [u8; KEY_SIZE],
mac_key: [u8; KEY_SIZE],
touch: bool,
) -> Result<()> {
Transaction::new(&mut self.client.card)?.put_credential(
self.client.version,
mgmkey.unwrap_or(MgmKey::default()),
label,
password,
enc_key,
mac_key,
touch,
)
}

/// Retun the inner `YubiKey`
pub fn into_inner(mut self) -> Result<YubiKey> {
Transaction::new(&mut self.client.card)?.select_piv_application()?;
Expand All @@ -124,12 +157,13 @@ impl HsmAuth {
}

#[derive(Debug)]
#[repr(u8)]
/// Algorithm for the credentials
pub enum Algorithm {
/// AES 128 keys
Aes128,
Aes128 = 38,
/// EC P256
EcP256,
EcP256 = 39,
}

impl fmt::Display for Algorithm {
Expand Down
76 changes: 74 additions & 2 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
use crate::{
apdu::Response,
apdu::{Apdu, Ins, StatusWords},
consts::{CB_BUF_MAX, CB_OBJ_MAX, TAG_CONTEXT, TAG_LABEL, TAG_PW},
consts::{
CB_BUF_MAX, CB_OBJ_MAX, TAG_ALGO, TAG_CONTEXT, TAG_KEY_ENC, TAG_KEY_MAC, TAG_LABEL,
TAG_MGMKEY, TAG_PW, TAG_TOUCH,
},
error::{Error, Result},
hsmauth::{self, Challenge, Context, Credential, Label, SessionKeys},
hsmauth::{self, Algorithm, Challenge, Context, Credential, Label, SessionKeys},
otp,
piv::{self, AlgorithmId, SlotId},
serialization::*,
Expand Down Expand Up @@ -636,4 +639,73 @@ impl<'tx> Transaction<'tx> {
let data = response.data();
Credential::parse_list(data)
}

/// Adds a credential to YubiHSM Auth applet
pub fn put_credential(
&mut self,
version: Version,
mgmkey: hsmauth::MgmKey,
label: Label,
password: &[u8],
enc_key: [u8; hsmauth::KEY_SIZE],
mac_key: [u8; hsmauth::KEY_SIZE],
touch: bool,
) -> Result<()> {
// YubiHSM was introduced by firmware 5.4.3
// https://docs.yubico.com/yesdk/users-manual/application-yubihsm-auth/yubihsm-auth-overview.html
if version
< (Version {
major: 5,
minor: 4,
patch: 3,
})
{
return Err(Error::NotSupported);
}

let mut data = [0u8; CB_BUF_MAX];
let mut len = data.len();
let mut data_remaining = &mut data[..];

let offset = Tlv::write(data_remaining, TAG_MGMKEY, &mgmkey.0)?;
data_remaining = &mut data_remaining[offset..];

let offset = Tlv::write(data_remaining, TAG_LABEL, &label.0)?;
data_remaining = &mut data_remaining[offset..];

let offset = Tlv::write(data_remaining, TAG_ALGO, &[Algorithm::Aes128 as u8])?;
data_remaining = &mut data_remaining[offset..];

let offset = Tlv::write(data_remaining, TAG_KEY_ENC, &enc_key)?;
data_remaining = &mut data_remaining[offset..];

let offset = Tlv::write(data_remaining, TAG_KEY_MAC, &mac_key)?;
data_remaining = &mut data_remaining[offset..];

let mut password = password.to_vec();
password.resize(hsmauth::PW_LEN, 0);

let offset = Tlv::write(data_remaining, TAG_PW, &password)?;
data_remaining = &mut data_remaining[offset..];

let offset = Tlv::write(data_remaining, TAG_TOUCH, &[touch as u8])?;
data_remaining = &mut data_remaining[offset..];

len -= data_remaining.len();

let response = Apdu::new(Ins::PutCredential)
.params(0x00, 0x00)
.data(&data[..len])
.transmit(self, 2)?;

if !response.is_success() {
error!(
"Unable to store credential: {:04x}",
response.status_words().code()
);
return Err(Error::GenericError);
}

Ok(())
}
}

0 comments on commit f7c4374

Please sign in to comment.