1 /* Software-based Trusted Platform Module (TPM) Emulator
2 * Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
3 *
4 * This module is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
8 *
9 * This module is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * $Id: tpm_integrity.c 474 2011-12-20 10:27:45Z mast $
15 */
16
17 #include "tpm_emulator.h"
18 #include "tpm_commands.h"
19 #include "tpm_data.h"
20 #include "crypto/sha1.h"
21 #include "crypto/rsa.h"
22 #include "tpm_handles.h"
23 #include "tpm_marshalling.h"
24
25 /*
26 * Integrity Collection and Reporting ([TPM_Part3], Section 16)
27 * This section deals with what commands have direct access to the PCR.
28 */
29
30 #define PCR_ATTRIB tpmData.permanent.data.pcrAttrib
31 #define PCR_VALUE tpmData.permanent.data.pcrValue
32 #define LOCALITY tpmData.stany.flags.localityModifier
33
TPM_Extend(TPM_PCRINDEX pcrNum,TPM_DIGEST * inDigest,TPM_PCRVALUE * outDigest)34 TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest,
35 TPM_PCRVALUE *outDigest)
36 {
37 tpm_sha1_ctx_t ctx;
38
39 info("TPM_Extend()");
40 if (pcrNum >= TPM_NUM_PCR) return TPM_BADINDEX;
41 if (!(PCR_ATTRIB[pcrNum].pcrExtendLocal & (1 << LOCALITY))) return TPM_BAD_LOCALITY;
42 /* compute new PCR value as SHA-1(old PCR value || inDigest) */
43 tpm_sha1_init(&ctx);
44 tpm_sha1_update(&ctx, PCR_VALUE[pcrNum].digest, sizeof(PCR_VALUE[pcrNum].digest));
45 tpm_sha1_update(&ctx, inDigest->digest, sizeof(inDigest->digest));
46 tpm_sha1_final(&ctx, PCR_VALUE[pcrNum].digest);
47 /* set output digest */
48 if (tpmData.permanent.flags.disable) {
49 memset(outDigest->digest, 0, sizeof(*outDigest->digest));
50 } else {
51 memcpy(outDigest, &PCR_VALUE[pcrNum], sizeof(TPM_PCRVALUE));
52 }
53 return TPM_SUCCESS;
54 }
55
TPM_PCRRead(TPM_PCRINDEX pcrIndex,TPM_PCRVALUE * outDigest)56 TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest)
57 {
58 info("TPM_PCRRead()");
59 if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX;
60 memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE));
61 return TPM_SUCCESS;
62 }
63
TPM_Quote(TPM_KEY_HANDLE keyHandle,TPM_NONCE * extrnalData,TPM_PCR_SELECTION * targetPCR,TPM_AUTH * auth1,TPM_PCR_COMPOSITE * pcrData,UINT32 * sigSize,BYTE ** sig)64 TPM_RESULT TPM_Quote(TPM_KEY_HANDLE keyHandle, TPM_NONCE *extrnalData,
65 TPM_PCR_SELECTION *targetPCR, TPM_AUTH *auth1,
66 TPM_PCR_COMPOSITE *pcrData,
67 UINT32 *sigSize, BYTE **sig)
68 {
69 TPM_RESULT res;
70 TPM_KEY_DATA *key;
71 TPM_COMPOSITE_HASH hash;
72 BYTE buf[48];
73 info("TPM_Quote()");
74 /* get key */
75 key = tpm_get_key(keyHandle);
76 if (key == NULL) return TPM_INVALID_KEYHANDLE;
77 /* verify authorization */
78 if (auth1->authHandle != TPM_INVALID_HANDLE
79 || key->authDataUsage != TPM_AUTH_NEVER) {
80 res = tpm_verify_auth(auth1, key->usageAuth, keyHandle);
81 if (res != TPM_SUCCESS) return res;
82 }
83 if (key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1)
84 return TPM_INAPPROPRIATE_SIG;
85 if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY
86 && key->keyUsage != TPM_KEY_IDENTITY)
87 return TPM_INVALID_KEYUSAGE;
88 /* compute composite hash */
89 res = tpm_compute_pcr_digest(targetPCR, &hash, pcrData);
90 if (res != TPM_SUCCESS) return res;
91 /* setup quote info and sign it */
92 memcpy(&buf[ 0], "\x01\x01\x00\x00QUOT", 8);
93 memcpy(&buf[ 8], hash.digest, 20);
94 memcpy(&buf[28], extrnalData->nonce, 20);
95 *sigSize = key->key.size >> 3;
96 *sig = tpm_malloc(*sigSize);
97 if (*sig == NULL) return TPM_FAIL;
98 if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, buf, 48, *sig)) {
99 tpm_free(*sig);
100 return TPM_FAIL;
101 }
102 return TPM_SUCCESS;
103 }
104
TPM_PCR_Reset(TPM_PCR_SELECTION * pcrSelection)105 TPM_RESULT TPM_PCR_Reset(TPM_PCR_SELECTION *pcrSelection)
106 {
107 int i;
108 info("TPM_PCR_Reset()");
109 if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR)
110 return TPM_INVALID_PCR_INFO;
111 /* this command must be atomic, thus we first verify that all
112 registers are resetable ... */
113 for (i = 0; i < pcrSelection->sizeOfSelect * 8; i++) {
114 /* is PCR number i selected ? */
115 if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) {
116 if (!PCR_ATTRIB[i].pcrReset) return TPM_NOTRESETABLE;
117 if (!(PCR_ATTRIB[i].pcrResetLocal & (1 << LOCALITY))) return TPM_NOTLOCAL;
118 }
119 }
120 /* ... then we reset all registers at once */
121 for (i = 0; i < pcrSelection->sizeOfSelect * 8; i++) {
122 /* is PCR number i selected ? */
123 if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) {
124 memset(PCR_VALUE[i].digest, 0, sizeof(PCR_VALUE[i].digest));
125 }
126 }
127 return TPM_SUCCESS;
128 }
129
tpm_compute_pcr_digest(TPM_PCR_SELECTION * pcrSelection,TPM_COMPOSITE_HASH * digest,TPM_PCR_COMPOSITE * composite)130 TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection,
131 TPM_COMPOSITE_HASH *digest,
132 TPM_PCR_COMPOSITE *composite)
133 {
134 int i,j;
135 TPM_PCR_COMPOSITE comp;
136 tpm_sha1_ctx_t ctx;
137 UINT32 len;
138 BYTE *buf, *ptr;
139 info("tpm_compute_pcr_digest()");
140 /* create PCR composite */
141 if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR
142 || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO;
143 for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) {
144 /* is PCR number i selected ? */
145 if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) {
146 memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE));
147 }
148 }
149 memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION));
150 comp.valueSize = j * sizeof(TPM_PCRVALUE);
151 debug("comp.valueSize = %d", comp.valueSize);
152 if (comp.valueSize > 0) {
153 /* marshal composite and compute hash */
154 len = sizeof_TPM_PCR_COMPOSITE(comp);
155 buf = ptr = tpm_malloc(len);
156 if (buf == NULL
157 || tpm_marshal_TPM_PCR_COMPOSITE(&ptr, &len, &comp)) {
158 tpm_free(buf);
159 return TPM_FAIL;
160 }
161 tpm_sha1_init(&ctx);
162 tpm_sha1_update(&ctx, buf, sizeof_TPM_PCR_COMPOSITE(comp));
163 tpm_sha1_final(&ctx, digest->digest);
164 tpm_free(buf);
165 } else {
166 memset(digest, 0, sizeof(TPM_COMPOSITE_HASH));
167 }
168 /* copy composite if requested */
169 if (composite != NULL)
170 memcpy(composite, &comp, sizeof(TPM_PCR_COMPOSITE));
171 return TPM_SUCCESS;
172 }
173
tpm_verify_pcr(TPM_KEY_DATA * key,BOOL atrelease,BOOL atcreation)174 TPM_RESULT tpm_verify_pcr(TPM_KEY_DATA *key, BOOL atrelease, BOOL atcreation)
175 {
176 TPM_RESULT res;
177 TPM_COMPOSITE_HASH digest;
178 info("tpm_verify_pcr()");
179 if (atrelease) {
180 res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection,
181 &digest, NULL);
182 if (res != TPM_SUCCESS) return res;
183 if (memcmp(&digest, &key->pcrInfo.digestAtRelease,
184 sizeof(TPM_COMPOSITE_HASH))) return TPM_WRONGPCRVAL;
185 if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG
186 && !(key->pcrInfo.localityAtRelease
187 & (1 << tpmData.stany.flags.localityModifier)))
188 return TPM_BAD_LOCALITY;
189 }
190 if (atcreation) {
191 res = tpm_compute_pcr_digest(&key->pcrInfo.creationPCRSelection,
192 &digest, NULL);
193 if (res != TPM_SUCCESS) return res;
194 if (memcmp(&digest, &key->pcrInfo.digestAtCreation,
195 sizeof(TPM_COMPOSITE_HASH))) return TPM_WRONGPCRVAL;
196 if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG
197 && !(key->pcrInfo.localityAtCreation
198 & (1 << tpmData.stany.flags.localityModifier)))
199 return TPM_BAD_LOCALITY;
200 }
201 return TPM_SUCCESS;
202 }
203
TPM_Quote2(TPM_KEY_HANDLE keyHandle,TPM_NONCE * externalData,TPM_PCR_SELECTION * targetPCR,BOOL addVersion,TPM_AUTH * auth1,TPM_PCR_INFO_SHORT * pcrData,UINT32 * versionInfoSize,TPM_CAP_VERSION_INFO * versionInfo,UINT32 * sigSize,BYTE ** sig)204 TPM_RESULT TPM_Quote2(TPM_KEY_HANDLE keyHandle, TPM_NONCE *externalData,
205 TPM_PCR_SELECTION *targetPCR, BOOL addVersion,
206 TPM_AUTH *auth1, TPM_PCR_INFO_SHORT *pcrData,
207 UINT32 *versionInfoSize,
208 TPM_CAP_VERSION_INFO *versionInfo,
209 UINT32 *sigSize, BYTE **sig)
210 {
211 TPM_RESULT res;
212 TPM_KEY_DATA *key;
213 TPM_COMPOSITE_HASH H1;
214 TPM_QUOTE_INFO2 Q1;
215 tpm_sha1_ctx_t ctx;
216 TPM_DIGEST digest;
217 UINT32 respSize, len, size;
218 BYTE *resp, *ptr, *buf;
219
220 info("TPM_Quote2()");
221 /* get key by keyHandle*/
222 key = tpm_get_key(keyHandle);
223 if (key == NULL) return TPM_INVALID_KEYHANDLE;
224 /* 1. The TPM MUST validate the AuthData to use the key pointed
225 * to by keyhandle */
226 if (auth1->authHandle != TPM_INVALID_HANDLE
227 || key->authDataUsage != TPM_AUTH_NEVER) {
228 res = tpm_verify_auth(auth1, key->usageAuth, keyHandle);
229 if (res != TPM_SUCCESS) return res;
230 }
231 /* 2. Validate that keyHandle->sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or
232 TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */
233 if ((key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) &&
234 (key->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO))
235 return TPM_INAPPROPRIATE_SIG;
236 /* 3. Validate that keyHandle->keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY,
237 or TPM_KEY_LEGACY, if not return TPM_INVALID_KEYUSAGE */
238 if ((key->keyUsage != TPM_KEY_SIGNING) && (key->keyUsage != TPM_KEY_LEGACY)
239 && (key->keyUsage != TPM_KEY_IDENTITY))
240 return TPM_INVALID_KEYUSAGE;
241 /* 4. Validate targetPCR is a valid TPM_PCR_SELECTION structure,
242 * on errors return TPM_INVALID_PCR_INFO */
243 if (targetPCR->sizeOfSelect > sizeof(targetPCR->pcrSelect))
244 return TPM_INVALID_PCR_INFO;
245 /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the
246 * TPM_STCLEAR_DATA->PCR[] indicated by targetPCR->pcrSelect */
247 res = tpm_compute_pcr_digest(targetPCR, &H1, NULL);
248 if (res != TPM_SUCCESS) return res;
249 /* 6. Create S1 a TPM_PCR_INFO_SHORT */
250 /* a. Set S1->pcrSelection to targetPCR */
251 pcrData->pcrSelection.sizeOfSelect = targetPCR->sizeOfSelect;
252 memcpy(pcrData->pcrSelection.pcrSelect, targetPCR->pcrSelect, targetPCR->sizeOfSelect);
253 /* b. Set S1->localityAtRelease to TPM_STANY_DATA -> localityModifier */
254 pcrData->localityAtRelease = 1 << tpmData.stany.flags.localityModifier;
255 /* c. Set S1->digestAtRelease to H1 */
256 memcpy(&pcrData->digestAtRelease, &H1, sizeof(TPM_COMPOSITE_HASH));
257 /* 7. Create Q1 a TPM_QUOTE_INFO2 structure */
258 Q1.tag = TPM_TAG_QUOTE_INFO2;
259 /* a. Set Q1->fixed to "QUT2" */
260 Q1.fixed[0] = 'Q', Q1.fixed[1] = 'U', Q1.fixed[2] = 'T', Q1.fixed[3] = '2';
261 /* b. Set Q1->infoShort to S1 */
262 Q1.infoShort.pcrSelection.sizeOfSelect = pcrData->pcrSelection.sizeOfSelect;
263 memcpy(Q1.infoShort.pcrSelection.pcrSelect,
264 pcrData->pcrSelection.pcrSelect, pcrData->pcrSelection.sizeOfSelect);
265 Q1.infoShort.localityAtRelease = pcrData->localityAtRelease;
266 memcpy(Q1.infoShort.digestAtRelease.digest,
267 pcrData->digestAtRelease.digest, sizeof(TPM_COMPOSITE_HASH));
268 /* c. Set Q1->externalData to externalData */
269 memcpy(&Q1.externalData, externalData, sizeof(TPM_NONCE));
270 size = len = sizeof_TPM_QUOTE_INFO2(Q1);
271 buf = ptr = tpm_malloc(size);
272 if (buf == NULL) return TPM_NOSPACE;
273 if (tpm_marshal_TPM_QUOTE_INFO2(&ptr, &len, &Q1) || (len != 0)) {
274 debug("TPM_Quote2(): tpm_marshal_TPM_QUOTE_INFO2() failed.");
275 tpm_free(buf);
276 return TPM_FAIL;
277 }
278 /* 8. If addVersion is TRUE */
279 if (addVersion == TRUE) {
280 debug("TPM_Quote2(): addVersion == TRUE");
281 /* a. Concatenate to Q1 a TPM_CAP_VERSION_INFO structure */
282 res = TPM_GetCapability(TPM_CAP_VERSION_VAL, 0, NULL, &respSize, &resp);
283 if (res != TPM_SUCCESS) {
284 debug("TPM_Quote2(): cap_version_val() failed.");
285 tpm_free(buf);
286 return TPM_FAIL;
287 }
288 /* b. Set the output parameters for versionInfo */
289 ptr = resp;
290 len = respSize;
291 if (tpm_unmarshal_TPM_CAP_VERSION_INFO(&ptr, &len, versionInfo) ||
292 (len != 0)) {
293 debug("TPM_Quote2(): tpm_unmarshal_TPM_CAP_VERSION_INFO() failed.");
294 tpm_free(buf);
295 return TPM_FAIL;
296 }
297 *versionInfoSize = respSize;
298 } else { /* 9. Else */
299 debug("TPM_Quote2(): addVersion == FALSE");
300 /* a. Set versionInfoSize to 0 */
301 *versionInfoSize = 0;
302 /* b. Return no bytes in versionInfo */
303 }
304 /* 10. Sign a SHA-1 hash of Q1 using keyHandle as the signature key */
305 tpm_sha1_init(&ctx);
306 tpm_sha1_update(&ctx, buf, size);
307 tpm_free(buf);
308 if (addVersion == TRUE) {
309 tpm_sha1_update(&ctx, resp, respSize);
310 tpm_free(resp);
311 }
312 tpm_sha1_final(&ctx, digest.digest);
313 /* 11. Return the signature in sig */
314 return tpm_sign(key, auth1, FALSE, digest.digest, sizeof(TPM_DIGEST), sig, sigSize);
315 }
316