tss_esapi/structures/nv/storage/
public.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    attributes::NvIndexAttributes,
6    handles::NvIndexTpmHandle,
7    interface_types::algorithm::HashingAlgorithm,
8    structures::Digest,
9    tss2_esys::{TPM2B_NV_PUBLIC, TPMS_NV_PUBLIC},
10    Error, Result, WrapperErrorKind,
11};
12use log::error;
13use std::{
14    convert::{TryFrom, TryInto},
15    mem::size_of,
16};
17
18/// Representation of the public parameters of a non-volatile
19/// space allocation.
20///
21/// # Details
22/// Corresponds to `TPMS_NV_PUBLIC`
23#[derive(Debug, Clone, Eq, PartialEq)]
24pub struct NvPublic {
25    nv_index: NvIndexTpmHandle,
26    name_algorithm: HashingAlgorithm,
27    attributes: NvIndexAttributes,
28    authorization_policy: Digest,
29    data_size: usize,
30}
31
32impl NvPublic {
33    const MAX_SIZE: usize = size_of::<TPMS_NV_PUBLIC>();
34
35    pub fn nv_index(&self) -> NvIndexTpmHandle {
36        self.nv_index
37    }
38
39    pub fn name_algorithm(&self) -> HashingAlgorithm {
40        self.name_algorithm
41    }
42
43    pub fn attributes(&self) -> NvIndexAttributes {
44        self.attributes
45    }
46
47    pub fn authorization_policy(&self) -> &Digest {
48        &self.authorization_policy
49    }
50
51    pub fn data_size(&self) -> usize {
52        self.data_size
53    }
54
55    /// Get a builder for the structure
56    pub const fn builder() -> NvPublicBuilder {
57        NvPublicBuilder::new()
58    }
59}
60
61impl TryFrom<TPM2B_NV_PUBLIC> for NvPublic {
62    type Error = Error;
63    fn try_from(tss_nv_public: TPM2B_NV_PUBLIC) -> Result<NvPublic> {
64        if tss_nv_public.size as usize > NvPublic::MAX_SIZE {
65            error!("Encountered an invalid size of the TPMS_NV_PUBLIC");
66            return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
67        }
68        // Parse actual data
69        Ok(NvPublic {
70            nv_index: tss_nv_public.nvPublic.nvIndex.try_into()?,
71            name_algorithm: tss_nv_public.nvPublic.nameAlg.try_into()?,
72            attributes: tss_nv_public.nvPublic.attributes.try_into()?,
73            authorization_policy: tss_nv_public.nvPublic.authPolicy.try_into()?,
74            data_size: tss_nv_public.nvPublic.dataSize as usize,
75        })
76    }
77}
78
79impl TryFrom<NvPublic> for TPM2B_NV_PUBLIC {
80    type Error = Error;
81    fn try_from(nv_public: NvPublic) -> Result<TPM2B_NV_PUBLIC> {
82        Ok(TPM2B_NV_PUBLIC {
83            // Will be ignored due to being a complex TPM2B type
84            // The marshalling functionality in TSS will calculate
85            // the correct value.
86            size: 0,
87            nvPublic: TPMS_NV_PUBLIC {
88                nvIndex: nv_public.nv_index.into(),
89                nameAlg: nv_public.name_algorithm.into(),
90                attributes: nv_public.attributes.try_into()?,
91                authPolicy: nv_public.authorization_policy.into(),
92                dataSize: nv_public.data_size as u16,
93            },
94        })
95    }
96}
97
98/// Builder for NvPublic.
99///
100///
101#[derive(Debug, Default)]
102pub struct NvPublicBuilder {
103    nv_index: Option<NvIndexTpmHandle>,
104    name_algorithm: Option<HashingAlgorithm>,
105    attributes: Option<NvIndexAttributes>,
106    authorization_policy: Option<Digest>,
107    data_size: Option<usize>,
108}
109
110impl NvPublicBuilder {
111    pub const fn new() -> Self {
112        NvPublicBuilder {
113            nv_index: None,
114            name_algorithm: None,
115            attributes: None,
116            authorization_policy: None,
117            data_size: None,
118        }
119    }
120
121    pub fn with_nv_index(mut self, nv_index: NvIndexTpmHandle) -> Self {
122        self.nv_index = Some(nv_index);
123        self
124    }
125
126    pub fn with_index_name_algorithm(mut self, nv_index_name_algorithm: HashingAlgorithm) -> Self {
127        self.name_algorithm = Some(nv_index_name_algorithm);
128        self
129    }
130
131    pub fn with_index_attributes(mut self, nv_index_attributes: NvIndexAttributes) -> Self {
132        self.attributes = Some(nv_index_attributes);
133        self
134    }
135
136    pub fn with_index_auth_policy(mut self, nv_index_auth_policy: Digest) -> Self {
137        self.authorization_policy = Some(nv_index_auth_policy);
138        self
139    }
140
141    pub fn with_data_area_size(mut self, nv_index_data_area_size: usize) -> Self {
142        self.data_size = Some(nv_index_data_area_size);
143        self
144    }
145
146    pub fn build(self) -> Result<NvPublic> {
147        // TODO: Do some clever checking of the values in
148        // order to determine some defaults values when
149        // some params have not been specified.
150        //
151
152        Ok(NvPublic {
153            // Nv Index
154            nv_index: self.nv_index.ok_or_else(|| {
155                error!("No NV index was specified");
156                Error::local_error(WrapperErrorKind::ParamsMissing)
157            })?,
158            // Hashing algorithm for the name of index
159            name_algorithm: self.name_algorithm.ok_or_else(|| {
160                error!("No name algorithm was specified");
161                Error::local_error(WrapperErrorKind::ParamsMissing)
162            })?,
163            // Index attributes
164            attributes: self.attributes.ok_or_else(|| {
165                error!("No attributes were specified");
166                Error::local_error(WrapperErrorKind::ParamsMissing)
167            })?,
168            // Index Auth policy
169            authorization_policy: self.authorization_policy.unwrap_or_default(),
170            // Size of the data area of the index
171            data_size: self
172                .data_size
173                .ok_or_else(|| {
174                    error!("No data size specified");
175                    Error::local_error(WrapperErrorKind::ParamsMissing)
176                })
177                .and_then(|v| {
178                    if v > u16::MAX.into() {
179                        error!("data area size is too large (>{})", u16::MAX);
180                        return Err(Error::local_error(WrapperErrorKind::InvalidParam));
181                    }
182                    Ok(v)
183                })?,
184        })
185    }
186}