]> git.proxmox.com Git - libtpms.git/blame - src/tpm_tpm12_interface.c
Move common debug, memory & nvfile units to src/
[libtpms.git] / src / tpm_tpm12_interface.c
CommitLineData
39c9604a
SB
1/********************************************************************************/
2/* */
3/* LibTPM TPM 1.2 call interface functions */
4/* Written by Stefan Berger */
5/* IBM Thomas J. Watson Research Center */
6/* */
7/* (c) Copyright IBM Corporation 2015. */
8/* */
9/* All rights reserved. */
10/* */
11/* Redistribution and use in source and binary forms, with or without */
12/* modification, are permitted provided that the following conditions are */
13/* met: */
14/* */
15/* Redistributions of source code must retain the above copyright notice, */
16/* this list of conditions and the following disclaimer. */
17/* */
18/* Redistributions in binary form must reproduce the above copyright */
19/* notice, this list of conditions and the following disclaimer in the */
20/* documentation and/or other materials provided with the distribution. */
21/* */
22/* Neither the names of the IBM Corporation nor the names of its */
23/* contributors may be used to endorse or promote products derived from */
24/* this software without specific prior written permission. */
25/* */
26/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
27/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
28/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
29/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
30/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
31/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
32/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
33/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
34/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
35/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
36/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
37/********************************************************************************/
38
39#include <config.h>
40
70547a75 41#define _GNU_SOURCE
39c9604a
SB
42#include <assert.h>
43#include <stdio.h>
44#include <stdlib.h>
70547a75 45#include <string.h>
fe481765 46#include <stdbool.h>
39c9604a 47
e60c35ec 48#include "tpm_debug.h"
39c9604a
SB
49#include "tpm_error.h"
50#include "tpm12/tpm_init.h"
51#include "tpm_library_intern.h"
52#include "tpm12/tpm_process.h"
53#include "tpm12/tpm_startup.h"
e11dbf25
SB
54#include "tpm12/tpm_global.h"
55#include "tpm12/tpm_permanent.h"
e60c35ec 56#include "tpm_nvfile.h"
39c9604a 57
5d7a04c6 58static TPM_RESULT TPM12_MainInit(void)
39c9604a
SB
59{
60 return TPM_MainInit();
61}
62
5d7a04c6 63static void TPM12_Terminate(void)
39c9604a
SB
64{
65 TPM_Global_Delete(tpm_instances[0]);
66 free(tpm_instances[0]);
67 tpm_instances[0] = NULL;
68}
69
5d7a04c6
SB
70static TPM_RESULT TPM12_Process(unsigned char **respbuffer, uint32_t *resp_size,
71 uint32_t *respbufsize,
72 unsigned char *command, uint32_t command_size)
39c9604a
SB
73{
74 *resp_size = 0;
75 return TPM_ProcessA(respbuffer, resp_size, respbufsize,
76 command, command_size);
77}
78
5d7a04c6
SB
79static TPM_RESULT TPM12_VolatileAllStore(unsigned char **buffer,
80 uint32_t *buflen)
39c9604a
SB
81{
82 TPM_RESULT rc;
83 TPM_STORE_BUFFER tsb;
84 TPM_Sbuffer_Init(&tsb);
85 uint32_t total;
86
87#ifdef TPM_DEBUG
88 assert(tpm_instances[0] != NULL);
89#endif
90
91 rc = TPM_VolatileAll_Store(&tsb, tpm_instances[0]);
92
93 if (rc == TPM_SUCCESS) {
94 /* caller now owns the buffer and needs to free it */
95 TPM_Sbuffer_GetAll(&tsb, buffer, buflen, &total);
96 } else {
97 TPM_Sbuffer_Delete(&tsb);
98 *buflen = 0;
99 *buffer = NULL;
100 }
101
102 return rc;
103}
104
5d7a04c6 105static TPM_RESULT TPM12_CancelCommand(void)
3cf528aa
SB
106{
107 return TPM_FAIL; /* not supported */
108}
109
110
5d7a04c6 111static TPM_RESULT TPM12_GetTPMProperty(enum TPMLIB_TPMProperty prop,
39c9604a
SB
112 int *result)
113{
114 switch (prop) {
115 case TPMPROP_TPM_RSA_KEY_LENGTH_MAX:
116 *result = TPM_RSA_KEY_LENGTH_MAX;
117 break;
118
119 case TPMPROP_TPM_KEY_HANDLES:
120 *result = TPM_KEY_HANDLES;
121 break;
122
123 case TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES:
124 *result = TPM_OWNER_EVICT_KEY_HANDLES;
125 break;
126
127 case TPMPROP_TPM_MIN_AUTH_SESSIONS:
128 *result = TPM_MIN_AUTH_SESSIONS;
129 break;
130
131 case TPMPROP_TPM_MIN_TRANS_SESSIONS:
132 *result = TPM_MIN_TRANS_SESSIONS;
133 break;
134
135 case TPMPROP_TPM_MIN_DAA_SESSIONS:
136 *result = TPM_MIN_DAA_SESSIONS;
137 break;
138
139 case TPMPROP_TPM_MIN_SESSION_LIST:
140 *result = TPM_MIN_SESSION_LIST;
141 break;
142
143 case TPMPROP_TPM_MIN_COUNTERS:
144 *result = TPM_MIN_COUNTERS;
145 break;
146
147 case TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN:
148 *result = TPM_NUM_FAMILY_TABLE_ENTRY_MIN;
149 break;
150
151 case TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN:
152 *result = TPM_NUM_DELEGATE_TABLE_ENTRY_MIN;
153 break;
154
155 case TPMPROP_TPM_SPACE_SAFETY_MARGIN:
156 *result = TPM_SPACE_SAFETY_MARGIN;
157 break;
158
159 case TPMPROP_TPM_MAX_NV_SPACE:
160 /* fill up 20 kb.; this provides some safety margin (currently
161 >4Kb) for possible future expansion of this blob */
162 *result = ROUNDUP(TPM_MAX_NV_SPACE, 20 * 1024);
163 break;
164
165 case TPMPROP_TPM_MAX_SAVESTATE_SPACE:
166 *result = TPM_MAX_SAVESTATE_SPACE;
167 break;
168
169 case TPMPROP_TPM_MAX_VOLATILESTATE_SPACE:
170 *result = TPM_MAX_VOLATILESTATE_SPACE;
171 break;
172
173 default:
174 return TPM_FAIL;
175 }
176
177 return TPM_SUCCESS;
178}
179
70547a75
SB
180/*
181 * TPM12_GetInfo:
182 *
183 * @flags: logical or of flags that query for information
184 *
185 * Return a JSON document with contents queried for by the user's passed flags
186 */
5d7a04c6 187static char *TPM12_GetInfo(enum TPMLIB_InfoFlags flags)
70547a75
SB
188{
189 const char *tpmspec =
190 "\"TPMSpecification\":{"
191 "\"family\":\"1.2\","
192 "\"level\":2,"
193 "\"revision\":116"
194 "}";
fe481765
SB
195 const char *tpmattrs =
196 "\"TPMAttributes\":{"
197 "\"manufacturer\":\"id:00001014\","
198 "\"version\":\"id:00740001\"," /* 146.1 */
199 "\"model\":\"swtpm\""
200 "}";
70547a75 201 char *fmt = NULL, *buffer;
fe481765 202 bool printed = false;
70547a75 203
fe481765 204 if (!(buffer = strdup("{%s%s%s}")))
70547a75
SB
205 return NULL;
206
207 if ((flags & TPMLIB_INFO_TPMSPECIFICATION)) {
208 fmt = buffer;
209 buffer = NULL;
fe481765
SB
210 if (asprintf(&buffer, fmt, "", tpmspec, "%s%s%s") < 0)
211 goto error;
212 free(fmt);
213 printed = true;
214 }
215 if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) {
216 fmt = buffer;
217 buffer = NULL;
218 if (asprintf(&buffer, fmt, printed ? "," : "",
219 tpmattrs, "%s%s%s") < 0)
70547a75
SB
220 goto error;
221 free(fmt);
fe481765 222 printed = true;
70547a75
SB
223 }
224
225 /* nothing else to add */
226 fmt = buffer;
227 buffer = NULL;
fe481765 228 if (asprintf(&buffer, fmt, "", "", "") < 0)
70547a75
SB
229 goto error;
230 free(fmt);
231
232 return buffer;
233
234error:
235 free(fmt);
236 free(buffer);
237
238 return NULL;
239}
240
ccdf2457
SB
241static uint32_t tpm12_buffersize = TPM_BUFFER_MAX;
242
5d7a04c6
SB
243static uint32_t TPM12_SetBufferSize(uint32_t wanted_size,
244 uint32_t *min_size,
245 uint32_t *max_size)
bc195a34 246{
ae3f105a 247 if (min_size)
ccdf2457 248 *min_size = TPM_BUFFER_MIN;
ae3f105a
SB
249 if (max_size)
250 *max_size = TPM_BUFFER_MAX;
ccdf2457 251
d77f29d6
SB
252 if (wanted_size == 0)
253 return tpm12_buffersize;
254
ccdf2457
SB
255 if (wanted_size > TPM_BUFFER_MAX)
256 wanted_size = TPM_BUFFER_MAX;
257 else if (wanted_size < TPM_BUFFER_MIN)
258 wanted_size = TPM_BUFFER_MIN;
259
260 tpm12_buffersize = wanted_size;
261
262 return tpm12_buffersize;
263}
264
265uint32_t TPM12_GetBufferSize(void)
266{
267 return TPM12_SetBufferSize(0, NULL, NULL);
bc195a34
SB
268}
269
5d7a04c6
SB
270static TPM_RESULT TPM12_ValidateState(enum TPMLIB_StateType st,
271 unsigned int flags)
e11dbf25
SB
272{
273 TPM_RESULT ret = TPM_SUCCESS;
274 tpm_state_t tpm_state;
32387429
SB
275 enum TPMLIB_StateType sts[] = {
276 TPMLIB_STATE_PERMANENT,
277 TPMLIB_STATE_VOLATILE,
278 TPMLIB_STATE_SAVE_STATE,
279 0,
280 };
7bbb41a1 281 enum TPMLIB_StateType c_st;
32387429 282 unsigned i;
e11dbf25
SB
283
284#ifdef TPM_LIBTPMS_CALLBACKS
285 struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
286
287 if (cbs->tpm_nvram_init) {
288 ret = cbs->tpm_nvram_init();
289 if (ret != TPM_SUCCESS)
290 return ret;
291 }
292#endif
293
294 ret = TPM_Global_Init(&tpm_state);
295 tpm_state.tpm_number = 0;
296
51f7c2f0
SB
297 if (ret == TPM_SUCCESS) {
298 /* permanent state needs to be there and loaded first */
299 ret = TPM_PermanentAll_NVLoad(&tpm_state);
300 }
301
32387429 302 for (i = 0; sts[i] && ret == TPM_SUCCESS; i++) {
7bbb41a1
SB
303 c_st = st & sts[i];
304
305 /* 'cached' state is known to 'work', so skip it */
51f7c2f0 306 if (!c_st || HasCachedState(c_st))
7bbb41a1
SB
307 continue;
308
309 switch (c_st) {
32387429 310 case TPMLIB_STATE_PERMANENT:
32387429
SB
311 break;
312 case TPMLIB_STATE_VOLATILE:
313 ret = TPM_VolatileAll_NVLoad(&tpm_state);
314 break;
315 case TPMLIB_STATE_SAVE_STATE:
316 ret = TPM_SaveState_NVLoad(&tpm_state);
317 break;
318 }
e11dbf25
SB
319 }
320
321 TPM_Global_Delete(&tpm_state);
322
323 return ret;
324}
325
c76f52ef
SB
326static TPM_RESULT _TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer,
327 tpm_state_t *tpm_state)
328{
329 const unsigned char *buffer = NULL;
330 uint32_t buflen;
331
332 return TPM_PermanentAll_Store(sbuffer, &buffer, &buflen, tpm_state);
333}
334
f031191a
SB
335/*
336 * TPM_PermanentAll_NVLoad_Preserve
337 *
338 * @tpm_state: The tpm_state to load the permanent state into
339 *
340 * Call TPM_PermanentAll_NVLoad and preserve any cached data that a call
341 * to TPM_PermanentAll_NVLoad (TPM_NVRAM_LoadData) may otherwise consume
342 * and remove if it was available.
343 */
344static TPM_RESULT TPM_PermanentAll_NVLoad_Preserve(tpm_state_t *tpm_state)
345{
346 TPM_RESULT ret;
347 unsigned char *buffer = NULL;
348 uint32_t buffer_len;
349 bool is_empty_buffer;
350
351 ret = CopyCachedState(TPMLIB_STATE_PERMANENT,
352 &buffer, &buffer_len, &is_empty_buffer);
353 if (ret == TPM_SUCCESS) {
354 ret = TPM_PermanentAll_NVLoad(tpm_state);
355
356 /* restore a previous empty buffer or any valid buffer */
357 if (is_empty_buffer || buffer != NULL)
358 SetCachedState(TPMLIB_STATE_PERMANENT, buffer, buffer_len);
359 }
360
361 return ret;
362}
363
c76f52ef
SB
364/*
365 * Get the state blob of the given type. If we TPM is not running, we
366 * get the cached state blobs, if available, otherwise we try to read
367 * it from files. In case the TPM is running, we get it from the running
368 * TPM.
369 */
5d7a04c6
SB
370static TPM_RESULT TPM12_GetState(enum TPMLIB_StateType st,
371 unsigned char **buffer, uint32_t *buflen)
c76f52ef
SB
372{
373 TPM_RESULT ret = TPM_FAIL;
374 TPM_STORE_BUFFER tsb;
375 uint32_t total;
376
377 /* TPM not running ? */
378 if (tpm_instances[0] == NULL) {
379 struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
380 bool is_empty_buffer;
381
382 /* try cached blob before file */
383 ret = CopyCachedState(st, buffer, buflen, &is_empty_buffer);
ee69f378 384 if (ret != TPM_SUCCESS || *buffer != NULL || is_empty_buffer)
c76f52ef
SB
385 return ret;
386
387 if (cbs->tpm_nvram_init) {
388 ret = cbs->tpm_nvram_init();
389 if (ret != TPM_SUCCESS)
390 return ret;
391
392 ret = TPM_NVRAM_LoadData(buffer, buflen, 0,
393 TPMLIB_StateTypeToName(st));
394 } else {
395 ret = TPM_FAIL;
396 }
397 return ret;
398 }
399
400 TPM_Sbuffer_Init(&tsb);
401
402 switch (st) {
403 case TPMLIB_STATE_PERMANENT:
404 ret = _TPM_PermanentAll_Store(&tsb, tpm_instances[0]);
405 break;
406 case TPMLIB_STATE_VOLATILE:
407 ret = TPM_VolatileAll_Store(&tsb, tpm_instances[0]);
408 break;
409 case TPMLIB_STATE_SAVE_STATE:
410 ret = TPM_SaveState_Store(&tsb, tpm_instances[0]);
411 break;
412 }
413
414 if (ret == TPM_SUCCESS) {
415 /* caller now owns the buffer and needs to free it */
416 TPM_Sbuffer_GetAll(&tsb, buffer, buflen, &total);
417 } else {
418 TPM_Sbuffer_Delete(&tsb);
419 *buflen = 0;
420 *buffer = NULL;
421 }
422
423 return ret;
424}
425
426/*
427 * Set the state the TPM 1.2 will use upon next TPM_MainInit(). The TPM 1.2
428 * must not have been started, yet, or it must have been terminated for this
429 * function to set the state.
430 *
431 * @st: The TPMLIB_StateType describing the type of blob in the buffer
432 * @buffer: pointer to the buffer containing the state blob; NULL pointer clears
433 * previous state
434 * @buflen: length of the buffer
435 */
5d7a04c6
SB
436static TPM_RESULT TPM12_SetState(enum TPMLIB_StateType st,
437 const unsigned char *buffer, uint32_t buflen)
c76f52ef
SB
438{
439 TPM_RESULT ret = TPM_SUCCESS;
440 unsigned char *stream = NULL, *orig_stream = NULL;
441 uint32_t stream_size = buflen;
442 tpm_state_t *tpm_state = NULL;
443
444 if (buffer == NULL) {
445 SetCachedState(st, NULL, 0);
446 return TPM_SUCCESS;
447 }
448
449 if (tpm_instances[0])
450 return TPM_INVALID_POSTINIT;
451
452 if (ret == TPM_SUCCESS) {
707a9046
SB
453 stream = malloc(buflen);
454 if (!stream) {
455 TPMLIB_LogError("Could not allocate %u bytes.\n", buflen);
456 ret = TPM_SIZE;
457 }
c76f52ef
SB
458 }
459
460 if (ret == TPM_SUCCESS) {
461 orig_stream = stream;
462 memcpy(stream, buffer, buflen);
463
707a9046
SB
464 tpm_state = malloc(sizeof(tpm_state_t));
465 if (!tpm_state) {
466 TPMLIB_LogError("Could not allocated %zu bytes.\n",
467 sizeof(tpm_state_t));
468 ret = TPM_SIZE;
469 }
c76f52ef
SB
470 }
471
472 if (ret == TPM_SUCCESS) {
473 ret = TPM_Global_Init(tpm_state);
474 }
475
476 /* test whether we can accept the blob */
477 if (ret == TPM_SUCCESS) {
f031191a
SB
478 tpm_state->tpm_number = 0;
479
c76f52ef
SB
480 switch (st) {
481 case TPMLIB_STATE_PERMANENT:
482 ret = TPM_PermanentAll_Load(tpm_state, &stream, &stream_size);
483 break;
484 case TPMLIB_STATE_VOLATILE:
f031191a
SB
485 /* permanent state needs to be there and loaded first */
486 ret = TPM_PermanentAll_NVLoad_Preserve(tpm_state);
487 if (ret == TPM_SUCCESS)
488 ret = TPM_VolatileAll_Load(tpm_state, &stream, &stream_size);
c76f52ef
SB
489 break;
490 case TPMLIB_STATE_SAVE_STATE:
f031191a
SB
491 ret = TPM_PermanentAll_NVLoad_Preserve(tpm_state);
492 if (ret == TPM_SUCCESS)
493 ret = TPM_SaveState_Load(tpm_state, &stream, &stream_size);
c76f52ef
SB
494 break;
495 }
7071a43b
SB
496 if (ret)
497 ClearAllCachedState();
c76f52ef
SB
498 }
499
500 /* cache the blob for the TPM_MainInit() to pick it up */
501 if (ret == TPM_SUCCESS) {
502 SetCachedState(st, orig_stream, buflen);
503 } else {
504 free(orig_stream);
505 }
506
507 TPM_Global_Delete(tpm_state);
508 free(tpm_state);
509
510 return ret;
511}
512
39c9604a
SB
513const struct tpm_interface TPM12Interface = {
514 .MainInit = TPM12_MainInit,
515 .Terminate = TPM12_Terminate,
516 .Process = TPM12_Process,
517 .VolatileAllStore = TPM12_VolatileAllStore,
3cf528aa 518 .CancelCommand = TPM12_CancelCommand,
39c9604a 519 .GetTPMProperty = TPM12_GetTPMProperty,
70547a75 520 .GetInfo = TPM12_GetInfo,
39c9604a 521 .TpmEstablishedGet = TPM12_IO_TpmEstablished_Get,
3cf528aa 522 .TpmEstablishedReset = TPM12_IO_TpmEstablished_Reset,
39c9604a
SB
523 .HashStart = TPM12_IO_Hash_Start,
524 .HashData = TPM12_IO_Hash_Data,
525 .HashEnd = TPM12_IO_Hash_End,
bc195a34 526 .SetBufferSize = TPM12_SetBufferSize,
e11dbf25 527 .ValidateState = TPM12_ValidateState,
c76f52ef
SB
528 .SetState = TPM12_SetState,
529 .GetState = TPM12_GetState,
39c9604a 530};