Coverage Report

Created: 2025-05-08 06:39

/src/libtpms/src/tpm_tpm12_interface.c
Line
Count
Source (jump to first uncovered line)
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
41
#define _GNU_SOURCE
42
#include <assert.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <stdbool.h>
47
48
#include "tpm_debug.h"
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"
54
#include "tpm12/tpm_global.h"
55
#include "tpm12/tpm_permanent.h"
56
#include "tpm_nvfile.h"
57
58
static TPM_RESULT TPM12_MainInit(void)
59
0
{
60
0
    return TPM_MainInit();
61
0
}
62
63
static void TPM12_Terminate(void)
64
0
{
65
0
    TPM_Global_Delete(tpm_instances[0]);
66
0
    free(tpm_instances[0]);
67
0
    tpm_instances[0] = NULL;
68
0
}
69
70
static TPM_RESULT TPM12_Process(unsigned char **respbuffer, uint32_t *resp_size,
71
                                uint32_t *respbufsize,
72
                                unsigned char *command, uint32_t command_size)
73
0
{
74
0
    *resp_size = 0;
75
0
    return TPM_ProcessA(respbuffer, resp_size, respbufsize,
76
0
                        command, command_size);
77
0
}
78
79
static TPM_RESULT TPM12_VolatileAllStore(unsigned char **buffer,
80
                                         uint32_t *buflen)
81
0
{
82
0
    TPM_RESULT rc;
83
0
    TPM_STORE_BUFFER tsb;
84
0
    TPM_Sbuffer_Init(&tsb);
85
0
    uint32_t total;
86
87
#ifdef TPM_DEBUG
88
    assert(tpm_instances[0] != NULL);
89
#endif
90
91
0
    rc = TPM_VolatileAll_Store(&tsb, tpm_instances[0]);
92
93
0
    if (rc == TPM_SUCCESS) {
94
        /* caller now owns the buffer and needs to free it */
95
0
        TPM_Sbuffer_GetAll(&tsb, buffer, buflen, &total);
96
0
    } else {
97
0
        TPM_Sbuffer_Delete(&tsb);
98
0
        *buflen = 0;
99
0
        *buffer = NULL;
100
0
    }
101
102
0
    return rc;
103
0
}
104
105
static TPM_RESULT TPM12_CancelCommand(void)
106
0
{
107
0
    return TPM_FAIL; /* not supported */
108
0
}
109
110
111
static TPM_RESULT TPM12_GetTPMProperty(enum TPMLIB_TPMProperty prop,
112
                                int *result)
113
0
{
114
0
    switch (prop) {
115
0
    case  TPMPROP_TPM_RSA_KEY_LENGTH_MAX:
116
0
        *result = TPM_RSA_KEY_LENGTH_MAX;
117
0
        break;
118
119
0
    case  TPMPROP_TPM_KEY_HANDLES:
120
0
        *result = TPM_KEY_HANDLES;
121
0
        break;
122
123
0
    case  TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES:
124
0
        *result = TPM_OWNER_EVICT_KEY_HANDLES;
125
0
        break;
126
127
0
    case  TPMPROP_TPM_MIN_AUTH_SESSIONS:
128
0
        *result = TPM_MIN_AUTH_SESSIONS;
129
0
        break;
130
131
0
    case  TPMPROP_TPM_MIN_TRANS_SESSIONS:
132
0
        *result = TPM_MIN_TRANS_SESSIONS;
133
0
        break;
134
135
0
    case  TPMPROP_TPM_MIN_DAA_SESSIONS:
136
0
        *result = TPM_MIN_DAA_SESSIONS;
137
0
        break;
138
139
0
    case  TPMPROP_TPM_MIN_SESSION_LIST:
140
0
        *result = TPM_MIN_SESSION_LIST;
141
0
        break;
142
143
0
    case  TPMPROP_TPM_MIN_COUNTERS:
144
0
        *result = TPM_MIN_COUNTERS;
145
0
        break;
146
147
0
    case  TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN:
148
0
        *result = TPM_NUM_FAMILY_TABLE_ENTRY_MIN;
149
0
        break;
150
151
0
    case  TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN:
152
0
        *result = TPM_NUM_DELEGATE_TABLE_ENTRY_MIN;
153
0
        break;
154
155
0
    case  TPMPROP_TPM_SPACE_SAFETY_MARGIN:
156
0
        *result = TPM_SPACE_SAFETY_MARGIN;
157
0
        break;
158
159
0
    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
0
        *result = ROUNDUP(TPM_MAX_NV_SPACE, 20 * 1024);
163
0
        break;
164
165
0
    case  TPMPROP_TPM_MAX_SAVESTATE_SPACE:
166
0
        *result = TPM_MAX_SAVESTATE_SPACE;
167
0
        break;
168
169
0
    case  TPMPROP_TPM_MAX_VOLATILESTATE_SPACE:
170
0
        *result = TPM_MAX_VOLATILESTATE_SPACE;
171
0
        break;
172
173
0
    default:
174
0
        return TPM_FAIL;
175
0
    }
176
177
0
    return TPM_SUCCESS;
178
0
}
179
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
 */
187
static char *TPM12_GetInfo(enum TPMLIB_InfoFlags flags)
188
0
{
189
0
    const char *tpmspec =
190
0
    "\"TPMSpecification\":{"
191
0
        "\"family\":\"1.2\","
192
0
        "\"level\":2,"
193
0
        "\"revision\":116"
194
0
    "}";
195
0
    const char *tpmattrs =
196
0
    "\"TPMAttributes\":{"
197
0
        "\"manufacturer\":\"id:00001014\","
198
0
        "\"version\":\"id:00740001\"," /* 146.1 */
199
0
        "\"model\":\"swtpm\""
200
0
    "}";
201
0
    char *fmt = NULL, *buffer;
202
0
    bool printed = false;
203
204
0
    if (!(buffer = strdup("{%s%s%s}")))
205
0
        return NULL;
206
207
0
    if ((flags & TPMLIB_INFO_TPMSPECIFICATION)) {
208
0
        fmt = buffer;
209
0
        buffer = NULL;
210
0
        if (asprintf(&buffer, fmt, "", tpmspec, "%s%s%s") < 0)
211
0
            goto error;
212
0
        free(fmt);
213
0
        printed = true;
214
0
    }
215
0
    if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) {
216
0
        fmt = buffer;
217
0
        buffer = NULL;
218
0
        if (asprintf(&buffer, fmt,  printed ? "," : "",
219
0
                     tpmattrs, "%s%s%s") < 0)
220
0
            goto error;
221
0
        free(fmt);
222
0
        printed = true;
223
0
    }
224
225
    /* nothing else to add */
226
0
    fmt = buffer;
227
0
    buffer = NULL;
228
0
    if (asprintf(&buffer, fmt, "", "", "") < 0)
229
0
        goto error;
230
0
    free(fmt);
231
232
0
    return buffer;
233
234
0
error:
235
0
    free(fmt);
236
0
    free(buffer);
237
238
0
    return NULL;
239
0
}
240
241
static uint32_t tpm12_buffersize = TPM_BUFFER_MAX;
242
243
static uint32_t TPM12_SetBufferSize(uint32_t wanted_size,
244
                                    uint32_t *min_size,
245
                                    uint32_t *max_size)
246
0
{
247
0
    if (min_size)
248
0
        *min_size = TPM_BUFFER_MIN;
249
0
    if (max_size)
250
0
        *max_size = TPM_BUFFER_MAX;
251
252
0
    if (wanted_size == 0)
253
0
        return tpm12_buffersize;
254
255
0
    if (wanted_size > TPM_BUFFER_MAX)
256
0
        wanted_size = TPM_BUFFER_MAX;
257
0
    else if (wanted_size < TPM_BUFFER_MIN)
258
0
        wanted_size = TPM_BUFFER_MIN;
259
260
0
    tpm12_buffersize = wanted_size;
261
262
0
    return tpm12_buffersize;
263
0
}
264
265
uint32_t TPM12_GetBufferSize(void)
266
0
{
267
0
    return TPM12_SetBufferSize(0, NULL, NULL);
268
0
}
269
270
static TPM_RESULT TPM12_ValidateState(enum TPMLIB_StateType st,
271
                                      unsigned int flags LIBTPMS_ATTR_UNUSED)
272
0
{
273
0
    TPM_RESULT ret = TPM_SUCCESS;
274
0
    tpm_state_t tpm_state;
275
0
    enum TPMLIB_StateType sts[] = {
276
0
        TPMLIB_STATE_PERMANENT,
277
0
        TPMLIB_STATE_VOLATILE,
278
0
        TPMLIB_STATE_SAVE_STATE,
279
0
        0,
280
0
    };
281
0
    enum TPMLIB_StateType c_st;
282
0
    unsigned i;
283
284
0
#ifdef TPM_LIBTPMS_CALLBACKS
285
0
    struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
286
287
0
    if (cbs->tpm_nvram_init) {
288
0
        ret = cbs->tpm_nvram_init();
289
0
        if (ret != TPM_SUCCESS)
290
0
            return ret;
291
0
    }
292
0
#endif
293
294
0
    ret = TPM_Global_Init(&tpm_state);
295
0
    tpm_state.tpm_number = 0;
296
297
0
    if (ret == TPM_SUCCESS) {
298
        /* permanent state needs to be there and loaded first */
299
0
        ret = TPM_PermanentAll_NVLoad(&tpm_state);
300
0
    }
301
302
0
    for (i = 0; sts[i] && ret == TPM_SUCCESS; i++) {
303
0
        c_st = st & sts[i];
304
305
        /* 'cached' state is known to 'work', so skip it */
306
0
        if (!c_st || HasCachedState(c_st))
307
0
            continue;
308
309
0
        switch (c_st) {
310
0
        case TPMLIB_STATE_PERMANENT:
311
0
            break;
312
0
        case TPMLIB_STATE_VOLATILE:
313
0
            ret = TPM_VolatileAll_NVLoad(&tpm_state);
314
0
            break;
315
0
        case TPMLIB_STATE_SAVE_STATE:
316
0
            ret = TPM_SaveState_NVLoad(&tpm_state);
317
0
            break;
318
0
        }
319
0
    }
320
321
0
    TPM_Global_Delete(&tpm_state);
322
323
0
    return ret;
324
0
}
325
326
static TPM_RESULT _TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer,
327
                                          tpm_state_t *tpm_state)
328
0
{
329
0
    const unsigned char *buffer = NULL;
330
0
    uint32_t buflen;
331
332
0
    return TPM_PermanentAll_Store(sbuffer, &buffer, &buflen, tpm_state);
333
0
}
334
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
 */
344
static TPM_RESULT TPM_PermanentAll_NVLoad_Preserve(tpm_state_t *tpm_state)
345
0
{
346
0
    TPM_RESULT ret;
347
0
    unsigned char *buffer = NULL;
348
0
    uint32_t buffer_len;
349
0
    bool is_empty_buffer;
350
351
0
    ret = CopyCachedState(TPMLIB_STATE_PERMANENT,
352
0
                          &buffer, &buffer_len, &is_empty_buffer);
353
0
    if (ret == TPM_SUCCESS) {
354
0
        ret = TPM_PermanentAll_NVLoad(tpm_state);
355
356
        /* restore a previous empty buffer or any valid buffer */
357
0
        if (is_empty_buffer || buffer != NULL)
358
0
            SetCachedState(TPMLIB_STATE_PERMANENT, buffer, buffer_len);
359
0
    }
360
361
0
    return ret;
362
0
}
363
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
 */
370
static TPM_RESULT TPM12_GetState(enum TPMLIB_StateType st,
371
                                 unsigned char **buffer, uint32_t *buflen)
372
0
{
373
0
    TPM_RESULT ret = TPM_FAIL;
374
0
    TPM_STORE_BUFFER tsb;
375
0
    uint32_t total;
376
377
    /* TPM not running ? */
378
0
    if (tpm_instances[0] == NULL) {
379
0
        struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
380
0
        bool is_empty_buffer;
381
382
        /* try cached blob before file */
383
0
        ret = CopyCachedState(st, buffer, buflen, &is_empty_buffer);
384
0
        if (ret != TPM_SUCCESS || *buffer != NULL || is_empty_buffer)
385
0
            return ret;
386
387
0
        if (cbs->tpm_nvram_init) {
388
0
            ret = cbs->tpm_nvram_init();
389
0
            if (ret != TPM_SUCCESS)
390
0
                return ret;
391
392
0
            ret = TPM_NVRAM_LoadData(buffer, buflen, 0,
393
0
                                     TPMLIB_StateTypeToName(st));
394
0
        } else {
395
0
            ret = TPM_FAIL;
396
0
        }
397
0
        return ret;
398
0
    }
399
400
0
    TPM_Sbuffer_Init(&tsb);
401
402
0
    switch (st) {
403
0
    case TPMLIB_STATE_PERMANENT:
404
0
        ret = _TPM_PermanentAll_Store(&tsb, tpm_instances[0]);
405
0
        break;
406
0
    case TPMLIB_STATE_VOLATILE:
407
0
        ret = TPM_VolatileAll_Store(&tsb, tpm_instances[0]);
408
0
        break;
409
0
    case TPMLIB_STATE_SAVE_STATE:
410
0
        ret = TPM_SaveState_Store(&tsb, tpm_instances[0]);
411
0
        break;
412
0
    }
413
414
0
    if (ret == TPM_SUCCESS) {
415
        /* caller now owns the buffer and needs to free it */
416
0
        TPM_Sbuffer_GetAll(&tsb, buffer, buflen, &total);
417
0
    } else {
418
0
        TPM_Sbuffer_Delete(&tsb);
419
0
        *buflen = 0;
420
0
        *buffer = NULL;
421
0
    }
422
423
0
    return ret;
424
0
}
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
 */
436
static TPM_RESULT TPM12_SetState(enum TPMLIB_StateType st,
437
                                 const unsigned char *buffer, uint32_t buflen)
438
0
{
439
0
    TPM_RESULT ret = TPM_SUCCESS;
440
0
    unsigned char *stream = NULL, *orig_stream = NULL;
441
0
    uint32_t stream_size = buflen;
442
0
    tpm_state_t *tpm_state = NULL;
443
444
0
    if (buffer == NULL) {
445
0
        SetCachedState(st, NULL, 0);
446
0
        return TPM_SUCCESS;
447
0
    }
448
449
0
    if (tpm_instances[0])
450
0
        return TPM_INVALID_POSTINIT;
451
452
0
    if (ret == TPM_SUCCESS) {
453
0
        stream = malloc(buflen);
454
0
        if (!stream) {
455
0
            TPMLIB_LogError("Could not allocate %u bytes.\n", buflen);
456
0
            ret = TPM_SIZE;
457
0
        }
458
0
    }
459
460
0
    if (ret == TPM_SUCCESS) {
461
0
        orig_stream = stream;
462
0
        memcpy(stream, buffer, buflen);
463
464
0
        tpm_state = malloc(sizeof(tpm_state_t));
465
0
        if (!tpm_state) {
466
0
            TPMLIB_LogError("Could not allocated %zu bytes.\n",
467
0
                            sizeof(tpm_state_t));
468
0
            ret = TPM_SIZE;
469
0
        }
470
0
    }
471
472
0
    if (ret == TPM_SUCCESS) {
473
0
        ret = TPM_Global_Init(tpm_state);
474
0
    }
475
476
    /* test whether we can accept the blob */
477
0
    if (ret == TPM_SUCCESS) {
478
0
        tpm_state->tpm_number = 0;
479
480
0
        switch (st) {
481
0
        case TPMLIB_STATE_PERMANENT:
482
0
            ret = TPM_PermanentAll_Load(tpm_state, &stream, &stream_size);
483
0
            break;
484
0
        case TPMLIB_STATE_VOLATILE:
485
            /* permanent state needs to be there and loaded first */
486
0
            ret = TPM_PermanentAll_NVLoad_Preserve(tpm_state);
487
0
            if (ret == TPM_SUCCESS)
488
0
                ret = TPM_VolatileAll_Load(tpm_state, &stream, &stream_size);
489
0
            break;
490
0
        case TPMLIB_STATE_SAVE_STATE:
491
0
            ret = TPM_PermanentAll_NVLoad_Preserve(tpm_state);
492
0
            if (ret == TPM_SUCCESS)
493
0
                 ret = TPM_SaveState_Load(tpm_state, &stream, &stream_size);
494
0
            break;
495
0
        }
496
0
        if (ret)
497
0
            ClearAllCachedState();
498
0
    }
499
500
    /* cache the blob for the TPM_MainInit() to pick it up */
501
0
    if (ret == TPM_SUCCESS) {
502
0
        SetCachedState(st, orig_stream, buflen);
503
0
    } else {
504
0
        free(orig_stream);
505
0
    }
506
507
0
    TPM_Global_Delete(tpm_state);
508
0
    free(tpm_state);
509
510
0
    return ret;
511
0
}
512
513
static TPM_RESULT TPM12_SetProfile(const char *profile)
514
0
{
515
0
    return TPM_FAIL;
516
0
}
517
518
static TPM_BOOL TPM12_WasManufactured(void)
519
0
{
520
0
    return FALSE;
521
0
}
522
523
const struct tpm_interface TPM12Interface = {
524
    .MainInit = TPM12_MainInit,
525
    .Terminate = TPM12_Terminate,
526
    .Process = TPM12_Process,
527
    .VolatileAllStore = TPM12_VolatileAllStore,
528
    .CancelCommand = TPM12_CancelCommand,
529
    .GetTPMProperty = TPM12_GetTPMProperty,
530
    .GetInfo = TPM12_GetInfo,
531
    .TpmEstablishedGet = TPM12_IO_TpmEstablished_Get,
532
    .TpmEstablishedReset = TPM12_IO_TpmEstablished_Reset,
533
    .HashStart = TPM12_IO_Hash_Start,
534
    .HashData = TPM12_IO_Hash_Data,
535
    .HashEnd = TPM12_IO_Hash_End,
536
    .SetBufferSize = TPM12_SetBufferSize,
537
    .ValidateState = TPM12_ValidateState,
538
    .SetState = TPM12_SetState,
539
    .GetState = TPM12_GetState,
540
    .SetProfile = TPM12_SetProfile,
541
    .WasManufactured = TPM12_WasManufactured,
542
};