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

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

View File

@@ -27,19 +27,19 @@ pub struct PublicKeyCredentialRpEntity {
pub rp_icon: Option<String>,
}
impl TryFrom<&cbor::Value> for PublicKeyCredentialRpEntity {
impl TryFrom<cbor::Value> for PublicKeyCredentialRpEntity {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let rp_map = read_map(cbor_value)?;
let rp_id = read_text_string(ok_or_missing(rp_map.get(&cbor_text!("id")))?)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut rp_map = extract_map(cbor_value)?;
let rp_id = extract_text_string(ok_or_missing(rp_map.remove(&cbor_text!("id")))?)?;
let rp_name = rp_map
.get(&cbor_text!("name"))
.map(read_text_string)
.remove(&cbor_text!("name"))
.map(extract_text_string)
.transpose()?;
let rp_icon = rp_map
.get(&cbor_text!("icon"))
.map(read_text_string)
.remove(&cbor_text!("icon"))
.map(extract_text_string)
.transpose()?;
Ok(Self {
rp_id,
@@ -58,23 +58,23 @@ pub struct PublicKeyCredentialUserEntity {
pub user_icon: Option<String>,
}
impl TryFrom<&cbor::Value> for PublicKeyCredentialUserEntity {
impl TryFrom<cbor::Value> for PublicKeyCredentialUserEntity {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let user_map = read_map(cbor_value)?;
let user_id = read_byte_string(ok_or_missing(user_map.get(&cbor_text!("id")))?)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut user_map = extract_map(cbor_value)?;
let user_id = extract_byte_string(ok_or_missing(user_map.remove(&cbor_text!("id")))?)?;
let user_name = user_map
.get(&cbor_text!("name"))
.map(read_text_string)
.remove(&cbor_text!("name"))
.map(extract_text_string)
.transpose()?;
let user_display_name = user_map
.get(&cbor_text!("displayName"))
.map(read_text_string)
.remove(&cbor_text!("displayName"))
.map(extract_text_string)
.transpose()?;
let user_icon = user_map
.get(&cbor_text!("icon"))
.map(read_text_string)
.remove(&cbor_text!("icon"))
.map(extract_text_string)
.transpose()?;
Ok(Self {
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;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_type_string = read_text_string(cbor_value)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_type_string = extract_text_string(cbor_value)?;
match &cred_type_string[..] {
"public-key" => Ok(PublicKeyCredentialType::PublicKey),
_ => Ok(PublicKeyCredentialType::Unknown),
@@ -137,16 +137,17 @@ pub struct PublicKeyCredentialParameter {
pub alg: SignatureAlgorithm,
}
impl TryFrom<&cbor::Value> for PublicKeyCredentialParameter {
impl TryFrom<cbor::Value> for PublicKeyCredentialParameter {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_param_map = read_map(cbor_value)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut cred_param_map = extract_map(cbor_value)?;
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 })
}
}
@@ -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;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let transport_string = read_text_string(cbor_value)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let transport_string = extract_text_string(cbor_value)?;
match &transport_string[..] {
"usb" => Ok(AuthenticatorTransport::Usb),
"nfc" => Ok(AuthenticatorTransport::Nfc),
@@ -204,23 +205,22 @@ pub struct PublicKeyCredentialDescriptor {
pub transports: Option<Vec<AuthenticatorTransport>>,
}
impl TryFrom<&cbor::Value> for PublicKeyCredentialDescriptor {
impl TryFrom<cbor::Value> for PublicKeyCredentialDescriptor {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let cred_desc_map = read_map(cbor_value)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut cred_desc_map = extract_map(cbor_value)?;
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 transports = match cred_desc_map.get(&cbor_text!("transports")) {
let key_id = extract_byte_string(ok_or_missing(cred_desc_map.remove(&cbor_text!("id")))?)?;
let transports = match cred_desc_map.remove(&cbor_text!("transports")) {
Some(exclude_entry) => {
let transport_vec = read_array(exclude_entry)?;
let transport_vec = extract_array(exclude_entry)?;
let transports = transport_vec
.iter()
.into_iter()
.map(AuthenticatorTransport::try_from)
.collect::<Result<Vec<AuthenticatorTransport>, Ctap2StatusCode>>(
)?;
.collect::<Result<Vec<AuthenticatorTransport>, Ctap2StatusCode>>()?;
Some(transports)
}
None => None,
@@ -246,12 +246,12 @@ impl From<PublicKeyCredentialDescriptor> for cbor::Value {
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
pub struct Extensions(BTreeMap<String, cbor::Value>);
impl TryFrom<&cbor::Value> for Extensions {
impl TryFrom<cbor::Value> for Extensions {
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();
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 {
extensions.insert(extension_key_string.to_string(), extension_value.clone());
} else {
@@ -281,23 +281,23 @@ impl Extensions {
pub fn has_make_credential_hmac_secret(&self) -> Result<bool, Ctap2StatusCode> {
self.0
.get("hmac-secret")
.map(read_bool)
.map(|b| extract_bool(b.clone()))
.unwrap_or(Ok(false))
}
pub fn get_assertion_hmac_secret(
&self,
mut self,
) -> Option<Result<GetAssertionHmacSecretInput, Ctap2StatusCode>> {
self.0
.get("hmac-secret")
.remove("hmac-secret")
.map(GetAssertionHmacSecretInput::try_from)
}
pub fn make_credential_cred_protect_policy(
&self,
mut self,
) -> Option<Result<CredentialProtectionPolicy, Ctap2StatusCode>> {
self.0
.get("credProtect")
.remove("credProtect")
.map(CredentialProtectionPolicy::try_from)
}
}
@@ -309,14 +309,14 @@ pub struct GetAssertionHmacSecretInput {
pub salt_auth: Vec<u8>,
}
impl TryFrom<&cbor::Value> for GetAssertionHmacSecretInput {
impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let input_map = read_map(cbor_value)?;
let cose_key = read_map(ok_or_missing(input_map.get(&cbor_unsigned!(1)))?)?;
let salt_enc = read_byte_string(ok_or_missing(input_map.get(&cbor_unsigned!(2)))?)?;
let salt_auth = read_byte_string(ok_or_missing(input_map.get(&cbor_unsigned!(3)))?)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut input_map = extract_map(cbor_value)?;
let cose_key = extract_map(ok_or_missing(input_map.remove(&cbor_unsigned!(1)))?)?;
let salt_enc = extract_byte_string(ok_or_missing(input_map.remove(&cbor_unsigned!(2)))?)?;
let salt_auth = extract_byte_string(ok_or_missing(input_map.remove(&cbor_unsigned!(3)))?)?;
Ok(Self {
key_agreement: CoseKey(cose_key.clone()),
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;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
Ok(GetAssertionHmacSecretOutput(read_byte_string(cbor_value)?))
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
Ok(GetAssertionHmacSecretOutput(extract_byte_string(
cbor_value,
)?))
}
}
@@ -349,22 +351,22 @@ pub struct MakeCredentialOptions {
pub uv: bool,
}
impl TryFrom<&cbor::Value> for MakeCredentialOptions {
impl TryFrom<cbor::Value> for MakeCredentialOptions {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let options_map = read_map(cbor_value)?;
let rk = match options_map.get(&cbor_text!("rk")) {
Some(options_entry) => read_bool(options_entry)?,
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut options_map = extract_map(cbor_value)?;
let rk = match options_map.remove(&cbor_text!("rk")) {
Some(options_entry) => extract_bool(options_entry)?,
None => false,
};
if let Some(options_entry) = options_map.get(&cbor_text!("up")) {
if !read_bool(options_entry)? {
if let Some(options_entry) = options_map.remove(&cbor_text!("up")) {
if !extract_bool(options_entry)? {
return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION);
}
}
let uv = match options_map.get(&cbor_text!("uv")) {
Some(options_entry) => read_bool(options_entry)?,
let uv = match options_map.remove(&cbor_text!("uv")) {
Some(options_entry) => extract_bool(options_entry)?,
None => false,
};
Ok(Self { rk, uv })
@@ -377,22 +379,22 @@ pub struct GetAssertionOptions {
pub uv: bool,
}
impl TryFrom<&cbor::Value> for GetAssertionOptions {
impl TryFrom<cbor::Value> for GetAssertionOptions {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let options_map = read_map(cbor_value)?;
if let Some(options_entry) = options_map.get(&cbor_text!("rk")) {
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let mut options_map = extract_map(cbor_value)?;
if let Some(options_entry) = options_map.remove(&cbor_text!("rk")) {
// This is only for returning the correct status code.
read_bool(options_entry)?;
extract_bool(options_entry)?;
return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_OPTION);
}
let up = match options_map.get(&cbor_text!("up")) {
Some(options_entry) => read_bool(options_entry)?,
let up = match options_map.remove(&cbor_text!("up")) {
Some(options_entry) => extract_bool(options_entry)?,
None => true,
};
let uv = match options_map.get(&cbor_text!("uv")) {
Some(options_entry) => read_bool(options_entry)?,
let uv = match options_map.remove(&cbor_text!("uv")) {
Some(options_entry) => extract_bool(options_entry)?,
None => false,
};
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;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
match read_integer(cbor_value)? {
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
match extract_integer(cbor_value)? {
ecdsa::PubKey::ES256_ALGORITHM => Ok(SignatureAlgorithm::ES256),
_ => 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
//
// 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;
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 {
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 {
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 {
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 {
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 {
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;
fn try_from(cbor_value: &cbor::Value) -> Result<Self, Ctap2StatusCode> {
let subcommand_int = read_unsigned(cbor_value)?;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
let subcommand_int = extract_unsigned(cbor_value)?;
match subcommand_int {
0x01 => Ok(ClientPinSubCommand::GetPinRetries),
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 {
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),
}
}
pub(super) fn read_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> {
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 {
@@ -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> {
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> {
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),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
pub(super) fn read_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> {
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),
_ => 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 {
cbor::Value::Array(array) => Ok(array),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
}
}
pub(super) fn read_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(
pub(super) fn extract_map(
cbor_value: cbor::Value,
) -> Result<BTreeMap<cbor::KeyType, cbor::Value>, Ctap2StatusCode> {
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 {
cbor::Value::Simple(cbor::SimpleValue::FalseValue) => Ok(false),
cbor::Value::Simple(cbor::SimpleValue::TrueValue) => Ok(true),
@@ -827,192 +778,192 @@ mod test {
use crypto::rng256::{Rng256, ThreadRng256};
#[test]
fn test_read_unsigned() {
assert_eq!(read_unsigned(&cbor_int!(123)), Ok(123));
fn test_extract_unsigned() {
assert_eq!(extract_unsigned(cbor_int!(123)), Ok(123));
assert_eq!(
read_unsigned(&cbor_bool!(true)),
extract_unsigned(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_text!("foo")),
extract_unsigned(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_bytes_lit!(b"bar")),
extract_unsigned(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_array![]),
extract_unsigned(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_map! {}),
extract_unsigned(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_unsigned_limits() {
fn test_extract_unsigned_limits() {
assert_eq!(
read_unsigned(&cbor_unsigned!(std::u64::MAX)),
extract_unsigned(cbor_unsigned!(std::u64::MAX)),
Ok(std::u64::MAX)
);
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)
);
assert_eq!(
read_unsigned(&cbor_int!(std::i64::MAX)),
extract_unsigned(cbor_int!(std::i64::MAX)),
Ok(std::i64::MAX as u64)
);
assert_eq!(read_unsigned(&cbor_int!(123)), Ok(123));
assert_eq!(read_unsigned(&cbor_int!(1)), Ok(1));
assert_eq!(read_unsigned(&cbor_int!(0)), Ok(0));
assert_eq!(extract_unsigned(cbor_int!(123)), Ok(123));
assert_eq!(extract_unsigned(cbor_int!(1)), Ok(1));
assert_eq!(extract_unsigned(cbor_int!(0)), Ok(0));
assert_eq!(
read_unsigned(&cbor_int!(-1)),
extract_unsigned(cbor_int!(-1)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_int!(-123)),
extract_unsigned(cbor_int!(-123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_unsigned(&cbor_int!(std::i64::MIN)),
extract_unsigned(cbor_int!(std::i64::MIN)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_integer() {
assert_eq!(read_integer(&cbor_int!(123)), Ok(123));
assert_eq!(read_integer(&cbor_int!(-123)), Ok(-123));
fn test_extract_integer() {
assert_eq!(extract_integer(cbor_int!(123)), Ok(123));
assert_eq!(extract_integer(cbor_int!(-123)), Ok(-123));
assert_eq!(
read_integer(&cbor_bool!(true)),
extract_integer(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_integer(&cbor_text!("foo")),
extract_integer(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_integer(&cbor_bytes_lit!(b"bar")),
extract_integer(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_integer(&cbor_array![]),
extract_integer(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_integer(&cbor_map! {}),
extract_integer(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_integer_limits() {
fn test_extract_integer_limits() {
assert_eq!(
read_integer(&cbor_unsigned!(std::u64::MAX)),
extract_integer(cbor_unsigned!(std::u64::MAX)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
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)
);
assert_eq!(read_integer(&cbor_int!(std::i64::MAX)), Ok(std::i64::MAX));
assert_eq!(read_integer(&cbor_int!(123)), Ok(123));
assert_eq!(read_integer(&cbor_int!(1)), Ok(1));
assert_eq!(read_integer(&cbor_int!(0)), Ok(0));
assert_eq!(read_integer(&cbor_int!(-1)), Ok(-1));
assert_eq!(read_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::MAX)), Ok(std::i64::MAX));
assert_eq!(extract_integer(cbor_int!(123)), Ok(123));
assert_eq!(extract_integer(cbor_int!(1)), Ok(1));
assert_eq!(extract_integer(cbor_int!(0)), Ok(0));
assert_eq!(extract_integer(cbor_int!(-1)), Ok(-1));
assert_eq!(extract_integer(cbor_int!(-123)), Ok(-123));
assert_eq!(extract_integer(cbor_int!(std::i64::MIN)), Ok(std::i64::MIN));
}
#[test]
fn test_read_byte_string() {
fn test_extract_byte_string() {
assert_eq!(
read_byte_string(&cbor_int!(123)),
extract_byte_string(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_byte_string(&cbor_bool!(true)),
extract_byte_string(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_byte_string(&cbor_text!("foo")),
extract_byte_string(cbor_text!("foo")),
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!(
read_byte_string(&cbor_bytes_lit!(b"bar")),
extract_byte_string(cbor_bytes_lit!(b"bar")),
Ok(b"bar".to_vec())
);
assert_eq!(
read_byte_string(&cbor_array![]),
extract_byte_string(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_byte_string(&cbor_map! {}),
extract_byte_string(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_text_string() {
fn test_extract_text_string() {
assert_eq!(
read_text_string(&cbor_int!(123)),
extract_text_string(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_text_string(&cbor_bool!(true)),
extract_text_string(cbor_bool!(true)),
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!(
read_text_string(&cbor_text!("foo")),
extract_text_string(cbor_text!("foo")),
Ok(String::from("foo"))
);
assert_eq!(
read_text_string(&cbor_bytes_lit!(b"bar")),
extract_text_string(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_text_string(&cbor_array![]),
extract_text_string(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_text_string(&cbor_map! {}),
extract_text_string(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_array() {
fn test_extract_array() {
assert_eq!(
read_array(&cbor_int!(123)),
extract_array(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_array(&cbor_bool!(true)),
extract_array(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_array(&cbor_text!("foo")),
extract_array(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_array(&cbor_bytes_lit!(b"bar")),
extract_array(cbor_bytes_lit!(b"bar")),
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!(
read_array(&cbor_array![
extract_array(cbor_array![
123,
cbor_null!(),
"foo",
cbor_array![],
cbor_map! {},
]),
Ok(&vec![
Ok(vec![
cbor_int!(123),
cbor_null!(),
cbor_text!("foo"),
@@ -1021,41 +972,41 @@ mod test {
])
);
assert_eq!(
read_array(&cbor_map! {}),
extract_array(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
#[test]
fn test_read_map() {
fn test_extract_map() {
assert_eq!(
read_map(&cbor_int!(123)),
extract_map(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_map(&cbor_bool!(true)),
extract_map(cbor_bool!(true)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_map(&cbor_text!("foo")),
extract_map(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_map(&cbor_bytes_lit!(b"bar")),
extract_map(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_map(&cbor_array![]),
extract_map(cbor_array![]),
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!(
read_map(&cbor_map! {
extract_map(cbor_map! {
1 => cbor_false!(),
"foo" => b"bar",
b"bin" => -42,
}),
Ok(&[
Ok([
(cbor_unsigned!(1), cbor_false!()),
(cbor_text!("foo"), cbor_bytes_lit!(b"bar")),
(cbor_bytes_lit!(b"bin"), cbor_int!(-42)),
@@ -1067,27 +1018,27 @@ mod test {
}
#[test]
fn test_read_bool() {
fn test_extract_bool() {
assert_eq!(
read_bool(&cbor_int!(123)),
extract_bool(cbor_int!(123)),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(read_bool(&cbor_bool!(true)), Ok(true));
assert_eq!(read_bool(&cbor_bool!(false)), Ok(false));
assert_eq!(extract_bool(cbor_bool!(true)), Ok(true));
assert_eq!(extract_bool(cbor_bool!(false)), Ok(false));
assert_eq!(
read_bool(&cbor_text!("foo")),
extract_bool(cbor_text!("foo")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_bool(&cbor_bytes_lit!(b"bar")),
extract_bool(cbor_bytes_lit!(b"bar")),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_bool(&cbor_array![]),
extract_bool(cbor_array![]),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
assert_eq!(
read_bool(&cbor_map! {}),
extract_bool(cbor_map! {}),
Err(CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
);
}
@@ -1099,7 +1050,7 @@ mod test {
"name" => "Example",
"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 {
rp_id: "example.com".to_string(),
rp_name: Some("Example".to_string()),
@@ -1116,7 +1067,7 @@ mod test {
"displayName" => "bar",
"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 {
user_id: vec![0x1D, 0x1D, 0x1D, 0x1D],
user_name: Some("foo".to_string()),
@@ -1130,30 +1081,30 @@ mod test {
#[test]
fn test_from_into_public_key_credential_type() {
let cbor_credential_type = cbor_text!("public-key");
let credential_type = PublicKeyCredentialType::try_from(&cbor_credential_type);
let cbor_credential_type: cbor::Value = cbor_text!("public-key");
let credential_type = PublicKeyCredentialType::try_from(cbor_credential_type.clone());
let expected_credential_type = PublicKeyCredentialType::PublicKey;
assert_eq!(credential_type, Ok(expected_credential_type));
let created_cbor: cbor::Value = credential_type.unwrap().into();
assert_eq!(created_cbor, cbor_credential_type);
let cbor_unknown_type = cbor_text!("unknown-type");
let unknown_type = PublicKeyCredentialType::try_from(&cbor_unknown_type);
let cbor_unknown_type: cbor::Value = cbor_text!("unknown-type");
let unknown_type = PublicKeyCredentialType::try_from(cbor_unknown_type);
let expected_unknown_type = PublicKeyCredentialType::Unknown;
assert_eq!(unknown_type, Ok(expected_unknown_type));
}
#[test]
fn test_from_into_signature_algorithm() {
let cbor_signature_algorithm = cbor_int!(ecdsa::PubKey::ES256_ALGORITHM);
let signature_algorithm = SignatureAlgorithm::try_from(&cbor_signature_algorithm);
let cbor_signature_algorithm: cbor::Value = cbor_int!(ecdsa::PubKey::ES256_ALGORITHM);
let signature_algorithm = SignatureAlgorithm::try_from(cbor_signature_algorithm.clone());
let expected_signature_algorithm = SignatureAlgorithm::ES256;
assert_eq!(signature_algorithm, Ok(expected_signature_algorithm));
let created_cbor = cbor::Value::from(signature_algorithm.unwrap());
assert_eq!(created_cbor, cbor_signature_algorithm);
let cbor_unknown_algorithm = cbor_int!(-1);
let unknown_algorithm = SignatureAlgorithm::try_from(&cbor_unknown_algorithm);
let cbor_unknown_algorithm: cbor::Value = cbor_int!(-1);
let unknown_algorithm = SignatureAlgorithm::try_from(cbor_unknown_algorithm);
let expected_unknown_algorithm = SignatureAlgorithm::Unknown;
assert_eq!(unknown_algorithm, Ok(expected_unknown_algorithm));
}
@@ -1177,23 +1128,23 @@ mod test {
#[test]
fn test_from_into_cred_protection_policy() {
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;
assert_eq!(policy, Ok(expected_policy));
let created_cbor = cbor::Value::from(policy.unwrap());
assert_eq!(created_cbor, cbor_policy);
let cbor_policy_error = cbor_int!(-1);
let policy_error = CredentialProtectionPolicy::try_from(&cbor_policy_error);
let cbor_policy_error: cbor::Value = cbor_int!(-1);
let policy_error = CredentialProtectionPolicy::try_from(cbor_policy_error);
let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
assert_eq!(policy_error, expected_error);
}
#[test]
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 =
AuthenticatorTransport::try_from(&cbor_authenticator_transport);
AuthenticatorTransport::try_from(cbor_authenticator_transport.clone());
let expected_authenticator_transport = AuthenticatorTransport::Usb;
assert_eq!(
authenticator_transport,
@@ -1210,7 +1161,7 @@ mod test {
"alg" => ecdsa::PubKey::ES256_ALGORITHM,
};
let credential_parameter =
PublicKeyCredentialParameter::try_from(&cbor_credential_parameter);
PublicKeyCredentialParameter::try_from(cbor_credential_parameter.clone());
let expected_credential_parameter = PublicKeyCredentialParameter {
cred_type: PublicKeyCredentialType::PublicKey,
alg: SignatureAlgorithm::ES256,
@@ -1228,7 +1179,7 @@ mod test {
"transports" => cbor_array!["usb"],
};
let credential_descriptor =
PublicKeyCredentialDescriptor::try_from(&cbor_credential_descriptor);
PublicKeyCredentialDescriptor::try_from(cbor_credential_descriptor.clone());
let expected_credential_descriptor = PublicKeyCredentialDescriptor {
key_type: PublicKeyCredentialType::PublicKey,
key_id: vec![0x2D, 0x2D, 0x2D, 0x2D],
@@ -1244,7 +1195,7 @@ mod test {
let cbor_extensions = cbor_map! {
"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());
expected_extensions
.0
@@ -1256,8 +1207,8 @@ mod test {
#[test]
fn test_from_into_get_assertion_hmac_secret_output() {
let cbor_output = cbor_bytes![vec![0xC0; 32]];
let output = GetAssertionHmacSecretOutput::try_from(&cbor_output);
let cbor_output: cbor::Value = cbor_bytes![vec![0xC0; 32]];
let output = GetAssertionHmacSecretOutput::try_from(cbor_output.clone());
let expected_output = GetAssertionHmacSecretOutput(vec![0xC0; 32]);
assert_eq!(output, Ok(expected_output));
let created_cbor: cbor::Value = output.unwrap().into();
@@ -1269,13 +1220,13 @@ mod test {
let cbor_extensions = cbor_map! {
"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());
let cbor_extensions = cbor_map! {
"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());
let mut rng = ThreadRng256 {};
@@ -1289,7 +1240,7 @@ mod test {
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 expected_input = GetAssertionHmacSecretInput {
key_agreement: cose_key,
@@ -1304,7 +1255,7 @@ mod test {
let cbor_extensions = cbor_map! {
"credProtect" => CredentialProtectionPolicy::UserVerificationRequired,
};
let extensions = Extensions::try_from(&cbor_extensions).unwrap();
let extensions = Extensions::try_from(cbor_extensions).unwrap();
assert_eq!(
extensions.make_credential_cred_protect_policy(),
Some(Ok(CredentialProtectionPolicy::UserVerificationRequired))
@@ -1317,7 +1268,7 @@ mod test {
"rk" => true,
"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 {
rk: true,
uv: false,
@@ -1331,7 +1282,7 @@ mod test {
"up" => true,
"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 {
up: true,
uv: false,
@@ -1370,8 +1321,8 @@ mod test {
#[test]
fn test_from_into_client_pin_sub_command() {
let cbor_sub_command = cbor_int!(0x01);
let sub_command = ClientPinSubCommand::try_from(&cbor_sub_command);
let cbor_sub_command: cbor::Value = cbor_int!(0x01);
let sub_command = ClientPinSubCommand::try_from(cbor_sub_command.clone());
let expected_sub_command = ClientPinSubCommand::GetPinRetries;
assert_eq!(sub_command, Ok(expected_sub_command));
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 has_hmac_secret = extensions.has_make_credential_hmac_secret()?;
let mut cred_protect = extensions
.make_credential_cred_protect_policy()
.transpose()?;
@@ -444,7 +445,7 @@ where
{
cred_protect = DEFAULT_CRED_PROTECT;
}
(extensions.has_make_credential_hmac_secret()?, cred_protect)
(has_hmac_secret, cred_protect)
} else {
(false, None)
};