aikpub2: Output AIK signature algorithm
[strongswan.git] / src / libtpmtss / tpm_tss_quote_info.c
1 /*
2 * Copyright (C) 2016 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <tpm_tss_quote_info.h>
17
18 #include <bio/bio_writer.h>
19
20 #ifndef TPM_TAG_QUOTE_INFO2
21 #define TPM_TAG_QUOTE_INFO2 0x0036
22 #endif
23 #ifndef TPM_LOC_ZERO
24 #define TPM_LOC_ZERO 0x01
25 #endif
26
27 typedef struct private_tpm_tss_quote_info_t private_tpm_tss_quote_info_t;
28
29 /**
30 * Private data of an tpm_tss_quote_info_t object.
31 */
32 struct private_tpm_tss_quote_info_t {
33
34 /**
35 * Public tpm_tss_quote_info_t interface.
36 */
37 tpm_tss_quote_info_t public;
38
39 /**
40 * TPM Quote Mode
41 */
42 tpm_quote_mode_t quote_mode;
43
44 /**
45 * TPM Qualified Signer
46 */
47 chunk_t qualified_signer;
48
49 /**
50 * TPM Clock Info
51 */
52 chunk_t clock_info;
53
54 /**
55 * TPM Version Info
56 */
57 chunk_t version_info;
58
59 /**
60 * TPM PCR Selection
61 */
62 chunk_t pcr_select;
63
64 /**
65 * TPM PCR Composite Hash
66 */
67 chunk_t pcr_digest;
68
69 /**
70 * TPM PCR Composite Hash algoritm
71 */
72 hash_algorithm_t pcr_digest_alg;
73
74 /**
75 * Reference count
76 */
77 refcount_t ref;
78
79 };
80
81 METHOD(tpm_tss_quote_info_t, get_quote_mode, tpm_quote_mode_t,
82 private_tpm_tss_quote_info_t *this)
83 {
84 return this->quote_mode;
85 }
86
87 METHOD(tpm_tss_quote_info_t, get_pcr_digest_alg, hash_algorithm_t,
88 private_tpm_tss_quote_info_t *this)
89 {
90 return this->pcr_digest_alg;
91 }
92
93 METHOD(tpm_tss_quote_info_t, get_pcr_digest, chunk_t,
94 private_tpm_tss_quote_info_t *this)
95 {
96 return this->pcr_digest;
97 }
98
99 METHOD(tpm_tss_quote_info_t, get_quote, bool,
100 private_tpm_tss_quote_info_t *this, chunk_t nonce,
101 tpm_tss_pcr_composite_t *composite, chunk_t *quoted)
102 {
103 chunk_t pcr_composite, pcr_digest;
104 bio_writer_t *writer;
105 hasher_t *hasher;
106 bool equal_digests;
107
108 /* Construct PCR Composite */
109 writer = bio_writer_create(32);
110
111 switch (this->quote_mode)
112 {
113 case TPM_QUOTE:
114 case TPM_QUOTE2:
115 case TPM_QUOTE2_VERSION_INFO:
116 writer->write_data16(writer, composite->pcr_select);
117 writer->write_data32(writer, composite->pcr_composite);
118
119 break;
120 case TPM_QUOTE_TPM2:
121 writer->write_data(writer, composite->pcr_composite);
122 break;
123 case TPM_QUOTE_NONE:
124 break;
125 }
126
127 pcr_composite = writer->extract_buf(writer);
128 writer->destroy(writer);
129
130 DBG2(DBG_PTS, "constructed PCR Composite: %B", &pcr_composite);
131
132 /* Compute PCR Composite Hash */
133 hasher = lib->crypto->create_hasher(lib->crypto, this->pcr_digest_alg);
134 if (!hasher || !hasher->allocate_hash(hasher, pcr_composite, &pcr_digest))
135 {
136 DESTROY_IF(hasher);
137 chunk_free(&pcr_composite);
138 return FALSE;
139 }
140 hasher->destroy(hasher);
141 chunk_free(&pcr_composite);
142
143 DBG2(DBG_PTS, "constructed PCR Composite digest: %B", &pcr_digest);
144
145 equal_digests = chunk_equals(pcr_digest, this->pcr_digest);
146
147 /* Construct Quote Info */
148 writer = bio_writer_create(32);
149
150 switch (this->quote_mode)
151 {
152 case TPM_QUOTE:
153 /* Version number */
154 writer->write_data(writer, chunk_from_chars(1, 1, 0, 0));
155
156 /* Magic QUOT value */
157 writer->write_data(writer, chunk_from_str("QUOT"));
158
159 /* PCR Composite Hash */
160 writer->write_data(writer, pcr_digest);
161
162 /* Secret assessment value 20 bytes (nonce) */
163 writer->write_data(writer, nonce);
164 break;
165 case TPM_QUOTE2:
166 case TPM_QUOTE2_VERSION_INFO:
167 /* TPM Structure Tag */
168 writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2);
169
170 /* Magic QUT2 value */
171 writer->write_data(writer, chunk_from_str("QUT2"));
172
173 /* Secret assessment value 20 bytes (nonce) */
174 writer->write_data(writer, nonce);
175
176 /* PCR selection */
177 writer->write_data16(writer, composite->pcr_select);
178
179 /* TPM Locality Selection */
180 writer->write_uint8(writer, TPM_LOC_ZERO);
181
182 /* PCR Composite Hash */
183 writer->write_data(writer, pcr_digest);
184
185 if (this->quote_mode == TPM_QUOTE2_VERSION_INFO)
186 {
187 /* TPM version Info */
188 writer->write_data(writer, this->version_info);
189 }
190 break;
191 case TPM_QUOTE_TPM2:
192 /* Magic */
193 writer->write_data(writer, chunk_from_chars(0xff,0x54,0x43,0x47));
194
195 /* Type */
196 writer->write_uint16(writer, 0x8018);
197
198 /* Qualified Signer */
199 writer->write_data16(writer, this->qualified_signer);
200
201 /* Extra Data */
202 writer->write_data16(writer, nonce);
203
204 /* Clock Info */
205 writer->write_data(writer, this->clock_info);
206
207 /* Firmware Version */
208 writer->write_data(writer, this->version_info);
209
210 /* PCR Selection */
211 writer->write_data(writer, this->pcr_select);
212
213 /* PCR Composite Hash */
214 writer->write_data16(writer, pcr_digest);
215 break;
216 case TPM_QUOTE_NONE:
217 break;
218 }
219 chunk_free(&pcr_digest);
220 *quoted = writer->extract_buf(writer);
221 writer->destroy(writer);
222
223 DBG2(DBG_PTS, "constructed TPM Quote Info: %B", quoted);
224
225 if (!equal_digests)
226 {
227 DBG1(DBG_IMV, "received PCR Composite digest does not match "
228 "constructed one");
229 chunk_free(quoted);
230 }
231 return equal_digests;
232 }
233
234 METHOD(tpm_tss_quote_info_t, set_version_info, void,
235 private_tpm_tss_quote_info_t *this, chunk_t version_info)
236 {
237 chunk_free(&this->version_info);
238 this->version_info = chunk_clone(version_info);
239 }
240
241 METHOD(tpm_tss_quote_info_t, get_version_info, chunk_t,
242 private_tpm_tss_quote_info_t *this)
243 {
244 return this->version_info;
245 }
246
247 METHOD(tpm_tss_quote_info_t, set_tpm2_info, void,
248 private_tpm_tss_quote_info_t *this, chunk_t qualified_signer,
249 chunk_t clock_info, chunk_t pcr_select)
250 {
251 chunk_free(&this->qualified_signer);
252 this->qualified_signer = chunk_clone(qualified_signer);
253
254 chunk_free(&this->clock_info);
255 this->clock_info = chunk_clone(clock_info);
256
257 chunk_free(&this->pcr_select);
258 this->pcr_select = chunk_clone(pcr_select);
259 }
260
261 METHOD(tpm_tss_quote_info_t, get_tpm2_info, void,
262 private_tpm_tss_quote_info_t *this, chunk_t *qualified_signer,
263 chunk_t *clock_info, chunk_t *pcr_select)
264 {
265 if (qualified_signer)
266 {
267 *qualified_signer = this->qualified_signer;
268 }
269 if (clock_info)
270 {
271 *clock_info = this->clock_info;
272 }
273 if (pcr_select)
274 {
275 *pcr_select = this->pcr_select;
276 }
277 }
278
279 METHOD(tpm_tss_quote_info_t, get_ref, tpm_tss_quote_info_t*,
280 private_tpm_tss_quote_info_t *this)
281 {
282 ref_get(&this->ref);
283
284 return &this->public;
285 }
286
287 METHOD(tpm_tss_quote_info_t, destroy, void,
288 private_tpm_tss_quote_info_t *this)
289 {
290 if (ref_put(&this->ref))
291 {
292 chunk_free(&this->qualified_signer);
293 chunk_free(&this->clock_info);
294 chunk_free(&this->version_info);
295 chunk_free(&this->pcr_select);
296 chunk_free(&this->pcr_digest);
297 free(this);
298 }
299 }
300
301 /**
302 * See header
303 */
304 tpm_tss_quote_info_t *tpm_tss_quote_info_create(tpm_quote_mode_t quote_mode,
305 hash_algorithm_t pcr_digest_alg, chunk_t pcr_digest)
306
307 {
308 private_tpm_tss_quote_info_t *this;
309
310 INIT(this,
311 .public = {
312 .get_quote_mode = _get_quote_mode,
313 .get_pcr_digest_alg = _get_pcr_digest_alg,
314 .get_pcr_digest = _get_pcr_digest,
315 .get_quote = _get_quote,
316 .set_version_info = _set_version_info,
317 .get_version_info = _get_version_info,
318 .set_tpm2_info = _set_tpm2_info,
319 .get_tpm2_info = _get_tpm2_info,
320 .get_ref = _get_ref,
321 .destroy = _destroy,
322 },
323 .quote_mode = quote_mode,
324 .pcr_digest_alg = pcr_digest_alg,
325 .pcr_digest = chunk_clone(pcr_digest),
326 .ref = 1,
327 );
328
329 return &this->public;
330 }