1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, Linaro Limited 4 */ 5 6 #include <crypto/crypto.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <tee/tee_cryp_hkdf.h> 10 #include <tee/tee_cryp_utl.h> 11 #include <utee_defines.h> 12 13 14 static const uint8_t zero_salt[TEE_MAX_HASH_SIZE]; 15 16 static TEE_Result hkdf_extract(uint32_t hash_id, const uint8_t *ikm, 17 size_t ikm_len, const uint8_t *salt, 18 size_t salt_len, uint8_t *prk, size_t *prk_len) 19 { 20 TEE_Result res; 21 void *ctx = NULL; 22 uint32_t hash_algo = TEE_ALG_HASH_ALGO(hash_id); 23 uint32_t hmac_algo = (TEE_OPERATION_MAC << 28) | hash_id; 24 25 if (!salt || !salt_len) { 26 /* 27 * RFC 5869 section 2.2: 28 * If not provided, [the salt] is set to a string of HashLen 29 * zeros 30 */ 31 salt = zero_salt; 32 res = tee_alg_get_digest_size(hash_algo, &salt_len); 33 if (res != TEE_SUCCESS) 34 goto out; 35 } 36 37 res = crypto_mac_alloc_ctx(&ctx, hmac_algo); 38 if (res) 39 goto out; 40 41 /* 42 * RFC 5869 section 2.1: "Note that in the extract step, 'IKM' is used 43 * as the HMAC input, not as the HMAC key." 44 * Therefore, salt is the HMAC key in the formula from section 2.2: 45 * "PRK = HMAC-Hash(salt, IKM)" 46 */ 47 res = crypto_mac_init(ctx, salt, salt_len); 48 if (res != TEE_SUCCESS) 49 goto out; 50 51 res = crypto_mac_update(ctx, ikm, ikm_len); 52 if (res != TEE_SUCCESS) 53 goto out; 54 55 res = crypto_mac_final(ctx, prk, *prk_len); 56 if (res != TEE_SUCCESS) 57 goto out; 58 59 res = tee_alg_get_digest_size(hash_algo, prk_len); 60 out: 61 crypto_mac_free_ctx(ctx); 62 return res; 63 } 64 65 static TEE_Result hkdf_expand(uint32_t hash_id, const uint8_t *prk, 66 size_t prk_len, const uint8_t *info, 67 size_t info_len, uint8_t *okm, size_t okm_len) 68 { 69 uint8_t tn[TEE_MAX_HASH_SIZE]; 70 size_t tn_len, hash_len, i, n, where; 71 TEE_Result res = TEE_SUCCESS; 72 void *ctx = NULL; 73 uint32_t hash_algo = TEE_ALG_HASH_ALGO(hash_id); 74 uint32_t hmac_algo = TEE_ALG_HMAC_ALGO(hash_id); 75 76 res = tee_alg_get_digest_size(hash_algo, &hash_len); 77 if (res != TEE_SUCCESS) 78 goto out; 79 80 if (!okm || prk_len < hash_len) { 81 res = TEE_ERROR_BAD_STATE; 82 goto out; 83 } 84 85 if (!info) 86 info_len = 0; 87 88 res = crypto_mac_alloc_ctx(&ctx, hmac_algo); 89 if (res) 90 goto out; 91 92 /* N = ceil(L/HashLen) */ 93 n = okm_len / hash_len; 94 if ((okm_len % hash_len) != 0) 95 n++; 96 97 if (n > 255) { 98 res = TEE_ERROR_BAD_PARAMETERS; 99 goto out; 100 } 101 102 103 /* 104 * RFC 5869 section 2.3 105 * T = T(1) | T(2) | T(3) | ... | T(N) 106 * OKM = first L octets of T 107 * T(0) = empty string (zero length) 108 * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) 109 * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) 110 * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03) 111 * ... 112 */ 113 tn_len = 0; 114 where = 0; 115 for (i = 1; i <= n; i++) { 116 uint8_t c = i; 117 118 res = crypto_mac_init(ctx, prk, prk_len); 119 if (res != TEE_SUCCESS) 120 goto out; 121 res = crypto_mac_update(ctx, tn, tn_len); 122 if (res != TEE_SUCCESS) 123 goto out; 124 res = crypto_mac_update(ctx, info, info_len); 125 if (res != TEE_SUCCESS) 126 goto out; 127 res = crypto_mac_update(ctx, &c, 1); 128 if (res != TEE_SUCCESS) 129 goto out; 130 res = crypto_mac_final(ctx, tn, sizeof(tn)); 131 if (res != TEE_SUCCESS) 132 goto out; 133 134 memcpy(okm + where, tn, (i < n) ? hash_len : (okm_len - where)); 135 where += hash_len; 136 tn_len = hash_len; 137 } 138 139 out: 140 crypto_mac_free_ctx(ctx); 141 return res; 142 } 143 144 TEE_Result tee_cryp_hkdf(uint32_t hash_id, const uint8_t *ikm, size_t ikm_len, 145 const uint8_t *salt, size_t salt_len, 146 const uint8_t *info, size_t info_len, uint8_t *okm, 147 size_t okm_len) 148 { 149 TEE_Result res; 150 uint8_t prk[TEE_MAX_HASH_SIZE]; 151 size_t prk_len = sizeof(prk); 152 153 res = hkdf_extract(hash_id, ikm, ikm_len, salt, salt_len, prk, 154 &prk_len); 155 if (res != TEE_SUCCESS) 156 return res; 157 res = hkdf_expand(hash_id, prk, prk_len, info, info_len, okm, 158 okm_len); 159 160 return res; 161 } 162