Refactor piv-p256-specific stanza unwrapping onto RecipientLine
This commit is contained in:
+8
-29
@@ -1,10 +1,6 @@
|
||||
//! Structs for handling YubiKeys.
|
||||
|
||||
use age_core::{
|
||||
format::{FileKey, FILE_KEY_BYTES},
|
||||
primitives::{aead_decrypt, hkdf},
|
||||
secrecy::{zeroize::Zeroize, ExposeSecret, SecretString},
|
||||
};
|
||||
use age_core::secrecy::{ExposeSecret, SecretString};
|
||||
use age_plugin::{identity, Callbacks};
|
||||
use bech32::{ToBase32, Variant};
|
||||
use dialoguer::Password;
|
||||
@@ -25,7 +21,7 @@ use yubikey::{
|
||||
use crate::{
|
||||
error::Error,
|
||||
fl,
|
||||
format::{RecipientLine, STANZA_KEY_LABEL},
|
||||
format::RecipientLine,
|
||||
p256::{Recipient, TAG_BYTES},
|
||||
util::{otp_serial_prefix, Metadata},
|
||||
IDENTITY_PREFIX,
|
||||
@@ -623,7 +619,6 @@ impl Stub {
|
||||
cert,
|
||||
pk,
|
||||
slot: self.slot,
|
||||
tag: self.tag,
|
||||
identity_index: self.identity_index,
|
||||
cached_metadata: None,
|
||||
last_touch: None,
|
||||
@@ -636,7 +631,6 @@ pub(crate) struct Connection {
|
||||
cert: Certificate,
|
||||
pk: Recipient,
|
||||
slot: RetiredSlotId,
|
||||
tag: [u8; 4],
|
||||
identity_index: usize,
|
||||
cached_metadata: Option<Metadata>,
|
||||
last_touch: Option<Instant>,
|
||||
@@ -705,8 +699,10 @@ impl Connection {
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
pub(crate) fn unwrap_file_key(&mut self, line: &RecipientLine) -> Result<FileKey, ()> {
|
||||
assert_eq!(self.tag, line.tag);
|
||||
pub(crate) fn p256_ecdh(&mut self, epk_bytes: &[u8]) -> Result<yubikey::Buffer, ()> {
|
||||
// The YubiKey API for performing scalar multiplication takes the point in its
|
||||
// uncompressed SEC-1 encoding.
|
||||
assert_eq!(epk_bytes.len(), 65);
|
||||
|
||||
// Check if the touch policy requires a touch.
|
||||
let needs_touch = match (
|
||||
@@ -718,11 +714,9 @@ impl Connection {
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// The YubiKey API for performing scalar multiplication takes the point in its
|
||||
// uncompressed SEC-1 encoding.
|
||||
let shared_secret = match decrypt_data(
|
||||
&mut self.yubikey,
|
||||
line.epk_bytes.decompress().as_bytes(),
|
||||
epk_bytes,
|
||||
AlgorithmId::EccP256,
|
||||
SlotId::Retired(self.slot),
|
||||
) {
|
||||
@@ -739,22 +733,7 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
let mut salt = vec![];
|
||||
salt.extend_from_slice(line.epk_bytes.as_bytes());
|
||||
salt.extend_from_slice(self.pk.to_encoded().as_bytes());
|
||||
|
||||
let enc_key = hkdf(&salt, STANZA_KEY_LABEL, shared_secret.as_ref());
|
||||
|
||||
// A failure to decrypt is fatal, because we assume that we won't
|
||||
// encounter 32-bit collisions on the key tag embedded in the header.
|
||||
aead_decrypt(&enc_key, FILE_KEY_BYTES, &line.encrypted_file_key)
|
||||
.map_err(|_| ())
|
||||
.map(|mut pt| {
|
||||
FileKey::init_with_mut(|file_key| {
|
||||
file_key.copy_from_slice(&pt);
|
||||
pt.zeroize();
|
||||
})
|
||||
})
|
||||
Ok(shared_secret)
|
||||
}
|
||||
|
||||
/// Close this connection without resetting the YubiKey.
|
||||
|
||||
Reference in New Issue
Block a user