Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up signing algorithms #79

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 13 additions & 111 deletions src/ctap2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ use sha2::{Digest as _, Sha256};
use trussed::{
syscall, try_syscall,
types::{
KeyId, KeySerialization, Location, Mechanism, MediumData, Message, Path, PathBuf,
SignatureSerialization,
KeyId, Location, Mechanism, MediumData, Message, Path, PathBuf, SignatureSerialization,
},
};

Expand Down Expand Up @@ -206,7 +205,6 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
-8 => {
algorithm = Some(SigningAlgorithm::Ed25519);
}
// -9 => { algorithm = Some(SigningAlgorithm::Totp); }
_ => {}
}
}
Expand Down Expand Up @@ -270,55 +268,8 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
true => Location::Internal,
false => Location::Volatile,
};

let private_key: KeyId;
let public_key: KeyId;
let cose_public_key;
match algorithm {
SigningAlgorithm::P256 => {
private_key = syscall!(self.trussed.generate_p256_private_key(location)).key;
public_key = syscall!(self
.trussed
.derive_p256_public_key(private_key, Location::Volatile))
.key;
cose_public_key = syscall!(self.trussed.serialize_key(
Mechanism::P256,
public_key,
KeySerialization::Cose
))
.serialized_key;
let _success = syscall!(self.trussed.delete(public_key)).success;
info_now!("deleted public P256 key: {}", _success);
}
SigningAlgorithm::Ed25519 => {
private_key = syscall!(self.trussed.generate_ed255_private_key(location)).key;
public_key = syscall!(self
.trussed
.derive_ed255_public_key(private_key, Location::Volatile))
.key;
cose_public_key = syscall!(self.trussed.serialize_key(
Mechanism::Ed255,
public_key,
KeySerialization::Cose
))
.serialized_key;
let _success = syscall!(self.trussed.delete(public_key)).success;
info_now!("deleted public Ed25519 key: {}", _success);
} // SigningAlgorithm::Totp => {
// if parameters.client_data_hash.len() != 32 {
// return Err(Error::InvalidParameter);
// }
// // b'TOTP---W\x0e\xf1\xe0\xd7\x83\xfe\t\xd1\xc1U\xbf\x08T_\x07v\xb2\xc6--TOTP'
// let totp_secret: [u8; 20] = parameters.client_data_hash[6..26].try_into().unwrap();
// private_key = syscall!(self.trussed.unsafe_inject_shared_key(
// &totp_secret, Location::Internal)).key;
// // info_now!("totes injected");
// let fake_cose_pk = ctap_types::cose::TotpPublicKey {};
// let fake_serialized_cose_pk = trussed::cbor_serialize_bytes(&fake_cose_pk)
// .map_err(|_| Error::NotAllowed)?;
// cose_public_key = fake_serialized_cose_pk; // Bytes::from_slice(&[0u8; 20]).unwrap();
// }
}
let private_key = algorithm.generate_private_key(&mut self.trussed, location);
let cose_public_key = algorithm.derive_public_key(&mut self.trussed, private_key);

// 12. if `rk` is set, store or overwrite key pair, if full error KeyStoreFull

Expand Down Expand Up @@ -509,61 +460,20 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
// we should also directly support "none" format, it's a bit weird
// how browsers firefox this

let (signature, attestation_algorithm) = {
if let Some(attestation) = attestation_maybe.as_ref() {
let signature = syscall!(self.trussed.sign_p256(
attestation.0,
&commitment,
SignatureSerialization::Asn1Der,
))
.signature;
(signature.to_bytes().map_err(|_| Error::Other)?, -7)
} else {
match algorithm {
SigningAlgorithm::Ed25519 => {
let signature =
syscall!(self.trussed.sign_ed255(private_key, &commitment)).signature;
(signature.to_bytes().map_err(|_| Error::Other)?, -8)
}

SigningAlgorithm::P256 => {
// DO NOT prehash here, `trussed` does that
let der_signature = syscall!(self.trussed.sign_p256(
private_key,
&commitment,
SignatureSerialization::Asn1Der
))
.signature;
(der_signature.to_bytes().map_err(|_| Error::Other)?, -7)
} // SigningAlgorithm::Totp => {
// // maybe we can fake it here too, but seems kinda weird
// // return Err(Error::UnsupportedAlgorithm);
// // micro-ecc is borked. let's self-sign anyway
// let hash = syscall!(self.trussed.hash_sha256(&commitment.as_ref())).hash;
// let tmp_key = syscall!(self.trussed
// .generate_p256_private_key(Location::Volatile))
// .key;

// let signature = syscall!(self.trussed.sign_p256(
// tmp_key,
// &hash,
// SignatureSerialization::Asn1Der,
// )).signature;
// (signature.to_bytes().map_err(|_| Error::Other)?, -7)
// }
}
}
};
// debug_now!("SIG = {:?}", &signature);
let (attestation_key, attestation_algorithm) = attestation_maybe
.as_ref()
.map(|attestation| (attestation.0, SigningAlgorithm::P256))
.unwrap_or((private_key, algorithm));
let signature = attestation_algorithm.sign(&mut self.trussed, attestation_key, &commitment);

if !rk_requested {
let _success = syscall!(self.trussed.delete(private_key)).success;
info_now!("deleted private credential key: {}", _success);
}

let packed_attn_stmt = ctap2::make_credential::PackedAttestationStatement {
alg: attestation_algorithm,
sig: signature,
alg: attestation_algorithm.into(),
sig: signature.to_bytes().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();
Expand Down Expand Up @@ -1482,16 +1392,9 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
Key::WrappedKey(_) => true,
Key::ResidentKey(key) => {
debug_now!("checking if ResidentKey {:?} exists", key);
match alg {
-7 => syscall!(self.trussed.exists(Mechanism::P256, *key)).exists,
-8 => syscall!(self.trussed.exists(Mechanism::Ed255, *key)).exists,
// -9 => {
// let exists = syscall!(self.trussed.exists(Mechanism::Totp, key)).exists;
// info_now!("found it");
// exists
// }
_ => false,
}
SigningAlgorithm::try_from(alg)
.map(|alg| syscall!(self.trussed.exists(alg.mechanism(), *key)).exists)
.unwrap_or_default()
}
}
}
Expand Down Expand Up @@ -1667,7 +1570,6 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
let (mechanism, serialization) = match credential.algorithm() {
-7 => (Mechanism::P256, SignatureSerialization::Asn1Der),
-8 => (Mechanism::Ed255, SignatureSerialization::Raw),
// -9 => (Mechanism::Totp, SignatureSerialization::Raw),
_ => {
return Err(Error::Other);
}
Expand Down
33 changes: 4 additions & 29 deletions src/ctap2/credential_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,41 +407,16 @@ where
};

use crate::SigningAlgorithm;
use trussed::types::{KeySerialization, Mechanism};

let algorithm = SigningAlgorithm::try_from(credential.algorithm)?;
let cose_public_key = algorithm.derive_public_key(&mut self.trussed, private_key);
let cose_public_key = match algorithm {
SigningAlgorithm::P256 => {
let public_key = syscall!(self
.trussed
.derive_p256_public_key(private_key, Location::Volatile))
.key;
let cose_public_key = syscall!(self.trussed.serialize_key(
Mechanism::P256,
public_key,
// KeySerialization::EcdhEsHkdf256
KeySerialization::Cose,
))
.serialized_key;
syscall!(self.trussed.delete(public_key));
PublicKey::P256Key(ctap_types::serde::cbor_deserialize(&cose_public_key).unwrap())
}
SigningAlgorithm::Ed25519 => {
let public_key = syscall!(self
.trussed
.derive_ed255_public_key(private_key, Location::Volatile))
.key;
let cose_public_key = syscall!(self
.trussed
.serialize_ed255_key(public_key, KeySerialization::Cose))
.serialized_key;
syscall!(self.trussed.delete(public_key));
PublicKey::Ed25519Key(
ctap_types::serde::cbor_deserialize(&cose_public_key).unwrap(),
)
} // SigningAlgorithm::Totp => {
// PublicKey::TotpKey(Default::default())
// }
SigningAlgorithm::Ed25519 => PublicKey::Ed25519Key(
ctap_types::serde::cbor_deserialize(&cose_public_key).unwrap(),
),
};
let cred_protect = match credential.cred_protect {
Some(x) => Some(x),
Expand Down
82 changes: 75 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ generate_macros!();

use core::time::Duration;

use trussed::{client, syscall, types::Message, Client as TrussedClient};
use trussed::{
client, syscall,
types::{
KeyId, KeySerialization, Location, Mechanism, Message, SerializedKey, Signature,
SignatureSerialization, StorageAttributes,
},
Client as TrussedClient,
};
use trussed_hkdf::HkdfClient;

use ctap_types::heapless_bytes::Bytes;
Expand Down Expand Up @@ -58,7 +65,7 @@ pub trait TrussedRequirements:
+ client::Aes256Cbc
+ client::Sha256
+ client::HmacSha256
+ client::Ed255 // + client::Totp
+ client::Ed255
+ HkdfClient
+ ExtensionRequirements
{
Expand All @@ -71,7 +78,7 @@ impl<T> TrussedRequirements for T where
+ client::Aes256Cbc
+ client::Sha256
+ client::HmacSha256
+ client::Ed255 // + client::Totp
+ client::Ed255
+ HkdfClient
+ ExtensionRequirements
{
Expand Down Expand Up @@ -185,17 +192,78 @@ pub enum SigningAlgorithm {
Ed25519 = -8,
/// The NIST P-256 signature algorithm.
P256 = -7,
// #[doc(hidden)]
// Totp = -9,
}

impl core::convert::TryFrom<i32> for SigningAlgorithm {
impl SigningAlgorithm {
pub fn mechanism(&self) -> Mechanism {
match self {
Self::Ed25519 => Mechanism::Ed255,
Self::P256 => Mechanism::P256,
}
}

pub fn signature_serialization(&self) -> SignatureSerialization {
match self {
Self::Ed25519 => SignatureSerialization::Raw,
Self::P256 => SignatureSerialization::Asn1Der,
}
}

pub fn generate_private_key<C: TrussedClient>(
&self,
trussed: &mut C,
location: Location,
) -> KeyId {
syscall!(trussed.generate_key(
self.mechanism(),
StorageAttributes::new().set_persistence(location)
))
.key
}

pub fn derive_public_key<C: TrussedClient>(
&self,
trussed: &mut C,
private_key: KeyId,
) -> SerializedKey {
let mechanism = self.mechanism();
let public_key = syscall!(trussed.derive_key(
mechanism,
private_key,
None,
StorageAttributes::new().set_persistence(Location::Volatile)
))
.key;
let cose_public_key =
syscall!(trussed.serialize_key(mechanism, public_key, KeySerialization::Cose))
.serialized_key;
if !syscall!(trussed.delete(public_key)).success {
error!("failed to delete credential public key");
}
cose_public_key
}

pub fn sign<C: TrussedClient>(&self, trussed: &mut C, key: KeyId, data: &[u8]) -> Signature {
syscall!(trussed.sign(self.mechanism(), key, data, self.signature_serialization()))
.signature
}
}

impl From<SigningAlgorithm> for i32 {
fn from(alg: SigningAlgorithm) -> Self {
match alg {
SigningAlgorithm::P256 => -7,
SigningAlgorithm::Ed25519 => -8,
}
}
}

impl TryFrom<i32> for SigningAlgorithm {
type Error = Error;
fn try_from(alg: i32) -> Result<Self> {
Ok(match alg {
-7 => SigningAlgorithm::P256,
-8 => SigningAlgorithm::Ed25519,
// -9 => SigningAlgorithm::Totp,
_ => return Err(Error::UnsupportedAlgorithm),
})
}
Expand Down
Loading