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