blob: affd9db01b1e04b06e3455e56724f0783d230344 [file] [log] [blame]
/********************************************************************************/
/* */
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <ibmtss/tssresponsecode.h>
#include <ibmtss/tsserror.h>
#include <ibmtss/tssprint.h>
#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 */