use ring::digest;
use yubikey_piv::{MgmKey, YubiKey};
use yubikey_piv::policy::{PinPolicy, TouchPolicy};
use yubikey_piv::key::{attest, AlgorithmId, sign_data as yk_sign_data, SlotId};
use yubikey_piv::certificate::{Certificate, PublicKeyInfo};
use std::convert::From;
use super::Error;
impl From<yubikey_piv::error::Error> for Error {
fn from(e: yubikey_piv::error::Error) -> Self {
Error::InternalYubiKeyError(e.to_string())
}
}
impl crate::yubikey::Yubikey {
pub fn new() -> Result<Self, Error> {
Ok(Self {
yk: YubiKey::open()?,
})
}
pub fn reconnect(&mut self) -> Result <(), Error> {
match self.yk.reconnect() {
Ok(()) => Ok(()),
Err(_) => Err(Error::NoSuchYubikey)
}
}
pub fn unlock(&mut self, pin: &[u8], mgm_key: &[u8]) -> Result<(), Error> {
self.yk.verify_pin(pin)?;
match MgmKey::from_bytes(mgm_key) {
Ok(mgm) => self.yk.authenticate(mgm)?,
Err(_) => return Err(Error::InvalidManagementKey),
};
Ok(())
}
pub fn configured(&mut self, slot: &SlotId) -> Result<PublicKeyInfo, Error> {
let cert = yubikey_piv::certificate::Certificate::read(&mut self.yk, *slot)?;
Ok(cert.subject_pki().clone())
}
pub fn fetch_subject(&mut self, slot: &SlotId) -> Result<String, Error> {
let cert = yubikey_piv::certificate::Certificate::read(&mut self.yk, *slot)?;
Ok(cert.subject().to_string())
}
pub fn fetch_certificate(&mut self, slot: &SlotId) -> Result<Vec<u8>, Error> {
let cert = yubikey_piv::certificate::Certificate::read(&mut self.yk, *slot)?;
Ok(cert.as_ref().to_vec())
}
pub fn fetch_pubkey(&mut self, slot: &SlotId) -> Result<PublicKeyInfo, Error> {
self.configured(slot)
}
pub fn fetch_attestation(&mut self, slot: &SlotId) -> Result<Vec<u8>, Error> {
Ok(attest(&mut self.yk, *slot)?.to_vec())
}
pub fn provision(&mut self, slot: &SlotId, subject: &str, alg: AlgorithmId, touch_policy: TouchPolicy, pin_policy: PinPolicy) -> Result<PublicKeyInfo, Error> {
let key_info = yubikey_piv::key::generate(&mut self.yk, *slot, alg, pin_policy, touch_policy)?;
Certificate::generate_self_signed(
&mut self.yk,
*slot,
[0u8; 20],
None,
subject.to_string(),
key_info,
)?;
self.configured(slot)
}
pub fn sign_data(&mut self, data: &[u8], alg: AlgorithmId, slot: &SlotId) -> Result<Vec<u8>, Error> {
let (slot_alg, hash_alg) = match self.configured(slot) {
Ok(PublicKeyInfo::EcP256(_)) => (AlgorithmId::EccP256, &digest::SHA256),
Ok(PublicKeyInfo::EcP384(_)) => (AlgorithmId::EccP384, &digest::SHA384),
Ok(_) => (AlgorithmId::Rsa2048, &digest::SHA256), Err(_) => return Err(Error::Unprovisioned),
};
if slot_alg != alg {
return Err(Error::WrongKeyType);
}
let signature = yk_sign_data(&mut self.yk, digest::digest(hash_alg, data).as_ref(), alg, *slot)?;
Ok(signature.to_vec())
}
}