blob: debfdb68c42ad5aecd48ffb483e417b4d3f5bc80 [file] [log] [blame]
/* Software-based Trusted Platform Module (TPM) Emulator
* Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
*
* This module is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This module is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* $Id: tpm_ticks.c 364 2010-02-11 10:24:45Z mast $
*/
#include "tpm_emulator.h"
#include "tpm_commands.h"
#include "tpm_data.h"
#include "tpm_handles.h"
#include "tpm_marshalling.h"
/*
* Timing Ticks ([TPM_Part3], Section 23)
* The TPM timing ticks are always available for use. The association of
* timing ticks to actual time is a protocol that occurs outside of the TPM.
* See the design document for details.
*/
TPM_RESULT TPM_GetTicks(TPM_CURRENT_TICKS *currentTime)
{
info("TPM_GetTicks()");
memcpy(currentTime, &tpmData.stany.data.currentTicks,
sizeof(TPM_CURRENT_TICKS));
return TPM_SUCCESS;
}
TPM_RESULT TPM_TickStampBlob(TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay,
TPM_DIGEST *digestToStamp, TPM_AUTH *auth1,
TPM_CURRENT_TICKS *currentTicks,
UINT32 *sigSize, BYTE **sig)
{
TPM_RESULT res;
TPM_KEY_DATA *key;
BYTE *info, *ptr;
UINT32 info_length, len;
info("TPM_TickStampBlob()");
/* get key */
key = tpm_get_key(keyHandle);
if (key == NULL) return TPM_INVALID_KEYHANDLE;
/* verify authorization */
if (auth1->authHandle != TPM_INVALID_HANDLE
|| key->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth1, key->usageAuth, keyHandle);
if (res != TPM_SUCCESS) return res;
}
if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY
&& key->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE;
if (key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1)
return TPM_INAPPROPRIATE_SIG;
/* get current ticks */
TPM_GetTicks(currentTicks);
/* sign data using signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */
*sigSize = key->key.size >> 3;
*sig = tpm_malloc(*sigSize);
if (*sig == NULL) return TPM_FAIL;
/* setup TPM_SIGN_INFO structure */
info_length = 30 + sizeof(TPM_DIGEST) + sizeof_TPM_CURRENT_TICKS(currentTicks);
info = tpm_malloc(info_length);
if (info == NULL) {
tpm_free(*sig);
return TPM_FAIL;
}
memcpy(&info[0], "\x00\x05TSTP", 6);
memcpy(&info[6], antiReplay->nonce, 20);
ptr = &info[26]; len = info_length - 26;
tpm_marshal_UINT32(&ptr, &len, info_length - 30);
memcpy(ptr, digestToStamp->digest, sizeof(TPM_DIGEST));
ptr += sizeof(TPM_DIGEST); len -= sizeof(TPM_DIGEST);
if (tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, currentTicks)
|| tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, info, info_length, *sig)) {
tpm_free(*sig);
tpm_free(info);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
void tpm_update_ticks(void)
{
if (tpmData.stany.data.currentTicks.tag == 0) {
tpmData.stany.data.currentTicks.tag = TPM_TAG_CURRENT_TICKS;
tpmData.stany.data.currentTicks.currentTicks += tpm_get_ticks();
tpm_get_random_bytes(tpmData.stany.data.currentTicks.tickNonce.nonce,
sizeof(TPM_NONCE));
tpmData.stany.data.currentTicks.tickRate = 1;
} else {
tpmData.stany.data.currentTicks.currentTicks += tpm_get_ticks();
}
}