From 795d356ab66d00e15a1ced2e3d4e95415026cc80 Mon Sep 17 00:00:00 2001 From: Nick Zana Date: Tue, 13 Jun 2023 23:44:12 -0400 Subject: [PATCH] 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. --- .../authenticator/client_pin/auth_protocol.rs | 129 ++++++++++-------- 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs b/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs index 63436c7..342ceef 100644 --- a/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs +++ b/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs @@ -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 authenticator’s public key as a COSE_Key structure. - fn get_public_key(&self) -> Result; - - /// 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, Self::Error>; - - /// Decrypts a ciphertext, using sharedSecret as a key, and returns the - /// plaintext. - fn decrypt(&self, ciphertext: &[u8]) -> Result, 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 authenticator’s public key and - /// returns the message to transmit and the shared secret. - fn encapsulate( - &self, - peer_cose_key: cosey::PublicKey, - ) -> Result<(cosey::PublicKey, Vec), 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, 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, 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, Self::Error>; -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr( feature = "serde", @@ -86,3 +29,75 @@ impl TryFrom 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 authenticator’s public key as a COSE_Key structure. + fn get_public_key(&self) -> Result; + + /// 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, Self::Error>; + + /// Decrypts a ciphertext, using sharedSecret as a key, and returns the + /// plaintext. + fn decrypt(&self, ciphertext: &[u8]) -> Result, 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: 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; + + 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( + &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, + 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>; + } +}