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 //** Description
36 //
37 // This file contains the NV read and write access methods. This implementation
38 // uses RAM/file and does not manage the RAM/file as NV blocks.
39 // The implementation may become more sophisticated over time.
40 //
41
42 //** Includes and Local
43 #include <memory.h>
44 #include <string.h>
45 #include <assert.h>
46 #include "Platform.h"
47 #if FILE_BACKED_NV
48 # include <stdio.h>
49 static FILE *s_NvFile = NULL;
50 static int s_NeedsManufacture = FALSE;
51 #endif
52
53 //**Functions
54
55 #if FILE_BACKED_NV
56
57 //*** NvFileOpen()
58 // This function opens the file used to hold the NV image.
59 // Return Type: int
60 // >= 0 success
61 // -1 error
62 static int
NvFileOpen(const char * mode)63 NvFileOpen(
64 const char *mode
65 )
66 {
67 #if defined(NV_FILE_PATH)
68 # define TO_STRING(s) TO_STRING_IMPL(s)
69 # define TO_STRING_IMPL(s) #s
70 const char* s_NvFilePath = TO_STRING(NV_FILE_PATH);
71 # undef TO_STRING
72 # undef TO_STRING_IMPL
73 #else
74 const char* s_NvFilePath = "NVChip";
75 #endif
76
77 // Try to open an exist NVChip file for read/write
78 # if defined _MSC_VER && 1
79 if(fopen_s(&s_NvFile, s_NvFilePath, mode) != 0)
80 s_NvFile = NULL;
81 # else
82 s_NvFile = fopen(s_NvFilePath, mode);
83 # endif
84 return (s_NvFile == NULL) ? -1 : 0;
85 }
86
87 //*** NvFileCommit()
88 // Write all of the contents of the NV image to a file.
89 // Return Type: int
90 // TRUE(1) success
91 // FALSE(0) failure
92 static int
NvFileCommit(void)93 NvFileCommit(
94 void
95 )
96 {
97 int OK;
98 // If NV file is not available, return failure
99 if(s_NvFile == NULL)
100 return 1;
101 // Write RAM data to NV
102 fseek(s_NvFile, 0, SEEK_SET);
103 OK = (NV_MEMORY_SIZE == fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NvFile));
104 OK = OK && (0 == fflush(s_NvFile));
105 assert(OK);
106 return OK;
107 }
108
109 //*** NvFileSize()
110 // This function gets the size of the NV file and puts the file pointer where desired
111 // using the seek method values. SEEK_SET => beginning; SEEK_CUR => current position
112 // and SEEK_END => to the end of the file.
113 static long
NvFileSize(int leaveAt)114 NvFileSize(
115 int leaveAt
116 )
117 {
118 long fileSize;
119 long filePos = ftell(s_NvFile);
120 //
121 assert(NULL != s_NvFile);
122
123 int fseek_result = fseek(s_NvFile, 0, SEEK_END);
124 NOT_REFERENCED(fseek_result); // Fix compiler warning for NDEBUG
125 assert(fseek_result == 0);
126 fileSize = ftell(s_NvFile);
127 assert(fileSize >= 0);
128 switch(leaveAt)
129 {
130 case SEEK_SET:
131 filePos = 0;
132 case SEEK_CUR:
133 fseek(s_NvFile, filePos, SEEK_SET);
134 break;
135 case SEEK_END:
136 break;
137 default:
138 assert(FALSE);
139 break;
140 }
141 return fileSize;
142 }
143 #endif
144
145 //*** _plat__NvErrors()
146 // This function is used by the simulator to set the error flags in the NV
147 // subsystem to simulate an error in the NV loading process
148 LIB_EXPORT void
_plat__NvErrors(int recoverable,int unrecoverable)149 _plat__NvErrors(
150 int recoverable,
151 int unrecoverable
152 )
153 {
154 s_NV_unrecoverable = unrecoverable;
155 s_NV_recoverable = recoverable;
156 }
157
158 //***_plat__NVEnable()
159 // Enable NV memory.
160 //
161 // This version just pulls in data from a file. In a real TPM, with NV on chip,
162 // this function would verify the integrity of the saved context. If the NV
163 // memory was not on chip but was in something like RPMB, the NV state would be
164 // read in, decrypted and integrity checked.
165 //
166 // The recovery from an integrity failure depends on where the error occurred. It
167 // it was in the state that is discarded by TPM Reset, then the error is
168 // recoverable if the TPM is reset. Otherwise, the TPM must go into failure mode.
169 // Return Type: int
170 // 0 if success
171 // > 0 if receive recoverable error
172 // <0 if unrecoverable error
173 LIB_EXPORT int
_plat__NVEnable(void * platParameter)174 _plat__NVEnable(
175 void *platParameter // IN: platform specific parameters
176 )
177 {
178 NOT_REFERENCED(platParameter); // to keep compiler quiet
179 //
180 // Start assuming everything is OK
181 s_NV_unrecoverable = FALSE;
182 s_NV_recoverable = FALSE;
183 #if FILE_BACKED_NV
184 if(s_NvFile != NULL)
185 return 0;
186 // Initialize all the bytes in the ram copy of the NV
187 _plat__NvMemoryClear(0, NV_MEMORY_SIZE);
188
189 // If the file exists
190 if(NvFileOpen("r+b") >= 0)
191 {
192 long fileSize = NvFileSize(SEEK_SET); // get the file size and leave the
193 // file pointer at the start
194 //
195 // If the size is right, read the data
196 if (NV_MEMORY_SIZE == fileSize)
197 {
198 s_NeedsManufacture =
199 fread(s_NV, 1, NV_MEMORY_SIZE, s_NvFile) != NV_MEMORY_SIZE;
200 }
201 else
202 {
203 printf("acs 6\n");
204 NvFileCommit(); // for any other size, initialize it
205 s_NeedsManufacture = TRUE;
206 }
207 }
208 // If NVChip file does not exist, try to create it for read/write.
209 else if(NvFileOpen("w+b") >= 0)
210 {
211 NvFileCommit(); // Initialize the file
212 s_NeedsManufacture = TRUE;
213 }
214 assert(NULL != s_NvFile); // Just in case we are broken for some reason.
215 #endif
216 // NV contents have been initialized and the error checks have been performed. For
217 // simulation purposes, use the signaling interface to indicate if an error is
218 // to be simulated and the type of the error.
219 if(s_NV_unrecoverable)
220 return -1;
221 return s_NV_recoverable;
222 }
223
224 //***_plat__NVDisable()
225 // Disable NV memory
226 LIB_EXPORT void
_plat__NVDisable(int delete)227 _plat__NVDisable(
228 int delete // IN: If TRUE, delete the NV contents.
229 )
230 {
231 #if FILE_BACKED_NV
232 if(NULL != s_NvFile)
233 {
234 fclose(s_NvFile); // Close NV file
235 // Alternative to deleting the file is to set its size to 0. This will not
236 // match the NV size so the TPM will need to be remanufactured.
237 if(delete)
238 {
239 // Open for writing at the start. Sets the size to zero.
240 if(NvFileOpen("w") >= 0)
241 {
242 fflush(s_NvFile);
243 fclose(s_NvFile);
244 }
245 }
246 }
247 s_NvFile = NULL; // Set file handle to NULL
248 #endif
249 return;
250 }
251
252 //***_plat__IsNvAvailable()
253 // Check if NV is available
254 // Return Type: int
255 // 0 NV is available
256 // 1 NV is not available due to write failure
257 // 2 NV is not available due to rate limit
258 LIB_EXPORT int
_plat__IsNvAvailable(void)259 _plat__IsNvAvailable(
260 void
261 )
262 {
263 int retVal = 0;
264 // NV is not available if the TPM is in failure mode
265 if(!s_NvIsAvailable)
266 retVal = 1;
267 #if FILE_BACKED_NV
268 else
269 retVal = (s_NvFile == NULL);
270 #endif
271 return retVal;
272 }
273
274 //***_plat__NvMemoryRead()
275 // Function: Read a chunk of NV memory
276 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)277 _plat__NvMemoryRead(
278 unsigned int startOffset, // IN: read start
279 unsigned int size, // IN: size of bytes to read
280 void *data // OUT: data buffer
281 )
282 {
283 assert(startOffset + size <= NV_MEMORY_SIZE);
284 memcpy(data, &s_NV[startOffset], size); // Copy data from RAM
285 return;
286 }
287
288 //*** _plat__NvIsDifferent()
289 // This function checks to see if the NV is different from the test value. This is
290 // so that NV will not be written if it has not changed.
291 // Return Type: int
292 // TRUE(1) the NV location is different from the test value
293 // FALSE(0) the NV location is the same as the test value
294 LIB_EXPORT int
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)295 _plat__NvIsDifferent(
296 unsigned int startOffset, // IN: read start
297 unsigned int size, // IN: size of bytes to read
298 void *data // IN: data buffer
299 )
300 {
301 return (memcmp(&s_NV[startOffset], data, size) != 0);
302 }
303
304 //***_plat__NvMemoryWrite()
305 // This function is used to update NV memory. The "write" is to a memory copy of
306 // NV. At the end of the current command, any changes are written to
307 // the actual NV memory.
308 // NOTE: A useful optimization would be for this code to compare the current
309 // contents of NV with the local copy and note the blocks that have changed. Then
310 // only write those blocks when _plat__NvCommit() is called.
311 LIB_EXPORT int
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)312 _plat__NvMemoryWrite(
313 unsigned int startOffset, // IN: write start
314 unsigned int size, // IN: size of bytes to write
315 void *data // OUT: data buffer
316 )
317 {
318 if(startOffset + size <= NV_MEMORY_SIZE)
319 {
320 memcpy(&s_NV[startOffset], data, size); // Copy the data to the NV image
321 return TRUE;
322 }
323 return FALSE;
324 }
325
326 //***_plat__NvMemoryClear()
327 // Function is used to set a range of NV memory bytes to an implementation-dependent
328 // value. The value represents the erase state of the memory.
329 LIB_EXPORT void
_plat__NvMemoryClear(unsigned int start,unsigned int size)330 _plat__NvMemoryClear(
331 unsigned int start, // IN: clear start
332 unsigned int size // IN: number of bytes to clear
333 )
334 {
335 assert(start + size <= NV_MEMORY_SIZE);
336 // In this implementation, assume that the erase value for NV is all 1s
337 memset(&s_NV[start], 0xff, size);
338 }
339
340 //***_plat__NvMemoryMove()
341 // Function: Move a chunk of NV memory from source to destination
342 // This function should ensure that if there overlap, the original data is
343 // copied before it is written
344 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)345 _plat__NvMemoryMove(
346 unsigned int sourceOffset, // IN: source offset
347 unsigned int destOffset, // IN: destination offset
348 unsigned int size // IN: size of data being moved
349 )
350 {
351 assert(sourceOffset + size <= NV_MEMORY_SIZE);
352 assert(destOffset + size <= NV_MEMORY_SIZE);
353 memmove(&s_NV[destOffset], &s_NV[sourceOffset], size); // Move data in RAM
354 return;
355 }
356
357 //***_plat__NvCommit()
358 // This function writes the local copy of NV to NV for permanent store. It will write
359 // NV_MEMORY_SIZE bytes to NV. If a file is use, the entire file is written.
360 // Return Type: int
361 // 0 NV write success
362 // non-0 NV write fail
363 LIB_EXPORT int
_plat__NvCommit(void)364 _plat__NvCommit(
365 void
366 )
367 {
368 #if FILE_BACKED_NV
369 return (NvFileCommit() ? 0 : 1);
370 #else
371 return 0;
372 #endif
373 }
374
375 //***_plat__SetNvAvail()
376 // Set the current NV state to available. This function is for testing purpose
377 // only. It is not part of the platform NV logic
378 LIB_EXPORT void
_plat__SetNvAvail(void)379 _plat__SetNvAvail(
380 void
381 )
382 {
383 s_NvIsAvailable = TRUE;
384 return;
385 }
386
387 //***_plat__ClearNvAvail()
388 // Set the current NV state to unavailable. This function is for testing purpose
389 // only. It is not part of the platform NV logic
390 LIB_EXPORT void
_plat__ClearNvAvail(void)391 _plat__ClearNvAvail(
392 void
393 )
394 {
395 s_NvIsAvailable = FALSE;
396 return;
397 }
398
399 //*** _plat__NVNeedsManufacture()
400 // This function is used by the simulator to determine when the TPM's NV state
401 // needs to be manufactured.
402 LIB_EXPORT int
_plat__NVNeedsManufacture(void)403 _plat__NVNeedsManufacture(
404 void
405 )
406 {
407 #if FILE_BACKED_NV
408 return s_NeedsManufacture;
409 #else
410 return FALSE;
411 #endif
412 }
413