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,63 +1,6 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait Authenticator {
type Error; // TODO: Can the error cases be enumerated here?
/// This process is run by the authenticator at power-on.
fn initialize(&mut self) -> Result<(), Self::Error>;
/// Generates a fresh public key.
fn regenerate(&mut self) -> Result<(), Self::Error>;
/// Generates a fresh pinUvAuthToken.
fn reset_pin_uv_auth_token(&mut self) -> Result<(), Self::Error>;
/// 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.
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.
fn verify(&self, key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Self::Error>;
}
pub trait Platform {
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?
/// 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>;
/// 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>;
/// 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",
@ -86,3 +29,75 @@ impl TryFrom<u8> for Version {
}
}
}
/// 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>;
/// Generates a fresh public key.
fn regenerate(&mut self) -> Result<(), Self::Error>;
/// Generates a fresh pinUvAuthToken.
fn reset_pin_uv_auth_token(&mut self) -> Result<(), Self::Error>;
/// 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.
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.
fn verify(&self, key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Self::Error>;
}
}
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?
/// 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.
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<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, message: &[u8]) -> Result<[u8; 16], Self::Error>;
}
}

Loading…
Cancel
Save