diff --git a/Cargo.toml b/Cargo.toml index e2d1461..ae4e1d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ expectrl = "0.6.0" 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" +asn1 = "0.15.2" [features] default = [] diff --git a/src/lib.rs b/src/lib.rs index 28e1507..779ddbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -685,7 +685,7 @@ impl<'a, T: Client> LoadedAuthenticator<'a, T> { alg.sign_mechanism(), id, message, - trussed::types::SignatureSerialization::Raw, + alg.sign_serialization(), )) .signature; reply.expand(&[0x7C])?; diff --git a/src/piv_types.rs b/src/piv_types.rs index 595abe1..aa6e636 100644 --- a/src/piv_types.rs +++ b/src/piv_types.rs @@ -6,7 +6,7 @@ use core::convert::{TryFrom, TryInto}; use flexiber::Encodable; use hex_literal::hex; use serde::{Deserialize, Serialize}; -use trussed::types::Mechanism; +use trussed::types::{Mechanism, SignatureSerialization}; #[macro_export] macro_rules! enum_u8 { @@ -171,6 +171,13 @@ impl AsymmetricAlgorithms { } } + pub fn sign_serialization(self) -> SignatureSerialization { + match self { + Self::Rsa2048 | Self::Rsa4096 => SignatureSerialization::Raw, + Self::P256 => SignatureSerialization::Asn1Der, + } + } + pub fn is_rsa(self) -> bool { use AsymmetricAlgorithms::*; matches!(self, Rsa2048 | Rsa4096) diff --git a/tests/pivy.rs b/tests/pivy.rs index f81a9e5..ea9b15b 100644 --- a/tests/pivy.rs +++ b/tests/pivy.rs @@ -86,6 +86,65 @@ fn ecdh() { with_vsc(WITHOUT_UUID, test); } +#[test_log::test] +fn sign() { + let test_rsa = || { + let mut p = spawn(&format!("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}")).unwrap(); + p.expect(Eof).unwrap(); + assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0)); + + let mut p = Command::new("pivy-tool") + .args(["sign", "9A", "-P", "123456"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = p.stdin.take().unwrap(); + write!(stdin, "data").unwrap(); + drop(stdin); + + assert_eq!(p.wait().unwrap().code(), Some(0)); + }; + + let test_p256 = || { + let mut p = spawn(&format!("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}")).unwrap(); + p.expect(Eof).unwrap(); + assert_eq!(p.wait().unwrap(), WaitStatus::Exited(p.pid(), 0)); + + let mut p = Command::new("pivy-tool") + .args(["sign", "9A", "-P", "123456"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = p.stdin.take().unwrap(); + let mut stdout = p.stdout.take().unwrap(); + write!(stdin, "data").unwrap(); + drop(stdin); + + let mut out = Vec::new(); + stdout.read_to_end(&mut out).unwrap(); + // Check that the signature is an asn.1 sequence + let res: asn1::ParseResult<_> = asn1::parse(&out, |d| { + return d.read_element::()?.parse(|d| { + d.read_element::()?; + d.read_element::()?; + return Ok(()); + }); + }); + res.unwrap(); + + assert_eq!(p.wait().unwrap().code(), Some(0)); + }; + + let test = || (test_rsa(), test_p256()); + + with_vsc(WITH_UUID, test); + with_vsc(WITHOUT_UUID, test); +} + const LARGE_CERT: &str = "-----BEGIN CERTIFICATE----- MIIHNTCCBh2gAwIBAgIUBeJLVUnOULY3fhLvjaWOZe/qWfYwDQYJKoZIhvcNAQEL BQAwggIoMQswCQYDVQQGEwJURTGBizCBiAYDVQQIDIGAVEVTVFRFU1RURVNUVEVT