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