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