security-rs 0.2.1

Safe Rust bindings for Apple's Security framework — keychain, identity, certificates, trust, authorization, CMS, SecureTransport, and cryptographic primitives on macOS
Documentation
use serde_json::Value;

use crate::bridge::{self, Handle};
use crate::certificate::PublicKey;
use crate::error::Result;

#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ExternalFormat {
    Unknown = 0,
    OpenSsl = 1,
    Ssh = 2,
    Bsafe = 3,
    RawKey = 4,
    WrappedPkcs8 = 5,
    WrappedOpenSsl = 6,
    WrappedSsh = 7,
    WrappedLsh = 8,
    X509Certificate = 9,
    PemSequence = 10,
    Pkcs7 = 11,
    Pkcs12 = 12,
    NetscapeCertificateSequence = 13,
    SshV2 = 14,
}

#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ExternalItemType {
    Unknown = 0,
    PrivateKey = 1,
    PublicKey = 2,
    SessionKey = 3,
    Certificate = 4,
    Aggregate = 5,
}

#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KeyType {
    Rsa = 0,
    EcSecPrimeRandom = 1,
}

#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SignatureAlgorithm {
    RsaSignatureMessagePkcs1v15Sha256 = 0,
    RsaSignatureDigestPkcs1v15Sha256 = 1,
    RsaSignatureMessagePssSha256 = 2,
    EcdsaSignatureMessageX962Sha256 = 3,
    EcdsaSignatureDigestX962Sha256 = 4,
}

#[derive(Debug)]
pub struct PrivateKey {
    handle: Handle,
}

impl PrivateKey {
    pub(crate) fn from_handle(handle: Handle) -> Self {
        Self { handle }
    }

    pub fn from_data(data: &[u8], key_type: KeyType, key_size_bits: usize) -> Result<Self> {
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_private_key_create_with_data(
                data.as_ptr().cast(),
                bridge::len_to_isize(data.len())?,
                key_type as u32,
                bridge::len_to_isize(key_size_bits)?,
                &mut status,
                &mut error,
            )
        };
        bridge::required_handle("security_private_key_create_with_data", raw, status, error)
            .map(Self::from_handle)
    }

    pub fn import_item(
        data: &[u8],
        file_name_or_extension: Option<&str>,
        format: ExternalFormat,
        item_type: ExternalItemType,
    ) -> Result<Self> {
        let file_name_or_extension = file_name_or_extension.map(bridge::cstring).transpose()?;
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_private_key_import_item(
                data.as_ptr().cast(),
                bridge::len_to_isize(data.len())?,
                file_name_or_extension
                    .as_ref()
                    .map_or(std::ptr::null(), |value| value.as_ptr()),
                format as u32,
                item_type as u32,
                &mut status,
                &mut error,
            )
        };
        bridge::required_handle("security_private_key_import_item", raw, status, error)
            .map(Self::from_handle)
    }

    pub fn import_pem(pem: &[u8]) -> Result<Self> {
        Self::import_item(
            pem,
            Some(".pem"),
            ExternalFormat::Unknown,
            ExternalItemType::PrivateKey,
        )
    }

    pub fn public_key(&self) -> Result<PublicKey> {
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_key_copy_public_key(self.handle.as_ptr(), &mut status, &mut error)
        };
        bridge::required_handle("security_key_copy_public_key", raw, status, error)
            .map(PublicKey::from_handle)
    }

    pub fn attributes(&self) -> Result<Value> {
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_key_copy_attributes(self.handle.as_ptr(), &mut status, &mut error)
        };
        bridge::required_json("security_key_copy_attributes", raw, status, error)
    }

    pub fn sign(&self, algorithm: SignatureAlgorithm, data: &[u8]) -> Result<Vec<u8>> {
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_private_key_create_signature(
                self.handle.as_ptr(),
                algorithm as u32,
                data.as_ptr().cast(),
                bridge::len_to_isize(data.len())?,
                &mut status,
                &mut error,
            )
        };
        bridge::required_data("security_private_key_create_signature", raw, status, error)
    }
}