]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libtpmtss/tpm_tss_tss2_session.c
libtpmtss: Some minor improvements
[people/ms/strongswan.git] / src / libtpmtss / tpm_tss_tss2_session.c
1 /*
2 * Copyright (C) 2021 Andreas Steffen, strongSec GmbH
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #ifdef TSS_TSS2_V2
16
17 #include "tpm_tss_tss2_session.h"
18 #include "tpm_tss_tss2_names.h"
19
20 #define LABEL "TPM 2.0 - "
21
22 typedef struct private_tpm_tss_tss2_session_t private_tpm_tss_tss2_session_t;
23
24 /**
25 * Private data of an tpm_tss_tss2_session_t object.
26 */
27 struct private_tpm_tss_tss2_session_t {
28
29 /**
30 * Public tpm_tss_tss2_session_t interface.
31 */
32 tpm_tss_tss2_session_t public;
33
34 /**
35 * Session handle for protected communication with TPM 2.0
36 */
37 uint32_t session_handle;
38
39 /**
40 * Session key for protected communication with TPM 2.0
41 */
42 chunk_t session_key;
43
44 /**
45 * Hash algorithm to be used for protected communication with TPM 2.0
46 */
47 TPM2_ALG_ID hash_alg;
48
49 /**
50 * nonceCaller used for protected communication with TPM 2.0
51 */
52 TPM2B_NONCE nonceCaller;
53
54 /**
55 * nonceTPM used for protected communication with TPM 2.0
56 */
57 TPM2B_NONCE nonceTPM;
58
59 /**
60 * AES-CFB key size in bytes
61 */
62 size_t aes_key_len;
63
64 /**
65 * SYS context
66 */
67 TSS2_SYS_CONTEXT *sys_context;
68
69 };
70
71 /**
72 * Two functions shared with tpm_tss_tss2_v2.c
73 */
74
75 hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg);
76
77 size_t hash_len_from_tpm_alg_id(TPM2_ALG_ID alg);
78
79
80 /**
81 * Convert TPM2_ALG_ID to PRF algorithm
82 */
83 pseudo_random_function_t prf_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
84 {
85 switch (alg)
86 {
87 case TPM2_ALG_SHA1:
88 return PRF_HMAC_SHA1;
89 case TPM2_ALG_SHA256:
90 return PRF_HMAC_SHA2_256;
91 case TPM2_ALG_SHA384:
92 return PRF_HMAC_SHA2_384;
93 case TPM2_ALG_SHA512:
94 return PRF_HMAC_SHA2_512;
95 default:
96 return PRF_UNDEFINED;
97 }
98 }
99
100 static bool generate_nonce(size_t size, TPM2B_NONCE *nonce)
101 {
102 nonce_gen_t *nonce_gen;
103 bool success;
104
105 nonce_gen = lib->crypto->create_nonce_gen(lib->crypto);
106 if (!nonce_gen)
107 {
108 DBG1(DBG_PTS, "no nonce generator available");
109 return FALSE;
110 }
111 nonce->size = size;
112 success = nonce_gen->get_nonce(nonce_gen, nonce->size, nonce->buffer);
113 nonce_gen->destroy(nonce_gen);
114
115 if (!success)
116 {
117 DBG1(DBG_PTS, "generation of nonce failed");
118 return FALSE;
119 }
120
121 return TRUE;
122 }
123
124 METHOD(tpm_tss_tss2_session_t, set_cmd_auths, bool,
125 private_tpm_tss_tss2_session_t *this)
126 {
127 size_t hash_len, param_size, cp_size;
128 const uint8_t *param_buffer, *cp_buffer;
129 uint8_t cc_buffer[4];
130 hash_algorithm_t hash_algorithm;
131 hasher_t *hasher;
132 pseudo_random_function_t prf_alg;
133 prf_t *prf;
134 chunk_t data, cp_hash, cp_hmac, nonce_caller, nonce_tpm, session_attributes;
135 bool success;
136 uint32_t rval;
137
138 TSS2L_SYS_AUTH_COMMAND cmd;
139 TPM2B_DIGEST cpHash;
140
141 cmd.count = 1;
142 cmd.auths[0].sessionHandle = this->session_handle;
143 cmd.auths[0].sessionAttributes = TPMA_SESSION_CONTINUESESSION |
144 TPMA_SESSION_ENCRYPT;
145 session_attributes = chunk_create(&cmd.auths[0].sessionAttributes, 1);
146
147 hash_len = hash_len_from_tpm_alg_id(this->hash_alg);
148
149 if (!generate_nonce(hash_len, &this->nonceCaller))
150 {
151 return FALSE;
152 }
153 cmd.auths[0].nonce.size = this->nonceCaller.size;
154 memcpy(cmd.auths[0].nonce.buffer, this->nonceCaller.buffer,
155 this->nonceCaller.size);
156
157 rval = Tss2_Sys_GetEncryptParam(this->sys_context, &param_size,
158 &param_buffer);
159 if (rval == TSS2_SYS_RC_NO_ENCRYPT_PARAM)
160 {
161 DBG2(DBG_PTS, LABEL "parameter encryption not possible");
162 return FALSE;
163 }
164
165 rval = Tss2_Sys_GetCommandCode(this->sys_context, cc_buffer);
166 if (rval != TSS2_RC_SUCCESS)
167 {
168 DBG1(DBG_PTS, LABEL "Tss2_Sys_GetCommandCode failed: 0x%06x", rval);
169 return FALSE;
170 }
171
172 rval = Tss2_Sys_GetCpBuffer(this->sys_context, &cp_size, &cp_buffer);
173 if (rval != TSS2_RC_SUCCESS)
174 {
175 DBG1(DBG_PTS, LABEL "Tss2_GetCpBuffer failed: 0x%06x", rval);
176 return FALSE;
177 }
178
179 /* compute cpHash */
180 hash_algorithm = hash_alg_from_tpm_alg_id(this->hash_alg);
181 hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
182 if (!hasher)
183 {
184 DBG1(DBG_PTS, "hasher could not be created");
185 return FALSE;
186 }
187
188 data = chunk_alloc(4 + cp_size);
189 memcpy(data.ptr, cc_buffer, 4);
190 memcpy(data.ptr + 4, cp_buffer, cp_size);
191
192 success = hasher->get_hash(hasher, data, cpHash.buffer);
193 cpHash.size = hasher->get_hash_size(hasher);
194 hasher->destroy(hasher);
195 chunk_free(&data);
196
197 if (!success)
198 {
199 DBG1(DBG_PTS, "computation of cpHash failed");
200 return FALSE;
201 }
202 cp_hash = chunk_create(cpHash.buffer, cpHash.size);
203
204 /* compute cp HMAC */
205 prf_alg = prf_alg_from_tpm_alg_id(this->hash_alg);
206 prf = lib->crypto->create_prf(lib->crypto, prf_alg);
207 if (!prf)
208 {
209 DBG1(DBG_PTS, "could not create PRF");
210 return FALSE;
211 }
212 if (!prf->set_key(prf, this->session_key))
213 {
214 DBG1(DBG_PTS, "could not set PRF key");
215 prf->destroy(prf);
216 return FALSE;
217 }
218
219 nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
220 nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
221
222 success = prf->get_bytes(prf, cp_hash, NULL) &&
223 prf->get_bytes(prf, nonce_caller, NULL) &&
224 prf->get_bytes(prf, nonce_tpm, NULL) &&
225 prf->get_bytes(prf, session_attributes, cmd.auths[0].hmac.buffer);
226 cmd.auths[0].hmac.size = prf->get_block_size(prf);
227 prf->destroy(prf);
228
229 if (!success)
230 {
231 DBG1(DBG_PTS, "cpHmac computation failed");
232 return FALSE;
233 }
234 cp_hmac = chunk_create(cmd.auths[0].hmac.buffer, cmd.auths[0].hmac.size);
235 DBG2(DBG_PTS, LABEL "cpHmac: %B", &cp_hmac);
236
237 rval = Tss2_Sys_SetCmdAuths(this->sys_context, &cmd);
238 if (rval != TSS2_RC_SUCCESS)
239 {
240 DBG1(DBG_PTS, LABEL "Tss2_Sys_SetCmdAuths failed: 0x%06x", rval);
241 return FALSE;
242 }
243
244 return TRUE;
245 }
246
247 /**
248 * Key Derivation Function using Counter Mode as defined by NIST SP800-108
249 * - the label is expected to be NUL terminated
250 */
251 static bool kdf_a(TPMI_ALG_HASH hash_alg, chunk_t key, chunk_t label,
252 chunk_t context_u, chunk_t context_v, uint32_t bytes,
253 chunk_t *key_mat)
254 {
255 pseudo_random_function_t prf_alg;
256 chunk_t count_chunk, bits_chunk;
257 uint32_t iterations, counter, count, bits;
258 uint8_t *pos;
259 size_t hlen;
260 prf_t *prf;
261
262 bits = htonl(8 * bytes);
263 bits_chunk = chunk_create((uint8_t*)&bits, sizeof(bits));
264
265 prf_alg = prf_alg_from_tpm_alg_id(hash_alg);
266 prf = lib->crypto->create_prf(lib->crypto, prf_alg);
267 if (!prf)
268 {
269 DBG1(DBG_PTS, "could not create PRF");
270 return FALSE;
271 }
272 if (!prf->set_key(prf, key))
273 {
274 DBG1(DBG_PTS, "could not set PRF key");
275 prf->destroy(prf);
276 return FALSE;
277 }
278
279 hlen = prf->get_block_size(prf);
280 iterations = (bytes + hlen - 1) / hlen;
281 *key_mat = chunk_alloc(iterations * hlen);
282 pos = key_mat->ptr;
283
284 for (counter = 1; counter <= iterations; counter++)
285 {
286 count = htonl(counter);
287 count_chunk = chunk_create((uint8_t*)&count, sizeof(count));
288
289 if (!prf->get_bytes(prf, count_chunk, NULL) ||
290 !prf->get_bytes(prf, label, NULL) ||
291 !prf->get_bytes(prf, context_u, NULL) ||
292 !prf->get_bytes(prf, context_v, NULL) ||
293 !prf->get_bytes(prf, bits_chunk, pos))
294 {
295 DBG1(DBG_PTS, "KDFa computation failed");
296 chunk_free(key_mat);
297 prf->destroy(prf);
298 return FALSE;
299 }
300 pos += hlen;
301 }
302 prf->destroy(prf);
303
304 return TRUE;
305 }
306
307 METHOD(tpm_tss_tss2_session_t, get_rsp_auths, bool,
308 private_tpm_tss_tss2_session_t *this)
309 {
310 size_t param_size, rp_size, key_len, iv_len;
311 const uint8_t *param_buffer, *rp_buffer;
312 uint8_t rc_buffer[4] = { 0 };
313 uint8_t cc_buffer[4];
314 hash_algorithm_t hash_algorithm;
315 hasher_t *hasher;
316 pseudo_random_function_t prf_alg;
317 prf_t *prf;
318 crypter_t *crypter;
319 chunk_t kdf_label = chunk_from_chars('C','F','B', 0x00);
320 chunk_t data, rp_hash, rp_hmac, nonce_caller, nonce_tpm, session_attributes;
321 chunk_t key_mat, aes_key, aes_iv;
322 bool success;
323 uint32_t rval;
324
325 TSS2L_SYS_AUTH_RESPONSE rsp;
326 TPM2B_DIGEST rpHash, rpHmac;
327
328 rval = Tss2_Sys_GetRspAuths(this->sys_context, &rsp);
329 if (rval != TSS2_RC_SUCCESS)
330 {
331 DBG1(DBG_PTS, LABEL "Tss2_Sys_GetRspAuths failed: 0x%06x", rval);
332 return FALSE;
333 }
334
335 /* update nonceTPM */
336 memcpy(this->nonceTPM.buffer, rsp.auths[0].nonce.buffer,
337 rsp.auths[0].nonce.size);
338 this->nonceTPM.size = rsp.auths[0].nonce.size;
339
340 rval = Tss2_Sys_GetRpBuffer(this->sys_context, &rp_size, &rp_buffer);
341 if (rval != TSS2_RC_SUCCESS)
342 {
343 DBG1(DBG_PTS, LABEL "Tss2_Sys_GetRpBuffer failed: 0x%06x", rval);
344 return FALSE;
345 }
346
347 rval = Tss2_Sys_GetCommandCode(this->sys_context, cc_buffer);
348 if (rval != TSS2_RC_SUCCESS)
349 {
350 DBG1(DBG_PTS, LABEL "Tss2_Sys_GetCommandCode failed: 0x%06x", rval);
351 return FALSE;
352 }
353
354 /* compute rpHash */
355 hash_algorithm = hash_alg_from_tpm_alg_id(this->hash_alg);
356 hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
357 if (!hasher)
358 {
359 DBG1(DBG_PTS, "hasher could not be created");
360 return FALSE;
361 }
362
363 data = chunk_alloc(4 + 4 + rp_size);
364 memcpy(data.ptr, rc_buffer, 4);
365 memcpy(data.ptr + 4, cc_buffer, 4);
366 memcpy(data.ptr + 8, rp_buffer, rp_size);
367
368 success = hasher->get_hash(hasher, data, rpHash.buffer);
369 rpHash.size = hasher->get_hash_size(hasher);
370 hasher->destroy(hasher);
371 chunk_free(&data);
372
373 if (!success)
374 {
375 DBG1(DBG_PTS, "computation of rpHash failed");
376 return FALSE;
377 }
378 rp_hash = chunk_create(rpHash.buffer, rpHash.size);
379
380 /* compute rpHmac */
381 prf_alg = prf_alg_from_tpm_alg_id(this->hash_alg);
382 prf = lib->crypto->create_prf(lib->crypto, prf_alg);
383 if (!prf)
384 {
385 DBG1(DBG_PTS, "could not create PRF");
386 return FALSE;
387 }
388 if (!prf->set_key(prf, this->session_key))
389 {
390 DBG1(DBG_PTS, "could not set PRF key");
391 prf->destroy(prf);
392 return FALSE;
393 }
394
395 nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
396 nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
397 session_attributes = chunk_create(&rsp.auths[0].sessionAttributes, 1);
398
399 success = prf->get_bytes(prf, rp_hash, NULL) &&
400 prf->get_bytes(prf, nonce_tpm, NULL) &&
401 prf->get_bytes(prf, nonce_caller, NULL) &&
402 prf->get_bytes(prf, session_attributes, rpHmac.buffer);
403 rpHmac.size = prf->get_block_size(prf);
404 prf->destroy(prf);
405
406 if (!success)
407 {
408 DBG1(DBG_PTS, "computation of rpHmac failed");
409 return FALSE;
410 }
411 rp_hmac = chunk_create(rpHmac.buffer, rpHmac.size);
412 DBG2(DBG_PTS, LABEL "rpHMAC: %B", &rp_hmac);
413
414 /* verify rpHmac */
415 if (!memeq(rsp.auths[0].hmac.buffer, rpHmac.buffer, rpHmac.size))
416 {
417 DBG1(DBG_PTS, LABEL "invalid HMAC received for session 0x%08x",
418 this->session_handle);
419 return FALSE;
420 }
421
422 /* decrypt parameter */
423 rval = Tss2_Sys_GetEncryptParam(this->sys_context, &param_size,
424 &param_buffer);
425 if (rval != TSS2_RC_SUCCESS)
426 {
427 DBG1(DBG_PTS, LABEL "Tss2_Sys_GetEncryptParam failed: 0x%06x", rval);
428 return FALSE;
429 }
430
431 crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CFB,
432 this->aes_key_len);
433 if (!crypter)
434 {
435 DBG1(DBG_PTS, "could not create %N crypter", encryption_algorithm_names,
436 ENCR_AES_CFB);
437 return FALSE;
438 }
439
440 key_len = crypter->get_key_size(crypter);
441 iv_len = crypter->get_iv_size(crypter);
442
443 /* derive decryption key using KDFa */
444 if (!kdf_a(this->hash_alg, this->session_key, kdf_label, nonce_tpm,
445 nonce_caller, key_len + iv_len , &key_mat))
446 {
447 return FALSE;
448 }
449 aes_key = chunk_create(key_mat.ptr, key_len);
450 aes_iv = chunk_create(key_mat.ptr + key_len, iv_len);
451
452 if (!crypter->set_key(crypter, aes_key))
453 {
454 crypter->destroy(crypter);
455 chunk_clear(&key_mat);
456 return FALSE;
457 }
458
459 /* copy ciphertext */
460 data = chunk_alloc(param_size);
461 memcpy(data.ptr, param_buffer, param_size);
462
463 /* decrypt ciphertext */
464 success = crypter->decrypt(crypter, data, aes_iv, NULL);
465 crypter->destroy(crypter);
466 chunk_clear(&key_mat);
467 if (!success)
468 {
469 chunk_free(&data);
470 return FALSE;
471 }
472 DBG4(DBG_PTS, LABEL "plaintext: %B", &data);
473
474 /* copy back plaintext */
475 rval = Tss2_Sys_SetEncryptParam(this->sys_context, data.len, data.ptr);
476 chunk_clear(&data);
477
478 if (rval != TSS2_RC_SUCCESS)
479 {
480 DBG1(DBG_PTS, LABEL "Tss2_Sys_SetEncryptParam failed: 0x%06x", rval);
481 return FALSE;
482 }
483
484 return TRUE;
485 }
486
487
488 METHOD(tpm_tss_tss2_session_t, destroy, void,
489 private_tpm_tss_tss2_session_t *this)
490 {
491 if (this->session_handle)
492 {
493 uint32_t rval;
494
495 /* flush session context */
496 rval = Tss2_Sys_FlushContext(this->sys_context, this->session_handle);
497 if (rval != TPM2_RC_SUCCESS)
498 {
499 DBG2(DBG_PTS, LABEL "Tss2_Sys_FlushContext failed: 0x%06x", rval);
500 }
501 chunk_clear(&this->session_key);
502 }
503 free(this);
504 }
505
506 static chunk_t secret_label = chunk_from_chars('S','E','C','R','E','T', 0x00);
507
508 static bool rsa_salt(TPM2B_PUBLIC *public, TPMI_ALG_HASH hash_alg,
509 chunk_t *secret, TPM2B_ENCRYPTED_SECRET *encryptedSalt)
510 {
511 encryption_scheme_t encryption_scheme;
512 public_key_t *pubkey = NULL;
513 nonce_gen_t *nonce_gen;
514 chunk_t encrypted_salt = chunk_empty;
515 chunk_t rsa_modulus;
516 chunk_t rsa_exponent = chunk_from_chars(0x01, 0x00, 0x01);
517 uint32_t exponent;
518 size_t hash_len;
519 bool success;
520
521 TPM2B_PUBLIC_KEY_RSA *rsa;
522
523 switch (hash_alg)
524 {
525 case TPM2_ALG_SHA1:
526 encryption_scheme = ENCRYPT_RSA_OAEP_SHA1;
527 break;
528 case TPM2_ALG_SHA256:
529 encryption_scheme = ENCRYPT_RSA_OAEP_SHA256;
530 break;
531 case TPM2_ALG_SHA384:
532 encryption_scheme = ENCRYPT_RSA_OAEP_SHA384;
533 break;
534 case TPM2_ALG_SHA512:
535 encryption_scheme = ENCRYPT_RSA_OAEP_SHA512;
536 break;
537 default:
538 DBG1(DBG_PTS, LABEL "unsupported key hash algorithm");
539 return FALSE;
540 }
541
542 hash_len = hash_len_from_tpm_alg_id(hash_alg);
543
544 /* create a salt nonce to be used as a shared secret */
545 nonce_gen = lib->crypto->create_nonce_gen(lib->crypto);
546 if (!nonce_gen)
547 {
548 DBG1(DBG_PTS, "no nonce generator available");
549 return FALSE;
550 }
551 success = nonce_gen->allocate_nonce(nonce_gen, hash_len, secret);
552 nonce_gen->destroy(nonce_gen);
553 if (!success)
554 {
555 DBG1(DBG_PTS, "generation of salt nonce failed");
556 return FALSE;
557 }
558
559 /* get RSA public key */
560 rsa = &public->publicArea.unique.rsa;
561 rsa_modulus = chunk_create(rsa->buffer, rsa->size);
562 exponent = htonl(public->publicArea.parameters.rsaDetail.exponent);
563 if (exponent)
564 {
565 rsa_exponent = chunk_from_thing(exponent);
566 }
567 pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
568 BUILD_RSA_MODULUS, rsa_modulus, BUILD_RSA_PUB_EXP,
569 rsa_exponent, BUILD_END);
570 if (!pubkey)
571 {
572 DBG1(DBG_PTS, "retrieval of EK public key failed");
573 chunk_clear(secret);
574 return FALSE;
575 }
576
577 /* use RSA public key encryption to encrypt secret salt nonce */
578 success = pubkey->encrypt(pubkey, encryption_scheme, &secret_label,
579 *secret, &encrypted_salt);
580 pubkey->destroy(pubkey);
581 if (!success)
582 {
583 DBG1(DBG_PTS, "encryption of salt failed");
584 chunk_clear(secret);
585 return FALSE;
586 }
587
588 /* copy encryptedSalt to output parameter */
589 encryptedSalt->size = encrypted_salt.len;
590 memcpy(encryptedSalt->secret, encrypted_salt.ptr, encrypted_salt.len);
591 free(encrypted_salt.ptr);
592
593 return TRUE;
594 }
595
596
597 /**
598 * Key Derivation Function used to derive an ecc-based secret
599 * - the label is expected to be NUL terminated
600 */
601 static bool kdf_e(TPMI_ALG_HASH hash_alg, chunk_t z, chunk_t label,
602 chunk_t context_u, chunk_t context_v, uint32_t bytes,
603 chunk_t *key_mat)
604 {
605 hash_algorithm_t hash_algorithm;
606 chunk_t count_chunk;
607 uint32_t iterations, counter, count;
608 uint8_t *pos;
609 size_t hlen;
610 hasher_t *hasher;
611
612 hash_algorithm = hash_alg_from_tpm_alg_id(hash_alg);
613 hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
614 if (!hasher)
615 {
616 DBG1(DBG_PTS, "could not create hasher");
617 return FALSE;
618 }
619
620 hlen = hasher->get_hash_size(hasher);
621 iterations = (bytes + hlen - 1) / hlen;
622 *key_mat = chunk_alloc(iterations * hlen);
623 pos = key_mat->ptr;
624
625 for (counter = 1; counter <= iterations; counter++)
626 {
627 count = htonl(counter);
628 count_chunk = chunk_create((uint8_t*)&count, sizeof(count));
629
630 if (!hasher->get_hash(hasher, count_chunk, NULL) ||
631 !hasher->get_hash(hasher, z, NULL) ||
632 !hasher->get_hash(hasher, label, NULL) ||
633 !hasher->get_hash(hasher, context_u, NULL) ||
634 !hasher->get_hash(hasher, context_v, pos))
635 {
636 DBG1(DBG_PTS, "KDFe computation failed");
637 chunk_free(key_mat);
638 hasher->destroy(hasher);
639 return FALSE;
640 }
641 pos += hlen;
642 }
643 hasher->destroy(hasher);
644
645 return TRUE;
646 }
647
648 static bool ecc_salt(TPM2B_PUBLIC *public, TPMI_ALG_HASH hash_alg,
649 chunk_t *secret, TPM2B_ENCRYPTED_SECRET *encryptedSalt)
650 {
651 diffie_hellman_group_t ec_group;
652 diffie_hellman_t *dh;
653 chunk_t ecdh_pubkey = chunk_empty, ecdh_pubkey_x, ecdh_pubkey_y;
654 chunk_t ecc_pubkey = chunk_empty, ecc_pubkey_x, ecc_pubkey_y;
655 chunk_t z = chunk_empty;
656 uint16_t len;
657 uint8_t *pos;
658 size_t hash_len;
659 bool success = FALSE;
660
661 switch (public->publicArea.parameters.eccDetail.curveID)
662 {
663 case TPM2_ECC_NIST_P256:
664 ec_group = ECP_256_BIT;
665 break;
666 case TPM2_ECC_NIST_P384:
667 ec_group = ECP_384_BIT;
668 break;
669 case TPM2_ECC_NIST_P521:
670 ec_group = ECP_521_BIT;
671 break;
672 default:
673 DBG1(DBG_PTS, "type of ECC EK key not supported");
674 return FALSE;
675 }
676
677 /* Generate ECDH key pair */
678 dh = lib->crypto->create_dh(lib->crypto, ec_group);
679 if (!dh)
680 {
681 DBG1(DBG_PTS, "DH group could not be created");
682 return FALSE;
683 }
684 if (!dh->get_my_public_value(dh, &ecdh_pubkey))
685 {
686 DBG1(DBG_PTS, "DH public key could not be generated");
687 dh->destroy(dh);
688 return FALSE;
689 }
690 ecdh_pubkey_x = chunk_create(ecdh_pubkey.ptr, ecdh_pubkey.len / 2);
691 ecdh_pubkey_y = chunk_create(ecdh_pubkey.ptr + ecdh_pubkey_x.len,
692 ecdh_pubkey_x.len);
693
694 /* get ECC public key */
695 ecc_pubkey_x = chunk_create(public->publicArea.unique.ecc.x.buffer,
696 public->publicArea.unique.ecc.x.size);
697 ecc_pubkey_y = chunk_create(public->publicArea.unique.ecc.y.buffer,
698 public->publicArea.unique.ecc.y.size);
699 ecc_pubkey = chunk_cat("cc", ecc_pubkey_x, ecc_pubkey_y);
700
701 /* compute point multiplication of ecc_pubkey with ecdh_privkey */
702 if (!dh->set_other_public_value(dh, ecc_pubkey))
703 {
704 DBG1(DBG_PTS, "ECC public could not be set");
705 goto error;
706 }
707 if (!dh->get_shared_secret(dh, &z))
708 {
709 DBG1(DBG_PTS, "could not create shared secret");
710 goto error;
711 }
712
713 hash_len = hash_len_from_tpm_alg_id(hash_alg);
714
715 /* derive secret using KDFe */
716 if (!kdf_e(hash_alg, z, secret_label, ecdh_pubkey_x, ecc_pubkey_x,
717 hash_len, secret))
718 {
719 goto error;
720 }
721
722 /* copy ECDH pubkey to encrypted salt parameter */
723 len = htons(ecdh_pubkey_x.len);
724 encryptedSalt->size = 2 * sizeof(len) + ecdh_pubkey.len;
725 pos = encryptedSalt->secret;
726 memcpy(pos, (uint8_t*)&len, sizeof(len));
727 pos += sizeof(len);
728 memcpy(pos, ecdh_pubkey_x.ptr, ecdh_pubkey_x.len);
729 pos += ecdh_pubkey_x.len;
730 memcpy(pos, (uint8_t*)&len, sizeof(len));
731 pos += sizeof(len);
732 memcpy(pos, ecdh_pubkey_y.ptr, ecdh_pubkey_y.len);
733
734 success = TRUE;
735
736 error:
737 dh->destroy(dh);
738 chunk_free(&ecdh_pubkey);
739 chunk_free(&ecc_pubkey);
740 chunk_clear(&z);
741
742 return success;
743 }
744
745 /**
746 * See header
747 */
748 tpm_tss_tss2_session_t* tpm_tss_tss2_session_create(uint32_t ek_handle,
749 TPM2B_PUBLIC *public, TSS2_SYS_CONTEXT *sys_context)
750 {
751 private_tpm_tss_tss2_session_t *this;
752 chunk_t secret = chunk_empty;
753 chunk_t kdf_label = chunk_from_chars('A','T','H', 0x00);
754 chunk_t nonce_caller, nonce_tpm;
755 size_t hash_len;
756 uint32_t rval;
757
758 TPM2B_ENCRYPTED_SECRET encryptedSalt;
759 TPM2_SE sessionType = TPM2_SE_HMAC;
760 TPMT_SYM_DEF *sym;
761
762 INIT(this,
763 .public = {
764 .set_cmd_auths = _set_cmd_auths,
765 .get_rsp_auths = _get_rsp_auths,
766 .destroy = _destroy,
767 },
768 .sys_context = sys_context,
769 .hash_alg = public->publicArea.nameAlg,
770 );
771
772 hash_len = hash_len_from_tpm_alg_id(this->hash_alg);
773
774 if (!generate_nonce(hash_len, &this->nonceCaller))
775 {
776 goto error;
777 }
778
779 /* determine endorsement key type */
780 switch (public->publicArea.type)
781 {
782 case TPM2_ALG_RSA:
783 DBG1(DBG_PTS, LABEL "RSA EK handle: 0x%08x", ek_handle);
784 if (!rsa_salt(public, this->hash_alg, &secret, &encryptedSalt))
785 {
786 goto error;
787 }
788 break;
789 case TPM2_ALG_ECC:
790 DBG1(DBG_PTS, LABEL "ECC %N EK handle: 0x%08x", tpm_ecc_curve_names,
791 public->publicArea.parameters.eccDetail.curveID, ek_handle);
792 if (!ecc_salt(public, this->hash_alg, &secret, &encryptedSalt))
793 {
794 goto error;
795 }
796 break;
797 default:
798 DBG1(DBG_PTS, LABEL "unsupported ek key type");
799 goto error;
800 }
801
802 sym = (TPMT_SYM_DEF*)&public->publicArea.parameters.asymDetail.symmetric;
803 DBG2(DBG_PTS, LABEL "AES-CFB with %u bits", sym->keyBits.aes);
804 this->aes_key_len = sym->keyBits.aes / 8;
805
806 rval = Tss2_Sys_StartAuthSession(this->sys_context, ek_handle, TPM2_RH_NULL,
807 NULL, &this->nonceCaller, &encryptedSalt, sessionType, sym,
808 this->hash_alg, &this->session_handle, &this->nonceTPM, NULL);
809 if (rval != TSS2_RC_SUCCESS)
810 {
811 DBG1(DBG_PTS, LABEL "Tss2_Sys_StartAuthSession failed: 0x%06x", rval);
812 goto error;
813 }
814 DBG2(DBG_PTS, LABEL "session handle: 0x%08x", this->session_handle);
815
816 nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
817 nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
818
819 /* derive sessionKey using KDFa */
820 if (!kdf_a(this->hash_alg, secret, kdf_label, nonce_tpm, nonce_caller,
821 hash_len, &this->session_key))
822 {
823 goto error;
824 }
825 chunk_clear(&secret);
826 DBG4(DBG_PTS, LABEL "session key: %B", &this->session_key);
827
828 return &this->public;
829
830 error:
831 chunk_clear(&secret);
832 destroy(this);
833 return NULL;
834 }
835
836 #endif /* TSS_TSS2_V2 */