/*
* 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 <inttypes.h>
#include "trousers/tss.h"
#include "trousers_types.h"
#include "tcs_tsp.h"
#include "tcsps.h"
#include "tcs_utils.h"
#include "tcs_int_literals.h"
#include "capabilities.h"
#include "tcslog.h"
#include "req_mgr.h"
#include "tcsd_wrap.h"
#include "tcsd.h"
/*
* Get a random number generated by the TPM. Most (all?) TPMs return a maximum number of random
* bytes that's less than the max allowed to be returned at the TSP level, which is 4K bytes.
* According to the TPM compliance work posted here: http://www.prosec.rub.de/tpmcompliance.html,
* some TPMs return as little as 132 bytes per query, which would require about 30 loops to get 4K.
* We'll be extremely conservative here and loop 50 times, since it won't affect performance on
* TPMs that return more bytes.
*/
TSS_RESULT
TCSP_GetRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */
UINT32 * bytesRequested, /* in, out */
BYTE ** randomBytes) /* out */
{
UINT64 offset;
TSS_RESULT result;
UINT32 paramSize, totalReturned = 0, bytesReturned, retries = 50;
BYTE txBlob[TSS_TPM_TXBLOB_SIZE], *rnd_tmp = NULL, *rnd_tmp2 = NULL;
LogDebugFn("%u bytes", *bytesRequested);
if ((result = ctx_verify_context(hContext)))
return result;
do {
offset = 0;
if ((result = tpm_rqu_build(TPM_ORD_GetRandom, &offset, txBlob,
*bytesRequested - totalReturned, NULL)))
break;
if ((result = req_mgr_submit_req(txBlob)))
break;;
result = UnloadBlob_Header(txBlob, ¶mSize);
if (!result) {
#if 0
offset = 10;
UnloadBlob_UINT32(&offset, &bytesReturned, txBlob);
LogDebugFn("received %u bytes from the TPM", bytesReturned);
rnd_tmp = realloc(rnd_tmp, totalReturned + bytesReturned);
if (rnd_tmp == NULL) {
LogError("malloc of %u bytes failed.", bytesReturned);
return TCSERR(TSS_E_OUTOFMEMORY);
}
UnloadBlob(&offset, bytesReturned, txBlob, &rnd_tmp[totalReturned]);
#else
/* XXX */
if ((result = tpm_rsp_parse(TPM_ORD_GetRandom, txBlob, paramSize,
&bytesReturned, &rnd_tmp, NULL, NULL)))
break;
rnd_tmp2 = realloc(*randomBytes, totalReturned + bytesReturned);
if (rnd_tmp2 == NULL) {
free(rnd_tmp);
rnd_tmp = NULL;
LogError("malloc of %u bytes failed.", bytesReturned);
result = TCSERR(TSS_E_OUTOFMEMORY);
break;
}
*randomBytes = rnd_tmp2;
memcpy(*randomBytes + totalReturned, rnd_tmp, bytesReturned);
free(rnd_tmp);
rnd_tmp = NULL;
#endif
totalReturned += bytesReturned;
} else {
free(rnd_tmp);
return result;
}
} while (totalReturned < *bytesRequested && retries--);
if (totalReturned != *bytesRequested) {
LogDebugFn("Only %u random bytes recieved from TPM.", totalReturned);
free(rnd_tmp);
result = TCSERR(TSS_E_FAIL);
#if 0
} else
*randomBytes = rnd_tmp;
#else
}
#endif
return result;
}
TSS_RESULT
TCSP_StirRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */
UINT32 inDataSize, /* in */
BYTE * inData) /* in */
{
UINT64 offset = 0;
UINT32 paramSize;
TSS_RESULT result;
BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
LogDebug("Entering stir random");
if (inDataSize > 255) {
LogDebugFn("inData is too large! (%u bytes)", inDataSize);
return TCSERR(TSS_E_BAD_PARAMETER);
}
if ((result = ctx_verify_context(hContext)))
return result;
if ((result = tpm_rqu_build(TPM_ORD_StirRandom, &offset, txBlob, inDataSize, inDataSize,
inData, NULL, NULL)))
return result;
if ((result = req_mgr_submit_req(txBlob)))
return result;
result = UnloadBlob_Header(txBlob, ¶mSize);
LogResult("Stir random", result);
return result;
}