/*
* Licensed Materials - Property of IBM
*
* trousers - An open source TCG Software Stack
*
* (C) Copyright International Business Machines Corp. 2004
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "trousers/tss.h"
#include "trousers_types.h"
#include "tcs_tsp.h"
#include "tcs_utils.h"
#include "tcs_int_literals.h"
#include "capabilities.h"
#include "tcsd_wrap.h"
#include "tcsd.h"
#include "tcslog.h"
#include "tcsem.h"
TSS_RESULT
TCS_LogPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */
TSS_PCR_EVENT Event, /* in */
UINT32 *pNumber) /* out */
{
TSS_RESULT result;
if((result = ctx_verify_context(hContext)))
return result;
if(Event.ulPcrIndex >= tpm_metrics.num_pcrs)
return TCSERR(TSS_E_BAD_PARAMETER);
if (tcsd_options.kernel_pcrs & (1 << Event.ulPcrIndex)) {
LogInfo("PCR %d is configured to be kernel controlled. Event logging denied.",
Event.ulPcrIndex);
return TCSERR(TSS_E_FAIL);
}
if (tcsd_options.firmware_pcrs & (1 << Event.ulPcrIndex)) {
LogInfo("PCR %d is configured to be firmware controlled. Event logging denied.",
Event.ulPcrIndex);
return TCSERR(TSS_E_FAIL);
}
return event_log_add(&Event, pNumber);
}
/* This routine will handle creating the TSS_PCR_EVENT structures from log
* data produced by an external source. The external source in mind here
* is the log of PCR extends done by the kernel from beneath the TSS
* (via direct calls to the device driver).
*/
TSS_RESULT
TCS_GetExternalPcrEvent(UINT32 PcrIndex, /* in */
UINT32 *pNumber, /* in, out */
TSS_PCR_EVENT **ppEvent) /* out */
{
FILE *log_handle;
char *source;
if (tcsd_options.kernel_pcrs & (1 << PcrIndex)) {
source = tcsd_options.kernel_log_file;
if (tcs_event_log->kernel_source != NULL) {
if (tcs_event_log->kernel_source->open((void *)source,
(FILE **) &log_handle))
return TCSERR(TSS_E_INTERNAL_ERROR);
if (tcs_event_log->kernel_source->get_entry(log_handle, PcrIndex,
pNumber, ppEvent)) {
tcs_event_log->kernel_source->close(log_handle);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
tcs_event_log->kernel_source->close(log_handle);
} else {
LogError("No source for externel kernel events was compiled in, but "
"the tcsd is configured to use one! (see %s)",
tcsd_config_file);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
} else if (tcsd_options.firmware_pcrs & (1 << PcrIndex)) {
source = tcsd_options.firmware_log_file;
if (tcs_event_log->firmware_source != NULL) {
if (tcs_event_log->firmware_source->open((void *)source, &log_handle))
return TCSERR(TSS_E_INTERNAL_ERROR);
if (tcs_event_log->firmware_source->get_entry(log_handle, PcrIndex,
pNumber, ppEvent)) {
tcs_event_log->firmware_source->close(log_handle);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
tcs_event_log->firmware_source->close(log_handle);
} else {
LogError("No source for externel firmware events was compiled in, but "
"the tcsd is configured to use one! (see %s)",
tcsd_config_file);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
} else {
LogError("PCR index %d not flagged as kernel or firmware controlled.", PcrIndex);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
return TSS_SUCCESS;
}
TSS_RESULT
TCS_GetPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */
UINT32 PcrIndex, /* in */
UINT32 *pNumber, /* in, out */
TSS_PCR_EVENT **ppEvent) /* out */
{
TSS_RESULT result;
TSS_PCR_EVENT *event;
if ((result = ctx_verify_context(hContext)))
return result;
if(PcrIndex >= tpm_metrics.num_pcrs)
return TCSERR(TSS_E_BAD_PARAMETER);
/* if this is a kernel or firmware controlled PCR, call an external routine */
if ((tcsd_options.kernel_pcrs & (1 << PcrIndex)) ||
(tcsd_options.firmware_pcrs & (1 << PcrIndex))) {
MUTEX_LOCK(tcs_event_log->lock);
result = TCS_GetExternalPcrEvent(PcrIndex, pNumber, ppEvent);
MUTEX_UNLOCK(tcs_event_log->lock);
return result;
}
if (ppEvent == NULL) {
MUTEX_LOCK(tcs_event_log->lock);
*pNumber = get_num_events(PcrIndex);
MUTEX_UNLOCK(tcs_event_log->lock);
} else {
*ppEvent = calloc(1, sizeof(TSS_PCR_EVENT));
if (*ppEvent == NULL) {
LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT));
return TCSERR(TSS_E_OUTOFMEMORY);
}
event = get_pcr_event(PcrIndex, *pNumber);
if (event == NULL) {
free(*ppEvent);
return TCSERR(TSS_E_BAD_PARAMETER);
}
if ((result = copy_pcr_event(*ppEvent, event))) {
free(*ppEvent);
return result;
}
}
return TSS_SUCCESS;
}
/* This routine will handle creating the TSS_PCR_EVENT structures from log
* data produced by an external source. The external source in mind here
* is the log of PCR extends done by the kernel from beneath the TSS
* (via direct calls to the device driver).
*/
TSS_RESULT
TCS_GetExternalPcrEventsByPcr(UINT32 PcrIndex, /* in */
UINT32 FirstEvent, /* in */
UINT32 *pEventCount, /* in, out */
TSS_PCR_EVENT **ppEvents) /* out */
{
FILE *log_handle;
char *source;
if (tcsd_options.kernel_pcrs & (1 << PcrIndex)) {
source = tcsd_options.kernel_log_file;
if (tcs_event_log->kernel_source != NULL) {
if (tcs_event_log->kernel_source->open((void *)source, &log_handle))
return TCSERR(TSS_E_INTERNAL_ERROR);
if (tcs_event_log->kernel_source->get_entries_by_pcr(log_handle, PcrIndex,
FirstEvent, pEventCount, ppEvents)) {
tcs_event_log->kernel_source->close(log_handle);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
tcs_event_log->kernel_source->close(log_handle);
} else {
LogError("No source for externel kernel events was compiled in, but "
"the tcsd is configured to use one! (see %s)",
tcsd_config_file);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
} else if (tcsd_options.firmware_pcrs & (1 << PcrIndex)) {
source = tcsd_options.firmware_log_file;
if (tcs_event_log->firmware_source != NULL) {
if (tcs_event_log->firmware_source->open((void *)source, &log_handle))
return TCSERR(TSS_E_INTERNAL_ERROR);
if (tcs_event_log->firmware_source->get_entries_by_pcr(log_handle, PcrIndex,
FirstEvent, pEventCount, ppEvents)) {
tcs_event_log->firmware_source->close(log_handle);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
tcs_event_log->firmware_source->close(log_handle);
} else {
LogError("No source for externel firmware events was compiled in, but "
"the tcsd is configured to use one! (see %s)",
tcsd_config_file);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
} else {
LogError("PCR index %d not flagged as kernel or firmware controlled.", PcrIndex);
return TCSERR(TSS_E_INTERNAL_ERROR);
}
return TSS_SUCCESS;
}
TSS_RESULT
TCS_GetPcrEventsByPcr_Internal(TCS_CONTEXT_HANDLE hContext, /* in */
UINT32 PcrIndex, /* in */
UINT32 FirstEvent, /* in */
UINT32 *pEventCount, /* in, out */
TSS_PCR_EVENT **ppEvents) /* out */
{
UINT32 lastEventNumber, i, eventIndex;
TSS_RESULT result;
struct event_wrapper *tmp;
if ((result = ctx_verify_context(hContext)))
return result;
if (PcrIndex >= tpm_metrics.num_pcrs)
return TCSERR(TSS_E_BAD_PARAMETER);
if (*pEventCount == 0) {
*ppEvents = NULL;
return TSS_SUCCESS;
}
/* if this is a kernel or firmware controlled PCR, call an external routine */
if ((tcsd_options.kernel_pcrs & (1 << PcrIndex)) ||
(tcsd_options.firmware_pcrs & (1 << PcrIndex))) {
MUTEX_LOCK(tcs_event_log->lock);
result = TCS_GetExternalPcrEventsByPcr(PcrIndex, FirstEvent,
pEventCount, ppEvents);
MUTEX_UNLOCK(tcs_event_log->lock);
return result;
}
MUTEX_LOCK(tcs_event_log->lock);
lastEventNumber = get_num_events(PcrIndex);
MUTEX_UNLOCK(tcs_event_log->lock);
/* if pEventCount is larger than the number of events to return, just return less.
* *pEventCount will be set to the number returned below. First, check for overflow.
*/
if ((FirstEvent + *pEventCount) >= FirstEvent &&
(FirstEvent + *pEventCount) >= *pEventCount)
lastEventNumber = MIN(lastEventNumber, FirstEvent + *pEventCount);
if (FirstEvent > lastEventNumber)
return TCSERR(TSS_E_BAD_PARAMETER);
if (lastEventNumber == 0) {
*pEventCount = 0;
*ppEvents = NULL;
return TSS_SUCCESS;
}
/* FirstEvent is 0 indexed see TSS 1.1b spec section 4.7.2.2.3. That means that
* the following calculation is not off by one. :-)
*/
*ppEvents = calloc((lastEventNumber - FirstEvent), sizeof(TSS_PCR_EVENT));
if (*ppEvents == NULL) {
LogError("malloc of %zd bytes failed.",
sizeof(TSS_PCR_EVENT) * (lastEventNumber - FirstEvent));
return TCSERR(TSS_E_OUTOFMEMORY);
}
MUTEX_LOCK(tcs_event_log->lock);
tmp = tcs_event_log->lists[PcrIndex];
/* move through the list until we get to the first event requested */
for (i = 0; i < FirstEvent; i++)
tmp = tmp->next;
/* copy events from the first requested to the last requested */
for (eventIndex = 0; i < lastEventNumber; eventIndex++, i++) {
copy_pcr_event(&((*ppEvents)[eventIndex]), &(tmp->event));
tmp = tmp->next;
}
MUTEX_UNLOCK(tcs_event_log->lock);
*pEventCount = eventIndex;
return TSS_SUCCESS;
}
TSS_RESULT
TCS_GetPcrEventLog_Internal(TCS_CONTEXT_HANDLE hContext,/* in */
UINT32 *pEventCount, /* out */
TSS_PCR_EVENT **ppEvents) /* out */
{
TSS_RESULT result;
UINT32 i, j, event_count, aggregate_count = 0;
struct event_wrapper *tmp;
TSS_PCR_EVENT *event_list = NULL, *aggregate_list = NULL;
if ((result = ctx_verify_context(hContext)))
return result;
MUTEX_LOCK(tcs_event_log->lock);
/* for each PCR index, if its externally controlled, get the total number of events
* externally, else copy the events from the TCSD list. Then tack that list onto a
* master list to returned. */
for (i = 0; i < tpm_metrics.num_pcrs; i++) {
if ((tcsd_options.kernel_pcrs & (1 << i)) ||
(tcsd_options.firmware_pcrs & (1 << i))) {
/* A kernel or firmware controlled PCR event list */
event_count = UINT_MAX;
if ((result = TCS_GetExternalPcrEventsByPcr(i, 0, &event_count,
&event_list))) {
LogDebug("Getting External event list for PCR %u failed", i);
free(aggregate_list);
goto error;
}
LogDebug("Retrieved %u events from PCR %u (external)", event_count, i);
} else {
/* A TCSD controlled PCR event list */
event_count = get_num_events(i);
if (event_count == 0)
continue;
if ((event_list = calloc(event_count, sizeof(TSS_PCR_EVENT))) == NULL) {
LogError("malloc of %zd bytes failed",
event_count * sizeof(TSS_PCR_EVENT));
result = TCSERR(TSS_E_OUTOFMEMORY);
free(aggregate_list);
goto error;
}
tmp = tcs_event_log->lists[i];
for (j = 0; j < event_count; j++) {
copy_pcr_event(&event_list[j], &(tmp->event));
tmp = tmp->next;
}
}
if (event_count == 0)
continue;
/* Tack the list onto the aggregate_list */
aggregate_list = concat_pcr_events(&aggregate_list, aggregate_count, event_list,
event_count);
if (aggregate_list == NULL) {
free(event_list);
result = TCSERR(TSS_E_OUTOFMEMORY);
goto error;
}
aggregate_count += event_count;
free(event_list);
}
*ppEvents = aggregate_list;
*pEventCount = aggregate_count;
result = TSS_SUCCESS;
error:
MUTEX_UNLOCK(tcs_event_log->lock);
return result;
}