Repository: google/OpenSK
File: src/ctap/data_formats.rs (Rust)

Code before:
    pub rp_id: String,
    pub user_handle: Vec<u8>, // not optional, but nullable
    pub other_ui: Option<String>,
    pub cred_random: Option<Vec<u8>>,

    /// Contains the unknown fields when parsing a CBOR value.
    ///
    /// Those fields could either be deleted fields from older versions (they should have reserved
    /// tags) or fields from newer versions (the tags should not be reserved). If this is empty,
    /// then the parsed credential is probably from the same version (but not necessarily).
    pub unknown_fields: BTreeMap<cbor::KeyType, cbor::Value>,
}

// We serialize credentials for the persistent storage using CBOR maps. Each field of a credential
// is associated with a unique tag, implemented with a CBOR unsigned key.
#[repr(u64)]
enum PublicKeyCredentialSourceField {
    CredentialId = 0,
    PrivateKey = 1,
    RpId = 2,
    UserHandle = 3,
    OtherUi = 4,
    CredRandom = 5,
    // When a field is removed, its tag should be reserved and not used for new fields. We document
    // those reserved tags below.
    // Reserved tags: none.
}

impl From<PublicKeyCredentialSourceField> for cbor::KeyType {
    fn from(field: PublicKeyCredentialSourceField) -> cbor::KeyType {
        (field as u64).into()
    }
}

impl From<PublicKeyCredentialSource> for cbor::Value {
    fn from(credential: PublicKeyCredentialSource) -> cbor::Value {
        use PublicKeyCredentialSourceField::*;
        let mut private_key = [0; 32];
        credential.private_key.to_bytes(&mut private_key);
        let mut result = credential.unknown_fields;
        extend_cbor_map_options! {
            &mut result,
            CredentialId => Some(credential.credential_id),
            PrivateKey => Some(private_key.to_vec()),
            RpId => Some(credential.rp_id),
            UserHandle => Some(credential.user_handle),
            OtherUi => credential.other_ui,
            CredRandom => credential.cred_random
        };
        cbor::Value::Map(result)
    }

Review comment (suggestion):
There are some more enums in this file that could implement "from" like this, I was wondering if it is worth adding these methods. This would be setting standards and I'd patch i.e. SignatureAlgorithm later.

Code after:
    pub key_type: PublicKeyCredentialType,
    pub credential_id: Vec<u8>,
    pub private_key: ecdsa::SecKey, // TODO(kaczmarczyck) open for other algorithms
    pub rp_id: String,
    pub user_handle: Vec<u8>, // not optional, but nullable
    pub other_ui: Option<String>,
    pub cred_random: Option<Vec<u8>>,
}

// We serialize credentials for the persistent storage using CBOR maps. Each field of a credential
// is associated with a unique tag, implemented with a CBOR unsigned key.
enum PublicKeyCredentialSourceField {
    CredentialId = 0,
    PrivateKey = 1,
    RpId = 2,
    UserHandle = 3,
    OtherUi = 4,
    CredRandom = 5,
    // When a field is removed, its tag should be reserved and not used for new fields. We document
    // those reserved tags below.
    // Reserved tags: none.
}

impl From<PublicKeyCredentialSourceField> for cbor::KeyType {
    fn from(field: PublicKeyCredentialSourceField) -> cbor::KeyType {
        (field as u64).into()
    }
}

impl From<PublicKeyCredentialSource> for cbor::Value {
    fn from(credential: PublicKeyCredentialSource) -> cbor::Value {
        use PublicKeyCredentialSourceField::*;
        let mut private_key = [0u8; 32];
        credential.private_key.to_bytes(&mut private_key);
        cbor_map_options! {
            CredentialId => Some(credential.credential_id),
            PrivateKey => Some(private_key.to_vec()),
            RpId => Some(credential.rp_id),
            UserHandle => Some(credential.user_handle),
            OtherUi => credential.other_ui,
            CredRandom => credential.cred_random
        }
    }
}

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

    fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
        use PublicKeyCredentialSourceField::*;
        let mut map = extract_map(cbor_value)?;