blob: 6800e39d2d43c2064e5937ae583d7401366a1b36 [file] [log] [blame]
Vadim Bendebury56797522015-05-20 10:32:25 -07001// 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}