/********************************************************************************/ /* */ /* Linux Device Transmit and Receive Utilities */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* */ /* (c) Copyright IBM Corporation 2015 - 2020. */ /* */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions are */ /* met: */ /* */ /* Redistributions of source code must retain the above copyright notice, */ /* this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* Neither the names of the IBM Corporation nor the names of its */ /* contributors may be used to endorse or promote products derived from */ /* this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /********************************************************************************/ #ifdef TPM_POSIX #include #include #include #include #include #include #include #include #include #include #include "tssproperties.h" #include "tssdev.h" /* local prototypes */ static uint32_t TSS_Dev_Open(TSS_CONTEXT *tssContext); static uint32_t TSS_Dev_SendCommand(int dev_fd, const uint8_t *buffer, uint16_t length, const char *message); static uint32_t TSS_Dev_ReceiveResponse(int dev_fd, uint8_t *buffer, uint32_t *length); /* global configuration */ extern int tssVverbose; extern int tssVerbose; /* TSS_Dev_Transmit() transmits the command and receives the response. Can return device transmit and receive packet errors, but normally returns the TPM response code. */ TPM_RC TSS_Dev_Transmit(TSS_CONTEXT *tssContext, uint8_t *responseBuffer, uint32_t *read, const uint8_t *commandBuffer, uint32_t written, const char *message) { TPM_RC rc = 0; /* open on first transmit */ if (tssContext->tssFirstTransmit) { if (rc == 0) { rc = TSS_Dev_Open(tssContext); } if (rc == 0) { tssContext->tssFirstTransmit = FALSE; } } /* send the command to the device. Error if the device send fails. */ if (rc == 0) { rc = TSS_Dev_SendCommand(tssContext->dev_fd, commandBuffer, written, message); } /* receive the response from the dev_fd. Returns dev_fd errors, malformed response errors. Else returns the TPM response code. */ if (rc == 0) { rc = TSS_Dev_ReceiveResponse(tssContext->dev_fd, responseBuffer, read); } return rc; } /* TSS_Dev_Open() opens the TPM device (through the device driver) */ static uint32_t TSS_Dev_Open(TSS_CONTEXT *tssContext) { uint32_t rc = 0; if (rc == 0) { if (tssVverbose) printf("TSS_Dev_Open: Opening %s\n", tssContext->tssDevice); tssContext->dev_fd = open(tssContext->tssDevice, O_RDWR); if (tssContext->dev_fd < 0) { if (tssVerbose) printf("TSS_Dev_Open: Error opening %s\n", tssContext->tssDevice); rc = TSS_RC_NO_CONNECTION; } } return rc; } /* TSS_Dev_SendCommand() sends the TPM command buffer to the device. Returns an error if the device write fails. */ static uint32_t TSS_Dev_SendCommand(int dev_fd, const uint8_t *buffer, uint16_t length, const char *message) { uint32_t rc = 0; int irc; if (message != NULL) { if (tssVverbose) printf("TSS_Dev_SendCommand: %s\n", message); } if ((rc == 0) && tssVverbose) { TSS_PrintAll("TSS_Dev_SendCommand", buffer, length); } if (rc == 0) { irc = write(dev_fd, buffer, length); if (irc < 0) { if (tssVerbose) printf("TSS_Dev_SendCommand: write error %d %s\n", errno, strerror(errno)); rc = TSS_RC_BAD_CONNECTION; } } return rc; } /* TSS_Dev_ReceiveResponse() reads a response buffer from the device. 'buffer' must be at least MAX_RESPONSE_SIZE bytes. Returns TPM packet error code. Validates that the packet length and the packet responseSize match */ static uint32_t TSS_Dev_ReceiveResponse(int dev_fd, uint8_t *buffer, uint32_t *length) { uint32_t rc = 0; int irc; /* read() return code, negative is error, positive is length */ uint32_t responseSize = 0; /* from TPM packet response stream */ if (tssVverbose) printf("TSS_Dev_ReceiveResponse:\n"); /* read the TPM device */ if (rc == 0) { irc = read(dev_fd, buffer, MAX_RESPONSE_SIZE); if (irc <= 0) { rc = TSS_RC_BAD_CONNECTION; if (irc < 0) { if (tssVerbose) printf("TSS_Dev_ReceiveResponse: read error %d %s\n", errno, strerror(errno)); } } } /* read() is successful, trace the response */ if ((rc == 0) && tssVverbose) { TSS_PrintAll("TSS_Dev_ReceiveResponse", buffer, irc); } /* verify that there is at least a tag, responseSize, and responseCode in TPM response */ if (rc == 0) { if ((unsigned int)irc < (sizeof(TPM_ST) + sizeof(uint32_t) + sizeof(uint32_t))) { if (tssVerbose) printf("TSS_Dev_ReceiveResponse: read bytes %u < header\n", irc); rc = TSS_RC_MALFORMED_RESPONSE; } } /* get responseSize from the packet */ if (rc == 0) { responseSize = ntohl(*(uint32_t *)(buffer + sizeof(TPM_ST))); /* sanity check against the length actually received, the return code */ if ((uint32_t)irc != responseSize) { if (tssVerbose) printf("TSS_Dev_ReceiveResponse: read bytes %u != responseSize %u\n", (uint32_t)irc, responseSize); rc = TSS_RC_MALFORMED_RESPONSE; } } /* if there was no lower level failure, return the TPM packet responseCode */ if (rc == 0) { rc = ntohl(*(uint32_t *)(buffer + sizeof(TPM_ST)+ sizeof(uint32_t))); } *length = responseSize; if (tssVverbose) printf("TSS_Dev_ReceiveResponse: rc %08x\n", rc); return rc; } TPM_RC TSS_Dev_Close(TSS_CONTEXT *tssContext) { if (tssVverbose) printf("TSS_Dev_Close: Closing %s\n", tssContext->tssDevice); close(tssContext->dev_fd); return 0; } #endif /* TPM_POSIX */