Change recipient type for identity encryption to p256tag
Encrypting to an identity requires the plugin binary, and there is a reasonable expectation that the same (or a later) plugin binary version will be used to decrypt, so we can assume support for the preferred recipient type.
This commit is contained in:
@@ -16,6 +16,8 @@ to 0.3.0 are beta releases.
|
||||
|
||||
### Changed
|
||||
- MSRV is now 1.70.0.
|
||||
- Encryption to an identity now uses the preferred recipient type supported for
|
||||
that identity.
|
||||
|
||||
## [0.5.0] - 2024-08-04
|
||||
### Fixed
|
||||
|
||||
+8
-4
@@ -20,7 +20,9 @@ use yubikey::{
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
fl, piv_p256,
|
||||
fl,
|
||||
native::p256tag,
|
||||
piv_p256,
|
||||
recipient::TAG_BYTES,
|
||||
util::{otp_serial_prefix, Metadata},
|
||||
Recipient, IDENTITY_PREFIX,
|
||||
@@ -592,9 +594,10 @@ impl Stub {
|
||||
let (cert, pk) = match Certificate::read(&mut yubikey, SlotId::Retired(self.slot))
|
||||
.ok()
|
||||
.and_then(|cert| {
|
||||
piv_p256::Recipient::from_certificate(&cert)
|
||||
.filter(|pk| pk.tag() == self.tag)
|
||||
.map(|pk| (cert, Recipient::PivP256(pk)))
|
||||
// Parse as the preferred recipient for each identity type.
|
||||
p256tag::Recipient::from_certificate(&cert)
|
||||
.filter(|pk| pk.static_tag() == self.tag)
|
||||
.map(|pk| (cert, Recipient::P256Tag(pk)))
|
||||
}) {
|
||||
Some(pk) => pk,
|
||||
None => {
|
||||
@@ -628,6 +631,7 @@ pub(crate) struct Connection {
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
/// Returns the preferred recipient for encrypting to this identity.
|
||||
pub(crate) fn recipient(&self) -> &Recipient {
|
||||
&self.pk
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use p256::{
|
||||
EncodedPoint,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use yubikey::{certificate::PublicKeyInfo, Certificate};
|
||||
|
||||
use super::{stanza_tag, YubiKeyKemPrivateKey};
|
||||
use crate::{
|
||||
@@ -84,6 +85,33 @@ impl Recipient {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn from_certificate(cert: &Certificate) -> Option<Self> {
|
||||
Self::from_spki(cert.subject_pki())
|
||||
}
|
||||
|
||||
pub(crate) fn from_spki(spki: &PublicKeyInfo) -> Option<Self> {
|
||||
let encoded = match spki {
|
||||
PublicKeyInfo::EcP256(pubkey) => Some(pubkey),
|
||||
_ => None,
|
||||
}?;
|
||||
|
||||
// Check that the certificate encoding is uncompressed.
|
||||
let pk_recip = <Kem as hpke::Kem>::PublicKey::from_bytes(encoded.as_bytes()).ok()?;
|
||||
|
||||
let point = p256::PublicKey::from_encoded_point(encoded).into_option()?;
|
||||
let compressed = point.to_encoded_point(true);
|
||||
|
||||
Some(Self {
|
||||
compressed,
|
||||
pk_recip,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the compressed SEC-1 encoding of this recipient.
|
||||
pub(crate) fn to_compressed(&self) -> p256::EncodedPoint {
|
||||
self.compressed
|
||||
}
|
||||
|
||||
pub(crate) fn static_tag(&self) -> [u8; TAG_BYTES] {
|
||||
static_tag(self.compressed.as_bytes())
|
||||
}
|
||||
|
||||
+13
-8
@@ -111,7 +111,7 @@ impl Recipient {
|
||||
|
||||
let shared_secret = esk.diffie_hellman(self.public_key());
|
||||
|
||||
let salt = salt(&epk_bytes, self);
|
||||
let salt = salt(&epk_bytes, self.to_encoded());
|
||||
|
||||
let enc_key = {
|
||||
let mut okm = [0; 32];
|
||||
@@ -138,13 +138,17 @@ impl Recipient {
|
||||
|
||||
impl RecipientLine {
|
||||
pub(crate) fn unwrap_file_key(&self, conn: &mut Connection) -> Result<FileKey, ()> {
|
||||
let recipient = match conn.recipient() {
|
||||
crate::recipient::Recipient::PivP256(recipient) => recipient,
|
||||
_ => panic!("should have been filtered out earlier"),
|
||||
let (static_tag, pk) = match conn.recipient() {
|
||||
crate::recipient::Recipient::PivP256(recipient) => {
|
||||
(recipient.tag(), recipient.to_encoded())
|
||||
}
|
||||
crate::recipient::Recipient::P256Tag(recipient) => {
|
||||
(recipient.static_tag(), recipient.to_compressed())
|
||||
}
|
||||
};
|
||||
assert_eq!(self.tag, recipient.tag());
|
||||
assert_eq!(self.tag, static_tag);
|
||||
|
||||
let salt = salt(&self.epk_bytes, recipient);
|
||||
let salt = salt(&self.epk_bytes, pk);
|
||||
|
||||
// The YubiKey API for performing scalar multiplication takes the point in its
|
||||
// uncompressed SEC-1 encoding.
|
||||
@@ -165,9 +169,10 @@ impl RecipientLine {
|
||||
}
|
||||
}
|
||||
|
||||
fn salt(epk_bytes: &EphemeralKeyBytes, pk: &Recipient) -> Vec<u8> {
|
||||
fn salt(epk_bytes: &EphemeralKeyBytes, pk: p256::EncodedPoint) -> Vec<u8> {
|
||||
assert!(pk.is_compressed());
|
||||
let mut salt = vec![];
|
||||
salt.extend_from_slice(epk_bytes.as_bytes());
|
||||
salt.extend_from_slice(pk.to_encoded().as_bytes());
|
||||
salt.extend_from_slice(pk.as_bytes());
|
||||
salt
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user