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