• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 other
22  *  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 
36 //**Introduction
37 /*
38     This file contains the NV read and write access methods.  This implementation
39     uses RAM/file and does not manage the RAM/file as NV blocks.
40     The implementation may become more sophisticated over time.
41 */
42 
43 //** Includes
44 #include <memory.h>
45 #include <string.h>
46 #include <assert.h>
47 #include <time.h>
48 #include <wolfssl/wolfcrypt/sha512.h>
49 #include "StmUtil.h"
50 #undef INLINE
51 #include "stm32l4xx_hal.h"
52 #include "PlatformData.h"
53 #include "Platform_fp.h"
54 
55 #define NVINTEGRITYMAGIC (0x44494E54) // TNID - TPM NV Integrity Data
56 typedef union
57 {
58     struct
59     {
60         struct
61         {
62             uint32_t magic;
63             time_t created;
64             time_t lastWrite;
65             uint32_t writeCount;
66             uint8_t nvDigest[WC_SHA512_DIGEST_SIZE];
67         } sig;
68         uint8_t nvSignature[WC_SHA512_DIGEST_SIZE];
69     } s;
70     unsigned char b[0x800];
71     unsigned int w[0x200];
72 } IntegrityData_t, *pIntegrityData_t;
73 
74 __attribute__((section(".integrity"))) const IntegrityData_t nvIntegrity;
75 __attribute__((section(".nvfile"))) const uint8_t nvFile[NV_MEMORY_SIZE];
76 
77 //**Functions
NvHash2Data(uint8_t * data1,uint32_t data1Size,uint8_t * data2,uint32_t data2Size,uint8_t * digest)78 static BOOL NvHash2Data(uint8_t* data1, uint32_t data1Size, uint8_t* data2, uint32_t data2Size, uint8_t* digest)
79 {
80     wc_Sha512 hash;
81     if(wc_InitSha512(&hash))
82     {
83         dbgPrint("ERROR wc_InitSha512() failed.\r\n");
84         return FALSE;
85     }
86     else if(data1 && (data1Size > 0) && wc_Sha512Update(&hash, data1, data1Size))
87     {
88         dbgPrint("ERROR wc_Sha512Update() failed.\r\n");
89         return FALSE;
90     }
91     else if(data2 && (data2Size > 0) && wc_Sha512Update(&hash, data2, data2Size))
92     {
93         dbgPrint("ERROR wc_Sha512Update() failed.\r\n");
94         return FALSE;
95     }
96     else if(wc_Sha512Final(&hash, (byte*)digest))
97     {
98         dbgPrint("ERROR wc_Sha512Final failed.\r\n");
99         return FALSE;
100     }
101     wc_Sha512Free(&hash);
102     return TRUE;
103 }
104 
NvErasePages(void * dest,uint32_t size)105 static BOOL NvErasePages(void* dest, uint32_t size)
106 {
107     BOOL result = TRUE;
108     uint32_t pageError = 0;
109     FLASH_EraseInitTypeDef eraseInfo = {FLASH_TYPEERASE_PAGES,
110                                         FLASH_BANK_1,
111                                         ((uint32_t)dest - 0x08000000) / 0x800,
112                                         (size + 0x7ff) / 0x800};
113 
114     // Open the memory protection
115     for(uint32_t m = 0; m < 10; m++)
116     {
117         if((result = (HAL_FLASH_Unlock() == HAL_OK)) != FALSE)
118         {
119             break;
120         }
121         dbgPrint("WARNING HAL_FLASH_Unlock() retry %u.\r\n", (unsigned int)m);
122         // Bring the flash subsystem into a defined state.
123         HAL_FLASH_Lock();
124         HAL_Delay(1);
125     }
126     if(!result)
127     {
128         dbgPrint("ERROR HAL_FLASH_Unlock() failed.\r\n");
129         goto Cleanup;
130     }
131 
132     // Erase the necessary pages
133     for(uint32_t m = 0; m < 10; m++)
134     {
135         if((result = ((HAL_FLASHEx_Erase(&eraseInfo, &pageError) == HAL_OK) && (pageError == 0xffffffff))))
136         {
137             break;
138         }
139         dbgPrint("WARNING HAL_FLASHEx_Erase() retry %u.\r\n", (unsigned int)m);
140     }
141     if(!result)
142     {
143         dbgPrint("ERROR HAL_FLASHEx_Erase() failed.\r\n");
144         goto Cleanup;
145     }
146 
147 Cleanup:
148     HAL_FLASH_Lock();
149     return result;
150 }
151 
NvFlashPages(void * dest,void * src,uint32_t size)152 static BOOL NvFlashPages(void* dest, void* src, uint32_t size)
153 {
154     BOOL result = TRUE;
155 
156     // Parameter check
157     if(!(result = ((((uint32_t)src % sizeof(uint32_t)) == 0))))
158     {
159         goto Cleanup;
160     }
161 
162     // Erase the required area
163     if(!(result = NvErasePages(dest, size)))
164     {
165         goto Cleanup;
166     }
167 
168     // Open the memory protection
169     if(!(result = (HAL_FLASH_Unlock() == HAL_OK)))
170     {
171         goto Cleanup;
172     }
173 
174     // Flash the src buffer 8 byte at a time and verify
175     for(uint32_t n = 0; n < ((size + sizeof(uint64_t) - 1) / sizeof(uint64_t)); n++)
176     {
177         result = FALSE;
178         for(uint32_t m = 0; m < 10; m++)
179         {
180             uint32_t progPtr = (uint32_t)&(((uint64_t*)dest)[n]);
181             uint64_t progData = ((uint64_t*)src)[n];
182             if((progData == *((uint64_t*)progPtr)) ||
183                ((result = (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, progPtr, progData) == HAL_OK)) &&
184                 (progData == *((uint64_t*)progPtr))))
185             {
186                 result = TRUE;
187                 break;
188             }
189             dbgPrint("WARNING HAL_FLASH_Program() retry %u.\r\n", (unsigned int)m);
190         }
191         if(result == FALSE)
192         {
193             dbgPrint("ERROR HAL_FLASH_Program() failed.\r\n");
194             goto Cleanup;
195         }
196     }
197 
198 Cleanup:
199     HAL_FLASH_Lock();
200     return result;
201 }
202 
NvMakeTimeStamp(time_t time,char * nvTimeStamp,uint32_t size)203 char* NvMakeTimeStamp(time_t time, char* nvTimeStamp, uint32_t size)
204 {
205     struct tm* timeInfo = NULL;
206     timeInfo = gmtime(&time);
207     snprintf(nvTimeStamp, size, "%04d.%02d.%02d-%02d:%02d:%02dGMT",
208                                  timeInfo->tm_year + 1900,
209                                  timeInfo->tm_mon + 1,
210                                  timeInfo->tm_mday,
211                                  timeInfo->tm_hour,
212                                  timeInfo->tm_min,
213                                  timeInfo->tm_sec);
214     return nvTimeStamp;
215 }
216 //*** _plat__NvErrors()
217 // This function is used by the simulator to set the error flags in the NV
218 // subsystem to simulate an error in the NV loading process
219 //LIB_EXPORT void
220 //_plat__NvErrors(
221 //    int              recoverable,
222 //    int            unrecoverable
223 //    )
224 //{
225 //    s_NV_unrecoverable = unrecoverable;
226 //    s_NV_recoverable = recoverable;
227 //}
228 
229 //***_plat__NVEnable()
230 // Enable NV memory.
231 //
232 // This version just pulls in data from a file. In a real TPM, with NV on chip,
233 // this function would verify the integrity of the saved context. If the NV
234 // memory was not on chip but was in something like RPMB, the NV state would be
235 // read in, decrypted and integrity checked.
236 //
237 // The recovery from an integrity failure depends on where the error occurred. It
238 // it was in the state that is discarded by TPM Reset, then the error is
239 // recoverable if the TPM is reset. Otherwise, the TPM must go into failure mode.
240 // return type: int
241 //      0           if success
242 //      > 0         if receive recoverable error
243 //      <0          if unrecoverable error
244 LIB_EXPORT int
_plat__NVEnable(void * platParameter)245 _plat__NVEnable(
246     void            *platParameter  // IN: platform specific parameters
247     )
248 {
249     BOOL result = TRUE;
250     uint8_t tpmUnique[WC_SHA512_DIGEST_SIZE];
251     uint8_t tpmUniqueSize = 0;
252     tpmUniqueSize = _plat__GetUnique(0, sizeof(tpmUnique), tpmUnique);
253 
254     // Start assuming everything is OK
255     s_NV_unrecoverable = FALSE;
256     s_NV_recoverable = FALSE;
257     memcpy(s_NV, nvFile, sizeof(s_NV));
258 
259     // Perform integrity verification
260     if((nvIntegrity.s.sig.magic != NVINTEGRITYMAGIC) || (platParameter))
261     {
262         // Initialize NV
263         IntegrityData_t newIntegrity = {0};
264 
265         if((result = NvErasePages((uint8_t*)&nvIntegrity, sizeof(nvIntegrity))) == FALSE)
266         {
267             dbgPrint("ERROR NvErasePages(nvIntegrity) failed.\r\n");
268             s_NV_unrecoverable = TRUE;
269             goto Cleanup;
270         }
271         if((result = NvErasePages((uint8_t*)nvFile, sizeof(nvFile))) == FALSE)
272         {
273             dbgPrint("ERROR NvErasePages(nvFile) failed.\r\n");
274             s_NV_unrecoverable = TRUE;
275             goto Cleanup;
276         }
277 
278         newIntegrity.s.sig.magic = NVINTEGRITYMAGIC;
279         newIntegrity.s.sig.created = time(NULL);
280         if((result = NvHash2Data((uint8_t*)nvFile, sizeof(nvFile), NULL, 0, newIntegrity.s.sig.nvDigest)) == FALSE)
281         {
282             dbgPrint("WARNING NvHash2Data(nvFile) failed.\r\n");
283             s_NV_unrecoverable = TRUE;
284             goto Cleanup;
285         }
286         if((result = NvHash2Data(tpmUnique, tpmUniqueSize, (uint8_t*)&newIntegrity.s.sig, sizeof(newIntegrity.s.sig), newIntegrity.s.nvSignature)) == FALSE)
287         {
288             dbgPrint("WARNING NvHash2Data(tpmUnique, newIntegrity) failed.\r\n");
289             s_NV_unrecoverable = TRUE;
290             goto Cleanup;
291         }
292         if((result = NvFlashPages((uint8_t*)&nvIntegrity, (uint8_t*)&newIntegrity, sizeof(newIntegrity))) == FALSE)
293         {
294             dbgPrint("ERROR NvFlashPages(nvIntegrity) failed.\r\n");
295             s_NV_unrecoverable = TRUE;
296             goto Cleanup;
297         }
298         dbgPrint("Initialized %dkb NVFile.\r\n", sizeof(nvFile)/1024);
299         memcpy(s_NV, nvFile, sizeof(s_NV));
300         s_NV_recoverable = TRUE;
301     }
302     else
303     {
304         uint8_t nvDigest[WC_SHA512_DIGEST_SIZE];
305         if((result = NvHash2Data(tpmUnique, tpmUniqueSize, (uint8_t*)&nvIntegrity.s.sig, sizeof(nvIntegrity.s.sig), nvDigest)) == FALSE)
306         {
307             dbgPrint("WARNING NvHash2Data(tpmUnique, nvIntegrity) failed.\r\n");
308             s_NV_unrecoverable = TRUE;
309             goto Cleanup;
310         }
311         if(memcmp(nvDigest, nvIntegrity.s.nvSignature, sizeof(nvDigest)))
312         {
313             dbgPrint("WARNING NV signature invalid.\r\n");
314             s_NV_unrecoverable = TRUE;
315             goto Cleanup;
316         }
317         if((result = NvHash2Data((uint8_t*)nvFile, sizeof(nvFile), NULL, 0, nvDigest)) == FALSE)
318         {
319             dbgPrint("WARNING NvHash2Data(nvFile) filed.\r\n");
320             s_NV_unrecoverable = TRUE;
321             goto Cleanup;
322         }
323         if(memcmp(nvDigest, nvIntegrity.s.sig.nvDigest, sizeof(nvDigest)))
324         {
325             dbgPrint("WARNING NV integrity measurement invalid.\r\n");
326             s_NV_unrecoverable = TRUE;
327             goto Cleanup;
328         }
329     }
330     char created[50];
331     char written[50];
332     dbgPrint("NVFile loaded (%dkb, %s created, %d writes, %s last)\r\n",
333              sizeof(nvFile)/1024,
334              NvMakeTimeStamp(nvIntegrity.s.sig.created, created, sizeof(created)),
335              (int)nvIntegrity.s.sig.writeCount,
336              (nvIntegrity.s.sig.lastWrite) ? NvMakeTimeStamp(nvIntegrity.s.sig.lastWrite, written, sizeof(written)) : "NEVER");
337 
338 Cleanup:
339     HAL_FLASH_Lock();
340     if(s_NV_unrecoverable)
341         return -1;
342     return s_NV_recoverable;
343 }
344 
345 //***_plat__NVDisable()
346 // Disable NV memory
347 LIB_EXPORT void
_plat__NVDisable(void)348 _plat__NVDisable(
349     void
350     )
351 {
352     return;
353 }
354 
355 //***_plat__IsNvAvailable()
356 // Check if NV is available
357 // return type: int
358 //      0               NV is available
359 //      1               NV is not available due to write failure
360 //      2               NV is not available due to rate limit
361 LIB_EXPORT int
_plat__IsNvAvailable(void)362 _plat__IsNvAvailable(
363     void
364     )
365 {
366     // NV is not available if the TPM is in failure mode
367     if(!s_NvIsAvailable)
368         return 1;
369 
370     return 0;
371 }
372 
373 //***_plat__NvMemoryRead()
374 // Function: Read a chunk of NV memory
375 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)376 _plat__NvMemoryRead(
377     unsigned int     startOffset,   // IN: read start
378     unsigned int     size,          // IN: size of bytes to read
379     void            *data           // OUT: data buffer
380     )
381 {
382     assert(startOffset + size <= NV_MEMORY_SIZE);
383 
384     // Copy data from RAM
385     memcpy(data, &s_NV[startOffset], size);
386     return;
387 }
388 
389 //*** _plat__NvIsDifferent()
390 // This function checks to see if the NV is different from the test value. This is
391 // so that NV will not be written if it has not changed.
392 // return value: int
393 //  TRUE(1)    the NV location is different from the test value
394 //  FALSE(0)   the NV location is the same as the test value
395 LIB_EXPORT int
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)396 _plat__NvIsDifferent(
397     unsigned int     startOffset,   // IN: read start
398     unsigned int     size,          // IN: size of bytes to read
399     void            *data           // IN: data buffer
400     )
401 {
402     return (memcmp(&s_NV[startOffset], data, size) != 0);
403 }
404 
405 //***_plat__NvMemoryWrite()
406 // This function is used to update NV memory. The "write" is to a memory copy of
407 // NV. At the end of the current command, any changes are written to
408 // the actual NV memory.
409 // NOTE: A useful optimization would be for this code to compare the current
410 // contents of NV with the local copy and note the blocks that have changed. Then
411 // only write those blocks when _plat__NvCommit() is called.
412 LIB_EXPORT void
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)413 _plat__NvMemoryWrite(
414     unsigned int     startOffset,   // IN: write start
415     unsigned int     size,          // IN: size of bytes to write
416     void            *data           // OUT: data buffer
417     )
418 {
419     assert(startOffset + size <= NV_MEMORY_SIZE);
420 
421     // Copy the data to the NV image
422     memcpy(&s_NV[startOffset], data, size);
423 }
424 
425 //***_plat__NvMemoryClear()
426 // Function is used to set a range of NV memory bytes to an implementation-dependent
427 // value. The value represents the erase state of the memory.
428 LIB_EXPORT void
_plat__NvMemoryClear(unsigned int start,unsigned int size)429 _plat__NvMemoryClear(
430     unsigned int     start,         // IN: clear start
431     unsigned int     size           // IN: number of bytes to clear
432     )
433 {
434     assert(start + size <= NV_MEMORY_SIZE);
435 
436     // In this implementation, assume that the errase value for NV is all 1s
437     memset(&s_NV[start], 0xff, size);
438 }
439 
440 //***_plat__NvMemoryMove()
441 // Function: Move a chunk of NV memory from source to destination
442 //      This function should ensure that if there overlap, the original data is
443 //      copied before it is written
444 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)445 _plat__NvMemoryMove(
446     unsigned int     sourceOffset,  // IN: source offset
447     unsigned int     destOffset,    // IN: destination offset
448     unsigned int     size           // IN: size of data being moved
449     )
450 {
451     assert(sourceOffset + size <= NV_MEMORY_SIZE);
452     assert(destOffset + size <= NV_MEMORY_SIZE);
453 
454     // Move data in RAM
455     memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);
456 
457     return;
458 }
459 
460 //***_plat__NvCommit()
461 // Update NV chip
462 // return type: int
463 //  0       NV write success
464 //  non-0   NV write fail
465 LIB_EXPORT int
_plat__NvCommit(void)466 _plat__NvCommit(
467     void
468     )
469 {
470     BOOL result = TRUE;
471     char created[50];
472     char written[50];
473     IntegrityData_t newIntegrity = {0};
474     uint8_t tpmUnique[WC_SHA512_DIGEST_SIZE];
475     uint8_t tpmUniqueSize = 0;
476 
477     tpmUniqueSize = _plat__GetUnique(0, sizeof(tpmUnique), tpmUnique);
478     memcpy(&newIntegrity, &nvIntegrity, sizeof(newIntegrity));
479 
480     if((result = NvHash2Data(s_NV, sizeof(s_NV), NULL, 0, newIntegrity.s.sig.nvDigest)) == FALSE)
481     {
482         dbgPrint("WARNING NvHash2Data(s_NV) failed.\r\n");
483         result = FALSE;
484         goto Cleanup;
485     }
486     if((result = NvHash2Data(tpmUnique, tpmUniqueSize, (uint8_t*)&nvIntegrity.s.sig, sizeof(nvIntegrity.s.sig), newIntegrity.s.nvSignature)) == FALSE)
487     {
488         dbgPrint("WARNING NvHash2Data(tpmUnique, nvIntegrity) failed.\r\n");
489         result = FALSE;
490         goto Cleanup;
491     }
492 
493     if((memcmp(newIntegrity.s.sig.nvDigest, nvIntegrity.s.sig.nvDigest, sizeof(newIntegrity.s.sig.nvDigest))) ||
494        (memcmp(newIntegrity.s.nvSignature, nvIntegrity.s.nvSignature, sizeof(newIntegrity.s.nvSignature))))
495     {
496         newIntegrity.s.sig.lastWrite = time(NULL);
497         newIntegrity.s.sig.writeCount++;
498         if((result = NvHash2Data(tpmUnique, tpmUniqueSize, (uint8_t*)&newIntegrity.s.sig, sizeof(newIntegrity.s.sig), newIntegrity.s.nvSignature)) == FALSE)
499         {
500             dbgPrint("WARNING NvHash2Data(tpmUnique, newIntegrity) failed.\r\n");
501             result = FALSE;
502             goto Cleanup;
503         }
504         if((result = NvFlashPages((uint8_t*)nvFile, s_NV, sizeof(s_NV))) == FALSE)
505         {
506             dbgPrint("ERROR NvFlashPages(nvFile) failed.\r\n");
507             result = FALSE;
508             goto Cleanup;
509         }
510         if((result = NvFlashPages((uint8_t*)&nvIntegrity, (uint8_t*)&newIntegrity, sizeof(newIntegrity))) == FALSE)
511         {
512             dbgPrint("ERROR NvFlashPages(nvIntegrity) failed.\r\n");
513             result = FALSE;
514             goto Cleanup;
515         }
516         dbgPrint("NVFile written (%dkb, %s created, %d writes, %s last)\r\n",
517                  sizeof(nvFile)/1024,
518                  NvMakeTimeStamp(nvIntegrity.s.sig.created, created, sizeof(created)),
519                  (int)nvIntegrity.s.sig.writeCount,
520                  (nvIntegrity.s.sig.lastWrite) ? NvMakeTimeStamp(nvIntegrity.s.sig.lastWrite, written, sizeof(written)) : "NEVER");
521     }
522     else
523     {
524         dbgPrint("NVFile unchanged (%dkb, %s created, %d writes, %s last)\r\n",
525                  sizeof(nvFile)/1024,
526                  NvMakeTimeStamp(nvIntegrity.s.sig.created, created, sizeof(created)),
527                  (int)nvIntegrity.s.sig.writeCount,
528                  (nvIntegrity.s.sig.lastWrite) ? NvMakeTimeStamp(nvIntegrity.s.sig.lastWrite, written, sizeof(written)) : "NEVER");
529     }
530 
531 
532 Cleanup:
533     return (result != TRUE);
534 }
535 
536 //***_plat__SetNvAvail()
537 // Set the current NV state to available.  This function is for testing purpose
538 // only.  It is not part of the platform NV logic
539 LIB_EXPORT void
_plat__SetNvAvail(void)540 _plat__SetNvAvail(
541     void
542     )
543 {
544     s_NvIsAvailable = TRUE;
545     return;
546 }
547 
548 //***_plat__ClearNvAvail()
549 // Set the current NV state to unavailable.  This function is for testing purpose
550 // only.  It is not part of the platform NV logic
551 LIB_EXPORT void
_plat__ClearNvAvail(void)552 _plat__ClearNvAvail(
553     void
554     )
555 {
556     s_NvIsAvailable = FALSE;
557     return;
558 }
559