1 /*
2 * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /************* Include Files ****************/
8
9 #include "cc_pal_mem.h"
10 #include "cc_common_math.h"
11 #include "mbedtls_cc_hkdf.h"
12 #include "mbedtls_cc_hkdf_error.h"
13 #include "cc_fips_defs.h"
14 #include "mbedtls/md.h"
15 #include "cc_general_defs.h"
16
17 /************************ Defines *******************************/
18
19 /************************ Enums *********************************/
20
21 /************************ macros ********************************/
22
23
24 /************************ Global Data ******************************/
25
26 /************************ Private Functions ******************************/
27
28 /**
29 * The function returns a number of attributes related to a given hkdf hash mode
30 */
GetParamsFromHKDFHashMode(mbedtls_hkdf_hashmode_t HKDFhashMode,CCHashOperationMode_t * HashMode_ptr,uint32_t * HashOutputSizeBytes_ptr,uint32_t * BlockSizeBytes_ptr,const mbedtls_md_info_t ** mdInfo)31 static CCError_t GetParamsFromHKDFHashMode(
32 mbedtls_hkdf_hashmode_t HKDFhashMode,
33 CCHashOperationMode_t* HashMode_ptr,
34 uint32_t* HashOutputSizeBytes_ptr,
35 uint32_t* BlockSizeBytes_ptr,
36 const mbedtls_md_info_t **mdInfo)
37 {
38 *BlockSizeBytes_ptr = CC_HASH_BLOCK_SIZE_IN_BYTES; /*for all modes, besides SHA512*/
39
40 switch (HKDFhashMode) {
41 case CC_HKDF_HASH_SHA1_mode:
42 *HashMode_ptr = CC_HASH_SHA1_mode;
43 *HashOutputSizeBytes_ptr = CC_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
44 break;
45 case CC_HKDF_HASH_SHA224_mode:
46 *HashMode_ptr = CC_HASH_SHA224_mode;
47 *HashOutputSizeBytes_ptr = CC_HASH_SHA224_DIGEST_SIZE_IN_BYTES;
48 break;
49 case CC_HKDF_HASH_SHA256_mode:
50 *HashMode_ptr = CC_HASH_SHA256_mode;
51 *HashOutputSizeBytes_ptr = CC_HASH_SHA256_DIGEST_SIZE_IN_BYTES;
52 break;
53 case CC_HKDF_HASH_SHA384_mode:
54 *HashMode_ptr = CC_HASH_SHA384_mode;
55 *HashOutputSizeBytes_ptr = CC_HASH_SHA384_DIGEST_SIZE_IN_BYTES;
56 *BlockSizeBytes_ptr = CC_HASH_SHA512_BLOCK_SIZE_IN_BYTES;
57 break;
58 case CC_HKDF_HASH_SHA512_mode:
59 *HashMode_ptr = CC_HASH_SHA512_mode;
60 *HashOutputSizeBytes_ptr = CC_HASH_SHA512_DIGEST_SIZE_IN_BYTES;
61 *BlockSizeBytes_ptr = CC_HASH_SHA512_BLOCK_SIZE_IN_BYTES;
62 break;
63 default:
64 *mdInfo = NULL;
65 return CC_HKDF_INVALID_ARGUMENT_HASH_MODE_ERROR;
66 }
67
68 *mdInfo = mbedtls_md_info_from_string( HashAlgMode2mbedtlsString[*HashMode_ptr] );
69 if( *mdInfo == NULL ){
70 return CC_HKDF_INVALID_ARGUMENT_HASH_MODE_ERROR;
71 }
72
73 return CC_OK;
74 }
75
76 /****************************************************************/
77 /**
78 * @brief HkdfExtract performs the extract stage of the HMAC-based key derivation, according to RFC5869.
79 Computes a pseudo random key as PRK = HMAC_HASH (key=Salt , Data=Ikm)
80 */
HkdfExtract(mbedtls_hkdf_hashmode_t HKDFhashMode,uint8_t * salt_ptr,size_t salt_len,uint8_t * ikm_ptr,uint32_t ikm_len,uint8_t * prk_ptr,uint32_t * prk_len_ptr)81 CCError_t HkdfExtract(mbedtls_hkdf_hashmode_t HKDFhashMode,
82 uint8_t* salt_ptr,
83 size_t salt_len,
84 uint8_t* ikm_ptr,
85 uint32_t ikm_len,
86 uint8_t* prk_ptr,
87 uint32_t* prk_len_ptr)
88 {
89 /* The return error identifier */
90 CCError_t Error = CC_OK;
91 /* HASH function context structure buffer and parameters */
92 CCHashOperationMode_t hashMode;
93 uint32_t HashOutputSizeBytes;
94 uint32_t BlockSizeBytes;
95
96 /*The result buffer for the Hash*/
97 CCHashResultBuf_t HmacResultBuff;
98 uint8_t SaltBuffer[CC_HKDF_MAX_HASH_KEY_SIZE_IN_BYTES]={0};
99 const mbedtls_md_info_t *mdInfo = NULL;
100
101
102 CHECK_AND_RETURN_ERR_UPON_FIPS_ERROR();
103
104 if (prk_ptr == NULL || prk_len_ptr == NULL || ikm_ptr == NULL) {
105 return CC_HKDF_INVALID_ARGUMENT_POINTER_ERROR;
106 }
107
108 Error = GetParamsFromHKDFHashMode(HKDFhashMode, &hashMode, &HashOutputSizeBytes, &BlockSizeBytes, &mdInfo);
109 if (Error != CC_OK)
110 goto End;
111
112 if (*prk_len_ptr < HashOutputSizeBytes ) {
113 return CC_HKDF_INVALID_ARGUMENT_SIZE_ERROR;
114 }
115
116 if (salt_ptr == NULL){
117 if (salt_len!=0)
118 return CC_HKDF_INVALID_ARGUMENT_SIZE_ERROR;
119 }
120
121 if (salt_len==0) {
122 salt_len = (uint16_t)HashOutputSizeBytes;
123 salt_ptr = SaltBuffer;
124 }
125
126 //check that salt len is not bigger than the macximum allowed size key
127 if ( salt_len != (uint16_t)salt_len )
128 return CC_HKDF_INVALID_ARGUMENT_SIZE_ERROR;
129
130 Error = mbedtls_md_hmac( mdInfo,
131 salt_ptr, (uint16_t)salt_len,
132 ikm_ptr, ikm_len,
133 (unsigned char*)HmacResultBuff );
134 if (Error != CC_OK){
135 goto End;
136 }
137
138
139 /* Copying HASH data into output buffer */
140 CC_PalMemCopy(prk_ptr,(uint8_t *)HmacResultBuff, HashOutputSizeBytes);
141 *prk_len_ptr = HashOutputSizeBytes;
142
143 End:
144 /* clean temp buffers */
145 CC_PalMemSetZero(&HmacResultBuff, sizeof(CCHashResultBuf_t));
146
147 return Error;
148
149 }/* END OF HkdfExtract */
150
151 /**
152 * @brief HkdfExpand performs the expand stage of the HMAC-based key derivation, according to RFC5869.
153 N = Ceil(L/HashLen)
154 T = T(1) | T(2) | T(3) . . . . . | T(N)
155 Computes the output key Material as follow OKM = first L octets of T
156 where:
157 T(0) = empty_string (zero length)
158 T(1) = HMAC_HASH ( PRK, T(0) | info |0x01 )
159 T(2) = HMAC_HASH ( PRK, T(1) | info |0x02 )
160 T(N) = HMAC_HASH ( PRK, T(N-1) | info |N ) N<=255
161 */
HkdfExpand(mbedtls_hkdf_hashmode_t HKDFhashMode,uint8_t * prk_ptr,uint32_t prk_len,uint8_t * info,uint32_t info_len,uint8_t * okm_ptr,uint32_t okm_len)162 CCError_t HkdfExpand(mbedtls_hkdf_hashmode_t HKDFhashMode,
163 uint8_t* prk_ptr,
164 uint32_t prk_len,
165 uint8_t* info,
166 uint32_t info_len,
167 uint8_t* okm_ptr,
168 uint32_t okm_len)
169 {
170 uint32_t T[CC_HKDF_MAX_HASH_DIGEST_SIZE_IN_BYTES/sizeof(uint32_t)]={0};
171 /* The return error identifier */
172 CCError_t Error = CC_OK;
173 /* HASH function context structure buffer and parameters */
174 CCHashOperationMode_t hashMode;
175 uint32_t HashOutputSizeBytes;
176 uint32_t BlockSizeBytes;
177
178 uint32_t N;
179 uint32_t i;
180 uint8_t counter;
181 uint32_t disp=0;
182 const mbedtls_md_info_t *mdInfo = NULL;
183 mbedtls_md_context_t hmacCtx;
184
185 CHECK_AND_RETURN_ERR_UPON_FIPS_ERROR();
186
187 if (info == NULL) {
188 info_len = 0;
189 }
190
191 if (prk_ptr == NULL || prk_len == 0 || okm_ptr == NULL) {
192 return CC_HKDF_INVALID_ARGUMENT_POINTER_ERROR;
193 }
194
195 Error = GetParamsFromHKDFHashMode(HKDFhashMode, &hashMode, &HashOutputSizeBytes, &BlockSizeBytes, &mdInfo);
196 if (Error != CC_OK)
197 return Error;
198
199 if (prk_len < HashOutputSizeBytes) {
200 return CC_HKDF_INVALID_ARGUMENT_SIZE_ERROR;
201 }
202
203 N = okm_len / HashOutputSizeBytes;
204 if ( N*HashOutputSizeBytes != okm_len ){
205 ++N;
206 }
207
208 if (N > 255)
209 return CC_HKDF_INVALID_ARGUMENT_SIZE_ERROR;
210
211 /* Initialize the hmac ctx */
212 mbedtls_md_init( &hmacCtx );
213 Error = mbedtls_md_setup( &hmacCtx, mdInfo, 1 );
214 if (Error != CC_OK){
215 goto End;
216 }
217
218 for (i=1; i<=N; i++) {
219 counter = (uint8_t)i;
220
221
222 Error = mbedtls_md_hmac_starts( &hmacCtx, prk_ptr, prk_len );
223 if(Error != CC_OK) {
224 goto End;
225 }
226
227 if (i != 1) {
228 Error = mbedtls_md_hmac_update( &hmacCtx, (uint8_t*)T, HashOutputSizeBytes );
229 if(Error != CC_OK) {
230 goto End;
231 }
232 }
233
234 Error = mbedtls_md_hmac_update( &hmacCtx, info, info_len );
235 if(Error != CC_OK) {
236 goto End;
237 }
238
239 Error = mbedtls_md_hmac_update( &hmacCtx, &counter, 1 );
240 if(Error != CC_OK) {
241 goto End;
242 }
243
244 Error = mbedtls_md_hmac_finish(&hmacCtx, (unsigned char*)T);
245 if(Error != CC_OK) {
246 goto End;
247 }
248
249 CC_PalMemCopy(okm_ptr+disp, T, (i!=N)?HashOutputSizeBytes:okm_len-disp);
250 disp += HashOutputSizeBytes;
251 }
252
253 mbedtls_md_free( &hmacCtx );
254 return Error;
255
256 End:
257 /* Free the md context */
258 mbedtls_md_free( &hmacCtx );
259 /* clean outbuffer when error */
260 CC_PalMemSetZero(okm_ptr, okm_len);
261
262 return Error;
263
264 }
265
266 /************************ Public Functions ******************************/
267
268 /**
269 * @brief mbedtls_hkdf_key_derivation performs the HMAC-based key derivation, according to RFC5869
270 */
mbedtls_hkdf_key_derivation(mbedtls_hkdf_hashmode_t HKDFhashMode,uint8_t * Salt_ptr,size_t SaltLen,uint8_t * Ikm_ptr,uint32_t IkmLen,uint8_t * Info,uint32_t InfoLen,uint8_t * Okm,uint32_t OkmLen,CCBool IsStrongKkey)271 CCError_t mbedtls_hkdf_key_derivation(
272 mbedtls_hkdf_hashmode_t HKDFhashMode,
273 uint8_t* Salt_ptr,
274 size_t SaltLen,
275 uint8_t* Ikm_ptr,
276 uint32_t IkmLen,
277 uint8_t* Info,
278 uint32_t InfoLen,
279 uint8_t* Okm,
280 uint32_t OkmLen,
281 CCBool IsStrongKkey
282 )
283 {
284 /* The return error identifier */
285 CCError_t Error = CC_OK;
286 uint8_t PRKBuffer[CC_HKDF_MAX_HASH_DIGEST_SIZE_IN_BYTES];
287 uint32_t PRKBuffer_Len = sizeof(PRKBuffer);
288
289 if (IsStrongKkey == CC_FALSE) {
290 Error = HkdfExtract(HKDFhashMode, Salt_ptr, SaltLen, Ikm_ptr, IkmLen,
291 PRKBuffer, &PRKBuffer_Len);
292
293 if (Error != CC_OK){
294 return Error;
295 }
296
297
298 Error = HkdfExpand(HKDFhashMode, PRKBuffer, PRKBuffer_Len, Info, InfoLen, Okm, OkmLen);
299 }
300 else { //skip extraction phase
301 Error = HkdfExpand(HKDFhashMode, Ikm_ptr, IkmLen, Info, InfoLen, Okm, OkmLen);
302 }
303
304 return Error;
305 }
306
307
308