diff --git a/aws-lc-rs/src/evp_pkey.rs b/aws-lc-rs/src/evp_pkey.rs index d8daf2ac5b77..cd1e6cedb17c 100644 --- a/aws-lc-rs/src/evp_pkey.rs +++ b/aws-lc-rs/src/evp_pkey.rs @@ -2,15 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 OR ISC use crate::aws_lc::{ - EVP_DigestSign, EVP_DigestSignInit, EVP_DigestVerify, EVP_DigestVerifyInit, EVP_PKEY_CTX_new, - EVP_PKEY_CTX_new_id, EVP_PKEY_bits, EVP_PKEY_cmp, EVP_PKEY_derive, EVP_PKEY_derive_init, - EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY, EVP_PKEY_get0_RSA, + BIO_new_mem_buf, EVP_DigestSign, EVP_DigestSignInit, EVP_DigestVerify, EVP_DigestVerifyInit, + EVP_PKEY_CTX_new, EVP_PKEY_CTX_new_id, EVP_PKEY_bits, EVP_PKEY_cmp, EVP_PKEY_derive, + EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY, EVP_PKEY_get0_RSA, EVP_PKEY_get_raw_private_key, EVP_PKEY_get_raw_public_key, EVP_PKEY_id, EVP_PKEY_keygen, EVP_PKEY_keygen_init, EVP_PKEY_new_raw_private_key, EVP_PKEY_new_raw_public_key, EVP_PKEY_sign, EVP_PKEY_sign_init, EVP_PKEY_size, EVP_PKEY_up_ref, EVP_PKEY_verify, EVP_PKEY_verify_init, EVP_marshal_private_key, EVP_marshal_private_key_v2, EVP_marshal_public_key, - EVP_parse_private_key, EVP_parse_public_key, EC_KEY, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_ED25519, - RSA, + EVP_parse_private_key, EVP_parse_public_key, PEM_read_bio_PUBKEY, PEM_read_bio_PrivateKey, BIO, + EC_KEY, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_ED25519, RSA, }; #[cfg(all(feature = "unstable", not(feature = "fips")))] use crate::aws_lc::{ @@ -225,6 +225,42 @@ impl LcPtr { .ok_or(KeyRejected::wrong_algorithm()) } + pub(crate) fn parse_pem_private_key( + bytes: &[u8], + evp_pkey_type: c_int, + ) -> Result { + let mut bio: LcPtr = LcPtr::new(unsafe { + BIO_new_mem_buf(bytes.as_ptr().cast(), bytes.len().cast_signed()) + })?; + let evp_pkey = LcPtr::new(unsafe { + PEM_read_bio_PrivateKey(*bio.as_mut(), null_mut(), None, null_mut()) + })?; + evp_pkey + .as_const() + .id() + .eq(&evp_pkey_type) + .then_some(evp_pkey) + .ok_or(KeyRejected::wrong_algorithm()) + } + + pub(crate) fn parse_pem_public_key( + bytes: &[u8], + evp_pkey_type: c_int, + ) -> Result { + let mut bio: LcPtr = LcPtr::new(unsafe { + BIO_new_mem_buf(bytes.as_ptr().cast(), bytes.len().cast_signed()) + })?; + let evp_pkey = LcPtr::new(unsafe { + PEM_read_bio_PUBKEY(*bio.as_mut(), null_mut(), None, null_mut()) + })?; + evp_pkey + .as_const() + .id() + .eq(&evp_pkey_type) + .then_some(evp_pkey) + .ok_or(KeyRejected::wrong_algorithm()) + } + #[allow(non_snake_case)] pub(crate) fn create_EVP_PKEY_CTX(&self) -> Result, ()> { // The only modification made by EVP_PKEY_CTX_new to `priv_key` is to increment its diff --git a/aws-lc-rs/src/ptr.rs b/aws-lc-rs/src/ptr.rs index 80279185c8cb..248887509281 100644 --- a/aws-lc-rs/src/ptr.rs +++ b/aws-lc-rs/src/ptr.rs @@ -7,6 +7,7 @@ use crate::aws_lc::{ ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX, EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX, RSA, }; +use aws_lc::{BIO_free, BIO}; use core::ops::Deref; use std::marker::PhantomData; @@ -271,6 +272,7 @@ create_pointer!(EVP_PKEY_CTX, EVP_PKEY_CTX_free); create_pointer!(RSA, RSA_free); create_pointer!(EVP_AEAD_CTX, EVP_AEAD_CTX_free); create_pointer!(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free); +create_pointer!(BIO, BIO_free); #[cfg(test)] mod tests { diff --git a/aws-lc-rs/src/rsa.rs b/aws-lc-rs/src/rsa.rs index ffced1a82923..d896e44b2ea9 100644 --- a/aws-lc-rs/src/rsa.rs +++ b/aws-lc-rs/src/rsa.rs @@ -141,4 +141,50 @@ mod tests { format!("{:?}", signature::RSA_PSS_2048_8192_SHA256) ); } + + #[test] + fn test_load_pem() { + use crate::signature::RsaKeyPair; + let pem_bytes = b"-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY-----"; + + let key = RsaKeyPair::from_pem(pem_bytes).unwrap(); + } } diff --git a/aws-lc-rs/src/rsa/key.rs b/aws-lc-rs/src/rsa/key.rs index 4c5c0098fe90..ce64ea884a25 100644 --- a/aws-lc-rs/src/rsa/key.rs +++ b/aws-lc-rs/src/rsa/key.rs @@ -164,6 +164,15 @@ impl KeyPair { Self::new(key) } + /// Parses a PEM-encoded private key. + /// + /// # Errors + /// `error:KeyRejected` on error. + pub fn from_pem(input: &[u8]) -> Result { + let key = LcPtr::::parse_pem_private_key(input, EVP_PKEY_RSA)?; + Self::new(key) + } + /// Returns a boolean indicator if this RSA key is an approved FIPS 140-3 key. #[cfg(feature = "fips")] #[must_use]