1 
2 /*
3  * Licensed Materials - Property of IBM
4  *
5  * trousers - An open source TCG Software Stack
6  *
7  * (C) Copyright International Business Machines Corp. 2004-2006
8  *
9  */
10 
11 /*
12  * symmetric.c - openssl TSS crypto routines
13  *
14  * Kent Yoder <shpedoikal@gmail.com>
15  *
16  */
17 
18 #include <limits.h>
19 #include <string.h>
20 
21 #include <openssl/evp.h>
22 #include <openssl/err.h>
23 #include <openssl/rand.h>
24 #include <limits.h>
25 
26 #include "trousers/tss.h"
27 #include "trousers/trousers.h"
28 #include "trousers_types.h"
29 #include "spi_utils.h"
30 #include "tsplog.h"
31 
32 
33 #ifdef TSS_DEBUG
34 #define DEBUG_print_openssl_errors() \
35           do { \
36                     ERR_load_crypto_strings(); \
37                     ERR_print_errors_fp(stderr); \
38           } while (0)
39 #else
40 #define DEBUG_print_openssl_errors()
41 #endif
42 
43 /*
44  * Hopefully this will make the code clearer since
45  * OpenSSL returns 1 on success
46  */
47 #define EVP_SUCCESS 1
48 
49 TSS_RESULT
Trspi_Encrypt_ECB(UINT16 alg,BYTE * key,BYTE * in,UINT32 in_len,BYTE * out,UINT32 * out_len)50 Trspi_Encrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out,
51                       UINT32 *out_len)
52 {
53           TSS_RESULT result = TSS_SUCCESS;
54           EVP_CIPHER_CTX *ctx = NULL;
55           UINT32 tmp;
56 
57           switch (alg) {
58                     case TSS_ALG_AES:
59                               break;
60                     default:
61                               result = TSPERR(TSS_E_INTERNAL_ERROR);
62                               goto done;
63                               break;
64           }
65 
66           ctx = EVP_CIPHER_CTX_new();
67 
68           if (!EVP_EncryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) {
69                     result = TSPERR(TSS_E_INTERNAL_ERROR);
70                     DEBUG_print_openssl_errors();
71                     goto done;
72           }
73 
74           if (*out_len < in_len + EVP_CIPHER_CTX_block_size(ctx) - 1) {
75                     result = TSPERR(TSS_E_INTERNAL_ERROR);
76                     goto done;
77           }
78 
79           if (!EVP_EncryptUpdate(ctx, out, (int *)out_len, in, in_len)) {
80                     result = TSPERR(TSS_E_INTERNAL_ERROR);
81                     DEBUG_print_openssl_errors();
82                     goto done;
83           }
84 
85           if (!EVP_EncryptFinal(ctx, out + *out_len, (int *)&tmp)) {
86                     result = TSPERR(TSS_E_INTERNAL_ERROR);
87                     DEBUG_print_openssl_errors();
88                     goto done;
89           }
90           *out_len += tmp;
91 done:
92           EVP_CIPHER_CTX_free(ctx);
93           return result;
94 }
95 
96 TSS_RESULT
Trspi_Decrypt_ECB(UINT16 alg,BYTE * key,BYTE * in,UINT32 in_len,BYTE * out,UINT32 * out_len)97 Trspi_Decrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out,
98                       UINT32 *out_len)
99 {
100           TSS_RESULT result = TSS_SUCCESS;
101           EVP_CIPHER_CTX *ctx = NULL;
102           UINT32 tmp;
103 
104           switch (alg) {
105                     case TSS_ALG_AES:
106                               break;
107                     default:
108                               result = TSPERR(TSS_E_INTERNAL_ERROR);
109                               goto done;
110                               break;
111           }
112 
113           ctx = EVP_CIPHER_CTX_new();
114 
115           if (!EVP_DecryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) {
116                     result = TSPERR(TSS_E_INTERNAL_ERROR);
117                     DEBUG_print_openssl_errors();
118                     goto done;
119           }
120 
121           if (!EVP_DecryptUpdate(ctx, out, (int *)out_len, in, in_len)) {
122                     result = TSPERR(TSS_E_INTERNAL_ERROR);
123                     DEBUG_print_openssl_errors();
124                     goto done;
125           }
126 
127           if (!EVP_DecryptFinal(ctx, out + *out_len, (int *)&tmp)) {
128                     result = TSPERR(TSS_E_INTERNAL_ERROR);
129                     DEBUG_print_openssl_errors();
130                     goto done;
131           }
132           *out_len += tmp;
133 done:
134           EVP_CIPHER_CTX_free(ctx);
135           return result;
136 }
137 
138 EVP_CIPHER *
get_openssl_cipher(UINT16 alg,UINT16 mode)139 get_openssl_cipher(UINT16 alg, UINT16 mode)
140 {
141           EVP_CIPHER *cipher = NULL;
142 
143           switch (alg) {
144                     case TSS_ALG_AES:
145                     case TCPA_ALG_AES:
146                               switch (mode) {
147                                         case TPM_ES_NONE:
148                                         case TSS_ES_NONE:
149                                         case TPM_ES_SYM_CBC_PKCS5PAD:
150                                                   LogDebug("XXX Make sure this is really PKCS5 padded");
151                                         case TR_SYM_MODE_CBC:
152                                                   cipher = (EVP_CIPHER *)EVP_aes_128_cbc();
153                                                   break;
154                                         case TPM_ES_SYM_OFB:
155                                                   cipher = (EVP_CIPHER *)EVP_aes_128_ofb();
156                                                   break;
157                                         case TPM_ES_SYM_CNT:
158                                                   LogDebug("XXX AES128 in CTR mode unsupp by openssl EVP");
159                                         default:
160                                                   LogDebug("Invalid mode in doing symmetric encryption");
161                                                   break;
162                               }
163                               break;
164                     case TSS_ALG_DES:
165                     case TCPA_ALG_DES:
166                               switch (mode) {
167                                         case TPM_ES_NONE:
168                                         case TSS_ES_NONE:
169                                         case TPM_ES_SYM_CBC_PKCS5PAD:
170                                                   LogDebug("XXX Make sure this is really PKCS5 padded");
171                                         case TR_SYM_MODE_CBC:
172                                                   cipher = (EVP_CIPHER *)EVP_des_cbc();
173                                                   break;
174                                         case TPM_ES_SYM_OFB:
175                                                   cipher = (EVP_CIPHER *)EVP_des_ofb();
176                                                   break;
177                                         case TPM_ES_SYM_CNT:
178                                                   LogDebug("XXX DES in CTR mode unsupp by openssl EVP");
179                                         default:
180                                                   LogDebug("Invalid mode in doing symmetric encryption");
181                                                   break;
182                               }
183                               break;
184                     case TSS_ALG_3DES:
185                     case TCPA_ALG_3DES:
186                               switch (mode) {
187                                         case TPM_ES_NONE:
188                                         case TSS_ES_NONE:
189                                         case TPM_ES_SYM_CBC_PKCS5PAD:
190                                                   LogDebug("XXX Make sure this is really PKCS5 padded");
191                                         case TR_SYM_MODE_CBC:
192                                                   cipher = (EVP_CIPHER *)EVP_des_ede3_cbc();
193                                                   break;
194                                         case TPM_ES_SYM_OFB:
195                                                   cipher = (EVP_CIPHER *)EVP_des_ede3_ofb();
196                                                   break;
197                                         case TPM_ES_SYM_CNT:
198                                                   LogDebug("XXX 3DES in CTR mode unsupp by openssl EVP");
199                                         default:
200                                                   LogDebug("Invalid mode in doing symmetric encryption");
201                                                   break;
202                               }
203                               break;
204                     case TPM_ALG_AES192:
205                     case TSS_ALG_AES192:
206                               switch (mode) {
207                                         case TPM_ES_NONE:
208                                         case TSS_ES_NONE:
209                                         case TPM_ES_SYM_CBC_PKCS5PAD:
210                                                   LogDebug("XXX Make sure this is really PKCS5 padded");
211                                         case TR_SYM_MODE_CBC:
212                                                   cipher = (EVP_CIPHER *)EVP_aes_192_cbc();
213                                                   break;
214                                         case TPM_ES_SYM_OFB:
215                                                   cipher = (EVP_CIPHER *)EVP_aes_192_ofb();
216                                                   break;
217                                         case TPM_ES_SYM_CNT:
218                                                   LogDebug("XXX AES192 in CTR mode unsupp by openssl EVP");
219                                         default:
220                                                   LogDebug("Invalid mode in doing symmetric encryption");
221                                                   break;
222                               }
223                               break;
224                     case TPM_ALG_AES256:
225                     case TSS_ALG_AES256:
226                               switch (mode) {
227                                         case TPM_ES_NONE:
228                                         case TSS_ES_NONE:
229                                         case TPM_ES_SYM_CBC_PKCS5PAD:
230                                                   LogDebug("XXX Make sure this is really PKCS5 padded");
231                                         case TR_SYM_MODE_CBC:
232                                                   cipher = (EVP_CIPHER *)EVP_aes_256_cbc();
233                                                   break;
234                                         case TPM_ES_SYM_OFB:
235                                                   cipher = (EVP_CIPHER *)EVP_aes_256_ofb();
236                                                   break;
237                                         case TPM_ES_SYM_CNT:
238                                                   LogDebug("XXX AES256 in CTR mode unsupp by openssl EVP");
239                                         default:
240                                                   LogDebug("Invalid mode in doing symmetric encryption");
241                                                   break;
242                               }
243                               break;
244                     default:
245                               LogDebug("Invalid algorithm in doing symmetric encryption");
246                               break;
247           }
248 
249           return cipher;
250 }
251 
252 TSS_RESULT
Trspi_SymEncrypt(UINT16 alg,UINT16 mode,BYTE * key,BYTE * iv,BYTE * in,UINT32 in_len,BYTE * out,UINT32 * out_len)253 Trspi_SymEncrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out,
254                      UINT32 *out_len)
255 {
256           TSS_RESULT result = TSS_SUCCESS;
257           EVP_CIPHER_CTX *ctx = NULL;
258           EVP_CIPHER *cipher;
259           BYTE *def_iv = NULL, *outiv_ptr;
260           UINT32 tmp;
261           int iv_len, outiv_len;
262 
263           if (*out_len > INT_MAX)
264                     outiv_len = INT_MAX;
265           else
266                     outiv_len = *(int *)out_len;
267 
268           if ((cipher = get_openssl_cipher(alg, mode)) == NULL)
269                     return TSPERR(TSS_E_INTERNAL_ERROR);
270 
271           ctx = EVP_CIPHER_CTX_new();
272 
273           /* If the iv passed in is NULL, create a new random iv and prepend it to the ciphertext */
274           iv_len = EVP_CIPHER_iv_length(cipher);
275           if (iv == NULL) {
276                     def_iv = malloc(iv_len);
277                     if (def_iv == NULL) {
278                               LogError("malloc of %d bytes failed.", iv_len);
279                               return TSPERR(TSS_E_OUTOFMEMORY);
280                     }
281                     RAND_bytes(def_iv, iv_len);
282 
283                     memcpy(out, def_iv, iv_len);
284                     outiv_ptr = &out[iv_len];
285                     outiv_len -= iv_len;
286           } else {
287                     def_iv = iv;
288                     outiv_ptr = out;
289           }
290 
291           if (!EVP_EncryptInit(ctx, (const EVP_CIPHER *)cipher, key, def_iv)) {
292                     result = TSPERR(TSS_E_INTERNAL_ERROR);
293                     DEBUG_print_openssl_errors();
294                     goto done;
295           }
296 
297           if ((UINT32)outiv_len < in_len + (EVP_CIPHER_CTX_block_size(ctx) * 2) - 1) {
298                     LogDebug("Not enough space to do symmetric encryption");
299                     result = TSPERR(TSS_E_INTERNAL_ERROR);
300                     goto done;
301           }
302 
303           if (!EVP_EncryptUpdate(ctx, outiv_ptr, &outiv_len, in, in_len)) {
304                     result = TSPERR(TSS_E_INTERNAL_ERROR);
305                     DEBUG_print_openssl_errors();
306                     goto done;
307           }
308 
309           if (!EVP_EncryptFinal(ctx, outiv_ptr + outiv_len, (int *)&tmp)) {
310                     result = TSPERR(TSS_E_INTERNAL_ERROR);
311                     DEBUG_print_openssl_errors();
312                     goto done;
313           }
314 
315           outiv_len += tmp;
316           *out_len = outiv_len;
317 done:
318           if (def_iv != iv) {
319                     *out_len += iv_len;
320                     free(def_iv);
321           }
322           EVP_CIPHER_CTX_free(ctx);
323           return result;
324 }
325 
326 TSS_RESULT
Trspi_SymDecrypt(UINT16 alg,UINT16 mode,BYTE * key,BYTE * iv,BYTE * in,UINT32 in_len,BYTE * out,UINT32 * out_len)327 Trspi_SymDecrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out,
328                      UINT32 *out_len)
329 {
330           TSS_RESULT result = TSS_SUCCESS;
331           EVP_CIPHER_CTX *ctx = NULL;
332           EVP_CIPHER *cipher;
333           BYTE *def_iv = NULL, *iniv_ptr;
334           UINT32 tmp;
335           int iv_len, iniv_len;
336 
337           if (in_len > INT_MAX)
338                     return TSS_E_BAD_PARAMETER;
339 
340           if ((cipher = get_openssl_cipher(alg, mode)) == NULL)
341                     return TSPERR(TSS_E_INTERNAL_ERROR);
342 
343           ctx = EVP_CIPHER_CTX_new();
344 
345           /* If the iv is NULL, assume that its prepended to the ciphertext */
346           if (iv == NULL) {
347                     iv_len = EVP_CIPHER_iv_length(cipher);
348                     def_iv = malloc(iv_len);
349                     if (def_iv == NULL) {
350                               LogError("malloc of %d bytes failed.", iv_len);
351                               return TSPERR(TSS_E_OUTOFMEMORY);
352                     }
353 
354                     memcpy(def_iv, in, iv_len);
355                     iniv_ptr = &in[iv_len];
356                     iniv_len = in_len - iv_len;
357           } else {
358                     def_iv = iv;
359                     iniv_ptr = in;
360                     iniv_len = in_len;
361           }
362 
363           if (!EVP_DecryptInit(ctx, cipher, key, def_iv)) {
364                     result = TSPERR(TSS_E_INTERNAL_ERROR);
365                     DEBUG_print_openssl_errors();
366                     goto done;
367           }
368 
369           if (!EVP_DecryptUpdate(ctx, out, (int *)out_len, iniv_ptr, iniv_len)) {
370                     result = TSPERR(TSS_E_INTERNAL_ERROR);
371                     DEBUG_print_openssl_errors();
372                     goto done;
373           }
374 
375           if (!EVP_DecryptFinal(ctx, out + *out_len, (int *)&tmp)) {
376                     result = TSPERR(TSS_E_INTERNAL_ERROR);
377                     DEBUG_print_openssl_errors();
378                     goto done;
379           }
380 
381           *out_len += tmp;
382 done:
383           if (def_iv != iv)
384                     free(def_iv);
385           EVP_CIPHER_CTX_free(ctx);
386           return result;
387 }
388