Merge pull request #511 from ia0/attestation_store

Abstract attestation support
This commit is contained in:
Julien Cretin
2022-07-14 13:27:48 +02:00
committed by GitHub
11 changed files with 278 additions and 163 deletions

View File

@@ -0,0 +1,100 @@
use alloc::vec::Vec;
use persistent_store::{StoreError, StoreUpdate};
use crate::env::Env;
/// Identifies an attestation.
#[derive(Clone, PartialEq, Eq)]
pub enum Id {
Batch,
Enterprise,
}
#[cfg_attr(feature = "std", derive(Debug, PartialEq, Eq))]
pub struct Attestation {
/// ECDSA private key (big-endian).
pub private_key: [u8; 32],
pub certificate: Vec<u8>,
}
/// Stores enterprise or batch attestations.
pub trait AttestationStore {
/// Returns an attestation given its id, if it exists.
///
/// This should always return the attestation. Checking whether it is ok to use the attestation
/// is done in the CTAP library.
fn get(&mut self, id: &Id) -> Result<Option<Attestation>, Error>;
/// Sets the attestation for a given id.
///
/// This function may not be supported.
fn set(&mut self, id: &Id, attestation: Option<&Attestation>) -> Result<(), Error>;
}
/// Attestation store errors.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
Storage,
Internal,
NoSupport,
}
/// Keys of the environment store reserved for the attestation store.
pub const STORAGE_KEYS: &[usize] = &[1, 2];
pub fn helper_get(env: &mut impl Env) -> Result<Option<Attestation>, Error> {
let private_key = env.store().find(PRIVATE_KEY_STORAGE_KEY)?;
let certificate = env.store().find(CERTIFICATE_STORAGE_KEY)?;
let (private_key, certificate) = match (private_key, certificate) {
(Some(x), Some(y)) => (x, y),
(None, None) => return Ok(None),
_ => return Err(Error::Internal),
};
if private_key.len() != 32 {
return Err(Error::Internal);
}
Ok(Some(Attestation {
private_key: *array_ref![private_key, 0, 32],
certificate,
}))
}
pub fn helper_set(env: &mut impl Env, attestation: Option<&Attestation>) -> Result<(), Error> {
let updates = match attestation {
None => [
StoreUpdate::Remove {
key: PRIVATE_KEY_STORAGE_KEY,
},
StoreUpdate::Remove {
key: CERTIFICATE_STORAGE_KEY,
},
],
Some(attestation) => [
StoreUpdate::Insert {
key: PRIVATE_KEY_STORAGE_KEY,
value: &attestation.private_key[..],
},
StoreUpdate::Insert {
key: CERTIFICATE_STORAGE_KEY,
value: &attestation.certificate[..],
},
],
};
Ok(env.store().transaction(&updates)?)
}
const PRIVATE_KEY_STORAGE_KEY: usize = STORAGE_KEYS[0];
const CERTIFICATE_STORAGE_KEY: usize = STORAGE_KEYS[1];
impl From<StoreError> for Error {
fn from(error: StoreError) -> Self {
match error {
StoreError::InvalidArgument
| StoreError::NoCapacity
| StoreError::NoLifetime
| StoreError::InvalidStorage => Error::Internal,
StoreError::StorageError => Error::Storage,
}
}
}

View File

@@ -17,6 +17,7 @@
//! The [environment](crate::env::Env) is split into components. Each component has an API described //! The [environment](crate::env::Env) is split into components. Each component has an API described
//! by a trait. This module gathers the API of those components. //! by a trait. This module gathers the API of those components.
pub mod attestation_store;
pub mod connection; pub mod connection;
pub mod customization; pub mod customization;
pub mod firmware_protection; pub mod firmware_protection;

View File

@@ -16,6 +16,8 @@ use alloc::vec::Vec;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom; use core::convert::TryFrom;
use crate::api::attestation_store;
const APDU_HEADER_LEN: usize = 4; const APDU_HEADER_LEN: usize = 4;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@@ -44,6 +46,17 @@ impl From<ApduStatusCode> for u16 {
} }
} }
impl From<attestation_store::Error> for ApduStatusCode {
fn from(error: attestation_store::Error) -> Self {
use attestation_store::Error;
match error {
Error::Storage => ApduStatusCode::SW_MEMERR,
Error::Internal => ApduStatusCode::SW_INTERNAL_EXCEPTION,
Error::NoSupport => ApduStatusCode::SW_INTERNAL_EXCEPTION,
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
pub enum ApduInstructions { pub enum ApduInstructions {
Select = 0xA4, Select = 0xA4,

View File

@@ -17,7 +17,7 @@ use super::apdu::{Apdu, ApduStatusCode};
use super::credential_id::{decrypt_credential_id, encrypt_to_credential_id}; use super::credential_id::{decrypt_credential_id, encrypt_to_credential_id};
use super::crypto_wrapper::PrivateKey; use super::crypto_wrapper::PrivateKey;
use super::CtapState; use super::CtapState;
use crate::ctap::storage; use crate::api::attestation_store::{self, Attestation, AttestationStore};
use crate::env::Env; use crate::env::Env;
use alloc::vec::Vec; use alloc::vec::Vec;
use arrayref::array_ref; use arrayref::array_ref;
@@ -258,11 +258,12 @@ impl Ctap1Command {
return Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION); return Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION);
} }
let certificate = storage::attestation_certificate(env) let Attestation {
.map_err(|_| Ctap1StatusCode::SW_MEMERR)? private_key,
.ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?; certificate,
let private_key = storage::attestation_private_key(env) } = env
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)? .attestation_store()
.get(&attestation_store::Id::Batch)?
.ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?; .ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
let mut response = Vec::with_capacity(105 + key_handle.len() + certificate.len()); let mut response = Vec::with_capacity(105 + key_handle.len() + certificate.len());
@@ -346,10 +347,10 @@ impl Ctap1Command {
mod test { mod test {
use super::super::credential_id::CBOR_CREDENTIAL_ID_SIZE; use super::super::credential_id::CBOR_CREDENTIAL_ID_SIZE;
use super::super::data_formats::SignatureAlgorithm; use super::super::data_formats::SignatureAlgorithm;
use super::super::key_material;
use super::*; use super::*;
use crate::api::customization::Customization; use crate::api::customization::Customization;
use crate::clock::TEST_CLOCK_FREQUENCY_HZ; use crate::clock::TEST_CLOCK_FREQUENCY_HZ;
use crate::ctap::storage;
use crate::env::test::TestEnv; use crate::env::test::TestEnv;
use crypto::Hash256; use crypto::Hash256;
@@ -423,21 +424,13 @@ mod test {
// Certificate and private key are missing // Certificate and private key are missing
assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)); assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION));
let fake_key = [0x41u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH]; let attestation = Attestation {
assert!(storage::set_attestation_private_key(&mut env, &fake_key).is_ok()); private_key: [0x41; 32],
ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); certificate: vec![0x99; 100],
ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); };
let response = Ctap1Command::process_command( env.attestation_store()
&mut env, .set(&attestation_store::Id::Batch, Some(&attestation))
&message, .unwrap();
&mut ctap_state,
CtapInstant::new(0_u64),
);
// Certificate is still missing
assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION));
let fake_cert = [0x99u8; 100]; // Arbitrary length
assert!(storage::set_attestation_certificate(&mut env, &fake_cert[..]).is_ok());
ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); ctap_state.u2f_up_state.consume_up(CtapInstant::new(0));
ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); ctap_state.u2f_up_state.grant_up(CtapInstant::new(0));
let response = let response =
@@ -455,8 +448,8 @@ mod test {
.is_some()); .is_some());
const CERT_START: usize = 67 + CBOR_CREDENTIAL_ID_SIZE; const CERT_START: usize = 67 + CBOR_CREDENTIAL_ID_SIZE;
assert_eq!( assert_eq!(
&response[CERT_START..CERT_START + fake_cert.len()], &response[CERT_START..][..attestation.certificate.len()],
&fake_cert[..] &attestation.certificate
); );
} }

View File

@@ -64,6 +64,7 @@ use self::status_code::Ctap2StatusCode;
use self::timed_permission::TimedPermission; use self::timed_permission::TimedPermission;
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
use self::timed_permission::U2fUserPresenceState; use self::timed_permission::U2fUserPresenceState;
use crate::api::attestation_store::{self, Attestation, AttestationStore};
use crate::api::connection::{HidConnection, SendOrRecvStatus}; use crate::api::connection::{HidConnection, SendOrRecvStatus};
use crate::api::customization::Customization; use crate::api::customization::Customization;
use crate::api::firmware_protection::FirmwareProtection; use crate::api::firmware_protection::FirmwareProtection;
@@ -920,21 +921,31 @@ 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, x5c) = if env.customization().use_batch_attestation() || ep_att { let attestation_id = if ep_att {
let attestation_private_key = storage::attestation_private_key(env)? Some(attestation_store::Id::Enterprise)
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?; } else if env.customization().use_batch_attestation() {
let attestation_key = Some(attestation_store::Id::Batch)
crypto::ecdsa::SecKey::from_bytes(&attestation_private_key).unwrap(); } else {
let attestation_certificate = storage::attestation_certificate(env)? None
};
let (signature, x5c) = match attestation_id {
Some(id) => {
let Attestation {
private_key,
certificate,
} = env
.attestation_store()
.get(&id)?
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?; .ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
let attestation_key = crypto::ecdsa::SecKey::from_bytes(&private_key).unwrap();
( (
attestation_key attestation_key
.sign_rfc6979::<Sha256>(&signature_data) .sign_rfc6979::<Sha256>(&signature_data)
.to_asn1_der(), .to_asn1_der(),
Some(vec![attestation_certificate]), Some(vec![certificate]),
) )
} else { }
(private_key.sign_and_encode(env, &signature_data)?, None) 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,
@@ -1341,41 +1352,26 @@ impl CtapState {
if params.attestation_material.is_some() || params.lockdown { if params.attestation_material.is_some() || params.lockdown {
check_user_presence(env, channel)?; check_user_presence(env, channel)?;
} }
// This command is for U2F support and we use the batch attestation there.
let attestation_id = attestation_store::Id::Batch;
// Sanity checks // Sanity checks
let current_priv_key = storage::attestation_private_key(env)?; let current_attestation = env.attestation_store().get(&attestation_id)?;
let current_cert = storage::attestation_certificate(env)?;
let response = match params.attestation_material { let response = match params.attestation_material {
// Only reading values.
None => AuthenticatorVendorConfigureResponse { None => AuthenticatorVendorConfigureResponse {
cert_programmed: current_cert.is_some(), cert_programmed: current_attestation.is_some(),
pkey_programmed: current_priv_key.is_some(), pkey_programmed: current_attestation.is_some(),
}, },
// Device is already fully programmed. We don't leak information.
Some(_) if current_cert.is_some() && current_priv_key.is_some() => {
AuthenticatorVendorConfigureResponse {
cert_programmed: true,
pkey_programmed: true,
}
}
// Device is partially or not programmed. We complete the process.
Some(data) => { Some(data) => {
if let Some(current_cert) = &current_cert { // We don't overwrite the attestation if it's already set. We don't return any error
if current_cert != &data.certificate { // to not leak information.
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); if current_attestation.is_none() {
} let attestation = Attestation {
} private_key: data.private_key,
if let Some(current_priv_key) = &current_priv_key { certificate: data.certificate,
if current_priv_key != &data.private_key { };
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); env.attestation_store()
} .set(&attestation_id, Some(&attestation))?;
}
if current_cert.is_none() {
storage::set_attestation_certificate(env, &data.certificate)?;
}
if current_priv_key.is_none() {
storage::set_attestation_private_key(env, &data.private_key)?;
} }
AuthenticatorVendorConfigureResponse { AuthenticatorVendorConfigureResponse {
cert_programmed: true, cert_programmed: true,
@@ -3148,12 +3144,11 @@ mod test {
)) ))
); );
assert_eq!( assert_eq!(
storage::attestation_certificate(&mut env).unwrap().unwrap(), env.attestation_store().get(&attestation_store::Id::Batch),
dummy_cert Ok(Some(Attestation {
); private_key: dummy_key,
assert_eq!( certificate: dummy_cert.to_vec(),
storage::attestation_private_key(&mut env).unwrap().unwrap(), }))
dummy_key
); );
// Try to inject other dummy values and check that initial values are retained. // Try to inject other dummy values and check that initial values are retained.
@@ -3179,12 +3174,11 @@ mod test {
)) ))
); );
assert_eq!( assert_eq!(
storage::attestation_certificate(&mut env).unwrap().unwrap(), env.attestation_store().get(&attestation_store::Id::Batch),
dummy_cert Ok(Some(Attestation {
); private_key: dummy_key,
assert_eq!( certificate: dummy_cert.to_vec(),
storage::attestation_private_key(&mut env).unwrap().unwrap(), }))
dummy_key
); );
// Now try to lock the device // Now try to lock the device

View File

@@ -12,8 +12,8 @@
// 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;
use crate::api::{attestation_store, key_store};
// CTAP specification (version 20190130) section 6.3 // CTAP specification (version 20190130) section 6.3
// For now, only the CTAP2 codes are here, the CTAP1 are not included. // For now, only the CTAP2 codes are here, the CTAP1 are not included.
@@ -100,3 +100,14 @@ impl From<key_store::Error> for Ctap2StatusCode {
Self::CTAP2_ERR_VENDOR_INTERNAL_ERROR Self::CTAP2_ERR_VENDOR_INTERNAL_ERROR
} }
} }
impl From<attestation_store::Error> for Ctap2StatusCode {
fn from(error: attestation_store::Error) -> Self {
use attestation_store::Error;
match error {
Error::Storage => Self::CTAP2_ERR_VENDOR_HARDWARE_FAILURE,
Error::Internal => Self::CTAP2_ERR_VENDOR_INTERNAL_ERROR,
Error::NoSupport => Self::CTAP2_ERR_VENDOR_INTERNAL_ERROR,
}
}
}

View File

@@ -14,6 +14,7 @@
mod key; mod key;
use crate::api::attestation_store::{self, AttestationStore};
use crate::api::customization::Customization; use crate::api::customization::Customization;
use crate::api::key_store::KeyStore; use crate::api::key_store::KeyStore;
use crate::ctap::client_pin::PIN_AUTH_LENGTH; use crate::ctap::client_pin::PIN_AUTH_LENGTH;
@@ -437,58 +438,6 @@ pub fn commit_large_blob_array(
)?) )?)
} }
/// Returns the attestation private key if defined.
pub fn attestation_private_key(
env: &mut impl Env,
) -> Result<Option<[u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH]>, Ctap2StatusCode> {
match env.store().find(key::ATTESTATION_PRIVATE_KEY)? {
None => Ok(None),
Some(key) if key.len() == key_material::ATTESTATION_PRIVATE_KEY_LENGTH => {
Ok(Some(*array_ref![
key,
0,
key_material::ATTESTATION_PRIVATE_KEY_LENGTH
]))
}
Some(_) => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR),
}
}
/// Sets the attestation private key.
///
/// If it is already defined, it is overwritten.
pub fn set_attestation_private_key(
env: &mut impl Env,
attestation_private_key: &[u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH],
) -> Result<(), Ctap2StatusCode> {
match env.store().find(key::ATTESTATION_PRIVATE_KEY)? {
None => Ok(env
.store()
.insert(key::ATTESTATION_PRIVATE_KEY, attestation_private_key)?),
Some(_) => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR),
}
}
/// Returns the attestation certificate if defined.
pub fn attestation_certificate(env: &mut impl Env) -> Result<Option<Vec<u8>>, Ctap2StatusCode> {
Ok(env.store().find(key::ATTESTATION_CERTIFICATE)?)
}
/// Sets the attestation certificate.
///
/// If it is already defined, it is overwritten.
pub fn set_attestation_certificate(
env: &mut impl Env,
attestation_certificate: &[u8],
) -> Result<(), Ctap2StatusCode> {
match env.store().find(key::ATTESTATION_CERTIFICATE)? {
None => Ok(env
.store()
.insert(key::ATTESTATION_CERTIFICATE, attestation_certificate)?),
Some(_) => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR),
}
}
/// Returns the AAGUID. /// Returns the AAGUID.
pub fn aaguid(env: &mut impl Env) -> Result<[u8; key_material::AAGUID_LENGTH], Ctap2StatusCode> { pub fn aaguid(env: &mut impl Env) -> Result<[u8; key_material::AAGUID_LENGTH], Ctap2StatusCode> {
let aaguid = env let aaguid = env
@@ -546,7 +495,11 @@ pub fn enterprise_attestation(env: &mut impl Env) -> Result<bool, Ctap2StatusCod
/// Marks enterprise attestation as enabled. /// Marks enterprise attestation as enabled.
pub fn enable_enterprise_attestation(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { pub fn enable_enterprise_attestation(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
if attestation_private_key(env)?.is_none() || attestation_certificate(env)?.is_none() { if env
.attestation_store()
.get(&attestation_store::Id::Enterprise)?
.is_none()
{
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR); return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
} }
if !enterprise_attestation(env)? { if !enterprise_attestation(env)? {
@@ -696,6 +649,7 @@ fn serialize_min_pin_length_rp_ids(rp_ids: Vec<String>) -> Result<Vec<u8>, Ctap2
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::api::attestation_store::{self, Attestation, AttestationStore};
use crate::ctap::crypto_wrapper::PrivateKey; use crate::ctap::crypto_wrapper::PrivateKey;
use crate::ctap::data_formats::{PublicKeyCredentialSource, PublicKeyCredentialType}; use crate::ctap::data_formats::{PublicKeyCredentialSource, PublicKeyCredentialType};
use crate::env::test::TestEnv; use crate::env::test::TestEnv;
@@ -1033,25 +987,26 @@ mod test {
init(&mut env).unwrap(); init(&mut env).unwrap();
// Make sure the attestation are absent. There is no batch attestation in tests. // Make sure the attestation are absent. There is no batch attestation in tests.
assert!(attestation_private_key(&mut env).unwrap().is_none()); assert_eq!(
assert!(attestation_certificate(&mut env).unwrap().is_none()); env.attestation_store().get(&attestation_store::Id::Batch),
Ok(None)
);
// Make sure the persistent keys are initialized to dummy values. // Make sure the persistent keys are initialized to dummy values.
let dummy_key = [0x41u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH]; let dummy_attestation = Attestation {
let dummy_cert = [0xddu8; 20]; private_key: [0x41; key_material::ATTESTATION_PRIVATE_KEY_LENGTH],
set_attestation_private_key(&mut env, &dummy_key).unwrap(); certificate: vec![0xdd; 20],
set_attestation_certificate(&mut env, &dummy_cert).unwrap(); };
env.attestation_store()
.set(&attestation_store::Id::Batch, Some(&dummy_attestation))
.unwrap();
assert_eq!(&aaguid(&mut env).unwrap(), key_material::AAGUID); assert_eq!(&aaguid(&mut env).unwrap(), key_material::AAGUID);
// The persistent keys stay initialized and preserve their value after a reset. // The persistent keys stay initialized and preserve their value after a reset.
reset(&mut env).unwrap(); reset(&mut env).unwrap();
assert_eq!( assert_eq!(
&attestation_private_key(&mut env).unwrap().unwrap(), env.attestation_store().get(&attestation_store::Id::Batch),
&dummy_key Ok(Some(dummy_attestation))
);
assert_eq!(
attestation_certificate(&mut env).unwrap().unwrap(),
&dummy_cert
); );
assert_eq!(&aaguid(&mut env).unwrap(), key_material::AAGUID); assert_eq!(&aaguid(&mut env).unwrap(), key_material::AAGUID);
} }
@@ -1187,17 +1142,13 @@ mod test {
fn test_enterprise_attestation() { fn test_enterprise_attestation() {
let mut env = TestEnv::new(); let mut env = TestEnv::new();
assert!(!enterprise_attestation(&mut env).unwrap()); let dummy_attestation = Attestation {
assert_eq!( private_key: [0x41; key_material::ATTESTATION_PRIVATE_KEY_LENGTH],
enable_enterprise_attestation(&mut env), certificate: vec![0xdd; 20],
Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR) };
); env.attestation_store()
assert!(!enterprise_attestation(&mut env).unwrap()); .set(&attestation_store::Id::Enterprise, Some(&dummy_attestation))
.unwrap();
let dummy_key = [0x41u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH];
let dummy_cert = [0xddu8; 20];
set_attestation_private_key(&mut env, &dummy_key).unwrap();
set_attestation_certificate(&mut env, &dummy_cert).unwrap();
assert!(!enterprise_attestation(&mut env).unwrap()); assert!(!enterprise_attestation(&mut env).unwrap());
assert_eq!(enable_enterprise_attestation(&mut env), Ok(())); assert_eq!(enable_enterprise_attestation(&mut env), Ok(()));

View File

@@ -61,11 +61,8 @@ make_partition! {
// WARNING: Keys should not be deleted but prefixed with `_` to avoid accidentally reusing them. // WARNING: Keys should not be deleted but prefixed with `_` to avoid accidentally reusing them.
/// The attestation private key. /// Reserved for the attestation store implementation of the environment.
ATTESTATION_PRIVATE_KEY = 1; _RESERVED_ATTESTATION_STORE = 1..3;
/// The attestation certificate.
ATTESTATION_CERTIFICATE = 2;
/// The aaguid. /// The aaguid.
AAGUID = 3; AAGUID = 3;

3
src/env/mod.rs vendored
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::attestation_store::AttestationStore;
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;
@@ -36,11 +37,13 @@ pub trait Env {
type Write: core::fmt::Write; type Write: core::fmt::Write;
type Customization: Customization; type Customization: Customization;
type HidConnection: HidConnection; type HidConnection: HidConnection;
type AttestationStore: AttestationStore;
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; fn key_store(&mut self) -> &mut Self::KeyStore;
fn attestation_store(&mut self) -> &mut Self::AttestationStore;
/// Returns the upgrade storage instance. /// Returns the upgrade storage instance.
/// ///

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

@@ -13,11 +13,12 @@
// limitations under the License. // limitations under the License.
use self::upgrade_storage::BufferUpgradeStorage; use self::upgrade_storage::BufferUpgradeStorage;
use crate::api::attestation_store::AttestationStore;
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::api::{attestation_store, key_store};
use crate::clock::ClockInt; use crate::clock::ClockInt;
use crate::env::Env; use crate::env::Env;
use customization::TestCustomization; use customization::TestCustomization;
@@ -150,11 +151,29 @@ impl FirmwareProtection for TestEnv {
impl key_store::Helper for TestEnv {} impl key_store::Helper for TestEnv {}
impl AttestationStore for TestEnv {
fn get(
&mut self,
_id: &attestation_store::Id,
) -> Result<Option<attestation_store::Attestation>, attestation_store::Error> {
attestation_store::helper_get(self)
}
fn set(
&mut self,
_id: &attestation_store::Id,
attestation: Option<&attestation_store::Attestation>,
) -> Result<(), attestation_store::Error> {
attestation_store::helper_set(self, attestation)
}
}
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 KeyStore = Self;
type AttestationStore = Self;
type UpgradeStorage = BufferUpgradeStorage; type UpgradeStorage = BufferUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = TestWrite; type Write = TestWrite;
@@ -177,6 +196,10 @@ impl Env for TestEnv {
self self
} }
fn attestation_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()
} }

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

@@ -13,11 +13,12 @@
// limitations under the License. // limitations under the License.
pub use self::storage::{TockStorage, TockUpgradeStorage}; pub use self::storage::{TockStorage, TockUpgradeStorage};
use crate::api::attestation_store::AttestationStore;
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::api::{attestation_store, key_store};
use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS}; use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS};
use crate::env::Env; use crate::env::Env;
use core::cell::Cell; use core::cell::Cell;
@@ -196,11 +197,35 @@ impl FirmwareProtection for TockEnv {
impl key_store::Helper for TockEnv {} impl key_store::Helper for TockEnv {}
impl AttestationStore for TockEnv {
fn get(
&mut self,
id: &attestation_store::Id,
) -> Result<Option<attestation_store::Attestation>, attestation_store::Error> {
if !matches!(id, attestation_store::Id::Batch) {
return Err(attestation_store::Error::NoSupport);
}
attestation_store::helper_get(self)
}
fn set(
&mut self,
id: &attestation_store::Id,
attestation: Option<&attestation_store::Attestation>,
) -> Result<(), attestation_store::Error> {
if !matches!(id, attestation_store::Id::Batch) {
return Err(attestation_store::Error::NoSupport);
}
attestation_store::helper_set(self, attestation)
}
}
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 KeyStore = Self;
type AttestationStore = Self;
type UpgradeStorage = TockUpgradeStorage; type UpgradeStorage = TockUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = Console; type Write = Console;
@@ -223,6 +248,10 @@ impl Env for TockEnv {
self self
} }
fn attestation_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()
} }