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
|
### Changed
|
||||||
- MSRV is now 1.70.0.
|
- 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
|
## [0.5.0] - 2024-08-04
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
+8
-4
@@ -20,7 +20,9 @@ use yubikey::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fl, piv_p256,
|
fl,
|
||||||
|
native::p256tag,
|
||||||
|
piv_p256,
|
||||||
recipient::TAG_BYTES,
|
recipient::TAG_BYTES,
|
||||||
util::{otp_serial_prefix, Metadata},
|
util::{otp_serial_prefix, Metadata},
|
||||||
Recipient, IDENTITY_PREFIX,
|
Recipient, IDENTITY_PREFIX,
|
||||||
@@ -592,9 +594,10 @@ impl Stub {
|
|||||||
let (cert, pk) = match Certificate::read(&mut yubikey, SlotId::Retired(self.slot))
|
let (cert, pk) = match Certificate::read(&mut yubikey, SlotId::Retired(self.slot))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|cert| {
|
.and_then(|cert| {
|
||||||
piv_p256::Recipient::from_certificate(&cert)
|
// Parse as the preferred recipient for each identity type.
|
||||||
.filter(|pk| pk.tag() == self.tag)
|
p256tag::Recipient::from_certificate(&cert)
|
||||||
.map(|pk| (cert, Recipient::PivP256(pk)))
|
.filter(|pk| pk.static_tag() == self.tag)
|
||||||
|
.map(|pk| (cert, Recipient::P256Tag(pk)))
|
||||||
}) {
|
}) {
|
||||||
Some(pk) => pk,
|
Some(pk) => pk,
|
||||||
None => {
|
None => {
|
||||||
@@ -628,6 +631,7 @@ pub(crate) struct Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
|
/// Returns the preferred recipient for encrypting to this identity.
|
||||||
pub(crate) fn recipient(&self) -> &Recipient {
|
pub(crate) fn recipient(&self) -> &Recipient {
|
||||||
&self.pk
|
&self.pk
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use p256::{
|
|||||||
EncodedPoint,
|
EncodedPoint,
|
||||||
};
|
};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
use yubikey::{certificate::PublicKeyInfo, Certificate};
|
||||||
|
|
||||||
use super::{stanza_tag, YubiKeyKemPrivateKey};
|
use super::{stanza_tag, YubiKeyKemPrivateKey};
|
||||||
use crate::{
|
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] {
|
pub(crate) fn static_tag(&self) -> [u8; TAG_BYTES] {
|
||||||
static_tag(self.compressed.as_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 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 enc_key = {
|
||||||
let mut okm = [0; 32];
|
let mut okm = [0; 32];
|
||||||
@@ -138,13 +138,17 @@ impl Recipient {
|
|||||||
|
|
||||||
impl RecipientLine {
|
impl RecipientLine {
|
||||||
pub(crate) fn unwrap_file_key(&self, conn: &mut Connection) -> Result<FileKey, ()> {
|
pub(crate) fn unwrap_file_key(&self, conn: &mut Connection) -> Result<FileKey, ()> {
|
||||||
let recipient = match conn.recipient() {
|
let (static_tag, pk) = match conn.recipient() {
|
||||||
crate::recipient::Recipient::PivP256(recipient) => recipient,
|
crate::recipient::Recipient::PivP256(recipient) => {
|
||||||
_ => panic!("should have been filtered out earlier"),
|
(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
|
// The YubiKey API for performing scalar multiplication takes the point in its
|
||||||
// uncompressed SEC-1 encoding.
|
// 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![];
|
let mut salt = vec![];
|
||||||
salt.extend_from_slice(epk_bytes.as_bytes());
|
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
|
salt
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user