Add trussed-auth as backend dependency

This commit is contained in:
Sosthène Guédon
2023-04-11 14:10:07 +02:00
parent 34a8674929
commit e9b8077fc2
8 changed files with 226 additions and 26 deletions
+7 -4
View File
@@ -17,7 +17,7 @@ required-features = ["vpicc"]
[[example]]
name = "usbip"
required-features = ["apdu-dispatch"]
required-features = ["apdu-dispatch", "virt"]
[dependencies]
apdu-dispatch = { version = "0.1", optional = true }
@@ -29,6 +29,7 @@ interchange = "0.2.2"
iso7816 = "0.1"
serde = { version = "1", default-features = false, features = ["derive"] }
trussed = { version = "0.1" }
trussed-auth = { version = "0.2" }
untrusted = "0.9"
vpicc = { version = "0.1.0", optional = true }
log = "0.4"
@@ -52,7 +53,7 @@ stoppable_thread = "0.2.1"
expectrl = "0.6.0"
# Examples
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", default-features = false, features = ["ccid"], rev = "d2957b6c24c2b0cafbbfacd6fecd62c80943630b"}
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", default-features = false, features = ["ccid"], rev = "f3a680ca4c9a1411838ae0774f1713f79d4c2979"}
usbd-ccid = { version = "0.2.0", features = ["highspeed-usb"]}
rand = "0.8.5"
@@ -60,7 +61,8 @@ rand = "0.8.5"
default = []
strict-pin = []
std = []
vpicc = ["std", "dep:vpicc", "trussed-rsa-alloc/virt"]
vpicc = ["std", "dep:vpicc", "virt"]
virt = ["std"]
pivy-tests = []
opensc-tests = []
@@ -72,7 +74,8 @@ log-warn = []
log-error = []
[patch.crates-io]
trussed = { git = "https://github.com/Nitrokey/trussed", tag = "v0.1.0-nitrokey.8"}
trussed = { git = "https://github.com/Nitrokey/trussed", tag = "v0.1.0-nitrokey.8"}
trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.2.1"}
littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-2" }
[profile.dev.package.rsa]
+20 -11
View File
@@ -3,9 +3,15 @@
use trussed::virt::{self, Ram, UserInterface};
use trussed::{ClientImplementation, Platform};
use trussed_usbip::ClientBuilder;
use piv_authenticator as piv;
use trussed_usbip::Syscall;
use piv_authenticator::{
self as piv,
virt::dispatch::{self, Dispatch},
};
type VirtClient =
ClientImplementation<trussed_usbip::Service<Ram, dispatch::Dispatch>, dispatch::Dispatch>;
const MANUFACTURER: &str = "Nitrokey";
const PRODUCT: &str = "Nitrokey 3";
@@ -13,16 +19,17 @@ const VID: u16 = 0x20a0;
const PID: u16 = 0x42b2;
struct PivApp {
piv: piv::Authenticator<ClientImplementation<Syscall<virt::Platform<Ram>>>>,
piv: piv::Authenticator<VirtClient>,
}
impl trussed_usbip::Apps<ClientImplementation<Syscall<virt::Platform<Ram>>>, ()> for PivApp {
fn new(
make_client: impl Fn(&str) -> ClientImplementation<Syscall<virt::Platform<Ram>>>,
_data: (),
) -> Self {
impl trussed_usbip::Apps<VirtClient, Dispatch> for PivApp {
type Data = ();
fn new<B: ClientBuilder<VirtClient, Dispatch>>(builder: &B, _data: ()) -> Self {
PivApp {
piv: piv::Authenticator::new(make_client("piv"), piv::Options::default()),
piv: piv::Authenticator::new(
builder.build("piv", dispatch::BACKENDS),
piv::Options::default(),
),
}
}
@@ -44,11 +51,13 @@ fn main() {
vid: VID,
pid: PID,
};
trussed_usbip::Runner::new(virt::Ram::default(), options)
trussed_usbip::Builder::new(virt::Ram::default(), options)
.dispatch(Dispatch::new())
.init_platform(move |platform| {
let ui: Box<dyn trussed::platform::UserInterface + Send + Sync> =
Box::new(UserInterface::new());
platform.user_interface().set_inner(ui);
})
.exec::<PivApp, _, _>(|_platform| {});
.build::<PivApp>()
.exec(|_platform| {});
}
+2 -2
View File
@@ -11,12 +11,12 @@
// TODO: add CLI
use piv_authenticator::{Authenticator, Options};
use piv_authenticator::{virt::with_ram_client, Authenticator, Options};
fn main() {
env_logger::init();
trussed_rsa_alloc::virt::with_ram_client("piv-authenticator", |client| {
with_ram_client("piv-authenticator", |client| {
let card = Authenticator::new(client, Options::default());
let mut vpicc_card = piv_authenticator::vpicc::VpiccCard::new(card);
let vpicc = vpicc::connect().expect("failed to connect to vpicc");
+2
View File
@@ -28,6 +28,8 @@ mod tlv;
pub use piv_types::{AsymmetricAlgorithms, Pin, Puk};
#[cfg(feature = "virt")]
pub mod virt;
#[cfg(feature = "vpicc")]
pub mod vpicc;
+183
View File
@@ -0,0 +1,183 @@
// Copyright (C) 2022 Nitrokey GmbH
// SPDX-License-Identifier: LGPL-3.0-only
//! Virtual trussed client (mostly for testing)
pub mod dispatch {
use trussed::{
api::{reply, request, Reply, Request},
backend::{Backend as _, BackendId},
error::Error,
platform::Platform,
serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl as _},
service::ServiceResources,
types::{Bytes, Context, Location},
};
use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN};
use trussed_rsa_alloc::SoftwareRsa;
/// Backends used by opcard
pub const BACKENDS: &[BackendId<Backend>] = &[
BackendId::Custom(Backend::Auth),
BackendId::Custom(Backend::Rsa),
BackendId::Core,
];
#[derive(Debug, Clone, Copy)]
pub enum Backend {
Auth,
Rsa,
}
#[derive(Debug, Clone, Copy)]
pub enum Extension {
Auth,
}
impl From<Extension> for u8 {
fn from(extension: Extension) -> Self {
match extension {
Extension::Auth => 0,
}
}
}
impl TryFrom<u8> for Extension {
type Error = Error;
fn try_from(id: u8) -> Result<Self, Self::Error> {
match id {
0 => Ok(Extension::Auth),
_ => Err(Error::InternalError),
}
}
}
/// Dispatch implementation with the backends required by opcard
#[derive(Debug)]
pub struct Dispatch {
auth: AuthBackend,
}
/// Dispatch context for the backends required by opcard
#[derive(Default, Debug)]
pub struct DispatchContext {
auth: AuthContext,
}
impl Dispatch {
pub fn new() -> Self {
Self {
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 Default for Dispatch {
fn default() -> Self {
Self::new()
}
}
impl ExtensionDispatch for Dispatch {
type BackendId = Backend;
type Context = DispatchContext;
type ExtensionId = Extension;
fn core_request<P: Platform>(
&mut self,
backend: &Self::BackendId,
ctx: &mut Context<Self::Context>,
request: &Request,
resources: &mut ServiceResources<P>,
) -> Result<Reply, Error> {
match backend {
Backend::Auth => {
self.auth
.request(&mut ctx.core, &mut ctx.backends.auth, request, resources)
}
Backend::Rsa => SoftwareRsa.request(&mut ctx.core, &mut (), request, resources),
}
}
fn extension_request<P: Platform>(
&mut self,
backend: &Self::BackendId,
extension: &Self::ExtensionId,
ctx: &mut Context<Self::Context>,
request: &request::SerdeExtension,
resources: &mut ServiceResources<P>,
) -> Result<reply::SerdeExtension, Error> {
match backend {
Backend::Auth => match extension {
Extension::Auth => self.auth.extension_request_serialized(
&mut ctx.core,
&mut ctx.backends.auth,
request,
resources,
),
},
Backend::Rsa => Err(Error::RequestNotAvailable),
}
}
}
impl ExtensionId<AuthExtension> for Dispatch {
type Id = Extension;
const ID: Self::Id = Self::Id::Auth;
}
}
use std::path::PathBuf;
use trussed::{
types::Bytes,
virt::{self, Client, Filesystem, Ram, StoreProvider},
};
/// Client type using a dispatcher with the backends required by opcard
pub type VirtClient<S> = Client<S, dispatch::Dispatch>;
/// Run a client using a provided store
pub fn with_client<S, R, F>(store: S, client_id: &str, f: F) -> R
where
F: FnOnce(VirtClient<S>) -> R,
S: StoreProvider,
{
#[allow(clippy::unwrap_used)]
virt::with_platform(store, |platform| {
platform.run_client_with_backends(
client_id,
dispatch::Dispatch::with_hw_key(Bytes::from_slice(b"some bytes").unwrap()),
dispatch::BACKENDS,
f,
)
})
}
/// Run the backend with the extensions required by opcard
/// using storage backed by a file
pub fn with_fs_client<P, R, F>(internal: P, client_id: &str, f: F) -> R
where
F: FnOnce(VirtClient<Filesystem>) -> R,
P: Into<PathBuf>,
{
with_client(Filesystem::new(internal), client_id, f)
}
/// Run the backend with the extensions required by opcard
/// using a RAM file storage
pub fn with_ram_client<R, F>(client_id: &str, f: F) -> R
where
F: FnOnce(VirtClient<Ram>) -> R,
{
with_client(Ram::default(), client_id, f)
}
+4 -3
View File
@@ -3,7 +3,8 @@
use iso7816::{command::FromSliceError, Command, Status};
use trussed::virt::Ram;
use trussed_rsa_alloc::virt::Client;
use crate::virt::VirtClient;
use std::convert::{TryFrom, TryInto};
@@ -19,12 +20,12 @@ const RESPONSE_LEN: usize = 7609;
pub struct VpiccCard {
request_buffer: RequestBuffer<REQUEST_LEN>,
response_buffer: ResponseBuffer<RESPONSE_LEN>,
card: Authenticator<Client<Ram>>,
card: Authenticator<VirtClient<Ram>>,
}
impl VpiccCard {
/// Creates a new virtual smart card from the given card.
pub fn new(card: Authenticator<Client<Ram>>) -> Self {
pub fn new(card: Authenticator<VirtClient<Ram>>) -> Self {
Self {
request_buffer: Default::default(),
response_buffer: Default::default(),
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright (C) 2022 Nitrokey GmbH
// SPDX-License-Identifier: LGPL-3.0-only
use piv_authenticator::{vpicc::VpiccCard, Authenticator, Options};
use piv_authenticator::{virt::with_ram_client, vpicc::VpiccCard, Authenticator, Options};
use std::{sync::mpsc, thread::sleep, time::Duration};
use stoppable_thread::spawn;
@@ -17,7 +17,7 @@ pub fn with_vsc<F: FnOnce() -> R, R>(f: F) -> R {
let (tx, rx) = mpsc::channel();
let handle = spawn(move |stopped| {
trussed_rsa_alloc::virt::with_ram_client("opcard", |client| {
with_ram_client("opcard", |client| {
let card = Authenticator::new(client, Options::default());
let mut vpicc_card = VpiccCard::new(card);
let mut result = Ok(());
+6 -4
View File
@@ -11,14 +11,16 @@ macro_rules! cmd {
};
}
use piv_authenticator::{Authenticator, Options};
use piv_authenticator::{
virt::{with_ram_client, VirtClient},
Authenticator, Options,
};
use trussed::virt::Ram;
use trussed_rsa_alloc::virt::Client;
pub type Piv = piv_authenticator::Authenticator<Client<Ram>>;
pub type Piv = piv_authenticator::Authenticator<VirtClient<Ram>>;
pub fn piv<R>(test: impl FnOnce(&mut Piv) -> R) -> R {
trussed_rsa_alloc::virt::with_ram_client("test", |client| {
with_ram_client("test", |client| {
let mut piv_app = Authenticator::new(client, Options::default());
test(&mut piv_app)
})