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