| // This file was extracted from the TCG Published |
| // Trusted Platform Module Library |
| // Part 4: Supporting Routines |
| // Family "2.0" |
| // Level 00 Revision 01.16 |
| // October 30, 2014 |
| |
| #include <stdio.h> |
| #include <windows.h> |
| #include <winsock.h> |
| #include "string.h" |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include "TpmTcpProtocol.h" |
| BOOL ReadBytes(SOCKET s, char* buffer, int NumBytes); |
| BOOL ReadVarBytes(SOCKET s, char* buffer, UINT32* BytesReceived, int MaxLen); |
| BOOL WriteVarBytes(SOCKET s, char *buffer, int BytesToSend); |
| BOOL WriteBytes(SOCKET s, char* buffer, int NumBytes); |
| BOOL WriteUINT32(SOCKET s, UINT32 val); |
| #ifndef __IGNORE_STATE__ |
| static UINT32 ServerVersion = 1; |
| #define MAX_BUFFER 1048576 |
| char InputBuffer[MAX_BUFFER]; //The input data buffer for the simulator. |
| char OutputBuffer[MAX_BUFFER]; //The output data buffer for the simulator. |
| struct { |
| UINT32 largestCommandSize; |
| UINT32 largestCommand; |
| UINT32 largestResponseSize; |
| UINT32 largestResponse; |
| } CommandResponseSizes = {0}; |
| #endif // __IGNORE_STATE___ |
| // |
| // |
| // Functions |
| // |
| // CreateSocket() |
| // |
| // This function creates a socket listening on PortNumber. |
| // |
| static int |
| CreateSocket( |
| int PortNumber, |
| SOCKET *listenSocket |
| ) |
| { |
| WSADATA wsaData; |
| struct sockaddr_in MyAddress; |
| int res; |
| // Initialize Winsock |
| res = WSAStartup(MAKEWORD(2,2), &wsaData); |
| if (res != 0) |
| { |
| printf("WSAStartup failed with error: %d\n", res); |
| return -1; |
| } |
| // create listening socket |
| *listenSocket = socket(PF_INET, SOCK_STREAM, 0); |
| // |
| if(INVALID_SOCKET == *listenSocket) |
| { |
| printf("Cannot create server listen socket. Error is 0x%x\n", |
| WSAGetLastError()); |
| return -1; |
| } |
| // bind the listening socket to the specified port |
| ZeroMemory(&MyAddress, sizeof(MyAddress)); |
| MyAddress.sin_port=htons((short) PortNumber); |
| MyAddress.sin_family=AF_INET; |
| res= bind(*listenSocket,(struct sockaddr*) &MyAddress,sizeof(MyAddress)); |
| if(res==SOCKET_ERROR) |
| { |
| printf("Bind error. Error is 0x%x\n", WSAGetLastError()); |
| return -1; |
| }; |
| // listen/wait for server connections |
| res= listen(*listenSocket,3); |
| if(res==SOCKET_ERROR) |
| { |
| printf("Listen error. Error is 0x%x\n", WSAGetLastError()); |
| return -1; |
| }; |
| return 0; |
| } |
| // |
| // |
| // PlatformServer() |
| // |
| // This function processes incoming platform requests. |
| // |
| BOOL |
| PlatformServer( |
| SOCKET s |
| ) |
| { |
| BOOL ok = TRUE; |
| UINT32 length = 0; |
| UINT32 Command; |
| for(;;) |
| { |
| ok = ReadBytes(s, (char*) &Command, 4); |
| // client disconnected (or other error). We stop processing this client |
| // and return to our caller who can stop the server or listen for another |
| // connection. |
| if(!ok) return TRUE; |
| Command = ntohl(Command); |
| switch(Command) |
| { |
| case TPM_SIGNAL_POWER_ON: |
| _rpc__Signal_PowerOn(FALSE); |
| break; |
| case TPM_SIGNAL_POWER_OFF: |
| _rpc__Signal_PowerOff(); |
| break; |
| case TPM_SIGNAL_RESET: |
| _rpc__Signal_PowerOn(TRUE); |
| break; |
| // |
| case TPM_SIGNAL_PHYS_PRES_ON: |
| _rpc__Signal_PhysicalPresenceOn(); |
| break; |
| case TPM_SIGNAL_PHYS_PRES_OFF: |
| _rpc__Signal_PhysicalPresenceOff(); |
| break; |
| case TPM_SIGNAL_CANCEL_ON: |
| _rpc__Signal_CancelOn(); |
| break; |
| case TPM_SIGNAL_CANCEL_OFF: |
| _rpc__Signal_CancelOff(); |
| break; |
| case TPM_SIGNAL_NV_ON: |
| _rpc__Signal_NvOn(); |
| break; |
| case TPM_SIGNAL_NV_OFF: |
| _rpc__Signal_NvOff(); |
| break; |
| case TPM_SESSION_END: |
| // Client signaled end-of-session |
| return TRUE; |
| case TPM_STOP: |
| // Client requested the simulator to exit |
| return FALSE; |
| case TPM_TEST_FAILURE_MODE: |
| _rpc__ForceFailureMode(); |
| break; |
| case TPM_GET_COMMAND_RESPONSE_SIZES: |
| ok = WriteVarBytes(s, (char *)&CommandResponseSizes, |
| sizeof(CommandResponseSizes)); |
| memset(&CommandResponseSizes, 0, sizeof(CommandResponseSizes)); |
| if(!ok) |
| return TRUE; |
| break; |
| default: |
| printf("Unrecognized platform interface command %d\n", Command); |
| WriteUINT32(s, 1); |
| return TRUE; |
| } |
| WriteUINT32(s,0); |
| } |
| return FALSE; |
| } |
| // |
| // |
| // PlatformSvcRoutine() |
| // |
| // This function is called to set up the socket interfaces to listen for commands. |
| // |
| DWORD WINAPI |
| PlatformSvcRoutine( |
| LPVOID port |
| ) |
| { |
| // |
| int PortNumber = (int)(INT_PTR) port; |
| SOCKET listenSocket, serverSocket; |
| struct sockaddr_in HerAddress; |
| int res; |
| int length; |
| BOOL continueServing; |
| res = CreateSocket(PortNumber, &listenSocket); |
| if(res != 0) |
| { |
| printf("Create platform service socket fail\n"); |
| return res; |
| } |
| // Loop accepting connections one-by-one until we are killed or asked to stop |
| // Note the platform service is single-threaded so we don't listen for a new |
| // connection until the prior connection drops. |
| do |
| { |
| printf("Platform server listening on port %d\n", PortNumber); |
| // blocking accept |
| length = sizeof(HerAddress); |
| serverSocket = accept(listenSocket, |
| (struct sockaddr*) &HerAddress, |
| &length); |
| if(serverSocket == SOCKET_ERROR) |
| { |
| printf("Accept error. Error is 0x%x\n", WSAGetLastError()); |
| return -1; |
| }; |
| printf("Client accepted\n"); |
| // normal behavior on client disconnection is to wait for a new client |
| // to connect |
| continueServing = PlatformServer(serverSocket); |
| closesocket(serverSocket); |
| } |
| while(continueServing); |
| return 0; |
| } |
| // |
| // |
| // PlatformSignalService() |
| // |
| // This function starts a new thread waiting for platform signals. Platform signals are processed one at a |
| // time in the order in which they are received. |
| // |
| int |
| PlatformSignalService( |
| int PortNumber |
| ) |
| { |
| HANDLE hPlatformSvc; |
| int ThreadId; |
| int port = PortNumber; |
| // Create service thread for platform signals |
| hPlatformSvc = CreateThread(NULL, 0, |
| (LPTHREAD_START_ROUTINE)PlatformSvcRoutine, |
| (LPVOID) (INT_PTR) port, 0, (LPDWORD)&ThreadId); |
| if(hPlatformSvc == NULL) |
| { |
| printf("Thread Creation failed\n"); |
| return -1; |
| } |
| return 0; |
| } |
| // |
| // |
| // RegularCommandService() |
| // |
| // This funciton services regular commands. |
| // |
| int |
| RegularCommandService( |
| int PortNumber |
| ) |
| { |
| SOCKET listenSocket; |
| SOCKET serverSocket; |
| struct sockaddr_in HerAddress; |
| int res, length; |
| BOOL continueServing; |
| res = CreateSocket(PortNumber, &listenSocket); |
| if(res != 0) |
| { |
| printf("Create platform service socket fail\n"); |
| return res; |
| } |
| // Loop accepting connections one-by-one until we are killed or asked to stop |
| // Note the TPM command service is single-threaded so we don't listen for |
| // a new connection until the prior connection drops. |
| do |
| { |
| printf("TPM command server listening on port %d\n", PortNumber); |
| // blocking accept |
| length = sizeof(HerAddress); |
| serverSocket = accept(listenSocket, |
| (struct sockaddr*) &HerAddress, |
| &length); |
| if(serverSocket ==SOCKET_ERROR) |
| { |
| printf("Accept error. Error is 0x%x\n", WSAGetLastError()); |
| return -1; |
| }; |
| printf("Client accepted\n"); |
| // normal behavior on client disconnection is to wait for a new client |
| // to connect |
| continueServing = TpmServer(serverSocket); |
| closesocket(serverSocket); |
| } |
| while(continueServing); |
| return 0; |
| } |
| // |
| // |
| // StartTcpServer() |
| // |
| // Main entry-point to the TCP server. The server listens on port specified. Note that there is no way to |
| // specify the network interface in this implementation. |
| // |
| int |
| StartTcpServer( |
| int PortNumber |
| ) |
| { |
| int res; |
| // Start Platform Signal Processing Service |
| res = PlatformSignalService(PortNumber+1); |
| if (res != 0) |
| { |
| printf("PlatformSignalService failed\n"); |
| return res; |
| } |
| // Start Regular/DRTM TPM command service |
| res = RegularCommandService(PortNumber); |
| if (res != 0) |
| { |
| printf("RegularCommandService failed\n"); |
| return res; |
| } |
| return 0; |
| } |
| // |
| // |
| // ReadBytes() |
| // |
| // This function reads the indicated number of bytes (NumBytes) into buffer from the indicated socket. |
| // |
| BOOL |
| ReadBytes( |
| SOCKET s, |
| char *buffer, |
| int NumBytes |
| ) |
| { |
| int res; |
| int numGot = 0; |
| while(numGot<NumBytes) |
| { |
| res = recv(s, buffer+numGot, NumBytes-numGot, 0); |
| if(res == -1) |
| { |
| printf("Receive error. Error is 0x%x\n", WSAGetLastError()); |
| return FALSE; |
| } |
| if(res==0) |
| { |
| return FALSE; |
| } |
| numGot+=res; |
| } |
| return TRUE; |
| } |
| // |
| // |
| // WriteBytes() |
| // |
| // This function will send the indicated number of bytes (NumBytes) to the indicated socket |
| // |
| BOOL |
| WriteBytes( |
| SOCKET s, |
| char *buffer, |
| int NumBytes |
| ) |
| { |
| int res; |
| int numSent = 0; |
| while(numSent<NumBytes) |
| { |
| res = send(s, buffer+numSent, NumBytes-numSent, 0); |
| if(res == -1) |
| { |
| if(WSAGetLastError() == 0x2745) |
| { |
| printf("Client disconnected\n"); |
| } |
| else |
| { |
| printf("Send error. Error is 0x%x\n", WSAGetLastError()); |
| } |
| return FALSE; |
| } |
| numSent+=res; |
| } |
| return TRUE; |
| } |
| // |
| // |
| // WriteUINT32() |
| // |
| // Send 4 bytes containing hton(1) |
| // |
| BOOL |
| WriteUINT32( |
| SOCKET s, |
| UINT32 val |
| ) |
| { |
| UINT32 netVal = htonl(val); |
| return WriteBytes(s, (char*) &netVal, 4); |
| } |
| // |
| // |
| // ReadVarBytes() |
| // |
| // Get a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big- |
| // endian). |
| // |
| BOOL |
| ReadVarBytes( |
| SOCKET s, |
| char *buffer, |
| UINT32 *BytesReceived, |
| int MaxLen |
| ) |
| { |
| int length; |
| BOOL res; |
| res = ReadBytes(s, (char*) &length, 4); |
| if(!res) return res; |
| length = ntohl(length); |
| *BytesReceived = length; |
| if(length>MaxLen) |
| { |
| printf("Buffer too big. Client says %d\n", length); |
| return FALSE; |
| } |
| if(length==0) return TRUE; |
| res = ReadBytes(s, buffer, length); |
| if(!res) return res; |
| return TRUE; |
| } |
| // |
| // |
| // WriteVarBytes() |
| // |
| // Send a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big- |
| // endian). |
| // |
| BOOL |
| WriteVarBytes( |
| SOCKET s, |
| char *buffer, |
| int BytesToSend |
| ) |
| { |
| UINT32 netLength = htonl(BytesToSend); |
| BOOL res; |
| res = WriteBytes(s, (char*) &netLength, 4); |
| if(!res) return res; |
| res = WriteBytes(s, buffer, BytesToSend); |
| if(!res) return res; |
| return TRUE; |
| } |
| // |
| // |
| // TpmServer() |
| // |
| // Processing incoming TPM command requests using the protocol / interface defined above. |
| // |
| BOOL |
| TpmServer( |
| SOCKET s |
| ) |
| { |
| UINT32 length; |
| UINT32 Command; |
| BYTE locality; |
| BOOL ok; |
| int result; |
| int clientVersion; |
| _IN_BUFFER InBuffer; |
| _OUT_BUFFER OutBuffer; |
| for(;;) |
| { |
| ok = ReadBytes(s, (char*) &Command, 4); |
| // client disconnected (or other error). We stop processing this client |
| // and return to our caller who can stop the server or listen for another |
| // connection. |
| if(!ok) |
| return TRUE; |
| Command = ntohl(Command); |
| switch(Command) |
| { |
| case TPM_SIGNAL_HASH_START: |
| _rpc__Signal_Hash_Start(); |
| break; |
| case TPM_SIGNAL_HASH_END: |
| _rpc__Signal_HashEnd(); |
| break; |
| case TPM_SIGNAL_HASH_DATA: |
| ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER); |
| if(!ok) return TRUE; |
| InBuffer.Buffer = (BYTE*) InputBuffer; |
| InBuffer.BufferSize = length; |
| _rpc__Signal_Hash_Data(InBuffer); |
| break; |
| case TPM_SEND_COMMAND: |
| ok = ReadBytes(s, (char*) &locality, 1); |
| if(!ok) |
| return TRUE; |
| ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER); |
| if(!ok) |
| return TRUE; |
| InBuffer.Buffer = (BYTE*) InputBuffer; |
| InBuffer.BufferSize = length; |
| OutBuffer.BufferSize = MAX_BUFFER; |
| OutBuffer.Buffer = (_OUTPUT_BUFFER) OutputBuffer; |
| // record the number of bytes in the command if it is the largest |
| // we have seen so far. |
| if(InBuffer.BufferSize > CommandResponseSizes.largestCommandSize) |
| { |
| CommandResponseSizes.largestCommandSize = InBuffer.BufferSize; |
| memcpy(&CommandResponseSizes.largestCommand, |
| &InputBuffer[6], sizeof(UINT32)); |
| } |
| _rpc__Send_Command(locality, InBuffer, &OutBuffer); |
| // record the number of bytes in the response if it is the largest |
| // we have seen so far. |
| if(OutBuffer.BufferSize > CommandResponseSizes.largestResponseSize) |
| { |
| CommandResponseSizes.largestResponseSize |
| = OutBuffer.BufferSize; |
| memcpy(&CommandResponseSizes.largestResponse, |
| &OutputBuffer[6], sizeof(UINT32)); |
| } |
| ok = WriteVarBytes(s, |
| (char*) OutBuffer.Buffer, |
| OutBuffer.BufferSize); |
| if(!ok) |
| return TRUE; |
| break; |
| case TPM_REMOTE_HANDSHAKE: |
| ok = ReadBytes(s, (char*)&clientVersion, 4); |
| if(!ok) |
| return TRUE; |
| if( clientVersion == 0 ) |
| { |
| printf("Unsupported client version (0).\n"); |
| return TRUE; |
| } |
| ok &= WriteUINT32(s, ServerVersion); |
| ok &= WriteUINT32(s, |
| tpmInRawMode | tpmPlatformAvailable | tpmSupportsPP); |
| break; |
| case TPM_SET_ALTERNATIVE_RESULT: |
| ok = ReadBytes(s, (char*)&result, 4); |
| if(!ok) |
| return TRUE; |
| // Alternative result is not applicable to the simulator. |
| break; |
| case TPM_SESSION_END: |
| // Client signaled end-of-session |
| return TRUE; |
| case TPM_STOP: |
| // Client requested the simulator to exit |
| return FALSE; |
| default: |
| printf("Unrecognized TPM interface command %d\n", Command); |
| return TRUE; |
| } |
| ok = WriteUINT32(s,0); |
| if(!ok) |
| return TRUE; |
| } |
| return FALSE; |
| } |