1 /*
2  * The Initial Developer of the Original Code is International
3  * Business Machines Corporation. Portions created by IBM
4  * Corporation are Copyright (C) 2005, 2006 International Business
5  * Machines Corporation. All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the Common Public License as published by
9  * IBM Corporation; either version 1 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * Common Public License for more details.
16  *
17  * You should have received a copy of the Common Public License
18  * along with this program; if not, a copy can be viewed at
19  * http://www.opensource.org/licenses/cpl1.0.php.
20  */
21 
22 #include "tpm_tspi.h"
23 #include "tpm_seal.h"
24 #include "tpm_unseal.h"
25 #include <errno.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <openssl/evp.h>
32 #include <trousers/tss.h>
33 #include <trousers/trousers.h>
34 
35 enum tspi_errors {
36           ETSPICTXCREAT = 0,
37           ETSPICTXCNCT,
38           ETSPICTXCO,
39           ETSPICTXLKBU,
40           ETSPICTXLKBB,
41           ETSPISETAD,
42           ETSPIGETPO,
43           ETSPIPOLSS,
44           ETSPIDATU,
45           ETSPIPOLATO,
46 };
47 
48 TSS_HCONTEXT hContext = 0;
49 #define TSPI_FUNCTION_NAME_MAX 30
50 char tspi_error_strings[][TSPI_FUNCTION_NAME_MAX]= {
51                                         "Tspi_Context_Create",
52                                         "Tspi_Context_Connect",
53                                         "Tspi_Context_CreateObject",
54                                         "Tspi_Context_LoadKeyByUUID",
55                                         "Tspi_Context_LoadKeyByBlob",
56                                         "Tspi_SetAttribData",
57                                         "Tspi_GetPolicyObject",
58                                         "Tspi_Policy_SetSecret",
59                                         "Tspi_Data_Unseal",
60                                         "Tspi_Policy_AssignToObject",
61 };
62 
63 #define TSSKEY_DEFAULT_SIZE 768
64 #define EVPKEY_DEFAULT_SIZE 512
65 
66 int tpm_errno;
67 
tpmUnsealFile(char * fname,unsigned char ** tss_data,int * tss_size,BOOL srkWellKnown)68 int tpmUnsealFile( char* fname, unsigned char** tss_data, int* tss_size,
69                        BOOL srkWellKnown ) {
70 
71           int rc, rcLen=0, tssLen=0, evpLen=0;
72           BYTE* rcPtr;
73           char data[EVP_CIPHER_block_size(EVP_aes_256_cbc()) * 16];
74           BYTE *tssKeyData = NULL;
75           int tssKeyDataSize = 0;
76           BYTE *evpKeyData = NULL;
77           int evpKeyDataSize = 0;
78           struct stat stats;
79           TSS_HENCDATA hEncdata;
80           TSS_HKEY hSrk, hKey;
81           TSS_HPOLICY hPolicy;
82           UINT32 symKeyLen;
83           BYTE *symKey;
84           BYTE wellKnown[TCPA_SHA1_160_HASH_LEN] = TSS_WELL_KNOWN_SECRET;
85           char *srkSecret = NULL;
86           int srkSecretLen;
87           unsigned char* res_data = NULL;
88           int res_size = 0;
89 
90           BIO *bdata = NULL, *b64 = NULL, *bmem = NULL;
91           int bioRc;
92 
93           if ( tss_data == NULL || tss_size == NULL ) {
94                     rc = TPMSEAL_STD_ERROR;
95                     tpm_errno = EINVAL;
96                     goto out;
97           }
98 
99           *tss_data = NULL;
100           *tss_size = 0;
101 
102           /* Test for file existence */
103           if ((rc = stat(fname, &stats))) {
104                     tpm_errno = errno;
105                     goto out;
106           }
107 
108           /* Create an input file BIO */
109           if((bdata = BIO_new_file(fname, "r")) == NULL ) {
110                     tpm_errno = errno;
111                     rc = TPMSEAL_STD_ERROR;
112                     goto out;
113           }
114 
115           /* Test file header for TSS */
116           BIO_gets(bdata, data, sizeof(data));
117           if (strncmp(data, TPMSEAL_HDR_STRING,
118                               strlen(TPMSEAL_HDR_STRING)) != 0) {
119                     rc = TPMSEAL_FILE_ERROR;
120                     tpm_errno = ENOTSSHDR;
121                     goto out;
122           }
123 
124           /* Looking for TSS Key Header */
125           BIO_gets(bdata, data, sizeof(data));
126           if (strncmp(data, TPMSEAL_TSS_STRING,
127                               strlen(TPMSEAL_TSS_STRING)) != 0) {
128                     rc = TPMSEAL_FILE_ERROR;
129                     tpm_errno = EWRONGTSSTAG;
130                     goto out;
131           }
132 
133           /* Create a memory BIO to hold the base64 TSS key */
134           if ((bmem = BIO_new(BIO_s_mem())) == NULL) {
135                     tpm_errno = EAGAIN;
136                     rc = TPMSEAL_STD_ERROR;
137                     goto out;
138           }
139           BIO_set_mem_eof_return(bmem, 0);
140 
141           /* Read the base64 TSS key into the memory BIO */
142           while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
143                     /* Look for EVP Key Header (end of key) */
144                     if (strncmp(data, TPMSEAL_EVP_STRING,
145                                         strlen(TPMSEAL_EVP_STRING)) == 0)
146                               break;
147 
148                     if (BIO_write(bmem, data, rcLen) <= 0) {
149                               tpm_errno = EIO;
150                               rc = TPMSEAL_STD_ERROR;
151                               goto out;
152                     }
153           }
154           if (strncmp(data, TPMSEAL_EVP_STRING,
155                               strlen(TPMSEAL_EVP_STRING)) != 0 ) {
156                     tpm_errno = EWRONGEVPTAG;
157                     rc = TPMSEAL_FILE_ERROR;
158                     goto out;
159           }
160 
161           /* Create a base64 BIO to decode the TSS key */
162           if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
163                     tpm_errno = EAGAIN;
164                     rc = TPMSEAL_STD_ERROR;
165                     goto out;
166           }
167 
168           /* Decode the TSS key */
169           bmem = BIO_push( b64, bmem );
170           while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
171                     if ((tssLen + rcLen) > tssKeyDataSize) {
172                               tssKeyDataSize += TSSKEY_DEFAULT_SIZE;
173                               rcPtr = realloc( tssKeyData, tssKeyDataSize);
174                               if ( rcPtr == NULL ) {
175                                         tpm_errno = ENOMEM;
176                                         rc = TPMSEAL_STD_ERROR;
177                                         goto out;
178                               }
179                               tssKeyData = rcPtr;
180                     }
181                     memcpy(tssKeyData + tssLen, data, rcLen);
182                     tssLen += rcLen;
183           }
184           bmem = BIO_pop(b64);
185           BIO_free(b64);
186           b64 = NULL;
187           bioRc = BIO_reset(bmem);
188           if (bioRc != 1) {
189                     tpm_errno = EIO;
190                     rc = TPMSEAL_STD_ERROR;
191                     goto out;
192           }
193 
194           /* Check for EVP Key Type Header */
195           BIO_gets(bdata, data, sizeof(data));
196           if (strncmp(data, TPMSEAL_KEYTYPE_SYM,
197                               strlen(TPMSEAL_KEYTYPE_SYM)) != 0 ) {
198                     rc = TPMSEAL_FILE_ERROR;
199                     tpm_errno = EWRONGKEYTYPE;
200                     goto out;
201           }
202 
203           /* Make sure it's a supported cipher
204              (currently only AES 256 CBC) */
205           if (strncmp(data + strlen(TPMSEAL_KEYTYPE_SYM),
206                               TPMSEAL_CIPHER_AES256CBC,
207                               strlen(TPMSEAL_CIPHER_AES256CBC)) != 0) {
208                     rc = TPMSEAL_FILE_ERROR;
209                     tpm_errno = EWRONGKEYTYPE;
210                     goto out;
211           }
212 
213           /* Read the base64 Symmetric key into the memory BIO */
214           while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
215                     /* Look for Encrypted Data Header (end of key) */
216                     if (strncmp(data, TPMSEAL_ENC_STRING,
217                                         strlen(TPMSEAL_ENC_STRING)) == 0)
218                               break;
219 
220                     if (BIO_write(bmem, data, rcLen) <= 0) {
221                               tpm_errno = EIO;
222                               rc = TPMSEAL_STD_ERROR;
223                               goto out;
224                     }
225           }
226           if (strncmp(data, TPMSEAL_ENC_STRING,
227                               strlen(TPMSEAL_ENC_STRING)) != 0 ) {
228                     tpm_errno = EWRONGDATTAG;
229                     rc = TPMSEAL_FILE_ERROR;
230                     goto out;
231           }
232 
233           /* Create a base64 BIO to decode the Symmetric key */
234           if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
235                     tpm_errno = EAGAIN;
236                     rc = TPMSEAL_STD_ERROR;
237                     goto out;
238           }
239 
240           /* Decode the Symmetric key */
241           bmem = BIO_push( b64, bmem );
242           while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
243                     if ((evpLen + rcLen) > evpKeyDataSize) {
244                               evpKeyDataSize += EVPKEY_DEFAULT_SIZE;
245                               rcPtr = realloc( evpKeyData, evpKeyDataSize);
246                               if ( rcPtr == NULL ) {
247                                         tpm_errno = ENOMEM;
248                                         rc = TPMSEAL_STD_ERROR;
249                                         goto out;
250                               }
251                               evpKeyData = rcPtr;
252                     }
253                     memcpy(evpKeyData + evpLen, data, rcLen);
254                     evpLen += rcLen;
255           }
256           bmem = BIO_pop(b64);
257           BIO_free(b64);
258           b64 = NULL;
259           bioRc = BIO_reset(bmem);
260           if (bioRc != 1) {
261                     tpm_errno = EIO;
262                     rc = TPMSEAL_STD_ERROR;
263                     goto out;
264           }
265 
266           /* Read the base64 encrypted data into the memory BIO */
267           while ((rcLen = BIO_gets(bdata, data, sizeof(data))) > 0) {
268                     /* Look for TSS Footer (end of data) */
269                     if (strncmp(data, TPMSEAL_FTR_STRING,
270                                         strlen(TPMSEAL_FTR_STRING)) == 0)
271                               break;
272 
273                     if (BIO_write(bmem, data, rcLen) <= 0) {
274                               tpm_errno = EIO;
275                               rc = TPMSEAL_STD_ERROR;
276                               goto out;
277                     }
278           }
279           if (strncmp(data, TPMSEAL_FTR_STRING,
280                               strlen(TPMSEAL_FTR_STRING)) != 0 ) {
281                     tpm_errno = ENOTSSFTR;
282                     rc = TPMSEAL_FILE_ERROR;
283                     goto out;
284           }
285 
286           /* Unseal */
287           if ((rc=Tspi_Context_Create(&hContext)) != TSS_SUCCESS) {
288                     tpm_errno = ETSPICTXCREAT;
289                     goto out;
290           }
291 
292           if (!srkWellKnown) {
293                     /* Prompt for SRK password */
294                     srkSecret = GETPASSWD(_("Enter SRK password: "), &srkSecretLen, FALSE);
295                     if (!srkSecret)
296                               goto out;
297           }
298           if ((rc=Tspi_Context_Connect(hContext, NULL)) != TSS_SUCCESS) {
299                     tpm_errno = ETSPICTXCNCT;
300                     goto tss_out;
301           }
302 
303           if ((rc=Tspi_Context_CreateObject(hContext,
304                                                   TSS_OBJECT_TYPE_ENCDATA,
305                                                   TSS_ENCDATA_SEAL,
306                                                   &hEncdata)) != TSS_SUCCESS) {
307                     tpm_errno = ETSPICTXCO;
308                     goto tss_out;
309           }
310 
311           if ((rc=Tspi_SetAttribData(hEncdata,
312                                         TSS_TSPATTRIB_ENCDATA_BLOB,
313                                         TSS_TSPATTRIB_ENCDATABLOB_BLOB,
314                                         evpLen, evpKeyData)) != TSS_SUCCESS) {
315                     tpm_errno = ETSPISETAD;
316                     goto tss_out;
317           }
318 
319           if ((rc=Tspi_Context_CreateObject(hContext,
320                                                   TSS_OBJECT_TYPE_POLICY,
321                                                   TSS_POLICY_USAGE,
322                                                   &hPolicy)) != TSS_SUCCESS) {
323                     tpm_errno = ETSPICTXCO;
324                     goto tss_out;
325           }
326 
327           if ((rc=Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_PLAIN,
328                                                   strlen(TPMSEAL_SECRET),
329                                                   (BYTE *)TPMSEAL_SECRET)) != TSS_SUCCESS) {
330                     tpm_errno = ETSPIPOLSS;
331                     goto tss_out;
332           }
333 
334           if ((rc=Tspi_Policy_AssignToObject(hPolicy, hEncdata)) != TSS_SUCCESS) {
335                     tpm_errno = ETSPIPOLATO;
336                     goto tss_out;
337           }
338 
339           if ((rc=Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
340                                                   SRK_UUID, &hSrk)) != TSS_SUCCESS) {
341                     tpm_errno = ETSPICTXLKBU;
342                     goto tss_out;
343           }
344 
345           /* Don't create a new policy for the SRK's secret, just use the context's
346            * default policy */
347           if ((rc=Tspi_GetPolicyObject(hSrk, TSS_POLICY_USAGE,
348                                                   &hPolicy)) != TSS_SUCCESS){
349                     tpm_errno = ETSPIGETPO;
350                     goto tss_out;
351           }
352 
353           if (srkWellKnown)
354                     rc = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
355                                                    sizeof(wellKnown),
356                                                    (BYTE *) wellKnown);
357           else
358                     rc = Tspi_Policy_SetSecret(hPolicy,TSS_SECRET_MODE_PLAIN,
359                                                      srkSecretLen,
360                                                      (BYTE *) srkSecret);
361 
362           if (rc != TSS_SUCCESS) {
363                     tpm_errno = ETSPIPOLSS;
364                     goto tss_out;
365           }
366 
367           /* Failure point if trying to unseal data on a differnt TPM */
368           if ((rc=Tspi_Context_LoadKeyByBlob(hContext, hSrk, tssLen,
369                                                   tssKeyData, &hKey)) != TSS_SUCCESS) {
370                     tpm_errno = ETSPICTXLKBB;
371                     goto tss_out;
372           }
373 
374           if ((rc=Tspi_Context_CreateObject(hContext,
375                                                   TSS_OBJECT_TYPE_POLICY,
376                                                   TSS_POLICY_USAGE,
377                                                   &hPolicy)) != TSS_SUCCESS) {
378                     tpm_errno = ETSPICTXCO;
379                     goto tss_out;
380           }
381 
382           if ((rc=Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_PLAIN,
383                                                   strlen(TPMSEAL_SECRET),
384                                                   (BYTE *)TPMSEAL_SECRET)) != TSS_SUCCESS) {
385                     tpm_errno = ETSPIPOLSS;
386                     goto tss_out;
387           }
388 
389           if ((rc=Tspi_Policy_AssignToObject(hPolicy, hKey)) != TSS_SUCCESS) {
390                     tpm_errno = ETSPIPOLATO;
391                     goto tss_out;
392           }
393 
394           if ((rc=Tspi_Data_Unseal(hEncdata, hKey, &symKeyLen,
395                                                   &symKey)) != TSS_SUCCESS) {
396                     tpm_errno = ETSPIDATU;
397                     goto tss_out;
398           }
399 
400           /* Malloc a block of storage to hold the decrypted data
401              Using the size of the mem BIO is more than enough
402              (plus an extra cipher block size) */
403           res_data = malloc(BIO_pending(bmem) + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
404           if ( res_data == NULL ) {
405                     rc = TPMSEAL_STD_ERROR;
406                     tpm_errno = ENOMEM;
407                     goto tss_out;
408           }
409 
410           /* Decode and decrypt the encrypted data */
411           EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
412           EVP_DecryptInit(ctx, EVP_aes_256_cbc(), symKey, (unsigned char *)TPMSEAL_IV);
413 
414           /* Create a base64 BIO to decode the encrypted data */
415           if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
416                     tpm_errno = EAGAIN;
417                     rc = TPMSEAL_STD_ERROR;
418                     goto tss_out;
419           }
420 
421           bmem = BIO_push( b64, bmem );
422           while ((rcLen = BIO_read(bmem, data, sizeof(data))) > 0) {
423                     EVP_DecryptUpdate(ctx, res_data+res_size,
424                                                   &rcLen, (unsigned char *)data, rcLen);
425                     res_size += rcLen;
426           }
427           EVP_DecryptFinal(ctx, res_data+res_size, &rcLen);
428           res_size += rcLen;
429           bmem = BIO_pop(b64);
430           BIO_free(b64);
431           b64 = NULL;
432           /* a BIO_reset failure shouldn't have an affect at this point */
433           BIO_reset(bmem);
434 
435 tss_out:
436           Tspi_Context_Close(hContext);
437 out:
438 
439           if (srkSecret)
440                     shredPasswd(srkSecret);
441 
442           if ( bdata )
443                     BIO_free(bdata);
444           if ( b64 )
445                     BIO_free(b64);
446           if ( bmem ) {
447                     BIO_set_close(bmem, BIO_CLOSE);
448                     BIO_free(bmem);
449           }
450 
451           if ( evpKeyData )
452                     free(evpKeyData);
453           if ( tssKeyData )
454                     free(tssKeyData);
455 
456           if ( rc == 0 ) {
457                     *tss_data = res_data;
458                     *tss_size = res_size;
459           } else
460                     free(res_data);
461 
462           return rc;
463 }
464 
tpmUnsealShred(unsigned char * data,int size)465 void tpmUnsealShred(unsigned char* data, int size) {
466 
467           if ( data != NULL ) {
468                     __memset( data, 0, size);
469                     free(data);
470           }
471 
472 }
473 
474 char tpm_error_buf[512];
tpmUnsealStrerror(int rc)475 char * tpmUnsealStrerror(int rc) {
476 
477           switch(rc) {
478                     case 0:
479                               return "Success";
480                     case TPMSEAL_STD_ERROR:
481                               return strerror(tpm_errno);
482                     case TPMSEAL_FILE_ERROR:
483                               switch(tpm_errno) {
484                                         case ENOTSSHDR:
485                                                   return _("No TSS header present");
486                                         case ENOTSSFTR:
487                                                   return _("No TSS footer present");
488                                         case EWRONGTSSTAG:
489                                                   return _("Wrong TSS tag");
490                                         case EWRONGEVPTAG:
491                                                   return _("Wrong EVP tag");
492                                         case EWRONGDATTAG:
493                                                   return _("Wrong DATA tag");
494                                         case EWRONGKEYTYPE:
495                                                   return _("Not a Symmetric EVP Key");
496                                         case EBADSEEK:
497                                                   return _("Unable to move to desired file position");
498                               }
499                     default:
500                               snprintf(tpm_error_buf, sizeof(tpm_error_buf),
501                                         "%s: 0x%08x - layer=%s, code=%04x (%d), %s",
502                                         tspi_error_strings[tpm_errno],
503                                         rc, Trspi_Error_Layer(rc),
504                                         Trspi_Error_Code(rc),
505                                         Trspi_Error_Code(rc),
506                                         Trspi_Error_String(rc));
507                               return tpm_error_buf;
508           }
509           return "";
510 }
511