blob: 14fb3cf2830ee460f5267e4337d99a69bc41e568 [file] [log] [blame]
// Copyright 2018 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.
#![allow(dead_code)]
use rand::Rng;
use anyhow::{format_err, Context as _};
use fidl::{self, endpoints::ServerEnd};
use fidl_fuchsia_kms::{
AsymmetricKeyAlgorithm, AsymmetricPrivateKeyProxy, Error, KeyManagerMarker, KeyManagerProxy,
KeyOrigin, KeyProvider,
};
use fidl_fuchsia_mem::Buffer;
use fuchsia_async as fasync;
use fuchsia_component::client::connect_to_service;
use fuchsia_syslog as syslog;
use fuchsia_zircon as zx;
use log::info;
use serde::{Deserialize, Serialize};
use serde_json;
use std::fs;
use mundane::hash::*;
use mundane::public::ec::ecdsa::EcdsaHash;
use mundane::public::ec::*;
use mundane::public::*;
static TEST_KEY_NAME: &str = "test-key";
static CONFIG_PATH: &str = "/config/data/crypto_provider_config.json";
fn map_err_to_string<T>(result: Result<Result<T, Error>, fidl::Error>) -> Result<T, String> {
match result {
Ok(Ok(a)) => Ok(a),
Ok(Err(err)) => Err(format!("{:?}", err)),
Err(err) => Err(format!("{:?}", err)),
}
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test() -> Result<(), anyhow::Error> {
syslog::init_with_tags(&["kms_test_client"]).expect("syslog init should not fail");
test_asymmetric_key(AsymmetricKeyAlgorithm::EcdsaSha256P256).await?;
test_asymmetric_key(AsymmetricKeyAlgorithm::EcdsaSha512P384).await?;
test_asymmetric_key(AsymmetricKeyAlgorithm::EcdsaSha512P521).await?;
test_seal_unseal_data().await?;
Ok(())
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Config<'a> {
pub crypto_provider: &'a str,
}
fn get_provider_from_config() -> Result<KeyProvider, anyhow::Error> {
let json = fs::read_to_string(CONFIG_PATH)?;
let config: Config<'_> = serde_json::from_str(&json)?;
match config.crypto_provider {
"OpteeProvider" => Ok(KeyProvider::OpteeProvider),
"SoftwareProvider" => Ok(KeyProvider::SoftwareProvider),
"SoftwareAsymmetricOnlyProvider" => Ok(KeyProvider::SoftwareAsymmetricOnlyProvider),
_ => Err(format_err!("Unsupported provider {:?}", config.crypto_provider)),
}
}
async fn test_asymmetric_key(algorithm: AsymmetricKeyAlgorithm) -> Result<(), anyhow::Error> {
info!("Begin asymmetric key tests for algorithm: {:?}", algorithm);
let key_manager = connect_to_service::<KeyManagerMarker>()
.context("Failed to connect to key manager service")?;
let public_key = {
// Generate a new key.
let asymmetric_key_proxy =
generate_asymmetric_key(&key_manager, TEST_KEY_NAME, algorithm).await?;
// Export public key.
let public_key = test_export_public_key(&asymmetric_key_proxy).await?;
// Get key property.
let key_algorithm = get_asymmetric_key_algorithm(&asymmetric_key_proxy).await?;
assert_eq!(key_algorithm, algorithm, "Key algorithm mismatch!");
let key_origin = get_asymmetric_key_origin(&asymmetric_key_proxy).await?;
assert_eq!(key_origin, KeyOrigin::Generated, "Key origin mismatch!");
let provider = get_asymmetric_key_provider(&asymmetric_key_proxy).await?;
assert_eq!(
provider,
get_provider_from_config().unwrap_or(KeyProvider::SoftwareProvider),
"Using the wrong crypto provider."
);
public_key
};
// Compare the exported public key.
let asymmetric_key_proxy = get_asymmetric_key(&key_manager, TEST_KEY_NAME).await?;
let public_key_compare = test_export_public_key(&asymmetric_key_proxy).await?;
assert_eq!(public_key, public_key_compare, "Public key for the same key mismatch.");
// Test signing using the generated key.
test_sign_verify_data(algorithm, &key_manager).await?;
{
// Test generating a key with the same name.
test_generate_asymmetric_key_exists(&key_manager, TEST_KEY_NAME, algorithm).await?;
}
{
// Read the generated key.
let asymmetric_key_proxy = get_asymmetric_key(&key_manager, TEST_KEY_NAME).await?;
// Test deleting the generated key.
test_delete_key(&key_manager, TEST_KEY_NAME).await?;
// Verify that the key is deleted.
check_key_not_exist(&key_manager, TEST_KEY_NAME).await?;
// Verify that user would get key_not_found if trying to use the deleted key.
test_sign_key_not_exists(&asymmetric_key_proxy).await?;
// Verify deleting a deleted key would fail.
test_delete_key_not_exist(&key_manager, TEST_KEY_NAME).await?;
}
{
// Generate a new key_manager to simulate another user.
let key_manager_2 = connect_to_service::<KeyManagerMarker>()
.context("Failed to connect to key manager service")?;
// The first user create a new key.
let asymmetric_key_proxy =
generate_asymmetric_key(&key_manager, TEST_KEY_NAME, algorithm).await?;
// The second user delete the same key.
test_delete_key(&key_manager_2, TEST_KEY_NAME).await?;
// The first user should get key_not_found if trying to get the deleted key.
check_key_not_exist(&key_manager, TEST_KEY_NAME).await?;
// The first user should get key_not_found if trying to use the deleted key.
test_sign_key_not_exists(&asymmetric_key_proxy).await?;
}
{
// Test importing private key.
let (private_key_data, public_key_data) = match algorithm {
AsymmetricKeyAlgorithm::EcdsaSha256P256 => {
let test_key = EcPrivKey::<P256>::generate()?;
(test_key.marshal_to_der(), test_key.public().marshal_to_der())
}
AsymmetricKeyAlgorithm::EcdsaSha512P384 => {
let test_key = EcPrivKey::<P384>::generate()?;
(test_key.marshal_to_der(), test_key.public().marshal_to_der())
}
AsymmetricKeyAlgorithm::EcdsaSha512P521 => {
let test_key = EcPrivKey::<P521>::generate()?;
(test_key.marshal_to_der(), test_key.public().marshal_to_der())
}
_ => panic!("not implemented!"),
};
let asymmetric_key_proxy =
import_asymmetric_key(&key_manager, private_key_data, TEST_KEY_NAME, algorithm).await?;
// Export public key.
let public_key = test_export_public_key(&asymmetric_key_proxy).await?;
assert_eq!(public_key, public_key_data, "Public key mismatch!");
// Get key property.
let key_algorithm = get_asymmetric_key_algorithm(&asymmetric_key_proxy).await?;
assert_eq!(key_algorithm, algorithm, "Key algorithm in key property mismatch!");
let key_origin = get_asymmetric_key_origin(&asymmetric_key_proxy).await?;
assert_eq!(key_origin, KeyOrigin::Imported, "Key origin mismatch!");
// Test signing using the imported key.
test_sign_verify_data(algorithm, &key_manager).await?;
// Test deleting the imported key.
test_delete_key(&key_manager, TEST_KEY_NAME).await?;
}
info!("All asymmetric key tests for algorithm: {:?} passed!", algorithm);
Ok(())
}
async fn test_sign_verify_data(
algorithm: AsymmetricKeyAlgorithm,
key_manager: &KeyManagerProxy,
) -> Result<(), anyhow::Error> {
// Read the key.
let asymmetric_key_proxy = get_asymmetric_key(&key_manager, TEST_KEY_NAME).await?;
let public_key = test_export_public_key(&asymmetric_key_proxy).await?;
// Sign test data with the key again.
let test_data = generate_test_data();
let signature = test_sign(&asymmetric_key_proxy, &test_data).await?;
// Verify signature.
verify_signature(algorithm, &signature, &public_key, &test_data)?;
Ok(())
}
async fn test_seal_unseal_data() -> Result<(), anyhow::Error> {
info!("Begin sealing and unsealing data test");
let key_manager = connect_to_service::<KeyManagerMarker>()
.context("Failed to connect to key manager service")?;
let test_data = generate_test_data();
let vmo = zx::Vmo::create(test_data.len() as u64)?;
vmo.write(&test_data, 0)?;
let mut buffer = Buffer { vmo, size: test_data.len() as u64 };
let result = key_manager.seal_data(&mut buffer).await;
let result_buffer =
map_err_to_string(result).map_err(|err| format_err!("Error sealing data: {:?}", err))?;
let mut result_data = vec![0; result_buffer.size as usize];
result_buffer.vmo.read(&mut result_data, 0).unwrap();
let vmo = zx::Vmo::create(result_data.len() as u64)?;
vmo.write(&result_data, 0)?;
let mut buffer = Buffer { vmo, size: result_data.len() as u64 };
let result = key_manager.unseal_data(&mut buffer).await;
let result_buffer =
map_err_to_string(result).map_err(|err| format_err!("Error unsealing data: {:?}", err))?;
let mut result_data = vec![0; result_buffer.size as usize];
result_buffer.vmo.read(&mut result_data, 0)?;
assert_eq!(&test_data, &result_data, "Unsealing after sealing gets different data!");
info!("Sealing and unsealing data tests passed!");
Ok(())
}
async fn generate_asymmetric_key<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
key_algorithm: AsymmetricKeyAlgorithm,
) -> Result<AsymmetricPrivateKeyProxy, anyhow::Error> {
let (server_chan, client_chan) = zx::Channel::create()?;
let result = key_manager
.generate_asymmetric_key_with_algorithm(
key_name,
key_algorithm,
ServerEnd::new(server_chan),
)
.await;
map_err_to_string(result)
.map_err(|err| format_err!("Error generating asymmetric key: {:?}", err))?;
info!("Asymmetric private key successfully generated.");
let client_async = fasync::Channel::from_channel(client_chan).unwrap();
let asymmetric_key_proxy = AsymmetricPrivateKeyProxy::new(client_async);
Ok(asymmetric_key_proxy)
}
async fn test_generate_asymmetric_key_exists<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
key_algorithm: AsymmetricKeyAlgorithm,
) -> Result<(), anyhow::Error> {
let (server_chan, _) = zx::Channel::create()?;
let result = key_manager
.generate_asymmetric_key_with_algorithm(
key_name,
key_algorithm,
ServerEnd::new(server_chan),
)
.await
.map_err(|err| format_err!("Error generating asymmetric key: {:?}", err))?;
match result {
Err(Error::KeyAlreadyExists) => {
info!("Verify that the key already exists.");
Ok(())
}
Ok(_) => Err(format_err!("Generating a key with the same name must not be allowed!")),
Err(err) => Err(format_err!("Error generating asymmetric key: {:?}", err)),
}
}
async fn get_asymmetric_key<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
) -> Result<AsymmetricPrivateKeyProxy, anyhow::Error> {
let (server_chan, client_chan) = zx::Channel::create()?;
let result =
key_manager.get_asymmetric_private_key(key_name, ServerEnd::new(server_chan)).await;
map_err_to_string(result)
.map_err(|err| format_err!("Error getting asymmetric key: {:?}", err))?;
info!("Asymmetric private key successfully read.");
let client_async = fasync::Channel::from_channel(client_chan).unwrap();
let asymmetric_key_proxy = AsymmetricPrivateKeyProxy::new(client_async);
Ok(asymmetric_key_proxy)
}
async fn test_sign_key_not_exists(key: &AsymmetricPrivateKeyProxy) -> Result<(), anyhow::Error> {
let test_data = generate_test_data();
let vmo = zx::Vmo::create(test_data.len() as u64)?;
vmo.write(&test_data, 0)?;
let result = key
.sign(&mut Buffer { vmo, size: test_data.len() as u64 })
.await
.map_err(|err| format_err!("Error generating signature: {:?}", err))?;
match result {
Err(Error::KeyNotFound) => {
info!("Verify that the key does not exist.");
Ok(())
}
Ok(_) => Err(format_err!("Key not deleted.")),
Err(err) => Err(format_err!("Error generating signature: {:?}", err)),
}
}
async fn check_key_not_exist<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
) -> Result<(), anyhow::Error> {
let (server_chan, _client_chan) = zx::Channel::create()?;
let result = key_manager
.get_asymmetric_private_key(key_name, ServerEnd::new(server_chan))
.await
.map_err(|err| format_err!("Error getting asymmetric key: {:?}", err))?;
match result {
Err(Error::KeyNotFound) => {
info!("Verify that the key does not exist.");
Ok(())
}
Ok(()) => Err(format_err!("Key not deleted.")),
Err(err) => Err(format_err!("Error getting asymmetric key: {:?}", err)),
}
}
async fn test_sign<'a>(
key: &'a AsymmetricPrivateKeyProxy,
test_data: &'a Vec<u8>,
) -> Result<Vec<u8>, anyhow::Error> {
let vmo = zx::Vmo::create(test_data.len() as u64)?;
vmo.write(test_data, 0)?;
let result = key.sign(&mut Buffer { vmo, size: test_data.len() as u64 }).await;
let signature = map_err_to_string(result)
.map_err(|err| format_err!("Error generating signature: {:?}", err))?;
let signature_data = signature.bytes;
info!("Signature successfully generated with size: {}", signature_data.len());
Ok(signature_data)
}
async fn test_export_public_key(key: &AsymmetricPrivateKeyProxy) -> Result<Vec<u8>, anyhow::Error> {
let result = key.get_public_key().await;
let public_key = map_err_to_string(result)
.map_err(|err| format_err!("Error exporting public key: {:?}", err))?;
let public_key_data = public_key.bytes;
info!("Public key successfully exported with size: {}", public_key_data.len());
Ok(public_key_data)
}
async fn test_delete_key<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
) -> Result<(), anyhow::Error> {
let result = key_manager.delete_key(key_name).await;
map_err_to_string(result).map_err(|err| format_err!("Error deleting key: {:?}", err))?;
info!("Key successfully deleted.");
Ok(())
}
async fn test_delete_key_not_exist<'a>(
key_manager: &'a KeyManagerProxy,
key_name: &'static str,
) -> Result<(), anyhow::Error> {
let result = key_manager
.delete_key(key_name)
.await
.map_err(|err| format_err!("Error deleting key: {:?}", err))?;
match result {
Err(Error::KeyNotFound) => {
info!("Verify a key that does not exist could not be deleted.");
Ok(())
}
Ok(()) => Err(format_err!(
"KEY_NOT_FOUND must be returned if the key to be deleted is not found."
)),
Err(err) => Err(format_err!("Error deleting key: {:?}", err)),
}
}
async fn get_asymmetric_key_algorithm(
key: &AsymmetricPrivateKeyProxy,
) -> Result<AsymmetricKeyAlgorithm, anyhow::Error> {
let result = key.get_key_algorithm().await;
map_err_to_string(result).map_err(|err| format_err!("Error exporting public key: {:?}", err))
}
async fn get_asymmetric_key_origin(
key: &AsymmetricPrivateKeyProxy,
) -> Result<KeyOrigin, anyhow::Error> {
let result = key.get_key_origin().await;
map_err_to_string(result).map_err(|err| format_err!("Error getting key origin: {:?}", err))
}
async fn get_asymmetric_key_provider(
key: &AsymmetricPrivateKeyProxy,
) -> Result<KeyProvider, anyhow::Error> {
let result = key.get_key_provider().await;
map_err_to_string(result)
.map_err(|err| format_err!("Error getting crypto provider name: {:?}", err))
}
async fn import_asymmetric_key<'a>(
key_manager: &'a KeyManagerProxy,
private_key_data: Vec<u8>,
key_name: &'static str,
key_algorithm: AsymmetricKeyAlgorithm,
) -> Result<AsymmetricPrivateKeyProxy, anyhow::Error> {
let (server_chan, client_chan) = zx::Channel::create()?;
let result = key_manager
.import_asymmetric_private_key(
&mut private_key_data.into_iter(),
key_name,
key_algorithm,
ServerEnd::new(server_chan),
)
.await;
map_err_to_string(result)
.map_err(|err| format_err!("Error importing asymmetric key: {:?}", err))?;
info!("Asymmetric private key successfully imported.");
let client_async = fasync::Channel::from_channel(client_chan).unwrap();
let asymmetric_key_proxy = AsymmetricPrivateKeyProxy::new(client_async);
Ok(asymmetric_key_proxy)
}
fn generate_test_data() -> Vec<u8> {
let mut test_data: Vec<u8> = vec![0; 512];
let mut rng = rand::thread_rng();
for i in 0..test_data.len() {
test_data[i] = rng.gen();
}
test_data
}
fn verify_signature<'a>(
algorithm: AsymmetricKeyAlgorithm,
signature: &'a Vec<u8>,
public_key: &'a Vec<u8>,
test_data: &'a Vec<u8>,
) -> Result<(), anyhow::Error> {
match algorithm {
AsymmetricKeyAlgorithm::EcdsaSha256P256 => {
verify_sig::<P256, Sha256>(&signature, &public_key, &test_data)?;
}
AsymmetricKeyAlgorithm::EcdsaSha512P384 => {
verify_sig::<P384, Sha512>(&signature, &public_key, &test_data)?;
}
AsymmetricKeyAlgorithm::EcdsaSha512P521 => {
verify_sig::<P521, Sha512>(&signature, &public_key, &test_data)?;
}
_ => (),
}
Ok(())
}
fn verify_sig<'a, C: PCurve, H: Hasher + EcdsaHash<C>>(
signature: &'a Vec<u8>,
public_key: &'a Vec<u8>,
test_data: &'a Vec<u8>,
) -> Result<(), anyhow::Error> {
let ec_key = EcPubKey::<C>::parse_from_der(public_key)
.map_err(|_| format_err!("Failed to parse public key!"))?;
let result = ecdsa::EcdsaSignature::<C, H>::from_bytes(signature).is_valid(&ec_key, test_data);
if !result {
Err(format_err!("Failed to verify signature."))
} else {
info!("Signature verified successfully with the exported public key.");
Ok(())
}
}