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