diff --git a/Cargo.lock b/Cargo.lock index 19159c50..d7596f0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" version = "0.15.2" @@ -77,6 +79,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -1066,7 +1074,7 @@ name = "parsec-service" version = "0.7.2" dependencies = [ "anyhow", - "base64", + "base64 0.13.0", "bincode", "bindgen 0.57.0", "cryptoki", @@ -1137,7 +1145,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e3f783e3e499bdb8e66d2a48c9da561fc369f96853eb83fb31e28931e4a492" dependencies = [ - "oid 0.1.1", + "oid", "serde", "serde_bytes", ] @@ -1155,12 +1163,12 @@ dependencies = [ [[package]] name = "picky-asn1-x509" -version = "0.6.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3033675030de806aba1d5470949701b7c9f1dbf77e3bb17bd12e5f945e560ba" +checksum = "b8501e799b4c18bac0a6e74672126b1826df41178dcf076eec9ddefd93edcb11" dependencies = [ - "base64", - "oid 0.2.1", + "base64 0.12.3", + "oid", "picky-asn1", "picky-asn1-der", "serde", diff --git a/e2e_tests/tests/all_providers/config/mod.rs b/e2e_tests/tests/all_providers/config/mod.rs index b45e0886..f03df786 100644 --- a/e2e_tests/tests/all_providers/config/mod.rs +++ b/e2e_tests/tests/all_providers/config/mod.rs @@ -103,6 +103,32 @@ fn pkcs11_verify_software() { .unwrap(); } +#[cfg(feature = "pkcs11-provider")] +#[test] +fn pkcs11_verify_software_ecc() { + use sha2::{Digest, Sha256}; + set_config("pkcs11_software.toml"); + reload_service(); + + let mut client = TestClient::new(); + let key_name = String::from("pkcs11_verify_software_ecc"); + + let mut hasher = Sha256::new(); + hasher.update(b"Bob wrote this message."); + let hash = hasher.finalize().to_vec(); + + client + .generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone()) + .unwrap(); + + let signature = client + .sign_with_ecdsa_sha256(key_name.clone(), hash.clone()) + .unwrap(); + client + .verify_with_ecdsa_sha256(key_name, hash, signature) + .unwrap(); +} + #[cfg(feature = "pkcs11-provider")] #[test] fn pkcs11_encrypt_software() { diff --git a/e2e_tests/tests/all_providers/cross.rs b/e2e_tests/tests/all_providers/cross.rs index d327f3da..71526f24 100644 --- a/e2e_tests/tests/all_providers/cross.rs +++ b/e2e_tests/tests/all_providers/cross.rs @@ -13,7 +13,7 @@ const PLAINTEXT_MESSAGE: [u8; 32] = [ 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, ]; -fn setup_sign(provider: ProviderId, key_name: String) -> Result<(TestClient, Vec, Vec)> { +fn setup_sign(provider: ProviderId, key_name: String) -> (TestClient, Vec, Vec) { let mut client = TestClient::new(); client.set_provider(provider); client.generate_rsa_sign_key(key_name.clone()).unwrap(); @@ -24,10 +24,26 @@ fn setup_sign(provider: ProviderId, key_name: String) -> Result<(TestClient, Vec let pub_key = client.export_public_key(key_name).unwrap(); - Ok((client, pub_key, signature)) + (client, pub_key, signature) } -fn setup_asym_encr(provider: ProviderId, key_name: String) -> Result<(TestClient, Vec)> { +fn setup_sign_ecc(provider: ProviderId, key_name: String) -> (TestClient, Vec, Vec) { + let mut client = TestClient::new(); + client.set_provider(provider); + client + .generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone()) + .unwrap(); + + let signature = client + .sign_with_ecdsa_sha256(key_name.clone(), HASH.to_vec()) + .unwrap(); + + let pub_key = client.export_public_key(key_name).unwrap(); + + (client, pub_key, signature) +} + +fn setup_asym_encr(provider: ProviderId, key_name: String) -> (TestClient, Vec) { let mut client = TestClient::new(); client.set_provider(provider); client @@ -36,7 +52,7 @@ fn setup_asym_encr(provider: ProviderId, key_name: String) -> Result<(TestClient let pub_key = client.export_public_key(key_name).unwrap(); - Ok((client, pub_key)) + (client, pub_key) } fn import_and_verify( @@ -55,6 +71,22 @@ fn import_and_verify( .unwrap(); } +fn import_and_verify_ecc( + client: &mut TestClient, + provider: ProviderId, + key_name: String, + pub_key: Vec, + signature: Vec, +) { + client.set_provider(provider); + client + .import_ecc_public_secp_r1_ecdsa_sha256_key(key_name.clone(), pub_key) + .unwrap(); + client + .verify_with_ecdsa_sha256(key_name, HASH.to_vec(), signature) + .unwrap(); +} + fn import_and_encrypt( client: &mut TestClient, provider: ProviderId, @@ -81,7 +113,7 @@ fn verify_encrypt( #[test] fn tpm_sign_cross() { let key_name = String::from("tpm_sign_cross"); - let (mut client, pub_key, signature) = setup_sign(ProviderId::Tpm, key_name.clone()).unwrap(); + let (mut client, pub_key, signature) = setup_sign(ProviderId::Tpm, key_name.clone()); // Mbed Crypto import_and_verify( @@ -102,11 +134,34 @@ fn tpm_sign_cross() { ); } +#[test] +fn tpm_sign_cross_ecc() { + let key_name = String::from("tpm_sign_cross_ecc"); + let (mut client, pub_key, signature) = setup_sign_ecc(ProviderId::Tpm, key_name.clone()); + + // Mbed Crypto + import_and_verify_ecc( + &mut client, + ProviderId::MbedCrypto, + key_name.clone(), + pub_key.clone(), + signature.clone(), + ); + + // PKCS11 + import_and_verify_ecc( + &mut client, + ProviderId::Pkcs11, + key_name, + pub_key, + signature, + ); +} + #[test] fn pkcs11_sign_cross() { let key_name = String::from("pkcs11_sign_cross"); - let (mut client, pub_key, signature) = - setup_sign(ProviderId::Pkcs11, key_name.clone()).unwrap(); + let (mut client, pub_key, signature) = setup_sign(ProviderId::Pkcs11, key_name.clone()); // Mbed Crypto import_and_verify( @@ -121,11 +176,25 @@ fn pkcs11_sign_cross() { import_and_verify(&mut client, ProviderId::Tpm, key_name, pub_key, signature); } +#[test] +fn pkcs11_sign_cross_ecc() { + let key_name = String::from("pkcs11_sign_cross_ecc"); + let (mut client, pub_key, signature) = setup_sign_ecc(ProviderId::Pkcs11, key_name.clone()); + + // Mbed Crypto + import_and_verify_ecc( + &mut client, + ProviderId::MbedCrypto, + key_name.clone(), + pub_key.clone(), + signature.clone(), + ); +} + #[test] fn mbed_crypto_sign_cross() { let key_name = String::from("mbed_crypto_sign_cross"); - let (mut client, pub_key, signature) = - setup_sign(ProviderId::MbedCrypto, key_name.clone()).unwrap(); + let (mut client, pub_key, signature) = setup_sign(ProviderId::MbedCrypto, key_name.clone()); // Mbed Crypto import_and_verify( @@ -140,10 +209,25 @@ fn mbed_crypto_sign_cross() { import_and_verify(&mut client, ProviderId::Tpm, key_name, pub_key, signature); } +#[test] +fn mbed_crypto_sign_cross_ecc() { + let key_name = String::from("mbed_crypto_sign_cross_ecc"); + let (mut client, pub_key, signature) = setup_sign_ecc(ProviderId::MbedCrypto, key_name.clone()); + + // Mbed Crypto + import_and_verify_ecc( + &mut client, + ProviderId::Pkcs11, + key_name.clone(), + pub_key.clone(), + signature.clone(), + ); +} + #[test] fn tpm_asym_encr_cross() { let key_name = String::from("tpm_asym_encr_cross"); - let (mut client, pub_key) = setup_asym_encr(ProviderId::Tpm, key_name.clone()).unwrap(); + let (mut client, pub_key) = setup_asym_encr(ProviderId::Tpm, key_name.clone()); // Mbed Crypto let ciphertext = import_and_encrypt( @@ -169,7 +253,7 @@ fn tpm_asym_encr_cross() { #[test] fn pkcs11_asym_encr_cross() { let key_name = String::from("pkcs11_asym_encr_cross"); - let (mut client, pub_key) = setup_asym_encr(ProviderId::Pkcs11, key_name.clone()).unwrap(); + let (mut client, pub_key) = setup_asym_encr(ProviderId::Pkcs11, key_name.clone()); // Mbed Crypto let ciphertext = import_and_encrypt( @@ -200,7 +284,7 @@ fn pkcs11_asym_encr_cross() { #[test] fn mbed_crypto_asym_encr_cross() { let key_name = String::from("mbed_crypto_asym_encr_cross"); - let (mut client, pub_key) = setup_asym_encr(ProviderId::MbedCrypto, key_name.clone()).unwrap(); + let (mut client, pub_key) = setup_asym_encr(ProviderId::MbedCrypto, key_name.clone()); // Pkcs11 let ciphertext = import_and_encrypt( diff --git a/e2e_tests/tests/per_provider/normal_tests/asym_sign_verify.rs b/e2e_tests/tests/per_provider/normal_tests/asym_sign_verify.rs index f65b3ee0..e4ae1bc8 100644 --- a/e2e_tests/tests/per_provider/normal_tests/asym_sign_verify.rs +++ b/e2e_tests/tests/per_provider/normal_tests/asym_sign_verify.rs @@ -767,7 +767,7 @@ fn verify_with_ring() { let pub_key = client.export_public_key(key_name.clone()).unwrap(); let mut hasher = Sha256::new(); - hasher.update(message.clone()); + hasher.update(message); let hash = hasher.finalize().to_vec(); let signature = client.sign_with_rsa_sha256(key_name, hash.clone()).unwrap(); @@ -775,7 +775,7 @@ fn verify_with_ring() { pk.verify(message, &signature).unwrap(); } -#[cfg(not(any(feature = "cryptoauthlib-provider", feature = "pkcs11-provider")))] +#[cfg(not(feature = "cryptoauthlib-provider"))] #[test] fn verify_ecc_with_ring() { use ring::signature::{self, UnparsedPublicKey}; @@ -790,7 +790,7 @@ fn verify_ecc_with_ring() { let pub_key = client.export_public_key(key_name.clone()).unwrap(); let mut hasher = Sha256::new(); - hasher.update(message.clone()); + hasher.update(message); let hash = hasher.finalize().to_vec(); let signature = client .sign_with_ecdsa_sha256(key_name, hash.clone()) diff --git a/e2e_tests/tests/per_provider/normal_tests/export_key.rs b/e2e_tests/tests/per_provider/normal_tests/export_key.rs index 21fc64fb..c56cec9e 100644 --- a/e2e_tests/tests/per_provider/normal_tests/export_key.rs +++ b/e2e_tests/tests/per_provider/normal_tests/export_key.rs @@ -1,15 +1,13 @@ // Copyright 2019 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#![allow(unused_imports, unused)] use crate::per_provider::normal_tests::import_key::ECC_PUBLIC_KEY; use e2e_tests::TestClient; use parsec_client::core::interface::operations::psa_algorithm::*; use parsec_client::core::interface::operations::psa_key_attributes::*; use parsec_client::core::interface::requests::Result; use parsec_client::core::interface::requests::{Opcode, ResponseStatus}; -#[cfg(not(feature = "cryptoauthlib-provider"))] use picky_asn1_x509::{RsaPrivateKey, RsaPublicKey}; -#[cfg(not(feature = "cryptoauthlib-provider"))] const PRIVATE_KEY: &str = "MIICWwIBAAKBgQCd+EKeRmZCKLmg7LasWqpKA9/01linY75ujilf6v/Kb8UP9r/E\ cO75Pvi2YPnYhBadmVOVxMOqS2zmKm1a9VTegT8dN9Unf2s2KbKrKXupaQTXcrGG\ SB/BmHeWeiqidEMw7i9ysjHK4KEuacmYmZpvKAnNWMyvQgjGgGNpsNzqawIDAQAB\ @@ -130,7 +128,7 @@ fn import_and_export_ecc_public_key_by_export_key_fn() -> Result<()> { return Ok(()); } - let key_name = String::from("import_and_export_ecc_public_key"); + let key_name = String::from("import_and_export_ecc_public_key_by_export_key_fn"); client.import_key( key_name.clone(), Attributes { @@ -466,4 +464,4 @@ fn export_rsa_private_key_matches_import() { .unwrap(); let exported_key = client.export_key(key_name).unwrap(); assert_eq!(decoded_key, exported_key); -} \ No newline at end of file +} diff --git a/e2e_tests/tests/per_provider/normal_tests/export_public_key.rs b/e2e_tests/tests/per_provider/normal_tests/export_public_key.rs index f8714dd8..6bcf2e94 100644 --- a/e2e_tests/tests/per_provider/normal_tests/export_public_key.rs +++ b/e2e_tests/tests/per_provider/normal_tests/export_public_key.rs @@ -1,6 +1,6 @@ // Copyright 2019 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#![allow(unused_imports, unused)] use crate::per_provider::normal_tests::import_key::ECC_PUBLIC_KEY; use e2e_tests::TestClient; use parsec_client::core::interface::operations::psa_algorithm::*; @@ -8,7 +8,6 @@ use parsec_client::core::interface::operations::psa_key_attributes::*; use parsec_client::core::interface::requests::Opcode; use parsec_client::core::interface::requests::ResponseStatus; use parsec_client::core::interface::requests::Result; -#[cfg(not(feature = "cryptoauthlib-provider"))] use picky_asn1_x509::RsaPublicKey; #[cfg(not(feature = "cryptoauthlib-provider"))] @@ -26,7 +25,7 @@ fn export_rsa_public_key() -> Result<()> { Ok(()) } -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#[cfg(not(feature = "tpm-provider"))] #[test] fn export_ecc_public_key() -> Result<()> { let mut client = TestClient::new(); @@ -79,11 +78,11 @@ fn import_and_export_rsa_public_key() -> Result<()> { Ok(()) } -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#[cfg(not(feature = "tpm-provider"))] #[test] fn import_and_export_ecc_public_key_by_export_public_key_fn() -> Result<()> { let mut client = TestClient::new(); - let key_name = String::from("import_and_export_ecc_public_key"); + let key_name = String::from("import_and_export_ecc_public_key_by_export_public_key_fn"); if !client.is_operation_supported(Opcode::PsaExportPublicKey) { return Ok(()); } @@ -109,7 +108,7 @@ fn check_public_rsa_export_format() -> Result<()> { Ok(()) } -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#[cfg(not(feature = "tpm-provider"))] #[test] fn check_public_ecc_export_format() -> Result<()> { let mut client = TestClient::new(); @@ -118,12 +117,11 @@ fn check_public_ecc_export_format() -> Result<()> { } let private_key_name = String::from("check_public_ecc_export_format_prv"); client.generate_ecc_key_pair_secpr1_ecdsa_sha256(private_key_name.clone())?; + let public_key_name = String::from("check_public_ecc_export_format_pub"); let public_key = client.export_public_key(private_key_name.clone())?; // That should not fail if the bytes are in the expected format. - let public_key_name = String::from("check_public_ecc_export_format_pub"); - let _ = - client.import_ecc_public_secp_r1_ecdsa_sha256_key(public_key_name.clone(), public_key)?; + client.import_ecc_public_secp_r1_ecdsa_sha256_key(public_key_name.clone(), public_key)?; Ok(()) } @@ -207,4 +205,37 @@ fn check_export_ecc_public_possible() -> Result<()> { let _public_key = client.export_public_key(key_name)?; Ok(()) -} \ No newline at end of file +} + +#[cfg(not(feature = "tpm-provider"))] +#[test] +fn import_and_export_ecc_public_key() -> Result<()> { + let mut client = TestClient::new(); + let key_name = String::from("import_and_export_ecc_public_key"); + if !client.is_operation_supported(Opcode::PsaExportPublicKey) { + return Ok(()); + } + client + .import_ecc_public_secp_r1_ecdsa_sha256_key(key_name.clone(), ECC_PUBLIC_KEY.to_vec()) + .unwrap(); + + assert_eq!(ECC_PUBLIC_KEY.to_vec(), client.export_public_key(key_name)?); + + Ok(()) +} + +#[test] +fn check_public_ecc_export_format2() -> Result<()> { + let mut client = TestClient::new(); + let key_name = String::from("check_public_ecc_export_format"); + if !client.is_operation_supported(Opcode::PsaExportPublicKey) { + return Ok(()); + } + client.generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone())?; + let public_key = client.export_public_key(key_name)?; + + assert_eq!(public_key[0], 0x04); + assert_eq!(public_key.len(), 65); + + Ok(()) +} diff --git a/e2e_tests/tests/per_provider/normal_tests/import_key.rs b/e2e_tests/tests/per_provider/normal_tests/import_key.rs index 3a62f44b..8f0989a2 100644 --- a/e2e_tests/tests/per_provider/normal_tests/import_key.rs +++ b/e2e_tests/tests/per_provider/normal_tests/import_key.rs @@ -1,6 +1,6 @@ // Copyright 2019 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -#![allow(unused_imports)] +#![allow(unused_imports, unused)] use e2e_tests::TestClient; use parsec_client::core::interface::operations::psa_algorithm::*; use parsec_client::core::interface::operations::psa_key_attributes::*; @@ -10,7 +10,6 @@ use parsec_client::core::interface::requests::Result; use picky_asn1::wrapper::IntegerAsn1; use picky_asn1_x509::RsaPublicKey; -#[cfg(not(feature = "cryptoauthlib-provider"))] const KEY_DATA: [u8; 140] = [ 48, 129, 137, 2, 129, 129, 0, 153, 165, 220, 135, 89, 101, 254, 229, 28, 33, 138, 247, 20, 102, 253, 217, 247, 246, 142, 107, 51, 40, 179, 149, 45, 117, 254, 236, 161, 109, 16, 81, 135, 72, @@ -21,7 +20,6 @@ const KEY_DATA: [u8; 140] = [ 39, 22, 141, 173, 85, 26, 58, 9, 128, 27, 57, 131, 2, 3, 1, 0, 1, ]; -#[cfg(feature = "tpm-provider")] const KEY_PAIR_DATA: [u8; 609] = [ 0x30, 0x82, 0x02, 0x5D, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xC7, 0xDF, 0x1D, 0x9B, 0x29, 0xBA, 0x60, 0x1B, 0x1C, 0x65, 0x2C, 0xB8, 0xEF, 0x7F, 0x8E, 0x2C, 0x01, 0x8A, 0x9B, 0xE9, 0x6B, @@ -64,13 +62,11 @@ const KEY_PAIR_DATA: [u8; 609] = [ 0x27, ]; -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] pub const ECC_PRIVATE_KEY: [u8; 32] = [ 0x26, 0xc8, 0x82, 0x9e, 0x22, 0xe3, 0x0c, 0xa6, 0x3d, 0x29, 0xf5, 0xf7, 0x27, 0x39, 0x58, 0x47, 0x41, 0x81, 0xf6, 0x57, 0x4f, 0xdb, 0xcb, 0x4d, 0xbb, 0xdd, 0x52, 0xff, 0x3a, 0xc0, 0xf6, 0x0d, ]; -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] pub const ECC_PUBLIC_KEY: [u8; 65] = [ 0x04, 0x01, 0xf7, 0x69, 0xe2, 0x40, 0x3a, 0xeb, 0x0d, 0x64, 0x3e, 0x81, 0xb8, 0xda, 0x95, 0xb0, 0x1c, 0x25, 0x80, 0xfe, 0xa3, 0xd3, 0xd0, 0x5b, 0x2f, 0xef, 0x6a, 0x31, 0x9c, 0xa9, 0xca, 0x5d, @@ -79,7 +75,6 @@ pub const ECC_PUBLIC_KEY: [u8; 65] = [ 0x71, ]; -#[cfg(not(feature = "cryptoauthlib-provider"))] fn example_modulus_1024() -> Vec { vec![ 153, 165, 220, 135, 89, 101, 254, 229, 28, 33, 138, 247, 20, 102, 253, 217, 247, 246, 142, @@ -104,16 +99,23 @@ fn import_rsa_key() -> Result<()> { client.import_rsa_public_key(key_name, KEY_DATA.to_vec()) } -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#[cfg(not(feature = "tpm-provider"))] #[test] -fn import_ecc_key() -> Result<()> { +fn import_ecc_key() { let mut client = TestClient::new(); - let key_name = String::from("import_key"); + let key_name = String::from("import_key_ecc"); if !client.is_operation_supported(Opcode::PsaImportKey) { - return Ok(()); + return; } - client.import_ecc_public_secp_r1_ecdsa_sha256_key(key_name, ECC_PUBLIC_KEY.to_vec()) + client + .import_ecc_public_secp_r1_ecdsa_sha256_key(key_name.clone(), ECC_PUBLIC_KEY.to_vec()) + .unwrap(); + + let status = client + .verify_with_ecdsa_sha256(key_name, vec![0xff; 32], vec![0xff; 32]) + .unwrap_err(); + assert_eq!(status, ResponseStatus::PsaErrorInvalidSignature); } #[cfg(not(feature = "cryptoauthlib-provider"))] @@ -126,26 +128,16 @@ fn create_and_import_rsa_key() -> Result<()> { } let status; - #[cfg(not(feature = "cryptoauthlib-provider"))] - { - client.generate_rsa_sign_key(key_name.clone())?; - status = client - .import_rsa_public_key(key_name, KEY_DATA.to_vec()) - .expect_err("Key should have already existed"); - } - #[cfg(feature = "cryptoauthlib-provider")] - { - client.generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone())?; - status = client - .import_ecc_public_secp_r1_ecdsa_sha256_key(key_name, PUB_KEY_ECC.to_vec()) - .expect_err("Key should have already existed"); - } + client.generate_rsa_sign_key(key_name.clone())?; + status = client + .import_rsa_public_key(key_name, KEY_DATA.to_vec()) + .expect_err("Key should have already existed"); assert_eq!(status, ResponseStatus::PsaErrorAlreadyExists); Ok(()) } -#[cfg(any(feature = "mbed-crypto-provider", feature = "cryptoauthlib-provider"))] +#[cfg(not(feature = "tpm-provider"))] #[test] fn create_and_import_ecc_key() -> Result<()> { let mut client = TestClient::new(); @@ -167,7 +159,7 @@ fn create_and_import_ecc_key() -> Result<()> { #[test] fn import_rsa_key_twice() -> Result<()> { let mut client = TestClient::new(); - let key_name = String::from("import_key_twice"); + let key_name = String::from("import_rsa_key_twice"); if !client.is_operation_supported(Opcode::PsaImportKey) { return Ok(()); } @@ -182,11 +174,11 @@ fn import_rsa_key_twice() -> Result<()> { Ok(()) } -#[cfg(feature = "cryptoauthlib-provider")] +#[cfg(not(feature = "tpm-provider"))] #[test] fn import_ecc_key_twice() -> Result<()> { let mut client = TestClient::new(); - let key_name = String::from("import_key_twice"); + let key_name = String::from("import_ecc_key_twice"); if !client.is_operation_supported(Opcode::PsaImportKey) { return Ok(()); } @@ -368,10 +360,7 @@ fn failed_imported_key_should_be_removed() -> Result<()> { .import_key(key_name.clone(), attributes, Vec::new()) .unwrap_err(); // Should succeed because key would have been destroyed. - #[cfg(not(feature = "cryptoauthlib-provider"))] client.import_rsa_public_key(key_name, picky_asn1_der::to_vec(&public_key).unwrap())?; - #[cfg(feature = "cryptoauthlib-provider")] - client.import_ecc_public_secp_r1_ecdsa_sha256_key(key_name, ECC_PUBLIC_KEY.to_vec())?; Ok(()) } diff --git a/src/providers/pkcs11/asym_sign.rs b/src/providers/pkcs11/asym_sign.rs index 49716e1e..f1bd1712 100644 --- a/src/providers/pkcs11/asym_sign.rs +++ b/src/providers/pkcs11/asym_sign.rs @@ -8,6 +8,7 @@ use crate::key_info_managers::KeyTriple; use cryptoki::types::mechanism::Mechanism; use log::{info, trace}; use parsec_interface::operations::psa_algorithm::Algorithm; +use parsec_interface::operations::psa_key_attributes::Type; use parsec_interface::operations::{psa_sign_hash, psa_verify_hash}; use parsec_interface::requests::{ProviderId, ResponseStatus, Result}; use std::convert::TryFrom; @@ -32,10 +33,18 @@ impl Provider { let key = self.find_key(&session, key_id, KeyPairType::PrivateKey)?; info!("Located signing key."); + let hash = match key_attributes.key_type { + // For RSA signatures we need to format the hash into a DigestInfo structure + Type::RsaKeyPair => utils::digest_info(op.alg, op.hash.to_vec())?.into(), + // For ECDSA the format we get it in is sufficient. + Type::EccKeyPair { .. } => op.hash, + _ => return Err(ResponseStatus::PsaErrorNotSupported), // this shouldn't be reachable + }; + trace!("Sign* command"); Ok(psa_sign_hash::Result { signature: session - .sign(&mech, key, &utils::digest_info(op.alg, op.hash.to_vec())?) + .sign(&mech, key, &hash) .map_err(to_response_status)? .into(), }) @@ -59,14 +68,19 @@ impl Provider { let key = self.find_key(&session, key_id, KeyPairType::PublicKey)?; info!("Located public key."); + let hash = match key_attributes.key_type { + // For RSA signatures we need to format the hash into a DigestInfo structure + Type::RsaKeyPair | Type::RsaPublicKey => { + utils::digest_info(op.alg, op.hash.to_vec())?.into() + } + // For ECDSA the format we get it in is sufficient. + Type::EccKeyPair { .. } | Type::EccPublicKey { .. } => op.hash, + _ => return Err(ResponseStatus::PsaErrorNotSupported), // this shouldn't be reachable + }; + trace!("Verify* command"); session - .verify( - &mech, - key, - &utils::digest_info(op.alg, op.hash.to_vec())?, - &op.signature, - ) + .verify(&mech, key, &hash, &op.signature) .map_err(to_response_status)?; Ok(psa_verify_hash::Result {}) } diff --git a/src/providers/pkcs11/key_management.rs b/src/providers/pkcs11/key_management.rs index b015cd11..fb9b1173 100644 --- a/src/providers/pkcs11/key_management.rs +++ b/src/providers/pkcs11/key_management.rs @@ -8,13 +8,13 @@ use cryptoki::types::mechanism::{Mechanism, MechanismType}; use cryptoki::types::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; use cryptoki::types::session::Session; use log::{error, info, trace}; -use parsec_interface::operations::psa_key_attributes::{Id, Lifetime, Type}; +use parsec_interface::operations::psa_key_attributes::{EccFamily, Id, Lifetime, Type}; use parsec_interface::operations::{ psa_destroy_key, psa_export_public_key, psa_generate_key, psa_import_key, }; use parsec_interface::requests::{ProviderId, ResponseStatus, Result}; use parsec_interface::secrecy::ExposeSecret; -use picky_asn1::wrapper::IntegerAsn1; +use picky_asn1::wrapper::{IntegerAsn1, OctetStringAsn1}; use picky_asn1_x509::RSAPublicKey; use std::convert::{TryFrom, TryInto}; @@ -170,23 +170,6 @@ impl Provider { &self, app_name: ApplicationName, op: psa_import_key::Operation, - ) -> Result { - match op.attributes.key_type { - Type::RsaPublicKey => self.psa_import_key_internal_rsa_public(app_name, op), - _ => { - error!( - "The pkcs11 provider does not support the {:?} key type.", - op.attributes.key_type - ); - Err(ResponseStatus::PsaErrorNotSupported) - } - } - } - - pub(super) fn psa_import_key_internal_rsa_public( - &self, - app_name: ApplicationName, - op: psa_import_key::Operation, ) -> Result { let key_name = op.key_name; let key_attributes = op.attributes; @@ -199,12 +182,68 @@ impl Provider { let key_id = self.create_key_id(); let mut template: Vec = Vec::new(); + template.push(Attribute::Class(ObjectClass::PUBLIC_KEY)); + template.push(Attribute::Token(true.into())); + template.push(Attribute::Verify(true.into())); + template.push(Attribute::Id(key_id.to_be_bytes().to_vec())); - let public_key: RSAPublicKey = picky_asn1_der::from_bytes(op.data.expose_secret()) - .map_err(|e| { - format_error!("Failed to parse RSAPublicKey data", e); - ResponseStatus::PsaErrorInvalidArgument - })?; + match op.attributes.key_type { + Type::RsaPublicKey => { + self.handle_rsa_public_import_attrib( + op.data.expose_secret(), + key_attributes.bits, + &mut template, + )?; + } + Type::EccPublicKey { curve_family } => { + self.handle_ecc_public_import_attrib( + op.data.expose_secret(), + key_attributes.bits, + curve_family, + &mut template, + )?; + } + _ => { + error!( + "The pkcs11 provider does not support the {:?} key type.", + op.attributes.key_type + ); + return Err(ResponseStatus::PsaErrorNotSupported); + } + } + trace!("CreateObject command"); + match session.create_object(&template) { + Ok(key) => { + if let Err(e) = + self.key_info_store + .insert_key_info(key_triple, &key_id, key_attributes) + { + format_error!("Failed to insert the mappings, deleting the key.", e); + if let Err(e) = session.destroy_object(key) { + format_error!("Failed to destroy public key: ", e); + } + Err(e) + } else { + Ok(psa_import_key::Result {}) + } + } + Err(error) => { + format_error!("Import key status: ", error); + Err(to_response_status(error)) + } + } + } + + pub(super) fn handle_rsa_public_import_attrib( + &self, + key_data: &[u8], + bits: usize, + template: &mut Vec, + ) -> Result<()> { + let public_key: RSAPublicKey = picky_asn1_der::from_bytes(key_data).map_err(|e| { + format_error!("Failed to parse RSAPublicKey data", e); + ResponseStatus::PsaErrorInvalidArgument + })?; if public_key.modulus.is_negative() || public_key.public_exponent.is_negative() { error!("Only positive modulus and public exponent are supported."); @@ -213,12 +252,11 @@ impl Provider { let modulus_object = public_key.modulus.as_unsigned_bytes_be(); let exponent_object = public_key.public_exponent.as_unsigned_bytes_be(); - let bits = key_attributes.bits; if bits != 0 && modulus_object.len() * 8 != bits { if crate::utils::GlobalConfig::log_error_details() { error!( "`bits` field of key attributes (value: {}) must be either 0 or equal to the size of the key in `data` (value: {}).", - key_attributes.bits, + bits, modulus_object.len() * 8 ); } else { @@ -228,38 +266,56 @@ impl Provider { return Err(ResponseStatus::PsaErrorInvalidArgument); } - template.push(Attribute::Class(ObjectClass::PUBLIC_KEY)); - template.push(Attribute::KeyType(KeyType::RSA)); - template.push(Attribute::Token(true.into())); template.push(Attribute::Modulus(modulus_object.into())); template.push(Attribute::PublicExponent(exponent_object.into())); - template.push(Attribute::Verify(true.into())); template.push(Attribute::Encrypt(true.into())); - template.push(Attribute::Id(key_id.to_be_bytes().to_vec())); template.push(Attribute::Private(false.into())); template.push(Attribute::AllowedMechanisms(vec![MechanismType::RSA_PKCS])); + template.push(Attribute::KeyType(KeyType::RSA)); - trace!("CreateObject command"); - match session.create_object(&template) { - Ok(key) => { - if let Err(e) = - self.key_info_store - .insert_key_info(key_triple, &key_id, key_attributes) - { - format_error!("Failed to insert the mappings, deleting the key.", e); - if let Err(e) = session.destroy_object(key) { - format_error!("Failed to destroy public key: ", e); - } - Err(e) - } else { - Ok(psa_import_key::Result {}) - } - } - Err(error) => { - format_error!("Import key status: ", error); - Err(to_response_status(error)) + Ok(()) + } + + pub(super) fn handle_ecc_public_import_attrib( + &self, + key_data: &[u8], + bits: usize, + curve_family: EccFamily, + template: &mut Vec, + ) -> Result<()> { + match curve_family { + EccFamily::Montgomery => { + // Montgomery curves aren't supported because their format differs from what + // we need below. + // In any case, the list of curves for which we can create `EcParams` below + // is even shorter than that. + error!("Importing EC keys using Montgomery curves is not currently supported."); + return Err(ResponseStatus::PsaErrorNotSupported); } + _ => (), } + // The format expected by PKCS11 is an ASN.1 OctetString containing the + // data that the PSA Crypto interface specifies. + // See ECPoint in [SEC1](https://www.secg.org/sec1-v2.pdf). PKCS11 mandates using + // [ANSI X9.62 ECPoint](https://cryptsoft.com/pkcs11doc/v220/group__SEC__12__3__3__ECDSA__PUBLIC__KEY__OBJECTS.html), + // however SEC1 is an equivalent spec. + let key_data = + picky_asn1_der::to_vec(&OctetStringAsn1(key_data.to_vec())).map_err(|e| { + error!("Failed to generate EC Point OctetString: {}", e); + ResponseStatus::PsaErrorInvalidArgument + })?; + template.push(Attribute::EcPoint(key_data)); + template.push(Attribute::Private(false.into())); + template.push(Attribute::AllowedMechanisms(vec![MechanismType::ECDSA])); + template.push(Attribute::KeyType(KeyType::EC)); + template.push(Attribute::EcParams( + picky_asn1_der::to_vec(&utils::ec_params(curve_family, bits)?).map_err(|e| { + error!("Failed to generate EC parameters: {}", e); + ResponseStatus::PsaErrorGenericError + })?, + )); + + Ok(()) } pub(super) fn psa_export_public_key_internal( @@ -269,13 +325,28 @@ impl Provider { ) -> Result { let key_name = op.key_name; let key_triple = KeyTriple::new(app_name, ProviderId::Pkcs11, key_name); + let key_attributes = self.key_info_store.get_key_attributes(&key_triple)?; let key_id = self.key_info_store.get_key_id(&key_triple)?; - let session = self.new_session()?; let key = self.find_key(&session, key_id, KeyPairType::PublicKey)?; info!("Located key for export."); + let data = match key_attributes.key_type { + Type::RsaKeyPair | Type::RsaPublicKey => { + self.export_public_rsa_internal(key, &session)? + } + Type::EccKeyPair { .. } | Type::EccPublicKey { .. } => { + self.export_public_ec_internal(key, &session)? + } + _ => { + return Err(ResponseStatus::PsaErrorNotSupported); + } + }; + + Ok(psa_export_public_key::Result { data: data.into() }) + } + fn export_public_rsa_internal(&self, key: ObjectHandle, session: &Session) -> Result> { let mut attributes = session .get_attributes( key, @@ -305,11 +376,35 @@ impl Provider { modulus, public_exponent, }; - let data = picky_asn1_der::to_vec(&key).map_err(|err| { + Ok(picky_asn1_der::to_vec(&key).map_err(|err| { format_error!("Could not serialise key elements", err); ResponseStatus::PsaErrorCommunicationFailure - })?; - Ok(psa_export_public_key::Result { data: data.into() }) + })?) + } + + fn export_public_ec_internal(&self, key: ObjectHandle, session: &Session) -> Result> { + let mut attributes = session + .get_attributes(key, &[AttributeType::EcPoint]) + .map_err(to_response_status)?; + + if attributes.len() != 1 { + error!("Expected to find EC point attribute in public key."); + return Err(ResponseStatus::PsaErrorCommunicationFailure); + } + + if let Attribute::EcPoint(data) = attributes.remove(0) { + // The format provided by PKCS11 is an ASN.1 OctetString containing the + // data that the PSA Crypto interface expects. + // See ECPoint in [SEC1](https://www.secg.org/sec1-v2.pdf). PKCS11 mandates using + // [ANSI X9.62 ECPoint](https://cryptsoft.com/pkcs11doc/v220/group__SEC__12__3__3__ECDSA__PUBLIC__KEY__OBJECTS.html), + // however SEC1 is an equivalent spec. + let key_data: OctetStringAsn1 = picky_asn1_der::from_bytes(&data) + .map_err(|_| ResponseStatus::PsaErrorGenericError)?; + Ok(key_data.0) + } else { + error!("Expected to find modulus attribute."); + Err(ResponseStatus::PsaErrorCommunicationFailure) + } } pub(super) fn psa_destroy_key_internal( diff --git a/src/providers/pkcs11/utils.rs b/src/providers/pkcs11/utils.rs index 26b66e66..33359e3d 100644 --- a/src/providers/pkcs11/utils.rs +++ b/src/providers/pkcs11/utils.rs @@ -114,9 +114,6 @@ pub fn digest_info(alg: AsymmetricSignature, hash: Vec) -> Result> { AsymmetricSignature::RsaPkcs1v15Sign { hash_alg: SignHash::Specific(Hash::Sha512), } => AlgorithmIdentifier::new_sha(SHAVariant::SHA2_512), - AsymmetricSignature::Ecdsa { - hash_alg: SignHash::Specific(Hash::Sha256), - } => AlgorithmIdentifier::new_ecdsa_with_sha256(), _ => return Err(ResponseStatus::PsaErrorNotSupported), }; picky_asn1_der::to_vec(&DigestInfo {