Skip to content

Commit

Permalink
ek abstractions: allow to specficy exact key type
Browse files Browse the repository at this point in the history
This adds support other keys than RSA2048 and ECC Nist P256.

Signed-off-by: Thore Sommer <[email protected]>
  • Loading branch information
THS-on committed Jun 12, 2023
1 parent 1e04007 commit 9ba573f
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 43 deletions.
102 changes: 84 additions & 18 deletions tss-esapi/src/abstraction/ek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,79 @@ use crate::{
},
Context, Error, Result, WrapperErrorKind,
};
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
// Section 2.2.1.4 (Low Range) for Windows compatibility
const RSA_2048_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00002;
const ECC_P256_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0000a;

// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
// Section 2.2.1.5 (High Range)
const ECC_P384_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00016;
const ECC_P521_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00018;
const ECC_P256_SM2_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001a;
const RSA_3072_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001c;
const RSA_4096_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001e;

/// Enum representing the asymmetric algorithm interface type with specific properties.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum AsymmetricAlgorithmSelection {
Rsa2048,
Rsa3072,
Rsa4096,
EccP256,
EccP384,
EccP521,
EccP256Sm2,
}

impl TryFrom<AsymmetricAlgorithm> for AsymmetricAlgorithmSelection {
type Error = Error;

fn try_from(value: AsymmetricAlgorithm) -> std::result::Result<Self, Self::Error> {
match value {
AsymmetricAlgorithm::Rsa => Ok(AsymmetricAlgorithmSelection::Rsa2048),
AsymmetricAlgorithm::Ecc => Ok(AsymmetricAlgorithmSelection::EccP256),
AsymmetricAlgorithm::Null => {
Err(Error::local_error(WrapperErrorKind::UnsupportedParam))
}
}
}
}

impl TryFrom<AsymmetricAlgorithmSelection> for RsaKeyBits {
type Error = Error;

fn try_from(value: AsymmetricAlgorithmSelection) -> std::result::Result<Self, Self::Error> {
match value {
AsymmetricAlgorithmSelection::Rsa2048 => Ok(RsaKeyBits::Rsa2048),
AsymmetricAlgorithmSelection::Rsa3072 => Ok(RsaKeyBits::Rsa3072),
AsymmetricAlgorithmSelection::Rsa4096 => Ok(RsaKeyBits::Rsa4096),
_ => Err(Error::local_error(WrapperErrorKind::InvalidParam)),
}
}
}

impl TryFrom<AsymmetricAlgorithmSelection> for EccCurve {
type Error = Error;

fn try_from(value: AsymmetricAlgorithmSelection) -> std::result::Result<Self, Self::Error> {
match value {
AsymmetricAlgorithmSelection::EccP256 => Ok(EccCurve::NistP256),
AsymmetricAlgorithmSelection::EccP384 => Ok(EccCurve::NistP384),
AsymmetricAlgorithmSelection::EccP521 => Ok(EccCurve::NistP521),
AsymmetricAlgorithmSelection::EccP256Sm2 => Ok(EccCurve::Sm2P256),
_ => Err(Error::local_error(WrapperErrorKind::InvalidParam)),
}
}
}

/// Get the [`Public`] representing a default Endorsement Key
///
/// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
/// Appendix B.3.3 and B.3.4
pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
alg: AsymmetricAlgorithm,
alg: AsymmetricAlgorithmSelection,
key_customization: IKC,
) -> Result<Public> {
let key_customization = key_customization.into_key_customization();
Expand Down Expand Up @@ -65,7 +126,9 @@ pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
];

let key_builder = match alg {
AsymmetricAlgorithm::Rsa => PublicBuilder::new()
AsymmetricAlgorithmSelection::Rsa2048
| AsymmetricAlgorithmSelection::Rsa3072
| AsymmetricAlgorithmSelection::Rsa4096 => PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Rsa)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(obj_attrs)
Expand All @@ -74,15 +137,18 @@ pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
PublicRsaParametersBuilder::new()
.with_symmetric(SymmetricDefinitionObject::AES_128_CFB)
.with_scheme(RsaScheme::Null)
.with_key_bits(RsaKeyBits::Rsa2048)
.with_key_bits(alg.try_into()?)
.with_exponent(RsaExponent::default())
.with_is_signing_key(obj_attrs.sign_encrypt())
.with_is_decryption_key(obj_attrs.decrypt())
.with_restricted(obj_attrs.decrypt())
.build()?,
)
.with_rsa_unique_identifier(PublicKeyRsa::new_empty_with_size(RsaKeyBits::Rsa2048)),
AsymmetricAlgorithm::Ecc => PublicBuilder::new()
AsymmetricAlgorithmSelection::EccP256
| AsymmetricAlgorithmSelection::EccP384
| AsymmetricAlgorithmSelection::EccP521
| AsymmetricAlgorithmSelection::EccP256Sm2 => PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(obj_attrs)
Expand All @@ -91,7 +157,7 @@ pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
PublicEccParametersBuilder::new()
.with_symmetric(SymmetricDefinitionObject::AES_128_CFB)
.with_ecc_scheme(EccScheme::Null)
.with_curve(EccCurve::NistP256)
.with_curve(alg.try_into()?)
.with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
.with_is_signing_key(obj_attrs.sign_encrypt())
.with_is_decryption_key(obj_attrs.decrypt())
Expand All @@ -102,10 +168,6 @@ pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
EccParameter::try_from(vec![0u8; 32])?,
EccParameter::try_from(vec![0u8; 32])?,
)),
AsymmetricAlgorithm::Null => {
// TDOD: Figure out what to with Null.
return Err(Error::local_error(WrapperErrorKind::UnsupportedParam));
}
};

let key_builder = if let Some(ref k) = key_customization {
Expand All @@ -119,7 +181,7 @@ pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
/// Create the Endorsement Key object from the specification templates
pub fn create_ek_object<IKC: IntoKeyCustomization>(
context: &mut Context,
alg: AsymmetricAlgorithm,
alg: AsymmetricAlgorithmSelection,
key_customization: IKC,
) -> Result<KeyHandle> {
let ek_public = create_ek_public_from_default_template(alg, key_customization)?;
Expand All @@ -132,14 +194,18 @@ pub fn create_ek_object<IKC: IntoKeyCustomization>(
}

/// Retrieve the Endorsement Key public certificate from the TPM
pub fn retrieve_ek_pubcert(context: &mut Context, alg: AsymmetricAlgorithm) -> Result<Vec<u8>> {
pub fn retrieve_ek_pubcert(
context: &mut Context,
alg: AsymmetricAlgorithmSelection,
) -> Result<Vec<u8>> {
let nv_idx = match alg {
AsymmetricAlgorithm::Rsa => RSA_2048_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithm::Ecc => ECC_P256_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithm::Null => {
// TDOD: Figure out what to with Null.
return Err(Error::local_error(WrapperErrorKind::UnsupportedParam));
}
AsymmetricAlgorithmSelection::Rsa2048 => RSA_2048_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::Rsa3072 => RSA_3072_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::Rsa4096 => RSA_4096_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::EccP256 => ECC_P256_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::EccP384 => ECC_P384_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::EccP521 => ECC_P521_EK_CERTIFICATE_NV_INDEX,
AsymmetricAlgorithmSelection::EccP256Sm2 => ECC_P256_SM2_EK_CERTIFICATE_NV_INDEX,
};

let nv_idx = NvIndexTpmHandle::new(nv_idx).unwrap();
Expand Down
22 changes: 13 additions & 9 deletions tss-esapi/src/abstraction/transient/key_attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
constants::SessionType,
handles::{AuthHandle, KeyHandle, SessionHandle},
interface_types::{
algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
algorithm::HashingAlgorithm,
session_handles::{AuthSession, PolicySession},
},
structures::{EncryptedSecret, IdObject, SymmetricDefinition},
Expand Down Expand Up @@ -154,13 +154,16 @@ impl TransientKeyContext {
None,
);
Ok((
ek::create_ek_object(&mut self.context, AsymmetricAlgorithm::Rsa, None).or_else(
|e| {
self.context
.flush_context(SessionHandle::from(session).into())?;
Err(e)
},
)?,
ek::create_ek_object(
&mut self.context,
ek::AsymmetricAlgorithmSelection::Rsa2048,
None,
)
.or_else(|e| {
self.context
.flush_context(SessionHandle::from(session).into())?;
Err(e)
})?,
session,
))
}
Expand Down Expand Up @@ -191,7 +194,8 @@ impl TransientKeyContext {
}

fn get_ek_object_public(context: &mut crate::Context) -> Result<PublicKey> {
let key_handle = ek::create_ek_object(context, AsymmetricAlgorithm::Rsa, None)?;
let key_handle =
ek::create_ek_object(context, ek::AsymmetricAlgorithmSelection::Rsa2048, None)?;
let (attesting_key_pub, _, _) = context.read_public(key_handle).or_else(|e| {
context.flush_context(key_handle.into())?;
Err(e)
Expand Down
15 changes: 10 additions & 5 deletions tss-esapi/tests/integration_tests/abstraction_tests/ak_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
use std::convert::{TryFrom, TryInto};

use tss_esapi::{
abstraction::ek::AsymmetricAlgorithmSelection,
abstraction::{ak, ek, KeyCustomization},
attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
constants::SessionType,
handles::AuthHandle,
interface_types::{
algorithm::{AsymmetricAlgorithm, HashingAlgorithm, SignatureSchemeAlgorithm},
algorithm::{HashingAlgorithm, SignatureSchemeAlgorithm},
session_handles::PolicySession,
},
structures::{Auth, Digest, PublicBuilder, SymmetricDefinition},
Expand All @@ -21,7 +22,8 @@ use crate::common::create_ctx_without_session;
fn test_create_ak_rsa_rsa() {
let mut context = create_ctx_without_session();

let ek_rsa = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Rsa, None).unwrap();
let ek_rsa =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::Rsa2048, None).unwrap();
ak::create_ak(
&mut context,
ek_rsa,
Expand All @@ -37,7 +39,8 @@ fn test_create_ak_rsa_rsa() {
fn test_create_ak_rsa_ecc() {
let mut context = create_ctx_without_session();

let ek_rsa = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Rsa, None).unwrap();
let ek_rsa =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::Rsa2048, None).unwrap();
if ak::create_ak(
&mut context,
ek_rsa,
Expand All @@ -57,7 +60,8 @@ fn test_create_ak_rsa_ecc() {
fn test_create_and_use_ak() {
let mut context = create_ctx_without_session();

let ek_rsa = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Rsa, None).unwrap();
let ek_rsa =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::Rsa2048, None).unwrap();
let ak_auth = Auth::try_from(vec![0x1, 0x2, 0x42]).unwrap();
let att_key = ak::create_ak(
&mut context,
Expand Down Expand Up @@ -158,7 +162,8 @@ fn test_create_custom_ak() {
}
let mut context = create_ctx_without_session();

let ek_rsa = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Rsa, None).unwrap();
let ek_rsa =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::Rsa2048, None).unwrap();
let ak_auth = Auth::try_from(vec![0x1, 0x2, 0x42]).unwrap();
// Without customization, no st clear
let att_key_without = ak::create_ak(
Expand Down
14 changes: 8 additions & 6 deletions tss-esapi/tests/integration_tests/abstraction_tests/ek_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

use tss_esapi::{
abstraction::ek, constants::return_code::TpmFormatOneError, error::TpmResponseCode,
interface_types::algorithm::AsymmetricAlgorithm, Error, ReturnCode,
abstraction::ek, abstraction::ek::AsymmetricAlgorithmSelection,
constants::return_code::TpmFormatOneError, error::TpmResponseCode, Error, ReturnCode,
};

use crate::common::create_ctx_without_session;
Expand All @@ -14,14 +14,14 @@ fn test_retrieve_ek_pubcert() {

// The error 395 is for "handle could not be found" - this makes it that if the NV Index
// did not exist (the test is run on a TPM without an endorsement cert), it still passes.
match ek::retrieve_ek_pubcert(&mut context, AsymmetricAlgorithm::Rsa) {
match ek::retrieve_ek_pubcert(&mut context, AsymmetricAlgorithmSelection::Rsa2048) {
Ok(_) => (),
Err(Error::TssError(ReturnCode::Tpm(TpmResponseCode::FormatOne(error)))) => {
assert_eq!(error.error_number(), TpmFormatOneError::Handle)
}
Err(e) => panic!("Error was unexpected: {:?}", e),
};
match ek::retrieve_ek_pubcert(&mut context, AsymmetricAlgorithm::Ecc) {
match ek::retrieve_ek_pubcert(&mut context, AsymmetricAlgorithmSelection::EccP256) {
Ok(_) => (),
Err(Error::TssError(ReturnCode::Tpm(TpmResponseCode::FormatOne(error)))) => {
assert_eq!(error.error_number(), TpmFormatOneError::Handle)
Expand All @@ -34,6 +34,8 @@ fn test_retrieve_ek_pubcert() {
fn test_create_ek() {
let mut context = create_ctx_without_session();

let _ = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Rsa, None).unwrap();
let _ = ek::create_ek_object(&mut context, AsymmetricAlgorithm::Ecc, None).unwrap();
let _ =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::Rsa2048, None).unwrap();
let _ =
ek::create_ek_object(&mut context, AsymmetricAlgorithmSelection::EccP256, None).unwrap();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
use std::convert::{TryFrom, TryInto};
use tss_esapi::{
abstraction::ek,
abstraction::ek::AsymmetricAlgorithmSelection,
abstraction::transient::{KeyParams, ObjectWrapper, TransientKeyContextBuilder},
constants::return_code::{TpmFormatOneError, TpmFormatZeroError},
error::{TpmFormatZeroResponseCode, TpmResponseCode},
interface_types::{
algorithm::{
AsymmetricAlgorithm, EccSchemeAlgorithm, HashingAlgorithm, RsaSchemeAlgorithm,
},
algorithm::{EccSchemeAlgorithm, HashingAlgorithm, RsaSchemeAlgorithm},
ecc::EccCurve,
key_bits::RsaKeyBits,
resource_handles::Hierarchy,
Expand Down Expand Up @@ -631,7 +630,8 @@ fn activate_credential() {

// the public part of the EK is used, so we retrieve the parameters
let key_pub =
ek::create_ek_public_from_default_template(AsymmetricAlgorithm::Rsa, None).unwrap();
ek::create_ek_public_from_default_template(AsymmetricAlgorithmSelection::Rsa2048, None)
.unwrap();
let key_pub = if let Public::Rsa {
object_attributes,
name_hashing_algorithm,
Expand Down Expand Up @@ -755,7 +755,8 @@ fn activate_credential_wrong_key() {

// the public part of the EK is used, so we retrieve the parameters
let key_pub =
ek::create_ek_public_from_default_template(AsymmetricAlgorithm::Rsa, None).unwrap();
ek::create_ek_public_from_default_template(AsymmetricAlgorithmSelection::Rsa2048, None)
.unwrap();
let key_pub = if let Public::Rsa {
object_attributes,
name_hashing_algorithm,
Expand Down

0 comments on commit 9ba573f

Please sign in to comment.