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