1
2/*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004-2007
8 *
9 */
10
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14#include <inttypes.h>
15
16#include "trousers/tss.h"
17#include "trousers/trousers.h"
18#include "trousers_types.h"
19#include "spi_utils.h"
20#include "capabilities.h"
21#include "tsplog.h"
22#include "obj.h"
23
24
25TSS_RESULT
26Tspi_TPM_CreateEndorsementKey(TSS_HTPM hTPM,			/* in */
27			      TSS_HKEY hKey,			/* in */
28			      TSS_VALIDATION * pValidationData)	/* in, out */
29{
30	TCPA_NONCE antiReplay;
31	TCPA_DIGEST digest;
32	TSS_RESULT result;
33	UINT32 ekSize;
34	BYTE *ek;
35	TSS_KEY dummyKey;
36	UINT64 offset;
37	TCPA_DIGEST hash;
38	UINT32 newEKSize;
39	BYTE *newEK;
40	TSS_HCONTEXT tspContext;
41	TCPA_PUBKEY pubEK;
42	Trspi_HashCtx hashCtx;
43
44	__tspi_memset(&pubEK, 0, sizeof(TCPA_PUBKEY));
45	__tspi_memset(&dummyKey, 0, sizeof(TSS_KEY));
46
47	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
48		return result;
49
50	if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek)))
51		return result;
52
53	offset = 0;
54	if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey)))
55		return result;
56
57	offset = 0;
58	Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms);
59	free_key_refs(&dummyKey);
60	ekSize = offset;
61
62	if (pValidationData == NULL) {
63		if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE),
64					       (BYTE **)antiReplay.nonce))) {
65			LogError("Failed to create random nonce");
66			return TSPERR(TSS_E_INTERNAL_ERROR);
67		}
68	} else {
69		if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce))
70			return TSPERR(TSS_E_BAD_PARAMETER);
71
72		memcpy(antiReplay.nonce, pValidationData->rgbExternalData,
73		       sizeof(antiReplay.nonce));
74	}
75
76	if ((result = TCS_API(tspContext)->CreateEndorsementKeyPair(tspContext, antiReplay, ekSize,
77								    ek, &newEKSize, &newEK,
78								    &digest)))
79		return result;
80
81	if (pValidationData == NULL) {
82		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
83		result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK);
84		result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, antiReplay.nonce);
85		if ((result |= Trspi_HashFinal(&hashCtx, hash.digest)))
86			goto done;
87
88		if (memcmp(hash.digest, digest.digest, TCPA_SHA1_160_HASH_LEN)) {
89			LogError("Internal verification failed");
90			result = TSPERR(TSS_E_EK_CHECKSUM);
91			goto done;
92		}
93	} else {
94		pValidationData->rgbData = calloc_tspi(tspContext, newEKSize);
95		if (pValidationData->rgbData == NULL) {
96			LogError("malloc of %u bytes failed.", newEKSize);
97			result = TSPERR(TSS_E_OUTOFMEMORY);
98			goto done;
99		}
100		pValidationData->ulDataLength = newEKSize;
101		memcpy(pValidationData->rgbData, newEK, newEKSize);
102		memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce,
103		       sizeof(antiReplay.nonce));
104
105		pValidationData->rgbValidationData = calloc_tspi(tspContext,
106								 TCPA_SHA1_160_HASH_LEN);
107		if (pValidationData->rgbValidationData == NULL) {
108			LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN);
109			free_tspi(tspContext, pValidationData->rgbData);
110			pValidationData->rgbData = NULL;
111			pValidationData->ulDataLength = 0;
112			result = TSPERR(TSS_E_OUTOFMEMORY);
113			goto done;
114		}
115		pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN;
116		memcpy(pValidationData->rgbValidationData, digest.digest, TCPA_SHA1_160_HASH_LEN);
117	}
118
119	if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK)) && pValidationData) {
120		free_tspi(tspContext, pValidationData->rgbValidationData);
121		free_tspi(tspContext, pValidationData->rgbData);
122		pValidationData->rgbData = NULL;
123		pValidationData->ulDataLength = 0;
124		pValidationData->rgbValidationData = NULL;
125		pValidationData->ulValidationDataLength = 0;
126	}
127
128done:
129	free(newEK);
130
131	return result;
132}
133
134TSS_RESULT
135Tspi_TPM_GetPubEndorsementKey(TSS_HTPM hTPM,			/* in */
136			      TSS_BOOL fOwnerAuthorized,	/* in */
137			      TSS_VALIDATION *pValidationData,	/* in, out */
138			      TSS_HKEY *phEndorsementPubKey)	/* out */
139{
140	TCPA_DIGEST digest;
141	TSS_RESULT result;
142	UINT64 offset;
143	UINT32 pubEKSize;
144	BYTE *pubEK;
145	TCPA_NONCE antiReplay;
146	TCPA_DIGEST checkSum;
147	TSS_HOBJECT retKey;
148	TSS_HCONTEXT tspContext;
149	TCPA_PUBKEY pubKey;
150	Trspi_HashCtx hashCtx;
151
152	__tspi_memset(&pubKey, 0, sizeof(TCPA_PUBKEY));
153
154	if (phEndorsementPubKey == NULL)
155		return TSPERR(TSS_E_BAD_PARAMETER);
156
157	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
158		return result;
159
160	if (fOwnerAuthorized)
161		return owner_get_pubek(tspContext, hTPM, phEndorsementPubKey);
162
163	if (pValidationData == NULL) {
164		if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE),
165					       (BYTE **)antiReplay.nonce))) {
166			LogDebug("Failed to generate random nonce");
167			return TSPERR(TSS_E_INTERNAL_ERROR);
168		}
169	} else {
170		if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce))
171			return TSPERR(TSS_E_BAD_PARAMETER);
172
173		memcpy(antiReplay.nonce, pValidationData->rgbExternalData,
174		       sizeof(antiReplay.nonce));
175	}
176
177	/* call down to the TPM */
178	if ((result = TCS_API(tspContext)->ReadPubek(tspContext, antiReplay, &pubEKSize, &pubEK,
179						     &checkSum)))
180		return result;
181
182	/* validate the returned hash, or set up the return so that the user can */
183	if (pValidationData == NULL) {
184		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
185		result |= Trspi_HashUpdate(&hashCtx, pubEKSize, pubEK);
186		result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce);
187		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
188			goto done;
189
190		/* check validation of the entire pubkey structure */
191		if (memcmp(digest.digest, checkSum.digest, TPM_SHA1_160_HASH_LEN)) {
192			/* validation failed, unload the pubEK in order to hash
193			 * just the pubKey portion of the pubEK. This is done on
194			 * Atmel chips specifically.
195			 */
196			offset = 0;
197			__tspi_memset(&pubKey, 0, sizeof(TCPA_PUBKEY));
198			if ((result = Trspi_UnloadBlob_PUBKEY(&offset, pubEK, &pubKey)))
199				goto done;
200
201			result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
202			result |= Trspi_HashUpdate(&hashCtx, pubKey.pubKey.keyLength,
203						   pubKey.pubKey.key);
204			result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN,
205						   antiReplay.nonce);
206			if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
207				goto done;
208
209			if (memcmp(digest.digest, checkSum.digest, TCPA_SHA1_160_HASH_LEN)) {
210				result = TSPERR(TSS_E_EK_CHECKSUM);
211				goto done;
212			}
213		}
214	} else {
215		/* validate the entire TCPA_PUBKEY structure */
216		pValidationData->ulDataLength = pubEKSize + TCPA_SHA1_160_HASH_LEN;
217		pValidationData->rgbData = calloc_tspi(tspContext,
218				pValidationData->ulDataLength);
219		if (pValidationData->rgbData == NULL) {
220			LogError("malloc of %u bytes failed.",
221					pValidationData->ulDataLength);
222			pValidationData->ulDataLength = 0;
223			result = TSPERR(TSS_E_OUTOFMEMORY);
224			goto done;
225		}
226
227		memcpy(pValidationData->rgbData, pubEK, pubEKSize);
228		memcpy(&pValidationData->rgbData[pubEKSize], antiReplay.nonce,
229				TCPA_SHA1_160_HASH_LEN);
230
231		pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN;
232		pValidationData->rgbValidationData = calloc_tspi(tspContext,
233				TCPA_SHA1_160_HASH_LEN);
234		if (pValidationData->rgbValidationData == NULL) {
235			LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN);
236			pValidationData->ulValidationDataLength = 0;
237			pValidationData->ulDataLength = 0;
238			free_tspi(tspContext,pValidationData->rgbData);
239			result = TSPERR(TSS_E_OUTOFMEMORY);
240			goto done;
241		}
242
243		memcpy(pValidationData->rgbValidationData, checkSum.digest,
244				TPM_SHA1_160_HASH_LEN);
245	}
246
247	if ((result = obj_rsakey_add(tspContext, TSS_KEY_SIZE_2048|TSS_KEY_TYPE_LEGACY, &retKey)))
248		goto done;
249
250	if ((result = obj_rsakey_set_pubkey(retKey, TRUE, pubEK)))
251		goto done;
252
253	*phEndorsementPubKey = retKey;
254
255done:
256	free(pubEK);
257	return result;
258}
259
260#ifdef TSS_BUILD_TSS12
261TSS_RESULT
262Tspi_TPM_CreateRevocableEndorsementKey(TSS_HTPM hTPM,			/* in */
263				       TSS_HKEY hKey,			/* in */
264				       TSS_VALIDATION * pValidationData,/* in, out */
265				       UINT32 * pulEkResetDataLength,	/* in, out */
266				       BYTE ** prgbEkResetData)		/* in, out */
267{
268	TPM_NONCE antiReplay;
269	TPM_DIGEST digest;
270	TSS_RESULT result;
271	UINT32 ekSize;
272	BYTE *ek;
273	TSS_KEY dummyKey;
274	UINT64 offset;
275	TSS_BOOL genResetAuth;
276	TPM_DIGEST eKResetAuth;
277	TPM_DIGEST hash;
278	UINT32 newEKSize;
279	BYTE *newEK;
280	TSS_HCONTEXT tspContext;
281	TPM_PUBKEY pubEK;
282	Trspi_HashCtx hashCtx;
283
284	__tspi_memset(&pubEK, 0, sizeof(TPM_PUBKEY));
285	__tspi_memset(&dummyKey, 0, sizeof(TSS_KEY));
286	__tspi_memset(&eKResetAuth, 0xff, sizeof(eKResetAuth));
287
288	if (!pulEkResetDataLength || !prgbEkResetData)
289		return TSPERR(TSS_E_BAD_PARAMETER);
290
291	if (*pulEkResetDataLength != 0) {
292		if (*prgbEkResetData == NULL)
293			return TSPERR(TSS_E_BAD_PARAMETER);
294
295		if (*pulEkResetDataLength < sizeof(eKResetAuth.digest))
296			return TSPERR(TSS_E_BAD_PARAMETER);
297
298		memcpy(eKResetAuth.digest, *prgbEkResetData, sizeof(eKResetAuth.digest));
299		genResetAuth = FALSE;
300	} else {
301		if (*prgbEkResetData != NULL)
302			return TSPERR(TSS_E_BAD_PARAMETER);
303
304		genResetAuth = TRUE;
305	}
306
307	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
308		return result;
309
310	if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek)))
311		return result;
312
313	offset = 0;
314	if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey)))
315		return result;
316
317	offset = 0;
318	Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms);
319	free_key_refs(&dummyKey);
320	ekSize = offset;
321
322	if (pValidationData == NULL) {
323		if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE),
324					       (BYTE **)antiReplay.nonce))) {
325			LogError("Failed to create random nonce");
326			return TSPERR(TSS_E_INTERNAL_ERROR);
327		}
328	} else {
329		if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce))
330			return TSPERR(TSS_E_BAD_PARAMETER);
331
332		memcpy(antiReplay.nonce, pValidationData->rgbExternalData,
333		       sizeof(antiReplay.nonce));
334	}
335
336	if ((result = RPC_CreateRevocableEndorsementKeyPair(tspContext, antiReplay, ekSize, ek,
337							    genResetAuth, &eKResetAuth, &newEKSize,
338							    &newEK, &digest)))
339		return result;
340
341	if (pValidationData == NULL) {
342		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
343		result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK);
344		result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce);
345		if ((result |= Trspi_HashFinal(&hashCtx, hash.digest)))
346			goto done;
347
348		if (memcmp(hash.digest, digest.digest, TPM_SHA1_160_HASH_LEN)) {
349			LogError("Internal verification failed");
350			result = TSPERR(TSS_E_EK_CHECKSUM);
351			goto done;
352		}
353	} else {
354		pValidationData->rgbData = calloc_tspi(tspContext, newEKSize);
355		if (pValidationData->rgbData == NULL) {
356			LogError("malloc of %u bytes failed.", newEKSize);
357			result = TSPERR(TSS_E_OUTOFMEMORY);
358			goto done;
359		}
360		pValidationData->ulDataLength = newEKSize;
361		memcpy(pValidationData->rgbData, newEK, newEKSize);
362		memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce,
363		       sizeof(antiReplay.nonce));
364
365		pValidationData->rgbValidationData = calloc_tspi(tspContext,
366								 TPM_SHA1_160_HASH_LEN);
367		if (pValidationData->rgbValidationData == NULL) {
368			LogError("malloc of %d bytes failed.", TPM_SHA1_160_HASH_LEN);
369			free_tspi(tspContext, pValidationData->rgbData);
370			pValidationData->rgbData = NULL;
371			pValidationData->ulDataLength = 0;
372			result = TSPERR(TSS_E_OUTOFMEMORY);
373			goto done;
374		}
375		pValidationData->ulValidationDataLength = TPM_SHA1_160_HASH_LEN;
376		memcpy(pValidationData->rgbValidationData, digest.digest, TPM_SHA1_160_HASH_LEN);
377	}
378
379	if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK))) {
380		if (pValidationData) {
381			free_tspi(tspContext, pValidationData->rgbValidationData);
382			free_tspi(tspContext, pValidationData->rgbData);
383			pValidationData->rgbData = NULL;
384			pValidationData->ulDataLength = 0;
385			pValidationData->rgbValidationData = NULL;
386			pValidationData->ulValidationDataLength = 0;
387		}
388		goto done;
389	}
390
391	if (genResetAuth) {
392		if ((*prgbEkResetData = calloc_tspi(tspContext, sizeof(eKResetAuth.digest))) == NULL) {
393			LogError("malloc of %zd bytes failed.", sizeof(eKResetAuth.digest));
394			if (pValidationData) {
395				free_tspi(tspContext, pValidationData->rgbValidationData);
396				free_tspi(tspContext, pValidationData->rgbData);
397				pValidationData->rgbData = NULL;
398				pValidationData->ulDataLength = 0;
399				pValidationData->rgbValidationData = NULL;
400				pValidationData->ulValidationDataLength = 0;
401			}
402			goto done;
403		}
404
405		memcpy(*prgbEkResetData, eKResetAuth.digest, sizeof(eKResetAuth.digest));
406		*pulEkResetDataLength = sizeof(eKResetAuth.digest);
407	}
408
409done:
410	free(newEK);
411
412	return result;
413}
414
415TSS_RESULT
416Tspi_TPM_RevokeEndorsementKey(TSS_HTPM hTPM,			/* in */
417			      UINT32  ulEkResetDataLength,	/* in */
418			      BYTE * rgbEkResetData)		/* in */
419{
420	TSS_HCONTEXT tspContext;
421	TPM_DIGEST eKResetAuth;
422	TSS_RESULT result;
423
424	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
425		return result;
426
427	if (ulEkResetDataLength < sizeof(eKResetAuth.digest) || !rgbEkResetData)
428		return TSPERR(TSS_E_BAD_PARAMETER);
429
430	memcpy(eKResetAuth.digest, rgbEkResetData, sizeof(eKResetAuth.digest));
431
432	if ((result = RPC_RevokeEndorsementKeyPair(tspContext, &eKResetAuth)))
433		return result;
434
435	return result;
436}
437#endif
438
439