tpm2_kdfe.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <errno.h>
  3. #include <stdint.h>
  4. #include <string.h>
  5. #include <openssl/bn.h>
  6. #include <openssl/ecdh.h>
  7. #include <tss2/tss2_tpm2_types.h>
  8. #include <tss2/tss2_mu.h>
  9. #include "log.h"
  10. #include "tpm2_openssl.h"
  11. #include "tpm2_alg_util.h"
  12. #include "tpm2_util.h"
  13. TSS2_RC tpm2_kdfe(
  14. TPMI_ALG_HASH hash_alg, TPM2B_ECC_PARAMETER *Z,
  15. const unsigned char *label, int label_length,
  16. TPM2B_ECC_PARAMETER *party_u, TPM2B_ECC_PARAMETER *party_v,
  17. UINT16 size_in_bits, TPM2B_MAX_BUFFER *result_key ) {
  18. TPM2B_MAX_BUFFER hash_input;
  19. TPM2B_DATA use;
  20. int bytes = ((size_in_bits + 7) / 8);
  21. int done;
  22. UINT32 counter, counter_be;
  23. UINT16 hash_size = tpm2_alg_util_get_hash_size(hash_alg);
  24. TSS2_RC rval = TPM2_RC_SUCCESS;
  25. memcpy(use.buffer, label, label_length);
  26. use.size = label_length;
  27. /*
  28. * Hash[i] := H(hash_input), where otherInfo := Use | PartyUInfo|PartyVInfo
  29. * hash_input := counter | Z | OtherInfo
  30. */
  31. hash_input.size = 4; // room for the counter
  32. tpm2_util_concat_buffer(&hash_input, (TPM2B *) Z);
  33. tpm2_util_concat_buffer(&hash_input, (TPM2B *) &use);
  34. tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_u);
  35. tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_v);
  36. digester d = tpm2_openssl_halg_to_digester(hash_alg);
  37. for (done = 0, counter = 1; done < bytes; done += hash_size, counter++) {
  38. counter_be = tpm2_util_hton_32(counter);
  39. memcpy(hash_input.buffer, &counter_be, 4);
  40. d(hash_input.buffer, hash_input.size, result_key->buffer + done);
  41. }
  42. // truncate the result to the desired size
  43. result_key->size = bytes;
  44. return rval;
  45. }
  46. static EC_POINT * tpm2_get_EC_public_key(TPM2B_PUBLIC *public) {
  47. EC_POINT *q = NULL;
  48. BIGNUM *bn_qx, *bn_qy;
  49. EC_KEY *key;
  50. const EC_GROUP *group;
  51. bool rval;
  52. TPMS_ECC_PARMS *tpm_ecc = &public->publicArea.parameters.eccDetail;
  53. TPMS_ECC_POINT *tpm_point = &public->publicArea.unique.ecc;
  54. int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
  55. if (nid < 0) {
  56. return NULL;
  57. }
  58. key = EC_KEY_new_by_curve_name(nid);
  59. if (!key) {
  60. LOG_ERR("Failed to create EC key from nid");
  61. return NULL;
  62. }
  63. bn_qx = BN_bin2bn(tpm_point->x.buffer, tpm_point->x.size, NULL);
  64. bn_qy = BN_bin2bn(tpm_point->y.buffer, tpm_point->y.size, NULL);
  65. if ((bn_qx == NULL) || (bn_qy == NULL)) {
  66. LOG_ERR("Could not convert EC public key to BN");
  67. goto out;
  68. }
  69. group = EC_KEY_get0_group(key);
  70. if (!group) {
  71. LOG_ERR("EC key missing group");
  72. goto out;
  73. }
  74. q = EC_POINT_new(group);
  75. if (q == NULL) {
  76. LOG_ERR("Could not allocate EC_POINT");
  77. goto out;
  78. }
  79. rval = EC_POINT_set_affine_coordinates_tss(group, q, bn_qx, bn_qy, NULL);
  80. if (rval == false) {
  81. LOG_ERR("Could not set affine_coordinates");
  82. EC_POINT_free(q);
  83. q = NULL;
  84. }
  85. out:
  86. if (bn_qx) {
  87. BN_free(bn_qx);
  88. }
  89. if (bn_qy) {
  90. BN_free(bn_qy);
  91. }
  92. if (key) {
  93. EC_KEY_free(key);
  94. }
  95. return q;
  96. }
  97. static bool get_public_key_from_ec_key(EC_KEY *key, TPMS_ECC_POINT *point) {
  98. BIGNUM *x = BN_new();
  99. BIGNUM *y = BN_new();
  100. const EC_POINT *pubkey = EC_KEY_get0_public_key(key);
  101. unsigned int nbx, nby;
  102. bool result = false;
  103. if ((x == NULL) || (y == NULL) || (pubkey == NULL)) {
  104. LOG_ERR("Failed to allocate memory to store EC public key.");
  105. goto out;
  106. }
  107. EC_POINT_get_affine_coordinates_tss(EC_KEY_get0_group(key),
  108. pubkey, x, y, NULL);
  109. nbx = BN_num_bytes(x);
  110. nby = BN_num_bytes(y);
  111. if ((nbx > sizeof(point->x.buffer))||
  112. (nby > sizeof(point->y.buffer))) {
  113. LOG_ERR("EC public key has too many bits.");
  114. goto out;
  115. }
  116. point->x.size = nbx;
  117. point->y.size = nby;
  118. BN_bn2bin(x, point->x.buffer);
  119. BN_bn2bin(y, point->y.buffer);
  120. result = true;
  121. out:
  122. if (x) {
  123. BN_free(x);
  124. }
  125. if (y) {
  126. BN_free(y);
  127. }
  128. return result;
  129. }
  130. static int get_ECDH_shared_secret(EC_KEY *key,
  131. const EC_POINT *p_pub, TPM2B_ECC_PARAMETER *secret) {
  132. int shared_secret_length;
  133. shared_secret_length = EC_GROUP_get_degree(EC_KEY_get0_group(key));
  134. shared_secret_length = (shared_secret_length + 7) / 8;
  135. if ((size_t) shared_secret_length > sizeof(secret->buffer)) {
  136. return -1;
  137. }
  138. secret->size = ECDH_compute_key(secret->buffer,
  139. shared_secret_length, p_pub, key, NULL);
  140. return secret->size;
  141. }
  142. bool ecdh_derive_seed_and_encrypted_seed(
  143. TPM2B_PUBLIC *parent_pub,
  144. const unsigned char *label, int label_len,
  145. TPM2B_DIGEST *seed,
  146. TPM2B_ENCRYPTED_SECRET *out_sym_seed) {
  147. TPMS_ECC_PARMS *tpm_ecc = &parent_pub->publicArea.parameters.eccDetail;
  148. TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg;
  149. UINT16 parent_hash_size = tpm2_alg_util_get_hash_size(parent_name_alg);
  150. bool result = false;
  151. EC_KEY *key = NULL;
  152. EC_POINT *qsv = NULL;
  153. TPMS_ECC_POINT qeu;
  154. bool qeu_is_valid;
  155. TPM2B_ECC_PARAMETER ecc_secret;
  156. // generate an ephemeral key
  157. int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
  158. if (nid >= 0) {
  159. key = EC_KEY_new_by_curve_name(nid);
  160. }
  161. if (key == NULL) {
  162. LOG_ERR("Failed to create EC key from curveID");
  163. return false;
  164. }
  165. EC_KEY_generate_key(key);
  166. // get public key for the ephemeral key
  167. qeu_is_valid = get_public_key_from_ec_key(key, &qeu);
  168. if (qeu_is_valid == false) {
  169. LOG_ERR("Could not get the ECC public key");
  170. goto out;
  171. }
  172. /* marshal the public key to encrypted seed */
  173. size_t offset = 0;
  174. TSS2_RC rval;
  175. rval = Tss2_MU_TPMS_ECC_POINT_Marshal(&qeu,
  176. out_sym_seed->secret, sizeof(out_sym_seed->secret), &offset);
  177. if (rval != TPM2_RC_SUCCESS) {
  178. LOG_ERR("Error serializing the ECC public key");
  179. goto out;
  180. }
  181. out_sym_seed->size = offset;
  182. /* get parents public key */
  183. qsv = tpm2_get_EC_public_key(parent_pub);
  184. if (qsv == NULL) {
  185. LOG_ERR("Could not get parent's public key");
  186. goto out;
  187. }
  188. get_ECDH_shared_secret(key, qsv, &ecc_secret);
  189. /* derive seed using KDFe */
  190. TPM2B_ECC_PARAMETER *party_u_info = &qeu.x;
  191. TPM2B_ECC_PARAMETER *party_v_info = &parent_pub->publicArea.unique.ecc.x;
  192. tpm2_kdfe(parent_name_alg, &ecc_secret, label, label_len,
  193. party_u_info, party_v_info, parent_hash_size * 8,
  194. (TPM2B_MAX_BUFFER *) seed);
  195. result = true;
  196. out:
  197. if (qsv) {
  198. EC_POINT_free(qsv);
  199. }
  200. if (key) {
  201. EC_KEY_free(key);
  202. }
  203. return result;
  204. }