Home | History | Annotate | Download | only in tpm2
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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