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