]> git.proxmox.com Git - libtpms.git/blob - src/tpm_library.c
Implement TPMLIB_GetInfo() to for example get TPM spec. info
[libtpms.git] / src / tpm_library.c
1 /********************************************************************************/
2 /* */
3 /* LibTPM interface functions */
4 /* Written by Stefan Berger */
5 /* IBM Thomas J. Watson Research Center */
6 /* $Id: tpm_library.c 4615 2011-08-30 15:35:24Z stefanb $ */
7 /* */
8 /* (c) Copyright IBM Corporation 2010. */
9 /* */
10 /* All rights reserved. */
11 /* */
12 /* Redistribution and use in source and binary forms, with or without */
13 /* modification, are permitted provided that the following conditions are */
14 /* met: */
15 /* */
16 /* Redistributions of source code must retain the above copyright notice, */
17 /* this list of conditions and the following disclaimer. */
18 /* */
19 /* Redistributions in binary form must reproduce the above copyright */
20 /* notice, this list of conditions and the following disclaimer in the */
21 /* documentation and/or other materials provided with the distribution. */
22 /* */
23 /* Neither the names of the IBM Corporation nor the names of its */
24 /* contributors may be used to endorse or promote products derived from */
25 /* this software without specific prior written permission. */
26 /* */
27 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
28 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
29 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
30 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
31 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
32 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
33 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
34 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
35 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
36 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
37 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38 /********************************************************************************/
39
40 #include <config.h>
41
42 #include <assert.h>
43 #include <string.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <ctype.h>
48 #include <unistd.h>
49
50 #ifdef USE_FREEBL_CRYPTO_LIBRARY
51 # include <plbase64.h>
52 #endif
53
54 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
55 # include <openssl/bio.h>
56 # include <openssl/evp.h>
57 #endif
58
59 #include "tpm12/tpm_debug.h"
60 #include "tpm_error.h"
61 #include "tpm_library.h"
62 #include "tpm_library_intern.h"
63 #include "tpm_memory.h"
64
65 static const struct tags_and_indices {
66 const char *starttag;
67 const char *endtag;
68 } tags_and_indices[] = {
69 [TPMLIB_BLOB_TYPE_INITSTATE] =
70 {
71 .starttag = TPMLIB_INITSTATE_START_TAG,
72 .endtag = TPMLIB_INITSTATE_END_TAG,
73 },
74 };
75
76 static const struct tpm_interface *const tpm_iface[] = {
77 &TPM12Interface,
78 };
79
80 static int debug_fd = -1;
81 static unsigned debug_level = 0;
82 static char *debug_prefix = NULL;
83
84 uint32_t TPMLIB_GetVersion(void)
85 {
86 return TPM_LIBRARY_VERSION;
87 }
88
89 TPM_RESULT TPMLIB_MainInit(void)
90 {
91 return tpm_iface[0]->MainInit();
92 }
93
94 void TPMLIB_Terminate(void)
95 {
96 tpm_iface[0]->Terminate();
97 }
98
99 /*
100 * Send a command to the TPM. The command buffer must hold a well formatted
101 * TPM command and the command_size indicate the size of the command.
102 * The respbuffer parameter may be provided by the user and grow if
103 * the respbufsize size indicator is determined to be too small for the
104 * response. In that case a new buffer will be allocated and the size of that
105 * buffer returned in the respbufsize parameter. resp_size describes the
106 * size of the actual response within the respbuffer.
107 */
108 TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size,
109 uint32_t *respbufsize,
110 unsigned char *command, uint32_t command_size)
111 {
112 return tpm_iface[0]->Process(respbuffer, resp_size, respbufsize,
113 command, command_size);
114 }
115
116 /*
117 * Get the volatile state from the TPM. This function will return the
118 * buffer and the length of the buffer to the caller in case everything
119 * went alright.
120 */
121 TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer,
122 uint32_t *buflen)
123 {
124 return tpm_iface[0]->VolatileAllStore(buffer, buflen);
125 }
126
127 /*
128 * Get a property of the TPM. The functions currently only
129 * return compile-time #defines but this may change in future
130 * versions where we may return parameters with which the TPM
131 * was created (rather than compiled).
132 */
133 TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop,
134 int *result)
135 {
136 switch (prop) {
137 case TPMPROP_TPM_BUFFER_MAX:
138 *result = TPM_BUFFER_MAX;
139 break;
140
141 default:
142 return tpm_iface[0]->GetTPMProperty(prop, result);
143 }
144
145 return TPM_SUCCESS;
146 }
147
148 char *TPMLIB_GetInfo(enum TPMLIB_InfoFlags flags)
149 {
150 return tpm_iface[0]->GetInfo(flags);
151 }
152
153 TPM_RESULT TPM_IO_Hash_Start(void)
154 {
155 return tpm_iface[0]->HashStart();
156 }
157
158 TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, uint32_t data_length)
159 {
160 return tpm_iface[0]->HashData(data, data_length);
161 }
162
163 TPM_RESULT TPM_IO_Hash_End(void)
164 {
165 return tpm_iface[0]->HashEnd();
166 }
167
168 TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished)
169 {
170 return tpm_iface[0]->TpmEstablishedGet(tpmEstablished);
171 }
172
173 uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size,
174 uint32_t *min_size,
175 uint32_t *max_size)
176 {
177 return tpm_iface[0]->SetBufferSize(wanted_size, min_size, max_size);
178 }
179
180 TPM_RESULT TPMLIB_ValidateState(enum TPMLIB_StateType st,
181 unsigned int flags)
182 {
183 return tpm_iface[0]->ValidateState(st, flags);
184 }
185
186 static struct libtpms_callbacks libtpms_cbs;
187
188 struct libtpms_callbacks *TPMLIB_GetCallbacks(void)
189 {
190 return &libtpms_cbs;
191 }
192
193 TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *callbacks)
194 {
195 int max_size = sizeof(struct libtpms_callbacks);
196
197 /* restrict the size of the structure to what we know currently
198 future versions may know more callbacks */
199 if (callbacks->sizeOfStruct < max_size)
200 max_size = callbacks->sizeOfStruct;
201
202 /* clear the internal callback structure and copy the user provided
203 callbacks into it */
204 memset(&libtpms_cbs, 0x0, sizeof(libtpms_cbs));
205 memcpy(&libtpms_cbs, callbacks, max_size);
206
207 return TPM_SUCCESS;
208 }
209
210 static int is_base64ltr(char c)
211 {
212 return ((c >= 'A' && c <= 'Z') ||
213 (c >= 'a' && c <= 'z') ||
214 (c >= '0' && c <= '9') ||
215 c == '+' ||
216 c == '/' ||
217 c == '=');
218 }
219
220 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
221 static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
222 unsigned int outputlen)
223 {
224 BIO *b64, *bmem;
225 unsigned char *res = NULL;
226 int n;
227 TPM_RESULT rc;
228
229 b64 = BIO_new(BIO_f_base64());
230 if (!b64) {
231 return NULL;
232 }
233
234 bmem = BIO_new_mem_buf(input, strlen(input));
235 if (!bmem) {
236 BIO_free(b64);
237 goto cleanup;
238 }
239 bmem = BIO_push(b64, bmem);
240 BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
241
242 rc = TPM_Malloc(&res, outputlen);
243 if (rc != TPM_SUCCESS) {
244 goto cleanup;
245 }
246
247 n = BIO_read(bmem, res, outputlen);
248 if (n <= 0) {
249 TPM_Free(res);
250 res = NULL;
251 goto cleanup;
252 }
253
254 cleanup:
255 BIO_free_all(bmem);
256
257 return res;
258 }
259 #endif
260
261 /*
262 * Base64 decode the string starting at 'start' and the last
263 * valid character may be a 'end'. The length of the decoded string
264 * is returned in *length.
265 */
266 static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end,
267 size_t *length)
268 {
269 unsigned char *ret = NULL;
270 char *input = NULL, *d;
271 const char *s;
272 char c;
273 unsigned int numbase64chars = 0;
274
275 if (end < start)
276 return NULL;
277
278 while (end > start && !is_base64ltr(*end))
279 end--;
280
281 end++;
282
283 if (TPM_Malloc((unsigned char **)&input, end - start + 1) != TPM_SUCCESS)
284 return NULL;
285
286 /* copy from source string skipping '\n' and '\r' and using
287 '=' to calculate the exact length */
288 d = input;
289 s = start;
290
291 while (s < end) {
292 c = *s;
293 if (is_base64ltr(c)) {
294 *d = c;
295 d++;
296 if (c != '=') {
297 numbase64chars++;
298 }
299 } else if (c == 0) {
300 break;
301 }
302 s++;
303 }
304 *d = 0;
305
306 *length = (numbase64chars / 4) * 3;
307 switch (numbase64chars % 4) {
308 case 2:
309 case 3:
310 *length += (numbase64chars % 4) - 1;
311 break;
312 case 0:
313 break;
314 case 1:
315 fprintf(stderr,"malformed base64\n");
316 goto err_exit;
317 break;
318 }
319
320 #ifdef USE_FREEBL_CRYPTO_LIBRARY
321 ret = (unsigned char *)PL_Base64Decode(input, 0, NULL);
322 #endif
323
324 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
325 ret = TPMLIB_OpenSSL_Base64Decode(input, *length);
326 #endif
327
328 err_exit:
329 free(input);
330
331 return ret;
332 }
333
334 static unsigned char *TPMLIB_GetPlaintext(const char *stream,
335 const char *starttag,
336 const char *endtag,
337 size_t *length)
338 {
339 char *start, *end;
340 unsigned char *plaintext = NULL;
341
342 start = strstr(stream, starttag);
343 if (start) {
344 start += strlen(starttag);
345 while (isspace((int)*start))
346 start++;
347 end = strstr(start, endtag);
348 if (end) {
349 plaintext = TPMLIB_Base64Decode(start, --end, length);
350 }
351 }
352 return plaintext;
353 }
354
355 TPM_RESULT TPMLIB_DecodeBlob(const char *buffer, enum TPMLIB_BlobType type,
356 unsigned char **result, size_t *result_len)
357 {
358 TPM_RESULT res = TPM_SUCCESS;
359
360 *result = TPMLIB_GetPlaintext(buffer,
361 tags_and_indices[type].starttag,
362 tags_and_indices[type].endtag,
363 result_len);
364
365 if (*result == NULL) {
366 res = TPM_FAIL;
367 }
368
369 return res;
370 }
371
372 void TPMLIB_SetDebugFD(int fd)
373 {
374 debug_fd = fd;
375 }
376
377 void TPMLIB_SetDebugLevel(unsigned level)
378 {
379 debug_level = level;
380 }
381
382 TPM_RESULT TPMLIB_SetDebugPrefix(const char *prefix)
383 {
384 free(debug_prefix);
385
386 if (prefix) {
387 debug_prefix = strdup(prefix);
388 if (!debug_prefix)
389 return TPM_FAIL;
390 } else {
391 debug_prefix = NULL;
392 }
393
394 return TPM_SUCCESS;
395 }
396
397 int TPMLIB_LogPrintf(const char *format, ...)
398 {
399 unsigned level = debug_level, i;
400 va_list args;
401 char buffer[256];
402 int n;
403
404 if (!debug_fd || !debug_level)
405 return -1;
406
407 va_start(args, format);
408 n = vsnprintf(buffer, sizeof(buffer), format, args);
409 va_end(args);
410
411 if (n < 0 || n >= (int)sizeof(buffer))
412 return -1;
413
414 level--;
415
416 i = 0;
417 while (1) {
418 if (buffer[i] == 0)
419 return -1;
420 if (buffer[i] != ' ')
421 break;
422 if (i == level)
423 return -1;
424 i++;
425 }
426
427 if (debug_prefix)
428 dprintf(debug_fd, "%s", debug_prefix);
429 dprintf(debug_fd, "%s", buffer);
430
431 return i;
432 }
433
434 /*
435 * TPMLIB_LogPrintfA: Printf to the logfd without indentation check
436 *
437 * @indent: how many spaces to indent; indent of ~0 forces logging
438 * with indent 0 even if not debug_level is set
439 * @format: format to use for formatting the following parameters
440 * @...: varargs
441 */
442 void TPMLIB_LogPrintfA(unsigned int indent, const char *format, ...)
443 {
444 va_list args;
445 char spaces[20];
446 int fd;
447
448 if (indent != (unsigned int)~0) {
449 if (!debug_fd || !debug_level)
450 return;
451 fd = debug_fd;
452 } else {
453 indent = 0;
454 fd = (debug_fd >= 0) ? debug_fd : STDERR_FILENO;
455 }
456
457 if (indent) {
458 if (indent > sizeof(spaces) - 1)
459 indent = sizeof(spaces) - 1;
460 memset(spaces, ' ', indent);
461 spaces[indent] = 0;
462 dprintf(fd, "%s", spaces);
463 }
464
465 va_start(args, format);
466 vdprintf(fd, format, args);
467 va_end(args);
468 }