557 lines
16 KiB
C
557 lines
16 KiB
C
// 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;
|
|
}
|