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"
15 BOOL ReadBytes(SOCKET s, char* buffer, int NumBytes);
16 BOOL ReadVarBytes(SOCKET s, char* buffer, UINT32* BytesReceived, int MaxLen);
17 BOOL WriteVarBytes(SOCKET s, char *buffer, int BytesToSend);
18 BOOL WriteBytes(SOCKET s, char* buffer, int NumBytes);
19 BOOL WriteUINT32(SOCKET s, UINT32 val);
20 #ifndef __IGNORE_STATE__
21 static UINT32 ServerVersion = 1;
22 #define MAX_BUFFER 1048576
23 char InputBuffer[MAX_BUFFER];        //The input data buffer for the simulator.
24 char OutputBuffer[MAX_BUFFER];       //The output data buffer for the simulator.
25 struct {
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 //
40 static int
CreateSocket(int PortNumber,SOCKET * listenSocket)41 CreateSocket(
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 //
90 BOOL
PlatformServer(SOCKET s)91 PlatformServer(
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 //
167 DWORD WINAPI
PlatformSvcRoutine(LPVOID port)168 PlatformSvcRoutine(
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 //
217 int
PlatformSignalService(int PortNumber)218 PlatformSignalService(
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 //
242 int
RegularCommandService(int PortNumber)243 RegularCommandService(
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 //
290 int
StartTcpServer(int PortNumber)291 StartTcpServer(
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 //
318 BOOL
ReadBytes(SOCKET s,char * buffer,int NumBytes)319 ReadBytes(
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 //
349 BOOL
WriteBytes(SOCKET s,char * buffer,int NumBytes)350 WriteBytes(
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 //
383 BOOL
WriteUINT32(SOCKET s,UINT32 val)384 WriteUINT32(
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 //
399 BOOL
ReadVarBytes(SOCKET s,char * buffer,UINT32 * BytesReceived,int MaxLen)400 ReadVarBytes(
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 //
430 BOOL
WriteVarBytes(SOCKET s,char * buffer,int BytesToSend)431 WriteVarBytes(
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 //
451 BOOL
TpmServer(SOCKET s)452 TpmServer(
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