Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Key agreement via SecKeyCopyKeyExchangeResult() #218

Merged
merged 2 commits into from
Dec 16, 2024

Conversation

crashdump
Copy link
Contributor

Added SecKeyCopyKeyExchangeResult() to leverage Security.framework for ECDH-type key agreement.

@crashdump crashdump changed the title SecKey: Add SecKeyCopyKeyExchangeResult() Key agreement via SecKeyCopyKeyExchangeResult() Dec 13, 2024
@crashdump
Copy link
Contributor Author

crashdump commented Dec 13, 2024

@kornelski, the code in this merge request works up to macOS 14, but it fails on 15+ due to the current implementation of SecKeyExt::from_data relying on SecKeyCreateFromData(), which is deprecated. Note that I do not believe key derivation to be possible today, and this MR shouldn't be breaking anything else.

I have successfully implemented key derivation on macOS 15+ by using the new method in my own code, however, I stopped short of making breaking changes in this project as I wasn't sure how you'd like to handle this.

Note that the new method to import public keys supports all the platforms, so it may warrant moving SecKeyExt outside the macos mod.

Let me know your thoughts, but this should be mergeable as-is - comments welcome.

Edit: In case someone stumbles on this while looking for a working solution to key exchange, this is the code in the host project.

let peer_public_key = unsafe {
    use core_foundation::base::TCFType;
    use core_foundation::data::CFData;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::error::CFError;
    use core_foundation::string::CFString;
    use security_framework_sys::item::{
        kSecAttrKeyClass, kSecAttrKeyClassPublic, kSecAttrKeyType,
        kSecAttrKeyTypeECSECPrimeRandom,
    };
    use std::ptr;

    let key_data = &CFData::from_buffer(&pub_key_raw);

    let dict = CFDictionary::from_CFType_pairs(&[
        (
            CFString::wrap_under_get_rule(kSecAttrKeyType),
            CFString::wrap_under_get_rule(kSecAttrKeyTypeECSECPrimeRandom).into_CFType(),
        ),
        (
            CFString::wrap_under_get_rule(kSecAttrKeyClass),
            CFString::wrap_under_get_rule(kSecAttrKeyClassPublic).into_CFType(),
        ),
    ]);

    let mut err = ptr::null_mut();
    let key = SecKeyCreateWithData(
        key_data.as_concrete_TypeRef(),
        dict.as_concrete_TypeRef(),
        &mut err,
    );
    if key.is_null() {
        Err(CFError::wrap_under_create_rule(err))
    } else {
        Ok(SecKey::wrap_under_create_rule(key))
    }
}?;

let shared_secret = self
    .key
    .key_exchange(
        Algorithm::ECDHKeyExchangeStandard,
        &peer_public_key,
        256,
        None,
    )
    .unwrap();

@kornelski kornelski merged commit b2189b2 into kornelski:main Dec 16, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants