1
2 /* Microsoft Reference Implementation for TPM 2.0
3 *
4 * The copyright in this software is being made available under the BSD License,
5 * included below. This software may be subject to other third party and
6 * contributor rights, including patent rights, and no such rights are granted
7 * under this license.
8 *
9 * Copyright (c) Microsoft Corporation
10 *
11 * All rights reserved.
12 *
13 * BSD License
14 *
15 * Redistribution and use in source and binary forms, with or without modification,
16 * are permitted provided that the following conditions are met:
17 *
18 * Redistributions of source code must retain the above copyright notice, this list
19 * of conditions and the following disclaimer.
20 *
21 * Redistributions in binary form must reproduce the above copyright notice, this
22 * list of conditions and the following disclaimer in the documentation and/or
23 * other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
32 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36 //** Description
37 //
38 // This file contains the socket interface to a TPM simulator.
39 //
40 //** Includes, Locals, Defines and Function Prototypes
41 #include "TpmBuildSwitches.h"
42 #include <stdio.h>
43 #include <stdbool.h>
44
45 #ifdef _MSC_VER
46 # pragma warning(push, 3)
47 # include <windows.h>
48 # include <winsock.h>
49 # pragma warning(pop)
50 typedef int socklen_t;
51 #elif defined(__unix__)
52 # include <string.h>
53 # include <unistd.h>
54 # include <errno.h>
55 # include <stdint.h>
56 # include <netinet/in.h>
57 # include <sys/socket.h>
58 # include <pthread.h>
59 # define ZeroMemory(ptr, sz) (memset((ptr), 0, (sz)))
60 # define closesocket(x) close(x)
61 # define INVALID_SOCKET (-1)
62 # define SOCKET_ERROR (-1)
63 # define WSAGetLastError() (errno)
64 # define INT_PTR intptr_t
65
66 typedef int SOCKET;
67 #else
68 # error "Unsupported platform."
69 #endif
70
71 #include "TpmTcpProtocol.h"
72 #include "Manufacture_fp.h"
73 #include "TpmProfile.h"
74
75 #include "Simulator_fp.h"
76 #include "Platform_fp.h"
77
78 // To access key cache control in TPM
79 void RsaKeyCacheControl(int state);
80
81 #ifndef __IGNORE_STATE__
82
83 static uint32_t ServerVersion = 1;
84
85 #define MAX_BUFFER 1048576
86 char InputBuffer[MAX_BUFFER]; //The input data buffer for the simulator.
87 char OutputBuffer[MAX_BUFFER]; //The output data buffer for the simulator.
88
89 struct
90 {
91 uint32_t largestCommandSize;
92 uint32_t largestCommand;
93 uint32_t largestResponseSize;
94 uint32_t largestResponse;
95 } CommandResponseSizes = {0};
96
97 #endif // __IGNORE_STATE___
98
99 //** Functions
100
101 //*** CreateSocket()
102 // This function creates a socket listening on 'PortNumber'.
103 static int
CreateSocket(int PortNumber,SOCKET * listenSocket)104 CreateSocket(
105 int PortNumber,
106 SOCKET *listenSocket
107 )
108 {
109 struct sockaddr_in MyAddress;
110 int res;
111 //
112 // Initialize Winsock
113 #ifdef _MSC_VER
114 WSADATA wsaData;
115 res = WSAStartup(MAKEWORD(2, 2), &wsaData);
116 if(res != 0)
117 {
118 printf("WSAStartup failed with error: %d\n", res);
119 return -1;
120 }
121 #endif
122 // create listening socket
123 *listenSocket = socket(PF_INET, SOCK_STREAM, 0);
124 if(INVALID_SOCKET == *listenSocket)
125 {
126 printf("Cannot create server listen socket. Error is 0x%x\n",
127 WSAGetLastError());
128 return -1;
129 }
130 // bind the listening socket to the specified port
131 ZeroMemory(&MyAddress, sizeof(MyAddress));
132 MyAddress.sin_port = htons((short)PortNumber);
133 MyAddress.sin_family = AF_INET;
134
135 res = bind(*listenSocket, (struct sockaddr*) &MyAddress, sizeof(MyAddress));
136 if(res == SOCKET_ERROR)
137 {
138 printf("Bind error. Error is 0x%x\n", WSAGetLastError());
139 return -1;
140 }
141 // listen/wait for server connections
142 res = listen(*listenSocket, 3);
143 if(res == SOCKET_ERROR)
144 {
145 printf("Listen error. Error is 0x%x\n", WSAGetLastError());
146 return -1;
147 }
148 return 0;
149 }
150
151 //*** PlatformServer()
152 // This function processes incoming platform requests.
153 bool
PlatformServer(SOCKET s)154 PlatformServer(
155 SOCKET s
156 )
157 {
158 bool OK = true;
159 uint32_t Command;
160 //
161 for(;;)
162 {
163 OK = ReadBytes(s, (char*)&Command, 4);
164 // client disconnected (or other error). We stop processing this client
165 // and return to our caller who can stop the server or listen for another
166 // connection.
167 if(!OK)
168 return true;
169 Command = ntohl(Command);
170 switch(Command)
171 {
172 case TPM_SIGNAL_POWER_ON:
173 _rpc__Signal_PowerOn(false);
174 break;
175 case TPM_SIGNAL_POWER_OFF:
176 _rpc__Signal_PowerOff();
177 break;
178 case TPM_SIGNAL_RESET:
179 _rpc__Signal_PowerOn(true);
180 break;
181 case TPM_SIGNAL_RESTART:
182 _rpc__Signal_Restart();
183 break;
184 case TPM_SIGNAL_PHYS_PRES_ON:
185 _rpc__Signal_PhysicalPresenceOn();
186 break;
187 case TPM_SIGNAL_PHYS_PRES_OFF:
188 _rpc__Signal_PhysicalPresenceOff();
189 break;
190 case TPM_SIGNAL_CANCEL_ON:
191 _rpc__Signal_CancelOn();
192 break;
193 case TPM_SIGNAL_CANCEL_OFF:
194 _rpc__Signal_CancelOff();
195 break;
196 case TPM_SIGNAL_NV_ON:
197 _rpc__Signal_NvOn();
198 break;
199 case TPM_SIGNAL_NV_OFF:
200 _rpc__Signal_NvOff();
201 break;
202 case TPM_SIGNAL_KEY_CACHE_ON:
203 _rpc__RsaKeyCacheControl(true);
204 break;
205 case TPM_SIGNAL_KEY_CACHE_OFF:
206 _rpc__RsaKeyCacheControl(false);
207 break;
208 case TPM_SESSION_END:
209 // Client signaled end-of-session
210 TpmEndSimulation();
211 return true;
212 case TPM_STOP:
213 // Client requested the simulator to exit
214 return false;
215 case TPM_TEST_FAILURE_MODE:
216 _rpc__ForceFailureMode();
217 break;
218 case TPM_GET_COMMAND_RESPONSE_SIZES:
219 OK = WriteVarBytes(s, (char *)&CommandResponseSizes,
220 sizeof(CommandResponseSizes));
221 memset(&CommandResponseSizes, 0, sizeof(CommandResponseSizes));
222 if(!OK)
223 return true;
224 break;
225 case TPM_ACT_GET_SIGNALED:
226 {
227 uint32_t actHandle;
228 OK = ReadUINT32(s, &actHandle);
229 WriteUINT32(s, _rpc__ACT_GetSignaled(actHandle));
230 break;
231 }
232 default:
233 printf("Unrecognized platform interface command %d\n",
234 (int)Command);
235 WriteUINT32(s, 1);
236 return true;
237 }
238 WriteUINT32(s, 0);
239 }
240 }
241
242 //*** PlatformSvcRoutine()
243 // This function is called to set up the socket interfaces to listen for
244 // commands.
245 DWORD WINAPI
PlatformSvcRoutine(LPVOID port)246 PlatformSvcRoutine(
247 LPVOID port
248 )
249 {
250 int PortNumber = (int)(INT_PTR)port;
251 SOCKET listenSocket, serverSocket;
252 struct sockaddr_in HerAddress;
253 int res;
254 socklen_t length;
255 bool continueServing;
256 //
257 res = CreateSocket(PortNumber, &listenSocket);
258 if(res != 0)
259 {
260 printf("Create platform service socket fail\n");
261 return res;
262 }
263 // Loop accepting connections one-by-one until we are killed or asked to stop
264 // Note the platform service is single-threaded so we don't listen for a new
265 // connection until the prior connection drops.
266 do
267 {
268 printf("Platform server listening on port %d\n", PortNumber);
269
270 // blocking accept
271 length = sizeof(HerAddress);
272 serverSocket = accept(listenSocket,
273 (struct sockaddr*) &HerAddress,
274 &length);
275 if(serverSocket == INVALID_SOCKET)
276 {
277 printf("Accept error. Error is 0x%x\n", WSAGetLastError());
278 return (DWORD)-1;
279 }
280 printf("Client accepted\n");
281
282 // normal behavior on client disconnection is to wait for a new client
283 // to connect
284 continueServing = PlatformServer(serverSocket);
285 closesocket(serverSocket);
286 } while(continueServing);
287
288 return 0;
289 }
290
291 //*** PlatformSignalService()
292 // This function starts a new thread waiting for platform signals.
293 // Platform signals are processed one at a time in the order in which they are
294 // received.
295 int
PlatformSignalService(int PortNumber)296 PlatformSignalService(
297 int PortNumber
298 )
299 {
300 #if defined(_MSC_VER)
301 HANDLE hPlatformSvc;
302 int ThreadId;
303 int port = PortNumber;
304 //
305 // Create service thread for platform signals
306 hPlatformSvc = CreateThread(NULL, 0,
307 (LPTHREAD_START_ROUTINE)PlatformSvcRoutine,
308 (LPVOID)(INT_PTR)port, 0, (LPDWORD)&ThreadId);
309 if(hPlatformSvc == NULL)
310 {
311 printf("Thread Creation failed\n");
312 return -1;
313 }
314 return 0;
315 #else
316 pthread_t thread_id;
317 int ret;
318 int port = PortNumber;
319
320 ret = pthread_create(&thread_id, NULL, (void*)PlatformSvcRoutine,
321 (LPVOID)(INT_PTR)port);
322 if (ret == -1)
323 {
324 printf("pthread_create failed: %s", strerror(ret));
325 }
326 return ret;
327 #endif // _MSC_VER
328 }
329
330 //*** RegularCommandService()
331 // This function services regular commands.
332 int
RegularCommandService(int PortNumber)333 RegularCommandService(
334 int PortNumber
335 )
336 {
337 SOCKET listenSocket;
338 SOCKET serverSocket;
339 struct sockaddr_in HerAddress;
340 int res;
341 socklen_t length;
342 bool continueServing;
343 //
344 res = CreateSocket(PortNumber, &listenSocket);
345 if(res != 0)
346 {
347 printf("Create platform service socket fail\n");
348 return res;
349 }
350 // Loop accepting connections one-by-one until we are killed or asked to stop
351 // Note the TPM command service is single-threaded so we don't listen for
352 // a new connection until the prior connection drops.
353 do
354 {
355 printf("TPM command server listening on port %d\n", PortNumber);
356
357 // blocking accept
358 length = sizeof(HerAddress);
359 serverSocket = accept(listenSocket,
360 (struct sockaddr*) &HerAddress,
361 &length);
362 if(serverSocket == INVALID_SOCKET)
363 {
364 printf("Accept error. Error is 0x%x\n", WSAGetLastError());
365 return -1;
366 }
367 printf("Client accepted\n");
368
369 // normal behavior on client disconnection is to wait for a new client
370 // to connect
371 continueServing = TpmServer(serverSocket);
372 closesocket(serverSocket);
373 } while(continueServing);
374 return 0;
375 }
376
377 #if RH_ACT_0
378
379 //*** SimulatorTimeServiceRoutine()
380 // This function is called to service the time 'ticks'.
381 static unsigned long WINAPI
SimulatorTimeServiceRoutine(LPVOID notUsed)382 SimulatorTimeServiceRoutine(
383 LPVOID notUsed
384 )
385 {
386 // All time is in ms
387 const int64_t tick = 1000;
388 uint64_t prevTime = _plat__RealTime();
389 int64_t timeout = tick;
390
391 (void)notUsed;
392
393 while (true)
394 {
395 uint64_t curTime;
396
397 #if defined(_MSC_VER)
398 Sleep((DWORD)timeout);
399 #else
400 struct timespec req = { timeout / 1000, (timeout % 1000) * 1000 };
401 struct timespec rem;
402 nanosleep(&req, &rem);
403 #endif // _MSC_VER
404 curTime = _plat__RealTime();
405
406 // May need to issue several ticks if the Sleep() took longer than asked,
407 // or no ticks at all, it Sleep() was interrupted prematurely.
408 while (prevTime < curTime - tick / 2)
409 {
410 //printf("%05lld | %05lld\n",
411 // prevTime % 100000, (curTime - tick / 2) % 100000);
412 _plat__ACT_Tick();
413 prevTime += (uint64_t)tick;
414 }
415 // Adjust the next timeout to keep the average interval of one second
416 timeout = tick + (prevTime - curTime);
417 //prevTime = curTime;
418 //printf("%04lld | c:%05lld | p:%05llu\n",
419 // timeout, curTime % 100000, prevTime);
420 }
421 return 0;
422 }
423
424 //*** ActTimeService()
425 // This function starts a new thread waiting to wait for time ticks.
426 // Return Type: int
427 // ==0 success
428 // !=0 failure
429 static int
ActTimeService(void)430 ActTimeService(
431 void
432 )
433 {
434 static bool running = false;
435 int ret = 0;
436 if(!running)
437 {
438 #if defined(_MSC_VER)
439 HANDLE hThr;
440 int ThreadId;
441 //
442 printf("Starting ACT thread...\n");
443 // Don't allow ticks to be processed before TPM is manufactured.
444 _plat__ACT_EnableTicks(false);
445
446 // Create service thread for ACT internal timer
447 hThr = CreateThread(NULL, 0,
448 (LPTHREAD_START_ROUTINE)SimulatorTimeServiceRoutine,
449 (LPVOID)(INT_PTR)NULL, 0, (LPDWORD)&ThreadId);
450 if(hThr != NULL)
451 CloseHandle(hThr);
452 else
453 ret = -1;
454 #else
455 pthread_t thread_id;
456 //
457 ret = pthread_create(&thread_id, NULL, (void*)SimulatorTimeServiceRoutine,
458 (LPVOID)(INT_PTR)NULL);
459 #endif // _MSC_VER
460
461 if(ret != 0)
462 printf("ACT thread Creation failed\n");
463 else
464 running = true;
465 }
466 return ret;
467 }
468
469 #endif // RH_ACT_0
470
471 //*** StartTcpServer()
472 // This is the main entry-point to the TCP server. The server listens on port
473 // specified.
474 //
475 // Note that there is no way to specify the network interface in this implementation.
476 int
StartTcpServer(int PortNumber)477 StartTcpServer(
478 int PortNumber
479 )
480 {
481 int res;
482 //
483 #ifdef RH_ACT_0
484 // Start the Time Service routine
485 res = ActTimeService();
486 if(res != 0)
487 {
488 printf("TimeService failed\n");
489 return res;
490 }
491 #endif
492
493 // Start Platform Signal Processing Service
494 res = PlatformSignalService(PortNumber + 1);
495 if(res != 0)
496 {
497 printf("PlatformSignalService failed\n");
498 return res;
499 }
500 // Start Regular/DRTM TPM command service
501 res = RegularCommandService(PortNumber);
502 if(res != 0)
503 {
504 printf("RegularCommandService failed\n");
505 return res;
506 }
507 return 0;
508 }
509
510 //*** ReadBytes()
511 // This function reads the indicated number of bytes ('NumBytes') into buffer
512 // from the indicated socket.
513 bool
ReadBytes(SOCKET s,char * buffer,int NumBytes)514 ReadBytes(
515 SOCKET s,
516 char *buffer,
517 int NumBytes
518 )
519 {
520 int res;
521 int numGot = 0;
522 //
523 while(numGot < NumBytes)
524 {
525 res = recv(s, buffer + numGot, NumBytes - numGot, 0);
526 if(res == -1)
527 {
528 printf("Receive error. Error is 0x%x\n", WSAGetLastError());
529 return false;
530 }
531 if(res == 0)
532 {
533 return false;
534 }
535 numGot += res;
536 }
537 return true;
538 }
539
540 //*** WriteBytes()
541 // This function will send the indicated number of bytes ('NumBytes') to the
542 // indicated socket
543 bool
WriteBytes(SOCKET s,char * buffer,int NumBytes)544 WriteBytes(
545 SOCKET s,
546 char *buffer,
547 int NumBytes
548 )
549 {
550 int res;
551 int numSent = 0;
552 //
553 while(numSent < NumBytes)
554 {
555 res = send(s, buffer + numSent, NumBytes - numSent, 0);
556 if(res == -1)
557 {
558 if(WSAGetLastError() == 0x2745)
559 {
560 printf("Client disconnected\n");
561 }
562 else
563 {
564 printf("Send error. Error is 0x%x\n", WSAGetLastError());
565 }
566 return false;
567 }
568 numSent += res;
569 }
570 return true;
571 }
572
573 //*** WriteUINT32()
574 // Send 4 byte integer
575 bool
WriteUINT32(SOCKET s,uint32_t val)576 WriteUINT32(
577 SOCKET s,
578 uint32_t val
579 )
580 {
581 uint32_t netVal = htonl(val);
582 //
583 return WriteBytes(s, (char*)&netVal, 4);
584 }
585
586 //*** ReadUINT32()
587 // Function to read 4 byte integer from socket.
588 bool
ReadUINT32(SOCKET s,uint32_t * val)589 ReadUINT32(
590 SOCKET s,
591 uint32_t *val
592 )
593 {
594 uint32_t netVal;
595 //
596 if (!ReadBytes(s, (char*)&netVal, 4))
597 return false;
598 *val = ntohl(netVal);
599 return true;
600 }
601
602
603 //*** ReadVarBytes()
604 // Get a uint32-length-prepended binary array. Note that the 4-byte length is
605 // in network byte order (big-endian).
606 bool
ReadVarBytes(SOCKET s,char * buffer,uint32_t * BytesReceived,int MaxLen)607 ReadVarBytes(
608 SOCKET s,
609 char *buffer,
610 uint32_t *BytesReceived,
611 int MaxLen
612 )
613 {
614 int length;
615 bool res;
616 //
617 res = ReadBytes(s, (char*)&length, 4);
618 if(!res) return res;
619 length = ntohl(length);
620 *BytesReceived = length;
621 if(length > MaxLen)
622 {
623 printf("Buffer too big. Client says %d\n", length);
624 return false;
625 }
626 if(length == 0) return true;
627 res = ReadBytes(s, buffer, length);
628 if(!res) return res;
629 return true;
630 }
631
632 //*** WriteVarBytes()
633 // Send a uint32-length-prepended binary array. Note that the 4-byte length is
634 // in network byte order (big-endian).
635 bool
WriteVarBytes(SOCKET s,char * buffer,int BytesToSend)636 WriteVarBytes(
637 SOCKET s,
638 char *buffer,
639 int BytesToSend
640 )
641 {
642 uint32_t netLength = htonl(BytesToSend);
643 bool res;
644 //
645 res = WriteBytes(s, (char*)&netLength, 4);
646 if(!res)
647 return res;
648 res = WriteBytes(s, buffer, BytesToSend);
649 if(!res)
650 return res;
651 return true;
652 }
653
654 //*** TpmServer()
655 // Processing incoming TPM command requests using the protocol / interface
656 // defined above.
657 bool
TpmServer(SOCKET s)658 TpmServer(
659 SOCKET s
660 )
661 {
662 uint32_t length;
663 uint32_t Command;
664 uint8_t locality;
665 bool OK;
666 int result;
667 int clientVersion;
668 _IN_BUFFER InBuffer;
669 _OUT_BUFFER OutBuffer;
670 //
671 for(;;)
672 {
673 OK = ReadBytes(s, (char*)&Command, 4);
674 // client disconnected (or other error). We stop processing this client
675 // and return to our caller who can stop the server or listen for another
676 // connection.
677 if(!OK)
678 return true;
679 Command = ntohl(Command);
680 switch(Command)
681 {
682 case TPM_SIGNAL_HASH_START:
683 _rpc__Signal_Hash_Start();
684 break;
685 case TPM_SIGNAL_HASH_END:
686 _rpc__Signal_HashEnd();
687 break;
688 case TPM_SIGNAL_HASH_DATA:
689 OK = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
690 if(!OK) return true;
691 InBuffer.Buffer = (uint8_t*)InputBuffer;
692 InBuffer.BufferSize = length;
693 _rpc__Signal_Hash_Data(InBuffer);
694 break;
695 case TPM_SEND_COMMAND:
696 OK = ReadBytes(s, (char*)&locality, 1);
697 if(!OK)
698 return true;
699 OK = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
700 if(!OK)
701 return true;
702 InBuffer.Buffer = (uint8_t*)InputBuffer;
703 InBuffer.BufferSize = length;
704 OutBuffer.BufferSize = MAX_BUFFER;
705 OutBuffer.Buffer = (_OUTPUT_BUFFER)OutputBuffer;
706 // record the number of bytes in the command if it is the largest
707 // we have seen so far.
708 if(InBuffer.BufferSize > CommandResponseSizes.largestCommandSize)
709 {
710 CommandResponseSizes.largestCommandSize = InBuffer.BufferSize;
711 memcpy(&CommandResponseSizes.largestCommand,
712 &InputBuffer[6], sizeof(uint32_t));
713 }
714 _rpc__Send_Command(locality, InBuffer, &OutBuffer);
715 // record the number of bytes in the response if it is the largest
716 // we have seen so far.
717 if(OutBuffer.BufferSize > CommandResponseSizes.largestResponseSize)
718 {
719 CommandResponseSizes.largestResponseSize
720 = OutBuffer.BufferSize;
721 memcpy(&CommandResponseSizes.largestResponse,
722 &OutputBuffer[6], sizeof(uint32_t));
723 }
724 OK = WriteVarBytes(s,
725 (char*)OutBuffer.Buffer,
726 OutBuffer.BufferSize);
727 if(!OK)
728 return true;
729 break;
730 case TPM_REMOTE_HANDSHAKE:
731 OK = ReadBytes(s, (char*)&clientVersion, 4);
732 if(!OK)
733 return true;
734 if(clientVersion == 0)
735 {
736 printf("Unsupported client version (0).\n");
737 return true;
738 }
739 OK &= WriteUINT32(s, ServerVersion);
740 OK &= WriteUINT32(s, tpmInRawMode
741 | tpmPlatformAvailable | tpmSupportsPP);
742 break;
743 case TPM_SET_ALTERNATIVE_RESULT:
744 OK = ReadBytes(s, (char*)&result, 4);
745 if(!OK)
746 return true;
747 // Alternative result is not applicable to the simulator.
748 break;
749 case TPM_SESSION_END:
750 // Client signaled end-of-session
751 return true;
752 case TPM_STOP:
753 // Client requested the simulator to exit
754 return false;
755 default:
756 printf("Unrecognized TPM interface command %d\n", (int)Command);
757 return true;
758 }
759 OK = WriteUINT32(s, 0);
760 if(!OK)
761 return true;
762 }
763 }
764