ctap2-proto: Simplify authenticator::client_pin::auth_protocol traits

Rather than use manual lifetime management for PinUvAuthProtocol session
keys, change the auth_protocol::platform::Session trait to represent a
single Session, which maintains its own platform key agreement key, and
can be managed with the lifetime of the value itself.
main
Nick Zana 1 year ago
parent 941a5f3949
commit 795d356ab6

@ -1,8 +1,43 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait Authenticator {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(into = "u8", try_from = "u8")
)]
pub enum Version {
One = 1,
Two = 2,
}
impl From<Version> for u8 {
fn from(value: Version) -> Self {
value as u8
}
}
impl TryFrom<u8> for Version {
type Error = super::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Version::One),
2 => Ok(Version::Two),
_ => Err(super::Error::InvalidParameter),
}
}
}
/// The AES block size, in bytes.
pub const BLOCK_SIZE: usize = 16;
pub mod authenticator {
use super::Version;
pub trait Authenticator {
type Error; // TODO: Can the error cases be enumerated here?
const VERSION: Version;
/// This process is run by the authenticator at power-on.
fn initialize(&mut self) -> Result<(), Self::Error>;
@ -16,73 +51,53 @@ pub trait Authenticator {
/// Returns the authenticators public key as a COSE_Key structure.
fn get_public_key(&self) -> Result<cosey::PublicKey, Self::Error>;
/// Processes the output of encapsulate from the peer and produces a shared
/// secret, known to both platform and authenticator.
/// Processes the output of encapsulate from the peer and produces a
/// shared secret, known to both platform and authenticator.
fn decapsulate(&self, peer_cose_key: cosey::PublicKey) -> Result<Vec<u8>, Self::Error>;
/// Decrypts a ciphertext, using sharedSecret as a key, and returns the
/// plaintext.
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Self::Error>;
/// Verifies that the signature is a valid MAC for the given message. If the
/// key parameter value is the current pinUvAuthToken, it also checks
/// whether the pinUvAuthToken is in use or not.
/// Verifies that the signature is a valid MAC for the given message. If
/// the key parameter value is the current pinUvAuthToken, it
/// also checks whether the pinUvAuthToken is in use or not.
fn verify(&self, key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Self::Error>;
}
}
pub trait Platform {
pub mod platform {
use super::{Version, BLOCK_SIZE};
pub trait Session<const VERSION: Version>: Sized {
type Error; // TODO: Can the error cases be enumerated here?
/// This is run by the platform when starting a series of transactions
/// with a specific authenticator.
fn initialize(&self) -> Result<(), Self::Error>;
/// Generates an encapsulation for the authenticators public key and
/// returns the message to transmit and the shared secret.
fn encapsulate(
&self,
peer_cose_key: cosey::PublicKey,
) -> Result<(cosey::PublicKey, Vec<u8>), Self::Error>; // TODO: Return a struct for OK variant?
/// Encompasses both the `initialize` and `encapsulate` functions in the
/// platform interface of the spec. This is done to guard against
/// private key reuse by the platform. As a consequence, a new
/// session must be initialized for each transaction with a
/// freshly generated private key.
fn initialize(peer_cose_key: cosey::PublicKey) -> Result<Self, Self::Error>;
fn platform_key_agreement_key(&self) -> &cosey::PublicKey;
/// Encrypts a plaintext to produce a ciphertext, which may be longer
/// than the plaintext. The plaintext is restricted to being a
/// multiple of the AES block size (16 bytes) in length.
// TODO: Return a specific type instead of raw bytes?
fn encrypt(&self, key: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, Self::Error>;
fn encrypt<const N: usize>(
&self,
plaintext: &[[u8; BLOCK_SIZE]; N],
) -> Result<[[u8; BLOCK_SIZE]; N], Self::Error>;
/// Decrypts a ciphertext and returns the plaintext.
// TODO: Return a specific type instead of raw bytes?
fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Self::Error>;
fn decrypt<const N: usize>(
&self,
ciphertext: &[[u8; BLOCK_SIZE]; N],
) -> [[u8; BLOCK_SIZE]; N];
/// Computes a MAC of the given message.
// TODO: Return a specific type instead of raw bytes?
fn authenticate(&self, key: &[u8], message: &[u8]) -> Result<Vec<u8>, Self::Error>;
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(into = "u8", try_from = "u8")
)]
pub enum Version {
One = 1,
Two = 2,
}
impl From<Version> for u8 {
fn from(value: Version) -> Self {
value as u8
}
}
impl TryFrom<u8> for Version {
type Error = super::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Version::One),
2 => Ok(Version::Two),
_ => Err(super::Error::InvalidParameter),
}
fn authenticate(&self, message: &[u8]) -> Result<[u8; 16], Self::Error>;
}
}

Loading…
Cancel
Save