Actually use ECDSA seed mechanism
This commit is contained in:
@@ -64,6 +64,7 @@ fn enumerate_rps_response(
|
|||||||
|
|
||||||
/// Generates the response for subcommands enumerating credentials.
|
/// Generates the response for subcommands enumerating credentials.
|
||||||
fn enumerate_credentials_response(
|
fn enumerate_credentials_response(
|
||||||
|
env: &mut impl Env,
|
||||||
credential: PublicKeyCredentialSource,
|
credential: PublicKeyCredentialSource,
|
||||||
total_credentials: Option<u64>,
|
total_credentials: Option<u64>,
|
||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
@@ -92,7 +93,9 @@ fn enumerate_credentials_response(
|
|||||||
key_id: credential_id,
|
key_id: credential_id,
|
||||||
transports: None, // You can set USB as a hint here.
|
transports: None, // You can set USB as a hint here.
|
||||||
};
|
};
|
||||||
let public_key = private_key.get_pub_key();
|
let public_key = private_key
|
||||||
|
.get_pub_key(env)
|
||||||
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
|
||||||
Ok(AuthenticatorCredentialManagementResponse {
|
Ok(AuthenticatorCredentialManagementResponse {
|
||||||
user: Some(user),
|
user: Some(user),
|
||||||
credential_id: Some(credential_id),
|
credential_id: Some(credential_id),
|
||||||
@@ -207,7 +210,7 @@ fn process_enumerate_credentials_begin(
|
|||||||
channel,
|
channel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
enumerate_credentials_response(credential, Some(total_credentials as u64))
|
enumerate_credentials_response(env, credential, Some(total_credentials as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
|
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
|
||||||
@@ -217,7 +220,7 @@ fn process_enumerate_credentials_get_next_credential(
|
|||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
let credential_key = stateful_command_permission.next_enumerate_credential()?;
|
let credential_key = stateful_command_permission.next_enumerate_credential()?;
|
||||||
let credential = storage::get_credential(env, credential_key)?;
|
let credential = storage::get_credential(env, credential_key)?;
|
||||||
enumerate_credentials_response(credential, None)
|
enumerate_credentials_response(env, credential, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes the subcommand deleteCredential for CredentialManagement.
|
/// Processes the subcommand deleteCredential for CredentialManagement.
|
||||||
@@ -369,12 +372,12 @@ mod test {
|
|||||||
|
|
||||||
const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);
|
const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);
|
||||||
|
|
||||||
fn create_credential_source(rng: &mut impl Rng256) -> PublicKeyCredentialSource {
|
fn create_credential_source(env: &mut TestEnv) -> PublicKeyCredentialSource {
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(rng);
|
let private_key = PrivateKey::new_ecdsa(env);
|
||||||
PublicKeyCredentialSource {
|
PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: rng.gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x01],
|
user_handle: vec![0x01],
|
||||||
user_display_name: Some("display_name".to_string()),
|
user_display_name: Some("display_name".to_string()),
|
||||||
@@ -393,7 +396,7 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
|
||||||
let credential_source = create_credential_source(env.rng());
|
let credential_source = create_credential_source(&mut env);
|
||||||
|
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
ctap_state.client_pin = client_pin;
|
ctap_state.client_pin = client_pin;
|
||||||
@@ -475,8 +478,8 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let credential_source1 = create_credential_source(env.rng());
|
let credential_source1 = create_credential_source(&mut env);
|
||||||
let mut credential_source2 = create_credential_source(env.rng());
|
let mut credential_source2 = create_credential_source(&mut env);
|
||||||
credential_source2.rp_id = "another.example.com".to_string();
|
credential_source2.rp_id = "another.example.com".to_string();
|
||||||
|
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
@@ -569,7 +572,7 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let credential_source = create_credential_source(env.rng());
|
let credential_source = create_credential_source(&mut env);
|
||||||
|
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
ctap_state.client_pin = client_pin;
|
ctap_state.client_pin = client_pin;
|
||||||
@@ -650,8 +653,8 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let credential_source1 = create_credential_source(env.rng());
|
let credential_source1 = create_credential_source(&mut env);
|
||||||
let mut credential_source2 = create_credential_source(env.rng());
|
let mut credential_source2 = create_credential_source(&mut env);
|
||||||
credential_source2.user_handle = vec![0x02];
|
credential_source2.user_handle = vec![0x02];
|
||||||
credential_source2.user_name = Some("user2".to_string());
|
credential_source2.user_name = Some("user2".to_string());
|
||||||
credential_source2.user_display_name = Some("User Two".to_string());
|
credential_source2.user_display_name = Some("User Two".to_string());
|
||||||
@@ -752,7 +755,7 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut credential_source = create_credential_source(env.rng());
|
let mut credential_source = create_credential_source(&mut env);
|
||||||
credential_source.credential_id = vec![0x1D; 32];
|
credential_source.credential_id = vec![0x1D; 32];
|
||||||
|
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
@@ -822,7 +825,7 @@ mod test {
|
|||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut credential_source = create_credential_source(env.rng());
|
let mut credential_source = create_credential_source(&mut env);
|
||||||
credential_source.credential_id = vec![0x1D; 32];
|
credential_source.credential_id = vec![0x1D; 32];
|
||||||
|
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|||||||
@@ -101,7 +101,9 @@ pub fn aes256_cbc_decrypt(
|
|||||||
// We shouldn't compare private keys in prod without constant-time operations.
|
// We shouldn't compare private keys in prod without constant-time operations.
|
||||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub enum PrivateKey {
|
pub enum PrivateKey {
|
||||||
Ecdsa(ecdsa::SecKey),
|
// We store the seed instead of the key since we can't get the seed back from the key. We could
|
||||||
|
// store both if we believe deriving the key is done more than once and costly.
|
||||||
|
Ecdsa([u8; 32]),
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
Ed25519(ed25519_compact::SecretKey),
|
Ed25519(ed25519_compact::SecretKey),
|
||||||
}
|
}
|
||||||
@@ -112,18 +114,25 @@ impl PrivateKey {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the algorithm is [`SignatureAlgorithm::Unknown`].
|
/// Panics if the algorithm is [`SignatureAlgorithm::Unknown`].
|
||||||
pub fn new(rng: &mut impl Rng256, alg: SignatureAlgorithm) -> Self {
|
pub fn new(env: &mut impl Env, alg: SignatureAlgorithm) -> Self {
|
||||||
match alg {
|
match alg {
|
||||||
SignatureAlgorithm::ES256 => PrivateKey::Ecdsa(crypto::ecdsa::SecKey::gensk(rng)),
|
SignatureAlgorithm::ES256 => {
|
||||||
|
PrivateKey::Ecdsa(env.key_store().generate_ecdsa_seed().unwrap())
|
||||||
|
}
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
SignatureAlgorithm::EDDSA => {
|
SignatureAlgorithm::EDDSA => {
|
||||||
let bytes = rng.gen_uniform_u8x32();
|
let bytes = env.rng().gen_uniform_u8x32();
|
||||||
Self::new_ed25519_from_bytes(&bytes).unwrap()
|
Self::new_ed25519_from_bytes(&bytes).unwrap()
|
||||||
}
|
}
|
||||||
SignatureAlgorithm::Unknown => unreachable!(),
|
SignatureAlgorithm::Unknown => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new ecdsa private key.
|
||||||
|
pub fn new_ecdsa(env: &mut impl Env) -> PrivateKey {
|
||||||
|
Self::new(env, SignatureAlgorithm::ES256)
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper function that creates a private key of type ECDSA.
|
/// Helper function that creates a private key of type ECDSA.
|
||||||
///
|
///
|
||||||
/// This function is public for legacy credential source parsing only.
|
/// This function is public for legacy credential source parsing only.
|
||||||
@@ -131,7 +140,7 @@ impl PrivateKey {
|
|||||||
if bytes.len() != 32 {
|
if bytes.len() != 32 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
ecdsa::SecKey::from_bytes(array_ref!(bytes, 0, 32)).map(PrivateKey::from)
|
Some(PrivateKey::Ecdsa(*array_ref!(bytes, 0, 32)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
@@ -143,22 +152,33 @@ impl PrivateKey {
|
|||||||
Some(Self::Ed25519(ed25519_compact::KeyPair::from_seed(seed).sk))
|
Some(Self::Ed25519(ed25519_compact::KeyPair::from_seed(seed).sk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the corresponding public key.
|
/// Returns the ECDSA private key.
|
||||||
pub fn get_pub_key(&self) -> CoseKey {
|
pub fn ecdsa_key(&self, env: &mut impl Env) -> Option<ecdsa::SecKey> {
|
||||||
match self {
|
match self {
|
||||||
PrivateKey::Ecdsa(ecdsa_key) => CoseKey::from(ecdsa_key.genpk()),
|
PrivateKey::Ecdsa(seed) => ecdsa_key(env, seed),
|
||||||
#[cfg(feature = "ed25519")]
|
#[allow(unreachable_patterns)]
|
||||||
PrivateKey::Ed25519(ed25519_key) => CoseKey::from(ed25519_key.public_key()),
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the corresponding public key.
|
||||||
|
pub fn get_pub_key(&self, env: &mut impl Env) -> Option<CoseKey> {
|
||||||
|
Some(match self {
|
||||||
|
PrivateKey::Ecdsa(ecdsa_seed) => CoseKey::from(ecdsa_key(env, ecdsa_seed)?.genpk()),
|
||||||
|
#[cfg(feature = "ed25519")]
|
||||||
|
PrivateKey::Ed25519(ed25519_key) => CoseKey::from(ed25519_key.public_key()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the encoded signature for a given message.
|
/// Returns the encoded signature for a given message.
|
||||||
pub fn sign_and_encode(&self, message: &[u8]) -> Vec<u8> {
|
pub fn sign_and_encode(&self, env: &mut impl Env, message: &[u8]) -> Option<Vec<u8>> {
|
||||||
match self {
|
Some(match self {
|
||||||
PrivateKey::Ecdsa(ecdsa_key) => ecdsa_key.sign_rfc6979::<Sha256>(message).to_asn1_der(),
|
PrivateKey::Ecdsa(ecdsa_seed) => ecdsa_key(env, ecdsa_seed)?
|
||||||
|
.sign_rfc6979::<Sha256>(message)
|
||||||
|
.to_asn1_der(),
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
PrivateKey::Ed25519(ed25519_key) => ed25519_key.sign(message, None).to_vec(),
|
PrivateKey::Ed25519(ed25519_key) => ed25519_key.sign(message, None).to_vec(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The associated COSE signature algorithm identifier.
|
/// The associated COSE signature algorithm identifier.
|
||||||
@@ -173,17 +193,18 @@ impl PrivateKey {
|
|||||||
/// Writes the key bytes.
|
/// Writes the key bytes.
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
match self {
|
match self {
|
||||||
PrivateKey::Ecdsa(ecdsa_key) => {
|
PrivateKey::Ecdsa(ecdsa_seed) => ecdsa_seed.to_vec(),
|
||||||
let mut key_bytes = vec![0u8; 32];
|
|
||||||
ecdsa_key.to_bytes(array_mut_ref!(key_bytes, 0, 32));
|
|
||||||
key_bytes
|
|
||||||
}
|
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
PrivateKey::Ed25519(ed25519_key) => ed25519_key.seed().to_vec(),
|
PrivateKey::Ed25519(ed25519_key) => ed25519_key.seed().to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ecdsa_key(env: &mut impl Env, seed: &[u8; 32]) -> Option<ecdsa::SecKey> {
|
||||||
|
let ecdsa_bytes = env.key_store().derive_ecdsa(seed).ok()?;
|
||||||
|
ecdsa::SecKey::from_bytes(&ecdsa_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PrivateKey> for cbor::Value {
|
impl From<PrivateKey> for cbor::Value {
|
||||||
fn from(private_key: PrivateKey) -> Self {
|
fn from(private_key: PrivateKey) -> Self {
|
||||||
cbor_array![
|
cbor_array![
|
||||||
@@ -213,12 +234,6 @@ impl TryFrom<cbor::Value> for PrivateKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ecdsa::SecKey> for PrivateKey {
|
|
||||||
fn from(ecdsa_key: ecdsa::SecKey) -> Self {
|
|
||||||
PrivateKey::Ecdsa(ecdsa_key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encrypts the given private key and relying party ID hash into a credential ID.
|
/// Encrypts the given private key and relying party ID hash into a credential ID.
|
||||||
///
|
///
|
||||||
/// Other information, such as a user name, are not stored. Since encrypted credential IDs are
|
/// Other information, such as a user name, are not stored. Since encrypted credential IDs are
|
||||||
@@ -249,8 +264,8 @@ pub fn encrypt_key_handle(
|
|||||||
|
|
||||||
let mut plaintext = [0; 64];
|
let mut plaintext = [0; 64];
|
||||||
let version = match private_key {
|
let version = match private_key {
|
||||||
PrivateKey::Ecdsa(ecdsa_key) => {
|
PrivateKey::Ecdsa(ecdsa_seed) => {
|
||||||
ecdsa_key.to_bytes(array_mut_ref!(plaintext, 0, 32));
|
plaintext[..32].copy_from_slice(ecdsa_seed);
|
||||||
ECDSA_CREDENTIAL_ID_VERSION
|
ECDSA_CREDENTIAL_ID_VERSION
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
@@ -416,7 +431,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_new_ecdsa_from_bytes() {
|
fn test_new_ecdsa_from_bytes() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256);
|
let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
|
||||||
let key_bytes = private_key.to_bytes();
|
let key_bytes = private_key.to_bytes();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
PrivateKey::new_ecdsa_from_bytes(&key_bytes),
|
PrivateKey::new_ecdsa_from_bytes(&key_bytes),
|
||||||
@@ -456,25 +471,31 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_private_key_get_pub_key() {
|
fn test_private_key_get_pub_key() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
|
let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
|
||||||
let public_key = ecdsa_key.genpk();
|
let public_key = ecdsa_key.genpk();
|
||||||
let private_key = PrivateKey::from(ecdsa_key);
|
assert_eq!(
|
||||||
assert_eq!(private_key.get_pub_key(), CoseKey::from(public_key));
|
private_key.get_pub_key(&mut env),
|
||||||
|
Some(CoseKey::from(public_key))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_private_key_sign_and_encode() {
|
fn test_private_key_sign_and_encode() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let message = [0x5A; 32];
|
let message = [0x5A; 32];
|
||||||
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
|
let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
|
||||||
let signature = ecdsa_key.sign_rfc6979::<Sha256>(&message).to_asn1_der();
|
let signature = ecdsa_key.sign_rfc6979::<Sha256>(&message).to_asn1_der();
|
||||||
let private_key = PrivateKey::from(ecdsa_key);
|
assert_eq!(
|
||||||
assert_eq!(private_key.sign_and_encode(&message), signature);
|
private_key.sign_and_encode(&mut env, &message),
|
||||||
|
Some(signature)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_private_key_signature_algorithm(signature_algorithm: SignatureAlgorithm) {
|
fn test_private_key_signature_algorithm(signature_algorithm: SignatureAlgorithm) {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
|
let private_key = PrivateKey::new(&mut env, signature_algorithm);
|
||||||
assert_eq!(private_key.signature_algorithm(), signature_algorithm);
|
assert_eq!(private_key.signature_algorithm(), signature_algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,7 +512,7 @@ mod test {
|
|||||||
|
|
||||||
fn test_private_key_from_to_cbor(signature_algorithm: SignatureAlgorithm) {
|
fn test_private_key_from_to_cbor(signature_algorithm: SignatureAlgorithm) {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
|
let private_key = PrivateKey::new(&mut env, signature_algorithm);
|
||||||
let cbor = cbor::Value::from(private_key.clone());
|
let cbor = cbor::Value::from(private_key.clone());
|
||||||
assert_eq!(PrivateKey::try_from(cbor), Ok(private_key),);
|
assert_eq!(PrivateKey::try_from(cbor), Ok(private_key),);
|
||||||
}
|
}
|
||||||
@@ -546,7 +567,7 @@ mod test {
|
|||||||
|
|
||||||
fn test_encrypt_decrypt_credential(signature_algorithm: SignatureAlgorithm) {
|
fn test_encrypt_decrypt_credential(signature_algorithm: SignatureAlgorithm) {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
|
let private_key = PrivateKey::new(&mut env, signature_algorithm);
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
||||||
@@ -571,7 +592,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encrypt_decrypt_bad_version() {
|
fn test_encrypt_decrypt_bad_version() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256);
|
let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let mut encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
let mut encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
||||||
@@ -590,7 +611,7 @@ mod test {
|
|||||||
|
|
||||||
fn test_encrypt_decrypt_bad_hmac(signature_algorithm: SignatureAlgorithm) {
|
fn test_encrypt_decrypt_bad_hmac(signature_algorithm: SignatureAlgorithm) {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
|
let private_key = PrivateKey::new(&mut env, signature_algorithm);
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
||||||
@@ -617,7 +638,7 @@ mod test {
|
|||||||
|
|
||||||
fn test_decrypt_credential_missing_blocks(signature_algorithm: SignatureAlgorithm) {
|
fn test_decrypt_credential_missing_blocks(signature_algorithm: SignatureAlgorithm) {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), signature_algorithm);
|
let private_key = PrivateKey::new(&mut env, signature_algorithm);
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
||||||
@@ -661,8 +682,8 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encrypt_decrypt_credential_legacy() {
|
fn test_encrypt_decrypt_credential_legacy() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let ecdsa_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let private_key = PrivateKey::from(ecdsa_key.clone());
|
let ecdsa_key = private_key.ecdsa_key(&mut env).unwrap();
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let encrypted_id = legacy_encrypt_key_handle(&mut env, ecdsa_key, &rp_id_hash).unwrap();
|
let encrypted_id = legacy_encrypt_key_handle(&mut env, ecdsa_key, &rp_id_hash).unwrap();
|
||||||
@@ -676,7 +697,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encrypt_credential_size() {
|
fn test_encrypt_credential_size() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = PrivateKey::new(env.rng(), SignatureAlgorithm::ES256);
|
let private_key = PrivateKey::new(&mut env, SignatureAlgorithm::ES256);
|
||||||
|
|
||||||
let rp_id_hash = [0x55; 32];
|
let rp_id_hash = [0x55; 32];
|
||||||
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
let encrypted_id = encrypt_key_handle(&mut env, &private_key, &rp_id_hash).unwrap();
|
||||||
|
|||||||
@@ -245,9 +245,12 @@ impl Ctap1Command {
|
|||||||
challenge: [u8; 32],
|
challenge: [u8; 32],
|
||||||
application: [u8; 32],
|
application: [u8; 32],
|
||||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(env);
|
||||||
|
let sk = private_key
|
||||||
|
.ecdsa_key(env)
|
||||||
|
.ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
|
||||||
let pk = sk.genpk();
|
let pk = sk.genpk();
|
||||||
let key_handle = encrypt_key_handle(env, &PrivateKey::from(sk), &application)
|
let key_handle = encrypt_key_handle(env, &private_key, &application)
|
||||||
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
|
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
|
||||||
if key_handle.len() > 0xFF {
|
if key_handle.len() > 0xFF {
|
||||||
// This is just being defensive with unreachable code.
|
// This is just being defensive with unreachable code.
|
||||||
@@ -309,12 +312,10 @@ impl Ctap1Command {
|
|||||||
let credential_source = decrypt_credential_source(env, key_handle, &application)
|
let credential_source = decrypt_credential_source(env, key_handle, &application)
|
||||||
.map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
|
.map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
|
||||||
if let Some(credential_source) = credential_source {
|
if let Some(credential_source) = credential_source {
|
||||||
// CTAP1 only supports ECDSA, the default case applies if CTAP2 adds more algorithms.
|
let ecdsa_key = credential_source
|
||||||
#[allow(unreachable_patterns)]
|
.private_key
|
||||||
let ecdsa_key = match credential_source.private_key {
|
.ecdsa_key(env)
|
||||||
PrivateKey::Ecdsa(k) => k,
|
.ok_or(Ctap1StatusCode::SW_WRONG_DATA)?;
|
||||||
_ => return Err(Ctap1StatusCode::SW_WRONG_DATA),
|
|
||||||
};
|
|
||||||
if flags == Ctap1Flags::CheckOnly {
|
if flags == Ctap1Flags::CheckOnly {
|
||||||
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
|
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2215,11 +2215,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_credential_source_cbor_round_trip() {
|
fn test_credential_source_cbor_round_trip() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: "example.com".to_string(),
|
rp_id: "example.com".to_string(),
|
||||||
user_handle: b"foo".to_vec(),
|
user_handle: b"foo".to_vec(),
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2300,13 +2300,12 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_credential_source_cbor_read_legacy() {
|
fn test_credential_source_cbor_read_legacy() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let mut key_bytes = [0u8; 32];
|
let key_bytes = private_key.to_bytes();
|
||||||
private_key.to_bytes(&mut key_bytes);
|
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: "example.com".to_string(),
|
rp_id: "example.com".to_string(),
|
||||||
user_handle: b"foo".to_vec(),
|
user_handle: b"foo".to_vec(),
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2333,13 +2332,12 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_credential_source_cbor_legacy_error() {
|
fn test_credential_source_cbor_legacy_error() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let mut key_bytes = [0u8; 32];
|
let key_bytes = private_key.to_bytes();
|
||||||
private_key.to_bytes(&mut key_bytes);
|
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key.clone()),
|
private_key: private_key.clone(),
|
||||||
rp_id: "example.com".to_string(),
|
rp_id: "example.com".to_string(),
|
||||||
user_handle: b"foo".to_vec(),
|
user_handle: b"foo".to_vec(),
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2366,7 +2364,7 @@ mod test {
|
|||||||
PublicKeyCredentialSourceField::EcdsaPrivateKey => key_bytes,
|
PublicKeyCredentialSourceField::EcdsaPrivateKey => key_bytes,
|
||||||
PublicKeyCredentialSourceField::RpId => credential.rp_id,
|
PublicKeyCredentialSourceField::RpId => credential.rp_id,
|
||||||
PublicKeyCredentialSourceField::UserHandle => credential.user_handle,
|
PublicKeyCredentialSourceField::UserHandle => credential.user_handle,
|
||||||
PublicKeyCredentialSourceField::PrivateKey => PrivateKey::from(private_key),
|
PublicKeyCredentialSourceField::PrivateKey => private_key,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
PublicKeyCredentialSource::try_from(source_cbor),
|
PublicKeyCredentialSource::try_from(source_cbor),
|
||||||
|
|||||||
@@ -853,7 +853,7 @@ impl CtapState {
|
|||||||
|
|
||||||
// We decide on the algorithm early, but delay key creation since it takes time.
|
// We decide on the algorithm early, but delay key creation since it takes time.
|
||||||
// We rather do that later so all intermediate checks may return faster.
|
// We rather do that later so all intermediate checks may return faster.
|
||||||
let private_key = PrivateKey::new(env.rng(), algorithm);
|
let private_key = PrivateKey::new(env, algorithm);
|
||||||
let credential_id = if options.rk {
|
let credential_id = if options.rk {
|
||||||
let random_id = env.rng().gen_uniform_u8x32().to_vec();
|
let random_id = env.rng().gen_uniform_u8x32().to_vec();
|
||||||
let credential_source = PublicKeyCredentialSource {
|
let credential_source = PublicKeyCredentialSource {
|
||||||
@@ -892,7 +892,9 @@ impl CtapState {
|
|||||||
}
|
}
|
||||||
auth_data.extend(vec![0x00, credential_id.len() as u8]);
|
auth_data.extend(vec![0x00, credential_id.len() as u8]);
|
||||||
auth_data.extend(&credential_id);
|
auth_data.extend(&credential_id);
|
||||||
let public_cose_key = private_key.get_pub_key();
|
let public_cose_key = private_key
|
||||||
|
.get_pub_key(env)
|
||||||
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
|
||||||
cbor_write(cbor::Value::from(public_cose_key), &mut auth_data)?;
|
cbor_write(cbor::Value::from(public_cose_key), &mut auth_data)?;
|
||||||
if has_extension_output {
|
if has_extension_output {
|
||||||
let hmac_secret_output = if extensions.hmac_secret {
|
let hmac_secret_output = if extensions.hmac_secret {
|
||||||
@@ -932,7 +934,12 @@ impl CtapState {
|
|||||||
Some(vec![attestation_certificate]),
|
Some(vec![attestation_certificate]),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(private_key.sign_and_encode(&signature_data), None)
|
(
|
||||||
|
private_key
|
||||||
|
.sign_and_encode(env, &signature_data)
|
||||||
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?,
|
||||||
|
None,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let attestation_statement = PackedAttestationStatement {
|
let attestation_statement = PackedAttestationStatement {
|
||||||
alg: SignatureAlgorithm::ES256 as i64,
|
alg: SignatureAlgorithm::ES256 as i64,
|
||||||
@@ -1014,7 +1021,10 @@ impl CtapState {
|
|||||||
|
|
||||||
let mut signature_data = auth_data.clone();
|
let mut signature_data = auth_data.clone();
|
||||||
signature_data.extend(client_data_hash);
|
signature_data.extend(client_data_hash);
|
||||||
let signature = credential.private_key.sign_and_encode(&signature_data);
|
let signature = credential
|
||||||
|
.private_key
|
||||||
|
.sign_and_encode(env, &signature_data)
|
||||||
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
|
||||||
|
|
||||||
let cred_desc = PublicKeyCredentialDescriptor {
|
let cred_desc = PublicKeyCredentialDescriptor {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
@@ -1720,7 +1730,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_make_credential_credential_excluded() {
|
fn test_process_make_credential_credential_excluded() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let excluded_private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let excluded_private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|
||||||
let excluded_credential_id = vec![0x01, 0x23, 0x45, 0x67];
|
let excluded_credential_id = vec![0x01, 0x23, 0x45, 0x67];
|
||||||
@@ -1729,7 +1739,7 @@ mod test {
|
|||||||
let excluded_credential_source = PublicKeyCredentialSource {
|
let excluded_credential_source = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: excluded_credential_id,
|
credential_id: excluded_credential_id,
|
||||||
private_key: PrivateKey::from(excluded_private_key),
|
private_key: excluded_private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![],
|
user_handle: vec![],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2538,7 +2548,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_resident_process_get_assertion_with_cred_protect() {
|
fn test_resident_process_get_assertion_with_cred_protect() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|
||||||
@@ -2550,7 +2560,7 @@ mod test {
|
|||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: credential_id.clone(),
|
credential_id: credential_id.clone(),
|
||||||
private_key: PrivateKey::from(private_key.clone()),
|
private_key: private_key.clone(),
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x1D],
|
user_handle: vec![0x1D],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2612,7 +2622,7 @@ mod test {
|
|||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id,
|
credential_id,
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x1D],
|
user_handle: vec![0x1D],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2652,14 +2662,14 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_get_assertion_with_cred_blob() {
|
fn test_process_get_assertion_with_cred_blob() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id,
|
credential_id,
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x1D],
|
user_handle: vec![0x1D],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2710,14 +2720,14 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_get_assertion_with_large_blob_key() {
|
fn test_process_get_assertion_with_large_blob_key() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
let credential_id = env.rng().gen_uniform_u8x32().to_vec();
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id,
|
credential_id,
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x1D],
|
user_handle: vec![0x1D],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -2996,14 +3006,14 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_reset() {
|
fn test_process_reset() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||||
|
|
||||||
let credential_id = vec![0x01, 0x23, 0x45, 0x67];
|
let credential_id = vec![0x01, 0x23, 0x45, 0x67];
|
||||||
let credential_source = PublicKeyCredentialSource {
|
let credential_source = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id,
|
credential_id,
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![],
|
user_handle: vec![],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -3501,11 +3511,11 @@ mod test {
|
|||||||
let client_pin =
|
let client_pin =
|
||||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential_source = PublicKeyCredentialSource {
|
let credential_source = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x01],
|
user_handle: vec![0x01],
|
||||||
user_display_name: Some("display_name".to_string()),
|
user_display_name: Some("display_name".to_string()),
|
||||||
|
|||||||
@@ -702,15 +702,15 @@ mod test {
|
|||||||
use rng256::Rng256;
|
use rng256::Rng256;
|
||||||
|
|
||||||
fn create_credential_source(
|
fn create_credential_source(
|
||||||
rng: &mut impl Rng256,
|
env: &mut TestEnv,
|
||||||
rp_id: &str,
|
rp_id: &str,
|
||||||
user_handle: Vec<u8>,
|
user_handle: Vec<u8>,
|
||||||
) -> PublicKeyCredentialSource {
|
) -> PublicKeyCredentialSource {
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(rng);
|
let private_key = PrivateKey::new_ecdsa(env);
|
||||||
PublicKeyCredentialSource {
|
PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: rng.gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from(rp_id),
|
rp_id: String::from(rp_id),
|
||||||
user_handle,
|
user_handle,
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -727,7 +727,7 @@ mod test {
|
|||||||
fn test_store() {
|
fn test_store() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", vec![]);
|
let credential_source = create_credential_source(&mut env, "example.com", vec![]);
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
assert!(count_credentials(&mut env).unwrap() > 0);
|
assert!(count_credentials(&mut env).unwrap() > 0);
|
||||||
}
|
}
|
||||||
@@ -740,7 +740,7 @@ mod test {
|
|||||||
let mut credential_ids = vec![];
|
let mut credential_ids = vec![];
|
||||||
for i in 0..env.customization().max_supported_resident_keys() {
|
for i in 0..env.customization().max_supported_resident_keys() {
|
||||||
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
|
let credential_source = create_credential_source(&mut env, "example.com", user_handle);
|
||||||
credential_ids.push(credential_source.credential_id.clone());
|
credential_ids.push(credential_source.credential_id.clone());
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
||||||
@@ -768,7 +768,7 @@ mod test {
|
|||||||
Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)
|
Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)
|
||||||
);
|
);
|
||||||
|
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", vec![0x1D]);
|
let credential_source = create_credential_source(&mut env, "example.com", vec![0x1D]);
|
||||||
let credential_id = credential_source.credential_id.clone();
|
let credential_id = credential_source.credential_id.clone();
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
let stored_credential = find_credential(&mut env, "example.com", &credential_id, false)
|
let stored_credential = find_credential(&mut env, "example.com", &credential_id, false)
|
||||||
@@ -789,10 +789,10 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_credential_order() {
|
fn test_credential_order() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", vec![]);
|
let credential_source = create_credential_source(&mut env, "example.com", vec![]);
|
||||||
let current_latest_creation = credential_source.creation_order;
|
let current_latest_creation = credential_source.creation_order;
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
let mut credential_source = create_credential_source(env.rng(), "example.com", vec![]);
|
let mut credential_source = create_credential_source(&mut env, "example.com", vec![]);
|
||||||
credential_source.creation_order = new_creation_order(&mut env).unwrap();
|
credential_source.creation_order = new_creation_order(&mut env).unwrap();
|
||||||
assert!(credential_source.creation_order > current_latest_creation);
|
assert!(credential_source.creation_order > current_latest_creation);
|
||||||
let current_latest_creation = credential_source.creation_order;
|
let current_latest_creation = credential_source.creation_order;
|
||||||
@@ -808,12 +808,12 @@ mod test {
|
|||||||
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
||||||
for i in 0..max_supported_resident_keys {
|
for i in 0..max_supported_resident_keys {
|
||||||
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
|
let credential_source = create_credential_source(&mut env, "example.com", user_handle);
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
||||||
}
|
}
|
||||||
let credential_source = create_credential_source(
|
let credential_source = create_credential_source(
|
||||||
env.rng(),
|
&mut env,
|
||||||
"example.com",
|
"example.com",
|
||||||
vec![max_supported_resident_keys as u8],
|
vec![max_supported_resident_keys as u8],
|
||||||
);
|
);
|
||||||
@@ -834,8 +834,8 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||||
// These should have different IDs.
|
// These should have different IDs.
|
||||||
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
|
||||||
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x00]);
|
||||||
let credential_id0 = credential_source0.credential_id.clone();
|
let credential_id0 = credential_source0.credential_id.clone();
|
||||||
let credential_id1 = credential_source1.credential_id.clone();
|
let credential_id1 = credential_source1.credential_id.clone();
|
||||||
|
|
||||||
@@ -857,12 +857,12 @@ mod test {
|
|||||||
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
||||||
for i in 0..max_supported_resident_keys {
|
for i in 0..max_supported_resident_keys {
|
||||||
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
||||||
let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
|
let credential_source = create_credential_source(&mut env, "example.com", user_handle);
|
||||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
assert_eq!(count_credentials(&mut env).unwrap(), i + 1);
|
||||||
}
|
}
|
||||||
let credential_source = create_credential_source(
|
let credential_source = create_credential_source(
|
||||||
env.rng(),
|
&mut env,
|
||||||
"example.com",
|
"example.com",
|
||||||
vec![max_supported_resident_keys as u8],
|
vec![max_supported_resident_keys as u8],
|
||||||
);
|
);
|
||||||
@@ -879,10 +879,10 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_get_credential() {
|
fn test_get_credential() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
|
||||||
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
|
let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x01]);
|
||||||
let credential_source2 =
|
let credential_source2 =
|
||||||
create_credential_source(env.rng(), "another.example.com", vec![0x02]);
|
create_credential_source(&mut env, "another.example.com", vec![0x02]);
|
||||||
let credential_sources = vec![credential_source0, credential_source1, credential_source2];
|
let credential_sources = vec![credential_source0, credential_source1, credential_source2];
|
||||||
for credential_source in credential_sources.into_iter() {
|
for credential_source in credential_sources.into_iter() {
|
||||||
let cred_id = credential_source.credential_id.clone();
|
let cred_id = credential_source.credential_id.clone();
|
||||||
@@ -897,8 +897,8 @@ mod test {
|
|||||||
fn test_find() {
|
fn test_find() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||||
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
let credential_source0 = create_credential_source(&mut env, "example.com", vec![0x00]);
|
||||||
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
|
let credential_source1 = create_credential_source(&mut env, "example.com", vec![0x01]);
|
||||||
let id0 = credential_source0.credential_id.clone();
|
let id0 = credential_source0.credential_id.clone();
|
||||||
let key0 = credential_source0.private_key.clone();
|
let key0 = credential_source0.private_key.clone();
|
||||||
assert!(store_credential(&mut env, credential_source0).is_ok());
|
assert!(store_credential(&mut env, credential_source0).is_ok());
|
||||||
@@ -928,11 +928,11 @@ mod test {
|
|||||||
fn test_find_with_cred_protect() {
|
fn test_find_with_cred_protect() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x00],
|
user_handle: vec![0x00],
|
||||||
user_display_name: None,
|
user_display_name: None,
|
||||||
@@ -1228,11 +1228,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_deserialize_credential() {
|
fn test_serialize_deserialize_credential() {
|
||||||
let mut env = TestEnv::new();
|
let mut env = TestEnv::new();
|
||||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
let private_key = PrivateKey::new_ecdsa(&mut env);
|
||||||
let credential = PublicKeyCredentialSource {
|
let credential = PublicKeyCredentialSource {
|
||||||
key_type: PublicKeyCredentialType::PublicKey,
|
key_type: PublicKeyCredentialType::PublicKey,
|
||||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||||
private_key: PrivateKey::from(private_key),
|
private_key,
|
||||||
rp_id: String::from("example.com"),
|
rp_id: String::from("example.com"),
|
||||||
user_handle: vec![0x00],
|
user_handle: vec![0x00],
|
||||||
user_display_name: Some(String::from("Display Name")),
|
user_display_name: Some(String::from("Display Name")),
|
||||||
|
|||||||
Reference in New Issue
Block a user