123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <errno.h>
- #include <stdint.h>
- #include <string.h>
- #include <openssl/bn.h>
- #include <openssl/ecdh.h>
- #include <tss2/tss2_tpm2_types.h>
- #include <tss2/tss2_mu.h>
- #include "log.h"
- #include "tpm2_openssl.h"
- #include "tpm2_alg_util.h"
- #include "tpm2_util.h"
- TSS2_RC tpm2_kdfe(
- TPMI_ALG_HASH hash_alg, TPM2B_ECC_PARAMETER *Z,
- const unsigned char *label, int label_length,
- TPM2B_ECC_PARAMETER *party_u, TPM2B_ECC_PARAMETER *party_v,
- UINT16 size_in_bits, TPM2B_MAX_BUFFER *result_key ) {
- TPM2B_MAX_BUFFER hash_input;
- TPM2B_DATA use;
- int bytes = ((size_in_bits + 7) / 8);
- int done;
- UINT32 counter, counter_be;
- UINT16 hash_size = tpm2_alg_util_get_hash_size(hash_alg);
- TSS2_RC rval = TPM2_RC_SUCCESS;
- memcpy(use.buffer, label, label_length);
- use.size = label_length;
- /*
- * Hash[i] := H(hash_input), where otherInfo := Use | PartyUInfo|PartyVInfo
- * hash_input := counter | Z | OtherInfo
- */
- hash_input.size = 4; // room for the counter
- tpm2_util_concat_buffer(&hash_input, (TPM2B *) Z);
- tpm2_util_concat_buffer(&hash_input, (TPM2B *) &use);
- tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_u);
- tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_v);
- digester d = tpm2_openssl_halg_to_digester(hash_alg);
- for (done = 0, counter = 1; done < bytes; done += hash_size, counter++) {
- counter_be = tpm2_util_hton_32(counter);
- memcpy(hash_input.buffer, &counter_be, 4);
- d(hash_input.buffer, hash_input.size, result_key->buffer + done);
- }
- // truncate the result to the desired size
- result_key->size = bytes;
- return rval;
- }
- static EC_POINT * tpm2_get_EC_public_key(TPM2B_PUBLIC *public) {
- EC_POINT *q = NULL;
- BIGNUM *bn_qx, *bn_qy;
- EC_KEY *key;
- const EC_GROUP *group;
- bool rval;
- TPMS_ECC_PARMS *tpm_ecc = &public->publicArea.parameters.eccDetail;
- TPMS_ECC_POINT *tpm_point = &public->publicArea.unique.ecc;
- int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
- if (nid < 0) {
- return NULL;
- }
- key = EC_KEY_new_by_curve_name(nid);
- if (!key) {
- LOG_ERR("Failed to create EC key from nid");
- return NULL;
- }
- bn_qx = BN_bin2bn(tpm_point->x.buffer, tpm_point->x.size, NULL);
- bn_qy = BN_bin2bn(tpm_point->y.buffer, tpm_point->y.size, NULL);
- if ((bn_qx == NULL) || (bn_qy == NULL)) {
- LOG_ERR("Could not convert EC public key to BN");
- goto out;
- }
- group = EC_KEY_get0_group(key);
- if (!group) {
- LOG_ERR("EC key missing group");
- goto out;
- }
- q = EC_POINT_new(group);
- if (q == NULL) {
- LOG_ERR("Could not allocate EC_POINT");
- goto out;
- }
- rval = EC_POINT_set_affine_coordinates_tss(group, q, bn_qx, bn_qy, NULL);
- if (rval == false) {
- LOG_ERR("Could not set affine_coordinates");
- EC_POINT_free(q);
- q = NULL;
- }
- out:
- if (bn_qx) {
- BN_free(bn_qx);
- }
- if (bn_qy) {
- BN_free(bn_qy);
- }
- if (key) {
- EC_KEY_free(key);
- }
- return q;
- }
- static bool get_public_key_from_ec_key(EC_KEY *key, TPMS_ECC_POINT *point) {
- BIGNUM *x = BN_new();
- BIGNUM *y = BN_new();
- const EC_POINT *pubkey = EC_KEY_get0_public_key(key);
- unsigned int nbx, nby;
- bool result = false;
- if ((x == NULL) || (y == NULL) || (pubkey == NULL)) {
- LOG_ERR("Failed to allocate memory to store EC public key.");
- goto out;
- }
- EC_POINT_get_affine_coordinates_tss(EC_KEY_get0_group(key),
- pubkey, x, y, NULL);
- nbx = BN_num_bytes(x);
- nby = BN_num_bytes(y);
- if ((nbx > sizeof(point->x.buffer))||
- (nby > sizeof(point->y.buffer))) {
- LOG_ERR("EC public key has too many bits.");
- goto out;
- }
- point->x.size = nbx;
- point->y.size = nby;
- BN_bn2bin(x, point->x.buffer);
- BN_bn2bin(y, point->y.buffer);
- result = true;
- out:
- if (x) {
- BN_free(x);
- }
- if (y) {
- BN_free(y);
- }
- return result;
- }
- static int get_ECDH_shared_secret(EC_KEY *key,
- const EC_POINT *p_pub, TPM2B_ECC_PARAMETER *secret) {
- int shared_secret_length;
- shared_secret_length = EC_GROUP_get_degree(EC_KEY_get0_group(key));
- shared_secret_length = (shared_secret_length + 7) / 8;
- if ((size_t) shared_secret_length > sizeof(secret->buffer)) {
- return -1;
- }
- secret->size = ECDH_compute_key(secret->buffer,
- shared_secret_length, p_pub, key, NULL);
- return secret->size;
- }
- bool ecdh_derive_seed_and_encrypted_seed(
- TPM2B_PUBLIC *parent_pub,
- const unsigned char *label, int label_len,
- TPM2B_DIGEST *seed,
- TPM2B_ENCRYPTED_SECRET *out_sym_seed) {
- TPMS_ECC_PARMS *tpm_ecc = &parent_pub->publicArea.parameters.eccDetail;
- TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg;
- UINT16 parent_hash_size = tpm2_alg_util_get_hash_size(parent_name_alg);
- bool result = false;
- EC_KEY *key = NULL;
- EC_POINT *qsv = NULL;
- TPMS_ECC_POINT qeu;
- bool qeu_is_valid;
- TPM2B_ECC_PARAMETER ecc_secret;
- // generate an ephemeral key
- int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
- if (nid >= 0) {
- key = EC_KEY_new_by_curve_name(nid);
- }
- if (key == NULL) {
- LOG_ERR("Failed to create EC key from curveID");
- return false;
- }
- EC_KEY_generate_key(key);
- // get public key for the ephemeral key
- qeu_is_valid = get_public_key_from_ec_key(key, &qeu);
- if (qeu_is_valid == false) {
- LOG_ERR("Could not get the ECC public key");
- goto out;
- }
- /* marshal the public key to encrypted seed */
- size_t offset = 0;
- TSS2_RC rval;
- rval = Tss2_MU_TPMS_ECC_POINT_Marshal(&qeu,
- out_sym_seed->secret, sizeof(out_sym_seed->secret), &offset);
- if (rval != TPM2_RC_SUCCESS) {
- LOG_ERR("Error serializing the ECC public key");
- goto out;
- }
- out_sym_seed->size = offset;
- /* get parents public key */
- qsv = tpm2_get_EC_public_key(parent_pub);
- if (qsv == NULL) {
- LOG_ERR("Could not get parent's public key");
- goto out;
- }
- get_ECDH_shared_secret(key, qsv, &ecc_secret);
- /* derive seed using KDFe */
- TPM2B_ECC_PARAMETER *party_u_info = &qeu.x;
- TPM2B_ECC_PARAMETER *party_v_info = &parent_pub->publicArea.unique.ecc.x;
- tpm2_kdfe(parent_name_alg, &ecc_secret, label, label_len,
- party_u_info, party_v_info, parent_hash_size * 8,
- (TPM2B_MAX_BUFFER *) seed);
- result = true;
- out:
- if (qsv) {
- EC_POINT_free(qsv);
- }
- if (key) {
- EC_KEY_free(key);
- }
- return result;
- }
|