1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 // This file contains the functions that support command audit.
37
38 //** Includes
39 #include "Tpm.h"
40
41 //** Functions
42
43 //*** CommandAuditPreInstall_Init()
44 // This function initializes the command audit list. This function simulates
45 // the behavior of manufacturing. A function is used instead of a structure
46 // definition because this is easier than figuring out the initialization value
47 // for a bit array.
48 //
49 // This function would not be implemented outside of a manufacturing or
50 // simulation environment.
51 void
CommandAuditPreInstall_Init(void)52 CommandAuditPreInstall_Init(
53 void
54 )
55 {
56 // Clear all the audit commands
57 MemorySet(gp.auditCommands, 0x00, sizeof(gp.auditCommands));
58
59 // TPM_CC_SetCommandCodeAuditStatus always being audited
60 CommandAuditSet(TPM_CC_SetCommandCodeAuditStatus);
61
62 // Set initial command audit hash algorithm to be context integrity hash
63 // algorithm
64 gp.auditHashAlg = CONTEXT_INTEGRITY_HASH_ALG;
65
66 // Set up audit counter to be 0
67 gp.auditCounter = 0;
68
69 // Write command audit persistent data to NV
70 NV_SYNC_PERSISTENT(auditCommands);
71 NV_SYNC_PERSISTENT(auditHashAlg);
72 NV_SYNC_PERSISTENT(auditCounter);
73
74 return;
75 }
76
77 //*** CommandAuditStartup()
78 // This function clears the command audit digest on a TPM Reset.
79 BOOL
CommandAuditStartup(STARTUP_TYPE type)80 CommandAuditStartup(
81 STARTUP_TYPE type // IN: start up type
82 )
83 {
84 if((type != SU_RESTART) && (type != SU_RESUME))
85 {
86 // Reset the digest size to initialize the digest
87 gr.commandAuditDigest.t.size = 0;
88 }
89 return TRUE;
90 }
91
92 //*** CommandAuditSet()
93 // This function will SET the audit flag for a command. This function
94 // will not SET the audit flag for a command that is not implemented. This
95 // ensures that the audit status is not SET when TPM2_GetCapability() is
96 // used to read the list of audited commands.
97 //
98 // This function is only used by TPM2_SetCommandCodeAuditStatus().
99 //
100 // The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the
101 // changes to be saved to NV after it is setting and clearing bits.
102 // Return Type: BOOL
103 // TRUE(1) command code audit status was changed
104 // FALSE(0) command code audit status was not changed
105 BOOL
CommandAuditSet(TPM_CC commandCode)106 CommandAuditSet(
107 TPM_CC commandCode // IN: command code
108 )
109 {
110 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
111
112 // Only SET a bit if the corresponding command is implemented
113 if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX)
114 {
115 // Can't audit shutdown
116 if(commandCode != TPM_CC_Shutdown)
117 {
118 if(!TEST_BIT(commandIndex, gp.auditCommands))
119 {
120 // Set bit
121 SET_BIT(commandIndex, gp.auditCommands);
122 return TRUE;
123 }
124 }
125 }
126 // No change
127 return FALSE;
128 }
129
130 //*** CommandAuditClear()
131 // This function will CLEAR the audit flag for a command. It will not CLEAR the
132 // audit flag for TPM_CC_SetCommandCodeAuditStatus().
133 //
134 // This function is only used by TPM2_SetCommandCodeAuditStatus().
135 //
136 // The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the
137 // changes to be saved to NV after it is setting and clearing bits.
138 // Return Type: BOOL
139 // TRUE(1) command code audit status was changed
140 // FALSE(0) command code audit status was not changed
141 BOOL
CommandAuditClear(TPM_CC commandCode)142 CommandAuditClear(
143 TPM_CC commandCode // IN: command code
144 )
145 {
146 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
147
148 // Do nothing if the command is not implemented
149 if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX)
150 {
151 // The bit associated with TPM_CC_SetCommandCodeAuditStatus() cannot be
152 // cleared
153 if(commandCode != TPM_CC_SetCommandCodeAuditStatus)
154 {
155 if(TEST_BIT(commandIndex, gp.auditCommands))
156 {
157 // Clear bit
158 CLEAR_BIT(commandIndex, gp.auditCommands);
159 return TRUE;
160 }
161 }
162 }
163 // No change
164 return FALSE;
165 }
166
167 //*** CommandAuditIsRequired()
168 // This function indicates if the audit flag is SET for a command.
169 // Return Type: BOOL
170 // TRUE(1) command is audited
171 // FALSE(0) command is not audited
172 BOOL
CommandAuditIsRequired(COMMAND_INDEX commandIndex)173 CommandAuditIsRequired(
174 COMMAND_INDEX commandIndex // IN: command index
175 )
176 {
177 // Check the bit map. If the bit is SET, command audit is required
178 return(TEST_BIT(commandIndex, gp.auditCommands));
179 }
180
181 //*** CommandAuditCapGetCCList()
182 // This function returns a list of commands that have their audit bit SET.
183 //
184 // The list starts at the input commandCode.
185 // Return Type: TPMI_YES_NO
186 // YES if there are more command code available
187 // NO all the available command code has been returned
188 TPMI_YES_NO
CommandAuditCapGetCCList(TPM_CC commandCode,UINT32 count,TPML_CC * commandList)189 CommandAuditCapGetCCList(
190 TPM_CC commandCode, // IN: start command code
191 UINT32 count, // IN: count of returned TPM_CC
192 TPML_CC *commandList // OUT: list of TPM_CC
193 )
194 {
195 TPMI_YES_NO more = NO;
196 COMMAND_INDEX commandIndex;
197
198 // Initialize output handle list
199 commandList->count = 0;
200
201 // The maximum count of command we may return is MAX_CAP_CC
202 if(count > MAX_CAP_CC) count = MAX_CAP_CC;
203
204 // Find the implemented command that has a command code that is the same or
205 // higher than the input
206 // Collect audit commands
207 for(commandIndex = GetClosestCommandIndex(commandCode);
208 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
209 commandIndex = GetNextCommandIndex(commandIndex))
210 {
211 if(CommandAuditIsRequired(commandIndex))
212 {
213 if(commandList->count < count)
214 {
215 // If we have not filled up the return list, add this command
216 // code to its
217 TPM_CC cc = GET_ATTRIBUTE(s_ccAttr[commandIndex],
218 TPMA_CC, commandIndex);
219 if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
220 cc += (1 << 29);
221 commandList->commandCodes[commandList->count] = cc;
222 commandList->count++;
223 }
224 else
225 {
226 // If the return list is full but we still have command
227 // available, report this and stop iterating
228 more = YES;
229 break;
230 }
231 }
232 }
233
234 return more;
235 }
236
237 //*** CommandAuditGetDigest
238 // This command is used to create a digest of the commands being audited. The
239 // commands are processed in ascending numeric order with a list of TPM_CC being
240 // added to a hash. This operates as if all the audited command codes were
241 // concatenated and then hashed.
242 void
CommandAuditGetDigest(TPM2B_DIGEST * digest)243 CommandAuditGetDigest(
244 TPM2B_DIGEST *digest // OUT: command digest
245 )
246 {
247 TPM_CC commandCode;
248 COMMAND_INDEX commandIndex;
249 HASH_STATE hashState;
250
251 // Start hash
252 digest->t.size = CryptHashStart(&hashState, gp.auditHashAlg);
253
254 // Add command code
255 for(commandIndex = 0; commandIndex < COMMAND_COUNT; commandIndex++)
256 {
257 if(CommandAuditIsRequired(commandIndex))
258 {
259 commandCode = GetCommandCode(commandIndex);
260 CryptDigestUpdateInt(&hashState, sizeof(commandCode), commandCode);
261 }
262 }
263
264 // Complete hash
265 CryptHashEnd2B(&hashState, &digest->b);
266
267 return;
268 }