tss_esapi/attributes/
command_code.rs

1// Copyright 2022 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    constants::CommandCode,
6    tss2_esys::{TPM2_CC, TPMA_CC},
7    Error, Result, WrapperErrorKind,
8};
9use bitfield::bitfield;
10use log::error;
11use std::convert::{TryFrom, TryInto};
12
13bitfield! {
14    /// Bitfield representing the command code attributes.
15    ///
16    /// # Details
17    /// This corresponds to TPMA_CC.
18    #[derive(Copy, Clone, Eq, PartialEq)]
19    pub struct CommandCodeAttributes(TPMA_CC);
20    impl Debug;
21    pub u16, command_index, _: 15, 0;
22    u16, _, set_command_index: 15, 0;
23    u8, reserved, set_reserved: 21, 16; // shall be zero
24    pub nv, _: 22;
25    _, set_nv: 22;
26    pub extensive, _: 23;
27    _, set_extensive: 23;
28    pub flushed, _: 24;
29    _, set_flushed: 24;
30    pub u8, c_handles, _: 27, 25;
31    u8, _, set_c_handles: 27, 25;
32    pub r_handle, _: 28;
33    _, set_r_handle: 28;
34    pub is_vendor_specific, _: 29;
35    _, set_vendor_specific: 29;
36    res, set_res: 31, 30; // shall be zero
37}
38
39impl CommandCodeAttributes {
40    /// Returns a command code attributes builder
41    pub const fn builder() -> CommandCodeAttributesBuilder {
42        CommandCodeAttributesBuilder::new()
43    }
44}
45
46impl TryFrom<TPMA_CC> for CommandCodeAttributes {
47    type Error = Error;
48
49    fn try_from(tpma_cc: TPMA_CC) -> Result<Self> {
50        let command_code_attributes = CommandCodeAttributes(tpma_cc);
51        if command_code_attributes.reserved() != 0 || command_code_attributes.res() != 0 {
52            error!(
53                "Command code attributes from the TPM contained a non zero value in a resrved area"
54            );
55            return Err(Error::local_error(WrapperErrorKind::InvalidParam));
56        }
57
58        if !command_code_attributes.is_vendor_specific() {
59            // Non vendor specific command code attributes needs to
60            // have a command index that corresponds to a command code.
61            let tpm_command_code: TPM2_CC = command_code_attributes.command_index().into();
62            let _ = CommandCode::try_from(tpm_command_code)?;
63        }
64        Ok(command_code_attributes)
65    }
66}
67
68impl From<CommandCodeAttributes> for TPMA_CC {
69    fn from(command_code_attributes: CommandCodeAttributes) -> Self {
70        command_code_attributes.0
71    }
72}
73
74/// A builder for [CommandCodeAttributes]
75#[derive(Copy, Clone, Eq, PartialEq, Debug)]
76pub struct CommandCodeAttributesBuilder {
77    command_code_attributes: CommandCodeAttributes,
78}
79
80impl CommandCodeAttributesBuilder {
81    /// Creates a new command code attributes builder.
82    pub const fn new() -> Self {
83        CommandCodeAttributesBuilder {
84            command_code_attributes: CommandCodeAttributes(0),
85        }
86    }
87
88    /// Sets the command code to the specified value
89    /// in the builder.
90    pub fn with_command_index(mut self, command_index: u16) -> Self {
91        self.command_code_attributes
92            .set_command_index(command_index);
93        self
94    }
95
96    /// Sets the 'nv' bit in the builder.
97    pub fn with_nv(mut self, set: bool) -> Self {
98        self.command_code_attributes.set_nv(set);
99        self
100    }
101
102    /// Sets the 'extensive' bit in the builder.
103    pub fn with_extensive(mut self, set: bool) -> Self {
104        self.command_code_attributes.set_extensive(set);
105        self
106    }
107
108    /// Sets the 'flushed' bit in the builder.
109    pub fn with_flushed(mut self, set: bool) -> Self {
110        self.command_code_attributes.set_flushed(set);
111        self
112    }
113
114    /// Sets the three 'c_handles' bits in the builder.
115    ///
116    /// # Details
117    /// All bits besides the three first in the provided
118    /// argument will be ignored.
119    pub fn with_c_handles(mut self, value: u8) -> Self {
120        self.command_code_attributes.set_c_handles(value);
121        self
122    }
123
124    /// Sets the 'r_handle' bit in the builder.
125    pub fn with_r_handle(mut self, set: bool) -> Self {
126        self.command_code_attributes.set_r_handle(set);
127        self
128    }
129
130    /// Sets the 'V'(i.e. vendor specific) bit in the builder.
131    pub fn with_vendor_specific(mut self, set: bool) -> Self {
132        self.command_code_attributes.set_vendor_specific(set);
133        self
134    }
135
136    /// Builds the command code attributes
137    ///
138    /// # Errors
139    /// Returns an error if command index is not
140    /// a command index associated with a CommandCode
141    /// specified in the TPM specification.
142    pub fn build(self) -> Result<CommandCodeAttributes> {
143        self.command_code_attributes.0.try_into()
144    }
145}
146
147impl Default for CommandCodeAttributesBuilder {
148    fn default() -> Self {
149        Self::new()
150    }
151}