summaryrefslogtreecommitdiff
path: root/src/tspi/tsp_pcr.c
blob: cc562d7c3f0e03075af317c5b21392c2c53c5ff7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

/*
 * Licensed Materials - Property of IBM
 *
 * trousers - An open source TCG Software Stack
 *
 * (C) Copyright International Business Machines Corp. 2004-2006
 *
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>

#include "trousers/tss.h"
#include "trousers/trousers.h"
#include "trousers_types.h"
#include "trousers_types.h"
#include "spi_utils.h"
#include "capabilities.h"
#include "tsplog.h"
#include "obj.h"


UINT16
get_num_pcrs(TSS_HCONTEXT tspContext)
{
	TSS_RESULT result;
	static UINT16 ret = 0;
	UINT32 subCap;
	UINT32 respSize;
	BYTE *resp;

	if (ret != 0)
		return ret;

	subCap = endian32(TPM_CAP_PROP_PCR);
	if ((result = TCS_API(tspContext)->GetTPMCapability(tspContext, TPM_CAP_PROPERTY,
							    sizeof(UINT32), (BYTE *)&subCap,
							    &respSize, &resp))) {
		if ((resp = (BYTE *)getenv("TSS_DEFAULT_NUM_PCRS")) == NULL)
			return TSS_DEFAULT_NUM_PCRS;

		/* don't set ret here, next time we may be connected */
		return atoi((char *)resp);
	}

	ret = (UINT16)Decode_UINT32(resp);
	free(resp);

	return ret;
}

TSS_RESULT
pcrs_calc_composite(TPM_PCR_SELECTION *select, TPM_PCRVALUE *arrayOfPcrs, TPM_DIGEST *digestOut)
{
	UINT32 size, index;
	BYTE mask;
	BYTE hashBlob[1024];
	UINT32 numPCRs = 0;
	UINT64 offset = 0;
	UINT64 sizeOffset = 0;

	if (select->sizeOfSelect > 0) {
		sizeOffset = 0;
		Trspi_LoadBlob_PCR_SELECTION(&sizeOffset, hashBlob, select);
		offset = sizeOffset + 4;

		for (size = 0; size < select->sizeOfSelect; size++) {
			for (index = 0, mask = 1; index < 8; index++, mask = mask << 1) {
				if (select->pcrSelect[size] & mask) {
					memcpy(&hashBlob[(numPCRs * TPM_SHA1_160_HASH_LEN) + offset],
					       arrayOfPcrs[index + (size << 3)].digest,
					       TPM_SHA1_160_HASH_LEN);
					numPCRs++;
				}
			}
		}

		if (numPCRs > 0) {
			offset += (numPCRs * TPM_SHA1_160_HASH_LEN);
			UINT32ToArray(numPCRs * TPM_SHA1_160_HASH_LEN, &hashBlob[sizeOffset]);

			return Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, digestOut->digest);
		}
	}

	return TSPERR(TSS_E_INTERNAL_ERROR);
}

TSS_RESULT
pcrs_sanity_check_selection(TSS_HCONTEXT tspContext,
			    struct tr_pcrs_obj *pcrs,
			    TPM_PCR_SELECTION *select)
{
	UINT16 num_pcrs, bytes_to_hold;

	if ((num_pcrs = get_num_pcrs(tspContext)) == 0)
		return TSPERR(TSS_E_INTERNAL_ERROR);

	bytes_to_hold = num_pcrs / 8;

	/* Is the current select object going to be interpretable by the TPM?
	 * If the select object is of a size greater than the one the TPM
	 * wants, just calculate the composite hash and let the TPM return an
	 * error code to the user.  If its less than the size of the one the
	 * TPM wants, add extra zero bytes until its the right size. */
	if (bytes_to_hold > select->sizeOfSelect) {
		if ((select->pcrSelect = realloc(select->pcrSelect, bytes_to_hold)) == NULL) {
			LogError("malloc of %hu bytes failed.", bytes_to_hold);
			return TSPERR(TSS_E_OUTOFMEMORY);
		}
		/* set the newly allocated bytes to 0 */
		memset(&select->pcrSelect[select->sizeOfSelect], 0,
				bytes_to_hold - select->sizeOfSelect);
		select->sizeOfSelect = bytes_to_hold;

		/* realloc the pcr array as well */
		if ((pcrs->pcrs = realloc(pcrs->pcrs,
					  (bytes_to_hold * 8) * TPM_SHA1_160_HASH_LEN)) == NULL) {
			LogError("malloc of %d bytes failed.",
				 (bytes_to_hold * 8) * TPM_SHA1_160_HASH_LEN);
			return TSPERR(TSS_E_OUTOFMEMORY);
		}
	}

#ifdef TSS_DEBUG
	{
		int i;
		for (i = 0; i < select->sizeOfSelect * 8; i++) {
			if (select->pcrSelect[i/8] & (1 << (i % 8))) {
				LogDebug("PCR%d: Selected", i);
				LogBlobData(APPID, TPM_SHA1_160_HASH_LEN,
					    (unsigned char *)&pcrs->pcrs[i]);
			} else {
				LogDebug("PCR%d: Not Selected", i);
			}
		}
	}
#endif

	return TSS_SUCCESS;
}