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