Coverage Report

Created: 2026-11-12 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfTPM/src/tpm2_wrap.c
Line
Count
Source
1
/* tpm2_wrap.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfTPM.
6
 *
7
 * wolfTPM is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfTPM is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
    #include <config.h>
24
#endif
25
26
#include <wolftpm/tpm2_wrap.h>
27
#include <wolftpm/tpm2_tis.h>
28
#include <wolftpm/tpm2_param_enc.h>
29
#ifdef WOLFTPM_SPDM
30
#include <wolftpm/tpm2_spdm.h>
31
#endif
32
#ifdef WOLFTPM_SWTPM
33
#include <wolftpm/tpm2_swtpm.h>
34
#endif
35
36
/* Convert big-endian byte array to native word32 */
37
word32 wolfTPM2_RsaKey_Exponent(const byte* e, word32 eSz)
38
31
{
39
31
    word32 exponent = 0, i;
40
87
    for (i = 0; i < eSz && i < sizeof(word32); i++) {
41
56
        exponent = (exponent << 8) | e[i];
42
56
    }
43
31
    return exponent;
44
31
}
45
46
#ifndef WOLFTPM2_NO_WRAPPER
47
48
/* For some struct to buffer conversions */
49
#include <wolftpm/tpm2_packet.h>
50
#include <hal/tpm_io.h> /* for default IO callback */
51
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
52
    #include <wolftpm/tpm2_linux.h>
53
#endif
54
55
/* Local Functions */
56
static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap);
57
static void wolfTPM2_CopySymmetric(TPMT_SYM_DEF* out, const TPMT_SYM_DEF* in);
58
static void wolfTPM2_CopyName(TPM2B_NAME* out, const TPM2B_NAME* in);
59
static void wolfTPM2_CopyAuth(TPM2B_AUTH* out, const TPM2B_AUTH* in);
60
static void wolfTPM2_CopyPubT(TPMT_PUBLIC* out, const TPMT_PUBLIC* in);
61
static void wolfTPM2_CopyPub(TPM2B_PUBLIC* out, const TPM2B_PUBLIC* in);
62
static void wolfTPM2_CopyPriv(TPM2B_PRIVATE* out, const TPM2B_PRIVATE* in);
63
static void wolfTPM2_CopyEccParam(TPM2B_ECC_PARAMETER* out, const TPM2B_ECC_PARAMETER* in);
64
static void wolfTPM2_CopyKeyFromBlob(WOLFTPM2_KEY* key, const WOLFTPM2_KEYBLOB* keyBlob);
65
static void wolfTPM2_CopyNvPublic(TPMS_NV_PUBLIC* out, const TPMS_NV_PUBLIC* in);
66
67
/******************************************************************************/
68
/* --- BEGIN Wrapper Device Functions -- */
69
/******************************************************************************/
70
71
static int wolfTPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
72
    int timeoutTries)
73
{
74
    int rc;
75
76
#if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_WINAPI)
77
    Startup_In startupIn;
78
#if defined(WOLFTPM_MICROCHIP) || defined(WOLFTPM_PERFORM_SELFTEST)
79
    SelfTest_In selfTest;
80
#endif
81
#endif /* ! WOLFTPM_LINUX_DEV */
82
83
    if (ctx == NULL)
84
        return BAD_FUNC_ARG;
85
86
#if defined(WOLFTPM_LINUX_DEV_AUTODETECT)
87
    /* Phase 1: Minimal init (sets up IO callback, no TIS chip startup) */
88
    rc = TPM2_Init_ex(ctx, ioCb, userCtx, 0);
89
    if (rc != TPM_RC_SUCCESS) {
90
        printf("TPM2_Init failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc));
91
        return rc;
92
    }
93
94
    /* Phase 2: TPM2_Init_ex already probed /dev/tpmrm0 then /dev/tpm0, so read
95
     * what it found rather than opening the nodes a second time. It cannot
96
     * reject the no-transport case for us - phase 1 passes timeoutTries 0 -
97
     * so phase 3 below still has to. */
98
    if (ctx->fd >= 0) {
99
        /* Using kernel driver - startup/locality handled by kernel */
100
    #ifdef DEBUG_WOLFTPM
101
        printf("TPM2: Using Linux kernel driver\n");
102
    #endif
103
        return TPM_RC_SUCCESS;
104
    }
105
106
    /* Phase 3: no kernel device, fall back to SPI - which needs the callback.
107
     * Phase 1 passes timeoutTries 0, so TPM2_Init_ex deliberately does not
108
     * reject this case there; it has to be caught here before TIS is used. */
109
    if (ioCb == NULL) {
110
    #ifdef DEBUG_WOLFTPM
111
        printf("TPM2: Kernel driver not available and no IO callback for SPI\n");
112
    #endif
113
        return TPM_RC_FAILURE;
114
    }
115
#ifdef DEBUG_WOLFTPM
116
    printf("TPM2: Kernel driver not available, trying SPI\n");
117
#endif
118
    if (timeoutTries > 0) {
119
        rc = TPM2_ChipStartup(ctx, timeoutTries);
120
        if (rc != TPM_RC_SUCCESS) {
121
            printf("TPM2_Init failed 0x%x: %s\n", rc,
122
                wolfTPM2_GetRCString(rc));
123
            return rc;
124
        }
125
    }
126
    else {
127
        rc = TPM_RC_SUCCESS; /* clear TryOpen sentinel */
128
    }
129
    /* Fall through to Startup/SelfTest below */
130
131
#elif defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \
132
    defined(WOLFTPM_OPTEE) || defined(WOLFTPM_WINAPI)
133
    rc = TPM2_Init_minimal(ctx);
134
    /* Using standard file I/O for the Linux TPM device */
135
    (void)ioCb;
136
    (void)userCtx;
137
    (void)timeoutTries;
138
#else
139
    rc = TPM2_Init_ex(ctx, ioCb, userCtx, timeoutTries);
140
#endif
141
    if (rc != TPM_RC_SUCCESS) {
142
    #ifdef DEBUG_WOLFTPM
143
        printf("TPM2_Init failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc));
144
    #endif
145
        return rc;
146
    }
147
#ifdef DEBUG_WOLFTPM
148
    printf("TPM2: Caps 0x%08x, Did 0x%04x, Vid 0x%04x, Rid 0x%2x \n",
149
        ctx->caps,
150
        ctx->did_vid >> 16,
151
        ctx->did_vid & 0xFFFF,
152
        ctx->rid);
153
#endif
154
155
#if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_WINAPI)
156
    /* startup */
157
    XMEMSET(&startupIn, 0, sizeof(Startup_In));
158
    startupIn.startupType = TPM_SU_CLEAR;
159
    rc = TPM2_Startup(&startupIn);
160
    if (rc != TPM_RC_SUCCESS &&
161
        rc != TPM_RC_INITIALIZE /* TPM_RC_INITIALIZE = Already started */ &&
162
        rc != TPM_RC_UPGRADE /* TPM_RC_UPGRADE = In firmware upgrade mode */ ) {
163
    #ifdef WOLFTPM_SPDM
164
        if (rc == (int)TPM_RC_DISABLED) {
165
            /* When SPDM-only mode is active on the TPM, TPM2_Startup returns
166
             * TPM_RC_DISABLED. This is expected - SPDM commands bypass the
167
             * normal TPM command path and work over raw SPI. */
168
            ctx->spdmOnlyDetected = 1;
169
        #ifdef DEBUG_WOLFTPM
170
            printf("TPM2_Startup: TPM_RC_DISABLED (SPDM-only mode active, "
171
                   "this is expected)\n");
172
        #endif
173
        }
174
        else
175
    #endif /* WOLFTPM_SPDM */
176
        {
177
        #ifdef DEBUG_WOLFTPM
178
            printf("TPM2_Startup failed %d: %s\n", rc,
179
                   wolfTPM2_GetRCString(rc));
180
        #endif
181
        #ifdef WOLFTPM_SWTPM
182
            TPM2_SwtpmClose(ctx);
183
        #endif
184
            return rc;
185
        }
186
    }
187
    /* Return upgrade status so caller can handle appropriately */
188
    if (rc == TPM_RC_UPGRADE) {
189
    #ifdef DEBUG_WOLFTPM
190
        printf("TPM2_Startup: TPM is in firmware upgrade mode\n");
191
    #endif
192
        return rc;
193
    }
194
#ifdef DEBUG_WOLFTPM
195
    if (rc == TPM_RC_SUCCESS || rc == TPM_RC_INITIALIZE) {
196
        printf("TPM2_Startup pass\n");
197
    }
198
#endif
199
200
#if defined(WOLFTPM_MICROCHIP) || defined(WOLFTPM_PERFORM_SELFTEST)
201
    /* Do full self-test (Chips such as ATTPM20 require this before some operations) */
202
    XMEMSET(&selfTest, 0, sizeof(selfTest));
203
    selfTest.fullTest = YES;
204
    rc = TPM2_SelfTest(&selfTest);
205
    if (rc != TPM_RC_SUCCESS) {
206
    #ifdef WOLFTPM_SPDM
207
        if (rc == (int)TPM_RC_DISABLED) {
208
            /* SPDM-only mode active - SelfTest not needed */
209
        #ifdef DEBUG_WOLFTPM
210
            printf("TPM2_SelfTest: TPM_RC_DISABLED (SPDM-only mode, "
211
                   "expected)\n");
212
        #endif
213
            rc = TPM_RC_SUCCESS;
214
        }
215
        else
216
    #endif /* WOLFTPM_SPDM */
217
        {
218
        #ifdef DEBUG_WOLFTPM
219
            printf("TPM2_SelfTest failed 0x%x: %s\n", rc,
220
                   TPM2_GetRCString(rc));
221
        #endif
222
        #ifdef WOLFTPM_SWTPM
223
            TPM2_SwtpmClose(ctx);
224
        #endif
225
            return rc;
226
        }
227
    }
228
#ifdef DEBUG_WOLFTPM
229
    if (rc == TPM_RC_SUCCESS) {
230
        printf("TPM2_SelfTest pass\n");
231
    }
232
#endif
233
#else
234
    rc = TPM_RC_SUCCESS;
235
#endif /* WOLFTPM_MICROCHIP || WOLFTPM_PERFORM_SELFTEST */
236
#endif /* !WOLFTPM_LINUX_DEV && !WOLFTPM_WINAPI */
237
238
    return rc;
239
}
240
241
/* Single-shot API for testing access to hardware and optionally return capabilities */
242
int wolfTPM2_Test(TPM2HalIoCb ioCb, void* userCtx, WOLFTPM2_CAPS* caps)
243
{
244
    int rc;
245
    TPM2_CTX* current_ctx;
246
    TPM2_CTX ctx;
247
248
    /* Backup active TPM context */
249
    current_ctx = TPM2_GetActiveCtx();
250
251
    /* Perform startup and test device */
252
    rc = wolfTPM2_Init_ex(&ctx, ioCb, userCtx, TPM_STARTUP_TEST_TRIES);
253
    if (rc != TPM_RC_SUCCESS) {
254
        TPM2_Cleanup(&ctx);
255
        /* Restore the active context before ctx leaves scope. */
256
        TPM2_SetActiveCtx(current_ctx);
257
        return rc;
258
    }
259
260
    /* Optionally get and return capabilities */
261
    if (caps) {
262
        rc = wolfTPM2_GetCapabilities_NoDev(caps);
263
    }
264
265
    /* Perform cleanup */
266
    TPM2_Cleanup(&ctx);
267
268
    /* Restore original context */
269
    TPM2_SetActiveCtx(current_ctx);
270
271
    return rc;
272
}
273
274
/* Initialization has not exposed a device to the caller yet, so do not use
275
 * wolfTPM2_Cleanup_ex() here: it unregisters the did_vid crypto callback even
276
 * though this initialization path never registered one. */
277
static void wolfTPM2_InitFailureCleanup(WOLFTPM2_DEV* dev)
278
{
279
    if (dev == NULL) {
280
        return;
281
    }
282
283
#ifdef WOLFTPM_SPDM
284
    if (dev->spdmCtx != NULL && dev->spdmCtx->spdmCtx != NULL &&
285
        wolfSPDM_IsConnected(dev->spdmCtx->spdmCtx)) {
286
        (void)wolfTPM2_SpdmDisconnect(dev);
287
    }
288
    (void)wolfTPM2_SpdmCleanup(dev);
289
#endif
290
291
    (void)TPM2_Cleanup(&dev->ctx);
292
    TPM2_ForceZero(dev->session, sizeof(dev->session));
293
    dev->ctx.session = NULL;
294
}
295
296
static int wolfTPM2_InitDevice(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb,
297
    void* userCtx)
298
{
299
    int rc;
300
301
    if (dev == NULL)
302
        return BAD_FUNC_ARG;
303
304
    XMEMSET(dev, 0, sizeof(WOLFTPM2_DEV));
305
306
    rc = wolfTPM2_Init_ex(&dev->ctx, ioCb, userCtx, TPM_TIMEOUT_TRIES);
307
    if (rc != TPM_RC_SUCCESS) {
308
        /* TPM_RC_UPGRADE leaves a usable active context so callers can
309
         * continue the vendor firmware-recovery flow. */
310
        if (rc != TPM_RC_UPGRADE) {
311
            wolfTPM2_InitFailureCleanup(dev);
312
        }
313
        return rc;
314
    }
315
316
    /* define the default session auth */
317
    XMEMSET(dev->session, 0, sizeof(dev->session));
318
    wolfTPM2_SetAuthPassword(dev, 0, NULL);
319
320
    return TPM_RC_SUCCESS;
321
}
322
323
#if defined(WOLFTPM_SPDM) && (defined(WOLFTPM_SPDM_PSK) || \
324
    defined(WOLFTPM_SPDM_TCG))
325
static int wolfTPM2_RetryStartupOverSpdm(WOLFTPM2_DEV* dev)
326
{
327
    int rc;
328
    Startup_In startupIn;
329
330
    if (!dev->ctx.spdmOnlyDetected) {
331
        return TPM_RC_SUCCESS;
332
    }
333
334
    /* Retry TPM2_Startup over the SPDM encrypted channel. */
335
    XMEMSET(&startupIn, 0, sizeof(startupIn));
336
    startupIn.startupType = TPM_SU_CLEAR;
337
    rc = TPM2_Startup(&startupIn);
338
    if (rc == TPM_RC_INITIALIZE) {
339
        rc = TPM_RC_SUCCESS;
340
    }
341
#ifdef DEBUG_WOLFTPM
342
    if (rc != TPM_RC_SUCCESS) {
343
        printf("TPM2_Startup over SPDM failed: 0x%x\n", rc);
344
    }
345
#endif
346
    return rc;
347
}
348
#endif /* WOLFTPM_SPDM and a credentialed transport */
349
350
#if defined(WOLFTPM_SPDM) && defined(WOLFTPM_SPDM_TCG)
351
static int wolfTPM2_SpdmConnectIdentityMode(WOLFTPM2_DEV* dev,
352
    WOLFSPDM_MODE mode, const byte* reqPubKey, word32 reqPubKeySz,
353
    const byte* reqPrivKey, word32 reqPrivKeySz);
354
355
static int wolfTPM2_IdentityModeSupported(WOLFSPDM_MODE mode)
356
{
357
    if (mode == WOLFSPDM_MODE_AUTO || mode == WOLFSPDM_MODE_TCG) {
358
        return 1;
359
    }
360
#ifdef WOLFSPDM_NUVOTON
361
    if (mode == WOLFSPDM_MODE_NUVOTON) {
362
        return 1;
363
    }
364
#endif
365
#ifdef WOLFSPDM_NATIONS
366
    if (mode == WOLFSPDM_MODE_NATIONS) {
367
        return 1;
368
    }
369
#endif
370
    return 0;
371
}
372
373
WOLFTPM_TEST_API int wolfTPM2_SpdmModeFromDidVid(UINT32 didVid,
374
    WOLFSPDM_MODE* mode)
375
{
376
    UINT16 vendorId;
377
378
    if (mode == NULL) {
379
        return BAD_FUNC_ARG;
380
    }
381
    *mode = WOLFSPDM_MODE_AUTO;
382
    vendorId = (UINT16)(didVid & 0xFFFFU);
383
#ifdef WOLFSPDM_NUVOTON
384
    if (vendorId == TPM_VENDOR_NUVOTON) {
385
        *mode = WOLFSPDM_MODE_NUVOTON;
386
        return TPM_RC_SUCCESS;
387
    }
388
#endif
389
#ifdef WOLFSPDM_NATIONS
390
    if (vendorId == TPM_VENDOR_NATIONTECH) {
391
        *mode = WOLFSPDM_MODE_NATIONS;
392
        return TPM_RC_SUCCESS;
393
    }
394
#endif
395
#ifdef WOLFSPDM_INFINEON
396
    if (vendorId == TPM_VENDOR_INFINEON) {
397
        *mode = WOLFSPDM_MODE_TCG;
398
        return TPM_RC_SUCCESS;
399
    }
400
#endif
401
    (void)vendorId;
402
    return WOLFSPDM_E_BAD_STATE;
403
}
404
405
static int wolfTPM2_SpdmConnectIdentity(WOLFTPM2_DEV* dev,
406
    WOLFSPDM_MODE mode)
407
{
408
    int rc;
409
410
    if (mode == WOLFSPDM_MODE_AUTO) {
411
#if (defined(WOLFSPDM_NUVOTON) && defined(WOLFSPDM_NATIONS)) || \
412
    (defined(WOLFSPDM_INFINEON) && (defined(WOLFSPDM_NUVOTON) || \
413
        defined(WOLFSPDM_NATIONS)))
414
        /* Multiple adapters: direct TIS exposes DID/VID. Other transports
415
         * require an explicit mode rather than guessing a vendor. */
416
        rc = wolfTPM2_SpdmModeFromDidVid(dev->ctx.did_vid, &mode);
417
        if (rc != TPM_RC_SUCCESS) {
418
            return rc;
419
        }
420
#elif defined(WOLFSPDM_NUVOTON)
421
        mode = WOLFSPDM_MODE_NUVOTON;
422
#elif defined(WOLFSPDM_NATIONS)
423
        mode = WOLFSPDM_MODE_NATIONS;
424
#else
425
        mode = WOLFSPDM_MODE_TCG;
426
#endif
427
    }
428
    rc = wolfTPM2_SpdmConnectIdentityMode(dev, mode, NULL, 0, NULL, 0);
429
    return rc;
430
}
431
432
int wolfTPM2_InitWithSpdmKey_ex(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb,
433
    void* userCtx, const byte* rspPubKey, word32 rspPubKeySz,
434
    WOLFSPDM_MODE mode)
435
{
436
    int rc;
437
438
    if (dev == NULL || rspPubKey == NULL ||
439
        rspPubKeySz != WOLFSPDM_ECC_POINT_SIZE ||
440
        !wolfTPM2_IdentityModeSupported(mode)) {
441
        return BAD_FUNC_ARG;
442
    }
443
444
    rc = wolfTPM2_InitDevice(dev, ioCb, userCtx);
445
    if (rc != TPM_RC_SUCCESS) {
446
        return rc;
447
    }
448
449
    /* A supplied key opts into authenticated transport regardless of the
450
     * cleartext startup result. */
451
    rc = wolfTPM2_SpdmInit(dev);
452
    if (rc == 0) {
453
        rc = wolfTPM2_SpdmSetResponderPubKey(dev, rspPubKey, rspPubKeySz);
454
    }
455
    if (rc == 0) {
456
        rc = wolfTPM2_SpdmConnectIdentity(dev, mode);
457
    }
458
    if (rc != 0) {
459
    #ifdef DEBUG_WOLFTPM
460
        printf("SPDM auto-connect failed: %d\n", rc);
461
    #endif
462
        wolfTPM2_InitFailureCleanup(dev);
463
        return rc;
464
    }
465
466
#ifdef DEBUG_WOLFTPM
467
    printf("SPDM session established (auto), SessionID=0x%08x\n",
468
        wolfTPM2_SpdmGetSessionId(dev));
469
#endif
470
471
    rc = wolfTPM2_RetryStartupOverSpdm(dev);
472
    if (rc != TPM_RC_SUCCESS) {
473
        wolfTPM2_InitFailureCleanup(dev);
474
    }
475
    return rc;
476
}
477
#endif /* WOLFTPM_SPDM && WOLFTPM_SPDM_TCG */
478
479
int wolfTPM2_Init(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
480
{
481
    int rc;
482
483
    rc = wolfTPM2_InitDevice(dev, ioCb, userCtx);
484
#ifdef WOLFTPM_SPDM
485
    if (rc == TPM_RC_SUCCESS && dev->ctx.spdmOnlyDetected) {
486
    #ifdef DEBUG_WOLFTPM
487
        printf("SPDM-only mode requires a trusted responder key or PSK\n");
488
    #endif
489
        wolfTPM2_InitFailureCleanup(dev);
490
        rc = WOLFSPDM_E_BAD_STATE;
491
    }
492
#endif
493
    return rc;
494
}
495
496
#if defined(WOLFTPM_SPDM) && defined(WOLFTPM_SPDM_TCG)
497
int wolfTPM2_InitWithSpdmKey(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb,
498
    void* userCtx, const byte* rspPubKey, word32 rspPubKeySz)
499
{
500
    if (rspPubKey == NULL || rspPubKeySz != WOLFSPDM_ECC_POINT_SIZE) {
501
        return BAD_FUNC_ARG;
502
    }
503
504
    return wolfTPM2_InitWithSpdmKey_ex(dev, ioCb, userCtx, rspPubKey,
505
        rspPubKeySz, WOLFSPDM_MODE_AUTO);
506
}
507
#endif
508
509
#if defined(WOLFTPM_SPDM) && defined(WOLFTPM_SPDM_PSK)
510
int wolfTPM2_InitWithSpdmPsk(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb,
511
    void* userCtx, const byte* psk, word32 pskSz, const byte* hint,
512
    word32 hintSz)
513
{
514
    int rc;
515
516
    if (dev == NULL || psk == NULL || pskSz == 0U ||
517
        (hint == NULL && hintSz != 0U)) {
518
        return BAD_FUNC_ARG;
519
    }
520
521
    rc = wolfTPM2_InitDevice(dev, ioCb, userCtx);
522
    if (rc != TPM_RC_SUCCESS) {
523
        return rc;
524
    }
525
    rc = wolfTPM2_SpdmInit(dev);
526
    if (rc == TPM_RC_SUCCESS) {
527
        rc = wolfTPM2_SpdmConnectPsk(dev, psk, pskSz, hint, hintSz);
528
    }
529
    if (rc == TPM_RC_SUCCESS) {
530
        rc = wolfTPM2_RetryStartupOverSpdm(dev);
531
    }
532
    if (rc != TPM_RC_SUCCESS) {
533
        wolfTPM2_InitFailureCleanup(dev);
534
    }
535
    return rc;
536
}
537
#endif /* WOLFTPM_SPDM && WOLFTPM_SPDM_PSK */
538
539
#ifndef WOLFTPM2_NO_HEAP
540
WOLFTPM2_DEV* wolfTPM2_New(void)
541
{
542
    WOLFTPM2_DEV *dev = (WOLFTPM2_DEV*)XMALLOC(
543
        sizeof(WOLFTPM2_DEV), NULL, DYNAMIC_TYPE_TMP_BUFFER);
544
    if (dev != NULL) {
545
        if (wolfTPM2_Init(dev, TPM2_IoCb, NULL) != TPM_RC_SUCCESS) {
546
            TPM2_ForceZero(dev, sizeof(WOLFTPM2_DEV));
547
            XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER);
548
            dev = NULL;
549
        }
550
    }
551
    return dev;
552
}
553
int wolfTPM2_Free(WOLFTPM2_DEV *dev)
554
{
555
    if (dev != NULL) {
556
        wolfTPM2_Cleanup(dev);
557
        /* Holds session auth values and the command buffer */
558
        TPM2_ForceZero(dev, sizeof(WOLFTPM2_DEV));
559
        XFREE(dev, NULL, DYNAMIC_TYPE_TMP_BUFFER);
560
    }
561
    return TPM_RC_SUCCESS;
562
}
563
564
WOLFTPM2_KEYBLOB* wolfTPM2_NewKeyBlob(void)
565
{
566
    WOLFTPM2_KEYBLOB* blob = (WOLFTPM2_KEYBLOB*)XMALLOC(
567
        sizeof(WOLFTPM2_KEYBLOB), NULL, DYNAMIC_TYPE_TMP_BUFFER);
568
    if (blob != NULL) {
569
        XMEMSET(blob, 0, sizeof(WOLFTPM2_KEYBLOB));
570
    }
571
    return blob;
572
}
573
int wolfTPM2_FreeKeyBlob(WOLFTPM2_KEYBLOB* blob)
574
{
575
    if (blob != NULL) {
576
        TPM2_ForceZero(blob, sizeof(WOLFTPM2_KEYBLOB));
577
        XFREE(blob, NULL, DYNAMIC_TYPE_TMP_BUFFER);
578
    }
579
    return TPM_RC_SUCCESS;
580
}
581
582
TPMT_PUBLIC* wolfTPM2_NewPublicTemplate(void)
583
{
584
    TPMT_PUBLIC* PublicTemplate = (TPMT_PUBLIC*)XMALLOC(
585
        sizeof(TPMT_PUBLIC), NULL, DYNAMIC_TYPE_TMP_BUFFER);
586
    if (PublicTemplate != NULL) {
587
        XMEMSET(PublicTemplate, 0, sizeof(TPMT_PUBLIC));
588
    }
589
    return PublicTemplate;
590
}
591
int wolfTPM2_FreePublicTemplate(TPMT_PUBLIC* PublicTemplate)
592
{
593
    if (PublicTemplate != NULL) {
594
        TPM2_ForceZero(PublicTemplate, sizeof(TPMT_PUBLIC));
595
        XFREE(PublicTemplate, NULL, DYNAMIC_TYPE_TMP_BUFFER);
596
    }
597
    return TPM_RC_SUCCESS;
598
}
599
600
WOLFTPM2_KEY* wolfTPM2_NewKey(void)
601
{
602
    WOLFTPM2_KEY* key = (WOLFTPM2_KEY*)XMALLOC(
603
        sizeof(WOLFTPM2_KEY), NULL, DYNAMIC_TYPE_TMP_BUFFER);
604
    if (key != NULL) {
605
        XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
606
    }
607
    return key;
608
}
609
int wolfTPM2_FreeKey(WOLFTPM2_KEY* key)
610
{
611
    if (key != NULL) {
612
        TPM2_ForceZero(key, sizeof(WOLFTPM2_KEY));
613
        XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
614
    }
615
    return TPM_RC_SUCCESS;
616
}
617
618
WOLFTPM2_SESSION* wolfTPM2_NewSession(void)
619
{
620
    WOLFTPM2_SESSION* session = (WOLFTPM2_SESSION*)XMALLOC(
621
        sizeof(WOLFTPM2_SESSION), NULL, DYNAMIC_TYPE_TMP_BUFFER);
622
    if (session != NULL) {
623
        XMEMSET(session, 0, sizeof(WOLFTPM2_SESSION));
624
    }
625
    return session;
626
}
627
int wolfTPM2_FreeSession(WOLFTPM2_SESSION* session)
628
{
629
    if (session != NULL) {
630
        TPM2_ForceZero(session, sizeof(WOLFTPM2_SESSION));
631
        XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
632
    }
633
    return TPM_RC_SUCCESS;
634
}
635
636
#ifdef WOLFTPM2_CERT_GEN
637
WOLFTPM2_CSR* wolfTPM2_NewCSR(void)
638
{
639
    WOLFTPM2_CSR* csr = (WOLFTPM2_CSR*)XMALLOC(
640
        sizeof(WOLFTPM2_CSR), NULL, DYNAMIC_TYPE_TMP_BUFFER);
641
    if (csr != NULL) {
642
        XMEMSET(csr, 0, sizeof(WOLFTPM2_CSR));
643
        if (wc_InitCert(&csr->req) != 0) {
644
            XFREE(csr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
645
            csr = NULL;
646
        }
647
        if (csr) {
648
            csr->req.version = 0; /* per RFC2986 : CSR version should be 0 */
649
        }
650
    }
651
    return csr;
652
}
653
int wolfTPM2_FreeCSR(WOLFTPM2_CSR* csr)
654
{
655
    if (csr != NULL) {
656
        TPM2_ForceZero(csr, sizeof(WOLFTPM2_CSR));
657
        XFREE(csr, NULL, DYNAMIC_TYPE_TMP_BUFFER);
658
    }
659
    return TPM_RC_SUCCESS;
660
}
661
#endif /* WOLFTPM2_CERT_GEN */
662
663
#endif /* !WOLFTPM2_NO_HEAP */
664
665
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKey(WOLFTPM2_KEY* key)
666
{
667
    return (key != NULL) ? &key->handle : NULL;
668
}
669
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromKeyBlob(WOLFTPM2_KEYBLOB* keyBlob)
670
{
671
    return (keyBlob != NULL) ? &keyBlob->handle : NULL;
672
}
673
674
WOLFTPM2_HANDLE* wolfTPM2_GetHandleRefFromSession(WOLFTPM2_SESSION* session)
675
{
676
    return (session != NULL) ? &session->handle : NULL;
677
}
678
679
TPM_HANDLE wolfTPM2_GetHandleValue(WOLFTPM2_HANDLE* handle)
680
{
681
    TPM_HANDLE hndl = 0;
682
    if (handle)
683
        hndl = handle->hndl;
684
    return hndl;
685
}
686
687
int wolfTPM2_GetKeyBlobAsBuffer(byte *buffer, word32 bufferSz,
688
    WOLFTPM2_KEYBLOB* key)
689
{
690
    int rc = 0;
691
    int sz = 0;
692
    byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
693
    int pubAreaSize;
694
695
    if (key == NULL) {
696
        return BAD_FUNC_ARG;
697
    }
698
699
    /* publicArea is encoded format. Eliminates empty fields, saves space. */
700
    rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer),
701
        &pubAreaSize, &key->pub);
702
    if (rc != TPM_RC_SUCCESS) {
703
        return rc;
704
    }
705
706
    if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size))) {
707
#ifdef DEBUG_WOLFTPM
708
        printf("Sanity check for publicArea size failed\n");
709
#endif
710
        return BUFFER_E;
711
    }
712
713
    /* calculate actual size */
714
    sz = sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size +
715
        sizeof(UINT16) + key->priv.size;
716
717
    /* return size only */
718
    if (buffer == NULL) {
719
        return sz;
720
721
    }
722
    if ((int)bufferSz < sz) {
723
        return BUFFER_E;
724
    }
725
726
    /* Write size marker for the public part */
727
    XMEMCPY(buffer, &key->pub.size, sizeof(key->pub.size));
728
    sz = sizeof(key->pub.size);
729
730
    /* Write the public part with bytes aligned */
731
    XMEMCPY(buffer + sz, pubAreaBuffer, sizeof(UINT16) + key->pub.size);
732
    sz += sizeof(UINT16) + key->pub.size;
733
734
    /* Write the private part, size marker is included */
735
    XMEMCPY(buffer + sz, &key->priv, sizeof(UINT16) + key->priv.size);
736
    sz += sizeof(UINT16) + key->priv.size;
737
738
#ifdef WOLFTPM_DEBUG_VERBOSE
739
    printf("Get KeyBlob: %d bytes\n", (int)sz);
740
    TPM2_PrintBin(buffer, sz);
741
#endif
742
743
    return sz;
744
}
745
746
int wolfTPM2_GetKeyBlobAsSeparateBuffers(byte* pubBuffer, word32* pubBufferSz,
747
    byte* privBuffer, word32* privBufferSz, WOLFTPM2_KEYBLOB* key)
748
{
749
    int rc = 0;
750
    byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
751
    int pubAreaSize;
752
753
    if (key == NULL || pubBufferSz == NULL || privBufferSz == NULL) {
754
        return BAD_FUNC_ARG;
755
    }
756
757
    /* publicArea is encoded format. Eliminates empty fields, saves space. */
758
    rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer),
759
        &pubAreaSize, &key->pub);
760
    if (rc != TPM_RC_SUCCESS) {
761
        return rc;
762
    }
763
764
    if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size))) {
765
#ifdef DEBUG_WOLFTPM
766
        printf("Sanity check for publicArea size failed\n");
767
#endif
768
        return BUFFER_E;
769
    }
770
771
    if (pubBuffer == NULL || privBuffer == NULL) {
772
        *privBufferSz = sizeof(UINT16) + key->priv.size;
773
        *pubBufferSz = sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size;
774
        return LENGTH_ONLY_E;
775
    }
776
777
    if (*pubBufferSz < sizeof(key->pub.size) + sizeof(UINT16) + key->pub.size ||
778
        *privBufferSz < sizeof(UINT16) + key->priv.size) {
779
        return BUFFER_E;
780
    }
781
782
    *pubBufferSz = 0;
783
    *privBufferSz = 0;
784
785
    /* Write size marker for the public part */
786
    XMEMCPY(pubBuffer, &key->pub.size, sizeof(key->pub.size));
787
    *pubBufferSz += sizeof(key->pub.size);
788
789
    /* Write the public part with bytes aligned */
790
    XMEMCPY(pubBuffer + *pubBufferSz, pubAreaBuffer, sizeof(UINT16) +
791
        key->pub.size);
792
    *pubBufferSz += sizeof(UINT16) + key->pub.size;
793
794
    /* Write the private part, size marker is included */
795
    XMEMCPY(privBuffer, &key->priv, sizeof(UINT16) + key->priv.size);
796
    *privBufferSz += sizeof(UINT16) + key->priv.size;
797
798
#ifdef WOLFTPM_DEBUG_VERBOSE
799
    printf("Get KeyBlob public: %d bytes\n", (int)*pubBufferSz);
800
    TPM2_PrintBin(pubBuffer, *pubBufferSz);
801
802
    printf("Get KeyBlob private: %d bytes\n", (int)*privBufferSz);
803
    TPM2_PrintBin(privBuffer, *privBufferSz);
804
#endif
805
806
    return TPM_RC_SUCCESS;
807
}
808
809
int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key, byte *buffer,
810
                                  word32 bufferSz)
811
{
812
    int rc = 0;
813
    byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
814
    int pubAreaSize;
815
    byte *runner = buffer;
816
    size_t done_reading = 0;
817
818
    if ((key == NULL) || (buffer == NULL) || (bufferSz <= 0)) {
819
        return BAD_FUNC_ARG;
820
    }
821
822
    XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB));
823
824
#ifdef WOLFTPM_DEBUG_VERBOSE
825
    printf("Set KeyBlob: %d bytes\n", (int)bufferSz);
826
    TPM2_PrintBin(buffer, bufferSz);
827
#endif
828
829
    if (bufferSz < done_reading + sizeof(key->pub.size)) {
830
#ifdef DEBUG_WOLFTPM
831
        printf("Buffer size check failed (%d)\n", bufferSz);
832
#endif
833
        return BUFFER_E;
834
    }
835
836
    XMEMCPY(&key->pub.size, runner, sizeof(key->pub.size));
837
    runner += sizeof(key->pub.size);
838
    done_reading += sizeof(key->pub.size);
839
840
    /* Validate pub.size fits in destination buffer */
841
    if (sizeof(UINT16) + key->pub.size > sizeof(pubAreaBuffer)) {
842
#ifdef DEBUG_WOLFTPM
843
        printf("Public area size too large (%u)\n", key->pub.size);
844
#endif
845
        return BUFFER_E;
846
    }
847
848
    if (bufferSz < done_reading + sizeof(UINT16) + key->pub.size) {
849
#ifdef DEBUG_WOLFTPM
850
        printf("Buffer size check failed (%d)\n", bufferSz);
851
#endif
852
        return BUFFER_E;
853
    }
854
855
    XMEMCPY(pubAreaBuffer, runner, sizeof(UINT16) + key->pub.size);
856
    runner += sizeof(UINT16) + key->pub.size;
857
    done_reading += sizeof(UINT16) + key->pub.size;
858
859
    /* Decode the byte stream into a publicArea structure ready for use */
860
    rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
861
        (word32)(sizeof(UINT16) + key->pub.size), &pubAreaSize);
862
    if (rc != TPM_RC_SUCCESS) {
863
        return rc;
864
    }
865
866
    if (bufferSz < done_reading + sizeof(key->priv.size)) {
867
#ifdef DEBUG_WOLFTPM
868
        printf("Buffer size check failed (%d)\n", bufferSz);
869
#endif
870
        return BUFFER_E;
871
    }
872
873
    XMEMCPY(&key->priv.size, runner, sizeof(key->priv.size));
874
    runner += sizeof(key->priv.size);
875
    done_reading += sizeof(key->priv.size);
876
877
    /* Validate priv.size fits in destination buffer */
878
    if (key->priv.size > sizeof(key->priv.buffer)) {
879
#ifdef DEBUG_WOLFTPM
880
        printf("Private area size too large (%u)\n", key->priv.size);
881
#endif
882
        return BUFFER_E;
883
    }
884
885
    if (bufferSz < done_reading + key->priv.size) {
886
#ifdef DEBUG_WOLFTPM
887
        printf("Buffer size check failed (%d)\n", bufferSz);
888
#endif
889
        return BUFFER_E;
890
    }
891
892
    XMEMCPY(key->priv.buffer, runner, key->priv.size);
893
    done_reading += key->priv.size;
894
895
    if (done_reading != bufferSz) {
896
#ifdef DEBUG_WOLFTPM
897
        printf("Extra data left in buffer (%d!=%d)\n",
898
            bufferSz, (word32)done_reading);
899
#endif
900
        TPM2_ForceZero(key, sizeof(*key));
901
        return BUFFER_E;
902
    }
903
904
    return TPM_RC_SUCCESS;
905
}
906
907
int wolfTPM2_SetKeyAuthPassword(WOLFTPM2_KEY *key, const byte* auth,
908
                               int authSz)
909
{
910
    if (key == NULL ||
911
        (auth == NULL && authSz > 0) ||
912
        (auth != NULL && authSz < 0)) {
913
        return BAD_FUNC_ARG;
914
    }
915
916
    /* Note: returns error instead of truncating for security (v3.11+) */
917
    if (authSz > (int)sizeof(key->handle.auth.buffer)) {
918
        return BUFFER_E;
919
    }
920
    if (auth != NULL) {
921
        XMEMMOVE(key->handle.auth.buffer, auth, authSz);
922
        if ((word32)authSz < sizeof(key->handle.auth.buffer)) {
923
            TPM2_ForceZero(&key->handle.auth.buffer[authSz],
924
                (word32)sizeof(key->handle.auth.buffer) - (word32)authSz);
925
        }
926
    }
927
    else {
928
        TPM2_ForceZero(key->handle.auth.buffer,
929
            sizeof(key->handle.auth.buffer));
930
    }
931
    key->handle.auth.size = (UINT16)authSz;
932
933
    return TPM_RC_SUCCESS;
934
}
935
936
/* Access already started TPM module */
937
int wolfTPM2_OpenExisting(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx)
938
{
939
    int rc;
940
941
    if (dev == NULL) {
942
        return BAD_FUNC_ARG;
943
    }
944
945
    XMEMSET(dev, 0, sizeof(WOLFTPM2_DEV));
946
947
    /* The 0 startup indicates use existing locality */
948
    rc = wolfTPM2_Init_ex(&dev->ctx, ioCb, userCtx, 0);
949
    if (rc != TPM_RC_SUCCESS) {
950
        return rc;
951
    }
952
953
    /* define the default session auth */
954
    XMEMSET(dev->session, 0, sizeof(dev->session));
955
    wolfTPM2_SetAuthPassword(dev, 0, NULL);
956
957
    return rc;
958
}
959
960
int wolfTPM2_GetTpmDevId(WOLFTPM2_DEV* dev)
961
{
962
    if (dev == NULL) {
963
        return BAD_FUNC_ARG;
964
    }
965
966
    return (int)dev->ctx.did_vid; /* return something besides INVALID_DEVID */
967
}
968
969
int wolfTPM2_SelfTest(WOLFTPM2_DEV* dev)
970
{
971
    int rc;
972
    SelfTest_In selfTest;
973
974
    if (dev == NULL)
975
        return BAD_FUNC_ARG;
976
977
    /* Full self test */
978
    XMEMSET(&selfTest, 0, sizeof(selfTest));
979
    selfTest.fullTest = YES;
980
    rc = TPM2_SelfTest(&selfTest);
981
#ifdef WOLFTPM_WINAPI
982
    if (rc == (int)TPM_E_COMMAND_BLOCKED) { /* 0x80280400 */
983
    #ifdef DEBUG_WOLFTPM
984
        printf("TPM2_SelfTest not allowed on Windows TBS (err 0x%x)\n", rc);
985
    #endif
986
        rc = TPM_RC_SUCCESS; /* report success */
987
    }
988
#endif
989
    if (rc != TPM_RC_SUCCESS) {
990
    #ifdef DEBUG_WOLFTPM
991
        printf("TPM2_SelfTest failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
992
    #endif
993
        return rc;
994
    }
995
#ifdef DEBUG_WOLFTPM
996
    printf("TPM2_SelfTest pass\n");
997
#endif
998
999
    return rc;
1000
}
1001
1002
/* Infineon SLB9670
1003
 *  TPM_PT_MANUFACTURER     "IFX"
1004
 *  TPM_PT_VENDOR_STRING_1  "SLB9"
1005
 *  TPM_PT_VENDOR_STRING_2  "670 "
1006
 *  TPM_PT_FIRMWARE_VERSION_1 0x00070055 = v7.85
1007
 *  TPM_PT_FIRMWARE_VERSION_2 0x0011CB02
1008
 *      Byte  1: reserved.
1009
 *      Bytes 2-3: build num = 11CB,
1010
 *      Byte  4: 0x00 (TPM CC), 0x02 (no CC)
1011
 *  TPM_PT_MODES = Bit 0 = FIPS_140_2 (spec v1.38+)
1012
 *                 Bit 1 = FIPS_140_3 (spec v1.83+)
1013
 */
1014
1015
#ifdef WOLFTPM_IFX_FW_UPGRADE
1016
    /* Infineon SLB9672 or SLB9673 Firmware Upgrade support */
1017
    #define TPM_PT_VENDOR_FIX 0x80000000
1018
    #define TPM_PT_VENDOR_FIX_FU_COUNTER        (TPM_PT_VENDOR_FIX + 3)
1019
    #define TPM_PT_VENDOR_FIX_FU_COUNTER_SAME   (TPM_PT_VENDOR_FIX + 4)
1020
    #define TPM_PT_VENDOR_FIX_FU_OPERATION_MODE (TPM_PT_VENDOR_FIX + 7)
1021
    #define TPM_PT_VENDOR_FIX_FU_KEYGROUP_ID    (TPM_PT_VENDOR_FIX + 8)
1022
#endif
1023
1024
/* ST33TP
1025
 *  TPM_PT_MANUFACTURER 0x53544D20: "STM"
1026
 *  TPM_PT_FIRMWARE_VERSION_1 TPM FW version: 0x00006400
1027
 *  TPM_PT_VENDOR_TPM_TYPE 1: TPM 2.0
1028
 *  TPM_PT_MODES: BIT 0 SET (1): indicates that the TPM is designed to
1029
 *      comply with all of the FIPS 140-2 requirements at Level 1 or higher.
1030
 *   TPM_PT_FIRMWARE_VERSION_2: ST Internal Additional Version
1031
 */
1032
int wolfTPM2_ParseCapabilities(WOLFTPM2_CAPS* caps,
1033
    TPML_TAGGED_TPM_PROPERTY* props)
1034
{
1035
    int rc = 0;
1036
    word32 i, val, len;
1037
1038
    for (i=0; i<props->count && i<MAX_TPM_PROPERTIES; i++) {
1039
        val = props->tpmProperty[i].value;
1040
        switch (props->tpmProperty[i].property) {
1041
            case TPM_PT_MANUFACTURER:
1042
                val = TPM2_Packet_SwapU32(val); /* swap for little endian */
1043
                XMEMCPY(&caps->mfgStr, &val, sizeof(UINT32));
1044
                if (XMEMCMP(&caps->mfgStr, "IFX", 3) == 0) {
1045
                    caps->mfg = TPM_MFG_INFINEON;
1046
                }
1047
                else if (XMEMCMP(&caps->mfgStr, "STM", 3) == 0) {
1048
                    caps->mfg = TPM_MFG_STM;
1049
                    caps->req_wait_state = 1;
1050
                }
1051
                else if (XMEMCMP(&caps->mfgStr, "MCHP", 4) == 0) {
1052
                    caps->mfg = TPM_MFG_MCHP;
1053
                    caps->req_wait_state = 1;
1054
                }
1055
                else if (XMEMCMP(&caps->mfgStr, "NTC", 4) == 0) {
1056
                    caps->mfg = TPM_MFG_NUVOTON;
1057
                    caps->req_wait_state = 1;
1058
                }
1059
                else if (XMEMCMP(&caps->mfgStr, "NTZ", 4) == 0) {
1060
                    caps->mfg = TPM_MFG_NATIONTECH;
1061
                    caps->req_wait_state = 1;
1062
                }
1063
                else if (XMEMCMP(&caps->mfgStr, "SEAL", 4) == 0) {
1064
                    caps->mfg = TPM_MFG_SEALSQ;
1065
                    caps->req_wait_state = 1;
1066
                }
1067
                else if (XMEMCMP(&caps->mfgStr, "MSFT", 4) == 0) {
1068
                    /* Microsoft TPM 2.0 reference implementation, used by
1069
                     * firmware TPMs rather than discrete parts (e.g. the
1070
                     * OP-TEE fTPM on NVIDIA Jetson, vendor "SSE fTPM"). The
1071
                     * vendor string, not this, identifies the platform.
1072
                     * No wait state: kernel driver, not a TIS bus. */
1073
                    caps->mfg = TPM_MFG_MSFT;
1074
                }
1075
                break;
1076
            case TPM_PT_VENDOR_STRING_1:
1077
            case TPM_PT_VENDOR_STRING_2:
1078
            case TPM_PT_VENDOR_STRING_3:
1079
            case TPM_PT_VENDOR_STRING_4:
1080
                val = TPM2_Packet_SwapU32(val); /* swap for little endian */
1081
                /* Offset by property, not string length: a chunk starting
1082
                 * with a zero byte would let the next one overwrite it */
1083
                len = (word32)(props->tpmProperty[i].property -
1084
                    TPM_PT_VENDOR_STRING_1) * (word32)sizeof(UINT32);
1085
                if (len + sizeof(UINT32) < sizeof(caps->vendorStr)) {
1086
                    XMEMCPY(&caps->vendorStr[len], &val, sizeof(UINT32));
1087
                }
1088
                if (val == 0x46495053) { /* FIPS */
1089
                    caps->fips140_2 = 1;
1090
                }
1091
                break;
1092
            case TPM_PT_VENDOR_TPM_TYPE:
1093
                caps->tpmType = val;
1094
                break;
1095
            case TPM_PT_FIRMWARE_VERSION_1:
1096
                caps->fwVerMajor = val >> 16;
1097
                caps->fwVerMinor = val & 0xFFFF;
1098
                break;
1099
            case TPM_PT_FIRMWARE_VERSION_2:
1100
                if (caps->mfg == TPM_MFG_INFINEON) {
1101
                    caps->fwVerVendor = val >> 8;
1102
                    caps->cc_eal4 = (val & 0x00000002) ? 0 : 1;
1103
                }
1104
                else {
1105
                    caps->fwVerVendor = val;
1106
                }
1107
                break;
1108
            case TPM_PT_MODES:
1109
                caps->fips140_2 = (val & TPMA_MODES_FIPS_140_2) ? 1 : 0;
1110
                caps->fips140_3 = (val & TPMA_MODES_FIPS_140_3) ? 1 : 0;
1111
                break;
1112
            default:
1113
                break;
1114
        }
1115
    }
1116
    return rc;
1117
}
1118
1119
#ifdef WOLFTPM_IFX_FW_UPGRADE
1120
static int tpm2_ifx_cap_vendor_get(WOLFTPM2_CAPS* cap, uint32_t property,
1121
    uint8_t* val, size_t valSz)
1122
{
1123
    int rc;
1124
    GetCapability_In  in;
1125
    GetCapability_Out out;
1126
1127
    XMEMSET(&in, 0, sizeof(in));
1128
    XMEMSET(&out, 0, sizeof(out));
1129
    in.capability = TPM_CAP_VENDOR_PROPERTY;
1130
    in.property = property;
1131
    in.propertyCount = 1;
1132
    rc = TPM2_GetCapability(&in, &out);
1133
    if (rc == TPM_RC_SUCCESS) {
1134
        TPM2B_MAX_BUFFER* buf = &out.capabilityData.data.vendor;
1135
        /* 4 bytes=count + 2 bytes=len + vendor value */
1136
        if (buf->size >= (int)(6 + valSz) && buf->buffer[3] == 1 && buf->buffer[5] == valSz) {
1137
            XMEMCPY(val, &buf->buffer[6], valSz);
1138
            if (valSz == 2) {
1139
                *((uint16_t*)val) = be16_to_cpu(*((uint16_t*)val));
1140
            }
1141
            else if (valSz == 4) {
1142
                *((uint32_t*)val) = be32_to_cpu(*((uint32_t*)val));
1143
            }
1144
        }
1145
    }
1146
    else {
1147
    #ifdef DEBUG_WOLFTPM
1148
        printf("TPM2_GetCapability vendor prop 0x%x failed 0x%x: %s\n",
1149
            property, rc, TPM2_GetRCString(rc));
1150
    #endif
1151
    }
1152
    (void)cap;
1153
    return rc;
1154
}
1155
#endif
1156
1157
static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap)
1158
{
1159
    int rc;
1160
    GetCapability_In  in;
1161
    GetCapability_Out out;
1162
1163
    if (cap == NULL)
1164
        return BAD_FUNC_ARG;
1165
1166
    /* clear caps */
1167
    XMEMSET(cap, 0, sizeof(WOLFTPM2_CAPS));
1168
1169
    /* Get Capabilities TPM_PT_MANUFACTURER thru TPM_PT_FIRMWARE_VERSION_2 */
1170
    XMEMSET(&in, 0, sizeof(in));
1171
    XMEMSET(&out, 0, sizeof(out));
1172
    in.capability = TPM_CAP_TPM_PROPERTIES;
1173
    in.property = TPM_PT_MANUFACTURER;
1174
    in.propertyCount = 8;
1175
    rc = TPM2_GetCapability(&in, &out);
1176
    if (rc != TPM_RC_SUCCESS) {
1177
    #ifdef DEBUG_WOLFTPM
1178
        printf("TPM2_GetCapability manufacture failed 0x%x: %s\n",
1179
            rc, TPM2_GetRCString(rc));
1180
    #endif
1181
        return rc;
1182
    }
1183
    rc = wolfTPM2_ParseCapabilities(cap, &out.capabilityData.data.tpmProperties);
1184
    if (rc != 0)
1185
        return rc;
1186
1187
    /* Get Capability TPM_PT_MODES */
1188
    XMEMSET(&in, 0, sizeof(in));
1189
    XMEMSET(&out, 0, sizeof(out));
1190
    in.capability = TPM_CAP_TPM_PROPERTIES;
1191
    in.property = TPM_PT_MODES;
1192
    in.propertyCount = 1;
1193
    rc = TPM2_GetCapability(&in, &out);
1194
    if (rc != TPM_RC_SUCCESS) {
1195
    #ifdef DEBUG_WOLFTPM
1196
        printf("TPM2_GetCapability modes failed 0x%x: %s\n",
1197
            rc, TPM2_GetRCString(rc));
1198
    #endif
1199
        return rc;
1200
    }
1201
    rc = wolfTPM2_ParseCapabilities(cap, &out.capabilityData.data.tpmProperties);
1202
1203
#ifdef WOLFTPM_IFX_FW_UPGRADE
1204
    /* Get vendor specific information. These properties only exist on
1205
     * Infineon parts - probing them on another manufacturer's TPM just
1206
     * produces misleading TPM_RC_VALUE errors. */
1207
    if (rc == 0 && cap->mfg == TPM_MFG_INFINEON) {
1208
        int rc_ifx;
1209
        rc_ifx = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_OPERATION_MODE,
1210
            &cap->opMode, sizeof(cap->opMode));
1211
        if (rc_ifx == 0) {
1212
            rc_ifx = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_KEYGROUP_ID,
1213
                (uint8_t*)&cap->keyGroupId, sizeof(cap->keyGroupId));
1214
        }
1215
        if (rc_ifx == 0) {
1216
            rc_ifx = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_COUNTER,
1217
                (uint8_t*)&cap->fwCounter, sizeof(cap->fwCounter));
1218
        }
1219
        if (rc_ifx == 0) {
1220
            rc_ifx = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_COUNTER_SAME,
1221
                (uint8_t*)&cap->fwCounterSame, sizeof(cap->fwCounterSame));
1222
        }
1223
        if (rc_ifx != 0) {
1224
        #ifdef DEBUG_WOLFTPM
1225
            printf("Error getting Infineon vendor capabilities 0x%x: %s\n",
1226
                rc_ifx, TPM2_GetRCString(rc_ifx));
1227
        #endif
1228
        }
1229
    }
1230
#endif
1231
1232
    return rc;
1233
}
1234
1235
int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* cap)
1236
{
1237
    if (dev == NULL)
1238
        return BAD_FUNC_ARG;
1239
1240
    return wolfTPM2_GetCapabilities_NoDev(cap);
1241
}
1242
1243
/* Report whether the TPM implements the given algorithm.
1244
 * Returns TPM_RC_SUCCESS with *isSupported set to 1 (supported) or 0 (not
1245
 * supported); on any failure a non-zero rc is returned and *isSupported is set
1246
 * to 0 so a caller that ignores the rc fails closed.
1247
 * Delegates to TPM2_IsAlgSupported(); dev is validated but unused. */
1248
int wolfTPM2_IsAlgSupported(WOLFTPM2_DEV* dev, TPM_ALG_ID alg, int* isSupported)
1249
{
1250
    if (isSupported == NULL) {
1251
        return BAD_FUNC_ARG;
1252
    }
1253
    /* fail closed: never leave the out-param indicating "supported" on error */
1254
    *isSupported = 0;
1255
    if (dev == NULL) {
1256
        return BAD_FUNC_ARG;
1257
    }
1258
    return TPM2_IsAlgSupported(alg, isSupported);
1259
}
1260
1261
int wolfTPM2_GetHandles(TPM_HANDLE handle, TPML_HANDLE* handles)
1262
{
1263
    int rc;
1264
    GetCapability_In  in;
1265
    GetCapability_Out out;
1266
#ifdef DEBUG_WOLFTPM
1267
    UINT32 i;
1268
#endif
1269
1270
    /* Get Capability TPM_CAP_HANDLES - PCR */
1271
    XMEMSET(&in, 0, sizeof(in));
1272
    in.capability = TPM_CAP_HANDLES;
1273
    in.property = handle;
1274
    in.propertyCount = MAX_CAP_HANDLES;
1275
    rc = TPM2_GetCapability(&in, &out);
1276
    if (rc != TPM_RC_SUCCESS) {
1277
    #ifdef DEBUG_WOLFTPM
1278
        printf("TPM2_GetCapability handles failed 0x%x: %s\n", rc,
1279
            TPM2_GetRCString(rc));
1280
    #endif
1281
        return rc;
1282
    }
1283
    if (handles != NULL) {
1284
        /* optionally return handles count/list */
1285
        XMEMCPY(handles, &out.capabilityData.data.handles, sizeof(TPML_HANDLE));
1286
    }
1287
    handles = &out.capabilityData.data.handles;
1288
#ifdef DEBUG_WOLFTPM
1289
    printf("Handles Cap: Start 0x%x, Count %d\n", handle, handles->count);
1290
    for (i=0; i<handles->count; i++) {
1291
        printf("\tHandle 0x%x\n", handles->handle[i]);
1292
    }
1293
#endif
1294
    return handles->count;
1295
}
1296
1297
#ifdef WOLFTPM_SPDM
1298
/* --- SPDM Secure Session Wrapper API ---
1299
 *
1300
 * These functions provide a high-level interface to wolfSPDM.
1301
 * All SPDM protocol logic is implemented in the wolfSPDM library.
1302
 */
1303
1304
int wolfTPM2_SpdmInit(WOLFTPM2_DEV* dev)
1305
{
1306
    int rc;
1307
1308
    if (dev == NULL) {
1309
        return BAD_FUNC_ARG;
1310
    }
1311
1312
    /* Already initialized (e.g., by auto-SPDM in wolfTPM2_Init) */
1313
    if (dev->spdmCtx != NULL) {
1314
        return TPM_RC_SUCCESS;
1315
    }
1316
1317
    /* Initialize inline SPDM context */
1318
    rc = wolfTPM2_SPDM_InitCtx(&dev->spdmCtxData, NULL, NULL);
1319
    if (rc != 0) {
1320
        return rc;
1321
    }
1322
1323
    rc = wolfTPM2_SPDM_SetTPMCtx(&dev->spdmCtxData, &dev->ctx);
1324
    if (rc != 0) {
1325
        wolfTPM2_SPDM_FreeCtx(&dev->spdmCtxData);
1326
        return rc;
1327
    }
1328
1329
    dev->spdmCtx = &dev->spdmCtxData;
1330
    dev->ctx.spdmCtx = dev->spdmCtx;
1331
1332
    return TPM_RC_SUCCESS;
1333
}
1334
1335
/* Validate SPDM context chain is fully initialized */
1336
#define WOLFTPM2_SPDM_CHECK_CTX(dev) \
1337
    if ((dev) == NULL || (dev)->spdmCtx == NULL || \
1338
            (dev)->spdmCtx->spdmCtx == NULL) \
1339
        return BAD_FUNC_ARG
1340
1341
int wolfTPM2_SpdmConnect(WOLFTPM2_DEV* dev)
1342
{
1343
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1344
    return wolfSPDM_Connect(dev->spdmCtx->spdmCtx);
1345
}
1346
1347
int wolfTPM2_SpdmIsConnected(WOLFTPM2_DEV* dev)
1348
{
1349
    if (dev == NULL || dev->spdmCtx == NULL || dev->spdmCtx->spdmCtx == NULL) {
1350
        return 0;
1351
    }
1352
    return wolfSPDM_IsConnected(dev->spdmCtx->spdmCtx);
1353
}
1354
1355
word32 wolfTPM2_SpdmGetSessionId(WOLFTPM2_DEV* dev)
1356
{
1357
    if (dev == NULL || dev->spdmCtx == NULL || dev->spdmCtx->spdmCtx == NULL) {
1358
        return 0;
1359
    }
1360
    return wolfSPDM_GetSessionId(dev->spdmCtx->spdmCtx);
1361
}
1362
1363
int wolfTPM2_GetCapability_SPDMSessionInfo(WOLFTPM2_DEV* dev,
1364
    TPML_SPDM_SESSION_INFO* spdmSessionInfo)
1365
{
1366
    int rc;
1367
    GetCapability_In in;
1368
    GetCapability_Out out;
1369
1370
    if (dev == NULL || spdmSessionInfo == NULL) {
1371
        return BAD_FUNC_ARG;
1372
    }
1373
1374
    XMEMSET(&in, 0, sizeof(in));
1375
    XMEMSET(&out, 0, sizeof(out));
1376
    in.capability = TPM_CAP_SPDM_SESSION_INFO;
1377
    in.property = 0; /* must be 0 per Part 3 */
1378
    /* This capability describes the current SPDM session only. */
1379
    in.propertyCount = 1;
1380
1381
    rc = TPM2_GetCapability(&in, &out);
1382
    if (rc == TPM_RC_SUCCESS) {
1383
        if (out.capabilityData.capability == TPM_CAP_SPDM_SESSION_INFO) {
1384
            XMEMCPY(spdmSessionInfo, &out.capabilityData.data.spdmSessionInfo,
1385
                sizeof(*spdmSessionInfo));
1386
        }
1387
        else {
1388
            rc = TPM_RC_VALUE;
1389
        }
1390
    }
1391
#ifdef DEBUG_WOLFTPM
1392
    if (rc != TPM_RC_SUCCESS) {
1393
        printf("wolfTPM2_GetCapability_SPDMSessionInfo failed 0x%x: %s\n",
1394
            rc, TPM2_GetRCString(rc));
1395
    }
1396
#endif
1397
    return rc;
1398
}
1399
1400
int wolfTPM2_SpdmDisconnect(WOLFTPM2_DEV* dev)
1401
{
1402
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1403
    return wolfSPDM_Disconnect(dev->spdmCtx->spdmCtx);
1404
}
1405
1406
int wolfTPM2_SpdmGetVersion(WOLFTPM2_DEV* dev)
1407
{
1408
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1409
    return wolfSPDM_GetVersion(dev->spdmCtx->spdmCtx);
1410
}
1411
1412
int wolfTPM2_SpdmCleanup(WOLFTPM2_DEV* dev)
1413
{
1414
    if (dev == NULL) {
1415
        return BAD_FUNC_ARG;
1416
    }
1417
    if (dev->spdmCtx != NULL) {
1418
        wolfTPM2_SPDM_FreeCtx(dev->spdmCtx);
1419
        dev->spdmCtx = NULL;
1420
        dev->ctx.spdmCtx = NULL;
1421
    }
1422
    return TPM_RC_SUCCESS;
1423
}
1424
1425
#ifdef WOLFTPM_SPDM_TCG
1426
/* Shared TCG SPDM functions */
1427
1428
int wolfTPM2_SpdmSetResponderPubKey(WOLFTPM2_DEV* dev,
1429
    const byte* pubKey, word32 pubKeySz)
1430
{
1431
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1432
    return wolfSPDM_SetResponderPubKey(dev->spdmCtx->spdmCtx,
1433
        pubKey, pubKeySz);
1434
}
1435
1436
int wolfTPM2_SpdmGetPubKey(WOLFTPM2_DEV* dev, byte* pubKey, word32* pubKeySz)
1437
{
1438
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1439
    return wolfSPDM_TCG_GetPubKey(dev->spdmCtx->spdmCtx, pubKey, pubKeySz);
1440
}
1441
#endif /* WOLFTPM_SPDM_TCG */
1442
1443
#ifdef WOLFTPM_SPDM_TCG
1444
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC)
1445
static int wolfTPM2_SpdmGenerateRequesterKey(WOLFTPM2_DEV* dev)
1446
{
1447
    ecc_key key;
1448
    WC_RNG rng;
1449
    TPMT_PUBLIC pub;
1450
    TPM2_Packet packet;
1451
    byte privKey[WOLFSPDM_ECC_KEY_SIZE];
1452
    byte rawPubKey[WOLFSPDM_ECC_POINT_SIZE];
1453
    byte tpmtPub[120];
1454
    word32 privKeySz = sizeof(privKey);
1455
    word32 xSz = WOLFSPDM_ECC_KEY_SIZE;
1456
    word32 ySz = WOLFSPDM_ECC_KEY_SIZE;
1457
    int keyInit = 0;
1458
    int rngInit = 0;
1459
    int rc;
1460
1461
    XMEMSET(&key, 0, sizeof(key));
1462
    XMEMSET(&rng, 0, sizeof(rng));
1463
    XMEMSET(&pub, 0, sizeof(pub));
1464
    XMEMSET(&packet, 0, sizeof(packet));
1465
    rc = wc_InitRng(&rng);
1466
    if (rc != TPM_RC_SUCCESS) goto exit;
1467
    rngInit = 1;
1468
    rc = wc_ecc_init(&key);
1469
    if (rc != TPM_RC_SUCCESS) goto exit;
1470
    keyInit = 1;
1471
    rc = wc_ecc_make_key_ex(&rng, WOLFSPDM_ECC_KEY_SIZE, &key,
1472
        ECC_SECP384R1);
1473
    if (rc != TPM_RC_SUCCESS) goto exit;
1474
    rc = wc_ecc_export_private_only(&key, privKey, &privKeySz);
1475
    if (rc != TPM_RC_SUCCESS) goto exit;
1476
    rc = wc_ecc_export_public_raw(&key, rawPubKey, &xSz,
1477
        rawPubKey + WOLFSPDM_ECC_KEY_SIZE, &ySz);
1478
    if (rc != TPM_RC_SUCCESS) goto exit;
1479
1480
    pub.type = TPM_ALG_ECC;
1481
    pub.nameAlg = TPM_ALG_SHA384;
1482
    pub.objectAttributes = TPMA_OBJECT_sign;
1483
    pub.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
1484
    pub.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDSA;
1485
    pub.parameters.eccDetail.scheme.details.ecdsa.hashAlg = TPM_ALG_SHA384;
1486
    pub.parameters.eccDetail.curveID = TPM_ECC_NIST_P384;
1487
    pub.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
1488
    pub.unique.ecc.x.size = (UINT16)xSz;
1489
    pub.unique.ecc.y.size = (UINT16)ySz;
1490
    XMEMCPY(pub.unique.ecc.x.buffer, rawPubKey, xSz);
1491
    XMEMCPY(pub.unique.ecc.y.buffer, rawPubKey + WOLFSPDM_ECC_KEY_SIZE, ySz);
1492
    packet.buf = tpmtPub;
1493
    packet.size = sizeof(tpmtPub);
1494
    TPM2_Packet_AppendPublicArea(&packet, &pub);
1495
    if (packet.overflow) {
1496
        rc = BUFFER_E;
1497
        goto exit;
1498
    }
1499
    rc = wolfSPDM_SetRequesterKeyPair(dev->spdmCtx->spdmCtx,
1500
        privKey, privKeySz, rawPubKey, sizeof(rawPubKey));
1501
    if (rc == TPM_RC_SUCCESS) {
1502
        rc = wolfSPDM_SetRequesterKeyTPMT(dev->spdmCtx->spdmCtx,
1503
            tpmtPub, (word32)packet.pos);
1504
    }
1505
exit:
1506
    if (keyInit) {
1507
        wc_ecc_free(&key);
1508
    }
1509
    if (rngInit) {
1510
        wc_FreeRng(&rng);
1511
    }
1512
    TPM2_ForceZero(privKey, sizeof(privKey));
1513
    TPM2_ForceZero(&key, sizeof(key));
1514
    TPM2_ForceZero(&rng, sizeof(rng));
1515
    return rc;
1516
}
1517
#endif
1518
1519
static int wolfTPM2_SpdmConnectIdentityMode(WOLFTPM2_DEV* dev,
1520
    WOLFSPDM_MODE mode,
1521
    const byte* reqPubKey, word32 reqPubKeySz,
1522
    const byte* reqPrivKey, word32 reqPrivKeySz)
1523
{
1524
    int rc;
1525
1526
    if (dev == NULL || dev->spdmCtx == NULL ||
1527
        dev->spdmCtx->spdmCtx == NULL ||
1528
        (reqPubKey == NULL) != (reqPubKeySz == 0) ||
1529
        (reqPrivKey == NULL) != (reqPrivKeySz == 0) ||
1530
        (reqPubKey == NULL) != (reqPrivKey == NULL)) {
1531
        return BAD_FUNC_ARG;
1532
    }
1533
1534
    /* Auto-set TIS I/O callback if not already configured by caller */
1535
    rc = wolfTPM2_SPDM_SetTisIO(dev->spdmCtx);
1536
    if (rc != 0 && rc != NOT_COMPILED_IN) {
1537
        return rc;
1538
    }
1539
1540
#ifdef DEBUG_WOLFTPM
1541
    wolfSPDM_SetDebug(dev->spdmCtx->spdmCtx, 1);
1542
#endif
1543
1544
    /* Select protocol behavior before configuring requester credentials. */
1545
    rc = wolfSPDM_SetMode(dev->spdmCtx->spdmCtx, mode);
1546
    if (rc != 0) {
1547
        return rc;
1548
    }
1549
1550
    /* Set requester key pair if provided (for mutual authentication) */
1551
    if (reqPrivKey != NULL && reqPrivKeySz > 0 &&
1552
        reqPubKey != NULL && reqPubKeySz > 0) {
1553
        /* Parse TPMT_PUBLIC to extract raw X||Y ECC point */
1554
        TPM2_Packet pktPub;
1555
        TPMT_PUBLIC pub;
1556
        byte rawPubKey[WOLFSPDM_ECC_POINT_SIZE];
1557
        UINT16 wireSize;
1558
1559
        XMEMSET(&pub, 0, sizeof(pub));
1560
        pktPub.buf = (byte*)reqPubKey;
1561
        pktPub.pos = 0;
1562
        pktPub.size = (int)reqPubKeySz;
1563
        pktPub.overflow = 0;
1564
1565
        TPM2_Packet_ParseU16(&pktPub, &pub.type);
1566
        TPM2_Packet_ParseU16(&pktPub, &pub.nameAlg);
1567
        TPM2_Packet_ParseU32(&pktPub, &pub.objectAttributes);
1568
        wireSize = 0;
1569
        TPM2_Packet_ParseU16(&pktPub, &wireSize);
1570
        pub.authPolicy.size = wireSize;
1571
        if (pub.authPolicy.size >
1572
                (UINT16)sizeof(pub.authPolicy.buffer)) {
1573
            pub.authPolicy.size =
1574
                (UINT16)sizeof(pub.authPolicy.buffer);
1575
        }
1576
        TPM2_Packet_ParseBytes(&pktPub, pub.authPolicy.buffer,
1577
            pub.authPolicy.size);
1578
        if (wireSize > pub.authPolicy.size)
1579
            TPM2_Packet_ParseBytes(&pktPub, NULL,
1580
                wireSize - pub.authPolicy.size);
1581
        TPM2_Packet_ParsePublicParms(&pktPub, pub.type, &pub.parameters);
1582
        TPM2_Packet_ParseEccPoint(&pktPub, &pub.unique.ecc);
1583
1584
        if (pktPub.overflow || pktPub.pos != pktPub.size ||
1585
            pub.type != TPM_ALG_ECC ||
1586
            pub.parameters.eccDetail.curveID != TPM_ECC_NIST_P384 ||
1587
            pub.unique.ecc.x.size != WOLFSPDM_ECC_KEY_SIZE ||
1588
            pub.unique.ecc.y.size != WOLFSPDM_ECC_KEY_SIZE) {
1589
            return BAD_FUNC_ARG;
1590
        }
1591
1592
        XMEMCPY(rawPubKey, pub.unique.ecc.x.buffer,
1593
            WOLFSPDM_ECC_KEY_SIZE);
1594
        XMEMCPY(rawPubKey + WOLFSPDM_ECC_KEY_SIZE,
1595
            pub.unique.ecc.y.buffer, WOLFSPDM_ECC_KEY_SIZE);
1596
        rc = wolfSPDM_SetRequesterKeyPair(dev->spdmCtx->spdmCtx,
1597
            reqPrivKey, reqPrivKeySz, rawPubKey, sizeof(rawPubKey));
1598
        if (rc != 0) {
1599
            return rc;
1600
        }
1601
        /* Also store the full TPMT_PUBLIC for GIVE_PUB step */
1602
        rc = wolfSPDM_SetRequesterKeyTPMT(dev->spdmCtx->spdmCtx,
1603
            reqPubKey, reqPubKeySz);
1604
        if (rc != 0) {
1605
            return rc;
1606
        }
1607
    }
1608
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC)
1609
    else {
1610
        rc = wolfTPM2_SpdmGenerateRequesterKey(dev);
1611
        if (rc != TPM_RC_SUCCESS) {
1612
            return rc;
1613
        }
1614
    }
1615
#endif /* !WOLFTPM2_NO_WOLFCRYPT && HAVE_ECC */
1616
1617
    /* Perform the selected TCG SPDM handshake. */
1618
    return wolfSPDM_Connect(dev->spdmCtx->spdmCtx);
1619
}
1620
#endif /* WOLFTPM_SPDM_TCG */
1621
1622
#ifdef WOLFSPDM_NUVOTON
1623
/* Nuvoton-specific SPDM functions */
1624
1625
int wolfTPM2_SpdmSetNuvotonMode(WOLFTPM2_DEV* dev)
1626
{
1627
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1628
    return wolfSPDM_SetMode(dev->spdmCtx->spdmCtx, WOLFSPDM_MODE_NUVOTON);
1629
}
1630
1631
int wolfTPM2_SpdmEnable(WOLFTPM2_DEV* dev)
1632
{
1633
    int rc;
1634
    TPM2_AUTH_SESSION saveSess;
1635
    if (dev == NULL || dev->spdmCtx == NULL) {
1636
        return BAD_FUNC_ARG;
1637
    }
1638
    /* Save session[0] — NTC2_PreConfig requires platform auth which
1639
     * overwrites any existing HMAC/parameter-encryption session. */
1640
    XMEMCPY(&saveSess, &dev->session[0], sizeof(saveSess));
1641
    rc = wolfTPM2_SetAuthPassword(dev, 0, NULL);
1642
    if (rc == 0) {
1643
        rc = wolfTPM2_SPDM_Enable(dev->spdmCtx);
1644
    }
1645
    /* Restore previous session[0] state and clear the stack copy */
1646
    XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1647
    TPM2_ForceZero(&saveSess, sizeof(saveSess));
1648
    return rc;
1649
}
1650
1651
int wolfTPM2_SpdmDisable(WOLFTPM2_DEV* dev)
1652
{
1653
    int rc;
1654
    TPM2_AUTH_SESSION saveSess;
1655
    if (dev == NULL || dev->spdmCtx == NULL) {
1656
        return BAD_FUNC_ARG;
1657
    }
1658
    /* Save session[0] — NTC2_PreConfig requires platform auth which
1659
     * overwrites any existing HMAC/parameter-encryption session. */
1660
    XMEMCPY(&saveSess, &dev->session[0], sizeof(saveSess));
1661
    rc = wolfTPM2_SetAuthPassword(dev, 0, NULL);
1662
    if (rc == 0) {
1663
        rc = wolfTPM2_SPDM_Disable(dev->spdmCtx);
1664
    }
1665
    /* Restore previous session[0] state and clear the stack copy */
1666
    XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1667
    TPM2_ForceZero(&saveSess, sizeof(saveSess));
1668
    return rc;
1669
}
1670
1671
int wolfTPM2_SpdmGetStatus(WOLFTPM2_DEV* dev, WOLFSPDM_NUVOTON_STATUS* status)
1672
{
1673
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1674
    return wolfSPDM_Nuvoton_GetStatus(dev->spdmCtx->spdmCtx, status);
1675
}
1676
1677
int wolfTPM2_SpdmSetOnlyMode(WOLFTPM2_DEV* dev, int lock)
1678
{
1679
    int rc;
1680
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1681
    rc = wolfSPDM_Nuvoton_SetOnlyMode(dev->spdmCtx->spdmCtx, lock);
1682
    if (rc == WOLFSPDM_SUCCESS) {
1683
        dev->spdmCtx->spdmOnlyLocked = lock;
1684
    }
1685
    return rc;
1686
}
1687
1688
int wolfTPM2_SpdmConnectNuvoton(WOLFTPM2_DEV* dev,
1689
    const byte* reqPubKey, word32 reqPubKeySz,
1690
    const byte* reqPrivKey, word32 reqPrivKeySz)
1691
{
1692
    return wolfTPM2_SpdmConnectIdentityMode(dev, WOLFSPDM_MODE_NUVOTON,
1693
        reqPubKey, reqPubKeySz, reqPrivKey, reqPrivKeySz);
1694
}
1695
1696
#endif /* WOLFSPDM_NUVOTON */
1697
1698
#ifdef WOLFSPDM_NATIONS
1699
/* Nations Technology NS350 SPDM functions */
1700
1701
int wolfTPM2_SpdmSetNationsMode(WOLFTPM2_DEV* dev)
1702
{
1703
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1704
    return wolfSPDM_SetMode(dev->spdmCtx->spdmCtx, WOLFSPDM_MODE_NATIONS);
1705
}
1706
1707
int wolfTPM2_SpdmConnectNations(WOLFTPM2_DEV* dev,
1708
    const byte* reqPubKey, word32 reqPubKeySz,
1709
    const byte* reqPrivKey, word32 reqPrivKeySz)
1710
{
1711
    return wolfTPM2_SpdmConnectIdentityMode(dev, WOLFSPDM_MODE_NATIONS,
1712
        reqPubKey, reqPubKeySz, reqPrivKey, reqPrivKeySz);
1713
}
1714
1715
int wolfTPM2_SpdmNationsIdentityKeySet(WOLFTPM2_DEV* dev, int set)
1716
{
1717
    int rc;
1718
    Nations_IdentityKeySet_In in;
1719
    TPM2_AUTH_SESSION saveSess;
1720
1721
    if (dev == NULL) {
1722
        return BAD_FUNC_ARG;
1723
    }
1724
1725
    /* Mutual exclusion: TPM enforces this by returning TPM_RC_VALUE if PSK
1726
     * is provisioned. The error message helps users understand the failure. */
1727
1728
    /* Save session[0] — platform auth setup overwrites any existing
1729
     * HMAC/parameter-encryption session. */
1730
    XMEMCPY(&saveSess, &dev->session[0], sizeof(saveSess));
1731
1732
    /* Set platform auth (empty password) with no continueSession.
1733
     * NS350 requires sessionAttributes=0x00, not 0x01 (continueSession). */
1734
    rc = wolfTPM2_SetAuthPassword(dev, 0, NULL);
1735
    if (rc == 0) {
1736
        dev->session[0].sessionAttributes = 0;
1737
1738
        XMEMSET(&in, 0, sizeof(in));
1739
        in.authHandle = TPM_RH_PLATFORM;
1740
        in.configuration = set ? 1 : 0;
1741
1742
        rc = TPM2_Nations_IdentityKeySet(&in);
1743
        if (rc != TPM_RC_SUCCESS) {
1744
        #ifdef DEBUG_WOLFTPM
1745
            printf("Nations IdentityKeySet(%d) failed: 0x%x: %s\n",
1746
                set, rc, TPM2_GetRCString(rc));
1747
        #endif
1748
        }
1749
    }
1750
1751
    /* Restore previous session[0] state and clear the stack copy */
1752
    XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
1753
    TPM2_ForceZero(&saveSess, sizeof(saveSess));
1754
1755
    return rc;
1756
}
1757
1758
int wolfTPM2_SpdmNationsGetStatus(WOLFTPM2_DEV* dev,
1759
    WOLFSPDM_NATIONS_STATUS* status)
1760
{
1761
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1762
    return wolfSPDM_Nations_GetStatus(dev->spdmCtx->spdmCtx, status);
1763
}
1764
1765
int wolfTPM2_SpdmNationsSetOnlyMode(WOLFTPM2_DEV* dev, int lock)
1766
{
1767
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1768
    return wolfSPDM_Nations_SetOnlyMode(dev->spdmCtx->spdmCtx, lock);
1769
}
1770
1771
int wolfTPM2_SpdmNationsPskSet(WOLFTPM2_DEV* dev,
1772
    const byte* psk, word32 pskSz)
1773
{
1774
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1775
    return wolfSPDM_Nations_PskSet(dev->spdmCtx->spdmCtx, psk, pskSz);
1776
}
1777
1778
int wolfTPM2_SpdmNationsPskClear(WOLFTPM2_DEV* dev,
1779
    const byte* clearAuth, word32 clearAuthSz)
1780
{
1781
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1782
    return wolfSPDM_Nations_PskClear(dev->spdmCtx->spdmCtx,
1783
        clearAuth, clearAuthSz);
1784
}
1785
1786
#endif /* WOLFSPDM_NATIONS */
1787
1788
#ifdef WOLFSPDM_INFINEON
1789
/* Infineon controls are a thin adapter over the shared TCG and PSK code. */
1790
1791
int wolfTPM2_SpdmConnectInfineonTcg(WOLFTPM2_DEV* dev,
1792
    const byte* reqPubKey, word32 reqPubKeySz,
1793
    const byte* reqPrivKey, word32 reqPrivKeySz)
1794
{
1795
    return wolfTPM2_SpdmConnectIdentityMode(dev, WOLFSPDM_MODE_TCG,
1796
        reqPubKey, reqPubKeySz, reqPrivKey, reqPrivKeySz);
1797
}
1798
1799
int wolfTPM2_SpdmSetInfineonMode(WOLFTPM2_DEV* dev)
1800
{
1801
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1802
#ifdef WOLFTPM_SPDM_PSK
1803
    /* Preserve the original PSK provisioning entry point. */
1804
    return wolfSPDM_SetMode(dev->spdmCtx->spdmCtx, WOLFSPDM_MODE_PSK);
1805
#else
1806
    return WOLFSPDM_E_NOT_AVAILABLE;
1807
#endif
1808
}
1809
1810
int wolfTPM2_SpdmInfineonGetStatus(WOLFTPM2_DEV* dev,
1811
    WOLFSPDM_INFINEON_STATUS* status)
1812
{
1813
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1814
    return wolfSPDM_Infineon_GetStatus(dev->spdmCtx->spdmCtx, status);
1815
}
1816
1817
int wolfTPM2_SpdmInfineonSetOnlyMode(WOLFTPM2_DEV* dev, int lock)
1818
{
1819
    WOLFTPM2_SPDM_CHECK_CTX(dev);
1820
    return wolfSPDM_Infineon_SetOnlyMode(dev->spdmCtx->spdmCtx, lock);
1821
}
1822
1823
int wolfTPM2_SpdmInfineonEnable(WOLFTPM2_DEV* dev, int enable, int lock)
1824
{
1825
    int rc;
1826
    int defaultAuth;
1827
    SetCapability_In in;
1828
    TPM2_AUTH_SESSION saveSess;
1829
1830
    if (dev == NULL) {
1831
        return BAD_FUNC_ARG;
1832
    }
1833
    XMEMSET(&in, 0, sizeof(in));
1834
    XMEMSET(&saveSess, 0, sizeof(saveSess));
1835
    /* Honor the caller's platform password or authorization session. Only
1836
     * an unused slot receives temporary empty-password authorization. */
1837
    defaultAuth = (dev->session[0].sessionHandle == 0);
1838
    if (defaultAuth) {
1839
        XMEMCPY(&saveSess, &dev->session[0], sizeof(saveSess));
1840
        rc = wolfTPM2_SetAuthPassword(dev, 0, NULL);
1841
    }
1842
    else {
1843
        rc = TPM2_SetSessionAuth(dev->session);
1844
    }
1845
    if (rc == 0) {
1846
        in.authHandle = TPM_RH_PLATFORM;
1847
        in.capability = TPM_CAP_CONFIGS;
1848
        in.config.configuration = TPM_PT_CONFIG_SPDM_PSK;
1849
        in.config.enable = enable ? 1 : 0;
1850
        in.config.lock = lock ? 1 : 0;
1851
        rc = TPM2_SetCapability(&in);
1852
        if (rc != TPM_RC_SUCCESS) {
1853
        #ifdef DEBUG_WOLFTPM
1854
            printf("Infineon SetCapability(SPDM_PSK en=%d lk=%d) failed: "
1855
                "0x%x: %s\n", enable, lock, rc, TPM2_GetRCString(rc));
1856
        #endif
1857
        }
1858
    }
1859
    if (defaultAuth) {
1860
        XMEMCPY(&dev->session[0], &saveSess, sizeof(saveSess));
1861
    }
1862
    TPM2_ForceZero(&saveSess, sizeof(saveSess));
1863
    return rc;
1864
}
1865
1866
#endif /* WOLFSPDM_INFINEON */
1867
1868
#ifdef WOLFTPM_SPDM_PSK
1869
/* Spec-pure PSK handshake (DSP0274 PSK_EXCHANGE / PSK_FINISH). The
1870
 * underlying state machine runs the standard messages - the mode enum
1871
 * still uses the historical NATIONS_PSK name. */
1872
int wolfTPM2_SpdmConnectPsk(WOLFTPM2_DEV* dev,
1873
    const byte* psk, word32 pskSz,
1874
    const byte* hint, word32 hintSz)
1875
{
1876
    int rc;
1877
1878
    if (dev == NULL || dev->spdmCtx == NULL || psk == NULL || pskSz == 0) {
1879
        return BAD_FUNC_ARG;
1880
    }
1881
1882
    rc = wolfTPM2_SPDM_SetTisIO(dev->spdmCtx);
1883
    if (rc != 0 && rc != NOT_COMPILED_IN) {
1884
        return rc;
1885
    }
1886
1887
#ifdef DEBUG_WOLFTPM
1888
    wolfSPDM_SetDebug(dev->spdmCtx->spdmCtx, 1);
1889
#endif
1890
1891
    rc = wolfSPDM_SetMode(dev->spdmCtx->spdmCtx, WOLFSPDM_MODE_NATIONS_PSK);
1892
    if (rc != 0) {
1893
        return rc;
1894
    }
1895
1896
    rc = wolfSPDM_SetPSK(dev->spdmCtx->spdmCtx, psk, pskSz, hint, hintSz);
1897
    if (rc != 0) {
1898
        return rc;
1899
    }
1900
1901
    return wolfSPDM_Connect(dev->spdmCtx->spdmCtx);
1902
}
1903
#endif /* WOLFTPM_SPDM_PSK */
1904
1905
#endif /* WOLFTPM_SPDM */
1906
1907
int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index)
1908
{
1909
    TPM2_AUTH_SESSION* session;
1910
1911
    if (dev == NULL || index >= MAX_SESSION_NUM || index < 0) {
1912
        return BAD_FUNC_ARG;
1913
    }
1914
1915
    session = &dev->session[index];
1916
    XMEMSET(session, 0, sizeof(TPM2_AUTH_SESSION));
1917
1918
    return TPM2_SetSessionAuth(dev->session);
1919
}
1920
1921
int wolfTPM2_UnsetAuthSession(WOLFTPM2_DEV* dev, int index,
1922
    WOLFTPM2_SESSION* tpmSession)
1923
{
1924
    TPM2_AUTH_SESSION* devSession;
1925
1926
    if (dev == NULL || tpmSession == NULL ||
1927
            index >= MAX_SESSION_NUM || index < 0) {
1928
        return BAD_FUNC_ARG;
1929
    }
1930
1931
    devSession = &dev->session[index];
1932
1933
    /* save off nonce from TPM to support continued use of session */
1934
    XMEMCPY(&tpmSession->nonceTPM, &devSession->nonceTPM, sizeof(TPM2B_NONCE));
1935
1936
    XMEMSET(devSession, 0, sizeof(TPM2_AUTH_SESSION));
1937
1938
    return TPM2_SetSessionAuth(dev->session);
1939
}
1940
1941
int wolfTPM2_SetAuth(WOLFTPM2_DEV* dev, int index,
1942
    TPM_HANDLE sessionHandle, const TPM2B_AUTH* auth,
1943
    TPMA_SESSION sessionAttributes, const TPM2B_NAME* name)
1944
{
1945
    TPM2_AUTH_SESSION* session;
1946
1947
    if (dev == NULL || index >= MAX_SESSION_NUM || index < 0) {
1948
        return BAD_FUNC_ARG;
1949
    }
1950
1951
    session = &dev->session[index];
1952
1953
  #ifdef WOLFTPM_DEBUG_VERBOSE
1954
    printf("Session %d: Edit\n", index);
1955
    printf("\tHandle 0x%x -> 0x%x\n", session->sessionHandle, sessionHandle);
1956
    printf("\tAttributes 0x%x -> 0x%x\n", session->sessionAttributes,
1957
        sessionAttributes);
1958
    if (auth) {
1959
        printf("\tAuth Sz %d -> %d\n", session->auth.size, auth->size);
1960
    #ifdef WOLFTPM_DEBUG_SECRETS
1961
        TPM2_PrintBin(session->auth.buffer, session->auth.size);
1962
        TPM2_PrintBin(auth->buffer, auth->size);
1963
    #endif
1964
    }
1965
    if (name) {
1966
        printf("\tName Sz %d -> %d\n", session->name.size, name->size);
1967
        TPM2_PrintBin(session->name.name, session->name.size);
1968
        TPM2_PrintBin(name->name, name->size);
1969
    }
1970
#endif
1971
1972
    /* Validate bounds before mutating session state so that an oversized
1973
     * auth value doesn't leave the session with an invalid auth.size that
1974
     * subsequent code paths could read past the buffer end. */
1975
    if ((auth != NULL && auth->size > sizeof(session->auth.buffer)) ||
1976
            (name != NULL && name->size > sizeof(session->name.name))) {
1977
        return BUFFER_E;
1978
    }
1979
    XMEMSET(session, 0, sizeof(TPM2_AUTH_SESSION));
1980
    session->sessionHandle = sessionHandle;
1981
    session->sessionAttributes = sessionAttributes;
1982
    if (auth) {
1983
        session->auth.size = auth->size;
1984
        XMEMCPY(session->auth.buffer, auth->buffer, session->auth.size);
1985
    }
1986
    if (name) {
1987
        session->name.size = name->size;
1988
        XMEMCPY(session->name.name, name->name, session->name.size);
1989
    }
1990
1991
    TPM2_SetSessionAuth(dev->session);
1992
1993
    return TPM_RC_SUCCESS;
1994
}
1995
1996
int wolfTPM2_SetAuthPassword(WOLFTPM2_DEV* dev, int index,
1997
    const TPM2B_AUTH* auth)
1998
{
1999
    return wolfTPM2_SetAuth(dev, index, TPM_RS_PW, auth, 0, NULL);
2000
}
2001
2002
int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index,
2003
    const WOLFTPM2_HANDLE* handle)
2004
{
2005
    const TPM2B_AUTH* auth = NULL;
2006
    const TPM2B_NAME* name = NULL;
2007
    if (dev == NULL || index < 0 || index >= MAX_SESSION_NUM) {
2008
        return BAD_FUNC_ARG;
2009
    }
2010
2011
    if (handle) {
2012
        /* don't set auth for policy session, just name */
2013
        if (handle->policyAuth) {
2014
            TPM2_AUTH_SESSION* session = &dev->session[index];
2015
            int authDigestSz = TPM2_GetHashDigestSize(session->authHash);
2016
            word32 authSz;
2017
2018
            /* Validate bounds before reading caller data or mutating the
2019
             * session so it isn't left inconsistent on BUFFER_E. */
2020
            if (authDigestSz <= 0 ||
2021
                (word32)authDigestSz >
2022
                    (word32)sizeof(session->auth.buffer) ||
2023
                handle->auth.size > (word32)sizeof(session->auth.buffer) -
2024
                    (word32)authDigestSz ||
2025
                handle->name.size > sizeof(session->name.name)) {
2026
                return BUFFER_E;
2027
            }
2028
            authSz = (word32)authDigestSz + handle->auth.size;
2029
        #ifdef WOLFTPM_DEBUG_VERBOSE
2030
            printf("Session %d: Edit (PolicyAuth)\n", index);
2031
            printf("\tHandle 0x%x (not touching)\n", session->sessionHandle);
2032
            printf("\tPolicyAuth %d->%d\n",
2033
                session->policyAuth, handle->policyAuth);
2034
            printf("\tAuth Sz %d -> %u\n", session->auth.size,
2035
                (unsigned int)authSz);
2036
        #ifdef WOLFTPM_DEBUG_SECRETS
2037
            TPM2_PrintBin(session->auth.buffer, session->auth.size);
2038
            TPM2_PrintBin(handle->auth.buffer, handle->auth.size);
2039
        #endif
2040
            printf("\tName Sz %d -> %d\n", session->name.size, handle->name.size);
2041
            TPM2_PrintBin(session->name.name, session->name.size);
2042
            TPM2_PrintBin(handle->name.name, handle->name.size);
2043
        #endif
2044
            session->policyAuth = handle->policyAuth;
2045
            session->auth.size = (word16)authSz;
2046
            XMEMMOVE(&session->auth.buffer[authDigestSz], handle->auth.buffer,
2047
                handle->auth.size);
2048
            if (authSz < sizeof(session->auth.buffer)) {
2049
                TPM2_ForceZero(&session->auth.buffer[authSz],
2050
                    (word32)sizeof(session->auth.buffer) - authSz);
2051
            }
2052
            session->name.size = handle->name.size;
2053
            XMEMCPY(session->name.name, handle->name.name, session->name.size);
2054
            return TPM_RC_SUCCESS;
2055
        }
2056
        auth = &handle->auth;
2057
        name = &handle->name;
2058
    }
2059
    return wolfTPM2_SetAuth(dev, index, TPM_RS_PW, auth, 0, name);
2060
}
2061
2062
int wolfTPM2_SetAuthHandleName(WOLFTPM2_DEV* dev, int index,
2063
    const WOLFTPM2_HANDLE* handle)
2064
{
2065
    const TPM2B_NAME* name = NULL;
2066
    TPM2_AUTH_SESSION* session;
2067
2068
    if (dev == NULL || handle == NULL || index < 0 || index >= MAX_SESSION_NUM) {
2069
        return BAD_FUNC_ARG;
2070
    }
2071
2072
    name = &handle->name;
2073
    session = &dev->session[index];
2074
2075
    /* Validate bounds before mutating persistent session state. */
2076
    if (handle->auth.size > sizeof(session->auth.buffer) ||
2077
            name->size > sizeof(session->name.name)) {
2078
        return BUFFER_E;
2079
    }
2080
    if (handle->auth.size > 0 || session->sessionHandle == TPM_RS_PW ||
2081
            (handle->policyPass && session->policyPass) ||
2082
            (handle->policyAuth && session->policyAuth)) {
2083
        if (session->sessionHandle != TPM_RS_PW && handle->policyAuth &&
2084
                !handle->policyPass) {
2085
            int authDigestSz = TPM2_GetHashDigestSize(session->authHash);
2086
2087
            if (authDigestSz <= 0 ||
2088
                    (authDigestSz + handle->auth.size) >
2089
                        (int)sizeof(session->auth.buffer)) {
2090
                return BUFFER_E;
2091
            }
2092
        }
2093
2094
        if (session->sessionHandle == TPM_RS_PW) {
2095
            /* password based authentication */
2096
            wolfTPM2_CopyAuth(&session->auth, &handle->auth);
2097
        }
2098
        else {
2099
            if (handle->policyPass) {
2100
                /* use policy password directly */
2101
                wolfTPM2_CopyAuth(&session->auth, &handle->auth);
2102
                session->policyPass = handle->policyPass;
2103
            }
2104
            else if (handle->policyAuth) {
2105
                /* HMAC + policy auth value */
2106
                int authDigestSz = TPM2_GetHashDigestSize(session->authHash);
2107
2108
                session->auth.size = (UINT16)(authDigestSz +
2109
                    handle->auth.size);
2110
                XMEMMOVE(&session->auth.buffer[authDigestSz],
2111
                    handle->auth.buffer, handle->auth.size);
2112
                if (session->auth.size < sizeof(session->auth.buffer)) {
2113
                    TPM2_ForceZero(&session->auth.buffer[session->auth.size],
2114
                        (word32)sizeof(session->auth.buffer) -
2115
                            session->auth.size);
2116
                }
2117
                session->policyAuth = handle->policyAuth;
2118
            }
2119
        }
2120
    }
2121
    session->name.size = name->size;
2122
    XMEMCPY(session->name.name, name->name, session->name.size);
2123
2124
    return TPM_RC_SUCCESS;
2125
}
2126
2127
int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index,
2128
    WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes)
2129
{
2130
    int rc;
2131
2132
    if (dev == NULL || index < 0 || index >= MAX_SESSION_NUM) {
2133
        return BAD_FUNC_ARG;
2134
    }
2135
2136
    if (tpmSession == NULL) {
2137
        /* clearing auth session */
2138
        TPM2_ForceZero(&dev->session[index], sizeof(TPM2_AUTH_SESSION));
2139
        return TPM_RC_SUCCESS;
2140
    }
2141
2142
    rc = wolfTPM2_SetAuth(dev, index, tpmSession->handle.hndl,
2143
        &tpmSession->handle.auth, sessionAttributes, NULL);
2144
    if (rc == TPM_RC_SUCCESS) {
2145
        TPM2_AUTH_SESSION* session = &dev->session[index];
2146
2147
        /* save off session attributes */
2148
        tpmSession->sessionAttributes = sessionAttributes;
2149
2150
        /* Capture auth type */
2151
        session->policyAuth = tpmSession->handle.policyAuth;
2152
        session->policyPass = tpmSession->handle.policyPass;
2153
2154
        /* Capture the bind auth pointer and the bind entity Name (set by
2155
         * wolfTPM2_StartSession). Used by parameter encryption to tell whether
2156
         * the session authorizes its own bind entity. */
2157
        session->bind = tpmSession->bind;
2158
        session->bindName.size = tpmSession->handle.name.size;
2159
        if (session->bindName.size > (UINT16)sizeof(session->bindName.name))
2160
            session->bindName.size = (UINT16)sizeof(session->bindName.name);
2161
        XMEMCPY(session->bindName.name, tpmSession->handle.name.name,
2162
            session->bindName.size);
2163
2164
        /* define the symmetric algorithm */
2165
        session->authHash = tpmSession->authHash;
2166
        XMEMCPY(&session->symmetric, &tpmSession->handle.symmetric,
2167
            sizeof(TPMT_SYM_DEF));
2168
2169
        /* Capture TPM provided nonce */
2170
        session->nonceTPM.size = tpmSession->nonceTPM.size;
2171
        if (session->nonceTPM.size > (UINT16)sizeof(session->nonceTPM.buffer))
2172
            session->nonceTPM.size = (UINT16)sizeof(session->nonceTPM.buffer);
2173
        XMEMCPY(session->nonceTPM.buffer, tpmSession->nonceTPM.buffer,
2174
            session->nonceTPM.size);
2175
2176
    }
2177
    return rc;
2178
}
2179
2180
int wolfTPM2_SetSessionHandle(WOLFTPM2_DEV* dev, int index,
2181
    WOLFTPM2_SESSION* tpmSession)
2182
{
2183
    TPM2_AUTH_SESSION* session;
2184
2185
    if (dev == NULL || index >= MAX_SESSION_NUM || index < 0) {
2186
        return BAD_FUNC_ARG;
2187
    }
2188
2189
    session = &dev->session[index];
2190
2191
    /* Set password handle unless TPM session is available */
2192
    if (tpmSession == NULL) {
2193
        TPM2_ForceZero(session, sizeof(TPM2_AUTH_SESSION));
2194
        session->sessionHandle = TPM_RS_PW;
2195
    }
2196
    else {
2197
        /* Validate bounds before mutating session state so the session
2198
         * isn't left inconsistent on BUFFER_E. */
2199
        if (tpmSession->handle.auth.size > sizeof(session->auth.buffer)) {
2200
        #ifdef DEBUG_WOLFTPM
2201
            printf("SetSessionHandle: auth size %d exceeds buffer %d\n",
2202
                tpmSession->handle.auth.size,
2203
                (int)sizeof(session->auth.buffer));
2204
        #endif
2205
            return BUFFER_E;
2206
        }
2207
2208
        session->sessionHandle = tpmSession->handle.hndl;
2209
        wolfTPM2_CopyAuth(&session->auth, &tpmSession->handle.auth);
2210
2211
        session->name.size = tpmSession->handle.name.size;
2212
        if (session->name.size > sizeof(session->name.name)) {
2213
            session->name.size = sizeof(session->name.name); /* truncate */
2214
        }
2215
        XMEMCPY(session->name.name, tpmSession->handle.name.name,
2216
            session->name.size);
2217
2218
        session->policyAuth = tpmSession->handle.policyAuth;
2219
        session->policyPass = tpmSession->handle.policyPass;
2220
    }
2221
2222
    TPM2_SetSessionAuth(dev->session);
2223
2224
    return TPM_RC_SUCCESS;
2225
}
2226
2227
2228
int wolfTPM2_CreateAuthSession_EkPolicy_ex(WOLFTPM2_DEV* dev,
2229
                                        WOLFTPM2_SESSION* tpmSession,
2230
                                        TPMI_ALG_HASH authHash)
2231
{
2232
    int rc = TPM_RC_FAILURE;
2233
    PolicySecret_In policySecretIn;
2234
    PolicySecret_Out policySecretOut;
2235
2236
    /* Endorsement Key requires authorization with Policy */
2237
    rc = wolfTPM2_StartSession_ex(dev, tpmSession, NULL, NULL,
2238
                               TPM_SE_POLICY, TPM_ALG_NULL, authHash);
2239
    if (rc == TPM_RC_SUCCESS) {
2240
        #ifdef DEBUG_WOLFTPM
2241
        printf("TPM2_StartAuthSession: sessionHandle 0x%x\n",
2242
                (word32)tpmSession->handle.hndl);
2243
        #endif
2244
        /* Provide Endorsement Auth using PolicySecret */
2245
        XMEMSET(&policySecretIn, 0, sizeof(policySecretIn));
2246
        policySecretIn.authHandle = TPM_RH_ENDORSEMENT;
2247
        policySecretIn.policySession = tpmSession->handle.hndl;
2248
        rc = TPM2_PolicySecret(&policySecretIn, &policySecretOut);
2249
        #ifdef DEBUG_WOLFTPM
2250
        if (rc == TPM_RC_SUCCESS) {
2251
            printf("policySecret applied on session\n");
2252
        }
2253
        #endif
2254
    }
2255
    return rc;
2256
}
2257
2258
int wolfTPM2_CreateAuthSession_EkPolicy(WOLFTPM2_DEV* dev,
2259
                                        WOLFTPM2_SESSION* tpmSession)
2260
{
2261
    return wolfTPM2_CreateAuthSession_EkPolicy_ex(dev, tpmSession,
2262
        WOLFTPM2_WRAP_DIGEST);
2263
}
2264
2265
int wolfTPM2_Cleanup_ex(WOLFTPM2_DEV* dev, int doShutdown)
2266
{
2267
    int rc = 0;
2268
    int cryptoCbRc = 0;
2269
2270
    if (dev == NULL) {
2271
        return BAD_FUNC_ARG;
2272
    }
2273
2274
#ifdef WOLFTPM_CRYPTOCB
2275
    /* make sure crypto dev callback is unregistered */
2276
    cryptoCbRc = wolfTPM2_ClearCryptoDevCb(dev, INVALID_DEVID);
2277
#endif
2278
2279
    if (doShutdown && TPM2_GetActiveCtx() != NULL)  {
2280
        Shutdown_In shutdownIn;
2281
        XMEMSET(&shutdownIn, 0, sizeof(shutdownIn));
2282
        shutdownIn.shutdownType = TPM_SU_CLEAR;
2283
        rc = TPM2_Shutdown(&shutdownIn);
2284
        if (rc != TPM_RC_SUCCESS) {
2285
        #ifdef WOLFTPM_SPDM
2286
            if (rc == (int)TPM_RC_DISABLED) {
2287
                /* SPDM-only mode active - shutdown not needed */
2288
            #ifdef DEBUG_WOLFTPM
2289
                printf("TPM2_Shutdown: TPM_RC_DISABLED (SPDM-only mode, "
2290
                       "expected)\n");
2291
            #endif
2292
                rc = TPM_RC_SUCCESS; /* Not an error in SPDM mode */
2293
            }
2294
            else
2295
        #endif /* WOLFTPM_SPDM */
2296
            {
2297
            #ifdef DEBUG_WOLFTPM
2298
                printf("TPM2_Shutdown failed %d: %s\n",
2299
                    rc, wolfTPM2_GetRCString(rc));
2300
            #endif
2301
            }
2302
            /* finish cleanup and return error */
2303
        }
2304
    }
2305
2306
#ifdef WOLFTPM_SPDM
2307
    /* Send END_SESSION to gracefully terminate SPDM session
2308
     * (TCG spec 5.5.1.6, Table 2: mandatory) */
2309
    if (dev->spdmCtx != NULL && dev->spdmCtx->spdmCtx != NULL &&
2310
        wolfSPDM_IsConnected(dev->spdmCtx->spdmCtx)) {
2311
        (void)wolfTPM2_SpdmDisconnect(dev);
2312
    }
2313
    /* Clean up SPDM context */
2314
    wolfTPM2_SpdmCleanup(dev);
2315
#endif
2316
2317
    TPM2_Cleanup(&dev->ctx);
2318
    TPM2_ForceZero(dev->session, sizeof(dev->session));
2319
    dev->ctx.session = NULL;
2320
2321
    return (cryptoCbRc != 0) ? cryptoCbRc : rc;
2322
}
2323
2324
int wolfTPM2_Cleanup(WOLFTPM2_DEV* dev)
2325
{
2326
#if defined(WOLFTPM_WINAPI)
2327
    return wolfTPM2_Cleanup_ex(dev, 0);
2328
#else
2329
    return wolfTPM2_Cleanup_ex(dev, 1);
2330
#endif
2331
}
2332
2333
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
2334
    !defined(WC_NO_RNG) && defined(HAVE_ECC_DHE) && \
2335
    defined(HAVE_ECC_KEY_IMPORT) && defined(HAVE_ECC_KEY_EXPORT)
2336
/* TPM2_KDFe is now in tpm2_crypto.c (shared with fwTPM) */
2337
/* returns both the plaintext and encrypted value */
2338
/* ECC: data = derived symmetric key
2339
 *      secret = exported public point */
2340
static int wolfTPM2_EncryptSecret_ECC(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
2341
    TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret,
2342
    const char* label)
2343
{
2344
    int rc;
2345
    WC_RNG rng;
2346
    ecc_key eccKeyPriv, eccKeyPub;
2347
    const TPMT_PUBLIC *publicArea;
2348
    TPM2B_ECC_POINT pubPoint, secretPoint;
2349
    word32 keySz = 0;
2350
    word32 xSz = sizeof(secretPoint.point.x.buffer);
2351
2352
    publicArea = &tpmKey->pub.publicArea;
2353
    XMEMSET(&rng, 0, sizeof(rng));
2354
    XMEMSET(&eccKeyPub, 0, sizeof(eccKeyPub));
2355
    XMEMSET(&eccKeyPriv, 0, sizeof(eccKeyPriv));
2356
    XMEMSET(&pubPoint, 0, sizeof(pubPoint));
2357
    XMEMSET(&secretPoint, 0, sizeof(secretPoint));
2358
2359
    rc = wc_InitRng_ex(&rng, NULL, INVALID_DEVID);
2360
    if (rc == 0) {
2361
        rc = wc_ecc_init_ex(&eccKeyPub, NULL, INVALID_DEVID);
2362
    }
2363
    if (rc == 0) {
2364
        rc = wc_ecc_init_ex(&eccKeyPriv, NULL, INVALID_DEVID);
2365
    }
2366
#ifdef ECC_TIMING_RESISTANT
2367
    if (rc == 0) {
2368
        wc_ecc_set_rng(&eccKeyPriv, &rng);
2369
        wc_ecc_set_rng(&eccKeyPub, &rng);
2370
    }
2371
#endif
2372
    if (rc == 0) {
2373
        /* import peer public key */
2374
        rc = wolfTPM2_EccKey_TpmToWolf(dev, (WOLFTPM2_KEY*)tpmKey, &eccKeyPub);
2375
    }
2376
    if (rc == 0) {
2377
        /* create local private key */
2378
        rc = wc_ecc_make_key_ex(&rng, 0, &eccKeyPriv,
2379
            TPM2_GetWolfCurve(publicArea->parameters.eccDetail.curveID));
2380
    }
2381
    if (rc == 0) {
2382
        keySz = wc_ecc_size(&eccKeyPriv);
2383
2384
        /* export private's public point as data */
2385
        rc = wolfTPM2_EccKey_WolfToPubPoint(dev, &eccKeyPriv, &pubPoint);
2386
    }
2387
    if (rc == 0) {
2388
        /* Export public point x/y into secret buffer for peer */
2389
        TPM2_Packet packet;
2390
        XMEMSET(&packet, 0, sizeof(packet));
2391
        packet.buf = secret->secret;
2392
        packet.size = sizeof(secret->secret);
2393
        TPM2_Packet_AppendEccPoint(&packet, &pubPoint.point);
2394
        secret->size = packet.pos;
2395
    }
2396
    if (rc == 0) {
2397
        rc = wc_ecc_shared_secret(&eccKeyPriv, &eccKeyPub,
2398
            secretPoint.point.x.buffer, &xSz);
2399
    }
2400
    if (rc == 0) {
2401
        if (xSz == keySz) {
2402
            secretPoint.point.x.size = (UINT16)xSz;
2403
        }
2404
        else {
2405
            rc = BUFFER_E;
2406
        }
2407
    }
2408
    if (rc == 0) {
2409
        /* set size encryption key */
2410
        int hashDigestSz = TPM2_GetHashDigestSize(publicArea->nameAlg);
2411
        if (hashDigestSz > 0 && hashDigestSz <= (int)sizeof(data->buffer)) {
2412
            data->size = (UINT16)hashDigestSz;
2413
        }
2414
        else {
2415
            rc = BUFFER_E;
2416
        }
2417
    }
2418
    if (rc == 0) {
2419
        rc = TPM2_KDFe_ex(
2420
            publicArea->nameAlg,
2421
            secretPoint.point.x.buffer, secretPoint.point.x.size,
2422
            label,
2423
            pubPoint.point.x.buffer, pubPoint.point.x.size,
2424
            publicArea->unique.ecc.x.buffer, publicArea->unique.ecc.x.size,
2425
            data->buffer,
2426
            data->size
2427
        );
2428
    }
2429
2430
    wc_ecc_free(&eccKeyPub);
2431
    wc_ecc_free(&eccKeyPriv);
2432
    wc_FreeRng(&rng);
2433
    TPM2_ForceZero(&eccKeyPub, sizeof(eccKeyPub));
2434
    TPM2_ForceZero(&eccKeyPriv, sizeof(eccKeyPriv));
2435
    TPM2_ForceZero(&rng, sizeof(rng));
2436
    TPM2_ForceZero(&secretPoint, sizeof(secretPoint));
2437
2438
    if (rc >= 0) {
2439
        rc = (rc == data->size) ? 0 /* success */ : BUFFER_E /* fail */;
2440
    }
2441
    if (rc != 0) {
2442
        TPM2_ForceZero(data->buffer, sizeof(data->buffer));
2443
        data->size = 0;
2444
    }
2445
2446
    return rc;
2447
}
2448
#endif /* !WOLFTPM2_NO_WOLFCRYPT && HAVE_ECC && !WC_NO_RNG */
2449
2450
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_RSA) && !defined(WC_NO_RNG)
2451
/* returns both the plaintext and encrypted value */
2452
/* RSA: data = input to encrypt or generated random value
2453
 *      secret = RSA encrypted random */
2454
static int wolfTPM2_EncryptSecret_RSA(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
2455
    TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret, const char* label)
2456
{
2457
    int rc, mgf;
2458
    enum wc_HashType hashType;
2459
    WC_RNG rng;
2460
    RsaKey rsaKey;
2461
    const TPMT_PUBLIC *publicArea;
2462
2463
    publicArea = &tpmKey->pub.publicArea;
2464
    if (publicArea->nameAlg == TPM_ALG_SHA1) {
2465
        hashType = WC_HASH_TYPE_SHA;
2466
        mgf = WC_MGF1SHA1;
2467
    }
2468
    else if (publicArea->nameAlg == TPM_ALG_SHA256) {
2469
        hashType = WC_HASH_TYPE_SHA256;
2470
        mgf = WC_MGF1SHA256;
2471
    }
2472
#ifdef WOLFSSL_SHA384
2473
    else if (publicArea->nameAlg == TPM_ALG_SHA384) {
2474
        hashType = WC_HASH_TYPE_SHA384;
2475
        mgf = WC_MGF1SHA384;
2476
    }
2477
#endif
2478
    else {
2479
        return NOT_COMPILED_IN;
2480
    }
2481
2482
    XMEMSET(&rng, 0, sizeof(rng));
2483
    XMEMSET(&rsaKey, 0, sizeof(rsaKey));
2484
2485
    rc = wc_InitRng_ex(&rng, NULL, INVALID_DEVID);
2486
    if (rc == 0) {
2487
        rc = wc_InitRsaKey_ex(&rsaKey, NULL, INVALID_DEVID);
2488
    }
2489
#ifdef WC_RSA_BLINDING
2490
    if (rc == 0) {
2491
        wc_RsaSetRNG(&rsaKey, &rng);
2492
    }
2493
#endif
2494
    if (rc == 0 && data->size == 0) {
2495
        /* Generate random value to exchange for encryption */
2496
        int hashDigestSz = TPM2_GetHashDigestSize(publicArea->nameAlg);
2497
        if (hashDigestSz > 0 && hashDigestSz <= (int)sizeof(data->buffer)) {
2498
            data->size = (UINT16)hashDigestSz;
2499
        }
2500
        else {
2501
            rc = BUFFER_E;
2502
        }
2503
    }
2504
    if (rc == 0) {
2505
        rc = wc_RNG_GenerateBlock(&rng, data->buffer, data->size);
2506
    }
2507
    if (rc == 0) {
2508
        rc = wolfTPM2_RsaKey_TpmToWolf(dev, (WOLFTPM2_KEY*)tpmKey, &rsaKey);
2509
    }
2510
    if (rc == 0) {
2511
        secret->size = publicArea->unique.rsa.size;
2512
        rc = wc_RsaPublicEncrypt_ex(
2513
            data->buffer,    /* in pointer to the buffer for encryption */
2514
            data->size,      /* inLen length of in parameter */
2515
            secret->secret,  /* out encrypted msg created */
2516
            secret->size,    /* outLen length of buffer available to hold encrypted msg */
2517
            &rsaKey,         /* key initialized RSA key struct */
2518
            &rng,            /* rng initialized WC_RNG struct */
2519
            WC_RSA_OAEP_PAD, /* type type of padding to use (WC_RSA_OAEP_PAD or WC_RSA_PKCSV15_PAD) */
2520
            hashType,        /* hash type of hash to use (choices can be found in hash.h) */
2521
            mgf,             /* mgf type of mask generation function to use */
2522
            (byte*)label,    /* label an optional label to associate with encrypted message */
2523
            (word32)XSTRLEN(label)+1 /* labelSz size of the optional label used */
2524
        );
2525
    }
2526
2527
    wc_FreeRsaKey(&rsaKey);
2528
    TPM2_ForceZero(&rsaKey, sizeof(rsaKey));
2529
    wc_FreeRng(&rng);
2530
    TPM2_ForceZero(&rng, sizeof(rng));
2531
2532
    if (rc > 0) {
2533
        rc = (rc == secret->size) ? 0 /* success */ : BUFFER_E /* fail */;
2534
    }
2535
2536
    if (rc != 0) {
2537
        /* Do not leave the plaintext salt or seed in the caller buffer */
2538
        TPM2_ForceZero(data->buffer, sizeof(data->buffer));
2539
        data->size = 0;
2540
    }
2541
2542
    return rc;
2543
}
2544
#endif /* !WOLFTPM2_NO_WOLFCRYPT && !NO_RSA && !WC_NO_RNG */
2545
2546
#if defined(WOLFTPM_MLKEM_ENCAP) && !defined(WOLFTPM2_NO_WOLFCRYPT) && \
2547
    (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \
2548
     defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024))
2549
#if defined(HAVE_LIBOQS)
2550
    #include <wolfssl/wolfcrypt/ext_mlkem.h>
2551
#else
2552
    #include <wolfssl/wolfcrypt/wc_mlkem.h>
2553
#endif
2554
2555
/* ML-KEM session-salt path per TCG TPM 2.0 Library v1.85 Part 1 Sec.24
2556
 * (p.316) and Sec.47.4 Equation 66 (Labeled KEM): caller encapsulates under
2557
 * the TPM's ML-KEM public key, then post-processes the raw ML-KEM shared
2558
 * secret K via KDFa to bind the label and the (ciphertext, publicKey)
2559
 * context into the returned salt:
2560
 *
2561
 *     seed = KDFa(nameAlg, K, label, ciphertext, publicKey, bits)
2562
 *
2563
 * The TPM decapsulates internally to recover K and runs the same KDFa so
2564
 * both sides agree on `seed` (not the raw K). This matches the Labeled-KEM
2565
 * derivation required for any session where ML-KEM is the key-exchange
2566
 * primitive; emitting raw K would be wire-incompatible with any conformant
2567
 * v1.85 TPM that implements ML-KEM salted sessions. */
2568
static int wolfTPM2_EncryptSecret_MLKEM(const WOLFTPM2_KEY* tpmKey,
2569
    TPM2B_DATA* data, TPM2B_ENCRYPTED_SECRET* secret, const char* label)
2570
{
2571
    int rc;
2572
    int wcType;
2573
    int digestSz;
2574
    int rngInit = 0, keyInit = 0;
2575
    WC_RNG rng;
2576
    MlKemKey mlkemKey;
2577
    const TPMS_MLKEM_PARMS* mlkemParams;
2578
    const TPM2B_PUBLIC_KEY_MLKEM* pubIn;
2579
    word32 ctSz = 0, ssSz = 0;
2580
    byte tmpK[WC_ML_KEM_SS_SZ];
2581
2582
    if (label == NULL) {
2583
        return BAD_FUNC_ARG;
2584
    }
2585
2586
    mlkemParams = &tpmKey->pub.publicArea.parameters.mlkemDetail;
2587
    pubIn = &tpmKey->pub.publicArea.unique.mlkem;
2588
2589
    switch (mlkemParams->parameterSet) {
2590
        case TPM_MLKEM_512:  wcType = WC_ML_KEM_512;  break;
2591
        case TPM_MLKEM_768:  wcType = WC_ML_KEM_768;  break;
2592
        case TPM_MLKEM_1024: wcType = WC_ML_KEM_1024; break;
2593
        default:             return TPM_RC_VALUE;
2594
    }
2595
2596
    digestSz = TPM2_GetHashDigestSize(tpmKey->pub.publicArea.nameAlg);
2597
    if (digestSz <= 0 || digestSz > (int)sizeof(data->buffer)) {
2598
        return TPM_RC_HASH;
2599
    }
2600
2601
    XMEMSET(&rng, 0, sizeof(rng));
2602
    XMEMSET(&mlkemKey, 0, sizeof(mlkemKey));
2603
    XMEMSET(tmpK, 0, sizeof(tmpK));
2604
2605
    rc = wc_InitRng_ex(&rng, NULL, INVALID_DEVID);
2606
    if (rc == 0) {
2607
        rngInit = 1;
2608
        rc = wc_MlKemKey_Init(&mlkemKey, wcType, NULL, INVALID_DEVID);
2609
    }
2610
    if (rc == 0) {
2611
        keyInit = 1;
2612
    }
2613
    if (rc == 0) {
2614
        rc = wc_MlKemKey_DecodePublicKey(&mlkemKey, pubIn->buffer,
2615
            pubIn->size);
2616
    }
2617
    if (rc == 0) {
2618
        rc = wc_MlKemKey_CipherTextSize(&mlkemKey, &ctSz);
2619
    }
2620
    if (rc == 0) {
2621
        rc = wc_MlKemKey_SharedSecretSize(&mlkemKey, &ssSz);
2622
    }
2623
    if (rc == 0 && (ctSz > sizeof(secret->secret) ||
2624
                    ssSz > sizeof(tmpK))) {
2625
        rc = BUFFER_E;
2626
    }
2627
    if (rc == 0) {
2628
        /* K (raw shared secret) lands in tmpK, ciphertext in secret->secret */
2629
        rc = wc_MlKemKey_Encapsulate(&mlkemKey, secret->secret,
2630
            tmpK, &rng);
2631
    }
2632
    if (rc == 0) {
2633
        secret->size = (UINT16)ctSz;
2634
2635
        /* Labeled KEM post-processing (Part 1 Sec.47.4 Eq 66):
2636
         *     data = KDFa(nameAlg, K, label, ciphertext, pubKey, bits)
2637
         * contextU is the ML-KEM ciphertext (already in secret->secret);
2638
         * contextV is the ML-KEM public key; output is `digestSz` bytes. */
2639
        rc = TPM2_KDFa_ex(tpmKey->pub.publicArea.nameAlg,
2640
            tmpK, (UINT32)ssSz, label,
2641
            secret->secret, secret->size,
2642
            pubIn->buffer, pubIn->size,
2643
            data->buffer, (UINT32)digestSz);
2644
        if (rc == digestSz) {
2645
            data->size = (UINT16)digestSz;
2646
            rc = 0;
2647
        }
2648
        else if (rc >= 0) {
2649
            rc = BUFFER_E;
2650
        }
2651
    }
2652
2653
    TPM2_ForceZero(tmpK, sizeof(tmpK));
2654
    if (keyInit) {
2655
        wc_MlKemKey_Free(&mlkemKey);
2656
    }
2657
    TPM2_ForceZero(&mlkemKey, sizeof(mlkemKey));
2658
    if (rngInit) {
2659
        wc_FreeRng(&rng);
2660
    }
2661
    TPM2_ForceZero(&rng, sizeof(rng));
2662
2663
    /* On any failure scrub the caller's data buffer so partial KDFa
2664
     * output (derived from the raw shared secret K) cannot leak via a
2665
     * caller that ignores rc. wolfCrypt's TPM2_KDFa never partially
2666
     * writes today, but defense-in-depth -- the buffer is always zeroed
2667
     * on the failure path. */
2668
    if (rc != 0) {
2669
        TPM2_ForceZero(data->buffer, sizeof(data->buffer));
2670
        data->size = 0;
2671
    }
2672
2673
    return rc;
2674
}
2675
#endif /* WOLFTPM_MLKEM_ENCAP && ML-KEM enabled */
2676
2677
int wolfTPM2_EncryptSecret(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpmKey,
2678
    TPM2B_DATA *data, TPM2B_ENCRYPTED_SECRET *secret,
2679
    const char* label)
2680
{
2681
    int rc = NOT_COMPILED_IN;
2682
2683
    /* if a tpmKey is not present then we are using an unsalted session */
2684
    if (tpmKey == NULL) {
2685
        return TPM_RC_SUCCESS;
2686
    }
2687
2688
    if (dev == NULL || data == NULL || secret == NULL) {
2689
        return BAD_FUNC_ARG;
2690
    }
2691
2692
#ifdef DEBUG_WOLFTPM
2693
    printf("Encrypt secret: Alg %s, Label %s\n",
2694
        TPM2_GetAlgName(tpmKey->pub.publicArea.type), label);
2695
#endif
2696
2697
#ifndef WOLFTPM2_NO_WOLFCRYPT
2698
    switch (tpmKey->pub.publicArea.type) {
2699
    #if defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
2700
        defined(HAVE_ECC_DHE) && defined(HAVE_ECC_KEY_IMPORT) && \
2701
        defined(HAVE_ECC_KEY_EXPORT)
2702
        case TPM_ALG_ECC:
2703
            rc = wolfTPM2_EncryptSecret_ECC(dev, tpmKey, data, secret, label);
2704
            break;
2705
    #endif
2706
    #if !defined(NO_RSA) && !defined(WC_NO_RNG)
2707
        case TPM_ALG_RSA:
2708
            rc = wolfTPM2_EncryptSecret_RSA(dev, tpmKey, data, secret, label);
2709
            break;
2710
    #endif
2711
    #if defined(WOLFTPM_MLKEM_ENCAP) && \
2712
        (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \
2713
         defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024))
2714
        case TPM_ALG_MLKEM:
2715
            /* Part 1 Sec.47.4 Eq 66 Labeled KEM: label MUST be threaded into
2716
             * the post-Encaps KDFa so client-derived `seed` matches what
2717
             * a conformant TPM derives on Decaps. */
2718
            rc = wolfTPM2_EncryptSecret_MLKEM(tpmKey, data, secret, label);
2719
            break;
2720
    #endif
2721
        default:
2722
            rc = NOT_COMPILED_IN;
2723
            break;
2724
    }
2725
2726
#ifdef WOLFTPM_DEBUG_VERBOSE
2727
    printf("Encrypt Secret %d: %d bytes\n", rc, data->size);
2728
#ifdef WOLFTPM_DEBUG_SECRETS
2729
    TPM2_PrintBin(data->buffer, data->size);
2730
#endif
2731
#endif
2732
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
2733
2734
    (void)label;
2735
2736
    return rc;
2737
}
2738
2739
int wolfTPM2_StartSession_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
2740
    WOLFTPM2_KEY* tpmKey, WOLFTPM2_HANDLE* bind, TPM_SE sesType,
2741
    int encDecAlg, TPMI_ALG_HASH authHash)
2742
{
2743
    int rc = TPM_RC_SUCCESS;
2744
    StartAuthSession_In  authSesIn;
2745
    StartAuthSession_Out authSesOut;
2746
    WOLFTPM2_HANDLE sessionHandle;
2747
    byte keyIn[TPM_MAX_DIGEST_SIZE * 2];
2748
    UINT16 keyInSz = 0;
2749
    int hashDigestSz;
2750
    TPMA_SESSION sessionAttributes = 0;
2751
2752
    if (dev == NULL || session == NULL)
2753
        return BAD_FUNC_ARG;
2754
2755
    /* TPM_ALG_NULL selects the wrapper default hash */
2756
    if (authHash == TPM_ALG_NULL)
2757
        authHash = WOLFTPM2_WRAP_DIGEST;
2758
2759
    XMEMSET(session, 0, sizeof(WOLFTPM2_SESSION));
2760
    XMEMSET(&authSesIn, 0, sizeof(authSesIn));
2761
    XMEMSET(&authSesOut, 0, sizeof(authSesOut));
2762
    XMEMSET(keyIn, 0, sizeof(keyIn));
2763
2764
    authSesIn.authHash = authHash;
2765
    hashDigestSz = TPM2_GetHashDigestSize(authHash);
2766
    if (hashDigestSz <= 0 ||
2767
        hashDigestSz > (int)sizeof(authSesIn.nonceCaller.buffer)) {
2768
        return BUFFER_E;
2769
    }
2770
    /* reject session hashes weaker than the wrapper default */
2771
    if (hashDigestSz < TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
2772
        return BAD_FUNC_ARG;
2773
    }
2774
2775
    /* StartAuthSession has no authorization area. Keep slot 0 clear instead
2776
     * of copying the salt key authorization into persistent device state. */
2777
    if (tpmKey && (encDecAlg == TPM_ALG_CFB || encDecAlg == TPM_ALG_XOR)) {
2778
        sessionAttributes = TPMA_SESSION_decrypt | TPMA_SESSION_encrypt;
2779
    }
2780
    wolfTPM2_SetAuth(dev, 0, TPM_RS_PW, NULL, sessionAttributes, NULL);
2781
    if (tpmKey) {
2782
        authSesIn.tpmKey = tpmKey->handle.hndl;
2783
    }
2784
    else {
2785
        authSesIn.tpmKey = (TPMI_DH_OBJECT)TPM_RH_NULL;
2786
    }
2787
    /* setup bind key */
2788
    authSesIn.bind = (TPMI_DH_ENTITY)TPM_RH_NULL;
2789
    if (bind) {
2790
        authSesIn.bind = bind->hndl;
2791
    }
2792
2793
    authSesIn.sessionType = sesType;
2794
    if (encDecAlg == TPM_ALG_CFB) {
2795
        authSesIn.symmetric.algorithm = TPM_ALG_AES;
2796
        /* Scale AES key size to match session hash strength */
2797
        authSesIn.symmetric.keyBits.aes = (hashDigestSz > 32) ? 256 : 128;
2798
        authSesIn.symmetric.mode.aes = TPM_ALG_CFB;
2799
    }
2800
    else if (encDecAlg == TPM_ALG_XOR) {
2801
        authSesIn.symmetric.algorithm = TPM_ALG_XOR;
2802
        authSesIn.symmetric.keyBits.xorr = authHash;
2803
        authSesIn.symmetric.mode.sym = TPM_ALG_NULL;
2804
    }
2805
    else {
2806
        authSesIn.symmetric.algorithm = TPM_ALG_NULL;
2807
    }
2808
    authSesIn.nonceCaller.size = hashDigestSz;
2809
    rc = TPM2_GetNonceNoLock(authSesIn.nonceCaller.buffer,
2810
                       authSesIn.nonceCaller.size);
2811
    if (rc < 0) {
2812
    #ifdef DEBUG_WOLFTPM
2813
        printf("TPM2_GetNonce failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
2814
    #endif
2815
        TPM2_ForceZero(&authSesIn, sizeof(authSesIn));
2816
        TPM2_ForceZero(&authSesOut, sizeof(authSesOut));
2817
        return rc;
2818
    }
2819
2820
    if (authSesIn.tpmKey != TPM_RH_NULL) {
2821
        /* Generate random salt */
2822
        session->salt.size = hashDigestSz;
2823
        rc = TPM2_GetNonceNoLock(session->salt.buffer, session->salt.size);
2824
        if (rc != 0) {
2825
            TPM2_ForceZero(&session->salt, sizeof(session->salt));
2826
            TPM2_ForceZero(&authSesIn, sizeof(authSesIn));
2827
            TPM2_ForceZero(&authSesOut, sizeof(authSesOut));
2828
            return rc;
2829
        }
2830
2831
        /* Encrypt salt using "SECRET" */
2832
        rc = wolfTPM2_EncryptSecret(dev, tpmKey, (TPM2B_DATA*)&session->salt,
2833
            &authSesIn.encryptedSalt, "SECRET");
2834
        if (rc != 0) {
2835
        #ifdef DEBUG_WOLFTPM
2836
            printf("Building encrypted salt failed %d: %s!\n", rc,
2837
                wolfTPM2_GetRCString(rc));
2838
        #endif
2839
            TPM2_ForceZero(&session->salt, sizeof(session->salt));
2840
            TPM2_ForceZero(&authSesIn, sizeof(authSesIn));
2841
            TPM2_ForceZero(&authSesOut, sizeof(authSesOut));
2842
            return rc;
2843
        }
2844
    }
2845
2846
    rc = TPM2_StartAuthSession(&authSesIn, &authSesOut);
2847
    if (rc != TPM_RC_SUCCESS) {
2848
    #ifdef DEBUG_WOLFTPM
2849
        printf("TPM2_StartAuthSession failed %d: %s\n", rc,
2850
            wolfTPM2_GetRCString(rc));
2851
    #endif
2852
        TPM2_ForceZero(&session->salt, sizeof(session->salt));
2853
        TPM2_ForceZero(&authSesIn, sizeof(authSesIn));
2854
        TPM2_ForceZero(&authSesOut, sizeof(authSesOut));
2855
        return rc;
2856
    }
2857
2858
    /* Calculate "key" and store into auth */
2859
    /* key is bindAuthValue || salt */
2860
    if (bind && bind->auth.size > 0) {
2861
        if (bind->auth.size > (UINT16)sizeof(bind->auth.buffer)) {
2862
            rc = BUFFER_E;
2863
        }
2864
        if (rc == TPM_RC_SUCCESS) {
2865
            if ((keyInSz + bind->auth.size) > (UINT16)sizeof(keyIn)) {
2866
                rc = BUFFER_E;
2867
            }
2868
            else {
2869
                XMEMCPY(&keyIn[keyInSz], bind->auth.buffer, bind->auth.size);
2870
                keyInSz += bind->auth.size;
2871
            }
2872
        }
2873
    }
2874
    if (rc == TPM_RC_SUCCESS && session->salt.size > 0) {
2875
        if (session->salt.size > (UINT16)sizeof(session->salt.buffer)) {
2876
            rc = BUFFER_E;
2877
        }
2878
        if (rc == TPM_RC_SUCCESS) {
2879
            if ((keyInSz + session->salt.size) > (UINT16)sizeof(keyIn)) {
2880
                rc = BUFFER_E;
2881
            }
2882
            else {
2883
                XMEMCPY(&keyIn[keyInSz], session->salt.buffer,
2884
                    session->salt.size);
2885
                keyInSz += session->salt.size;
2886
            }
2887
        }
2888
    }
2889
2890
    /* Compute the sessionKey when salted or bound. A bound EmptyAuth session
2891
     * still derives a key (KDFa over a zero-length input); only a fully
2892
     * unbound, unsalted session keeps an empty sessionKey. Gate on the bind
2893
     * handle value (not just the pointer) so a NULL-handle bind matches the
2894
     * TPM's own bound-ness test. */
2895
    if (rc == TPM_RC_SUCCESS &&
2896
            (keyInSz > 0 || (bind != NULL && bind->hndl != TPM_RH_NULL))) {
2897
        session->handle.auth.size = hashDigestSz;
2898
        rc = TPM2_KDFa_ex(authSesIn.authHash,
2899
            keyIn, keyInSz, "ATH",
2900
            authSesOut.nonceTPM.buffer, authSesOut.nonceTPM.size,
2901
            authSesIn.nonceCaller.buffer, authSesIn.nonceCaller.size,
2902
            session->handle.auth.buffer, session->handle.auth.size);
2903
        if (rc == hashDigestSz) {
2904
            rc = TPM_RC_SUCCESS;
2905
        }
2906
        else {
2907
        #ifdef DEBUG_WOLFTPM
2908
            printf("KDFa ATH Gen Error %d\n", rc);
2909
        #endif
2910
            rc = TPM_RC_FAILURE;
2911
        }
2912
    }
2913
2914
    /* Erase salt after key generation */
2915
    TPM2_ForceZero(&session->salt, sizeof(session->salt));
2916
2917
    if (rc == TPM_RC_SUCCESS) {
2918
#ifdef WOLFTPM_DEBUG_VERBOSE
2919
        printf("Session Key %d\n", session->handle.auth.size);
2920
    #ifdef WOLFTPM_DEBUG_SECRETS
2921
        TPM2_PrintBin(session->handle.auth.buffer, session->handle.auth.size);
2922
    #endif
2923
#endif
2924
2925
        /* return session */
2926
        session->type = authSesIn.sessionType;
2927
        session->authHash = authSesIn.authHash;
2928
        session->handle.hndl = authSesOut.sessionHandle;
2929
        wolfTPM2_CopySymmetric(&session->handle.symmetric, &authSesIn.symmetric);
2930
        if (bind) {
2931
            session->bind = &bind->auth; /* pointer to bind key auth */
2932
            wolfTPM2_CopyName(&session->handle.name, &bind->name);
2933
        }
2934
        session->nonceCaller.size = authSesIn.nonceCaller.size;
2935
        if (session->nonceCaller.size > (UINT16)sizeof(session->nonceCaller.buffer))
2936
            session->nonceCaller.size = (UINT16)sizeof(session->nonceCaller.buffer);
2937
        XMEMCPY(session->nonceCaller.buffer, authSesIn.nonceCaller.buffer,
2938
            session->nonceCaller.size);
2939
        session->nonceTPM.size = authSesOut.nonceTPM.size;
2940
        if (session->nonceTPM.size > (UINT16)sizeof(session->nonceTPM.buffer))
2941
            session->nonceTPM.size = (UINT16)sizeof(session->nonceTPM.buffer);
2942
        XMEMCPY(session->nonceTPM.buffer, authSesOut.nonceTPM.buffer,
2943
            session->nonceTPM.size);
2944
2945
#ifdef DEBUG_WOLFTPM
2946
        printf("TPM2_StartAuthSession: handle 0x%x, algorithm %s\n",
2947
            (word32)session->handle.hndl,
2948
            TPM2_GetAlgName(authSesIn.symmetric.algorithm));
2949
#endif
2950
    }
2951
    else {
2952
        /* flush the started session so a post-start failure does not leak
2953
         * a scarce TPM session slot */
2954
        XMEMSET(&sessionHandle, 0, sizeof(sessionHandle));
2955
        sessionHandle.hndl = authSesOut.sessionHandle;
2956
        (void)wolfTPM2_UnloadHandle(dev, &sessionHandle);
2957
    }
2958
2959
    TPM2_ForceZero(keyIn, sizeof(keyIn));
2960
    TPM2_ForceZero(&authSesIn, sizeof(authSesIn));
2961
    TPM2_ForceZero(&authSesOut, sizeof(authSesOut));
2962
2963
    return rc;
2964
}
2965
2966
int wolfTPM2_StartSession(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
2967
    WOLFTPM2_KEY* tpmKey, WOLFTPM2_HANDLE* bind, TPM_SE sesType,
2968
    int encDecAlg)
2969
{
2970
    return wolfTPM2_StartSession_ex(dev, session, tpmKey, bind, sesType,
2971
        encDecAlg, WOLFTPM2_WRAP_DIGEST);
2972
}
2973
2974
2975
int wolfTPM2_CreatePrimaryKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_PKEY* pkey,
2976
    TPM_HANDLE primaryHandle, TPMT_PUBLIC* publicTemplate,
2977
    const byte* auth, int authSz)
2978
{
2979
    int rc;
2980
    CreatePrimary_In  createPriIn;
2981
    CreatePrimary_Out createPriOut;
2982
    TPMT_TK_CREATION* ticket;
2983
2984
    if (dev == NULL || pkey == NULL || publicTemplate == NULL)
2985
        return BAD_FUNC_ARG;
2986
2987
    /* set session auth to blank */
2988
    wolfTPM2_SetAuthPassword(dev, 0, NULL);
2989
2990
    /* clear output key buffer */
2991
    XMEMSET(pkey, 0, sizeof(*pkey));
2992
2993
    /* setup create primary command */
2994
    XMEMSET(&createPriIn, 0, sizeof(createPriIn));
2995
    XMEMSET(&createPriOut, 0, sizeof(createPriOut));
2996
    /* TPM_RH_OWNER, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM or TPM_RH_NULL */
2997
    createPriIn.primaryHandle = primaryHandle;
2998
    if (auth && authSz > 0) {
2999
        TPM2B_AUTH* createPriAuth = &createPriIn.inSensitive.sensitive.userAuth;
3000
        int nameAlgDigestSz = TPM2_GetHashDigestSize(publicTemplate->nameAlg);
3001
        /* Ensure auth size matches the name algorithm digest size.
3002
         * Note: Auth values shorter than the digest size are zero-padded
3003
         * to the full digest length. This is a wolfTPM convention for
3004
         * primary keys and may differ from other TPM stacks that accept
3005
         * shorter auth values as-is. */
3006
        if (nameAlgDigestSz > 0) {
3007
            /* Reject oversized auth rather than silently truncating it,
3008
             * consistent with wolfTPM2_CreateKey */
3009
            if (authSz > nameAlgDigestSz) {
3010
                return BUFFER_E;
3011
            }
3012
            XMEMCPY(createPriAuth->buffer, auth, authSz);
3013
            if (authSz < nameAlgDigestSz) {
3014
                XMEMSET(createPriAuth->buffer + authSz, 0,
3015
                    nameAlgDigestSz - authSz);
3016
                authSz = nameAlgDigestSz;
3017
            }
3018
        }
3019
        else {
3020
            if (authSz > (int)sizeof(createPriAuth->buffer)) {
3021
                return BUFFER_E;
3022
            }
3023
            XMEMCPY(createPriAuth->buffer, auth, authSz);
3024
        }
3025
        createPriAuth->size = authSz;
3026
    }
3027
    XMEMCPY(&createPriIn.inPublic.publicArea, publicTemplate,
3028
        sizeof(TPMT_PUBLIC));
3029
    rc = TPM2_CreatePrimary(&createPriIn, &createPriOut);
3030
    if (rc != TPM_RC_SUCCESS) {
3031
    #ifdef DEBUG_WOLFTPM
3032
        printf("TPM2_CreatePrimary: failed %d: %s\n", rc,
3033
            wolfTPM2_GetRCString(rc));
3034
    #endif
3035
        TPM2_ForceZero(&createPriIn.inSensitive,
3036
            sizeof(createPriIn.inSensitive));
3037
        return rc;
3038
    }
3039
    pkey->handle.hndl = createPriOut.objectHandle;
3040
    wolfTPM2_CopyAuth(&pkey->handle.auth,
3041
        &createPriIn.inSensitive.sensitive.userAuth);
3042
    wolfTPM2_CopyName(&pkey->handle.name, &createPriOut.name);
3043
    wolfTPM2_CopySymmetric(&pkey->handle.symmetric,
3044
        &createPriOut.outPublic.publicArea.parameters.asymDetail.symmetric);
3045
    wolfTPM2_CopyPub(&pkey->pub, &createPriOut.outPublic);
3046
3047
    pkey->creationHash.size = createPriOut.creationHash.size;
3048
    if (pkey->creationHash.size > sizeof(pkey->creationHash.buffer)) {
3049
        pkey->creationHash.size = sizeof(pkey->creationHash.buffer);
3050
    }
3051
    XMEMCPY(pkey->creationHash.buffer, createPriOut.creationHash.buffer,
3052
        pkey->creationHash.size);
3053
3054
    ticket = &pkey->creationTicket;
3055
    ticket->tag = createPriOut.creationTicket.tag;
3056
    ticket->hierarchy = createPriOut.creationTicket.hierarchy;
3057
    ticket->digest.size = createPriOut.creationTicket.digest.size;
3058
    if (ticket->digest.size > sizeof(ticket->digest.buffer)) {
3059
        ticket->digest.size = sizeof(ticket->digest.buffer);
3060
    }
3061
    XMEMCPY(ticket->digest.buffer, createPriOut.creationTicket.digest.buffer,
3062
            ticket->digest.size);
3063
3064
#ifdef DEBUG_WOLFTPM
3065
    printf("TPM2_CreatePrimary: 0x%x (%d bytes)\n",
3066
        (word32)pkey->handle.hndl, pkey->pub.size);
3067
#endif
3068
3069
    TPM2_ForceZero(&createPriIn.inSensitive, sizeof(createPriIn.inSensitive));
3070
    return rc;
3071
}
3072
3073
int wolfTPM2_CreatePrimaryKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3074
    TPM_HANDLE primaryHandle, TPMT_PUBLIC* publicTemplate,
3075
    const byte* auth, int authSz)
3076
{
3077
    int rc;
3078
    WOLFTPM2_PKEY pKey;
3079
    if (dev == NULL || key == NULL || publicTemplate == NULL)
3080
        return BAD_FUNC_ARG;
3081
    rc = wolfTPM2_CreatePrimaryKey_ex(dev, &pKey, primaryHandle, publicTemplate,
3082
        auth, authSz);
3083
    if (rc == 0) {
3084
        /* return only the handle and public information */
3085
        XMEMCPY(&key->handle, &pKey.handle, sizeof(WOLFTPM2_HANDLE));
3086
        XMEMCPY(&key->pub, &pKey.pub, sizeof(TPM2B_PUBLIC));
3087
    }
3088
    /* scrub the duplicated primary-key auth from the local copy */
3089
    TPM2_ForceZero(&pKey, sizeof(pKey));
3090
    return rc;
3091
}
3092
3093
int wolfTPM2_ChangeAuthKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3094
    WOLFTPM2_HANDLE* parent, const byte* auth, int authSz)
3095
{
3096
    int rc;
3097
    ObjectChangeAuth_In changeIn;
3098
    ObjectChangeAuth_Out changeOut;
3099
    Load_In  loadIn;
3100
    Load_Out loadOut;
3101
3102
    if (dev == NULL || key == NULL || parent == NULL)
3103
        return BAD_FUNC_ARG;
3104
3105
    /* set session auth for key */
3106
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
3107
3108
    XMEMSET(&changeIn, 0, sizeof(changeIn));
3109
    changeIn.objectHandle = key->handle.hndl;
3110
    changeIn.parentHandle = parent->hndl;
3111
    if (auth) {
3112
        if (authSz < 0) {
3113
            return BAD_FUNC_ARG;
3114
        }
3115
        /* Note: returns error instead of truncating for security (v3.11+) */
3116
        if (authSz > (int)sizeof(changeIn.newAuth.buffer)) {
3117
            return BUFFER_E;
3118
        }
3119
        changeIn.newAuth.size = (UINT16)authSz;
3120
        XMEMCPY(changeIn.newAuth.buffer, auth, authSz);
3121
    }
3122
3123
    rc = TPM2_ObjectChangeAuth(&changeIn, &changeOut);
3124
    if (rc != TPM_RC_SUCCESS) {
3125
    #ifdef DEBUG_WOLFTPM
3126
        printf("TPM2_ObjectChangeAuth failed %d: %s\n", rc,
3127
                wolfTPM2_GetRCString(rc));
3128
    #endif
3129
        TPM2_ForceZero(&changeIn, sizeof(changeIn));
3130
        return rc;
3131
    }
3132
3133
    /* unload old key */
3134
    wolfTPM2_UnloadHandle(dev, &key->handle);
3135
3136
    /* set session auth for parent key */
3137
    wolfTPM2_SetAuthHandle(dev, 0, parent);
3138
3139
    /* Load new key */
3140
    XMEMSET(&loadIn, 0, sizeof(loadIn));
3141
    loadIn.parentHandle = parent->hndl;
3142
    wolfTPM2_CopyPriv(&loadIn.inPrivate, &changeOut.outPrivate);
3143
    wolfTPM2_CopyPub(&loadIn.inPublic, &key->pub);
3144
    rc = TPM2_Load(&loadIn, &loadOut);
3145
    if (rc != TPM_RC_SUCCESS) {
3146
    #ifdef DEBUG_WOLFTPM
3147
        printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
3148
    #endif
3149
        if (key->handle.hndl == 0 ||
3150
                key->handle.hndl == TPM_RH_NULL) {
3151
            TPM2_ForceZero(&key->handle.auth,
3152
                sizeof(key->handle.auth));
3153
        }
3154
        TPM2_ForceZero(&changeIn, sizeof(changeIn));
3155
        TPM2_ForceZero(&changeOut, sizeof(changeOut));
3156
        TPM2_ForceZero(&loadIn, sizeof(loadIn));
3157
        return rc;
3158
    }
3159
    key->handle.hndl = loadOut.objectHandle;
3160
    wolfTPM2_CopyAuth(&key->handle.auth, &changeIn.newAuth);
3161
    wolfTPM2_CopyName(&key->handle.name, &loadOut.name);
3162
3163
#ifdef DEBUG_WOLFTPM
3164
    printf("wolfTPM2_ChangeAuthKey: Key Handle 0x%x\n",
3165
        (word32)key->handle.hndl);
3166
#endif
3167
3168
    TPM2_ForceZero(&changeIn, sizeof(changeIn));
3169
    TPM2_ForceZero(&changeOut, sizeof(changeOut));
3170
    TPM2_ForceZero(&loadIn, sizeof(loadIn));
3171
3172
    return rc;
3173
}
3174
3175
int wolfTPM2_CreateKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
3176
    WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
3177
    const byte* auth, int authSz)
3178
{
3179
    int rc;
3180
    Create_In  createIn;
3181
    Create_Out createOut;
3182
3183
    if (dev == NULL || keyBlob == NULL || parent == NULL ||
3184
            publicTemplate == NULL || authSz < 0) {
3185
        return BAD_FUNC_ARG;
3186
    }
3187
3188
    /* clear output key buffer */
3189
    XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
3190
    XMEMSET(&createOut, 0, sizeof(createOut)); /* make sure pub struct is zero init */
3191
3192
    /* set session auth for parent key */
3193
    wolfTPM2_SetAuthHandle(dev, 0, parent);
3194
3195
    XMEMSET(&createIn, 0, sizeof(createIn));
3196
    createIn.parentHandle = parent->hndl;
3197
    if (auth) {
3198
        TPM2B_AUTH* pAuth = &createIn.inSensitive.sensitive.userAuth;
3199
        int nameAlgDigestSz = TPM2_GetHashDigestSize(publicTemplate->nameAlg);
3200
        if (nameAlgDigestSz > 0) {
3201
            /* Reject oversized auth rather than silently truncating it */
3202
            if (authSz > nameAlgDigestSz) {
3203
                return BUFFER_E;
3204
            }
3205
            XMEMCPY(pAuth->buffer, auth, authSz);
3206
            if (authSz < nameAlgDigestSz) {
3207
                XMEMSET(pAuth->buffer + authSz, 0,
3208
                    nameAlgDigestSz - authSz);
3209
                authSz = nameAlgDigestSz;
3210
            }
3211
        }
3212
        else {
3213
            if (authSz > (int)sizeof(pAuth->buffer)) {
3214
                return BUFFER_E;
3215
            }
3216
            XMEMCPY(pAuth->buffer, auth, authSz);
3217
        }
3218
        pAuth->size = (UINT16)authSz;
3219
    }
3220
    wolfTPM2_CopyPubT(&createIn.inPublic.publicArea, publicTemplate);
3221
3222
#if 0
3223
    /* Optional creation nonce */
3224
    createIn.outsideInfo.size = createNoneSz;
3225
    XMEMCPY(createIn.outsideInfo.buffer, createNonce, createIn.outsideInfo.size);
3226
#endif
3227
3228
    rc = TPM2_Create(&createIn, &createOut);
3229
    if (rc != TPM_RC_SUCCESS) {
3230
    #ifdef DEBUG_WOLFTPM
3231
        printf("TPM2_Create key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
3232
    #endif
3233
        TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
3234
        return rc;
3235
    }
3236
3237
#ifdef DEBUG_WOLFTPM
3238
    printf("TPM2_Create key: pub %d, priv %d\n",
3239
        createOut.outPublic.size, createOut.outPrivate.size);
3240
    TPM2_PrintPublicArea(&createOut.outPublic);
3241
#endif
3242
3243
    wolfTPM2_CopyAuth(&keyBlob->handle.auth,
3244
        &createIn.inSensitive.sensitive.userAuth);
3245
    wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
3246
            &createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
3247
    wolfTPM2_CopyPub(&keyBlob->pub, &createOut.outPublic);
3248
    wolfTPM2_CopyPriv(&keyBlob->priv, &createOut.outPrivate);
3249
3250
    TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
3251
    TPM2_ForceZero(&createOut.outPrivate, sizeof(createOut.outPrivate));
3252
    return rc;
3253
}
3254
3255
int wolfTPM2_LoadKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
3256
    WOLFTPM2_HANDLE* parent)
3257
{
3258
    int rc;
3259
    Load_In loadIn;
3260
    Load_Out loadOut;
3261
3262
    if (dev == NULL || keyBlob == NULL || parent == NULL)
3263
        return BAD_FUNC_ARG;
3264
3265
    /* set session auth for parent key */
3266
    wolfTPM2_SetAuthHandle(dev, 0, parent);
3267
3268
    /* Load new key */
3269
    XMEMSET(&loadIn, 0, sizeof(loadIn));
3270
    loadIn.parentHandle = parent->hndl;
3271
    wolfTPM2_CopyPriv(&loadIn.inPrivate, &keyBlob->priv);
3272
    wolfTPM2_CopyPub(&loadIn.inPublic, &keyBlob->pub);
3273
    rc = TPM2_Load(&loadIn, &loadOut);
3274
    if (rc != TPM_RC_SUCCESS) {
3275
    #ifdef DEBUG_WOLFTPM
3276
        printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
3277
    #endif
3278
        TPM2_ForceZero(&loadIn, sizeof(loadIn));
3279
        return rc;
3280
    }
3281
    keyBlob->handle.hndl = loadOut.objectHandle;
3282
    wolfTPM2_CopyName(&keyBlob->handle.name, &loadOut.name);
3283
3284
#ifdef DEBUG_WOLFTPM
3285
    printf("TPM2_Load Key Handle 0x%x\n", (word32)keyBlob->handle.hndl);
3286
#endif
3287
3288
    TPM2_ForceZero(&loadIn, sizeof(loadIn));
3289
    return rc;
3290
}
3291
3292
int wolfTPM2_CreateAndLoadKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3293
    WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
3294
    const byte* auth, int authSz)
3295
{
3296
    int rc;
3297
    WOLFTPM2_KEYBLOB keyBlob;
3298
3299
    if (dev == NULL || key == NULL)
3300
        return BAD_FUNC_ARG;
3301
3302
    XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
3303
    XMEMSET(&keyBlob, 0, sizeof(keyBlob));
3304
3305
    rc = wolfTPM2_CreateKey(dev, &keyBlob, parent, publicTemplate,
3306
        auth, authSz);
3307
    if (rc == TPM_RC_SUCCESS) {
3308
        rc = wolfTPM2_LoadKey(dev, &keyBlob, parent);
3309
    }
3310
3311
    if (rc == TPM_RC_SUCCESS) {
3312
        /* return loaded key */
3313
        XMEMCPY(key, &keyBlob, sizeof(WOLFTPM2_KEY));
3314
    }
3315
3316
    TPM2_ForceZero(&keyBlob, sizeof(keyBlob));
3317
    return rc;
3318
}
3319
3320
int wolfTPM2_CreateLoadedKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
3321
    WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
3322
    const byte* auth, int authSz)
3323
{
3324
    int rc;
3325
    CreateLoaded_In  createLoadedIn;
3326
    CreateLoaded_Out createLoadedOut;
3327
3328
    if (dev == NULL || keyBlob == NULL || parent == NULL ||
3329
            publicTemplate == NULL) {
3330
        return BAD_FUNC_ARG;
3331
    }
3332
3333
    /* clear output key buffer */
3334
    XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
3335
    XMEMSET(&createLoadedOut, 0, sizeof(createLoadedOut)); /* make sure pub struct is zero init */
3336
3337
    /* set session auth for parent key */
3338
    wolfTPM2_SetAuthHandle(dev, 0, parent);
3339
3340
    XMEMSET(&createLoadedIn, 0, sizeof(createLoadedIn));
3341
    createLoadedIn.parentHandle = parent->hndl;
3342
    if (auth) {
3343
        TPM2B_AUTH* pAuth = &createLoadedIn.inSensitive.sensitive.userAuth;
3344
        int nameAlgDigestSz = TPM2_GetHashDigestSize(publicTemplate->nameAlg);
3345
        if (authSz < 0) {
3346
            return BAD_FUNC_ARG;
3347
        }
3348
        if (nameAlgDigestSz > 0) {
3349
            /* Reject oversized auth rather than silently truncating it,
3350
             * consistent with wolfTPM2_CreateKey */
3351
            if (authSz > nameAlgDigestSz) {
3352
                return BUFFER_E;
3353
            }
3354
            XMEMCPY(pAuth->buffer, auth, authSz);
3355
            if (authSz < nameAlgDigestSz) {
3356
                XMEMSET(pAuth->buffer + authSz, 0,
3357
                    nameAlgDigestSz - authSz);
3358
                authSz = nameAlgDigestSz;
3359
            }
3360
        }
3361
        else {
3362
            if (authSz > (int)sizeof(pAuth->buffer)) {
3363
                return BUFFER_E;
3364
            }
3365
            XMEMCPY(pAuth->buffer, auth, authSz);
3366
        }
3367
        pAuth->size = (UINT16)authSz;
3368
    }
3369
    XMEMCPY(&createLoadedIn.inPublic.publicArea, publicTemplate,
3370
        sizeof(TPMT_PUBLIC));
3371
3372
    rc = TPM2_CreateLoaded(&createLoadedIn, &createLoadedOut);
3373
    if (rc != TPM_RC_SUCCESS) {
3374
    #ifdef DEBUG_WOLFTPM
3375
        printf("TPM2_CreateLoaded key failed %d: %s\n",
3376
            rc, wolfTPM2_GetRCString(rc));
3377
    #endif
3378
        TPM2_ForceZero(&createLoadedIn.inSensitive,
3379
            sizeof(createLoadedIn.inSensitive));
3380
        return rc;
3381
    }
3382
3383
#ifdef DEBUG_WOLFTPM
3384
    printf("TPM2_CreateLoaded key: pub %d, priv %d\n",
3385
        createLoadedOut.outPublic.size, createLoadedOut.outPrivate.size);
3386
    TPM2_PrintPublicArea(&createLoadedOut.outPublic);
3387
#endif
3388
3389
    keyBlob->handle.hndl = createLoadedOut.objectHandle;
3390
3391
    wolfTPM2_CopyAuth(&keyBlob->handle.auth,
3392
        &createLoadedIn.inSensitive.sensitive.userAuth);
3393
    wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
3394
      &createLoadedOut.outPublic.publicArea.parameters.asymDetail.symmetric);
3395
3396
    wolfTPM2_CopyPub(&keyBlob->pub, &createLoadedOut.outPublic);
3397
    wolfTPM2_CopyPriv(&keyBlob->priv, &createLoadedOut.outPrivate);
3398
    wolfTPM2_CopyName(&keyBlob->handle.name, &createLoadedOut.name);
3399
3400
    TPM2_ForceZero(&createLoadedIn.inSensitive,
3401
        sizeof(createLoadedIn.inSensitive));
3402
    TPM2_ForceZero(&createLoadedOut.outPrivate,
3403
        sizeof(createLoadedOut.outPrivate));
3404
    return rc;
3405
}
3406
3407
int wolfTPM2_LoadPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3408
    const TPM2B_PUBLIC* pub, TPM_HANDLE hierarchy)
3409
{
3410
    int rc;
3411
    LoadExternal_In  loadExtIn;
3412
    LoadExternal_Out loadExtOut;
3413
3414
    if (dev == NULL || key == NULL || pub == NULL)
3415
        return BAD_FUNC_ARG;
3416
3417
    /* Loading public key */
3418
    XMEMSET(&loadExtIn, 0, sizeof(loadExtIn));
3419
    wolfTPM2_CopyPub(&loadExtIn.inPublic, pub);
3420
    loadExtIn.hierarchy = hierarchy;
3421
    rc = TPM2_LoadExternal(&loadExtIn, &loadExtOut);
3422
    if (rc != TPM_RC_SUCCESS) {
3423
    #ifdef DEBUG_WOLFTPM
3424
        printf("TPM2_LoadExternal: failed %d: %s\n", rc,
3425
            wolfTPM2_GetRCString(rc));
3426
    #endif
3427
        return rc;
3428
    }
3429
    key->handle.hndl = loadExtOut.objectHandle;
3430
    wolfTPM2_CopySymmetric(&key->handle.symmetric,
3431
            &loadExtIn.inPublic.publicArea.parameters.asymDetail.symmetric);
3432
    wolfTPM2_CopyName(&key->handle.name, &loadExtOut.name);
3433
    wolfTPM2_CopyPub(&key->pub, &loadExtIn.inPublic);
3434
3435
#ifdef DEBUG_WOLFTPM
3436
    printf("TPM2_LoadExternal: 0x%x\n", (word32)loadExtOut.objectHandle);
3437
#endif
3438
3439
    return rc;
3440
}
3441
int wolfTPM2_LoadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3442
    const TPM2B_PUBLIC* pub)
3443
{
3444
    return wolfTPM2_LoadPublicKey_ex(dev, key, pub, TPM_RH_OWNER);
3445
}
3446
3447
int wolfTPM2_ComputeName(const TPM2B_PUBLIC* pub, TPM2B_NAME* out)
3448
{
3449
    int rc;
3450
    TPMI_ALG_HASH nameAlg;
3451
#ifndef WOLFTPM2_NO_WOLFCRYPT
3452
    TPM2_Packet packet;
3453
    TPM2B_TEMPLATE data;
3454
    int hashSz;
3455
    word32 digestSz;
3456
#endif
3457
3458
    if (pub == NULL || out == NULL)
3459
        return BAD_FUNC_ARG;
3460
3461
    XMEMSET(out, 0, sizeof(TPM2B_NAME));
3462
    nameAlg = pub->publicArea.nameAlg;
3463
    if (nameAlg == TPM_ALG_NULL)
3464
        return TPM_RC_SUCCESS;
3465
3466
#ifndef WOLFTPM2_NO_WOLFCRYPT
3467
    /* Encode public into buffer */
3468
    XMEMSET(&packet, 0, sizeof(packet));
3469
    XMEMSET(&data, 0, sizeof(data));
3470
    packet.buf = data.buffer;
3471
    packet.size = sizeof(data.buffer);
3472
    TPM2_Packet_AppendPublicArea(&packet, (TPMT_PUBLIC*)&pub->publicArea);
3473
    if (packet.overflow) {
3474
        /* A truncated public area would produce a wrong Name and corrupt
3475
         * authorization binding, so reject rather than hash a partial area */
3476
        return BUFFER_E;
3477
    }
3478
    data.size = packet.pos;
3479
3480
    hashSz = TPM2_GetHashDigestSize(nameAlg);
3481
    if (hashSz <= 0)
3482
        return NOT_COMPILED_IN;
3483
3484
    /* Encode hash algorithm in first 2 bytes */
3485
    nameAlg = TPM2_Packet_SwapU16(nameAlg);
3486
    XMEMCPY(&out->name[0], &nameAlg, sizeof(UINT16));
3487
3488
    /* Hash of public area goes into remainder */
3489
    digestSz = (word32)hashSz;
3490
    rc = TPM2_HashCompute(pub->publicArea.nameAlg,
3491
        data.buffer, data.size,
3492
        &out->name[sizeof(UINT16)], &digestSz);
3493
3494
    /* compute final size */
3495
    if (rc == 0)
3496
        out->size = hashSz + (int)sizeof(UINT16);
3497
#else
3498
    (void)out;
3499
    rc = NOT_COMPILED_IN;
3500
#endif
3501
    return rc;
3502
}
3503
3504
/* Convert TPM2B_SENSITIVE to TPM2B_PRIVATE */
3505
/* TPM2B_PRIVATE format:
3506
 *   Integrity (UINT16) + Integrity (HMAC Digest) +
3507
 *   IV (UINT16) + IV +
3508
 *   Sensitive
3509
 */
3510
static int SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE* priv,
3511
    TPMI_ALG_HASH nameAlg, TPM2B_NAME* name, const WOLFTPM2_KEY* parentKey,
3512
    TPMT_SYM_DEF_OBJECT* sym, TPM2B_DATA* symSeed, int useIv)
3513
{
3514
    int rc = 0;
3515
#ifndef WOLFTPM2_NO_WOLFCRYPT
3516
    int outerWrap = 0, innerWrap = 0;
3517
    int digestSz = 0;
3518
    int integritySz = 0;
3519
    int ivSz = 0;
3520
    int sensSz = 0;
3521
    TPM2B_IV ivField;
3522
    TPM2_Packet packet;
3523
#ifdef WOLFTPM2_PRIVATE_IMPORT
3524
    BYTE* sensitiveData = NULL;
3525
    TPM2B_SYM_KEY symKey;
3526
    TPM2B_DIGEST hmacKey;
3527
#endif
3528
3529
    if (sens == NULL || priv == NULL) {
3530
        return BAD_FUNC_ARG;
3531
    }
3532
3533
    /* if using a parent then use it's integrity algorithm */
3534
    if (parentKey != NULL) {
3535
        nameAlg = parentKey->pub.publicArea.nameAlg;
3536
    }
3537
    digestSz = TPM2_GetHashDigestSize(nameAlg);
3538
    if (digestSz <= 0) {
3539
    #ifdef DEBUG_WOLFTPM
3540
        printf("SensitiveToPrivate: Invalid name algorithm %d\n", nameAlg);
3541
    #endif
3542
        return BAD_FUNC_ARG;
3543
    }
3544
3545
    /* Use outer wrap (Integrity then Encrypt) */
3546
    if (symSeed && symSeed->size > 0) {
3547
        outerWrap = 1;
3548
        integritySz = sizeof(word16) + digestSz;
3549
    }
3550
3551
    /* Use inner wrap (Encrypt then Integrity) */
3552
    if (sym && sym->algorithm != TPM_ALG_NULL) {
3553
        innerWrap = 1;
3554
    }
3555
3556
    /* IV: Generate or use 0 */
3557
    XMEMSET(&ivField, 0, sizeof(ivField));
3558
    if (useIv) {
3559
        /* Encode IV into private buffer */
3560
        XMEMSET(&packet, 0, sizeof(packet));
3561
        packet.buf = &priv->buffer[integritySz];
3562
        packet.size = sizeof(priv->buffer) - integritySz;
3563
        TPM2_Packet_AppendU16(&packet, ivField.size);
3564
        TPM2_Packet_AppendBytes(&packet, ivField.buffer, ivField.size);
3565
        ivSz = packet.pos;
3566
    }
3567
3568
    /* Encode sensitive into private buffer */
3569
    XMEMSET(&packet, 0, sizeof(packet));
3570
    packet.buf = &priv->buffer[integritySz + ivSz];
3571
    packet.size = sizeof(priv->buffer) - (integritySz + ivSz);
3572
    TPM2_Packet_AppendSensitive(&packet, sens);
3573
    sensSz = packet.pos;
3574
    priv->size = integritySz + ivSz + sensSz;
3575
    sensSz = ivSz + sensSz;
3576
3577
#ifdef WOLFTPM2_PRIVATE_IMPORT
3578
    sensitiveData = &priv->buffer[integritySz];
3579
    if (parentKey != NULL) {
3580
        symKey.size = parentKey->handle.symmetric.keyBits.sym;
3581
        if (symKey.size == 0) {
3582
            /* A parent given as a public area alone, as when a key is
3583
             * wrapped offline for a remote TPM, has no handle symmetric
3584
             * definition. The public area carries it, but only for the
3585
             * types that can be a storage parent. Anything else leaves the
3586
             * size at zero so the wrap is refused below rather than reading
3587
             * an inactive member of the parameters union. */
3588
            switch (parentKey->pub.publicArea.type) {
3589
                case TPM_ALG_RSA:
3590
                    symKey.size = parentKey->pub.publicArea.parameters
3591
                        .rsaDetail.symmetric.keyBits.sym;
3592
                    break;
3593
                case TPM_ALG_ECC:
3594
                    symKey.size = parentKey->pub.publicArea.parameters
3595
                        .eccDetail.symmetric.keyBits.sym;
3596
                    break;
3597
                case TPM_ALG_SYMCIPHER:
3598
                    symKey.size = parentKey->pub.publicArea.parameters
3599
                        .symDetail.sym.keyBits.sym;
3600
                    break;
3601
                default:
3602
                    break;
3603
            }
3604
        }
3605
    }
3606
    else if (sym != NULL) {
3607
        symKey.size = sym->keyBits.sym;
3608
    }
3609
    else {
3610
        rc = BAD_FUNC_ARG;
3611
    }
3612
    if (rc == 0) {
3613
        /* convert from bit to byte and round up */
3614
        symKey.size = (symKey.size + 7) / 8;
3615
        /* check for invalid value */
3616
        if (symKey.size > sizeof(symKey.buffer)) {
3617
            rc = BUFFER_E;
3618
        }
3619
        else if (outerWrap && symKey.size == 0) {
3620
            /* Only the outer wrap encrypts with this key. KDFa returns
3621
             * success for a zero length request, so without this the
3622
             * sensitive would reach the cipher with no key. */
3623
            rc = BAD_FUNC_ARG;
3624
        }
3625
    }
3626
#endif
3627
3628
    if (innerWrap && !outerWrap) {
3629
        /* A symmetric definition without an outer wrap seed would emit the
3630
         * sensitive unprotected (inner-wrap-only is not implemented); reject
3631
         * rather than return success with plaintext. When an outer wrap is
3632
         * present it applies this symmetric encryption. */
3633
        rc = NOT_COMPILED_IN;
3634
    }
3635
3636
    if (rc == 0 && outerWrap) {
3637
    #ifdef WOLFTPM2_PRIVATE_IMPORT
3638
        /* Generate symmetric key for encryption of inner values */
3639
        rc = TPM2_KDFa_ex(nameAlg, symSeed->buffer, symSeed->size, "STORAGE",
3640
            name->name, name->size, NULL, 0,
3641
            symKey.buffer, symKey.size);
3642
        if (rc == symKey.size) {
3643
            rc = 0;
3644
        }
3645
        else {
3646
        #ifdef DEBUG_WOLFTPM
3647
            printf("KDFa STORAGE Gen Error %d\n", rc);
3648
        #endif
3649
            rc = TPM_RC_FAILURE;
3650
        }
3651
3652
        /* Encrypt the Sensitive Area using the generated symmetric key */
3653
        if (rc == 0) {
3654
            rc = TPM2_AesCfbEncrypt(symKey.buffer, symKey.size,
3655
                ivField.buffer, sensitiveData, sensSz);
3656
            if (rc != 0) {
3657
            #ifdef DEBUG_WOLFTPM
3658
                printf("SensitiveToPrivate AES error %d!\n", rc);
3659
            #endif
3660
            }
3661
        }
3662
3663
        /* Generate HMAC key for generation of the integrity value */
3664
        if (rc == 0) {
3665
            hmacKey.size = digestSz;
3666
            rc = TPM2_KDFa_ex(nameAlg, symSeed->buffer, symSeed->size,
3667
                        "INTEGRITY", NULL, 0, NULL, 0,
3668
                        hmacKey.buffer, hmacKey.size);
3669
            if (rc == hmacKey.size) {
3670
                rc = 0;
3671
            }
3672
            else {
3673
            #ifdef DEBUG_WOLFTPM
3674
                printf("KDFa INTEGRITY Gen Error %d\n", rc);
3675
            #endif
3676
                rc = TPM_RC_FAILURE;
3677
            }
3678
        }
3679
3680
        /* Compute HMAC integrity over encrypted data and name */
3681
        if (rc == 0) {
3682
            rc = TPM2_HmacCompute(nameAlg,
3683
                hmacKey.buffer, hmacKey.size,
3684
                sensitiveData, sensSz,
3685
                name->name, name->size,
3686
                &priv->buffer[sizeof(word16)], NULL);
3687
            if (rc != 0) {
3688
            #ifdef DEBUG_WOLFTPM
3689
                printf("SensitiveToPrivate HMAC error %d!\n", rc);
3690
            #endif
3691
            }
3692
        }
3693
3694
        /* store the size of the integrity */
3695
        if (rc == 0) {
3696
            TPM2_Packet_U16ToByteArray((word16)digestSz, &priv->buffer[0]);
3697
        }
3698
3699
        TPM2_ForceZero(&symKey, sizeof(symKey));
3700
        TPM2_ForceZero(&hmacKey, sizeof(hmacKey));
3701
    #else
3702
        (void)name;
3703
        (void)sensSz;
3704
        rc = NOT_COMPILED_IN;
3705
    #endif
3706
    }
3707
3708
#else
3709
    (void)sens;
3710
    (void)priv;
3711
    (void)nameAlg;
3712
    (void)name;
3713
    (void)parentKey;
3714
    (void)sym;
3715
    (void)symSeed;
3716
    (void)useIv;
3717
    rc = NOT_COMPILED_IN;
3718
#endif
3719
    /* a failed wrap leaves the marshalled sensitive area in the clear */
3720
    if (rc != 0 && priv != NULL) {
3721
        TPM2_ForceZero(priv, sizeof(*priv));
3722
    }
3723
    return rc;
3724
}
3725
3726
int wolfTPM2_SensitiveToPrivate(TPM2B_SENSITIVE* sens, TPM2B_PRIVATE* priv,
3727
    TPMI_ALG_HASH nameAlg, TPM2B_NAME* name, const WOLFTPM2_KEY* parentKey,
3728
    TPMT_SYM_DEF_OBJECT* sym, TPM2B_DATA* symSeed)
3729
{
3730
    return SensitiveToPrivate(sens, priv, nameAlg, name, parentKey, sym,
3731
        symSeed, 0);
3732
}
3733
3734
/* Import external private key */
3735
int wolfTPM2_ImportPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
3736
    WOLFTPM2_KEYBLOB* keyBlob, const TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens)
3737
{
3738
    int rc;
3739
    Import_In  importIn;
3740
    Import_Out importOut;
3741
    TPM2B_NAME name;
3742
    TPM_HANDLE parentHandle;
3743
    TPM2B_DATA symSeed;
3744
3745
    if (dev == NULL || keyBlob == NULL || pub == NULL ||
3746
            sens == NULL) {
3747
        return BAD_FUNC_ARG;
3748
    }
3749
3750
    /* set session auth for key */
3751
    if (parentKey != NULL) {
3752
        /* set session auth for parent key */
3753
        wolfTPM2_SetAuthHandle(dev, 0, &parentKey->handle);
3754
        parentHandle = parentKey->handle.hndl;
3755
    }
3756
    else {
3757
        parentHandle = TPM_RH_OWNER;
3758
    }
3759
3760
    /* Import private key */
3761
    XMEMSET(&importIn, 0, sizeof(importIn));
3762
    importIn.parentHandle = parentHandle;
3763
    wolfTPM2_CopyPub(&importIn.objectPublic, pub);
3764
    importIn.symmetricAlg.algorithm = TPM_ALG_NULL;
3765
    rc = wolfTPM2_ComputeName(pub, &name);
3766
    if (rc != TPM_RC_SUCCESS) {
3767
    #ifdef DEBUG_WOLFTPM
3768
        printf("wolfTPM2_ComputeName: failed %d: %s\n", rc,
3769
            wolfTPM2_GetRCString(rc));
3770
    #endif
3771
        return rc;
3772
    }
3773
3774
    /* Get symmetric seed for KDFa */
3775
    XMEMSET(&symSeed, 0, sizeof(symSeed));
3776
    rc = wolfTPM2_EncryptSecret(dev, parentKey, &symSeed, &importIn.inSymSeed,
3777
        "DUPLICATE");
3778
    if (rc != TPM_RC_SUCCESS) {
3779
    #ifdef DEBUG_WOLFTPM
3780
        printf("wolfTPM2_EncryptSecret: failed %d: %s\n", rc,
3781
            wolfTPM2_GetRCString(rc));
3782
    #endif
3783
        goto exit_import;
3784
    }
3785
3786
    /* Encrypt sensitive */
3787
    rc = wolfTPM2_SensitiveToPrivate(sens, &importIn.duplicate,
3788
        pub->publicArea.nameAlg, &name, parentKey, &importIn.symmetricAlg,
3789
        &symSeed);
3790
    if (rc != TPM_RC_SUCCESS) {
3791
    #ifdef DEBUG_WOLFTPM
3792
        printf("wolfTPM2_SensitiveToPrivate: failed %d: %s\n", rc,
3793
            wolfTPM2_GetRCString(rc));
3794
    #endif
3795
        goto exit_import;
3796
    }
3797
    rc = TPM2_Import(&importIn, &importOut);
3798
    if (rc != TPM_RC_SUCCESS) {
3799
    #ifdef DEBUG_WOLFTPM
3800
        printf("TPM2_Import: failed %d: %s\n", rc,
3801
            wolfTPM2_GetRCString(rc));
3802
    #endif
3803
        goto exit_import;
3804
    }
3805
3806
    wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
3807
            &importIn.objectPublic.publicArea.parameters.asymDetail.symmetric);
3808
    wolfTPM2_CopyPub(&keyBlob->pub, &importIn.objectPublic);
3809
    wolfTPM2_CopyPriv(&keyBlob->priv, &importOut.outPrivate);
3810
3811
exit_import:
3812
    TPM2_ForceZero(&symSeed, sizeof(symSeed));
3813
    TPM2_ForceZero(&importIn, sizeof(importIn));
3814
    TPM2_ForceZero(&importOut, sizeof(importOut));
3815
    return rc;
3816
}
3817
3818
/* Import and Load external private key to TPM */
3819
int wolfTPM2_LoadPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
3820
    WOLFTPM2_KEY* key, const TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens)
3821
{
3822
    int rc;
3823
    WOLFTPM2_KEYBLOB keyBlob;
3824
3825
    if (dev == NULL || key == NULL || pub == NULL || sens == NULL) {
3826
        return BAD_FUNC_ARG;
3827
    }
3828
3829
    XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
3830
    rc = wolfTPM2_ImportPrivateKey(dev, parentKey, &keyBlob, pub, sens);
3831
    if (rc == 0) {
3832
        WOLFTPM2_HANDLE parentHandle_lcl, *parentHandle = &parentHandle_lcl;
3833
        if (parentKey != NULL) {
3834
            parentHandle = (WOLFTPM2_HANDLE*)&parentKey->handle;
3835
        }
3836
        else {
3837
            XMEMSET(parentHandle, 0, sizeof(*parentHandle));
3838
            parentHandle->hndl = TPM_RH_OWNER;
3839
        }
3840
3841
        rc = wolfTPM2_LoadKey(dev, &keyBlob, parentHandle);
3842
    }
3843
3844
    /* return loaded key */
3845
    key->handle.hndl = keyBlob.handle.hndl;
3846
    wolfTPM2_CopyName(&key->handle.name, &keyBlob.handle.name);
3847
    wolfTPM2_CopySymmetric(&key->handle.symmetric, &keyBlob.handle.symmetric);
3848
    wolfTPM2_CopyPub(&key->pub, &keyBlob.pub);
3849
    wolfTPM2_CopyAuth(&key->handle.auth, &sens->sensitiveArea.authValue);
3850
3851
    TPM2_ForceZero(&keyBlob, sizeof(keyBlob));
3852
3853
    return rc;
3854
}
3855
3856
int wolfTPM2_LoadRsaPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3857
    const byte* rsaPub, word32 rsaPubSz, word32 exponent,
3858
    TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
3859
{
3860
    TPM2B_PUBLIC pub;
3861
3862
    if (dev == NULL || key == NULL || rsaPub == NULL)
3863
        return BAD_FUNC_ARG;
3864
    if (rsaPubSz > sizeof(pub.publicArea.unique.rsa.buffer))
3865
        return BUFFER_E;
3866
3867
    /* To support TPM hardware and firmware versions that do not allow
3868
        small exponents */
3869
#ifndef WOLFTPM_NO_SOFTWARE_RSA
3870
    /* The TPM reference implementation does not support an exponent size
3871
       smaller than 7 nor does it allow keys to be created on the TPM with a
3872
       public exponent less than 2^16 + 1. */
3873
    if (exponent < 7) {
3874
    #ifdef DEBUG_WOLFTPM
3875
        printf("TPM based RSA with exponent %u not allowed! Using soft RSA\n",
3876
            exponent);
3877
    #endif
3878
        return TPM_RC_KEY;
3879
    }
3880
#endif
3881
3882
    XMEMSET(&pub, 0, sizeof(pub));
3883
    pub.publicArea.type = TPM_ALG_RSA;
3884
    /* make sure nameAlg is set for ticket */
3885
    pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
3886
    pub.publicArea.objectAttributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
3887
        TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA | TPMA_OBJECT_stClear);
3888
    pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
3889
    pub.publicArea.parameters.rsaDetail.keyBits = rsaPubSz * 8;
3890
    pub.publicArea.parameters.rsaDetail.exponent = exponent;
3891
    pub.publicArea.parameters.rsaDetail.scheme.scheme = scheme;
3892
    pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = hashAlg;
3893
    pub.publicArea.unique.rsa.size = rsaPubSz;
3894
    XMEMCPY(pub.publicArea.unique.rsa.buffer, rsaPub, rsaPubSz);
3895
3896
    return wolfTPM2_LoadPublicKey(dev, key, &pub);
3897
}
3898
3899
int wolfTPM2_LoadRsaPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
3900
    const byte* rsaPub, word32 rsaPubSz, word32 exponent)
3901
{
3902
    return wolfTPM2_LoadRsaPublicKey_ex(dev, key, rsaPub, rsaPubSz, exponent,
3903
        TPM_ALG_NULL, TPM_ALG_NULL);
3904
}
3905
3906
int wolfTPM2_ImportRsaPrivateKeySeed(WOLFTPM2_DEV* dev,
3907
    const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* rsaPub,
3908
    word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
3909
    TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg, TPMA_OBJECT attributes,
3910
    byte* seed, word32 seedSz)
3911
{
3912
    int rc = TPM_RC_SUCCESS;
3913
    TPM2B_PUBLIC pub;
3914
    TPM2B_SENSITIVE sens;
3915
    word32 digestSz;
3916
3917
    if (dev == NULL || keyBlob == NULL || rsaPub == NULL || rsaPriv == NULL)
3918
        return BAD_FUNC_ARG;
3919
    if (rsaPubSz > sizeof(pub.publicArea.unique.rsa.buffer))
3920
        return BUFFER_E;
3921
    if (rsaPrivSz > sizeof(sens.sensitiveArea.sensitive.rsa.buffer))
3922
        return BUFFER_E;
3923
3924
    /* Set up public key */
3925
    XMEMSET(&pub, 0, sizeof(pub));
3926
    pub.publicArea.type = TPM_ALG_RSA;
3927
    pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
3928
    pub.publicArea.objectAttributes = attributes;
3929
    pub.publicArea.parameters.rsaDetail.keyBits = rsaPubSz * 8;
3930
    pub.publicArea.parameters.rsaDetail.exponent = exponent;
3931
    pub.publicArea.parameters.rsaDetail.scheme.scheme = scheme;
3932
    pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = hashAlg;
3933
    pub.publicArea.unique.rsa.size = rsaPubSz;
3934
    XMEMCPY(pub.publicArea.unique.rsa.buffer, rsaPub, rsaPubSz);
3935
3936
    /* For fixedParent or (decrypt and restricted) enable symmetric */
3937
    if ((attributes & TPMA_OBJECT_fixedParent) ||
3938
           ((attributes & TPMA_OBJECT_decrypt) &&
3939
            (attributes & TPMA_OBJECT_restricted))) {
3940
        pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
3941
        /* Scale AES key size to match RSA key strength (matches
3942
         * GetKeyTemplateRSA pattern) */
3943
        pub.publicArea.parameters.rsaDetail.symmetric.keyBits.aes =
3944
            (rsaPubSz * 8 > 2048) ? 256 : 128;
3945
        pub.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
3946
    }
3947
    else {
3948
        pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
3949
    }
3950
3951
    /* Set up private key */
3952
    XMEMSET(&sens, 0, sizeof(sens));
3953
    sens.sensitiveArea.sensitiveType = TPM_ALG_RSA;
3954
    if (keyBlob->handle.auth.size > 0) {
3955
        TPM2B_AUTH* auth = &sens.sensitiveArea.authValue;
3956
        auth->size = keyBlob->handle.auth.size;
3957
        if (auth->size > sizeof(auth->buffer)) {
3958
            auth->size = sizeof(auth->buffer);
3959
        }
3960
        XMEMCPY(auth->buffer, keyBlob->handle.auth.buffer, auth->size);
3961
    }
3962
    sens.sensitiveArea.sensitive.rsa.size = rsaPrivSz;
3963
    XMEMCPY(sens.sensitiveArea.sensitive.rsa.buffer, rsaPriv, rsaPrivSz);
3964
3965
    /* Use Seed */
3966
    digestSz = (word32)TPM2_GetHashDigestSize(pub.publicArea.nameAlg);
3967
    if (digestSz == 0 ||
3968
        digestSz > sizeof(sens.sensitiveArea.seedValue.buffer)) {
3969
    #ifdef DEBUG_WOLFTPM
3970
        printf("Import RSA name alg size invalid! %d\n", digestSz);
3971
    #endif
3972
        rc = BUFFER_E;
3973
    }
3974
3975
    if (rc == TPM_RC_SUCCESS) {
3976
        if (seed != NULL) {
3977
            /* use custom seed */
3978
            if (seedSz != digestSz) {
3979
            #ifdef DEBUG_WOLFTPM
3980
                printf("Import RSA seed size invalid! %d != %d\n",
3981
                    seedSz, digestSz);
3982
            #endif
3983
                rc = BAD_FUNC_ARG;
3984
            }
3985
            else {
3986
                sens.sensitiveArea.seedValue.size = seedSz;
3987
                XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
3988
            }
3989
        }
3990
        else {
3991
            /* assign random seed */
3992
            sens.sensitiveArea.seedValue.size = digestSz;
3993
            rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
3994
                sens.sensitiveArea.seedValue.size);
3995
        }
3996
    }
3997
    if (rc == TPM_RC_SUCCESS) {
3998
        rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
3999
    }
4000
4001
    TPM2_ForceZero(&sens, sizeof(sens));
4002
    return rc;
4003
}
4004
int wolfTPM2_ImportRsaPrivateKey(WOLFTPM2_DEV* dev,
4005
    const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* rsaPub,
4006
    word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
4007
    TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
4008
{
4009
    TPMA_OBJECT attributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
4010
        TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
4011
    return wolfTPM2_ImportRsaPrivateKeySeed(dev, parentKey, keyBlob,
4012
        rsaPub, rsaPubSz, exponent, rsaPriv, rsaPrivSz, scheme, hashAlg,
4013
        attributes, NULL, 0);
4014
}
4015
4016
int wolfTPM2_LoadRsaPrivateKey_ex(WOLFTPM2_DEV* dev,
4017
    const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEY* key, const byte* rsaPub,
4018
    word32 rsaPubSz, word32 exponent, const byte* rsaPriv, word32 rsaPrivSz,
4019
    TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
4020
{
4021
    int rc;
4022
    WOLFTPM2_KEYBLOB keyBlob;
4023
4024
    if (dev == NULL || key == NULL || rsaPub == NULL || rsaPriv == NULL)
4025
        return BAD_FUNC_ARG;
4026
4027
    XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
4028
    rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, &keyBlob, rsaPub, rsaPubSz,
4029
        exponent, rsaPriv, rsaPrivSz, scheme, hashAlg);
4030
    if (rc == 0) {
4031
        WOLFTPM2_HANDLE parentHandle_lcl, *parentHandle = &parentHandle_lcl;
4032
        if (parentKey != NULL) {
4033
            parentHandle = (WOLFTPM2_HANDLE*)&parentKey->handle;
4034
        }
4035
        else {
4036
            XMEMSET(parentHandle, 0, sizeof(*parentHandle));
4037
            parentHandle->hndl = TPM_RH_OWNER;
4038
        }
4039
        rc = wolfTPM2_LoadKey(dev, &keyBlob, parentHandle);
4040
    }
4041
4042
    /* return loaded key */
4043
    wolfTPM2_CopyKeyFromBlob(key, &keyBlob);
4044
4045
    TPM2_ForceZero(&keyBlob, sizeof(keyBlob));
4046
    return rc;
4047
}
4048
4049
int wolfTPM2_LoadRsaPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
4050
    WOLFTPM2_KEY* key, const byte* rsaPub, word32 rsaPubSz, word32 exponent,
4051
    const byte* rsaPriv, word32 rsaPrivSz)
4052
{
4053
    return wolfTPM2_LoadRsaPrivateKey_ex(dev, parentKey, key, rsaPub, rsaPubSz,
4054
        exponent, rsaPriv, rsaPrivSz, TPM_ALG_NULL, TPM_ALG_NULL);
4055
}
4056
4057
int wolfTPM2_LoadEccPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
4058
    int curveId, const byte* eccPubX, word32 eccPubXSz,
4059
    const byte* eccPubY, word32 eccPubYSz,
4060
    TPMI_ALG_ECC_SCHEME scheme, TPMI_ALG_HASH hashAlg,
4061
    TPMA_OBJECT objectAttributes)
4062
{
4063
    TPM2B_PUBLIC pub;
4064
4065
    if (dev == NULL || key == NULL || eccPubX == NULL || eccPubY == NULL)
4066
        return BAD_FUNC_ARG;
4067
    if (eccPubXSz > sizeof(pub.publicArea.unique.ecc.x.buffer))
4068
        return BUFFER_E;
4069
    if (eccPubYSz > sizeof(pub.publicArea.unique.ecc.y.buffer))
4070
        return BUFFER_E;
4071
    /* TPMS_SCHEME_ECDAA requires a 'count' field this helper cannot
4072
     * supply. Callers needing ECDAA must build TPM2B_PUBLIC manually and
4073
     * use wolfTPM2_LoadPublicKey directly. */
4074
    if (scheme == TPM_ALG_ECDAA)
4075
        return BAD_FUNC_ARG;
4076
4077
    XMEMSET(&pub, 0, sizeof(pub));
4078
    pub.publicArea.type = TPM_ALG_ECC;
4079
    /* make sure nameAlg is set for ticket */
4080
    pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
4081
    pub.publicArea.objectAttributes = objectAttributes;
4082
    pub.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
4083
    pub.publicArea.parameters.eccDetail.scheme.scheme = scheme;
4084
    if (scheme != TPM_ALG_NULL) {
4085
        pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg =
4086
            hashAlg;
4087
    }
4088
    pub.publicArea.parameters.eccDetail.curveID = curveId;
4089
    pub.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
4090
    pub.publicArea.unique.ecc.x.size = eccPubXSz;
4091
    XMEMCPY(pub.publicArea.unique.ecc.x.buffer, eccPubX, eccPubXSz);
4092
    pub.publicArea.unique.ecc.y.size = eccPubYSz;
4093
    XMEMCPY(pub.publicArea.unique.ecc.y.buffer, eccPubY, eccPubYSz);
4094
4095
    return wolfTPM2_LoadPublicKey(dev, key, &pub);
4096
}
4097
4098
int wolfTPM2_LoadEccPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, int curveId,
4099
    const byte* eccPubX, word32 eccPubXSz, const byte* eccPubY, word32 eccPubYSz)
4100
{
4101
    return wolfTPM2_LoadEccPublicKey_ex(dev, key, curveId,
4102
        eccPubX, eccPubXSz, eccPubY, eccPubYSz,
4103
        TPM_ALG_ECDSA, WOLFTPM2_WRAP_DIGEST,
4104
        TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
4105
}
4106
4107
int wolfTPM2_ImportEccPrivateKeySeed(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
4108
    WOLFTPM2_KEYBLOB* keyBlob, int curveId,
4109
    const byte* eccPubX, word32 eccPubXSz,
4110
    const byte* eccPubY, word32 eccPubYSz,
4111
    const byte* eccPriv, word32 eccPrivSz,
4112
    TPMA_OBJECT attributes, byte* seed, word32 seedSz)
4113
{
4114
    int rc = 0;
4115
    TPM2B_PUBLIC pub;
4116
    TPM2B_SENSITIVE sens;
4117
    word32 digestSz;
4118
4119
    if (dev == NULL || keyBlob == NULL || eccPubX == NULL || eccPubY == NULL ||
4120
        eccPriv == NULL) {
4121
        return BAD_FUNC_ARG;
4122
    }
4123
    if (eccPubXSz > sizeof(pub.publicArea.unique.ecc.x.buffer))
4124
        return BUFFER_E;
4125
    if (eccPubYSz > sizeof(pub.publicArea.unique.ecc.y.buffer))
4126
        return BUFFER_E;
4127
    if (eccPrivSz > sizeof(sens.sensitiveArea.sensitive.ecc.buffer))
4128
        return BUFFER_E;
4129
4130
    /* Set up public key */
4131
    XMEMSET(&pub, 0, sizeof(pub));
4132
    pub.publicArea.type = TPM_ALG_ECC;
4133
    pub.publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
4134
    pub.publicArea.objectAttributes = attributes;
4135
    pub.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
4136
    /* if both sign and decrypt are set then must use NULL algorithm */
4137
    pub.publicArea.parameters.eccDetail.scheme.scheme =
4138
        ((attributes & TPMA_OBJECT_sign) &&
4139
         (attributes & TPMA_OBJECT_decrypt)) ?
4140
            TPM_ALG_NULL : TPM_ALG_ECDSA;
4141
    pub.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg =
4142
        WOLFTPM2_WRAP_DIGEST;
4143
    pub.publicArea.parameters.eccDetail.curveID = curveId;
4144
    pub.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
4145
    pub.publicArea.unique.ecc.x.size = eccPubXSz;
4146
    XMEMCPY(pub.publicArea.unique.ecc.x.buffer, eccPubX, eccPubXSz);
4147
    pub.publicArea.unique.ecc.y.size = eccPubYSz;
4148
    XMEMCPY(pub.publicArea.unique.ecc.y.buffer, eccPubY, eccPubYSz);
4149
4150
    /* Set up private key */
4151
    XMEMSET(&sens, 0, sizeof(sens));
4152
    sens.sensitiveArea.sensitiveType = TPM_ALG_ECC;
4153
    if (keyBlob->handle.auth.size > 0) {
4154
        TPM2B_AUTH* auth = &sens.sensitiveArea.authValue;
4155
        auth->size = keyBlob->handle.auth.size;
4156
        if (auth->size > sizeof(auth->buffer)) {
4157
            auth->size = sizeof(auth->buffer);
4158
        }
4159
        XMEMCPY(auth->buffer, keyBlob->handle.auth.buffer, auth->size);
4160
    }
4161
    sens.sensitiveArea.sensitive.ecc.size = eccPrivSz;
4162
    XMEMCPY(sens.sensitiveArea.sensitive.ecc.buffer, eccPriv, eccPrivSz);
4163
4164
    /* Use Seed */
4165
    digestSz = (word32)TPM2_GetHashDigestSize(pub.publicArea.nameAlg);
4166
    if (digestSz == 0 ||
4167
        digestSz > sizeof(sens.sensitiveArea.seedValue.buffer)) {
4168
    #ifdef DEBUG_WOLFTPM
4169
        printf("Import ECC name alg size invalid! %d\n", digestSz);
4170
    #endif
4171
        rc = BUFFER_E;
4172
    }
4173
4174
    if (rc == 0) {
4175
        if (seed != NULL) {
4176
            /* use custom seed */
4177
            if (seedSz != digestSz) {
4178
            #ifdef DEBUG_WOLFTPM
4179
                printf("Import ECC seed size invalid! %d != %d\n",
4180
                    seedSz, digestSz);
4181
            #endif
4182
                rc = BAD_FUNC_ARG;
4183
            }
4184
            else {
4185
                sens.sensitiveArea.seedValue.size = seedSz;
4186
                XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
4187
            }
4188
        }
4189
        else {
4190
            /* assign random seed */
4191
            sens.sensitiveArea.seedValue.size = digestSz;
4192
            rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
4193
                sens.sensitiveArea.seedValue.size);
4194
        }
4195
    }
4196
4197
    if (rc == 0) {
4198
        rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
4199
    }
4200
    TPM2_ForceZero(&sens, sizeof(sens));
4201
    return rc;
4202
}
4203
4204
int wolfTPM2_ImportEccPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
4205
    WOLFTPM2_KEYBLOB* keyBlob, int curveId,
4206
    const byte* eccPubX, word32 eccPubXSz,
4207
    const byte* eccPubY, word32 eccPubYSz,
4208
    const byte* eccPriv, word32 eccPrivSz)
4209
{
4210
    TPMA_OBJECT attributes = (TPMA_OBJECT_sign | TPMA_OBJECT_decrypt |
4211
        TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
4212
    return wolfTPM2_ImportEccPrivateKeySeed(dev, parentKey, keyBlob, curveId,
4213
        eccPubX, eccPubXSz, eccPubY, eccPubYSz, eccPriv, eccPrivSz, attributes,
4214
        NULL, 0);
4215
}
4216
4217
int wolfTPM2_LoadEccPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
4218
    WOLFTPM2_KEY* key, int curveId,
4219
    const byte* eccPubX, word32 eccPubXSz,
4220
    const byte* eccPubY, word32 eccPubYSz,
4221
    const byte* eccPriv, word32 eccPrivSz)
4222
{
4223
    int rc;
4224
    WOLFTPM2_KEYBLOB keyBlob;
4225
4226
    if (dev == NULL || key == NULL || eccPubX == NULL || eccPubY == NULL ||
4227
        eccPriv == NULL) {
4228
        return BAD_FUNC_ARG;
4229
    }
4230
4231
    XMEMCPY(&keyBlob, key, sizeof(WOLFTPM2_KEY));
4232
    rc = wolfTPM2_ImportEccPrivateKey(dev, parentKey, &keyBlob, curveId,
4233
        eccPubX, eccPubXSz, eccPubY, eccPubYSz, eccPriv, eccPrivSz);
4234
    if (rc == 0) {
4235
        WOLFTPM2_HANDLE parentHandle_lcl, *parentHandle = &parentHandle_lcl;
4236
        if (parentKey != NULL) {
4237
            parentHandle = (WOLFTPM2_HANDLE*)&parentKey->handle;
4238
        }
4239
        else {
4240
            XMEMSET(parentHandle, 0, sizeof(*parentHandle));
4241
            parentHandle->hndl = TPM_RH_OWNER;
4242
        }
4243
        rc = wolfTPM2_LoadKey(dev, &keyBlob, parentHandle);
4244
    }
4245
4246
    /* return loaded key */
4247
    wolfTPM2_CopyKeyFromBlob(key, &keyBlob);
4248
4249
    TPM2_ForceZero(&keyBlob, sizeof(keyBlob));
4250
    return rc;
4251
}
4252
4253
int wolfTPM2_ReadPublicKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
4254
    const TPM_HANDLE handle)
4255
{
4256
    int rc;
4257
    ReadPublic_In  readPubIn;
4258
    ReadPublic_Out readPubOut;
4259
4260
    if (dev == NULL || key == NULL)
4261
        return BAD_FUNC_ARG;
4262
4263
    /* Read public key */
4264
    XMEMSET(&readPubIn, 0, sizeof(readPubIn));
4265
    XMEMSET(&readPubOut, 0, sizeof(readPubOut));
4266
    readPubIn.objectHandle = handle;
4267
    rc = TPM2_ReadPublic(&readPubIn, &readPubOut);
4268
    if (rc != TPM_RC_SUCCESS) {
4269
    #ifdef DEBUG_WOLFTPM
4270
        printf("TPM2_ReadPublic failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
4271
    #endif
4272
        return rc;
4273
    }
4274
4275
    key->handle.hndl = readPubIn.objectHandle;
4276
    wolfTPM2_CopySymmetric(&key->handle.symmetric,
4277
            &readPubOut.outPublic.publicArea.parameters.asymDetail.symmetric);
4278
    wolfTPM2_CopyName(&key->handle.name, &readPubOut.name);
4279
    wolfTPM2_CopyPub(&key->pub, &readPubOut.outPublic);
4280
4281
#ifdef DEBUG_WOLFTPM
4282
    printf("TPM2_ReadPublic Handle 0x%x: pub %d, name %d, qualifiedName %d\n",
4283
        (word32)readPubIn.objectHandle,
4284
        readPubOut.outPublic.size, readPubOut.name.size,
4285
        readPubOut.qualifiedName.size);
4286
#endif
4287
4288
    return rc;
4289
}
4290
4291
#ifndef WOLFTPM2_NO_WOLFCRYPT
4292
#ifndef NO_ASN
4293
#ifndef NO_RSA
4294
int wolfTPM2_DecodeRsaDer(const byte* der, word32 derSz,
4295
    TPM2B_PUBLIC* pub, TPM2B_SENSITIVE* sens, TPMA_OBJECT attributes)
4296
{
4297
    int rc = 0;
4298
    RsaKey key[1];
4299
    word32 idx = 0;
4300
    word32 e = 0;
4301
    byte n[RSA_MAX_SIZE / 8];
4302
    byte d[RSA_MAX_SIZE / 8];
4303
    byte p[RSA_MAX_SIZE / 8];
4304
    byte q[RSA_MAX_SIZE / 8];
4305
    word32  eSz = (word32)sizeof(e);
4306
    word32  nSz = (word32)sizeof(n);
4307
    word32  dSz = (word32)sizeof(d);
4308
    word32  pSz = (word32)sizeof(p);
4309
    word32  qSz = (word32)sizeof(q);
4310
    int isPrivateKey = 0;
4311
4312
    XMEMSET(n, 0, sizeof(n));
4313
    XMEMSET(d, 0, sizeof(d));
4314
    XMEMSET(p, 0, sizeof(p));
4315
    XMEMSET(q, 0, sizeof(q));
4316
4317
    if (attributes == 0) {
4318
        if (sens != NULL) {
4319
            /* Imported private keys: restricted must not be set when both
4320
             * sign and decrypt are set (TPM 2.0 Part 2 Table 31), and
4321
             * sensitiveDataOrigin must not be set for imported keys */
4322
            attributes = (TPMA_OBJECT_sign |
4323
                          TPMA_OBJECT_decrypt |
4324
                          TPMA_OBJECT_userWithAuth |
4325
                          TPMA_OBJECT_noDA);
4326
        }
4327
        else {
4328
            attributes = (TPMA_OBJECT_restricted |
4329
                          TPMA_OBJECT_sensitiveDataOrigin |
4330
                          TPMA_OBJECT_sign |
4331
                          TPMA_OBJECT_userWithAuth |
4332
                          TPMA_OBJECT_noDA);
4333
        }
4334
    }
4335
4336
    rc = wc_InitRsaKey(key, NULL);
4337
    if (rc == 0) {
4338
        idx = 0;
4339
    #ifdef HAVE_PKCS8
4340
        /* skip PKCS8 header */
4341
        (void)wc_GetPkcs8TraditionalOffset((byte*)der, &idx, derSz);
4342
    #endif
4343
        rc = wc_RsaPrivateKeyDecode(der, &idx, key, derSz);
4344
        if (rc == 0) {
4345
            isPrivateKey = 1;
4346
        }
4347
        else {
4348
            idx = 0;
4349
            rc = wc_RsaPublicKeyDecode(der, &idx, key, derSz);
4350
        }
4351
        if (rc == 0) {
4352
            if (isPrivateKey) {
4353
                PRIVATE_KEY_UNLOCK();
4354
                rc = wc_RsaExportKey(key, (byte*)&e, &eSz, n, &nSz, d, &dSz,
4355
                    p, &pSz, q, &qSz);
4356
                PRIVATE_KEY_LOCK();
4357
            }
4358
            else {
4359
                rc = wc_RsaFlattenPublicKey(key, (byte*)&e, &eSz, n, &nSz);
4360
            }
4361
        }
4362
        if (rc == 0 && nSz > sizeof(pub->publicArea.unique.rsa.buffer))
4363
            rc = BUFFER_E;
4364
        if (rc == 0 && sens != NULL && isPrivateKey &&
4365
                qSz > sizeof(sens->sensitiveArea.sensitive.rsa.buffer))
4366
            rc = BUFFER_E;
4367
        if (rc == 0) {
4368
            TPMS_RSA_PARMS* rsa = &pub->publicArea.parameters.rsaDetail;
4369
            /* Set up public key */
4370
            pub->publicArea.type = TPM_ALG_RSA;
4371
            pub->publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
4372
            pub->publicArea.objectAttributes = attributes;
4373
            rsa->keyBits = nSz * 8;
4374
            rsa->exponent = e;
4375
            /* if both sign and decrypt are set then must use NULL scheme */
4376
            rsa->scheme.scheme =
4377
                ((attributes & TPMA_OBJECT_sign) &&
4378
                 (attributes & TPMA_OBJECT_decrypt)) ?
4379
                    TPM_ALG_NULL :
4380
                ((attributes & TPMA_OBJECT_sign) ? TPM_ALG_RSASSA :
4381
                    TPM_ALG_NULL);
4382
            rsa->scheme.details.anySig.hashAlg = WOLFTPM2_WRAP_DIGEST;
4383
            pub->publicArea.unique.rsa.size = nSz;
4384
            XMEMCPY(pub->publicArea.unique.rsa.buffer, n, nSz);
4385
4386
            /* For fixedParent or (decrypt and restricted) enable symmetric.
4387
             * Match the AES wrap strength to the asymmetric key strength
4388
             * the same way GetKeyTemplateRSA / ImportRsaPrivateKeySeed do
4389
             * so a 3072+ bit parent does not silently downgrade child key
4390
             * protection to AES-128. */
4391
            if ((attributes & TPMA_OBJECT_fixedParent) ||
4392
                ((attributes & TPMA_OBJECT_decrypt) &&
4393
                    (attributes & TPMA_OBJECT_restricted))) {
4394
                rsa->symmetric.algorithm = TPM_ALG_AES;
4395
                rsa->symmetric.keyBits.aes = (nSz * 8 > 2048) ? 256 : 128;
4396
                rsa->symmetric.mode.aes = TPM_ALG_CFB;
4397
            }
4398
            else {
4399
                rsa->symmetric.algorithm = TPM_ALG_NULL;
4400
            }
4401
4402
            /* Set up private key */
4403
            if (sens != NULL && isPrivateKey) {
4404
                sens->sensitiveArea.sensitiveType = TPM_ALG_RSA;
4405
                sens->sensitiveArea.sensitive.rsa.size = qSz;
4406
                XMEMCPY(sens->sensitiveArea.sensitive.rsa.buffer, q, qSz);
4407
            }
4408
        }
4409
        wc_FreeRsaKey(key);
4410
        TPM2_ForceZero(key, sizeof(RsaKey));
4411
    }
4412
4413
    TPM2_ForceZero(d, sizeof(d));
4414
    TPM2_ForceZero(p, sizeof(p));
4415
    TPM2_ForceZero(q, sizeof(q));
4416
4417
    return rc;
4418
}
4419
#endif /* !NO_RSA */
4420
#ifdef HAVE_ECC
4421
int wolfTPM2_DecodeEccDer(const byte* der, word32 derSz, TPM2B_PUBLIC* pub,
4422
    TPM2B_SENSITIVE* sens, TPMA_OBJECT attributes)
4423
{
4424
    int rc;
4425
    int curveId = 0;
4426
    word32 idx;
4427
    ecc_key key[1];
4428
    byte    d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
4429
    byte    qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
4430
    byte    qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
4431
    word32  dSz = sizeof(d);
4432
    word32  qxSz = sizeof(qx);
4433
    word32  qySz = sizeof(qy);
4434
    int isPrivateKey = 0;
4435
4436
    XMEMSET(d, 0, sizeof(d));
4437
    XMEMSET(qx, 0, sizeof(qx));
4438
    XMEMSET(qy, 0, sizeof(qy));
4439
4440
    if (attributes == 0) {
4441
        if (sens != NULL) {
4442
            /* Imported private keys: restricted must not be set when both
4443
             * sign and decrypt are set (TPM 2.0 Part 2 Table 31), and
4444
             * sensitiveDataOrigin must not be set for imported keys */
4445
            attributes = (TPMA_OBJECT_sign |
4446
                          TPMA_OBJECT_decrypt |
4447
                          TPMA_OBJECT_userWithAuth |
4448
                          TPMA_OBJECT_noDA);
4449
        }
4450
        else {
4451
            attributes = (TPMA_OBJECT_restricted |
4452
                          TPMA_OBJECT_sensitiveDataOrigin |
4453
                          TPMA_OBJECT_sign |
4454
                          TPMA_OBJECT_userWithAuth |
4455
                          TPMA_OBJECT_noDA);
4456
        }
4457
    }
4458
4459
    rc = wc_ecc_init(key);
4460
    if (rc == 0) {
4461
        idx = 0;
4462
        rc = wc_EccPrivateKeyDecode(der, &idx, key, derSz);
4463
        if (rc == 0) {
4464
            isPrivateKey = 1;
4465
        }
4466
        else {
4467
            idx = 0;
4468
            rc = wc_EccPublicKeyDecode(der, &idx, key, derSz);
4469
        }
4470
        if (rc == 0) {
4471
            curveId = TPM2_GetTpmCurve(key->dp->id);
4472
4473
            if (isPrivateKey) {
4474
                PRIVATE_KEY_UNLOCK();
4475
                rc = wc_ecc_export_private_raw(key, qx, &qxSz, qy, &qySz,
4476
                    d, &dSz);
4477
                PRIVATE_KEY_LOCK();
4478
            }
4479
            else {
4480
                rc = wc_ecc_export_public_raw(key, qx, &qxSz, qy, &qySz);
4481
            }
4482
        }
4483
        if (rc == 0 && qxSz > sizeof(pub->publicArea.unique.ecc.x.buffer))
4484
            rc = BUFFER_E;
4485
        if (rc == 0 && qySz > sizeof(pub->publicArea.unique.ecc.y.buffer))
4486
            rc = BUFFER_E;
4487
        if (rc == 0 && sens != NULL && isPrivateKey &&
4488
                dSz > sizeof(sens->sensitiveArea.sensitive.ecc.buffer))
4489
            rc = BUFFER_E;
4490
        if (rc == 0) {
4491
            TPMS_ECC_PARMS* ecc = &pub->publicArea.parameters.eccDetail;
4492
            /* Set up public key */
4493
            pub->publicArea.type = TPM_ALG_ECC;
4494
            pub->publicArea.nameAlg = WOLFTPM2_WRAP_DIGEST;
4495
            pub->publicArea.objectAttributes = attributes;
4496
            ecc->symmetric.algorithm = TPM_ALG_NULL;
4497
            /* if both sign and decrypt are set then must use NULL scheme */
4498
            ecc->scheme.scheme =
4499
                ((attributes & TPMA_OBJECT_sign) &&
4500
                 (attributes & TPMA_OBJECT_decrypt)) ?
4501
                    TPM_ALG_NULL :
4502
                ((attributes & TPMA_OBJECT_sign) ? TPM_ALG_ECDSA :
4503
                    TPM_ALG_NULL);
4504
            ecc->scheme.details.ecdsa.hashAlg = WOLFTPM2_WRAP_DIGEST;
4505
            ecc->curveID = curveId;
4506
            ecc->kdf.scheme = TPM_ALG_NULL;
4507
            pub->publicArea.unique.ecc.x.size = qxSz;
4508
            XMEMCPY(pub->publicArea.unique.ecc.x.buffer, qx, qxSz);
4509
            pub->publicArea.unique.ecc.y.size = qySz;
4510
            XMEMCPY(pub->publicArea.unique.ecc.y.buffer, qy, qySz);
4511
4512
            /* For fixedParent or (decrypt and restricted) enable symmetric.
4513
             * Scale the AES wrap strength to the curve size, matching
4514
             * GetKeyTemplateECC, so a P-384 / P-521 parent does not
4515
             * silently downgrade child protection to AES-128. */
4516
            if ((attributes & TPMA_OBJECT_fixedParent) ||
4517
                ((attributes & TPMA_OBJECT_decrypt) &&
4518
                    (attributes & TPMA_OBJECT_restricted))) {
4519
                ecc->symmetric.algorithm = TPM_ALG_AES;
4520
                ecc->symmetric.keyBits.aes = (qxSz >= 48) ? 256 : 128;
4521
                ecc->symmetric.mode.aes = TPM_ALG_CFB;
4522
            }
4523
            else {
4524
                ecc->symmetric.algorithm = TPM_ALG_NULL;
4525
            }
4526
4527
            /* Set up private key */
4528
            if (sens != NULL && isPrivateKey) {
4529
                sens->sensitiveArea.sensitiveType = TPM_ALG_ECC;
4530
                sens->sensitiveArea.sensitive.ecc.size = dSz;
4531
                XMEMCPY(sens->sensitiveArea.sensitive.ecc.buffer, d, dSz);
4532
            }
4533
        }
4534
4535
        wc_ecc_free(key);
4536
        TPM2_ForceZero(key, sizeof(ecc_key));
4537
    }
4538
4539
    TPM2_ForceZero(d, sizeof(d));
4540
4541
    return rc;
4542
}
4543
#endif /* HAVE_ECC */
4544
4545
int wolfTPM2_ExportPublicKeyBuffer(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
4546
    int encodingType, byte* out, word32* outSz)
4547
{
4548
    int rc;
4549
    word32 derSz = 0;
4550
    union keyUnion {
4551
    #ifndef NO_RSA
4552
        RsaKey rsa;
4553
    #endif
4554
    #ifdef HAVE_ECC
4555
        ecc_key ecc;
4556
    #endif
4557
    } key;
4558
4559
    if (dev == NULL || tpmKey == NULL || outSz == NULL) {
4560
        return BAD_FUNC_ARG;
4561
    }
4562
4563
    XMEMSET(&key, 0, sizeof(key));
4564
4565
    /* determine the type of key in WOLFTPM2_KEY */
4566
    if (tpmKey->pub.publicArea.type == TPM_ALG_ECC) {
4567
    #if defined(HAVE_ECC) && \
4568
        defined(HAVE_ECC_KEY_IMPORT) && defined(HAVE_ECC_KEY_EXPORT)
4569
        rc = wc_ecc_init(&key.ecc);
4570
        if (rc == 0) {
4571
            /* load public portion of key into wolf ECC Key */
4572
            rc = wolfTPM2_EccKey_TpmToWolf(dev, tpmKey, &key.ecc);
4573
            if (rc == 0) {
4574
                rc = wc_EccPublicKeyToDer(&key.ecc, out, *outSz, 1);
4575
                if (rc > 0) {
4576
                    derSz = rc;
4577
                    rc = 0;
4578
                }
4579
                else {
4580
                    rc = BUFFER_E;
4581
                }
4582
            }
4583
            wc_ecc_free(&key.ecc);
4584
        }
4585
    #else
4586
        (void)out;
4587
        rc = NOT_COMPILED_IN;
4588
    #endif
4589
    }
4590
    else if (tpmKey->pub.publicArea.type == TPM_ALG_RSA) {
4591
        /* RSA public key export only enabled with:
4592
         * cert gen, key gen or openssl extra */
4593
    #if !defined(NO_RSA) && \
4594
        (defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA) || \
4595
         defined(WOLFSSL_KEY_GEN))
4596
        rc = wc_InitRsaKey(&key.rsa, NULL);
4597
        if (rc == 0) {
4598
            /* load public portion of key into wolf RSA Key */
4599
            rc = wolfTPM2_RsaKey_TpmToWolf(dev, tpmKey, &key.rsa);
4600
            if (rc == 0) {
4601
                rc = wc_RsaKeyToPublicDer(&key.rsa, out, *outSz);
4602
                if (rc > 0) {
4603
                    derSz = rc;
4604
                    rc = 0;
4605
                }
4606
                else {
4607
                    rc = BUFFER_E;
4608
                }
4609
            }
4610
            wc_FreeRsaKey(&key.rsa);
4611
        }
4612
    #else
4613
        (void)out;
4614
        rc = NOT_COMPILED_IN;
4615
    #endif
4616
    }
4617
    else {
4618
    #ifdef DEBUG_WOLFTPM
4619
        printf("Invalid tpmKey type!\n");
4620
    #endif
4621
        rc = BAD_FUNC_ARG;
4622
    }
4623
4624
    /* Optionally convert to PEM */
4625
    if (rc == 0 && encodingType == ENCODING_TYPE_PEM) {
4626
    #ifdef WOLFSSL_DER_TO_PEM
4627
        byte tmp[MAX_CONTEXT_SIZE];
4628
        if (derSz > (word32)sizeof(tmp)) {
4629
            rc = BUFFER_E;
4630
        }
4631
        else {
4632
            /* move DER to temp variable */
4633
            XMEMCPY(tmp, out, derSz);
4634
            XMEMSET(out, 0, *outSz);
4635
            rc = wc_DerToPem(tmp, derSz, out, *outSz, PUBLICKEY_TYPE);
4636
            if (rc > 0) {
4637
                *outSz = rc;
4638
                rc = 0;
4639
            }
4640
            else {
4641
                rc = BUFFER_E;
4642
            }
4643
        }
4644
    #else
4645
        (void)out;
4646
        rc = NOT_COMPILED_IN;
4647
    #endif
4648
    }
4649
    else if (rc == 0) {
4650
        *outSz = derSz;
4651
    }
4652
    return rc;
4653
}
4654
4655
int wolfTPM2_ImportPublicKeyBuffer(WOLFTPM2_DEV* dev, int keyType,
4656
    WOLFTPM2_KEY* key, int encodingType, const char* input, word32 inSz,
4657
    TPMA_OBJECT objectAttributes)
4658
{
4659
    int rc = 0;
4660
    byte* derBuf;
4661
    word32 derSz;
4662
4663
    if (dev == NULL || key == NULL || input == NULL || inSz == 0) {
4664
        return BAD_FUNC_ARG;
4665
    }
4666
4667
    if (keyType != TPM_ALG_RSA && keyType != TPM_ALG_ECC) {
4668
        return BAD_FUNC_ARG;
4669
    }
4670
4671
    if (encodingType == ENCODING_TYPE_PEM) {
4672
    #ifdef WOLFTPM2_PEM_DECODE
4673
        /* der size is base 64 decode length */
4674
        if (inSz > (0xFFFFFFFFU / 3))
4675
            return BAD_FUNC_ARG;
4676
        derSz = inSz * 3 / 4 + 1;
4677
        derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4678
        if (derBuf == NULL)
4679
            return MEMORY_E;
4680
        rc = wc_PubKeyPemToDer((byte*)input, inSz, derBuf, derSz);
4681
        if (rc >= 0) {
4682
            derSz = rc;
4683
            rc = 0;
4684
        }
4685
    #else
4686
        return NOT_COMPILED_IN;
4687
    #endif
4688
    }
4689
    else { /* ASN.1 (DER) */
4690
        derBuf = (byte*)input;
4691
        derSz = inSz;
4692
    }
4693
4694
    /* Handle DER Import (skip if PEM-to-DER conversion above failed) */
4695
    if (rc == 0 && keyType == TPM_ALG_RSA) {
4696
    #ifndef NO_RSA
4697
        rc = wolfTPM2_DecodeRsaDer(derBuf, derSz, &key->pub, NULL,
4698
            objectAttributes);
4699
    #else
4700
        rc = NOT_COMPILED_IN;
4701
    #endif
4702
    }
4703
    else if (rc == 0 && keyType == TPM_ALG_ECC) {
4704
    #ifdef HAVE_ECC
4705
        rc = wolfTPM2_DecodeEccDer(derBuf, derSz, &key->pub, NULL,
4706
            objectAttributes);
4707
    #else
4708
        rc = NOT_COMPILED_IN;
4709
    #endif
4710
    }
4711
4712
#ifdef WOLFTPM2_PEM_DECODE
4713
    if (derBuf != (byte*)input) {
4714
        XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4715
    }
4716
#endif
4717
4718
    return rc;
4719
}
4720
4721
int wolfTPM2_ImportPrivateKeyBuffer(WOLFTPM2_DEV* dev,
4722
    const WOLFTPM2_KEY* parentKey, int keyType, WOLFTPM2_KEYBLOB* keyBlob,
4723
    int encodingType, const char* input, word32 inSz, const char* pass,
4724
    TPMA_OBJECT objectAttributes, byte* seed, word32 seedSz)
4725
{
4726
    int rc = 0;
4727
    byte* derBuf;
4728
    word32 derSz;
4729
#ifdef WOLFTPM2_PEM_DECODE
4730
    word32 derBufSz = 0;
4731
#endif
4732
    TPM2B_PUBLIC* pub;
4733
    TPM2B_SENSITIVE sens;
4734
    word32 digestSz;
4735
4736
    if (dev == NULL || keyBlob == NULL || input == NULL || inSz == 0) {
4737
        return BAD_FUNC_ARG;
4738
    }
4739
4740
    if (keyType != TPM_ALG_RSA && keyType != TPM_ALG_ECC) {
4741
        return BAD_FUNC_ARG;
4742
    }
4743
4744
    pub = &keyBlob->pub;
4745
    XMEMSET(pub, 0, sizeof(*pub));
4746
    XMEMSET(&sens, 0, sizeof(sens));
4747
4748
    if (encodingType == ENCODING_TYPE_PEM) {
4749
    #ifdef WOLFTPM2_PEM_DECODE
4750
        /* der size is base 64 decode length */
4751
        if (inSz > (0xFFFFFFFFU / 3))
4752
            return BAD_FUNC_ARG;
4753
        derSz = inSz * 3 / 4 + 1;
4754
        derBufSz = derSz;
4755
        derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4756
        if (derBuf == NULL)
4757
            return MEMORY_E;
4758
        rc = wc_KeyPemToDer((byte*)input, inSz, derBuf, derSz, pass);
4759
        if (rc >= 0) {
4760
            derSz = rc;
4761
            rc = 0;
4762
        }
4763
    #else
4764
        (void)pass;
4765
        return NOT_COMPILED_IN;
4766
    #endif
4767
    }
4768
    else { /* ASN.1 (DER) */
4769
        derBuf = (byte*)input;
4770
        derSz = inSz;
4771
    }
4772
4773
    /* Handle DER Import (skip if PEM-to-DER conversion above failed) */
4774
    if (rc == 0 && keyType == TPM_ALG_RSA) {
4775
    #ifndef NO_RSA
4776
        rc = wolfTPM2_DecodeRsaDer(derBuf, derSz, pub, &sens, objectAttributes);
4777
    #else
4778
        rc = NOT_COMPILED_IN;
4779
    #endif
4780
    }
4781
    else if (rc == 0 && keyType == TPM_ALG_ECC) {
4782
    #ifdef HAVE_ECC
4783
        rc = wolfTPM2_DecodeEccDer(derBuf, derSz, pub, &sens, objectAttributes);
4784
    #else
4785
        rc = NOT_COMPILED_IN;
4786
    #endif
4787
    }
4788
4789
    if (rc == 0 && parentKey != NULL) {
4790
        /* Setup private key */
4791
        if (keyBlob->handle.auth.size > 0) {
4792
            TPM2B_AUTH* auth = &sens.sensitiveArea.authValue;
4793
            auth->size = keyBlob->handle.auth.size;
4794
            if (auth->size > sizeof(auth->buffer)) {
4795
                auth->size = sizeof(auth->buffer);
4796
            }
4797
            XMEMCPY(auth->buffer, keyBlob->handle.auth.buffer, auth->size);
4798
        }
4799
4800
        /* Use Seed */
4801
        digestSz = (word32)TPM2_GetHashDigestSize(pub->publicArea.nameAlg);
4802
        if (digestSz == 0 ||
4803
            digestSz > sizeof(sens.sensitiveArea.seedValue.buffer)) {
4804
        #ifdef DEBUG_WOLFTPM
4805
            printf("Import %s name alg size invalid! %d\n",
4806
                TPM2_GetAlgName((TPM_ALG_ID)keyType), digestSz);
4807
        #endif
4808
            rc = BUFFER_E;
4809
        }
4810
        if ((seed != NULL) && (rc == 0)) {
4811
            /* use custom seed */
4812
            if (seedSz != digestSz) {
4813
            #ifdef DEBUG_WOLFTPM
4814
                printf("Import %s seed size invalid! %d != %d\n",
4815
                    TPM2_GetAlgName(keyType), seedSz, digestSz);
4816
            #endif
4817
                rc = BAD_FUNC_ARG;
4818
            }
4819
            if (rc == 0) {
4820
                sens.sensitiveArea.seedValue.size = seedSz;
4821
                XMEMCPY(sens.sensitiveArea.seedValue.buffer, seed, seedSz);
4822
            }
4823
        }
4824
        else if (rc == 0) {
4825
            /* assign random seed */
4826
            sens.sensitiveArea.seedValue.size = digestSz;
4827
            rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
4828
                sens.sensitiveArea.seedValue.size);
4829
        }
4830
4831
        if (rc == 0) {
4832
            /* Import Private Key */
4833
            rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, pub, &sens);
4834
        }
4835
    }
4836
4837
#ifdef WOLFTPM2_PEM_DECODE
4838
    if (derBuf != (byte*)input) {
4839
        TPM2_ForceZero(derBuf, derBufSz);
4840
        XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4841
    }
4842
#endif
4843
4844
    TPM2_ForceZero(&sens, sizeof(sens));
4845
4846
    return rc;
4847
}
4848
4849
#ifndef NO_RSA
4850
int wolfTPM2_RsaPrivateKeyImportDer(WOLFTPM2_DEV* dev,
4851
    const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* input,
4852
    word32 inSz, TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
4853
{
4854
    int rc = 0;
4855
    int initRc = -1;
4856
    RsaKey key[1];
4857
    word32 idx = 0;
4858
    word32  e = 0;
4859
    byte n[RSA_MAX_SIZE / 8];
4860
    byte d[RSA_MAX_SIZE / 8];
4861
    byte p[RSA_MAX_SIZE / 8];
4862
    byte q[RSA_MAX_SIZE / 8];
4863
    word32  eSz = (word32)sizeof(e);
4864
    word32  nSz = (word32)sizeof(n);
4865
    word32  dSz = (word32)sizeof(d);
4866
    word32  pSz = (word32)sizeof(p);
4867
    word32  qSz = (word32)sizeof(q);
4868
4869
    if (dev == NULL || parentKey == NULL || keyBlob == NULL || input == NULL ||
4870
        inSz == 0) {
4871
        rc = BAD_FUNC_ARG;
4872
    }
4873
4874
    if (rc == 0)
4875
        rc = initRc = wc_InitRsaKey(key, NULL);
4876
4877
    if (rc == 0) {
4878
    #ifdef HAVE_PKCS8
4879
        /* Skip a PKCS#8 wrapper if present (BEGIN PRIVATE KEY) */
4880
        (void)wc_GetPkcs8TraditionalOffset((byte*)input, &idx, inSz);
4881
    #endif
4882
        rc = wc_RsaPrivateKeyDecode(input, &idx, key, inSz);
4883
    }
4884
4885
    if (rc == 0) {
4886
        PRIVATE_KEY_UNLOCK();
4887
        rc = wc_RsaExportKey(key, (byte*)&e, &eSz, n, &nSz, d, &dSz, p, &pSz, q,
4888
            &qSz);
4889
        PRIVATE_KEY_LOCK();
4890
    }
4891
4892
    if (rc == 0) {
4893
        rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, keyBlob, n, nSz, e, q,
4894
            qSz, scheme, hashAlg);
4895
    }
4896
4897
    if (initRc == 0) {
4898
        wc_FreeRsaKey(key);
4899
        TPM2_ForceZero(key, sizeof(RsaKey));
4900
    }
4901
4902
    TPM2_ForceZero(d, sizeof(d));
4903
    TPM2_ForceZero(p, sizeof(p));
4904
    TPM2_ForceZero(q, sizeof(q));
4905
4906
    return rc;
4907
}
4908
4909
#ifdef WOLFTPM2_PEM_DECODE
4910
int wolfTPM2_RsaPrivateKeyImportPem(WOLFTPM2_DEV* dev,
4911
    const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob,
4912
    const char* input, word32 inSz, char* pass,
4913
    TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg)
4914
{
4915
    int rc;
4916
    byte* derBuf;
4917
    word32 derSz;
4918
    word32 derBufSz;
4919
4920
    if (dev == NULL || parentKey == NULL || keyBlob == NULL ||
4921
            input == NULL || inSz == 0) {
4922
        return BAD_FUNC_ARG;
4923
    }
4924
4925
    /* der size is base 64 decode length */
4926
    if (inSz > (0xFFFFFFFFU / 3))
4927
        return BAD_FUNC_ARG;
4928
    derSz = inSz * 3 / 4 + 1;
4929
    derBufSz = derSz;
4930
    derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4931
    if (derBuf == NULL)
4932
        return MEMORY_E;
4933
4934
    /* Convert PEM to DER, then import through the DER path so the requested
4935
     * RSA scheme and hash are applied. The DER importer skips any PKCS#8
4936
     * wrapper wc_KeyPemToDer leaves in place. */
4937
    rc = wc_KeyPemToDer((byte*)input, inSz, derBuf, derBufSz, pass);
4938
    if (rc >= 0) {
4939
        derSz = (word32)rc;
4940
        rc = wolfTPM2_RsaPrivateKeyImportDer(dev, parentKey, keyBlob,
4941
            derBuf, derSz, scheme, hashAlg);
4942
    }
4943
4944
    TPM2_ForceZero(derBuf, derBufSz);
4945
    XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4946
    return rc;
4947
}
4948
#endif /* WOLFTPM2_PEM_DECODE */
4949
4950
int wolfTPM2_RsaKey_TpmToPemPub(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
4951
    byte* pem, word32* pemSz)
4952
{
4953
    return wolfTPM2_ExportPublicKeyBuffer(dev, tpmKey,
4954
        ENCODING_TYPE_PEM, pem, pemSz);
4955
}
4956
#endif /* !NO_RSA */
4957
#endif /* !NO_ASN */
4958
4959
#ifndef NO_RSA
4960
int wolfTPM2_RsaKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
4961
    RsaKey* wolfKey)
4962
{
4963
    int rc;
4964
    word32  exponent;
4965
    byte    e[sizeof(exponent)];
4966
    byte    n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
4967
    word32  eSz;
4968
    word32  nSz;
4969
4970
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
4971
        return BAD_FUNC_ARG;
4972
4973
    XMEMSET(e, 0, sizeof(e));
4974
    XMEMSET(n, 0, sizeof(n));
4975
4976
    /* load exponent */
4977
    exponent = tpmKey->pub.publicArea.parameters.rsaDetail.exponent;
4978
    if (exponent == 0)
4979
        exponent = RSA_DEFAULT_PUBLIC_EXPONENT;
4980
    /* big-endian, matching wc_RsaPublicKeyDecodeRaw and RsaKey_Exponent */
4981
    e[0] = (exponent >> 24) & 0xFF;
4982
    e[1] = (exponent >> 16) & 0xFF;
4983
    e[2] = (exponent >> 8)  & 0xFF;
4984
    e[3] =  exponent        & 0xFF;
4985
    eSz = e[0] ? 4 : e[1] ? 3 : e[2] ? 2 : e[3] ? 1 : 0; /* significant bytes */
4986
4987
    /* load public key */
4988
    nSz = tpmKey->pub.publicArea.unique.rsa.size;
4989
    if (nSz > sizeof(n)) {
4990
        return BUFFER_E;
4991
    }
4992
    XMEMCPY(n, tpmKey->pub.publicArea.unique.rsa.buffer, nSz);
4993
4994
    /* load public key portion into wolf RsaKey (pass trailing significant e) */
4995
    rc = wc_RsaPublicKeyDecodeRaw(n, nSz, e + (sizeof(e) - eSz), eSz, wolfKey);
4996
4997
    return rc;
4998
}
4999
5000
int wolfTPM2_CreateRsaKeyBlob(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
5001
    RsaKey* wolfKey, WOLFTPM2_KEYBLOB* tpmKey)
5002
{
5003
    int rc;
5004
    word32  exponent;
5005
    byte    e[sizeof(exponent)];
5006
    byte    n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5007
    byte    d[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5008
    byte    p[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5009
    byte    q[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5010
    word32  eSz = sizeof(e);
5011
    word32  nSz = sizeof(n);
5012
    word32  dSz = sizeof(d);
5013
    word32  pSz = sizeof(p);
5014
    word32  qSz = sizeof(q);
5015
5016
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL || parentKey == NULL ||
5017
        wolfKey->type != RSA_PRIVATE) {
5018
        return BAD_FUNC_ARG;
5019
    }
5020
5021
    XMEMSET(e, 0, sizeof(e));
5022
    XMEMSET(n, 0, sizeof(n));
5023
    XMEMSET(d, 0, sizeof(d));
5024
    XMEMSET(p, 0, sizeof(p));
5025
    XMEMSET(q, 0, sizeof(q));
5026
5027
    /* export the raw private and public RSA as unsigned binary */
5028
    PRIVATE_KEY_UNLOCK();
5029
    rc = wc_RsaExportKey(wolfKey, e, &eSz, n, &nSz,
5030
        d, &dSz, p, &pSz, q, &qSz);
5031
    PRIVATE_KEY_LOCK();
5032
    if (rc == 0) {
5033
        exponent = wolfTPM2_RsaKey_Exponent(e, eSz);
5034
5035
        rc = wolfTPM2_ImportRsaPrivateKey(dev, parentKey, tpmKey, n, nSz,
5036
            exponent, q, qSz, TPM_ALG_NULL, TPM_ALG_NULL);
5037
    }
5038
5039
    /* not used */
5040
    (void)p;
5041
5042
    TPM2_ForceZero(d, sizeof(d));
5043
    TPM2_ForceZero(p, sizeof(p));
5044
    TPM2_ForceZero(q, sizeof(q));
5045
    return rc;
5046
}
5047
5048
int wolfTPM2_RsaKey_WolfToTpm_ex(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
5049
    RsaKey* wolfKey, WOLFTPM2_KEY* tpmKey)
5050
{
5051
    int rc;
5052
    word32  exponent;
5053
    byte    e[sizeof(exponent)];
5054
    byte    n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5055
    word32  eSz = sizeof(e);
5056
    word32  nSz = sizeof(n);
5057
5058
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
5059
        return BAD_FUNC_ARG;
5060
5061
    XMEMSET(e, 0, sizeof(e));
5062
    XMEMSET(n, 0, sizeof(n));
5063
5064
    if (parentKey && wolfKey->type == RSA_PRIVATE) {
5065
        byte    d[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5066
        byte    p[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5067
        byte    q[WOLFTPM2_WRAP_RSA_KEY_BITS / 8];
5068
        word32  dSz = sizeof(d);
5069
        word32  pSz = sizeof(p);
5070
        word32  qSz = sizeof(q);
5071
5072
        XMEMSET(d, 0, sizeof(d));
5073
        XMEMSET(p, 0, sizeof(p));
5074
        XMEMSET(q, 0, sizeof(q));
5075
5076
        /* export the raw private and public RSA as unsigned binary */
5077
        PRIVATE_KEY_UNLOCK();
5078
        rc = wc_RsaExportKey(wolfKey, e, &eSz, n, &nSz,
5079
            d, &dSz, p, &pSz, q, &qSz);
5080
        PRIVATE_KEY_LOCK();
5081
        if (rc == 0) {
5082
            exponent = wolfTPM2_RsaKey_Exponent(e, eSz);
5083
            rc = wolfTPM2_LoadRsaPrivateKey(dev, parentKey, tpmKey, n, nSz,
5084
                exponent, q, qSz);
5085
        }
5086
5087
        /* not used */
5088
        (void)p;
5089
5090
        TPM2_ForceZero(d, sizeof(d));
5091
        TPM2_ForceZero(p, sizeof(p));
5092
        TPM2_ForceZero(q, sizeof(q));
5093
    }
5094
    else {
5095
        /* export the raw public RSA portion */
5096
        rc = wc_RsaFlattenPublicKey(wolfKey, e, &eSz, n, &nSz);
5097
        if (rc == 0) {
5098
            exponent = wolfTPM2_RsaKey_Exponent(e, eSz);
5099
            rc = wolfTPM2_LoadRsaPublicKey(dev, tpmKey, n, nSz, exponent);
5100
        }
5101
    }
5102
5103
    return rc;
5104
}
5105
int wolfTPM2_RsaKey_WolfToTpm(WOLFTPM2_DEV* dev, RsaKey* wolfKey,
5106
    WOLFTPM2_KEY* tpmKey)
5107
{
5108
    return wolfTPM2_RsaKey_WolfToTpm_ex(dev, NULL, wolfKey, tpmKey);
5109
}
5110
5111
#ifndef NO_ASN
5112
int wolfTPM2_RsaKey_PubPemToTpm(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
5113
    const byte* pem, word32 pemSz)
5114
{
5115
    int rc = TPM_RC_FAILURE;
5116
#ifdef WOLFTPM2_PEM_DECODE
5117
    RsaKey rsaKey;
5118
#endif
5119
5120
    if (dev == NULL || tpmKey == NULL || pem == NULL)
5121
        return BAD_FUNC_ARG;
5122
5123
#ifdef WOLFTPM2_PEM_DECODE
5124
    /* Prepare wolfCrypt key structure */
5125
    rc = wc_InitRsaKey(&rsaKey, NULL);
5126
    if (rc == 0) {
5127
        /* allocate buffer for DER */
5128
        word32 derSz = pemSz; /* DER is always smaller */
5129
        byte* derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
5130
        if (derBuf == NULL) {
5131
            rc = MEMORY_E;
5132
        }
5133
        if (rc == 0) {
5134
            /* Convert PEM format key from file to DER - inline okay */
5135
            rc = wc_PubKeyPemToDer(pem, pemSz, derBuf, derSz);
5136
        }
5137
        if (rc >= 0) {
5138
            /* Convert DER to wolfCrypt file */
5139
            word32 idx = 0;
5140
            derSz = (word32)rc;
5141
            rc = wc_RsaPublicKeyDecode(derBuf, &idx, &rsaKey, derSz);
5142
        }
5143
        if (rc == 0) {
5144
            /* Load into the TPM */
5145
            rc = wolfTPM2_RsaKey_WolfToTpm(dev, &rsaKey, tpmKey);
5146
        }
5147
        XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
5148
        wc_FreeRsaKey(&rsaKey);
5149
    }
5150
#else
5151
    (void)pemSz;
5152
#endif
5153
5154
    return rc;
5155
}
5156
#endif /* !NO_ASN */
5157
#endif /* !NO_RSA */
5158
5159
#ifdef HAVE_ECC
5160
#ifdef HAVE_ECC_KEY_IMPORT
5161
int wolfTPM2_EccKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey,
5162
    ecc_key* wolfKey)
5163
{
5164
    int rc, curve_id, keySz;
5165
    byte    qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5166
    byte    qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5167
    word32  qxSz;
5168
    word32  qySz;
5169
5170
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
5171
        return BAD_FUNC_ARG;
5172
5173
    XMEMSET(qx, 0, sizeof(qx));
5174
    XMEMSET(qy, 0, sizeof(qy));
5175
5176
    /* load curve type */
5177
    curve_id = tpmKey->pub.publicArea.parameters.eccDetail.curveID;
5178
    keySz = wolfTPM2_GetCurveSize(curve_id); /* field size for right-align */
5179
    rc = TPM2_GetWolfCurve(curve_id);
5180
    if (rc < 0)
5181
        return rc;
5182
    curve_id = rc;
5183
    if (keySz <= 0 || keySz > (int)sizeof(qx)) {
5184
        return BUFFER_E;
5185
    }
5186
5187
    /* load public key; right-align each coordinate into the field-size buffer
5188
     * so wc_ecc_import_unsigned reads the correct big-endian value even when
5189
     * the TPM stripped leading zero bytes */
5190
    qxSz = tpmKey->pub.publicArea.unique.ecc.x.size;
5191
    if (qxSz > (word32)keySz ||
5192
        qxSz > sizeof(tpmKey->pub.publicArea.unique.ecc.x.buffer)) {
5193
        return BUFFER_E;
5194
    }
5195
    XMEMCPY(qx + (keySz - (int)qxSz),
5196
        tpmKey->pub.publicArea.unique.ecc.x.buffer, qxSz);
5197
    qySz = tpmKey->pub.publicArea.unique.ecc.y.size;
5198
    if (qySz > (word32)keySz ||
5199
        qySz > sizeof(tpmKey->pub.publicArea.unique.ecc.y.buffer)) {
5200
        return BUFFER_E;
5201
    }
5202
    XMEMCPY(qy + (keySz - (int)qySz),
5203
        tpmKey->pub.publicArea.unique.ecc.y.buffer, qySz);
5204
5205
    /* load public key portion into wolf ecc_key */
5206
    rc = wc_ecc_import_unsigned(wolfKey, qx, qy, NULL, curve_id);
5207
5208
    return rc;
5209
}
5210
#endif /* HAVE_ECC_KEY_IMPORT */
5211
#ifdef HAVE_ECC_KEY_EXPORT
5212
static int wolfTPM2_EccMakePubBlinded(ecc_key* key, ecc_point* point)
5213
{
5214
#if defined(ECC_TIMING_RESISTANT) && !defined(WC_NO_RNG)
5215
    WC_RNG rng;
5216
    int rc;
5217
5218
    XMEMSET(&rng, 0, sizeof(rng));
5219
    rc = wc_InitRng(&rng);
5220
    if (rc == 0) {
5221
        rc = wc_ecc_make_pub_ex(key, point, &rng);
5222
        wc_FreeRng(&rng);
5223
    }
5224
5225
    TPM2_ForceZero(&rng, sizeof(rng));
5226
    return rc;
5227
#else
5228
    /* blinding requires ECC_TIMING_RESISTANT in wolfCrypt */
5229
    return wc_ecc_make_pub(key, point);
5230
#endif
5231
}
5232
5233
int wolfTPM2_CreateEccKeyBlob(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* parentKey,
5234
    ecc_key* wolfKey, WOLFTPM2_KEYBLOB* tpmKey)
5235
{
5236
    int rc, curve_id = 0;
5237
    byte    qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5238
    byte    qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5239
    byte    d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5240
    word32  qxSz = sizeof(qx);
5241
    word32  qySz = sizeof(qy);
5242
    word32  dSz = sizeof(d);
5243
5244
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL || parentKey == NULL ||
5245
        wolfKey->type == ECC_PUBLICKEY) {
5246
        return BAD_FUNC_ARG;
5247
    }
5248
5249
    XMEMSET(tpmKey, 0, sizeof(*tpmKey));
5250
    XMEMSET(qx, 0, sizeof(qx));
5251
    XMEMSET(qy, 0, sizeof(qy));
5252
    XMEMSET(d, 0, sizeof(d));
5253
5254
    if (wolfKey->dp)
5255
        curve_id = wolfKey->dp->id;
5256
5257
    rc = TPM2_GetTpmCurve(curve_id);
5258
    if (rc < 0)
5259
        return rc;
5260
    curve_id = rc;
5261
    rc = 0;
5262
5263
    if (wolfKey->type == ECC_PRIVATEKEY_ONLY) {
5264
        /* compute public point without modifying incoming wolf key */
5265
        int keySz = wc_ecc_size(wolfKey);
5266
        ecc_point* point = wc_ecc_new_point();
5267
        if (point == NULL) {
5268
            rc = MEMORY_E;
5269
        }
5270
        if (rc == 0) {
5271
            rc = wolfTPM2_EccMakePubBlinded(wolfKey, point);
5272
            if (rc == 0)
5273
                rc = wc_export_int(point->x, qx, &qxSz, keySz,
5274
                    WC_TYPE_UNSIGNED_BIN);
5275
            if (rc == 0)
5276
                rc = wc_export_int(point->y, qy, &qySz, keySz,
5277
                    WC_TYPE_UNSIGNED_BIN);
5278
            if (rc == 0) {
5279
                PRIVATE_KEY_UNLOCK();
5280
                rc = wc_ecc_export_private_only(wolfKey, d, &dSz);
5281
                PRIVATE_KEY_LOCK();
5282
            }
5283
            wc_ecc_del_point(point);
5284
        }
5285
    }
5286
    else {
5287
        /* export the raw private/public ECC portions */
5288
        PRIVATE_KEY_UNLOCK();
5289
        rc = wc_ecc_export_private_raw(wolfKey,
5290
            qx, &qxSz,
5291
            qy, &qySz,
5292
            d, &dSz);
5293
        PRIVATE_KEY_LOCK();
5294
    }
5295
5296
    if (rc == 0) {
5297
        rc = wolfTPM2_ImportEccPrivateKey(dev, parentKey, tpmKey, curve_id,
5298
            qx, qxSz, qy, qySz, d, dSz);
5299
    }
5300
5301
    TPM2_ForceZero(d, sizeof(d));
5302
    return rc;
5303
}
5304
5305
int wolfTPM2_EccKey_WolfToTpm_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* parentKey,
5306
    ecc_key* wolfKey, WOLFTPM2_KEY* tpmKey)
5307
{
5308
    int rc, curve_id = 0;
5309
    byte    qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5310
    byte    qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5311
    word32  qxSz = sizeof(qx);
5312
    word32  qySz = sizeof(qy);
5313
5314
    if (dev == NULL || tpmKey == NULL || wolfKey == NULL)
5315
        return BAD_FUNC_ARG;
5316
5317
    XMEMSET(tpmKey, 0, sizeof(*tpmKey));
5318
    XMEMSET(qx, 0, sizeof(qx));
5319
    XMEMSET(qy, 0, sizeof(qy));
5320
5321
    if (wolfKey->dp)
5322
        curve_id = wolfKey->dp->id;
5323
5324
    rc = TPM2_GetTpmCurve(curve_id);
5325
    if (rc < 0)
5326
        return rc;
5327
    curve_id = rc;
5328
    rc = 0;
5329
5330
    if (parentKey && wolfKey->type != ECC_PUBLICKEY) {
5331
        byte    d[WOLFTPM2_WRAP_ECC_KEY_BITS / 8];
5332
        word32  dSz = sizeof(d);
5333
5334
        XMEMSET(d, 0, sizeof(d));
5335
5336
        if (wolfKey->type == ECC_PRIVATEKEY_ONLY) {
5337
            /* compute public point without modifying incoming wolf key */
5338
            int keySz = wc_ecc_size(wolfKey);
5339
            ecc_point* point = wc_ecc_new_point();
5340
            if (point == NULL) {
5341
                rc = MEMORY_E;
5342
            }
5343
            if (rc == 0) {
5344
                rc = wolfTPM2_EccMakePubBlinded(wolfKey, point);
5345
                if (rc == 0)
5346
                    rc = wc_export_int(point->x, qx, &qxSz, keySz,
5347
                        WC_TYPE_UNSIGNED_BIN);
5348
                if (rc == 0)
5349
                    rc = wc_export_int(point->y, qy, &qySz, keySz,
5350
                        WC_TYPE_UNSIGNED_BIN);
5351
                if (rc == 0) {
5352
                    PRIVATE_KEY_UNLOCK();
5353
                    rc = wc_ecc_export_private_only(wolfKey, d, &dSz);
5354
                    PRIVATE_KEY_LOCK();
5355
                }
5356
                wc_ecc_del_point(point);
5357
            }
5358
        }
5359
        else {
5360
            /* export the raw private/public ECC portions */
5361
            PRIVATE_KEY_UNLOCK();
5362
            rc = wc_ecc_export_private_raw(wolfKey,
5363
                qx, &qxSz,
5364
                qy, &qySz,
5365
                d, &dSz);
5366
            PRIVATE_KEY_LOCK();
5367
        }
5368
5369
        if (rc == 0) {
5370
            rc = wolfTPM2_LoadEccPrivateKey(dev, parentKey, tpmKey, curve_id,
5371
                qx, qxSz, qy, qySz, d, dSz);
5372
        }
5373
        TPM2_ForceZero(d, sizeof(d));
5374
    }
5375
    else {
5376
        /* export the raw public ECC portion */
5377
        rc = wc_ecc_export_public_raw(wolfKey, qx, &qxSz, qy, &qySz);
5378
        if (rc == 0) {
5379
            rc = wolfTPM2_LoadEccPublicKey(dev, tpmKey, curve_id, qx, qxSz,
5380
                qy, qySz);
5381
        }
5382
    }
5383
5384
    return rc;
5385
}
5386
int wolfTPM2_EccKey_WolfToTpm(WOLFTPM2_DEV* dev, ecc_key* wolfKey,
5387
    WOLFTPM2_KEY* tpmKey)
5388
{
5389
    return wolfTPM2_EccKey_WolfToTpm_ex(dev, NULL, wolfKey, tpmKey);
5390
}
5391
5392
int wolfTPM2_EccKey_WolfToPubPoint(WOLFTPM2_DEV* dev, ecc_key* wolfKey,
5393
    TPM2B_ECC_POINT* pubPoint)
5394
{
5395
    int rc;
5396
    word32 xSz, ySz;
5397
5398
    if (dev == NULL || wolfKey == NULL || pubPoint == NULL)
5399
        return BAD_FUNC_ARG;
5400
5401
    XMEMSET(pubPoint, 0, sizeof(TPM2B_ECC_POINT));
5402
    xSz = sizeof(pubPoint->point.x.buffer);;
5403
    ySz = sizeof(pubPoint->point.y.buffer);;
5404
5405
    /* load wolf ECC public key into TPM2B_ECC_POINT */
5406
    rc = wc_ecc_export_public_raw(wolfKey,
5407
        pubPoint->point.x.buffer, &xSz,
5408
        pubPoint->point.y.buffer, &ySz);
5409
    if (rc == 0) {
5410
        pubPoint->point.x.size = xSz;
5411
        pubPoint->point.y.size = ySz;
5412
    }
5413
5414
    return rc;
5415
}
5416
#endif /* HAVE_ECC_KEY_EXPORT */
5417
#endif /* HAVE_ECC */
5418
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
5419
5420
5421
/* primaryHandle must be owner or platform hierarchy */
5422
/* Owner    Persistent Handle Range: 0x81000000 to 0x817FFFFF */
5423
/* Platform Persistent Handle Range: 0x81800000 to 0x81FFFFFF */
5424
int wolfTPM2_NVStoreKey(WOLFTPM2_DEV* dev, TPM_HANDLE primaryHandle,
5425
    WOLFTPM2_KEY* key, TPM_HANDLE persistentHandle)
5426
{
5427
    int rc;
5428
    EvictControl_In in;
5429
5430
    if (dev == NULL || key == NULL) {
5431
        return BAD_FUNC_ARG;
5432
    }
5433
    if (primaryHandle == TPM_RH_OWNER &&
5434
        (persistentHandle < PERSISTENT_FIRST ||
5435
         persistentHandle > PERSISTENT_LAST)) {
5436
        return BAD_FUNC_ARG;
5437
    }
5438
    if (primaryHandle == TPM_RH_PLATFORM &&
5439
        (persistentHandle < PLATFORM_PERSISTENT ||
5440
         persistentHandle > PERSISTENT_LAST)) {
5441
        return BAD_FUNC_ARG;
5442
    }
5443
5444
    /* if key is already persistent then just return success */
5445
    if (key->handle.hndl == persistentHandle)
5446
        return TPM_RC_SUCCESS;
5447
5448
    /* set session auth to blank */
5449
    wolfTPM2_SetAuthPassword(dev, 0, NULL);
5450
5451
    /* Move key into NV to persist */
5452
    XMEMSET(&in, 0, sizeof(in));
5453
    in.auth = primaryHandle;
5454
    in.objectHandle = key->handle.hndl;
5455
    in.persistentHandle = persistentHandle;
5456
5457
    rc = TPM2_EvictControl(&in);
5458
    if (rc != TPM_RC_SUCCESS) {
5459
    #ifdef WOLFTPM_WINAPI
5460
        if (rc == (int)TPM_E_COMMAND_BLOCKED) { /* 0x80280400 */
5461
        #ifdef DEBUG_WOLFTPM
5462
            printf("TPM2_EvictControl (storing key to NV) not allowed on "
5463
                   "Windows TBS (err 0x%x)\n", rc);
5464
        #endif
5465
            rc = TPM_RC_COMMAND_CODE;
5466
        }
5467
    #endif
5468
5469
    #ifdef DEBUG_WOLFTPM
5470
        printf("TPM2_EvictControl failed %d: %s\n", rc,
5471
            wolfTPM2_GetRCString(rc));
5472
    #endif
5473
        return rc;
5474
    }
5475
5476
#ifdef DEBUG_WOLFTPM
5477
    printf("TPM2_EvictControl Auth 0x%x, Key 0x%x, Persistent 0x%x\n",
5478
        (word32)in.auth, (word32)in.objectHandle, (word32)in.persistentHandle);
5479
#endif
5480
5481
    /* unload transient handle */
5482
    wolfTPM2_UnloadHandle(dev, &key->handle);
5483
5484
    /* replace handle with persistent one */
5485
    key->handle.hndl = persistentHandle;
5486
5487
    return rc;
5488
}
5489
5490
int wolfTPM2_NVDeleteKey(WOLFTPM2_DEV* dev, TPM_HANDLE primaryHandle,
5491
    WOLFTPM2_KEY* key)
5492
{
5493
    int rc;
5494
    EvictControl_In in;
5495
5496
    if (dev == NULL || key == NULL || primaryHandle == 0) {
5497
        return BAD_FUNC_ARG;
5498
    }
5499
5500
    /* if key is not persistent then just return success */
5501
    if (key->handle.hndl < PERSISTENT_FIRST ||
5502
            key->handle.hndl > PERSISTENT_LAST)
5503
        return TPM_RC_SUCCESS;
5504
5505
    /* remove key from NV */
5506
    XMEMSET(&in, 0, sizeof(in));
5507
    in.auth = primaryHandle;
5508
    in.objectHandle = key->handle.hndl;
5509
    in.persistentHandle = key->handle.hndl;
5510
5511
    rc = TPM2_EvictControl(&in);
5512
    if (rc != TPM_RC_SUCCESS) {
5513
    #ifdef DEBUG_WOLFTPM
5514
        printf("TPM2_EvictControl failed %d: %s\n", rc,
5515
            wolfTPM2_GetRCString(rc));
5516
    #endif
5517
        return rc;
5518
    }
5519
5520
#ifdef DEBUG_WOLFTPM
5521
    printf("TPM2_EvictControl Auth 0x%x, Key 0x%x, Persistent 0x%x\n",
5522
        (word32)in.auth, (word32)in.objectHandle, (word32)in.persistentHandle);
5523
#endif
5524
5525
    /* indicate no handle */
5526
    key->handle.hndl = TPM_RH_NULL;
5527
5528
    return rc;
5529
}
5530
5531
/* Wrapper signatures use fixed-width R || S even when the TPM encodes a
5532
 * scalar without leading zero octets. Validate all lengths before writing. */
5533
static int wolfTPM2_ExtractEccSignature(const WOLFTPM2_KEY* key,
5534
    const TPMS_SIGNATURE_ECDSA* ecc, byte* sig, int* sigSz)
5535
{
5536
    int curveSize;
5537
5538
    if (key == NULL || ecc == NULL || sig == NULL || sigSz == NULL) {
5539
        return BAD_FUNC_ARG;
5540
    }
5541
    if (key->pub.publicArea.type != TPM_ALG_ECC) {
5542
        return BAD_FUNC_ARG;
5543
    }
5544
    curveSize = wolfTPM2_GetCurveSize(
5545
        key->pub.publicArea.parameters.eccDetail.curveID);
5546
    if (curveSize <= 0) {
5547
        return BAD_FUNC_ARG;
5548
    }
5549
    if (2 * curveSize > *sigSz ||
5550
            ecc->signatureR.size > curveSize ||
5551
            ecc->signatureS.size > curveSize ||
5552
            ecc->signatureR.size > sizeof(ecc->signatureR.buffer) ||
5553
            ecc->signatureS.size > sizeof(ecc->signatureS.buffer)) {
5554
        return BUFFER_E;
5555
    }
5556
    XMEMSET(sig, 0, 2 * curveSize);
5557
    XMEMCPY(sig + curveSize - ecc->signatureR.size,
5558
        ecc->signatureR.buffer, ecc->signatureR.size);
5559
    XMEMCPY(sig + 2 * curveSize - ecc->signatureS.size,
5560
        ecc->signatureS.buffer, ecc->signatureS.size);
5561
    *sigSz = 2 * curveSize;
5562
    return TPM_RC_SUCCESS;
5563
}
5564
5565
/* sigAlg: TPM_ALG_RSASSA, TPM_ALG_RSAPSS, TPM_ALG_ECDSA or TPM_ALG_ECDAA */
5566
/* hashAlg: TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384 or TPM_ALG_SHA512 */
5567
int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5568
    const byte* digest, int digestSz, byte* sig, int* sigSz,
5569
    TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg)
5570
{
5571
    int rc;
5572
    Sign_In  signIn;
5573
    Sign_Out signOut;
5574
    int curveSize = 0;
5575
    int sigOutSz = 0;
5576
5577
    if (dev == NULL || key == NULL || digest == NULL || sig == NULL ||
5578
                                                                sigSz == NULL) {
5579
        return BAD_FUNC_ARG;
5580
    }
5581
5582
    if (key->pub.publicArea.type != TPM_ALG_ECC &&
5583
            key->pub.publicArea.type != TPM_ALG_RSA) {
5584
        return BAD_FUNC_ARG;
5585
    }
5586
5587
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
5588
        /* get curve size */
5589
        curveSize = wolfTPM2_GetCurveSize(
5590
            key->pub.publicArea.parameters.eccDetail.curveID);
5591
        if (curveSize <= 0) {
5592
            return BAD_FUNC_ARG;
5593
        }
5594
    }
5595
5596
    /* set session auth for key */
5597
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
5598
5599
    XMEMSET(&signIn, 0, sizeof(signIn));
5600
    signIn.keyHandle = key->handle.hndl;
5601
    signIn.digest.size = (UINT16)TPM2_GetHashDigestSize(hashAlg);
5602
    if (signIn.digest.size == 0 ||
5603
        signIn.digest.size > sizeof(signIn.digest.buffer)) {
5604
        return BUFFER_E;
5605
    }
5606
    /* Hard upper bound: digest must fit the message-buffer. */
5607
    if (digestSz < 0 || digestSz > (int)sizeof(signIn.digest.buffer)) {
5608
        return BUFFER_E;
5609
    }
5610
    if (key->pub.publicArea.type != TPM_ALG_ECC) {
5611
        /* RSA: digest size must match the declared hash algorithm.
5612
         * Silently zero-padding produces a signature over crafted
5613
         * but incorrect content, so this is a caller error. */
5614
        if (digestSz != (int)signIn.digest.size) {
5615
            return BUFFER_E;
5616
        }
5617
        XMEMCPY(signIn.digest.buffer, digest, digestSz);
5618
    }
5619
    else {
5620
        /* ECDSA: digests shorter than hashAlg's size are left-padded with
5621
         * zeros; longer digests are silently truncated to hashAlg's size
5622
         * (TCG Part 1 - ECDSA admits short or long inputs). */
5623
        if (digestSz < (int)signIn.digest.size) {
5624
            XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz],
5625
                digest, digestSz);
5626
        }
5627
        else {
5628
            XMEMCPY(signIn.digest.buffer, digest, signIn.digest.size);
5629
        }
5630
    }
5631
    signIn.inScheme.scheme = sigAlg;
5632
    signIn.inScheme.details.any.hashAlg = hashAlg;
5633
    signIn.validation.tag = TPM_ST_HASHCHECK;
5634
    signIn.validation.hierarchy = TPM_RH_NULL;
5635
    rc = TPM2_Sign(&signIn, &signOut);
5636
    if (rc != TPM_RC_SUCCESS) {
5637
    #ifdef DEBUG_WOLFTPM
5638
        printf("TPM2_Sign failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
5639
    #endif
5640
        return rc;
5641
    }
5642
5643
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
5644
        rc = wolfTPM2_ExtractEccSignature(key,
5645
            &signOut.signature.signature.ecdsa, sig, sigSz);
5646
        if (rc != TPM_RC_SUCCESS) {
5647
            return rc;
5648
        }
5649
        sigOutSz = *sigSz;
5650
    }
5651
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
5652
        /* RSA signature size and buffer (with padding depending on scheme) */
5653
        sigOutSz = signOut.signature.signature.rsassa.sig.size;
5654
        if (sigOutSz > *sigSz) {
5655
        #ifdef DEBUG_WOLFTPM
5656
            printf("TPM2_Sign: RSA result buffer too small %d -> %d\n",
5657
                sigOutSz, *sigSz);
5658
        #endif
5659
            return BUFFER_E;
5660
        }
5661
        XMEMCPY(sig, signOut.signature.signature.rsassa.sig.buffer, sigOutSz);
5662
    }
5663
    *sigSz = sigOutSz;
5664
5665
#ifdef DEBUG_WOLFTPM
5666
    printf("TPM2_Sign: %s %d\n",
5667
        TPM2_GetAlgName(signIn.inScheme.scheme), *sigSz);
5668
#endif
5669
5670
    return rc;
5671
}
5672
5673
int wolfTPM2_SignHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5674
    const byte* digest, int digestSz, byte* sig, int* sigSz)
5675
{
5676
    TPM_ALG_ID sigAlg = TPM_ALG_NULL;
5677
    TPMI_ALG_HASH hashAlg = WOLFTPM2_WRAP_DIGEST;
5678
    TPMT_PUBLIC* pub;
5679
5680
    if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
5681
        return BAD_FUNC_ARG;
5682
    }
5683
5684
    pub = &key->pub.publicArea;
5685
    if (pub->type == TPM_ALG_ECC) {
5686
        /* Keys that are created with sign and decrypt require scheme to
5687
         * be NULL, but we must supply ECDSA and Hash Algorithm for signing */
5688
        sigAlg = pub->parameters.eccDetail.scheme.scheme;
5689
        hashAlg = pub->parameters.eccDetail.scheme.details.any.hashAlg;
5690
        if (sigAlg == 0 || sigAlg == TPM_ALG_NULL) {
5691
            sigAlg = TPM_ALG_ECDSA;
5692
        }
5693
        if (hashAlg == 0 || hashAlg == TPM_ALG_NULL) {
5694
            /* determine hash type based on curve */
5695
            int curve_id = pub->parameters.eccDetail.curveID;
5696
            if (curve_id == TPM_ECC_NIST_P521)
5697
                hashAlg = TPM_ALG_SHA512;
5698
            else if (curve_id == TPM_ECC_NIST_P384)
5699
                hashAlg = TPM_ALG_SHA384;
5700
            else
5701
                hashAlg = TPM_ALG_SHA256;
5702
        }
5703
    }
5704
    else if (pub->type == TPM_ALG_RSA) {
5705
        sigAlg = pub->parameters.rsaDetail.scheme.scheme;
5706
        hashAlg = pub->parameters.rsaDetail.scheme.details.anySig.hashAlg;
5707
    }
5708
5709
    return wolfTPM2_SignHashScheme(dev, key, digest, digestSz, sig, sigSz,
5710
        sigAlg, hashAlg);
5711
5712
}
5713
5714
/* Reject a signature the TPM cannot accept as a parameter. Some parts stop
5715
 * responding until a hardware reset rather than erroring, so this must not be
5716
 * left to the TPM. Two limits apply: TPM_PT_INPUT_BUFFER bounds the parameter
5717
 * and TPM_PT_MAX_COMMAND_SIZE bounds the whole command, so the capability read
5718
 * is skipped only when the signature plus overhead fits inside
5719
 * TPM_MIN_INPUT_BUFFER, the floor every conformant TPM meets. That still
5720
 * covers every ECC signature and RSA up to 4096. Above it the limit must be
5721
 * established, so this fails closed. Returns TPM_RC_SUCCESS if it fits,
5722
 * BUFFER_E if it provably does not, and the query error otherwise so callers
5723
 * can tell the two apart. */
5724
5725
/* Bytes that share the command with the signature: 10-byte header, up to two
5726
 * 4-byte handles, a 4-byte auth-area size, a password session (~9) or an HMAC
5727
 * session with a nonce and digest (~75), the digest TPM2B (up to 66), and the
5728
 * TPMT_SIGNATURE tag/alg/size fields (~8). Rounded up with margin. Only used
5729
 * to reserve room against TPM_PT_MAX_COMMAND_SIZE, so an over-estimate can
5730
 * reject a signature that would just fit; override if that ever bites. */
5731
#ifndef TPM_SIG_CMD_OVERHEAD
5732
#define TPM_SIG_CMD_OVERHEAD 176
5733
#endif
5734
5735
/* extraSz is the caller's other variable-length parameters (digest, context),
5736
 * which the fixed overhead estimate does not cover. */
5737
static int wolfTPM2_CheckSigInputBuffer(int sigSz, int extraSz)
5738
{
5739
    int rc;
5740
    GetCapability_In  in;
5741
    GetCapability_Out out;
5742
    TPML_TAGGED_TPM_PROPERTY* props;
5743
    UINT32 inputBuffer;
5744
    UINT32 cmdSz;
5745
5746
    if (sigSz < 0 || extraSz < 0) {
5747
        return BUFFER_E;
5748
    }
5749
    cmdSz = (UINT32)sigSz + (UINT32)extraSz + TPM_SIG_CMD_OVERHEAD;
5750
    /* Overhead is included: a signature that fits the parameter floor could
5751
     * still overflow a TPM whose command limit equals that floor. */
5752
    if (cmdSz <= TPM_MIN_INPUT_BUFFER) {
5753
        return TPM_RC_SUCCESS;
5754
    }
5755
5756
    XMEMSET(&in, 0, sizeof(in));
5757
    XMEMSET(&out, 0, sizeof(out));
5758
    in.capability = TPM_CAP_TPM_PROPERTIES;
5759
    in.property = TPM_PT_INPUT_BUFFER;
5760
    in.propertyCount = 1;
5761
    rc = TPM2_GetCapability(&in, &out);
5762
    if (rc != TPM_RC_SUCCESS) {
5763
    #ifdef DEBUG_WOLFTPM
5764
        printf("Signature size check: cannot read TPM_PT_INPUT_BUFFER "
5765
            "(0x%x), refusing a %d byte signature\n", rc, sigSz);
5766
    #endif
5767
        return rc; /* query failure, distinct from a genuine oversize */
5768
    }
5769
    /* union - confirm the capability and property asked for */
5770
    props = &out.capabilityData.data.tpmProperties;
5771
    if (out.capabilityData.capability != TPM_CAP_TPM_PROPERTIES ||
5772
            props->count == 0 ||
5773
            props->tpmProperty[0].property != TPM_PT_INPUT_BUFFER) {
5774
    #ifdef DEBUG_WOLFTPM
5775
        printf("Signature size check: unexpected capability response, "
5776
            "refusing a %d byte signature\n", sigSz);
5777
    #endif
5778
        return TPM_RC_VALUE; /* not an oversize; the TPM answered wrongly */
5779
    }
5780
5781
    inputBuffer = props->tpmProperty[0].value;
5782
    if (inputBuffer == 0) {
5783
        return TPM_RC_VALUE; /* nonsensical limit, treat as unreadable */
5784
    }
5785
    if ((UINT32)sigSz > inputBuffer) {
5786
    #ifdef DEBUG_WOLFTPM
5787
        printf("Signature size check: signature %d bytes exceeds the TPM's "
5788
            "%u byte input buffer\n", sigSz, (unsigned int)inputBuffer);
5789
    #endif
5790
        return BUFFER_E;
5791
    }
5792
5793
    /* The whole command has to fit too, and that is the limit this guard
5794
     * exists to respect, so an unreadable or malformed answer fails closed
5795
     * rather than letting the oversized command through. */
5796
    XMEMSET(&in, 0, sizeof(in));
5797
    XMEMSET(&out, 0, sizeof(out));
5798
    in.capability = TPM_CAP_TPM_PROPERTIES;
5799
    in.property = TPM_PT_MAX_COMMAND_SIZE;
5800
    in.propertyCount = 1;
5801
    rc = TPM2_GetCapability(&in, &out);
5802
    if (rc != TPM_RC_SUCCESS) {
5803
    #ifdef DEBUG_WOLFTPM
5804
        printf("Signature size check: cannot read TPM_PT_MAX_COMMAND_SIZE "
5805
            "(0x%x), refusing a %d byte signature\n", rc, sigSz);
5806
    #endif
5807
        return rc;
5808
    }
5809
    props = &out.capabilityData.data.tpmProperties;
5810
    if (out.capabilityData.capability != TPM_CAP_TPM_PROPERTIES ||
5811
            props->count == 0 ||
5812
            props->tpmProperty[0].property != TPM_PT_MAX_COMMAND_SIZE ||
5813
            props->tpmProperty[0].value == 0) {
5814
    #ifdef DEBUG_WOLFTPM
5815
        printf("Signature size check: unexpected command-size response, "
5816
            "refusing a %d byte signature\n", sigSz);
5817
    #endif
5818
        return TPM_RC_VALUE;
5819
    }
5820
    if (cmdSz > props->tpmProperty[0].value) {
5821
    #ifdef DEBUG_WOLFTPM
5822
        printf("Signature size check: command %u bytes exceeds the TPM's "
5823
            "%u byte command limit\n", (unsigned int)cmdSz,
5824
            (unsigned int)props->tpmProperty[0].value);
5825
    #endif
5826
        return BUFFER_E;
5827
    }
5828
5829
    return TPM_RC_SUCCESS;
5830
}
5831
5832
/* sigAlg: TPM_ALG_RSASSA, TPM_ALG_RSAPSS, TPM_ALG_ECDSA or TPM_ALG_ECDAA */
5833
/* hashAlg: TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384 or TPM_ALG_SHA512 */
5834
int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5835
    const byte* sig, int sigSz, const byte* digest, int digestSz,
5836
    TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg,
5837
    TPMT_TK_VERIFIED* checkTicket)
5838
{
5839
    int rc;
5840
    VerifySignature_In  verifySigIn;
5841
    TPMU_SIGNATURE* signature = &verifySigIn.signature.signature;
5842
    VerifySignature_Out verifySigOut;
5843
    int curveSize = 0;
5844
5845
    if (dev == NULL || key == NULL || digest == NULL || sig == NULL) {
5846
        return BAD_FUNC_ARG;
5847
    }
5848
5849
    rc = wolfTPM2_CheckSigInputBuffer(sigSz, digestSz);
5850
    if (rc != TPM_RC_SUCCESS) {
5851
        return rc;
5852
    }
5853
5854
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
5855
        if (sigAlg == TPM_ALG_NULL)
5856
            sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
5857
5858
        /* get curve size */
5859
        curveSize = wolfTPM2_GetCurveSize(
5860
            key->pub.publicArea.parameters.eccDetail.curveID);
5861
        if (curveSize <= 0 || sigSz < (curveSize * 2)) {
5862
            return BAD_FUNC_ARG;
5863
        }
5864
        /* verify curve size cannot exceed buffer */
5865
        if (curveSize > (int)sizeof(signature->ecdsa.signatureR.buffer)) {
5866
            return BAD_FUNC_ARG;
5867
        }
5868
5869
        /* hash cannot be larger than key size for TPM */
5870
        if (digestSz > curveSize)
5871
            digestSz = curveSize;
5872
    }
5873
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
5874
        if (sigAlg == TPM_ALG_NULL)
5875
            sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
5876
        if (sigSz > (int)sizeof(signature->rsassa.sig.buffer)){
5877
            return BAD_FUNC_ARG;
5878
        }
5879
    }
5880
    else {
5881
        return BAD_FUNC_ARG;
5882
    }
5883
5884
    /* set session auth for key */
5885
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
5886
5887
    XMEMSET(&verifySigIn, 0, sizeof(verifySigIn));
5888
    verifySigIn.keyHandle = key->handle.hndl;
5889
    verifySigIn.digest.size = (UINT16)TPM2_GetHashDigestSize(hashAlg);
5890
    if (verifySigIn.digest.size == 0 ||
5891
        verifySigIn.digest.size > sizeof(verifySigIn.digest.buffer)) {
5892
        return BUFFER_E;
5893
    }
5894
    /* Hard upper bound: digest must fit the message-buffer. */
5895
    if (digestSz < 0 || digestSz > (int)sizeof(verifySigIn.digest.buffer)) {
5896
        return BUFFER_E;
5897
    }
5898
    if (key->pub.publicArea.type != TPM_ALG_ECC) {
5899
        /* RSA: digest size must match the declared hash algorithm. */
5900
        if (digestSz != (int)verifySigIn.digest.size) {
5901
            return BUFFER_E;
5902
        }
5903
        XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
5904
    }
5905
    else {
5906
        /* ECDSA: short digests are left-padded with zeros, longer digests
5907
         * are silently truncated to hashAlg's size. */
5908
        if (digestSz < (int)verifySigIn.digest.size) {
5909
            XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size -
5910
                digestSz], digest, digestSz);
5911
        }
5912
        else {
5913
            XMEMCPY(verifySigIn.digest.buffer, digest, verifySigIn.digest.size);
5914
        }
5915
    }
5916
    verifySigIn.signature.sigAlg = sigAlg;
5917
    signature->any.hashAlg = hashAlg;
5918
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
5919
        /* Signature is R then S */
5920
        signature->ecdsa.signatureR.size = curveSize;
5921
        XMEMCPY(signature->ecdsa.signatureR.buffer, sig, curveSize);
5922
        signature->ecdsa.signatureS.size = curveSize;
5923
        XMEMCPY(signature->ecdsa.signatureS.buffer, sig + curveSize, curveSize);
5924
    }
5925
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
5926
        signature->rsassa.sig.size = sigSz;
5927
        XMEMCPY(signature->rsassa.sig.buffer, sig, sigSz);
5928
    }
5929
5930
    XMEMSET(&verifySigOut, 0, sizeof(verifySigOut));
5931
    rc = TPM2_VerifySignature(&verifySigIn, &verifySigOut);
5932
    if (rc != TPM_RC_SUCCESS) {
5933
    #ifdef DEBUG_WOLFTPM
5934
        printf("TPM2_VerifySignature failed %d: %s\n", rc,
5935
            wolfTPM2_GetRCString(rc));
5936
    #endif
5937
    }
5938
    else {
5939
        /* optionally return ticket */
5940
        if (checkTicket) {
5941
            XMEMCPY(checkTicket, &verifySigOut.validation,
5942
                sizeof(TPMT_TK_VERIFIED));
5943
        }
5944
    #ifdef DEBUG_WOLFTPM
5945
        printf("TPM2_VerifySignature: Tag %d\n", verifySigOut.validation.tag);
5946
    #endif
5947
    }
5948
    return rc;
5949
}
5950
5951
int wolfTPM2_VerifyHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5952
    const byte* sig, int sigSz, const byte* digest, int digestSz,
5953
    TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg)
5954
{
5955
    return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest,
5956
        digestSz, sigAlg, hashAlg, NULL);
5957
}
5958
5959
int wolfTPM2_VerifyHash_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5960
    const byte* sig, int sigSz, const byte* digest, int digestSz,
5961
    int hashAlg)
5962
{
5963
    return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest,
5964
        digestSz, TPM_ALG_NULL, hashAlg, NULL);
5965
}
5966
5967
int wolfTPM2_VerifyHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5968
    const byte* sig, int sigSz, const byte* digest, int digestSz)
5969
{
5970
    int hashAlg = TPM_ALG_SHA256;
5971
5972
    /* detect hash algorithm based on key type and parameters */
5973
    if (key != NULL) {
5974
        TPMT_PUBLIC* pub = &key->pub.publicArea;
5975
        if (pub->type == TPM_ALG_ECC) {
5976
            int curve_id = pub->parameters.eccDetail.curveID;
5977
            if (curve_id == TPM_ECC_NIST_P521)
5978
                hashAlg = TPM_ALG_SHA512;
5979
            else if (curve_id == TPM_ECC_NIST_P384)
5980
                hashAlg = TPM_ALG_SHA384;
5981
            else
5982
                hashAlg = TPM_ALG_SHA256;
5983
        }
5984
        else if (pub->type == TPM_ALG_RSA) {
5985
            hashAlg = pub->parameters.rsaDetail.scheme.details.anySig.hashAlg;
5986
            if (hashAlg == TPM_ALG_NULL || hashAlg == TPM_ALG_ERROR)
5987
                hashAlg = TPM_ALG_SHA256;
5988
        }
5989
    }
5990
5991
    return wolfTPM2_VerifyHashTicket(dev, key, sig, sigSz, digest, digestSz,
5992
        TPM_ALG_NULL, hashAlg, NULL);
5993
}
5994
5995
/* Post-Quantum Cryptography (PQC) Wrapper Functions - TPM 2.0 v185 */
5996
5997
#ifdef WOLFTPM_MLDSA_SIGN
5998
int wolfTPM2_SignSequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
5999
    const byte* context, int contextSz, TPM_HANDLE* sequenceHandle)
6000
{
6001
    int rc;
6002
    SignSequenceStart_In signSeqStartIn;
6003
    SignSequenceStart_Out signSeqStartOut;
6004
6005
    if (dev == NULL || key == NULL || sequenceHandle == NULL) {
6006
        return BAD_FUNC_ARG;
6007
    }
6008
6009
    if (contextSz < 0 || contextSz > (int)sizeof(signSeqStartIn.context.buffer)) {
6010
        return BUFFER_E;
6011
    }
6012
    if (contextSz > 0 && context == NULL) {
6013
        return BAD_FUNC_ARG;
6014
    }
6015
6016
    /* keyHandle has Auth Index None per Part 3 Sec.17.6.3 — no SetAuth */
6017
6018
    XMEMSET(&signSeqStartIn, 0, sizeof(signSeqStartIn));
6019
    signSeqStartIn.keyHandle = key->handle.hndl;
6020
    signSeqStartIn.context.size = (UINT16)contextSz;
6021
    if (context != NULL && contextSz > 0) {
6022
        XMEMCPY(signSeqStartIn.context.buffer, context, contextSz);
6023
    }
6024
6025
    XMEMSET(&signSeqStartOut, 0, sizeof(signSeqStartOut));
6026
    rc = TPM2_SignSequenceStart(&signSeqStartIn, &signSeqStartOut);
6027
    if (rc == TPM_RC_SUCCESS) {
6028
        *sequenceHandle = signSeqStartOut.sequenceHandle;
6029
    }
6030
6031
    TPM2_ForceZero(&signSeqStartIn, sizeof(signSeqStartIn));
6032
6033
    return rc;
6034
}
6035
6036
int wolfTPM2_SignSequenceUpdate(WOLFTPM2_DEV* dev,
6037
    TPM_HANDLE sequenceHandle, const byte* data, int dataSz)
6038
{
6039
    int rc;
6040
    SequenceUpdate_In seqUpdateIn;
6041
    WOLFTPM2_HANDLE seqHandleObj;
6042
6043
    if (dev == NULL || data == NULL || dataSz <= 0) {
6044
        return BAD_FUNC_ARG;
6045
    }
6046
6047
    if (dataSz > (int)sizeof(seqUpdateIn.buffer.buffer)) {
6048
        return BUFFER_E;
6049
    }
6050
6051
    /* Bind session auth slot 0 to the sequence handle so SequenceUpdate
6052
     * uses the per-sequence auth set at SignSequenceStart, not whatever
6053
     * stale handle (e.g. the key handle) was last bound to slot 0. */
6054
    XMEMSET(&seqHandleObj, 0, sizeof(seqHandleObj));
6055
    seqHandleObj.hndl = sequenceHandle;
6056
    wolfTPM2_SetAuthHandle(dev, 0, &seqHandleObj);
6057
6058
    XMEMSET(&seqUpdateIn, 0, sizeof(seqUpdateIn));
6059
    seqUpdateIn.sequenceHandle = sequenceHandle;
6060
    seqUpdateIn.buffer.size = (UINT16)dataSz;
6061
    XMEMCPY(seqUpdateIn.buffer.buffer, data, dataSz);
6062
6063
    rc = TPM2_SequenceUpdate(&seqUpdateIn);
6064
6065
    TPM2_ForceZero(&seqUpdateIn, sizeof(seqUpdateIn));
6066
6067
    return rc;
6068
}
6069
6070
int wolfTPM2_SignSequenceComplete(WOLFTPM2_DEV* dev,
6071
    TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz,
6072
    byte* sig, int* sigSz)
6073
{
6074
    int rc;
6075
    SignSequenceComplete_In signSeqCompleteIn;
6076
    SignSequenceComplete_Out signSeqCompleteOut;
6077
    WOLFTPM2_HANDLE seqHandleObj;
6078
#if MAX_SESSION_NUM > 1
6079
    TPM2_AUTH_SESSION session1;
6080
    int restore = 0;
6081
#endif
6082
#if MAX_SESSION_NUM > 2
6083
    int moved = 0;
6084
#endif
6085
6086
    if (dev == NULL || key == NULL || sig == NULL || sigSz == NULL) {
6087
        return BAD_FUNC_ARG;
6088
    }
6089
6090
    if (dataSz < 0 || dataSz > (int)sizeof(signSeqCompleteIn.buffer.buffer)) {
6091
        return BUFFER_E;
6092
    }
6093
    if (dataSz > 0 && data == NULL) {
6094
        return BAD_FUNC_ARG;
6095
    }
6096
6097
    /* Part 3 Sec.20.6 Table 124: sequenceHandle is the 1st auth handle (slot 0),
6098
     * keyHandle is the 2nd (slot 1). Both require USER auth. The current
6099
     * TPM2_SignSequenceStart wrapper starts sequences with empty auth, so
6100
     * slot 0 carries an empty auth value; slot 1 carries the signing key's
6101
     * auth. Missing the slot-1 assignment silently signs with the wrong auth
6102
     * area when the key has a non-empty auth value. */
6103
    XMEMSET(&seqHandleObj, 0, sizeof(seqHandleObj));
6104
    seqHandleObj.hndl = sequenceHandle;
6105
    wolfTPM2_SetAuthHandle(dev, 0, &seqHandleObj);
6106
#if MAX_SESSION_NUM > 1
6107
    /* SetAuthHandle resets slot 1 to password auth; restore the caller's
6108
     * slot-1 session (e.g. parameter encryption) after the command. While
6109
     * slot 2 is free, that session also protects this command from there.
6110
     * A policy-auth key runs on the slot-1 session itself; keep it live. */
6111
    if (!key->handle.policyAuth) {
6112
        XMEMCPY(&session1, &dev->session[1], sizeof(session1));
6113
        restore = 1;
6114
    #if MAX_SESSION_NUM > 2
6115
        if (TPM2_IS_HMAC_SESSION(session1.sessionHandle) &&
6116
                dev->session[2].sessionHandle == 0) {
6117
            XMEMCPY(&dev->session[2], &session1, sizeof(session1));
6118
            /* slot 2 authorizes no handle; a bound Name would fold the bind
6119
             * authValue into the param-enc key, which the TPM does not */
6120
            dev->session[2].name.size = 0;
6121
            moved = 1;
6122
        }
6123
    #endif
6124
    }
6125
#endif
6126
    wolfTPM2_SetAuthHandle(dev, 1, &key->handle);
6127
6128
    XMEMSET(&signSeqCompleteIn, 0, sizeof(signSeqCompleteIn));
6129
    signSeqCompleteIn.sequenceHandle = sequenceHandle;
6130
    signSeqCompleteIn.keyHandle = key->handle.hndl;
6131
    signSeqCompleteIn.buffer.size = (UINT16)dataSz;
6132
    if (data != NULL && dataSz > 0) {
6133
        XMEMCPY(signSeqCompleteIn.buffer.buffer, data, dataSz);
6134
    }
6135
6136
    XMEMSET(&signSeqCompleteOut, 0, sizeof(signSeqCompleteOut));
6137
    rc = TPM2_SignSequenceComplete(&signSeqCompleteIn, &signSeqCompleteOut);
6138
#if MAX_SESSION_NUM > 1
6139
    if (restore) {
6140
    #if MAX_SESSION_NUM > 2
6141
        if (moved) {
6142
            /* keep the nonces the command advanced; a retired session
6143
             * stays cleared */
6144
            if (dev->session[2].sessionHandle == session1.sessionHandle) {
6145
                XMEMCPY(&dev->session[2].name, &session1.name,
6146
                    sizeof(session1.name));
6147
            }
6148
            XMEMCPY(&session1, &dev->session[2], sizeof(session1));
6149
            TPM2_ForceZero(&dev->session[2], sizeof(dev->session[2]));
6150
        }
6151
    #endif
6152
        XMEMCPY(&dev->session[1], &session1, sizeof(session1));
6153
        TPM2_ForceZero(&session1, sizeof(session1));
6154
    }
6155
#endif
6156
    if (rc == TPM_RC_SUCCESS) {
6157
        /* Extract signature based on algorithm */
6158
        if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_ECDSA ||
6159
            signSeqCompleteOut.signature.sigAlg == TPM_ALG_ECDAA) {
6160
            rc = wolfTPM2_ExtractEccSignature(key,
6161
                &signSeqCompleteOut.signature.signature.ecdsa, sig, sigSz);
6162
        }
6163
        else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_RSASSA ||
6164
                 signSeqCompleteOut.signature.sigAlg == TPM_ALG_RSAPSS) {
6165
            int sigOutSz = signSeqCompleteOut.signature.signature.rsassa.sig.size;
6166
            if (*sigSz >= sigOutSz) {
6167
                XMEMCPY(sig, signSeqCompleteOut.signature.signature.rsassa.sig.buffer, sigOutSz);
6168
                *sigSz = sigOutSz;
6169
            }
6170
            else {
6171
                rc = BUFFER_E;
6172
            }
6173
        }
6174
        else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_HMAC) {
6175
            int sigOutSz = TPM2_GetHashDigestSize(
6176
                signSeqCompleteOut.signature.signature.hmac.hashAlg);
6177
            if (sigOutSz > 0 && *sigSz >= sigOutSz) {
6178
                XMEMCPY(sig,
6179
                    signSeqCompleteOut.signature.signature.hmac.digest.H,
6180
                    sigOutSz);
6181
                *sigSz = sigOutSz;
6182
            }
6183
            else {
6184
                rc = BUFFER_E;
6185
            }
6186
        }
6187
#ifdef WOLFTPM_MLDSA
6188
        else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_MLDSA) {
6189
            /* Pure ML-DSA: bare TPM2B, no hash field. */
6190
            int sigOutSz = signSeqCompleteOut.signature.signature.mldsa.size;
6191
            if (*sigSz >= sigOutSz) {
6192
                XMEMCPY(sig,
6193
                    signSeqCompleteOut.signature.signature.mldsa.buffer,
6194
                    sigOutSz);
6195
                *sigSz = sigOutSz;
6196
            }
6197
            else {
6198
                rc = BUFFER_E;
6199
            }
6200
        }
6201
        else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_HASH_MLDSA) {
6202
            /* HashML-DSA: hash + TPM2B signature. */
6203
            int sigOutSz =
6204
                signSeqCompleteOut.signature.signature.hash_mldsa.signature.size;
6205
            if (*sigSz >= sigOutSz) {
6206
                XMEMCPY(sig,
6207
                    signSeqCompleteOut.signature.signature.hash_mldsa.signature.buffer,
6208
                    sigOutSz);
6209
                *sigSz = sigOutSz;
6210
            }
6211
            else {
6212
                rc = BUFFER_E;
6213
            }
6214
        }
6215
#endif /* WOLFTPM_MLDSA */
6216
        else {
6217
            /* Unknown algorithm */
6218
            rc = BUFFER_E;
6219
        }
6220
    }
6221
6222
    TPM2_ForceZero(&signSeqCompleteIn, sizeof(signSeqCompleteIn));
6223
6224
    return rc;
6225
}
6226
#endif /* WOLFTPM_MLDSA_SIGN */
6227
6228
#ifdef WOLFTPM_MLDSA_VERIFY
6229
int wolfTPM2_VerifySequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
6230
    const byte* context, int contextSz, TPM_HANDLE* sequenceHandle)
6231
{
6232
    int rc;
6233
    VerifySequenceStart_In verifySeqStartIn;
6234
    VerifySequenceStart_Out verifySeqStartOut;
6235
6236
    if (dev == NULL || key == NULL || sequenceHandle == NULL) {
6237
        return BAD_FUNC_ARG;
6238
    }
6239
6240
    if (contextSz < 0 || contextSz > (int)sizeof(verifySeqStartIn.context.buffer)) {
6241
        return BUFFER_E;
6242
    }
6243
    if (contextSz > 0 && context == NULL) {
6244
        return BAD_FUNC_ARG;
6245
    }
6246
6247
    XMEMSET(&verifySeqStartIn, 0, sizeof(verifySeqStartIn));
6248
    verifySeqStartIn.keyHandle = key->handle.hndl;
6249
    verifySeqStartIn.context.size = (UINT16)contextSz;
6250
    if (context != NULL && contextSz > 0) {
6251
        XMEMCPY(verifySeqStartIn.context.buffer, context, contextSz);
6252
    }
6253
6254
    XMEMSET(&verifySeqStartOut, 0, sizeof(verifySeqStartOut));
6255
    rc = TPM2_VerifySequenceStart(&verifySeqStartIn, &verifySeqStartOut);
6256
    if (rc == TPM_RC_SUCCESS) {
6257
        *sequenceHandle = verifySeqStartOut.sequenceHandle;
6258
    }
6259
6260
    TPM2_ForceZero(&verifySeqStartIn, sizeof(verifySeqStartIn));
6261
6262
    return rc;
6263
}
6264
6265
int wolfTPM2_VerifySequenceUpdate(WOLFTPM2_DEV* dev,
6266
    TPM_HANDLE sequenceHandle, const byte* data, int dataSz)
6267
{
6268
    int rc;
6269
    SequenceUpdate_In seqUpdateIn;
6270
    WOLFTPM2_HANDLE seqHandleObj;
6271
6272
    if (dev == NULL || data == NULL || dataSz <= 0) {
6273
        return BAD_FUNC_ARG;
6274
    }
6275
6276
    if (dataSz > (int)sizeof(seqUpdateIn.buffer.buffer)) {
6277
        return BUFFER_E;
6278
    }
6279
6280
    /* Bind session auth slot 0 to the sequence handle so SequenceUpdate
6281
     * uses the per-sequence auth, not whatever stale handle was last
6282
     * bound to slot 0. */
6283
    XMEMSET(&seqHandleObj, 0, sizeof(seqHandleObj));
6284
    seqHandleObj.hndl = sequenceHandle;
6285
    wolfTPM2_SetAuthHandle(dev, 0, &seqHandleObj);
6286
6287
    XMEMSET(&seqUpdateIn, 0, sizeof(seqUpdateIn));
6288
    seqUpdateIn.sequenceHandle = sequenceHandle;
6289
    seqUpdateIn.buffer.size = (UINT16)dataSz;
6290
    XMEMCPY(seqUpdateIn.buffer.buffer, data, dataSz);
6291
6292
    rc = TPM2_SequenceUpdate(&seqUpdateIn);
6293
6294
    TPM2_ForceZero(&seqUpdateIn, sizeof(seqUpdateIn));
6295
6296
    return rc;
6297
}
6298
6299
int wolfTPM2_VerifySequenceComplete(WOLFTPM2_DEV* dev,
6300
    TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz,
6301
    const byte* sig, int sigSz, TPMT_TK_VERIFIED* validation)
6302
{
6303
    int rc;
6304
    VerifySequenceComplete_In verifySeqCompleteIn;
6305
    VerifySequenceComplete_Out verifySeqCompleteOut;
6306
    TPMT_SIGNATURE signature;
6307
    WOLFTPM2_HANDLE seqHandleObj;
6308
6309
    if (dev == NULL || key == NULL || sig == NULL || sigSz <= 0) {
6310
        return BAD_FUNC_ARG;
6311
    }
6312
6313
    if (dataSz < 0) {
6314
        return BUFFER_E;
6315
    }
6316
    if (dataSz > 0 && data == NULL) {
6317
        return BAD_FUNC_ARG;
6318
    }
6319
6320
    /* Before the sequence is advanced: bailing out after SequenceUpdate
6321
     * would leave the sequence slot allocated. The data is hashed by the TPM
6322
     * rather than carried in the verify command, so only the signature and
6323
     * the fixed overhead count here. */
6324
    rc = wolfTPM2_CheckSigInputBuffer(sigSz, 0);
6325
    if (rc != TPM_RC_SUCCESS) {
6326
        return rc;
6327
    }
6328
6329
    /* Validate per-key-type sigSz BEFORE the internal SequenceUpdate
6330
     * call. Otherwise we advance the TPM-side sequence and then bail out
6331
     * before Complete, leaving the slot allocated until the caller
6332
     * manually flushes it (CWE-772 DoS). All key types covered here so
6333
     * the cleanup invariant holds for every supported scheme. */
6334
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
6335
        int curveSize = wolfTPM2_GetCurveSize(
6336
            key->pub.publicArea.parameters.eccDetail.curveID);
6337
        if (curveSize <= 0 || sigSz != (curveSize * 2)) {
6338
            return BAD_FUNC_ARG;
6339
        }
6340
    }
6341
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
6342
        if (sigSz > (int)sizeof(((TPMT_SIGNATURE*)0)->signature.rsassa.sig.buffer)) {
6343
            return BUFFER_E;
6344
        }
6345
    }
6346
    else if (key->pub.publicArea.type == TPM_ALG_KEYEDHASH) {
6347
        TPMT_KEYEDHASH_SCHEME* scheme =
6348
            &key->pub.publicArea.parameters.keyedHashDetail.scheme;
6349
        int hmacSz = TPM2_GetHashDigestSize(scheme->details.hmac.hashAlg);
6350
        if (scheme->scheme != TPM_ALG_HMAC || hmacSz <= 0 ||
6351
                sigSz != hmacSz) {
6352
            return BAD_FUNC_ARG;
6353
        }
6354
    }
6355
#ifdef WOLFTPM_MLDSA
6356
    else if (key->pub.publicArea.type == TPM_ALG_MLDSA) {
6357
        if (sigSz > (int)sizeof(((TPMT_SIGNATURE*)0)->signature.mldsa.buffer)) {
6358
            return BUFFER_E;
6359
        }
6360
    }
6361
    else if (key->pub.publicArea.type == TPM_ALG_HASH_MLDSA) {
6362
        if (sigSz > (int)sizeof(((TPMT_SIGNATURE*)0)->signature.hash_mldsa.signature.buffer)) {
6363
            return BUFFER_E;
6364
        }
6365
    }
6366
#endif
6367
    else {
6368
        /* Unknown key type -- reject before SequenceUpdate runs. */
6369
        return BAD_FUNC_ARG;
6370
    }
6371
6372
    /* Part 3 Sec.20.3 Table 118: VerifySequenceComplete parameters are
6373
     * {signature} only — no buffer field. The documented `data`/`dataSz`
6374
     * "final chunk" arguments are folded into the sequence here via an
6375
     * internal SequenceUpdate before completing, so callers can still pass
6376
     * the last chunk in one call. */
6377
    if (dataSz > 0) {
6378
        rc = wolfTPM2_VerifySequenceUpdate(dev, sequenceHandle, data, dataSz);
6379
        if (rc != TPM_RC_SUCCESS) {
6380
            return rc;
6381
        }
6382
    }
6383
6384
    /* Part 3 Sec.20.3 Table 118: @sequenceHandle has Auth Role: USER. Install
6385
     * the sequence-handle auth into session slot 0 so the marshaler computes
6386
     * the HMAC against the auth value bound at VerifySequenceStart (rather
6387
     * than whatever auth the slot inherited from a prior command). Mirrors
6388
     * wolfTPM2_SignSequenceComplete (line 5415-5417). */
6389
    XMEMSET(&seqHandleObj, 0, sizeof(seqHandleObj));
6390
    seqHandleObj.hndl = sequenceHandle;
6391
    wolfTPM2_SetAuthHandle(dev, 0, &seqHandleObj);
6392
6393
    XMEMSET(&verifySeqCompleteIn, 0, sizeof(verifySeqCompleteIn));
6394
    verifySeqCompleteIn.sequenceHandle = sequenceHandle;
6395
    verifySeqCompleteIn.keyHandle = key->handle.hndl;
6396
6397
    /* Build signature structure from raw signature.
6398
     * sigSz validated up-front (see early per-key-type check above). */
6399
    XMEMSET(&signature, 0, sizeof(signature));
6400
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
6401
        /* ECC signature: R then S */
6402
        int curveSize = wolfTPM2_GetCurveSize(
6403
            key->pub.publicArea.parameters.eccDetail.curveID);
6404
        signature.sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
6405
        if (signature.sigAlg == TPM_ALG_NULL) {
6406
            signature.sigAlg = TPM_ALG_ECDSA;
6407
        }
6408
        signature.signature.ecdsa.hash = 
6409
            key->pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg;
6410
        signature.signature.ecdsa.signatureR.size = curveSize;
6411
        XMEMCPY(signature.signature.ecdsa.signatureR.buffer, sig, curveSize);
6412
        signature.signature.ecdsa.signatureS.size = curveSize;
6413
        XMEMCPY(signature.signature.ecdsa.signatureS.buffer, sig + curveSize, curveSize);
6414
    }
6415
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
6416
        /* RSA signature */
6417
        signature.sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
6418
        if (signature.sigAlg == TPM_ALG_NULL) {
6419
            signature.sigAlg = TPM_ALG_RSASSA;
6420
        }
6421
        signature.signature.rsassa.hash = 
6422
            key->pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg;
6423
        if (sigSz > (int)sizeof(signature.signature.rsassa.sig.buffer)) {
6424
            return BUFFER_E;
6425
        }
6426
        signature.signature.rsassa.sig.size = (UINT16)sigSz;
6427
        XMEMCPY(signature.signature.rsassa.sig.buffer, sig, sigSz);
6428
    }
6429
    else if (key->pub.publicArea.type == TPM_ALG_KEYEDHASH) {
6430
        signature.sigAlg = TPM_ALG_HMAC;
6431
        signature.signature.hmac.hashAlg = key->pub.publicArea.parameters
6432
            .keyedHashDetail.scheme.details.hmac.hashAlg;
6433
        XMEMCPY(signature.signature.hmac.digest.H, sig, sigSz);
6434
    }
6435
#ifdef WOLFTPM_MLDSA
6436
    else if (key->pub.publicArea.type == TPM_ALG_MLDSA) {
6437
        /* Pure ML-DSA: bare TPM2B signature, no hash. */
6438
        signature.sigAlg = TPM_ALG_MLDSA;
6439
        if (sigSz > (int)sizeof(signature.signature.mldsa.buffer)) {
6440
            return BUFFER_E;
6441
        }
6442
        signature.signature.mldsa.size = (UINT16)sigSz;
6443
        XMEMCPY(signature.signature.mldsa.buffer, sig, sigSz);
6444
    }
6445
    else if (key->pub.publicArea.type == TPM_ALG_HASH_MLDSA) {
6446
        /* HashML-DSA: hash alg (from key parameters) + TPM2B signature. */
6447
        signature.sigAlg = TPM_ALG_HASH_MLDSA;
6448
        signature.signature.hash_mldsa.hash =
6449
            key->pub.publicArea.parameters.hash_mldsaDetail.hashAlg;
6450
        if (sigSz >
6451
                (int)sizeof(signature.signature.hash_mldsa.signature.buffer)) {
6452
            return BUFFER_E;
6453
        }
6454
        signature.signature.hash_mldsa.signature.size = (UINT16)sigSz;
6455
        XMEMCPY(signature.signature.hash_mldsa.signature.buffer, sig, sigSz);
6456
    }
6457
#endif /* WOLFTPM_MLDSA */
6458
    else {
6459
        /* Unknown key type */
6460
        return BAD_FUNC_ARG;
6461
    }
6462
    verifySeqCompleteIn.signature = signature;
6463
6464
    XMEMSET(&verifySeqCompleteOut, 0, sizeof(verifySeqCompleteOut));
6465
    rc = TPM2_VerifySequenceComplete(&verifySeqCompleteIn, &verifySeqCompleteOut);
6466
    if (rc == TPM_RC_SUCCESS) {
6467
        if (validation != NULL) {
6468
            XMEMCPY(validation, &verifySeqCompleteOut.validation,
6469
                sizeof(TPMT_TK_VERIFIED));
6470
        }
6471
    }
6472
    else {
6473
        /* On an error return (e.g. TPM_RC_SIGNATURE) the TPM does not consume
6474
         * the sequence object. Flush it so repeated failed verifies do not
6475
         * exhaust transient memory (TPM_RC_OBJECT_MEMORY). */
6476
        wolfTPM2_UnloadHandle(dev, &seqHandleObj);
6477
    }
6478
6479
    return rc;
6480
}
6481
#endif /* WOLFTPM_MLDSA_VERIFY */
6482
6483
#ifdef WOLFTPM_MLDSA_SIGN
6484
int wolfTPM2_SignDigest(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
6485
    const byte* digest, int digestSz, const byte* context, int contextSz,
6486
    byte* sig, int* sigSz)
6487
{
6488
    int rc;
6489
    SignDigest_In signDigestIn;
6490
    SignDigest_Out signDigestOut;
6491
6492
    if (dev == NULL || key == NULL || digest == NULL || sig == NULL || sigSz == NULL) {
6493
        return BAD_FUNC_ARG;
6494
    }
6495
6496
    if (digestSz <= 0 || digestSz > (int)sizeof(signDigestIn.digest.buffer)) {
6497
        return BUFFER_E;
6498
    }
6499
6500
    if (contextSz < 0 || contextSz > (int)sizeof(signDigestIn.context.buffer)) {
6501
        return BUFFER_E;
6502
    }
6503
    if (contextSz > 0 && context == NULL) {
6504
        return BAD_FUNC_ARG;
6505
    }
6506
6507
    /* set session auth for key */
6508
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
6509
6510
    XMEMSET(&signDigestIn, 0, sizeof(signDigestIn));
6511
    signDigestIn.keyHandle = key->handle.hndl;
6512
    signDigestIn.digest.size = (UINT16)digestSz;
6513
    XMEMCPY(signDigestIn.digest.buffer, digest, digestSz);
6514
    signDigestIn.context.size = (UINT16)contextSz;
6515
    if (context != NULL && contextSz > 0) {
6516
        XMEMCPY(signDigestIn.context.buffer, context, contextSz);
6517
    }
6518
    /* Synthesize a NULL TPMT_TK_HASHCHECK per Part 2 Sec.10.6.4 — the wire
6519
     * format MUST carry tag = TPM_ST_HASHCHECK and hierarchy = TPM_RH_NULL
6520
     * even for unrestricted keys where the ticket is informational. */
6521
    signDigestIn.validation.tag = TPM_ST_HASHCHECK;
6522
    signDigestIn.validation.hierarchy = TPM_RH_NULL;
6523
    /* signDigestIn.validation.digest.size already 0 from XMEMSET */
6524
6525
    XMEMSET(&signDigestOut, 0, sizeof(signDigestOut));
6526
    rc = TPM2_SignDigest(&signDigestIn, &signDigestOut);
6527
    if (rc == TPM_RC_SUCCESS) {
6528
        /* Extract signature based on algorithm */
6529
        if (signDigestOut.signature.sigAlg == TPM_ALG_ECDSA ||
6530
            signDigestOut.signature.sigAlg == TPM_ALG_ECDAA) {
6531
            rc = wolfTPM2_ExtractEccSignature(key,
6532
                &signDigestOut.signature.signature.ecdsa, sig, sigSz);
6533
        }
6534
        else if (signDigestOut.signature.sigAlg == TPM_ALG_RSASSA ||
6535
                 signDigestOut.signature.sigAlg == TPM_ALG_RSAPSS) {
6536
            int sigOutSz = signDigestOut.signature.signature.rsassa.sig.size;
6537
            if (*sigSz >= sigOutSz) {
6538
                XMEMCPY(sig, signDigestOut.signature.signature.rsassa.sig.buffer, sigOutSz);
6539
                *sigSz = sigOutSz;
6540
            }
6541
            else {
6542
                rc = BUFFER_E;
6543
            }
6544
        }
6545
#ifdef WOLFTPM_MLDSA
6546
        else if (signDigestOut.signature.sigAlg == TPM_ALG_MLDSA) {
6547
            /* Pure ML-DSA: bare TPM2B, no hash field. */
6548
            int sigOutSz = signDigestOut.signature.signature.mldsa.size;
6549
            if (*sigSz >= sigOutSz) {
6550
                XMEMCPY(sig,
6551
                    signDigestOut.signature.signature.mldsa.buffer, sigOutSz);
6552
                *sigSz = sigOutSz;
6553
            }
6554
            else {
6555
                rc = BUFFER_E;
6556
            }
6557
        }
6558
        else if (signDigestOut.signature.sigAlg == TPM_ALG_HASH_MLDSA) {
6559
            /* HashML-DSA: hash + TPM2B signature. */
6560
            int sigOutSz =
6561
                signDigestOut.signature.signature.hash_mldsa.signature.size;
6562
            if (*sigSz >= sigOutSz) {
6563
                XMEMCPY(sig,
6564
                    signDigestOut.signature.signature.hash_mldsa.signature.buffer,
6565
                    sigOutSz);
6566
                *sigSz = sigOutSz;
6567
            }
6568
            else {
6569
                rc = BUFFER_E;
6570
            }
6571
        }
6572
#endif /* WOLFTPM_MLDSA */
6573
        else {
6574
            /* Unknown algorithm */
6575
            rc = BUFFER_E;
6576
        }
6577
    }
6578
6579
    return rc;
6580
}
6581
#endif /* WOLFTPM_MLDSA_SIGN */
6582
6583
#ifdef WOLFTPM_MLDSA_VERIFY
6584
int wolfTPM2_VerifyDigestSignature(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
6585
    const byte* digest, int digestSz, const byte* sig, int sigSz,
6586
    const byte* context, int contextSz, TPMT_TK_VERIFIED* validation)
6587
{
6588
    int rc;
6589
    VerifyDigestSignature_In verifyDigestSigIn;
6590
    VerifyDigestSignature_Out verifyDigestSigOut;
6591
    TPMT_SIGNATURE signature;
6592
6593
    if (dev == NULL || key == NULL || digest == NULL || sig == NULL || sigSz <= 0) {
6594
        return BAD_FUNC_ARG;
6595
    }
6596
6597
    if (digestSz <= 0 || digestSz > (int)sizeof(verifyDigestSigIn.digest.buffer)) {
6598
        return BUFFER_E;
6599
    }
6600
6601
    if (contextSz < 0 || contextSz > (int)sizeof(verifyDigestSigIn.context.buffer)) {
6602
        return BUFFER_E;
6603
    }
6604
    if (contextSz > 0 && context == NULL) {
6605
        return BAD_FUNC_ARG;
6606
    }
6607
6608
    rc = wolfTPM2_CheckSigInputBuffer(sigSz, digestSz + contextSz);
6609
    if (rc != TPM_RC_SUCCESS) {
6610
        return rc;
6611
    }
6612
6613
    XMEMSET(&verifyDigestSigIn, 0, sizeof(verifyDigestSigIn));
6614
    verifyDigestSigIn.keyHandle = key->handle.hndl;
6615
    verifyDigestSigIn.digest.size = (UINT16)digestSz;
6616
    XMEMCPY(verifyDigestSigIn.digest.buffer, digest, digestSz);
6617
6618
    /* Build signature structure from raw signature */
6619
    /* For PQ algorithms, we need to determine the signature format from the key */
6620
    XMEMSET(&signature, 0, sizeof(signature));
6621
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
6622
        /* ECC signature: R then S */
6623
        int curveSize = wolfTPM2_GetCurveSize(
6624
            key->pub.publicArea.parameters.eccDetail.curveID);
6625
        if (curveSize <= 0 || sigSz != (curveSize * 2)) {
6626
            return BAD_FUNC_ARG;
6627
        }
6628
        signature.sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
6629
        if (signature.sigAlg == TPM_ALG_NULL) {
6630
            signature.sigAlg = TPM_ALG_ECDSA;
6631
        }
6632
        signature.signature.ecdsa.hash = 
6633
            key->pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg;
6634
        signature.signature.ecdsa.signatureR.size = curveSize;
6635
        XMEMCPY(signature.signature.ecdsa.signatureR.buffer, sig, curveSize);
6636
        signature.signature.ecdsa.signatureS.size = curveSize;
6637
        XMEMCPY(signature.signature.ecdsa.signatureS.buffer, sig + curveSize, curveSize);
6638
    }
6639
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
6640
        /* RSA signature */
6641
        signature.sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme;
6642
        if (signature.sigAlg == TPM_ALG_NULL) {
6643
            signature.sigAlg = TPM_ALG_RSASSA;
6644
        }
6645
        signature.signature.rsassa.hash = 
6646
            key->pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg;
6647
        if (sigSz > (int)sizeof(signature.signature.rsassa.sig.buffer)) {
6648
            return BUFFER_E;
6649
        }
6650
        signature.signature.rsassa.sig.size = (UINT16)sigSz;
6651
        XMEMCPY(signature.signature.rsassa.sig.buffer, sig, sigSz);
6652
    }
6653
#ifdef WOLFTPM_MLDSA
6654
    else if (key->pub.publicArea.type == TPM_ALG_MLDSA) {
6655
        /* Pure ML-DSA: bare TPM2B signature, no hash. */
6656
        signature.sigAlg = TPM_ALG_MLDSA;
6657
        if (sigSz > (int)sizeof(signature.signature.mldsa.buffer)) {
6658
            return BUFFER_E;
6659
        }
6660
        signature.signature.mldsa.size = (UINT16)sigSz;
6661
        XMEMCPY(signature.signature.mldsa.buffer, sig, sigSz);
6662
    }
6663
    else if (key->pub.publicArea.type == TPM_ALG_HASH_MLDSA) {
6664
        /* HashML-DSA: hash alg (from key parameters) + TPM2B signature. */
6665
        signature.sigAlg = TPM_ALG_HASH_MLDSA;
6666
        signature.signature.hash_mldsa.hash =
6667
            key->pub.publicArea.parameters.hash_mldsaDetail.hashAlg;
6668
        if (sigSz >
6669
                (int)sizeof(signature.signature.hash_mldsa.signature.buffer)) {
6670
            return BUFFER_E;
6671
        }
6672
        signature.signature.hash_mldsa.signature.size = (UINT16)sigSz;
6673
        XMEMCPY(signature.signature.hash_mldsa.signature.buffer, sig, sigSz);
6674
    }
6675
#endif /* WOLFTPM_MLDSA */
6676
    else {
6677
        /* Unknown key type */
6678
        return BAD_FUNC_ARG;
6679
    }
6680
    verifyDigestSigIn.signature = signature;
6681
6682
    verifyDigestSigIn.context.size = (UINT16)contextSz;
6683
    if (context != NULL && contextSz > 0) {
6684
        XMEMCPY(verifyDigestSigIn.context.buffer, context, contextSz);
6685
    }
6686
6687
    XMEMSET(&verifyDigestSigOut, 0, sizeof(verifyDigestSigOut));
6688
    rc = TPM2_VerifyDigestSignature(&verifyDigestSigIn, &verifyDigestSigOut);
6689
    if (rc == TPM_RC_SUCCESS && validation != NULL) {
6690
        XMEMCPY(validation, &verifyDigestSigOut.validation, sizeof(TPMT_TK_VERIFIED));
6691
    }
6692
6693
    return rc;
6694
}
6695
#endif /* WOLFTPM_MLDSA_VERIFY */
6696
6697
#if defined(WOLFTPM_MLKEM_ENCAP) || defined(WOLFTPM_MLKEM_DECAP)
6698
#define WOLFTPM2_MLKEM_SS_SZ 32
6699
#endif
6700
6701
#ifdef WOLFTPM_MLKEM_ENCAP
6702
/* FIPS 203 ciphertext size for the parameter set, or 0 if unknown */
6703
static int MlKemCiphertextSize(TPMI_MLKEM_PARAMETER_SET parameterSet)
6704
{
6705
    switch (parameterSet) {
6706
        case TPM_MLKEM_512:  return 768;
6707
        case TPM_MLKEM_768:  return 1088;
6708
        case TPM_MLKEM_1024: return 1568;
6709
        default:             return 0;
6710
    }
6711
}
6712
#endif /* WOLFTPM_MLKEM_ENCAP */
6713
6714
#ifdef WOLFTPM_MLKEM_ENCAP
6715
int wolfTPM2_Encapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
6716
    byte* ciphertext, int* ciphertextSz, byte* sharedSecret, int* sharedSecretSz)
6717
{
6718
    int rc;
6719
    Encapsulate_In encapsulateIn;
6720
    Encapsulate_Out encapsulateOut;
6721
6722
    if (dev == NULL || key == NULL || ciphertext == NULL || ciphertextSz == NULL ||
6723
        sharedSecret == NULL || sharedSecretSz == NULL) {
6724
        return BAD_FUNC_ARG;
6725
    }
6726
6727
    XMEMSET(&encapsulateIn, 0, sizeof(encapsulateIn));
6728
    encapsulateIn.keyHandle = key->handle.hndl;
6729
6730
    XMEMSET(&encapsulateOut, 0, sizeof(encapsulateOut));
6731
    rc = TPM2_Encapsulate(&encapsulateIn, &encapsulateOut);
6732
    if (rc == TPM_RC_SUCCESS && key->pub.publicArea.type == TPM_ALG_MLKEM &&
6733
            ((int)encapsulateOut.ciphertext.size != MlKemCiphertextSize(
6734
                key->pub.publicArea.parameters.mlkemDetail.parameterSet) ||
6735
             encapsulateOut.sharedSecret.size != WOLFTPM2_MLKEM_SS_SZ)) {
6736
        rc = TPM_RC_SIZE;
6737
    }
6738
    if (rc == TPM_RC_SUCCESS) {
6739
        if (*ciphertextSz >= (int)encapsulateOut.ciphertext.size) {
6740
            XMEMCPY(ciphertext, encapsulateOut.ciphertext.buffer, encapsulateOut.ciphertext.size);
6741
            *ciphertextSz = encapsulateOut.ciphertext.size;
6742
        }
6743
        else {
6744
            rc = BUFFER_E;
6745
        }
6746
6747
        if (rc == TPM_RC_SUCCESS) {
6748
            if (*sharedSecretSz >= (int)encapsulateOut.sharedSecret.size) {
6749
                XMEMCPY(sharedSecret, encapsulateOut.sharedSecret.buffer, encapsulateOut.sharedSecret.size);
6750
                *sharedSecretSz = encapsulateOut.sharedSecret.size;
6751
            }
6752
            else {
6753
                rc = BUFFER_E;
6754
            }
6755
        }
6756
    }
6757
6758
    /* Clear sensitive shared secret from stack */
6759
    TPM2_ForceZero(&encapsulateOut.sharedSecret, sizeof(encapsulateOut.sharedSecret));
6760
6761
    return rc;
6762
}
6763
#endif /* WOLFTPM_MLKEM_ENCAP */
6764
6765
#ifdef WOLFTPM_MLKEM_DECAP
6766
int wolfTPM2_Decapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
6767
    const byte* ciphertext, int ciphertextSz, byte* sharedSecret, int* sharedSecretSz)
6768
{
6769
    int rc;
6770
    Decapsulate_In decapsulateIn;
6771
    Decapsulate_Out decapsulateOut;
6772
6773
    if (dev == NULL || key == NULL || ciphertext == NULL || ciphertextSz <= 0 ||
6774
        sharedSecret == NULL || sharedSecretSz == NULL) {
6775
        return BAD_FUNC_ARG;
6776
    }
6777
6778
    if (ciphertextSz > (int)sizeof(decapsulateIn.ciphertext.buffer)) {
6779
        return BUFFER_E;
6780
    }
6781
6782
    /* set session auth for key */
6783
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
6784
6785
    XMEMSET(&decapsulateIn, 0, sizeof(decapsulateIn));
6786
    decapsulateIn.keyHandle = key->handle.hndl;
6787
    decapsulateIn.ciphertext.size = (UINT16)ciphertextSz;
6788
    XMEMCPY(decapsulateIn.ciphertext.buffer, ciphertext, ciphertextSz);
6789
6790
    XMEMSET(&decapsulateOut, 0, sizeof(decapsulateOut));
6791
    rc = TPM2_Decapsulate(&decapsulateIn, &decapsulateOut);
6792
    if (rc == TPM_RC_SUCCESS && key->pub.publicArea.type == TPM_ALG_MLKEM &&
6793
            decapsulateOut.sharedSecret.size != WOLFTPM2_MLKEM_SS_SZ) {
6794
        rc = TPM_RC_SIZE;
6795
    }
6796
    if (rc == TPM_RC_SUCCESS) {
6797
        if (*sharedSecretSz >= (int)decapsulateOut.sharedSecret.size) {
6798
            XMEMCPY(sharedSecret, decapsulateOut.sharedSecret.buffer, decapsulateOut.sharedSecret.size);
6799
            *sharedSecretSz = decapsulateOut.sharedSecret.size;
6800
        }
6801
        else {
6802
            rc = BUFFER_E;
6803
        }
6804
    }
6805
6806
    /* Clear sensitive shared secret from stack */
6807
    TPM2_ForceZero(&decapsulateOut.sharedSecret, sizeof(decapsulateOut.sharedSecret));
6808
6809
    return rc;
6810
}
6811
#endif /* WOLFTPM_MLKEM_DECAP */
6812
6813
#ifdef WOLFTPM_MLDSA
6814
/* GetKeyTemplate_MLDSA - Create a key template for ML-DSA signing keys */
6815
int wolfTPM2_GetKeyTemplate_MLDSA_ex(TPMT_PUBLIC* publicTemplate,
6816
    TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet,
6817
    int allowExternalMu, TPMI_ALG_HASH nameAlg)
6818
{
6819
    if (publicTemplate == NULL)
6820
        return BAD_FUNC_ARG;
6821
6822
    /* TPM_ALG_NULL selects the wrapper default name algorithm */
6823
    if (nameAlg == TPM_ALG_NULL)
6824
        nameAlg = WOLFTPM2_WRAP_DIGEST;
6825
    /* reject object Name hashes weaker than the wrapper default */
6826
    if (TPM2_GetHashDigestSize(nameAlg) <
6827
            TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
6828
        return BAD_FUNC_ARG;
6829
    }
6830
6831
    /* TCG v185: MLDSA is sign-only. Enforce correct attributes. */
6832
    objectAttributes &= ~TPMA_OBJECT_decrypt;
6833
    objectAttributes |= TPMA_OBJECT_sign;
6834
6835
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
6836
    publicTemplate->type = TPM_ALG_MLDSA;
6837
    publicTemplate->nameAlg = nameAlg;
6838
    publicTemplate->objectAttributes = objectAttributes;
6839
    publicTemplate->parameters.mldsaDetail.parameterSet = parameterSet;
6840
    publicTemplate->parameters.mldsaDetail.allowExternalMu =
6841
        (allowExternalMu ? YES : NO);
6842
    return TPM_RC_SUCCESS;
6843
}
6844
6845
int wolfTPM2_GetKeyTemplate_MLDSA(TPMT_PUBLIC* publicTemplate,
6846
    TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet,
6847
    int allowExternalMu)
6848
{
6849
    return wolfTPM2_GetKeyTemplate_MLDSA_ex(publicTemplate, objectAttributes,
6850
        parameterSet, allowExternalMu, WOLFTPM2_WRAP_DIGEST);
6851
}
6852
#endif /* WOLFTPM_MLDSA */
6853
6854
#ifdef WOLFTPM_HASH_MLDSA
6855
/* GetKeyTemplate_HASH_MLDSA - Create a key template for Pre-Hash ML-DSA signing keys */
6856
int wolfTPM2_GetKeyTemplate_HASH_MLDSA_ex(TPMT_PUBLIC* publicTemplate,
6857
    TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet,
6858
    TPMI_ALG_HASH hashAlg, TPMI_ALG_HASH nameAlg)
6859
{
6860
    if (publicTemplate == NULL)
6861
        return BAD_FUNC_ARG;
6862
6863
    /* TPM_ALG_NULL selects the wrapper default name algorithm */
6864
    if (nameAlg == TPM_ALG_NULL)
6865
        nameAlg = WOLFTPM2_WRAP_DIGEST;
6866
    /* reject object Name hashes weaker than the wrapper default */
6867
    if (TPM2_GetHashDigestSize(nameAlg) <
6868
            TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
6869
        return BAD_FUNC_ARG;
6870
    }
6871
6872
    /* TCG v185: HASH_MLDSA is sign-only. Enforce correct attributes. */
6873
    objectAttributes &= ~TPMA_OBJECT_decrypt;
6874
    objectAttributes |= TPMA_OBJECT_sign;
6875
6876
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
6877
    publicTemplate->type = TPM_ALG_HASH_MLDSA;
6878
    publicTemplate->nameAlg = nameAlg;
6879
    publicTemplate->objectAttributes = objectAttributes;
6880
    publicTemplate->parameters.hash_mldsaDetail.parameterSet = parameterSet;
6881
    publicTemplate->parameters.hash_mldsaDetail.hashAlg = hashAlg;
6882
    return TPM_RC_SUCCESS;
6883
}
6884
6885
int wolfTPM2_GetKeyTemplate_HASH_MLDSA(TPMT_PUBLIC* publicTemplate,
6886
    TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet,
6887
    TPMI_ALG_HASH hashAlg)
6888
{
6889
    return wolfTPM2_GetKeyTemplate_HASH_MLDSA_ex(publicTemplate,
6890
        objectAttributes, parameterSet, hashAlg, WOLFTPM2_WRAP_DIGEST);
6891
}
6892
#endif /* WOLFTPM_HASH_MLDSA */
6893
6894
#ifdef WOLFTPM_MLKEM
6895
/* GetKeyTemplate_MLKEM - Create a key template for ML-KEM decryption keys */
6896
int wolfTPM2_GetKeyTemplate_MLKEM_ex(TPMT_PUBLIC* publicTemplate,
6897
    TPMA_OBJECT objectAttributes, TPMI_MLKEM_PARAMETER_SET parameterSet,
6898
    TPMI_ALG_HASH nameAlg)
6899
{
6900
    if (publicTemplate == NULL)
6901
        return BAD_FUNC_ARG;
6902
6903
    /* TPM_ALG_NULL selects the wrapper default name algorithm */
6904
    if (nameAlg == TPM_ALG_NULL)
6905
        nameAlg = WOLFTPM2_WRAP_DIGEST;
6906
    /* reject object Name hashes weaker than the wrapper default */
6907
    if (TPM2_GetHashDigestSize(nameAlg) <
6908
            TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
6909
        return BAD_FUNC_ARG;
6910
    }
6911
6912
    /* TCG v185: MLKEM is decrypt-only. Enforce correct attributes. */
6913
    objectAttributes &= ~TPMA_OBJECT_sign;
6914
    objectAttributes |= TPMA_OBJECT_decrypt;
6915
6916
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
6917
    publicTemplate->type = TPM_ALG_MLKEM;
6918
    publicTemplate->nameAlg = nameAlg;
6919
    publicTemplate->objectAttributes = objectAttributes;
6920
    publicTemplate->parameters.mlkemDetail.parameterSet = parameterSet;
6921
    if ((objectAttributes & TPMA_OBJECT_decrypt) &&
6922
            (objectAttributes & TPMA_OBJECT_restricted)) {
6923
        publicTemplate->parameters.mlkemDetail.symmetric.algorithm =
6924
            TPM_ALG_AES;
6925
        publicTemplate->parameters.mlkemDetail.symmetric.keyBits.aes = 128;
6926
        publicTemplate->parameters.mlkemDetail.symmetric.mode.aes = TPM_ALG_CFB;
6927
    }
6928
    else {
6929
        publicTemplate->parameters.mlkemDetail.symmetric.algorithm =
6930
            TPM_ALG_NULL;
6931
    }
6932
    return TPM_RC_SUCCESS;
6933
}
6934
6935
int wolfTPM2_GetKeyTemplate_MLKEM(TPMT_PUBLIC* publicTemplate,
6936
    TPMA_OBJECT objectAttributes, TPMI_MLKEM_PARAMETER_SET parameterSet)
6937
{
6938
    return wolfTPM2_GetKeyTemplate_MLKEM_ex(publicTemplate, objectAttributes,
6939
        parameterSet, WOLFTPM2_WRAP_DIGEST);
6940
}
6941
#endif /* WOLFTPM_MLKEM */
6942
6943
/* Generate ECC key-pair with NULL hierarchy and load (populates handle) */
6944
int wolfTPM2_ECDHGenKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ecdhKey, int curve_id,
6945
    const byte* auth, int authSz)
6946
{
6947
    int rc;
6948
    TPMT_PUBLIC publicTemplate;
6949
    WOLFTPM2_HANDLE nullParent;
6950
6951
    if (dev == NULL || ecdhKey == NULL) {
6952
        return BAD_FUNC_ARG;
6953
    }
6954
6955
    XMEMSET(&nullParent, 0, sizeof(nullParent));
6956
    nullParent.hndl = TPM_RH_NULL;
6957
6958
    /* Create and load ECC key for DH */
6959
    rc = wolfTPM2_GetKeyTemplate_ECC(&publicTemplate,
6960
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
6961
        TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA,
6962
        curve_id, TPM_ALG_ECDH);
6963
    if (rc == 0) {
6964
        rc = wolfTPM2_CreatePrimaryKey(dev, ecdhKey, TPM_RH_NULL,
6965
            &publicTemplate, auth, authSz);
6966
    }
6967
6968
    return rc;
6969
}
6970
6971
/* Copy the ECDH shared secret to the caller buffer, reject if larger */
6972
int wolfTPM2_EccZToBuffer(byte* out, int* outSz, const TPM2B_ECC_PARAMETER* z)
6973
{
6974
    if (out == NULL || outSz == NULL || z == NULL) {
6975
        return BAD_FUNC_ARG;
6976
    }
6977
    if (z->size > (UINT16)sizeof(z->buffer) || (int)z->size > *outSz) {
6978
        return BUFFER_E;
6979
    }
6980
    *outSz = (int)z->size;
6981
    XMEMCPY(out, z->buffer, z->size);
6982
    return TPM_RC_SUCCESS;
6983
}
6984
6985
/* Generate ephemeral key and compute Z (shared secret) */
6986
/* One shot API using private key handle to generate key-pair and return
6987
    pub-point and shared secret */
6988
int wolfTPM2_ECDHGen(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* privKey,
6989
    TPM2B_ECC_POINT* pubPoint, byte* out, int* outSz)
6990
{
6991
    int rc;
6992
    ECDH_KeyGen_In  ecdhIn;
6993
    ECDH_KeyGen_Out ecdhOut;
6994
    int curveSize;
6995
6996
    if (dev == NULL || privKey == NULL || pubPoint == NULL || out == NULL ||
6997
                                                                outSz == NULL) {
6998
        return BAD_FUNC_ARG;
6999
    }
7000
7001
    /* get curve size to verify output is large enough */
7002
    curveSize = wolfTPM2_GetCurveSize(
7003
        privKey->pub.publicArea.parameters.eccDetail.curveID);
7004
    if (curveSize <= 0 || *outSz < curveSize) {
7005
        return BAD_FUNC_ARG;
7006
    }
7007
7008
    /* set session auth for key */
7009
    wolfTPM2_SetAuthHandle(dev, 0, &privKey->handle);
7010
7011
    XMEMSET(&ecdhIn, 0, sizeof(ecdhIn));
7012
    ecdhIn.keyHandle = privKey->handle.hndl;
7013
    rc = TPM2_ECDH_KeyGen(&ecdhIn, &ecdhOut);
7014
    if (rc != TPM_RC_SUCCESS) {
7015
    #ifdef DEBUG_WOLFTPM
7016
        printf("TPM2_ECDH_KeyGen failed %d: %s\n", rc,
7017
            wolfTPM2_GetRCString(rc));
7018
    #endif
7019
        return rc;
7020
    }
7021
7022
    pubPoint->size = ecdhOut.pubPoint.size;
7023
    wolfTPM2_CopyEccParam(&pubPoint->point.x, &ecdhOut.pubPoint.point.x);
7024
    wolfTPM2_CopyEccParam(&pubPoint->point.y, &ecdhOut.pubPoint.point.y);
7025
    rc = wolfTPM2_EccZToBuffer(out, outSz, &ecdhOut.zPoint.point.x);
7026
7027
#ifdef DEBUG_WOLFTPM
7028
    if (rc == TPM_RC_SUCCESS) {
7029
        printf("TPM2_ECDH_KeyGen: zPt %d, pubPt %d\n",
7030
            ecdhOut.zPoint.size,
7031
            ecdhOut.pubPoint.size);
7032
    }
7033
#endif
7034
7035
    TPM2_ForceZero(&ecdhOut, sizeof(ecdhOut));
7036
    return rc;
7037
}
7038
7039
/* Compute Z (shared secret) using pubPoint and loaded private ECC key */
7040
int wolfTPM2_ECDHGenZ(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* privKey,
7041
    const TPM2B_ECC_POINT* pubPoint, byte* out, int* outSz)
7042
{
7043
    int rc;
7044
    ECDH_ZGen_In  ecdhZIn;
7045
    ECDH_ZGen_Out ecdhZOut;
7046
    int curveSize;
7047
7048
    if (dev == NULL || privKey == NULL || pubPoint == NULL || out == NULL ||
7049
                                                                outSz == NULL) {
7050
        return BAD_FUNC_ARG;
7051
    }
7052
7053
    /* get curve size to verify output is large enough */
7054
    curveSize = wolfTPM2_GetCurveSize(
7055
        privKey->pub.publicArea.parameters.eccDetail.curveID);
7056
    if (curveSize <= 0 || *outSz < curveSize) {
7057
        return BAD_FUNC_ARG;
7058
    }
7059
7060
    /* set session auth for key */
7061
    wolfTPM2_SetAuthHandle(dev, 0, &privKey->handle);
7062
7063
    XMEMSET(&ecdhZIn, 0, sizeof(ecdhZIn));
7064
    ecdhZIn.keyHandle = privKey->handle.hndl;
7065
    XMEMCPY(&ecdhZIn.inPoint.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
7066
    rc = TPM2_ECDH_ZGen(&ecdhZIn, &ecdhZOut);
7067
    if (rc != TPM_RC_SUCCESS) {
7068
    #ifdef DEBUG_WOLFTPM
7069
        printf("TPM2_ECDH_ZGen failed %d: %s\n", rc,
7070
            wolfTPM2_GetRCString(rc));
7071
    #endif
7072
        return rc;
7073
    }
7074
7075
    rc = wolfTPM2_EccZToBuffer(out, outSz, &ecdhZOut.outPoint.point.x);
7076
7077
#ifdef DEBUG_WOLFTPM
7078
    if (rc == TPM_RC_SUCCESS) {
7079
        printf("TPM2_ECDH_ZGen: zPt %d\n", ecdhZOut.outPoint.size);
7080
    }
7081
#endif
7082
7083
    TPM2_ForceZero(&ecdhZOut, sizeof(ecdhZOut));
7084
    return rc;
7085
}
7086
7087
7088
/* Generate ephemeral ECC key and return array index (2 phase method) */
7089
/* One time use key */
7090
int wolfTPM2_ECDHEGenKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ecdhKey, int curve_id)
7091
{
7092
    int rc;
7093
    EC_Ephemeral_In in;
7094
    EC_Ephemeral_Out out;
7095
7096
    if (dev == NULL || ecdhKey == NULL) {
7097
        return BAD_FUNC_ARG;
7098
    }
7099
7100
    XMEMSET(&in, 0, sizeof(in));
7101
    in.curveID = curve_id;
7102
    rc = TPM2_EC_Ephemeral(&in, &out);
7103
    if (rc != TPM_RC_SUCCESS) {
7104
    #ifdef DEBUG_WOLFTPM
7105
        printf("TPM2_EC_Ephemeral failed %d: %s\n", rc,
7106
            wolfTPM2_GetRCString(rc));
7107
    #endif
7108
        return rc;
7109
    }
7110
7111
    /* Save the point and counter (commit ID) into ecdhKey */
7112
    wolfTPM2_CopyEccParam(&ecdhKey->pub.publicArea.unique.ecc.x,
7113
        &out.Q.point.x);
7114
    wolfTPM2_CopyEccParam(&ecdhKey->pub.publicArea.unique.ecc.y,
7115
        &out.Q.point.y);
7116
    ecdhKey->handle.hndl = (UINT32)out.counter;
7117
7118
    return rc;
7119
}
7120
7121
/* Compute Z (shared secret) using pubPoint and counter (2 phase method) */
7122
/* The counter / array ID can only be used one time */
7123
int wolfTPM2_ECDHEGenZ(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* parentKey,
7124
    WOLFTPM2_KEY* ecdhKey, const TPM2B_ECC_POINT* pubPoint,
7125
    byte* out, int* outSz)
7126
{
7127
    int rc;
7128
    ZGen_2Phase_In  inZGen2Ph;
7129
    ZGen_2Phase_Out outZGen2Ph;
7130
    int curveSize;
7131
7132
    if (dev == NULL || parentKey == NULL || ecdhKey == NULL ||
7133
        pubPoint == NULL || out == NULL || outSz == NULL) {
7134
        return BAD_FUNC_ARG;
7135
    }
7136
7137
    /* get curve size to verify output is large enough */
7138
    curveSize = wolfTPM2_GetCurveSize(
7139
        parentKey->pub.publicArea.parameters.eccDetail.curveID);
7140
    if (curveSize <= 0 || *outSz < curveSize) {
7141
        return BAD_FUNC_ARG;
7142
    }
7143
7144
    /* set session auth for key */
7145
    wolfTPM2_SetAuthHandle(dev, 0, &parentKey->handle);
7146
7147
    XMEMSET(&inZGen2Ph, 0, sizeof(inZGen2Ph));
7148
    inZGen2Ph.keyA = parentKey->handle.hndl;
7149
    inZGen2Ph.counter = (UINT16)ecdhKey->handle.hndl;
7150
    ecdhKey->handle.hndl = TPM_RH_NULL;
7151
    XMEMCPY(&inZGen2Ph.inQsB.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
7152
    XMEMCPY(&inZGen2Ph.inQeB.point, &pubPoint->point, sizeof(TPMS_ECC_POINT));
7153
    inZGen2Ph.inScheme = TPM_ALG_ECDH;
7154
7155
    rc = TPM2_ZGen_2Phase(&inZGen2Ph, &outZGen2Ph);
7156
    if (rc != TPM_RC_SUCCESS) {
7157
    #ifdef DEBUG_WOLFTPM
7158
        printf("TPM2_ZGen_2Phase failed %d: %s\n", rc,
7159
            wolfTPM2_GetRCString(rc));
7160
    #endif
7161
        TPM2_ForceZero(&outZGen2Ph, sizeof(outZGen2Ph));
7162
        return rc;
7163
    }
7164
7165
    rc = wolfTPM2_EccZToBuffer(out, outSz, &outZGen2Ph.outZ2.point.x);
7166
7167
#ifdef DEBUG_WOLFTPM
7168
    if (rc == TPM_RC_SUCCESS) {
7169
        printf("TPM2_ZGen_2Phase: zPt %d\n", outZGen2Ph.outZ2.size);
7170
    }
7171
#endif
7172
7173
    TPM2_ForceZero(&outZGen2Ph, sizeof(outZGen2Ph));
7174
    return rc;
7175
}
7176
7177
7178
int wolfTPM2_RsaEncrypt_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
7179
    TPM_ALG_ID padScheme, const byte* msg, int msgSz, byte* out, int* outSz,
7180
    TPMI_ALG_HASH hashAlg)
7181
{
7182
    int rc;
7183
    RSA_Encrypt_In  rsaEncIn;
7184
    RSA_Encrypt_Out rsaEncOut;
7185
7186
    if (dev == NULL || key == NULL || msg == NULL || out == NULL ||
7187
                                                                outSz == NULL) {
7188
        return BAD_FUNC_ARG;
7189
    }
7190
7191
    /* TPM_ALG_NULL selects the wrapper default scheme hash */
7192
    if (hashAlg == TPM_ALG_NULL)
7193
        hashAlg = WOLFTPM2_WRAP_DIGEST;
7194
    /* OAEP MGF uses the scheme hash; reject weaker than the default */
7195
    if (padScheme == TPM_ALG_OAEP &&
7196
            TPM2_GetHashDigestSize(hashAlg) <
7197
            TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
7198
        return BAD_FUNC_ARG;
7199
    }
7200
7201
    /* set session auth for key */
7202
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
7203
7204
    /* RSA Encrypt */
7205
    XMEMSET(&rsaEncIn, 0, sizeof(rsaEncIn));
7206
    rsaEncIn.keyHandle = key->handle.hndl;
7207
    if (msgSz < 0 || (size_t)msgSz > sizeof(rsaEncIn.message.buffer)) {
7208
        return BUFFER_E;
7209
    }
7210
    rsaEncIn.message.size = (UINT16)msgSz;
7211
    XMEMCPY(rsaEncIn.message.buffer, msg, rsaEncIn.message.size);
7212
    /* TPM_ALG_NULL, TPM_ALG_OAEP, TPM_ALG_RSASSA or TPM_ALG_RSAPSS */
7213
    rsaEncIn.inScheme.scheme = padScheme;
7214
    rsaEncIn.inScheme.details.anySig.hashAlg = hashAlg;
7215
7216
#if 0
7217
    /* Optional label */
7218
    rsaEncIn.label.size = sizeof(label); /* Null term required */
7219
    XMEMCPY(rsaEncIn.label.buffer, label, rsaEncIn.label.size);
7220
#endif
7221
7222
    rc = TPM2_RSA_Encrypt(&rsaEncIn, &rsaEncOut);
7223
    if (rc != TPM_RC_SUCCESS) {
7224
    #ifdef DEBUG_WOLFTPM
7225
        printf("TPM2_RSA_Encrypt failed %d: %s\n", rc,
7226
            wolfTPM2_GetRCString(rc));
7227
    #endif
7228
    }
7229
    else if (*outSz < rsaEncOut.outData.size) {
7230
        rc = BUFFER_E;
7231
    }
7232
    else {
7233
        *outSz = rsaEncOut.outData.size;
7234
        XMEMCPY(out, rsaEncOut.outData.buffer, *outSz);
7235
    #ifdef DEBUG_WOLFTPM
7236
        printf("TPM2_RSA_Encrypt: %d\n", rsaEncOut.outData.size);
7237
    #endif
7238
    }
7239
7240
    /* Plaintext copy lingers in rsaEncIn after the XMEMCPY above. Scrub
7241
     * before returning so the stack frame doesn't leak it. The early
7242
     * BUFFER_E returns above happen before the XMEMCPY so they don't
7243
     * need this path. */
7244
    TPM2_ForceZero(&rsaEncIn, sizeof(rsaEncIn));
7245
    return rc;
7246
}
7247
7248
int wolfTPM2_RsaEncrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
7249
    TPM_ALG_ID padScheme, const byte* msg, int msgSz, byte* out, int* outSz)
7250
{
7251
    return wolfTPM2_RsaEncrypt_ex(dev, key, padScheme, msg, msgSz, out, outSz,
7252
        WOLFTPM2_WRAP_DIGEST);
7253
}
7254
7255
int wolfTPM2_RsaDecrypt_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
7256
    TPM_ALG_ID padScheme, const byte* in, int inSz, byte* msg, int* msgSz,
7257
    TPMI_ALG_HASH hashAlg)
7258
{
7259
    int rc;
7260
    RSA_Decrypt_In  rsaDecIn;
7261
    RSA_Decrypt_Out rsaDecOut;
7262
7263
    if (dev == NULL || key == NULL || in == NULL || msg == NULL ||
7264
                                                                msgSz == NULL) {
7265
        return BAD_FUNC_ARG;
7266
    }
7267
7268
    /* TPM_ALG_NULL selects the wrapper default scheme hash */
7269
    if (hashAlg == TPM_ALG_NULL)
7270
        hashAlg = WOLFTPM2_WRAP_DIGEST;
7271
    /* OAEP MGF uses the scheme hash; reject weaker than the default */
7272
    if (padScheme == TPM_ALG_OAEP &&
7273
            TPM2_GetHashDigestSize(hashAlg) <
7274
            TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST)) {
7275
        return BAD_FUNC_ARG;
7276
    }
7277
7278
    /* set session auth and name for key */
7279
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
7280
7281
    /* RSA Decrypt */
7282
    XMEMSET(&rsaDecIn, 0, sizeof(rsaDecIn));
7283
    rsaDecIn.keyHandle = key->handle.hndl;
7284
    if (inSz < 0 || (size_t)inSz > sizeof(rsaDecIn.cipherText.buffer)) {
7285
        return BUFFER_E;
7286
    }
7287
    rsaDecIn.cipherText.size = (UINT16)inSz;
7288
    XMEMCPY(rsaDecIn.cipherText.buffer, in, inSz);
7289
    /* TPM_ALG_NULL, TPM_ALG_OAEP, TPM_ALG_RSASSA or TPM_ALG_RSAPSS */
7290
    rsaDecIn.inScheme.scheme = padScheme;
7291
    rsaDecIn.inScheme.details.anySig.hashAlg = hashAlg;
7292
7293
#if 0
7294
    /* Optional label */
7295
    rsaDecIn.label.size = sizeof(label); /* Null term required */
7296
    XMEMCPY(rsaDecIn.label.buffer, label, rsaEncIn.label.size);
7297
#endif
7298
7299
    rc = TPM2_RSA_Decrypt(&rsaDecIn, &rsaDecOut);
7300
    if (rc != TPM_RC_SUCCESS) {
7301
    #ifdef DEBUG_WOLFTPM
7302
        printf("TPM2_RSA_Decrypt failed %d: %s\n", rc,
7303
            wolfTPM2_GetRCString(rc));
7304
    #endif
7305
        TPM2_ForceZero(&rsaDecOut, sizeof(rsaDecOut));
7306
        return rc;
7307
    }
7308
7309
    if (*msgSz < rsaDecOut.message.size) {
7310
        TPM2_ForceZero(&rsaDecOut, sizeof(rsaDecOut));
7311
        return BUFFER_E;
7312
    }
7313
    *msgSz = rsaDecOut.message.size;
7314
    XMEMCPY(msg, rsaDecOut.message.buffer, *msgSz);
7315
7316
#ifdef DEBUG_WOLFTPM
7317
    printf("TPM2_RSA_Decrypt: %d\n", rsaDecOut.message.size);
7318
#endif
7319
7320
    TPM2_ForceZero(&rsaDecOut, sizeof(rsaDecOut));
7321
7322
    return rc;
7323
}
7324
7325
int wolfTPM2_RsaDecrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
7326
    TPM_ALG_ID padScheme, const byte* in, int inSz, byte* msg, int* msgSz)
7327
{
7328
    return wolfTPM2_RsaDecrypt_ex(dev, key, padScheme, in, inSz, msg, msgSz,
7329
        WOLFTPM2_WRAP_DIGEST);
7330
}
7331
7332
int wolfTPM2_ResetPCR(WOLFTPM2_DEV* dev, int pcrIndex)
7333
{
7334
    int rc;
7335
    PCR_Reset_In pcrReset;
7336
7337
    if (pcrIndex < (int)PCR_FIRST || pcrIndex > (int)PCR_LAST)
7338
        return BAD_FUNC_ARG;
7339
7340
    XMEMSET(&pcrReset, 0, sizeof(pcrReset));
7341
    pcrReset.pcrHandle = pcrIndex;
7342
    rc = TPM2_PCR_Reset(&pcrReset);
7343
    (void)dev;
7344
    return rc;
7345
}
7346
7347
int wolfTPM2_SetLocality(WOLFTPM2_DEV* dev, int locality)
7348
{
7349
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_WINAPI) || \
7350
    defined(WOLFTPM_OPTEE)
7351
    /* The Linux kernel driver and Windows TBS own the TPM locality, and the
7352
     * OP-TEE trusted application fixes it at FWTPM_OPTEE_LOCALITY */
7353
    (void)dev;
7354
    (void)locality;
7355
    return NOT_COMPILED_IN;
7356
#elif defined(WOLFTPM_SWTPM)
7357
    /* The swtpm/mssim transport carries the locality with each command
7358
     * (see TPM2_SWTPM_SendCommand), so just record it for subsequent
7359
     * commands - no TIS handshake is involved. */
7360
    if (dev == NULL || locality < 0 || locality > 4) {
7361
        return BAD_FUNC_ARG;
7362
    }
7363
    dev->ctx.locality = locality;
7364
    return TPM_RC_SUCCESS;
7365
#else
7366
    /* Built-in TIS driver (SPI/memory-mapped). The fwtpm-tis CI config exercises
7367
     * both the immediate-grant and the release-and-retry branches below: the
7368
     * fwTPM SHM-TIS emulation does not preempt (like the ST33), so switching
7369
     * locality there forces the release-then-retry path. Only the
7370
     * restore-on-failure branch (target ungrantable) is not auto-triggered; it
7371
     * was checked on the ST33 over SPI. */
7372
    int rc;
7373
    int oldLocality;
7374
7375
    if (dev == NULL || locality < 0 || locality > 4) {
7376
        return BAD_FUNC_ARG;
7377
    }
7378
7379
#ifdef WOLFTPM_I2C
7380
    /* The I2C HAL transmits only the low 8 address bits, so the TIS locality
7381
     * (address bits 12+) never reaches the TPM. A non-zero locality would read
7382
     * back locality 0's ACCESS register and falsely appear granted, so reject
7383
     * it until locality-aware I2C addressing is implemented. */
7384
    if (locality != 0) {
7385
        return NOT_COMPILED_IN;
7386
    }
7387
#endif
7388
7389
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
7390
    /* When the Linux kernel driver is in use the kernel owns the locality */
7391
    if (dev->ctx.fd >= 0) {
7392
        return NOT_COMPILED_IN;
7393
    }
7394
#endif
7395
7396
    oldLocality = dev->ctx.locality;
7397
    if (oldLocality == locality) {
7398
        return TPM_RC_SUCCESS; /* already active */
7399
    }
7400
7401
    /* TPM2_TIS_RequestLocalityEx returns the granted locality (0-4) on success,
7402
     * or a TPM_RC_* code on failure (which may be positive), so success is
7403
     * exactly rc == locality. Try to acquire the target while holding the
7404
     * current locality (bounded timeout, so it fails fast when the TPM does not
7405
     * preempt). */
7406
    rc = TPM2_TIS_RequestLocalityEx(&dev->ctx, locality,
7407
        WOLFTPM_LOCALITY_TIMEOUT_TRIES);
7408
    if (rc != locality) {
7409
        /* No preemption: relinquish the current locality and retry */
7410
        (void)TPM2_TIS_ReleaseLocality(&dev->ctx, oldLocality);
7411
        rc = TPM2_TIS_RequestLocalityEx(&dev->ctx, locality,
7412
            WOLFTPM_LOCALITY_TIMEOUT_TRIES);
7413
        if (rc != locality) {
7414
            /* Not grantable - restore the old locality so the TPM stays usable.
7415
             * If that restore also fails, rc still holds the failed (non-success)
7416
             * target request, so the caller sees an error and can re-init.
7417
             * This branch is reached only when the target locality is
7418
             * ungrantable; the fwTPM SHM emulation and CI cannot force that, so
7419
             * it is regression-verified only on ST33 hardware (over SPI). */
7420
            (void)TPM2_TIS_RequestLocalityEx(&dev->ctx, oldLocality,
7421
                WOLFTPM_LOCALITY_TIMEOUT_TRIES);
7422
        }
7423
    }
7424
    else if (oldLocality < locality) {
7425
        /* Preempted the lower locality; relinquish it now */
7426
        (void)TPM2_TIS_ReleaseLocality(&dev->ctx, oldLocality);
7427
    }
7428
    if (rc == locality) {
7429
        rc = TPM_RC_SUCCESS; /* granted; ctx->locality now the target */
7430
    }
7431
7432
    return rc;
7433
#endif
7434
}
7435
7436
/* TODO: Version that can read up to 8 PCR's at a time */
7437
int wolfTPM2_ReadPCR(WOLFTPM2_DEV* dev, int pcrIndex, int hashAlg, byte* digest,
7438
    int* pDigestLen)
7439
{
7440
    int rc;
7441
    PCR_Read_In  pcrReadIn;
7442
    PCR_Read_Out pcrReadOut;
7443
    int digestLen = 0;
7444
7445
    if (dev == NULL || pcrIndex < (int)PCR_FIRST || pcrIndex > (int)PCR_LAST)
7446
        return BAD_FUNC_ARG;
7447
7448
    /* set session auth to blank */
7449
    if (dev->ctx.session) {
7450
        wolfTPM2_SetAuthPassword(dev, 0, NULL);
7451
    }
7452
7453
    XMEMSET(&pcrReadIn, 0, sizeof(pcrReadIn));
7454
    wolfTPM2_SetupPCRSel(&pcrReadIn.pcrSelectionIn, hashAlg, pcrIndex);
7455
    rc = TPM2_PCR_Read(&pcrReadIn, &pcrReadOut);
7456
    if (rc != TPM_RC_SUCCESS) {
7457
    #ifdef DEBUG_WOLFTPM
7458
        printf("TPM2_PCR_Read failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
7459
    #endif
7460
        return rc;
7461
    }
7462
7463
    /* A successful read must return at least one digest; otherwise the
7464
     * digests[0] access below reads uninitialized data. */
7465
    if (pcrReadOut.pcrValues.count == 0) {
7466
        return TPM_RC_FAILURE;
7467
    }
7468
7469
    digestLen = (int)pcrReadOut.pcrValues.digests[0].size;
7470
    if (digest) {
7471
        if (pDigestLen == NULL) {
7472
        #ifdef DEBUG_WOLFTPM
7473
            printf("TPM2_PCR_Read: NULL pDigestLen with non-NULL digest\n");
7474
        #endif
7475
            return BAD_FUNC_ARG;
7476
        }
7477
        if (*pDigestLen < (int)pcrReadOut.pcrValues.digests[0].size) {
7478
        #ifdef DEBUG_WOLFTPM
7479
            printf("TPM2_PCR_Read: Digest buffer too small %d -> %d\n",
7480
                *pDigestLen, (int)pcrReadOut.pcrValues.digests[0].size);
7481
        #endif
7482
            return BUFFER_E;
7483
        }
7484
        XMEMCPY(digest, pcrReadOut.pcrValues.digests[0].buffer, digestLen);
7485
    }
7486
7487
#ifdef DEBUG_WOLFTPM
7488
    printf("TPM2_PCR_Read: Index %d, Digest Sz %d, Update Counter %d\n",
7489
        pcrIndex, digestLen, (int)pcrReadOut.pcrUpdateCounter);
7490
    TPM2_PrintBin(digest, digestLen);
7491
#endif
7492
7493
    if (pDigestLen)
7494
        *pDigestLen = digestLen;
7495
7496
    return rc;
7497
}
7498
7499
int wolfTPM2_ExtendPCR(WOLFTPM2_DEV* dev, int pcrIndex, int hashAlg,
7500
    const byte* digest, int digestLen)
7501
{
7502
    int rc;
7503
    PCR_Extend_In pcrExtend;
7504
7505
    if (dev == NULL || digestLen < 0 || digestLen > TPM_MAX_DIGEST_SIZE ||
7506
            pcrIndex < (int)PCR_FIRST || pcrIndex > (int)PCR_LAST) {
7507
        return BAD_FUNC_ARG;
7508
    }
7509
7510
    /* set session auth to blank */
7511
    if (dev->ctx.session) {
7512
        wolfTPM2_SetAuthPassword(dev, 0, NULL);
7513
    }
7514
7515
    XMEMSET(&pcrExtend, 0, sizeof(pcrExtend));
7516
    pcrExtend.pcrHandle = pcrIndex;
7517
    pcrExtend.digests.count = 1;
7518
    pcrExtend.digests.digests[0].hashAlg = hashAlg;
7519
    XMEMCPY(pcrExtend.digests.digests[0].digest.H, digest, digestLen);
7520
    rc = TPM2_PCR_Extend(&pcrExtend);
7521
    if (rc != TPM_RC_SUCCESS) {
7522
    #ifdef DEBUG_WOLFTPM
7523
        printf("TPM2_PCR_Extend failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
7524
    #endif
7525
    }
7526
7527
#ifdef DEBUG_WOLFTPM
7528
    printf("TPM2_PCR_Extend: Index %d, Digest Sz %d\n", pcrIndex, digestLen);
7529
#endif
7530
7531
    return rc;
7532
}
7533
7534
int wolfTPM2_AllocatePCRBanks_ex(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
7535
    const TPM_ALG_ID* hashAlgs, int hashAlgCount, PCR_Allocate_Out* allocOut)
7536
{
7537
    int rc;
7538
    int i, wanted;
7539
    word32 j, selIdx;
7540
    byte pcrArray[PCR_LAST - PCR_FIRST + 1];
7541
    GetCapability_In capIn;
7542
    GetCapability_Out capOut;
7543
    TPML_PCR_SELECTION* banks;
7544
    PCR_Allocate_In in;
7545
    PCR_Allocate_Out out;
7546
    TPM2_AUTH_SESSION saveSess;
7547
7548
    if (allocOut != NULL) {
7549
        XMEMSET(allocOut, 0, sizeof(*allocOut));
7550
    }
7551
    if (dev == NULL || hashAlgs == NULL) {
7552
        return BAD_FUNC_ARG;
7553
    }
7554
    /* A zero-length selection is legal and leaves the TPM with no PCR banks */
7555
    if (hashAlgCount <= 0 || hashAlgCount > (int)HASH_COUNT) {
7556
        return BAD_FUNC_ARG;
7557
    }
7558
7559
    for (i = 0; i < hashAlgCount; i++) {
7560
        if (hashAlgs[i] == TPM_ALG_NULL || hashAlgs[i] == TPM_ALG_ERROR) {
7561
            return BAD_FUNC_ARG;
7562
        }
7563
        for (j = 0; j < (word32)i; j++) {
7564
            if (hashAlgs[j] == hashAlgs[i]) {
7565
                return BAD_FUNC_ARG;
7566
            }
7567
        }
7568
    }
7569
7570
    /* The bank list is the authority on what can be allocated, not
7571
     * TPM_CAP_ALGS - parts advertise hashes there that have no PCR bank */
7572
    XMEMSET(&capIn, 0, sizeof(capIn));
7573
    XMEMSET(&capOut, 0, sizeof(capOut));
7574
    capIn.capability = TPM_CAP_PCRS;
7575
    capIn.property = 0;
7576
    capIn.propertyCount = HASH_COUNT;
7577
    rc = TPM2_GetCapability(&capIn, &capOut);
7578
    if (rc != TPM_RC_SUCCESS) {
7579
        return rc;
7580
    }
7581
    if (capOut.capabilityData.capability != TPM_CAP_PCRS) {
7582
        return TPM_RC_VALUE;
7583
    }
7584
    /* A truncated list would mean mirroring an incomplete selection, which
7585
     * silently deallocates the banks that did not fit the page. */
7586
    if (capOut.moreData == YES) {
7587
        return TPM_RC_SIZE;
7588
    }
7589
    banks = &capOut.capabilityData.data.assignedPCR;
7590
7591
    /* An unimplemented bank is silently ignored (Part 3 22.5), which would
7592
     * allocate nothing and still report success */
7593
    for (i = 0; i < hashAlgCount; i++) {
7594
        wanted = 0;
7595
        for (j = 0; j < banks->count; j++) {
7596
            if (banks->pcrSelections[j].hash == hashAlgs[i]) {
7597
                wanted = 1;
7598
                break;
7599
            }
7600
        }
7601
        if (!wanted) {
7602
            return TPM_RC_HASH;
7603
        }
7604
    }
7605
7606
    for (i = 0; i < (int)sizeof(pcrArray); i++) {
7607
        pcrArray[i] = (byte)(PCR_FIRST + i);
7608
    }
7609
7610
    XMEMSET(&in, 0, sizeof(in));
7611
    XMEMSET(&out, 0, sizeof(out));
7612
    in.authHandle = TPM_RH_PLATFORM;
7613
7614
    /* Mirror the bank list, giving dropped banks an all-zero bitmap. Part 3
7615
     * 22.5 says an omitted bank is deallocated, but Infineon parts answer
7616
     * TPM_RC_PCR unless each deallocation is spelled out. */
7617
    for (j = 0; j < banks->count; j++) {
7618
        wanted = 0;
7619
        for (i = 0; i < hashAlgCount; i++) {
7620
            if (hashAlgs[i] == banks->pcrSelections[j].hash) {
7621
                wanted = 1;
7622
                break;
7623
            }
7624
        }
7625
        if (wanted) {
7626
            TPM2_SetupPCRSelArray(&in.pcrAllocation,
7627
                banks->pcrSelections[j].hash, pcrArray,
7628
                (word32)sizeof(pcrArray));
7629
        }
7630
        else {
7631
            selIdx = in.pcrAllocation.count;
7632
            if (selIdx >= HASH_COUNT) {
7633
                return TPM_RC_VALUE; /* the TPM reported more banks than fit */
7634
            }
7635
            in.pcrAllocation.pcrSelections[selIdx].hash =
7636
                banks->pcrSelections[j].hash;
7637
            in.pcrAllocation.pcrSelections[selIdx].sizeofSelect =
7638
                banks->pcrSelections[j].sizeofSelect;
7639
            in.pcrAllocation.count++;
7640
        }
7641
    }
7642
7643
    /* Platform auth setup below overwrites session[0] */
7644
    XMEMCPY(&saveSess, &dev->session[0], sizeof(saveSess));
7645
7646
    if (session == NULL) {
7647
        rc = wolfTPM2_SetAuthPassword(dev, 0, NULL);
7648
        if (rc == TPM_RC_SUCCESS) {
7649
            dev->session[0].sessionAttributes = 0;
7650
        }
7651
    }
7652
    else {
7653
        rc = wolfTPM2_SetAuthSession(dev, 0, session,
7654
            (TPMA_SESSION_continueSession));
7655
    }
7656
    if (rc == TPM_RC_SUCCESS) {
7657
        rc = TPM2_PCR_Allocate(&in, &out);
7658
        if (rc != TPM_RC_SUCCESS) {
7659
        #ifdef DEBUG_WOLFTPM
7660
            printf("TPM2_PCR_Allocate failed 0x%x: %s\n", rc,
7661
                TPM2_GetRCString(rc));
7662
        #endif
7663
        }
7664
    }
7665
7666
    /* A continuing session gets a fresh nonceTPM from the response; hand it
7667
     * back before slot 0 is overwritten or the caller's next use of the
7668
     * session computes an invalid HMAC (see wolfTPM2_UnsetAuthSession). */
7669
    if (session != NULL) {
7670
        XMEMCPY(&session->nonceTPM, &dev->session[0].nonceTPM,
7671
            sizeof(TPM2B_NONCE));
7672
    }
7673
7674
    /* Restore previous session[0] state and clear the stack copy */
7675
    XMEMCPY(&dev->session[0], &saveSess, sizeof(dev->session[0]));
7676
    TPM2_ForceZero(&saveSess, sizeof(saveSess));
7677
7678
    if (allocOut != NULL) {
7679
        XMEMCPY(allocOut, &out, sizeof(*allocOut));
7680
    }
7681
    if (rc != TPM_RC_SUCCESS) {
7682
        return rc;
7683
    }
7684
    /* No room for the set - fail rather than make the caller check a field */
7685
    if (out.allocationSuccess != YES) {
7686
        return BUFFER_E;
7687
    }
7688
    /* Staged: applied at the next Startup(CLEAR), which needs a _TPM_Init
7689
     * only a power cycle provides - no command does it */
7690
    return TPM_RC_SUCCESS;
7691
}
7692
7693
int wolfTPM2_AllocatePCRBanks(WOLFTPM2_DEV* dev, const TPM_ALG_ID* hashAlgs,
7694
    int hashAlgCount, PCR_Allocate_Out* allocOut)
7695
{
7696
    return wolfTPM2_AllocatePCRBanks_ex(dev, NULL, hashAlgs, hashAlgCount,
7697
        allocOut);
7698
}
7699
7700
int wolfTPM2_UnloadHandle(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle)
7701
{
7702
    int rc, i;
7703
    int isSession;
7704
    TPM_HANDLE flushHandle;
7705
    FlushContext_In in;
7706
7707
    if (dev == NULL || handle == NULL)
7708
        return BAD_FUNC_ARG;
7709
7710
    /* don't try and unload null or persistent handles */
7711
    if (handle->hndl == 0 || handle->hndl == TPM_RH_NULL ||
7712
        (handle->hndl >= PERSISTENT_FIRST && handle->hndl <= PERSISTENT_LAST)) {
7713
        return TPM_RC_SUCCESS;
7714
    }
7715
7716
    flushHandle = handle->hndl;
7717
    isSession = TPM2_IS_HMAC_SESSION(flushHandle) ||
7718
        TPM2_IS_POLICY_SESSION(flushHandle);
7719
7720
    XMEMSET(&in, 0, sizeof(in));
7721
    in.flushHandle = flushHandle;
7722
    rc = TPM2_FlushContext(&in);
7723
    if (rc != TPM_RC_SUCCESS) {
7724
    #ifdef DEBUG_WOLFTPM
7725
        printf("TPM2_FlushContext failed %d: %s\n", rc,
7726
            wolfTPM2_GetRCString(rc));
7727
    #endif
7728
        return rc;
7729
    }
7730
7731
#ifdef DEBUG_WOLFTPM
7732
    printf("TPM2_FlushContext: Closed handle 0x%x\n", (word32)handle->hndl);
7733
#endif
7734
7735
    if (isSession) {
7736
        TPM2_ForceZero(&handle->auth, sizeof(handle->auth));
7737
        for (i = 0; i < MAX_SESSION_NUM; i++) {
7738
            if (dev->session[i].sessionHandle == flushHandle) {
7739
                TPM2_ForceZero(&dev->session[i], sizeof(dev->session[i]));
7740
                dev->session[i].sessionHandle = TPM_RS_PW;
7741
            }
7742
        }
7743
    }
7744
    handle->hndl = TPM_RH_NULL;
7745
7746
    return TPM_RC_SUCCESS;
7747
}
7748
7749
/* Read the NV Index public area and compute its Name */
7750
static int wolfTPM2_NVComputeName(WOLFTPM2_DEV* dev, word32 nvIndex,
7751
    TPM2B_NAME* name, TPMA_NV* attributes)
7752
{
7753
    int rc;
7754
    TPMS_NV_PUBLIC nvPublic;
7755
7756
    rc = wolfTPM2_NVReadPublic(dev, nvIndex, &nvPublic);
7757
    if (rc == TPM_RC_SUCCESS) {
7758
        if (attributes != NULL) {
7759
            *attributes = nvPublic.attributes;
7760
        }
7761
    #ifndef WOLFTPM2_NO_WOLFCRYPT
7762
        rc = TPM2_HashNvPublic(&nvPublic, (byte*)&name->name, &name->size);
7763
    #else
7764
        (void)name;
7765
    #endif
7766
    }
7767
    return rc;
7768
}
7769
7770
/* NV read/write authHandle may be the owner or platform hierarchy instead of
7771
 * the NV Index (TPMA_NV_OWNERWRITE/PPWRITE/OWNERREAD/PPREAD) */
7772
static int wolfTPM2_NVIsHierarchyAuth(TPM_HANDLE authHandle)
7773
{
7774
    return (authHandle == TPM_RH_OWNER || authHandle == TPM_RH_PLATFORM);
7775
}
7776
7777
/* nv is the populated handle and auth */
7778
/* auth and authSz are optional NV authentication */
7779
/* authPolicy and authPolicySz are optional policy digest */
7780
/* nameAlg is the index name hash algorithm; must match the hash that
7781
 *   produced authPolicy when one is supplied, otherwise the policy can
7782
 *   never be satisfied. Pass TPM_ALG_NULL to use WOLFTPM2_WRAP_DIGEST
7783
 *   (default) or auto-infer from authPolicySz for SHA-only policies. */
7784
int wolfTPM2_NVCreateAuthPolicy_ex(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
7785
    WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
7786
    const byte* auth, int authSz, const byte* authPolicy, int authPolicySz,
7787
    TPMI_ALG_HASH nameAlg)
7788
{
7789
    int rc, rctmp;
7790
    NV_DefineSpace_In in;
7791
7792
    if (dev == NULL || nv == NULL || parent == NULL) {
7793
        return BAD_FUNC_ARG;
7794
    }
7795
    if (maxSize > 0xFFFF) {
7796
        return BUFFER_E;
7797
    }
7798
    if (auth != NULL && authSz > 0 &&
7799
            authSz > (int)sizeof(in.auth.buffer)) {
7800
        return BUFFER_E;
7801
    }
7802
    if (authPolicy != NULL && authPolicySz > 0 &&
7803
            authPolicySz >
7804
                (int)sizeof(in.publicInfo.nvPublic.authPolicy.buffer)) {
7805
        return BUFFER_E;
7806
    }
7807
7808
    /* set session auth for key */
7809
    if (dev->ctx.session && !parent->policyAuth) {
7810
        rc = wolfTPM2_SetAuthHandle(dev, 0, parent);
7811
        if (rc != TPM_RC_SUCCESS) { return rc; }
7812
    }
7813
7814
    XMEMSET(&in, 0, sizeof(in));
7815
    in.authHandle = parent->hndl;
7816
    if (auth != NULL && authSz > 0) {
7817
        in.auth.size = authSz;
7818
        XMEMCPY(in.auth.buffer, auth, in.auth.size);
7819
    }
7820
    in.publicInfo.nvPublic.nvIndex = nvIndex;
7821
    if (nameAlg != TPM_ALG_NULL) {
7822
        /* Caller supplied an explicit nameAlg; use it as-is and only
7823
         * sanity-check against the policy digest size. */
7824
        if (authPolicy != NULL && authPolicySz > 0) {
7825
            int expectSz = TPM2_GetHashDigestSize(nameAlg);
7826
            if (expectSz <= 0 || expectSz != authPolicySz) {
7827
                TPM2_ForceZero(&in.auth, sizeof(in.auth));
7828
                return BAD_FUNC_ARG;
7829
            }
7830
        }
7831
        in.publicInfo.nvPublic.nameAlg = nameAlg;
7832
    }
7833
    else if (authPolicy != NULL && authPolicySz > 0) {
7834
        /* No explicit nameAlg supplied. Infer from policy digest size for
7835
         * SHA-only policies. The TPM stores the policy digest verbatim,
7836
         * so we don't need wolfCrypt to support the hash here - the
7837
         * caller has already computed the digest. SM3-256 / SHA3-256
7838
         * also produce 32 bytes; callers needing those must pass
7839
         * nameAlg explicitly via the _ex API. */
7840
        switch (authPolicySz) {
7841
            case TPM_SHA_DIGEST_SIZE:
7842
                in.publicInfo.nvPublic.nameAlg = TPM_ALG_SHA1;
7843
                break;
7844
            case TPM_SHA256_DIGEST_SIZE:
7845
                in.publicInfo.nvPublic.nameAlg = TPM_ALG_SHA256;
7846
                break;
7847
            case TPM_SHA384_DIGEST_SIZE:
7848
                in.publicInfo.nvPublic.nameAlg = TPM_ALG_SHA384;
7849
                break;
7850
            case TPM_SHA512_DIGEST_SIZE:
7851
                in.publicInfo.nvPublic.nameAlg = TPM_ALG_SHA512;
7852
                break;
7853
            default:
7854
                TPM2_ForceZero(&in.auth, sizeof(in.auth));
7855
                return BAD_FUNC_ARG;
7856
        }
7857
    }
7858
    else {
7859
        in.publicInfo.nvPublic.nameAlg = WOLFTPM2_WRAP_DIGEST;
7860
    }
7861
    in.publicInfo.nvPublic.attributes = nvAttributes;
7862
    in.publicInfo.nvPublic.dataSize = (UINT16)maxSize;
7863
    if (authPolicy != NULL && authPolicySz > 0) {
7864
        in.publicInfo.nvPublic.authPolicy.size = authPolicySz;
7865
        XMEMCPY(in.publicInfo.nvPublic.authPolicy.buffer, authPolicy,
7866
            in.publicInfo.nvPublic.authPolicy.size);
7867
    }
7868
7869
    rc = TPM2_NV_DefineSpace(&in);
7870
    if (rc == TPM_RC_NV_DEFINED) {
7871
    #ifdef DEBUG_WOLFTPM
7872
        printf("TPM2_NV_DefineSpace: handle already exists\n");
7873
    #endif
7874
    }
7875
    else if (rc != TPM_RC_SUCCESS) {
7876
    #ifdef DEBUG_WOLFTPM
7877
        printf("TPM2_NV_DefineSpace failed %d: %s\n", rc,
7878
            wolfTPM2_GetRCString(rc));
7879
    #endif
7880
        TPM2_ForceZero(&in.auth, sizeof(in.auth));
7881
        return rc;
7882
    }
7883
7884
    /* compute NV object with name */
7885
    XMEMSET(nv, 0, sizeof(*nv));
7886
    rctmp = wolfTPM2_NVOpen(dev, nv, nvIndex, auth, authSz);
7887
    if (rctmp != TPM_RC_SUCCESS)
7888
        rc = rctmp;
7889
7890
#ifdef DEBUG_WOLFTPM
7891
    printf("TPM2_NV_DefineSpace: Auth 0x%x, Idx 0x%x, Attribs 0x%x, Size %d\n",
7892
        (word32)in.authHandle,
7893
        (word32)in.publicInfo.nvPublic.nvIndex,
7894
        (word32)in.publicInfo.nvPublic.attributes,
7895
        in.publicInfo.nvPublic.dataSize);
7896
#endif
7897
7898
    TPM2_ForceZero(&in.auth, sizeof(in.auth));
7899
    return rc;
7900
}
7901
7902
int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
7903
    WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
7904
    const byte* auth, int authSz, const byte* authPolicy, int authPolicySz)
7905
{
7906
    return wolfTPM2_NVCreateAuthPolicy_ex(dev, parent, nv, nvIndex,
7907
        nvAttributes, maxSize, auth, authSz, authPolicy, authPolicySz,
7908
        TPM_ALG_NULL);
7909
}
7910
7911
int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
7912
    WOLFTPM2_NV* nv, word32 nvIndex, word32 nvAttributes, word32 maxSize,
7913
    const byte* auth, int authSz)
7914
{
7915
    return wolfTPM2_NVCreateAuthPolicy(dev, parent, nv, nvIndex, nvAttributes,
7916
        maxSize, auth, authSz, NULL, 0);
7917
}
7918
7919
/* older API kept for compatibility, recommend using wolfTPM2_NVCreateAuth */
7920
int wolfTPM2_NVCreate(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
7921
    word32 nvIndex, word32 nvAttributes, word32 maxSize,
7922
    const byte* auth, int authSz)
7923
{
7924
    int rc;
7925
    WOLFTPM2_NV nv;
7926
    WOLFTPM2_HANDLE parent;
7927
7928
    XMEMSET(&nv, 0, sizeof(nv));
7929
    XMEMSET(&parent, 0, sizeof(parent));
7930
    parent.hndl = authHandle;
7931
    rc = wolfTPM2_NVCreateAuth(dev, &parent, &nv, nvIndex, nvAttributes,
7932
        maxSize, auth, authSz);
7933
    /* NVOpen copied the index password into the local copy */
7934
    TPM2_ForceZero(&nv, sizeof(nv));
7935
    return rc;
7936
}
7937
7938
static int wolfTPM2_NVWriteData(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
7939
    TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz, WOLFTPM2_NV* nv,
7940
    word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset, int extend)
7941
{
7942
    int rc = TPM_RC_SUCCESS;
7943
    word32 pos = 0, towrite;
7944
    int hierAuth;
7945
    union {
7946
        NV_Write_In write;
7947
        NV_Extend_In extend;
7948
    } in;
7949
7950
    if (dev == NULL || nv == NULL || dataBuf == NULL) {
7951
        return BAD_FUNC_ARG;
7952
    }
7953
    if ((pcrArray == NULL) != (pcrArraySz == 0)) {
7954
        return BAD_FUNC_ARG;
7955
    }
7956
    /* A caller built policy (no PCR) is consumed by the first chunk */
7957
    if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)
7958
            && pcrArray == NULL && dataSz > MAX_NV_BUFFER_SIZE) {
7959
        return BUFFER_E;
7960
    }
7961
    hierAuth = wolfTPM2_NVIsHierarchyAuth(nv->handle.hndl);
7962
7963
    while (dataSz > 0) {
7964
        towrite = dataSz;
7965
        if (towrite > MAX_NV_BUFFER_SIZE)
7966
            towrite = MAX_NV_BUFFER_SIZE;
7967
7968
        if (hierAuth) {
7969
            /* Keep the hierarchy authHandle, only refresh the NV Index Name */
7970
            if (pos == 0 || (nv->attributes & TPMA_NV_WRITTEN) == 0) {
7971
                rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name,
7972
                    &nv->attributes);
7973
                if (rc != 0)
7974
                    break;
7975
            }
7976
        }
7977
        /* Refresh for the first policy chunk and until NV_WRITTEN is cached. */
7978
        else if (!nv->handle.nameLoaded ||
7979
            nv->handle.hndl != (TPM_HANDLE)nvIndex ||
7980
            (nv->attributes & TPMA_NV_WRITTEN) == 0 ||
7981
            (pos == 0 && tpmSession != NULL &&
7982
                TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl))) {
7983
            rc = wolfTPM2_NVOpen(dev, nv, nvIndex, NULL, 0);
7984
            if (rc != 0)
7985
                break;
7986
        }
7987
        /* For policy session recompute PCR for each iteration */
7988
        if (tpmSession != NULL
7989
                           && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)) {
7990
            /* PCR resets after each call for TPMA_SESSION_continueSession */
7991
            if (pcrArray != NULL) {
7992
                rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl,
7993
                    pcrAlg, pcrArray, pcrArraySz);
7994
                if (rc != TPM_RC_SUCCESS)
7995
                    break;
7996
            }
7997
7998
            /* Set policy session while saving nonceTPM */
7999
            wolfTPM2_SetSessionHandle(dev, 0, tpmSession);
8000
        }
8001
8002
        /* Necessary, because NVWrite has two handles, second is NV Index
8003
         * If policy session Name will update via nonceTPM each iteration */
8004
        if ((wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle) != 0) ||
8005
            (wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle) != 0)) {
8006
        #ifdef DEBUG_WOLFTPM
8007
            printf("wolfTPM2_NVWriteData: Setting NV index name failed\n");
8008
        #endif
8009
            rc = TPM_RC_FAILURE;
8010
            break;
8011
        }
8012
8013
        XMEMSET(&in, 0, sizeof(in));
8014
        in.write.authHandle = nv->handle.hndl;
8015
        in.write.nvIndex = nvIndex;
8016
        in.write.data.size = towrite;
8017
        if (dataBuf)
8018
            XMEMCPY(in.write.data.buffer, &dataBuf[pos], towrite);
8019
        if (!extend) {
8020
            in.write.offset = offset+pos;
8021
        }
8022
8023
    #ifdef DEBUG_WOLFTPM
8024
        printf("wolfTPM2_NVWriteData: Auth 0x%x, Idx 0x%x, Offset %d, Size %d, "
8025
            "Extend %d\n",
8026
            (word32)in.write.authHandle, (word32)in.write.nvIndex,
8027
            in.write.offset, in.write.data.size, extend);
8028
    #endif
8029
8030
        if (!extend) {
8031
            rc = TPM2_NV_Write(&in.write);
8032
        }
8033
        else {
8034
            rc = TPM2_NV_Extend(&in.extend);
8035
        }
8036
        if (rc != TPM_RC_SUCCESS) {
8037
            break;
8038
        }
8039
8040
        pos += towrite;
8041
        dataSz -= towrite;
8042
    }
8043
8044
#ifdef DEBUG_WOLFTPM
8045
    if (rc != TPM_RC_SUCCESS) {
8046
        printf("wolfTPM2_NVWriteData failed %d: %s\n",
8047
            rc, wolfTPM2_GetRCString(rc));
8048
    }
8049
#endif
8050
8051
    TPM2_ForceZero(&in, sizeof(in));
8052
    return rc;
8053
}
8054
8055
int wolfTPM2_NVExtend(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
8056
    word32 nvIndex, byte* dataBuf, word32 dataSz)
8057
{
8058
    return wolfTPM2_NVWriteData(dev, NULL, TPM_ALG_NULL, NULL, 0,
8059
        nv, nvIndex, dataBuf, dataSz, 0, 1);
8060
}
8061
8062
int wolfTPM2_NVWriteAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
8063
    TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz, WOLFTPM2_NV* nv,
8064
    word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset)
8065
{
8066
    return wolfTPM2_NVWriteData(dev, tpmSession, pcrAlg, pcrArray, pcrArraySz,
8067
        nv, nvIndex, dataBuf, dataSz, offset, 0);
8068
}
8069
8070
int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
8071
    word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset)
8072
{
8073
    return wolfTPM2_NVWriteData(dev, NULL, TPM_ALG_NULL, NULL, 0,
8074
        nv, nvIndex, dataBuf, dataSz, offset, 0);
8075
}
8076
8077
/* older API kept for compatibility, recommend using wolfTPM2_NVWriteAuth */
8078
int wolfTPM2_NVWrite(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
8079
    word32 nvIndex, byte* dataBuf, word32 dataSz, word32 offset)
8080
{
8081
    WOLFTPM2_NV nv;
8082
    XMEMSET(&nv, 0, sizeof(nv));
8083
    nv.handle.hndl = (TPM_HANDLE)nvIndex;
8084
    (void)authHandle;
8085
    return wolfTPM2_NVWriteAuth(dev, &nv, nvIndex, dataBuf, dataSz, offset);
8086
}
8087
8088
int wolfTPM2_NVReadAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
8089
    TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz, WOLFTPM2_NV* nv,
8090
    word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
8091
{
8092
    int rc = TPM_RC_SUCCESS;
8093
    word32 pos = 0, toread, dataSz;
8094
    int hierAuth;
8095
    NV_Read_In in;
8096
    NV_Read_Out out;
8097
8098
    if (dev == NULL || nv == NULL || pDataSz == NULL || dataBuf == NULL) {
8099
        return BAD_FUNC_ARG;
8100
    }
8101
8102
    dataSz = *pDataSz;
8103
    if ((pcrArray == NULL) != (pcrArraySz == 0)) {
8104
        return BAD_FUNC_ARG;
8105
    }
8106
    /* A caller built policy (no PCR) is consumed by the first chunk */
8107
    if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)
8108
            && pcrArray == NULL && dataSz > MAX_NV_BUFFER_SIZE) {
8109
        return BUFFER_E;
8110
    }
8111
    hierAuth = wolfTPM2_NVIsHierarchyAuth(nv->handle.hndl);
8112
8113
    while (dataSz > 0) {
8114
        toread = dataSz;
8115
        if (toread > MAX_NV_BUFFER_SIZE)
8116
            toread = MAX_NV_BUFFER_SIZE;
8117
8118
        if (hierAuth) {
8119
            /* Keep the hierarchy authHandle, only refresh the NV Index Name */
8120
            if (pos == 0) {
8121
                rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name,
8122
                    &nv->attributes);
8123
                if (rc != 0)
8124
                    break;
8125
            }
8126
        }
8127
        /* Make sure the name is computed for the handle. */
8128
        else if (!nv->handle.nameLoaded || (pos == 0 && tpmSession != NULL
8129
                         && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl))) {
8130
            rc = wolfTPM2_NVOpen(dev, nv, nvIndex, NULL, 0);
8131
            if (rc != 0)
8132
                break;
8133
        }
8134
        /* For policy session recompute PCR for each iteration */
8135
        if (tpmSession != NULL
8136
                           && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)) {
8137
            /* PCR resets after each call for TPMA_SESSION_continueSession */
8138
            if (pcrArray != NULL) {
8139
                rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl,
8140
                    pcrAlg, pcrArray, pcrArraySz);
8141
                if (rc != 0)
8142
                    break;
8143
            }
8144
8145
            /* Set policy session while saving nonceTPM */
8146
            wolfTPM2_SetSessionHandle(dev, 0, tpmSession);
8147
        }
8148
8149
        /* Necessary, because NVWrite has two handles, second is NV Index
8150
         * If policy session Name will update via nonceTPM each iteration */
8151
        if ((wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle) != 0) ||
8152
            (wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle) != 0)) {
8153
        #ifdef DEBUG_WOLFTPM
8154
            printf("Setting NV index name failed\n");
8155
        #endif
8156
            rc = TPM_RC_FAILURE;
8157
            break;
8158
        }
8159
8160
        XMEMSET(&in, 0, sizeof(in));
8161
        in.authHandle = nv->handle.hndl;
8162
        in.nvIndex = nvIndex;
8163
        in.offset = offset+pos;
8164
        in.size = toread;
8165
8166
        rc = TPM2_NV_Read(&in, &out);
8167
        if (rc != TPM_RC_SUCCESS) {
8168
            break;
8169
        }
8170
8171
        toread = out.data.size;
8172
        if (toread > dataSz) {
8173
            rc = BAD_FUNC_ARG;
8174
            break;
8175
        }
8176
        if (dataBuf) {
8177
            XMEMCPY(&dataBuf[pos], out.data.buffer, toread);
8178
        }
8179
8180
    #ifdef DEBUG_WOLFTPM
8181
        printf("TPM2_NV_Read: Auth 0x%x, Idx 0x%x, Offset %d, Size %d\n",
8182
            (word32)in.authHandle, (word32)in.nvIndex, in.offset,
8183
            out.data.size);
8184
    #endif
8185
8186
        /* if we are done reading, exit loop */
8187
        if (toread == 0) {
8188
            break;
8189
        }
8190
8191
        pos += toread;
8192
        dataSz -= toread;
8193
    }
8194
    if (rc != TPM_RC_SUCCESS && pos > 0) {
8195
        TPM2_ForceZero(dataBuf, pos);
8196
        pos = 0;
8197
    }
8198
    *pDataSz = pos;
8199
8200
#ifdef DEBUG_WOLFTPM
8201
    if (rc != TPM_RC_SUCCESS) {
8202
        printf("TPM2_NV_Read failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
8203
    }
8204
#endif
8205
8206
    TPM2_ForceZero(&out, sizeof(out));
8207
    return rc;
8208
}
8209
8210
int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
8211
    word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
8212
{
8213
    return wolfTPM2_NVReadAuthPolicy(dev, NULL, TPM_ALG_NULL, NULL, 0,
8214
        nv, nvIndex, dataBuf, pDataSz, offset);
8215
}
8216
8217
int wolfTPM2_NVReadCert(WOLFTPM2_DEV* dev, TPM_HANDLE handle,
8218
    uint8_t* buffer, uint32_t* len)
8219
{
8220
    int rc;
8221
    WOLFTPM2_NV nv;
8222
    TPMS_NV_PUBLIC nvPublic;
8223
8224
    if (len == NULL) {
8225
        return BAD_FUNC_ARG;
8226
    }
8227
8228
    XMEMSET(&nvPublic, 0, sizeof(nvPublic));
8229
    XMEMSET(&nv, 0, sizeof(nv));
8230
8231
    /* Get or check size of NV */
8232
    rc = wolfTPM2_NVReadPublic(dev, handle, &nvPublic);
8233
    if (rc == 0) {
8234
        if (buffer == NULL) {
8235
            /* just set size and return success */
8236
            *len = nvPublic.dataSize;
8237
            return 0;
8238
        }
8239
        if (nvPublic.dataSize > *len) {
8240
            return BUFFER_E;
8241
        }
8242
        *len = nvPublic.dataSize;
8243
    }
8244
    else {
8245
    #ifdef DEBUG_WOLFTPM
8246
        printf("NV public read of handle 0x%x failed %d: %s\n",
8247
            handle, rc, wolfTPM2_GetRCString(rc));
8248
    #endif
8249
        return rc;
8250
    }
8251
8252
    /* Perform read of NV without auth password */
8253
    nv.handle.hndl = handle;
8254
    rc = wolfTPM2_NVReadAuth(dev, &nv, handle, buffer, (word32*)len, 0);
8255
8256
#ifdef DEBUG_WOLFTPM
8257
    printf("NV public read certificate 0x%x (%u bytes)\n",
8258
        handle, *len);
8259
    TPM2_PrintBin(buffer, *len);
8260
#endif
8261
8262
    return rc;
8263
}
8264
8265
/* older API kept for compatibility, recommend using wolfTPM2_NVReadAuth */
8266
int wolfTPM2_NVRead(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
8267
    word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
8268
{
8269
    WOLFTPM2_NV nv;
8270
    XMEMSET(&nv, 0, sizeof(nv));
8271
    nv.handle.hndl = (TPM_HANDLE)nvIndex;
8272
    (void)authHandle;
8273
    return wolfTPM2_NVReadAuth(dev, &nv, nvIndex, dataBuf, pDataSz, offset);
8274
}
8275
8276
int wolfTPM2_NVOpen(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, word32 nvIndex,
8277
    const byte* auth, word32 authSz)
8278
{
8279
    int rc = TPM_RC_SUCCESS;
8280
    TPM2B_AUTH newAuth;
8281
8282
    if (dev == NULL || nv == NULL || authSz > sizeof(nv->handle.auth.buffer)) {
8283
        return BAD_FUNC_ARG;
8284
    }
8285
8286
    XMEMSET(&newAuth, 0, sizeof(newAuth));
8287
    /* build the "handle" */
8288
    nv->handle.hndl = nvIndex;
8289
    /* auth can also be set already via nv->handle */
8290
    if (auth != NULL && authSz > 0) {
8291
        newAuth.size = (UINT16)authSz;
8292
        XMEMCPY(newAuth.buffer, auth, authSz);
8293
    }
8294
8295
    /* Read the NV Index publicArea to have up to date NV Index Name.
8296
     * Name is needed in case of parameter encryption */
8297
    rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name,
8298
        &nv->attributes);
8299
    if (rc != TPM_RC_SUCCESS) {
8300
    #ifdef DEBUG_WOLFTPM
8301
        printf("Failed to open (read) NV\n");
8302
    #endif
8303
        goto nv_open_exit;
8304
    }
8305
8306
    if (auth != NULL && authSz > 0) {
8307
        wolfTPM2_CopyAuth(&nv->handle.auth, &newAuth);
8308
    }
8309
    /* flag that the NV was "opened" and name was loaded */
8310
    nv->handle.nameLoaded = 1;
8311
8312
nv_open_exit:
8313
    TPM2_ForceZero(&newAuth, sizeof(newAuth));
8314
    return rc;
8315
}
8316
8317
int wolfTPM2_NVReadPublic(WOLFTPM2_DEV* dev, word32 nvIndex,
8318
    TPMS_NV_PUBLIC* nvPublic)
8319
{
8320
    int rc;
8321
    NV_ReadPublic_In  in;
8322
    NV_ReadPublic_Out out;
8323
8324
    if (dev == NULL) {
8325
        return BAD_FUNC_ARG;
8326
    }
8327
8328
    XMEMSET(&in, 0, sizeof(in));
8329
    in.nvIndex = nvIndex;
8330
    rc = TPM2_NV_ReadPublic(&in, &out);
8331
    if (rc != TPM_RC_SUCCESS) {
8332
    #ifdef DEBUG_WOLFTPM
8333
        printf("TPM2_NV_ReadPublic failed %d: %s\n", rc,
8334
            wolfTPM2_GetRCString(rc));
8335
    #endif
8336
        return rc;
8337
    }
8338
8339
#ifdef DEBUG_WOLFTPM
8340
    printf("TPM2_NV_ReadPublic: Sz %d, Idx 0x%x, nameAlg %d, Attr 0x%x, "
8341
            "authPol %d, dataSz %d, name %d\n",
8342
        out.nvPublic.size,
8343
        (word32)out.nvPublic.nvPublic.nvIndex,
8344
        out.nvPublic.nvPublic.nameAlg,
8345
        (word32)out.nvPublic.nvPublic.attributes,
8346
        out.nvPublic.nvPublic.authPolicy.size,
8347
        out.nvPublic.nvPublic.dataSize,
8348
        out.nvName.size);
8349
#endif
8350
8351
    if (nvPublic) {
8352
        wolfTPM2_CopyNvPublic(nvPublic, &out.nvPublic.nvPublic);
8353
    }
8354
8355
    return rc;
8356
}
8357
8358
int wolfTPM2_NVIncrement(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv)
8359
{
8360
    int rc = TPM_RC_SUCCESS;
8361
    NV_Increment_In in;
8362
8363
    if (dev == NULL || nv == NULL) {
8364
        return BAD_FUNC_ARG;
8365
    }
8366
8367
    /* make sure the name is computed for the handle */
8368
    if (!nv->handle.nameLoaded) {
8369
        rc = wolfTPM2_NVOpen(dev, nv, nv->handle.hndl, NULL, 0);
8370
        if (rc != TPM_RC_SUCCESS) { return rc; }
8371
    }
8372
8373
    /* Necessary, because NVRead has two handles, second is NV Index */
8374
    if ((wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle) != 0) ||
8375
        (wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle) != 0)) {
8376
    #ifdef DEBUG_WOLFTPM
8377
        printf("Setting NV index name failed\n");
8378
    #endif
8379
        return TPM_RC_FAILURE;
8380
    }
8381
8382
    XMEMSET(&in, 0, sizeof(in));
8383
    in.authHandle = nv->handle.hndl;
8384
    in.nvIndex = nv->handle.hndl;
8385
8386
#ifdef DEBUG_WOLFTPM
8387
    printf("TPM2_NV_Increment: Auth 0x%x, Idx 0x%x\n",
8388
        (word32)in.authHandle, (word32)in.nvIndex);
8389
#endif
8390
8391
    rc = TPM2_NV_Increment(&in);
8392
    if (rc != TPM_RC_SUCCESS) {
8393
    #ifdef DEBUG_WOLFTPM
8394
        printf("TPM2_NV_Increment failed %d: %s\n", rc,
8395
            wolfTPM2_GetRCString(rc));
8396
    #endif
8397
        return rc;
8398
    }
8399
8400
    return rc;
8401
}
8402
8403
int wolfTPM2_NVWriteLock(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv)
8404
{
8405
    int rc;
8406
    NV_WriteLock_In in;
8407
8408
    if (dev == NULL || nv == NULL) {
8409
        return BAD_FUNC_ARG;
8410
    }
8411
8412
    /* make sure the name is computed for the handle */
8413
    if (!nv->handle.nameLoaded) {
8414
        rc = wolfTPM2_NVOpen(dev, nv, nv->handle.hndl, NULL, 0);
8415
        if (rc != 0) {
8416
            return rc;
8417
        }
8418
    }
8419
8420
    /* Necessary, because NVRead has two handles, second is NV Index */
8421
    if ((wolfTPM2_SetAuthHandleName(dev, 0, &nv->handle) != 0) ||
8422
        (wolfTPM2_SetAuthHandleName(dev, 1, &nv->handle) != 0)) {
8423
    #ifdef DEBUG_WOLFTPM
8424
        printf("Setting NV index name failed\n");
8425
    #endif
8426
        return TPM_RC_FAILURE;
8427
    }
8428
8429
    XMEMSET(&in, 0, sizeof(in));
8430
    in.authHandle = nv->handle.hndl;
8431
    in.nvIndex = nv->handle.hndl;
8432
    return TPM2_NV_WriteLock(&in);
8433
}
8434
8435
int wolfTPM2_NVDeleteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
8436
    word32 nvIndex)
8437
{
8438
    int rc;
8439
    NV_UndefineSpace_In in;
8440
8441
    if (dev == NULL || parent == NULL) {
8442
        return BAD_FUNC_ARG;
8443
    }
8444
8445
    /* set session auth for key */
8446
    if (dev->ctx.session) {
8447
        rc = wolfTPM2_SetAuthHandle(dev, 0, parent);
8448
        if (rc != TPM_RC_SUCCESS) { return rc; }
8449
    }
8450
8451
    XMEMSET(&in, 0, sizeof(in));
8452
    in.authHandle = parent->hndl;
8453
    in.nvIndex = nvIndex;
8454
8455
    rc = TPM2_NV_UndefineSpace(&in);
8456
    if (rc != TPM_RC_SUCCESS) {
8457
    #ifdef DEBUG_WOLFTPM
8458
        printf("TPM2_NV_UndefineSpace failed %d: %s\n", rc,
8459
            wolfTPM2_GetRCString(rc));
8460
    #endif
8461
        return rc;
8462
    }
8463
8464
#ifdef DEBUG_WOLFTPM
8465
    printf("TPM2_NV_UndefineSpace: Auth 0x%x, Idx 0x%x\n",
8466
        (word32)in.authHandle, (word32)in.nvIndex);
8467
#endif
8468
8469
    return rc;
8470
}
8471
8472
/* older API kept for compatibility, recommend using wolfTPM2_NVDeleteAuth */
8473
int wolfTPM2_NVDelete(WOLFTPM2_DEV* dev, TPM_HANDLE authHandle,
8474
    word32 nvIndex)
8475
{
8476
    WOLFTPM2_HANDLE parent;
8477
    XMEMSET(&parent, 0, sizeof(parent));
8478
    parent.hndl = authHandle;
8479
    return wolfTPM2_NVDeleteAuth(dev, &parent, nvIndex);
8480
}
8481
8482
#ifndef WOLFTPM2_NO_WOLFCRYPT
8483
struct WC_RNG* wolfTPM2_GetRng(WOLFTPM2_DEV* dev)
8484
{
8485
    WC_RNG* rng = NULL;
8486
    if (dev) {
8487
    #ifdef WOLFTPM2_USE_WOLF_RNG
8488
        (void)TPM2_GetWolfRng(&rng);
8489
    #endif
8490
    }
8491
    return rng;
8492
}
8493
#endif
8494
8495
int wolfTPM2_GetRandom(WOLFTPM2_DEV* dev, byte* buf, word32 len)
8496
{
8497
    int rc = TPM_RC_SUCCESS;
8498
    GetRandom_In in;
8499
    GetRandom_Out out;
8500
    word32 sz, pos = 0;
8501
8502
    if (dev == NULL || buf == NULL)
8503
        return BAD_FUNC_ARG;
8504
8505
    while (pos < len) {
8506
        /* calculate size to get */
8507
        sz = len - pos;
8508
        if (sz > MAX_RNG_REQ_SIZE)
8509
            sz = MAX_RNG_REQ_SIZE;
8510
8511
        XMEMSET(&in, 0, sizeof(in));
8512
        in.bytesRequested = sz;
8513
        rc = TPM2_GetRandom(&in, &out);
8514
        if (rc != TPM_RC_SUCCESS) {
8515
        #ifdef DEBUG_WOLFTPM
8516
            printf("TPM2_GetRandom failed 0x%x: %s\n", rc,
8517
                TPM2_GetRCString(rc));
8518
        #endif
8519
            break;
8520
        }
8521
8522
        sz = out.randomBytes.size; /* use actual returned size */
8523
        if (sz == 0 || sz > MAX_RNG_REQ_SIZE || sz > (len - pos)) {
8524
        #ifdef DEBUG_WOLFTPM
8525
            printf("wolfTPM2_GetRandom out size error\n");
8526
        #endif
8527
            rc = BAD_FUNC_ARG;
8528
            break;
8529
        }
8530
8531
        XMEMCPY(&buf[pos], out.randomBytes.buffer, sz);
8532
        pos += sz;
8533
        /* Scrub each iteration so earlier random material does not
8534
         * linger across multi-chunk requests. */
8535
        TPM2_ForceZero(&out, sizeof(out));
8536
    }
8537
    TPM2_ForceZero(&out, sizeof(out));
8538
    if (rc != TPM_RC_SUCCESS) {
8539
        /* Scrub any partial random material already written to the caller */
8540
        TPM2_ForceZero(buf, len);
8541
    }
8542
    return rc;
8543
}
8544
8545
int wolfTPM2_Clear(WOLFTPM2_DEV* dev)
8546
{
8547
    int rc;
8548
    Clear_In in;
8549
8550
    if (dev == NULL)
8551
        return BAD_FUNC_ARG;
8552
8553
    XMEMSET(&in, 0, sizeof(in));
8554
    in.authHandle = TPM_RH_LOCKOUT;
8555
8556
    rc = TPM2_Clear(&in);
8557
    if (rc != TPM_RC_SUCCESS) {
8558
    #ifdef DEBUG_WOLFTPM
8559
        printf("TPM2_Clear failed %d: %s\n", rc,
8560
            wolfTPM2_GetRCString(rc));
8561
    #endif
8562
        return rc;
8563
    }
8564
8565
#ifdef DEBUG_WOLFTPM
8566
    printf("TPM2_Clear Auth 0x%x\n", (word32)in.authHandle);
8567
#endif
8568
8569
    return rc;
8570
}
8571
8572
int wolfTPM2_DictionaryAttackLockReset(WOLFTPM2_DEV* dev)
8573
{
8574
    int rc;
8575
    DictionaryAttackLockReset_In in;
8576
8577
    if (dev == NULL)
8578
        return BAD_FUNC_ARG;
8579
8580
    XMEMSET(&in, 0, sizeof(in));
8581
    in.lockHandle = TPM_RH_LOCKOUT;
8582
8583
    rc = TPM2_DictionaryAttackLockReset(&in);
8584
#ifdef DEBUG_WOLFTPM
8585
    if (rc != TPM_RC_SUCCESS) {
8586
        printf("TPM2_DictionaryAttackLockReset failed %d: %s\n", rc,
8587
            wolfTPM2_GetRCString(rc));
8588
    }
8589
#endif
8590
    return rc;
8591
}
8592
8593
int wolfTPM2_DictionaryAttackParameters(WOLFTPM2_DEV* dev,
8594
    word32 newMaxTries, word32 newRecoveryTime, word32 lockoutRecovery)
8595
{
8596
    int rc;
8597
    DictionaryAttackParameters_In in;
8598
8599
    /* newMaxTries of 0 would permanently disable lockout enforcement */
8600
    if (dev == NULL || newMaxTries == 0)
8601
        return BAD_FUNC_ARG;
8602
8603
    XMEMSET(&in, 0, sizeof(in));
8604
    in.lockHandle = TPM_RH_LOCKOUT;
8605
    in.newMaxTries = newMaxTries;
8606
    in.newRecoveryTime = newRecoveryTime;
8607
    in.lockoutRecovery = lockoutRecovery;
8608
8609
    rc = TPM2_DictionaryAttackParameters(&in);
8610
#ifdef DEBUG_WOLFTPM
8611
    if (rc != TPM_RC_SUCCESS) {
8612
        printf("TPM2_DictionaryAttackParameters failed %d: %s\n", rc,
8613
            wolfTPM2_GetRCString(rc));
8614
    }
8615
#endif
8616
    return rc;
8617
}
8618
8619
/* Hashing */
8620
/* usageAuth: Optional auth for handle */
8621
int wolfTPM2_HashStart(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
8622
    TPMI_ALG_HASH hashAlg, const byte* usageAuth, word32 usageAuthSz)
8623
{
8624
    int rc;
8625
    HashSequenceStart_In in;
8626
    HashSequenceStart_Out out;
8627
8628
    /* TPM2_GetHashDigestSize() is 0 for any algorithm that is not a hash,
8629
     * so this rejects them locally instead of relying on TPM_RC_HASH. */
8630
    if (dev == NULL || hash == NULL || TPM2_GetHashDigestSize(hashAlg) == 0 ||
8631
        (usageAuthSz > 0 && usageAuth == NULL)) {
8632
        return BAD_FUNC_ARG;
8633
    }
8634
    if (usageAuthSz > sizeof(hash->handle.auth.buffer))
8635
        return BUFFER_E;
8636
8637
    /* Capture usage auth */
8638
    XMEMSET(hash, 0, sizeof(WOLFTPM2_HASH));
8639
    hash->handle.auth.size = usageAuthSz;
8640
    if (usageAuth != NULL)
8641
        XMEMCPY(hash->handle.auth.buffer, usageAuth, usageAuthSz);
8642
8643
    XMEMSET(&in, 0, sizeof(in));
8644
    wolfTPM2_CopyAuth(&in.auth, &hash->handle.auth);
8645
    in.hashAlg = hashAlg;
8646
    rc = TPM2_HashSequenceStart(&in, &out);
8647
    /* Clear auth copy on stack regardless of outcome */
8648
    TPM2_ForceZero(&in.auth, sizeof(in.auth));
8649
    if (rc != TPM_RC_SUCCESS) {
8650
    #ifdef DEBUG_WOLFTPM
8651
        printf("TPM2_HashSequenceStart failed 0x%x: %s\n", rc,
8652
            TPM2_GetRCString(rc));
8653
    #endif
8654
        TPM2_ForceZero(&hash->handle.auth, sizeof(hash->handle.auth));
8655
        return rc;
8656
    }
8657
8658
    /* Capture hash sequence handle */
8659
    hash->handle.hndl = out.sequenceHandle;
8660
8661
#ifdef DEBUG_WOLFTPM
8662
    printf("wolfTPM2_HashStart: Handle 0x%x\n",
8663
        (word32)out.sequenceHandle);
8664
#endif
8665
8666
    return rc;
8667
}
8668
8669
int wolfTPM2_HashUpdate(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
8670
    const byte* data, word32 dataSz)
8671
{
8672
    int rc = TPM_RC_SUCCESS;
8673
    SequenceUpdate_In in;
8674
    word32 pos = 0, hashSz;
8675
8676
    if (dev == NULL || hash == NULL || (data == NULL && dataSz > 0) ||
8677
            hash->handle.hndl == 0) {
8678
        return BAD_FUNC_ARG;
8679
    }
8680
8681
    /* set session auth for hash handle */
8682
    wolfTPM2_SetAuthHandle(dev, 0, &hash->handle);
8683
8684
    XMEMSET(&in, 0, sizeof(in));
8685
    in.sequenceHandle = hash->handle.hndl;
8686
8687
    while (pos < dataSz) {
8688
        hashSz = dataSz - pos;
8689
        if (hashSz > sizeof(in.buffer.buffer))
8690
            hashSz = sizeof(in.buffer.buffer);
8691
8692
        in.buffer.size = hashSz;
8693
        XMEMCPY(in.buffer.buffer, &data[pos], hashSz);
8694
        rc = TPM2_SequenceUpdate(&in);
8695
        if (rc != TPM_RC_SUCCESS) {
8696
        #ifdef DEBUG_WOLFTPM
8697
            printf("TPM2_SequenceUpdate failed 0x%x: %s\n", rc,
8698
                TPM2_GetRCString(rc));
8699
        #endif
8700
            break;
8701
        }
8702
        pos += hashSz;
8703
    }
8704
8705
#ifdef DEBUG_WOLFTPM
8706
    printf("wolfTPM2_HashUpdate: Handle 0x%x, DataSz %d\n",
8707
        (word32)in.sequenceHandle, dataSz);
8708
#endif
8709
8710
    /* holds a copy of the hashed input */
8711
    TPM2_ForceZero(&in, sizeof(in));
8712
8713
    return rc;
8714
}
8715
8716
int wolfTPM2_HashFinish(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
8717
    byte* digest, word32* digestSz)
8718
{
8719
    int rc;
8720
    SequenceComplete_In in;
8721
    SequenceComplete_Out out;
8722
8723
    if (dev == NULL || hash == NULL || digest == NULL || digestSz == NULL ||
8724
            hash->handle.hndl == 0) {
8725
        return BAD_FUNC_ARG;
8726
    }
8727
8728
    /* set session auth for hash handle */
8729
    wolfTPM2_SetAuthHandle(dev, 0, &hash->handle);
8730
8731
    XMEMSET(&in, 0, sizeof(in));
8732
    in.sequenceHandle = hash->handle.hndl;
8733
    in.hierarchy = TPM_RH_NULL;
8734
    rc = TPM2_SequenceComplete(&in, &out);
8735
8736
    if (rc != TPM_RC_SUCCESS) {
8737
    #ifdef DEBUG_WOLFTPM
8738
        printf("TPM2_SequenceComplete failed 0x%x: %s: Handle 0x%x\n", rc,
8739
            TPM2_GetRCString(rc), (word32)in.sequenceHandle);
8740
    #endif
8741
        /* handle is only consumed by the TPM on success */
8742
        wolfTPM2_UnloadHandle(dev, &hash->handle);
8743
        if (hash->handle.hndl == TPM_RH_NULL) {
8744
            TPM2_ForceZero(&hash->handle.auth,
8745
                sizeof(hash->handle.auth));
8746
            TPM2_ForceZero(&dev->session[0].auth,
8747
                sizeof(dev->session[0].auth));
8748
            dev->session[0].auth.size = 0;
8749
        }
8750
        goto exit;
8751
    }
8752
8753
    /* mark hash handle as done */
8754
    hash->handle.hndl = TPM_RH_NULL;
8755
    TPM2_ForceZero(&hash->handle.auth, sizeof(hash->handle.auth));
8756
    TPM2_ForceZero(&dev->session[0].auth, sizeof(dev->session[0].auth));
8757
    dev->session[0].auth.size = 0;
8758
8759
    if (out.result.size > *digestSz) {
8760
        *digestSz = out.result.size;
8761
        rc = BUFFER_E;
8762
        goto exit;
8763
    }
8764
    *digestSz = out.result.size;
8765
    XMEMCPY(digest, out.result.buffer, *digestSz);
8766
8767
#ifdef DEBUG_WOLFTPM
8768
    printf("wolfTPM2_HashFinish: Handle 0x%x, DigestSz %d\n",
8769
        (word32)in.sequenceHandle, *digestSz);
8770
#endif
8771
8772
exit:
8773
    TPM2_ForceZero(&out, sizeof(out));
8774
    return rc;
8775
}
8776
8777
8778
static int wolfTPM2_ComputeSymmetricUnique(WOLFTPM2_DEV* dev, int hashAlg,
8779
    const TPMT_SENSITIVE* sensitive, TPM2B_DIGEST* unique)
8780
{
8781
    int rc;
8782
8783
#ifdef WOLFTPM_USE_SYMMETRIC
8784
    WOLFTPM2_HASH hash;
8785
    word32 uniqueSz;
8786
#elif !defined(WOLFTPM2_NO_WOLFCRYPT)
8787
    wc_HashAlg hash;
8788
    enum wc_HashType hashType;
8789
    int hashSz;
8790
#endif
8791
8792
    if (dev == NULL || sensitive == NULL || unique == NULL) {
8793
        return BAD_FUNC_ARG;
8794
    }
8795
8796
#ifdef WOLFTPM_USE_SYMMETRIC
8797
    uniqueSz = TPM2_GetHashDigestSize(hashAlg);
8798
    if (uniqueSz == 0 || uniqueSz > sizeof(unique->buffer)) {
8799
        return BUFFER_E;
8800
    }
8801
    rc = wolfTPM2_HashStart(dev, &hash, hashAlg, NULL, 0);
8802
    if (rc == 0) {
8803
        /* sensitive seed */
8804
        rc = wolfTPM2_HashUpdate(dev, &hash, sensitive->seedValue.buffer,
8805
            sensitive->seedValue.size);
8806
        if (rc == 0) {
8807
            /* sensitive value */
8808
            rc = wolfTPM2_HashUpdate(dev, &hash,
8809
                sensitive->sensitive.any.buffer, sensitive->sensitive.any.size);
8810
        }
8811
        if (rc == 0) {
8812
            rc = wolfTPM2_HashFinish(dev, &hash, unique->buffer, &uniqueSz);
8813
            unique->size = uniqueSz;
8814
        }
8815
        else {
8816
            /* Make sure hash if free'd on failure */
8817
            wolfTPM2_UnloadHandle(dev, &hash.handle);
8818
        }
8819
    }
8820
#elif !defined(WOLFTPM2_NO_WOLFCRYPT)
8821
    rc = TPM2_GetHashType(hashAlg);
8822
    hashType = (enum wc_HashType)rc;
8823
    rc = wc_HashGetDigestSize(hashType);
8824
    if (rc < 0)
8825
        return rc;
8826
    hashSz = rc;
8827
8828
    /* Hash of data (name) goes into remainder */
8829
    rc = wc_HashInit(&hash, hashType);
8830
    if (rc == 0) {
8831
        /* sensitive seed */
8832
        rc = wc_HashUpdate(&hash, hashType, sensitive->seedValue.buffer,
8833
            sensitive->seedValue.size);
8834
        if (rc == 0) {
8835
            /* sensitive value */
8836
            rc = wc_HashUpdate(&hash, hashType, sensitive->sensitive.any.buffer,
8837
                sensitive->sensitive.any.size);
8838
        }
8839
        if (rc == 0) {
8840
            rc = wc_HashFinal(&hash, hashType, unique->buffer);
8841
            if (rc == 0)
8842
                unique->size = hashSz;
8843
        }
8844
        wc_HashFree(&hash, hashType);
8845
        TPM2_ForceZero(&hash, sizeof(hash));
8846
    }
8847
#else
8848
    (void)hashAlg;
8849
    rc = NOT_COMPILED_IN;
8850
#endif
8851
8852
    return rc;
8853
}
8854
8855
int wolfTPM2_LoadSymmetricKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, int alg,
8856
    const byte* keyBuf, word32 keySz)
8857
{
8858
    int rc;
8859
    LoadExternal_In  loadExtIn;
8860
    LoadExternal_Out loadExtOut;
8861
    int hashAlg, hashAlgDigSz;
8862
8863
    if (dev == NULL || key == NULL || keyBuf == NULL ||
8864
            (keySz != 16 && keySz != 32)) {
8865
        return BAD_FUNC_ARG;
8866
    }
8867
    if (keySz > sizeof(loadExtIn.inPrivate.sensitiveArea.sensitive.sym.buffer)) {
8868
        return BUFFER_E;
8869
    }
8870
8871
    hashAlg = WOLFTPM2_WRAP_DIGEST;
8872
    hashAlgDigSz = TPM2_GetHashDigestSize(hashAlg);
8873
    if (hashAlgDigSz <= 0 ||
8874
        hashAlgDigSz > (int)sizeof(loadExtIn.inPrivate.sensitiveArea.seedValue.buffer)) {
8875
        return BUFFER_E;
8876
    }
8877
8878
    /* Setup load command */
8879
    XMEMSET(&loadExtIn, 0, sizeof(loadExtIn));
8880
    loadExtIn.hierarchy = TPM_RH_NULL;
8881
8882
    /* Setup private key */
8883
    loadExtIn.inPrivate.sensitiveArea.sensitiveType = TPM_ALG_SYMCIPHER;
8884
    if (key->handle.auth.size > 0) {
8885
        TPM2B_AUTH* auth = &loadExtIn.inPrivate.sensitiveArea.authValue;
8886
        auth->size = key->handle.auth.size;
8887
        if (auth->size > sizeof(auth->buffer))
8888
            auth->size = sizeof(auth->buffer);
8889
        XMEMCPY(auth->buffer, key->handle.auth.buffer, auth->size);
8890
    }
8891
    loadExtIn.inPrivate.sensitiveArea.seedValue.size = hashAlgDigSz;
8892
    rc = wolfTPM2_GetRandom(dev,
8893
        loadExtIn.inPrivate.sensitiveArea.seedValue.buffer,
8894
        loadExtIn.inPrivate.sensitiveArea.seedValue.size);
8895
    if (rc != 0)
8896
        goto exit;
8897
8898
    loadExtIn.inPrivate.sensitiveArea.sensitive.sym.size = keySz;
8899
    XMEMCPY(loadExtIn.inPrivate.sensitiveArea.sensitive.sym.buffer,
8900
        keyBuf, keySz);
8901
8902
    /* Setup public key */
8903
    rc = wolfTPM2_GetKeyTemplate_Symmetric(&loadExtIn.inPublic.publicArea,
8904
        keySz * 8, alg, YES, YES);
8905
    if (rc != 0)
8906
        goto exit;
8907
    loadExtIn.inPublic.publicArea.nameAlg = hashAlg;
8908
    loadExtIn.inPublic.publicArea.unique.sym.size = hashAlgDigSz;
8909
    rc = wolfTPM2_ComputeSymmetricUnique(dev, hashAlg,
8910
        &loadExtIn.inPrivate.sensitiveArea,
8911
        &loadExtIn.inPublic.publicArea.unique.sym);
8912
    if (rc != 0)
8913
        goto exit;
8914
8915
    /* Load private key */
8916
    rc = TPM2_LoadExternal(&loadExtIn, &loadExtOut);
8917
    if (rc == TPM_RC_SUCCESS) {
8918
        key->handle.hndl = loadExtOut.objectHandle;
8919
        wolfTPM2_CopySymmetric(&key->handle.symmetric,
8920
                &loadExtIn.inPublic.publicArea.parameters.asymDetail.symmetric);
8921
        wolfTPM2_CopyPub(&key->pub, &loadExtIn.inPublic);
8922
8923
    #ifdef DEBUG_WOLFTPM
8924
        printf("wolfTPM2_LoadSymmetricKey: 0x%x\n",
8925
            (word32)loadExtOut.objectHandle);
8926
    #endif
8927
    }
8928
8929
exit:
8930
8931
    TPM2_ForceZero(&loadExtIn.inPrivate, sizeof(loadExtIn.inPrivate));
8932
8933
    if (rc != TPM_RC_SUCCESS) {
8934
    #ifdef DEBUG_WOLFTPM
8935
        printf("TPM2_LoadExternal: failed %d: %s\n",
8936
            rc, wolfTPM2_GetRCString(rc));
8937
    #endif
8938
    }
8939
8940
    return rc;
8941
}
8942
8943
/* EncryptDecrypt */
8944
int wolfTPM2_EncryptDecryptBlock(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
8945
    const byte* in, byte* out, word32 inOutSz, byte* iv, word32 ivSz,
8946
    int isDecrypt)
8947
{
8948
    int rc;
8949
    EncryptDecrypt2_In encDecIn;
8950
    EncryptDecrypt2_Out encDecOut;
8951
8952
    if (dev == NULL || key == NULL || in == NULL || out == NULL ||
8953
            inOutSz == 0) {
8954
        return BAD_FUNC_ARG;
8955
    }
8956
    if (inOutSz > sizeof(encDecIn.inData.buffer)) {
8957
        return BUFFER_E;
8958
    }
8959
8960
    /* Validate IV vs mode before mutating dev->session[0] so argument
8961
     * errors don't leave the session with the key's auth. */
8962
    XMEMSET(&encDecIn, 0, sizeof(encDecIn));
8963
    encDecIn.mode = key->pub.publicArea.parameters.symDetail.sym.mode.aes;
8964
    if (iv == NULL || ivSz == 0) {
8965
        /* Modes other than ECB and NULL require an explicit IV */
8966
        if (encDecIn.mode != TPM_ALG_ECB && encDecIn.mode != TPM_ALG_NULL) {
8967
            return BAD_FUNC_ARG;
8968
        }
8969
    }
8970
    else if (ivSz > sizeof(encDecIn.ivIn.buffer)) {
8971
        return BUFFER_E;
8972
    }
8973
8974
    /* Block modes require a whole-block input. Stream-style modes (CFB,
8975
     * OFB, CTR) accept any length and silently rounding up would advance
8976
     * the TPM-returned IV past the bytes the caller consumed, breaking
8977
     * chained-mode encryption. */
8978
    if (encDecIn.mode == TPM_ALG_CBC || encDecIn.mode == TPM_ALG_ECB) {
8979
        if ((inOutSz % MAX_AES_BLOCK_SIZE_BYTES) != 0) {
8980
            return BAD_FUNC_ARG;
8981
        }
8982
    }
8983
8984
    /* set session auth for key */
8985
    wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
8986
8987
    encDecIn.keyHandle = key->handle.hndl;
8988
    if (iv == NULL || ivSz == 0) {
8989
        encDecIn.ivIn.size = encDecIn.mode == TPM_ALG_ECB ? 0 :
8990
            MAX_AES_BLOCK_SIZE_BYTES; /* zeros */
8991
    }
8992
    else {
8993
        encDecIn.ivIn.size = ivSz;
8994
        XMEMCPY(encDecIn.ivIn.buffer, iv, encDecIn.ivIn.size);
8995
    }
8996
    encDecIn.decrypt = isDecrypt;
8997
8998
    encDecIn.inData.size = inOutSz;
8999
    XMEMCPY(encDecIn.inData.buffer, in, inOutSz);
9000
9001
    /* CBC/ECB sizes are validated above as block-aligned. Stream modes
9002
     * (CFB/OFB/CTR) pass through the caller's length unchanged so the
9003
     * TPM-returned IV reflects exactly the bytes consumed. TPM_ALG_NULL
9004
     * (no symmetric algorithm) is forwarded to the TPM, which rejects
9005
     * it with TPM_RC_VALUE / TPM_RC_KEY per TPM 2.0 Part 3. */
9006
9007
    rc = TPM2_EncryptDecrypt2(&encDecIn, &encDecOut);
9008
    if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { /* some TPM's lack the command */
9009
        /* try to enable support */
9010
        rc = wolfTPM2_SetCommand(dev, TPM_CC_EncryptDecrypt2, YES);
9011
        if (rc == TPM_RC_SUCCESS) {
9012
            /* reset session auth for key */
9013
            wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
9014
9015
            /* try command again */
9016
            rc = TPM2_EncryptDecrypt2(&encDecIn, &encDecOut);
9017
        }
9018
    }
9019
9020
    if (rc != TPM_RC_SUCCESS) {
9021
    #ifdef DEBUG_WOLFTPM
9022
        printf("TPM2_EncryptDecrypt2 failed 0x%x: %s\n", rc,
9023
            TPM2_GetRCString(rc));
9024
    #endif
9025
        TPM2_ForceZero(&encDecIn, sizeof(encDecIn));
9026
        TPM2_ForceZero(&encDecOut, sizeof(encDecOut));
9027
        return rc;
9028
    }
9029
9030
    /* update IV */
9031
    if (iv) {
9032
        if (ivSz > encDecOut.ivOut.size)
9033
            ivSz = encDecOut.ivOut.size;
9034
        XMEMCPY(iv, encDecOut.ivOut.buffer, ivSz);
9035
    }
9036
9037
    /* return block */
9038
    if (inOutSz > encDecOut.outData.size)
9039
        inOutSz = encDecOut.outData.size;
9040
    XMEMCPY(out, encDecOut.outData.buffer, inOutSz);
9041
9042
    TPM2_ForceZero(&encDecIn, sizeof(encDecIn));
9043
    TPM2_ForceZero(&encDecOut, sizeof(encDecOut));
9044
    return rc;
9045
}
9046
9047
int wolfTPM2_EncryptDecrypt(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
9048
    const byte* in, byte* out, word32 inOutSz,
9049
    byte* iv, word32 ivSz, int isDecrypt)
9050
{
9051
    int rc = 0;
9052
    word32 pos = 0, xfer;
9053
9054
    while (pos < inOutSz) {
9055
        xfer = inOutSz - pos;
9056
        if (xfer > MAX_DIGEST_BUFFER)
9057
            xfer = MAX_DIGEST_BUFFER;
9058
9059
        rc = wolfTPM2_EncryptDecryptBlock(dev, key, &in[pos], &out[pos],
9060
            xfer, iv, ivSz, isDecrypt);
9061
        if (rc != TPM_RC_SUCCESS)
9062
            break;
9063
9064
        pos += xfer;
9065
    }
9066
9067
    if (rc != TPM_RC_SUCCESS && isDecrypt && pos > 0) {
9068
        TPM2_ForceZero(out, pos);
9069
    }
9070
9071
#ifdef DEBUG_WOLFTPM
9072
    printf("wolfTPM2_EncryptDecrypt: 0x%x: %s, %d bytes\n",
9073
        rc, TPM2_GetRCString(rc), inOutSz);
9074
#endif
9075
9076
    return rc;
9077
}
9078
9079
9080
int wolfTPM2_SetCommand(WOLFTPM2_DEV* dev, TPM_CC commandCode, int enableFlag)
9081
{
9082
    int rc = TPM_RC_COMMAND_CODE; /* not supported */
9083
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
9084
    if (TPM2_GetVendorID() == TPM_VENDOR_STM) {
9085
        SetCommandSet_In in;
9086
9087
        /* set blank platform auth */
9088
        wolfTPM2_SetAuthPassword(dev, 0, NULL);
9089
9090
        /* Enable commands (like TPM2_EncryptDecrypt2) */
9091
        XMEMSET(&in, 0, sizeof(in));
9092
        in.authHandle = TPM_RH_PLATFORM;
9093
        in.commandCode = commandCode;
9094
        in.enableFlag = enableFlag;
9095
        rc = TPM2_SetCommandSet(&in);
9096
        if (rc != TPM_RC_SUCCESS) {
9097
        #ifdef DEBUG_WOLFTPM
9098
            printf("TPM2_SetCommandSet failed 0x%x: %s\n", rc,
9099
                TPM2_GetRCString(rc));
9100
        #endif
9101
        }
9102
    }
9103
#else
9104
    (void)commandCode;
9105
    (void)enableFlag;
9106
#endif
9107
    (void)dev;
9108
    return rc;
9109
}
9110
9111
9112
9113
/* HMAC */
9114
int wolfTPM2_LoadKeyedHashKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
9115
    WOLFTPM2_HANDLE* parent, int hashAlg, const byte* keyBuf, word32 keySz,
9116
    const byte* usageAuth, word32 usageAuthSz)
9117
{
9118
    int rc;
9119
    Create_In  createIn;
9120
    Create_Out createOut;
9121
    Load_In  loadIn;
9122
    Load_Out loadOut;
9123
    int hashAlgDigSz;
9124
9125
    if (dev == NULL || key == NULL || parent == NULL || keyBuf == NULL) {
9126
        return BAD_FUNC_ARG;
9127
    }
9128
    if (keySz == 0 || keySz > MAX_SYM_DATA) {
9129
        return BUFFER_E;
9130
    }
9131
    if (usageAuth != NULL && usageAuthSz >
9132
            sizeof(createIn.inSensitive.sensitive.userAuth.buffer)) {
9133
        return BUFFER_E;
9134
    }
9135
9136
    hashAlgDigSz = TPM2_GetHashDigestSize(hashAlg);
9137
    if (hashAlgDigSz <= 0) {
9138
        return BAD_FUNC_ARG;
9139
    }
9140
9141
    /* clear output key buffer */
9142
    XMEMSET(key, 0, sizeof(WOLFTPM2_KEY));
9143
9144
    /* set session auth for parent key */
9145
    wolfTPM2_SetAuthHandle(dev, 0, parent);
9146
9147
    XMEMSET(&createIn, 0, sizeof(createIn));
9148
    createIn.parentHandle = parent->hndl;
9149
    if (usageAuth) {
9150
        createIn.inSensitive.sensitive.userAuth.size = usageAuthSz;
9151
        XMEMCPY(createIn.inSensitive.sensitive.userAuth.buffer, usageAuth,
9152
            usageAuthSz);
9153
    }
9154
    createIn.inSensitive.sensitive.data.size = keySz;
9155
    XMEMCPY(createIn.inSensitive.sensitive.data.buffer, keyBuf, keySz);
9156
9157
    rc = wolfTPM2_GetKeyTemplate_KeyedHash(&createIn.inPublic.publicArea,
9158
        hashAlg, YES, NO);
9159
    if (rc != 0) {
9160
        TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
9161
        return rc;
9162
    }
9163
9164
    rc = TPM2_Create(&createIn, &createOut);
9165
    if (rc != TPM_RC_SUCCESS) {
9166
    #ifdef DEBUG_WOLFTPM
9167
        printf("TPM2_Create key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
9168
    #endif
9169
        TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
9170
        return rc;
9171
    }
9172
9173
#ifdef DEBUG_WOLFTPM
9174
    printf("TPM2_Create key: pub %d, priv %d\n", createOut.outPublic.size,
9175
        createOut.outPrivate.size);
9176
    TPM2_PrintPublicArea(&createOut.outPublic);
9177
#endif
9178
    wolfTPM2_CopySymmetric(&key->handle.symmetric,
9179
            &createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
9180
    wolfTPM2_CopyPub(&key->pub, &createOut.outPublic);
9181
9182
    /* Load new key */
9183
    XMEMSET(&loadIn, 0, sizeof(loadIn));
9184
    loadIn.parentHandle = parent->hndl;
9185
    wolfTPM2_CopyPriv(&loadIn.inPrivate, &createOut.outPrivate);
9186
    wolfTPM2_CopyPub(&loadIn.inPublic, &key->pub);
9187
    rc = TPM2_Load(&loadIn, &loadOut);
9188
    if (rc != TPM_RC_SUCCESS) {
9189
    #ifdef DEBUG_WOLFTPM
9190
        printf("TPM2_Load key failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
9191
    #endif
9192
        TPM2_ForceZero(&createIn.inSensitive,
9193
            sizeof(createIn.inSensitive));
9194
        TPM2_ForceZero(&createOut, sizeof(createOut));
9195
        TPM2_ForceZero(&loadIn, sizeof(loadIn));
9196
        return rc;
9197
    }
9198
    key->handle.hndl = loadOut.objectHandle;
9199
    wolfTPM2_CopyAuth(&key->handle.auth,
9200
        &createIn.inSensitive.sensitive.userAuth);
9201
    wolfTPM2_CopyName(&key->handle.name, &loadOut.name);
9202
9203
#ifdef DEBUG_WOLFTPM
9204
    printf("wolfTPM2_LoadKeyedHashKey Key Handle 0x%x\n",
9205
        (word32)key->handle.hndl);
9206
#endif
9207
9208
    TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
9209
    TPM2_ForceZero(&createOut, sizeof(createOut));
9210
    TPM2_ForceZero(&loadIn, sizeof(loadIn));
9211
9212
    return rc;
9213
}
9214
9215
int wolfTPM2_HmacStart(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
9216
    WOLFTPM2_HANDLE* parent, TPMI_ALG_HASH hashAlg, const byte* keyBuf,
9217
    word32 keySz, const byte* usageAuth, word32 usageAuthSz)
9218
{
9219
    int rc;
9220
    int newKeyLoaded = 0;
9221
    int authSet = 0;
9222
    HMAC_Start_In in;
9223
    HMAC_Start_Out out;
9224
9225
    if (dev == NULL || hmac == NULL || hashAlg == TPM_ALG_NULL) {
9226
        return BAD_FUNC_ARG;
9227
    }
9228
    if (usageAuth != NULL &&
9229
            usageAuthSz > sizeof(hmac->hash.handle.auth.buffer)) {
9230
        return BUFFER_E;
9231
    }
9232
9233
    if (usageAuth != NULL) {
9234
        /* Capture usage auth, clearing any longer prior value first */
9235
        TPM2_ForceZero(hmac->hash.handle.auth.buffer,
9236
            sizeof(hmac->hash.handle.auth.buffer));
9237
        hmac->hash.handle.auth.size = usageAuthSz;
9238
        XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz);
9239
    }
9240
9241
    XMEMSET(&in, 0, sizeof(in));
9242
    if (!hmac->hmacKeyLoaded) {
9243
        if (hmac->key.handle.hndl == 0 || hmac->key.handle.hndl == TPM_RH_NULL){
9244
            /* Load Keyed Hash Key */
9245
            rc = wolfTPM2_LoadKeyedHashKey(dev, &hmac->key, parent, hashAlg,
9246
                keyBuf, keySz, usageAuth, usageAuthSz);
9247
            if (rc != 0) {
9248
                goto hmac_start_cleanup;
9249
            }
9250
            newKeyLoaded = 1;
9251
        }
9252
        hmac->hmacKeyLoaded = 1;
9253
    }
9254
9255
    /* set session auth for hmac key */
9256
    rc = wolfTPM2_SetAuthHandle(dev, 0, &hmac->hash.handle);
9257
    if (rc != TPM_RC_SUCCESS) {
9258
        goto hmac_start_cleanup;
9259
    }
9260
    authSet = 1;
9261
9262
    /* Setup HMAC start command */
9263
    in.handle = hmac->key.handle.hndl;
9264
    wolfTPM2_CopyAuth(&in.auth, &hmac->hash.handle.auth);
9265
    in.hashAlg = hashAlg;
9266
    rc = TPM2_HMAC_Start(&in, &out);
9267
    if (rc != TPM_RC_SUCCESS) {
9268
    #ifdef DEBUG_WOLFTPM
9269
        printf("TPM2_HMAC_Start failed 0x%x: %s\n", rc,
9270
            TPM2_GetRCString(rc));
9271
    #endif
9272
        goto hmac_start_cleanup;
9273
    }
9274
9275
    /* Capture hash sequence handle */
9276
    hmac->hash.handle.hndl = out.sequenceHandle;
9277
9278
#ifdef DEBUG_WOLFTPM
9279
    printf("wolfTPM2_HmacStart: Handle 0x%x\n",
9280
        (word32)out.sequenceHandle);
9281
#endif
9282
9283
    TPM2_ForceZero(&in.auth, sizeof(in.auth));
9284
    return rc;
9285
9286
hmac_start_cleanup:
9287
    TPM2_ForceZero(&in.auth, sizeof(in.auth));
9288
    TPM2_ForceZero(&hmac->hash.handle.auth,
9289
        sizeof(hmac->hash.handle.auth));
9290
    if (authSet) {
9291
        TPM2_ForceZero(&dev->session[0].auth,
9292
            sizeof(dev->session[0].auth));
9293
        dev->session[0].auth.size = 0;
9294
    }
9295
    if (newKeyLoaded) {
9296
        (void)wolfTPM2_UnloadHandle(dev, &hmac->key.handle);
9297
        if (hmac->key.handle.hndl == 0 ||
9298
                hmac->key.handle.hndl == TPM_RH_NULL) {
9299
            hmac->hmacKeyLoaded = 0;
9300
        }
9301
        /* FlushContext does not require object authorization. */
9302
        TPM2_ForceZero(&hmac->key.handle.auth,
9303
            sizeof(hmac->key.handle.auth));
9304
    }
9305
    return rc;
9306
}
9307
9308
int wolfTPM2_HmacUpdate(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
9309
    const byte* data, word32 dataSz)
9310
{
9311
    if (dev == NULL || hmac == NULL) {
9312
        return BAD_FUNC_ARG;
9313
    }
9314
9315
    return wolfTPM2_HashUpdate(dev, &hmac->hash, data, dataSz);
9316
}
9317
9318
int wolfTPM2_HmacFinish(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
9319
    byte* digest, word32* digestSz)
9320
{
9321
    int rc;
9322
9323
    if (dev == NULL || hmac == NULL) {
9324
        return BAD_FUNC_ARG;
9325
    }
9326
9327
    rc = wolfTPM2_HashFinish(dev, &hmac->hash, digest, digestSz);
9328
9329
    if (!hmac->hmacKeyKeep) {
9330
        /* unload HMAC key */
9331
        (void)wolfTPM2_UnloadHandle(dev, &hmac->key.handle);
9332
        if (hmac->key.handle.hndl == 0 ||
9333
                hmac->key.handle.hndl == TPM_RH_NULL) {
9334
            hmac->hmacKeyLoaded = 0;
9335
        }
9336
        if (hmac->hash.handle.hndl == 0 ||
9337
                hmac->hash.handle.hndl == TPM_RH_NULL) {
9338
            TPM2_ForceZero(&hmac->hash.handle.auth,
9339
                sizeof(hmac->hash.handle.auth));
9340
        }
9341
        TPM2_ForceZero(&hmac->key.handle.auth,
9342
            sizeof(hmac->key.handle.auth));
9343
    }
9344
9345
    return rc;
9346
}
9347
9348
/* performs a reset, shutdown, or startup sequence */
9349
int wolfTPM2_Reset(WOLFTPM2_DEV* dev, int doShutdown, int doStartup)
9350
{
9351
    int rc = TPM_RC_SUCCESS;
9352
#if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_WINAPI)
9353
    Shutdown_In shutdownIn;
9354
    Startup_In startupIn;
9355
#endif
9356
9357
    if (dev == NULL) {
9358
        return BAD_FUNC_ARG;
9359
    }
9360
9361
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_WINAPI)
9362
    /* The kernel driver and Windows TBS own TPM startup state, as they own the
9363
     * locality (see wolfTPM2_SetLocality, which returns NOT_COMPILED_IN here
9364
     * for the same reason). On the shared /dev/tpmrm0 a TPM_SU_CLEAR from one
9365
     * caller would hit every other process using the TPM, and the kernel does
9366
     * not block it - on Linux 5.15 it passes through and succeeds. */
9367
    if (doShutdown == 0 && doStartup == 0) {
9368
        /* nothing was asked for, so nothing was declined */
9369
        rc = TPM_RC_SUCCESS;
9370
    }
9371
    else {
9372
        rc = NOT_COMPILED_IN;
9373
    }
9374
#else
9375
9376
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
9377
    /* Autodetect resolved to the kernel driver, which owns startup as above.
9378
     * Clear both requests so the common tail still runs, and only report a
9379
     * decline if something was actually requested. */
9380
    if (dev->ctx.fd >= 0) {
9381
        if (doShutdown == 1 || doStartup == 1) {
9382
            rc = NOT_COMPILED_IN;
9383
        }
9384
        doShutdown = 0;
9385
        doStartup = 0;
9386
    }
9387
#endif
9388
9389
    /* shutdown */
9390
    if (doShutdown == 1) {
9391
        XMEMSET(&shutdownIn, 0, sizeof(shutdownIn));
9392
        shutdownIn.shutdownType = TPM_SU_CLEAR;
9393
        rc = TPM2_Shutdown(&shutdownIn);
9394
        if (rc != TPM_RC_SUCCESS) {
9395
        #ifdef DEBUG_WOLFTPM
9396
            printf("TPM2_Shutdown failed 0x%x: %s\n",
9397
                rc, TPM2_GetRCString(rc));
9398
        #endif
9399
        }
9400
    }
9401
9402
    /* startup */
9403
    if (doStartup == 1 && rc == TPM_RC_SUCCESS) {
9404
        XMEMSET(&startupIn, 0, sizeof(startupIn));
9405
        startupIn.startupType = TPM_SU_CLEAR;
9406
        rc = TPM2_Startup(&startupIn);
9407
        if (rc != TPM_RC_SUCCESS) {
9408
        #ifdef DEBUG_WOLFTPM
9409
            printf("TPM2_Startup failed %d: %s\n",
9410
                rc, wolfTPM2_GetRCString(rc));
9411
        #endif
9412
        }
9413
    }
9414
#endif /* !WOLFTPM_LINUX_DEV && !WOLFTPM_WINAPI */
9415
9416
#ifdef DEBUG_WOLFTPM
9417
    printf("wolfTPM2_Reset complete\n");
9418
#endif
9419
9420
    return rc;
9421
}
9422
9423
/* performs a shutdown or reset sequence */
9424
int wolfTPM2_Shutdown(WOLFTPM2_DEV* dev, int doStartup)
9425
{
9426
    return wolfTPM2_Reset(dev, 1, doStartup);
9427
}
9428
9429
int wolfTPM2_UnloadHandles(WOLFTPM2_DEV* dev, word32 handleStart,
9430
    word32 handleCount)
9431
{
9432
    int rc = TPM_RC_SUCCESS;
9433
    word32 i;
9434
    WOLFTPM2_HANDLE handle;
9435
    if (dev == NULL) {
9436
        return BAD_FUNC_ARG;
9437
    }
9438
    if (handleCount != 0 && handleStart > (word32)0xFFFFFFFF - (handleCount - 1)) {
9439
        return BAD_FUNC_ARG;
9440
    }
9441
    XMEMSET(&handle, 0, sizeof(handle));
9442
    wolfTPM2_CopyAuth(&handle.auth, &dev->session[0].auth);
9443
9444
    for (i = 0; i < handleCount; i++) {
9445
        handle.hndl = handleStart + i;
9446
        /* ignore return code failures */
9447
        (void)wolfTPM2_UnloadHandle(dev, &handle);
9448
    }
9449
    TPM2_ForceZero(&handle, sizeof(handle));
9450
    return rc;
9451
}
9452
9453
int wolfTPM2_UnloadHandles_AllTransient(WOLFTPM2_DEV* dev)
9454
{
9455
    int rc;
9456
    int flushRc;
9457
    int firstFlushRc = TPM_RC_SUCCESS;
9458
    word32 i;
9459
    TPM_HANDLE next = TRANSIENT_FIRST;
9460
    GetCapability_In  in;
9461
    GetCapability_Out out;
9462
    TPML_HANDLE* handles = &out.capabilityData.data.handles;
9463
    WOLFTPM2_HANDLE handle;
9464
9465
    if (dev == NULL) {
9466
        return BAD_FUNC_ARG;
9467
    }
9468
9469
    /* flush only the handles the TPM reports as loaded */
9470
    XMEMSET(&handle, 0, sizeof(handle));
9471
    wolfTPM2_CopyAuth(&handle.auth, &dev->session[0].auth);
9472
    for (;;) {
9473
        XMEMSET(&in, 0, sizeof(in));
9474
        in.capability = TPM_CAP_HANDLES;
9475
        in.property = next;
9476
        in.propertyCount = MAX_CAP_HANDLES;
9477
        rc = TPM2_GetCapability(&in, &out);
9478
        if (rc == TPM_RC_SUCCESS &&
9479
                out.capabilityData.capability != TPM_CAP_HANDLES) {
9480
            rc = TPM_RC_FAILURE;
9481
        }
9482
        if (rc != TPM_RC_SUCCESS) {
9483
            break;
9484
        }
9485
        for (i = 0; i < handles->count; i++) {
9486
            if (handles->handle[i] < next ||
9487
                    (handles->handle[i] & HR_RANGE_MASK) != HR_TRANSIENT) {
9488
                break;
9489
            }
9490
            next = handles->handle[i] + 1;
9491
            handle.hndl = handles->handle[i];
9492
            flushRc = wolfTPM2_UnloadHandle(dev, &handle);
9493
            if (flushRc != TPM_RC_SUCCESS && firstFlushRc == TPM_RC_SUCCESS) {
9494
                firstFlushRc = flushRc;
9495
            }
9496
        }
9497
        /* continue only after a non-empty page of ascending transient
9498
         * handles that reports more data */
9499
        if (!out.moreData || handles->count == 0 || i < handles->count) {
9500
            break;
9501
        }
9502
    }
9503
    TPM2_ForceZero(&handle, sizeof(handle));
9504
9505
    /* The fixed range ignores individual flush results, so it cannot confirm
9506
     * anything was unloaded: try it, but report that discovery failed. */
9507
    if (rc != TPM_RC_SUCCESS && next == TRANSIENT_FIRST) {
9508
        (void)wolfTPM2_UnloadHandles(dev, TRANSIENT_FIRST, MAX_HANDLE_NUM);
9509
    }
9510
    return (rc != TPM_RC_SUCCESS) ? rc : firstFlushRc;
9511
}
9512
9513
int wolfTPM2_ChangeHierarchyAuth(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
9514
    TPMI_RH_HIERARCHY_AUTH authHandle)
9515
{
9516
    int rc = 0;
9517
    HierarchyChangeAuth_In in;
9518
#ifdef DEBUG_WOLFTPM
9519
    const char* desc = NULL;
9520
#endif
9521
9522
    if (dev == NULL) {
9523
        return BAD_FUNC_ARG;
9524
    }
9525
9526
    XMEMSET(&in, 0, sizeof(in));
9527
    in.authHandle = authHandle;
9528
9529
    /* use parameter encryption if session supplied */
9530
    if (session != NULL) {
9531
        rc = wolfTPM2_SetAuthSession(dev, 1, session, (TPMA_SESSION_decrypt |
9532
            TPMA_SESSION_encrypt | TPMA_SESSION_continueSession));
9533
    }
9534
    if (rc == 0) {
9535
        /* TPM 2.0 PCR's are typically SHA-1 and SHA2-256 */
9536
        in.newAuth.size = (UINT16)TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST);
9537
        if (in.newAuth.size == 0) {
9538
            rc = BAD_FUNC_ARG;
9539
        }
9540
    }
9541
    if (rc == 0) {
9542
        rc = TPM2_GetNonceNoLock(in.newAuth.buffer, in.newAuth.size);
9543
    }
9544
    if (rc == 0) {
9545
        rc = TPM2_HierarchyChangeAuth(&in);
9546
    }
9547
#ifdef DEBUG_WOLFTPM
9548
    desc = TPM2_GetHierarchyDesc(authHandle);
9549
9550
    if (rc == 0) {
9551
        printf("%s auth set to %d bytes of random\n", desc, in.newAuth.size);
9552
        #ifdef WOLFTPM_DEBUG_VERBOSE
9553
            printf("\tAuth Sz %d\n", in.newAuth.size);
9554
            #ifdef WOLFTPM_DEBUG_SECRETS
9555
                TPM2_PrintBin(in.newAuth.buffer, in.newAuth.size);
9556
            #endif
9557
        #endif
9558
    } else {
9559
        printf("Error %d setting %s auth! %s\n",
9560
            rc, desc, wolfTPM2_GetRCString(rc));
9561
    }
9562
#endif
9563
    /* ensure the random secret is not left in stack */
9564
    TPM2_ForceZero(in.newAuth.buffer, in.newAuth.size);
9565
    return rc;
9566
}
9567
9568
int wolfTPM2_ChangePlatformAuth(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session)
9569
{
9570
    return wolfTPM2_ChangeHierarchyAuth(dev, session, TPM_RH_PLATFORM);
9571
}
9572
9573
/******************************************************************************/
9574
/* --- END Wrapper Device Functions-- */
9575
/******************************************************************************/
9576
9577
9578
/******************************************************************************/
9579
/* --- BEGIN Utility Functions -- */
9580
/******************************************************************************/
9581
9582
int GetKeyTemplateRSA(TPMT_PUBLIC* publicTemplate,
9583
    TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, int keyBits, long exponent,
9584
    TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
9585
{
9586
    if (publicTemplate == NULL)
9587
        return BAD_FUNC_ARG;
9588
9589
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
9590
    publicTemplate->type = TPM_ALG_RSA;
9591
    publicTemplate->unique.rsa.size = keyBits / 8;
9592
    publicTemplate->nameAlg = nameAlg;
9593
    publicTemplate->objectAttributes = objectAttributes;
9594
    publicTemplate->parameters.rsaDetail.keyBits = keyBits;
9595
    publicTemplate->parameters.rsaDetail.exponent = (UINT32)exponent;
9596
    publicTemplate->parameters.rsaDetail.scheme.scheme = sigScheme;
9597
    publicTemplate->parameters.rsaDetail.scheme.details.anySig.hashAlg = sigHash;
9598
    /* For restricted decryption key enable symmetric */
9599
    if ((objectAttributes & TPMA_OBJECT_decrypt) &&
9600
        (objectAttributes & TPMA_OBJECT_restricted)) {
9601
        publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
9602
        publicTemplate->parameters.rsaDetail.symmetric.keyBits.aes =
9603
            (keyBits > 2048) ? 256 : 128;
9604
        publicTemplate->parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
9605
    }
9606
    else {
9607
        publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
9608
    }
9609
9610
    return TPM_RC_SUCCESS;
9611
}
9612
9613
int GetKeyTemplateECC(TPMT_PUBLIC* publicTemplate,
9614
    TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve,
9615
    TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
9616
{
9617
    int curveSz;
9618
9619
    if (publicTemplate == NULL)
9620
        return BAD_FUNC_ARG;
9621
9622
#ifdef NO_ECC256
9623
    /* P256 compiled out; substitute an enabled curve (availability-driven, all
9624
     * callers) since the build cannot honor P256. */
9625
    if (curve == TPM_ECC_NIST_P256) {
9626
        curve = WOLFTPM2_ECC_DEFAULT_CURVE;
9627
        nameAlg = TPM2_GetCurveHashAlg(curve);
9628
        if (sigHash != TPM_ALG_NULL)
9629
            sigHash = nameAlg;
9630
    }
9631
#endif
9632
9633
    /* Compute curve size after any substitution so coordinate sizes and the
9634
     * AES wrap strength below match the curve actually used. */
9635
    curveSz = TPM2_GetCurveSize(curve);
9636
    if (curveSz == 0)
9637
        return BAD_FUNC_ARG;
9638
9639
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
9640
    publicTemplate->type = TPM_ALG_ECC;
9641
    publicTemplate->nameAlg = nameAlg;
9642
    publicTemplate->unique.ecc.x.size = curveSz;
9643
    publicTemplate->unique.ecc.y.size = curveSz;
9644
    publicTemplate->objectAttributes = objectAttributes;
9645
    /* For restricted decryption key enable symmetric */
9646
    if ((objectAttributes & TPMA_OBJECT_decrypt) &&
9647
        (objectAttributes & TPMA_OBJECT_restricted)) {
9648
        publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
9649
        publicTemplate->parameters.eccDetail.symmetric.keyBits.aes =
9650
            (curveSz >= 48) ? 256 : 128;
9651
        publicTemplate->parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
9652
    }
9653
    else {
9654
        publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
9655
    }
9656
    /* TPM_ALG_ECDSA or TPM_ALG_ECDH */
9657
    publicTemplate->parameters.eccDetail.scheme.scheme = sigScheme;
9658
    publicTemplate->parameters.eccDetail.scheme.details.ecdsa.hashAlg = sigHash;
9659
    publicTemplate->parameters.eccDetail.curveID = curve;
9660
    publicTemplate->parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
9661
9662
    return TPM_RC_SUCCESS;
9663
}
9664
9665
int wolfTPM2_GetKeyTemplate_RSA_ex(TPMT_PUBLIC* publicTemplate,
9666
    TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, int keyBits, long exponent,
9667
    TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
9668
{
9669
    return GetKeyTemplateRSA(publicTemplate, nameAlg,
9670
        objectAttributes, keyBits, exponent, sigScheme, sigHash);
9671
}
9672
9673
int wolfTPM2_GetKeyTemplate_RSA(TPMT_PUBLIC* publicTemplate,
9674
    TPMA_OBJECT objectAttributes)
9675
{
9676
    return GetKeyTemplateRSA(publicTemplate, WOLFTPM2_WRAP_DIGEST,
9677
        objectAttributes, WOLFTPM2_WRAP_RSA_KEY_BITS, WOLFTPM2_WRAP_RSA_EXPONENT,
9678
        TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST);
9679
}
9680
9681
/* Resolve a P256 "use the library default" request to the build-configured
9682
 * WOLFTPM2_ECC_DEFAULT_CURVE, pairing the name/sig hash via TPM2_GetCurveHashAlg.
9683
 * No-op when the default is P256 (the shipped default). Used only by the
9684
 * no-explicit-curve named templates (SRK/AIK) so a build can make P384 the
9685
 * default - e.g. wolfTPM2_CreateSRK(TPM_ALG_ECC). The explicit-curve APIs
9686
 * (_ECC/_ex, EK, IAK/IDevID) and the crypto callback honor the exact curve. */
9687
static void wolfTPM2_ResolveDefaultEccCurve(TPM_ECC_CURVE* curve,
9688
    TPM_ALG_ID* nameAlg, TPM_ALG_ID* sigHash)
9689
{
9690
    if (*curve == TPM_ECC_NIST_P256 &&
9691
            WOLFTPM2_ECC_DEFAULT_CURVE != TPM_ECC_NIST_P256) {
9692
        *curve = WOLFTPM2_ECC_DEFAULT_CURVE;
9693
        if (nameAlg != NULL)
9694
            *nameAlg = TPM2_GetCurveHashAlg(*curve);
9695
        if (sigHash != NULL && *sigHash != TPM_ALG_NULL)
9696
            *sigHash = TPM2_GetCurveHashAlg(*curve);
9697
    }
9698
}
9699
9700
int wolfTPM2_GetKeyTemplate_ECC_ex(TPMT_PUBLIC* publicTemplate,
9701
    TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve,
9702
    TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash)
9703
{
9704
    /* Explicit-curve API: the requested curve is honored exactly (an explicit
9705
     * P256 is NOT remapped to WOLFTPM2_ECC_DEFAULT_CURVE - protocol-bound
9706
     * callers such as ECDH depend on the exact curve). */
9707
    return GetKeyTemplateECC(publicTemplate, nameAlg,
9708
        objectAttributes, curve, sigScheme, sigHash);
9709
}
9710
9711
int wolfTPM2_GetKeyTemplate_ECC(TPMT_PUBLIC* publicTemplate,
9712
    TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme)
9713
{
9714
    /* Explicit-curve API: the requested curve is honored exactly. */
9715
    return GetKeyTemplateECC(publicTemplate, WOLFTPM2_WRAP_DIGEST,
9716
        objectAttributes, curve, sigScheme, WOLFTPM2_WRAP_DIGEST);
9717
}
9718
9719
int wolfTPM2_GetKeyTemplate_Symmetric(TPMT_PUBLIC* publicTemplate, int keyBits,
9720
    TPM_ALG_ID algMode, int isSign, int isDecrypt)
9721
{
9722
    if (publicTemplate == NULL)
9723
        return BAD_FUNC_ARG;
9724
9725
#ifdef WOLFTPM_MICROCHIP
9726
    isSign = 0; /* Microchip TPM does not like "sign" set for symmetric keys */
9727
#endif
9728
9729
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
9730
    publicTemplate->type = TPM_ALG_SYMCIPHER;
9731
    publicTemplate->nameAlg = WOLFTPM2_WRAP_DIGEST;
9732
    publicTemplate->unique.sym.size = keyBits / 8;
9733
    publicTemplate->objectAttributes = (
9734
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
9735
        TPMA_OBJECT_noDA | (isSign ? TPMA_OBJECT_sign : 0) |
9736
        (isDecrypt ? TPMA_OBJECT_decrypt : 0));
9737
    publicTemplate->parameters.symDetail.sym.algorithm = TPM_ALG_AES;
9738
    publicTemplate->parameters.symDetail.sym.keyBits.sym = keyBits;
9739
    publicTemplate->parameters.symDetail.sym.mode.sym = algMode;
9740
9741
    return TPM_RC_SUCCESS;
9742
}
9743
9744
int wolfTPM2_GetKeyTemplate_KeyedHash(TPMT_PUBLIC* publicTemplate,
9745
    TPM_ALG_ID hashAlg, int isSign, int isDecrypt)
9746
{
9747
    if (publicTemplate == NULL)
9748
        return BAD_FUNC_ARG;
9749
9750
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
9751
    publicTemplate->type = TPM_ALG_KEYEDHASH;
9752
    publicTemplate->nameAlg = WOLFTPM2_WRAP_DIGEST;
9753
    publicTemplate->objectAttributes = (
9754
        TPMA_OBJECT_userWithAuth |
9755
        TPMA_OBJECT_noDA |
9756
        (isSign ? TPMA_OBJECT_sign : 0) |
9757
        (isDecrypt ? TPMA_OBJECT_decrypt : 0));
9758
    /* HMAC scheme requires the sign attribute. When the caller asks for
9759
     * neither sign nor decrypt, treat this as a data/seal-style keyed-hash
9760
     * object and use TPM_ALG_NULL so the template is loadable and not
9761
     * stuck with an unusable HMAC binding. */
9762
    if (isSign || isDecrypt) {
9763
        publicTemplate->parameters.keyedHashDetail.scheme.scheme =
9764
            TPM_ALG_HMAC;
9765
        publicTemplate->parameters.keyedHashDetail.scheme.details.hmac.hashAlg
9766
            = hashAlg;
9767
    }
9768
    else {
9769
        publicTemplate->parameters.keyedHashDetail.scheme.scheme =
9770
            TPM_ALG_NULL;
9771
    }
9772
    return TPM_RC_SUCCESS;
9773
}
9774
9775
int wolfTPM2_GetKeyTemplate_KeySeal(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID nameAlg)
9776
{
9777
    if (publicTemplate == NULL)
9778
        return BAD_FUNC_ARG;
9779
    /* Seal Object can be only of type KEYEDHASH and can not be used for
9780
     * signing or encryption. Hash algorithm can be chosen by the developer.
9781
     */
9782
    XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC));
9783
    publicTemplate->type = TPM_ALG_KEYEDHASH;
9784
    publicTemplate->nameAlg = nameAlg;
9785
    publicTemplate->objectAttributes = (
9786
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
9787
        TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA);
9788
    publicTemplate->parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
9789
    return TPM_RC_SUCCESS;
9790
}
9791
9792
int wolfTPM2_GetKeyTemplate_EK(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID alg,
9793
    int keyBits, TPM_ECC_CURVE curveID, TPM_ALG_ID nameAlg, int highRange)
9794
{
9795
    int rc;
9796
    TPMA_OBJECT objectAttributes = (
9797
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
9798
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_adminWithPolicy |
9799
        TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt);
9800
    if (highRange) {
9801
        /* High range requires userWithAuth=1 */
9802
        objectAttributes |= TPMA_OBJECT_userWithAuth;
9803
    }
9804
9805
    if (alg == TPM_ALG_RSA) {
9806
        rc = GetKeyTemplateRSA(publicTemplate, nameAlg,
9807
            objectAttributes, keyBits, 0, TPM_ALG_NULL, TPM_ALG_NULL);
9808
        if (rc == 0 && highRange) { /* high range uses 0 unique size */
9809
            publicTemplate->unique.rsa.size = 0;
9810
        }
9811
    }
9812
    else if (alg == TPM_ALG_ECC) {
9813
        rc = GetKeyTemplateECC(publicTemplate, nameAlg,
9814
            objectAttributes, curveID, TPM_ALG_NULL, TPM_ALG_NULL);
9815
        if (rc == 0 && highRange) { /* high range uses 0 unique size */
9816
            publicTemplate->unique.ecc.x.size = 0;
9817
            publicTemplate->unique.ecc.y.size = 0;
9818
        }
9819
9820
    }
9821
    else {
9822
        rc = BAD_FUNC_ARG; /* not supported */
9823
    }
9824
9825
    if (rc == 0) {
9826
        /* Select the auth policy from the resolved publicTemplate->nameAlg, not
9827
         * the local nameAlg: under NO_ECC256 GetKeyTemplateECC may have
9828
         * substituted the curve and rewritten nameAlg to the paired hash, and
9829
         * the policy must match the name hash actually used. */
9830
        TPM_ALG_ID policyNameAlg = publicTemplate->nameAlg;
9831
        if (policyNameAlg == TPM_ALG_SHA256 && !highRange) {
9832
            publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY);
9833
            XMEMCPY(publicTemplate->authPolicy.buffer,
9834
                TPM_20_EK_AUTH_POLICY, publicTemplate->authPolicy.size);
9835
        }
9836
        else if (policyNameAlg == TPM_ALG_SHA256) {
9837
            publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY_SHA256);
9838
            XMEMCPY(publicTemplate->authPolicy.buffer,
9839
                TPM_20_EK_AUTH_POLICY_SHA256, publicTemplate->authPolicy.size);
9840
        }
9841
    #ifdef WOLFSSL_SHA384
9842
        else if (policyNameAlg == TPM_ALG_SHA384) {
9843
            publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY_SHA384);
9844
            XMEMCPY(publicTemplate->authPolicy.buffer,
9845
                TPM_20_EK_AUTH_POLICY_SHA384, publicTemplate->authPolicy.size);
9846
        }
9847
    #endif
9848
    #ifdef WOLFSSL_SHA512
9849
        else if (policyNameAlg == TPM_ALG_SHA512) {
9850
            publicTemplate->authPolicy.size = sizeof(TPM_20_EK_AUTH_POLICY_SHA512);
9851
            XMEMCPY(publicTemplate->authPolicy.buffer,
9852
                TPM_20_EK_AUTH_POLICY_SHA512, publicTemplate->authPolicy.size);
9853
        }
9854
    #endif
9855
    }
9856
9857
    return rc;
9858
}
9859
9860
int wolfTPM2_GetKeyTemplate_EKIndex(word32 nvIndex,
9861
    TPMT_PUBLIC* publicTemplate)
9862
{
9863
    TPM_ALG_ID alg = TPM_ALG_NULL;
9864
    TPM_ALG_ID nameAlg = TPM_ALG_NULL;
9865
    TPM_ECC_CURVE curveID = TPM_ECC_NONE;
9866
    uint32_t keyBits = 0;
9867
    int highRange = 0;
9868
    word32 offset;
9869
9870
    /* Validate index is in TCG NV space */
9871
    if (nvIndex < TPM_20_TCG_NV_SPACE ||
9872
        nvIndex > TPM_20_TCG_NV_SPACE + 0x7FFF) {
9873
        return BAD_FUNC_ARG;
9874
    }
9875
9876
    offset = nvIndex - TPM_20_TCG_NV_SPACE;
9877
9878
    /* Reject indices in dead zones that cannot produce valid templates:
9879
     * - Between High Range (0x1FF) and Policy Indices (0x7F01)
9880
     * - After Policy Indices (0x7F04) */
9881
    if ((offset > 0x1FF && offset < 0x7F01) || offset > 0x7F04) {
9882
        return BAD_FUNC_ARG;
9883
    }
9884
9885
    /* determine if low or high range */
9886
    if (nvIndex >= TPM2_NV_EK_RSA2048) {
9887
        highRange = 1;
9888
    }
9889
9890
    /* Determine algorithm based on index */
9891
    switch (nvIndex) {
9892
        case TPM2_NV_RSA_EK_CERT: /* EK (Low Range): RSA 2048 */
9893
        case TPM2_NV_EK_RSA2048:  /* EK (High Range) */
9894
            alg = TPM_ALG_RSA;
9895
            nameAlg = TPM_ALG_SHA256;
9896
            keyBits = 2048;
9897
            break;
9898
        case TPM2_NV_EK_RSA3072:
9899
            alg = TPM_ALG_RSA;
9900
            nameAlg = TPM_ALG_SHA384;
9901
            keyBits = 3072;
9902
            break;
9903
        case TPM2_NV_EK_RSA4096:
9904
            alg = TPM_ALG_RSA;
9905
            nameAlg = TPM_ALG_SHA512;
9906
            keyBits = 4096;
9907
            break;
9908
        case TPM2_NV_ECC_EK_CERT: /* EK (Low Range): ECC P256 */
9909
        case TPM2_NV_EK_ECC_P256: /* EK (High Range) */
9910
            alg = TPM_ALG_ECC;
9911
            curveID = TPM_ECC_NIST_P256;
9912
            nameAlg = TPM_ALG_SHA256;
9913
            keyBits = 256;
9914
            break;
9915
        case TPM2_NV_EK_ECC_P384:
9916
            alg = TPM_ALG_ECC;
9917
            curveID = TPM_ECC_NIST_P384;
9918
            nameAlg = TPM_ALG_SHA384;
9919
            keyBits = 384;
9920
            break;
9921
        case TPM2_NV_EK_ECC_P521:
9922
            alg = TPM_ALG_ECC;
9923
            curveID = TPM_ECC_NIST_P521;
9924
            nameAlg = TPM_ALG_SHA512;
9925
            keyBits = 521;
9926
            break;
9927
        case TPM2_NV_EK_ECC_SM2:
9928
            alg = TPM_ALG_SM2;
9929
            curveID = TPM_ECC_SM2_P256;
9930
            nameAlg = TPM_ALG_SHA256;
9931
            keyBits = 256;
9932
            break;
9933
        default:
9934
            alg = TPM_ALG_NULL;
9935
            curveID = TPM_ECC_NONE;
9936
            nameAlg = TPM_ALG_NULL;
9937
            keyBits = 0;
9938
            break;
9939
    }
9940
9941
    return wolfTPM2_GetKeyTemplate_EK(publicTemplate, alg, keyBits, curveID,
9942
            nameAlg, highRange);
9943
}
9944
9945
int wolfTPM2_GetKeyTemplate_RSA_EK(TPMT_PUBLIC* publicTemplate)
9946
{
9947
    return wolfTPM2_GetKeyTemplate_EK(publicTemplate, TPM_ALG_RSA, 2048,
9948
        TPM_ALG_NULL, TPM_ALG_SHA256, 0);
9949
}
9950
9951
int wolfTPM2_GetKeyTemplate_ECC_EK(TPMT_PUBLIC* publicTemplate)
9952
{
9953
    return wolfTPM2_GetKeyTemplate_EK(publicTemplate, TPM_ALG_ECC, 256,
9954
        TPM_ECC_NIST_P256, TPM_ALG_SHA256, 0);
9955
}
9956
9957
int wolfTPM2_GetKeyTemplate_RSA_SRK(TPMT_PUBLIC* publicTemplate)
9958
{
9959
    TPMA_OBJECT objectAttributes = (
9960
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
9961
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
9962
        TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA);
9963
9964
    return GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256,
9965
        objectAttributes, 2048, 0, TPM_ALG_NULL, TPM_ALG_NULL);
9966
}
9967
9968
int wolfTPM2_GetKeyTemplate_ECC_SRK(TPMT_PUBLIC* publicTemplate)
9969
{
9970
    TPM_ECC_CURVE curve = TPM_ECC_NIST_P256;
9971
    TPM_ALG_ID nameAlg = TPM_ALG_SHA256;
9972
    TPMA_OBJECT objectAttributes = (
9973
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
9974
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
9975
        TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA);
9976
9977
    /* Storage primary defaults to P256 but follows WOLFTPM2_ECC_DEFAULT_CURVE. */
9978
    wolfTPM2_ResolveDefaultEccCurve(&curve, &nameAlg, NULL);
9979
    return GetKeyTemplateECC(publicTemplate, nameAlg,
9980
        objectAttributes, curve, TPM_ALG_NULL, TPM_ALG_NULL);
9981
}
9982
9983
int wolfTPM2_GetKeyTemplate_RSA_AIK(TPMT_PUBLIC* publicTemplate)
9984
{
9985
    int ret;
9986
    TPMA_OBJECT objectAttributes = (
9987
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
9988
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
9989
        TPMA_OBJECT_restricted | TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
9990
9991
    ret = GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256,
9992
        objectAttributes, 2048, 0, TPM_ALG_RSASSA, TPM_ALG_SHA256);
9993
    if (ret == 0) {
9994
        publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
9995
    }
9996
    return ret;
9997
}
9998
9999
int wolfTPM2_GetKeyTemplate_ECC_AIK(TPMT_PUBLIC* publicTemplate)
10000
{
10001
    int ret;
10002
    TPM_ECC_CURVE curve = TPM_ECC_NIST_P256;
10003
    TPM_ALG_ID nameAlg = TPM_ALG_SHA256;
10004
    TPM_ALG_ID sigHash = TPM_ALG_SHA256;
10005
    TPMA_OBJECT objectAttributes = (
10006
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
10007
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
10008
        TPMA_OBJECT_restricted | TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
10009
10010
    /* Attestation signing key defaults to P256 but follows the configured
10011
     * default curve. */
10012
    wolfTPM2_ResolveDefaultEccCurve(&curve, &nameAlg, &sigHash);
10013
    ret = GetKeyTemplateECC(publicTemplate, nameAlg,
10014
        objectAttributes, curve, TPM_ALG_ECDSA, sigHash);
10015
    if (ret == 0) {
10016
        publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
10017
    }
10018
    return ret;
10019
}
10020
10021
#ifdef WOLFTPM_PROVISIONING
10022
static int wolfTPM2_SetKeyTemplate_IAK(TPMT_PUBLIC* publicTemplate,
10023
    TPM_ALG_ID hashAlg)
10024
{
10025
    int ret = 0;
10026
    if (hashAlg == TPM_ALG_SHA256) {
10027
        publicTemplate->authPolicy.size = sizeof(TPM_20_IAK_POLICY);
10028
        XMEMCPY(publicTemplate->authPolicy.buffer,
10029
            TPM_20_IAK_POLICY, publicTemplate->authPolicy.size);
10030
    }
10031
#ifdef WOLFSSL_SHA384
10032
    else if (hashAlg == TPM_ALG_SHA384) {
10033
        publicTemplate->authPolicy.size = sizeof(TPM_20_IAK_POLICY_SHA384);
10034
        XMEMCPY(publicTemplate->authPolicy.buffer,
10035
            TPM_20_IAK_POLICY_SHA384, publicTemplate->authPolicy.size);
10036
    }
10037
#endif
10038
#ifdef WOLFSSL_SHA512
10039
    else if (hashAlg == TPM_ALG_SHA512) {
10040
        publicTemplate->authPolicy.size = sizeof(TPM_20_IAK_POLICY_SHA512);
10041
        XMEMCPY(publicTemplate->authPolicy.buffer,
10042
            TPM_20_IAK_POLICY_SHA512, publicTemplate->authPolicy.size);
10043
    }
10044
#endif
10045
    else {
10046
        ret = BAD_FUNC_ARG;
10047
    }
10048
    if (ret == 0) {
10049
        const char* IAKStr = "IAK";
10050
        ret = wolfTPM2_SetKeyTemplate_Unique(publicTemplate,
10051
            (const byte*)IAKStr, (int)XSTRLEN(IAKStr));
10052
    }
10053
    return ret;
10054
}
10055
10056
int wolfTPM2_GetKeyTemplate_RSA_IAK(TPMT_PUBLIC* publicTemplate, int keyBits,
10057
    TPM_ALG_ID hashAlg)
10058
{
10059
    int ret;
10060
    TPMA_OBJECT objectAttributes = (
10061
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
10062
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
10063
        TPMA_OBJECT_adminWithPolicy | TPMA_OBJECT_restricted |
10064
        TPMA_OBJECT_sign);
10065
10066
    ret = GetKeyTemplateRSA(publicTemplate, hashAlg,
10067
        objectAttributes, keyBits, 0, TPM_ALG_RSASSA, hashAlg);
10068
    if (ret == 0) {
10069
        publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
10070
        ret = wolfTPM2_SetKeyTemplate_IAK(publicTemplate, hashAlg);
10071
    }
10072
    return ret;
10073
}
10074
int wolfTPM2_GetKeyTemplate_ECC_IAK(TPMT_PUBLIC* publicTemplate,
10075
    TPM_ECC_CURVE curveID, TPM_ALG_ID hashAlg)
10076
{
10077
    int ret;
10078
    TPMA_OBJECT objectAttributes = (
10079
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
10080
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
10081
        TPMA_OBJECT_adminWithPolicy | TPMA_OBJECT_restricted |
10082
        TPMA_OBJECT_sign);
10083
10084
    ret = GetKeyTemplateECC(publicTemplate, hashAlg,
10085
        objectAttributes, curveID, TPM_ALG_ECDSA, hashAlg);
10086
    if (ret == 0) {
10087
        publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
10088
        ret = wolfTPM2_SetKeyTemplate_IAK(publicTemplate, hashAlg);
10089
    }
10090
    return ret;
10091
}
10092
10093
static int wolfTPM2_SetKeyTemplate_IDevID(TPMT_PUBLIC* publicTemplate,
10094
    TPM_ALG_ID hashAlg)
10095
{
10096
    int ret = 0;
10097
    if (hashAlg == TPM_ALG_SHA256) {
10098
        publicTemplate->authPolicy.size = sizeof(TPM_20_IDEVID_POLICY);
10099
        XMEMCPY(publicTemplate->authPolicy.buffer,
10100
            TPM_20_IDEVID_POLICY, publicTemplate->authPolicy.size);
10101
    }
10102
#ifdef WOLFSSL_SHA384
10103
    else if (hashAlg == TPM_ALG_SHA384) {
10104
        publicTemplate->authPolicy.size = sizeof(TPM_20_IDEVID_POLICY_SHA384);
10105
        XMEMCPY(publicTemplate->authPolicy.buffer,
10106
            TPM_20_IDEVID_POLICY_SHA384, publicTemplate->authPolicy.size);
10107
    }
10108
#endif
10109
#ifdef WOLFSSL_SHA512
10110
    else if (hashAlg == TPM_ALG_SHA512) {
10111
        publicTemplate->authPolicy.size = sizeof(TPM_20_IDEVID_POLICY_SHA512);
10112
        XMEMCPY(publicTemplate->authPolicy.buffer,
10113
            TPM_20_IDEVID_POLICY_SHA512, publicTemplate->authPolicy.size);
10114
    }
10115
#endif
10116
    else {
10117
        ret = BAD_FUNC_ARG;
10118
    }
10119
    if (ret == 0) {
10120
        const char* IDevIDStr = "IDEVID";
10121
        ret = wolfTPM2_SetKeyTemplate_Unique(publicTemplate,
10122
            (const byte*)IDevIDStr, (int)XSTRLEN(IDevIDStr));
10123
    }
10124
    return ret;
10125
}
10126
int wolfTPM2_GetKeyTemplate_RSA_IDevID(TPMT_PUBLIC* publicTemplate, int keyBits,
10127
    TPM_ALG_ID hashAlg)
10128
{
10129
    int ret;
10130
    TPMA_OBJECT objectAttributes = (
10131
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
10132
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
10133
        TPMA_OBJECT_adminWithPolicy | TPMA_OBJECT_sign);
10134
10135
    ret = GetKeyTemplateRSA(publicTemplate, hashAlg,
10136
        objectAttributes, keyBits, 0, TPM_ALG_NULL, TPM_ALG_NULL);
10137
    if (ret == 0) {
10138
        publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL;
10139
        ret = wolfTPM2_SetKeyTemplate_IDevID(publicTemplate, hashAlg);
10140
    }
10141
    return ret;
10142
}
10143
int wolfTPM2_GetKeyTemplate_ECC_IDevID(TPMT_PUBLIC* publicTemplate,
10144
    TPM_ECC_CURVE curveID, TPM_ALG_ID hashAlg)
10145
{
10146
    int ret;
10147
    TPMA_OBJECT objectAttributes = (
10148
        TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent |
10149
        TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
10150
        TPMA_OBJECT_adminWithPolicy | TPMA_OBJECT_sign);
10151
10152
    ret = GetKeyTemplateECC(publicTemplate, hashAlg,
10153
        objectAttributes, curveID, TPM_ALG_ECDSA, hashAlg);
10154
    if (ret == 0) {
10155
        publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
10156
        ret = wolfTPM2_SetKeyTemplate_IDevID(publicTemplate, hashAlg);
10157
    }
10158
    return ret;
10159
}
10160
#endif /* WOLFTPM_PROVISIONING */
10161
10162
/* Returns key size (in bytes) for the public template */
10163
static int GetKeyTemplateSize(TPMT_PUBLIC* publicTemplate)
10164
{
10165
    int ret;
10166
    if (publicTemplate == NULL) {
10167
        return BAD_FUNC_ARG;
10168
    }
10169
    switch (publicTemplate->type) {
10170
        case TPM_ALG_RSA:
10171
            ret = publicTemplate->parameters.rsaDetail.keyBits / 8;
10172
            break;
10173
        case TPM_ALG_ECC:
10174
            ret = TPM2_GetCurveSize(
10175
                publicTemplate->parameters.eccDetail.curveID);
10176
            break;
10177
        case TPM_ALG_SYMCIPHER:
10178
            ret = publicTemplate->parameters.symDetail.sym.keyBits.sym / 8;
10179
            break;
10180
    #ifdef WOLFTPM_MLDSA
10181
        case TPM_ALG_MLDSA:
10182
        case TPM_ALG_HASH_MLDSA: {
10183
            TPMI_MLDSA_PARAMETER_SET ps =
10184
                (publicTemplate->type == TPM_ALG_MLDSA)
10185
                    ? publicTemplate->parameters.mldsaDetail.parameterSet
10186
                    : publicTemplate->parameters.hash_mldsaDetail.parameterSet;
10187
            /* Per Part 2 Table 207 MLDSA public-key sizes. */
10188
            if (ps == TPM_MLDSA_44)      ret = 1312;
10189
            else if (ps == TPM_MLDSA_65) ret = 1952;
10190
            else if (ps == TPM_MLDSA_87) ret = 2592;
10191
            else                          ret = BAD_FUNC_ARG;
10192
            break;
10193
        }
10194
    #endif /* WOLFTPM_MLDSA */
10195
    #ifdef WOLFTPM_MLKEM
10196
        case TPM_ALG_MLKEM: {
10197
            TPMI_MLKEM_PARAMETER_SET ps =
10198
                publicTemplate->parameters.mlkemDetail.parameterSet;
10199
            /* Per Part 2 Table 204 MLKEM public-key sizes. */
10200
            if (ps == TPM_MLKEM_512)       ret = 800;
10201
            else if (ps == TPM_MLKEM_768)  ret = 1184;
10202
            else if (ps == TPM_MLKEM_1024) ret = 1568;
10203
            else                            ret = BAD_FUNC_ARG;
10204
            break;
10205
        }
10206
    #endif /* WOLFTPM_MLKEM */
10207
        case TPM_ALG_KEYEDHASH:
10208
        default:
10209
            ret = BAD_FUNC_ARG;
10210
    }
10211
    return ret;
10212
}
10213
10214
int wolfTPM2_SetKeyTemplate_Unique(TPMT_PUBLIC* publicTemplate,
10215
    const byte* unique, int uniqueSz)
10216
{
10217
    int ret = 0;
10218
    int keySz;
10219
10220
    if (publicTemplate == NULL || (unique != NULL && uniqueSz <= 0)) {
10221
        return BAD_FUNC_ARG;
10222
    }
10223
10224
    keySz = GetKeyTemplateSize(publicTemplate);
10225
    if (keySz <= 0) {
10226
        return BAD_FUNC_ARG;
10227
    }
10228
10229
    switch (publicTemplate->type) {
10230
        case TPM_ALG_RSA:
10231
            if (uniqueSz == 0) {
10232
                uniqueSz = keySz;
10233
            }
10234
            else if (uniqueSz > keySz) {
10235
                uniqueSz = keySz;
10236
            }
10237
            if (uniqueSz > (int)sizeof(publicTemplate->unique.rsa.buffer)) {
10238
                uniqueSz = (int)sizeof(publicTemplate->unique.rsa.buffer); /* truncate */
10239
            }
10240
            if (unique == NULL) {
10241
                XMEMSET(publicTemplate->unique.rsa.buffer, 0, uniqueSz);
10242
            }
10243
            else {
10244
                XMEMCPY(publicTemplate->unique.rsa.buffer, unique, uniqueSz);
10245
            }
10246
            publicTemplate->unique.rsa.size = uniqueSz;
10247
            break;
10248
        case TPM_ALG_ECC:
10249
            /* ECC uses X and Y */
10250
            if (uniqueSz == 0) {
10251
                uniqueSz = keySz * 2;
10252
            }
10253
            else if (uniqueSz > keySz * 2) {
10254
                uniqueSz = keySz * 2;
10255
            }
10256
            uniqueSz /= 2;
10257
            if (uniqueSz > (int)sizeof(publicTemplate->unique.ecc.x.buffer)) {
10258
                uniqueSz = (int)sizeof(publicTemplate->unique.ecc.x.buffer);
10259
            }
10260
            if (unique == NULL) {
10261
                XMEMSET(publicTemplate->unique.ecc.x.buffer, 0, uniqueSz);
10262
                XMEMSET(publicTemplate->unique.ecc.y.buffer, 0, uniqueSz);
10263
            }
10264
            else {
10265
                XMEMCPY(publicTemplate->unique.ecc.x.buffer, unique, uniqueSz);
10266
                XMEMCPY(publicTemplate->unique.ecc.y.buffer, unique + uniqueSz,
10267
                    uniqueSz);
10268
            }
10269
            publicTemplate->unique.ecc.x.size = uniqueSz;
10270
            publicTemplate->unique.ecc.y.size = uniqueSz;
10271
            break;
10272
        case TPM_ALG_SYMCIPHER:
10273
            if (uniqueSz == 0) {
10274
                uniqueSz = keySz;
10275
            }
10276
            else if (uniqueSz > keySz) {
10277
                uniqueSz = keySz;
10278
            }
10279
            if (uniqueSz > (int)sizeof(publicTemplate->unique.sym.buffer)) {
10280
                uniqueSz = (int)sizeof(publicTemplate->unique.sym.buffer);
10281
            }
10282
            if (unique == NULL) {
10283
                XMEMSET(publicTemplate->unique.sym.buffer, 0, uniqueSz);
10284
            }
10285
            else {
10286
                XMEMCPY(publicTemplate->unique.sym.buffer, unique, uniqueSz);
10287
            }
10288
            publicTemplate->unique.sym.size = uniqueSz;
10289
            break;
10290
#ifdef WOLFTPM_MLDSA
10291
        /* TPMU_PUBLIC_ID shares the mldsa arm between MLDSA and HASH_MLDSA
10292
         * (Part 2 Table 225 note — one union field, two selectors). */
10293
        case TPM_ALG_MLDSA:
10294
        case TPM_ALG_HASH_MLDSA:
10295
            if (uniqueSz == 0) {
10296
                uniqueSz = keySz;
10297
            }
10298
            else if (uniqueSz > keySz) {
10299
                uniqueSz = keySz;
10300
            }
10301
            if (uniqueSz > (int)sizeof(publicTemplate->unique.mldsa.buffer)) {
10302
                uniqueSz =
10303
                    (int)sizeof(publicTemplate->unique.mldsa.buffer); /* truncate */
10304
            }
10305
            if (unique == NULL) {
10306
                XMEMSET(publicTemplate->unique.mldsa.buffer, 0, uniqueSz);
10307
            }
10308
            else {
10309
                XMEMCPY(publicTemplate->unique.mldsa.buffer, unique, uniqueSz);
10310
            }
10311
            publicTemplate->unique.mldsa.size = uniqueSz;
10312
            break;
10313
#endif /* WOLFTPM_MLDSA */
10314
#ifdef WOLFTPM_MLKEM
10315
        case TPM_ALG_MLKEM:
10316
            if (uniqueSz == 0) {
10317
                uniqueSz = keySz;
10318
            }
10319
            else if (uniqueSz > keySz) {
10320
                uniqueSz = keySz;
10321
            }
10322
            if (uniqueSz > (int)sizeof(publicTemplate->unique.mlkem.buffer)) {
10323
                uniqueSz =
10324
                    (int)sizeof(publicTemplate->unique.mlkem.buffer); /* truncate */
10325
            }
10326
            if (unique == NULL) {
10327
                XMEMSET(publicTemplate->unique.mlkem.buffer, 0, uniqueSz);
10328
            }
10329
            else {
10330
                XMEMCPY(publicTemplate->unique.mlkem.buffer, unique, uniqueSz);
10331
            }
10332
            publicTemplate->unique.mlkem.size = uniqueSz;
10333
            break;
10334
#endif /* WOLFTPM_MLKEM */
10335
        case TPM_ALG_KEYEDHASH:
10336
            /* not supported */
10337
            ret = BAD_FUNC_ARG;
10338
            break;
10339
        default:
10340
            ret = BAD_FUNC_ARG;
10341
            break;
10342
    }
10343
    return ret;
10344
}
10345
10346
int wolfTPM2_GetNvAttributesTemplate(TPM_HANDLE auth, word32* nvAttributes)
10347
{
10348
    if (nvAttributes == NULL)
10349
        return BAD_FUNC_ARG;
10350
10351
    *nvAttributes = (
10352
        TPMA_NV_AUTHWRITE  |     /* password or HMAC can authorize writing */
10353
        TPMA_NV_AUTHREAD   |     /* password or HMAC can authorize reading */
10354
        TPMA_NV_OWNERREAD  |     /* Allow owner to read */
10355
        TPMA_NV_NO_DA            /* Don't increment dictionary attack counter */
10356
    );
10357
10358
    if (auth == TPM_RH_PLATFORM) {
10359
        *nvAttributes |= (
10360
            TPMA_NV_PLATFORMCREATE | /* Platform created NV */
10361
            TPMA_NV_PPWRITE |        /* Write may be authorized by platform */
10362
            TPMA_NV_PPREAD           /* Read may be authorized by platform */
10363
        );
10364
    }
10365
    else if (auth == TPM_RH_OWNER) {
10366
        *nvAttributes |= (
10367
            TPMA_NV_OWNERWRITE   /* Owner Hierarchy auth can be used to write */
10368
        );
10369
    }
10370
10371
    return 0;
10372
}
10373
10374
int wolfTPM2_CreateEK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ekKey, TPM_ALG_ID alg)
10375
{
10376
    int rc;
10377
    TPMT_PUBLIC publicTemplate;
10378
10379
    if (alg == TPM_ALG_RSA) {
10380
        rc = wolfTPM2_GetKeyTemplate_RSA_EK(&publicTemplate);
10381
    }
10382
    else if (alg == TPM_ALG_ECC) {
10383
        rc = wolfTPM2_GetKeyTemplate_ECC_EK(&publicTemplate);
10384
    }
10385
    else {
10386
        /* Supported algorithms for EK are only RSA 2048-bit & ECC P256 */
10387
        return BAD_FUNC_ARG;
10388
    }
10389
    /* GetKeyTemplate check */
10390
    if (rc != 0)
10391
        return rc;
10392
10393
    rc = wolfTPM2_CreatePrimaryKey(dev, ekKey, TPM_RH_ENDORSEMENT,
10394
        &publicTemplate, NULL, 0);
10395
10396
    return rc;
10397
}
10398
10399
int wolfTPM2_CreateSRK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* srkKey, TPM_ALG_ID alg,
10400
    const byte* auth, int authSz)
10401
{
10402
    int rc;
10403
    TPMT_PUBLIC publicTemplate;
10404
10405
    /* Supported algorithms for SRK are only 2048bit RSA & ECC */
10406
    if (alg == TPM_ALG_RSA) {
10407
        rc = wolfTPM2_GetKeyTemplate_RSA_SRK(&publicTemplate);
10408
    }
10409
    else if (alg == TPM_ALG_ECC) {
10410
        rc = wolfTPM2_GetKeyTemplate_ECC_SRK(&publicTemplate);
10411
    }
10412
    else {
10413
        /* Supported algorithms for SRK are only RSA 2048-bit & ECC P256 */
10414
        return BAD_FUNC_ARG;
10415
    }
10416
    /* GetKeyTemplate check */
10417
    if (rc != 0)
10418
        return rc;
10419
10420
    rc = wolfTPM2_CreatePrimaryKey(dev, srkKey, TPM_RH_OWNER,
10421
        &publicTemplate, auth, authSz);
10422
10423
    return rc;
10424
}
10425
10426
int wolfTPM2_CreateAndLoadAIK(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* aikKey,
10427
    TPM_ALG_ID alg, WOLFTPM2_KEY* srkKey, const byte* auth, int authSz)
10428
{
10429
    int rc;
10430
    TPMT_PUBLIC publicTemplate;
10431
10432
    if (alg == TPM_ALG_RSA) {
10433
        rc = wolfTPM2_GetKeyTemplate_RSA_AIK(&publicTemplate);
10434
    }
10435
    else if (alg == TPM_ALG_ECC) {
10436
        rc = wolfTPM2_GetKeyTemplate_ECC_AIK(&publicTemplate);
10437
    }
10438
    else {
10439
        return BAD_FUNC_ARG;
10440
    }
10441
    /* GetKeyTemplate check */
10442
    if (rc != 0)
10443
        return rc;
10444
10445
    rc = wolfTPM2_CreateAndLoadKey(dev, aikKey, &srkKey->handle,
10446
        &publicTemplate, auth, authSz);
10447
10448
    return rc;
10449
}
10450
10451
int wolfTPM2_CreateKeySeal(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
10452
    WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
10453
    const byte* auth, int authSz, const byte* sealData, int sealSize)
10454
{
10455
    return wolfTPM2_CreateKeySeal_ex(dev, keyBlob, parent, publicTemplate, auth,
10456
        authSz, TPM_ALG_NULL, NULL, 0, sealData, sealSize);
10457
}
10458
10459
int wolfTPM2_CreateKeySeal_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEYBLOB* keyBlob,
10460
    WOLFTPM2_HANDLE* parent, TPMT_PUBLIC* publicTemplate,
10461
    const byte* auth, int authSz, TPM_ALG_ID pcrAlg, byte* pcrArray,
10462
    word32 pcrArraySz, const byte* sealData, int sealSize)
10463
{
10464
    int rc;
10465
    Create_In  createIn;
10466
    Create_Out createOut;
10467
10468
    if (dev == NULL || keyBlob == NULL || parent == NULL ||
10469
            publicTemplate == NULL) {
10470
        return BAD_FUNC_ARG;
10471
    }
10472
10473
    /* Seal size is limited to TCG defined MAX_SYM_DATA, which is 128 bytes */
10474
    if (sealSize < 0 || sealSize > MAX_SYM_DATA) {
10475
#ifdef DEBUG_WOLFTPM
10476
        printf("Seal size %d should not be larger than %d bytes\n",
10477
            sealSize, MAX_SYM_DATA);
10478
#endif
10479
        return BAD_FUNC_ARG;
10480
    }
10481
10482
    /* Seal size must be 0 when data pointer is NULL */
10483
    if (sealSize > 0 && sealData == NULL) {
10484
#ifdef DEBUG_WOLFTPM
10485
        printf("Seal size %d specified with NULL data pointer\n",
10486
            sealSize);
10487
#endif
10488
        return BAD_FUNC_ARG;
10489
    }
10490
10491
    /* clear output key buffer */
10492
    XMEMSET(keyBlob, 0, sizeof(WOLFTPM2_KEYBLOB));
10493
    XMEMSET(&createOut, 0, sizeof(createOut)); /* make sure pub struct is zero init */
10494
10495
    /* set session auth for parent key */
10496
    wolfTPM2_SetAuthHandle(dev, 0, parent);
10497
10498
    XMEMSET(&createIn, 0, sizeof(createIn));
10499
    createIn.parentHandle = parent->hndl;
10500
    if (auth) {
10501
        TPM2B_AUTH* pAuth = &createIn.inSensitive.sensitive.userAuth;
10502
        if (authSz < 0) {
10503
            return BAD_FUNC_ARG;
10504
        }
10505
        if (authSz > (int)sizeof(pAuth->buffer)) {
10506
            return BUFFER_E;
10507
        }
10508
        pAuth->size = authSz;
10509
        XMEMCPY(pAuth->buffer, auth, authSz);
10510
    }
10511
    wolfTPM2_CopyPubT(&createIn.inPublic.publicArea, publicTemplate);
10512
10513
    /* Seal user (arbitrary) data in the newly generated TPM key */
10514
    createIn.inSensitive.sensitive.data.size = sealSize;
10515
    XMEMCPY(createIn.inSensitive.sensitive.data.buffer, sealData, sealSize);
10516
10517
    /* set the pcr selection if passed in */
10518
    if (pcrArray != NULL) {
10519
        TPM2_SetupPCRSelArray(&createIn.creationPCR, pcrAlg, pcrArray,
10520
            pcrArraySz);
10521
    }
10522
10523
    rc = TPM2_Create(&createIn, &createOut);
10524
    if (rc != TPM_RC_SUCCESS) {
10525
    #ifdef DEBUG_WOLFTPM
10526
        printf("wolfTPM2_CreateKeySeal failed %d: %s\n",
10527
            rc, wolfTPM2_GetRCString(rc));
10528
    #endif
10529
        TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
10530
        return rc;
10531
    }
10532
10533
#ifdef DEBUG_WOLFTPM
10534
    printf("wolfTPM2_CreateKeySeal generated key with: pub %d, priv %d\n",
10535
        createOut.outPublic.size, createOut.outPrivate.size);
10536
    TPM2_PrintPublicArea(&createOut.outPublic);
10537
#endif
10538
10539
    wolfTPM2_CopyAuth(&keyBlob->handle.auth,
10540
        &createIn.inSensitive.sensitive.userAuth);
10541
    wolfTPM2_CopySymmetric(&keyBlob->handle.symmetric,
10542
        &createOut.outPublic.publicArea.parameters.asymDetail.symmetric);
10543
10544
    wolfTPM2_CopyPub(&keyBlob->pub, &createOut.outPublic);
10545
    wolfTPM2_CopyPriv(&keyBlob->priv, &createOut.outPrivate);
10546
10547
    TPM2_ForceZero(&createIn.inSensitive, sizeof(createIn.inSensitive));
10548
    TPM2_ForceZero(&createOut.outPrivate, sizeof(createOut.outPrivate));
10549
10550
    return rc;
10551
}
10552
10553
int wolfTPM2_GetTime(WOLFTPM2_KEY* aikKey, GetTime_Out* getTimeOut)
10554
{
10555
    int rc;
10556
    GetTime_In getTimeCmd;
10557
10558
    if (getTimeOut == NULL)
10559
        return BAD_FUNC_ARG;
10560
10561
    /* GetTime */
10562
    XMEMSET(&getTimeCmd, 0, sizeof(getTimeCmd));
10563
    XMEMSET(getTimeOut, 0, sizeof(*getTimeOut));
10564
    getTimeCmd.privacyAdminHandle = TPM_RH_ENDORSEMENT;
10565
    if (aikKey != NULL) {
10566
        TPMT_ASYM_SCHEME* scheme =
10567
            &aikKey->pub.publicArea.parameters.asymDetail.scheme;
10568
        getTimeCmd.signHandle = aikKey->handle.hndl;
10569
        getTimeCmd.inScheme.scheme = scheme->scheme;
10570
        getTimeCmd.inScheme.details.any.hashAlg =
10571
            scheme->details.anySig.hashAlg;
10572
    }
10573
    else {
10574
        getTimeCmd.signHandle = TPM_RH_NULL;
10575
    }
10576
    getTimeCmd.qualifyingData.size = 0; /* optional */
10577
    rc = TPM2_GetTime(&getTimeCmd, getTimeOut);
10578
    if (rc != TPM_RC_SUCCESS) {
10579
    #ifdef DEBUG_WOLFTPM
10580
        printf("TPM2_GetTime failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc));
10581
    #endif
10582
    }
10583
10584
    return rc;
10585
}
10586
10587
static void wolfTPM2_CopySymmetric(TPMT_SYM_DEF* out, const TPMT_SYM_DEF* in)
10588
{
10589
    if (out == NULL || in == NULL)
10590
        return;
10591
10592
    out->algorithm = in->algorithm;
10593
    switch (out->algorithm) {
10594
        case TPM_ALG_XOR:
10595
            out->keyBits.xorr = in->keyBits.xorr;
10596
            break;
10597
        case TPM_ALG_AES:
10598
            out->keyBits.aes = in->keyBits.aes;
10599
            out->mode.aes = in->mode.aes;
10600
            break;
10601
        case TPM_ALG_NULL:
10602
            break;
10603
        default:
10604
            out->keyBits.sym = in->keyBits.sym;
10605
            out->mode.sym = in->mode.sym;
10606
            break;
10607
    }
10608
}
10609
10610
static void wolfTPM2_CopyName(TPM2B_NAME* out, const TPM2B_NAME* in)
10611
{
10612
    if (out != NULL && in != NULL) {
10613
        out->size = in->size;
10614
        if (out->size > (UINT16)sizeof(out->name))
10615
            out->size = (UINT16)sizeof(out->name);
10616
        XMEMCPY(out->name, in->name, out->size);
10617
    }
10618
}
10619
10620
static void wolfTPM2_CopyAuth(TPM2B_AUTH* out, const TPM2B_AUTH* in)
10621
{
10622
    if (out != NULL && in != NULL) {
10623
        UINT16 copySz = in->size;
10624
10625
        if (copySz > (UINT16)sizeof(out->buffer))
10626
            copySz = (UINT16)sizeof(out->buffer);
10627
        XMEMMOVE(out->buffer, in->buffer, copySz);
10628
        if (copySz < (UINT16)sizeof(out->buffer)) {
10629
            TPM2_ForceZero(&out->buffer[copySz],
10630
                (word32)sizeof(out->buffer) - copySz);
10631
        }
10632
        out->size = copySz;
10633
    }
10634
}
10635
10636
static void wolfTPM2_CopyPubT(TPMT_PUBLIC* out, const TPMT_PUBLIC* in)
10637
{
10638
    if (out == NULL || in == NULL)
10639
        return;
10640
10641
    out->type = in->type;
10642
    out->nameAlg = in->nameAlg;
10643
    out->objectAttributes = in->objectAttributes;
10644
    out->authPolicy.size = in->authPolicy.size;
10645
    if (out->authPolicy.size > 0) {
10646
        if (out->authPolicy.size > (UINT16)sizeof(out->authPolicy.buffer)) {
10647
            out->authPolicy.size =
10648
                (UINT16)sizeof(out->authPolicy.buffer); /* truncate */
10649
        }
10650
        XMEMCPY(out->authPolicy.buffer, in->authPolicy.buffer,
10651
            out->authPolicy.size);
10652
    }
10653
10654
    switch (out->type) {
10655
    case TPM_ALG_KEYEDHASH:
10656
        out->parameters.keyedHashDetail.scheme =
10657
            in->parameters.keyedHashDetail.scheme;
10658
10659
        out->unique.keyedHash.size =
10660
            in->unique.keyedHash.size;
10661
        if (out->unique.keyedHash.size >
10662
                (UINT16)sizeof(out->unique.keyedHash.buffer)) {
10663
            out->unique.keyedHash.size =
10664
                (UINT16)sizeof(out->unique.keyedHash.buffer); /* truncate */
10665
        }
10666
        XMEMCPY(out->unique.keyedHash.buffer, in->unique.keyedHash.buffer,
10667
            out->unique.keyedHash.size);
10668
        break;
10669
    case TPM_ALG_SYMCIPHER:
10670
        out->parameters.symDetail.sym.algorithm =
10671
            in->parameters.symDetail.sym.algorithm;
10672
        out->parameters.symDetail.sym.keyBits.sym =
10673
            in->parameters.symDetail.sym.keyBits.sym;
10674
        out->parameters.symDetail.sym.mode.sym =
10675
            in->parameters.symDetail.sym.mode.sym;
10676
10677
        out->unique.sym.size =
10678
            in->unique.sym.size;
10679
        if (out->unique.sym.size > (UINT16)sizeof(out->unique.sym.buffer)) {
10680
            out->unique.sym.size =
10681
                (UINT16)sizeof(out->unique.sym.buffer); /* truncate */
10682
        }
10683
        XMEMCPY(out->unique.sym.buffer, in->unique.sym.buffer,
10684
                out->unique.sym.size);
10685
        break;
10686
    case TPM_ALG_RSA:
10687
        wolfTPM2_CopySymmetric(&out->parameters.rsaDetail.symmetric,
10688
            &in->parameters.rsaDetail.symmetric);
10689
        out->parameters.rsaDetail.scheme.scheme =
10690
            in->parameters.rsaDetail.scheme.scheme;
10691
        if (out->parameters.rsaDetail.scheme.scheme != TPM_ALG_NULL)
10692
            out->parameters.rsaDetail.scheme.details.anySig.hashAlg =
10693
                in->parameters.rsaDetail.scheme.details.anySig.hashAlg;
10694
        out->parameters.rsaDetail.keyBits =
10695
            in->parameters.rsaDetail.keyBits;
10696
        out->parameters.rsaDetail.exponent =
10697
            in->parameters.rsaDetail.exponent;
10698
10699
        out->unique.rsa.size =
10700
            in->unique.rsa.size;
10701
        if (out->unique.rsa.size > (UINT16)sizeof(out->unique.rsa.buffer)) {
10702
            out->unique.rsa.size =
10703
                (UINT16)sizeof(out->unique.rsa.buffer); /* truncate */
10704
        }
10705
        XMEMCPY(out->unique.rsa.buffer, in->unique.rsa.buffer,
10706
            out->unique.rsa.size);
10707
        break;
10708
    case TPM_ALG_ECC:
10709
        wolfTPM2_CopySymmetric(&out->parameters.eccDetail.symmetric,
10710
            &in->parameters.eccDetail.symmetric);
10711
        out->parameters.eccDetail.scheme.scheme =
10712
            in->parameters.eccDetail.scheme.scheme;
10713
        out->parameters.eccDetail.scheme.details.any.hashAlg =
10714
            in->parameters.eccDetail.scheme.details.any.hashAlg;
10715
        if (in->parameters.eccDetail.scheme.scheme == TPM_ALG_ECDAA) {
10716
            out->parameters.eccDetail.scheme.details.ecdaa.count =
10717
                in->parameters.eccDetail.scheme.details.ecdaa.count;
10718
        }
10719
        out->parameters.eccDetail.curveID =
10720
            in->parameters.eccDetail.curveID;
10721
        out->parameters.eccDetail.kdf.scheme =
10722
            in->parameters.eccDetail.kdf.scheme;
10723
        out->parameters.eccDetail.kdf.details.any.hashAlg =
10724
            in->parameters.eccDetail.kdf.details.any.hashAlg;
10725
        wolfTPM2_CopyEccParam(&out->unique.ecc.x,
10726
            &in->unique.ecc.x);
10727
        wolfTPM2_CopyEccParam(&out->unique.ecc.y,
10728
            &in->unique.ecc.y);
10729
        break;
10730
#ifdef WOLFTPM_MLDSA
10731
    case TPM_ALG_MLDSA:
10732
        out->parameters.mldsaDetail.parameterSet =
10733
            in->parameters.mldsaDetail.parameterSet;
10734
        out->parameters.mldsaDetail.allowExternalMu =
10735
            in->parameters.mldsaDetail.allowExternalMu;
10736
        out->unique.mldsa.size = in->unique.mldsa.size;
10737
        if (out->unique.mldsa.size > (UINT16)sizeof(out->unique.mldsa.buffer)) {
10738
            out->unique.mldsa.size = (UINT16)sizeof(out->unique.mldsa.buffer);
10739
        }
10740
        XMEMCPY(out->unique.mldsa.buffer, in->unique.mldsa.buffer,
10741
            out->unique.mldsa.size);
10742
        break;
10743
    case TPM_ALG_HASH_MLDSA:
10744
        out->parameters.hash_mldsaDetail.parameterSet =
10745
            in->parameters.hash_mldsaDetail.parameterSet;
10746
        out->parameters.hash_mldsaDetail.hashAlg =
10747
            in->parameters.hash_mldsaDetail.hashAlg;
10748
        /* TPMU_PUBLIC_ID shares the mldsa arm between MLDSA and HASH_MLDSA
10749
         * (Part 2 Table 225 note — one union field, two selectors). */
10750
        out->unique.mldsa.size = in->unique.mldsa.size;
10751
        if (out->unique.mldsa.size > (UINT16)sizeof(out->unique.mldsa.buffer)) {
10752
            out->unique.mldsa.size = (UINT16)sizeof(out->unique.mldsa.buffer);
10753
        }
10754
        XMEMCPY(out->unique.mldsa.buffer, in->unique.mldsa.buffer,
10755
            out->unique.mldsa.size);
10756
        break;
10757
#endif /* WOLFTPM_MLDSA */
10758
#ifdef WOLFTPM_MLKEM
10759
    case TPM_ALG_MLKEM:
10760
        wolfTPM2_CopySymmetric(&out->parameters.mlkemDetail.symmetric,
10761
            &in->parameters.mlkemDetail.symmetric);
10762
        out->parameters.mlkemDetail.parameterSet =
10763
            in->parameters.mlkemDetail.parameterSet;
10764
        out->unique.mlkem.size = in->unique.mlkem.size;
10765
        if (out->unique.mlkem.size > (UINT16)sizeof(out->unique.mlkem.buffer)) {
10766
            out->unique.mlkem.size = (UINT16)sizeof(out->unique.mlkem.buffer);
10767
        }
10768
        XMEMCPY(out->unique.mlkem.buffer, in->unique.mlkem.buffer,
10769
            out->unique.mlkem.size);
10770
        break;
10771
#endif /* WOLFTPM_MLKEM */
10772
    default:
10773
        wolfTPM2_CopySymmetric(&out->parameters.asymDetail.symmetric,
10774
            &in->parameters.asymDetail.symmetric);
10775
        out->parameters.asymDetail.scheme.scheme =
10776
            in->parameters.asymDetail.scheme.scheme;
10777
        out->parameters.asymDetail.scheme.details.anySig.hashAlg =
10778
            in->parameters.asymDetail.scheme.details.anySig.hashAlg;
10779
        break;
10780
    }
10781
}
10782
10783
static void wolfTPM2_CopyPub(TPM2B_PUBLIC* out, const TPM2B_PUBLIC* in)
10784
{
10785
    if (out != NULL && in != NULL) {
10786
        out->size = in->size;
10787
        wolfTPM2_CopyPubT(&out->publicArea, &in->publicArea);
10788
    }
10789
}
10790
10791
static void wolfTPM2_CopyPriv(TPM2B_PRIVATE* out, const TPM2B_PRIVATE* in)
10792
{
10793
    if (out != NULL && in != NULL) {
10794
        /* Clear any longer prior blob so its tail does not remain resident */
10795
        TPM2_ForceZero(out->buffer, sizeof(out->buffer));
10796
        out->size = in->size;
10797
        if (out->size > (UINT16)sizeof(out->buffer))
10798
            out->size = (UINT16)sizeof(out->buffer);
10799
        XMEMCPY(out->buffer, in->buffer, out->size);
10800
    }
10801
}
10802
10803
static void wolfTPM2_CopyEccParam(TPM2B_ECC_PARAMETER* out,
10804
    const TPM2B_ECC_PARAMETER* in)
10805
{
10806
    if (out != NULL && in != NULL) {
10807
        out->size = in->size;
10808
        if (out->size > (UINT16)sizeof(out->buffer))
10809
            out->size = (UINT16)sizeof(out->buffer);
10810
        XMEMCPY(out->buffer, in->buffer, out->size);
10811
    }
10812
}
10813
10814
static void wolfTPM2_CopyKeyFromBlob(WOLFTPM2_KEY* key, const WOLFTPM2_KEYBLOB* keyBlob)
10815
{
10816
    if (key != NULL && keyBlob != NULL) {
10817
        key->handle.hndl = keyBlob->handle.hndl;
10818
        wolfTPM2_CopyAuth(&key->handle.auth, &keyBlob->handle.auth);
10819
        wolfTPM2_CopyName(&key->handle.name, &keyBlob->handle.name);
10820
        wolfTPM2_CopySymmetric(&key->handle.symmetric, &keyBlob->handle.symmetric);
10821
        wolfTPM2_CopyPub(&key->pub, &keyBlob->pub);
10822
    }
10823
}
10824
10825
static void wolfTPM2_CopyNvPublic(TPMS_NV_PUBLIC* out, const TPMS_NV_PUBLIC* in)
10826
{
10827
    if (out != NULL && in != NULL) {
10828
        out->attributes = in->attributes;
10829
        out->authPolicy.size = in->authPolicy.size;
10830
        if (out->authPolicy.size > 0) {
10831
            if (out->authPolicy.size > (UINT16)sizeof(out->authPolicy.buffer)) {
10832
                out->authPolicy.size =
10833
                    (UINT16)sizeof(out->authPolicy.buffer); /* truncate */
10834
            }
10835
            XMEMCPY(out->authPolicy.buffer, in->authPolicy.buffer,
10836
                out->authPolicy.size);
10837
        }
10838
        out->dataSize = in->dataSize;
10839
        out->nameAlg = in->nameAlg;
10840
        out->nvIndex = in->nvIndex;
10841
    }
10842
}
10843
10844
/******************************************************************************/
10845
/* --- END Utility Functions -- */
10846
/******************************************************************************/
10847
10848
10849
/******************************************************************************/
10850
/* --- BEGIN Certificate Signing Request (CSR) Functions -- */
10851
/******************************************************************************/
10852
10853
#if defined(WOLFTPM2_CERT_GEN) && defined(WOLFTPM_CRYPTOCB)
10854
10855
/* Distinguished Name Strings */
10856
typedef struct DNTags {
10857
    const char* tag;
10858
    size_t certNameOff;
10859
} DNTags;
10860
10861
static int CSR_Parse_DN(CertName* name, const char* subject)
10862
{
10863
    int rc = 0, i;
10864
    const DNTags tags[] = {
10865
        {"/CN=",     OFFSETOF(CertName, commonName)}, /* Common Name */
10866
        {"/C=",      OFFSETOF(CertName, country)},    /* Country */
10867
        {"/ST=",     OFFSETOF(CertName, state)},      /* State */
10868
        {"/L=",      OFFSETOF(CertName, locality)},   /* Locality */
10869
        {"/SN=",     OFFSETOF(CertName, sur)},        /* Surname */
10870
        {"/O=",      OFFSETOF(CertName, org)},        /* Organization */
10871
        {"/OU=",     OFFSETOF(CertName, unit)},       /* Organization Unit */
10872
        {"/serialNumber=", OFFSETOF(CertName, serialDev)},  /* Serial Number */
10873
        {"/emailAddress=", OFFSETOF(CertName, email)},      /* Email Address */
10874
    #if defined(LIBWOLFSSL_VERSION_HEX) && LIBWOLFSSL_VERSION_HEX > 0x05000000
10875
        {"/street=", OFFSETOF(CertName, street)},     /* Street */
10876
        {"/postalCode=",   OFFSETOF(CertName, postalCode)}, /* PostalCode */
10877
    #endif
10878
    #if defined(LIBWOLFSSL_VERSION_HEX) && LIBWOLFSSL_VERSION_HEX > 0x05003000
10879
        {"/userid=",       OFFSETOF(CertName, userId)},     /* UserID */
10880
    #endif
10881
    #ifdef WOLFSSL_CERT_EXT
10882
        {"/businessCategory=", OFFSETOF(CertName, busCat)}, /* Business Category */
10883
    #endif
10884
    };
10885
10886
    for (i = 0; i < (int)(sizeof(tags) / sizeof(DNTags)); i++) {
10887
        const char *begin, *end;
10888
        char* dst;
10889
        word32 len = 0;
10890
        /* find start tag */
10891
        begin = XSTRSTR(subject, tags[i].tag);
10892
        if (begin != NULL) {
10893
            /* find end of string or / */
10894
            begin += XSTRLEN(tags[i].tag);
10895
            end = XSTRSTR(begin, "/");
10896
            if (end == NULL) {
10897
                end = begin + XSTRLEN(begin); /* remainder of string */
10898
            }
10899
            if (end > begin) {
10900
                len = (word32)(size_t)(end - begin);
10901
            }
10902
            if (len > CTC_NAME_SIZE-1) {
10903
                len = CTC_NAME_SIZE-1; /* leave room for null term */
10904
            }
10905
            /* Clear only the component being written: SetSubject may be
10906
             * called more than once to build a DN, so components absent from
10907
             * this subject must survive */
10908
            dst = (char*)name + tags[i].certNameOff;
10909
            XMEMSET(dst, 0, CTC_NAME_SIZE);
10910
            XMEMCPY(dst, begin, len);
10911
            dst[len] = '\0';
10912
        }
10913
    }
10914
    return rc;
10915
}
10916
10917
typedef struct CSRKey {
10918
    int keyType;
10919
    int tpmDevId;
10920
    WOLFTPM2_KEY* tpmKey;
10921
    union {
10922
    #ifndef NO_RSA
10923
        RsaKey rsa;
10924
    #endif
10925
    #ifdef HAVE_ECC
10926
        ecc_key ecc;
10927
    #endif
10928
    } key;
10929
    TpmCryptoDevCtx tpmCtx;
10930
} CSRKey;
10931
10932
#ifdef WOLFSSL_CERT_SIGN_CB
10933
/*
10934
 * Internal callback function for wc_SignCert_cb that uses TPM for signing.
10935
 *
10936
 * This callback implements the wc_SignCertCb interface to perform certificate
10937
 * and CSR signing using the TPM. It is used internally by CSR_MakeAndSign_Cb
10938
 * when the callback-based signing approach is selected.
10939
 *
10940
 * For RSA keys:
10941
 *   - Input is PKCS#1 v1.5 padded digest (already encoded by wolfSSL)
10942
 *   - Uses wolfTPM2_RsaDecrypt with TPM_ALG_NULL (no padding) to perform
10943
 *     the private key operation for signing
10944
 *
10945
 * For ECC keys:
10946
 *   - Input is the raw hash to sign
10947
 *   - Uses wolfTPM2_SignHash to sign with TPM
10948
 *   - Converts TPM's R||S format to DER-encoded ECDSA signature
10949
 *
10950
 * Parameters:
10951
 *   in       - Data to sign (encoded for RSA, raw hash for ECC)
10952
 *   inLen    - Length of input data
10953
 *   out      - Output buffer for signature
10954
 *   outLen   - Input: buffer size, Output: signature size
10955
 *   sigAlgo  - Signature algorithm (not used, determined by keyType)
10956
 *   keyType  - Key type (RSA_TYPE or ECC_TYPE)
10957
 *   ctx      - TpmSignCbCtx containing TPM device and key
10958
 *
10959
 * Returns:
10960
 *   0 on success
10961
 *   BAD_FUNC_ARG on invalid parameters
10962
 *   NOT_COMPILED_IN if key type not supported
10963
 *   Other negative values on TPM errors
10964
 */
10965
static int wolfTPM2_SignCertCb(const byte* in, word32 inLen,
10966
    byte* out, word32* outLen, int sigAlgo, int keyType, void* ctx)
10967
{
10968
    int rc;
10969
    TpmSignCbCtx* tpmCtx = (TpmSignCbCtx*)ctx;
10970
10971
    if (tpmCtx == NULL || tpmCtx->dev == NULL || tpmCtx->key == NULL ||
10972
            in == NULL || out == NULL || outLen == NULL) {
10973
        return BAD_FUNC_ARG;
10974
    }
10975
10976
    (void)sigAlgo; /* Algorithm determined by key type */
10977
10978
    if (keyType == ECC_TYPE) {
10979
#ifdef HAVE_ECC
10980
        byte sigRS[MAX_ECC_BYTES * 2];
10981
        int rsLen = (int)sizeof(sigRS);
10982
10983
        /* Sign using TPM */
10984
        rc = wolfTPM2_SignHash(tpmCtx->dev, tpmCtx->key,
10985
            in, inLen, sigRS, &rsLen);
10986
10987
        if (rc == 0) {
10988
            byte *r, *s;
10989
            word32 rLen, sLen;
10990
10991
            /* Validate concatenated R||S length before splitting */
10992
            if (rsLen <= 0 || (rsLen & 1) != 0) {
10993
                rc = BAD_FUNC_ARG;
10994
            }
10995
            else {
10996
                /* Split R and S from concatenated signature */
10997
                rLen = sLen = (word32)(rsLen / 2);
10998
                r = &sigRS[0];
10999
                s = &sigRS[rLen];
11000
11001
                /* Encode as DER ECDSA signature */
11002
                rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outLen);
11003
            }
11004
        }
11005
#else
11006
        rc = NOT_COMPILED_IN;
11007
#endif
11008
    }
11009
    else if (keyType == RSA_TYPE) {
11010
#ifndef NO_RSA
11011
        int outSz = (int)*outLen;
11012
11013
        /* For RSA, input is already PKCS#1 v1.5 padded digest
11014
         * Use RSA decrypt (private key operation) for signing */
11015
        rc = wolfTPM2_RsaDecrypt(tpmCtx->dev, tpmCtx->key,
11016
            TPM_ALG_NULL, /* No padding - input is pre-padded */
11017
            in, inLen, out, &outSz);
11018
11019
        if (rc == 0) {
11020
            *outLen = (word32)outSz;
11021
        }
11022
#else
11023
        rc = NOT_COMPILED_IN;
11024
#endif
11025
    }
11026
    else {
11027
        rc = BAD_FUNC_ARG;
11028
    }
11029
11030
    return rc;
11031
}
11032
#endif /* WOLFSSL_CERT_SIGN_CB */
11033
11034
11035
static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key,
11036
    int outFormat, byte* out, int outSz, int selfSignCert)
11037
{
11038
    int rc = 0;
11039
11040
    if (dev == NULL || csr == NULL || key == NULL || out == NULL) {
11041
        return BAD_FUNC_ARG;
11042
    }
11043
11044
    if (rc == 0 && selfSignCert) {
11045
    #ifdef WOLFSSL_CERT_GEN
11046
        rc = wc_MakeCert_ex(&csr->req, out, outSz, key->keyType, &key->key,
11047
            wolfTPM2_GetRng(dev));
11048
    #else
11049
        rc = NOT_COMPILED_IN;
11050
    #endif
11051
    }
11052
    if (rc == 0 && !selfSignCert) {
11053
        rc = wc_MakeCertReq_ex(&csr->req, out, outSz, key->keyType, &key->key);
11054
    }
11055
11056
    if (rc >= 0) {
11057
        rc = wc_SignCert_ex(csr->req.bodySz, csr->req.sigType, out,
11058
            (word32)outSz, key->keyType, &key->key, wolfTPM2_GetRng(dev));
11059
    }
11060
11061
    /* Optionally convert to PEM */
11062
    if (rc >= 0 && outFormat == ENCODING_TYPE_PEM) {
11063
    #ifdef WOLFSSL_DER_TO_PEM
11064
    #ifdef WOLFTPM_SMALL_STACK
11065
        byte* tmp = (byte*)XMALLOC(rc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
11066
        if (tmp == NULL) {
11067
            rc = MEMORY_E;
11068
        }
11069
        else
11070
    #else
11071
        byte tmp[MAX_CONTEXT_SIZE];
11072
        if (rc > (int)sizeof(tmp)) {
11073
            rc = BUFFER_E;
11074
        }
11075
        else
11076
    #endif
11077
        {
11078
            int derSz = rc;
11079
            XMEMCPY(tmp, out, derSz);
11080
            XMEMSET(out, 0, outSz);
11081
            rc = wc_DerToPem(tmp, (word32)derSz, out, outSz,
11082
                selfSignCert ? CERT_TYPE : CERTREQ_TYPE);
11083
        #ifdef WOLFTPM_SMALL_STACK
11084
            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
11085
        #endif
11086
        }
11087
    #else
11088
        #ifdef DEBUG_WOLFTPM
11089
        printf("CSR_MakeAndSign PEM not supported\n");
11090
        #endif
11091
        rc = NOT_COMPILED_IN;
11092
    #endif
11093
    }
11094
11095
    return rc;
11096
}
11097
11098
#ifdef WOLFSSL_CERT_SIGN_CB
11099
/*
11100
 * Internal function for CSR/Certificate generation and signing using the
11101
 * callback-based approach.
11102
 *
11103
 * This function generates and signs a Certificate Signing Request (CSR) or
11104
 * self-signed certificate using the new wc_SignCert_cb() API. Unlike the
11105
 * legacy CSR_MakeAndSign() function which requires crypto callback setup,
11106
 * this function calls TPM signing directly via wolfTPM2_SignCertCb().
11107
 *
11108
 * Advantages of this approach:
11109
 *   - FIPS compliant (no wolfCrypt crypto offloading)
11110
 *   - Simpler code path (no crypto callback infrastructure)
11111
 *   - Direct TPM signing without intermediate key structures
11112
 *
11113
 * Parameters:
11114
 *   dev          - Initialized TPM device
11115
 *   csr          - CSR structure with subject, extensions, etc.
11116
 *   key          - TPM key to use for signing
11117
 *   keyType      - Key type (RSA_TYPE or ECC_TYPE)
11118
 *   outFormat    - Output format (ENCODING_TYPE_PEM or ENCODING_TYPE_ASN1)
11119
 *   out          - Output buffer
11120
 *   outSz        - Size of output buffer
11121
 *   selfSignCert - 1 to create self-signed cert, 0 for CSR
11122
 *
11123
 * Returns:
11124
 *   Positive value: size of generated CSR/certificate
11125
 *   BAD_FUNC_ARG: invalid parameters
11126
 *   BUFFER_E: output buffer too small
11127
 *   Other negative: error code from wolfSSL or TPM
11128
 */
11129
static int CSR_MakeAndSign_Cb(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11130
    WOLFTPM2_KEY* key, int keyType, int outFormat, byte* out, int outSz,
11131
    int selfSignCert)
11132
{
11133
    int rc = 0;
11134
    int keyInited = 0;
11135
    TpmSignCbCtx signCtx;
11136
    union {
11137
    #ifndef NO_RSA
11138
        RsaKey rsa;
11139
    #endif
11140
    #ifdef HAVE_ECC
11141
        ecc_key ecc;
11142
    #endif
11143
    } wolfKey;
11144
11145
    if (dev == NULL || csr == NULL || key == NULL || out == NULL) {
11146
        return BAD_FUNC_ARG;
11147
    }
11148
11149
    XMEMSET(&signCtx, 0, sizeof(signCtx));
11150
    XMEMSET(&wolfKey, 0, sizeof(wolfKey));
11151
11152
    /* Extract public key from TPM key into wolfCrypt key structure */
11153
    if (keyType == ECC_TYPE) {
11154
    #ifdef HAVE_ECC
11155
        rc = wc_ecc_init(&wolfKey.ecc);
11156
        if (rc == 0) {
11157
            keyInited = 1;
11158
            /* load public portion of key into wolf ECC Key */
11159
            rc = wolfTPM2_EccKey_TpmToWolf(dev, key, &wolfKey.ecc);
11160
        }
11161
    #else
11162
        rc = NOT_COMPILED_IN;
11163
    #endif
11164
    }
11165
    else if (keyType == RSA_TYPE) {
11166
    #ifndef NO_RSA
11167
        rc = wc_InitRsaKey(&wolfKey.rsa, NULL);
11168
        if (rc == 0) {
11169
            keyInited = 1;
11170
            /* load public portion of key into wolf RSA Key */
11171
            rc = wolfTPM2_RsaKey_TpmToWolf(dev, key, &wolfKey.rsa);
11172
        }
11173
    #else
11174
        rc = NOT_COMPILED_IN;
11175
    #endif
11176
    }
11177
    else {
11178
        rc = BAD_FUNC_ARG;
11179
    }
11180
11181
    /* Setup signing context */
11182
    if (rc == 0) {
11183
        signCtx.dev = dev;
11184
        signCtx.key = key;
11185
    }
11186
11187
#ifdef WOLFSSL_CERT_EXT
11188
    /* add SKID from the Public Key */
11189
    if (rc == 0) {
11190
        rc = wc_SetSubjectKeyIdFromPublicKey_ex(&csr->req, keyType, &wolfKey);
11191
    }
11192
#endif
11193
11194
    /* Create certificate body with public key */
11195
    if (rc == 0 && selfSignCert) {
11196
#ifdef WOLFSSL_CERT_GEN
11197
        rc = wc_MakeCert_ex(&csr->req, out, outSz, keyType, &wolfKey,
11198
            wolfTPM2_GetRng(dev));
11199
#else
11200
        rc = NOT_COMPILED_IN;
11201
#endif
11202
    }
11203
    if (rc == 0 && !selfSignCert) {
11204
        rc = wc_MakeCertReq_ex(&csr->req, out, outSz, keyType, &wolfKey);
11205
    }
11206
11207
    /* Sign using TPM via callback */
11208
    if (rc >= 0) {
11209
        rc = wc_SignCert_cb(csr->req.bodySz, csr->req.sigType, out,
11210
            (word32)outSz, keyType, wolfTPM2_SignCertCb, &signCtx,
11211
            wolfTPM2_GetRng(dev));
11212
    }
11213
11214
    /* Optionally convert to PEM */
11215
    if (rc >= 0 && outFormat == ENCODING_TYPE_PEM) {
11216
#ifdef WOLFSSL_DER_TO_PEM
11217
    #ifdef WOLFTPM_SMALL_STACK
11218
        byte* tmp = (byte*)XMALLOC(rc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
11219
        if (tmp == NULL) {
11220
            rc = MEMORY_E;
11221
        }
11222
        else
11223
    #else
11224
        byte tmp[MAX_CONTEXT_SIZE];
11225
        if (rc > (int)sizeof(tmp)) {
11226
            rc = BUFFER_E;
11227
        }
11228
        else
11229
    #endif
11230
        {
11231
            int derSz = rc;
11232
            XMEMCPY(tmp, out, derSz);
11233
            XMEMSET(out, 0, outSz);
11234
            rc = wc_DerToPem(tmp, (word32)derSz, out, outSz,
11235
                selfSignCert ? CERT_TYPE : CERTREQ_TYPE);
11236
        #ifdef WOLFTPM_SMALL_STACK
11237
            XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
11238
        #endif
11239
        }
11240
#else
11241
        #ifdef DEBUG_WOLFTPM
11242
        printf("CSR_MakeAndSign_Cb PEM not supported\n");
11243
        #endif
11244
        rc = NOT_COMPILED_IN;
11245
#endif
11246
    }
11247
11248
    /* Cleanup wolfCrypt key structure */
11249
    if (keyInited) {
11250
        if (keyType == ECC_TYPE) {
11251
        #ifdef HAVE_ECC
11252
            wc_ecc_free(&wolfKey.ecc);
11253
        #endif
11254
        }
11255
        else if (keyType == RSA_TYPE) {
11256
        #ifndef NO_RSA
11257
            wc_FreeRsaKey(&wolfKey.rsa);
11258
        #endif
11259
        }
11260
    }
11261
11262
    return rc;
11263
}
11264
#endif /* WOLFSSL_CERT_SIGN_CB */
11265
11266
11267
static int CSR_KeySetup(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, WOLFTPM2_KEY* key,
11268
    CSRKey* csrKey, int sigType, int devId)
11269
{
11270
    int rc;
11271
11272
    if (dev == NULL || key == NULL || csrKey == NULL) {
11273
        return BAD_FUNC_ARG;
11274
    }
11275
11276
    XMEMSET(csrKey, 0, sizeof(CSRKey));
11277
    csrKey->tpmDevId = INVALID_DEVID;
11278
    csrKey->tpmKey = key;
11279
11280
    /* confirm crypto callback is setup */
11281
    if (devId == INVALID_DEVID) {
11282
        /* Setup the wolf crypto device callback */
11283
    #ifndef NO_RSA
11284
        csrKey->tpmCtx.rsaKey = key;
11285
    #endif
11286
    #ifdef HAVE_ECC
11287
        csrKey->tpmCtx.eccKey = key;
11288
    #endif
11289
11290
        rc = wolfTPM2_GetTpmDevId(dev);
11291
        if (rc >= 0) {
11292
            devId = rc;
11293
            devId += 1; /* use a different devId for the CSR callback */
11294
            rc = 0;
11295
        }
11296
        if (rc == 0) {
11297
            csrKey->tpmCtx.dev = dev;
11298
            rc = wc_CryptoCb_RegisterDevice(devId, wolfTPM2_CryptoDevCb,
11299
                &csrKey->tpmCtx);
11300
        }
11301
        if (rc != 0) {
11302
            return rc;
11303
        }
11304
        csrKey->tpmDevId = devId;
11305
    }
11306
11307
    /* determine the type of key in WOLFTPM2_KEY */
11308
    if (key->pub.publicArea.type == TPM_ALG_ECC) {
11309
        csrKey->keyType = ECC_TYPE;
11310
11311
    #ifdef HAVE_ECC
11312
        /* setup wolf ECC key with TPM deviceID, so crypto callbacks are used */
11313
        rc = wc_ecc_init_ex(&csrKey->key.ecc, NULL, devId);
11314
        if (rc == 0) {
11315
            /* load public portion of key into wolf ECC Key */
11316
            rc = wolfTPM2_EccKey_TpmToWolf(dev, key, &csrKey->key.ecc);
11317
        }
11318
    #else
11319
        rc = NOT_COMPILED_IN;
11320
    #endif
11321
    }
11322
    else if (key->pub.publicArea.type == TPM_ALG_RSA) {
11323
        csrKey->keyType = RSA_TYPE;
11324
11325
    #ifndef NO_RSA
11326
        /* setup wolf RSA key with TPM deviceID, so crypto callbacks are used */
11327
        rc = wc_InitRsaKey_ex(&csrKey->key.rsa, NULL, devId);
11328
        if (rc == 0) {
11329
            /* load public portion of key into wolf RSA Key */
11330
            rc = wolfTPM2_RsaKey_TpmToWolf(dev, key, &csrKey->key.rsa);
11331
        }
11332
    #else
11333
        rc = NOT_COMPILED_IN;
11334
    #endif
11335
    }
11336
    else {
11337
    #ifdef DEBUG_WOLFTPM
11338
        printf("CSR_KeySetup invalid input key\n");
11339
    #endif
11340
        rc = BAD_FUNC_ARG;
11341
    }
11342
11343
    /* Set the signature type */
11344
    if (rc == 0) {
11345
        if (sigType == 0 && csrKey != NULL) {
11346
            /* Choose defaults if sigType is zero */
11347
            if (csrKey->keyType == RSA_TYPE) {
11348
                csr->req.sigType = CTC_SHA256wRSA;
11349
            }
11350
            else if (csrKey->keyType == ECC_TYPE) {
11351
                csr->req.sigType = CTC_SHA256wECDSA;
11352
            }
11353
        }
11354
        else if (sigType != 0) {
11355
            csr->req.sigType = sigType;
11356
        }
11357
    }
11358
11359
#ifdef WOLFSSL_CERT_EXT
11360
    /* add SKID from the Public Key */
11361
    if (rc == 0 && csrKey != NULL) {
11362
        rc = wc_SetSubjectKeyIdFromPublicKey_ex(&csr->req, csrKey->keyType,
11363
            &csrKey->key);
11364
    }
11365
#endif
11366
11367
    return rc;
11368
}
11369
11370
static void CSR_KeyCleanup(WOLFTPM2_DEV* dev, CSRKey* csrKey)
11371
{
11372
    if (dev != NULL && csrKey != NULL) {
11373
    #ifdef HAVE_ECC
11374
        if (csrKey->keyType == ECC_TYPE) {
11375
            wc_ecc_free(&csrKey->key.ecc);
11376
        }
11377
    #endif
11378
    #ifndef NO_RSA
11379
        if (csrKey->keyType == RSA_TYPE) {
11380
            wc_FreeRsaKey(&csrKey->key.rsa);
11381
        }
11382
    #endif
11383
        if (csrKey->tpmDevId != INVALID_DEVID) {
11384
            wolfTPM2_ClearCryptoDevCb(dev, csrKey->tpmDevId);
11385
        }
11386
    }
11387
}
11388
11389
int wolfTPM2_CSR_SetCustomExt(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11390
    int critical, const char *oid, const byte *der, word32 derSz)
11391
{
11392
    int rc;
11393
    if (csr == NULL) {
11394
        return BAD_FUNC_ARG;
11395
    }
11396
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CUSTOM_OID) && \
11397
    defined(HAVE_OID_ENCODING)
11398
    rc = wc_SetCustomExtension(&csr->req, critical, oid, der, derSz);
11399
#else
11400
    (void)critical;
11401
    (void)oid;
11402
    (void)der;
11403
    (void)derSz;
11404
    /* Requires:
11405
     * ./configure --enable-wolftpm --enable-certgen --enable-asn=template \
11406
                 CFLAGS="-DWOLFSSL_CUSTOM_OID -DHAVE_OID_ENCODING"
11407
     */
11408
    rc = NOT_COMPILED_IN;
11409
#endif
11410
    (void)dev; /* not used */
11411
    return rc;
11412
}
11413
11414
int wolfTPM2_CSR_SetSubject(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11415
    const char* subject)
11416
{
11417
    int rc = BAD_FUNC_ARG;
11418
    if (csr != NULL && subject != NULL) {
11419
        rc = CSR_Parse_DN(&csr->req.subject, subject);
11420
    }
11421
    (void)dev; /* not used */
11422
    return rc;
11423
}
11424
11425
int wolfTPM2_CSR_SetKeyUsage(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11426
    const char* keyUsage)
11427
{
11428
    int rc;
11429
11430
    if (csr == NULL) {
11431
        return BAD_FUNC_ARG;
11432
    }
11433
11434
#ifdef WOLFSSL_CERT_EXT
11435
    if (keyUsage == NULL) {
11436
        /* use a default key usage value */
11437
        keyUsage = "serverAuth,clientAuth,codeSigning";
11438
    }
11439
11440
    /* add Extended Key Usage */
11441
    rc = wc_SetExtKeyUsage(&csr->req, keyUsage);
11442
    if (rc == EXTKEYUSAGE_E) {
11443
        /* try setting key usage values */
11444
        rc = wc_SetKeyUsage(&csr->req, keyUsage);
11445
    }
11446
#else
11447
#ifdef DEBUG_WOLFTPM
11448
    printf("CSR_Generate key usage supplied, but not available\n");
11449
#endif
11450
    rc = NOT_COMPILED_IN;
11451
#endif
11452
    (void)dev; /* not used */
11453
    return rc;
11454
}
11455
11456
int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11457
    WOLFTPM2_KEY* key, int outFormat, byte* out, int outSz,
11458
    int sigType, int selfSignCert, int devId)
11459
{
11460
    int rc;
11461
11462
    if (dev == NULL || key == NULL || csr == NULL || out == NULL) {
11463
        return BAD_FUNC_ARG;
11464
    }
11465
11466
    /* Set version to 2 for self-signed certificates, 0 for regular CSRs per RFC2986 */
11467
    if (selfSignCert) {
11468
        csr->req.version = 2;
11469
    }
11470
    else {
11471
        csr->req.version = 0;
11472
    }
11473
11474
#ifdef WOLFSSL_CERT_SIGN_CB
11475
    /* Use new callback-based signing if devId not specified */
11476
    if (devId == INVALID_DEVID) {
11477
        int keyType;
11478
11479
        /* Determine key type from TPM key */
11480
        if (key->pub.publicArea.type == TPM_ALG_ECC) {
11481
            keyType = ECC_TYPE;
11482
        }
11483
        else if (key->pub.publicArea.type == TPM_ALG_RSA) {
11484
            keyType = RSA_TYPE;
11485
        }
11486
        else {
11487
            return BAD_FUNC_ARG;
11488
        }
11489
11490
        /* Set signature type if not specified */
11491
        if (sigType == 0) {
11492
            if (keyType == RSA_TYPE) {
11493
                csr->req.sigType = CTC_SHA256wRSA;
11494
            }
11495
            else if (keyType == ECC_TYPE) {
11496
                csr->req.sigType = CTC_SHA256wECDSA;
11497
            }
11498
        }
11499
        else {
11500
            csr->req.sigType = sigType;
11501
        }
11502
        rc = CSR_MakeAndSign_Cb(dev, csr, key, keyType, outFormat, out, outSz,
11503
            selfSignCert);
11504
    }
11505
    else
11506
#endif /* WOLFSSL_CERT_SIGN_CB */
11507
    {
11508
        /* Use crypto callback approach */
11509
        CSRKey csrKey;
11510
        rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId);
11511
        if (rc == 0) {
11512
            rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz,
11513
                selfSignCert);
11514
        }
11515
        CSR_KeyCleanup(dev, &csrKey);
11516
    }
11517
11518
    return rc;
11519
}
11520
int wolfTPM2_CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
11521
    WOLFTPM2_KEY* key, int outFormat, byte* out, int outSz)
11522
{
11523
    return wolfTPM2_CSR_MakeAndSign_ex(dev, csr, key, outFormat, out, outSz,
11524
        0, 0, INVALID_DEVID);
11525
}
11526
11527
int wolfTPM2_CSR_Generate_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
11528
    const char* subject, const char* keyUsage, int outFormat,
11529
    byte* out, int outSz, int sigType, int selfSignCert, int devId)
11530
{
11531
    int rc;
11532
    WOLFTPM2_CSR csr;
11533
    CSRKey csrKey;
11534
11535
    if (dev == NULL || key == NULL || subject == NULL || out == NULL) {
11536
        return BAD_FUNC_ARG;
11537
    }
11538
11539
    XMEMSET(&csrKey, 0, sizeof(csrKey));
11540
    rc = wc_InitCert(&csr.req);
11541
    if (rc == 0) {
11542
        /* Set version to 2 for self-signed certificates, 0 for regular CSRs per RFC2986 */
11543
        if (selfSignCert) {
11544
            csr.req.version = 2;
11545
        }
11546
        else {
11547
            csr.req.version = 0;
11548
        }
11549
11550
        rc = CSR_KeySetup(dev, &csr, key, &csrKey, sigType, devId);
11551
    }
11552
    if (rc == 0) {
11553
        rc = wolfTPM2_CSR_SetSubject(dev, &csr, subject);
11554
    }
11555
    if (rc == 0) {
11556
        rc = wolfTPM2_CSR_SetKeyUsage(dev, &csr, keyUsage);
11557
    }
11558
    if (rc == 0) {
11559
        rc = CSR_MakeAndSign(dev, &csr, &csrKey, outFormat, out, outSz,
11560
            selfSignCert);
11561
    }
11562
    CSR_KeyCleanup(dev, &csrKey);
11563
11564
    return rc;
11565
}
11566
11567
int wolfTPM2_CSR_Generate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
11568
    const char* subject, const char* keyUsage, int outFormat,
11569
    byte* out, int outSz)
11570
{
11571
    return wolfTPM2_CSR_Generate_ex(dev, key, subject, keyUsage, outFormat,
11572
        out, outSz, 0, 0, INVALID_DEVID);
11573
}
11574
11575
#endif /* WOLFTPM2_CERT_GEN && WOLFTPM_CRYPTOCB */
11576
11577
/******************************************************************************/
11578
/* --- END Certificate Signing Request (CSR) Functions -- */
11579
/******************************************************************************/
11580
11581
11582
11583
/******************************************************************************/
11584
/* --- BEGIN Policy Support -- */
11585
/******************************************************************************/
11586
11587
int wolfTPM2_PolicyRestart(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle)
11588
{
11589
    int rc;
11590
    PolicyRestart_In policyRestartIn[1];
11591
11592
    if (dev == NULL)
11593
        return BAD_FUNC_ARG;
11594
11595
    XMEMSET(policyRestartIn, 0, sizeof(PolicyRestart_In));
11596
11597
    policyRestartIn->sessionHandle = sessionHandle;
11598
11599
    rc = TPM2_PolicyRestart(policyRestartIn);
11600
11601
    return rc;
11602
}
11603
11604
int wolfTPM2_GetPolicyDigest(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
11605
    byte* policyDigest, word32* policyDigestSz)
11606
{
11607
    int rc;
11608
    PolicyGetDigest_In policyGetDigestIn[1];
11609
    PolicyGetDigest_Out policyGetDigestOut[1];
11610
11611
    if (dev == NULL || policyDigestSz == NULL)
11612
        return BAD_FUNC_ARG;
11613
11614
    XMEMSET(policyGetDigestIn, 0, sizeof(PolicyGetDigest_In));
11615
    XMEMSET(policyGetDigestOut, 0, sizeof(PolicyGetDigest_Out));
11616
11617
    policyGetDigestIn->policySession = sessionHandle;
11618
11619
    rc = TPM2_PolicyGetDigest(policyGetDigestIn, policyGetDigestOut);
11620
11621
    if (rc == 0) {
11622
        if (policyDigest == NULL) {
11623
            rc = LENGTH_ONLY_E;
11624
        }
11625
        else if (policyGetDigestOut->policyDigest.size > *policyDigestSz) {
11626
            rc = BUFFER_E;
11627
        }
11628
        else {
11629
            XMEMCPY(policyDigest, policyGetDigestOut->policyDigest.buffer,
11630
                policyGetDigestOut->policyDigest.size);
11631
        }
11632
11633
        *policyDigestSz = policyGetDigestOut->policyDigest.size;
11634
    }
11635
11636
    return rc;
11637
}
11638
11639
int wolfTPM2_PolicyPCR(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
11640
    TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz)
11641
{
11642
    int rc;
11643
    PolicyPCR_In policyPcr[1];
11644
11645
    if (dev == NULL || pcrArray == NULL || pcrArraySz == 0)
11646
        return BAD_FUNC_ARG;
11647
11648
    XMEMSET(policyPcr, 0, sizeof(PolicyPCR_In));
11649
11650
    /* add PolicyPCR to the policy */
11651
    policyPcr->policySession = sessionHandle;
11652
    TPM2_SetupPCRSelArray(&policyPcr->pcrs, pcrAlg, pcrArray, pcrArraySz);
11653
11654
    rc = TPM2_PolicyPCR(policyPcr);
11655
11656
    return rc;
11657
}
11658
11659
#ifdef WOLFTPM_SPDM
11660
int wolfTPM2_PolicyTransportSPDM(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
11661
    const TPM2B_NAME* reqKeyName, const TPM2B_NAME* tpmKeyName)
11662
{
11663
    int rc;
11664
    PolicyTransportSPDM_In in;
11665
11666
    if (dev == NULL)
11667
        return BAD_FUNC_ARG;
11668
11669
    XMEMSET(&in, 0, sizeof(in));
11670
    in.policySession = sessionHandle;
11671
    if (reqKeyName != NULL) {
11672
        if (reqKeyName->size > sizeof(in.reqKeyName.name))
11673
            return BUFFER_E;
11674
        in.reqKeyName.size = reqKeyName->size;
11675
        XMEMCPY(in.reqKeyName.name, reqKeyName->name, reqKeyName->size);
11676
    }
11677
    if (tpmKeyName != NULL) {
11678
        if (tpmKeyName->size > sizeof(in.tpmKeyName.name))
11679
            return BUFFER_E;
11680
        in.tpmKeyName.size = tpmKeyName->size;
11681
        XMEMCPY(in.tpmKeyName.name, tpmKeyName->name, tpmKeyName->size);
11682
    }
11683
11684
    rc = TPM2_PolicyTransportSPDM(&in);
11685
#ifdef DEBUG_WOLFTPM
11686
    if (rc != TPM_RC_SUCCESS) {
11687
        printf("wolfTPM2_PolicyTransportSPDM failed 0x%x: %s\n",
11688
            rc, TPM2_GetRCString(rc));
11689
    }
11690
#endif
11691
    return rc;
11692
}
11693
#endif /* WOLFTPM_SPDM */
11694
11695
/* Use this password (in clear) for the policy session instead of the HMAC */
11696
int wolfTPM2_PolicyPassword(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
11697
    const byte* auth, int authSz)
11698
{
11699
    PolicyPassword_In policyPasswordIn;
11700
11701
    if (dev == NULL || tpmSession == NULL) {
11702
        return BAD_FUNC_ARG;
11703
    }
11704
11705
    if (auth != NULL && authSz >= 0) {
11706
        if (authSz > (int)sizeof(tpmSession->handle.auth.buffer)) {
11707
            return BUFFER_E;
11708
        }
11709
        XMEMMOVE(tpmSession->handle.auth.buffer, auth, authSz);
11710
        if ((word32)authSz < sizeof(tpmSession->handle.auth.buffer)) {
11711
            TPM2_ForceZero(&tpmSession->handle.auth.buffer[authSz],
11712
                (word32)sizeof(tpmSession->handle.auth.buffer) -
11713
                    (word32)authSz);
11714
        }
11715
        tpmSession->handle.auth.size = (UINT16)authSz;
11716
        tpmSession->handle.policyPass = 1;
11717
    }
11718
11719
    XMEMSET(&policyPasswordIn, 0, sizeof(policyPasswordIn));
11720
    policyPasswordIn.policySession = tpmSession->handle.hndl;
11721
11722
    return TPM2_PolicyPassword(&policyPasswordIn);
11723
}
11724
11725
/* Use this auth with HMAC key on HMAC computation */
11726
int wolfTPM2_PolicyAuthValue(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
11727
    const byte* auth, int authSz)
11728
{
11729
    PolicyAuthValue_In policyAuthValueIn;
11730
11731
    if (dev == NULL || tpmSession == NULL) {
11732
        return BAD_FUNC_ARG;
11733
    }
11734
11735
    if (auth != NULL && authSz >= 0) {
11736
        int authDigestSz = TPM2_GetHashDigestSize(tpmSession->authHash);
11737
        if (authDigestSz <= 0 ||
11738
            authDigestSz > (int)sizeof(tpmSession->handle.auth.buffer) ||
11739
            authSz > (int)sizeof(tpmSession->handle.auth.buffer) -
11740
                authDigestSz) {
11741
            return BUFFER_E;
11742
        }
11743
        /* leave room for the computed HMAC key */
11744
        XMEMMOVE(&tpmSession->handle.auth.buffer[authDigestSz], auth, authSz);
11745
        tpmSession->handle.auth.size = (UINT16)(authDigestSz + authSz);
11746
        if (tpmSession->handle.auth.size <
11747
                sizeof(tpmSession->handle.auth.buffer)) {
11748
            TPM2_ForceZero(&tpmSession->handle.auth.buffer[
11749
                    tpmSession->handle.auth.size],
11750
                (word32)sizeof(tpmSession->handle.auth.buffer) -
11751
                    tpmSession->handle.auth.size);
11752
        }
11753
        tpmSession->handle.policyAuth = 1;
11754
    }
11755
11756
    XMEMSET(&policyAuthValueIn, 0, sizeof(policyAuthValueIn));
11757
    policyAuthValueIn.policySession = tpmSession->handle.hndl;
11758
11759
    return TPM2_PolicyAuthValue(&policyAuthValueIn);
11760
}
11761
11762
int wolfTPM2_PolicyCommandCode(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
11763
    TPM_CC cc)
11764
{
11765
    PolicyCommandCode_In policyCC;
11766
11767
    if (dev == NULL || tpmSession == NULL) {
11768
        return BAD_FUNC_ARG;
11769
    }
11770
11771
    XMEMSET(&policyCC, 0, sizeof(policyCC));
11772
    policyCC.policySession = tpmSession->handle.hndl;
11773
    policyCC.code = cc;
11774
    return TPM2_PolicyCommandCode(&policyCC);
11775
}
11776
11777
/* Satisfy a policy session with a compound OR of pre-computed policy digests.
11778
 * The digest list is hash-agnostic (each branch carries its own size), so it
11779
 * works for SHA2-256 as well as SHA2-512 policy branches. */
11780
int wolfTPM2_PolicyOR(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession,
11781
    const TPML_DIGEST* pHashList)
11782
{
11783
    PolicyOR_In policyOR;
11784
    word32 i;
11785
11786
    if (dev == NULL || tpmSession == NULL || pHashList == NULL) {
11787
        return BAD_FUNC_ARG;
11788
    }
11789
    /* TPM 2.0 Part 3 Sec.23.6 requires at least two digests, so reject a
11790
     * one-branch list here rather than letting the TPM return TPM_RC_VALUE. */
11791
    if (pHashList->count < 2 ||
11792
            pHashList->count > (word32)(sizeof(pHashList->digests) /
11793
                sizeof(pHashList->digests[0]))) {
11794
        return BAD_FUNC_ARG;
11795
    }
11796
    /* Validate each branch digest size against its buffer so TPM2_PolicyOR
11797
     * cannot marshal past the fixed digest buffer (out-of-bounds read). */
11798
    for (i = 0; i < pHashList->count; i++) {
11799
        if (pHashList->digests[i].size >
11800
                (UINT16)sizeof(pHashList->digests[i].buffer)) {
11801
            return BAD_FUNC_ARG;
11802
        }
11803
    }
11804
11805
    XMEMSET(&policyOR, 0, sizeof(policyOR));
11806
    policyOR.policySession = tpmSession->handle.hndl;
11807
    XMEMCPY(&policyOR.pHashList, pHashList, sizeof(policyOR.pHashList));
11808
    return TPM2_PolicyOR(&policyOR);
11809
}
11810
11811
/* Set (or clear) the authPolicy for a hierarchy (owner/endorsement/platform/
11812
 * lockout). Pass authPolicy=NULL/authPolicySz=0 with hashAlg=TPM_ALG_NULL to
11813
 * clear an existing policy. */
11814
int wolfTPM2_SetPrimaryPolicy(WOLFTPM2_DEV* dev,
11815
    TPMI_RH_HIERARCHY_AUTH authHandle, TPM_ALG_ID hashAlg,
11816
    const byte* authPolicy, word32 authPolicySz)
11817
{
11818
    SetPrimaryPolicy_In in;
11819
11820
    if (dev == NULL) {
11821
        return BAD_FUNC_ARG;
11822
    }
11823
    if (authPolicySz > (word32)sizeof(in.authPolicy.buffer)) {
11824
        return BAD_FUNC_ARG;
11825
    }
11826
    /* Reject NULL policy with a non-zero size: setting size 0 here would clear
11827
     * the policy, silently downgrading "set" to "remove all policy" */
11828
    if (authPolicy == NULL && authPolicySz > 0) {
11829
        return BAD_FUNC_ARG;
11830
    }
11831
11832
    XMEMSET(&in, 0, sizeof(in));
11833
    in.authHandle = authHandle;
11834
    in.hashAlg = hashAlg;
11835
    if (authPolicy != NULL && authPolicySz > 0) {
11836
        in.authPolicy.size = (UINT16)authPolicySz;
11837
        XMEMCPY(in.authPolicy.buffer, authPolicy, authPolicySz);
11838
    }
11839
    return TPM2_SetPrimaryPolicy(&in);
11840
}
11841
11842
#ifndef WOLFTPM2_NO_WOLFCRYPT
11843
/* Authorize a policy based on external key for a verified policy digiest signature */
11844
int wolfTPM2_PolicyAuthorize(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle,
11845
    const TPM2B_PUBLIC* pub, const TPMT_TK_VERIFIED* checkTicket,
11846
    const byte* pcrDigest, word32 pcrDigestSz,
11847
    const byte* policyRef, word32 policyRefSz)
11848
{
11849
    int rc;
11850
    PolicyAuthorize_In policyAuthIn;
11851
11852
    if (dev == NULL || pub == NULL || checkTicket == NULL || pcrDigest == NULL) {
11853
        return BAD_FUNC_ARG;
11854
    }
11855
11856
    XMEMSET(&policyAuthIn, 0, sizeof(policyAuthIn));
11857
    policyAuthIn.policySession = sessionHandle;
11858
    XMEMCPY(&policyAuthIn.checkTicket, checkTicket, sizeof(TPMT_TK_VERIFIED));
11859
11860
    /* set the approved policy digest */
11861
    if (pcrDigestSz > sizeof(policyAuthIn.approvedPolicy.buffer)) {
11862
        return BUFFER_E;
11863
    }
11864
    policyAuthIn.approvedPolicy.size = pcrDigestSz;
11865
    XMEMCPY(policyAuthIn.approvedPolicy.buffer, pcrDigest, pcrDigestSz);
11866
11867
    /* policyRef (nonce) */
11868
    if (policyRefSz > sizeof(policyAuthIn.policyRef.buffer)) {
11869
        return BUFFER_E;
11870
    }
11871
    policyAuthIn.policyRef.size = policyRefSz;
11872
    if (policyRef != NULL) {
11873
        XMEMCPY(policyAuthIn.policyRef.buffer, policyRef, policyRefSz);
11874
    }
11875
11876
    /* Compute name for the authoring public key for policy */
11877
    rc = wolfTPM2_ComputeName(pub, &policyAuthIn.keySign);
11878
    if (rc == TPM_RC_SUCCESS) {
11879
        rc = TPM2_PolicyAuthorize(&policyAuthIn);
11880
    }
11881
#ifdef DEBUG_WOLFTPM
11882
    if (rc != TPM_RC_SUCCESS) {
11883
        printf("PolicyAuthorize failed %d: %s\n", rc, wolfTPM2_GetRCString(rc));
11884
    }
11885
#endif
11886
    return rc;
11887
}
11888
11889
/* Build Hash of PCR's */
11890
int wolfTPM2_PCRGetDigest(WOLFTPM2_DEV* dev, TPM_ALG_ID pcrAlg,
11891
    byte* pcrArray, word32 pcrArraySz, byte* pcrDigest, word32* pcrDigestSz)
11892
{
11893
    int rc;
11894
    word32 i;
11895
    enum wc_HashType hashType;
11896
    wc_HashAlg hash_ctx;
11897
11898
    if (dev == NULL || pcrArray == NULL || pcrArraySz == 0 ||
11899
            pcrDigest == NULL || pcrDigestSz == NULL) {
11900
        return BAD_FUNC_ARG;
11901
    }
11902
11903
    rc = TPM2_GetHashType(pcrAlg);
11904
    hashType = (enum wc_HashType)rc;
11905
    rc = wc_HashGetDigestSize(hashType);
11906
    if (rc < 0)
11907
        return rc;
11908
    *pcrDigestSz = rc; /* set actual size */
11909
11910
    rc = wc_HashInit(&hash_ctx, hashType);
11911
    if (rc != 0)
11912
        return rc;
11913
11914
    /* PCR(s) hash */
11915
    for (i=0; i<pcrArraySz && rc == 0; i++) {
11916
        rc = wolfTPM2_ReadPCR(dev, pcrArray[i], pcrAlg,
11917
            pcrDigest, (int*)pcrDigestSz);
11918
        if (rc == 0) {
11919
            rc = wc_HashUpdate(&hash_ctx, hashType, pcrDigest, *pcrDigestSz);
11920
        }
11921
    }
11922
    if (rc == 0) {
11923
        rc = wc_HashFinal(&hash_ctx, hashType, pcrDigest);
11924
    }
11925
    wc_HashFree(&hash_ctx, hashType);
11926
    TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx));
11927
11928
#ifdef DEBUG_WOLFTPM
11929
    if (rc != 0) {
11930
        printf("wolfTPM2_PCRGetDigest failed %d: %s\n",
11931
            rc, wolfTPM2_GetRCString(rc));
11932
    }
11933
    #ifdef WOLFTPM_DEBUG_VERBOSE
11934
    else {
11935
        printf("wolfTPM2_PCRGetDigest: %d\n", *pcrDigestSz);
11936
        TPM2_PrintBin(pcrDigest, *pcrDigestSz);
11937
    }
11938
    #endif
11939
#endif
11940
    return rc;
11941
}
11942
11943
/* Generic Policy Hashing Function */
11944
/* digest is in/out (input "old" / output "new") */
11945
/* policyDigestnew = hash(policyDigestOld || [cc] || [Input]) */
11946
int wolfTPM2_PolicyHash(TPM_ALG_ID hashAlg,
11947
    byte* digest, word32* digestSz, TPM_CC cc,
11948
    const byte* input, word32 inputSz)
11949
{
11950
    int rc;
11951
    word32 val;
11952
    enum wc_HashType hashType;
11953
    wc_HashAlg hash_ctx;
11954
    word32 inSz;
11955
11956
    if (digest == NULL || digestSz == NULL ||
11957
        (input == NULL && inputSz > 0)) {
11958
        return BAD_FUNC_ARG;
11959
    }
11960
11961
    inSz = *digestSz; /* capture input digest size (for policyDigestOld) */
11962
    rc = TPM2_GetHashType(hashAlg);
11963
    hashType = (enum wc_HashType)rc;
11964
    rc = wc_HashGetDigestSize(hashType);
11965
    if (rc < 0)
11966
        return rc;
11967
    *digestSz = rc;
11968
11969
    rc = wc_HashInit(&hash_ctx, hashType);
11970
    if (rc != 0)
11971
        return rc;
11972
11973
    /* policyDigestOld */
11974
    if (rc == 0 && inSz > 0) {
11975
        /* old digest cannot be larger than digest size */
11976
        if (inSz > *digestSz)
11977
            inSz = *digestSz;
11978
        rc = wc_HashUpdate(&hash_ctx, hashType, digest, inSz);
11979
    }
11980
    /* Command Code (optional) */
11981
    if (rc == 0 && cc >= TPM_CC_FIRST) {
11982
        val = TPM2_Packet_SwapU32(cc);
11983
        rc = wc_HashUpdate(&hash_ctx, hashType, (byte*)&val, sizeof(val));
11984
    }
11985
    /* Input (optional) */
11986
    if (rc == 0 && input != NULL && inputSz > 0) {
11987
        rc = wc_HashUpdate(&hash_ctx, hashType, input, inputSz);
11988
    }
11989
    if (rc == 0) {
11990
        rc = wc_HashFinal(&hash_ctx, hashType, digest);
11991
    }
11992
    wc_HashFree(&hash_ctx, hashType);
11993
    TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx));
11994
11995
#ifdef DEBUG_WOLFTPM
11996
    if (rc != 0) {
11997
        printf("wolfTPM2_PolicyHash failed %d: %s\n",
11998
            rc, wolfTPM2_GetRCString(rc));
11999
    }
12000
    #ifdef WOLFTPM_DEBUG_VERBOSE
12001
    else {
12002
        printf("wolfTPM2_PolicyHash: %d\n", *digestSz);
12003
        TPM2_PrintBin(digest, *digestSz);
12004
    }
12005
    #endif
12006
#endif
12007
    return rc;
12008
}
12009
12010
/* Assemble a PolicyCommandCode digest for a fresh policy session */
12011
/* policyDigest = hash(zeroDigest || TPM_CC_PolicyCommandCode || cc) */
12012
/* digestSz is in/out: input is the digest buffer capacity, output is the
12013
 * hash size actually written */
12014
int wolfTPM2_PolicyCommandCodeMake(TPM_ALG_ID hashAlg,
12015
    byte* digest, word32* digestSz, TPM_CC cc)
12016
{
12017
    int hashSz;
12018
    byte val[4]; /* command code big-endian, matching the TPM wire format */
12019
12020
    if (digest == NULL || digestSz == NULL) {
12021
        return BAD_FUNC_ARG;
12022
    }
12023
    hashSz = TPM2_GetHashDigestSize(hashAlg);
12024
    if (hashSz <= 0) {
12025
        return BAD_FUNC_ARG;
12026
    }
12027
    /* The whole hash is written to digest, so the caller must supply at least
12028
     * that much room. Checked before any write, since *digestSz (the capacity)
12029
     * is overwritten with the output size below. */
12030
    if (*digestSz < (word32)hashSz) {
12031
        return BUFFER_E;
12032
    }
12033
    /* fresh policy session starts from a zero digest of the hash size */
12034
    XMEMSET(digest, 0, hashSz);
12035
    *digestSz = (word32)hashSz;
12036
12037
    val[0] = (byte)((cc >> 24) & 0xFF);
12038
    val[1] = (byte)((cc >> 16) & 0xFF);
12039
    val[2] = (byte)((cc >> 8) & 0xFF);
12040
    val[3] = (byte)(cc & 0xFF);
12041
    return wolfTPM2_PolicyHash(hashAlg, digest, digestSz,
12042
        TPM_CC_PolicyCommandCode, val, sizeof(val));
12043
}
12044
12045
/* Assemble a PCR policy */
12046
/* policyDigestnew = hash(policyDigestOld || TPM_CC_PolicyPCR  || PCRS ||
12047
 *                        pcrDigest) */
12048
int wolfTPM2_PolicyPCRMake(TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz,
12049
    const byte* pcrDigest, word32 pcrDigestSz, byte* digest, word32* digestSz)
12050
{
12051
    int rc;
12052
    int hashSz;
12053
    TPM2_Packet packet;
12054
    byte buf[sizeof(TPML_PCR_SELECTION)+WC_MAX_DIGEST_SIZE];
12055
    TPML_PCR_SELECTION pcr;
12056
12057
    if (digest == NULL || digestSz == NULL || pcrArray == NULL ||
12058
        pcrArraySz == 0 || (pcrDigest == NULL && pcrDigestSz > 0)) {
12059
        return BAD_FUNC_ARG;
12060
    }
12061
    hashSz = TPM2_GetHashDigestSize(pcrAlg);
12062
    if (hashSz <= 0) {
12063
        return BAD_FUNC_ARG;
12064
    }
12065
    if (*digestSz < (word32)hashSz) {
12066
        return BUFFER_E;
12067
    }
12068
12069
    /* Build PCRS (PCR Count and PCR Selection) */
12070
    XMEMSET(&pcr, 0, sizeof(pcr));
12071
    XMEMSET(&packet, 0, sizeof(packet));
12072
    TPM2_SetupPCRSelArray(&pcr, pcrAlg, pcrArray, pcrArraySz);
12073
    packet.buf = buf;
12074
    packet.size = (int)sizeof(buf);
12075
    TPM2_Packet_AppendPCR(&packet, &pcr);
12076
12077
    /* Copy the pcrDigest to the end of buffer */
12078
    if (packet.overflow || packet.pos > packet.size) {
12079
        return BUFFER_E;
12080
    }
12081
    if (pcrDigestSz > 0) {
12082
        if (packet.pos >= packet.size ||
12083
            pcrDigestSz > (word32)(packet.size - packet.pos)) {
12084
            return BUFFER_E;
12085
        }
12086
        XMEMCPY(buf + packet.pos, pcrDigest, pcrDigestSz);
12087
        packet.pos += (int)pcrDigestSz;
12088
    }
12089
12090
    rc = wolfTPM2_PolicyHash(pcrAlg, digest, digestSz, TPM_CC_PolicyPCR,
12091
        buf, packet.pos);
12092
12093
#ifdef DEBUG_WOLFTPM
12094
    if (rc != 0) {
12095
        printf("wolfTPM2_PolicyPCRMake failed %d: %s\n",
12096
            rc, wolfTPM2_GetRCString(rc));
12097
    }
12098
    #ifdef WOLFTPM_DEBUG_VERBOSE
12099
    else {
12100
        printf("wolfTPM2_PolicyPCRMake: %d\n", *digestSz);
12101
        TPM2_PrintBin(digest, *digestSz);
12102
    }
12103
    #endif
12104
#endif
12105
    return rc;
12106
}
12107
12108
#ifdef WOLFTPM_SPDM
12109
/* A non-empty SPDM key name is nameAlg(2) || digest and must match the hash
12110
 * the TPM would require; empty names are allowed. Mirrors the TPM-side check
12111
 * so an offline authPolicy cannot be built from a name the TPM rejects. */
12112
static int wolfTPM2_CheckSpdmName(const TPM2B_NAME* name)
12113
{
12114
    UINT16 alg;
12115
    int digestSz;
12116
12117
    if (name == NULL || name->size == 0) {
12118
        return TPM_RC_SUCCESS;
12119
    }
12120
    if (name->size < 2 || name->size > sizeof(name->name)) {
12121
        return BAD_FUNC_ARG;
12122
    }
12123
    alg = (UINT16)(((UINT16)name->name[0] << 8) | name->name[1]);
12124
    digestSz = TPM2_GetHashDigestSize(alg);
12125
    if (digestSz <= 0 || (int)name->size - 2 != digestSz) {
12126
        return BAD_FUNC_ARG;
12127
    }
12128
    return TPM_RC_SUCCESS;
12129
}
12130
12131
/* Part 3 PolicyTransportSPDM: when either name is present the policy binds
12132
 * scKeyNameHash = H(req.size || req.name || tpm.size || tpm.name), else an
12133
 * empty buffer. digest is policyDigestOld in and policyDigestNew out. */
12134
int wolfTPM2_PolicyTransportSPDMMake(TPM_ALG_ID hashAlg,
12135
    const TPM2B_NAME* reqKeyName, const TPM2B_NAME* tpmKeyName,
12136
    byte* digest, word32* digestSz)
12137
{
12138
    int rc;
12139
    int hashSz;
12140
    word32 pos = 0;
12141
    word32 scSz = 0;
12142
    byte sc[TPM_MAX_DIGEST_SIZE];
12143
    byte buf[2 * (sizeof(UINT16) + sizeof(TPM2B_NAME))];
12144
    UINT16 reqSz = (reqKeyName != NULL) ? reqKeyName->size : 0;
12145
    UINT16 tpmSz = (tpmKeyName != NULL) ? tpmKeyName->size : 0;
12146
12147
    if (digest == NULL || digestSz == NULL ||
12148
        reqSz > sizeof(reqKeyName->name) || tpmSz > sizeof(tpmKeyName->name)) {
12149
        return BAD_FUNC_ARG;
12150
    }
12151
    if (wolfTPM2_CheckSpdmName(reqKeyName) != TPM_RC_SUCCESS ||
12152
        wolfTPM2_CheckSpdmName(tpmKeyName) != TPM_RC_SUCCESS) {
12153
        return BAD_FUNC_ARG;
12154
    }
12155
    hashSz = TPM2_GetHashDigestSize(hashAlg);
12156
    if (hashSz <= 0) {
12157
        return BAD_FUNC_ARG;
12158
    }
12159
    if (*digestSz < (word32)hashSz) {
12160
        return BUFFER_E;
12161
    }
12162
12163
    rc = TPM_RC_SUCCESS;
12164
    if (reqSz > 0 || tpmSz > 0) {
12165
        buf[pos++] = (byte)(reqSz >> 8);
12166
        buf[pos++] = (byte)reqSz;
12167
        if (reqSz > 0) {
12168
            XMEMCPY(buf + pos, reqKeyName->name, reqSz);
12169
            pos += reqSz;
12170
        }
12171
        buf[pos++] = (byte)(tpmSz >> 8);
12172
        buf[pos++] = (byte)tpmSz;
12173
        if (tpmSz > 0) {
12174
            XMEMCPY(buf + pos, tpmKeyName->name, tpmSz);
12175
            pos += tpmSz;
12176
        }
12177
        scSz = 0; /* no policyDigestOld for the key name hash */
12178
        rc = wolfTPM2_PolicyHash(hashAlg, sc, &scSz, 0, buf, pos);
12179
    }
12180
    if (rc == TPM_RC_SUCCESS) {
12181
        rc = wolfTPM2_PolicyHash(hashAlg, digest, digestSz,
12182
            TPM_CC_PolicyTransportSPDM, sc, scSz);
12183
    }
12184
12185
#ifdef DEBUG_WOLFTPM
12186
    if (rc != 0) {
12187
        printf("wolfTPM2_PolicyTransportSPDMMake failed %d: %s\n",
12188
            rc, wolfTPM2_GetRCString(rc));
12189
    }
12190
#endif
12191
    return rc;
12192
}
12193
#endif /* WOLFTPM_SPDM */
12194
12195
/* Assemble a PCR policy ref - optional */
12196
/* aHash = hash(approvedPolicy || policyRef) */
12197
int wolfTPM2_PolicyRefMake(TPM_ALG_ID pcrAlg, byte* digest, word32* digestSz,
12198
    const byte* policyRef, word32 policyRefSz)
12199
{
12200
    return wolfTPM2_PolicyHash(pcrAlg, digest, digestSz, 0,
12201
        policyRef, policyRefSz);
12202
}
12203
12204
/* Assemble a PCR Authorization for a public key */
12205
/* policyDigestnew = hash(policyDigestOld || TPM_CC_PolicyAuthorize ||
12206
 *                        Public.Name || PolicyRef) */
12207
int wolfTPM2_PolicyAuthorizeMake(TPM_ALG_ID pcrAlg,
12208
    const TPM2B_PUBLIC* pub, byte* digest, word32* digestSz,
12209
    const byte* policyRef, word32 policyRefSz)
12210
{
12211
    int rc;
12212
    TPM2B_NAME name;
12213
12214
    if (digest == NULL || digestSz == NULL || pub == NULL) {
12215
        return BAD_FUNC_ARG;
12216
    }
12217
12218
    rc = wolfTPM2_ComputeName(pub, &name);
12219
    if (rc == 0) {
12220
        rc = wolfTPM2_PolicyHash(pcrAlg, digest, digestSz,
12221
            TPM_CC_PolicyAuthorize, name.name, name.size);
12222
    }
12223
    if (rc == 0) {
12224
        rc = wolfTPM2_PolicyRefMake(pcrAlg, digest, digestSz,
12225
            policyRef, policyRefSz);
12226
    }
12227
12228
#ifdef DEBUG_WOLFTPM
12229
    if (rc != 0) {
12230
        printf("wolfTPM2_PolicyAuthorizeMake failed %d: %s\n",
12231
            rc, wolfTPM2_GetRCString(rc));
12232
    }
12233
    #ifdef WOLFTPM_DEBUG_VERBOSE
12234
    else {
12235
        printf("wolfTPM2_PolicyAuthorizeMake: %d\n", *digestSz);
12236
        TPM2_PrintBin(digest, *digestSz);
12237
    }
12238
    #endif
12239
#endif
12240
    return rc;
12241
}
12242
12243
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
12244
12245
/******************************************************************************/
12246
/* --- END Policy Support -- */
12247
/******************************************************************************/
12248
12249
12250
/******************************************************************************/
12251
/* --- BEGIN Provisioned TPM Support -- */
12252
/******************************************************************************/
12253
12254
/* pre-provisioned IAK and IDevID key/cert from TPM vendor */
12255
#ifdef WOLFTPM_MFG_IDENTITY
12256
12257
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12258
static const uint8_t TPM2_IAK_SAMPLE_MASTER_PASSWORD[] = {
12259
    0xFE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00,
12260
    0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B
12261
};
12262
#endif
12263
12264
int wolfTPM2_SetIdentityAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle,
12265
    uint8_t* masterPassword, uint16_t masterPasswordSz)
12266
{
12267
    int rc;
12268
    uint8_t serialNum[7];
12269
    wc_HashAlg hash_ctx;
12270
    enum wc_HashType hashType = WC_HASH_TYPE_SHA256;
12271
    uint8_t digest[TPM_SHA256_DIGEST_SIZE];
12272
12273
    if (handle == NULL) {
12274
        return BAD_FUNC_ARG;
12275
    }
12276
12277
#if !defined(WOLFTPM_ST33) && !defined(WOLFTPM_AUTODETECT)
12278
    /* The sample master password only provisions ST33 sample parts; require an
12279
     * explicit secret on other targets rather than deriving from a public value */
12280
    if (masterPassword == NULL || masterPasswordSz == 0) {
12281
        return BAD_FUNC_ARG;
12282
    }
12283
#endif
12284
12285
    /* Get TPM serial number */
12286
    rc = TPM2_GetProductInfo(serialNum, (uint16_t)sizeof(serialNum));
12287
    if (rc != 0) {
12288
    #ifdef DEBUG_WOLFTPM
12289
        printf("TPM2_GetProductInfo failed %d: %s\n",
12290
            rc, wolfTPM2_GetRCString(rc));
12291
    #endif
12292
        return rc;
12293
    }
12294
#ifdef DEBUG_WOLFTPM
12295
    printf("TPM Serial Number (%d bytes)\n", (int)sizeof(serialNum));
12296
    TPM2_PrintBin(serialNum, sizeof(serialNum));
12297
#endif
12298
12299
    /* Hash both values */
12300
    rc = wc_HashInit(&hash_ctx, hashType);
12301
    if (rc == 0) {
12302
        rc = wc_HashUpdate(&hash_ctx, hashType, serialNum, sizeof(serialNum));
12303
        if (rc == 0) {
12304
            if (masterPassword != NULL && masterPasswordSz > 0) {
12305
                rc = wc_HashUpdate(&hash_ctx, hashType,
12306
                    masterPassword, masterPasswordSz);
12307
            }
12308
        #if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12309
            else {
12310
                rc = wc_HashUpdate(&hash_ctx, hashType,
12311
                    TPM2_IAK_SAMPLE_MASTER_PASSWORD,
12312
                    sizeof(TPM2_IAK_SAMPLE_MASTER_PASSWORD));
12313
            }
12314
        #endif
12315
        }
12316
        if (rc == 0) {
12317
            rc = wc_HashFinal(&hash_ctx, hashType, digest);
12318
        }
12319
12320
        wc_HashFree(&hash_ctx, hashType);
12321
        /* scrub the hash state: it retains trailing plaintext of the input */
12322
        TPM2_ForceZero(&hash_ctx, sizeof(hash_ctx));
12323
    }
12324
12325
    /* Only copy digest to handle auth when hashing succeeded — otherwise
12326
     * `digest` contains uninitialized stack data. */
12327
    TPM2_ForceZero(&handle->auth, sizeof(handle->auth));
12328
    if (rc == 0) {
12329
        /* Hash Final truncate to 16 bytes — use 16-byte auth for key access */
12330
        handle->auth.size = 16;
12331
        XMEMCPY(handle->auth.buffer, &digest[16], 16);
12332
    #ifdef DEBUG_WOLFTPM
12333
        printf("Handle 0x%x, Auth %d\n", handle->hndl, handle->auth.size);
12334
        #ifdef WOLFTPM_DEBUG_SECRETS
12335
            TPM2_PrintBin(handle->auth.buffer, handle->auth.size);
12336
        #endif
12337
    #endif
12338
    }
12339
    TPM2_ForceZero(digest, sizeof(digest));
12340
    TPM2_ForceZero(serialNum, sizeof(serialNum));
12341
12342
    (void)dev;
12343
12344
    return rc;
12345
}
12346
12347
#endif /* WOLFTPM_MFG_IDENTITY */
12348
12349
/******************************************************************************/
12350
/* --- END Provisioned TPM Support -- */
12351
/******************************************************************************/
12352
12353
12354
/******************************************************************************/
12355
/* --- BEGIN Firmware Upgrade Support -- */
12356
/******************************************************************************/
12357
12358
#ifdef WOLFTPM_FIRMWARE_UPGRADE
12359
12360
/* Validate a caller-supplied firmware-start authorization session.
12361
 *
12362
 * The vendor FieldUpgradeStart commands are hand-marshalled (see
12363
 * TPM2_IFX_FieldUpgradeStart / TPM2_ST33_FieldUpgradeStart in tpm2.c): they
12364
 * emit a TPMS_AUTH_COMMAND carrying only the session handle, with an empty
12365
 * nonceCaller, zero sessionAttributes and an empty HMAC. That wire format is
12366
 * only correct for an unsalted, unbound policy session with no auth value. Any
12367
 * session that would require a computed session HMAC or parameter encryption
12368
 * is rejected here instead of failing on the wire with TPM_RC_AUTH_FAIL. */
12369
static int tpm2_firmware_check_session(WOLFTPM2_SESSION* startSession)
12370
{
12371
    if (startSession == NULL) {
12372
        return TPM_RC_SUCCESS; /* library-managed authorization */
12373
    }
12374
    /* must be a policy session; an HMAC session always needs a session HMAC */
12375
    if (!TPM2_IS_POLICY_SESSION(startSession->handle.hndl)) {
12376
        return BAD_FUNC_ARG;
12377
    }
12378
    /* PolicyAuthValue / PolicyPassword require the entity auth value to be
12379
     * carried in the auth area, which this command does not serialize */
12380
    if (startSession->handle.policyAuth || startSession->handle.policyPass) {
12381
        return BAD_FUNC_ARG;
12382
    }
12383
    /* an attached auth value, a bound session or a salted session all imply a
12384
     * non-empty session HMAC */
12385
    if (startSession->handle.auth.size > 0 || startSession->bind != NULL ||
12386
            startSession->salt.size > 0) {
12387
        return BAD_FUNC_ARG;
12388
    }
12389
    /* parameter encryption and audit are not applied on this raw path */
12390
    if (startSession->sessionAttributes &
12391
            (TPMA_SESSION_encrypt | TPMA_SESSION_decrypt |
12392
             TPMA_SESSION_audit)) {
12393
        return BAD_FUNC_ARG;
12394
    }
12395
    return TPM_RC_SUCCESS;
12396
}
12397
12398
#ifdef WOLFTPM_IFX_FW_UPGRADE
12399
12400
/* Maximum size of firmware chunks */
12401
#define IFX_FW_MAX_CHUNK_SZ 1024
12402
12403
/* Setup the policy to enable firmware upgrade start */
12404
static int tpm2_ifx_firmware_enable_policy(WOLFTPM2_DEV* dev)
12405
{
12406
    int rc;
12407
    byte policyDigest[TPM_MAX_DIGEST_SIZE];
12408
    word32 policySz = (word32)sizeof(policyDigest);
12409
    WOLFTPM2_SESSION tpmSession;
12410
12411
    XMEMSET(&tpmSession, 0, sizeof(tpmSession));
12412
    XMEMSET(policyDigest, 0, sizeof(policyDigest));
12413
12414
    rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL,
12415
        TPM_SE_POLICY, TPM_ALG_NULL);
12416
    if (rc == TPM_RC_SUCCESS) {
12417
        rc = wolfTPM2_PolicyCommandCode(dev, &tpmSession,
12418
            TPM_CC_FieldUpgradeStartVendor);
12419
        if (rc == TPM_RC_SUCCESS) {
12420
            policySz = (word32)sizeof(policyDigest);
12421
            rc = wolfTPM2_GetPolicyDigest(dev, tpmSession.handle.hndl,
12422
                policyDigest, &policySz);
12423
        }
12424
        wolfTPM2_UnloadHandle(dev, &tpmSession.handle);
12425
    }
12426
    if (rc == TPM_RC_SUCCESS) {
12427
        rc = wolfTPM2_SetPrimaryPolicy(dev, TPM_RH_PLATFORM, TPM_ALG_SHA256,
12428
            policyDigest, policySz);
12429
    }
12430
12431
#ifdef DEBUG_WOLFTPM
12432
    if (rc != TPM_RC_SUCCESS) {
12433
        printf("Enable firmware start policy failed 0x%x: %s\n",
12434
            rc, TPM2_GetRCString(rc));
12435
    }
12436
#endif
12437
    return rc;
12438
}
12439
12440
static int tpm2_ifx_firmware_start(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg,
12441
    uint8_t* manifest_hash, uint32_t manifest_hash_sz,
12442
    WOLFTPM2_SESSION* startSession)
12443
{
12444
    int rc;
12445
    WOLFTPM2_SESSION tpmSession;
12446
    TPM_HANDLE sessionHandle = TPM_RH_NULL;
12447
    int ownSession = 0;
12448
12449
    if (dev == NULL || manifest_hash == NULL || manifest_hash_sz == 0 ||
12450
            manifest_hash_sz > TPM_SHA512_DIGEST_SIZE) {
12451
        return BAD_FUNC_ARG;
12452
    }
12453
    if (manifest_hash_sz != (uint32_t)TPM2_GetHashDigestSize(hashAlg)) {
12454
        return BAD_FUNC_ARG;
12455
    }
12456
12457
    XMEMSET(&tpmSession, 0, sizeof(tpmSession));
12458
12459
    if (startSession != NULL) {
12460
        /* Caller has already satisfied the platform policy on this session */
12461
        sessionHandle = startSession->handle.hndl;
12462
        rc = TPM_RC_SUCCESS;
12463
    }
12464
    else {
12465
        /* Default: internal policy session asserting the firmware start
12466
         * command code, matching the policy installed on the platform
12467
         * hierarchy by tpm2_ifx_firmware_enable_policy */
12468
        rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL,
12469
            TPM_SE_POLICY, TPM_ALG_NULL);
12470
        if (rc == TPM_RC_SUCCESS) {
12471
            ownSession = 1;
12472
            sessionHandle = tpmSession.handle.hndl;
12473
            rc = wolfTPM2_PolicyCommandCode(dev, &tpmSession,
12474
                TPM_CC_FieldUpgradeStartVendor);
12475
        }
12476
    }
12477
12478
    if (rc == TPM_RC_SUCCESS) {
12479
        /* build command for manifest header */
12480
        uint16_t val16;
12481
        /* max cmd: type (1) + data sz (2) + hash alg (2) + max digest (64) */
12482
        uint8_t cmd[1 + 2 + 2 + TPM_SHA512_DIGEST_SIZE];
12483
        cmd[0] = 0x01; /* type */
12484
        val16 = be16_to_cpu(manifest_hash_sz + 2);
12485
        XMEMCPY(&cmd[1], &val16, sizeof(val16)); /* data size */
12486
        val16 = be16_to_cpu(hashAlg);
12487
        XMEMCPY(&cmd[3], &val16, sizeof(val16)); /* hash algorithm */
12488
        XMEMCPY(&cmd[5], manifest_hash, manifest_hash_sz);
12489
12490
        rc = TPM2_IFX_FieldUpgradeStart(sessionHandle,
12491
            cmd, 1 + 2 + 2 + manifest_hash_sz);
12492
    }
12493
12494
    if (rc == TPM_RC_SUCCESS) {
12495
        /* The TPM consumed the session entering firmware upgrade mode; mark a
12496
         * caller-supplied session as released so the caller does not flush it */
12497
        if (startSession != NULL) {
12498
            startSession->handle.hndl = TPM_RH_NULL;
12499
        }
12500
12501
        /* delay to give the TPM time to switch modes */
12502
        XSLEEP_MS(300);
12503
        /* it is not required to release session handle,
12504
         * since TPM reset into firmware upgrade mode */
12505
12506
    #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \
12507
        !defined(WOLFTPM_OPTEE) && !defined(WOLFTPM_WINAPI)
12508
        /* Do chip startup and request locality again */
12509
    #ifdef WOLFTPM_LINUX_DEV_AUTODETECT
12510
        if (dev->ctx.fd < 0) /* Only needed for SPI path */
12511
    #endif
12512
        rc = TPM2_ChipStartup(&dev->ctx, 10);
12513
    #endif
12514
    }
12515
    else if (ownSession) {
12516
        /* only release a session we started ourselves */
12517
        wolfTPM2_UnloadHandle(dev, &tpmSession.handle);
12518
    }
12519
#ifdef DEBUG_WOLFTPM
12520
    if (rc != TPM_RC_SUCCESS) {
12521
        printf("Firmware upgrade start failed 0x%x: %s\n",
12522
            rc, TPM2_GetRCString(rc));
12523
    }
12524
#endif
12525
    return rc;
12526
}
12527
12528
static int tpm2_ifx_firmware_manifest(WOLFTPM2_DEV* dev,
12529
    uint8_t* manifest, uint32_t manifest_sz)
12530
{
12531
    int rc = TPM_RC_FAILURE;
12532
    uint32_t offset, chunk_sz;
12533
    uint8_t state; /* 1=start, 2=more, 0=done */
12534
12535
    (void)dev;
12536
    for (offset = 0; offset < manifest_sz; offset += chunk_sz) {
12537
        /* max cmd: type (1) + chunk sz (2) + max chunk (1024) */
12538
        uint8_t cmd[1 + 2 + IFX_FW_MAX_CHUNK_SZ];
12539
        uint16_t val16;
12540
12541
        chunk_sz = manifest_sz - offset;
12542
        if (chunk_sz > IFX_FW_MAX_CHUNK_SZ) {
12543
            chunk_sz = IFX_FW_MAX_CHUNK_SZ;
12544
            state = (offset == 0) ? 1 : 2;
12545
        }
12546
        else {
12547
            state = 0;
12548
        }
12549
    #ifdef DEBUG_WOLFTPM
12550
        printf("Firmware manifest chunk %u offset (%u / %u), state %d\n",
12551
            chunk_sz, offset, manifest_sz, state);
12552
    #endif
12553
12554
        cmd[0] = state;
12555
        val16 = be16_to_cpu(chunk_sz);
12556
        XMEMCPY(&cmd[1], &val16, sizeof(val16)); /* chunk size */
12557
        XMEMCPY(&cmd[3], &manifest[offset], chunk_sz);
12558
12559
        rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeManifestVendor,
12560
            cmd, 1 + 2 + chunk_sz);
12561
        if (rc != TPM_RC_SUCCESS) {
12562
            break;
12563
        }
12564
    }
12565
#ifdef DEBUG_WOLFTPM
12566
    if (rc != TPM_RC_SUCCESS) {
12567
        printf("Firmware upgrade manifest failed 0x%x: %s\n",
12568
            rc, TPM2_GetRCString(rc));
12569
    }
12570
#endif
12571
    return rc;
12572
}
12573
12574
static int tpm2_ifx_firmware_data(WOLFTPM2_DEV* dev,
12575
    wolfTPM2FwDataCb cb, void* cb_ctx)
12576
{
12577
    int rc;
12578
    uint32_t offset, chunk_sz;
12579
    uint8_t cmd[2 + IFX_FW_MAX_CHUNK_SZ];
12580
    uint16_t val16;
12581
12582
    (void)dev;
12583
    for (offset = 0; ; offset += chunk_sz) {
12584
        XMEMSET(cmd, 0, sizeof(cmd));
12585
12586
        /* get chunk */
12587
        rc = cb(&cmd[2], IFX_FW_MAX_CHUNK_SZ, offset, cb_ctx);
12588
        if (rc > 0 && rc <= IFX_FW_MAX_CHUNK_SZ) {
12589
            chunk_sz = rc;
12590
        }
12591
        else if (rc == 0) {
12592
        #ifdef DEBUG_WOLFTPM
12593
            printf("Firmware data done\n");
12594
        #endif
12595
            break;
12596
        }
12597
        else {
12598
        #ifdef DEBUG_WOLFTPM
12599
            printf("Firmware data callback error! %d\n", rc);
12600
        #endif
12601
            break;
12602
        }
12603
12604
    #ifdef DEBUG_WOLFTPM
12605
        printf("Firmware data chunk offset %u\n", offset);
12606
    #endif
12607
12608
        val16 = be16_to_cpu(chunk_sz);
12609
        XMEMCPY(&cmd[0], &val16, sizeof(val16)); /* chunk size */
12610
12611
        rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeDataVendor,
12612
            cmd, 2 + chunk_sz);
12613
        if (rc != TPM_RC_SUCCESS) {
12614
            break;
12615
        }
12616
    }
12617
12618
    if (rc == TPM_RC_SUCCESS) {
12619
        /* Give the TPM time to start the new firmware */
12620
        XSLEEP_MS(300);
12621
12622
    #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \
12623
        !defined(WOLFTPM_OPTEE) && !defined(WOLFTPM_WINAPI)
12624
        /* Do chip startup and request locality again */
12625
    #ifdef WOLFTPM_LINUX_DEV_AUTODETECT
12626
        if (dev->ctx.fd < 0) /* Only needed for SPI path */
12627
    #endif
12628
        rc = TPM2_ChipStartup(&dev->ctx, 10);
12629
    #endif
12630
    }
12631
#ifdef DEBUG_WOLFTPM
12632
    else {
12633
        printf("Firmware upgrade data failed 0x%x: %s\n",
12634
            rc, TPM2_GetRCString(rc));
12635
    }
12636
#endif
12637
    return rc;
12638
}
12639
12640
static int tpm2_ifx_firmware_final(WOLFTPM2_DEV* dev)
12641
{
12642
    int rc;
12643
    uint8_t cmd[2];
12644
    uint16_t val16;
12645
12646
    (void)dev;
12647
12648
    val16 = 0;
12649
    XMEMCPY(&cmd[0], &val16, sizeof(val16)); /* data size */
12650
12651
    rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeFinalizeVendor,
12652
        cmd, sizeof(cmd));
12653
#ifdef DEBUG_WOLFTPM
12654
    if (rc != TPM_RC_SUCCESS) {
12655
        printf("Firmware finalize failed 0x%x: %s\n",
12656
            rc, TPM2_GetRCString(rc));
12657
    }
12658
#endif
12659
    return rc;
12660
}
12661
12662
#endif /* WOLFTPM_IFX_FW_UPGRADE */
12663
12664
/* Public Firmware Upgrade APIs - routes to appropriate vendor implementation
12665
 * Available when any firmware upgrade vendor support is enabled */
12666
#if (defined(WOLFTPM_IFX_FW_UPGRADE) || \
12667
     defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT))
12668
12669
/* Forward declarations for vendor-specific firmware functions */
12670
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12671
static int tpm2_st33_firmware_upgrade_hash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg,
12672
    uint8_t* manifest_hash, uint32_t manifest_hash_sz,
12673
    uint8_t* manifest, uint32_t manifest_sz,
12674
    wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession);
12675
static int tpm2_st33_firmware_cancel(WOLFTPM2_DEV* dev);
12676
#endif
12677
12678
int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg,
12679
    uint8_t* manifest_hash, uint32_t manifest_hash_sz,
12680
    uint8_t* manifest, uint32_t manifest_sz,
12681
    wolfTPM2FwDataCb cb, void* cb_ctx)
12682
{
12683
    /* Default behavior: library-managed platform authorization */
12684
    return wolfTPM2_FirmwareUpgradeHash_ex(dev, hashAlg,
12685
        manifest_hash, manifest_hash_sz, manifest, manifest_sz,
12686
        cb, cb_ctx, NULL);
12687
}
12688
12689
int wolfTPM2_FirmwareUpgradeHash_ex(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg,
12690
    uint8_t* manifest_hash, uint32_t manifest_hash_sz,
12691
    uint8_t* manifest, uint32_t manifest_sz,
12692
    wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession)
12693
{
12694
    int rc;
12695
    WOLFTPM2_CAPS caps;
12696
12697
    /* Check the caller session before any TPM traffic, so an unsupported
12698
     * session is reported without leaving the TPM in a partial state */
12699
    rc = tpm2_firmware_check_session(startSession);
12700
    if (rc != TPM_RC_SUCCESS) {
12701
        return rc;
12702
    }
12703
12704
    /* Get capabilities to determine manufacturer */
12705
    rc = wolfTPM2_GetCapabilities(dev, &caps);
12706
    if (rc != TPM_RC_SUCCESS) {
12707
        return rc;
12708
    }
12709
12710
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12711
    if (caps.mfg == TPM_MFG_STM) {
12712
        /* Route to ST33 firmware update - LMS vs non-LMS is
12713
         * auto-detected from manifest size */
12714
        return tpm2_st33_firmware_upgrade_hash(dev, hashAlg,
12715
            manifest_hash, manifest_hash_sz,
12716
            manifest, manifest_sz,
12717
            cb, cb_ctx, startSession);
12718
    }
12719
#endif
12720
12721
#ifdef WOLFTPM_IFX_FW_UPGRADE
12722
    if (caps.mfg == TPM_MFG_INFINEON) {
12723
        /* Route to Infineon firmware update implementation */
12724
        /* check the operational mode */
12725
        if (caps.opMode == 0x03) {
12726
            /* firmware update is done, just needs finalized and TPM reset */
12727
        #ifdef DEBUG_WOLFTPM
12728
            printf("Firmware update done, finalizing\n");
12729
        #endif
12730
            return tpm2_ifx_firmware_final(dev);
12731
        }
12732
        if (caps.opMode == 0x00) {
12733
            /* Ensure rc is assigned in this scope regardless of the branch
12734
             * below (the caller-session path does not call enable_policy). */
12735
            rc = TPM_RC_SUCCESS;
12736
            /* When the caller supplies a session it must already satisfy the
12737
             * platform authPolicy, so do not overwrite the platform primary
12738
             * policy - only manage it for the library-default path */
12739
            if (startSession == NULL) {
12740
                rc = tpm2_ifx_firmware_enable_policy(dev);
12741
            }
12742
            if (rc == TPM_RC_SUCCESS) {
12743
                rc = tpm2_ifx_firmware_start(dev, hashAlg,
12744
                    manifest_hash, manifest_hash_sz, startSession);
12745
            }
12746
        }
12747
        if (rc == TPM_RC_SUCCESS) {
12748
            rc = tpm2_ifx_firmware_manifest(dev, manifest, manifest_sz);
12749
        }
12750
        if (rc == TPM_RC_SUCCESS) {
12751
            rc = tpm2_ifx_firmware_data(dev, cb, cb_ctx);
12752
        }
12753
        if (rc == TPM_RC_SUCCESS) {
12754
            rc = tpm2_ifx_firmware_final(dev);
12755
        }
12756
    #ifdef DEBUG_WOLFTPM
12757
        if (rc != TPM_RC_SUCCESS) {
12758
            printf("Firmware update failed 0x%x: %s\n",
12759
                rc, TPM2_GetRCString(rc));
12760
        }
12761
    #endif
12762
        return rc;
12763
    }
12764
#endif
12765
12766
    /* Unsupported manufacturer */
12767
#ifdef DEBUG_WOLFTPM
12768
    printf("Firmware update not supported for manufacturer %d\n", caps.mfg);
12769
#endif
12770
    return TPM_RC_COMMAND_CODE;
12771
}
12772
12773
#ifndef WOLFTPM2_NO_WOLFCRYPT
12774
int wolfTPM2_FirmwareUpgrade_ex(WOLFTPM2_DEV* dev,
12775
    uint8_t* manifest, uint32_t manifest_sz,
12776
    wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession)
12777
{
12778
#ifdef WOLFSSL_SHA384
12779
    int rc;
12780
    uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE];
12781
12782
    /* hash the manifest */
12783
    rc = wc_Sha384Hash(manifest, manifest_sz, manifest_hash);
12784
    if (rc == 0) {
12785
        rc = wolfTPM2_FirmwareUpgradeHash_ex(dev, TPM_ALG_SHA384,
12786
            manifest_hash, (uint32_t)sizeof(manifest_hash),
12787
            manifest, manifest_sz, cb, cb_ctx, startSession);
12788
    }
12789
    return rc;
12790
#else
12791
    (void)dev; (void)manifest; (void)manifest_sz;
12792
    (void)cb; (void)cb_ctx; (void)startSession;
12793
    return NOT_COMPILED_IN;
12794
#endif
12795
}
12796
12797
int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev,
12798
    uint8_t* manifest, uint32_t manifest_sz,
12799
    wolfTPM2FwDataCb cb, void* cb_ctx)
12800
{
12801
    /* Default behavior: library-managed platform authorization */
12802
    return wolfTPM2_FirmwareUpgrade_ex(dev, manifest, manifest_sz,
12803
        cb, cb_ctx, NULL);
12804
}
12805
#endif
12806
12807
int wolfTPM2_FirmwareUpgradeRecover_ex(WOLFTPM2_DEV* dev,
12808
    uint8_t* manifest, uint32_t manifest_sz,
12809
    wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession)
12810
{
12811
    uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE];
12812
12813
    /* recovery mode manifest hash is all 0x3C */
12814
    XMEMSET(manifest_hash, 0x3C, sizeof(manifest_hash));
12815
12816
    return wolfTPM2_FirmwareUpgradeHash_ex(dev, TPM_ALG_SHA384,
12817
            manifest_hash, (uint32_t)sizeof(manifest_hash),
12818
            manifest, manifest_sz, cb, cb_ctx, startSession);
12819
}
12820
12821
int wolfTPM2_FirmwareUpgradeRecover(WOLFTPM2_DEV* dev,
12822
    uint8_t* manifest, uint32_t manifest_sz,
12823
    wolfTPM2FwDataCb cb, void* cb_ctx)
12824
{
12825
    /* Default behavior: library-managed platform authorization */
12826
    return wolfTPM2_FirmwareUpgradeRecover_ex(dev, manifest, manifest_sz,
12827
        cb, cb_ctx, NULL);
12828
}
12829
12830
/* terminate a firmware update */
12831
int wolfTPM2_FirmwareUpgradeCancel(WOLFTPM2_DEV* dev)
12832
{
12833
    int rc;
12834
    WOLFTPM2_CAPS caps;
12835
12836
    /* Get capabilities to determine manufacturer */
12837
    rc = wolfTPM2_GetCapabilities(dev, &caps);
12838
    if (rc != TPM_RC_SUCCESS) {
12839
        return rc;
12840
    }
12841
12842
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12843
    if (caps.mfg == TPM_MFG_STM) {
12844
        /* Route to ST33 firmware cancel */
12845
        return tpm2_st33_firmware_cancel(dev);
12846
    }
12847
#endif
12848
12849
#ifdef WOLFTPM_IFX_FW_UPGRADE
12850
    if (caps.mfg == TPM_MFG_INFINEON) {
12851
        /* Route to Infineon firmware cancel */
12852
        uint8_t cmd[2];
12853
        uint16_t val16;
12854
12855
        val16 = 0; /* data size */
12856
        XMEMCPY(&cmd[0], &val16, sizeof(val16));
12857
12858
        rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor,
12859
            cmd, sizeof(cmd));
12860
    #ifdef DEBUG_WOLFTPM
12861
        if (rc != TPM_RC_SUCCESS) {
12862
            printf("Firmware abandon failed 0x%x: %s\n",
12863
                rc, TPM2_GetRCString(rc));
12864
        }
12865
    #endif
12866
        return rc;
12867
    }
12868
#endif
12869
12870
    /* Unsupported manufacturer */
12871
#ifdef DEBUG_WOLFTPM
12872
    printf("Firmware cancel not supported for manufacturer %d\n", caps.mfg);
12873
#endif
12874
    return TPM_RC_COMMAND_CODE;
12875
}
12876
12877
#endif /* WOLFTPM_IFX_FW_UPGRADE || WOLFTPM_ST33 || WOLFTPM_AUTODETECT */
12878
12879
#if defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)
12880
12881
/* Maximum size of firmware chunks for ST33 */
12882
#define ST33_FW_MAX_CHUNK_SZ 2048  /* Must be large enough for firmware blobs */
12883
12884
/* The manifest format follows the silicon family, which the firmware major
12885
 * version identifies. ST33TPHF2X (majors 1, 2 and the older 74 line) signs
12886
 * with SHA-256 + RSA-PSS; ST33KTPM (majors 9 and 10) signs with ECDSA P-384,
12887
 * and from minor 512 with LMS. A major outside both lists is unknown and no
12888
 * size is asserted for it, rather than guessing an upgrade into a rejection. */
12889
#define ST33_FW_FAMILY_UNKNOWN 0
12890
#define ST33_FW_FAMILY_TPHF2X  1
12891
#define ST33_FW_FAMILY_KTPM    2
12892
#define ST33_FW_VERSION_LMS_REQUIRED 512
12893
12894
static int tpm2_st33_family(word16 fwVerMajor)
12895
{
12896
    switch (fwVerMajor) {
12897
        case 1:  /* ST33TPHF2X, SPI firmware line */
12898
        case 2:  /* ST33TPHF2X, I2C firmware line */
12899
        case 74: /* ST33TPHF2X, older line both buses (74.8 SPI, 74.9 I2C) */
12900
            return ST33_FW_FAMILY_TPHF2X;
12901
        case 9:  /* ST33KTPM2X */
12902
        case 10: /* ST33KTPM2A */
12903
            return ST33_FW_FAMILY_KTPM;
12904
        /* Uncharacterized majors stay unknown so no size or family rule is
12905
         * asserted against them, even ones the tool can name */
12906
        default:
12907
            return ST33_FW_FAMILY_UNKNOWN;
12908
    }
12909
}
12910
12911
/* ST33 manifest (blob0) sizes determine firmware format. The manifest is a
12912
 * 33 byte fixed header followed by the firmware digest and the signature over
12913
 * it, so its size follows the algorithms that generation signs with. */
12914
/* gen 1: SHA-256 + RSAPSS-2048 */
12915
#define ST33_MANIFEST_SIZE_NON_LMS_RSA 321
12916
/* gen 9 below 512: SHA-384 + ECDSA P-384 */
12917
#define ST33_MANIFEST_SIZE_NON_LMS     177
12918
/* gen 9 at 512 and above: embedded LMS signature */
12919
#define ST33_MANIFEST_SIZE_LMS         2697
12920
12921
/* Manifest size the running firmware expects for its next update. Returns 0
12922
 * when the family is unknown, meaning no size can be asserted. */
12923
static uint32_t tpm2_st33_expected_manifest_sz(const WOLFTPM2_CAPS* caps)
12924
{
12925
    switch (tpm2_st33_family(caps->fwVerMajor)) {
12926
        case ST33_FW_FAMILY_TPHF2X:
12927
            return ST33_MANIFEST_SIZE_NON_LMS_RSA;
12928
        case ST33_FW_FAMILY_KTPM:
12929
            if (caps->fwVerMinor < ST33_FW_VERSION_LMS_REQUIRED) {
12930
                return ST33_MANIFEST_SIZE_NON_LMS;
12931
            }
12932
            return ST33_MANIFEST_SIZE_LMS;
12933
        default:
12934
            return 0;
12935
    }
12936
}
12937
12938
/* Target firmware version carried in the manifest (blob0) header. The header
12939
 * opens with a zero byte followed by the version the image upgrades to, laid
12940
 * out exactly like TPM_PT_FIRMWARE_VERSION_1: UINT16 major then UINT16 minor,
12941
 * big endian (for example 00 | 00 02 02 00 for 2.512). */
12942
#define ST33_MANIFEST_VERSION_OFFSET 1
12943
12944
int wolfTPM2_ST33_ManifestVersion(const uint8_t* manifest,
12945
    uint32_t manifest_sz, word16* major, word16* minor)
12946
{
12947
    const uint8_t* ver;
12948
12949
    if (manifest == NULL ||
12950
            manifest_sz < (uint32_t)(ST33_MANIFEST_VERSION_OFFSET + 4)) {
12951
        return BAD_FUNC_ARG;
12952
    }
12953
    ver = &manifest[ST33_MANIFEST_VERSION_OFFSET];
12954
    if (major != NULL) {
12955
        *major = (word16)(((word16)ver[0] << 8) | ver[1]);
12956
    }
12957
    if (minor != NULL) {
12958
        *minor = (word16)(((word16)ver[2] << 8) | ver[3]);
12959
    }
12960
    return TPM_RC_SUCCESS;
12961
}
12962
12963
/* ST33 implements the field upgrade with one of two command code pairs and
12964
 * the wrong one is answered with TPM_RC_COMMAND_CODE. This mirrors the
12965
 * selection in ST's reference tool (TPM_FU_STM_V1.py), which uses the
12966
 * standard TPM command codes when the running firmware minor version is
12967
 * below 256, or when the image targets firmware generation 2, and the
12968
 * ST33KTPM vendor codes otherwise. Exposed so the example tool and the unit
12969
 * tests exercise the same implementation the library sends from. It is only
12970
 * a fallback: wolfTPM2_ST33_GetFwUpgradeCommands asks the TPM first, as the
12971
 * heuristic does not hold on every firmware line (an ST33KTPMQ at 11.1
12972
 * implements only the vendor pair despite a minor version below 256). */
12973
#define ST33_FW_VERSION_STD_CC_MINOR 256
12974
#define ST33_FW_GENERATION_STD_CC    2
12975
12976
int wolfTPM2_ST33_FwUpgradeCommands(word16 fwVerMinor, int haveFwVer,
12977
    word16 manifestMajor, TPM_CC* ccStart, TPM_CC* ccData)
12978
{
12979
    int useStd;
12980
12981
    if (ccStart == NULL || ccData == NULL) {
12982
        return BAD_FUNC_ARG;
12983
    }
12984
    useStd = (manifestMajor == ST33_FW_GENERATION_STD_CC);
12985
    if (haveFwVer && fwVerMinor < ST33_FW_VERSION_STD_CC_MINOR) {
12986
        useStd = 1;
12987
    }
12988
    if (useStd) {
12989
        *ccStart = TPM_CC_FieldUpgradeStart;
12990
        *ccData  = TPM_CC_FieldUpgradeData;
12991
    }
12992
    else {
12993
        *ccStart = TPM_CC_FieldUpgradeStartVendor_ST33;
12994
        *ccData  = TPM_CC_FieldUpgradeDataVendor_ST33;
12995
    }
12996
    return TPM_RC_SUCCESS;
12997
}
12998
12999
/* Report whether the TPM implements a command code. TPM_CAP_COMMANDS returns
13000
 * commands with a code at or above the requested property, so a match at
13001
 * index 0 of a single-property query means it is implemented. The attributes
13002
 * carry the command index with the vendor bit separate, so the full code has
13003
 * to be put back together before comparing. */
13004
int wolfTPM2_ST33_CmdImplemented(TPM_CC cc, int* isImpl)
13005
{
13006
    int rc;
13007
    GetCapability_In in;
13008
    GetCapability_Out out;
13009
    TPML_CCA* cmds;
13010
    TPM_CC got;
13011
13012
    if (isImpl == NULL) {
13013
        return BAD_FUNC_ARG;
13014
    }
13015
    *isImpl = 0;
13016
    XMEMSET(&in, 0, sizeof(in));
13017
    XMEMSET(&out, 0, sizeof(out));
13018
    in.capability = TPM_CAP_COMMANDS;
13019
    in.property = cc;
13020
    in.propertyCount = 1;
13021
    rc = TPM2_GetCapability(&in, &out);
13022
    if (rc != TPM_RC_SUCCESS) {
13023
        return rc;
13024
    }
13025
    /* capabilityData.data is a union - confirm the TPM answered with the
13026
     * capability that was asked for before reading the command member */
13027
    if (out.capabilityData.capability != TPM_CAP_COMMANDS) {
13028
        return TPM_RC_VALUE;
13029
    }
13030
    cmds = &out.capabilityData.data.command;
13031
    if (cmds->count > 0) {
13032
        got = (TPM_CC)(cmds->commandAttributes[0] & TPMA_CC_commandIndex);
13033
        if (cmds->commandAttributes[0] & TPMA_CC_V) {
13034
            got |= CC_VEND;
13035
        }
13036
        if (got == cc) {
13037
            *isImpl = 1;
13038
        }
13039
    }
13040
    return TPM_RC_SUCCESS;
13041
}
13042
13043
/* Select the field upgrade command codes. The TPM's own command list is
13044
 * authoritative, so ask it rather than infer: ST33 firmware lines do not
13045
 * follow the version heuristic consistently (an ST33KTPMQ at 11.1 implements
13046
 * only the vendor pair even though its minor version is below 256). Only the
13047
 * start codes are queried, the data code always follows its start code.
13048
 * wolfTPM2_ST33_FwUpgradeCommands decides when the TPM will not answer -
13049
 * which is the case in firmware upgrade mode - or the answer is ambiguous.
13050
 * Pass caps as NULL when the running firmware version is not known. */
13051
int wolfTPM2_ST33_GetFwUpgradeCommands(const WOLFTPM2_CAPS* caps,
13052
    word16 manifestMajor, TPM_CC* ccStart, TPM_CC* ccData, int* fromTpm)
13053
{
13054
    int vendorImpl = 0, stdImpl = 0;
13055
    int rcVendor, rcStd;
13056
13057
    if (ccStart == NULL || ccData == NULL) {
13058
        return BAD_FUNC_ARG;
13059
    }
13060
    if (fromTpm != NULL) {
13061
        *fromTpm = 0;
13062
    }
13063
13064
    /* caps NULL means the TPM is already in firmware upgrade mode, where it
13065
     * accepts only FieldUpgradeData - any other command leaves that mode. No
13066
     * capability query may be issued here, so the image decides alone. */
13067
    if (caps == NULL) {
13068
        return wolfTPM2_ST33_FwUpgradeCommands(0, 0, manifestMajor, ccStart,
13069
            ccData);
13070
    }
13071
13072
    rcVendor = wolfTPM2_ST33_CmdImplemented(TPM_CC_FieldUpgradeStartVendor_ST33,
13073
        &vendorImpl);
13074
    rcStd = wolfTPM2_ST33_CmdImplemented(TPM_CC_FieldUpgradeStart, &stdImpl);
13075
13076
    if (rcVendor == TPM_RC_SUCCESS && rcStd == TPM_RC_SUCCESS &&
13077
            vendorImpl != stdImpl) {
13078
        if (vendorImpl) {
13079
            *ccStart = TPM_CC_FieldUpgradeStartVendor_ST33;
13080
            *ccData  = TPM_CC_FieldUpgradeDataVendor_ST33;
13081
        }
13082
        else {
13083
            *ccStart = TPM_CC_FieldUpgradeStart;
13084
            *ccData  = TPM_CC_FieldUpgradeData;
13085
        }
13086
        if (fromTpm != NULL) {
13087
            *fromTpm = 1;
13088
        }
13089
    #ifdef DEBUG_WOLFTPM
13090
        printf("ST33 Field upgrade command codes from TPM_CAP_COMMANDS\n");
13091
    #endif
13092
        return TPM_RC_SUCCESS;
13093
    }
13094
13095
#ifdef DEBUG_WOLFTPM
13096
    /* A TPM that lists neither pair may simply not enumerate its vendor
13097
     * commands, so the version rule still gets a turn rather than refusing
13098
     * an image the part would have taken */
13099
    if (rcVendor == TPM_RC_SUCCESS && rcStd == TPM_RC_SUCCESS &&
13100
            !vendorImpl && !stdImpl) {
13101
        printf("ST33 TPM lists neither field upgrade pair, using the "
13102
            "firmware version rule\n");
13103
    }
13104
    else {
13105
        printf("ST33 Field upgrade command set inconclusive (vendor rc 0x%x "
13106
            "impl %d, standard rc 0x%x impl %d), using the firmware version "
13107
            "rule\n", (unsigned int)rcVendor, vendorImpl, (unsigned int)rcStd,
13108
            stdImpl);
13109
    }
13110
#endif
13111
    return wolfTPM2_ST33_FwUpgradeCommands(caps->fwVerMinor, 1,
13112
        manifestMajor, ccStart, ccData);
13113
}
13114
13115
/* ST33 uses password auth (TPM_RS_PW) for firmware update, not policy */
13116
13117
/* Common firmware upgrade start function
13118
 * Sends manifest (blob0) via FieldUpgradeStart
13119
 * 300ms delay: ST reference implementation uses this delay to allow
13120
 * TPM to switch modes after FieldUpgradeStart command */
13121
static int tpm2_st33_firmware_start_common(WOLFTPM2_DEV* dev,
13122
    uint8_t* manifest, uint32_t manifest_sz, int is_lms, TPM_CC ccStart,
13123
    WOLFTPM2_SESSION* startSession)
13124
{
13125
    int rc;
13126
    TPM_HANDLE sessionHandle;
13127
13128
    (void)dev;
13129
13130
    /* By default ST33 uses password auth (TPM_RS_PW) for FieldUpgradeStart,
13131
     * matching the ST reference implementation behavior. When the caller
13132
     * supplies a session (for example a policy session that satisfies a
13133
     * custom platform authPolicy), use it instead.
13134
     * For LMS format, the manifest (blob0) already contains the embedded
13135
     * LMS signature. Send the full manifest directly. */
13136
    sessionHandle = (startSession != NULL) ?
13137
        startSession->handle.hndl : (TPM_HANDLE)TPM_RS_PW;
13138
    rc = TPM2_ST33_FieldUpgradeStart_ex(sessionHandle, ccStart, manifest,
13139
        manifest_sz);
13140
13141
    if (rc == TPM_RC_SUCCESS) {
13142
        /* The TPM consumed the session entering firmware upgrade mode; mark a
13143
         * caller-supplied session as released so the caller does not flush it */
13144
        if (startSession != NULL) {
13145
            startSession->handle.hndl = TPM_RH_NULL;
13146
        }
13147
13148
        /* 300ms delay: ST reference implementation uses this delay to allow
13149
         * TPM to switch modes after FieldUpgradeStart command */
13150
        XSLEEP_MS(300);
13151
13152
    #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \
13153
        !defined(WOLFTPM_OPTEE) && !defined(WOLFTPM_WINAPI)
13154
        /* Do chip startup and request locality again */
13155
    #ifdef WOLFTPM_LINUX_DEV_AUTODETECT
13156
        if (dev->ctx.fd < 0) /* Only needed for SPI path */
13157
    #endif
13158
        rc = TPM2_ChipStartup(&dev->ctx, 10);
13159
    #endif
13160
    }
13161
#ifdef DEBUG_WOLFTPM
13162
    if (rc != TPM_RC_SUCCESS) {
13163
        printf("ST33 Firmware upgrade start%s (cc 0x%08x) failed 0x%x: %s\n",
13164
            is_lms ? " (LMS)" : "", (unsigned int)ccStart, rc,
13165
            TPM2_GetRCString(rc));
13166
    }
13167
#else
13168
    (void)is_lms;  /* Suppress unused parameter warning when DEBUG_WOLFTPM not defined */
13169
#endif
13170
    return rc;
13171
}
13172
13173
/* ST33 sends full manifest (blob0) directly in FieldUpgradeStart */
13174
13175
/* Send firmware data as blobs per ST reference implementation
13176
 * Firmware data format (after blob0/manifest):
13177
 * - Byte 0: blob type
13178
 * - Bytes 1-2: blob data length (big-endian)
13179
 * - Bytes 3+: blob data
13180
 * Each blob is sent complete to the TPM via FieldUpgradeData command */
13181
static int tpm2_st33_firmware_data(WOLFTPM2_DEV* dev, TPM_CC ccData,
13182
    wolfTPM2FwDataCb cb, void* cb_ctx)
13183
{
13184
    int rc;
13185
    uint32_t offset = 0;
13186
    uint8_t blob_header[3];
13187
    uint8_t* blob_buf = NULL;
13188
    uint32_t blob_len;
13189
    uint32_t blob_total;
13190
13191
    (void)dev;
13192
13193
    /* Allocate buffer for largest possible blob */
13194
    blob_buf = (uint8_t*)XMALLOC(ST33_FW_MAX_CHUNK_SZ + 3, NULL,
13195
        DYNAMIC_TYPE_TMP_BUFFER);
13196
    if (blob_buf == NULL) {
13197
        return MEMORY_E;
13198
    }
13199
13200
    for (;;) {
13201
        /* Read blob header: type (1 byte) + length (2 bytes big-endian) */
13202
        rc = cb(blob_header, 3, offset, cb_ctx);
13203
        if (rc < 3) {
13204
            /* End of data or error */
13205
            if (rc == 0 || blob_header[0] == 0) {
13206
            #ifdef DEBUG_WOLFTPM
13207
                printf("ST33 Firmware data done\n");
13208
            #endif
13209
                rc = TPM_RC_SUCCESS;
13210
            }
13211
            else {
13212
            #ifdef DEBUG_WOLFTPM
13213
                printf("ST33 Firmware data read error at offset %u\n", offset);
13214
            #endif
13215
                rc = BUFFER_E;
13216
            }
13217
            break;
13218
        }
13219
13220
        /* Check for end marker (type byte = 0) */
13221
        if (blob_header[0] == 0) {
13222
        #ifdef DEBUG_WOLFTPM
13223
            printf("ST33 Firmware data end marker at offset %u\n", offset);
13224
        #endif
13225
            rc = TPM_RC_SUCCESS;
13226
            break;
13227
        }
13228
13229
        /* Parse blob length from bytes 1-2 (big-endian) */
13230
        blob_len = ((uint32_t)blob_header[1] << 8) | blob_header[2];
13231
        blob_total = blob_len + 3; /* total blob size including header */
13232
13233
        if (blob_total > ST33_FW_MAX_CHUNK_SZ + 3) {
13234
        #ifdef DEBUG_WOLFTPM
13235
            printf("ST33 Blob too large: %u bytes at offset %u\n",
13236
                blob_total, offset);
13237
        #endif
13238
            rc = BUFFER_E;
13239
            break;
13240
        }
13241
13242
    #ifdef DEBUG_WOLFTPM
13243
        printf("ST33 Firmware blob offset %u, type 0x%02x, len %u\n",
13244
            offset, blob_header[0], blob_len);
13245
    #endif
13246
13247
        /* Read complete blob (header + data) */
13248
        rc = cb(blob_buf, blob_total, offset, cb_ctx);
13249
        if (rc != (int)blob_total) {
13250
        #ifdef DEBUG_WOLFTPM
13251
            printf("ST33 Failed to read blob data at offset %u\n", offset);
13252
        #endif
13253
            rc = BUFFER_E;
13254
            break;
13255
        }
13256
13257
        /* Send blob to TPM - blob is sent as-is per ST reference */
13258
        rc = TPM2_ST33_FieldUpgradeCommand(ccData, blob_buf, blob_total);
13259
        if (rc != TPM_RC_SUCCESS) {
13260
        #ifdef DEBUG_WOLFTPM
13261
            printf("ST33 FieldUpgradeData failed at offset %u: 0x%x\n",
13262
                offset, rc);
13263
        #endif
13264
            break;
13265
        }
13266
13267
        offset += blob_total;
13268
    }
13269
13270
    XFREE(blob_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
13271
13272
    if (rc == TPM_RC_SUCCESS) {
13273
        /* 300ms delay: ST reference implementation uses this delay to allow
13274
         * TPM to process firmware data blobs */
13275
        XSLEEP_MS(300);
13276
13277
    #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \
13278
        !defined(WOLFTPM_OPTEE) && !defined(WOLFTPM_WINAPI)
13279
        /* Do chip startup and request locality again */
13280
    #ifdef WOLFTPM_LINUX_DEV_AUTODETECT
13281
        if (dev->ctx.fd < 0) /* Only needed for SPI path */
13282
    #endif
13283
        rc = TPM2_ChipStartup(&dev->ctx, 10);
13284
    #endif
13285
    }
13286
#ifdef DEBUG_WOLFTPM
13287
    else {
13288
        printf("ST33 Firmware upgrade data failed 0x%x: %s\n",
13289
            rc, TPM2_GetRCString(rc));
13290
    }
13291
#endif
13292
    return rc;
13293
}
13294
13295
13296
/* Main ST33 firmware upgrade function. The manifest size selects the format
13297
 * and must match what the running firmware generation expects:
13298
 * - 321 bytes:  Non-LMS, generation 1 (e.g. 1.257, 1.771)
13299
 * - 177 bytes:  Non-LMS, generation 9 below 512 (e.g. 9.257)
13300
 * - 2697 bytes: LMS, generation 9 at 512 and above
13301
 */
13302
static int tpm2_st33_firmware_upgrade_hash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg,
13303
    uint8_t* manifest_hash, uint32_t manifest_hash_sz,
13304
    uint8_t* manifest, uint32_t manifest_sz,
13305
    wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession)
13306
{
13307
    int rc;
13308
    WOLFTPM2_CAPS caps;
13309
    int is_lms;
13310
    uint32_t expected_sz;
13311
    word16 manifestMajor = 0, manifestMinor = 0;
13312
    TPM_CC ccStart, ccData;
13313
13314
    /* ST33 sends full manifest directly, not hash */
13315
    (void)hashAlg;
13316
    (void)manifest_hash;
13317
    (void)manifest_hash_sz;
13318
13319
    /* Auto-detect LMS format from manifest size */
13320
    if (manifest_sz == ST33_MANIFEST_SIZE_LMS) {
13321
        is_lms = 1;
13322
    }
13323
    else if (manifest_sz == ST33_MANIFEST_SIZE_NON_LMS ||
13324
             manifest_sz == ST33_MANIFEST_SIZE_NON_LMS_RSA) {
13325
        is_lms = 0;
13326
    }
13327
    else {
13328
    #ifdef DEBUG_WOLFTPM
13329
        printf("ST33 Error: Invalid manifest size %u (expected %d or %d "
13330
            "for non-LMS or %d for LMS)\n", manifest_sz,
13331
            ST33_MANIFEST_SIZE_NON_LMS_RSA, ST33_MANIFEST_SIZE_NON_LMS,
13332
            ST33_MANIFEST_SIZE_LMS);
13333
    #endif
13334
        return BAD_FUNC_ARG;
13335
    }
13336
13337
    /* Get capabilities to check firmware version */
13338
    rc = wolfTPM2_GetCapabilities(dev, &caps);
13339
    if (rc != TPM_RC_SUCCESS) {
13340
    #ifdef DEBUG_WOLFTPM
13341
        printf("ST33 GetCapabilities failed 0x%x: %s\n",
13342
            rc, TPM2_GetRCString(rc));
13343
    #endif
13344
        return rc;
13345
    }
13346
13347
    rc = wolfTPM2_ST33_ManifestVersion(manifest, manifest_sz, &manifestMajor,
13348
        &manifestMinor);
13349
    if (rc != TPM_RC_SUCCESS) {
13350
    #ifdef DEBUG_WOLFTPM
13351
        printf("ST33 Error: manifest too small to hold a version header\n");
13352
    #endif
13353
        return rc;
13354
    }
13355
    rc = wolfTPM2_ST33_GetFwUpgradeCommands(&caps, manifestMajor, &ccStart,
13356
        &ccData, NULL);
13357
    if (rc != TPM_RC_SUCCESS) {
13358
    #ifdef DEBUG_WOLFTPM
13359
        printf("ST33 Could not select field upgrade command codes 0x%x: %s\n",
13360
            rc, TPM2_GetRCString(rc));
13361
    #endif
13362
        return rc;
13363
    }
13364
13365
#ifdef DEBUG_WOLFTPM
13366
    printf("ST33 Firmware version: Major=%u, Minor=%u, Vendor=0x%x\n",
13367
        caps.fwVerMajor, caps.fwVerMinor, caps.fwVerVendor);
13368
    printf("ST33 Manifest size: %u bytes, format: %s, targets %u.%u\n",
13369
        manifest_sz, is_lms ? "LMS" : "non-LMS", manifestMajor, manifestMinor);
13370
    printf("ST33 Field upgrade command codes: start 0x%08x, data 0x%08x\n",
13371
        (unsigned int)ccStart, (unsigned int)ccData);
13372
#endif
13373
13374
    /* Validate the manifest matches what this firmware generation expects */
13375
    expected_sz = tpm2_st33_expected_manifest_sz(&caps);
13376
    if (expected_sz != 0 && manifest_sz != expected_sz) {
13377
    #ifdef DEBUG_WOLFTPM
13378
        printf("ST33 Error: manifest size %u does not match the %u bytes "
13379
            "firmware %u.%u expects\n", manifest_sz, expected_sz,
13380
            caps.fwVerMajor, caps.fwVerMinor);
13381
    #endif
13382
        return BAD_FUNC_ARG;
13383
    }
13384
13385
    /* The manifest carries the firmware line it upgrades. Within a family a
13386
     * version jump is normal and expected - an ST33TPHF2X goes 74.9 to 2.512 -
13387
     * so only an image from a different silicon family is refused. The TPM
13388
     * would otherwise report that as a signature or command code failure. */
13389
    if (tpm2_st33_family(manifestMajor) != ST33_FW_FAMILY_UNKNOWN &&
13390
            tpm2_st33_family(caps.fwVerMajor) != ST33_FW_FAMILY_UNKNOWN &&
13391
            tpm2_st33_family(manifestMajor) !=
13392
                tpm2_st33_family(caps.fwVerMajor)) {
13393
    #ifdef DEBUG_WOLFTPM
13394
        printf("ST33 Error: firmware image targets %u.%u, a different part "
13395
            "family than this TPM running %u.%u\n", manifestMajor,
13396
            manifestMinor, caps.fwVerMajor, caps.fwVerMinor);
13397
    #endif
13398
        return BAD_FUNC_ARG;
13399
    }
13400
13401
    /* Send manifest - the common function handles both LMS and non-LMS */
13402
    rc = tpm2_st33_firmware_start_common(dev, manifest, manifest_sz, is_lms,
13403
        ccStart, startSession);
13404
13405
    if (rc == TPM_RC_SUCCESS) {
13406
        rc = tpm2_st33_firmware_data(dev, ccData, cb, cb_ctx);
13407
    }
13408
    /* Note: ST33 doesn't require a finalize command - the firmware update
13409
     * is complete after all blobs are sent. The TPM will automatically
13410
     * apply the update on next reset/power cycle. */
13411
#ifdef DEBUG_WOLFTPM
13412
    if (rc != TPM_RC_SUCCESS) {
13413
        printf("ST33 Firmware update failed 0x%x: %s\n",
13414
            rc, TPM2_GetRCString(rc));
13415
    }
13416
#endif
13417
    return rc;
13418
}
13419
13420
/* Cancel/abandon firmware upgrade */
13421
static int tpm2_st33_firmware_cancel(WOLFTPM2_DEV* dev)
13422
{
13423
    int rc;
13424
    uint8_t cmd[2];
13425
    uint16_t val16;
13426
13427
    (void)dev;
13428
13429
    val16 = 0; /* data size */
13430
    XMEMCPY(&cmd[0], &val16, sizeof(val16));
13431
13432
    rc = TPM2_ST33_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor_ST33,
13433
        cmd, sizeof(cmd));
13434
#ifdef DEBUG_WOLFTPM
13435
    if (rc != TPM_RC_SUCCESS) {
13436
        printf("ST33 Firmware abandon failed 0x%x: %s\n",
13437
            rc, TPM2_GetRCString(rc));
13438
    }
13439
#endif
13440
    return rc;
13441
}
13442
13443
#endif /* WOLFTPM_ST33 || WOLFTPM_AUTODETECT */
13444
#endif /* WOLFTPM_FIRMWARE_UPGRADE */
13445
13446
/******************************************************************************/
13447
/* --- END Firmware Upgrade Support -- */
13448
/******************************************************************************/
13449
13450
#endif /* !WOLFTPM2_NO_WRAPPER */