tss_esapi/abstraction/
ek.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    abstraction::{nv, AsymmetricAlgorithmSelection, IntoKeyCustomization, KeyCustomization},
6    attributes::ObjectAttributesBuilder,
7    handles::{KeyHandle, NvIndexTpmHandle, TpmHandle},
8    interface_types::{
9        algorithm::{AsymmetricAlgorithm, HashingAlgorithm, PublicAlgorithm},
10        ecc::EccCurve,
11        key_bits::RsaKeyBits,
12        resource_handles::{Hierarchy, NvAuth},
13    },
14    structures::{
15        Digest, EccParameter, EccPoint, EccScheme, KeyDerivationFunctionScheme, Public,
16        PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa, PublicRsaParametersBuilder,
17        RsaExponent, RsaScheme, SymmetricDefinitionObject,
18    },
19    Context, Error, Result, WrapperErrorKind,
20};
21use std::convert::TryFrom;
22// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
23// Section 2.2.1.4 (Low Range) for Windows compatibility
24const RSA_2048_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00002;
25const ECC_P256_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0000a;
26
27// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
28// Section 2.2.1.5 (High Range)
29const ECC_P384_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00016;
30const ECC_P521_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00018;
31const ECC_P256_SM2_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001a;
32const RSA_3072_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001c;
33const RSA_4096_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0001e;
34
35// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.5 Revision 2
36// Section B.3 and B.4
37const AUTH_POLICY_A_SHA256: [u8; 32] = [
38    0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8, 0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24,
39    0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64, 0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa,
40];
41const AUTH_POLICY_B_SHA384: [u8; 48] = [
42    0xb2, 0x6e, 0x7d, 0x28, 0xd1, 0x1a, 0x50, 0xbc, 0x53, 0xd8, 0x82, 0xbc, 0xf5, 0xfd, 0x3a, 0x1a,
43    0x07, 0x41, 0x48, 0xbb, 0x35, 0xd3, 0xb4, 0xe4, 0xcb, 0x1c, 0x0a, 0xd9, 0xbd, 0xe4, 0x19, 0xca,
44    0xcb, 0x47, 0xba, 0x09, 0x69, 0x96, 0x46, 0x15, 0x0f, 0x9f, 0xc0, 0x00, 0xf3, 0xf8, 0x0e, 0x12,
45];
46const AUTH_POLICY_B_SHA512: [u8; 64] = [
47    0xb8, 0x22, 0x1c, 0xa6, 0x9e, 0x85, 0x50, 0xa4, 0x91, 0x4d, 0xe3, 0xfa, 0xa6, 0xa1, 0x8c, 0x07,
48    0x2c, 0xc0, 0x12, 0x08, 0x07, 0x3a, 0x92, 0x8d, 0x5d, 0x66, 0xd5, 0x9e, 0xf7, 0x9e, 0x49, 0xa4,
49    0x29, 0xc4, 0x1a, 0x6b, 0x26, 0x95, 0x71, 0xd5, 0x7e, 0xdb, 0x25, 0xfb, 0xdb, 0x18, 0x38, 0x42,
50    0x56, 0x08, 0xb4, 0x13, 0xcd, 0x61, 0x6a, 0x5f, 0x6d, 0xb5, 0xb6, 0x07, 0x1a, 0xf9, 0x9b, 0xea,
51];
52const AUTH_POLICY_B_SM3_256: [u8; 32] = [
53    0x16, 0x78, 0x60, 0xa3, 0x5f, 0x2c, 0x5c, 0x35, 0x67, 0xf9, 0xc9, 0x27, 0xac, 0x56, 0xc0, 0x32,
54    0xf3, 0xb3, 0xa6, 0x46, 0x2f, 0x8d, 0x03, 0x79, 0x98, 0xe7, 0xa1, 0x0f, 0x77, 0xfa, 0x45, 0x4a,
55];
56
57/// Get the [`Public`] representing a default Endorsement Key
58///
59/// **Note**: This only works for key algorithms specified in TCG EK Credential Profile for TPM Family 2.0.
60///
61/// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
62/// Appendix B.3.3 and B.3.4
63///
64/// <div class="warning">
65///
66/// The API of this function will be changed to that of [`create_ek_public_from_default_template_2`]
67/// in the next major version.
68///
69/// </div>
70pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
71    alg: AsymmetricAlgorithm,
72    key_customization: IKC,
73) -> Result<Public> {
74    create_ek_public_from_default_template_2(
75        AsymmetricAlgorithmSelection::try_from(alg)?,
76        key_customization,
77    )
78}
79
80/// Get the [`Public`] representing a default Endorsement Key
81///
82/// **Note**: This only works for key algorithms specified in TCG EK Credential Profile for TPM Family 2.0.
83///
84/// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
85/// Appendix B.3.3 and B.3.4
86///
87/// <div class="warning">
88///
89/// This function will be removed in the next major version.
90///
91/// </div>
92pub fn create_ek_public_from_default_template_2<IKC: IntoKeyCustomization>(
93    alg: AsymmetricAlgorithmSelection,
94    key_customization: IKC,
95) -> Result<Public> {
96    let key_customization = key_customization.into_key_customization();
97
98    // user_with_auth is not set for the lower profiles (RSA 2048 and ECC P256)
99    let user_with_auth = !matches!(
100        alg,
101        AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048)
102            | AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256)
103    );
104
105    let obj_attrs_builder = ObjectAttributesBuilder::new()
106        .with_fixed_tpm(true)
107        .with_st_clear(false)
108        .with_fixed_parent(true)
109        .with_sensitive_data_origin(true)
110        .with_user_with_auth(user_with_auth)
111        .with_admin_with_policy(true)
112        .with_no_da(false)
113        .with_encrypted_duplication(false)
114        .with_restricted(true)
115        .with_decrypt(true)
116        .with_sign_encrypt(false);
117
118    let obj_attrs = if let Some(ref k) = key_customization {
119        k.attributes(obj_attrs_builder)
120    } else {
121        obj_attrs_builder
122    }
123    .build()?;
124
125    let key_builder = match alg {
126        AsymmetricAlgorithmSelection::Rsa(key_bits) => {
127            let (hash_alg, auth_policy, symmetric, unique) = match key_bits {
128                RsaKeyBits::Rsa2048 => (
129                    HashingAlgorithm::Sha256,
130                    Digest::try_from(AUTH_POLICY_A_SHA256.as_slice())?,
131                    SymmetricDefinitionObject::AES_128_CFB,
132                    PublicKeyRsa::new_empty_with_size(RsaKeyBits::Rsa2048),
133                ),
134                RsaKeyBits::Rsa3072 | RsaKeyBits::Rsa4096 => (
135                    HashingAlgorithm::Sha384,
136                    Digest::try_from(AUTH_POLICY_B_SHA384.as_slice())?,
137                    SymmetricDefinitionObject::AES_256_CFB,
138                    PublicKeyRsa::default(),
139                ),
140                // Other key sizes are not supported in the spec, so return a error
141                _ => return Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
142            };
143
144            PublicBuilder::new()
145                .with_public_algorithm(PublicAlgorithm::Rsa)
146                .with_name_hashing_algorithm(hash_alg)
147                .with_object_attributes(obj_attrs)
148                .with_auth_policy(auth_policy)
149                .with_rsa_parameters(
150                    PublicRsaParametersBuilder::new()
151                        .with_symmetric(symmetric)
152                        .with_scheme(RsaScheme::Null)
153                        .with_key_bits(key_bits)
154                        .with_exponent(RsaExponent::default())
155                        .with_is_signing_key(obj_attrs.sign_encrypt())
156                        .with_is_decryption_key(obj_attrs.decrypt())
157                        .with_restricted(obj_attrs.decrypt())
158                        .build()?,
159                )
160                .with_rsa_unique_identifier(unique)
161        }
162        AsymmetricAlgorithmSelection::Ecc(ecc_curve) => {
163            let (hash_alg, auth_policy, symmetric, xy_size) = match ecc_curve {
164                EccCurve::NistP256 => (
165                    HashingAlgorithm::Sha256,
166                    Digest::try_from(AUTH_POLICY_A_SHA256.as_slice())?,
167                    SymmetricDefinitionObject::AES_128_CFB,
168                    32,
169                ),
170                EccCurve::NistP384 => (
171                    HashingAlgorithm::Sha384,
172                    Digest::try_from(AUTH_POLICY_B_SHA384.as_slice())?,
173                    SymmetricDefinitionObject::AES_256_CFB,
174                    0,
175                ),
176                EccCurve::NistP521 => (
177                    HashingAlgorithm::Sha512,
178                    Digest::try_from(AUTH_POLICY_B_SHA512.as_slice())?,
179                    SymmetricDefinitionObject::AES_256_CFB,
180                    0,
181                ),
182                EccCurve::Sm2P256 => (
183                    HashingAlgorithm::Sm3_256,
184                    Digest::try_from(AUTH_POLICY_B_SM3_256.as_slice())?,
185                    SymmetricDefinitionObject::SM4_128_CFB,
186                    0,
187                ),
188                // Other curves are not supported in the spec, so return a error
189                _ => return Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
190            };
191            PublicBuilder::new()
192                .with_public_algorithm(PublicAlgorithm::Ecc)
193                .with_name_hashing_algorithm(hash_alg)
194                .with_object_attributes(obj_attrs)
195                .with_auth_policy(auth_policy)
196                .with_ecc_parameters(
197                    PublicEccParametersBuilder::new()
198                        .with_symmetric(symmetric)
199                        .with_ecc_scheme(EccScheme::Null)
200                        .with_curve(ecc_curve)
201                        .with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
202                        .with_is_signing_key(obj_attrs.sign_encrypt())
203                        .with_is_decryption_key(obj_attrs.decrypt())
204                        .with_restricted(obj_attrs.decrypt())
205                        .build()?,
206                )
207                .with_ecc_unique_identifier(EccPoint::new(
208                    EccParameter::try_from(vec![0u8; xy_size])?,
209                    EccParameter::try_from(vec![0u8; xy_size])?,
210                ))
211        }
212    };
213
214    let key_builder = if let Some(ref k) = key_customization {
215        k.template(key_builder)
216    } else {
217        key_builder
218    };
219    key_builder.build()
220}
221
222/// Create the Endorsement Key object from the specification templates
223///
224/// <div class="warning">
225///
226/// The API of this function will be changed to that of [`create_ek_object_2`]
227/// in the next major version.
228///
229/// </div>
230pub fn create_ek_object<IKC: IntoKeyCustomization>(
231    context: &mut Context,
232    alg: AsymmetricAlgorithm,
233    key_customization: IKC,
234) -> Result<KeyHandle> {
235    create_ek_object_2(
236        context,
237        AsymmetricAlgorithmSelection::try_from(alg)?,
238        key_customization,
239    )
240}
241
242/// Create the Endorsement Key object from the specification templates
243///
244/// <div class="warning">
245///
246/// This function will be removed in the next major version.
247///
248/// </div>
249pub fn create_ek_object_2<IKC: IntoKeyCustomization>(
250    context: &mut Context,
251    alg: AsymmetricAlgorithmSelection,
252    key_customization: IKC,
253) -> Result<KeyHandle> {
254    let ek_public = create_ek_public_from_default_template_2(alg, key_customization)?;
255
256    Ok(context
257        .execute_with_nullauth_session(|ctx| {
258            ctx.create_primary(Hierarchy::Endorsement, ek_public, None, None, None, None)
259        })?
260        .key_handle)
261}
262
263/// Retrieve the Endorsement Key public certificate from the TPM
264pub fn retrieve_ek_pubcert(
265    context: &mut Context,
266    alg: AsymmetricAlgorithmSelection,
267) -> Result<Vec<u8>> {
268    let nv_idx = match alg {
269        AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048) => RSA_2048_EK_CERTIFICATE_NV_INDEX,
270        AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa3072) => RSA_3072_EK_CERTIFICATE_NV_INDEX,
271        AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa4096) => RSA_4096_EK_CERTIFICATE_NV_INDEX,
272        AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256) => ECC_P256_EK_CERTIFICATE_NV_INDEX,
273        AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP384) => ECC_P384_EK_CERTIFICATE_NV_INDEX,
274        AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP521) => ECC_P521_EK_CERTIFICATE_NV_INDEX,
275        AsymmetricAlgorithmSelection::Ecc(EccCurve::Sm2P256) => {
276            ECC_P256_SM2_EK_CERTIFICATE_NV_INDEX
277        }
278        _ => return Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
279    };
280
281    let nv_idx = NvIndexTpmHandle::new(nv_idx).unwrap();
282
283    let nv_auth_handle = TpmHandle::NvIndex(nv_idx);
284    let nv_auth_handle = context.execute_without_session(|ctx| {
285        ctx.tr_from_tpm_public(nv_auth_handle)
286            .map(|v| NvAuth::NvIndex(v.into()))
287    })?;
288
289    context.execute_with_nullauth_session(|ctx| nv::read_full(ctx, nv_auth_handle, nv_idx))
290}