mirror of
https://github.com/trussed-dev/fido-authenticator.git
synced 2026-06-20 04:16:16 -07:00
Update to heapless 0.9 and trussed-core 0.2
This commit is contained in:
+12
-1
@@ -6,7 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
-
|
||||
- Update dependencies:
|
||||
- `apdu-app` v0.2
|
||||
- `cosey` v0.4
|
||||
- `ctap-types` v0.5
|
||||
- `ctaphid-app` v0.2
|
||||
- `heapless` v0.9
|
||||
- `heapless-bytes` v0.5
|
||||
- `iso7816` v0.2
|
||||
- `trussed-chunked` v0.3
|
||||
- `trussed-core` v0.2
|
||||
- `trussed-fs-info` v0.3
|
||||
- `trussed-hkdf` v0.4
|
||||
|
||||
## [v0.2.0](https://github.com/trussed-dev/fido-authenticator/releases/tag/v0.2.0) (2025-09-02)
|
||||
|
||||
|
||||
+19
-19
@@ -9,24 +9,24 @@ documentation = "https://docs.rs/fido-authenticator"
|
||||
description = "FIDO authenticator Trussed app"
|
||||
|
||||
[dependencies]
|
||||
apdu-app = { version = "0.1", optional = true }
|
||||
apdu-app = { version = "0.2", optional = true }
|
||||
cbor-smol = "0.5"
|
||||
cosey = "0.3"
|
||||
ctap-types = { version = "0.4", features = ["get-info-full", "large-blobs", "third-party-payment"] }
|
||||
ctaphid-app = { version = "0.1", optional = true }
|
||||
cosey = "0.4"
|
||||
ctap-types = { version = "0.5", features = ["get-info-full", "large-blobs", "third-party-payment"] }
|
||||
ctaphid-app = { version = "0.2", optional = true }
|
||||
delog = "0.1"
|
||||
heapless = "0.7"
|
||||
heapless-bytes = "0.3"
|
||||
iso7816 = { version = "0.1.2", optional = true }
|
||||
heapless = "0.9"
|
||||
heapless-bytes = { version = "0.5", features = ["heapless-0.9"]}
|
||||
iso7816 = { version = "0.2", optional = true }
|
||||
littlefs2-core = "0.1"
|
||||
serde = { version = "1.0", default-features = false }
|
||||
serde_bytes = { version = "0.11.14", default-features = false }
|
||||
serde-indexed = "0.1"
|
||||
sha2 = { version = "0.10", default-features = false }
|
||||
trussed-chunked = { version = "0.2", optional = true }
|
||||
trussed-core = { version = "0.1", features = ["aes256-cbc", "certificate-client", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "hmac-sha256", "management-client", "p256", "sha256", "ui-client"] }
|
||||
trussed-fs-info = "0.2"
|
||||
trussed-hkdf = "0.3"
|
||||
trussed-chunked = { version = "0.3", optional = true }
|
||||
trussed-core = { version = "0.2", features = ["aes256-cbc", "certificate-client", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "hmac-sha256", "management-client", "p256", "sha256", "ui-client"] }
|
||||
trussed-fs-info = "0.3"
|
||||
trussed-hkdf = "0.4"
|
||||
|
||||
[features]
|
||||
dispatch = ["apdu-dispatch", "ctaphid-dispatch", "dep:iso7816"]
|
||||
@@ -46,38 +46,38 @@ log-warn = []
|
||||
log-error = []
|
||||
|
||||
[dev-dependencies]
|
||||
admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20", features = ["migration-tests"] }
|
||||
admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.21", features = ["migration-tests"] }
|
||||
aes = "0.8.4"
|
||||
cbc = { version = "0.1.2", features = ["alloc"] }
|
||||
ciborium = "0.2.2"
|
||||
ciborium-io = "0.2.2"
|
||||
cipher = "0.4.4"
|
||||
ctaphid = { version = "0.3.1", default-features = false }
|
||||
ctaphid-dispatch = "0.3"
|
||||
ctaphid-dispatch = "0.4"
|
||||
delog = { version = "0.1.6", features = ["std-log"] }
|
||||
env_logger = "0.11"
|
||||
hex-literal = "0.4.1"
|
||||
hmac = "0.12.1"
|
||||
interchange = "0.3"
|
||||
itertools = "0.14"
|
||||
littlefs2 = "0.6"
|
||||
littlefs2 = "0.7"
|
||||
log = "0.4.21"
|
||||
p256 = { version = "0.13.2", features = ["ecdh"] }
|
||||
rand = "0.8.4"
|
||||
rand_chacha = "0.3"
|
||||
sha2 = "0.10"
|
||||
serde_test = "1.0.176"
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "024e0eca5fb7dbd2457831f7c7bffe4341e08775", features = ["virt"] }
|
||||
trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3", features = ["chunked", "hkdf", "virt", "fs-info"] }
|
||||
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner.git", rev = "504674453c9573a30aa2f155101df49eb2af1ba7", default-features = false, features = ["ctaphid"] }
|
||||
usbd-ctaphid = "0.3"
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b", features = ["virt"] }
|
||||
trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0", features = ["chunked", "hkdf", "virt", "fs-info"] }
|
||||
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner.git", rev = "017921df0930707c4af68882ccb1f8b3f1bbf7c5", default-features = false, features = ["ctaphid"] }
|
||||
usbd-ctaphid = "0.4"
|
||||
x509-parser = "0.16"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["chunked", "dispatch"]
|
||||
|
||||
[patch.crates-io]
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "024e0eca5fb7dbd2457831f7c7bffe4341e08775" }
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b" }
|
||||
|
||||
[profile.test]
|
||||
opt-level = 2
|
||||
|
||||
+5
-5
@@ -8,10 +8,10 @@ edition = "2021"
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
ctap-types = { version = "0.4", features = ["arbitrary"] }
|
||||
ctap-types = { version = "0.5", features = ["arbitrary"] }
|
||||
libfuzzer-sys = "0.4"
|
||||
trussed = { version = "0.1", features = ["clients-1", "certificate-client", "crypto-client", "filesystem-client", "management-client", "aes256-cbc", "ed255", "p256", "sha256"] }
|
||||
trussed-staging = { version = "0.3.0", features = ["chunked", "hkdf", "virt", "fs-info"] }
|
||||
trussed = { version = "0.1", features = ["certificate-client", "crypto-client", "filesystem-client", "management-client", "aes256-cbc", "ed255", "p256", "sha256"] }
|
||||
trussed-staging = { version = "0.4.0", features = ["chunked", "hkdf", "virt", "fs-info"] }
|
||||
|
||||
[dependencies.fido-authenticator]
|
||||
path = ".."
|
||||
@@ -24,5 +24,5 @@ doc = false
|
||||
bench = false
|
||||
|
||||
[patch.crates-io]
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "6bba8fde36d05c0227769eb63345744e87d84b2b" }
|
||||
trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", rev = "1e1ca03a3a62ea9b802f4070ea4bce002eeb4bec" }
|
||||
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b" }
|
||||
trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0" }
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
use ctap_types::{authenticator::Request, ctap1::Authenticator as _, ctap2::Authenticator as _};
|
||||
use fido_authenticator::{Authenticator, Config, Conforming};
|
||||
use trussed::virt::StoreConfig;
|
||||
use trussed_staging::virt;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|requests: Vec<Request<'_>>| {
|
||||
virt::with_ram_client("fido", |client| {
|
||||
virt::with_client(StoreConfig::ram(), "fido", |client| {
|
||||
let mut authenticator = Authenticator::new(
|
||||
client,
|
||||
Conforming {},
|
||||
|
||||
+21
-20
@@ -202,13 +202,14 @@ impl Credential {
|
||||
fn deserialize_bytes<E: serde::de::Error, const N: usize>(
|
||||
s: &[u8],
|
||||
) -> core::result::Result<Bytes<N>, E> {
|
||||
Bytes::from_slice(s).map_err(|_| E::invalid_length(s.len(), &"a fixed-size sequence of bytes"))
|
||||
Bytes::try_from(s).map_err(|_| E::invalid_length(s.len(), &"a fixed-size sequence of bytes"))
|
||||
}
|
||||
|
||||
fn deserialize_str<E: serde::de::Error, const N: usize>(
|
||||
s: &str,
|
||||
) -> core::result::Result<String<N>, E> {
|
||||
Ok(s.into())
|
||||
s.try_into()
|
||||
.map_err(|_| E::custom("Serialized string doesn't fit "))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@@ -794,12 +795,12 @@ mod test {
|
||||
fn credential_data() -> CredentialData {
|
||||
CredentialData {
|
||||
rp: Rp::new(PublicKeyCredentialRpEntity {
|
||||
id: String::from("John Doe"),
|
||||
id: String::try_from("John Doe").unwrap(),
|
||||
name: None,
|
||||
icon: None,
|
||||
}),
|
||||
user: User::new(PublicKeyCredentialUserEntity {
|
||||
id: Bytes::from_slice(&[1, 2, 3]).unwrap(),
|
||||
id: Bytes::from(&[1, 2, 3]),
|
||||
icon: None,
|
||||
name: None,
|
||||
display_name: None,
|
||||
@@ -807,7 +808,7 @@ mod test {
|
||||
creation_time: 123,
|
||||
use_counter: false,
|
||||
algorithm: -7,
|
||||
key: Key::WrappedKey(Bytes::from_slice(&[1, 2, 3]).unwrap()),
|
||||
key: Key::WrappedKey(Bytes::from(&[1, 2, 3])),
|
||||
hmac_secret: Some(false),
|
||||
cred_protect: None,
|
||||
use_short_id: Some(true),
|
||||
@@ -821,7 +822,7 @@ mod test {
|
||||
rp: Rp {
|
||||
format: SerializationFormat::Long,
|
||||
inner: PublicKeyCredentialRpEntity {
|
||||
id: String::from("John Doe"),
|
||||
id: String::try_from("John Doe").unwrap(),
|
||||
name: None,
|
||||
icon: None,
|
||||
},
|
||||
@@ -829,7 +830,7 @@ mod test {
|
||||
user: User {
|
||||
format: SerializationFormat::Long,
|
||||
inner: PublicKeyCredentialUserEntity {
|
||||
id: Bytes::from_slice(&[1, 2, 3]).unwrap(),
|
||||
id: Bytes::from(&[1, 2, 3]),
|
||||
icon: None,
|
||||
name: None,
|
||||
display_name: None,
|
||||
@@ -838,7 +839,7 @@ mod test {
|
||||
creation_time: 123,
|
||||
use_counter: false,
|
||||
algorithm: -7,
|
||||
key: Key::WrappedKey(Bytes::from_slice(&[1, 2, 3]).unwrap()),
|
||||
key: Key::WrappedKey(Bytes::from(&[1, 2, 3])),
|
||||
hmac_secret: Some(false),
|
||||
cred_protect: None,
|
||||
use_short_id: None,
|
||||
@@ -865,7 +866,7 @@ mod test {
|
||||
let between = Uniform::from(0..(N + 1));
|
||||
let n = between.sample(&mut OsRng);
|
||||
|
||||
bytes.resize_default(n).unwrap();
|
||||
bytes.resize_zero(n).unwrap();
|
||||
|
||||
OsRng.fill_bytes(&mut bytes);
|
||||
bytes
|
||||
@@ -1079,7 +1080,7 @@ mod test {
|
||||
#[test]
|
||||
fn max_credential_id() {
|
||||
let rp_id: String<256> = core::iter::repeat_n('?', 256).collect();
|
||||
let key = Bytes::from_slice(&[u8::MAX; 128]).unwrap();
|
||||
let key = Bytes::from(&[u8::MAX; 128]);
|
||||
let credential = StrippedCredential {
|
||||
ctap: CtapVersion::Fido21Pre,
|
||||
creation_time: u32::MAX,
|
||||
@@ -1160,8 +1161,8 @@ mod test {
|
||||
|
||||
fn inner(&self) -> PublicKeyCredentialRpEntity {
|
||||
PublicKeyCredentialRpEntity {
|
||||
id: self.id.into(),
|
||||
name: self.name.map(From::from),
|
||||
id: self.id.try_into().unwrap(),
|
||||
name: self.name.map(|n| n.try_into().unwrap()),
|
||||
icon: None,
|
||||
}
|
||||
}
|
||||
@@ -1225,10 +1226,10 @@ mod test {
|
||||
|
||||
fn inner(&self) -> PublicKeyCredentialUserEntity {
|
||||
PublicKeyCredentialUserEntity {
|
||||
id: Bytes::from_slice(self.id).unwrap(),
|
||||
icon: self.icon.map(From::from),
|
||||
name: self.name.map(From::from),
|
||||
display_name: self.display_name.map(From::from),
|
||||
id: Bytes::try_from(self.id).unwrap(),
|
||||
icon: self.icon.map(|v| v.try_into().unwrap()),
|
||||
name: self.name.map(|v| v.try_into().unwrap()),
|
||||
display_name: self.display_name.map(|v| v.try_into().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1300,7 +1301,7 @@ mod test {
|
||||
"
|
||||
);
|
||||
|
||||
let credential = FullCredential::deserialize(&Bytes::from_slice(&data).unwrap()).unwrap();
|
||||
let credential = FullCredential::deserialize(&Bytes::from(&data)).unwrap();
|
||||
assert!(matches!(credential.ctap, CtapVersion::Fido21Pre));
|
||||
assert_eq!(credential.nonce, &hex!("F62CA01ED181A3D03D561FC7"));
|
||||
assert_eq!(
|
||||
@@ -1309,7 +1310,7 @@ mod test {
|
||||
rp: Rp {
|
||||
format: SerializationFormat::Long,
|
||||
inner: PublicKeyCredentialRpEntity {
|
||||
id: "webauthn.io".into(),
|
||||
id: "webauthn.io".try_into().unwrap(),
|
||||
name: None,
|
||||
icon: None,
|
||||
},
|
||||
@@ -1317,9 +1318,9 @@ mod test {
|
||||
user: User {
|
||||
format: SerializationFormat::Long,
|
||||
inner: PublicKeyCredentialUserEntity {
|
||||
id: Bytes::from_slice(&hex!("6447567A644445")).unwrap(),
|
||||
id: Bytes::from(&hex!("6447567A644445")),
|
||||
icon: None,
|
||||
name: Some("test1".into()),
|
||||
name: Some("test1".try_into().unwrap()),
|
||||
display_name: None,
|
||||
},
|
||||
},
|
||||
|
||||
+21
-23
@@ -1,9 +1,7 @@
|
||||
//! The `ctap_types::ctap1::Authenticator` implementation.
|
||||
|
||||
use ctap_types::{
|
||||
ctap1::{authenticate, register, Authenticator, ControlByte, Error, Result},
|
||||
heapless_bytes::Bytes,
|
||||
};
|
||||
use ctap_types::ctap1::{authenticate, register, Authenticator, ControlByte, Error, Result};
|
||||
use heapless_bytes::Bytes;
|
||||
use serde_bytes::ByteArray;
|
||||
|
||||
use trussed_core::{
|
||||
@@ -71,9 +69,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
syscall!(self.trussed.delete(private_key));
|
||||
|
||||
let key = Key::WrappedKey(
|
||||
wrapped_key
|
||||
.to_bytes()
|
||||
.map_err(|_| Error::UnspecifiedCheckingError)?,
|
||||
Bytes::try_from(&*wrapped_key).map_err(|_| Error::UnspecifiedCheckingError)?,
|
||||
);
|
||||
let nonce = ByteArray::new(self.nonce());
|
||||
|
||||
@@ -124,14 +120,15 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
(Some((key, cert)), _aaguid) => {
|
||||
info!("aaguid: {}", hex_str!(&_aaguid));
|
||||
(
|
||||
syscall!(self.trussed.sign(
|
||||
Mechanism::P256,
|
||||
key,
|
||||
&commitment,
|
||||
SignatureSerialization::Asn1Der
|
||||
))
|
||||
.signature
|
||||
.to_bytes()
|
||||
Bytes::try_from(
|
||||
&*syscall!(self.trussed.sign(
|
||||
Mechanism::P256,
|
||||
key,
|
||||
&commitment,
|
||||
SignatureSerialization::Asn1Der
|
||||
))
|
||||
.signature,
|
||||
)
|
||||
.unwrap(),
|
||||
cert,
|
||||
)
|
||||
@@ -226,14 +223,15 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
.unwrap();
|
||||
commitment.extend_from_slice(auth.challenge).unwrap();
|
||||
|
||||
let signature = syscall!(self.trussed.sign(
|
||||
Mechanism::P256,
|
||||
key,
|
||||
&commitment,
|
||||
SignatureSerialization::Asn1Der
|
||||
))
|
||||
.signature
|
||||
.to_bytes()
|
||||
let signature = Bytes::try_from(
|
||||
&*syscall!(self.trussed.sign(
|
||||
Mechanism::P256,
|
||||
key,
|
||||
&commitment,
|
||||
SignatureSerialization::Asn1Der
|
||||
))
|
||||
.signature,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(authenticate::Response {
|
||||
|
||||
+19
-17
@@ -96,7 +96,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
let mut response = ctap2::get_info::Response::default();
|
||||
response.versions = versions;
|
||||
response.extensions = Some(extensions);
|
||||
response.aaguid = Bytes::from_slice(&aaguid).unwrap();
|
||||
response.aaguid = Bytes::from(&aaguid);
|
||||
response.options = Some(options);
|
||||
response.transports = Some(transports);
|
||||
// 1200
|
||||
@@ -293,7 +293,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
// Turns out it's size 92 (enum serialization not optimized yet...)
|
||||
// let mut wrapped_key = Bytes::<60>::new();
|
||||
// wrapped_key.extend_from_slice(&wrapped_key_msg).unwrap();
|
||||
Key::WrappedKey(wrapped_key.to_bytes().map_err(|_| Error::Other)?)
|
||||
Key::WrappedKey(Bytes::try_from(&*wrapped_key).map_err(|_| Error::Other)?)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -450,7 +450,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
attestation_algorithm.sign(&mut self.trussed, attestation_key, &commitment);
|
||||
let packed = PackedAttestationStatement {
|
||||
alg: attestation_algorithm.into(),
|
||||
sig: signature.to_bytes().map_err(|_| Error::Other)?,
|
||||
sig: Bytes::try_from(&*signature).map_err(|_| Error::Other)?,
|
||||
x5c: attestation_maybe.as_ref().map(|attestation| {
|
||||
// See: https://www.w3.org/TR/webauthn-2/#sctn-packed-attestation-cert-requirements
|
||||
let cert = attestation.1.clone();
|
||||
@@ -900,11 +900,15 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
fn vendor(&mut self, op: VendorOperation) -> Result<()> {
|
||||
info_now!("hello VO {:?}", &op);
|
||||
match op.into() {
|
||||
0x79 => syscall!(self.trussed.debug_dump_store()),
|
||||
_ => return Err(Error::InvalidCommand),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
0x79 => {
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
syscall!(self.trussed.debug_dump_store());
|
||||
}
|
||||
Err(Error::InvalidCommand)
|
||||
}
|
||||
_ => Err(Error::InvalidCommand),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
@@ -1249,7 +1253,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
return Err(Error::PinPolicyViolation);
|
||||
}
|
||||
|
||||
pin.resize_default(pin_length).unwrap();
|
||||
pin.resize_zero(pin_length).unwrap();
|
||||
|
||||
Ok(pin)
|
||||
}
|
||||
@@ -1286,7 +1290,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
|
||||
// check pinAuth
|
||||
let mut data: Bytes<{ sizes::MAX_CREDENTIAL_ID_LENGTH_PLUS_256 }> =
|
||||
Bytes::from_slice(&[parameters.sub_command as u8]).unwrap();
|
||||
Bytes::from(&[parameters.sub_command as u8]);
|
||||
let len = 1 + match parameters.sub_command {
|
||||
Subcommand::EnumerateCredentialsBegin
|
||||
| Subcommand::DeleteCredential
|
||||
@@ -1468,7 +1472,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
let cred_random = syscall!(self.trussed.derive_key(
|
||||
Mechanism::HmacSha256,
|
||||
credential_key,
|
||||
Some(Bytes::from_slice(&[get_assertion_state.uv_performed as u8]).unwrap()),
|
||||
Some(Bytes::from(&[get_assertion_state.uv_performed as u8])),
|
||||
StorageAttributes::new().set_persistence(Location::Volatile)
|
||||
))
|
||||
.key;
|
||||
@@ -1515,7 +1519,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
|
||||
shared_secret.delete(&mut self.trussed);
|
||||
|
||||
output.hmac_secret = Some(Bytes::from_slice(&output_enc).unwrap());
|
||||
output.hmac_secret = Some(Bytes::try_from(&*output_enc).unwrap());
|
||||
}
|
||||
|
||||
if extensions.third_party_payment.unwrap_or_default() {
|
||||
@@ -1619,10 +1623,8 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
|
||||
let signing_algorithm =
|
||||
SigningAlgorithm::try_from(credential.algorithm()).map_err(|_| Error::Other)?;
|
||||
let signature = signing_algorithm
|
||||
.sign(&mut self.trussed, key, &commitment)
|
||||
.to_bytes()
|
||||
.unwrap();
|
||||
let signature =
|
||||
Bytes::try_from(&*signing_algorithm.sign(&mut self.trussed, key, &commitment)).unwrap();
|
||||
|
||||
// select preferred format or skip attestation statement
|
||||
let att_stmt_fmt = data
|
||||
@@ -1645,7 +1647,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
&commitment,
|
||||
);
|
||||
(
|
||||
signature.to_bytes().map_err(|_| Error::Other)?,
|
||||
Bytes::try_from(&*signature).map_err(|_| Error::Other)?,
|
||||
signing_algorithm.into(),
|
||||
)
|
||||
} else {
|
||||
|
||||
+15
-10
@@ -106,7 +106,7 @@ impl<T: CryptoClient> PinTokenMut<'_, T> {
|
||||
// in spec: encrypt(..., pinUvAuthToken)
|
||||
pub fn encrypt(&mut self, shared_secret: &SharedSecret) -> Result<Bytes<48>> {
|
||||
let token = shared_secret.wrap(self.trussed, self.pin_token.key_id);
|
||||
Bytes::from_slice(&token).map_err(|_| Error::Other)
|
||||
Bytes::try_from(&*token).map_err(|_| Error::Other)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ struct Rp {
|
||||
impl Rp {
|
||||
fn new<T: CryptoClient>(trussed: &mut T, id: String<256>) -> Self {
|
||||
let hash =
|
||||
syscall!(trussed.hash(Mechanism::Sha256, Message::from_slice(id.as_ref()).unwrap()))
|
||||
syscall!(trussed.hash(Mechanism::Sha256, Message::try_from(id.as_bytes()).unwrap()))
|
||||
.hash
|
||||
.as_slice()
|
||||
.try_into()
|
||||
@@ -366,7 +366,7 @@ impl<'a, T: CryptoClient + HkdfClient + HmacSha256 + P256> PinProtocol<'a, T> {
|
||||
// operations. For simplicity, we store two separate keys instead.
|
||||
fn kdf_v2(&mut self, input: KeyId) -> Option<SharedSecret> {
|
||||
fn hkdf<T: HkdfClient>(trussed: &mut T, okm: OkmId, info: &[u8]) -> Option<KeyId> {
|
||||
let info = Message::from_slice(info).ok()?;
|
||||
let info = Message::try_from(info).ok()?;
|
||||
try_syscall!(trussed.hkdf_expand(okm, info, 32, Location::Volatile))
|
||||
.ok()
|
||||
.map(|reply| reply.key)
|
||||
@@ -420,11 +420,10 @@ impl SharedSecret {
|
||||
|
||||
fn generate_iv<T: CryptoClient>(&self, trussed: &mut T) -> ShortData {
|
||||
match self {
|
||||
Self::V1 { .. } => ShortData::from_slice(&[0; 16]).unwrap(),
|
||||
Self::V2 { .. } => syscall!(trussed.random_bytes(16))
|
||||
.bytes
|
||||
.try_convert_into()
|
||||
.unwrap(),
|
||||
Self::V1 { .. } => ShortData::from(&[0; 16]),
|
||||
Self::V2 { .. } => {
|
||||
ShortData::try_from(&*syscall!(trussed.random_bytes(16)).bytes).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +435,10 @@ impl SharedSecret {
|
||||
syscall!(trussed.encrypt(Mechanism::Aes256Cbc, key_id, data, &[], Some(iv.clone())))
|
||||
.ciphertext;
|
||||
if matches!(self, Self::V2 { .. }) {
|
||||
ciphertext.insert_slice_at(&iv, 0).unwrap();
|
||||
let ciphertext_len = ciphertext.len();
|
||||
ciphertext.resize_zero(iv.len() + ciphertext_len).unwrap();
|
||||
ciphertext.copy_within(..ciphertext_len, iv.len());
|
||||
ciphertext[..iv.len()].copy_from_slice(&iv);
|
||||
}
|
||||
ciphertext
|
||||
}
|
||||
@@ -454,7 +456,10 @@ impl SharedSecret {
|
||||
))
|
||||
.wrapped_key;
|
||||
if matches!(self, Self::V2 { .. }) {
|
||||
wrapped_key.insert_slice_at(&iv, 0).unwrap();
|
||||
let wrapped_key_len = wrapped_key.len();
|
||||
wrapped_key.resize_zero(iv.len() + wrapped_key_len).unwrap();
|
||||
wrapped_key.copy_within(..wrapped_key_len, iv.len());
|
||||
wrapped_key[..iv.len()].copy_from_slice(&iv);
|
||||
}
|
||||
wrapped_key
|
||||
}
|
||||
|
||||
+10
-9
@@ -8,7 +8,8 @@ use crate::msp;
|
||||
use crate::{Authenticator, TrussedRequirements, UserPresence};
|
||||
|
||||
use ctap_types::{ctap1, ctap2};
|
||||
use iso7816::{command::CommandView, Data, Status};
|
||||
use heapless::VecView;
|
||||
use iso7816::{command::CommandView, Status};
|
||||
|
||||
impl<UP, T> iso7816::App for Authenticator<UP, T>
|
||||
where
|
||||
@@ -21,10 +22,10 @@ where
|
||||
|
||||
#[inline(never)]
|
||||
/// Deserialize U2F, call authenticator, serialize response *Result*.
|
||||
fn handle_ctap1_from_hid<T, UP, const R: usize>(
|
||||
fn handle_ctap1_from_hid<T, UP>(
|
||||
authenticator: &mut Authenticator<UP, T>,
|
||||
data: &[u8],
|
||||
response: &mut Data<R>,
|
||||
response: &mut VecView<u8>,
|
||||
) where
|
||||
T: TrussedRequirements,
|
||||
UP: UserPresence,
|
||||
@@ -65,10 +66,10 @@ fn handle_ctap1_from_hid<T, UP, const R: usize>(
|
||||
|
||||
#[inline(never)]
|
||||
/// Deserialize CBOR, call authenticator, serialize response *Result*.
|
||||
fn handle_ctap2<T, UP, const R: usize>(
|
||||
fn handle_ctap2<T, UP>(
|
||||
authenticator: &mut Authenticator<UP, T>,
|
||||
data: &[u8],
|
||||
response: &mut Data<R>,
|
||||
response: &mut VecView<u8>,
|
||||
) where
|
||||
T: TrussedRequirements,
|
||||
UP: UserPresence,
|
||||
@@ -89,10 +90,10 @@ fn handle_ctap2<T, UP, const R: usize>(
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn try_handle_ctap1<T, UP, const R: usize>(
|
||||
fn try_handle_ctap1<T, UP>(
|
||||
authenticator: &mut Authenticator<UP, T>,
|
||||
command: CommandView<'_>,
|
||||
response: &mut Data<R>,
|
||||
response: &mut VecView<u8>,
|
||||
) -> Result<(), Status>
|
||||
where
|
||||
T: TrussedRequirements,
|
||||
@@ -124,10 +125,10 @@ where
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn try_handle_ctap2<T, UP, const R: usize>(
|
||||
fn try_handle_ctap2<T, UP>(
|
||||
authenticator: &mut Authenticator<UP, T>,
|
||||
data: &[u8],
|
||||
response: &mut Data<R>,
|
||||
response: &mut VecView<u8>,
|
||||
) -> Result<(), u8>
|
||||
where
|
||||
T: TrussedRequirements,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use apdu_app::Interface;
|
||||
use ctap_types::{serde::error::Error as SerdeError, Error};
|
||||
use iso7816::{command::CommandView, Data, Status};
|
||||
use heapless::VecView;
|
||||
use iso7816::{command::CommandView, Status};
|
||||
|
||||
use crate::{Authenticator, TrussedRequirements, UserPresence};
|
||||
|
||||
@@ -21,7 +22,7 @@ impl From<CtapMappingError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<UP, T, const R: usize> apdu_app::App<R> for Authenticator<UP, T>
|
||||
impl<UP, T> apdu_app::App for Authenticator<UP, T>
|
||||
where
|
||||
UP: UserPresence,
|
||||
T: TrussedRequirements,
|
||||
@@ -30,7 +31,7 @@ where
|
||||
&mut self,
|
||||
interface: Interface,
|
||||
_: CommandView<'_>,
|
||||
reply: &mut Data<R>,
|
||||
reply: &mut VecView<u8>,
|
||||
) -> apdu_app::Result {
|
||||
// FIDO-over-CCID does not seem to officially be a thing; we don't support it.
|
||||
// If we would, need to review the following cases catering to semi-documented U2F legacy.
|
||||
@@ -48,7 +49,7 @@ where
|
||||
&mut self,
|
||||
interface: Interface,
|
||||
apdu: CommandView<'_>,
|
||||
response: &mut Data<R>,
|
||||
response: &mut VecView<u8>,
|
||||
) -> apdu_app::Result {
|
||||
// FIDO-over-CCID does not seem to officially be a thing; we don't support it.
|
||||
// If we would, need to review the following cases catering to semi-documented U2F legacy.
|
||||
@@ -77,7 +78,7 @@ where
|
||||
super::handle_ctap2(self, apdu.data(), response)
|
||||
}
|
||||
Ok(ctaphid_app::Command::Msg) => super::try_handle_ctap1(self, apdu, response)?,
|
||||
Ok(ctaphid_app::Command::Deselect) => apdu_app::App::<R>::deselect(self),
|
||||
Ok(ctaphid_app::Command::Deselect) => apdu_app::App::deselect(self),
|
||||
_ => {
|
||||
info!("Unsupported ins for fido app {:02x}", instruction);
|
||||
return Err(iso7816::Status::InstructionNotSupportedOrInvalid);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use ctaphid_app::{App, Command, Error};
|
||||
use heapless_bytes::Bytes;
|
||||
use heapless_bytes::BytesView;
|
||||
use trussed_core::InterruptFlag;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::msp;
|
||||
use crate::{Authenticator, TrussedRequirements, UserPresence};
|
||||
|
||||
impl<UP, T, const N: usize> App<'static, N> for Authenticator<UP, T>
|
||||
impl<UP, T> App<'static> for Authenticator<UP, T>
|
||||
where
|
||||
UP: UserPresence,
|
||||
T: TrussedRequirements,
|
||||
@@ -20,7 +20,7 @@ where
|
||||
&mut self,
|
||||
command: Command,
|
||||
request: &[u8],
|
||||
response: &mut Bytes<N>,
|
||||
response: &mut BytesView,
|
||||
) -> Result<(), Error> {
|
||||
debug_now!(
|
||||
"ctaphid-dispatch: remaining stack: {} bytes",
|
||||
@@ -35,8 +35,8 @@ where
|
||||
// info_now!("request: ");
|
||||
// blocking::dump_hex(request, request.len());
|
||||
match command {
|
||||
Command::Cbor => super::handle_ctap2(self, request, response),
|
||||
Command::Msg => super::handle_ctap1_from_hid(self, request, response),
|
||||
Command::Cbor => super::handle_ctap2(self, request, response.as_mut()),
|
||||
Command::Msg => super::handle_ctap1_from_hid(self, request, response.as_mut()),
|
||||
_ => {
|
||||
debug_now!("ctaphid trying to dispatch {:?}", command);
|
||||
}
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ impl<'a, const N: usize> Pipe<'a, N> {
|
||||
}
|
||||
match self.interchange.request((
|
||||
request.command,
|
||||
Bytes::from_slice(&self.buffer[..request.length as usize]).unwrap(),
|
||||
Bytes::try_from(&self.buffer[..request.length as usize]).unwrap(),
|
||||
)) {
|
||||
Ok(_) => {
|
||||
self.state = State::WaitingOnAuthenticator(request);
|
||||
|
||||
@@ -33,6 +33,7 @@ macro_rules! exhaustive_struct {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use exhaustive_struct;
|
||||
|
||||
pub struct KeyAgreementKey(p256::ecdh::EphemeralSecret);
|
||||
|
||||
Reference in New Issue
Block a user