Skip to content

Commit

Permalink
Implement CanDoCrypto trait and use it for PKCS11 and TPM providers
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Antonov <Anton.Antonov@arm.com>
  • Loading branch information
anta5010 committed Oct 26, 2021
1 parent 94f538c commit 07b89e0
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 96 deletions.
65 changes: 37 additions & 28 deletions e2e_tests/tests/all_providers/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use parsec_client::core::interface::requests::{
AuthType, Opcode, ProviderId, ResponseStatus, Result,
};
use std::collections::HashSet;
use std::iter::FromIterator;

#[test]
fn list_providers() {
Expand Down Expand Up @@ -68,39 +69,47 @@ fn list_authenticators() {
#[test]
fn list_opcodes() {
let mut client = TestClient::new();
let mut crypto_providers_tpm = HashSet::new();
let mut core_provider_opcodes = HashSet::new();
let core_opcodes = vec![
Opcode::Ping,
Opcode::ListProviders,
Opcode::ListAuthenticators,
Opcode::ListOpcodes,
Opcode::ListKeys,
];
let common_opcodes = vec![
Opcode::PsaGenerateKey,
Opcode::PsaDestroyKey,
Opcode::PsaSignHash,
Opcode::PsaVerifyHash,
Opcode::PsaImportKey,
Opcode::PsaExportPublicKey,
Opcode::PsaAsymmetricDecrypt,
Opcode::PsaAsymmetricEncrypt,
];
let mut mbed_crypto_opcodes = vec![
Opcode::PsaHashCompute,
Opcode::PsaHashCompare,
Opcode::PsaRawKeyAgreement,
Opcode::PsaAeadEncrypt,
Opcode::PsaAeadDecrypt,
Opcode::PsaExportKey,
Opcode::PsaGenerateRandom,
];
mbed_crypto_opcodes.extend(common_opcodes.clone());

let core_provider_opcodes = HashSet::from_iter(core_opcodes);

let mut crypto_providers_cal = HashSet::new();
// Not that much to be tested with test-interface
let _ = crypto_providers_cal.insert(Opcode::PsaGenerateRandom);

let _ = crypto_providers_tpm.insert(Opcode::PsaGenerateKey);
let _ = crypto_providers_tpm.insert(Opcode::PsaDestroyKey);
let _ = crypto_providers_tpm.insert(Opcode::PsaSignHash);
let _ = crypto_providers_tpm.insert(Opcode::PsaVerifyHash);
let _ = crypto_providers_tpm.insert(Opcode::PsaImportKey);
let _ = crypto_providers_tpm.insert(Opcode::PsaExportPublicKey);
let _ = crypto_providers_tpm.insert(Opcode::PsaAsymmetricDecrypt);
let _ = crypto_providers_tpm.insert(Opcode::PsaAsymmetricEncrypt);
let mut crypto_providers_tpm = HashSet::from_iter(common_opcodes.clone());
let _ = crypto_providers_tpm.insert(Opcode::CanDoCrypto);

let mut crypto_providers_hsm = crypto_providers_tpm.clone();
let mut crypto_providers_hsm = HashSet::from_iter(common_opcodes.clone());
let _ = crypto_providers_hsm.insert(Opcode::CanDoCrypto);

let mut crypto_providers_mbed_crypto = crypto_providers_tpm.clone();
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaHashCompute);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaHashCompare);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaRawKeyAgreement);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaAeadEncrypt);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaAeadDecrypt);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaExportKey);
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaGenerateRandom);

let _ = core_provider_opcodes.insert(Opcode::Ping);
let _ = core_provider_opcodes.insert(Opcode::ListProviders);
let _ = core_provider_opcodes.insert(Opcode::ListAuthenticators);
let _ = core_provider_opcodes.insert(Opcode::ListOpcodes);
let _ = core_provider_opcodes.insert(Opcode::ListKeys);

// Not that much to be tested with test-interface
let _ = crypto_providers_cal.insert(Opcode::PsaGenerateRandom);
let crypto_providers_mbed_crypto = HashSet::from_iter(mbed_crypto_opcodes);

assert_eq!(
client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ fn use_check() {

let status = client.can_do_crypto(CheckType::Use, attributes);

assert_eq!(Err(ResponseStatus::PsaErrorNotPermitted), status)
assert_eq!(Err(ResponseStatus::PsaErrorNotSupported), status)
}

#[test]
Expand Down
113 changes: 113 additions & 0 deletions src/providers/crypto_capability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2019 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! Crypto capabilities trait for Parsec providers
//!
//! The trait provides generic crypto compatibility checking methods
//! https://parallaxsecond.github.io/parsec-book/parsec_client/operations/can_do_crypto.html
//! https://parallaxsecond.github.io/parsec-book/parsec_client/operations/service_api_coverage.html
use crate::authenticators::ApplicationName;
use log::{info, trace};
use parsec_interface::operations::can_do_crypto;
use parsec_interface::operations::can_do_crypto::{CheckType, Operation};
use parsec_interface::operations::psa_algorithm::Algorithm;
use parsec_interface::operations::psa_key_attributes::Attributes;
use parsec_interface::requests::ResponseStatus::PsaErrorNotSupported;
use parsec_interface::requests::Result;

/// Provider interface for checking crypto capabilities
///
/// Definition of the interface that a provider must expand to
/// be correctly checked for crypto compatibility.
pub trait CanDoCrypto {
/// Check if the crypto operation is supported by provider.
/// This method is called by Provide trait and doesn't need to be changed.
fn can_do_crypto_main(
&self,
app_name: ApplicationName,
op: Operation,
) -> Result<can_do_crypto::Result> {
trace!("can_do_crypto_main in CanDoCrypto trait");
let _ = self.can_do_crypto_internal(app_name, op)?;

match op.check_type {
CheckType::Generate => self.generate_check(op.attributes),
CheckType::Import => self.import_check(op.attributes),
CheckType::Use => self.use_check(op.attributes),
CheckType::Derive => self.derive_check(op.attributes),
}
}

/// Common checks if an existing key of the key type that defined in the attributes
/// and the same length can be used to perform the algorithm in policy.key_algorithm
fn use_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("Use check in CanDoCrypto trait");
if attributes.policy.permitted_algorithms == Algorithm::None {
info!("No algorithm defined for the operation");
return Err(PsaErrorNotSupported);
}
if !(attributes.policy.usage_flags.decrypt()
|| attributes.policy.usage_flags.encrypt()
|| attributes.policy.usage_flags.sign_hash()
|| attributes.policy.usage_flags.sign_message()
|| attributes.policy.usage_flags.verify_hash()
|| attributes.policy.usage_flags.verify_message())
{
info!("No usage flags defined for the operation");
return Err(PsaErrorNotSupported);
}
attributes
.compatible_with_alg(attributes.policy.permitted_algorithms)
.map_err(|_| PsaErrorNotSupported)?;

self.use_check_internal(attributes)
}

/// Common checks if a key with the attributes can be generated
fn generate_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("Generate check in CanDoCrypto trait");
let _ = self.generate_check_internal(attributes)?;

if attributes.policy.permitted_algorithms != Algorithm::None {
return self.use_check(attributes);
}
Ok(can_do_crypto::Result)
}

/// Common checks if a key with the attributes can be imported.
fn import_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("Import check in CanDoCrypto trait");
let _ = self.import_check_internal(attributes)?;

if attributes.policy.permitted_algorithms != Algorithm::None {
return self.use_check(attributes);
}
Ok(can_do_crypto::Result)
}

/// Checks if a key with the attributes can be derived.
fn derive_check(&self, _attributes: Attributes) -> Result<can_do_crypto::Result> {
info!("Derive check type is not supported");
Err(PsaErrorNotSupported)
}

/// Provider specific heck if the crypto operation is supported by provider.
/// This method should be re-implemented by providers.
fn can_do_crypto_internal(
&self,
_app_name: ApplicationName,
_op: Operation,
) -> Result<can_do_crypto::Result>;

/// Provider specific Use check.
/// This method should be re-implemented by providers.
fn use_check_internal(&self, _attributes: Attributes) -> Result<can_do_crypto::Result> ;

/// Provider specific Generate check.
/// This method should be re-implemented by providers.
fn generate_check_internal(&self, attributes: Attributes) -> Result<can_do_crypto::Result> ;

/// Provider specific Import check.
/// This method should be re-implemented by providers.
fn import_check_internal(&self, attributes: Attributes) -> Result<can_do_crypto::Result> ;
}
6 changes: 4 additions & 2 deletions src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use std::collections::HashSet;

pub mod core;

pub mod crypto_capability;

#[cfg(feature = "pkcs11-provider")]
//TODO: To remove when #301 is merged
#[allow(clippy::all)]
Expand Down Expand Up @@ -297,13 +299,13 @@ pub trait Provide {
Err(ResponseStatus::PsaErrorNotSupported)
}

///Get the filtered list of supported algorithms.
///Check if the crypto operation is supported by provider.
fn can_do_crypto(
&self,
_app_name: ApplicationName,
_op: can_do_crypto::Operation,
) -> Result<can_do_crypto::Result> {
trace!("can_do_crypto ingress");
trace!("can_do_crypto main ingress");
Err(ResponseStatus::PsaErrorNotSupported)
}
}
83 changes: 24 additions & 59 deletions src/providers/pkcs11/capability_discovery.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
#![allow(unused, trivial_numeric_casts)]
#![allow(trivial_numeric_casts)]
use super::{utils, Provider};
use crate::authenticators::ApplicationName;
use crate::providers::crypto_capability::CanDoCrypto;
use crate::providers::pkcs11::to_response_status;
use cryptoki::types::mechanism::Mechanism;
use cryptoki::types::mechanism::MechanismInfo;
use cryptoki::types::mechanism::MechanismType;
use cryptoki::types::mechanism::{Mechanism, MechanismInfo, MechanismType};
use cryptoki::types::Ulong;
use log::info;
use log::{info, trace};
use parsec_interface::operations::can_do_crypto;
use parsec_interface::operations::can_do_crypto::CheckType;
use parsec_interface::operations::psa_algorithm::Algorithm;
use parsec_interface::operations::psa_key_attributes::Attributes;
use parsec_interface::operations::psa_key_attributes::EccFamily;
use parsec_interface::operations::psa_key_attributes::Type;
use parsec_interface::requests::ResponseStatus::{InvalidEncoding, PsaErrorNotSupported};
use parsec_interface::operations::psa_key_attributes::{Attributes, Type};
use parsec_interface::requests::ResponseStatus::PsaErrorNotSupported;
use parsec_interface::requests::Result;
use std::convert::TryFrom;
use std::ops::Deref;

impl Provider {
pub(super) fn can_do_crypto_internal(
impl CanDoCrypto for Provider {
fn can_do_crypto_internal(
&self,
_app_name: ApplicationName,
op: can_do_crypto::Operation,
) -> Result<can_do_crypto::Result> {
trace!("can_do_crypto_internal for PKCS11 provider");
let attributes = op.attributes;
match attributes.key_type {
Type::RsaKeyPair | Type::RsaPublicKey => Ok(can_do_crypto::Result {}),
Type::EccKeyPair { curve_family } | Type::EccPublicKey { curve_family } => {
let _ = utils::ec_params(curve_family, attributes.bits).map_err(|_| {
info!(
Expand All @@ -34,37 +30,17 @@ impl Provider {
);
PsaErrorNotSupported
})?;
Ok(can_do_crypto::Result)
}
Type::RsaKeyPair | Type::RsaPublicKey => (),
_ => {
info!("Unsupported key type {:?}", attributes.key_type);
return Err(PsaErrorNotSupported);
Err(PsaErrorNotSupported)
}
}
match op.check_type {
CheckType::Generate => return self.generate_check(attributes),
CheckType::Import => return self.import_check(attributes),
CheckType::Use => return self.use_check(attributes),
CheckType::Derive => return Provider::derive_check(attributes),
};
}

fn use_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
if attributes.policy.permitted_algorithms == Algorithm::None {
info!("No algorithm defined for the operation");
return Err(PsaErrorNotSupported);
}
if !(attributes.policy.usage_flags.decrypt()
|| attributes.policy.usage_flags.encrypt()
|| attributes.policy.usage_flags.sign_hash()
|| attributes.policy.usage_flags.sign_message()
|| attributes.policy.usage_flags.verify_hash()
|| attributes.policy.usage_flags.verify_message())
{
info!("No usage flags defined for the operation");
return Err(PsaErrorNotSupported);
}
attributes.compatible_with_alg(attributes.policy.permitted_algorithms)?;
fn use_check_internal(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("use_check_internal for PKCS11 provider");

let supported_mechanisms: Vec<MechanismType> = self
.backend
Expand Down Expand Up @@ -102,39 +78,28 @@ impl Provider {
return Err(PsaErrorNotSupported);
}
}
return Ok(can_do_crypto::Result {});
}

fn derive_check(attributes: Attributes) -> Result<can_do_crypto::Result> {
info!("Derive check type is not supported");
return Err(PsaErrorNotSupported);
Ok(can_do_crypto::Result)
}

fn generate_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
fn generate_check_internal(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("generate_check_internal for PKCS11 provider");
match attributes.key_type {
Type::RsaKeyPair | Type::EccKeyPair { .. } => (),
Type::RsaKeyPair | Type::EccKeyPair { .. } => Ok(can_do_crypto::Result),
_ => {
info!("Unsupported key type {:?}", attributes.key_type);
return Err(PsaErrorNotSupported);
Err(PsaErrorNotSupported)
}
}
if attributes.policy.permitted_algorithms != Algorithm::None {
return self.use_check(attributes);
}
return Ok(can_do_crypto::Result);
}

fn import_check(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
fn import_check_internal(&self, attributes: Attributes) -> Result<can_do_crypto::Result> {
trace!("import_check_internal for PKCS11 provider");
match attributes.key_type {
Type::RsaPublicKey | Type::EccPublicKey { .. } => (),
Type::RsaPublicKey | Type::EccPublicKey { .. } => Ok(can_do_crypto::Result),
_ => {
info!("Unsupported key type {:?}", attributes.key_type);
return Err(PsaErrorNotSupported);
Err(PsaErrorNotSupported)
}
}
if attributes.policy.permitted_algorithms != Algorithm::None {
return self.use_check(attributes);
}
return Ok(can_do_crypto::Result);
}
}
}
7 changes: 5 additions & 2 deletions src/providers/pkcs11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use super::Provide;
use crate::authenticators::ApplicationName;
use crate::key_info_managers::{KeyInfoManagerClient, KeyTriple};
use crate::providers::crypto_capability::CanDoCrypto;
use cryptoki::types::locking::CInitializeArgs;
use cryptoki::types::session::{Session, UserType};
use cryptoki::types::slot_token::Slot;
Expand Down Expand Up @@ -340,13 +341,15 @@ impl Provide for Provider {
self.psa_asymmetric_decrypt_internal(app_name, op)
}

/// Check if the crypto operation is supported by PKCS11 provider
/// by using CanDoCrypto trait.
fn can_do_crypto(
&self,
app_name: ApplicationName,
op: can_do_crypto::Operation,
) -> Result<can_do_crypto::Result> {
trace!("can_do_crypto ingress");
self.can_do_crypto_internal(app_name, op)
trace!("can_do_crypto PKCS11 ingress");
self.can_do_crypto_main(app_name, op)
}
}

Expand Down
Loading

0 comments on commit 07b89e0

Please sign in to comment.