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