1// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#include <stdio.h>
9#include <windows.h>
10#include <winsock.h>
11#include "string.h"
12#include <stdlib.h>
13#include <stdint.h>
14#include "TpmTcpProtocol.h"
15BOOL ReadBytes(SOCKET s, char* buffer, int NumBytes);
16BOOL ReadVarBytes(SOCKET s, char* buffer, UINT32* BytesReceived, int MaxLen);
17BOOL WriteVarBytes(SOCKET s, char *buffer, int BytesToSend);
18BOOL WriteBytes(SOCKET s, char* buffer, int NumBytes);
19BOOL WriteUINT32(SOCKET s, UINT32 val);
20#ifndef __IGNORE_STATE__
21static UINT32 ServerVersion = 1;
22#define MAX_BUFFER 1048576
23char InputBuffer[MAX_BUFFER];        //The input data buffer for the simulator.
24char OutputBuffer[MAX_BUFFER];       //The output data buffer for the simulator.
25struct {
26   UINT32      largestCommandSize;
27   UINT32      largestCommand;
28   UINT32      largestResponseSize;
29   UINT32      largestResponse;
30} CommandResponseSizes = {0};
31#endif // __IGNORE_STATE___
32//
33//
34//          Functions
35//
36//          CreateSocket()
37//
38//     This function creates a socket listening on PortNumber.
39//
40static int
41CreateSocket(
42     int                      PortNumber,
43     SOCKET                  *listenSocket
44     )
45{
46     WSADATA                  wsaData;
47     struct                   sockaddr_in MyAddress;
48     int res;
49     // Initialize Winsock
50     res = WSAStartup(MAKEWORD(2,2), &wsaData);
51     if (res != 0)
52     {
53         printf("WSAStartup failed with error: %d\n", res);
54         return -1;
55     }
56     // create listening socket
57     *listenSocket = socket(PF_INET, SOCK_STREAM, 0);
58//
59   if(INVALID_SOCKET == *listenSocket)
60   {
61       printf("Cannot create server listen socket.         Error is 0x%x\n",
62               WSAGetLastError());
63       return -1;
64   }
65   // bind the listening socket to the specified port
66   ZeroMemory(&MyAddress, sizeof(MyAddress));
67   MyAddress.sin_port=htons((short) PortNumber);
68   MyAddress.sin_family=AF_INET;
69   res= bind(*listenSocket,(struct sockaddr*) &MyAddress,sizeof(MyAddress));
70   if(res==SOCKET_ERROR)
71   {
72       printf("Bind error. Error is 0x%x\n", WSAGetLastError());
73       return -1;
74   };
75   // listen/wait for server connections
76   res= listen(*listenSocket,3);
77   if(res==SOCKET_ERROR)
78   {
79       printf("Listen error. Error is 0x%x\n", WSAGetLastError());
80       return -1;
81   };
82   return 0;
83}
84//
85//
86//         PlatformServer()
87//
88//      This function processes incoming platform requests.
89//
90BOOL
91PlatformServer(
92   SOCKET               s
93   )
94{
95   BOOL                      ok = TRUE;
96   UINT32                    length = 0;
97   UINT32                    Command;
98   for(;;)
99   {
100       ok = ReadBytes(s, (char*) &Command, 4);
101       // client disconnected (or other error). We stop processing this client
102       // and return to our caller who can stop the server or listen for another
103       // connection.
104       if(!ok) return TRUE;
105       Command = ntohl(Command);
106       switch(Command)
107       {
108           case TPM_SIGNAL_POWER_ON:
109               _rpc__Signal_PowerOn(FALSE);
110               break;
111             case TPM_SIGNAL_POWER_OFF:
112                 _rpc__Signal_PowerOff();
113                 break;
114             case TPM_SIGNAL_RESET:
115                 _rpc__Signal_PowerOn(TRUE);
116                 break;
117//
118              case TPM_SIGNAL_PHYS_PRES_ON:
119                  _rpc__Signal_PhysicalPresenceOn();
120                  break;
121              case TPM_SIGNAL_PHYS_PRES_OFF:
122                  _rpc__Signal_PhysicalPresenceOff();
123                  break;
124              case TPM_SIGNAL_CANCEL_ON:
125                  _rpc__Signal_CancelOn();
126                  break;
127              case TPM_SIGNAL_CANCEL_OFF:
128                  _rpc__Signal_CancelOff();
129                  break;
130              case TPM_SIGNAL_NV_ON:
131                  _rpc__Signal_NvOn();
132                  break;
133              case TPM_SIGNAL_NV_OFF:
134                  _rpc__Signal_NvOff();
135                  break;
136              case TPM_SESSION_END:
137                  // Client signaled end-of-session
138                  return TRUE;
139              case TPM_STOP:
140                  // Client requested the simulator to exit
141                  return FALSE;
142              case TPM_TEST_FAILURE_MODE:
143                  _rpc__ForceFailureMode();
144                  break;
145              case TPM_GET_COMMAND_RESPONSE_SIZES:
146                  ok = WriteVarBytes(s, (char *)&CommandResponseSizes,
147                                     sizeof(CommandResponseSizes));
148                  memset(&CommandResponseSizes, 0, sizeof(CommandResponseSizes));
149                  if(!ok)
150                      return TRUE;
151                  break;
152              default:
153                  printf("Unrecognized platform interface command %d\n", Command);
154                  WriteUINT32(s, 1);
155                  return TRUE;
156          }
157          WriteUINT32(s,0);
158    }
159    return FALSE;
160}
161//
162//
163//          PlatformSvcRoutine()
164//
165//      This function is called to set up the socket interfaces to listen for commands.
166//
167DWORD WINAPI
168PlatformSvcRoutine(
169    LPVOID               port
170    )
171{
172//
173   int                      PortNumber = (int)(INT_PTR) port;
174   SOCKET                   listenSocket, serverSocket;
175   struct                   sockaddr_in HerAddress;
176   int                      res;
177   int                      length;
178   BOOL                     continueServing;
179   res = CreateSocket(PortNumber, &listenSocket);
180   if(res != 0)
181   {
182       printf("Create platform service socket fail\n");
183       return res;
184   }
185   // Loop accepting connections one-by-one until we are killed or asked to stop
186   // Note the platform service is single-threaded so we don't listen for a new
187   // connection until the prior connection drops.
188   do
189   {
190       printf("Platform server listening on port %d\n", PortNumber);
191          // blocking accept
192          length = sizeof(HerAddress);
193          serverSocket = accept(listenSocket,
194                                (struct sockaddr*) &HerAddress,
195                                &length);
196          if(serverSocket == SOCKET_ERROR)
197          {
198              printf("Accept error. Error is 0x%x\n", WSAGetLastError());
199              return -1;
200          };
201          printf("Client accepted\n");
202          // normal behavior on client disconnection is to wait for a new client
203          // to connect
204          continueServing = PlatformServer(serverSocket);
205          closesocket(serverSocket);
206   }
207   while(continueServing);
208   return 0;
209}
210//
211//
212//          PlatformSignalService()
213//
214//      This function starts a new thread waiting for platform signals. Platform signals are processed one at a
215//      time in the order in which they are received.
216//
217int
218PlatformSignalService(
219   int                 PortNumber
220   )
221{
222   HANDLE                   hPlatformSvc;
223   int                      ThreadId;
224   int                      port = PortNumber;
225   // Create service thread for platform signals
226   hPlatformSvc = CreateThread(NULL, 0,
227                               (LPTHREAD_START_ROUTINE)PlatformSvcRoutine,
228                               (LPVOID) (INT_PTR) port, 0, (LPDWORD)&ThreadId);
229   if(hPlatformSvc == NULL)
230   {
231       printf("Thread Creation failed\n");
232          return -1;
233   }
234   return 0;
235}
236//
237//
238//          RegularCommandService()
239//
240//      This funciton services regular commands.
241//
242int
243RegularCommandService(
244   int                 PortNumber
245   )
246{
247   SOCKET                     listenSocket;
248   SOCKET                     serverSocket;
249   struct                     sockaddr_in HerAddress;
250   int res, length;
251   BOOL continueServing;
252   res = CreateSocket(PortNumber, &listenSocket);
253   if(res != 0)
254   {
255       printf("Create platform service socket fail\n");
256       return res;
257   }
258   // Loop accepting connections one-by-one until we are killed or asked to stop
259   // Note the TPM command service is single-threaded so we don't listen for
260   // a new connection until the prior connection drops.
261   do
262   {
263       printf("TPM command server listening on port %d\n", PortNumber);
264          // blocking accept
265          length = sizeof(HerAddress);
266          serverSocket = accept(listenSocket,
267                                (struct sockaddr*) &HerAddress,
268                                &length);
269          if(serverSocket ==SOCKET_ERROR)
270          {
271              printf("Accept error. Error is 0x%x\n", WSAGetLastError());
272              return -1;
273          };
274          printf("Client accepted\n");
275          // normal behavior on client disconnection is to wait for a new client
276          // to connect
277          continueServing = TpmServer(serverSocket);
278          closesocket(serverSocket);
279   }
280   while(continueServing);
281   return 0;
282}
283//
284//
285//          StartTcpServer()
286//
287//      Main entry-point to the TCP server. The server listens on port specified. Note that there is no way to
288//      specify the network interface in this implementation.
289//
290int
291StartTcpServer(
292   int                  PortNumber
293   )
294{
295   int                       res;
296   // Start Platform Signal Processing Service
297   res = PlatformSignalService(PortNumber+1);
298   if (res != 0)
299   {
300       printf("PlatformSignalService failed\n");
301       return res;
302   }
303   // Start Regular/DRTM TPM command service
304   res = RegularCommandService(PortNumber);
305   if (res != 0)
306   {
307       printf("RegularCommandService failed\n");
308       return res;
309   }
310   return 0;
311}
312//
313//
314//         ReadBytes()
315//
316//      This function reads the indicated number of bytes (NumBytes) into buffer from the indicated socket.
317//
318BOOL
319ReadBytes(
320   SOCKET               s,
321   char                *buffer,
322   int                  NumBytes
323   )
324{
325   int                       res;
326   int                       numGot = 0;
327   while(numGot<NumBytes)
328   {
329       res = recv(s, buffer+numGot, NumBytes-numGot, 0);
330       if(res == -1)
331       {
332           printf("Receive error. Error is 0x%x\n", WSAGetLastError());
333           return FALSE;
334       }
335       if(res==0)
336       {
337           return FALSE;
338       }
339       numGot+=res;
340   }
341   return TRUE;
342}
343//
344//
345//         WriteBytes()
346//
347//      This function will send the indicated number of bytes (NumBytes) to the indicated socket
348//
349BOOL
350WriteBytes(
351   SOCKET              s,
352   char               *buffer,
353   int                 NumBytes
354   )
355{
356   int                   res;
357   int                   numSent = 0;
358   while(numSent<NumBytes)
359   {
360       res = send(s, buffer+numSent, NumBytes-numSent, 0);
361       if(res == -1)
362       {
363           if(WSAGetLastError() == 0x2745)
364           {
365               printf("Client disconnected\n");
366           }
367           else
368           {
369               printf("Send error. Error is 0x%x\n", WSAGetLastError());
370           }
371           return FALSE;
372       }
373       numSent+=res;
374   }
375   return TRUE;
376}
377//
378//
379//         WriteUINT32()
380//
381//      Send 4 bytes containing hton(1)
382//
383BOOL
384WriteUINT32(
385   SOCKET              s,
386   UINT32              val
387   )
388{
389   UINT32 netVal = htonl(val);
390   return WriteBytes(s, (char*) &netVal, 4);
391}
392//
393//
394//       ReadVarBytes()
395//
396//      Get a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big-
397//      endian).
398//
399BOOL
400ReadVarBytes(
401   SOCKET              s,
402   char               *buffer,
403   UINT32             *BytesReceived,
404   int                 MaxLen
405   )
406{
407   int                       length;
408   BOOL                      res;
409   res = ReadBytes(s, (char*) &length, 4);
410   if(!res) return res;
411   length = ntohl(length);
412   *BytesReceived = length;
413   if(length>MaxLen)
414   {
415        printf("Buffer too big.       Client says %d\n", length);
416        return FALSE;
417   }
418   if(length==0) return TRUE;
419   res = ReadBytes(s, buffer, length);
420   if(!res) return res;
421   return TRUE;
422}
423//
424//
425//       WriteVarBytes()
426//
427//      Send a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big-
428//      endian).
429//
430BOOL
431WriteVarBytes(
432   SOCKET              s,
433   char               *buffer,
434   int                 BytesToSend
435   )
436{
437   UINT32                   netLength = htonl(BytesToSend);
438   BOOL res;
439   res = WriteBytes(s, (char*) &netLength, 4);
440   if(!res) return res;
441   res = WriteBytes(s, buffer, BytesToSend);
442   if(!res) return res;
443   return TRUE;
444}
445//
446//
447//       TpmServer()
448//
449//      Processing incoming TPM command requests using the protocol / interface defined above.
450//
451BOOL
452TpmServer(
453   SOCKET              s
454   )
455{
456   UINT32                   length;
457   UINT32                   Command;
458   BYTE                     locality;
459   BOOL                     ok;
460   int                      result;
461   int                      clientVersion;
462   _IN_BUFFER               InBuffer;
463   _OUT_BUFFER              OutBuffer;
464   for(;;)
465   {
466       ok = ReadBytes(s, (char*) &Command, 4);
467       // client disconnected (or other error). We stop processing this client
468       // and return to our caller who can stop the server or listen for another
469       // connection.
470       if(!ok)
471           return TRUE;
472       Command = ntohl(Command);
473       switch(Command)
474       {
475           case TPM_SIGNAL_HASH_START:
476               _rpc__Signal_Hash_Start();
477               break;
478              case TPM_SIGNAL_HASH_END:
479                  _rpc__Signal_HashEnd();
480                  break;
481              case TPM_SIGNAL_HASH_DATA:
482                  ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
483                  if(!ok) return TRUE;
484                  InBuffer.Buffer = (BYTE*) InputBuffer;
485                  InBuffer.BufferSize = length;
486                  _rpc__Signal_Hash_Data(InBuffer);
487                  break;
488              case TPM_SEND_COMMAND:
489                  ok = ReadBytes(s, (char*) &locality, 1);
490                  if(!ok)
491                      return TRUE;
492                  ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
493                  if(!ok)
494                      return TRUE;
495                  InBuffer.Buffer = (BYTE*) InputBuffer;
496                  InBuffer.BufferSize = length;
497                  OutBuffer.BufferSize = MAX_BUFFER;
498                  OutBuffer.Buffer = (_OUTPUT_BUFFER) OutputBuffer;
499                  // record the number of bytes in the command if it is the largest
500                  // we have seen so far.
501                  if(InBuffer.BufferSize > CommandResponseSizes.largestCommandSize)
502                  {
503                      CommandResponseSizes.largestCommandSize = InBuffer.BufferSize;
504                      memcpy(&CommandResponseSizes.largestCommand,
505                             &InputBuffer[6], sizeof(UINT32));
506                  }
507                  _rpc__Send_Command(locality, InBuffer, &OutBuffer);
508                  // record the number of bytes in the response if it is the largest
509                  // we have seen so far.
510                  if(OutBuffer.BufferSize > CommandResponseSizes.largestResponseSize)
511                  {
512                      CommandResponseSizes.largestResponseSize
513                          = OutBuffer.BufferSize;
514                      memcpy(&CommandResponseSizes.largestResponse,
515                             &OutputBuffer[6], sizeof(UINT32));
516                  }
517                  ok = WriteVarBytes(s,
518                                     (char*) OutBuffer.Buffer,
519                                     OutBuffer.BufferSize);
520                  if(!ok)
521                      return TRUE;
522                  break;
523              case TPM_REMOTE_HANDSHAKE:
524                  ok = ReadBytes(s, (char*)&clientVersion, 4);
525                  if(!ok)
526                      return TRUE;
527                  if( clientVersion == 0 )
528                  {
529                      printf("Unsupported client version (0).\n");
530                      return TRUE;
531                  }
532                  ok &= WriteUINT32(s, ServerVersion);
533                  ok &= WriteUINT32(s,
534                                 tpmInRawMode | tpmPlatformAvailable | tpmSupportsPP);
535                  break;
536              case TPM_SET_ALTERNATIVE_RESULT:
537                  ok = ReadBytes(s, (char*)&result, 4);
538                  if(!ok)
539                      return TRUE;
540                  // Alternative result is not applicable to the simulator.
541                  break;
542             case TPM_SESSION_END:
543                 // Client signaled end-of-session
544                 return TRUE;
545             case TPM_STOP:
546                 // Client requested the simulator to exit
547                 return FALSE;
548             default:
549                 printf("Unrecognized TPM interface command %d\n", Command);
550                 return TRUE;
551        }
552        ok = WriteUINT32(s,0);
553        if(!ok)
554            return TRUE;
555   }
556   return FALSE;
557}
558