d7d853bf442a117fd2920621c85059562127dfa4
[vboot.git] / firmware / lib / tpm2_lite / tlcl.c
1 /*
2  * Copyright 2016 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  *
6  * Some TPM constants and type definitions for standalone compilation for use
7  * in the firmware
8  */
9
10 #include "rollback_index.h"
11 #include "tpm2_marshaling.h"
12 #include "utility.h"
13 #include "tlcl.h"
14
15 static struct tpm2_response *tpm_process_command(TPM_CC command,
16                                                  void *command_body)
17 {
18         /* Command/response buffer. */
19         static uint8_t cr_buffer[TPM_BUFFER_SIZE];
20         uint32_t out_size, in_size;
21         struct tpm2_response *response;
22
23         out_size = tpm_marshal_command(command, command_body,
24                                        cr_buffer, sizeof(cr_buffer));
25         if (out_size < 0) {
26                 VBDEBUG(("command %#x, cr size %d\n",
27                          command, out_size));
28                 return NULL;
29         }
30
31         in_size = sizeof(cr_buffer);
32         if (VbExTpmSendReceive(cr_buffer, out_size,
33                                cr_buffer, &in_size) != TPM_SUCCESS) {
34                 VBDEBUG(("tpm transaction failed for %#x\n", command));
35                 return NULL;
36         }
37
38         response = tpm_unmarshal_response(command, cr_buffer, in_size);
39
40         VBDEBUG(("%s: command %#x, return code %#x\n", __func__, command,
41                  response ? response->hdr.tpm_code : -1));
42
43         return response;
44 }
45
46 static uint32_t tlcl_read_ph_disabled(void)
47 {
48         uint32_t rv;
49         TPM_STCLEAR_FLAGS flags;
50
51         rv = TlclGetSTClearFlags(&flags);
52         if (rv != TPM_SUCCESS)
53                 return rv;
54
55         tpm_set_ph_disabled(!flags.phEnable);
56
57         return TPM_SUCCESS;
58 }
59
60 uint32_t TlclLibInit(void)
61 {
62         uint32_t rv;
63
64         rv = VbExTpmInit();
65         if (rv != TPM_SUCCESS)
66                 return rv;
67
68         rv = tlcl_read_ph_disabled();
69         if (rv != TPM_SUCCESS) {
70                 TlclLibClose();
71                 return rv;
72         }
73
74         return TPM_SUCCESS;
75 }
76
77 uint32_t TlclLibClose(void)
78 {
79         return VbExTpmClose();
80 }
81
82 uint32_t TlclSendReceive(const uint8_t *request, uint8_t *response,
83                          int max_length)
84 {
85         uint32_t rv, resp_size;
86
87         resp_size = max_length;
88         rv = VbExTpmSendReceive(request, tpm_get_packet_size(request),
89                                 response, &resp_size);
90
91         return rv ? rv : tpm_get_packet_response_code(response);
92 }
93
94 int TlclPacketSize(const uint8_t *packet)
95 {
96         return tpm_get_packet_size(packet);
97 }
98
99 uint32_t TlclStartup(void)
100 {
101         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
102         return TPM_SUCCESS;
103 }
104
105 uint32_t TlclSaveState(void)
106 {
107         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
108         return TPM_SUCCESS;
109 }
110
111 uint32_t TlclResume(void)
112 {
113         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
114         return TPM_SUCCESS;
115 }
116
117 uint32_t TlclSelfTestFull(void)
118 {
119         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
120         return TPM_SUCCESS;
121 }
122
123 uint32_t TlclContinueSelfTest(void)
124 {
125         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
126         return TPM_SUCCESS;
127 }
128
129 uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
130 {
131         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
132         return TPM_SUCCESS;
133 }
134
135 /**
136  * Issue a ForceClear.  The TPM error code is returned.
137  */
138 uint32_t TlclForceClear(void)
139 {
140         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
141         return TPM_SUCCESS;
142 }
143
144 uint32_t TlclSetDeactivated(uint8_t flag)
145 {
146         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
147         return TPM_SUCCESS;
148 }
149
150 uint32_t TlclSetEnable(void)
151 {
152         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
153         return TPM_SUCCESS;
154 }
155
156 uint32_t TlclGetFlags(uint8_t* disable,
157                       uint8_t* deactivated,
158                       uint8_t *nvlocked)
159 {
160         /* For TPM2 the flags are always the same */
161         if (disable)
162                 *disable = 0;
163         if (deactivated)
164                 *deactivated = 0;
165         if (nvlocked)
166                 *nvlocked = 1;
167         return TPM_SUCCESS;
168 }
169
170 int TlclIsOwned(void)
171 {
172         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
173         return 0;
174 }
175
176 uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
177 {
178         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
179         return TPM_SUCCESS;
180 }
181
182 /**
183  * Get the permission bits for the NVRAM space with |index|.
184  */
185 uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions)
186 {
187         *permissions = 0;
188         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
189         return TPM_SUCCESS;
190 }
191
192 static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property,
193                                     struct get_capability_response **presp)
194 {
195         struct tpm2_response *response;
196         struct tpm2_get_capability_cmd getcap;
197
198         getcap.capability = cap;
199         getcap.property = property;
200         getcap.property_count = 1;
201
202         response = tpm_process_command(TPM2_GetCapability, &getcap);
203         if (!response || response->hdr.tpm_code)
204                 return TPM_E_IOERROR;
205         *presp = &response->cap;
206
207         return TPM_SUCCESS;
208 }
209
210 static uint32_t tlcl_get_tpm_property(TPM_PT property, uint32_t *pvalue)
211 {
212         uint32_t rv;
213         struct get_capability_response *resp;
214         TPML_TAGGED_TPM_PROPERTY *tpm_prop;
215
216         rv = tlcl_get_capability(TPM_CAP_TPM_PROPERTIES, property, &resp);
217         if (rv != TPM_SUCCESS)
218                 return rv;
219
220         if (resp->capability_data.capability != TPM_CAP_TPM_PROPERTIES)
221                 return TPM_E_IOERROR;
222
223         tpm_prop = &resp->capability_data.data.tpm_properties;
224
225         if ((tpm_prop->count != 1) ||
226             (tpm_prop->tpm_property[0].property != property))
227                 return TPM_E_IOERROR;
228
229         *pvalue = tpm_prop->tpm_property[0].value;
230         return TPM_SUCCESS;
231 }
232
233 uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
234 {
235         return tlcl_get_tpm_property(TPM_PT_PERMANENT,
236                                      (uint32_t *)pflags);
237 }
238
239 uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags)
240 {
241         return tlcl_get_tpm_property(TPM_PT_STARTUP_CLEAR,
242                                      (uint32_t *)pflags);
243 }
244
245 uint32_t TlclGetOwnership(uint8_t *owned)
246 {
247         *owned = 0;
248         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
249         return TPM_SUCCESS;
250 }
251
252 static uint32_t tlcl_lock_nv_write(uint32_t index)
253 {
254         struct tpm2_response *response;
255         struct tpm2_nv_write_lock_cmd nv_wl;
256
257         nv_wl.nvIndex = HR_NV_INDEX + index;
258         response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
259
260         if (!response || response->hdr.tpm_code)
261                 return TPM_E_INTERNAL_INCONSISTENCY;
262
263         return TPM_SUCCESS;
264 }
265
266 static uint32_t tlcl_disable_platform_hierarchy(void)
267 {
268         struct tpm2_response *response;
269         struct tpm2_hierarchy_control_cmd hc;
270
271         hc.enable = TPM_RH_PLATFORM;
272         hc.state = 0;
273
274         response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
275
276         if (!response || response->hdr.tpm_code)
277                 return TPM_E_INTERNAL_INCONSISTENCY;
278
279         tpm_set_ph_disabled(1);
280         return TPM_SUCCESS;
281 }
282
283 /**
284  * The name of the function was kept to maintain the existing TPM API, but
285  * TPM2.0 does not use the global lock to protect the FW rollback counter.
286  * Instead it calls WriteLock for the FW NVRAM index to prevent future
287  * writes to it.
288  *
289  * It first checks if the platform hierarchy is already disabled, and does
290  * nothing, if so. Otherwise, WriteLock for the index obviously fails.
291  */
292 uint32_t TlclSetGlobalLock(void)
293 {
294         if (tpm_is_ph_disabled())
295                 return TPM_SUCCESS;
296         else
297                 return tlcl_lock_nv_write(FIRMWARE_NV_INDEX);
298 }
299
300 /**
301  * Turn off physical presence and locks it off until next reboot.  The TPM
302  * error code is returned.
303  *
304  * The name of the function was kept to maintain the existing TPM API, but
305  * TPM2.0 does not have to use the Physical Presence concept. Instead it just
306  * removes platform authorization - this makes sure that firmware and kernel
307  * rollback counter spaces can not be modified.
308  *
309  * It also explicitly locks the kernel rollback counter space (the FW rollback
310  * counter space was locked before RW firmware started.)
311  */
312 uint32_t TlclLockPhysicalPresence(void)
313 {
314         uint32_t rv;
315
316         if (tpm_is_ph_disabled())
317                 return TPM_SUCCESS;
318
319         rv = tlcl_lock_nv_write(KERNEL_NV_INDEX);
320         if (rv == TPM_SUCCESS)
321                 rv = tlcl_disable_platform_hierarchy();
322
323         return rv;
324 }
325
326 uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
327 {
328         struct tpm2_nv_read_cmd nv_readc;
329         struct tpm2_response *response;
330
331         Memset(&nv_readc, 0, sizeof(nv_readc));
332
333         nv_readc.nvIndex = HR_NV_INDEX + index;
334         nv_readc.size = length;
335
336         response = tpm_process_command(TPM2_NV_Read, &nv_readc);
337
338         /* Need to map tpm error codes into internal values. */
339         if (!response)
340                 return TPM_E_READ_FAILURE;
341
342         switch (response->hdr.tpm_code) {
343         case 0:
344                 break;
345
346         case 0x28b:
347                 return TPM_E_BADINDEX;
348
349         default:
350                 return TPM_E_READ_FAILURE;
351         }
352
353         if (length > response->nvr.buffer.t.size)
354                 return TPM_E_RESPONSE_TOO_LARGE;
355
356         if (length < response->nvr.buffer.t.size)
357                 return TPM_E_READ_EMPTY;
358
359         Memcpy(data, response->nvr.buffer.t.buffer, length);
360
361         return TPM_SUCCESS;
362 }
363
364 uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
365 {
366         struct tpm2_nv_write_cmd nv_writec;
367         struct tpm2_response *response;
368
369         Memset(&nv_writec, 0, sizeof(nv_writec));
370
371         nv_writec.nvIndex = HR_NV_INDEX + index;
372         nv_writec.data.t.size = length;
373         nv_writec.data.t.buffer = data;
374
375         response = tpm_process_command(TPM2_NV_Write, &nv_writec);
376
377         /* Need to map tpm error codes into internal values. */
378         if (!response)
379                 return TPM_E_WRITE_FAILURE;
380
381         return TPM_SUCCESS;
382 }
383
384 uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length)
385 {
386         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
387         return TPM_SUCCESS;
388 }
389
390 uint32_t TlclWriteLock(uint32_t index)
391 {
392         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
393         return TPM_SUCCESS;
394 }
395
396 uint32_t TlclReadLock(uint32_t index)
397 {
398         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
399         return TPM_SUCCESS;
400 }
401
402 uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size)
403 {
404         *size = 0;
405         VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
406         return TPM_E_IOERROR;
407 }