blob: 7a62d5adad8339ac007a968ec088d8cbb6cca4f1 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use boringssl_sys::{
BN_bin2bn, BN_bn2bin, BN_dup, BN_free, BN_new, BN_num_bytes, CBB_cleanup, CBB_finish, CBB_init,
CBS_init, EC_GROUP_new_by_curve_name, EC_KEY_free, EC_KEY_get0_group, EC_KEY_get0_private_key,
EC_KEY_get0_public_key, EC_KEY_new_by_curve_name, EC_KEY_parse_private_key,
EC_KEY_set_public_key_affine_coordinates, EC_POINT_get_affine_coordinates_GFp, EVP_PKEY_free,
EVP_PKEY_new, EVP_PKEY_set1_EC_KEY, EVP_PKEY_set1_RSA, EVP_marshal_public_key, OPENSSL_free,
RSA_free, RSA_get0_key, RSA_new, RSA_parse_private_key, RSA_set0_key, BIGNUM as BN, CBB, CBS,
EC_KEY, EVP_PKEY, RSA,
};
use std::convert::{TryFrom, TryInto};
use std::mem;
use std::ptr;
use std::slice;
/// Wrapper around openssl BIGNUM.
struct BigNum<'a> {
bignum: &'a mut BN,
}
impl<'a> BigNum<'a> {
/// Creates an new empty big number object.
pub fn new() -> Option<Self> {
unsafe { BN_new().as_mut().map(|bignum| BigNum { bignum }) }
}
/// Parses the binary data into a big number object.
pub fn parse(buffer: &[u8]) -> Option<Self> {
// Don't panic while unsafe.
let buffer_len = buffer.len().try_into().unwrap();
unsafe {
BN_bin2bn(buffer.as_ptr(), buffer_len, ptr::null_mut())
.as_mut()
.map(|bignum| BigNum { bignum })
}
}
/// Turns the big number object to binary representation.
pub fn to_vec(&self) -> Option<Vec<u8>> {
Self::bn_to_vec(self.bignum as *const BN)
}
/// Static function to turn an openssl BIGNUM structure to binary.
///
/// This should be used by caller which does not own a BIGNUM.
pub fn bn_to_vec(bignum: *const BN) -> Option<Vec<u8>> {
let num_bytes = unsafe { BN_num_bytes(bignum) };
let mut bignum_binary: Vec<u8> = vec![0; num_bytes as usize];
let actual = unsafe { BN_bn2bin(bignum, bignum_binary.as_mut_ptr()) };
if usize::try_from(num_bytes).unwrap() != usize::try_from(actual).unwrap() {
return None;
}
Some(bignum_binary)
}
/// Gets an internal mutable pointer to the wrapped object.
pub fn get_mut_ptr(&mut self) -> *mut BN {
self.bignum as *mut BN
}
/// Duplicate the BigNum and gets a mutable pointer to the duplicated openssl BigNumber object.
/// Caller is responsible to free the returned object.
pub fn get_dup_mut_ptr(&self) -> *mut BN {
unsafe { BN_dup(self.bignum as *const BN) }
}
}
impl<'a> Drop for BigNum<'a> {
fn drop(&mut self) {
unsafe {
BN_free(self.bignum as *mut BN);
}
}
}
/// Wrapper around openssl CBB.
struct Cbb {
cbb: CBB,
}
impl Cbb {
/// Creates a new CBB with initial size.
pub fn new(size: usize) -> Option<Self> {
let mut cbb: CBB = unsafe { mem::zeroed() };
// Don't panic while unsafe.
let cbb_len = size.try_into().unwrap();
let result = unsafe { CBB_init(&mut cbb, cbb_len) };
if result == 0 {
return None;
}
Some(Cbb { cbb })
}
/// Gets an internal mutable pointer to the wrapped object.
pub fn get_mut_ptr(&mut self) -> *mut CBB {
&mut self.cbb
}
/// Turns a CBB structure into an AllocatedBuffer.
pub fn finish(&mut self) -> Option<Vec<u8>> {
let mut output_bytes: *mut u8 = ptr::null_mut();
let mut output_size = 0;
let result = unsafe { CBB_finish(&mut self.cbb, &mut output_bytes, &mut output_size) };
if result == 0 {
return None;
}
let output_size = output_size.try_into().unwrap();
let v = unsafe { slice::from_raw_parts(output_bytes, output_size).to_vec() };
unsafe { OPENSSL_free(output_bytes as *mut std::ffi::c_void) };
Some(v)
}
}
impl Drop for Cbb {
fn drop(&mut self) {
unsafe {
CBB_cleanup(&mut self.cbb);
}
}
}
/// Wrapper around openssl EVP_PKEY.
struct EvpPkey<'a> {
pkey: &'a mut EVP_PKEY,
}
impl<'a> EvpPkey<'a> {
/// Creates a new EVP_PKEY.
pub fn new() -> Option<Self> {
unsafe { EVP_PKEY_new().as_mut().map(|pkey| EvpPkey { pkey }) }
}
/// Gets an internal mutable pointer to the wrapped object.
pub fn get_mut_ptr(&mut self) -> *mut EVP_PKEY {
self.pkey as *mut EVP_PKEY
}
pub fn marshal_public_key(&self) -> Option<Vec<u8>> {
let mut cbb = Cbb::new(64)?;
let result =
unsafe { EVP_marshal_public_key(cbb.get_mut_ptr(), self.pkey as *const EVP_PKEY) };
if result == 0 {
return None;
}
cbb.finish()
}
}
impl<'a> Drop for EvpPkey<'a> {
fn drop(&mut self) {
unsafe {
EVP_PKEY_free(self.pkey as *mut EVP_PKEY);
}
}
}
/// An RSA public key object wrapping openssl RSA.
pub struct RsaPublicKey<'a> {
rsa: &'a mut RSA,
}
impl<'a> RsaPublicKey<'a> {
/// Creates a new public key using the modulus and public exponent.
pub fn new(modulus: &[u8], public_exponent: &[u8]) -> Result<Self, &'static str> {
let modulus_bn = BigNum::parse(modulus).ok_or("Modulus is not a valid BigNum!")?;
let public_exponent_bn =
BigNum::parse(public_exponent).ok_or("Public exponent is not a valid BigNum!")?;
let rsa = unsafe { RSA_new().as_mut().ok_or("Failed to initialize Rsa!") }?;
let result = unsafe {
RSA_set0_key(
rsa as *mut RSA,
// We need to duplicate the BigNumber here because this function expects to obtain
// the BIGNUM arguments.
modulus_bn.get_dup_mut_ptr(),
public_exponent_bn.get_dup_mut_ptr(),
ptr::null_mut(),
)
};
if result == 0 {
// Return 1 on success or 0 on failure.
return Err("Failed to set rsa public key!");
}
Ok(RsaPublicKey { rsa })
}
/// Marshals the public key into DER format.
pub fn marshal_public_key(&mut self) -> Result<Vec<u8>, &'static str> {
let mut evp_pkey = EvpPkey::new().ok_or("Failed to initialize EvpPkey!")?;
let result = unsafe { EVP_PKEY_set1_RSA(evp_pkey.get_mut_ptr(), self.rsa as *mut RSA) };
if result == 0 {
// Return 1 on success or 0 on failure.
return Err("Failed to parse EVP key to RSA key!");
}
evp_pkey.marshal_public_key().ok_or("Failed to marshal public key!")
}
}
impl<'a> Drop for RsaPublicKey<'a> {
fn drop(&mut self) {
unsafe {
RSA_free(self.rsa as *mut RSA);
}
}
}
/// An RSA private key object wrapping openssl RSA.
pub struct RsaPrivateKey<'a> {
rsa: &'a mut RSA,
}
impl<'a> RsaPrivateKey<'a> {
/// Creates a new RSA private key using the DER format key data.
pub fn new(key_data: &[u8]) -> Result<Self, &'static str> {
// Don't panic while unsafe.
let key_data_len = key_data.len().try_into().unwrap();
let rsa = unsafe {
let mut cbs: CBS = mem::zeroed();
CBS_init(&mut cbs, key_data.as_ptr(), key_data_len);
RSA_parse_private_key(&mut cbs).as_mut().ok_or("Failed to parse RSA Key!")
}?;
Ok(RsaPrivateKey { rsa })
}
/// Gets the modulus for this key.
pub fn get_modulus(&self) -> Result<Vec<u8>, &'static str> {
// Note that modulus here is not owned by us, so we could not use BigNum wrapper.
let mut modulus: *const BN = ptr::null_mut();
unsafe {
RSA_get0_key(self.rsa as *const RSA, &mut modulus, ptr::null_mut(), ptr::null_mut())
};
BigNum::bn_to_vec(modulus).ok_or("Failed to convert BigNum to vector!")
}
/// Gets the public exponent for this key.
pub fn get_public_exponent(&self) -> Result<Vec<u8>, &'static str> {
let mut public_exponent: *const BN = ptr::null_mut();
unsafe {
RSA_get0_key(
self.rsa as *const RSA,
ptr::null_mut(),
&mut public_exponent,
ptr::null_mut(),
)
};
BigNum::bn_to_vec(public_exponent).ok_or("Failed to convert BigNum to vector!")
}
/// Gets the private exponent for this key.
pub fn get_private_exponent(&self) -> Result<Vec<u8>, &'static str> {
let mut private_exponent: *const BN = ptr::null_mut();
unsafe {
RSA_get0_key(
self.rsa as *const RSA,
ptr::null_mut(),
ptr::null_mut(),
&mut private_exponent,
)
};
BigNum::bn_to_vec(private_exponent).ok_or("Failed to convert BigNum to vector!")
}
}
impl<'a> Drop for RsaPrivateKey<'a> {
fn drop(&mut self) {
unsafe {
RSA_free(self.rsa as *mut RSA);
}
}
}
/// An EC public key object wrapping openssl EC_KEY.
pub struct EcPublicKey<'a> {
ec_key: &'a mut EC_KEY,
}
impl<'a> EcPublicKey<'a> {
/// Creates a new EC key on the specific curve using public_x and public_y.
pub fn new(nid: i32, x: &[u8], y: &[u8]) -> Result<Self, &'static str> {
let ec_key = unsafe {
EC_KEY_new_by_curve_name(nid).as_mut().ok_or("Failed to initialize EcPublicKey!")
}?;
let mut x_bn = BigNum::parse(x).ok_or("Public value x is not a valid BigNum!")?;
let mut y_bn = BigNum::parse(y).ok_or("Public value y is not a valid BigNum!")?;
let result = unsafe {
EC_KEY_set_public_key_affine_coordinates(
ec_key as *mut EC_KEY,
x_bn.get_mut_ptr(),
y_bn.get_mut_ptr(),
)
};
if result == 0 {
// Return 1 on success or 0 on failure.
return Err("Failed to set EC public key!");
}
Ok(EcPublicKey { ec_key })
}
/// Marshals the EC key to DER format.
pub fn marshal_public_key(&mut self) -> Result<Vec<u8>, &'static str> {
let mut evp_pkey = EvpPkey::new().ok_or("Failed to initialize EvpPkey!")?;
let result =
unsafe { EVP_PKEY_set1_EC_KEY(evp_pkey.get_mut_ptr(), self.ec_key as *mut EC_KEY) };
if result == 0 {
return Err("Failed to set ec key!");
}
evp_pkey.marshal_public_key().ok_or("Failed to marshal public key!")
}
}
impl<'a> Drop for EcPublicKey<'a> {
fn drop(&mut self) {
unsafe {
EC_KEY_free(self.ec_key as *mut EC_KEY);
}
}
}
/// An EC private key object wrapping openssl EC_KEY.
pub struct EcPrivateKey<'a> {
ec_key: &'a mut EC_KEY,
}
impl<'a> EcPrivateKey<'a> {
/// Creates a new EC private key using the DER format key data on a specific curve.
pub fn new(nid: i32, key_data: &[u8]) -> Result<Self, &'static str> {
let ec_group = unsafe { EC_GROUP_new_by_curve_name(nid) };
if ec_group.is_null() {
return Err("Invalid ec curve type!");
}
// Don't panic while unsafe.
let key_data_len = key_data.len().try_into().unwrap();
let ec_key = unsafe {
let mut cbs = mem::zeroed();
CBS_init(&mut cbs, key_data.as_ptr(), key_data_len);
EC_KEY_parse_private_key(&mut cbs, ec_group).as_mut().ok_or("Failed to parse EC Key!")
}?;
Ok(EcPrivateKey { ec_key })
}
/// Gets the private key for this EC key.
pub fn get_private_key(&self) -> Result<Vec<u8>, &'static str> {
let bignum = unsafe { EC_KEY_get0_private_key(self.ec_key as *const EC_KEY) };
// We can't use BigNum here because BigNum would take responsibility and here bignum is
// just a reference.
BigNum::bn_to_vec(bignum as *const BN).ok_or("Failed to covert BigNum to vector!")
}
/// Gets the public key x for this EC key.
pub fn get_public_key_x(&self) -> Result<Vec<u8>, &'static str> {
let ec_point = unsafe { EC_KEY_get0_public_key(self.ec_key as *const EC_KEY) };
let mut public_x_bignum = BigNum::new().ok_or("Failed to initialize BigNum!")?;
let ec_group = unsafe { EC_KEY_get0_group(self.ec_key as *const EC_KEY) };
let result = unsafe {
EC_POINT_get_affine_coordinates_GFp(
ec_group,
ec_point,
public_x_bignum.get_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
)
};
if result == 0 {
return Err("Failed to convert point to x and y value!");
}
public_x_bignum.to_vec().ok_or("Failed to covert BigNum to vector!")
}
/// Gets the public key y for this EC key.
pub fn get_public_key_y(&self) -> Result<Vec<u8>, &'static str> {
let ec_point = unsafe { EC_KEY_get0_public_key(self.ec_key as *const EC_KEY) };
let mut public_y_bignum = BigNum::new().ok_or("Failed to initialize BigNum!")?;
let ec_group = unsafe { EC_KEY_get0_group(self.ec_key as *const EC_KEY) };
let result = unsafe {
EC_POINT_get_affine_coordinates_GFp(
ec_group,
ec_point,
ptr::null_mut(),
public_y_bignum.get_mut_ptr(),
ptr::null_mut(),
)
};
if result == 0 {
return Err("Failed to convert point to x and y value!");
}
public_y_bignum.to_vec().ok_or("Failed to covert BigNum to vector!")
}
}
impl<'a> Drop for EcPrivateKey<'a> {
fn drop(&mut self) {
unsafe {
EC_KEY_free(self.ec_key as *mut EC_KEY);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use boringssl_sys::{NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1};
use mundane::public::ec::*;
use mundane::public::rsa::*;
use mundane::public::*;
#[test]
fn test_ec_key() {
// Right now only these algorithms are supported.
test_ec_key_alg::<P256>(NID_X9_62_prime256v1 as i32);
test_ec_key_alg::<P384>(NID_secp384r1 as i32);
test_ec_key_alg::<P521>(NID_secp521r1 as i32);
}
fn test_ec_key_alg<C: PCurve>(nid: i32) {
let ec_key = EcPrivKey::<C>::generate().unwrap();
let ec_key_data = ec_key.marshal_to_der();
let ec_private_key = EcPrivateKey::new(nid, &ec_key_data).unwrap();
let _private_key_data = ec_private_key.get_private_key().unwrap();
let public_key_x = ec_private_key.get_public_key_x().unwrap();
let public_key_y = ec_private_key.get_public_key_y().unwrap();
let mut ec_public_key = EcPublicKey::new(nid, &public_key_x, &public_key_y).unwrap();
let public_key_data = ec_public_key.marshal_public_key().unwrap();
assert_eq!(ec_key.public().marshal_to_der(), public_key_data);
}
#[test]
fn test_rsa_key() {
// Right now only these algorithms are supported.
test_rsa_key_alg::<B2048>();
test_rsa_key_alg::<B3072>();
test_rsa_key_alg::<B4096>();
}
fn test_rsa_key_alg<B: RsaKeyBits>() {
let rsa_key = RsaPrivKey::<B>::generate().unwrap();
let rsa_key_data = rsa_key.marshal_to_der();
let rsa_private_key = RsaPrivateKey::new(&rsa_key_data).unwrap();
let _private_exponent = rsa_private_key.get_private_exponent().unwrap();
let modulus = rsa_private_key.get_modulus().unwrap();
let public_exponent = rsa_private_key.get_public_exponent().unwrap();
let mut rsa_public_key = RsaPublicKey::new(&modulus, &public_exponent).unwrap();
let public_key_data = rsa_public_key.marshal_public_key().unwrap();
assert_eq!(rsa_key.public().marshal_to_der(), public_key_data);
}
}