]> git.proxmox.com Git - libtpms.git/blob - src/tpm_library.c
Implement TPMLIB_SetBufferSize() for setting the size of the I/O buffer
[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
49 #ifdef USE_FREEBL_CRYPTO_LIBRARY
50 # include <plbase64.h>
51 #endif
52
53 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
54 # include <openssl/bio.h>
55 # include <openssl/evp.h>
56 #endif
57
58 #include "tpm12/tpm_debug.h"
59 #include "tpm_error.h"
60 #include "tpm_library.h"
61 #include "tpm_library_intern.h"
62 #include "tpm_memory.h"
63
64 static const struct tags_and_indices {
65 const char *starttag;
66 const char *endtag;
67 } tags_and_indices[] = {
68 [TPMLIB_BLOB_TYPE_INITSTATE] =
69 {
70 .starttag = TPMLIB_INITSTATE_START_TAG,
71 .endtag = TPMLIB_INITSTATE_END_TAG,
72 },
73 };
74
75 static const struct tpm_interface *const tpm_iface[] = {
76 &TPM12Interface,
77 };
78
79 static int debug_fd = -1;
80 static unsigned debug_level = 0;
81 static char *debug_prefix = NULL;
82
83 uint32_t TPMLIB_GetVersion(void)
84 {
85 return TPM_LIBRARY_VERSION;
86 }
87
88 TPM_RESULT TPMLIB_MainInit(void)
89 {
90 return tpm_iface[0]->MainInit();
91 }
92
93 void TPMLIB_Terminate(void)
94 {
95 tpm_iface[0]->Terminate();
96 }
97
98 /*
99 * Send a command to the TPM. The command buffer must hold a well formatted
100 * TPM command and the command_size indicate the size of the command.
101 * The respbuffer parameter may be provided by the user and grow if
102 * the respbufsize size indicator is determined to be too small for the
103 * response. In that case a new buffer will be allocated and the size of that
104 * buffer returned in the respbufsize parameter. resp_size describes the
105 * size of the actual response within the respbuffer.
106 */
107 TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size,
108 uint32_t *respbufsize,
109 unsigned char *command, uint32_t command_size)
110 {
111 return tpm_iface[0]->Process(respbuffer, resp_size, respbufsize,
112 command, command_size);
113 }
114
115 /*
116 * Get the volatile state from the TPM. This function will return the
117 * buffer and the length of the buffer to the caller in case everything
118 * went alright.
119 */
120 TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer,
121 uint32_t *buflen)
122 {
123 return tpm_iface[0]->VolatileAllStore(buffer, buflen);
124 }
125
126 /*
127 * Get a property of the TPM. The functions currently only
128 * return compile-time #defines but this may change in future
129 * versions where we may return parameters with which the TPM
130 * was created (rather than compiled).
131 */
132 TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop,
133 int *result)
134 {
135 switch (prop) {
136 case TPMPROP_TPM_BUFFER_MAX:
137 *result = TPM_BUFFER_MAX;
138 break;
139
140 default:
141 return tpm_iface[0]->GetTPMProperty(prop, result);
142 }
143
144 return TPM_SUCCESS;
145 }
146
147 TPM_RESULT TPM_IO_Hash_Start(void)
148 {
149 return tpm_iface[0]->HashStart();
150 }
151
152 TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, uint32_t data_length)
153 {
154 return tpm_iface[0]->HashData(data, data_length);
155 }
156
157 TPM_RESULT TPM_IO_Hash_End(void)
158 {
159 return tpm_iface[0]->HashEnd();
160 }
161
162 TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished)
163 {
164 return tpm_iface[0]->TpmEstablishedGet(tpmEstablished);
165 }
166
167 uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size)
168 {
169 return tpm_iface[0]->SetBufferSize(wanted_size);
170 }
171
172 static struct libtpms_callbacks libtpms_cbs;
173
174 struct libtpms_callbacks *TPMLIB_GetCallbacks(void)
175 {
176 return &libtpms_cbs;
177 }
178
179 TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *callbacks)
180 {
181 int max_size = sizeof(struct libtpms_callbacks);
182
183 /* restrict the size of the structure to what we know currently
184 future versions may know more callbacks */
185 if (callbacks->sizeOfStruct < max_size)
186 max_size = callbacks->sizeOfStruct;
187
188 /* clear the internal callback structure and copy the user provided
189 callbacks into it */
190 memset(&libtpms_cbs, 0x0, sizeof(libtpms_cbs));
191 memcpy(&libtpms_cbs, callbacks, max_size);
192
193 return TPM_SUCCESS;
194 }
195
196 static int is_base64ltr(char c)
197 {
198 return ((c >= 'A' && c <= 'Z') ||
199 (c >= 'a' && c <= 'z') ||
200 (c >= '0' && c <= '9') ||
201 c == '+' ||
202 c == '/' ||
203 c == '=');
204 }
205
206 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
207 static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
208 unsigned int outputlen)
209 {
210 BIO *b64, *bmem;
211 unsigned char *res = NULL;
212 int n;
213 TPM_RESULT rc;
214
215 b64 = BIO_new(BIO_f_base64());
216 if (!b64) {
217 return NULL;
218 }
219
220 bmem = BIO_new_mem_buf(input, strlen(input));
221 if (!bmem) {
222 BIO_free(b64);
223 goto cleanup;
224 }
225 bmem = BIO_push(b64, bmem);
226 BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
227
228 rc = TPM_Malloc(&res, outputlen);
229 if (rc != TPM_SUCCESS) {
230 goto cleanup;
231 }
232
233 n = BIO_read(bmem, res, outputlen);
234 if (n <= 0) {
235 TPM_Free(res);
236 res = NULL;
237 goto cleanup;
238 }
239
240 cleanup:
241 BIO_free_all(bmem);
242
243 return res;
244 }
245 #endif
246
247 /*
248 * Base64 decode the string starting at 'start' and the last
249 * valid character may be a 'end'. The length of the decoded string
250 * is returned in *length.
251 */
252 static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end,
253 size_t *length)
254 {
255 unsigned char *ret = NULL;
256 char *input = NULL, *d;
257 const char *s;
258 char c;
259 unsigned int numbase64chars = 0;
260
261 if (end < start)
262 return NULL;
263
264 while (end > start && !is_base64ltr(*end))
265 end--;
266
267 end++;
268
269 if (TPM_Malloc((unsigned char **)&input, end - start + 1) != TPM_SUCCESS)
270 return NULL;
271
272 /* copy from source string skipping '\n' and '\r' and using
273 '=' to calculate the exact length */
274 d = input;
275 s = start;
276
277 while (s < end) {
278 c = *s;
279 if (is_base64ltr(c)) {
280 *d = c;
281 d++;
282 if (c != '=') {
283 numbase64chars++;
284 }
285 } else if (c == 0) {
286 break;
287 }
288 s++;
289 }
290 *d = 0;
291
292 *length = (numbase64chars / 4) * 3;
293 switch (numbase64chars % 4) {
294 case 2:
295 case 3:
296 *length += (numbase64chars % 4) - 1;
297 break;
298 case 0:
299 break;
300 case 1:
301 fprintf(stderr,"malformed base64\n");
302 goto err_exit;
303 break;
304 }
305
306 #ifdef USE_FREEBL_CRYPTO_LIBRARY
307 ret = (unsigned char *)PL_Base64Decode(input, 0, NULL);
308 #endif
309
310 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
311 ret = TPMLIB_OpenSSL_Base64Decode(input, *length);
312 #endif
313
314 err_exit:
315 free(input);
316
317 return ret;
318 }
319
320 static unsigned char *TPMLIB_GetPlaintext(const char *stream,
321 const char *starttag,
322 const char *endtag,
323 size_t *length)
324 {
325 char *start, *end;
326 unsigned char *plaintext = NULL;
327
328 start = strstr(stream, starttag);
329 if (start) {
330 start += strlen(starttag);
331 while (isspace((int)*start))
332 start++;
333 end = strstr(start, endtag);
334 if (end) {
335 plaintext = TPMLIB_Base64Decode(start, --end, length);
336 }
337 }
338 return plaintext;
339 }
340
341 TPM_RESULT TPMLIB_DecodeBlob(const char *buffer, enum TPMLIB_BlobType type,
342 unsigned char **result, size_t *result_len)
343 {
344 TPM_RESULT res = TPM_SUCCESS;
345
346 *result = TPMLIB_GetPlaintext(buffer,
347 tags_and_indices[type].starttag,
348 tags_and_indices[type].endtag,
349 result_len);
350
351 if (*result == NULL) {
352 res = TPM_FAIL;
353 }
354
355 return res;
356 }
357
358 void TPMLIB_SetDebugFD(int fd)
359 {
360 debug_fd = fd;
361 }
362
363 void TPMLIB_SetDebugLevel(unsigned level)
364 {
365 debug_level = level;
366 }
367
368 TPM_RESULT TPMLIB_SetDebugPrefix(const char *prefix)
369 {
370 free(debug_prefix);
371
372 if (prefix) {
373 debug_prefix = strdup(prefix);
374 if (!debug_prefix)
375 return TPM_FAIL;
376 } else {
377 debug_prefix = NULL;
378 }
379
380 return TPM_SUCCESS;
381 }
382
383 int TPMLIB_LogPrintf(const char *format, ...)
384 {
385 unsigned level = debug_level, i;
386 va_list args;
387 char buffer[256];
388 int n;
389
390 if (!debug_fd || !debug_level)
391 return -1;
392
393 va_start(args, format);
394 n = vsnprintf(buffer, sizeof(buffer), format, args);
395 va_end(args);
396
397 if (n < 0 || n >= (int)sizeof(buffer))
398 return -1;
399
400 level--;
401
402 i = 0;
403 while (1) {
404 if (buffer[i] == 0)
405 return -1;
406 if (buffer[i] != ' ')
407 break;
408 if (i == level)
409 return -1;
410 i++;
411 }
412
413 if (debug_prefix)
414 dprintf(debug_fd, "%s", debug_prefix);
415 dprintf(debug_fd, "%s", buffer);
416
417 return i;
418 }
419
420 /*
421 * TPMLIB_LogPrintfA: Printf to the logfd without indentation check
422 */
423 void TPMLIB_LogPrintfA(unsigned int indent, const char *format, ...)
424 {
425 va_list args;
426 char spaces[20];
427
428 if (!debug_fd || !debug_level)
429 return;
430
431 if (indent) {
432 if (indent > sizeof(spaces) - 1)
433 indent = sizeof(spaces) - 1;
434 memset(spaces, ' ', indent);
435 spaces[indent] = 0;
436 dprintf(debug_fd, "%s", spaces);
437 }
438
439 va_start(args, format);
440 vdprintf(debug_fd, format, args);
441 va_end(args);
442 }