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