mirror of
https://github.com/trussed-dev/trussed-auth.git
synced 2026-06-20 04:16:21 -07:00
Implement fetching the pin keys and add tests
This commit is contained in:
committed by
Markus Meissner
parent
1f83b95678
commit
ba9e0f4b6c
+17
-5
@@ -11,9 +11,10 @@ use sha2::Sha256;
|
||||
use trussed::{
|
||||
backend::Backend,
|
||||
error::Result,
|
||||
key::{Kind, Secrecy},
|
||||
platform::Platform,
|
||||
serde_extensions::ExtensionImpl,
|
||||
service::ServiceResources,
|
||||
service::{Keystore, ServiceResources},
|
||||
store::filestore::Filestore,
|
||||
types::{CoreContext, Location, PathBuf},
|
||||
Bytes,
|
||||
@@ -23,7 +24,7 @@ use crate::{
|
||||
extension::{reply, AuthExtension, AuthReply, AuthRequest},
|
||||
PIN_PATH, SALT_PATH,
|
||||
};
|
||||
use data::{Key, PinData, Salt, SALT_LEN};
|
||||
use data::{Key, PinData, Salt, KEY_LEN, SALT_LEN};
|
||||
|
||||
/// max accepted length for the hardware initial key material
|
||||
pub const MAX_HW_KEY_LEN: usize = 64;
|
||||
@@ -180,6 +181,7 @@ impl<P: Platform> ExtensionImpl<AuthExtension, P> for AuthBackend {
|
||||
let trussed_fs = &mut resources.trussed_filestore();
|
||||
let rng = &mut resources.rng()?;
|
||||
let client_id = core_ctx.path.clone();
|
||||
let keystore = &mut resources.keystore(core_ctx)?;
|
||||
match request {
|
||||
AuthRequest::HasPin(request) => {
|
||||
let has_pin = fs.exists(&request.id.path(), self.location);
|
||||
@@ -205,10 +207,20 @@ impl<P: Platform> ExtensionImpl<AuthExtension, P> for AuthBackend {
|
||||
self.location,
|
||||
|data| data.get_pin_key(&request.pin, &application_key),
|
||||
)??;
|
||||
if verification.is_none() {
|
||||
return Ok(reply::GetPinKey { result: None }.into());
|
||||
if let Some(k) = verification {
|
||||
let key_id = keystore.store_key(
|
||||
Location::Volatile,
|
||||
Secrecy::Secret,
|
||||
Kind::Symmetric(KEY_LEN),
|
||||
&*k,
|
||||
)?;
|
||||
Ok(reply::GetPinKey {
|
||||
result: Some(key_id),
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
Ok(reply::GetPinKey { result: None }.into())
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
AuthRequest::SetPin(request) => {
|
||||
let maybe_app_key = if request.derive_key {
|
||||
|
||||
@@ -80,6 +80,19 @@ pub trait AuthClient: ExtensionClient<AuthExtension> {
|
||||
self.extension(request::CheckPin { id: id.into(), pin })
|
||||
}
|
||||
|
||||
/// Returns a keyid if the provided PIN is correct and not blocked.
|
||||
///
|
||||
/// The pin must have been created with `derive_key` set to true.
|
||||
/// If the PIN is not correct and a retry counter is configured, the counter is decremented.
|
||||
/// Once it reaches zero, authentication attempts for that PIN fail. If the PIN with the given
|
||||
/// ID is not set, an error is returned.
|
||||
fn get_pin_key<I>(&mut self, id: I, pin: Pin) -> AuthResult<'_, reply::GetPinKey, Self>
|
||||
where
|
||||
I: Into<PinId>,
|
||||
{
|
||||
self.extension(request::GetPinKey { id: id.into(), pin })
|
||||
}
|
||||
|
||||
/// Sets the given PIN and resets its retry counter.
|
||||
///
|
||||
/// If the retry counter is `None`, the number of retries is not limited and the PIN will never
|
||||
|
||||
+13
-2
@@ -44,6 +44,17 @@ impl From<CheckPin> for AuthReply {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AuthReply> for CheckPin {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(reply: AuthReply) -> Result<Self> {
|
||||
match reply {
|
||||
AuthReply::CheckPin(reply) => Ok(reply),
|
||||
_ => Err(Error::InternalError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[must_use]
|
||||
pub struct GetPinKey {
|
||||
@@ -57,12 +68,12 @@ impl From<GetPinKey> for AuthReply {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AuthReply> for CheckPin {
|
||||
impl TryFrom<AuthReply> for GetPinKey {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(reply: AuthReply) -> Result<Self> {
|
||||
match reply {
|
||||
AuthReply::CheckPin(reply) => Ok(reply),
|
||||
AuthReply::GetPinKey(reply) => Ok(reply),
|
||||
_ => Err(Error::InternalError),
|
||||
}
|
||||
}
|
||||
|
||||
+113
-4
@@ -9,9 +9,9 @@ mod dispatch {
|
||||
platform::Platform,
|
||||
serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl as _},
|
||||
service::ServiceResources,
|
||||
types::{Context, Location},
|
||||
types::{Bytes, Context, Location},
|
||||
};
|
||||
use trussed_auth::{AuthBackend, AuthContext, AuthExtension};
|
||||
use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN};
|
||||
|
||||
pub const BACKENDS: &[BackendId<Backend>] =
|
||||
&[BackendId::Custom(Backend::Auth), BackendId::Core];
|
||||
@@ -58,6 +58,12 @@ mod dispatch {
|
||||
auth: AuthBackend::new(Location::Internal),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_hw_key(hw_key: Bytes<MAX_HW_KEY_LEN>) -> Self {
|
||||
Self {
|
||||
auth: AuthBackend::with_hw_key(Location::Internal, hw_key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Platform> ExtensionDispatch<P> for Dispatch {
|
||||
@@ -111,13 +117,13 @@ mod dispatch {
|
||||
use rand_core::{OsRng, RngCore as _};
|
||||
use trussed::{
|
||||
backend::BackendId,
|
||||
client::ClientImplementation,
|
||||
client::{ClientImplementation, HmacSha256},
|
||||
service::Service,
|
||||
syscall, try_syscall,
|
||||
types::Bytes,
|
||||
virt::{self, Ram},
|
||||
};
|
||||
use trussed_auth::{AuthClient as _, PinId};
|
||||
use trussed_auth::{AuthClient as _, PinId, MAX_HW_KEY_LEN};
|
||||
|
||||
use dispatch::{Backend, Dispatch, BACKENDS};
|
||||
|
||||
@@ -154,6 +160,21 @@ fn run<F: FnOnce(&mut Client)>(backends: &'static [BackendId<Backend>], f: F) {
|
||||
})
|
||||
}
|
||||
|
||||
fn run_with_hw_key<F: FnOnce(&mut Client)>(
|
||||
backends: &'static [BackendId<Backend>],
|
||||
hw_key: Bytes<{ MAX_HW_KEY_LEN }>,
|
||||
f: F,
|
||||
) {
|
||||
virt::with_platform(Ram::default(), |platform| {
|
||||
platform.run_client_with_backends(
|
||||
"test",
|
||||
Dispatch::with_hw_key(hw_key),
|
||||
backends,
|
||||
|mut client| f(&mut client),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn random_pin() -> trussed_auth::Pin {
|
||||
let mut pin = Bytes::new();
|
||||
pin.resize_to_capacity();
|
||||
@@ -249,6 +270,94 @@ fn basic_wrapped() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hw_key_wrapped() {
|
||||
run_with_hw_key(
|
||||
BACKENDS,
|
||||
Bytes::from_slice(b"Some HW ikm").unwrap(),
|
||||
|client| {
|
||||
let pin1 = Bytes::from_slice(b"12345678").unwrap();
|
||||
let pin2 = Bytes::from_slice(b"123456").unwrap();
|
||||
|
||||
let reply = syscall!(client.has_pin(Pin::User));
|
||||
assert!(!reply.has_pin);
|
||||
|
||||
syscall!(client.set_pin(Pin::User, pin1.clone(), None, true));
|
||||
|
||||
let reply = syscall!(client.has_pin(Pin::User));
|
||||
assert!(reply.has_pin);
|
||||
let reply = syscall!(client.has_pin(Pin::Admin));
|
||||
assert!(!reply.has_pin);
|
||||
|
||||
let reply = syscall!(client.pin_retries(Pin::User));
|
||||
assert_eq!(reply.retries, None);
|
||||
|
||||
let reply = syscall!(client.check_pin(Pin::User, pin1.clone()));
|
||||
assert!(reply.success);
|
||||
|
||||
let reply = syscall!(client.pin_retries(Pin::User));
|
||||
assert_eq!(reply.retries, None);
|
||||
|
||||
let reply = syscall!(client.check_pin(Pin::User, pin2));
|
||||
assert!(!reply.success);
|
||||
|
||||
let result = try_syscall!(client.check_pin(Pin::Admin, pin1.clone()));
|
||||
assert!(result.is_err());
|
||||
|
||||
let reply = syscall!(client.pin_retries(Pin::User));
|
||||
assert_eq!(reply.retries, None);
|
||||
|
||||
syscall!(client.delete_pin(Pin::User));
|
||||
|
||||
let result = try_syscall!(client.check_pin(Pin::User, pin1));
|
||||
assert!(result.is_err());
|
||||
|
||||
let result = try_syscall!(client.pin_retries(Pin::User));
|
||||
assert!(result.is_err());
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pin_key() {
|
||||
run_with_hw_key(
|
||||
BACKENDS,
|
||||
Bytes::from_slice(b"Some HW ikm").unwrap(),
|
||||
|client| {
|
||||
let pin1 = Bytes::from_slice(b"12345678").unwrap();
|
||||
let pin2 = Bytes::from_slice(b"123456").unwrap();
|
||||
|
||||
syscall!(client.set_pin(Pin::User, pin1.clone(), Some(3), true));
|
||||
assert!(syscall!(client.get_pin_key(Pin::User, pin2.clone()))
|
||||
.result
|
||||
.is_none());
|
||||
assert_eq!(syscall!(client.pin_retries(Pin::User)).retries, Some(2));
|
||||
assert!(!syscall!(client.check_pin(Pin::User, pin2.clone())).success);
|
||||
assert_eq!(syscall!(client.pin_retries(Pin::User)).retries, Some(1));
|
||||
assert!(syscall!(client.check_pin(Pin::User, pin1.clone())).success);
|
||||
let key = syscall!(client.get_pin_key(Pin::User, pin1.clone()))
|
||||
.result
|
||||
.unwrap();
|
||||
assert_eq!(syscall!(client.pin_retries(Pin::User)).retries, Some(3));
|
||||
let mac = syscall!(client.sign_hmacsha256(key, b"Some data")).signature;
|
||||
let key2 = syscall!(client.get_pin_key(Pin::User, pin1.clone()))
|
||||
.result
|
||||
.unwrap();
|
||||
let mac2 = syscall!(client.sign_hmacsha256(key2, b"Some data")).signature;
|
||||
assert_eq!(mac, mac2);
|
||||
|
||||
assert!(!syscall!(client.check_pin(Pin::User, pin2.clone())).success);
|
||||
assert!(!syscall!(client.check_pin(Pin::User, pin2.clone())).success);
|
||||
assert!(!syscall!(client.check_pin(Pin::User, pin2.clone())).success);
|
||||
assert!(!syscall!(client.check_pin(Pin::User, pin1.clone())).success);
|
||||
assert!(syscall!(client.get_pin_key(Pin::User, pin1.clone()))
|
||||
.result
|
||||
.is_none());
|
||||
assert_eq!(syscall!(client.pin_retries(Pin::User)).retries, Some(0));
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocked_pin() {
|
||||
run(BACKENDS, |client| {
|
||||
|
||||
Reference in New Issue
Block a user