mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Add a setter for the UUID in the builder
This commit is contained in:
+12
-5
@@ -57,6 +57,12 @@ pub struct Options {
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
storage: Location::External,
|
||||
label: NITROKEY_APPLICATION_LABEL,
|
||||
@@ -64,18 +70,19 @@ impl Default for Options {
|
||||
uuid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn storage(self, storage: Location) -> Self {
|
||||
pub const fn storage(self, storage: Location) -> Self {
|
||||
Self { storage, ..self }
|
||||
}
|
||||
pub fn url(self, url: &'static [u8]) -> Self {
|
||||
pub const fn url(self, url: &'static [u8]) -> Self {
|
||||
Self { url, ..self }
|
||||
}
|
||||
pub fn label(self, label: &'static [u8]) -> Self {
|
||||
pub const fn label(self, label: &'static [u8]) -> Self {
|
||||
Self { label, ..self }
|
||||
}
|
||||
pub const fn uuid(self, uuid: Option<[u8; 16]>) -> Self {
|
||||
Self { uuid, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
/// PIV authenticator Trussed app.
|
||||
|
||||
+5
-2
@@ -10,7 +10,10 @@ use std::sync::Mutex;
|
||||
|
||||
static VSC_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
pub fn with_vsc<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
pub const WITH_UUID: Options = Options::new().uuid(Some([0; 16]));
|
||||
pub const WITHOUT_UUID: Options = Options::new();
|
||||
|
||||
pub fn with_vsc<F: FnOnce() -> R, R>(options: Options, f: F) -> R {
|
||||
let _lock = VSC_MUTEX.lock().unwrap();
|
||||
|
||||
let mut vpicc = vpicc::connect().expect("failed to connect to vpcd");
|
||||
@@ -18,7 +21,7 @@ pub fn with_vsc<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let handle = spawn(move |stopped| {
|
||||
with_ram_client("opcard", |client| {
|
||||
let card = Authenticator::new(client, Options::default());
|
||||
let card = Authenticator::new(client, options);
|
||||
let mut vpicc_card = VpiccCard::new(card);
|
||||
let mut result = Ok(());
|
||||
while !stopped.get() && result.is_ok() {
|
||||
|
||||
@@ -140,4 +140,50 @@
|
||||
Reset(),
|
||||
]
|
||||
),
|
||||
IoTest(
|
||||
name: "UUID",
|
||||
uuid_config: None,
|
||||
cmd_resp: [
|
||||
GetData(
|
||||
input: "5C 03 5FC102",
|
||||
output: Len(61),
|
||||
),
|
||||
AuthenticateManagement(
|
||||
key: (
|
||||
algorithm: Tdes,
|
||||
key: "0102030405060708 0102030405060708 0102030405060708"
|
||||
)
|
||||
),
|
||||
PutData(
|
||||
input: "5C 03 5FC102 53 3b 3019d4e739d821086c1084210d8360d8210842108421804210c3f3341000112233445566778899aabbccddeeff350839393939313233313e00fe00",
|
||||
),
|
||||
GetData(
|
||||
input: "5C 03 5FC102",
|
||||
output: Data("53 3b 3019d4e739d821086c1084210d8360d8210842108421804210c3f3341000112233445566778899aabbccddeeff350839393939313233313e00fe00"),
|
||||
),
|
||||
]
|
||||
),
|
||||
IoTest(
|
||||
name: "With UUID",
|
||||
uuid_config: WithUuid("00112233445566778899AABBCCDDEEFF"),
|
||||
cmd_resp: [
|
||||
GetData(
|
||||
input: "5C 03 5FC102",
|
||||
output: Data("53 3b 3019d4e739d821086c1084210d8360d8210842108421804210c3f3341000112233445566778899aabbccddeeff350839393939313233313e00fe00"),
|
||||
),
|
||||
AuthenticateManagement(
|
||||
key: (
|
||||
algorithm: Tdes,
|
||||
key: "0102030405060708 0102030405060708 0102030405060708"
|
||||
)
|
||||
),
|
||||
PutData(
|
||||
input: "5C 03 5FC102 53 3b 3019d4e739d821086c1084210d8360d8210842108421804210c3f33410B0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB30839393939313233313e00fe00",
|
||||
),
|
||||
GetData(
|
||||
input: "5C 03 5FC102",
|
||||
output: Data("53 3b 3019d4e739d821086c1084210d8360d8210842108421804210c3f33410B0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB30839393939313233313e00fe00"),
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -191,6 +191,8 @@ impl TryFrom<u16> for Status {
|
||||
struct IoTest {
|
||||
name: String,
|
||||
cmd_resp: Vec<IoCmd>,
|
||||
#[serde(default)]
|
||||
uuid_config: UuidConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -394,7 +396,11 @@ impl IoCmd {
|
||||
.map(Into::into)
|
||||
.unwrap_or_default();
|
||||
|
||||
println!("Output: {:?}\nStatus: {status:?}", hex::encode(&rep));
|
||||
println!(
|
||||
"Output({}): {:?}\nStatus: {status:?}",
|
||||
rep.len(),
|
||||
hex::encode(&rep)
|
||||
);
|
||||
|
||||
if !output.validate(&rep) {
|
||||
panic!("Bad output. Expected {output:02x?}");
|
||||
@@ -532,6 +538,19 @@ impl IoCmd {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
||||
enum UuidConfig {
|
||||
None,
|
||||
WithUuid(String),
|
||||
WithBoth(String),
|
||||
}
|
||||
|
||||
impl Default for UuidConfig {
|
||||
fn default() -> Self {
|
||||
Self::WithBoth("00".repeat(16))
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn command_response() {
|
||||
let data = std::fs::read_to_string("tests/command_response.ron").unwrap();
|
||||
@@ -539,10 +558,26 @@ fn command_response() {
|
||||
for t in tests {
|
||||
println!("\n\n===========================================================",);
|
||||
println!("Running {}", t.name);
|
||||
setup::piv(|card| {
|
||||
for io in t.cmd_resp {
|
||||
io.run(card);
|
||||
if matches!(t.uuid_config, UuidConfig::None | UuidConfig::WithBoth(_)) {
|
||||
println!("Running {} without uuid", t.name);
|
||||
setup::piv(setup::WITHOUT_UUID, |card| {
|
||||
for io in &t.cmd_resp {
|
||||
io.run(card);
|
||||
}
|
||||
});
|
||||
}
|
||||
match t.uuid_config {
|
||||
UuidConfig::WithUuid(uuid) | UuidConfig::WithBoth(uuid) => {
|
||||
println!("Running {} with uuid {uuid:?}", t.name);
|
||||
let uuid = (&*parse_hex(&uuid)).try_into().unwrap();
|
||||
|
||||
setup::piv(piv_authenticator::Options::new().uuid(Some(uuid)), |card| {
|
||||
for io in &t.cmd_resp {
|
||||
io.run(card);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (C) 2022 Nicolas Stalder AND Nitrokey GmbH
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
mod setup;
|
||||
|
||||
// example: 00 47 00 9A 0B
|
||||
// AC 09
|
||||
// # P256
|
||||
// 80 01 11
|
||||
// # 0xAA = Yubico extension (of course...), PinPolicy, 0x2 =
|
||||
// AA 01 02
|
||||
// # 0xAB = Yubico extension (of course...), TouchPolicy, 0x2 =
|
||||
// AB 01 02
|
||||
|
||||
#[test_log::test]
|
||||
fn gen_keypair() {
|
||||
let _cmd = cmd!("00 47 00 9A 0B AC 09 80 01 11 AA 01 02 AB 01 02");
|
||||
|
||||
// without PIN, no key generation
|
||||
setup::piv(|_piv| {
|
||||
// not currently implemented
|
||||
//
|
||||
// let mut response = iso7816::Data::<16>::default();
|
||||
// assert_eq!(Err(SecurityStatusNotSatisfied), piv.respond(&cmd, &mut response));
|
||||
});
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (C) 2022 Nicolas Stalder AND Nitrokey GmbH
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
mod setup;
|
||||
|
||||
// use delog::hex_str;
|
||||
// use iso7816::Status::*;
|
||||
|
||||
#[test_log::test]
|
||||
fn get_data() {
|
||||
// let cmd = cmd!("00 47 00 9A 0B AC 09 80 01 11 AA 01 02 AB 01 02");
|
||||
// let cmd = cmd!("00 47 00 9A 0B AC 09 80 01 11 AA 01 02 AB 01 02");
|
||||
|
||||
// let cmd = cmd!("00 f8 00 00");
|
||||
// // without PIN, no key generation
|
||||
setup::piv(|_piv| {
|
||||
|
||||
// ykGetSerial
|
||||
// println!("{}", hex_str!(&piv.respond(&cmd!("00 f8 00 00")).unwrap()));
|
||||
// panic!();
|
||||
// let mut response = iso7816::Data::<16>::default();
|
||||
// piv.respond(&cmd!("00 f8 00 00"), &mut response).unwrap();
|
||||
// // assert_eq!([].as_ref(), piv.respond(&cmd!("00 f8 00 00")).unwrap());
|
||||
// // ykGetVersion
|
||||
// piv.respond(&cmd!("00 fd 00 00"), &mut response).unwrap();
|
||||
});
|
||||
}
|
||||
+21
-10
@@ -7,25 +7,27 @@ mod card;
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
use card::with_vsc;
|
||||
use card::{with_vsc, WITHOUT_UUID, WITH_UUID};
|
||||
|
||||
use expectrl::{spawn, Eof, WaitStatus};
|
||||
|
||||
#[test_log::test]
|
||||
fn list() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut p = spawn("piv-tool -n").unwrap();
|
||||
p.expect("Using reader with a card: Virtual PCD 00 00")
|
||||
.unwrap();
|
||||
p.expect("Personal Identity Verification Card").unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn admin_mutual() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut command = Command::new("piv-tool");
|
||||
command
|
||||
.env("PIV_EXT_AUTH_KEY", "tests/default_admin_key")
|
||||
@@ -36,14 +38,16 @@ fn admin_mutual() {
|
||||
// p.expect("Personal Identity Verification Card").unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
/// Fails because of https://github.com/OpenSC/OpenSC/issues/2658
|
||||
#[test_log::test]
|
||||
#[ignore]
|
||||
fn admin_card() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut command = Command::new("piv-tool");
|
||||
command
|
||||
.env("PIV_EXT_AUTH_KEY", "tests/default_admin_key")
|
||||
@@ -54,12 +58,14 @@ fn admin_card() {
|
||||
p.expect("Personal Identity Verification Card").unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn generate_key() {
|
||||
// with_vsc(|| {
|
||||
// let test = || {
|
||||
// let mut command = Command::new("piv-tool");
|
||||
// command
|
||||
// .env("PIV_EXT_AUTH_KEY", "tests/default_admin_key")
|
||||
@@ -71,7 +77,10 @@ fn generate_key() {
|
||||
// // Non zero exit code?
|
||||
// assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 1));
|
||||
// });
|
||||
// with_vsc(|| {
|
||||
// with_vsc(WITH_UUID, test);
|
||||
// with_vsc(WITHOUT_UUID, test);
|
||||
|
||||
// let test = || {
|
||||
// let mut command = Command::new("piv-tool");
|
||||
// command
|
||||
// .env("PIV_EXT_AUTH_KEY", "tests/default_admin_key")
|
||||
@@ -82,5 +91,7 @@ fn generate_key() {
|
||||
// p.expect(Eof).unwrap();
|
||||
// // Non zero exit code?
|
||||
// assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 1));
|
||||
// });
|
||||
// };
|
||||
// with_vsc(WITH_UUID, test);
|
||||
// with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
+22
-11
@@ -5,7 +5,7 @@
|
||||
|
||||
mod card;
|
||||
|
||||
use card::with_vsc;
|
||||
use card::{with_vsc, WITHOUT_UUID, WITH_UUID};
|
||||
|
||||
use expectrl::{spawn, Eof, Regex, WaitStatus};
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::process::{Command, Stdio};
|
||||
|
||||
#[test_log::test]
|
||||
fn list() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut p = spawn("pivy-tool list").unwrap();
|
||||
p.expect(Regex("card: [0-9A-Z]*")).unwrap();
|
||||
p.expect("device: Virtual PCD 00 00").unwrap();
|
||||
@@ -24,12 +24,14 @@ fn list() {
|
||||
.unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn generate() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut p = spawn("pivy-tool -A 3des -K 010203040506070801020304050607080102030405060708 generate 9A -a eccp256 -P 123456").unwrap();
|
||||
p.expect(Regex(
|
||||
"ecdsa-sha2-nistp256 (?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)? PIV_slot_9A@[A-F0-9]{20}",
|
||||
@@ -37,8 +39,11 @@ fn generate() {
|
||||
.unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
with_vsc(|| {
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
|
||||
let test = || {
|
||||
let mut p = spawn("pivy-tool -A 3des -K 010203040506070801020304050607080102030405060708 generate 9A -a rsa2048 -P 123456").unwrap();
|
||||
p.expect(Regex(
|
||||
"ssh-rsa (?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)? PIV_slot_9A@[A-F0-9]{20}",
|
||||
@@ -46,12 +51,14 @@ fn generate() {
|
||||
.unwrap();
|
||||
p.expect(Eof).unwrap();
|
||||
assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn ecdh() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut p = spawn("pivy-tool -A 3des -K 010203040506070801020304050607080102030405060708 generate 9A -a eccp256 -P 123456").unwrap();
|
||||
p.expect(Regex(
|
||||
"ecdsa-sha2-nistp256 (?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)? PIV_slot_9A@[A-F0-9]{20}",
|
||||
@@ -74,7 +81,9 @@ fn ecdh() {
|
||||
drop(stdin);
|
||||
|
||||
assert_eq!(p.wait().unwrap().code(), Some(0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
const LARGE_CERT: &str = "-----BEGIN CERTIFICATE-----
|
||||
@@ -122,7 +131,7 @@ N4vF6RP8Ck9wj1OYq/w82MkgxOPleUju4Q==
|
||||
|
||||
#[test_log::test]
|
||||
fn large_cert() {
|
||||
with_vsc(|| {
|
||||
let test = || {
|
||||
let mut p = Command::new("pivy-tool")
|
||||
.args(["write-cert", "9A"])
|
||||
.stdin(Stdio::piped())
|
||||
@@ -145,5 +154,7 @@ fn large_cert() {
|
||||
stdout.read_to_string(&mut buf).unwrap();
|
||||
assert_eq!(&buf, LARGE_CERT);
|
||||
assert_eq!(p.wait().unwrap().code(), Some(0));
|
||||
});
|
||||
};
|
||||
with_vsc(WITH_UUID, test);
|
||||
with_vsc(WITHOUT_UUID, test);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (C) 2022 Nicolas Stalder AND Nitrokey GmbH
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
mod setup;
|
||||
|
||||
// use apdu_dispatch::dispatch::Interface::Contact;
|
||||
// use apdu_dispatch::app::App as _;
|
||||
// use hex_literal::hex;
|
||||
// use iso7816::Command;
|
||||
|
||||
// # PutData
|
||||
// 00 DB 3F FF 23
|
||||
// # data object: 5FC109
|
||||
// 5C 03 5F C1 09
|
||||
// # data:
|
||||
// 53 1C
|
||||
// # actual data
|
||||
// 88 1A 89 18 AA 81 D5 48 A5 EC 26 01 60 BA 06 F6 EC 3B B6 05 00 2E B6 3D 4B 28 7F 86
|
||||
|
||||
#[test_log::test]
|
||||
fn put_data() {
|
||||
setup::piv(|_piv| {
|
||||
|
||||
// let mut response = iso7816::Data::<16>::default();
|
||||
// piv.respond(&cmd!(
|
||||
// "00 DB 3F FF 23 5C 03 5F C1 09 53 1C 88 1A 89 18 AA 81 D5 48 A5 EC 26 01 60 BA 06 F6 EC 3B B6 05 00 2E B6 3D 4B 28 7F 86"
|
||||
// ), &mut response).unwrap();
|
||||
});
|
||||
}
|
||||
+4
-2
@@ -19,9 +19,11 @@ use trussed::virt::Ram;
|
||||
|
||||
pub type Piv = piv_authenticator::Authenticator<VirtClient<Ram>>;
|
||||
|
||||
pub fn piv<R>(test: impl FnOnce(&mut Piv) -> R) -> R {
|
||||
pub const WITHOUT_UUID: Options = Options::new();
|
||||
|
||||
pub fn piv<R>(options: Options, test: impl FnOnce(&mut Piv) -> R) -> R {
|
||||
with_ram_client("test", |client| {
|
||||
let mut piv_app = Authenticator::new(client, Options::default());
|
||||
let mut piv_app = Authenticator::new(client, options);
|
||||
test(&mut piv_app)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user