tss_esapi/utils/
mod.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Utility module
4//!
5//! This module mostly contains helper elements meant to act as either wrappers around FFI-level
6//! structs or builders for them, along with other convenience elements.
7//! The naming structure usually takes the names inherited from the TSS spec and applies Rust
8//! guidelines to them. Structures that are meant to act as builders have `Builder` appended to
9//! type name. Unions are converted to Rust `enum`s by dropping the `TPMU` qualifier and appending
10//! `Union`.
11use crate::attributes::ObjectAttributesBuilder;
12use crate::constants::PropertyTag;
13use crate::interface_types::{
14    algorithm::{HashingAlgorithm, PublicAlgorithm},
15    ecc::EccCurve,
16    key_bits::RsaKeyBits,
17};
18use crate::structures::{
19    EccPoint, EccScheme, Public, PublicBuilder, PublicEccParametersBuilder, PublicKeyRsa,
20    PublicRsaParametersBuilder, RsaExponent, RsaScheme, SymmetricDefinitionObject,
21};
22use crate::tss2_esys::*;
23use crate::{Context, Error, Result, WrapperErrorKind};
24use zeroize::Zeroize;
25
26use serde::{Deserialize, Serialize};
27use std::convert::{TryFrom, TryInto};
28
29/// Rust native wrapper for `TPMS_CONTEXT` objects.
30///
31/// This structure is intended to help with persisting object contexts. As the main reason for
32/// saving the context of an object is to be able to reuse it later, on demand, a serializable
33/// structure is most commonly needed. `TpmsContext` implements the `Serialize` and `Deserialize`
34/// defined by `serde`.
35#[derive(Debug, Serialize, Deserialize, Clone, Zeroize)]
36#[zeroize(drop)]
37pub struct TpmsContext {
38    sequence: u64,
39    saved_handle: TPMI_DH_CONTEXT,
40    hierarchy: TPMI_RH_HIERARCHY,
41    context_blob: Vec<u8>,
42}
43
44impl TpmsContext {
45    /// Get a reference to the `context_blob` field
46    pub fn context_blob(&self) -> &Vec<u8> {
47        &self.context_blob
48    }
49}
50
51// TODO: Replace with `From`
52impl TryFrom<TPMS_CONTEXT> for TpmsContext {
53    type Error = Error;
54
55    fn try_from(tss2_context: TPMS_CONTEXT) -> Result<Self> {
56        let mut context = TpmsContext {
57            sequence: tss2_context.sequence,
58            saved_handle: tss2_context.savedHandle,
59            hierarchy: tss2_context.hierarchy,
60            context_blob: tss2_context.contextBlob.buffer.to_vec(),
61        };
62        context
63            .context_blob
64            .truncate(tss2_context.contextBlob.size.into());
65        Ok(context)
66    }
67}
68
69#[allow(clippy::needless_update)]
70impl TryFrom<TpmsContext> for TPMS_CONTEXT {
71    type Error = Error;
72
73    fn try_from(context: TpmsContext) -> Result<Self> {
74        let buffer_size = context.context_blob.len();
75        if buffer_size > 5188 {
76            return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
77        }
78        let mut buffer = [0_u8; 5188];
79        for (i, val) in context.context_blob.iter().enumerate() {
80            buffer[i] = *val;
81        }
82        Ok(TPMS_CONTEXT {
83            sequence: context.sequence,
84            savedHandle: context.saved_handle,
85            hierarchy: context.hierarchy,
86            contextBlob: TPM2B_CONTEXT_DATA {
87                size: buffer_size.try_into().unwrap(), // should not panic given the check above
88                buffer,
89            },
90            ..Default::default()
91        })
92    }
93}
94
95/// Create the [Public] structure for a restricted decryption key.
96///
97/// * `symmetric` - Cipher to be used for decrypting children of the key
98/// * `key_bits` - Size in bits of the decryption key
99/// * `pub_exponent` - Public exponent of the RSA key
100pub fn create_restricted_decryption_rsa_public(
101    symmetric: SymmetricDefinitionObject,
102    rsa_key_bits: RsaKeyBits,
103    rsa_pub_exponent: RsaExponent,
104) -> Result<Public> {
105    let object_attributes = ObjectAttributesBuilder::new()
106        .with_fixed_tpm(true)
107        .with_fixed_parent(true)
108        .with_sensitive_data_origin(true)
109        .with_user_with_auth(true)
110        .with_decrypt(true)
111        .with_sign_encrypt(false)
112        .with_restricted(true)
113        .build()?;
114
115    PublicBuilder::new()
116        .with_public_algorithm(PublicAlgorithm::Rsa)
117        .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
118        .with_object_attributes(object_attributes)
119        .with_rsa_parameters(
120            PublicRsaParametersBuilder::new_restricted_decryption_key(
121                symmetric,
122                rsa_key_bits,
123                rsa_pub_exponent,
124            )
125            .build()?,
126        )
127        .with_rsa_unique_identifier(PublicKeyRsa::default())
128        .build()
129}
130
131/// Create the [Public] structure for an unrestricted encryption/decryption key.
132///
133/// * `symmetric` - Cipher to be used for decrypting children of the key
134/// * `key_bits` - Size in bits of the decryption key
135/// * `pub_exponent` - Public exponent of the RSA key
136pub fn create_unrestricted_encryption_decryption_rsa_public(
137    rsa_key_bits: RsaKeyBits,
138    rsa_pub_exponent: RsaExponent,
139) -> Result<Public> {
140    let object_attributes = ObjectAttributesBuilder::new()
141        .with_fixed_tpm(true)
142        .with_fixed_parent(true)
143        .with_sensitive_data_origin(true)
144        .with_user_with_auth(true)
145        .with_decrypt(true)
146        .with_sign_encrypt(true)
147        .with_restricted(false)
148        .build()?;
149
150    PublicBuilder::new()
151        .with_public_algorithm(PublicAlgorithm::Rsa)
152        .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
153        .with_object_attributes(object_attributes)
154        .with_rsa_parameters(
155            PublicRsaParametersBuilder::new()
156                .with_scheme(RsaScheme::Null)
157                .with_key_bits(rsa_key_bits)
158                .with_exponent(rsa_pub_exponent)
159                .with_is_signing_key(true)
160                .with_is_decryption_key(true)
161                .with_restricted(false)
162                .build()?,
163        )
164        .with_rsa_unique_identifier(PublicKeyRsa::default())
165        .build()
166}
167
168/// Create the [Public] structure for an RSA unrestricted signing key.
169///
170/// * `scheme` - RSA scheme to be used for signing
171/// * `key_bits` - Size in bits of the decryption key
172/// * `pub_exponent` - Public exponent of the RSA key
173pub fn create_unrestricted_signing_rsa_public(
174    scheme: RsaScheme,
175    rsa_key_bits: RsaKeyBits,
176    rsa_pub_exponent: RsaExponent,
177) -> Result<Public> {
178    let object_attributes = ObjectAttributesBuilder::new()
179        .with_fixed_tpm(true)
180        .with_fixed_parent(true)
181        .with_sensitive_data_origin(true)
182        .with_user_with_auth(true)
183        .with_decrypt(false)
184        .with_sign_encrypt(true)
185        .with_restricted(false)
186        .build()?;
187
188    PublicBuilder::new()
189        .with_public_algorithm(PublicAlgorithm::Rsa)
190        .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
191        .with_object_attributes(object_attributes)
192        .with_rsa_parameters(
193            PublicRsaParametersBuilder::new_unrestricted_signing_key(
194                scheme,
195                rsa_key_bits,
196                rsa_pub_exponent,
197            )
198            .build()?,
199        )
200        .with_rsa_unique_identifier(PublicKeyRsa::default())
201        .build()
202}
203
204/// Create the [Public] structure for an RSA unrestricted signing key.
205///
206/// * `scheme` - RSA scheme to be used for signing
207/// * `key_bits` - Size in bits of the decryption key
208/// * `pub_exponent` - Public exponent of the RSA key
209/// * `rsa_public_key` - The public part of the RSA key that is going to be used as unique identifier.
210pub fn create_unrestricted_signing_rsa_public_with_unique(
211    scheme: RsaScheme,
212    rsa_key_bits: RsaKeyBits,
213    rsa_pub_exponent: RsaExponent,
214    rsa_public_key: PublicKeyRsa,
215) -> Result<Public> {
216    let object_attributes = ObjectAttributesBuilder::new()
217        .with_fixed_tpm(true)
218        .with_fixed_parent(true)
219        .with_sensitive_data_origin(true)
220        .with_user_with_auth(true)
221        .with_decrypt(false)
222        .with_sign_encrypt(true)
223        .with_restricted(false)
224        .build()?;
225
226    PublicBuilder::new()
227        .with_public_algorithm(PublicAlgorithm::Rsa)
228        .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
229        .with_object_attributes(object_attributes)
230        .with_rsa_parameters(
231            PublicRsaParametersBuilder::new_unrestricted_signing_key(
232                scheme,
233                rsa_key_bits,
234                rsa_pub_exponent,
235            )
236            .build()?,
237        )
238        .with_rsa_unique_identifier(rsa_public_key)
239        .build()
240}
241
242/// Create the [Public] structure for an ECC unrestricted signing key.
243///
244/// * `scheme` - Asymmetric scheme to be used for signing; *must* be an RSA signing scheme
245/// * `curve` - identifier of the precise curve to be used with the key
246pub fn create_unrestricted_signing_ecc_public(
247    scheme: EccScheme,
248    curve: EccCurve,
249) -> Result<Public> {
250    let object_attributes = ObjectAttributesBuilder::new()
251        .with_fixed_tpm(true)
252        .with_fixed_parent(true)
253        .with_sensitive_data_origin(true)
254        .with_user_with_auth(true)
255        .with_decrypt(false)
256        .with_sign_encrypt(true)
257        .with_restricted(false)
258        .build()?;
259
260    PublicBuilder::new()
261        .with_public_algorithm(PublicAlgorithm::Ecc)
262        .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
263        .with_object_attributes(object_attributes)
264        .with_ecc_parameters(
265            PublicEccParametersBuilder::new_unrestricted_signing_key(scheme, curve).build()?,
266        )
267        .with_ecc_unique_identifier(EccPoint::default())
268        .build()
269}
270
271/// Container for public key values
272#[derive(Debug, Clone, Serialize, Deserialize, Zeroize, PartialEq, Eq)]
273pub enum PublicKey {
274    /// RSA public modulus (see 27.5.3.4 in the Architecture spec)
275    ///
276    /// This is the value extracted from the `unique` part of `TPMT_PUBLIC`.
277    /// The exponent is not included here as the expectation is that the
278    /// exponent is always pinned to 65537 (2^16 + 1).
279    ///
280    /// The modulus is in Big-Endian format.
281    Rsa(Vec<u8>),
282    /// Public elliptic curve point (see 27.5.3.5 in the Architecture spec)
283    ///
284    /// The x and y coordinates are given uncompressed.
285    Ecc { x: Vec<u8>, y: Vec<u8> },
286}
287
288impl TryFrom<Public> for PublicKey {
289    type Error = Error;
290
291    fn try_from(public: Public) -> Result<Self> {
292        match public {
293            Public::Rsa { unique, .. } => Ok(PublicKey::Rsa(unique.value().to_vec())),
294            Public::Ecc { unique, .. } => Ok(PublicKey::Ecc {
295                x: unique.x().value().to_vec(),
296                y: unique.y().value().to_vec(),
297            }),
298            _ => Err(Error::local_error(WrapperErrorKind::WrongValueFromTpm)),
299        }
300    }
301}
302
303fn tpm_int_to_string(num: u32) -> String {
304    num.to_be_bytes()
305        .iter()
306        .filter(|x| **x != 0)
307        .map(|x| char::from(*x))
308        .collect()
309}
310
311/// Get the TPM vendor name
312pub fn get_tpm_vendor(context: &mut Context) -> Result<String> {
313    // Retrieve the TPM property values
314    Ok([
315        PropertyTag::VendorString1,
316        PropertyTag::VendorString2,
317        PropertyTag::VendorString3,
318        PropertyTag::VendorString4,
319    ]
320    .iter()
321    // Retrieve property values
322    .map(|prop_id| context.get_tpm_property(*prop_id))
323    // Collect and return an error if we got one
324    .collect::<Result<Vec<Option<u32>>>>()?
325    .iter()
326    // Filter out the Option::None values
327    .filter_map(|x| *x)
328    // Filter out zero values
329    .filter(|x| *x != 0)
330    // Map through int_to_string
331    .map(tpm_int_to_string)
332    // Collect to a single string
333    .collect())
334}