Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update TS submodule and add asym encryption #406

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
# 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 all
# 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 all
# 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 all

mbed-crypto-provider:
name: Integration tests using Mbed Crypto provider
Expand All @@ -26,8 +26,8 @@ jobs:
# 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 mbed-crypto
# 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 mbed-crypto
# 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 mbed-crypto

pkcs11-provider:
name: Integration tests using PKCS 11 provider
Expand All @@ -40,8 +40,8 @@ jobs:
- name: Run the container to execute the test script
# Not running stress tests because they fail, presumably because of the same issue as #264
run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec ghcr.io/parallaxsecond/parsec-service-test-all /tmp/parsec/ci.sh pkcs11 --no-stress-test
# 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 pkcs11 --no-stress-test
# 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 pkcs11 --no-stress-test

tpm-provider:
name: Integration tests using TPM provider
Expand All @@ -53,21 +53,21 @@ jobs:
# 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 tpm
# 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 tpm
# 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 tpm

trusted-service-provider:
name: Integration tests using Cypto Trusted Service provider
runs-on: ubuntu-latest
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 All @@ -80,8 +80,8 @@ jobs:
- name: Run the container to execute the test script
# Not running stress tests because rust-cryptoauthlib test-interface does not support required calls
run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec ghcr.io/parallaxsecond/parsec-service-test-all /tmp/parsec/ci.sh cryptoauthlib --no-stress-test
# 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 cryptoauthlib --no-stress-test
# 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 cryptoauthlib --no-stress-test

fuzz-test-checker:
name: Check that the fuzz testing framework is still working
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ mbed-crypto-provider = ["psa-crypto"]
pkcs11-provider = ["cryptoki", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "psa-crypto", "rand"]
tpm-provider = ["tss-esapi", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "hex"]
cryptoauthlib-provider = ["rust-cryptoauthlib"]
trusted-service-provider = ["mbed-crypto-provider", "bindgen", "prost-build", "prost"]
trusted-service-provider = ["psa-crypto", "bindgen", "prost-build", "prost"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we actually need psa-crypto for this provider?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All over the place - we use the conversions implemented in psa-crypto to native types to fill in the protobuf objects. For example, the protobuf contract for KeyPolicy contains a u32 alg field to which we can just convert using the PSA crate, because it expects the same values as PSA Crypto would (just in a protobuf wrapper)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, make sense!

all-providers = ["tpm-provider", "pkcs11-provider", "mbed-crypto-provider", "cryptoauthlib-provider"]

# Authenticators
Expand Down
9 changes: 6 additions & 3 deletions e2e_tests/docker_image/parsec-service-test-all.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,18 @@ RUN cd nanopb-0.4.4-linux-x86 \
RUN rm -rf nanopb-0.4.4-linux-x86 nanopb-0.4.4-linux-x86.tar.gz

# Install mock Trusted Services
RUN git clone https://git.trustedfirmware.org/TS/trusted-services.git --branch main \
# Setup git config for patching dependencies
RUN git config --global user.email "some@email.com"
RUN git config --global user.name "Parsec Team"
Comment on lines +98 to +99
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it failing before without this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they've added some step in their build process to apply git patches to some dependencies, I think, and this is needed :(

RUN git clone https://git.trustedfirmware.org/TS/trusted-services.git --branch integration \
&& cd trusted-services \
&& git reset --hard 2fc7e10c7c21e4dafbf63dc9d00dfc2a7a7fddad
&& git reset --hard c1cf9120e4ab0b359a27176b079769b9a7e6bb87
# Install correct python dependencies
RUN pip3 install -r trusted-services/requirements.txt
RUN cd trusted-services/deployments/libts/linux-pc/ \
&& cmake . \
&& make \
&& cp libts.so nanopb_install/lib/libprotobuf-nanopb.a mbedcrypto_install/lib/libmbedcrypto.a /usr/local/lib/
&& cp libts.so nanopb_install/lib/libprotobuf-nanopb.a mbedtls_install/lib/libmbedcrypto.a /usr/local/lib/
RUN rm -rf trusted-services

# Create a new token in a new slot. The slot number assigned will be random
Expand Down
64 changes: 64 additions & 0 deletions src/providers/trusted_service/asym_encryption.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::Provider;
use crate::authenticators::ApplicationName;
use crate::key_info_managers::KeyTriple;
use log::error;
use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt};
use parsec_interface::requests::{ProviderId, Result};

impl Provider {
pub(super) fn psa_asymmetric_encrypt_internal(
&self,
app_name: ApplicationName,
op: psa_asymmetric_encrypt::Operation,
) -> Result<psa_asymmetric_encrypt::Result> {
let key_name = op.key_name.clone();

let key_triple = KeyTriple::new(app_name, ProviderId::TrustedService, key_name);
let key_id = self.key_info_store.get_key_id(&key_triple)?;
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,
app_name: ApplicationName,
op: psa_asymmetric_decrypt::Operation,
) -> Result<psa_asymmetric_decrypt::Result> {
let key_triple = KeyTriple::new(app_name, ProviderId::TrustedService, op.key_name.clone());
let key_id = self.key_info_store.get_key_id(&key_triple)?;
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)
}
}
8 changes: 4 additions & 4 deletions src/providers/trusted_service/context/asym_sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ impl Context {
) -> Result<Vec<u8>, Error> {
info!("Handling SignHash request");
let proto_req = SignHashIn {
handle: 0,
id: key_id,
hash,
alg: algorithm.try_into()?,
};
let SignHashOut { signature } = self.send_request_with_key(proto_req, key_id)?;
let SignHashOut { signature } = self.send_request(&proto_req)?;

Ok(signature)
}
Expand All @@ -36,12 +36,12 @@ impl Context {
) -> Result<(), Error> {
info!("Handling VerifyHash request");
let proto_req = VerifyHashIn {
handle: 0,
id: key_id,
hash,
signature,
alg: algorithm.try_into()?,
};
self.send_request_with_key(proto_req, key_id)?;
self.send_request(&proto_req)?;

Ok(())
}
Expand Down
42 changes: 7 additions & 35 deletions src/providers/trusted_service/context/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use super::error::Error;
use super::ts_protobuf::{
CloseKeyIn, DestroyKeyIn, DestroyKeyOut, ExportPublicKeyIn, GenerateKeyIn, GenerateKeyOut,
ImportKeyIn, ImportKeyOut, KeyAttributes, KeyLifetime, KeyPolicy, OpenKeyIn, OpenKeyOut,
DestroyKeyIn, DestroyKeyOut, ExportPublicKeyIn, GenerateKeyIn, ImportKeyIn, KeyAttributes,
KeyLifetime, KeyPolicy,
};
use super::Context;
use log::info;
use psa_crypto::types::key::Attributes;
use psa_crypto::types::status::Error as PsaError;
use std::convert::{TryFrom, TryInto};
use zeroize::Zeroize;

Expand All @@ -31,10 +30,7 @@ impl Context {
}),
}),
};
let GenerateKeyOut { handle } = self.send_request(&generate_req)?;

let close_req = CloseKeyIn { handle };
self.send_request(&close_req)?;
let _ = self.send_request(&generate_req)?;

Ok(())
}
Expand Down Expand Up @@ -74,10 +70,7 @@ impl Context {
}),
data,
};
let ImportKeyOut { handle } = self.send_request(&import_req)?;

let close_req = CloseKeyIn { handle };
self.send_request(&close_req)?;
let _ = self.send_request(&import_req)?;

Ok(())
}
Expand All @@ -88,37 +81,16 @@ impl Context {
/// format.
pub fn export_public_key(&self, id: u32) -> Result<Vec<u8>, Error> {
info!("Handling ExportPublicKey request");
self.send_request_with_key(ExportPublicKeyIn::default(), id)
let req = ExportPublicKeyIn { id };
self.send_request(&req)
}

/// Destroy a key given its ID.
pub fn destroy_key(&self, key_id: u32) -> Result<(), Error> {
info!("Handling DestroyKey request");
let open_req = OpenKeyIn { id: key_id };
let OpenKeyOut { handle } = self.send_request(&open_req)?;

let destroy_req = DestroyKeyIn { handle };
let destroy_req = DestroyKeyIn { id: key_id };
let _proto_resp: DestroyKeyOut = self.send_request(&destroy_req)?;
Ok(())
}

/// Verify if a key with a given ID exists.
pub fn check_key_exists(&self, key_id: u32) -> Result<bool, Error> {
info!("Handling CheckKey request");
let open_req = OpenKeyIn { id: key_id };
match self.send_request(&open_req) {
Ok(OpenKeyOut { handle }) => {
let close_req = CloseKeyIn { handle };
self.send_request(&close_req)?;
Ok(true)
}
Err(e) => {
if e == Error::PsaCrypto(PsaError::DoesNotExist) {
Ok(false)
} else {
Err(e)
}
}
}
}
}
27 changes: 5 additions & 22 deletions src/providers/trusted_service/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use std::ptr::null_mut;
use std::slice;
use std::sync::Mutex;
use ts_binding::*;
use ts_protobuf::{CloseKeyIn, GetOpcode, OpenKeyIn, OpenKeyOut, SetHandle};
use ts_protobuf::GetOpcode;

// Bindgen fails to generate this constant.
ionut-arm marked this conversation as resolved.
Show resolved Hide resolved
pub const PSA_KEY_ID_USER_MAX: u32 = 0x3fffffff;

#[allow(
non_snake_case,
Expand All @@ -30,6 +33,7 @@ pub mod ts_binding {
include!(concat!(env!("OUT_DIR"), "/ts_bindings.rs"));
}

mod asym_encryption;
mod asym_sign;
pub mod error;
mod key_management;
Expand Down Expand Up @@ -176,27 +180,6 @@ impl Context {

Ok(resp)
}

// Send a request that requires a key, given the key's ID.
// This function is responsible for opening the key, for sending the
// request with `send_request` and for closing the key afterwards.
fn send_request_with_key<T: Message + Default>(
&self,
mut req: impl Message + GetOpcode + SetHandle,
key_id: u32,
) -> Result<T, Error> {
let open_req = OpenKeyIn { id: key_id };
let OpenKeyOut { handle } = self.send_request(&open_req)?;

req.set_handle(handle);
let res = self.send_request(&req);
let close_req = CloseKeyIn { handle };

let res_close = self.send_request(&close_req);
let res = res?;
res_close?;
Ok(res)
}
}

impl Drop for Context {
Expand Down
Loading