Change PIN data path

This patch changes the path used to store PIN data inside the client
namespace from backend-auth/pin/<id> to backend-auth/pin.<id> to make
better use of the available space.

It also adds documentation for the filesystem layout.

Fixes https://github.com/trussed-dev/trussed-auth/issues/9
This commit is contained in:
Robin Krahl
2023-03-03 12:39:26 +01:00
parent b307dafb57
commit bb13c5606a
3 changed files with 47 additions and 9 deletions
+1
View File
@@ -22,6 +22,7 @@ subtle = { version = "2.4.1", default-features = false }
trussed = { version = "0.1.0", features = ["serde-extensions"] }
[dev-dependencies]
quickcheck = { version = "1.0.3", default-features = false }
rand_core = { version = "0.6.4", default-features = false, features = ["getrandom"] }
trussed = { version = "0.1.0", features = ["serde-extensions", "virt"] }
+17 -3
View File
@@ -22,7 +22,7 @@ use trussed::{
use crate::{
extension::{reply, AuthExtension, AuthReply, AuthRequest},
PIN_PATH, SALT_PATH,
BACKEND_DIR,
};
use data::{Key, PinData, Salt, KEY_LEN, SALT_LEN};
@@ -50,6 +50,20 @@ impl fmt::Debug for HardwareKey {
///
/// This implementation stores PINs together with their retry counters on the filesystem. PINs are
/// hashed with SHA-256 using a salt that is generated per PIN.
///
/// # Filesystem Layout
///
/// ```text
/// trussed/
/// backend-auth/
/// salt global salt for key derivation
/// <client>/
/// backend-auth/
/// pin.<id> PIN data, can be deleted with DeletePin or DeleteAllPins
/// ```
///
/// The storage location can be set when creating the backend, see [`AuthBackend::new`][] and
/// [`AuthBackend::with_hw_key`][].
#[derive(Clone, Debug)]
pub struct AuthBackend {
location: Location,
@@ -80,7 +94,7 @@ impl AuthBackend {
trussed_filestore: &mut impl Filestore,
rng: &mut R,
) -> Result<Salt, Error> {
let path = PathBuf::from(SALT_PATH);
let path = PathBuf::from(BACKEND_DIR).join(&PathBuf::from("salt"));
trussed_filestore
.read(&path, self.location)
.or_else(|_| {
@@ -263,7 +277,7 @@ impl ExtensionImpl<AuthExtension> for AuthBackend {
Ok(reply::DeletePin.into())
}
AuthRequest::DeleteAllPins(_) => {
fs.remove_dir_all(&PathBuf::from(PIN_PATH), self.location)
fs.remove_dir_all(&PathBuf::from(BACKEND_DIR), self.location)
.map_err(|_| Error::WriteFailed)?;
Ok(reply::DeleteAllPins.into())
}
+29 -6
View File
@@ -1,7 +1,7 @@
// Copyright (C) Nitrokey GmbH
// SPDX-License-Identifier: Apache-2.0 or MIT
#![no_std]
#![cfg_attr(not(test), no_std)]
#![warn(
missing_debug_implementations,
missing_docs,
@@ -80,8 +80,7 @@ pub const MAX_PIN_LENGTH: usize = MAX_SHORT_DATA_LENGTH;
/// A PIN.
pub type Pin = Bytes<MAX_PIN_LENGTH>;
const PIN_PATH: &str = "backend-auth/pin";
const SALT_PATH: &str = "backend-auth/salt";
const BACKEND_DIR: &str = "backend-auth";
/// The ID of a PIN within the namespace of a client.
///
@@ -112,9 +111,18 @@ pub struct PinId(u8);
impl PinId {
fn path(&self) -> PathBuf {
let mut path = PathBuf::from(PIN_PATH);
path.push(&PathBuf::from(&self.hex()));
path
const PIN_PREFIX: &[u8] = b"/pin.";
const N: usize = BACKEND_DIR.len();
const M: usize = PIN_PREFIX.len();
let mut path = [0; N + M + 2];
let (backend_dir, rest) = path.split_at_mut(N);
let (pin, id) = rest.split_at_mut(M);
backend_dir.copy_from_slice(BACKEND_DIR.as_bytes());
pin.copy_from_slice(PIN_PREFIX);
id.copy_from_slice(&self.hex());
PathBuf::from(&path)
}
fn hex(&self) -> [u8; 2] {
@@ -137,3 +145,18 @@ impl From<PinId> for u8 {
id.0
}
}
#[cfg(test)]
mod tests {
use super::PinId;
use trussed::types::PathBuf;
quickcheck::quickcheck! {
fn test_pin_path(id: u8) -> bool {
let actual = PinId(id).path();
let expected = PathBuf::from(format!("backend-auth/pin.{id:02x}").as_str());
println!("id: {id}, actual: {actual}, expected: {expected}");
actual == expected
}
}
}