reads CBOR maps by moving instead of references

This commit is contained in:
Fabian Kaczmarczyck
2020-06-05 15:42:06 +02:00
parent 642ee69a9b
commit 679c1cb291
5 changed files with 253 additions and 306 deletions

View File

@@ -1,9 +0,0 @@
c182bb4902fff51b2f56810fc2a27df3646cd66ba21359162354d53445623ab8 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
2c2879a0263ebaa6e841db4b352346cc5b4cef5084ce85525cf49669d3b0b41d target/nrf52840dk_merged.hex
0a9929ba8fa57e8a502a49fc7c53177397202e1b11f4c7c3cb6ed68b2b99dd46 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
652824a90674dc3199070f2f46a791ab4951e367982ecae6f65fc41338a5a856 target/nrf52840_dongle_merged.hex
cca9086c9149c607589b23ffa599a5e4c26db7c20bd3700b79528bd3a5df991d third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
a030505f5576129954a3977f97957b8b4e023b2b51a29d45d4511566458666ac target/nrf52840_dongle_dfu_merged.hex
8857488ba6a69e366f0da229bbfc012a2ad291d3a88d9494247d600c10bb19b7 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
82ac4290967ae67a78c986444fd6c2a2aa5668ac254a2af642c98be4a064f913 target/nrf52840_mdk_dfu_merged.hex
c3e901a80fd779b15a6f266e48dcef5140b318f5f62b23a96547498572ac1666 target/tab/ctap2.tab

Binary file not shown.

View File

@@ -13,10 +13,10 @@
// limitations under the License. // limitations under the License.
use super::data_formats::{ use super::data_formats::{
ok_or_missing, read_array, read_byte_string, read_map, read_text_string, read_unsigned, extract_array, extract_byte_string, extract_map, extract_text_string, extract_unsigned,
ClientPinSubCommand, CoseKey, Extensions, GetAssertionOptions, MakeCredentialOptions, ok_or_missing, ClientPinSubCommand, CoseKey, Extensions, GetAssertionOptions,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialRpEntity, MakeCredentialOptions, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialUserEntity, PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity,
}; };
use super::status_code::Ctap2StatusCode; use super::status_code::Ctap2StatusCode;
use alloc::string::String; use alloc::string::String;
@@ -124,30 +124,32 @@ impl TryFrom<cbor::Value> for AuthenticatorMakeCredentialParameters {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let param_map = read_map(&cbor_value)?; let mut param_map = extract_map(cbor_value)?;
let client_data_hash = read_byte_string(ok_or_missing(param_map.get(&cbor_unsigned!(1)))?)?; let client_data_hash =
extract_byte_string(ok_or_missing(param_map.remove(&cbor_unsigned!(1)))?)?;
let rp = PublicKeyCredentialRpEntity::try_from(ok_or_missing( let rp = PublicKeyCredentialRpEntity::try_from(ok_or_missing(
param_map.get(&cbor_unsigned!(2)), param_map.remove(&cbor_unsigned!(2)),
)?)?; )?)?;
let user = PublicKeyCredentialUserEntity::try_from(ok_or_missing( let user = PublicKeyCredentialUserEntity::try_from(ok_or_missing(
param_map.get(&cbor_unsigned!(3)), param_map.remove(&cbor_unsigned!(3)),
)?)?; )?)?;
let cred_param_vec = read_array(ok_or_missing(param_map.get(&cbor_unsigned!(4)))?)?; let cred_param_vec = extract_array(ok_or_missing(param_map.remove(&cbor_unsigned!(4)))?)?;
let pub_key_cred_params = cred_param_vec let pub_key_cred_params = cred_param_vec
.iter() .into_iter()
.map(PublicKeyCredentialParameter::try_from) .map(PublicKeyCredentialParameter::try_from)
.collect::<Result<Vec<PublicKeyCredentialParameter>, Ctap2StatusCode>>()?; .collect::<Result<Vec<PublicKeyCredentialParameter>, Ctap2StatusCode>>()?;
let exclude_list = match param_map.get(&cbor_unsigned!(5)) { let exclude_list = match param_map.remove(&cbor_unsigned!(5)) {
Some(entry) => { Some(entry) => {
let exclude_list_vec = read_array(entry)?; let exclude_list_vec = extract_array(entry)?;
let list_len = MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(exclude_list_vec.len());
let exclude_list = exclude_list_vec let exclude_list = exclude_list_vec
.iter() .into_iter()
.take(MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(exclude_list_vec.len())) .take(list_len)
.map(PublicKeyCredentialDescriptor::try_from) .map(PublicKeyCredentialDescriptor::try_from)
.collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?; .collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?;
Some(exclude_list) Some(exclude_list)
@@ -156,11 +158,11 @@ impl TryFrom<cbor::Value> for AuthenticatorMakeCredentialParameters {
}; };
let extensions = param_map let extensions = param_map
.get(&cbor_unsigned!(6)) .remove(&cbor_unsigned!(6))
.map(Extensions::try_from) .map(Extensions::try_from)
.transpose()?; .transpose()?;
let options = match param_map.get(&cbor_unsigned!(7)) { let options = match param_map.remove(&cbor_unsigned!(7)) {
Some(entry) => MakeCredentialOptions::try_from(entry)?, Some(entry) => MakeCredentialOptions::try_from(entry)?,
None => MakeCredentialOptions { None => MakeCredentialOptions {
rk: false, rk: false,
@@ -169,13 +171,13 @@ impl TryFrom<cbor::Value> for AuthenticatorMakeCredentialParameters {
}; };
let pin_uv_auth_param = param_map let pin_uv_auth_param = param_map
.get(&cbor_unsigned!(8)) .remove(&cbor_unsigned!(8))
.map(read_byte_string) .map(extract_byte_string)
.transpose()?; .transpose()?;
let pin_uv_auth_protocol = param_map let pin_uv_auth_protocol = param_map
.get(&cbor_unsigned!(9)) .remove(&cbor_unsigned!(9))
.map(read_unsigned) .map(extract_unsigned)
.transpose()?; .transpose()?;
Ok(AuthenticatorMakeCredentialParameters { Ok(AuthenticatorMakeCredentialParameters {
@@ -208,18 +210,20 @@ impl TryFrom<cbor::Value> for AuthenticatorGetAssertionParameters {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let param_map = read_map(&cbor_value)?; let mut param_map = extract_map(cbor_value)?;
let rp_id = read_text_string(ok_or_missing(param_map.get(&cbor_unsigned!(1)))?)?; let rp_id = extract_text_string(ok_or_missing(param_map.remove(&cbor_unsigned!(1)))?)?;
let client_data_hash = read_byte_string(ok_or_missing(param_map.get(&cbor_unsigned!(2)))?)?; let client_data_hash =
extract_byte_string(ok_or_missing(param_map.remove(&cbor_unsigned!(2)))?)?;
let allow_list = match param_map.get(&cbor_unsigned!(3)) { let allow_list = match param_map.remove(&cbor_unsigned!(3)) {
Some(entry) => { Some(entry) => {
let allow_list_vec = read_array(entry)?; let allow_list_vec = extract_array(entry)?;
let list_len = MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(allow_list_vec.len());
let allow_list = allow_list_vec let allow_list = allow_list_vec
.iter() .into_iter()
.take(MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(allow_list_vec.len())) .take(list_len)
.map(PublicKeyCredentialDescriptor::try_from) .map(PublicKeyCredentialDescriptor::try_from)
.collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?; .collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?;
Some(allow_list) Some(allow_list)
@@ -228,11 +232,11 @@ impl TryFrom<cbor::Value> for AuthenticatorGetAssertionParameters {
}; };
let extensions = param_map let extensions = param_map
.get(&cbor_unsigned!(4)) .remove(&cbor_unsigned!(4))
.map(Extensions::try_from) .map(Extensions::try_from)
.transpose()?; .transpose()?;
let options = match param_map.get(&cbor_unsigned!(5)) { let options = match param_map.remove(&cbor_unsigned!(5)) {
Some(entry) => GetAssertionOptions::try_from(entry)?, Some(entry) => GetAssertionOptions::try_from(entry)?,
None => GetAssertionOptions { None => GetAssertionOptions {
up: true, up: true,
@@ -241,13 +245,13 @@ impl TryFrom<cbor::Value> for AuthenticatorGetAssertionParameters {
}; };
let pin_uv_auth_param = param_map let pin_uv_auth_param = param_map
.get(&cbor_unsigned!(6)) .remove(&cbor_unsigned!(6))
.map(read_byte_string) .map(extract_byte_string)
.transpose()?; .transpose()?;
let pin_uv_auth_protocol = param_map let pin_uv_auth_protocol = param_map
.get(&cbor_unsigned!(7)) .remove(&cbor_unsigned!(7))
.map(read_unsigned) .map(extract_unsigned)
.transpose()?; .transpose()?;
Ok(AuthenticatorGetAssertionParameters { Ok(AuthenticatorGetAssertionParameters {
@@ -276,32 +280,32 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let param_map = read_map(&cbor_value)?; let mut param_map = extract_map(cbor_value)?;
let pin_protocol = read_unsigned(ok_or_missing(param_map.get(&cbor_unsigned!(1)))?)?; let pin_protocol = extract_unsigned(ok_or_missing(param_map.remove(&cbor_unsigned!(1)))?)?;
let sub_command = let sub_command =
ClientPinSubCommand::try_from(ok_or_missing(param_map.get(&cbor_unsigned!(2)))?)?; ClientPinSubCommand::try_from(ok_or_missing(param_map.remove(&cbor_unsigned!(2)))?)?;
let key_agreement = param_map let key_agreement = param_map
.get(&cbor_unsigned!(3)) .remove(&cbor_unsigned!(3))
.map(read_map) .map(extract_map)
.transpose()? .transpose()?
.map(|x| CoseKey(x.clone())); .map(|x| CoseKey(x));
let pin_auth = param_map let pin_auth = param_map
.get(&cbor_unsigned!(4)) .remove(&cbor_unsigned!(4))
.map(read_byte_string) .map(extract_byte_string)
.transpose()?; .transpose()?;
let new_pin_enc = param_map let new_pin_enc = param_map
.get(&cbor_unsigned!(5)) .remove(&cbor_unsigned!(5))
.map(read_byte_string) .map(extract_byte_string)
.transpose()?; .transpose()?;
let pin_hash_enc = param_map let pin_hash_enc = param_map
.get(&cbor_unsigned!(6)) .remove(&cbor_unsigned!(6))
.map(read_byte_string) .map(extract_byte_string)
.transpose()?; .transpose()?;
Ok(AuthenticatorClientPinParameters { Ok(AuthenticatorClientPinParameters {

View File

@@ -27,19 +27,19 @@ pub struct PublicKeyCredentialRpEntity {
pub rp_icon: Option<String>, pub rp_icon: Option<String>,
} }
impl TryFrom<&cbor::Value> for PublicKeyCredentialRpEntity { impl TryFrom<cbor::Value> for PublicKeyCredentialRpEntity {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let rp_map = read_map(cbor_value)?; let mut rp_map = extract_map(cbor_value)?;
let rp_id = read_text_string(ok_or_missing(rp_map.get(&cbor_text!("id")))?)?; let rp_id = extract_text_string(ok_or_missing(rp_map.remove(&cbor_text!("id")))?)?;
let rp_name = rp_map let rp_name = rp_map
.get(&cbor_text!("name")) .remove(&cbor_text!("name"))
.map(read_text_string) .map(extract_text_string)
.transpose()?; .transpose()?;
let rp_icon = rp_map let rp_icon = rp_map
.get(&cbor_text!("icon")) .remove(&cbor_text!("icon"))
.map(read_text_string) .map(extract_text_string)
.transpose()?; .transpose()?;
Ok(Self { Ok(Self {
rp_id, rp_id,
@@ -58,23 +58,23 @@ pub struct PublicKeyCredentialUserEntity {
pub user_icon: Option<String>, pub user_icon: Option<String>,
} }
impl TryFrom<&cbor::Value> for PublicKeyCredentialUserEntity { impl TryFrom<cbor::Value> for PublicKeyCredentialUserEntity {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let user_map = read_map(cbor_value)?; let mut user_map = extract_map(cbor_value)?;
let user_id = read_byte_string(ok_or_missing(user_map.get(&cbor_text!("id")))?)?; let user_id = extract_byte_string(ok_or_missing(user_map.remove(&cbor_text!("id")))?)?;
let user_name = user_map let user_name = user_map
.get(&cbor_text!("name")) .remove(&cbor_text!("name"))
.map(read_text_string) .map(extract_text_string)
.transpose()?; .transpose()?;
let user_display_name = user_map let user_display_name = user_map
.get(&cbor_text!("displayName")) .remove(&cbor_text!("displayName"))
.map(read_text_string) .map(extract_text_string)
.transpose()?; .transpose()?;
let user_icon = user_map let user_icon = user_map
.get(&cbor_text!("icon")) .remove(&cbor_text!("icon"))
.map(read_text_string) .map(extract_text_string)
.transpose()?; .transpose()?;
Ok(Self { Ok(Self {
user_id, user_id,
@@ -117,11 +117,11 @@ impl From<PublicKeyCredentialType> for cbor::Value {
} }
} }
impl TryFrom<&cbor::Value> for PublicKeyCredentialType { impl TryFrom<cbor::Value> for PublicKeyCredentialType {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_type_string = read_text_string(cbor_value)?; let cred_type_string = extract_text_string(cbor_value)?;
match &cred_type_string[..] { match &cred_type_string[..] {
"public-key" => Ok(PublicKeyCredentialType::PublicKey), "public-key" => Ok(PublicKeyCredentialType::PublicKey),
_ => Ok(PublicKeyCredentialType::Unknown), _ => Ok(PublicKeyCredentialType::Unknown),
@@ -137,16 +137,17 @@ pub struct PublicKeyCredentialParameter {
pub alg: SignatureAlgorithm, pub alg: SignatureAlgorithm,
} }
impl TryFrom<&cbor::Value> for PublicKeyCredentialParameter { impl TryFrom<cbor::Value> for PublicKeyCredentialParameter {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_param_map = read_map(cbor_value)?; let mut cred_param_map = extract_map(cbor_value)?;
let cred_type = PublicKeyCredentialType::try_from(ok_or_missing( let cred_type = PublicKeyCredentialType::try_from(ok_or_missing(
cred_param_map.get(&cbor_text!("type")), cred_param_map.remove(&cbor_text!("type")),
)?)?;
let alg = SignatureAlgorithm::try_from(ok_or_missing(
cred_param_map.remove(&cbor_text!("alg")),
)?)?; )?)?;
let alg =
SignatureAlgorithm::try_from(ok_or_missing(cred_param_map.get(&cbor_text!("alg")))?)?;
Ok(Self { cred_type, alg }) Ok(Self { cred_type, alg })
} }
} }
@@ -181,11 +182,11 @@ impl From<AuthenticatorTransport> for cbor::Value {
} }
} }
impl TryFrom<&cbor::Value> for AuthenticatorTransport { impl TryFrom<cbor::Value> for AuthenticatorTransport {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let transport_string = read_text_string(cbor_value)?; let transport_string = extract_text_string(cbor_value)?;
match &transport_string[..] { match &transport_string[..] {
"usb" => Ok(AuthenticatorTransport::Usb), "usb" => Ok(AuthenticatorTransport::Usb),
"nfc" => Ok(AuthenticatorTransport::Nfc), "nfc" => Ok(AuthenticatorTransport::Nfc),
@@ -204,23 +205,22 @@ pub struct PublicKeyCredentialDescriptor {
pub transports: Option<Vec<AuthenticatorTransport>>, pub transports: Option<Vec<AuthenticatorTransport>>,
} }
impl TryFrom<&cbor::Value> for PublicKeyCredentialDescriptor { impl TryFrom<cbor::Value> for PublicKeyCredentialDescriptor {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_desc_map = read_map(cbor_value)?; let mut cred_desc_map = extract_map(cbor_value)?;
let key_type = PublicKeyCredentialType::try_from(ok_or_missing( let key_type = PublicKeyCredentialType::try_from(ok_or_missing(
cred_desc_map.get(&cbor_text!("type")), cred_desc_map.remove(&cbor_text!("type")),
)?)?; )?)?;
let key_id = read_byte_string(ok_or_missing(cred_desc_map.get(&cbor_text!("id")))?)?; let key_id = extract_byte_string(ok_or_missing(cred_desc_map.remove(&cbor_text!("id")))?)?;
let transports = match cred_desc_map.get(&cbor_text!("transports")) { let transports = match cred_desc_map.remove(&cbor_text!("transports")) {
Some(exclude_entry) => { Some(exclude_entry) => {
let transport_vec = read_array(exclude_entry)?; let transport_vec = extract_array(exclude_entry)?;
let transports = transport_vec let transports = transport_vec
.iter() .into_iter()
.map(AuthenticatorTransport::try_from) .map(AuthenticatorTransport::try_from)
.collect::<Result<Vec<AuthenticatorTransport>, Ctap2StatusCode>>( .collect::<Result<Vec<AuthenticatorTransport>, Ctap2StatusCode>>()?;
)?;
Some(transports) Some(transports)
} }
None => None, None => None,
@@ -246,12 +246,12 @@ impl From<PublicKeyCredentialDescriptor> for cbor::Value {
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))] #[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
pub struct Extensions(BTreeMap<String, cbor::Value>); pub struct Extensions(BTreeMap<String, cbor::Value>);
impl TryFrom<&cbor::Value> for Extensions { impl TryFrom<cbor::Value> for Extensions {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut extensions = BTreeMap::new(); let mut extensions = BTreeMap::new();
for (extension_key, extension_value) in read_map(cbor_value)? { for (extension_key, extension_value) in extract_map(cbor_value)? {
if let cbor::KeyType::TextString(extension_key_string) = extension_key { if let cbor::KeyType::TextString(extension_key_string) = extension_key {
extensions.insert(extension_key_string.to_string(), extension_value.clone()); extensions.insert(extension_key_string.to_string(), extension_value.clone());
} else { } else {
@@ -281,23 +281,23 @@ impl Extensions {
pub fn has_make_credential_hmac_secret(&self) -> Result<bool, Ctap2StatusCode> { pub fn has_make_credential_hmac_secret(&self) -> Result<bool, Ctap2StatusCode> {
self.0 self.0
.get("hmac-secret") .get("hmac-secret")
.map(read_bool) .map(|b| extract_bool(b.clone()))
.unwrap_or(Ok(false)) .unwrap_or(Ok(false))
} }
pub fn get_assertion_hmac_secret( pub fn get_assertion_hmac_secret(
&self, mut self,
) -> Option<Result<GetAssertionHmacSecretInput, Ctap2StatusCode>> { ) -> Option<Result<GetAssertionHmacSecretInput, Ctap2StatusCode>> {
self.0 self.0
.get("hmac-secret") .remove("hmac-secret")
.map(GetAssertionHmacSecretInput::try_from) .map(GetAssertionHmacSecretInput::try_from)
} }
pub fn make_credential_cred_protect_policy( pub fn make_credential_cred_protect_policy(
&self, mut self,
) -> Option<Result<CredentialProtectionPolicy, Ctap2StatusCode>> { ) -> Option<Result<CredentialProtectionPolicy, Ctap2StatusCode>> {
self.0 self.0
.get("credProtect") .remove("credProtect")
.map(CredentialProtectionPolicy::try_from) .map(CredentialProtectionPolicy::try_from)
} }
} }
@@ -309,14 +309,14 @@ pub struct GetAssertionHmacSecretInput {
pub salt_auth: Vec<u8>, pub salt_auth: Vec<u8>,
} }
impl TryFrom<&cbor::Value> for GetAssertionHmacSecretInput { impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let input_map = read_map(cbor_value)?; let mut input_map = extract_map(cbor_value)?;
let cose_key = read_map(ok_or_missing(input_map.get(&cbor_unsigned!(1)))?)?; let cose_key = extract_map(ok_or_missing(input_map.remove(&cbor_unsigned!(1)))?)?;
let salt_enc = read_byte_string(ok_or_missing(input_map.get(&cbor_unsigned!(2)))?)?; let salt_enc = extract_byte_string(ok_or_missing(input_map.remove(&cbor_unsigned!(2)))?)?;
let salt_auth = read_byte_string(ok_or_missing(input_map.get(&cbor_unsigned!(3)))?)?; let salt_auth = extract_byte_string(ok_or_missing(input_map.remove(&cbor_unsigned!(3)))?)?;
Ok(Self { Ok(Self {
key_agreement: CoseKey(cose_key.clone()), key_agreement: CoseKey(cose_key.clone()),
salt_enc, salt_enc,
@@ -334,11 +334,13 @@ impl From<GetAssertionHmacSecretOutput> for cbor::Value {
} }
} }
impl TryFrom<&cbor::Value> for GetAssertionHmacSecretOutput { impl TryFrom<cbor::Value> for GetAssertionHmacSecretOutput {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
Ok(GetAssertionHmacSecretOutput(read_byte_string(cbor_value)?)) Ok(GetAssertionHmacSecretOutput(extract_byte_string(
cbor_value,
)?))
} }
} }
@@ -349,22 +351,22 @@ pub struct MakeCredentialOptions {
pub uv: bool, pub uv: bool,
} }
impl TryFrom<&cbor::Value> for MakeCredentialOptions { impl TryFrom<cbor::Value> for MakeCredentialOptions {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let options_map = read_map(cbor_value)?; let mut options_map = extract_map(cbor_value)?;
let rk = match options_map.get(&cbor_text!("rk")) { let rk = match options_map.remove(&cbor_text!("rk")) {
Some(options_entry) => read_bool(options_entry)?, Some(options_entry) => extract_bool(options_entry)?,
None => false, None => false,
}; };
if let Some(options_entry) = options_map.get(&cbor_text!("up")) { if let Some(options_entry) = options_map.remove(&cbor_text!("up")) {
if !read_bool(options_entry)? { if !extract_bool(options_entry)? {
return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION); return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION);
} }
} }
let uv = match options_map.get(&cbor_text!("uv")) { let uv = match options_map.remove(&cbor_text!("uv")) {
Some(options_entry) => read_bool(options_entry)?, Some(options_entry) => extract_bool(options_entry)?,
None => false, None => false,
}; };
Ok(Self { rk, uv }) Ok(Self { rk, uv })
@@ -377,22 +379,22 @@ pub struct GetAssertionOptions {
pub uv: bool, pub uv: bool,
} }
impl TryFrom<&cbor::Value> for GetAssertionOptions { impl TryFrom<cbor::Value> for GetAssertionOptions {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let options_map = read_map(cbor_value)?; let mut options_map = extract_map(cbor_value)?;
if let Some(options_entry) = options_map.get(&cbor_text!("rk")) { if let Some(options_entry) = options_map.remove(&cbor_text!("rk")) {
// This is only for returning the correct status code. // This is only for returning the correct status code.
read_bool(options_entry)?; extract_bool(options_entry)?;
return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION); return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION);
} }
let up = match options_map.get(&cbor_text!("up")) { let up = match options_map.remove(&cbor_text!("up")) {
Some(options_entry) => read_bool(options_entry)?, Some(options_entry) => extract_bool(options_entry)?,
None => true, None => true,
}; };
let uv = match options_map.get(&cbor_text!("uv")) { let uv = match options_map.remove(&cbor_text!("uv")) {
Some(options_entry) => read_bool(options_entry)?, Some(options_entry) => extract_bool(options_entry)?,
None => false, None => false,
}; };
Ok(Self { up, uv }) Ok(Self { up, uv })
@@ -435,11 +437,11 @@ impl From<SignatureAlgorithm> for cbor::Value {
} }
} }
impl TryFrom<&cbor::Value> for SignatureAlgorithm { impl TryFrom<cbor::Value> for SignatureAlgorithm {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
match read_integer(cbor_value)? { match extract_integer(cbor_value)? {
ecdsa::PubKey::ES256_ALGORITHM => Ok(SignatureAlgorithm::ES256), ecdsa::PubKey::ES256_ALGORITHM => Ok(SignatureAlgorithm::ES256),
_ => Ok(SignatureAlgorithm::Unknown), _ => Ok(SignatureAlgorithm::Unknown),
} }
@@ -473,19 +475,6 @@ impl TryFrom<cbor::Value> for CredentialProtectionPolicy {
} }
} }
impl TryFrom<&cbor::Value> for CredentialProtectionPolicy {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
match read_integer(cbor_value)? {
0x01 => Ok(CredentialProtectionPolicy::UserVerificationOptional),
0x02 => Ok(CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList),
0x03 => Ok(CredentialProtectionPolicy::UserVerificationRequired),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
}
// https://www.w3.org/TR/webauthn/#public-key-credential-source // https://www.w3.org/TR/webauthn/#public-key-credential-source
// //
// Note that we only use the WebAuthn definition as an example. This data-structure is not specified // Note that we only use the WebAuthn definition as an example. This data-structure is not specified
@@ -645,23 +634,24 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cose_key: CoseKey) -> Result<Self, Ctap2StatusCode> { fn try_from(cose_key: CoseKey) -> Result<Self, Ctap2StatusCode> {
let key_type = read_integer(ok_or_missing(cose_key.0.get(&cbor_int!(1)))?)?; let mut cose_map = cose_key.0;
let key_type = extract_integer(ok_or_missing(cose_map.remove(&cbor_int!(1)))?)?;
if key_type != EC2_KEY_TYPE { if key_type != EC2_KEY_TYPE {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
} }
let algorithm = read_integer(ok_or_missing(cose_key.0.get(&cbor_int!(3)))?)?; let algorithm = extract_integer(ok_or_missing(cose_map.remove(&cbor_int!(3)))?)?;
if algorithm != ECDH_ALGORITHM && algorithm != ES256_ALGORITHM { if algorithm != ECDH_ALGORITHM && algorithm != ES256_ALGORITHM {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
} }
let curve = read_integer(ok_or_missing(cose_key.0.get(&cbor_int!(-1)))?)?; let curve = extract_integer(ok_or_missing(cose_map.remove(&cbor_int!(-1)))?)?;
if curve != P_256_CURVE { if curve != P_256_CURVE {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
} }
let x_bytes = read_byte_string(ok_or_missing(cose_key.0.get(&cbor_int!(-2)))?)?; let x_bytes = extract_byte_string(ok_or_missing(cose_map.remove(&cbor_int!(-2)))?)?;
if x_bytes.len() != ecdh::NBYTES { if x_bytes.len() != ecdh::NBYTES {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
} }
let y_bytes = read_byte_string(ok_or_missing(cose_key.0.get(&cbor_int!(-3)))?)?; let y_bytes = extract_byte_string(ok_or_missing(cose_map.remove(&cbor_int!(-3)))?)?;
if y_bytes.len() != ecdh::NBYTES { if y_bytes.len() != ecdh::NBYTES {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
} }
@@ -698,11 +688,11 @@ impl From<ClientPinSubCommand> for cbor::Value {
} }
} }
impl TryFrom<&cbor::Value> for ClientPinSubCommand { impl TryFrom<cbor::Value> for ClientPinSubCommand {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> { fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let subcommand_int = read_unsigned(cbor_value)?; let subcommand_int = extract_unsigned(cbor_value)?;
match subcommand_int { match subcommand_int {
0x01 => Ok(ClientPinSubCommand::GetPinRetries), 0x01 => Ok(ClientPinSubCommand::GetPinRetries),
0x02 => Ok(ClientPinSubCommand::GetKeyAgreement), 0x02 => Ok(ClientPinSubCommand::GetKeyAgreement),
@@ -717,28 +707,14 @@ impl TryFrom<&cbor::Value> for ClientPinSubCommand {
} }
} }
pub(super) fn read_unsigned(cbor_value: &cbor::Value) -> Result<u64, Ctap2StatusCode> { pub(super) fn extract_unsigned(cbor_value: cbor::Value) -> Result<u64, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => Ok(*unsigned), cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => Ok(unsigned),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn read_integer(cbor_value: &cbor::Value) -> Result<i64, Ctap2StatusCode> { pub(super) fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> {
match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => {
if *unsigned <= core::i64::MAX as u64 {
Ok(*unsigned as i64)
} else {
Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
}
}
cbor::Value::KeyValue(cbor::KeyType::Negative(signed)) => Ok(*signed),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => { cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => {
if unsigned <= core::i64::MAX as u64 { if unsigned <= core::i64::MAX as u64 {
@@ -752,53 +728,28 @@ fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> {
} }
} }
pub fn read_byte_string(cbor_value: &cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> { pub fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> {
match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::ByteString(byte_string)) => Ok(byte_string.to_vec()),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::ByteString(byte_string)) => Ok(byte_string), cbor::Value::KeyValue(cbor::KeyType::ByteString(byte_string)) => Ok(byte_string),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn read_text_string(cbor_value: &cbor::Value) -> Result<String, Ctap2StatusCode> { pub(super) fn extract_text_string(cbor_value: cbor::Value) -> Result<String, Ctap2StatusCode> {
match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::TextString(text_string)) => {
Ok(text_string.to_string())
}
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
fn extract_text_string(cbor_value: cbor::Value) -> Result<String, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::TextString(text_string)) => Ok(text_string), cbor::Value::KeyValue(cbor::KeyType::TextString(text_string)) => Ok(text_string),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn read_array(cbor_value: &cbor::Value) -> Result<&Vec<cbor::Value>, Ctap2StatusCode> { pub(super) fn extract_array(cbor_value: cbor::Value) -> Result<Vec<cbor::Value>, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::Array(array) => Ok(array), cbor::Value::Array(array) => Ok(array),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn read_map( pub(super) fn extract_map(
cbor_value: &cbor::Value,
) -> Result<&BTreeMap<cbor::KeyType, cbor::Value>, Ctap2StatusCode> {
match cbor_value {
cbor::Value::Map(map) => Ok(map),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
fn extract_map(
cbor_value: cbor::Value, cbor_value: cbor::Value,
) -> Result<BTreeMap<cbor::KeyType, cbor::Value>, Ctap2StatusCode> { ) -> Result<BTreeMap<cbor::KeyType, cbor::Value>, Ctap2StatusCode> {
match cbor_value { match cbor_value {
@@ -807,7 +758,7 @@ fn extract_map(
} }
} }
pub(super) fn read_bool(cbor_value: &cbor::Value) -> Result<bool, Ctap2StatusCode> { pub(super) fn extract_bool(cbor_value: cbor::Value) -> Result<bool, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::Simple(cbor::SimpleValue::FalseValue) => Ok(false), cbor::Value::Simple(cbor::SimpleValue::FalseValue) => Ok(false),
cbor::Value::Simple(cbor::SimpleValue::TrueValue) => Ok(true), cbor::Value::Simple(cbor::SimpleValue::TrueValue) => Ok(true),
@@ -827,192 +778,192 @@ mod test {
use crypto::rng256::{Rng256, ThreadRng256}; use crypto::rng256::{Rng256, ThreadRng256};
#[test] #[test]
fn test_read_unsigned() { fn test_extract_unsigned() {
assert_eq!(read_unsigned(&cbor_int!(123)), Ok(123)); assert_eq!(extract_unsigned(cbor_int!(123)), Ok(123));
assert_eq!( assert_eq!(
read_unsigned(&cbor_bool!(true)), extract_unsigned(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_text!("foo")), extract_unsigned(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_bytes_lit!(b"bar")), extract_unsigned(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_array![]), extract_unsigned(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_map! {}), extract_unsigned(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_unsigned_limits() { fn test_extract_unsigned_limits() {
assert_eq!( assert_eq!(
read_unsigned(&cbor_unsigned!(std::u64::MAX)), extract_unsigned(cbor_unsigned!(std::u64::MAX)),
Ok(std::u64::MAX) Ok(std::u64::MAX)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_unsigned!((std::i64::MAX as u64) + 1)), extract_unsigned(cbor_unsigned!((std::i64::MAX as u64) + 1)),
Ok((std::i64::MAX as u64) + 1) Ok((std::i64::MAX as u64) + 1)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_int!(std::i64::MAX)), extract_unsigned(cbor_int!(std::i64::MAX)),
Ok(std::i64::MAX as u64) Ok(std::i64::MAX as u64)
); );
assert_eq!(read_unsigned(&cbor_int!(123)), Ok(123)); assert_eq!(extract_unsigned(cbor_int!(123)), Ok(123));
assert_eq!(read_unsigned(&cbor_int!(1)), Ok(1)); assert_eq!(extract_unsigned(cbor_int!(1)), Ok(1));
assert_eq!(read_unsigned(&cbor_int!(0)), Ok(0)); assert_eq!(extract_unsigned(cbor_int!(0)), Ok(0));
assert_eq!( assert_eq!(
read_unsigned(&cbor_int!(-1)), extract_unsigned(cbor_int!(-1)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_int!(-123)), extract_unsigned(cbor_int!(-123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_unsigned(&cbor_int!(std::i64::MIN)), extract_unsigned(cbor_int!(std::i64::MIN)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_integer() { fn test_extract_integer() {
assert_eq!(read_integer(&cbor_int!(123)), Ok(123)); assert_eq!(extract_integer(cbor_int!(123)), Ok(123));
assert_eq!(read_integer(&cbor_int!(-123)), Ok(-123)); assert_eq!(extract_integer(cbor_int!(-123)), Ok(-123));
assert_eq!( assert_eq!(
read_integer(&cbor_bool!(true)), extract_integer(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_integer(&cbor_text!("foo")), extract_integer(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_integer(&cbor_bytes_lit!(b"bar")), extract_integer(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_integer(&cbor_array![]), extract_integer(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_integer(&cbor_map! {}), extract_integer(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_integer_limits() { fn test_extract_integer_limits() {
assert_eq!( assert_eq!(
read_integer(&cbor_unsigned!(std::u64::MAX)), extract_integer(cbor_unsigned!(std::u64::MAX)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_integer(&cbor_unsigned!((std::i64::MAX as u64) + 1)), extract_integer(cbor_unsigned!((std::i64::MAX as u64) + 1)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_integer(&cbor_int!(std::i64::MAX)), Ok(std::i64::MAX)); assert_eq!(extract_integer(cbor_int!(std::i64::MAX)), Ok(std::i64::MAX));
assert_eq!(read_integer(&cbor_int!(123)), Ok(123)); assert_eq!(extract_integer(cbor_int!(123)), Ok(123));
assert_eq!(read_integer(&cbor_int!(1)), Ok(1)); assert_eq!(extract_integer(cbor_int!(1)), Ok(1));
assert_eq!(read_integer(&cbor_int!(0)), Ok(0)); assert_eq!(extract_integer(cbor_int!(0)), Ok(0));
assert_eq!(read_integer(&cbor_int!(-1)), Ok(-1)); assert_eq!(extract_integer(cbor_int!(-1)), Ok(-1));
assert_eq!(read_integer(&cbor_int!(-123)), Ok(-123)); assert_eq!(extract_integer(cbor_int!(-123)), Ok(-123));
assert_eq!(read_integer(&cbor_int!(std::i64::MIN)), Ok(std::i64::MIN)); assert_eq!(extract_integer(cbor_int!(std::i64::MIN)), Ok(std::i64::MIN));
} }
#[test] #[test]
fn test_read_byte_string() { fn test_extract_byte_string() {
assert_eq!( assert_eq!(
read_byte_string(&cbor_int!(123)), extract_byte_string(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_byte_string(&cbor_bool!(true)), extract_byte_string(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_byte_string(&cbor_text!("foo")), extract_byte_string(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_byte_string(&cbor_bytes_lit!(b"")), Ok(Vec::new())); assert_eq!(extract_byte_string(cbor_bytes_lit!(b"")), Ok(Vec::new()));
assert_eq!( assert_eq!(
read_byte_string(&cbor_bytes_lit!(b"bar")), extract_byte_string(cbor_bytes_lit!(b"bar")),
Ok(b"bar".to_vec()) Ok(b"bar".to_vec())
); );
assert_eq!( assert_eq!(
read_byte_string(&cbor_array![]), extract_byte_string(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_byte_string(&cbor_map! {}), extract_byte_string(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_text_string() { fn test_extract_text_string() {
assert_eq!( assert_eq!(
read_text_string(&cbor_int!(123)), extract_text_string(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_text_string(&cbor_bool!(true)), extract_text_string(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_text_string(&cbor_text!("")), Ok(String::new())); assert_eq!(extract_text_string(cbor_text!("")), Ok(String::new()));
assert_eq!( assert_eq!(
read_text_string(&cbor_text!("foo")), extract_text_string(cbor_text!("foo")),
Ok(String::from("foo")) Ok(String::from("foo"))
); );
assert_eq!( assert_eq!(
read_text_string(&cbor_bytes_lit!(b"bar")), extract_text_string(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_text_string(&cbor_array![]), extract_text_string(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_text_string(&cbor_map! {}), extract_text_string(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_array() { fn test_extract_array() {
assert_eq!( assert_eq!(
read_array(&cbor_int!(123)), extract_array(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_array(&cbor_bool!(true)), extract_array(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_array(&cbor_text!("foo")), extract_array(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_array(&cbor_bytes_lit!(b"bar")), extract_array(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_array(&cbor_array![]), Ok(&Vec::new())); assert_eq!(extract_array(cbor_array![]), Ok(Vec::new()));
assert_eq!( assert_eq!(
read_array(&cbor_array![ extract_array(cbor_array![
123, 123,
cbor_null!(), cbor_null!(),
"foo", "foo",
cbor_array![], cbor_array![],
cbor_map! {}, cbor_map! {},
]), ]),
Ok(&vec![ Ok(vec![
cbor_int!(123), cbor_int!(123),
cbor_null!(), cbor_null!(),
cbor_text!("foo"), cbor_text!("foo"),
@@ -1021,41 +972,41 @@ mod test {
]) ])
); );
assert_eq!( assert_eq!(
read_array(&cbor_map! {}), extract_array(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
#[test] #[test]
fn test_read_map() { fn test_extract_map() {
assert_eq!( assert_eq!(
read_map(&cbor_int!(123)), extract_map(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_map(&cbor_bool!(true)), extract_map(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_map(&cbor_text!("foo")), extract_map(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_map(&cbor_bytes_lit!(b"bar")), extract_map(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_map(&cbor_array![]), extract_map(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_map(&cbor_map! {}), Ok(&BTreeMap::new())); assert_eq!(extract_map(cbor_map! {}), Ok(BTreeMap::new()));
assert_eq!( assert_eq!(
read_map(&cbor_map! { extract_map(cbor_map! {
1 => cbor_false!(), 1 => cbor_false!(),
"foo" => b"bar", "foo" => b"bar",
b"bin" => -42, b"bin" => -42,
}), }),
Ok(&[ Ok([
(cbor_unsigned!(1), cbor_false!()), (cbor_unsigned!(1), cbor_false!()),
(cbor_text!("foo"), cbor_bytes_lit!(b"bar")), (cbor_text!("foo"), cbor_bytes_lit!(b"bar")),
(cbor_bytes_lit!(b"bin"), cbor_int!(-42)), (cbor_bytes_lit!(b"bin"), cbor_int!(-42)),
@@ -1067,27 +1018,27 @@ mod test {
} }
#[test] #[test]
fn test_read_bool() { fn test_extract_bool() {
assert_eq!( assert_eq!(
read_bool(&cbor_int!(123)), extract_bool(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!(read_bool(&cbor_bool!(true)), Ok(true)); assert_eq!(extract_bool(cbor_bool!(true)), Ok(true));
assert_eq!(read_bool(&cbor_bool!(false)), Ok(false)); assert_eq!(extract_bool(cbor_bool!(false)), Ok(false));
assert_eq!( assert_eq!(
read_bool(&cbor_text!("foo")), extract_bool(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_bool(&cbor_bytes_lit!(b"bar")), extract_bool(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_bool(&cbor_array![]), extract_bool(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
assert_eq!( assert_eq!(
read_bool(&cbor_map! {}), extract_bool(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
); );
} }
@@ -1099,7 +1050,7 @@ mod test {
"name" => "Example", "name" => "Example",
"icon" => "example.com/icon.png", "icon" => "example.com/icon.png",
}; };
let rp_entity = PublicKeyCredentialRpEntity::try_from(&cbor_rp_entity); let rp_entity = PublicKeyCredentialRpEntity::try_from(cbor_rp_entity);
let expected_rp_entity = PublicKeyCredentialRpEntity { let expected_rp_entity = PublicKeyCredentialRpEntity {
rp_id: "example.com".to_string(), rp_id: "example.com".to_string(),
rp_name: Some("Example".to_string()), rp_name: Some("Example".to_string()),
@@ -1116,7 +1067,7 @@ mod test {
"displayName" => "bar", "displayName" => "bar",
"icon" => "example.com/foo/icon.png", "icon" => "example.com/foo/icon.png",
}; };
let user_entity = PublicKeyCredentialUserEntity::try_from(&cbor_user_entity); let user_entity = PublicKeyCredentialUserEntity::try_from(cbor_user_entity.clone());
let expected_user_entity = PublicKeyCredentialUserEntity { let expected_user_entity = PublicKeyCredentialUserEntity {
user_id: vec![0x1D, 0x1D, 0x1D, 0x1D], user_id: vec![0x1D, 0x1D, 0x1D, 0x1D],
user_name: Some("foo".to_string()), user_name: Some("foo".to_string()),
@@ -1130,30 +1081,30 @@ mod test {
#[test] #[test]
fn test_from_into_public_key_credential_type() { fn test_from_into_public_key_credential_type() {
let cbor_credential_type = cbor_text!("public-key"); let cbor_credential_type: cbor::Value = cbor_text!("public-key");
let credential_type = PublicKeyCredentialType::try_from(&cbor_credential_type); let credential_type = PublicKeyCredentialType::try_from(cbor_credential_type.clone());
let expected_credential_type = PublicKeyCredentialType::PublicKey; let expected_credential_type = PublicKeyCredentialType::PublicKey;
assert_eq!(credential_type, Ok(expected_credential_type)); assert_eq!(credential_type, Ok(expected_credential_type));
let created_cbor: cbor::Value = credential_type.unwrap().into(); let created_cbor: cbor::Value = credential_type.unwrap().into();
assert_eq!(created_cbor, cbor_credential_type); assert_eq!(created_cbor, cbor_credential_type);
let cbor_unknown_type = cbor_text!("unknown-type"); let cbor_unknown_type: cbor::Value = cbor_text!("unknown-type");
let unknown_type = PublicKeyCredentialType::try_from(&cbor_unknown_type); let unknown_type = PublicKeyCredentialType::try_from(cbor_unknown_type);
let expected_unknown_type = PublicKeyCredentialType::Unknown; let expected_unknown_type = PublicKeyCredentialType::Unknown;
assert_eq!(unknown_type, Ok(expected_unknown_type)); assert_eq!(unknown_type, Ok(expected_unknown_type));
} }
#[test] #[test]
fn test_from_into_signature_algorithm() { fn test_from_into_signature_algorithm() {
let cbor_signature_algorithm = cbor_int!(ecdsa::PubKey::ES256_ALGORITHM); let cbor_signature_algorithm: cbor::Value = cbor_int!(ecdsa::PubKey::ES256_ALGORITHM);
let signature_algorithm = SignatureAlgorithm::try_from(&cbor_signature_algorithm); let signature_algorithm = SignatureAlgorithm::try_from(cbor_signature_algorithm.clone());
let expected_signature_algorithm = SignatureAlgorithm::ES256; let expected_signature_algorithm = SignatureAlgorithm::ES256;
assert_eq!(signature_algorithm, Ok(expected_signature_algorithm)); assert_eq!(signature_algorithm, Ok(expected_signature_algorithm));
let created_cbor = cbor::Value::from(signature_algorithm.unwrap()); let created_cbor = cbor::Value::from(signature_algorithm.unwrap());
assert_eq!(created_cbor, cbor_signature_algorithm); assert_eq!(created_cbor, cbor_signature_algorithm);
let cbor_unknown_algorithm = cbor_int!(-1); let cbor_unknown_algorithm: cbor::Value = cbor_int!(-1);
let unknown_algorithm = SignatureAlgorithm::try_from(&cbor_unknown_algorithm); let unknown_algorithm = SignatureAlgorithm::try_from(cbor_unknown_algorithm);
let expected_unknown_algorithm = SignatureAlgorithm::Unknown; let expected_unknown_algorithm = SignatureAlgorithm::Unknown;
assert_eq!(unknown_algorithm, Ok(expected_unknown_algorithm)); assert_eq!(unknown_algorithm, Ok(expected_unknown_algorithm));
} }
@@ -1177,23 +1128,23 @@ mod test {
#[test] #[test]
fn test_from_into_cred_protection_policy() { fn test_from_into_cred_protection_policy() {
let cbor_policy = cbor::Value::from(CredentialProtectionPolicy::UserVerificationOptional); let cbor_policy = cbor::Value::from(CredentialProtectionPolicy::UserVerificationOptional);
let policy = CredentialProtectionPolicy::try_from(&cbor_policy); let policy = CredentialProtectionPolicy::try_from(cbor_policy.clone());
let expected_policy = CredentialProtectionPolicy::UserVerificationOptional; let expected_policy = CredentialProtectionPolicy::UserVerificationOptional;
assert_eq!(policy, Ok(expected_policy)); assert_eq!(policy, Ok(expected_policy));
let created_cbor = cbor::Value::from(policy.unwrap()); let created_cbor = cbor::Value::from(policy.unwrap());
assert_eq!(created_cbor, cbor_policy); assert_eq!(created_cbor, cbor_policy);
let cbor_policy_error = cbor_int!(-1); let cbor_policy_error: cbor::Value = cbor_int!(-1);
let policy_error = CredentialProtectionPolicy::try_from(&cbor_policy_error); let policy_error = CredentialProtectionPolicy::try_from(cbor_policy_error);
let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE); let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
assert_eq!(policy_error, expected_error); assert_eq!(policy_error, expected_error);
} }
#[test] #[test]
fn test_from_into_authenticator_transport() { fn test_from_into_authenticator_transport() {
let cbor_authenticator_transport = cbor_text!("usb"); let cbor_authenticator_transport: cbor::Value = cbor_text!("usb");
let authenticator_transport = let authenticator_transport =
AuthenticatorTransport::try_from(&cbor_authenticator_transport); AuthenticatorTransport::try_from(cbor_authenticator_transport.clone());
let expected_authenticator_transport = AuthenticatorTransport::Usb; let expected_authenticator_transport = AuthenticatorTransport::Usb;
assert_eq!( assert_eq!(
authenticator_transport, authenticator_transport,
@@ -1210,7 +1161,7 @@ mod test {
"alg" => ecdsa::PubKey::ES256_ALGORITHM, "alg" => ecdsa::PubKey::ES256_ALGORITHM,
}; };
let credential_parameter = let credential_parameter =
PublicKeyCredentialParameter::try_from(&cbor_credential_parameter); PublicKeyCredentialParameter::try_from(cbor_credential_parameter.clone());
let expected_credential_parameter = PublicKeyCredentialParameter { let expected_credential_parameter = PublicKeyCredentialParameter {
cred_type: PublicKeyCredentialType::PublicKey, cred_type: PublicKeyCredentialType::PublicKey,
alg: SignatureAlgorithm::ES256, alg: SignatureAlgorithm::ES256,
@@ -1228,7 +1179,7 @@ mod test {
"transports" => cbor_array!["usb"], "transports" => cbor_array!["usb"],
}; };
let credential_descriptor = let credential_descriptor =
PublicKeyCredentialDescriptor::try_from(&cbor_credential_descriptor); PublicKeyCredentialDescriptor::try_from(cbor_credential_descriptor.clone());
let expected_credential_descriptor = PublicKeyCredentialDescriptor { let expected_credential_descriptor = PublicKeyCredentialDescriptor {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
key_id: vec![0x2D, 0x2D, 0x2D, 0x2D], key_id: vec![0x2D, 0x2D, 0x2D, 0x2D],
@@ -1244,7 +1195,7 @@ mod test {
let cbor_extensions = cbor_map! { let cbor_extensions = cbor_map! {
"the_answer" => 42, "the_answer" => 42,
}; };
let extensions = Extensions::try_from(&cbor_extensions); let extensions = Extensions::try_from(cbor_extensions.clone());
let mut expected_extensions = Extensions(BTreeMap::new()); let mut expected_extensions = Extensions(BTreeMap::new());
expected_extensions expected_extensions
.0 .0
@@ -1256,8 +1207,8 @@ mod test {
#[test] #[test]
fn test_from_into_get_assertion_hmac_secret_output() { fn test_from_into_get_assertion_hmac_secret_output() {
let cbor_output = cbor_bytes![vec![0xC0; 32]]; let cbor_output: cbor::Value = cbor_bytes![vec![0xC0; 32]];
let output = GetAssertionHmacSecretOutput::try_from(&cbor_output); let output = GetAssertionHmacSecretOutput::try_from(cbor_output.clone());
let expected_output = GetAssertionHmacSecretOutput(vec![0xC0; 32]); let expected_output = GetAssertionHmacSecretOutput(vec![0xC0; 32]);
assert_eq!(output, Ok(expected_output)); assert_eq!(output, Ok(expected_output));
let created_cbor: cbor::Value = output.unwrap().into(); let created_cbor: cbor::Value = output.unwrap().into();
@@ -1269,13 +1220,13 @@ mod test {
let cbor_extensions = cbor_map! { let cbor_extensions = cbor_map! {
"hmac-secret" => true, "hmac-secret" => true,
}; };
let extensions = Extensions::try_from(&cbor_extensions).unwrap(); let extensions = Extensions::try_from(cbor_extensions).unwrap();
assert!(extensions.has_make_credential_hmac_secret().unwrap()); assert!(extensions.has_make_credential_hmac_secret().unwrap());
let cbor_extensions = cbor_map! { let cbor_extensions = cbor_map! {
"hmac-secret" => false, "hmac-secret" => false,
}; };
let extensions = Extensions::try_from(&cbor_extensions).unwrap(); let extensions = Extensions::try_from(cbor_extensions).unwrap();
assert!(!extensions.has_make_credential_hmac_secret().unwrap()); assert!(!extensions.has_make_credential_hmac_secret().unwrap());
let mut rng = ThreadRng256 {}; let mut rng = ThreadRng256 {};
@@ -1289,7 +1240,7 @@ mod test {
3 => vec![0x03; 32], 3 => vec![0x03; 32],
}, },
}; };
let extensions = Extensions::try_from(&cbor_extensions).unwrap(); let extensions = Extensions::try_from(cbor_extensions).unwrap();
let get_assertion_input = extensions.get_assertion_hmac_secret(); let get_assertion_input = extensions.get_assertion_hmac_secret();
let expected_input = GetAssertionHmacSecretInput { let expected_input = GetAssertionHmacSecretInput {
key_agreement: cose_key, key_agreement: cose_key,
@@ -1304,7 +1255,7 @@ mod test {
let cbor_extensions = cbor_map! { let cbor_extensions = cbor_map! {
"credProtect" => CredentialProtectionPolicy::UserVerificationRequired, "credProtect" => CredentialProtectionPolicy::UserVerificationRequired,
}; };
let extensions = Extensions::try_from(&cbor_extensions).unwrap(); let extensions = Extensions::try_from(cbor_extensions).unwrap();
assert_eq!( assert_eq!(
extensions.make_credential_cred_protect_policy(), extensions.make_credential_cred_protect_policy(),
Some(Ok(CredentialProtectionPolicy::UserVerificationRequired)) Some(Ok(CredentialProtectionPolicy::UserVerificationRequired))
@@ -1317,7 +1268,7 @@ mod test {
"rk" => true, "rk" => true,
"uv" => false, "uv" => false,
}; };
let make_options = MakeCredentialOptions::try_from(&cbor_make_options); let make_options = MakeCredentialOptions::try_from(cbor_make_options);
let expected_make_options = MakeCredentialOptions { let expected_make_options = MakeCredentialOptions {
rk: true, rk: true,
uv: false, uv: false,
@@ -1331,7 +1282,7 @@ mod test {
"up" => true, "up" => true,
"uv" => false, "uv" => false,
}; };
let get_assertion = GetAssertionOptions::try_from(&cbor_get_assertion); let get_assertion = GetAssertionOptions::try_from(cbor_get_assertion);
let expected_get_assertion = GetAssertionOptions { let expected_get_assertion = GetAssertionOptions {
up: true, up: true,
uv: false, uv: false,
@@ -1370,8 +1321,8 @@ mod test {
#[test] #[test]
fn test_from_into_client_pin_sub_command() { fn test_from_into_client_pin_sub_command() {
let cbor_sub_command = cbor_int!(0x01); let cbor_sub_command: cbor::Value = cbor_int!(0x01);
let sub_command = ClientPinSubCommand::try_from(&cbor_sub_command); let sub_command = ClientPinSubCommand::try_from(cbor_sub_command.clone());
let expected_sub_command = ClientPinSubCommand::GetPinRetries; let expected_sub_command = ClientPinSubCommand::GetPinRetries;
assert_eq!(sub_command, Ok(expected_sub_command)); assert_eq!(sub_command, Ok(expected_sub_command));
let created_cbor: cbor::Value = sub_command.unwrap().into(); let created_cbor: cbor::Value = sub_command.unwrap().into();

View File

@@ -435,6 +435,7 @@ where
} }
let (use_hmac_extension, cred_protect_policy) = if let Some(extensions) = extensions { let (use_hmac_extension, cred_protect_policy) = if let Some(extensions) = extensions {
let has_hmac_secret = extensions.has_make_credential_hmac_secret()?;
let mut cred_protect = extensions let mut cred_protect = extensions
.make_credential_cred_protect_policy() .make_credential_cred_protect_policy()
.transpose()?; .transpose()?;
@@ -444,7 +445,7 @@ where
{ {
cred_protect = DEFAULT_CRED_PROTECT; cred_protect = DEFAULT_CRED_PROTECT;
} }
(extensions.has_make_credential_hmac_secret()?, cred_protect) (has_hmac_secret, cred_protect)
} else { } else {
(false, None) (false, None)
}; };