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

Code before:
    // +------+-------------------+-----------------+------------+--------------------+
    // + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
    // +------+-------------------+-----------------+------------+--------------------+
    fn process_register<R, CheckUserPresence>(
        challenge: [u8; 32],
        application: [u8; 32],
        ctap_state: &mut CtapState<R, CheckUserPresence>,
    ) -> Result<Vec<u8>, Ctap1StatusCode>
    where
        R: Rng256,
        CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
    {
        let sk = crypto::ecdsa::SecKey::gensk(ctap_state.rng);
        let pk = sk.genpk();
        let key_handle = ctap_state
            .encrypt_key_handle(sk, &application)
            .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
        if key_handle.len() > 0xFF {
            // This is just being defensive with unreachable code.
            return Err(Ctap1StatusCode::SW_WRONG_LENGTH);
        }

        let certificate = ctap_state
            .persistent_store
            .attestation_certificate()
            .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?
            .ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
        let private_key = ctap_state
            .persistent_store
            .attestation_private_key()
            .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?
            .ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;

        let mut response = Vec::with_capacity(105 + key_handle.len() + certificate.len());
        response.push(Ctap1Command::LEGACY_BYTE);
        let user_pk = pk.to_uncompressed();
        response.extend_from_slice(&user_pk);
        response.push(key_handle.len() as u8);
        response.extend(key_handle.clone());
        response.extend_from_slice(&certificate);

        // The first byte is reserved.
        let mut signature_data = Vec::with_capacity(66 + key_handle.len());
        signature_data.push(0x00);
        signature_data.extend(&application);
        signature_data.extend(&challenge);
        signature_data.extend(key_handle);
        signature_data.extend_from_slice(&user_pk);

        let attestation_key = crypto::ecdsa::SecKey::from_bytes(&private_key).unwrap();
        let signature = attestation_key.sign_rfc6979::<crypto::sha256::Sha256>(&signature_data);

Review comment (bug):
We decided in a PR #222  to report separate errors for potential storage/hardware failure (SW_MEMERR) or the entry not being present (SW_COMMAND_ABORTED)

Code after:
    // +------+-------------------+-----------------+------------+--------------------+
    // + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
    // +------+-------------------+-----------------+------------+--------------------+
    fn process_register<R, CheckUserPresence>(
        challenge: [u8; 32],
        application: [u8; 32],
        ctap_state: &mut CtapState<R, CheckUserPresence>,
    ) -> Result<Vec<u8>, Ctap1StatusCode>
    where
        R: Rng256,
        CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
    {
        let sk = crypto::ecdsa::SecKey::gensk(ctap_state.rng);
        let pk = sk.genpk();
        let key_handle = ctap_state
            .encrypt_key_handle(sk, &application)
            .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
        if key_handle.len() > 0xFF {
            // This is just being defensive with unreachable code.
            return Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION);
        }

        let certificate = ctap_state
            .persistent_store
            .attestation_certificate()
            .map_err(|_| Ctap1StatusCode::SW_MEMERR)?
            .ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
        let private_key = ctap_state
            .persistent_store
            .attestation_private_key()
            .map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?
            .ok_or(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;

        let mut response = Vec::with_capacity(105 + key_handle.len() + certificate.len());
        response.push(Ctap1Command::LEGACY_BYTE);
        let user_pk = pk.to_uncompressed();
        response.extend_from_slice(&user_pk);
        response.push(key_handle.len() as u8);
        response.extend(key_handle.clone());
        response.extend_from_slice(&certificate);

        // The first byte is reserved.
        let mut signature_data = Vec::with_capacity(66 + key_handle.len());
        signature_data.push(0x00);
        signature_data.extend(&application);
        signature_data.extend(&challenge);
        signature_data.extend(key_handle);
        signature_data.extend_from_slice(&user_pk);

        let attestation_key = crypto::ecdsa::SecKey::from_bytes(&private_key).unwrap();
        let signature = attestation_key.sign_rfc6979::<crypto::sha256::Sha256>(&signature_data);