Coverage Report

Created: 2022-04-27 14:33

/libfido2/src/tpm.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021 Yubico AB. All rights reserved.
3
 * Use of this source code is governed by a BSD-style
4
 * license that can be found in the LICENSE file.
5
 */
6
7
/*
8
 * Trusted Platform Module (TPM) 2.0 attestation support. Documentation
9
 * references are relative to revision 01.38 of the TPM 2.0 specification.
10
 */
11
12
#include <openssl/sha.h>
13
14
#include "packed.h"
15
#include "fido.h"
16
17
/* Part 1, 4.89: TPM_GENERATED_VALUE */
18
12
#define TPM_MAGIC       0xff544347
19
20
/* Part 2, 6.3: TPM_ALG_ID */
21
12
#define TPM_ALG_RSA     0x0001
22
34
#define TPM_ALG_SHA256  0x000b
23
45
#define TPM_ALG_NULL    0x0010
24
7
#define TPM_ALG_ECC     0x0023
25
26
/* Part 2, 6.4: TPM_ECC_CURVE */
27
7
#define TPM_ECC_P256    0x0003
28
29
/* Part 2, 6.9: TPM_ST_ATTEST_CERTIFY */
30
12
#define TPM_ST_CERTIFY  0x8017
31
32
/* Part 2, 8.3: TPMA_OBJECT */
33
19
#define TPMA_RESERVED   0xfff8f309        /* reserved bits; must be zero */
34
19
#define TPMA_FIXED      0x00000002        /* object has fixed hierarchy */
35
19
#define TPMA_CLEAR      0x00000004        /* object persists */
36
19
#define TPMA_FIXED_P    0x00000010        /* object has fixed parent */
37
19
#define TPMA_SENSITIVE  0x00000020        /* data originates within tpm */
38
19
#define TPMA_SIGN       0x00040000        /* object may sign */
39
40
/* Part 2, 10.4.2: TPM2B_DIGEST */
41
PACKED_TYPE(tpm_sha256_digest_t,
42
struct tpm_sha256_digest {
43
        uint16_t size; /* sizeof(body) */
44
        uint8_t  body[32];
45
})
46
47
/* Part 2, 10.4.3: TPM2B_DATA */
48
PACKED_TYPE(tpm_sha1_data_t,
49
struct tpm_sha1_data {
50
        uint16_t size; /* sizeof(body */
51
        uint8_t  body[20];
52
})
53
54
/* Part 2, 10.5.3: TPM2B_NAME */
55
PACKED_TYPE(tpm_sha256_name_t,
56
struct tpm_sha256_name {
57
        uint16_t size; /* sizeof(alg) + sizeof(body) */
58
        uint16_t alg;  /* TPM_ALG_SHA256 */
59
        uint8_t  body[32];
60
})
61
62
/* Part 2, 10.11.1: TPMS_CLOCK_INFO */
63
PACKED_TYPE(tpm_clock_info_t,
64
struct tpm_clock_info {
65
        uint64_t timestamp_ms;
66
        uint32_t reset_count;   /* obfuscated by tpm */
67
        uint32_t restart_count; /* obfuscated by tpm */
68
        uint8_t  safe;          /* 1 if timestamp_ms is current */
69
})
70
71
/* Part 2, 10.12.8 TPMS_ATTEST */
72
PACKED_TYPE(tpm_sha1_attest_t,
73
struct tpm_sha1_attest {
74
        uint32_t          magic;     /* TPM_MAGIC */
75
        uint16_t          type;      /* TPM_ST_ATTEST_CERTIFY */
76
        tpm_sha256_name_t signer;    /* full tpm path of signing key */
77
        tpm_sha1_data_t   data;      /* signed sha1 */
78
        tpm_clock_info_t  clock;
79
        uint64_t          fwversion; /* obfuscated by tpm */
80
        tpm_sha256_name_t name;      /* sha256 of tpm_rs256_pubarea_t */
81
        tpm_sha256_name_t qual_name; /* full tpm path of attested key */
82
})
83
84
/* Part 2, 11.2.4.5: TPM2B_PUBLIC_KEY_RSA */
85
PACKED_TYPE(tpm_rs256_key_t,
86
struct tpm_rs256_key {
87
        uint16_t size; /* sizeof(body) */
88
        uint8_t  body[256];
89
})
90
91
/* Part 2, 11.2.5.1: TPM2B_ECC_PARAMETER */
92
PACKED_TYPE(tpm_es256_coord_t,
93
struct tpm_es256_coord {
94
        uint16_t size; /* sizeof(body) */
95
        uint8_t  body[32];
96
})
97
98
/* Part 2, 11.2.5.2: TPMS_ECC_POINT */
99
PACKED_TYPE(tpm_es256_point_t,
100
struct tpm_es256_point {
101
        tpm_es256_coord_t x;
102
        tpm_es256_coord_t y;
103
})
104
105
/* Part 2, 12.2.3.5: TPMS_RSA_PARMS */
106
PACKED_TYPE(tpm_rs256_param_t,
107
struct tpm_rs256_param {
108
        uint16_t symmetric; /* TPM_ALG_NULL */
109
        uint16_t scheme;    /* TPM_ALG_NULL */
110
        uint16_t keybits;   /* 2048 */
111
        uint32_t exponent;  /* zero (meaning 2^16 + 1) */
112
})
113
114
/* Part 2, 12.2.3.6: TPMS_ECC_PARMS */
115
PACKED_TYPE(tpm_es256_param_t,
116
struct tpm_es256_param {
117
        uint16_t symmetric; /* TPM_ALG_NULL */
118
        uint16_t scheme;    /* TPM_ALG_NULL */
119
        uint16_t curve_id;  /* TPM_ECC_P256 */
120
        uint16_t kdf;       /* TPM_ALG_NULL */
121
})
122
123
/* Part 2, 12.2.4: TPMT_PUBLIC */
124
PACKED_TYPE(tpm_rs256_pubarea_t,
125
struct tpm_rs256_pubarea {
126
        uint16_t            alg;    /* TPM_ALG_RSA */
127
        uint16_t            hash;   /* TPM_ALG_SHA256 */
128
        uint32_t            attr;
129
        tpm_sha256_digest_t policy; /* must be present? */
130
        tpm_rs256_param_t   param;
131
        tpm_rs256_key_t     key;
132
})
133
134
/* Part 2, 12.2.4: TPMT_PUBLIC */
135
PACKED_TYPE(tpm_es256_pubarea_t,
136
struct tpm_es256_pubarea {
137
        uint16_t            alg;    /* TPM_ALG_ECC */
138
        uint16_t            hash;   /* TPM_ALG_SHA256 */
139
        uint32_t            attr;
140
        tpm_sha256_digest_t policy; /* must be present? */
141
        tpm_es256_param_t   param;
142
        tpm_es256_point_t   point;
143
})
144
145
static int
146
get_signed_sha1(tpm_sha1_data_t *dgst, const fido_blob_t *authdata,
147
    const fido_blob_t *clientdata)
148
17
{
149
17
        const EVP_MD    *md = NULL;
150
17
        EVP_MD_CTX      *ctx = NULL;
151
17
        int              ok = -1;
152
153
17
        if ((dgst->size = sizeof(dgst->body)) != SHA_DIGEST_LENGTH ||
154
17
            (md = EVP_sha1()) == NULL ||
155
17
            (ctx = EVP_MD_CTX_new()) == NULL ||
156
17
            EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
157
17
            EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
158
17
            EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
159
17
            EVP_DigestFinal_ex(ctx, dgst->body, NULL) != 1) {
160
2
                fido_log_debug("%s: sha1", __func__);
161
2
                goto fail;
162
2
        }
163
164
15
        ok = 0;
165
17
fail:
166
17
        EVP_MD_CTX_free(ctx);
167
168
17
        return (ok);
169
15
}
170
171
static int
172
get_signed_name(tpm_sha256_name_t *name, const fido_blob_t *pubarea)
173
15
{
174
15
        name->alg = TPM_ALG_SHA256;
175
15
        name->size = sizeof(name->alg) + sizeof(name->body);
176
15
        if (sizeof(name->body) != SHA256_DIGEST_LENGTH ||
177
15
            SHA256(pubarea->ptr, pubarea->len, name->body) != name->body) {
178
1
                fido_log_debug("%s: sha256", __func__);
179
1
                return -1;
180
1
        }
181
182
14
        return 0;
183
15
}
184
185
static void
186
bswap_rs256_pubarea(tpm_rs256_pubarea_t *x)
187
12
{
188
12
        x->alg = htobe16(x->alg);
189
12
        x->hash = htobe16(x->hash);
190
12
        x->attr = htobe32(x->attr);
191
12
        x->policy.size = htobe16(x->policy.size);
192
12
        x->param.symmetric = htobe16(x->param.symmetric);
193
12
        x->param.scheme = htobe16(x->param.scheme);
194
12
        x->param.keybits = htobe16(x->param.keybits);
195
12
        x->key.size = htobe16(x->key.size);
196
12
}
197
198
static void
199
bswap_es256_pubarea(tpm_es256_pubarea_t *x)
200
7
{
201
7
        x->alg = htobe16(x->alg);
202
7
        x->hash = htobe16(x->hash);
203
7
        x->attr = htobe32(x->attr);
204
7
        x->policy.size = htobe16(x->policy.size);
205
7
        x->param.symmetric = htobe16(x->param.symmetric);
206
7
        x->param.scheme = htobe16(x->param.scheme);
207
7
        x->param.curve_id = htobe16(x->param.curve_id);
208
7
        x->param.kdf = htobe16(x->param.kdf);
209
7
        x->point.x.size = htobe16(x->point.x.size);
210
7
        x->point.y.size = htobe16(x->point.y.size);
211
7
}
212
213
static void
214
bswap_sha1_certinfo(tpm_sha1_attest_t *x)
215
12
{
216
12
        x->magic = htobe32(x->magic);
217
12
        x->type = htobe16(x->type);
218
12
        x->signer.size = htobe16(x->signer.size);
219
12
        x->data.size = htobe16(x->data.size);
220
12
        x->name.alg = htobe16(x->name.alg);
221
12
        x->name.size = htobe16(x->name.size);
222
12
}
223
224
static int
225
check_rs256_pubarea(const fido_blob_t *buf, const rs256_pk_t *pk)
226
12
{
227
12
        const tpm_rs256_pubarea_t       *actual;
228
12
        tpm_rs256_pubarea_t              expected;
229
12
        int                              ok;
230
231
12
        if (buf->len != sizeof(*actual)) {
232
0
                fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
233
0
                return -1;
234
0
        }
235
12
        actual = (const void *)buf->ptr;
236
237
12
        memset(&expected, 0, sizeof(expected));
238
12
        expected.alg = TPM_ALG_RSA;
239
12
        expected.hash = TPM_ALG_SHA256;
240
12
        expected.attr = be32toh(actual->attr);
241
12
        expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR);
242
12
        expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN);
243
12
        expected.policy = actual->policy;
244
12
        expected.policy.size = sizeof(expected.policy.body);
245
12
        expected.param.symmetric = TPM_ALG_NULL;
246
12
        expected.param.scheme = TPM_ALG_NULL;
247
12
        expected.param.keybits = 2048;
248
12
        expected.param.exponent = 0; /* meaning 2^16+1 */
249
12
        expected.key.size = sizeof(expected.key.body);
250
12
        memcpy(&expected.key.body, &pk->n, sizeof(expected.key.body));
251
12
        bswap_rs256_pubarea(&expected);
252
253
12
        ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
254
12
        explicit_bzero(&expected, sizeof(expected));
255
256
12
        return ok != 0 ? -1 : 0;
257
12
}
258
259
static int
260
check_es256_pubarea(const fido_blob_t *buf, const es256_pk_t *pk)
261
7
{
262
7
        const tpm_es256_pubarea_t       *actual;
263
7
        tpm_es256_pubarea_t              expected;
264
7
        int                              ok;
265
266
7
        if (buf->len != sizeof(*actual)) {
267
0
                fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
268
0
                return -1;
269
0
        }
270
7
        actual = (const void *)buf->ptr;
271
272
7
        memset(&expected, 0, sizeof(expected));
273
7
        expected.alg = TPM_ALG_ECC;
274
7
        expected.hash = TPM_ALG_SHA256;
275
7
        expected.attr = be32toh(actual->attr);
276
7
        expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR);
277
7
        expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN);
278
7
        expected.policy = actual->policy;
279
7
        expected.policy.size = sizeof(expected.policy.body);
280
7
        expected.param.symmetric = TPM_ALG_NULL;
281
7
        expected.param.scheme = TPM_ALG_NULL; /* TCG Alg. Registry, 5.2.4 */
282
7
        expected.param.curve_id = TPM_ECC_P256;
283
7
        expected.param.kdf = TPM_ALG_NULL;
284
7
        expected.point.x.size = sizeof(expected.point.x.body);
285
7
        expected.point.y.size = sizeof(expected.point.y.body);
286
7
        memcpy(&expected.point.x.body, &pk->x, sizeof(expected.point.x.body));
287
7
        memcpy(&expected.point.y.body, &pk->y, sizeof(expected.point.y.body));
288
7
        bswap_es256_pubarea(&expected);
289
290
7
        ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
291
7
        explicit_bzero(&expected, sizeof(expected));
292
293
7
        return ok != 0 ? -1 : 0;
294
7
}
295
296
static int
297
check_sha1_certinfo(const fido_blob_t *buf, const fido_blob_t *clientdata_hash,
298
    const fido_blob_t *authdata_raw, const fido_blob_t *pubarea)
299
17
{
300
17
        const tpm_sha1_attest_t *actual;
301
17
        tpm_sha1_attest_t        expected;
302
17
        tpm_sha1_data_t          signed_data;
303
17
        tpm_sha256_name_t        signed_name;
304
17
        int                      ok = -1;
305
306
17
        memset(&signed_data, 0, sizeof(signed_data));
307
17
        memset(&signed_name, 0, sizeof(signed_name));
308
309
17
        if (get_signed_sha1(&signed_data, authdata_raw, clientdata_hash) < 0 ||
310
17
            get_signed_name(&signed_name, pubarea) < 0) {
311
3
                fido_log_debug("%s: get_signed_sha1/name", __func__);
312
3
                goto fail;
313
3
        }
314
14
        if (buf->len != sizeof(*actual)) {
315
2
                fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
316
2
                goto fail;
317
2
        }
318
12
        actual = (const void *)buf->ptr;
319
320
12
        memset(&expected, 0, sizeof(expected));
321
12
        expected.magic = TPM_MAGIC;
322
12
        expected.type = TPM_ST_CERTIFY;
323
12
        expected.signer = actual->signer;
324
12
        expected.signer.size = sizeof(expected.signer.alg) +
325
12
            sizeof(expected.signer.body);
326
12
        expected.data = signed_data;
327
12
        expected.clock = actual->clock;
328
12
        expected.clock.safe = 1;
329
12
        expected.fwversion = actual->fwversion;
330
12
        expected.name = signed_name;
331
12
        expected.qual_name = actual->qual_name;
332
12
        bswap_sha1_certinfo(&expected);
333
334
12
        ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
335
17
fail:
336
17
        explicit_bzero(&expected, sizeof(expected));
337
17
        explicit_bzero(&signed_data, sizeof(signed_data));
338
17
        explicit_bzero(&signed_name, sizeof(signed_name));
339
340
17
        return ok != 0 ? -1 : 0;
341
12
}
342
343
int
344
fido_get_signed_hash_tpm(fido_blob_t *dgst, const fido_blob_t *clientdata_hash,
345
    const fido_blob_t *authdata_raw, const fido_attstmt_t *attstmt,
346
    const fido_attcred_t *attcred)
347
22
{
348
22
        const fido_blob_t *pubarea = &attstmt->pubarea;
349
22
        const fido_blob_t *certinfo = &attstmt->certinfo;
350
351
22
        if (attstmt->alg != COSE_RS1) {
352
2
                fido_log_debug("%s: unsupported alg %d", __func__,
353
2
                    attstmt->alg);
354
2
                return -1;
355
2
        }
356
357
20
        switch (attcred->type) {
358
7
        case COSE_ES256:
359
7
                if (check_es256_pubarea(pubarea, &attcred->pubkey.es256) < 0) {
360
1
                        fido_log_debug("%s: check_es256_pubarea", __func__);
361
1
                        return -1;
362
1
                }
363
6
                break;
364
12
        case COSE_RS256:
365
12
                if (check_rs256_pubarea(pubarea, &attcred->pubkey.rs256) < 0) {
366
1
                        fido_log_debug("%s: check_rs256_pubarea", __func__);
367
1
                        return -1;
368
1
                }
369
11
                break;
370
11
        default:
371
1
                fido_log_debug("%s: unsupported type %d", __func__,
372
1
                    attcred->type);
373
1
                return -1;
374
20
        }
375
376
17
        if (check_sha1_certinfo(certinfo, clientdata_hash, authdata_raw,
377
17
            pubarea) < 0) {
378
8
                fido_log_debug("%s: check_sha1_certinfo", __func__);
379
8
                return -1;
380
8
        }
381
382
9
        if (dgst->len < SHA_DIGEST_LENGTH ||
383
9
            SHA1(certinfo->ptr, certinfo->len, dgst->ptr) != dgst->ptr) {
384
0
                fido_log_debug("%s: sha1", __func__);
385
0
                return -1;
386
0
        }
387
9
        dgst->len = SHA_DIGEST_LENGTH;
388
389
9
        return 0;
390
9
}