blob: f11b9902b3e65fdfbda23548efd2a76d1a454d3b [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 crate::common::{self as common, KeyAttributes, KeyRequestType, KeyType, KmsKey};
use crate::crypto_provider::{AsymmetricProviderKey, CryptoProvider};
use fidl_fuchsia_kms::{
AsymmetricKeyAlgorithm, AsymmetricPrivateKeyRequest, Error, KeyOrigin, KeyProvider, PublicKey,
Signature, MAX_DATA_SIZE,
};
use fidl_fuchsia_mem::Buffer;
#[derive(Debug)]
pub struct KmsAsymmetricKey {
provider_key: Box<dyn AsymmetricProviderKey>,
key_name: String,
deleted: bool,
key_origin: KeyOrigin,
}
impl KmsKey for KmsAsymmetricKey {
fn get_key_name(&self) -> &str {
&self.key_name
}
fn is_deleted(&self) -> bool {
self.deleted
}
fn handle_request(&self, req: KeyRequestType<'_>) -> Result<(), fidl::Error> {
if let KeyRequestType::AsymmetricPrivateKeyRequest(req) = req {
self.handle_asym_request(req)?;
} else {
panic!("Invalid request!");
}
Ok(())
}
fn get_key_type(&self) -> KeyType {
KeyType::AsymmetricPrivateKey
}
fn get_key_provider(&self) -> KeyProvider {
self.provider_key.get_key_provider()
}
fn get_key_data(&self) -> Vec<u8> {
self.provider_key.get_key_data()
}
fn delete(&mut self) -> Result<(), Error> {
// Inform the provider to delete key.
self.provider_key.delete().map_err(|_| Error::InternalError)?;
self.deleted = true;
Ok(())
}
}
impl KmsAsymmetricKey {
/// Create a new KmsAsymmetricKey object.
///
/// # Arguments
///
/// * `provider` - The crypto provider to generate the key with.
/// * `key_name` - The name for the new key.
/// * `key_algorithm` - The algorithm for the new key.
pub fn new<C: CryptoProvider + ?Sized>(
provider: &C,
key_name: &str,
key_algorithm: AsymmetricKeyAlgorithm,
) -> Result<Self, Error> {
// Ask the provider to generate a provider key.
let provider_key = provider.generate_asymmetric_key(key_algorithm, key_name).map_err(
debug_err_fn!(Error::InternalError, "Failed to generate asymmetric key: {:?}"),
)?;
// Create the key object.
Ok(KmsAsymmetricKey {
provider_key,
key_name: key_name.to_string(),
deleted: false,
key_origin: KeyOrigin::Generated,
})
}
/// Parse the key data and generate a new KmsAsymmetricKey object.
///
/// # Arguments
///
/// * `key_name` - The name for the new key.
/// * `key_attributes` - The attributes for the new key.
pub fn parse_key(key_name: &str, key_attributes: KeyAttributes<'_>) -> Result<Self, Error> {
if key_attributes.key_type != KeyType::AsymmetricPrivateKey {
// The key is a different type.
return Err(Error::KeyNotFound);
}
// It is safe to unwrap here because KeyType would always be AsymmetricPrivateKey when
// we called read_key_attributes_from_file in key_manager and asymmetric_key_algorithm
// would never be None.
let key_algorithm = key_attributes.asymmetric_key_algorithm.unwrap();
// Ask the provider to parse the key.
let provider_key = key_attributes
.provider
.parse_asymmetric_key(&key_attributes.key_data, key_algorithm)
.map_err(debug_err_fn!(
Error::ParseKeyError,
"Failed to parse asymmetric key data: {:?}"
))?;
// Create the key object.
Ok(KmsAsymmetricKey {
provider_key,
key_name: key_name.to_string(),
deleted: false,
key_origin: key_attributes.key_origin,
})
}
/// Import an asymmetric private key and returns the imported key object.
///
/// # Arguments
///
/// * `provider` - The crypto provider to parse the private key data.
/// * `data` - The PKCS8 DER encoded private key data.
/// * `key_name` - The name for the new key.
/// * `key_algorithm` - The algorithm for the new key.
pub fn import_key<C: CryptoProvider + ?Sized>(
provider: &C,
data: &[u8],
key_name: &str,
key_algorithm: AsymmetricKeyAlgorithm,
) -> Result<Self, Error> {
let provider_key = provider.import_asymmetric_key(data, key_algorithm, key_name).map_err(
debug_err_fn!(Error::ParseKeyError, "Failed to import asymmetric key: {:?}"),
)?;
// Create the key object.
Ok(KmsAsymmetricKey {
provider_key,
key_name: key_name.to_string(),
deleted: false,
key_origin: KeyOrigin::Imported,
})
}
/// Sign a piece of data. Return the signature.
///
/// # Arguments
///
/// * `buffer` - The input data buffer, need to be less than 32k bytes. Otherwise InputTooLarge
/// would be returned.
fn sign(&self, buffer: Buffer) -> Result<Vec<u8>, Error> {
if buffer.size > MAX_DATA_SIZE.into() {
return Err(Error::InputTooLarge);
}
let input = common::buffer_to_data(buffer)?;
if self.is_deleted() {
return Err(Error::KeyNotFound);
}
self.provider_key
.sign(&input)
.map_err(debug_err_fn!(Error::InternalError, "Failed to sign data: {:?}"))
}
pub fn get_key_algorithm(&self) -> AsymmetricKeyAlgorithm {
self.provider_key.get_key_algorithm()
}
pub fn get_key_origin(&self) -> KeyOrigin {
self.key_origin
}
/// Get the DER encoded public key.
fn get_der_public_key(&self) -> Result<Vec<u8>, Error> {
if self.is_deleted() {
return Err(Error::KeyNotFound);
}
Ok(self
.provider_key
.get_der_public_key()
.map_err(debug_err_fn!(Error::InternalError, "Failed to get public key: {:?}"))?)
}
pub fn handle_asym_request(&self, req: AsymmetricPrivateKeyRequest) -> Result<(), fidl::Error> {
match req {
AsymmetricPrivateKeyRequest::Sign { data, responder } => {
responder.send(&mut self.sign(data).map(|signature| Signature { bytes: signature }))
}
AsymmetricPrivateKeyRequest::GetPublicKey { responder } => responder.send(
&mut self.get_der_public_key().map(|public_key| PublicKey { bytes: public_key }),
),
AsymmetricPrivateKeyRequest::GetKeyAlgorithm { responder } => {
let key_algorithm = self.get_key_algorithm();
if self.is_deleted() {
responder.send(&mut Err(Error::KeyNotFound))
} else {
responder.send(&mut Ok(key_algorithm))
}
}
AsymmetricPrivateKeyRequest::GetKeyOrigin { responder } => {
let origin = self.get_key_origin();
if self.is_deleted() {
responder.send(&mut Err(Error::KeyNotFound))
} else {
responder.send(&mut Ok(origin))
}
}
AsymmetricPrivateKeyRequest::GetKeyProvider { responder } => {
let provider_name = self.get_key_provider();
if self.is_deleted() {
responder.send(&mut Err(Error::KeyNotFound))
} else {
responder.send(&mut Ok(provider_name))
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::{self as common, ASYMMETRIC_KEY_ALGORITHMS};
use crate::crypto_provider::mock_provider::MockProvider;
static TEST_KEY_NAME: &str = "TestKey";
#[test]
fn test_sign_mock_provider() {
for algorithm in ASYMMETRIC_KEY_ALGORITHMS.iter() {
sign_mock_provider(*algorithm);
}
}
fn sign_mock_provider(key_algorithm: AsymmetricKeyAlgorithm) {
let test_output_data = common::generate_random_data(32);
let test_key_data = common::generate_random_data(32);
let mock_provider = Box::new(MockProvider::new());
mock_provider.set_result(&test_key_data);
mock_provider.set_key_result(Ok(test_output_data.clone()));
let test_key =
KmsAsymmetricKey::new(&*mock_provider, TEST_KEY_NAME, key_algorithm).unwrap();
let test_sign_data = common::generate_random_data(32);
let signature = test_key.sign(common::data_to_buffer(&test_sign_data).unwrap()).unwrap();
assert_eq!(test_key.get_key_data(), test_key_data);
assert_eq!(signature, test_output_data);
}
#[test]
fn sign_mock_provider_input_too_large() {
let key_algorithm = AsymmetricKeyAlgorithm::EcdsaSha256P256;
let test_output_data = common::generate_random_data(32);
let test_key_data = common::generate_random_data(32);
let mock_provider = Box::new(MockProvider::new());
mock_provider.set_result(&test_key_data);
mock_provider.set_key_result(Ok(test_output_data.clone()));
let test_key =
KmsAsymmetricKey::new(&*mock_provider, TEST_KEY_NAME, key_algorithm).unwrap();
// Input is 1 byte larger than the maximum data size.
let test_sign_data = common::generate_random_data(MAX_DATA_SIZE + 1);
let result = test_key.sign(common::data_to_buffer(&test_sign_data).unwrap());
if Err(Error::InputTooLarge) == result {
assert!(true);
} else {
assert!(false);
}
}
#[test]
fn sign_mock_provider_key_deleted() {
let key_algorithm = AsymmetricKeyAlgorithm::EcdsaSha256P256;
let test_key_data = common::generate_random_data(32);
let mock_provider = Box::new(MockProvider::new());
mock_provider.set_result(&test_key_data);
// Make sure the delete operation on the key succeed.
mock_provider.set_key_result(Ok(Vec::new()));
let mut test_key =
KmsAsymmetricKey::new(&*mock_provider, TEST_KEY_NAME, key_algorithm).unwrap();
test_key.delete().unwrap();
let test_sign_data = common::generate_random_data(32);
let result = test_key.sign(common::data_to_buffer(&test_sign_data).unwrap());
if Err(Error::KeyNotFound) == result {
assert!(true);
} else {
assert!(false);
}
}
#[test]
fn get_get_public_key_mock_provider() {
for algorithm in ASYMMETRIC_KEY_ALGORITHMS.iter() {
get_public_key_mock_provider(*algorithm);
}
}
fn get_public_key_mock_provider(key_algorithm: AsymmetricKeyAlgorithm) {
let test_key_data = common::generate_random_data(32);
let test_output_data = common::generate_random_data(32);
let mock_provider = Box::new(MockProvider::new());
mock_provider.set_result(&test_key_data);
mock_provider.set_key_result(Ok(test_output_data.clone()));
let test_key =
KmsAsymmetricKey::new(&*mock_provider, TEST_KEY_NAME, key_algorithm).unwrap();
let public_key = test_key.get_der_public_key().unwrap();
// The key data should be the output data from generate_key call.
assert_eq!(test_key.get_key_data(), test_key_data);
assert_eq!(public_key, test_output_data);
}
}