• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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