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