Skip to content

Commit

Permalink
implements credential management commands
Browse files Browse the repository at this point in the history
  • Loading branch information
kaczmarczyck committed Dec 30, 2020
1 parent 8cf0845 commit 3532b56
Show file tree
Hide file tree
Showing 7 changed files with 1,092 additions and 67 deletions.
1 change: 1 addition & 0 deletions libraries/crypto/src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ impl PubKey {
.map(|p| PubKey { p })
}

// Writes the coordinates into the passed in arrays.
pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) {
self.p.getx().to_int().to_bin(x);
self.p.gety().to_int().to_bin(y);
Expand Down
41 changes: 10 additions & 31 deletions libraries/crypto/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ use super::rng256::Rng256;
use super::{Hash256, HashBlockSize64Bytes};
use alloc::vec;
use alloc::vec::Vec;
#[cfg(test)]
use arrayref::array_mut_ref;
#[cfg(feature = "std")]
use arrayref::array_ref;
use arrayref::{array_mut_ref, mut_array_refs};
use cbor::{cbor_bytes, cbor_map_options};
use arrayref::mut_array_refs;
use core::marker::PhantomData;

pub const NBYTES: usize = int256::NBYTES;

#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "derive_debug", derive(Debug))]
pub struct SecKey {
Expand All @@ -38,6 +41,7 @@ pub struct Signature {
s: NonZeroExponentP256,
}

#[cfg_attr(feature = "derive_debug", derive(Clone))]
pub struct PubKey {
p: PointP256,
}
Expand Down Expand Up @@ -242,35 +246,10 @@ impl PubKey {
representation
}

// Encodes the key according to CBOR Object Signing and Encryption, defined in RFC 8152.
pub fn to_cose_key(&self) -> Option<Vec<u8>> {
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
let mut x_bytes = vec![0; int256::NBYTES];
self.p
.getx()
.to_int()
.to_bin(array_mut_ref![x_bytes.as_mut_slice(), 0, int256::NBYTES]);
let x_byte_cbor: cbor::Value = cbor_bytes!(x_bytes);
let mut y_bytes = vec![0; int256::NBYTES];
self.p
.gety()
.to_int()
.to_bin(array_mut_ref![y_bytes.as_mut_slice(), 0, int256::NBYTES]);
let y_byte_cbor: cbor::Value = cbor_bytes!(y_bytes);
let cbor_value = cbor_map_options! {
1 => EC2_KEY_TYPE,
3 => PubKey::ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_byte_cbor,
-3 => y_byte_cbor,
};
let mut encoded_key = Vec::new();
if cbor::write(cbor_value, &mut encoded_key) {
Some(encoded_key)
} else {
None
}
// Writes the coordinates into the passed in arrays.
pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) {
self.p.getx().to_int().to_bin(x);
self.p.gety().to_int().to_bin(y);
}

#[cfg(feature = "std")]
Expand Down
78 changes: 60 additions & 18 deletions src/ctap/data_formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use alloc::string::String;
use alloc::vec::Vec;
use arrayref::array_ref;
use cbor::{cbor_array_vec, cbor_bytes_lit, cbor_map_options, destructure_cbor_map};
use core::convert::TryFrom;
use core::convert::{TryFrom, TryInto};
use crypto::{ecdh, ecdsa};
#[cfg(test)]
use enum_iterator::IntoEnumIterator;
Expand Down Expand Up @@ -646,26 +646,39 @@ const ES256_ALGORITHM: i64 = -7;
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;

impl TryFrom<cbor::Value> for CoseKey {
type Error = Ctap2StatusCode;

fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
if let cbor::Value::Map(cose_map) = cbor_value {
Ok(CoseKey(cose_map))
} else {
Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)
}
}
}

fn cose_key_from_bytes(x_bytes: [u8; ecdh::NBYTES], y_bytes: [u8; ecdh::NBYTES]) -> CoseKey {
let x_byte_cbor: cbor::Value = cbor_bytes_lit!(&x_bytes);
let y_byte_cbor: cbor::Value = cbor_bytes_lit!(&y_bytes);
// TODO(kaczmarczyck) do not write optional parameters, spec is unclear
let cose_cbor_value = cbor_map_options! {
1 => EC2_KEY_TYPE,
3 => ECDH_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_byte_cbor,
-3 => y_byte_cbor,
};
// Unwrap is safe here since we know it's a map.
cose_cbor_value.try_into().unwrap()
}

impl From<ecdh::PubKey> for CoseKey {
fn from(pk: ecdh::PubKey) -> Self {
let mut x_bytes = [0; ecdh::NBYTES];
let mut y_bytes = [0; ecdh::NBYTES];
pk.to_coordinates(&mut x_bytes, &mut y_bytes);
let x_byte_cbor: cbor::Value = cbor_bytes_lit!(&x_bytes);
let y_byte_cbor: cbor::Value = cbor_bytes_lit!(&y_bytes);
// TODO(kaczmarczyck) do not write optional parameters, spec is unclear
let cose_cbor_value = cbor_map_options! {
1 => EC2_KEY_TYPE,
3 => ECDH_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_byte_cbor,
-3 => y_byte_cbor,
};
if let cbor::Value::Map(cose_map) = cose_cbor_value {
CoseKey(cose_map)
} else {
unreachable!();
}
cose_key_from_bytes(x_bytes, y_bytes)
}
}

Expand Down Expand Up @@ -711,6 +724,15 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
}
}

impl From<ecdsa::PubKey> for CoseKey {
fn from(pk: ecdsa::PubKey) -> Self {
let mut x_bytes = [0; ecdh::NBYTES];
let mut y_bytes = [0; ecdh::NBYTES];
pk.to_coordinates(&mut x_bytes, &mut y_bytes);
cose_key_from_bytes(x_bytes, y_bytes)
}
}

#[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))]
#[cfg_attr(test, derive(IntoEnumIterator))]
pub enum ClientPinSubCommand {
Expand Down Expand Up @@ -763,7 +785,8 @@ impl TryFrom<cbor::Value> for ClientPinSubCommand {
}

#[cfg(feature = "with_ctap2_1")]
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))]
#[derive(Clone, Copy)]
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
#[cfg_attr(test, derive(IntoEnumIterator))]
pub enum CredentialManagementSubCommand {
GetCredsMetadata = 0x01,
Expand Down Expand Up @@ -1435,7 +1458,7 @@ mod test {
}

#[test]
fn test_from_into_cose_key() {
fn test_from_into_cose_key_ecdh() {
let mut rng = ThreadRng256 {};
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
let pk = sk.genpk();
Expand All @@ -1444,6 +1467,25 @@ mod test {
assert_eq!(created_pk, Ok(pk));
}

#[test]
fn test_into_cose_key_ecdsa() {
let mut rng = ThreadRng256 {};
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
let pk = sk.genpk();
let cose_key = CoseKey::from(pk);
let cose_map = cose_key.0;
let template = cbor_map! {
1 => 0,
3 => 0,
-1 => 0,
-2 => 0,
-3 => 0,
};
for key in CoseKey::try_from(template).unwrap().0.keys() {
assert!(cose_map.contains_key(key));
}
}

#[test]
fn test_from_into_client_pin_sub_command() {
let cbor_sub_command: cbor::Value = cbor_int!(0x01);
Expand Down
Loading

0 comments on commit 3532b56

Please sign in to comment.