Skip to main content

tss_esapi/structures/tagged/
public.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3pub mod ecc;
4pub mod keyed_hash;
5pub mod rsa;
6
7use crate::{
8    attributes::ObjectAttributes,
9    interface_types::algorithm::{HashingAlgorithm, PublicAlgorithm},
10    structures::{
11        Digest, EccPoint, PublicKeyRsa, SymmetricCipherParameters, SymmetricDefinitionObject,
12    },
13    traits::{Marshall, UnMarshall},
14    tss2_esys::{TPM2B_PUBLIC, TPMT_PUBLIC},
15    Error, Result, WrapperErrorKind,
16};
17
18use ecc::PublicEccParameters;
19use keyed_hash::PublicKeyedHashParameters;
20use rsa::PublicRsaParameters;
21
22use log::error;
23use std::{
24    convert::{TryFrom, TryInto},
25    mem::size_of,
26};
27use tss_esapi_sys::{TPMU_PUBLIC_ID, TPMU_PUBLIC_PARMS};
28
29/// A builder for the [Public] type.
30#[derive(Debug, Clone)]
31pub struct PublicBuilder {
32    public_algorithm: Option<PublicAlgorithm>,
33    object_attributes: Option<ObjectAttributes>,
34    name_hashing_algorithm: Option<HashingAlgorithm>,
35    auth_policy: Option<Digest>,
36    rsa_parameters: Option<PublicRsaParameters>,
37    rsa_unique_identifier: Option<PublicKeyRsa>,
38    keyed_hash_parameters: Option<PublicKeyedHashParameters>,
39    keyed_hash_unique_identifier: Option<Digest>,
40    ecc_parameters: Option<PublicEccParameters>,
41    ecc_unique_identifier: Option<EccPoint>,
42    symmetric_cipher_parameters: Option<SymmetricCipherParameters>,
43    symmetric_cipher_unique_identifier: Option<Digest>,
44}
45
46impl PublicBuilder {
47    /// Creates a new [PublicBuilder]
48    ///
49    /// # Details
50    /// Builds the [Public] type using the provided parameters. Parameters
51    /// associated with other algorithms then the provided public algorithm
52    /// will be ignored.
53    pub const fn new() -> Self {
54        PublicBuilder {
55            public_algorithm: None,
56            object_attributes: None,
57            name_hashing_algorithm: None,
58            auth_policy: None,
59            rsa_parameters: None,
60            rsa_unique_identifier: None,
61            keyed_hash_parameters: None,
62            keyed_hash_unique_identifier: None,
63            ecc_parameters: None,
64            ecc_unique_identifier: None,
65            symmetric_cipher_parameters: None,
66            symmetric_cipher_unique_identifier: None,
67        }
68    }
69
70    /// Adds the public algorithm for the [Public] structure
71    /// to the builder.
72    pub const fn with_public_algorithm(mut self, public_algorithm: PublicAlgorithm) -> Self {
73        self.public_algorithm = Some(public_algorithm);
74        self
75    }
76
77    /// Adds the attributes of the [Public] structure
78    /// to the builder
79    pub const fn with_object_attributes(mut self, object_attributes: ObjectAttributes) -> Self {
80        self.object_attributes = Some(object_attributes);
81        self
82    }
83
84    /// Adds the name hash algorithm for the [Public] structure
85    /// to the builder.
86    pub const fn with_name_hashing_algorithm(
87        mut self,
88        name_hashing_algorithm: HashingAlgorithm,
89    ) -> Self {
90        self.name_hashing_algorithm = Some(name_hashing_algorithm);
91        self
92    }
93
94    /// Adds the auth policy for the [Public] structure
95    /// to the builder
96    pub fn with_auth_policy(mut self, auth_policy: Digest) -> Self {
97        self.auth_policy = Some(auth_policy);
98        self
99    }
100
101    /// Adds the RSA parameters for the [Public] structure
102    /// to the builder.
103    ///
104    /// # Details
105    /// This is required if the public algorithm is set to
106    /// [Rsa][`crate::interface_types::algorithm::PublicAlgorithm::Rsa].
107    pub fn with_rsa_parameters(mut self, rsa_parameters: PublicRsaParameters) -> Self {
108        self.rsa_parameters = Some(rsa_parameters);
109        self
110    }
111
112    /// Adds the RSA unique identifier for the [Public] structure
113    /// to the builder.
114    ///
115    /// # Details
116    /// This is required if the public algorithm is set to
117    /// [Rsa][`crate::interface_types::algorithm::PublicAlgorithm::Rsa].
118    ///
119    /// The unique identifier is the public key.
120    pub fn with_rsa_unique_identifier(mut self, rsa_unique_identifier: PublicKeyRsa) -> Self {
121        self.rsa_unique_identifier = Some(rsa_unique_identifier);
122        self
123    }
124
125    /// Adds the keyed hash parameters for the [Public] structure
126    /// to the builder.
127    ///
128    /// # Details
129    /// This is required if the public algorithm is set to
130    /// [KeyedHash][`crate::interface_types::algorithm::PublicAlgorithm::KeyedHash].
131    pub fn with_keyed_hash_parameters(
132        mut self,
133        keyed_hash_parameters: PublicKeyedHashParameters,
134    ) -> Self {
135        self.keyed_hash_parameters = Some(keyed_hash_parameters);
136        self
137    }
138
139    /// Adds the keyed hash unique identifier for the [Public] structure
140    /// to the builder.
141    ///
142    /// # Details
143    /// This is required if the public algorithm is set to
144    /// [KeyedHash][`crate::interface_types::algorithm::PublicAlgorithm::KeyedHash].
145    pub fn with_keyed_hash_unique_identifier(
146        mut self,
147        keyed_hash_unique_identifier: Digest,
148    ) -> Self {
149        self.keyed_hash_unique_identifier = Some(keyed_hash_unique_identifier);
150        self
151    }
152
153    /// Adds the ECC parameters for the [Public] structure
154    /// to the builder.
155    ///
156    /// # Details
157    /// This is required if the public algorithm is set to
158    /// [Ecc][`crate::interface_types::algorithm::PublicAlgorithm::Ecc].
159    pub const fn with_ecc_parameters(mut self, ecc_parameters: PublicEccParameters) -> Self {
160        self.ecc_parameters = Some(ecc_parameters);
161        self
162    }
163
164    /// Adds the ECC unique identifier for the [Public] structure
165    /// to the builder.
166    ///
167    /// # Details
168    /// This is required if the public algorithm is set to
169    /// [Ecc][`crate::interface_types::algorithm::PublicAlgorithm::Ecc].
170    ///
171    /// The unique identifier is a ecc point.
172    pub fn with_ecc_unique_identifier(mut self, ecc_unique_identifier: EccPoint) -> Self {
173        self.ecc_unique_identifier = Some(ecc_unique_identifier);
174        self
175    }
176
177    /// Adds the symmetric cipher parameters for the [Public] structure
178    /// to the builder.
179    ///
180    /// # Details
181    /// This is required if the public algorithm is set to
182    /// [SymCipher][`crate::interface_types::algorithm::PublicAlgorithm::SymCipher].
183    pub const fn with_symmetric_cipher_parameters(
184        mut self,
185        symmetric_cipher_parameters: SymmetricCipherParameters,
186    ) -> Self {
187        self.symmetric_cipher_parameters = Some(symmetric_cipher_parameters);
188        self
189    }
190
191    /// Adds the symmetric cipher unique identifier for the [Public] structure
192    /// to the builder.
193    ///
194    /// # Details
195    /// This is required if the public algorithm is set to
196    /// [SymCipher][`crate::interface_types::algorithm::PublicAlgorithm::SymCipher].
197    pub fn with_symmetric_cipher_unique_identifier(
198        mut self,
199        symmetric_cipher_unique_identifier: Digest,
200    ) -> Self {
201        self.symmetric_cipher_unique_identifier = Some(symmetric_cipher_unique_identifier);
202        self
203    }
204
205    /// Builds the [Public] structure.
206    ///
207    /// # Errors
208    /// Will return error if the public algorithm, object attributes or name
209    /// hashing algorithm have not been set or if the parameters and unique identifier
210    /// does not match the selected public algorithm.
211    pub fn build(self) -> Result<Public> {
212        let algorithm = self.public_algorithm.ok_or_else(|| {
213            error!("Algorithm is required and has not been set in the PublicBuilder");
214            Error::local_error(WrapperErrorKind::ParamsMissing)
215        })?;
216
217        let object_attributes = self.object_attributes.ok_or_else(|| {
218            error!("ObjectAttributes is required and has not been set in the PublicBuilder");
219            Error::local_error(WrapperErrorKind::ParamsMissing)
220        })?;
221
222        let name_hashing_algorithm = self.name_hashing_algorithm.ok_or_else(|| {
223            error!(
224                "The name hashing algorithm is required and has not been set in the PublicBuilder"
225            );
226            Error::local_error(WrapperErrorKind::ParamsMissing)
227        })?;
228
229        let auth_policy = self.auth_policy.unwrap_or_default();
230
231        match algorithm {
232            PublicAlgorithm::Rsa => {
233                Ok(Public::Rsa {
234                    object_attributes,
235                    name_hashing_algorithm,
236                    auth_policy,
237                    parameters: self.rsa_parameters.ok_or_else(|| {
238                        error!("RSA parameters have not been set in the PublicBuilder even though the RSA algorithm had been selected.");
239                        Error::local_error(WrapperErrorKind::ParamsMissing)
240                    })?,
241                    unique: self.rsa_unique_identifier.ok_or_else(|| {
242                        error!("RSA unique identifier has not been set in the PublicBuilder even though the RSA algorithm had been selected. Consider using: .with_rsa_unique_identifier(&PublicKeyRsa::default())");
243                        Error::local_error(WrapperErrorKind::ParamsMissing)
244                    })?,
245                })
246            },
247            PublicAlgorithm::KeyedHash => {
248                Ok(Public::KeyedHash {
249                    object_attributes,
250                    name_hashing_algorithm,
251                    auth_policy,
252                    parameters: self.keyed_hash_parameters.ok_or_else(|| {
253                        error!("Keyed hash parameters have not been set in the Public Builder even though the keyed hash algorithm have been selected");
254                        Error::local_error(WrapperErrorKind::ParamsMissing)
255                    })?,
256                    unique: self.keyed_hash_unique_identifier.ok_or_else(|| {
257                        error!("Keyed hash unique identifier have not been set in the Public Builder even though the keyed hash algorithm have been selected. Consider using: .with_keyed_hash_unique_identifier(&Digest::default())");
258                        Error::local_error(WrapperErrorKind::ParamsMissing)
259                    })?,
260                })
261            },
262            PublicAlgorithm::Ecc => {
263                Ok(Public::Ecc {
264                    object_attributes,
265                    name_hashing_algorithm,
266                    auth_policy,
267                    parameters: self.ecc_parameters.ok_or_else(|| {
268                        error!("ECC parameters have not been set in the Public Builder even though the ECC algorithm have been selected");
269                        Error::local_error(WrapperErrorKind::ParamsMissing)
270                    })?,
271                    unique: self.ecc_unique_identifier.ok_or_else(|| {
272                        error!("ECC unique identifier have not been set in the Public Builder even though the ECC algorithm have been selected. Consider using: .with_ecc_unique_identifier(&EccPoint::default())");
273                        Error::local_error(WrapperErrorKind::ParamsMissing)
274                    })?,
275                })
276            }
277            PublicAlgorithm::SymCipher => {
278                Ok(Public::SymCipher {
279                    object_attributes,
280                    name_hashing_algorithm,
281                    auth_policy,
282                    parameters: self.symmetric_cipher_parameters.ok_or_else(|| {
283                        error!("Symmetric cipher parameters have not been set in the Public Builder even though the symmetric cipher algorithm have been selected");
284                        Error::local_error(WrapperErrorKind::ParamsMissing)
285                    })?,
286                    unique: self.symmetric_cipher_unique_identifier.ok_or_else(|| {
287                        error!("Symmetric cipher unique identifier have not been set in the Public Builder even though the symmetric cipher algorithm have been selected. Consider using: .with_symmetric_cipher_unique_identifier(&Digest::default())");
288                        Error::local_error(WrapperErrorKind::ParamsMissing)
289                    })?,
290                })
291            }
292        }
293    }
294}
295
296impl Default for PublicBuilder {
297    fn default() -> Self {
298        Self::new()
299    }
300}
301
302/// Enum representing the Public structure.
303///
304/// # Details
305/// This corresponds to TPMT_PUBLIC
306#[derive(Debug, Clone, Eq, PartialEq)]
307pub enum Public {
308    Rsa {
309        object_attributes: ObjectAttributes,
310        name_hashing_algorithm: HashingAlgorithm,
311        auth_policy: Digest,
312        parameters: PublicRsaParameters,
313        unique: PublicKeyRsa,
314    },
315    KeyedHash {
316        object_attributes: ObjectAttributes,
317        name_hashing_algorithm: HashingAlgorithm,
318        auth_policy: Digest,
319        parameters: PublicKeyedHashParameters,
320        unique: Digest,
321    },
322    Ecc {
323        object_attributes: ObjectAttributes,
324        name_hashing_algorithm: HashingAlgorithm,
325        auth_policy: Digest,
326        parameters: PublicEccParameters,
327        unique: EccPoint,
328    },
329    SymCipher {
330        object_attributes: ObjectAttributes,
331        name_hashing_algorithm: HashingAlgorithm,
332        auth_policy: Digest,
333        parameters: SymmetricCipherParameters,
334        unique: Digest,
335    },
336}
337
338impl Public {
339    /// Returns the object attributes
340    pub fn object_attributes(&self) -> ObjectAttributes {
341        match self {
342            Public::Rsa {
343                object_attributes, ..
344            }
345            | Public::KeyedHash {
346                object_attributes, ..
347            }
348            | Public::Ecc {
349                object_attributes, ..
350            }
351            | Public::SymCipher {
352                object_attributes, ..
353            } => *object_attributes,
354        }
355    }
356
357    /// Returns the name hashing algorithm
358    pub fn name_hashing_algorithm(&self) -> HashingAlgorithm {
359        match self {
360            Public::Rsa {
361                name_hashing_algorithm,
362                ..
363            }
364            | Public::KeyedHash {
365                name_hashing_algorithm,
366                ..
367            }
368            | Public::Ecc {
369                name_hashing_algorithm,
370                ..
371            }
372            | Public::SymCipher {
373                name_hashing_algorithm,
374                ..
375            } => *name_hashing_algorithm,
376        }
377    }
378
379    /// Returns the name symmetric definition object if available.
380    pub fn symmetric_algorithm(&self) -> Option<SymmetricDefinitionObject> {
381        match self {
382            Public::Rsa { parameters, .. } => Some(parameters.symmetric_definition_object()),
383            Public::KeyedHash { .. } => None,
384            Public::Ecc { parameters, .. } => Some(parameters.symmetric_definition_object()),
385            Public::SymCipher { parameters, .. } => Some(parameters.symmetric_definition_object()),
386        }
387    }
388
389    /// Returns the auth policy digest.
390    pub fn auth_policy(&self) -> &Digest {
391        match self {
392            Public::Rsa { auth_policy, .. }
393            | Public::KeyedHash { auth_policy, .. }
394            | Public::Ecc { auth_policy, .. }
395            | Public::SymCipher { auth_policy, .. } => auth_policy,
396        }
397    }
398
399    /// Get a builder for this structure
400    pub const fn builder() -> PublicBuilder {
401        PublicBuilder::new()
402    }
403}
404
405impl From<Public> for TPMT_PUBLIC {
406    fn from(public: Public) -> Self {
407        match public {
408            Public::Rsa {
409                object_attributes,
410                name_hashing_algorithm,
411                auth_policy,
412                parameters,
413                unique,
414            } => TPMT_PUBLIC {
415                type_: PublicAlgorithm::Rsa.into(),
416                nameAlg: name_hashing_algorithm.into(),
417                objectAttributes: object_attributes.into(),
418                authPolicy: auth_policy.into(),
419                parameters: TPMU_PUBLIC_PARMS {
420                    rsaDetail: parameters.into(),
421                },
422                unique: TPMU_PUBLIC_ID { rsa: unique.into() },
423            },
424            Public::KeyedHash {
425                object_attributes,
426                name_hashing_algorithm,
427                auth_policy,
428                parameters,
429                unique,
430            } => TPMT_PUBLIC {
431                type_: PublicAlgorithm::KeyedHash.into(),
432                nameAlg: name_hashing_algorithm.into(),
433                objectAttributes: object_attributes.into(),
434                authPolicy: auth_policy.into(),
435                parameters: TPMU_PUBLIC_PARMS {
436                    keyedHashDetail: parameters.into(),
437                },
438                unique: TPMU_PUBLIC_ID {
439                    keyedHash: unique.into(),
440                },
441            },
442            Public::Ecc {
443                object_attributes,
444                name_hashing_algorithm,
445                auth_policy,
446                parameters,
447                unique,
448            } => TPMT_PUBLIC {
449                type_: PublicAlgorithm::Ecc.into(),
450                nameAlg: name_hashing_algorithm.into(),
451                objectAttributes: object_attributes.into(),
452                authPolicy: auth_policy.into(),
453                parameters: TPMU_PUBLIC_PARMS {
454                    eccDetail: parameters.into(),
455                },
456                unique: TPMU_PUBLIC_ID { ecc: unique.into() },
457            },
458            Public::SymCipher {
459                object_attributes,
460                name_hashing_algorithm,
461                auth_policy,
462                parameters,
463                unique,
464            } => TPMT_PUBLIC {
465                type_: PublicAlgorithm::SymCipher.into(),
466                nameAlg: name_hashing_algorithm.into(),
467                objectAttributes: object_attributes.into(),
468                authPolicy: auth_policy.into(),
469                parameters: TPMU_PUBLIC_PARMS {
470                    symDetail: parameters.into(),
471                },
472                unique: TPMU_PUBLIC_ID { sym: unique.into() },
473            },
474        }
475    }
476}
477
478impl TryFrom<TPMT_PUBLIC> for Public {
479    type Error = Error;
480
481    fn try_from(tpmt_public: TPMT_PUBLIC) -> Result<Self> {
482        match PublicAlgorithm::try_from(tpmt_public.type_)? {
483            PublicAlgorithm::Rsa => Ok(Public::Rsa {
484                object_attributes: tpmt_public.objectAttributes.into(),
485                name_hashing_algorithm: tpmt_public.nameAlg.try_into()?,
486                auth_policy: tpmt_public.authPolicy.try_into()?,
487                parameters: unsafe { tpmt_public.parameters.rsaDetail }.try_into()?,
488                unique: unsafe { tpmt_public.unique.rsa }.try_into()?,
489            }),
490            PublicAlgorithm::KeyedHash => Ok(Public::KeyedHash {
491                object_attributes: tpmt_public.objectAttributes.into(),
492                name_hashing_algorithm: tpmt_public.nameAlg.try_into()?,
493                auth_policy: tpmt_public.authPolicy.try_into()?,
494                parameters: unsafe { tpmt_public.parameters.keyedHashDetail }.try_into()?,
495                unique: unsafe { tpmt_public.unique.keyedHash }.try_into()?,
496            }),
497            PublicAlgorithm::Ecc => Ok(Public::Ecc {
498                object_attributes: tpmt_public.objectAttributes.into(),
499                name_hashing_algorithm: tpmt_public.nameAlg.try_into()?,
500                auth_policy: tpmt_public.authPolicy.try_into()?,
501                parameters: unsafe { tpmt_public.parameters.eccDetail }.try_into()?,
502                unique: unsafe { tpmt_public.unique.ecc }.try_into()?,
503            }),
504            PublicAlgorithm::SymCipher => Ok(Public::SymCipher {
505                object_attributes: tpmt_public.objectAttributes.into(),
506                name_hashing_algorithm: tpmt_public.nameAlg.try_into()?,
507                auth_policy: tpmt_public.authPolicy.try_into()?,
508                parameters: unsafe { tpmt_public.parameters.symDetail }.try_into()?,
509                unique: unsafe { tpmt_public.unique.sym }.try_into()?,
510            }),
511        }
512    }
513}
514
515impl Marshall for Public {
516    const BUFFER_SIZE: usize = size_of::<TPMT_PUBLIC>();
517
518    /// Produce a marshalled [TPMT_PUBLIC]
519    ///
520    /// Note: for [TPM2B_PUBLIC] marshalling use [PublicBuffer][`crate::structures::PublicBuffer]
521    fn marshall(&self) -> Result<Vec<u8>> {
522        let mut buffer = vec![0; Self::BUFFER_SIZE];
523        let mut offset = 0;
524
525        let ret = Error::from_tss_rc(unsafe {
526            crate::tss2_esys::Tss2_MU_TPMT_PUBLIC_Marshal(
527                &self.clone().into(),
528                buffer.as_mut_ptr(),
529                Self::BUFFER_SIZE.try_into().map_err(|e| {
530                    error!("Failed to convert size of buffer to TSS size_t type: {}", e);
531                    Error::local_error(WrapperErrorKind::InvalidParam)
532                })?,
533                &mut offset,
534            )
535        });
536
537        if !ret.is_success() {
538            return Err(ret);
539        }
540
541        let checked_offset = usize::try_from(offset).map_err(|e| {
542            error!("Failed to parse offset as usize: {}", e);
543            Error::local_error(WrapperErrorKind::InvalidParam)
544        })?;
545
546        buffer.truncate(checked_offset);
547
548        Ok(buffer)
549    }
550}
551
552impl UnMarshall for Public {
553    /// Unmarshall the structure from [`TPMT_PUBLIC`]
554    ///
555    /// Note: for [TPM2B_PUBLIC] unmarshalling use [PublicBuffer][`crate::structures::PublicBuffer]
556    fn unmarshall(marshalled_data: &[u8]) -> Result<Self> {
557        let mut dest = TPMT_PUBLIC::default();
558        let mut offset = 0;
559
560        let ret = Error::from_tss_rc(unsafe {
561            crate::tss2_esys::Tss2_MU_TPMT_PUBLIC_Unmarshal(
562                marshalled_data.as_ptr(),
563                marshalled_data.len().try_into().map_err(|e| {
564                    error!("Failed to convert length of marshalled data: {}", e);
565                    Error::local_error(WrapperErrorKind::InvalidParam)
566                })?,
567                &mut offset,
568                &mut dest,
569            )
570        });
571
572        if !ret.is_success() {
573            return Err(ret);
574        }
575
576        Public::try_from(dest)
577    }
578}
579
580impl TryFrom<TPM2B_PUBLIC> for Public {
581    type Error = Error;
582
583    fn try_from(tpm2b_public: TPM2B_PUBLIC) -> Result<Self> {
584        Public::try_from(tpm2b_public.publicArea)
585    }
586}
587
588impl TryFrom<Public> for TPM2B_PUBLIC {
589    type Error = Error;
590
591    fn try_from(public: Public) -> Result<Self> {
592        let mut buffer = vec![0; Public::BUFFER_SIZE];
593        let mut size = 0;
594        let public_area = TPMT_PUBLIC::from(public);
595
596        let ret = Error::from_tss_rc(unsafe {
597            crate::tss2_esys::Tss2_MU_TPMT_PUBLIC_Marshal(
598                &public_area,
599                buffer.as_mut_ptr(),
600                Public::BUFFER_SIZE.try_into().map_err(|e| {
601                    error!("Failed to convert size of buffer to TSS size_t type: {}", e);
602                    Error::local_error(WrapperErrorKind::InvalidParam)
603                })?,
604                &mut size,
605            )
606        });
607
608        if !ret.is_success() {
609            return Err(ret);
610        }
611
612        Ok(TPM2B_PUBLIC {
613            size: size.try_into().map_err(|e| {
614                error!(
615                    "Failed to convert size of buffer from TSS size_t type: {}",
616                    e
617                );
618                Error::local_error(WrapperErrorKind::InvalidParam)
619            })?,
620            publicArea: public_area,
621        })
622    }
623}