Skip to content

Commit

Permalink
Add asymmetric encryption to TS provider
Browse files Browse the repository at this point in the history
Adding support for asymmetric encryption to the Trusted Services
provider. However, the version of the TS implementation used for testing
has a bug which prevents us from properly testing using some of the
algorithms.

Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
  • Loading branch information
ionut-arm committed Feb 1, 2022
1 parent 4a7b313 commit ce800cb
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 18 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ jobs:
steps:
- uses: actions/checkout@v2
# Use the following step when updating the `parsec-service-test-all` image
# - name: Build the container
# run: pushd e2e_tests/docker_image && docker build -t parsec-service-test-all -f parsec-service-test-all.Dockerfile . && popd
- name: Build the container
run: pushd e2e_tests/docker_image && docker build -t parsec-service-test-all -f parsec-service-test-all.Dockerfile . && popd
- name: Run the container to execute the test script
run:
docker run -v $(pwd):/tmp/parsec -w /tmp/parsec ghcr.io/parallaxsecond/parsec-service-test-all /tmp/parsec/ci.sh trusted-service
# run:
# docker run -v $(pwd):/tmp/parsec -w /tmp/parsec ghcr.io/parallaxsecond/parsec-service-test-all /tmp/parsec/ci.sh trusted-service
# When running the container built on the CI
# run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec -t parsec-service-test-all /tmp/parsec/ci.sh trusted-service
run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec -t parsec-service-test-all /tmp/parsec/ci.sh trusted-service

cryptoauthlib-provider:
name: Integration tests using CryptoAuthentication Library provider
Expand Down
12 changes: 6 additions & 6 deletions e2e_tests/docker_image/parsec-service-test-all.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ RUN rm -rf tpm2-tss
# Download and install TPM 2.0 Tools verison 4.1.1
RUN git clone https://github.com/tpm2-software/tpm2-tools.git --branch 4.1.1
RUN cd tpm2-tools \
&& ./bootstrap \
&& ./configure --prefix=/usr \
&& make -j$(nproc) \
&& make install
&& ./bootstrap \
&& ./configure --prefix=/usr \
&& make -j$(nproc) \
&& make install
RUN rm -rf tpm2-tools

# Download and install software TPM
Expand All @@ -48,7 +48,7 @@ RUN mkdir -p $ibmtpm_name \
WORKDIR $ibmtpm_name/src
RUN sed -i 's/-DTPM_NUVOTON/-DTPM_NUVOTON $(CFLAGS)/' makefile
RUN CFLAGS="-DNV_MEMORY_SIZE=32768 -DMIN_EVICT_OBJECTS=7" make -j$(nproc) \
&& cp tpm_server /usr/local/bin
&& cp tpm_server /usr/local/bin
RUN rm -rf $ibmtpm_name/src $ibmtpm_name

# Download and install SoftHSMv2
Expand Down Expand Up @@ -90,7 +90,7 @@ RUN git config --global user.email "some@email.com"
RUN git config --global user.name "Parsec Team"
RUN git clone https://git.trustedfirmware.org/TS/trusted-services.git --branch integration \
&& cd trusted-services \
&& git reset --hard c1cf9120e4ab0b359a27176b079769b9a7e6bb87
&& git reset --hard d5cc32b531e41cf19f37bf3c9bf299ebfcd25cb0
# Install correct python dependencies
RUN pip3 install -r trusted-services/requirements.txt
RUN cd trusted-services/deployments/libts/linux-pc/ \
Expand Down
70 changes: 70 additions & 0 deletions src/providers/trusted_service/asym_encryption.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::Provider;
use crate::authenticators::ApplicationIdentity;
use crate::key_info_managers::KeyIdentity;
use log::error;
use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt};
use parsec_interface::requests::Result;

impl Provider {
pub(super) fn psa_asymmetric_encrypt_internal(
&self,
application_identity: &ApplicationIdentity,
op: psa_asymmetric_encrypt::Operation,
) -> Result<psa_asymmetric_encrypt::Result> {
let key_identity = KeyIdentity::new(
application_identity.clone(),
self.provider_identity.clone(),
op.key_name.clone(),
);
let key_id = self.key_info_store.get_key_id(&key_identity)?;
let salt_buff = match &op.salt {
Some(salt) => salt.to_vec(),
None => Vec::new(),
};

match self
.context
.asym_encrypt(key_id, op.alg, op.plaintext.to_vec(), salt_buff)
{
Ok(ciphertext) => Ok(psa_asymmetric_encrypt::Result {
ciphertext: ciphertext.into(),
}),
Err(error) => {
error!("Encrypt failed with status: {}", error);
Err(error)
}
}
}

pub(super) fn psa_asymmetric_decrypt_internal(
&self,
application_identity: &ApplicationIdentity,
op: psa_asymmetric_decrypt::Operation,
) -> Result<psa_asymmetric_decrypt::Result> {
let key_identity = KeyIdentity::new(
application_identity.clone(),
self.provider_identity.clone(),
op.key_name.clone(),
);
let key_id = self.key_info_store.get_key_id(&key_identity)?;
let salt_buff = match &op.salt {
Some(salt) => salt.to_vec(),
None => Vec::new(),
};

match self
.context
.asym_decrypt(key_id, op.alg, op.ciphertext.to_vec(), salt_buff)
{
Ok(plaintext) => Ok(psa_asymmetric_decrypt::Result {
plaintext: plaintext.into(),
}),
Err(error) => {
error!("Decrypt failed with status: {}", error);
Err(error)
}
}
}
}
58 changes: 58 additions & 0 deletions src/providers/trusted_service/context/asym_encryption.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::ts_protobuf::{
AsymmetricDecryptIn, AsymmetricDecryptOut, AsymmetricEncryptIn, AsymmetricEncryptOut,
};
use super::Context;
use parsec_interface::operations::psa_algorithm::AsymmetricEncryption;
use parsec_interface::requests::ResponseStatus;
use std::convert::TryInto;
use zeroize::Zeroize;

impl Context {
pub fn asym_encrypt(
&self,
key_id: u32,
alg: AsymmetricEncryption,
mut plaintext: Vec<u8>,
mut salt: Vec<u8>,
) -> Result<Vec<u8>, ResponseStatus> {
let alg = alg.try_into().map_err(|e| {
plaintext.zeroize();
salt.zeroize();
e
})?;
let req = AsymmetricEncryptIn {
id: key_id,
alg,
plaintext,
salt,
};
let AsymmetricEncryptOut { ciphertext } = self.send_request(&req)?;

Ok(ciphertext)
}

pub fn asym_decrypt(
&self,
key_id: u32,
alg: AsymmetricEncryption,
mut ciphertext: Vec<u8>,
mut salt: Vec<u8>,
) -> Result<Vec<u8>, ResponseStatus> {
let alg = alg.try_into().map_err(|e| {
ciphertext.zeroize();
salt.zeroize();
e
})?;
let req = AsymmetricDecryptIn {
id: key_id,
alg,
ciphertext,
salt,
};
let AsymmetricDecryptOut { plaintext } = self.send_request(&req)?;

Ok(plaintext)
}
}
5 changes: 5 additions & 0 deletions src/providers/trusted_service/context/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ pub enum WrapperError {
CallBufferNull,
/// serialization or deserialization of protobuf message failed
FailedPbConversion,
/// invalid operation status value
InvalidOpStatus,
/// a parameter passed to the function was invalid
InvalidParam,
}
Expand All @@ -196,6 +198,9 @@ impl fmt::Display for WrapperError {
WrapperError::InvalidParam => {
write!(f, "a parameter passed to the function was invalid")
}
WrapperError::InvalidOpStatus => {
write!(f, "the RPC layer returned an invalid operation status")
}
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/providers/trusted_service/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use error::{Error, WrapperError};
use log::{error, info, trace};
use prost::Message;
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};
use std::ffi::{c_void, CString};
use std::io::{self};
use std::ptr::null_mut;
Expand All @@ -30,6 +30,7 @@ pub mod ts_binding {
include!(concat!(env!("OUT_DIR"), "/ts_bindings.rs"));
}

mod asym_encryption;
mod asym_sign;
pub mod error;
mod generate_random;
Expand Down Expand Up @@ -158,7 +159,11 @@ impl Context {
&mut resp_buf_size,
)
};
Error::from_status_opstatus(status, opstatus).map_err(|e| {
Error::from_status_opstatus(
status,
i32::try_from(opstatus).map_err(|_| Error::Wrapper(WrapperError::InvalidOpStatus))?,
)
.map_err(|e| {
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
e
})?;
Expand Down
2 changes: 2 additions & 0 deletions src/providers/trusted_service/context/ts_protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ opcode_impl!(ImportKeyIn, ImportKeyOut, ImportKey);
opcode_impl!(ExportPublicKeyIn, ExportPublicKeyOut, ExportPublicKey);
opcode_impl!(ExportKeyIn, ExportKeyOut, ExportKey);
opcode_impl!(GenerateRandomIn, GenerateRandomOut, GenerateRandom);
opcode_impl!(AsymmetricDecryptIn, AsymmetricDecryptOut, AsymmetricDecrypt);
opcode_impl!(AsymmetricEncryptIn, AsymmetricEncryptOut, AsymmetricEncrypt);

impl Drop for ImportKeyIn {
fn drop(&mut self) {
Expand Down
3 changes: 2 additions & 1 deletion src/providers/trusted_service/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ impl From<WrapperError> for ResponseStatus {
WrapperError::CallBufferNull
| WrapperError::CallHandleNull
| WrapperError::FailedPbConversion
| WrapperError::InvalidParam => ResponseStatus::PsaErrorCommunicationFailure,
| WrapperError::InvalidParam
| WrapperError::InvalidOpStatus => ResponseStatus::PsaErrorCommunicationFailure,
}
}
}
Expand Down
28 changes: 25 additions & 3 deletions src/providers/trusted_service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ use derivative::Derivative;
use log::{error, trace};
use parsec_interface::operations::list_providers::ProviderInfo;
use parsec_interface::operations::{
can_do_crypto, list_clients, list_keys, psa_destroy_key, psa_export_key, psa_export_public_key,
psa_generate_key, psa_generate_random, psa_import_key, psa_sign_hash, psa_verify_hash,
can_do_crypto, list_clients, list_keys, psa_asymmetric_decrypt, psa_asymmetric_encrypt,
psa_destroy_key, psa_export_key, psa_export_public_key, psa_generate_key, psa_generate_random,
psa_import_key, psa_sign_hash, psa_verify_hash,
};
use parsec_interface::requests::{Opcode, ProviderId, Result};
use psa_crypto::types::key;
use std::collections::HashSet;
use std::sync::atomic::{AtomicU32, Ordering};
use uuid::Uuid;

mod asym_encryption;
mod asym_sign;
mod capability_discovery;
mod context;
mod error;
mod generate_random;
mod key_management;

const SUPPORTED_OPCODES: [Opcode; 9] = [
const SUPPORTED_OPCODES: [Opcode; 11] = [
Opcode::PsaDestroyKey,
Opcode::PsaGenerateKey,
Opcode::PsaSignHash,
Expand All @@ -38,6 +40,8 @@ const SUPPORTED_OPCODES: [Opcode; 9] = [
Opcode::PsaExportKey,
Opcode::PsaGenerateRandom,
Opcode::CanDoCrypto,
Opcode::PsaAsymmetricEncrypt,
Opcode::PsaAsymmetricDecrypt,
];
/// Trusted Service provider structure
///
Expand Down Expand Up @@ -239,6 +243,24 @@ impl Provide for Provider {
trace!("can_do_crypto ingress");
self.can_do_crypto_main(application_identity, op)
}

fn psa_asymmetric_encrypt(
&self,
application_identity: &ApplicationIdentity,
op: psa_asymmetric_encrypt::Operation,
) -> Result<psa_asymmetric_encrypt::Result> {
trace!("psa_asymmetric_encrypt ingress");
self.psa_asymmetric_encrypt_internal(application_identity, op)
}

fn psa_asymmetric_decrypt(
&self,
application_identity: &ApplicationIdentity,
op: psa_asymmetric_decrypt::Operation,
) -> Result<psa_asymmetric_decrypt::Result> {
trace!("psa_asymmetric_decrypt ingress");
self.psa_asymmetric_decrypt_internal(application_identity, op)
}
}

/// Trusted Service provider builder
Expand Down
2 changes: 1 addition & 1 deletion trusted-services-vendor
Submodule trusted-services-vendor updated from c1cf91 to d5cc32

0 comments on commit ce800cb

Please sign in to comment.