Skip to content

Commit 1adde22

Browse files
authored
Upgrade commands (#381)
* upgrade commands * precise metadata length * const METADATA_LEN for test
1 parent 31df2ca commit 1adde22

4 files changed

Lines changed: 525 additions & 36 deletions

File tree

src/ctap/command.rs

Lines changed: 131 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ use super::customization::{MAX_CREDENTIAL_COUNT_IN_LIST, MAX_LARGE_BLOB_ARRAY_SI
1717
use super::data_formats::{
1818
extract_array, extract_bool, extract_byte_string, extract_map, extract_text_string,
1919
extract_unsigned, ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams,
20-
CoseKey, CredentialManagementSubCommand, CredentialManagementSubCommandParameters,
21-
GetAssertionExtensions, GetAssertionOptions, MakeCredentialExtensions, MakeCredentialOptions,
22-
PinUvAuthProtocol, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
23-
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, SetMinPinLengthParams,
20+
CoseKey, CoseSignature, CredentialManagementSubCommand,
21+
CredentialManagementSubCommandParameters, GetAssertionExtensions, GetAssertionOptions,
22+
MakeCredentialExtensions, MakeCredentialOptions, PinUvAuthProtocol,
23+
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialRpEntity,
24+
PublicKeyCredentialUserEntity, SetMinPinLengthParams,
2425
};
2526
use super::key_material;
2627
use super::status_code::Ctap2StatusCode;
@@ -49,6 +50,8 @@ pub enum Command {
4950
AuthenticatorConfig(AuthenticatorConfigParameters),
5051
// Vendor specific commands
5152
AuthenticatorVendorConfigure(AuthenticatorVendorConfigureParameters),
53+
AuthenticatorVendorUpgrade(AuthenticatorVendorUpgradeParameters),
54+
AuthenticatorVendorUpgradeInfo,
5255
}
5356

5457
impl Command {
@@ -66,6 +69,8 @@ impl Command {
6669
const AUTHENTICATOR_CONFIG: u8 = 0x0D;
6770
const _AUTHENTICATOR_VENDOR_FIRST: u8 = 0x40;
6871
const AUTHENTICATOR_VENDOR_CONFIGURE: u8 = 0x40;
72+
const AUTHENTICATOR_VENDOR_UPGRADE: u8 = 0x41;
73+
const AUTHENTICATOR_VENDOR_UPGRADE_INFO: u8 = 0x42;
6974
const _AUTHENTICATOR_VENDOR_LAST: u8 = 0xBF;
7075

7176
pub fn deserialize(bytes: &[u8]) -> Result<Command, Ctap2StatusCode> {
@@ -134,6 +139,16 @@ impl Command {
134139
AuthenticatorVendorConfigureParameters::try_from(decoded_cbor)?,
135140
))
136141
}
142+
Command::AUTHENTICATOR_VENDOR_UPGRADE => {
143+
let decoded_cbor = cbor_read(&bytes[1..])?;
144+
Ok(Command::AuthenticatorVendorUpgrade(
145+
AuthenticatorVendorUpgradeParameters::try_from(decoded_cbor)?,
146+
))
147+
}
148+
Command::AUTHENTICATOR_VENDOR_UPGRADE_INFO => {
149+
// Parameters are ignored.
150+
Ok(Command::AuthenticatorVendorUpgradeInfo)
151+
}
137152
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND),
138153
}
139154
}
@@ -573,11 +588,47 @@ impl TryFrom<cbor::Value> for AuthenticatorVendorConfigureParameters {
573588
}
574589
}
575590

591+
#[derive(Debug, PartialEq)]
592+
pub struct AuthenticatorVendorUpgradeParameters {
593+
pub address: Option<usize>,
594+
pub data: Vec<u8>,
595+
pub hash: Vec<u8>,
596+
pub signature: Option<CoseSignature>,
597+
}
598+
599+
impl TryFrom<cbor::Value> for AuthenticatorVendorUpgradeParameters {
600+
type Error = Ctap2StatusCode;
601+
602+
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
603+
destructure_cbor_map! {
604+
let {
605+
0x01 => address,
606+
0x02 => data,
607+
0x03 => hash,
608+
0x04 => signature,
609+
} = extract_map(cbor_value)?;
610+
}
611+
let address = address
612+
.map(extract_unsigned)
613+
.transpose()?
614+
.map(|u| u as usize);
615+
let data = extract_byte_string(ok_or_missing(data)?)?;
616+
let hash = extract_byte_string(ok_or_missing(hash)?)?;
617+
let signature = signature.map(CoseSignature::try_from).transpose()?;
618+
Ok(AuthenticatorVendorUpgradeParameters {
619+
address,
620+
data,
621+
hash,
622+
signature,
623+
})
624+
}
625+
}
626+
576627
#[cfg(test)]
577628
mod test {
578629
use super::super::data_formats::{
579630
AuthenticatorTransport, PublicKeyCredentialRpEntity, PublicKeyCredentialType,
580-
PublicKeyCredentialUserEntity,
631+
PublicKeyCredentialUserEntity, SignatureAlgorithm,
581632
};
582633
use super::super::ES256_CRED_PARAM;
583634
use super::*;
@@ -997,7 +1048,7 @@ mod test {
9971048
0x02 => cbor_map! {
9981049
0x01 => dummy_cert,
9991050
0x02 => dummy_pkey
1000-
}
1051+
},
10011052
};
10021053
assert_eq!(
10031054
AuthenticatorVendorConfigureParameters::try_from(cbor_value),
@@ -1006,8 +1057,81 @@ mod test {
10061057
attestation_material: Some(AuthenticatorAttestationMaterial {
10071058
certificate: dummy_cert.to_vec(),
10081059
private_key: dummy_pkey
1009-
})
1060+
}),
10101061
})
10111062
);
10121063
}
1064+
1065+
#[test]
1066+
fn test_vendor_upgrade() {
1067+
// Incomplete command
1068+
let cbor_bytes = vec![Command::AUTHENTICATOR_VENDOR_UPGRADE];
1069+
let command = Command::deserialize(&cbor_bytes);
1070+
assert_eq!(command, Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR));
1071+
1072+
// Missing data
1073+
let cbor_value = cbor_map! {
1074+
0x01 => 0x1000,
1075+
0x03 => [0x44; 32],
1076+
};
1077+
assert_eq!(
1078+
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
1079+
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
1080+
);
1081+
1082+
// Missing hash
1083+
let cbor_value = cbor_map! {
1084+
0x01 => 0x1000,
1085+
0x02 => [0xFF; 0x100],
1086+
};
1087+
assert_eq!(
1088+
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
1089+
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
1090+
);
1091+
1092+
// Valid without address
1093+
let cbor_value = cbor_map! {
1094+
0x02 => [0xFF; 0x100],
1095+
0x03 => [0x44; 32],
1096+
0x04 => cbor_map! {
1097+
"alg" => -7,
1098+
"signature" => [0x55; 64],
1099+
},
1100+
};
1101+
assert_eq!(
1102+
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
1103+
Ok(AuthenticatorVendorUpgradeParameters {
1104+
address: None,
1105+
data: vec![0xFF; 0x100],
1106+
hash: vec![0x44; 32],
1107+
signature: Some(CoseSignature {
1108+
algorithm: SignatureAlgorithm::ES256,
1109+
bytes: [0x55; 64],
1110+
}),
1111+
})
1112+
);
1113+
1114+
// Valid without signature
1115+
let cbor_value = cbor_map! {
1116+
0x01 => 0x1000,
1117+
0x02 => [0xFF; 0x100],
1118+
0x03 => [0x44; 32],
1119+
};
1120+
assert_eq!(
1121+
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
1122+
Ok(AuthenticatorVendorUpgradeParameters {
1123+
address: Some(0x1000),
1124+
data: vec![0xFF; 0x100],
1125+
hash: vec![0x44; 32],
1126+
signature: None,
1127+
})
1128+
);
1129+
}
1130+
1131+
#[test]
1132+
fn test_deserialize_vendor_upgrade_info() {
1133+
let cbor_bytes = [Command::AUTHENTICATOR_VENDOR_UPGRADE_INFO];
1134+
let command = Command::deserialize(&cbor_bytes);
1135+
assert_eq!(command, Ok(Command::AuthenticatorVendorUpgradeInfo));
1136+
}
10131137
}

src/ctap/key_material.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
1616
pub const AAGUID_LENGTH: usize = 16;
17-
pub const _UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;
17+
pub const UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;
1818

1919
pub const AAGUID: &[u8; AAGUID_LENGTH] =
2020
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
21-
pub const _UPGRADE_PUBLIC_KEY: &[u8; _UPGRADE_PUBLIC_KEY_LENGTH] =
21+
pub const UPGRADE_PUBLIC_KEY: &[u8; UPGRADE_PUBLIC_KEY_LENGTH] =
2222
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey_cbor.bin"));

0 commit comments

Comments
 (0)