Merge pull request #509 from ia0/keystore

Add a key store to avoid storing secrets in the store
This commit is contained in:
Julien Cretin
2022-07-01 14:31:10 +02:00
committed by GitHub
13 changed files with 355 additions and 204 deletions

149
src/api/key_store.rs Normal file
View File

@@ -0,0 +1,149 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use alloc::vec::Vec;
use crypto::ecdsa::SecKey;
use persistent_store::StoreError;
use rng256::Rng256;
use crate::env::Env;
/// Provides storage for secret keys.
///
/// Implementations may use the environment store: [`STORAGE_KEY`] is reserved for this usage.
pub trait KeyStore {
/// Returns the AES key for key handles encryption.
fn key_handle_encryption(&mut self) -> Result<[u8; 32], Error>;
/// Returns the key for key handles authentication.
fn key_handle_authentication(&mut self) -> Result<[u8; 32], Error>;
/// Derives an ECDSA private key from a seed.
///
/// The result is big-endian.
fn derive_ecdsa(&mut self, seed: &[u8; 32]) -> Result<[u8; 32], Error>;
/// Generates a seed to derive an ECDSA private key.
fn generate_ecdsa_seed(&mut self) -> Result<[u8; 32], Error>;
/// Resets the key store.
fn reset(&mut self) -> Result<(), Error>;
}
/// Key store errors.
///
/// They are deliberately indistinguishable to avoid leaking information.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Error;
/// Key of the environment store reserved for the key store.
pub const STORAGE_KEY: usize = 2046;
/// Implements a default key store using the environment rng and store.
pub trait Helper: Env {}
impl<T: Helper> KeyStore for T {
fn key_handle_encryption(&mut self) -> Result<[u8; 32], Error> {
Ok(get_master_keys(self)?.encryption)
}
fn key_handle_authentication(&mut self) -> Result<[u8; 32], Error> {
Ok(get_master_keys(self)?.authentication)
}
fn derive_ecdsa(&mut self, seed: &[u8; 32]) -> Result<[u8; 32], Error> {
match SecKey::from_bytes(seed) {
None => Err(Error),
Some(_) => Ok(*seed),
}
}
fn generate_ecdsa_seed(&mut self) -> Result<[u8; 32], Error> {
let mut seed = [0; 32];
SecKey::gensk(self.rng()).to_bytes(&mut seed);
Ok(seed)
}
fn reset(&mut self) -> Result<(), Error> {
Ok(self.store().remove(STORAGE_KEY)?)
}
}
/// Wrapper for master keys.
struct MasterKeys {
/// Master encryption key.
encryption: [u8; 32],
/// Master authentication key.
authentication: [u8; 32],
}
fn get_master_keys(env: &mut impl Env) -> Result<MasterKeys, Error> {
let master_keys = match env.store().find(STORAGE_KEY)? {
Some(x) => x,
None => {
let master_encryption_key = env.rng().gen_uniform_u8x32();
let master_authentication_key = env.rng().gen_uniform_u8x32();
let mut master_keys = Vec::with_capacity(64);
master_keys.extend_from_slice(&master_encryption_key);
master_keys.extend_from_slice(&master_authentication_key);
env.store().insert(STORAGE_KEY, &master_keys)?;
master_keys
}
};
if master_keys.len() != 64 {
return Err(Error);
}
Ok(MasterKeys {
encryption: *array_ref![master_keys, 0, 32],
authentication: *array_ref![master_keys, 32, 32],
})
}
impl From<StoreError> for Error {
fn from(_: StoreError) -> Self {
Error
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_key_store() {
let mut env = crate::env::test::TestEnv::new();
let key_store = env.key_store();
// Master keys are well-defined and stable.
let encryption_key = key_store.key_handle_encryption().unwrap();
let authentication_key = key_store.key_handle_authentication().unwrap();
assert_eq!(key_store.key_handle_encryption(), Ok(encryption_key));
assert_eq!(
key_store.key_handle_authentication(),
Ok(authentication_key)
);
// ECDSA seeds are well-defined and stable.
let ecdsa_seed = key_store.generate_ecdsa_seed().unwrap();
let ecdsa_key = key_store.derive_ecdsa(&ecdsa_seed).unwrap();
assert_eq!(key_store.derive_ecdsa(&ecdsa_seed), Ok(ecdsa_key));
// Master keys change after reset. We don't require this for ECDSA seeds because it's not
// the case, but it might be better.
key_store.reset().unwrap();
assert!(key_store.key_handle_encryption().unwrap() != encryption_key);
assert!(key_store.key_handle_authentication().unwrap() != authentication_key);
}
}

View File

@@ -20,5 +20,6 @@
pub mod connection; pub mod connection;
pub mod customization; pub mod customization;
pub mod firmware_protection; pub mod firmware_protection;
pub mod key_store;
pub mod upgrade_storage; pub mod upgrade_storage;
pub mod user_presence; pub mod user_presence;

View File

@@ -64,6 +64,7 @@ fn enumerate_rps_response(
/// Generates the response for subcommands enumerating credentials. /// Generates the response for subcommands enumerating credentials.
fn enumerate_credentials_response( fn enumerate_credentials_response(
env: &mut impl Env,
credential: PublicKeyCredentialSource, credential: PublicKeyCredentialSource,
total_credentials: Option<u64>, total_credentials: Option<u64>,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
@@ -92,7 +93,7 @@ fn enumerate_credentials_response(
key_id: credential_id, key_id: credential_id,
transports: None, // You can set USB as a hint here. transports: None, // You can set USB as a hint here.
}; };
let public_key = private_key.get_pub_key(); let public_key = private_key.get_pub_key(env)?;
Ok(AuthenticatorCredentialManagementResponse { Ok(AuthenticatorCredentialManagementResponse {
user: Some(user), user: Some(user),
credential_id: Some(credential_id), credential_id: Some(credential_id),
@@ -207,7 +208,7 @@ fn process_enumerate_credentials_begin(
channel, channel,
); );
} }
enumerate_credentials_response(credential, Some(total_credentials as u64)) enumerate_credentials_response(env, credential, Some(total_credentials as u64))
} }
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement. /// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
@@ -217,7 +218,7 @@ fn process_enumerate_credentials_get_next_credential(
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
let credential_key = stateful_command_permission.next_enumerate_credential()?; let credential_key = stateful_command_permission.next_enumerate_credential()?;
let credential = storage::get_credential(env, credential_key)?; let credential = storage::get_credential(env, credential_key)?;
enumerate_credentials_response(credential, None) enumerate_credentials_response(env, credential, None)
} }
/// Processes the subcommand deleteCredential for CredentialManagement. /// Processes the subcommand deleteCredential for CredentialManagement.
@@ -369,12 +370,12 @@ mod test {
const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]); const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);
fn create_credential_source(rng: &mut impl Rng256) -> PublicKeyCredentialSource { fn create_credential_source(env: &mut TestEnv) -> PublicKeyCredentialSource {
let private_key = crypto::ecdsa::SecKey::gensk(rng); let private_key = PrivateKey::new_ecdsa(env);
PublicKeyCredentialSource { PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: rng.gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x01], user_handle: vec![0x01],
user_display_name: Some("display_name".to_string()), user_display_name: Some("display_name".to_string()),
@@ -393,7 +394,7 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
let credential_source = create_credential_source(env.rng()); let credential_source = create_credential_source(&mut env);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
ctap_state.client_pin = client_pin; ctap_state.client_pin = client_pin;
@@ -475,8 +476,8 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let credential_source1 = create_credential_source(env.rng()); let credential_source1 = create_credential_source(&mut env);
let mut credential_source2 = create_credential_source(env.rng()); let mut credential_source2 = create_credential_source(&mut env);
credential_source2.rp_id = "another.example.com".to_string(); credential_source2.rp_id = "another.example.com".to_string();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
@@ -569,7 +570,7 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let credential_source = create_credential_source(env.rng()); let credential_source = create_credential_source(&mut env);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
ctap_state.client_pin = client_pin; ctap_state.client_pin = client_pin;
@@ -650,8 +651,8 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let credential_source1 = create_credential_source(env.rng()); let credential_source1 = create_credential_source(&mut env);
let mut credential_source2 = create_credential_source(env.rng()); let mut credential_source2 = create_credential_source(&mut env);
credential_source2.user_handle = vec![0x02]; credential_source2.user_handle = vec![0x02];
credential_source2.user_name = Some("user2".to_string()); credential_source2.user_name = Some("user2".to_string());
credential_source2.user_display_name = Some("User Two".to_string()); credential_source2.user_display_name = Some("User Two".to_string());
@@ -752,7 +753,7 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let mut credential_source = create_credential_source(env.rng()); let mut credential_source = create_credential_source(&mut env);
credential_source.credential_id = vec![0x1D; 32]; credential_source.credential_id = vec![0x1D; 32];
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
@@ -822,7 +823,7 @@ mod test {
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let mut credential_source = create_credential_source(env.rng()); let mut credential_source = create_credential_source(&mut env);
credential_source.credential_id = vec![0x1D; 32]; credential_source.credential_id = vec![0x1D; 32];
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::api::key_store::KeyStore;
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
use crate::ctap::data_formats::EDDSA_ALGORITHM; use crate::ctap::data_formats::EDDSA_ALGORITHM;
use crate::ctap::data_formats::{ use crate::ctap::data_formats::{
@@ -19,7 +20,6 @@ use crate::ctap::data_formats::{
PublicKeyCredentialType, SignatureAlgorithm, ES256_ALGORITHM, PublicKeyCredentialType, SignatureAlgorithm, ES256_ALGORITHM,
}; };
use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::status_code::Ctap2StatusCode;
use crate::ctap::storage;
use crate::env::Env; use crate::env::Env;
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::vec;
@@ -101,7 +101,9 @@ pub fn aes256_cbc_decrypt(
// We shouldn't compare private keys in prod without constant-time operations. // We shouldn't compare private keys in prod without constant-time operations.
#[cfg_attr(test, derive(PartialEq, Eq))] #[cfg_attr(test, derive(PartialEq, Eq))]
pub enum PrivateKey { pub enum PrivateKey {
Ecdsa(ecdsa::SecKey), // We store the seed instead of the key since we can't get the seed back from the key. We could
// store both if we believe deriving the key is done more than once and costly.
Ecdsa([u8; 32]),
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
Ed25519(ed25519_compact::SecretKey), Ed25519(ed25519_compact::SecretKey),
} }
@@ -112,18 +114,25 @@ impl PrivateKey {
/// # Panics /// # Panics
/// ///
/// Panics if the algorithm is [`SignatureAlgorithm::Unknown`]. /// Panics if the algorithm is [`SignatureAlgorithm::Unknown`].
pub fn new(rng: &mut impl Rng256, alg: SignatureAlgorithm) -> Self { pub fn new(env: &mut impl Env, alg: SignatureAlgorithm) -> Self {
match alg { match alg {
SignatureAlgorithm::ES256 => PrivateKey::Ecdsa(crypto::ecdsa::SecKey::gensk(rng)), SignatureAlgorithm::ES256 => {
PrivateKey::Ecdsa(env.key_store().generate_ecdsa_seed().unwrap())
}
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
SignatureAlgorithm::EDDSA => { SignatureAlgorithm::EDDSA => {
let bytes = rng.gen_uniform_u8x32(); let bytes = env.rng().gen_uniform_u8x32();
Self::new_ed25519_from_bytes(&bytes).unwrap() Self::new_ed25519_from_bytes(&bytes).unwrap()
} }
SignatureAlgorithm::Unknown => unreachable!(), SignatureAlgorithm::Unknown => unreachable!(),
} }
} }
/// Creates a new ecdsa private key.
pub fn new_ecdsa(env: &mut impl Env) -> PrivateKey {
Self::new(env, SignatureAlgorithm::ES256)
}
/// Helper function that creates a private key of type ECDSA. /// Helper function that creates a private key of type ECDSA.
/// ///
/// This function is public for legacy credential source parsing only. /// This function is public for legacy credential source parsing only.
@@ -131,7 +140,7 @@ impl PrivateKey {
if bytes.len() != 32 { if bytes.len() != 32 {
return None; return None;
} }
ecdsa::SecKey::from_bytes(array_ref!(bytes, 0, 32)).map(PrivateKey::from) Some(PrivateKey::Ecdsa(*array_ref!(bytes, 0, 32)))
} }
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
@@ -143,22 +152,39 @@ impl PrivateKey {
Some(Self::Ed25519(ed25519_compact::KeyPair::from_seed(seed).sk)) Some(Self::Ed25519(ed25519_compact::KeyPair::from_seed(seed).sk))
} }
/// Returns the corresponding public key. /// Returns the ECDSA private key.
pub fn get_pub_key(&self) -> CoseKey { pub fn ecdsa_key(&self, env: &mut impl Env) -> Result<ecdsa::SecKey, Ctap2StatusCode> {
match self { match self {
PrivateKey::Ecdsa(ecdsa_key) => CoseKey::from(ecdsa_key.genpk()), PrivateKey::Ecdsa(seed) => ecdsa_key_from_seed(env, seed),
#[cfg(feature = "ed25519")] #[allow(unreachable_patterns)]
PrivateKey::Ed25519(ed25519_key) => CoseKey::from(ed25519_key.public_key()), _ => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR),
} }
} }
/// Returns the corresponding public key.
pub fn get_pub_key(&self, env: &mut impl Env) -> Result<CoseKey, Ctap2StatusCode> {
Ok(match self {
PrivateKey::Ecdsa(ecdsa_seed) => {
CoseKey::from(ecdsa_key_from_seed(env, ecdsa_seed)?.genpk())
}
#[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => CoseKey::from(ed25519_key.public_key()),
})
}
/// Returns the encoded signature for a given message. /// Returns the encoded signature for a given message.
pub fn sign_and_encode(&self, message: &[u8]) -> Vec<u8> { pub fn sign_and_encode(
match self { &self,
PrivateKey::Ecdsa(ecdsa_key) => ecdsa_key.sign_rfc6979::<Sha256>(message).to_asn1_der(), env: &mut impl Env,
message: &[u8],
) -> Result<Vec<u8>, Ctap2StatusCode> {
Ok(match self {
PrivateKey::Ecdsa(ecdsa_seed) => ecdsa_key_from_seed(env, ecdsa_seed)?
.sign_rfc6979::<Sha256>(message)
.to_asn1_der(),
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => ed25519_key.sign(message, None).to_vec(), PrivateKey::Ed25519(ed25519_key) => ed25519_key.sign(message, None).to_vec(),
} })
} }
/// The associated COSE signature algorithm identifier. /// The associated COSE signature algorithm identifier.
@@ -173,17 +199,21 @@ impl PrivateKey {
/// Writes the key bytes. /// Writes the key bytes.
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
match self { match self {
PrivateKey::Ecdsa(ecdsa_key) => { PrivateKey::Ecdsa(ecdsa_seed) => ecdsa_seed.to_vec(),
let mut key_bytes = vec![0u8; 32];
ecdsa_key.to_bytes(array_mut_ref!(key_bytes, 0, 32));
key_bytes
}
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => ed25519_key.seed().to_vec(), PrivateKey::Ed25519(ed25519_key) => ed25519_key.seed().to_vec(),
} }
} }
} }
fn ecdsa_key_from_seed(
env: &mut impl Env,
seed: &[u8; 32],
) -> Result<ecdsa::SecKey, Ctap2StatusCode> {
let ecdsa_bytes = env.key_store().derive_ecdsa(seed)?;
Ok(ecdsa::SecKey::from_bytes(&ecdsa_bytes).unwrap())
}
impl From<PrivateKey> for cbor::Value { impl From<PrivateKey> for cbor::Value {
fn from(private_key: PrivateKey) -> Self { fn from(private_key: PrivateKey) -> Self {
cbor_array![ cbor_array![
@@ -213,12 +243,6 @@ impl TryFrom<cbor::Value> for PrivateKey {
} }
} }
impl From<ecdsa::SecKey> for PrivateKey {
fn from(ecdsa_key: ecdsa::SecKey) -> Self {
PrivateKey::Ecdsa(ecdsa_key)
}
}
/// Encrypts the given private key and relying party ID hash into a credential ID. /// Encrypts the given private key and relying party ID hash into a credential ID.
/// ///
/// Other information, such as a user name, are not stored. Since encrypted credential IDs are /// Other information, such as a user name, are not stored. Since encrypted credential IDs are
@@ -245,13 +269,12 @@ pub fn encrypt_key_handle(
private_key: &PrivateKey, private_key: &PrivateKey,
application: &[u8; 32], application: &[u8; 32],
) -> Result<Vec<u8>, Ctap2StatusCode> { ) -> Result<Vec<u8>, Ctap2StatusCode> {
let master_keys = storage::master_keys(env)?; let aes_enc_key = crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
let aes_enc_key = crypto::aes256::EncryptionKey::new(&master_keys.encryption);
let mut plaintext = [0; 64]; let mut plaintext = [0; 64];
let version = match private_key { let version = match private_key {
PrivateKey::Ecdsa(ecdsa_key) => { PrivateKey::Ecdsa(ecdsa_seed) => {
ecdsa_key.to_bytes(array_mut_ref!(plaintext, 0, 32)); plaintext[..32].copy_from_slice(ecdsa_seed);
ECDSA_CREDENTIAL_ID_VERSION ECDSA_CREDENTIAL_ID_VERSION
} }
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
@@ -265,7 +288,10 @@ pub fn encrypt_key_handle(
let mut encrypted_id = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true)?; let mut encrypted_id = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true)?;
encrypted_id.insert(0, version); encrypted_id.insert(0, version);
let id_hmac = hmac_256::<Sha256>(&master_keys.hmac, &encrypted_id[..]); let id_hmac = hmac_256::<Sha256>(
&env.key_store().key_handle_authentication()?,
&encrypted_id[..],
);
encrypted_id.extend(&id_hmac); encrypted_id.extend(&id_hmac);
Ok(encrypted_id) Ok(encrypted_id)
} }
@@ -289,10 +315,9 @@ pub fn decrypt_credential_source(
if credential_id.len() < LEGACY_CREDENTIAL_ID_SIZE { if credential_id.len() < LEGACY_CREDENTIAL_ID_SIZE {
return Ok(None); return Ok(None);
} }
let master_keys = storage::master_keys(env)?;
let hmac_message_size = credential_id.len() - 32; let hmac_message_size = credential_id.len() - 32;
if !verify_hmac_256::<Sha256>( if !verify_hmac_256::<Sha256>(
&master_keys.hmac, &env.key_store().key_handle_authentication()?,
&credential_id[..hmac_message_size], &credential_id[..hmac_message_size],
array_ref![credential_id, hmac_message_size, 32], array_ref![credential_id, hmac_message_size, 32],
) { ) {
@@ -316,7 +341,7 @@ pub fn decrypt_credential_source(
return Ok(None); return Ok(None);
} }
let aes_enc_key = crypto::aes256::EncryptionKey::new(&master_keys.encryption); let aes_enc_key = crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
let decrypted_id = aes256_cbc_decrypt(&aes_enc_key, payload, true)?; let decrypted_id = aes256_cbc_decrypt(&aes_enc_key, payload, true)?;
if rp_id_hash != &decrypted_id[32..] { if rp_id_hash != &decrypted_id[32..] {
@@ -418,7 +443,7 @@ mod test {
#[test] #[test]
fn test_new_ecdsa_from_bytes() { fn test_new_ecdsa_from_bytes() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let key_bytes = private_key.to_bytes(); let key_bytes = private_key.to_bytes();
assert_eq!( assert_eq!(
PrivateKey::new_ecdsa_from_bytes(&key_bytes), PrivateKey::new_ecdsa_from_bytes(&key_bytes),
@@ -430,7 +455,7 @@ mod test {
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
fn test_new_ed25519_from_bytes() { fn test_new_ed25519_from_bytes() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::EDDSA); let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::EDDSA);
let key_bytes = private_key.to_bytes(); let key_bytes = private_key.to_bytes();
assert_eq!( assert_eq!(
PrivateKey::new_ed25519_from_bytes(&key_bytes), PrivateKey::new_ed25519_from_bytes(&key_bytes),
@@ -458,25 +483,31 @@ mod test {
#[test] #[test]
fn test_private_key_get_pub_key() { fn test_private_key_get_pub_key() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
let public_key = ecdsa_key.genpk(); let public_key = ecdsa_key.genpk();
let private_key = PrivateKey::from(ecdsa_key); assert_eq!(
assert_eq!(private_key.get_pub_key(), CoseKey::from(public_key)); private_key.get_pub_key(&mut env),
Ok(CoseKey::from(public_key))
);
} }
#[test] #[test]
fn test_private_key_sign_and_encode() { fn test_private_key_sign_and_encode() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let message = [0x5A; 32]; let message = [0x5A; 32];
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
let signature = ecdsa_key.sign_rfc6979::<Sha256>(&message).to_asn1_der(); let signature = ecdsa_key.sign_rfc6979::<Sha256>(&message).to_asn1_der();
let private_key = PrivateKey::from(ecdsa_key); assert_eq!(
assert_eq!(private_key.sign_and_encode(&message), signature); private_key.sign_and_encode(&mut env, &message),
Ok(signature)
);
} }
fn test_private_key_signature_algorithm(signature_algorithm: SignatureAlgorithm) { fn test_private_key_signature_algorithm(signature_algorithm: SignatureAlgorithm) {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = PrivateKey::new(env.rng(), signature_algorithm); let private_key = PrivateKey::new(&mut env, signature_algorithm);
assert_eq!(private_key.signature_algorithm(), signature_algorithm); assert_eq!(private_key.signature_algorithm(), signature_algorithm);
} }
@@ -493,7 +524,7 @@ mod test {
fn test_private_key_from_to_cbor(signature_algorithm: SignatureAlgorithm) { fn test_private_key_from_to_cbor(signature_algorithm: SignatureAlgorithm) {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = PrivateKey::new(env.rng(), signature_algorithm); let private_key = PrivateKey::new(&mut env, signature_algorithm);
let cbor = cbor::Value::from(private_key.clone()); let cbor = cbor::Value::from(private_key.clone());
assert_eq!(PrivateKey::try_from(cbor), Ok(private_key),); assert_eq!(PrivateKey::try_from(cbor), Ok(private_key),);
} }
@@ -548,8 +579,7 @@ mod test {
fn test_encrypt_decrypt_credential(signature_algorithm: SignatureAlgorithm) { fn test_encrypt_decrypt_credential(signature_algorithm: SignatureAlgorithm) {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new(&mut env, signature_algorithm);
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap(); let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
@@ -574,16 +604,15 @@ mod test {
#[test] #[test]
fn test_encrypt_decrypt_bad_version() { fn test_encrypt_decrypt_bad_version() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256);
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let mut encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap(); let mut encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
encrypted_id[0] = UNSUPPORTED_CREDENTIAL_ID_VERSION; encrypted_id[0] = UNSUPPORTED_CREDENTIAL_ID_VERSION;
// Override the HMAC to pass the check. // Override the HMAC to pass the check.
encrypted_id.truncate(&encrypted_id.len() - 32); encrypted_id.truncate(&encrypted_id.len() - 32);
let master_keys = storage::master_keys(&mut env).unwrap(); let hmac_key = env.key_store().key_handle_authentication().unwrap();
let id_hmac = hmac_256::<Sha256>(&master_keys.hmac, &encrypted_id[..]); let id_hmac = hmac_256::<Sha256>(&hmac_key, &encrypted_id[..]);
encrypted_id.extend(&id_hmac); encrypted_id.extend(&id_hmac);
assert_eq!( assert_eq!(
@@ -594,8 +623,7 @@ mod test {
fn test_encrypt_decrypt_bad_hmac(signature_algorithm: SignatureAlgorithm) { fn test_encrypt_decrypt_bad_hmac(signature_algorithm: SignatureAlgorithm) {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new(&mut env, signature_algorithm);
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap(); let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
@@ -622,8 +650,7 @@ mod test {
fn test_decrypt_credential_missing_blocks(signature_algorithm: SignatureAlgorithm) { fn test_decrypt_credential_missing_blocks(signature_algorithm: SignatureAlgorithm) {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new(&mut env, signature_algorithm);
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap(); let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
@@ -653,14 +680,17 @@ mod test {
private_key: crypto::ecdsa::SecKey, private_key: crypto::ecdsa::SecKey,
application: &[u8; 32], application: &[u8; 32],
) -> Result<Vec<u8>, Ctap2StatusCode> { ) -> Result<Vec<u8>, Ctap2StatusCode> {
let master_keys = storage::master_keys(env)?; let aes_enc_key =
let aes_enc_key = crypto::aes256::EncryptionKey::new(&master_keys.encryption); crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
let mut plaintext = [0; 64]; let mut plaintext = [0; 64];
private_key.to_bytes(array_mut_ref!(plaintext, 0, 32)); private_key.to_bytes(array_mut_ref!(plaintext, 0, 32));
plaintext[32..64].copy_from_slice(application); plaintext[32..64].copy_from_slice(application);
let mut encrypted_id = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true)?; let mut encrypted_id = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true)?;
let id_hmac = hmac_256::<Sha256>(&master_keys.hmac, &encrypted_id[..]); let id_hmac = hmac_256::<Sha256>(
&env.key_store().key_handle_authentication()?,
&encrypted_id[..],
);
encrypted_id.extend(&id_hmac); encrypted_id.extend(&id_hmac);
Ok(encrypted_id) Ok(encrypted_id)
} }
@@ -668,9 +698,8 @@ mod test {
#[test] #[test]
fn test_encrypt_decrypt_credential_legacy() { fn test_encrypt_decrypt_credential_legacy() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new_ecdsa(&mut env);
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng()); let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
let private_key = PrivateKey::from(ecdsa_key.clone());
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let encrypted_id = legacy_encrypt_key_handle(&mut env, ecdsa_key, &rp_id_hash).unwrap(); let encrypted_id = legacy_encrypt_key_handle(&mut env, ecdsa_key, &rp_id_hash).unwrap();
@@ -684,8 +713,7 @@ mod test {
#[test] #[test]
fn test_encrypt_credential_size() { fn test_encrypt_credential_size() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
storage::init(&mut env).ok().unwrap(); let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256);
let rp_id_hash = [0x55; 32]; let rp_id_hash = [0x55; 32];
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap(); let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();

View File

@@ -245,9 +245,12 @@ impl Ctap1Command {
challenge: [u8; 32], challenge: [u8; 32],
application: [u8; 32], application: [u8; 32],
) -> Result<Vec<u8>, Ctap1StatusCode> { ) -> Result<Vec<u8>, Ctap1StatusCode> {
let sk = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(env);
let sk = private_key
.ecdsa_key(env)
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
let pk = sk.genpk(); let pk = sk.genpk();
let key_handle = encrypt_key_handle(env, &PrivateKey::from(sk), &application) let key_handle = encrypt_key_handle(env, &private_key, &application)
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?; .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
if key_handle.len() > 0xFF { if key_handle.len() > 0xFF {
// This is just being defensive with unreachable code. // This is just being defensive with unreachable code.
@@ -309,12 +312,10 @@ impl Ctap1Command {
let credential_source = decrypt_credential_source(env, key_handle, &application) let credential_source = decrypt_credential_source(env, key_handle, &application)
.map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?; .map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
if let Some(credential_source) = credential_source { if let Some(credential_source) = credential_source {
// CTAP1 only supports ECDSA, the default case applies if CTAP2 adds more algorithms. let ecdsa_key = credential_source
#[allow(unreachable_patterns)] .private_key
let ecdsa_key = match credential_source.private_key { .ecdsa_key(env)
PrivateKey::Ecdsa(k) => k, .map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
_ => return Err(Ctap1StatusCode::SW_WRONG_DATA),
};
if flags == Ctap1Flags::CheckOnly { if flags == Ctap1Flags::CheckOnly {
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED); return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
} }
@@ -501,7 +502,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -519,7 +520,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -538,7 +539,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -576,7 +577,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -596,7 +597,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -616,7 +617,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -644,7 +645,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";
@@ -672,7 +673,7 @@ mod test {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
env.user_presence() env.user_presence()
.set(|| panic!("Unexpected user presence check in CTAP1")); .set(|| panic!("Unexpected user presence check in CTAP1"));
let sk = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256); let sk = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let rp_id = "example.com"; let rp_id = "example.com";

View File

@@ -2215,11 +2215,11 @@ mod test {
#[test] #[test]
fn test_credential_source_cbor_round_trip() { fn test_credential_source_cbor_round_trip() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: "example.com".to_string(), rp_id: "example.com".to_string(),
user_handle: b"foo".to_vec(), user_handle: b"foo".to_vec(),
user_display_name: None, user_display_name: None,
@@ -2300,13 +2300,12 @@ mod test {
#[test] #[test]
fn test_credential_source_cbor_read_legacy() { fn test_credential_source_cbor_read_legacy() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let mut key_bytes = [0u8; 32]; let key_bytes = private_key.to_bytes();
private_key.to_bytes(&mut key_bytes);
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: "example.com".to_string(), rp_id: "example.com".to_string(),
user_handle: b"foo".to_vec(), user_handle: b"foo".to_vec(),
user_display_name: None, user_display_name: None,
@@ -2333,13 +2332,12 @@ mod test {
#[test] #[test]
fn test_credential_source_cbor_legacy_error() { fn test_credential_source_cbor_legacy_error() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let mut key_bytes = [0u8; 32]; let key_bytes = private_key.to_bytes();
private_key.to_bytes(&mut key_bytes);
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key.clone()), private_key: private_key.clone(),
rp_id: "example.com".to_string(), rp_id: "example.com".to_string(),
user_handle: b"foo".to_vec(), user_handle: b"foo".to_vec(),
user_display_name: None, user_display_name: None,
@@ -2366,7 +2364,7 @@ mod test {
PublicKeyCredentialSourceField::EcdsaPrivateKey => key_bytes, PublicKeyCredentialSourceField::EcdsaPrivateKey => key_bytes,
PublicKeyCredentialSourceField::RpId => credential.rp_id, PublicKeyCredentialSourceField::RpId => credential.rp_id,
PublicKeyCredentialSourceField::UserHandle => credential.user_handle, PublicKeyCredentialSourceField::UserHandle => credential.user_handle,
PublicKeyCredentialSourceField::PrivateKey => PrivateKey::from(private_key), PublicKeyCredentialSourceField::PrivateKey => private_key,
}; };
assert_eq!( assert_eq!(
PublicKeyCredentialSource::try_from(source_cbor), PublicKeyCredentialSource::try_from(source_cbor),

View File

@@ -853,7 +853,7 @@ impl CtapState {
// We decide on the algorithm early, but delay key creation since it takes time. // We decide on the algorithm early, but delay key creation since it takes time.
// We rather do that later so all intermediate checks may return faster. // We rather do that later so all intermediate checks may return faster.
let private_key = PrivateKey::new(env.rng(), algorithm); let private_key = PrivateKey::new(env, algorithm);
let credential_id = if options.rk { let credential_id = if options.rk {
let random_id = env.rng().gen_uniform_u8x32().to_vec(); let random_id = env.rng().gen_uniform_u8x32().to_vec();
let credential_source = PublicKeyCredentialSource { let credential_source = PublicKeyCredentialSource {
@@ -892,7 +892,7 @@ impl CtapState {
} }
auth_data.extend(vec![0x00, credential_id.len() as u8]); auth_data.extend(vec![0x00, credential_id.len() as u8]);
auth_data.extend(&credential_id); auth_data.extend(&credential_id);
let public_cose_key = private_key.get_pub_key(); let public_cose_key = private_key.get_pub_key(env)?;
cbor_write(cbor::Value::from(public_cose_key), &mut auth_data)?; cbor_write(cbor::Value::from(public_cose_key), &mut auth_data)?;
if has_extension_output { if has_extension_output {
let hmac_secret_output = if extensions.hmac_secret { let hmac_secret_output = if extensions.hmac_secret {
@@ -932,7 +932,7 @@ impl CtapState {
Some(vec![attestation_certificate]), Some(vec![attestation_certificate]),
) )
} else { } else {
(private_key.sign_and_encode(&signature_data), None) (private_key.sign_and_encode(env, &signature_data)?, None)
}; };
let attestation_statement = PackedAttestationStatement { let attestation_statement = PackedAttestationStatement {
alg: SignatureAlgorithm::ES256 as i64, alg: SignatureAlgorithm::ES256 as i64,
@@ -1014,7 +1014,9 @@ impl CtapState {
let mut signature_data = auth_data.clone(); let mut signature_data = auth_data.clone();
signature_data.extend(client_data_hash); signature_data.extend(client_data_hash);
let signature = credential.private_key.sign_and_encode(&signature_data); let signature = credential
.private_key
.sign_and_encode(env, &signature_data)?;
let cred_desc = PublicKeyCredentialDescriptor { let cred_desc = PublicKeyCredentialDescriptor {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
@@ -1720,7 +1722,7 @@ mod test {
#[test] #[test]
fn test_process_make_credential_credential_excluded() { fn test_process_make_credential_credential_excluded() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let excluded_private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let excluded_private_key = PrivateKey::new_ecdsa(&mut env);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let excluded_credential_id = vec![0x01, 0x23, 0x45, 0x67]; let excluded_credential_id = vec![0x01, 0x23, 0x45, 0x67];
@@ -1729,7 +1731,7 @@ mod test {
let excluded_credential_source = PublicKeyCredentialSource { let excluded_credential_source = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: excluded_credential_id, credential_id: excluded_credential_id,
private_key: PrivateKey::from(excluded_private_key), private_key: excluded_private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![], user_handle: vec![],
user_display_name: None, user_display_name: None,
@@ -2538,7 +2540,7 @@ mod test {
#[test] #[test]
fn test_resident_process_get_assertion_with_cred_protect() { fn test_resident_process_get_assertion_with_cred_protect() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential_id = env.rng().gen_uniform_u8x32().to_vec(); let credential_id = env.rng().gen_uniform_u8x32().to_vec();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
@@ -2550,7 +2552,7 @@ mod test {
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: credential_id.clone(), credential_id: credential_id.clone(),
private_key: PrivateKey::from(private_key.clone()), private_key: private_key.clone(),
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x1D], user_handle: vec![0x1D],
user_display_name: None, user_display_name: None,
@@ -2612,7 +2614,7 @@ mod test {
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id, credential_id,
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x1D], user_handle: vec![0x1D],
user_display_name: None, user_display_name: None,
@@ -2652,14 +2654,14 @@ mod test {
#[test] #[test]
fn test_process_get_assertion_with_cred_blob() { fn test_process_get_assertion_with_cred_blob() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential_id = env.rng().gen_uniform_u8x32().to_vec(); let credential_id = env.rng().gen_uniform_u8x32().to_vec();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id, credential_id,
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x1D], user_handle: vec![0x1D],
user_display_name: None, user_display_name: None,
@@ -2710,14 +2712,14 @@ mod test {
#[test] #[test]
fn test_process_get_assertion_with_large_blob_key() { fn test_process_get_assertion_with_large_blob_key() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential_id = env.rng().gen_uniform_u8x32().to_vec(); let credential_id = env.rng().gen_uniform_u8x32().to_vec();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id, credential_id,
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x1D], user_handle: vec![0x1D],
user_display_name: None, user_display_name: None,
@@ -2996,14 +2998,14 @@ mod test {
#[test] #[test]
fn test_process_reset() { fn test_process_reset() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let credential_id = vec![0x01, 0x23, 0x45, 0x67]; let credential_id = vec![0x01, 0x23, 0x45, 0x67];
let credential_source = PublicKeyCredentialSource { let credential_source = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id, credential_id,
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![], user_handle: vec![],
user_display_name: None, user_display_name: None,
@@ -3501,11 +3503,11 @@ mod test {
let client_pin = let client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential_source = PublicKeyCredentialSource { let credential_source = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x01], user_handle: vec![0x01],
user_display_name: Some("display_name".to_string()), user_display_name: Some("display_name".to_string()),

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::api::key_store;
use crate::api::user_presence::UserPresenceError; use crate::api::user_presence::UserPresenceError;
// CTAP specification (version 20190130) section 6.3 // CTAP specification (version 20190130) section 6.3
@@ -93,3 +94,9 @@ impl From<UserPresenceError> for Ctap2StatusCode {
} }
} }
} }
impl From<key_store::Error> for Ctap2StatusCode {
fn from(_: key_store::Error) -> Self {
Self::CTAP2_ERR_VENDOR_INTERNAL_ERROR
}
}

View File

@@ -15,6 +15,7 @@
mod key; mod key;
use crate::api::customization::Customization; use crate::api::customization::Customization;
use crate::api::key_store::KeyStore;
use crate::ctap::client_pin::PIN_AUTH_LENGTH; use crate::ctap::client_pin::PIN_AUTH_LENGTH;
use crate::ctap::data_formats::{ use crate::ctap::data_formats::{
extract_array, extract_text_string, CredentialProtectionPolicy, PublicKeyCredentialSource, extract_array, extract_text_string, CredentialProtectionPolicy, PublicKeyCredentialSource,
@@ -33,15 +34,6 @@ use persistent_store::{fragment, StoreUpdate};
use rng256::Rng256; use rng256::Rng256;
use sk_cbor::cbor_array_vec; use sk_cbor::cbor_array_vec;
/// Wrapper for master keys.
pub struct MasterKeys {
/// Master encryption key.
pub encryption: [u8; 32],
/// Master hmac key.
pub hmac: [u8; 32],
}
/// Wrapper for PIN properties. /// Wrapper for PIN properties.
struct PinProperties { struct PinProperties {
/// 16 byte prefix of SHA256 of the currently set PIN. /// 16 byte prefix of SHA256 of the currently set PIN.
@@ -53,16 +45,6 @@ struct PinProperties {
/// Initializes the store by creating missing objects. /// Initializes the store by creating missing objects.
pub fn init(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { pub fn init(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
// Generate and store the master keys if they are missing.
if env.store().find_handle(key::MASTER_KEYS)?.is_none() {
let master_encryption_key = env.rng().gen_uniform_u8x32();
let master_hmac_key = env.rng().gen_uniform_u8x32();
let mut master_keys = Vec::with_capacity(64);
master_keys.extend_from_slice(&master_encryption_key);
master_keys.extend_from_slice(&master_hmac_key);
env.store().insert(key::MASTER_KEYS, &master_keys)?;
}
// Generate and store the CredRandom secrets if they are missing. // Generate and store the CredRandom secrets if they are missing.
if env.store().find_handle(key::CRED_RANDOM_SECRET)?.is_none() { if env.store().find_handle(key::CRED_RANDOM_SECRET)?.is_none() {
let cred_random_with_uv = env.rng().gen_uniform_u8x32(); let cred_random_with_uv = env.rng().gen_uniform_u8x32();
@@ -280,21 +262,6 @@ pub fn incr_global_signature_counter(
Ok(()) Ok(())
} }
/// Returns the master keys.
pub fn master_keys(env: &mut impl Env) -> Result<MasterKeys, Ctap2StatusCode> {
let master_keys = env
.store()
.find(key::MASTER_KEYS)?
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
if master_keys.len() != 64 {
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
}
Ok(MasterKeys {
encryption: *array_ref![master_keys, 0, 32],
hmac: *array_ref![master_keys, 32, 32],
})
}
/// Returns the CredRandom secret. /// Returns the CredRandom secret.
pub fn cred_random_secret(env: &mut impl Env, has_uv: bool) -> Result<[u8; 32], Ctap2StatusCode> { pub fn cred_random_secret(env: &mut impl Env, has_uv: bool) -> Result<[u8; 32], Ctap2StatusCode> {
let cred_random_secret = env let cred_random_secret = env
@@ -549,6 +516,7 @@ pub fn set_aaguid(
/// In particular persistent entries are not reset. /// In particular persistent entries are not reset.
pub fn reset(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { pub fn reset(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
env.store().clear(key::NUM_PERSISTENT_KEYS)?; env.store().clear(key::NUM_PERSISTENT_KEYS)?;
env.key_store().reset()?;
init(env)?; init(env)?;
Ok(()) Ok(())
} }
@@ -734,15 +702,15 @@ mod test {
use rng256::Rng256; use rng256::Rng256;
fn create_credential_source( fn create_credential_source(
rng: &mut impl Rng256, env: &mut TestEnv,
rp_id: &str, rp_id: &str,
user_handle: Vec<u8>, user_handle: Vec<u8>,
) -> PublicKeyCredentialSource { ) -> PublicKeyCredentialSource {
let private_key = crypto::ecdsa::SecKey::gensk(rng); let private_key = PrivateKey::new_ecdsa(env);
PublicKeyCredentialSource { PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: rng.gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from(rp_id), rp_id: String::from(rp_id),
user_handle, user_handle,
user_display_name: None, user_display_name: None,
@@ -759,7 +727,7 @@ mod test {
fn test_store() { fn test_store() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
assert_eq!(count_credentials(&mut env).unwrap(), 0); assert_eq!(count_credentials(&mut env).unwrap(), 0);
let credential_source = create_credential_source(env.rng(), "example.com", vec![]); let credential_source = create_credential_source(&mut env, "example.com", vec![]);
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
assert!(count_credentials(&mut env).unwrap() > 0); assert!(count_credentials(&mut env).unwrap() > 0);
} }
@@ -772,7 +740,7 @@ mod test {
let mut credential_ids = vec![]; let mut credential_ids = vec![];
for i in 0..env.customization().max_supported_resident_keys() { for i in 0..env.customization().max_supported_resident_keys() {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(env.rng(), "example.com", user_handle); let credential_source = create_credential_source(&mut env, "example.com", user_handle);
credential_ids.push(credential_source.credential_id.clone()); credential_ids.push(credential_source.credential_id.clone());
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
assert_eq!(count_credentials(&mut env).unwrap(), i + 1); assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
@@ -800,7 +768,7 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS) Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)
); );
let credential_source = create_credential_source(env.rng(), "example.com", vec![0x1D]); let credential_source = create_credential_source(&mut env, "example.com", vec![0x1D]);
let credential_id = credential_source.credential_id.clone(); let credential_id = credential_source.credential_id.clone();
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
let stored_credential = find_credential(&mut env, "example.com", &credential_id, false) let stored_credential = find_credential(&mut env, "example.com", &credential_id, false)
@@ -821,10 +789,10 @@ mod test {
#[test] #[test]
fn test_credential_order() { fn test_credential_order() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let credential_source = create_credential_source(env.rng(), "example.com", vec![]); let credential_source = create_credential_source(&mut env, "example.com", vec![]);
let current_latest_creation = credential_source.creation_order; let current_latest_creation = credential_source.creation_order;
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
let mut credential_source = create_credential_source(env.rng(), "example.com", vec![]); let mut credential_source = create_credential_source(&mut env, "example.com", vec![]);
credential_source.creation_order = new_creation_order(&mut env).unwrap(); credential_source.creation_order = new_creation_order(&mut env).unwrap();
assert!(credential_source.creation_order > current_latest_creation); assert!(credential_source.creation_order > current_latest_creation);
let current_latest_creation = credential_source.creation_order; let current_latest_creation = credential_source.creation_order;
@@ -840,12 +808,12 @@ mod test {
let max_supported_resident_keys = env.customization().max_supported_resident_keys(); let max_supported_resident_keys = env.customization().max_supported_resident_keys();
for i in 0..max_supported_resident_keys { for i in 0..max_supported_resident_keys {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(env.rng(), "example.com", user_handle); let credential_source = create_credential_source(&mut env, "example.com", user_handle);
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
assert_eq!(count_credentials(&mut env).unwrap(), i + 1); assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
} }
let credential_source = create_credential_source( let credential_source = create_credential_source(
env.rng(), &mut env,
"example.com", "example.com",
vec![max_supported_resident_keys as u8], vec![max_supported_resident_keys as u8],
); );
@@ -866,8 +834,8 @@ mod test {
assert_eq!(count_credentials(&mut env).unwrap(), 0); assert_eq!(count_credentials(&mut env).unwrap(), 0);
// These should have different IDs. // These should have different IDs.
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]); let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x00]); let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x00]);
let credential_id0 = credential_source0.credential_id.clone(); let credential_id0 = credential_source0.credential_id.clone();
let credential_id1 = credential_source1.credential_id.clone(); let credential_id1 = credential_source1.credential_id.clone();
@@ -889,12 +857,12 @@ mod test {
let max_supported_resident_keys = env.customization().max_supported_resident_keys(); let max_supported_resident_keys = env.customization().max_supported_resident_keys();
for i in 0..max_supported_resident_keys { for i in 0..max_supported_resident_keys {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(env.rng(), "example.com", user_handle); let credential_source = create_credential_source(&mut env, "example.com", user_handle);
assert!(store_credential(&mut env, credential_source).is_ok()); assert!(store_credential(&mut env, credential_source).is_ok());
assert_eq!(count_credentials(&mut env).unwrap(), i + 1); assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
} }
let credential_source = create_credential_source( let credential_source = create_credential_source(
env.rng(), &mut env,
"example.com", "example.com",
vec![max_supported_resident_keys as u8], vec![max_supported_resident_keys as u8],
); );
@@ -911,10 +879,10 @@ mod test {
#[test] #[test]
fn test_get_credential() { fn test_get_credential() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]); let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]); let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x01]);
let credential_source2 = let credential_source2 =
create_credential_source(env.rng(), "another.example.com", vec![0x02]); create_credential_source(&mut env, "another.example.com", vec![0x02]);
let credential_sources = vec![credential_source0, credential_source1, credential_source2]; let credential_sources = vec![credential_source0, credential_source1, credential_source2];
for credential_source in credential_sources.into_iter() { for credential_source in credential_sources.into_iter() {
let cred_id = credential_source.credential_id.clone(); let cred_id = credential_source.credential_id.clone();
@@ -929,8 +897,8 @@ mod test {
fn test_find() { fn test_find() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
assert_eq!(count_credentials(&mut env).unwrap(), 0); assert_eq!(count_credentials(&mut env).unwrap(), 0);
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]); let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]); let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x01]);
let id0 = credential_source0.credential_id.clone(); let id0 = credential_source0.credential_id.clone();
let key0 = credential_source0.private_key.clone(); let key0 = credential_source0.private_key.clone();
assert!(store_credential(&mut env, credential_source0).is_ok()); assert!(store_credential(&mut env, credential_source0).is_ok());
@@ -960,11 +928,11 @@ mod test {
fn test_find_with_cred_protect() { fn test_find_with_cred_protect() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
assert_eq!(count_credentials(&mut env).unwrap(), 0); assert_eq!(count_credentials(&mut env).unwrap(), 0);
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x00], user_handle: vec![0x00],
user_display_name: None, user_display_name: None,
@@ -981,27 +949,6 @@ mod test {
assert_eq!(no_credential, None); assert_eq!(no_credential, None);
} }
#[test]
fn test_master_keys() {
let mut env = TestEnv::new();
init(&mut env).unwrap();
// Master keys stay the same within the same CTAP reset cycle.
let master_keys_1 = master_keys(&mut env).unwrap();
let master_keys_2 = master_keys(&mut env).unwrap();
assert_eq!(master_keys_2.encryption, master_keys_1.encryption);
assert_eq!(master_keys_2.hmac, master_keys_1.hmac);
// Master keys change after reset. This test may fail if the random generator produces the
// same keys.
let master_encryption_key = master_keys_1.encryption.to_vec();
let master_hmac_key = master_keys_1.hmac.to_vec();
reset(&mut env).unwrap();
let master_keys_3 = master_keys(&mut env).unwrap();
assert!(master_keys_3.encryption != master_encryption_key.as_slice());
assert!(master_keys_3.hmac != master_hmac_key.as_slice());
}
#[test] #[test]
fn test_cred_random_secret() { fn test_cred_random_secret() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
@@ -1281,11 +1228,11 @@ mod test {
#[test] #[test]
fn test_serialize_deserialize_credential() { fn test_serialize_deserialize_credential() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let private_key = PrivateKey::new_ecdsa(&mut env);
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: env.rng().gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key: PrivateKey::from(private_key), private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x00], user_handle: vec![0x00],
user_display_name: Some(String::from("Display Name")), user_display_name: Some(String::from("Display Name")),

View File

@@ -125,10 +125,8 @@ make_partition! {
/// the length, the following are an array with the hash. /// the length, the following are an array with the hash.
PIN_PROPERTIES = 2045; PIN_PROPERTIES = 2045;
/// The encryption and hmac keys. /// Reserved for the key store implementation of the environment.
/// _RESERVED_KEY_STORE = 2046;
/// This entry is always present. It is generated at startup if absent.
MASTER_KEYS = 2046;
/// The global signature counter. /// The global signature counter.
/// ///

3
src/env/mod.rs vendored
View File

@@ -15,6 +15,7 @@
use crate::api::connection::HidConnection; use crate::api::connection::HidConnection;
use crate::api::customization::Customization; use crate::api::customization::Customization;
use crate::api::firmware_protection::FirmwareProtection; use crate::api::firmware_protection::FirmwareProtection;
use crate::api::key_store::KeyStore;
use crate::api::upgrade_storage::UpgradeStorage; use crate::api::upgrade_storage::UpgradeStorage;
use crate::api::user_presence::UserPresence; use crate::api::user_presence::UserPresence;
use persistent_store::{Storage, Store}; use persistent_store::{Storage, Store};
@@ -29,6 +30,7 @@ pub trait Env {
type Rng: Rng256; type Rng: Rng256;
type UserPresence: UserPresence; type UserPresence: UserPresence;
type Storage: Storage; type Storage: Storage;
type KeyStore: KeyStore;
type UpgradeStorage: UpgradeStorage; type UpgradeStorage: UpgradeStorage;
type FirmwareProtection: FirmwareProtection; type FirmwareProtection: FirmwareProtection;
type Write: core::fmt::Write; type Write: core::fmt::Write;
@@ -38,6 +40,7 @@ pub trait Env {
fn rng(&mut self) -> &mut Self::Rng; fn rng(&mut self) -> &mut Self::Rng;
fn user_presence(&mut self) -> &mut Self::UserPresence; fn user_presence(&mut self) -> &mut Self::UserPresence;
fn store(&mut self) -> &mut Store<Self::Storage>; fn store(&mut self) -> &mut Store<Self::Storage>;
fn key_store(&mut self) -> &mut Self::KeyStore;
/// Returns the upgrade storage instance. /// Returns the upgrade storage instance.
/// ///

8
src/env/test/mod.rs vendored
View File

@@ -16,6 +16,7 @@ use self::upgrade_storage::BufferUpgradeStorage;
use crate::api::connection::{HidConnection, SendOrRecvResult, SendOrRecvStatus}; use crate::api::connection::{HidConnection, SendOrRecvResult, SendOrRecvStatus};
use crate::api::customization::DEFAULT_CUSTOMIZATION; use crate::api::customization::DEFAULT_CUSTOMIZATION;
use crate::api::firmware_protection::FirmwareProtection; use crate::api::firmware_protection::FirmwareProtection;
use crate::api::key_store;
use crate::api::user_presence::{UserPresence, UserPresenceResult}; use crate::api::user_presence::{UserPresence, UserPresenceResult};
use crate::clock::ClockInt; use crate::clock::ClockInt;
use crate::env::Env; use crate::env::Env;
@@ -147,10 +148,13 @@ impl FirmwareProtection for TestEnv {
} }
} }
impl key_store::Helper for TestEnv {}
impl Env for TestEnv { impl Env for TestEnv {
type Rng = TestRng256; type Rng = TestRng256;
type UserPresence = TestUserPresence; type UserPresence = TestUserPresence;
type Storage = BufferStorage; type Storage = BufferStorage;
type KeyStore = Self;
type UpgradeStorage = BufferUpgradeStorage; type UpgradeStorage = BufferUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = TestWrite; type Write = TestWrite;
@@ -169,6 +173,10 @@ impl Env for TestEnv {
&mut self.store &mut self.store
} }
fn key_store(&mut self) -> &mut Self {
self
}
fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> { fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> {
self.upgrade_storage.as_mut() self.upgrade_storage.as_mut()
} }

8
src/env/tock/mod.rs vendored
View File

@@ -16,6 +16,7 @@ pub use self::storage::{TockStorage, TockUpgradeStorage};
use crate::api::connection::{HidConnection, SendOrRecvError, SendOrRecvResult, SendOrRecvStatus}; use crate::api::connection::{HidConnection, SendOrRecvError, SendOrRecvResult, SendOrRecvStatus};
use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION}; use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION};
use crate::api::firmware_protection::FirmwareProtection; use crate::api::firmware_protection::FirmwareProtection;
use crate::api::key_store;
use crate::api::user_presence::{UserPresence, UserPresenceError, UserPresenceResult}; use crate::api::user_presence::{UserPresence, UserPresenceError, UserPresenceResult};
use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS}; use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS};
use crate::env::Env; use crate::env::Env;
@@ -193,10 +194,13 @@ impl FirmwareProtection for TockEnv {
} }
} }
impl key_store::Helper for TockEnv {}
impl Env for TockEnv { impl Env for TockEnv {
type Rng = TockRng256; type Rng = TockRng256;
type UserPresence = Self; type UserPresence = Self;
type Storage = TockStorage; type Storage = TockStorage;
type KeyStore = Self;
type UpgradeStorage = TockUpgradeStorage; type UpgradeStorage = TockUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = Console; type Write = Console;
@@ -215,6 +219,10 @@ impl Env for TockEnv {
&mut self.store &mut self.store
} }
fn key_store(&mut self) -> &mut Self {
self
}
fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> { fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> {
self.upgrade_storage.as_mut() self.upgrade_storage.as_mut()
} }