Skip to content

Commit

Permalink
Merge branch 'put-data'
Browse files Browse the repository at this point in the history
  • Loading branch information
sosthene-nitrokey committed Mar 20, 2023
2 parents 1e1d990 + 17d9565 commit 9a4d0ba
Show file tree
Hide file tree
Showing 27 changed files with 2,355 additions and 786 deletions.
7 changes: 7 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: piv-authenticator
Source: https://github.com/Nitrokey/piv-authenticator

Files: tests/default_admin_key
Copyright: 2022 Nitrokey GmbH
License: LGPL-3.0-only
33 changes: 29 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ documentation = "https://docs.rs/piv-authenticator"
name = "virtual"
required-features = ["virtual"]


[[example]]
name = "usbip"
required-features = ["apdu-dispatch"]

[dependencies]
apdu-dispatch = { version = "0.1", optional = true }
delog = { version = "0.1.5", optional = true }
Expand All @@ -23,11 +28,13 @@ hex-literal = "0.3"
interchange = "0.2.2"
iso7816 = "0.1"
serde = { version = "1", default-features = false, features = ["derive"] }
trussed = "0.1"
trussed = { version = "0.1" }
untrusted = "0.9"
vpicc = { version = "0.1.0", optional = true }
log = "0.4"
heapless-bytes = "0.3.0"
subtle = { version = "2", default-features = false }
trussed-rsa-alloc = { git = "https://github.com/Nitrokey/trussed-rsa-backend.git", rev = "e29b26ab3800217b7eb73ecde67134bbb3acb9da", features = ["raw"] }

[dev-dependencies]
littlefs2 = "0.3.2"
Expand All @@ -37,15 +44,25 @@ env_logger = "0.9"
serde = { version = "1", features = ["derive"] }
serde_cbor = { version = "0.11", features = ["std"] }
hex = "0.4"
test-log = "0.2"
test-log = "0.2.11"
ron = "0.8"
des = "0.8"
aes = "0.8.2"
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"}
usbd-ccid = { version = "0.2.0", features = ["highspeed-usb"]}
rand = "0.8.5"

[features]
default = []
strict-pin = []
std = []
virtual = ["std", "vpicc","trussed/virt"]
virtual = ["std", "vpicc", "trussed-rsa-alloc/virt"]
pivy-tests = []
opensc-tests = []

log-all = []
log-none = []
Expand All @@ -55,4 +72,12 @@ log-warn = []
log-error = []

[patch.crates-io]
trussed = { git = "https://github.com/trussed-dev/trussed", rev = "28478f8abed11d78c51e6a6a32326821ed61957a"}
# trussed = { git = "https://github.com/Nitrokey/trussed", tag = "v0.1.0-nitrokey-4"}
trussed = { git = "https://github.com/trussed-dev/trussed", rev = "d9276a689d68ffeb4c5d9ac635b18232be172f45"}
# littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-1" }

[profile.dev.package.rsa]
opt-level = 2

[profile.dev.package.num-bigint-dig]
opt-level = 2
13 changes: 9 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,36 @@
.NOTPARALLEL:

export RUST_LOG ?= info,cargo_tarpaulin=off
TEST_FEATURES ?=virtual,pivy-tests,opensc-tests

.PHONY: build-cortex-m4
build-cortex-m4:
cargo build --target thumbv7em-none-eabi

.PHONY: test
test:
cargo test --features virtual
cargo test --features $(TEST_FEATURES)

.PHONY: check
check:
RUSTLFAGS='-Dwarnings' cargo check --all-features --all-targets

.PHONY: lint
lint:
cargo fmt --check
cargo check --all-targets --all-features
RUSTLFAGS='-Dwarnings' cargo check --all-features --all-targets
cargo clippy --all-targets --all-features -- -Dwarnings
RUSTDOCFLAGS='-Dwarnings' cargo doc --all-features
reuse lint

.PHONY: tarpaulin
tarpaulin:
cargo tarpaulin --features virtual -o Html -o Xml
cargo tarpaulin --features $(TEST_FEATURES) -o Html -o Xml

.PHONY: example
example:
cargo run --example virtual --features virtual

.PHONY: ci
ci: check tarpaulin
ci: lint tarpaulin

12 changes: 11 additions & 1 deletion ci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@

FROM docker.io/rust:latest

RUN apt update && apt install --yes scdaemon libclang-dev llvm python3-pip vsmartcard-vpcd pkg-config nettle-dev libpcsclite-dev
RUN apt update && apt install --yes libpcsclite-dev \
&& wget https://github.com/arekinath/pivy/releases/download/v0.10.0/pivy-0.10.0-src.tar.gz \
&& tar xvf pivy-0.10.0-src.tar.gz \
&& cd pivy-0.10.0 \
&& make pivy-tool

FROM docker.io/rust:latest

RUN apt update && apt install --yes scdaemon libclang-dev llvm python3-pip vsmartcard-vpcd pkg-config nettle-dev libpcsclite-dev opensc

RUN python3 -m pip install reuse

Expand All @@ -14,6 +22,8 @@ RUN cargo search

ENV CARGO_HOME=/app/.cache/cargo

COPY --from=0 pivy-0.10.0/pivy-tool /bin/pivy-tool

WORKDIR /app

COPY entrypoint.sh /entrypoint.sh
Expand Down
54 changes: 54 additions & 0 deletions examples/usbip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (C) 2022 Nitrokey GmbH
// SPDX-License-Identifier: CC0-1.0

use trussed::virt::{self, Ram, UserInterface};
use trussed::{ClientImplementation, Platform};

use piv_authenticator as piv;
use trussed_usbip::Syscall;

const MANUFACTURER: &str = "Nitrokey";
const PRODUCT: &str = "Nitrokey 3";
const VID: u16 = 0x20a0;
const PID: u16 = 0x42b2;

struct PivApp {
piv: piv::Authenticator<ClientImplementation<Syscall<virt::Platform<Ram>>>>,
}

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 {
PivApp {
piv: piv::Authenticator::new(make_client("piv")),
}
}

fn with_ccid_apps<T>(
&mut self,
f: impl FnOnce(&mut [&mut dyn apdu_dispatch::App<7609, 7609>]) -> T,
) -> T {
f(&mut [&mut self.piv])
}
}

fn main() {
env_logger::init();

let options = trussed_usbip::Options {
manufacturer: Some(MANUFACTURER.to_owned()),
product: Some(PRODUCT.to_owned()),
serial_number: Some("TEST".into()),
vid: VID,
pid: PID,
};
trussed_usbip::Runner::new(virt::Ram::default(), options)
.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| {});
}
2 changes: 1 addition & 1 deletion examples/virtual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
fn main() {
env_logger::init();

trussed::virt::with_ram_client("piv-authenticator", |client| {
trussed_rsa_alloc::virt::with_ram_client("piv-authenticator", |client| {
let card = piv_authenticator::Authenticator::new(client);
let mut virtual_card = piv_authenticator::vpicc::VirtualCard::new(card);
let vpicc = vpicc::connect().expect("failed to connect to vpicc");
Expand Down
83 changes: 60 additions & 23 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ use core::convert::{TryFrom, TryInto};
// use flexiber::Decodable;
use iso7816::{Instruction, Status};

use crate::container::{Container, KeyReference};

use crate::state::TouchPolicy;
pub use crate::{
container::{
self as containers, AttestKeyReference, AuthenticateKeyReference,
ChangeReferenceKeyReference, GenerateAsymmetricKeyReference, VerifyKeyReference,
self as containers, AsymmetricKeyReference, AttestKeyReference, AuthenticateKeyReference,
ChangeReferenceKeyReference, GenerateKeyReference, VerifyKeyReference,
},
piv_types, Pin, Puk,
};
Expand All @@ -30,7 +32,7 @@ pub enum YubicoPivExtension {
SetPinRetries,
Attest(AttestKeyReference),
GetSerial, // also used via 0x01
GetMetadata,
GetMetadata(KeyReference),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand All @@ -51,23 +53,23 @@ pub enum Command<'l> {
/// Change PIN or PUK
ChangeReference(ChangeReference),
/// If the PIN is blocked, reset it using the PUK
ResetPinRetries(ResetPinRetries),
ResetRetryCounter(ResetRetryCounter),
/// The most general purpose method, performing actual cryptographic operations
///
/// In particular, this can also decrypt or similar.
GeneralAuthenticate(GeneralAuthenticate),
/// Store a data object / container.
PutData(PutData),
GenerateAsymmetric(GenerateAsymmetricKeyReference),
PutData(PutData<'l>),
GenerateAsymmetric(GenerateKeyReference),

/* Yubico commands */
YkExtension(YubicoPivExtension),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GeneralAuthenticate {
algorithm: piv_types::Algorithms,
key_reference: AuthenticateKeyReference,
pub algorithm: piv_types::Algorithms,
pub key_reference: AuthenticateKeyReference,
}

impl<'l> Command<'l> {
Expand Down Expand Up @@ -111,8 +113,7 @@ impl TryFrom<&[u8]> for GetData {
if tagged_slice.tag() != flexiber::Tag::application(0x1C) {
return Err(Status::IncorrectDataParameter);
}
let container: containers::Container = containers::Tag::new(tagged_slice.as_bytes())
.try_into()
let container = containers::Container::try_from(tagged_slice.as_bytes())
.map_err(|_| Status::IncorrectDataParameter)?;

info!("request to GetData for container {:?}", container);
Expand Down Expand Up @@ -218,19 +219,19 @@ impl TryFrom<ChangeReferenceArguments<'_>> for ChangeReference {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ResetPinRetries {
pub padded_pin: [u8; 8],
pub struct ResetRetryCounter {
pub pin: [u8; 8],
pub puk: [u8; 8],
}

impl TryFrom<&[u8]> for ResetPinRetries {
impl TryFrom<&[u8]> for ResetRetryCounter {
type Error = Status;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != 16 {
return Err(Status::IncorrectDataParameter);
}
Ok(Self {
padded_pin: data[..8].try_into().unwrap(),
pin: data[..8].try_into().unwrap(),
puk: data[8..].try_into().unwrap(),
})
}
Expand All @@ -246,12 +247,48 @@ pub struct AuthenticateArguments<'l> {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PutData {}
pub enum PutData<'data> {
DiscoveryObject(&'data [u8]),
BitGroupTemplate(&'data [u8]),
Any(Container, &'data [u8]),
}

impl TryFrom<&[u8]> for PutData {
impl<'data> TryFrom<&'data [u8]> for PutData<'data> {
type Error = Status;
fn try_from(_data: &[u8]) -> Result<Self, Self::Error> {
todo!();
fn try_from(data: &'data [u8]) -> Result<Self, Self::Error> {
use crate::tlv::take_do;
let (tag, inner, rem) = take_do(data).ok_or_else(|| {
warn!("Failed to parse PUT DATA: {:02x?}", data);
Status::IncorrectDataParameter
})?;
if matches!(tag, 0x7E | 0x7F61) && !rem.is_empty() {
warn!("Empty remainder expected, got: {:02x?}", rem);
}

let container: Container = match tag {
0x7E => return Ok(PutData::DiscoveryObject(inner)),
0x7F61 => return Ok(PutData::BitGroupTemplate(inner)),
0x5C => Container::try_from(inner).map_err(|_| Status::IncorrectDataParameter)?,
_ => return Err(Status::IncorrectDataParameter),
};

let (tag, inner, rem) = take_do(rem).ok_or_else(|| {
warn!(
"Failed to parse PUT DATA's second field: {:02x?}, {:02x?}",
data, rem
);
Status::IncorrectDataParameter
})?;

if !rem.is_empty() {
warn!("Empty second remainder expected, got: {:02x?}", rem);
}

if tag != 0x53 {
warn!("Expected 0x53 tag, got: 0x{:02x?}", rem);
}

Ok(PutData::Any(container, inner))
}
}

Expand Down Expand Up @@ -310,7 +347,7 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
}

(0x00, Instruction::ResetRetryCounter, 0x00, 0x80) => {
Self::ResetPinRetries(ResetPinRetries::try_from(data.as_slice())?)
Self::ResetRetryCounter(ResetRetryCounter::try_from(data.as_slice())?)
}

(0x00, Instruction::GeneralAuthenticate, p1, p2) => {
Expand All @@ -327,7 +364,7 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
}

(0x00, Instruction::GenerateAsymmetricKeyPair, 0x00, p2) => {
Self::GenerateAsymmetric(GenerateAsymmetricKeyReference::try_from(p2)?)
Self::GenerateAsymmetric(GenerateKeyReference::try_from(p2)?)
}
// (0x00, 0x01, 0x10, 0x00)
(0x00, Instruction::Unknown(0x01), 0x00, 0x00) => {
Expand Down Expand Up @@ -359,9 +396,9 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
(0x00, Instruction::Unknown(0xf8), _, _) => {
Self::YkExtension(YubicoPivExtension::GetSerial)
}
(0x00, Instruction::Unknown(0xf7), _, _) => {
Self::YkExtension(YubicoPivExtension::GetMetadata)
}
(0x00, Instruction::Unknown(0xf7), 0x00, reference) => Self::YkExtension(
YubicoPivExtension::GetMetadata(KeyReference::try_from(reference)?),
),

_ => return Err(Status::FunctionNotSupported),
})
Expand Down
Loading

0 comments on commit 9a4d0ba

Please sign in to comment.