/src/libtpms/src/tpm_tpm2_interface.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* LibTPM TPM 2 call interface functions */ |
4 | | /* Written by Stefan Berger */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* */ |
7 | | /* (c) Copyright IBM Corporation 2015. */ |
8 | | /* */ |
9 | | /* All rights reserved. */ |
10 | | /* */ |
11 | | /* Redistribution and use in source and binary forms, with or without */ |
12 | | /* modification, are permitted provided that the following conditions are */ |
13 | | /* met: */ |
14 | | /* */ |
15 | | /* Redistributions of source code must retain the above copyright notice, */ |
16 | | /* this list of conditions and the following disclaimer. */ |
17 | | /* */ |
18 | | /* Redistributions in binary form must reproduce the above copyright */ |
19 | | /* notice, this list of conditions and the following disclaimer in the */ |
20 | | /* documentation and/or other materials provided with the distribution. */ |
21 | | /* */ |
22 | | /* Neither the names of the IBM Corporation nor the names of its */ |
23 | | /* contributors may be used to endorse or promote products derived from */ |
24 | | /* this software without specific prior written permission. */ |
25 | | /* */ |
26 | | /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ |
27 | | /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ |
28 | | /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ |
29 | | /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ |
30 | | /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ |
31 | | /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ |
32 | | /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ |
33 | | /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ |
34 | | /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ |
35 | | /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ |
36 | | /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
37 | | /********************************************************************************/ |
38 | | |
39 | | #include <config.h> |
40 | | |
41 | | #include <string.h> |
42 | | #include <stdbool.h> |
43 | | |
44 | | #ifndef LIB_EXPORT |
45 | | #define LIB_EXPORT |
46 | | #endif |
47 | | #include "tpm2/Tpm.h" |
48 | | #include "tpm2/Manufacture_fp.h" |
49 | | #include "tpm2/Platform_fp.h" |
50 | | #include "tpm2/ExecCommand_fp.h" |
51 | | #include "tpm2/TpmTcpProtocol.h" |
52 | | #include "tpm2/Simulator_fp.h" |
53 | | #include "tpm2/_TPM_Hash_Data_fp.h" |
54 | | #include "tpm2/_TPM_Init_fp.h" |
55 | | #include "tpm2/StateMarshal.h" |
56 | | #include "tpm2/PlatformACT.h" |
57 | | #include "tpm2/PlatformData.h" |
58 | | #include "tpm2/Volatile.h" |
59 | | #include "tpm2/crypto/openssl/ExpDCache_fp.h" |
60 | | |
61 | | #define TPM_HAVE_TPM2_DECLARATIONS |
62 | | #include "tpm_nvfile.h" // TPM_NVRAM_Loaddata() |
63 | | #include "tpm_error.h" |
64 | | #include "tpm_library_intern.h" |
65 | | #include "tpm_nvfilename.h" |
66 | | |
67 | | extern BOOL g_inFailureMode; |
68 | | static BOOL reportedFailureCommand; |
69 | | static char *g_profile; |
70 | | static TPM_BOOL g_wasManufactured; |
71 | | |
72 | | /* |
73 | | * Check whether the main NVRAM file exists. Return TRUE if it doesn, FALSE otherwise |
74 | | */ |
75 | | static TPM_BOOL _TPM2_CheckNVRAMFileExists(bool *has_nvram_loaddata_callback) |
76 | 14.2k | { |
77 | 14.2k | #ifdef TPM_LIBTPMS_CALLBACKS |
78 | 14.2k | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); |
79 | 14.2k | const char *name = TPM_PERMANENT_ALL_NAME; |
80 | 14.2k | unsigned char *data = NULL; |
81 | 14.2k | uint32_t length = 0; |
82 | 14.2k | uint32_t tpm_number = 0; |
83 | 14.2k | TPM_RESULT ret; |
84 | | |
85 | 14.2k | *has_nvram_loaddata_callback = cbs->tpm_nvram_loaddata != NULL; |
86 | 14.2k | if (cbs->tpm_nvram_loaddata) { |
87 | 14.2k | ret = cbs->tpm_nvram_loaddata(&data, &length, tpm_number, name); |
88 | 14.2k | free(data); |
89 | | /* a file exists once NOT TPM_RETRY is returned */ |
90 | 14.2k | if (ret != TPM_RETRY) |
91 | 7.10k | return TRUE; |
92 | 14.2k | } |
93 | | #else |
94 | | *has_nvram_loaddata_callback = FALSE; |
95 | | #endif /* TPM_LIBTPMS_CALLBACKS */ |
96 | | |
97 | 7.10k | return FALSE; |
98 | 14.2k | } |
99 | | |
100 | | static TPM_RESULT TPM2_MainInit(void) |
101 | 14.2k | { |
102 | 14.2k | TPM_RESULT ret = TPM_SUCCESS; |
103 | 14.2k | bool has_cached_state; |
104 | 14.2k | bool has_nvram_file; |
105 | 14.2k | bool has_nvram_loaddata_callback; |
106 | | |
107 | 14.2k | g_inFailureMode = FALSE; |
108 | 14.2k | reportedFailureCommand = FALSE; |
109 | 14.2k | g_wasManufactured = FALSE; |
110 | | |
111 | 14.2k | #ifdef TPM_LIBTPMS_CALLBACKS |
112 | 14.2k | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); |
113 | | |
114 | 14.2k | if (cbs->tpm_io_init) { |
115 | 14.2k | ret = cbs->tpm_io_init(); |
116 | 14.2k | if (ret != TPM_SUCCESS) |
117 | 0 | return ret; |
118 | 14.2k | } |
119 | | |
120 | 14.2k | if (cbs->tpm_nvram_init) { |
121 | 0 | ret = cbs->tpm_nvram_init(); |
122 | 0 | if (ret != TPM_SUCCESS) |
123 | 0 | return ret; |
124 | 0 | } |
125 | 14.2k | #endif /* TPM_LIBTPMS_CALLBACKS */ |
126 | | |
127 | 14.2k | _rpc__Signal_PowerOff(); |
128 | | |
129 | 14.2k | has_cached_state = HasCachedState(TPMLIB_STATE_PERMANENT); |
130 | 14.2k | has_nvram_file = _TPM2_CheckNVRAMFileExists(&has_nvram_loaddata_callback); |
131 | | |
132 | 14.2k | if (!has_cached_state) { |
133 | 7.10k | if (!has_nvram_file) { |
134 | 7.10k | ret = _plat__NVEnable(NULL, 0); |
135 | 7.10k | if (ret) |
136 | 0 | TPMLIB_LogTPM2Error( |
137 | 7.10k | "%s: _plat__NVEnable(NULL) failed: %d\n", |
138 | 7.10k | __func__, ret); |
139 | 7.10k | if (TPM_Manufacture(TRUE, g_profile) < 0 || g_inFailureMode) { |
140 | 0 | TPMLIB_LogTPM2Error("%s: TPM_Manufacture(TRUE) failed or TPM in " |
141 | 0 | "failure mode\n", __func__); |
142 | 0 | reportedFailureCommand = TRUE; |
143 | 7.10k | } else { |
144 | 7.10k | g_wasManufactured = TRUE; |
145 | 7.10k | } |
146 | 7.10k | } |
147 | 7.10k | } else if (!has_nvram_loaddata_callback) { |
148 | 0 | ret = _plat__NVEnable_NVChipFile(NULL); |
149 | 0 | if (ret) |
150 | 0 | TPMLIB_LogTPM2Error("%s: _plat__NVEnable_File(NULL) failed: %d\n", |
151 | 0 | __func__, ret); |
152 | 0 | } |
153 | | |
154 | 14.2k | _rpc__Signal_PowerOn(FALSE); |
155 | | |
156 | 14.2k | _rpc__Signal_NvOn(); |
157 | | |
158 | 14.2k | if (ret == TPM_SUCCESS) { |
159 | 14.2k | if (g_inFailureMode) |
160 | 0 | ret = TPM_RC_FAILURE; |
161 | 14.2k | } |
162 | | |
163 | 14.2k | if (ret == TPM_SUCCESS && has_cached_state) { |
164 | 7.10k | NvCommit(); |
165 | 7.10k | } |
166 | | |
167 | 14.2k | return ret; |
168 | 14.2k | } |
169 | | |
170 | | static void TPM2_Terminate(void) |
171 | 14.2k | { |
172 | 14.2k | TPM_TearDown(); |
173 | | |
174 | 14.2k | _rpc__Signal_PowerOff(); |
175 | 14.2k | ExpDCacheFree(); |
176 | | |
177 | 14.2k | free(g_profile); |
178 | 14.2k | g_profile = NULL; |
179 | 14.2k | } |
180 | | |
181 | | static TPM_RESULT TPM2_Process(unsigned char **respbuffer, uint32_t *resp_size, |
182 | | uint32_t *respbufsize, |
183 | | unsigned char *command, uint32_t command_size) |
184 | 14.2k | { |
185 | 14.2k | uint8_t locality = 0; |
186 | 14.2k | _IN_BUFFER req; |
187 | 14.2k | _OUT_BUFFER resp; |
188 | 14.2k | unsigned char *tmp; |
189 | | |
190 | 14.2k | #ifdef TPM_LIBTPMS_CALLBACKS |
191 | 14.2k | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); |
192 | | |
193 | 14.2k | if (cbs->tpm_io_getlocality) { |
194 | 14.2k | TPM_MODIFIER_INDICATOR locty; |
195 | | |
196 | | /* called function is trusted and must return valid value */ |
197 | 14.2k | cbs->tpm_io_getlocality(&locty, 0); |
198 | | |
199 | 14.2k | locality = locty; |
200 | 14.2k | } |
201 | 14.2k | #endif /* TPM_LIBTPMS_CALLBACKS */ |
202 | | |
203 | 14.2k | req.BufferSize = command_size; |
204 | 14.2k | req.Buffer = command; |
205 | | |
206 | | /* have the TPM 2 write directly into the response buffer */ |
207 | 14.2k | if (*respbufsize < TPM_BUFFER_MAX || !*respbuffer) { |
208 | 7.10k | tmp = realloc(*respbuffer, TPM_BUFFER_MAX); |
209 | 7.10k | if (!tmp) { |
210 | 0 | TPMLIB_LogTPM2Error("Could not allocated %u bytes.\n", |
211 | 0 | TPM_BUFFER_MAX); |
212 | 0 | return TPM_SIZE; |
213 | 0 | } |
214 | 7.10k | *respbuffer = tmp; |
215 | 7.10k | *respbufsize = TPM_BUFFER_MAX; |
216 | 7.10k | } |
217 | 14.2k | resp.BufferSize = *respbufsize; |
218 | 14.2k | resp.Buffer = *respbuffer; |
219 | | |
220 | | /* |
221 | | * signals for cancellation have to come after we start processing |
222 | | */ |
223 | 14.2k | _rpc__Signal_CancelOff(); |
224 | | |
225 | 14.2k | _rpc__Send_Command(locality, req, &resp); |
226 | | |
227 | | /* it may come back with a different buffer, especially in failure mode */ |
228 | 14.2k | if (resp.Buffer != *respbuffer) { |
229 | 0 | if (resp.BufferSize > *respbufsize) |
230 | 0 | resp.BufferSize = *respbufsize; |
231 | 0 | memcpy(*respbuffer, resp.Buffer, resp.BufferSize); |
232 | 0 | } |
233 | | |
234 | 14.2k | *resp_size = resp.BufferSize; |
235 | | |
236 | 14.2k | if (g_inFailureMode && !reportedFailureCommand) { |
237 | 0 | reportedFailureCommand = TRUE; |
238 | 0 | TPMLIB_LogTPM2Error("%s: Entered failure mode through command:\n", |
239 | 0 | __func__); |
240 | 0 | TPMLIB_LogArray(~0, command, command_size); |
241 | 0 | } |
242 | | |
243 | 14.2k | return TPM_SUCCESS; |
244 | 14.2k | } |
245 | | |
246 | | TPM_RESULT TPM2_PersistentAllStore(unsigned char **buf, |
247 | | uint32_t *buflen) |
248 | 28.6k | { |
249 | 28.6k | BYTE *buffer; |
250 | 28.6k | INT32 size; |
251 | 28.6k | unsigned char *nbuffer; |
252 | 28.6k | TPM_RESULT ret = TPM_SUCCESS; |
253 | 28.6k | UINT32 written = 0; |
254 | | |
255 | 28.6k | *buflen = NV_MEMORY_SIZE + 32 * 1024; |
256 | 28.6k | *buf = NULL; |
257 | | |
258 | | /* the marshal functions do not indicate insufficient |
259 | | buffer; to make sure we didn't run out of buffer, |
260 | | we check that enough room for the biggest type of |
261 | | chunk (64k) is available and try again. */ |
262 | 28.6k | do { |
263 | 28.6k | *buflen += 66 * 1024; |
264 | | |
265 | 28.6k | nbuffer = realloc(*buf, *buflen); |
266 | 28.6k | if (nbuffer == NULL) { |
267 | 0 | free(*buf); |
268 | 0 | *buf = NULL; |
269 | 0 | ret = TPM_SIZE; |
270 | 0 | written = 0; |
271 | 0 | break; |
272 | 0 | } |
273 | | |
274 | 28.6k | *buf = buffer = nbuffer; |
275 | 28.6k | size = *buflen; |
276 | 28.6k | written = PERSISTENT_ALL_Marshal(&buffer, &size); |
277 | 28.6k | } while (size < 66 * 1024); |
278 | | |
279 | 0 | *buflen = written; |
280 | | |
281 | 28.6k | return ret; |
282 | 28.6k | } |
283 | | |
284 | | static TPM_RESULT TPM2_VolatileAllStore(unsigned char **buffer, |
285 | | uint32_t *buflen) |
286 | 7.10k | { |
287 | 7.10k | TPM_RESULT rc = 0; |
288 | 7.10k | INT32 size = NV_MEMORY_SIZE; |
289 | 7.10k | UINT16 written; |
290 | 7.10k | unsigned char *statebuffer = NULL; |
291 | | |
292 | 7.10k | *buffer = NULL; |
293 | 7.10k | statebuffer = malloc(size); |
294 | 7.10k | if (!statebuffer) { |
295 | 0 | TPMLIB_LogTPM2Error("Could not allocate %u bytes.\n", size); |
296 | 0 | return TPM_SIZE; |
297 | 0 | } |
298 | | |
299 | | /* statebuffer will change */ |
300 | 7.10k | *buffer = statebuffer; |
301 | | |
302 | 7.10k | written = VolatileSave(&statebuffer, &size); |
303 | 7.10k | if (written >= size) { |
304 | 0 | free(*buffer); |
305 | 0 | *buffer = NULL; |
306 | 0 | rc = TPM_FAIL; |
307 | 7.10k | } else { |
308 | 7.10k | *buflen = written; |
309 | 7.10k | } |
310 | | |
311 | 7.10k | return rc; |
312 | 7.10k | } |
313 | | |
314 | | static TPM_RESULT TPM2_CancelCommand(void) |
315 | 0 | { |
316 | 0 | _rpc__Signal_CancelOn(); |
317 | |
|
318 | 0 | return TPM_SUCCESS; |
319 | 0 | } |
320 | | |
321 | | static TPM_RESULT TPM2_GetTPMProperty(enum TPMLIB_TPMProperty prop, |
322 | | int *result) |
323 | 0 | { |
324 | 0 | switch (prop) { |
325 | 0 | case TPMPROP_TPM_RSA_KEY_LENGTH_MAX: |
326 | 0 | *result = MAX_RSA_KEY_BITS; |
327 | 0 | break; |
328 | | |
329 | 0 | case TPMPROP_TPM_KEY_HANDLES: |
330 | 0 | *result = MAX_HANDLE_NUM; |
331 | 0 | break; |
332 | | |
333 | | /* not supported for TPM 2 */ |
334 | 0 | case TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES: |
335 | 0 | case TPMPROP_TPM_MIN_AUTH_SESSIONS: |
336 | 0 | case TPMPROP_TPM_MIN_TRANS_SESSIONS: |
337 | 0 | case TPMPROP_TPM_MIN_DAA_SESSIONS: |
338 | 0 | case TPMPROP_TPM_MIN_SESSION_LIST: |
339 | 0 | case TPMPROP_TPM_MIN_COUNTERS: |
340 | 0 | case TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN: |
341 | 0 | case TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN: |
342 | 0 | case TPMPROP_TPM_SPACE_SAFETY_MARGIN: |
343 | 0 | case TPMPROP_TPM_MAX_NV_SPACE: |
344 | 0 | case TPMPROP_TPM_MAX_SAVESTATE_SPACE: |
345 | 0 | case TPMPROP_TPM_MAX_VOLATILESTATE_SPACE: |
346 | |
|
347 | 0 | default: |
348 | 0 | return TPM_FAIL; |
349 | 0 | } |
350 | | |
351 | 0 | return TPM_SUCCESS; |
352 | 0 | } |
353 | | |
354 | | /* |
355 | | * TPM2_GetInfo: |
356 | | * |
357 | | * @flags: logical or of flags that query for information |
358 | | * |
359 | | * Return a JSON document with contents queried for by the user's passed flags |
360 | | */ |
361 | | static char *TPM2_GetInfo(enum TPMLIB_InfoFlags flags) |
362 | 0 | { |
363 | 0 | const char *tpmspec = |
364 | 0 | "\"TPMSpecification\":{" |
365 | 0 | "\"family\":\"2.0\"," |
366 | 0 | "\"level\":" STRINGIFY(TPM_SPEC_LEVEL_NUM) "," |
367 | 0 | "\"revision\":" STRINGIFY(TPM_SPEC_VERSION) |
368 | 0 | "}"; |
369 | 0 | const char *tpmattrs_temp = |
370 | 0 | "\"TPMAttributes\":{" |
371 | 0 | "\"manufacturer\":\"id:00001014\"," |
372 | 0 | "\"version\":\"id:%08X\"," |
373 | 0 | "\"model\":\"swtpm\"" |
374 | 0 | "}"; |
375 | 0 | const char *tpmfeatures_temp = |
376 | 0 | "\"TPMFeatures\":{" |
377 | 0 | "\"RSAKeySizes\":[%s]," |
378 | 0 | "\"CamelliaKeySizes\":[%s]" |
379 | | #if ALG_SM4 |
380 | | ", \"SM4KeySizes\":[128]" |
381 | | #endif |
382 | 0 | "}"; |
383 | 0 | const char *runtimeAlgorithms_temp = |
384 | 0 | "\"RuntimeAlgorithms\":{" |
385 | 0 | "\"Implemented\":%s," |
386 | 0 | "\"CanBeDisabled\":%s," |
387 | 0 | "\"Enabled\":%s," |
388 | 0 | "\"Disabled\":%s" |
389 | 0 | "}"; |
390 | 0 | const char *runtimeCommands_temp = |
391 | 0 | "\"RuntimeCommands\":{" |
392 | 0 | "\"Implemented\":%s," |
393 | 0 | "\"CanBeDisabled\":%s," |
394 | 0 | "\"Enabled\":%s," |
395 | 0 | "\"Disabled\":%s" |
396 | 0 | "}"; |
397 | 0 | const char *runtimeAttributes_temp = |
398 | 0 | "\"RuntimeAttributes\":{" |
399 | 0 | "\"Implemented\":%s," |
400 | 0 | "\"CanBeDisabled\":%s," |
401 | 0 | "\"Enabled\":%s," |
402 | 0 | "\"Disabled\":%s" |
403 | 0 | "}"; |
404 | 0 | const char *tpmProfile_temp = "\"ActiveProfile\":%s"; |
405 | 0 | const char *availableProfiles_temp = |
406 | 0 | "\"AvailableProfiles\":[" |
407 | 0 | "%s%s%s" |
408 | 0 | "]"; |
409 | 0 | char *fmt = NULL, *buffer; |
410 | 0 | bool printed = false; |
411 | 0 | char *tpmattrs = NULL; |
412 | 0 | char *tpmfeatures = NULL; |
413 | 0 | char rsakeys[32]; |
414 | 0 | char camelliakeys[16]; |
415 | 0 | char *runtimeAlgos[RUNTIME_ALGO_NUM] = { NULL, }; |
416 | 0 | char *runtimeCmds[RUNTIME_CMD_NUM] = { NULL, }; |
417 | 0 | char *runtimeAttrs[RUNTIME_ATTR_NUM] = { NULL, }; |
418 | 0 | enum RuntimeAlgorithmType rat; |
419 | 0 | enum RuntimeCommandType rct; |
420 | 0 | enum RuntimeAttributeType rabt; |
421 | 0 | char *runtimeAlgorithms = NULL; |
422 | 0 | char *runtimeCommands = NULL; |
423 | 0 | char *runtimeAttributes = NULL; |
424 | 0 | char *profile = NULL; |
425 | 0 | const char *profileJSON; |
426 | 0 | char *availableProfiles = NULL; |
427 | 0 | char *tmp = NULL; |
428 | 0 | size_t n; |
429 | |
|
430 | 0 | if (!(buffer = strdup("{%s%s%s}"))) |
431 | 0 | return NULL; |
432 | | |
433 | 0 | if ((flags & TPMLIB_INFO_TPMSPECIFICATION)) { |
434 | 0 | fmt = buffer; |
435 | 0 | buffer = NULL; |
436 | 0 | if (TPMLIB_asprintf(&buffer, fmt, "", tpmspec, "%s%s%s") < 0) |
437 | 0 | goto error; |
438 | 0 | free(fmt); |
439 | 0 | printed = true; |
440 | 0 | } |
441 | | |
442 | 0 | if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) { |
443 | 0 | uint32_t firmware_v1 = _plat__GetTpmFirmwareVersionHigh(); |
444 | |
|
445 | 0 | fmt = buffer; |
446 | 0 | buffer = NULL; |
447 | 0 | if (TPMLIB_asprintf(&tpmattrs, tpmattrs_temp, firmware_v1) < 0) |
448 | 0 | goto error; |
449 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
450 | 0 | tpmattrs, "%s%s%s") < 0) |
451 | 0 | goto error; |
452 | 0 | free(fmt); |
453 | 0 | printed = true; |
454 | 0 | } |
455 | | |
456 | 0 | if ((flags & TPMLIB_INFO_TPMFEATURES)) { |
457 | 0 | fmt = buffer; |
458 | 0 | buffer = NULL; |
459 | 0 | n = snprintf(rsakeys, sizeof(rsakeys), "%s2048%s%s", |
460 | 0 | RSA_1024 ? "1024," : "", |
461 | 0 | RSA_3072 ? ",3072" : "", |
462 | 0 | RSA_4096 ? ",4096" : ""); |
463 | 0 | if (n >= sizeof(rsakeys)) |
464 | 0 | goto error; |
465 | 0 | n = snprintf(camelliakeys, sizeof(camelliakeys), "%s%s%s", |
466 | 0 | CAMELLIA_128 ? "128" : "", |
467 | 0 | CAMELLIA_192 ? ",192" : "", |
468 | 0 | CAMELLIA_256 ? ",256" : ""); |
469 | 0 | if (n >= sizeof(camelliakeys)) |
470 | 0 | goto error; |
471 | 0 | if (TPMLIB_asprintf(&tpmfeatures, tpmfeatures_temp, |
472 | 0 | rsakeys, camelliakeys) < 0) |
473 | 0 | goto error; |
474 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
475 | 0 | tpmfeatures, "%s%s%s") < 0) |
476 | 0 | goto error; |
477 | 0 | free(fmt); |
478 | 0 | printed = true; |
479 | 0 | } |
480 | | |
481 | 0 | if ((flags & TPMLIB_INFO_RUNTIME_ALGORITHMS)) { |
482 | 0 | fmt = buffer; |
483 | 0 | buffer = NULL; |
484 | 0 | for (rat = RUNTIME_ALGO_IMPLEMENTED; rat < RUNTIME_ALGO_NUM; rat++) { |
485 | 0 | runtimeAlgos[rat] = RuntimeAlgorithmPrint(&g_RuntimeProfile.RuntimeAlgorithm, rat); |
486 | 0 | if (!runtimeAlgos[rat]) |
487 | 0 | goto error; |
488 | 0 | } |
489 | 0 | if (TPMLIB_asprintf(&runtimeAlgorithms, runtimeAlgorithms_temp, |
490 | 0 | runtimeAlgos[RUNTIME_ALGO_IMPLEMENTED], |
491 | 0 | runtimeAlgos[RUNTIME_ALGO_CAN_BE_DISABLED], |
492 | 0 | runtimeAlgos[RUNTIME_ALGO_ENABLED], |
493 | 0 | runtimeAlgos[RUNTIME_ALGO_DISABLED]) < 0) |
494 | 0 | goto error; |
495 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
496 | 0 | runtimeAlgorithms, "%s%s%s") < 0) |
497 | 0 | goto error; |
498 | 0 | free(fmt); |
499 | 0 | printed = true; |
500 | 0 | } |
501 | | |
502 | 0 | if ((flags & TPMLIB_INFO_RUNTIME_COMMANDS)) { |
503 | 0 | fmt = buffer; |
504 | 0 | buffer = NULL; |
505 | 0 | for (rct = RUNTIME_CMD_IMPLEMENTED; rct < RUNTIME_CMD_NUM; rct++) { |
506 | 0 | runtimeCmds[rct] = RuntimeCommandsPrint(&g_RuntimeProfile.RuntimeCommands, rct); |
507 | 0 | if (!runtimeCmds[rct]) |
508 | 0 | goto error; |
509 | 0 | } |
510 | 0 | if (TPMLIB_asprintf(&runtimeCommands, runtimeCommands_temp, |
511 | 0 | runtimeCmds[RUNTIME_CMD_IMPLEMENTED], |
512 | 0 | runtimeCmds[RUNTIME_CMD_CAN_BE_DISABLED], |
513 | 0 | runtimeCmds[RUNTIME_CMD_ENABLED], |
514 | 0 | runtimeCmds[RUNTIME_CMD_DISABLED]) < 0) |
515 | 0 | goto error; |
516 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
517 | 0 | runtimeCommands, "%s%s%s") < 0) |
518 | 0 | goto error; |
519 | 0 | free(fmt); |
520 | 0 | printed = true; |
521 | 0 | } |
522 | | |
523 | 0 | if ((flags & TPMLIB_INFO_RUNTIME_ATTRIBUTES)) { |
524 | 0 | fmt = buffer; |
525 | 0 | buffer = NULL; |
526 | 0 | for (rabt = RUNTIME_ATTR_IMPLEMENTED; rabt < RUNTIME_ATTR_NUM; rabt++) { |
527 | 0 | runtimeAttrs[rabt] = RuntimeAttributesGet(&g_RuntimeProfile.RuntimeAttributes, rabt); |
528 | 0 | if (!runtimeAttrs[rabt]) |
529 | 0 | goto error; |
530 | 0 | } |
531 | 0 | if (TPMLIB_asprintf(&runtimeAttributes, runtimeAttributes_temp, |
532 | 0 | runtimeAttrs[RUNTIME_ATTR_IMPLEMENTED], |
533 | 0 | runtimeAttrs[RUNTIME_ATTR_CAN_BE_DISABLED], |
534 | 0 | runtimeAttrs[RUNTIME_ATTR_ENABLED], |
535 | 0 | runtimeAttrs[RUNTIME_ATTR_DISABLED]) < 0) |
536 | 0 | goto error; |
537 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
538 | 0 | runtimeAttributes, "%s%s%s") < 0) |
539 | 0 | goto error; |
540 | 0 | free(fmt); |
541 | 0 | printed = true; |
542 | 0 | } |
543 | | |
544 | 0 | if ((flags & TPMLIB_INFO_ACTIVE_PROFILE) && |
545 | 0 | (profileJSON = RuntimeProfileGetJSON(&g_RuntimeProfile))) { |
546 | 0 | fmt = buffer; |
547 | 0 | buffer = NULL; |
548 | 0 | if (TPMLIB_asprintf(&profile, tpmProfile_temp, profileJSON) < 0) |
549 | 0 | goto error; |
550 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
551 | 0 | profile, "%s%s%s") < 0) |
552 | 0 | goto error; |
553 | 0 | free(fmt); |
554 | 0 | printed = true; |
555 | 0 | } |
556 | | |
557 | 0 | if ((flags & TPMLIB_INFO_AVAILABLE_PROFILES)) { |
558 | 0 | size_t idx = 0; |
559 | 0 | char *json = NULL; |
560 | |
|
561 | 0 | fmt = buffer; // keep here in case of 'goto error' |
562 | 0 | buffer = NULL; |
563 | |
|
564 | 0 | tmp = NULL; |
565 | |
|
566 | 0 | while (RuntimeProfileGetByIndex(idx, &json) == TPM_RC_SUCCESS) { |
567 | 0 | if (TPMLIB_asprintf(&availableProfiles, |
568 | 0 | idx > 0 ? tmp : availableProfiles_temp, |
569 | 0 | idx > 0 ? "," : "", |
570 | 0 | json, |
571 | 0 | "%s%s%s") < 0) { |
572 | 0 | free(json); |
573 | 0 | goto error; |
574 | 0 | } |
575 | | |
576 | 0 | free(json); |
577 | 0 | free(tmp); |
578 | 0 | tmp = availableProfiles; |
579 | 0 | idx++; |
580 | 0 | } |
581 | 0 | availableProfiles = NULL; |
582 | 0 | if (TPMLIB_asprintf(&availableProfiles, tmp, "", "", "") < 0) |
583 | 0 | goto error; |
584 | | |
585 | 0 | if (TPMLIB_asprintf(&buffer, fmt, printed ? "," : "", |
586 | 0 | availableProfiles, "%s%s%s") < 0) |
587 | 0 | goto error; |
588 | 0 | free(fmt); |
589 | 0 | printed = true; |
590 | 0 | } |
591 | | |
592 | | /* nothing else to add */ |
593 | 0 | fmt = buffer; |
594 | 0 | buffer = NULL; |
595 | 0 | if (TPMLIB_asprintf(&buffer, fmt, "", "", "") < 0) |
596 | 0 | goto error; |
597 | | |
598 | 0 | exit: |
599 | 0 | free(fmt); |
600 | 0 | free(tpmattrs); |
601 | 0 | free(tpmfeatures); |
602 | 0 | free(profile); |
603 | 0 | for (rat = RUNTIME_ALGO_IMPLEMENTED; rat < RUNTIME_ALGO_NUM; rat++) |
604 | 0 | free(runtimeAlgos[rat]); |
605 | 0 | for (rct = RUNTIME_CMD_IMPLEMENTED; rct < RUNTIME_CMD_NUM; rct++) |
606 | 0 | free(runtimeCmds[rct]); |
607 | 0 | for (rabt = RUNTIME_ATTR_IMPLEMENTED; rabt < RUNTIME_ATTR_NUM; rabt++) |
608 | 0 | free(runtimeAttrs[rabt]); |
609 | 0 | free(runtimeAlgorithms); |
610 | 0 | free(runtimeCommands); |
611 | 0 | free(runtimeAttributes); |
612 | 0 | free(availableProfiles); |
613 | 0 | free(tmp); |
614 | |
|
615 | 0 | return buffer; |
616 | | |
617 | 0 | error: |
618 | 0 | free(buffer); |
619 | 0 | buffer = NULL; |
620 | 0 | goto exit; |
621 | 0 | } |
622 | | |
623 | | static uint32_t tpm2_buffersize = TPM_BUFFER_MAX; |
624 | | |
625 | | static uint32_t TPM2_SetBufferSize(uint32_t wanted_size, |
626 | | uint32_t *min_size, |
627 | | uint32_t *max_size) |
628 | 14.0k | { |
629 | 14.0k | const uint32_t min = MAX_CONTEXT_SIZE + 128; |
630 | 14.0k | const uint32_t max = TPM_BUFFER_MAX; |
631 | | |
632 | 14.0k | if (min_size) |
633 | 0 | *min_size = min; |
634 | 14.0k | if (max_size) |
635 | 0 | *max_size = max; |
636 | | |
637 | 14.0k | if (wanted_size == 0) |
638 | 14.0k | return tpm2_buffersize; |
639 | | |
640 | 0 | if (wanted_size > max) |
641 | 0 | wanted_size = max; |
642 | 0 | else if (wanted_size < min) |
643 | 0 | wanted_size = min; |
644 | |
|
645 | 0 | tpm2_buffersize = wanted_size; |
646 | |
|
647 | 0 | return tpm2_buffersize; |
648 | 14.0k | } |
649 | | |
650 | | uint32_t TPM2_GetBufferSize(void) |
651 | 14.0k | { |
652 | 14.0k | return TPM2_SetBufferSize(0, NULL, NULL); |
653 | 14.0k | } |
654 | | |
655 | | /* |
656 | | * Validate the state blobs to check whether they can be |
657 | | * successfully used by a TPM_INIT. |
658 | | */ |
659 | | static TPM_RESULT TPM2_ValidateState(enum TPMLIB_StateType st, |
660 | | unsigned int flags LIBTPMS_ATTR_UNUSED) |
661 | 0 | { |
662 | 0 | TPM_RESULT ret = TPM_SUCCESS; |
663 | 0 | TPM_RC rc = TPM_RC_SUCCESS; |
664 | 0 | unsigned char *data = NULL; |
665 | 0 | uint32_t length; |
666 | 0 | unsigned char bak_NV[NV_MEMORY_SIZE]; |
667 | 0 | INT32 size; |
668 | 0 | BYTE *buffer; |
669 | 0 | BOOL restored; |
670 | | |
671 | | /* make backup of current NvChip memory */ |
672 | 0 | memcpy(bak_NV, s_NV, sizeof(bak_NV)); |
673 | |
|
674 | 0 | #ifdef TPM_LIBTPMS_CALLBACKS |
675 | 0 | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); |
676 | |
|
677 | 0 | if (cbs->tpm_nvram_init) { |
678 | 0 | ret = cbs->tpm_nvram_init(); |
679 | 0 | if (ret != TPM_SUCCESS) |
680 | 0 | return ret; |
681 | 0 | } |
682 | | |
683 | 0 | #endif |
684 | | |
685 | 0 | if ((rc == TPM_RC_SUCCESS) && |
686 | 0 | (st & (TPMLIB_STATE_PERMANENT | TPMLIB_STATE_SAVE_STATE))) { |
687 | |
|
688 | 0 | #ifdef TPM_LIBTPMS_CALLBACKS |
689 | 0 | if (cbs->tpm_nvram_loaddata) { |
690 | 0 | ret = cbs->tpm_nvram_loaddata(&data, &length, 0, |
691 | 0 | TPM_PERMANENT_ALL_NAME); |
692 | 0 | if (ret != TPM_SUCCESS) |
693 | 0 | return ret; |
694 | 0 | } |
695 | 0 | #endif |
696 | | |
697 | 0 | if (!data) |
698 | 0 | return TPM_FAIL; |
699 | | |
700 | 0 | buffer = data; |
701 | 0 | size = length; |
702 | 0 | rc = PERSISTENT_ALL_Unmarshal(&buffer, &size); |
703 | 0 | free(data); |
704 | 0 | } |
705 | | |
706 | 0 | if ((rc == TPM_RC_SUCCESS) && |
707 | 0 | (st & TPMLIB_STATE_VOLATILE)) { |
708 | 0 | rc = VolatileLoad(&restored); |
709 | 0 | } |
710 | |
|
711 | 0 | ret = rc; |
712 | |
|
713 | 0 | return ret; |
714 | 0 | } |
715 | | |
716 | | /* |
717 | | * Get the state blob of the given type. If the TPM is not running, we |
718 | | * get the cached state blobs, if available, otherwise we try to read |
719 | | * it from files. In case the TPM is running, we get it from the running |
720 | | * TPM. |
721 | | */ |
722 | | static TPM_RESULT TPM2_GetState(enum TPMLIB_StateType st, |
723 | | unsigned char **buffer, uint32_t *buflen) |
724 | 21.3k | { |
725 | 21.3k | TPM_RESULT ret = TPM_FAIL; |
726 | | |
727 | 21.3k | if (!_rpc__Signal_IsPowerOn()) { |
728 | 7.10k | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); |
729 | 7.10k | bool is_empty_buffer; |
730 | | |
731 | 7.10k | ret = CopyCachedState(st, buffer, buflen, &is_empty_buffer); |
732 | 7.10k | if (ret != TPM_SUCCESS || *buffer != NULL || is_empty_buffer) |
733 | 7.10k | return ret; |
734 | | |
735 | 0 | if (cbs->tpm_nvram_init) { |
736 | 0 | ret = cbs->tpm_nvram_init(); |
737 | 0 | if (ret != TPM_SUCCESS) |
738 | 0 | return ret; |
739 | | |
740 | | /* we can call the TPM 1.2 function here ... */ |
741 | 0 | ret = TPM_NVRAM_LoadData(buffer, buflen, 0, |
742 | 0 | TPMLIB_StateTypeToName(st)); |
743 | 0 | } else { |
744 | 0 | ret = TPM_FAIL; |
745 | 0 | } |
746 | 0 | return ret; |
747 | 0 | } |
748 | | |
749 | | /* from the running TPM */ |
750 | 14.2k | switch (st) { |
751 | 7.10k | case TPMLIB_STATE_PERMANENT: |
752 | 7.10k | ret = TPM2_PersistentAllStore(buffer, buflen); |
753 | 7.10k | break; |
754 | 7.10k | case TPMLIB_STATE_VOLATILE: |
755 | 7.10k | ret = TPM2_VolatileAllStore(buffer, buflen); |
756 | 7.10k | break; |
757 | 0 | case TPMLIB_STATE_SAVE_STATE: |
758 | 0 | *buffer = NULL; |
759 | 0 | *buflen = 0; |
760 | 0 | ret = 0; |
761 | 0 | break; |
762 | 14.2k | } |
763 | | |
764 | 14.2k | return ret; |
765 | 14.2k | } |
766 | | |
767 | | /* |
768 | | * Set the state the TPM 2 will use upon next TPM_MainInit(). The TPM 2 |
769 | | * must not have been started, yet, or it must have been terminated for this |
770 | | * function to set the state. |
771 | | * |
772 | | * @st: The TPMLIB_StateType describing the type of blob in the buffer |
773 | | * @buffer: pointer to the buffer containing the state blob; NULL pointer clears |
774 | | * previous state |
775 | | * @buflen: length of the buffer |
776 | | */ |
777 | | static TPM_RESULT TPM2_SetState(enum TPMLIB_StateType st, |
778 | | const unsigned char *buffer, uint32_t buflen) |
779 | 14.2k | { |
780 | 14.2k | TPM_RESULT ret = TPM_SUCCESS; |
781 | 14.2k | TPM_RC rc = TPM_RC_SUCCESS; |
782 | 14.2k | BYTE *stream = NULL, *orig_stream = NULL; |
783 | 14.2k | INT32 stream_size = buflen; |
784 | 14.2k | unsigned char *permanent = NULL, *ptr; |
785 | 14.2k | INT32 permanent_len; |
786 | | |
787 | 14.2k | if (buffer == NULL) { |
788 | 0 | SetCachedState(st, NULL, 0); |
789 | 0 | return TPM_SUCCESS; |
790 | 0 | } |
791 | | |
792 | 14.2k | if (_rpc__Signal_IsPowerOn()) |
793 | 0 | return TPM_INVALID_POSTINIT; |
794 | | |
795 | 14.2k | if (ret == TPM_SUCCESS) { |
796 | 14.2k | stream = malloc(buflen); |
797 | 14.2k | if (!stream) |
798 | 0 | ret = TPM_SIZE; |
799 | 14.2k | } |
800 | | |
801 | 14.2k | if (ret == TPM_SUCCESS) { |
802 | 14.2k | orig_stream = stream; |
803 | 14.2k | memcpy(stream, buffer, buflen); |
804 | 14.2k | } |
805 | | |
806 | | /* test whether we can accept the blob */ |
807 | 14.2k | if (ret == TPM_SUCCESS) { |
808 | 14.2k | switch (st) { |
809 | 7.10k | case TPMLIB_STATE_PERMANENT: |
810 | 7.10k | rc = PERSISTENT_ALL_Unmarshal(&stream, &stream_size); |
811 | 7.10k | break; |
812 | 7.10k | case TPMLIB_STATE_VOLATILE: |
813 | | /* load permanent state first */ |
814 | 7.10k | rc = TPM2_GetState(TPMLIB_STATE_PERMANENT, |
815 | 7.10k | &permanent, (uint32_t *)&permanent_len); |
816 | 7.10k | if (rc == TPM_RC_SUCCESS) { |
817 | 7.10k | ptr = permanent; |
818 | 7.10k | rc = PERSISTENT_ALL_Unmarshal(&ptr, &permanent_len); |
819 | 7.10k | if (rc == TPM_RC_SUCCESS) |
820 | 7.10k | rc = VolatileState_Load(&stream, &stream_size); |
821 | 7.10k | } |
822 | 7.10k | break; |
823 | 0 | case TPMLIB_STATE_SAVE_STATE: |
824 | 0 | if (buffer != NULL) |
825 | 0 | rc = TPM_BAD_TYPE; |
826 | 0 | break; |
827 | 14.2k | } |
828 | 14.2k | ret = rc; |
829 | 14.2k | if (ret != TPM_SUCCESS) |
830 | 0 | ClearAllCachedState(); |
831 | 14.2k | } |
832 | | |
833 | | /* cache the blob for the TPM_MainInit() to pick it up */ |
834 | 14.2k | if (ret == TPM_SUCCESS) { |
835 | 14.2k | SetCachedState(st, orig_stream, buflen); |
836 | 14.2k | } else { |
837 | 0 | free(orig_stream); |
838 | 0 | } |
839 | 14.2k | free(permanent); |
840 | | |
841 | 14.2k | return ret; |
842 | 14.2k | } |
843 | | |
844 | | static TPM_RESULT TPM2_SetProfile(const char *profile) |
845 | 0 | { |
846 | 0 | char *copyProfile = NULL; |
847 | 0 | TPM_RC rc; |
848 | |
|
849 | 0 | if (_rpc__Signal_IsPowerOn()) |
850 | 0 | return TPM_INVALID_POSTINIT; |
851 | | |
852 | 0 | if (profile) { |
853 | | /* test the profile */ |
854 | 0 | rc = RuntimeProfileTest(&g_RuntimeProfile, profile, true); |
855 | 0 | if (rc != TPM_RC_SUCCESS) |
856 | 0 | return TPM_FAIL; |
857 | | |
858 | 0 | copyProfile = strdup(profile); |
859 | 0 | if (!copyProfile) |
860 | 0 | return TPM_SIZE; |
861 | 0 | } |
862 | | |
863 | 0 | free(g_profile); |
864 | 0 | g_profile = copyProfile; |
865 | |
|
866 | 0 | return TPM_SUCCESS; |
867 | 0 | } |
868 | | |
869 | | static TPM_BOOL TPM2_WasManufactured(void) |
870 | 0 | { |
871 | 0 | return g_wasManufactured; |
872 | 0 | } |
873 | | |
874 | | const struct tpm_interface TPM2Interface = { |
875 | | .MainInit = TPM2_MainInit, |
876 | | .Terminate = TPM2_Terminate, |
877 | | .Process = TPM2_Process, |
878 | | .VolatileAllStore = TPM2_VolatileAllStore, |
879 | | .CancelCommand = TPM2_CancelCommand, |
880 | | .GetTPMProperty = TPM2_GetTPMProperty, |
881 | | .GetInfo = TPM2_GetInfo, |
882 | | .TpmEstablishedGet = TPM2_IO_TpmEstablished_Get, |
883 | | .TpmEstablishedReset = TPM2_IO_TpmEstablished_Reset, |
884 | | .HashStart = TPM2_IO_Hash_Start, |
885 | | .HashData = TPM2_IO_Hash_Data, |
886 | | .HashEnd = TPM2_IO_Hash_End, |
887 | | .SetBufferSize = TPM2_SetBufferSize, |
888 | | .ValidateState = TPM2_ValidateState, |
889 | | .SetState = TPM2_SetState, |
890 | | .GetState = TPM2_GetState, |
891 | | .SetProfile = TPM2_SetProfile, |
892 | | .WasManufactured = TPM2_WasManufactured, |
893 | | }; |