]>
Commit | Line | Data |
---|---|---|
a3bcde70 | 1 | /** @file\r |
9166f840 | 2 | Common interfaces to call Security library.\r |
a3bcde70 | 3 | \r |
6b16c9e7 | 4 | Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r |
a3bcde70 HT |
5 | \r |
6 | This program and the accompanying materials\r | |
7 | are licensed and made available under the terms and conditions of the BSD License\r | |
8 | which accompanies this distribution. The full text of the license may be found at\r | |
9 | http://opensource.org/licenses/bsd-license.php.\r | |
10 | \r | |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
13 | \r | |
14 | **/\r | |
15 | \r | |
16 | #include "IpSecCryptIo.h"\r | |
17 | //\r | |
9166f840 | 18 | // The informations for the supported Encrypt/Decrpt Alogrithm.\r |
a3bcde70 | 19 | //\r |
9166f840 | 20 | GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r |
68d3f2fb | 21 | {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r |
9166f840 | 22 | {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL}, \r |
23 | {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},\r | |
24 | {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}\r | |
a3bcde70 | 25 | };\r |
9166f840 | 26 | \r |
27 | //\r | |
28 | // The informations for the supported Authentication algorithm\r | |
29 | //\r | |
30 | GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r | |
31 | {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r | |
32 | {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r | |
33 | {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}\r | |
34 | };\r | |
35 | \r | |
a3bcde70 | 36 | //\r |
9166f840 | 37 | // The information for the supported Hash aglorithm\r |
a3bcde70 | 38 | //\r |
9166f840 | 39 | GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {\r |
68d3f2fb | 40 | {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r |
41 | {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r | |
9166f840 | 42 | {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}\r |
a3bcde70 HT |
43 | };\r |
44 | \r | |
9166f840 | 45 | BOOLEAN mInitialRandomSeed = FALSE;\r |
a3bcde70 HT |
46 | \r |
47 | /**\r | |
d1c85a17 | 48 | Get the block size of specified encryption algorithm.\r |
a3bcde70 | 49 | \r |
9166f840 | 50 | @param[in] AlgorithmId The encryption algorithm ID.\r |
a3bcde70 HT |
51 | \r |
52 | @return The value of block size.\r | |
53 | \r | |
54 | **/\r | |
55 | UINTN\r | |
56 | IpSecGetEncryptBlockSize (\r | |
57 | IN UINT8 AlgorithmId\r | |
58 | )\r | |
59 | {\r | |
60 | UINT8 Index;\r | |
61 | \r | |
62 | for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r | |
63 | if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r | |
a3bcde70 HT |
64 | return mIpsecEncryptAlgorithmList[Index].BlockSize;\r |
65 | }\r | |
66 | }\r | |
67 | \r | |
68 | return (UINTN) -1;\r | |
69 | }\r | |
70 | \r | |
71 | /**\r | |
d1c85a17 | 72 | Get the key length of the specified encryption algorithm.\r |
9166f840 | 73 | \r |
74 | @param[in] AlgorithmId The encryption algorithm ID.\r | |
75 | \r | |
76 | @return The value of key length.\r | |
77 | \r | |
78 | **/\r | |
79 | UINTN\r | |
80 | IpSecGetEncryptKeyLength (\r | |
81 | IN UINT8 AlgorithmId\r | |
82 | )\r | |
83 | {\r | |
84 | UINT8 Index;\r | |
85 | \r | |
86 | for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r | |
87 | if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r | |
88 | return mIpsecEncryptAlgorithmList[Index].KeyLength;\r | |
89 | }\r | |
90 | }\r | |
91 | \r | |
92 | return (UINTN) -1;\r | |
93 | }\r | |
94 | \r | |
95 | /**\r | |
d1c85a17 | 96 | Get the IV size of the specified encryption algorithm.\r |
a3bcde70 | 97 | \r |
9166f840 | 98 | @param[in] AlgorithmId The encryption algorithm ID.\r |
a3bcde70 HT |
99 | \r |
100 | @return The value of IV size.\r | |
101 | \r | |
102 | **/\r | |
103 | UINTN\r | |
104 | IpSecGetEncryptIvLength (\r | |
105 | IN UINT8 AlgorithmId\r | |
106 | )\r | |
107 | {\r | |
108 | UINT8 Index;\r | |
109 | \r | |
110 | for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r | |
111 | if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r | |
a3bcde70 HT |
112 | return mIpsecEncryptAlgorithmList[Index].IvLength;\r |
113 | }\r | |
114 | }\r | |
115 | \r | |
116 | return (UINTN) -1;\r | |
117 | }\r | |
118 | \r | |
119 | /**\r | |
9166f840 | 120 | Get the HMAC digest length by the specified Algorithm ID.\r |
121 | \r | |
122 | @param[in] AlgorithmId The specified Alogrithm ID.\r | |
123 | \r | |
124 | @return The digest length of the specified Authentication Algorithm ID.\r | |
125 | \r | |
126 | **/\r | |
127 | UINTN\r | |
128 | IpSecGetHmacDigestLength (\r | |
129 | IN UINT8 AlgorithmId\r | |
130 | )\r | |
131 | {\r | |
132 | UINT8 Index;\r | |
133 | \r | |
134 | for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r | |
135 | if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {\r | |
136 | //\r | |
137 | // Return the Digest Length of the Algorithm.\r | |
138 | //\r | |
139 | return mIpsecAuthAlgorithmList[Index].DigestLength;\r | |
140 | }\r | |
141 | }\r | |
142 | \r | |
143 | return 0;\r | |
144 | }\r | |
145 | \r | |
146 | /**\r | |
d1c85a17 | 147 | Get the ICV size of the specified Authenticaion algorithm.\r |
a3bcde70 | 148 | \r |
9166f840 | 149 | @param[in] AlgorithmId The Authentication algorithm ID.\r |
a3bcde70 HT |
150 | \r |
151 | @return The value of ICV size.\r | |
152 | \r | |
153 | **/\r | |
154 | UINTN\r | |
155 | IpSecGetIcvLength (\r | |
9166f840 | 156 | IN UINT8 AlgorithmId\r |
a3bcde70 HT |
157 | )\r |
158 | {\r | |
159 | UINT8 Index;\r | |
9166f840 | 160 | \r |
a3bcde70 | 161 | for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r |
9166f840 | 162 | if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r |
a3bcde70 HT |
163 | return mIpsecAuthAlgorithmList[Index].IcvLength;\r |
164 | }\r | |
165 | }\r | |
9166f840 | 166 | \r |
a3bcde70 HT |
167 | return (UINTN) -1;\r |
168 | }\r | |
169 | \r | |
170 | /**\r | |
171 | Generate a random data for IV. If the IvSize is zero, not needed to create\r | |
172 | IV and return EFI_SUCCESS.\r | |
173 | \r | |
174 | @param[in] IvBuffer The pointer of the IV buffer.\r | |
9166f840 | 175 | @param[in] IvSize The IV size in bytes.\r |
a3bcde70 HT |
176 | \r |
177 | @retval EFI_SUCCESS Create a random data for IV.\r | |
178 | \r | |
179 | **/\r | |
180 | EFI_STATUS\r | |
181 | IpSecGenerateIv (\r | |
182 | IN UINT8 *IvBuffer,\r | |
183 | IN UINTN IvSize\r | |
184 | )\r | |
185 | {\r | |
186 | if (IvSize != 0) {\r | |
9166f840 | 187 | return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r |
188 | }\r | |
189 | \r | |
190 | return EFI_SUCCESS;\r | |
191 | }\r | |
192 | \r | |
193 | /**\r | |
d1c85a17 | 194 | Get index of the specified encryption algorithm from the mIpsecEncryptAlgorithmList.\r |
9166f840 | 195 | \r |
196 | @param[in] AlgorithmId The encryption algorithm ID.\r | |
197 | \r | |
198 | @return the index.\r | |
199 | \r | |
200 | **/\r | |
201 | UINTN\r | |
202 | IpSecGetIndexFromEncList (\r | |
203 | IN UINT8 AlgorithmId\r | |
204 | )\r | |
205 | {\r | |
206 | UINT8 Index;\r | |
207 | \r | |
208 | for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r | |
209 | if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r | |
210 | return Index;\r | |
211 | }\r | |
212 | }\r | |
213 | \r | |
214 | return (UINTN) -1;\r | |
215 | }\r | |
216 | \r | |
217 | /**\r | |
d1c85a17 | 218 | Get index of the specified encryption algorithm from the mIpsecAuthAlgorithmList.\r |
9166f840 | 219 | \r |
220 | @param[in] AlgorithmId The encryption algorithm ID.\r | |
221 | \r | |
222 | @return the index.\r | |
223 | \r | |
224 | **/\r | |
225 | UINTN\r | |
226 | IpSecGetIndexFromAuthList (\r | |
227 | IN UINT8 AlgorithmId\r | |
228 | )\r | |
229 | {\r | |
230 | UINT8 Index;\r | |
231 | \r | |
232 | for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r | |
233 | if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r | |
234 | //\r | |
235 | // The BlockSize is same with IvSize.\r | |
236 | //\r | |
237 | return Index;\r | |
238 | }\r | |
239 | }\r | |
240 | \r | |
241 | return (UINTN) -1;\r | |
242 | }\r | |
243 | \r | |
244 | /**\r | |
245 | Encrypt the buffer.\r | |
246 | \r | |
247 | This function calls relevant encryption interface from CryptoLib according to\r | |
d1c85a17 | 248 | the input algorithm ID. The InData should be multiple of block size. This function\r |
9166f840 | 249 | doesn't perform the padding. If it has the Ivec data, the length of it should be\r |
250 | same with the block size. The block size is different from the different algorithm.\r | |
251 | \r | |
d1c85a17 | 252 | @param[in] AlgorithmId The Algorithm identification defined in RFC.\r |
9166f840 | 253 | @param[in] Key Pointer to the buffer containing encrypting key.\r |
76389e18 | 254 | @param[in] KeyBits The length of the key in bits.\r |
d1c85a17 | 255 | @param[in] Ivec Point to the buffer containing the Initialization\r |
9166f840 | 256 | Vector (IV) data.\r |
257 | @param[in] InData Point to the buffer containing the data to be\r | |
258 | encrypted.\r | |
259 | @param[in] InDataLength The length of InData in Bytes.\r | |
260 | @param[out] OutData Point to the buffer that receives the encryption\r | |
261 | output.\r | |
262 | \r | |
263 | @retval EFI_UNSUPPORTED The input Algorithm is not supported.\r | |
264 | @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.\r | |
265 | @retval EFI_SUCCESS The operation completed successfully.\r | |
266 | \r | |
267 | **/\r | |
268 | EFI_STATUS\r | |
269 | IpSecCryptoIoEncrypt (\r | |
270 | IN CONST UINT8 AlgorithmId,\r | |
271 | IN CONST UINT8 *Key,\r | |
272 | IN CONST UINTN KeyBits,\r | |
273 | IN CONST UINT8 *Ivec, OPTIONAL\r | |
274 | IN UINT8 *InData,\r | |
275 | IN UINTN InDataLength,\r | |
276 | OUT UINT8 *OutData\r | |
277 | )\r | |
278 | { \r | |
279 | UINTN Index;\r | |
280 | UINTN ContextSize;\r | |
281 | UINT8 *Context;\r | |
282 | EFI_STATUS Status;\r | |
283 | \r | |
284 | Status = EFI_UNSUPPORTED;\r | |
285 | \r | |
286 | switch (AlgorithmId) {\r | |
287 | \r | |
288 | case IKE_EALG_NULL:\r | |
289 | case IKE_EALG_NONE:\r | |
290 | CopyMem (OutData, InData, InDataLength);\r | |
291 | return EFI_SUCCESS;\r | |
292 | \r | |
293 | case IKE_EALG_3DESCBC:\r | |
294 | case IKE_EALG_AESCBC:\r | |
295 | Index = IpSecGetIndexFromEncList (AlgorithmId);\r | |
296 | if (Index == -1) {\r | |
297 | return Status;\r | |
298 | }\r | |
299 | //\r | |
300 | // Get Context Size\r | |
301 | //\r | |
302 | ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();\r | |
303 | Context = AllocateZeroPool (ContextSize);\r | |
304 | \r | |
305 | if (Context == NULL) {\r | |
306 | return EFI_OUT_OF_RESOURCES;\r | |
307 | }\r | |
a3bcde70 | 308 | //\r |
9166f840 | 309 | // Initiate Context\r |
a3bcde70 | 310 | //\r |
9166f840 | 311 | if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r |
312 | if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {\r | |
313 | Status = EFI_SUCCESS;\r | |
314 | }\r | |
315 | }\r | |
316 | break;\r | |
317 | \r | |
318 | default:\r | |
319 | return Status;\r | |
320 | \r | |
321 | }\r | |
322 | \r | |
323 | if (Context != NULL) {\r | |
324 | FreePool (Context);\r | |
325 | }\r | |
326 | \r | |
327 | return Status;\r | |
328 | }\r | |
329 | \r | |
330 | /**\r | |
331 | Decrypts the buffer.\r | |
332 | \r | |
333 | This function calls relevant Decryption interface from CryptoLib according to\r | |
d1c85a17 | 334 | the input algorithm ID. The InData should be multiple of block size. This function\r |
9166f840 | 335 | doesn't perform the padding. If it has the Ivec data, the length of it should be\r |
336 | same with the block size. The block size is different from the different algorithm.\r | |
337 | \r | |
d1c85a17 | 338 | @param[in] AlgorithmId The Algorithm identification defined in RFC.\r |
9166f840 | 339 | @param[in] Key Pointer to the buffer containing encrypting key.\r |
76389e18 | 340 | @param[in] KeyBits The length of the key in bits.\r |
d1c85a17 | 341 | @param[in] Ivec Point to the buffer containing the Initialization\r |
9166f840 | 342 | Vector (IV) data.\r |
343 | @param[in] InData Point to the buffer containing the data to be\r | |
76389e18 | 344 | decrypted.\r |
9166f840 | 345 | @param[in] InDataLength The length of InData in Bytes.\r |
346 | @param[out] OutData Pointer to the buffer that receives the decryption\r | |
347 | output.\r | |
348 | \r | |
349 | @retval EFI_UNSUPPORTED The input Algorithm is not supported.\r | |
350 | @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.\r | |
351 | @retval EFI_SUCCESS The operation completed successfully.\r | |
352 | \r | |
353 | **/\r | |
354 | EFI_STATUS\r | |
355 | IpSecCryptoIoDecrypt (\r | |
356 | IN CONST UINT8 AlgorithmId,\r | |
357 | IN CONST UINT8 *Key,\r | |
358 | IN CONST UINTN KeyBits,\r | |
359 | IN CONST UINT8 *Ivec, OPTIONAL\r | |
360 | IN UINT8 *InData,\r | |
361 | IN UINTN InDataLength,\r | |
362 | OUT UINT8 *OutData\r | |
363 | )\r | |
364 | { \r | |
365 | UINTN Index;\r | |
366 | UINTN ContextSize;\r | |
367 | UINT8 *Context;\r | |
368 | EFI_STATUS Status;\r | |
369 | \r | |
370 | Status = EFI_UNSUPPORTED;\r | |
371 | \r | |
372 | switch (AlgorithmId) {\r | |
373 | \r | |
374 | case IKE_EALG_NULL:\r | |
375 | case IKE_EALG_NONE:\r | |
376 | CopyMem (OutData, InData, InDataLength);\r | |
a3bcde70 | 377 | return EFI_SUCCESS;\r |
9166f840 | 378 | \r |
379 | case IKE_EALG_3DESCBC:\r | |
380 | case IKE_EALG_AESCBC:\r | |
381 | Index = IpSecGetIndexFromEncList(AlgorithmId);\r | |
382 | if (Index == -1) {\r | |
383 | return Status;\r | |
384 | }\r | |
385 | \r | |
386 | //\r | |
387 | // Get Context Size\r | |
388 | //\r | |
389 | ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();\r | |
390 | Context = AllocateZeroPool (ContextSize);\r | |
391 | if (Context == NULL) {\r | |
392 | return EFI_OUT_OF_RESOURCES;\r | |
393 | }\r | |
394 | \r | |
395 | //\r | |
396 | // Initiate Context\r | |
397 | //\r | |
398 | if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r | |
399 | if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {\r | |
400 | Status = EFI_SUCCESS; \r | |
401 | }\r | |
402 | }\r | |
403 | break;\r | |
404 | \r | |
405 | default:\r | |
406 | return Status;\r | |
407 | }\r | |
408 | \r | |
409 | if (Context != NULL) {\r | |
410 | FreePool (Context);\r | |
a3bcde70 | 411 | }\r |
9166f840 | 412 | \r |
413 | return Status;\r | |
414 | }\r | |
415 | \r | |
416 | /**\r | |
417 | Digests the Payload with key and store the result into the OutData.\r | |
418 | \r | |
419 | This function calls relevant Hmac interface from CryptoLib according to\r | |
d1c85a17 | 420 | the input algorithm ID. It computes all datas from InDataFragment and output\r |
9166f840 | 421 | the result into the OutData buffer. If the OutDataSize is larger than the related\r |
d1c85a17 | 422 | HMAC algorithm output size, return EFI_INVALID_PARAMETER.\r |
9166f840 | 423 | \r |
424 | @param[in] AlgorithmId The authentication Identification.\r | |
425 | @param[in] Key Pointer of the authentication key.\r | |
426 | @param[in] KeyLength The length of the Key in bytes.\r | |
427 | @param[in] InDataFragment The list contains all data to be authenticated.\r | |
428 | @param[in] FragmentCount The size of the InDataFragment.\r | |
429 | @param[out] OutData For in, the buffer to receive the output data.\r | |
430 | For out, the buffer contains the authenticated data.\r | |
431 | @param[in] OutDataSize The size of the buffer of OutData.\r | |
432 | \r | |
433 | @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.\r | |
434 | @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.\r | |
435 | @retval EFI_SUCCESS Authenticate the payload successfully.\r | |
436 | @retval otherwise Authentication of the payload fails.\r | |
437 | \r | |
438 | **/\r | |
439 | EFI_STATUS\r | |
440 | IpSecCryptoIoHmac (\r | |
441 | IN CONST UINT8 AlgorithmId,\r | |
442 | IN CONST UINT8 *Key,\r | |
443 | IN UINTN KeyLength,\r | |
444 | IN HASH_DATA_FRAGMENT *InDataFragment,\r | |
445 | IN UINTN FragmentCount,\r | |
446 | OUT UINT8 *OutData,\r | |
447 | IN UINTN OutDataSize\r | |
448 | )\r | |
449 | {\r | |
450 | UINTN ContextSize;\r | |
451 | UINTN Index;\r | |
452 | UINT8 FragmentIndex;\r | |
453 | UINT8 *HashContext;\r | |
454 | EFI_STATUS Status;\r | |
455 | UINT8 *OutHashData;\r | |
456 | UINTN OutHashSize;\r | |
457 | \r | |
458 | Status = EFI_UNSUPPORTED;\r | |
459 | OutHashData = NULL;\r | |
460 | \r | |
461 | OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r | |
462 | //\r | |
463 | // If the expected hash data size is larger than the related Hash algorithm\r | |
464 | // output length, return EFI_INVALID_PARAMETER.\r | |
465 | //\r | |
466 | if (OutDataSize > OutHashSize) {\r | |
467 | return EFI_INVALID_PARAMETER;\r | |
468 | }\r | |
469 | OutHashData = AllocatePool (OutHashSize);\r | |
470 | \r | |
471 | if (OutHashData == NULL) {\r | |
472 | return EFI_OUT_OF_RESOURCES;\r | |
473 | }\r | |
474 | \r | |
475 | switch (AlgorithmId) {\r | |
476 | \r | |
477 | case IKE_AALG_NONE :\r | |
478 | case IKE_AALG_NULL :\r | |
479 | return EFI_SUCCESS;\r | |
480 | \r | |
481 | case IKE_AALG_SHA1HMAC:\r | |
482 | Index = IpSecGetIndexFromAuthList (AlgorithmId);\r | |
483 | if (Index == -1) {\r | |
484 | return Status;\r | |
485 | }\r | |
486 | \r | |
487 | //\r | |
488 | // Get Context Size\r | |
489 | //\r | |
490 | ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();\r | |
491 | HashContext = AllocateZeroPool (ContextSize);\r | |
492 | \r | |
493 | if (HashContext == NULL) {\r | |
494 | Status = EFI_OUT_OF_RESOURCES;\r | |
495 | goto Exit;\r | |
496 | }\r | |
497 | \r | |
498 | //\r | |
499 | // Initiate HMAC context and hash the input data.\r | |
500 | //\r | |
501 | if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {\r | |
502 | for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r | |
503 | if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (\r | |
504 | HashContext,\r | |
505 | InDataFragment[FragmentIndex].Data,\r | |
506 | InDataFragment[FragmentIndex].DataSize\r | |
507 | )\r | |
508 | ) {\r | |
509 | goto Exit;\r | |
510 | }\r | |
511 | }\r | |
512 | if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {\r | |
513 | //\r | |
514 | // In some cases, like the Icv computing, the Icv size might be less than\r | |
515 | // the key length size, so copy the part of hash data to the OutData.\r | |
516 | //\r | |
517 | CopyMem (OutData, OutHashData, OutDataSize);\r | |
518 | Status = EFI_SUCCESS;\r | |
519 | }\r | |
520 | \r | |
521 | goto Exit;\r | |
522 | } \r | |
523 | \r | |
524 | default:\r | |
525 | return Status;\r | |
526 | }\r | |
527 | \r | |
528 | Exit:\r | |
529 | if (HashContext != NULL) {\r | |
530 | FreePool (HashContext);\r | |
531 | }\r | |
532 | if (OutHashData != NULL) {\r | |
533 | FreePool (OutHashData);\r | |
534 | }\r | |
535 | \r | |
536 | return Status;\r | |
537 | }\r | |
538 | \r | |
539 | /**\r | |
540 | Digests the Payload and store the result into the OutData.\r | |
541 | \r | |
542 | This function calls relevant Hash interface from CryptoLib according to\r | |
d1c85a17 | 543 | the input algorithm ID. It computes all datas from InDataFragment and output\r |
9166f840 | 544 | the result into the OutData buffer. If the OutDataSize is larger than the related\r |
d1c85a17 | 545 | Hash algorithm output size, return EFI_INVALID_PARAMETER.\r |
9166f840 | 546 | \r |
547 | @param[in] AlgorithmId The authentication Identification.\r | |
548 | @param[in] InDataFragment A list contains all data to be authenticated.\r | |
549 | @param[in] FragmentCount The size of the InDataFragment.\r | |
550 | @param[out] OutData For in, the buffer to receive the output data.\r | |
551 | For out, the buffer contains the authenticated data.\r | |
552 | @param[in] OutDataSize The size of the buffer of OutData.\r | |
553 | \r | |
554 | @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.\r | |
555 | @retval EFI_SUCCESS Authenticated the payload successfully.\r | |
556 | @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash\r | |
557 | algorithm could handle.\r | |
558 | @retval otherwise Authentication of the payload failed.\r | |
559 | \r | |
560 | **/\r | |
561 | EFI_STATUS\r | |
562 | IpSecCryptoIoHash (\r | |
563 | IN CONST UINT8 AlgorithmId,\r | |
564 | IN HASH_DATA_FRAGMENT *InDataFragment,\r | |
565 | IN UINTN FragmentCount,\r | |
566 | OUT UINT8 *OutData,\r | |
567 | IN UINTN OutDataSize\r | |
568 | )\r | |
569 | {\r | |
570 | UINTN ContextSize;\r | |
571 | UINTN Index;\r | |
572 | UINT8 FragmentIndex;\r | |
573 | UINT8 *HashContext;\r | |
574 | EFI_STATUS Status;\r | |
575 | UINT8 *OutHashData;\r | |
576 | UINTN OutHashSize;\r | |
577 | \r | |
578 | Status = EFI_UNSUPPORTED;\r | |
579 | OutHashData = NULL;\r | |
580 | \r | |
581 | OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r | |
582 | //\r | |
583 | // If the expected hash data size is larger than the related Hash algorithm\r | |
584 | // output length, return EFI_INVALID_PARAMETER. \r | |
585 | //\r | |
586 | if (OutDataSize > OutHashSize) {\r | |
587 | return EFI_INVALID_PARAMETER;\r | |
588 | }\r | |
589 | OutHashData = AllocatePool (OutHashSize);\r | |
590 | if (OutHashData == NULL) {\r | |
591 | return EFI_OUT_OF_RESOURCES;\r | |
592 | }\r | |
593 | \r | |
594 | switch (AlgorithmId) {\r | |
595 | \r | |
596 | case IKE_AALG_NONE:\r | |
597 | case IKE_AALG_NULL:\r | |
598 | return EFI_SUCCESS;\r | |
599 | \r | |
600 | case IKE_AALG_SHA1HMAC:\r | |
601 | Index = IpSecGetIndexFromAuthList (AlgorithmId);\r | |
602 | if (Index == -1) {\r | |
603 | return Status;\r | |
604 | }\r | |
605 | //\r | |
606 | // Get Context Size\r | |
607 | //\r | |
608 | ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();\r | |
609 | HashContext = AllocateZeroPool (ContextSize);\r | |
610 | if (HashContext == NULL) {\r | |
611 | Status = EFI_OUT_OF_RESOURCES;\r | |
612 | goto Exit;\r | |
613 | }\r | |
614 | \r | |
615 | //\r | |
616 | // Initiate Hash context and hash the input data.\r | |
617 | //\r | |
618 | if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {\r | |
619 | for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r | |
620 | if (!mIpsecHashAlgorithmList[Index].HashUpdate (\r | |
621 | HashContext,\r | |
622 | InDataFragment[FragmentIndex].Data,\r | |
623 | InDataFragment[FragmentIndex].DataSize\r | |
624 | )\r | |
625 | ) {\r | |
626 | goto Exit;\r | |
627 | }\r | |
628 | }\r | |
629 | if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {\r | |
630 | //\r | |
631 | // In some cases, like the Icv computing, the Icv size might be less than\r | |
632 | // the key length size, so copy the part of hash data to the OutData.\r | |
633 | //\r | |
634 | CopyMem (OutData, OutHashData, OutDataSize); \r | |
635 | Status = EFI_SUCCESS;\r | |
636 | }\r | |
637 | \r | |
638 | goto Exit; \r | |
639 | } \r | |
640 | \r | |
641 | default:\r | |
642 | return Status;\r | |
643 | }\r | |
644 | \r | |
645 | Exit:\r | |
646 | if (HashContext != NULL) {\r | |
647 | FreePool (HashContext);\r | |
648 | }\r | |
649 | if (OutHashData != NULL) {\r | |
650 | FreePool (OutHashData);\r | |
651 | }\r | |
652 | \r | |
653 | return Status;\r | |
654 | }\r | |
655 | \r | |
656 | /**\r | |
657 | Generates the Diffie-Hellman public key.\r | |
658 | \r | |
659 | This function first initiate a DHContext, then call the DhSetParameter() to set\r | |
d1c85a17 | 660 | the prime and primelength, at end call the DhGenerateKey() to generates random\r |
9166f840 | 661 | secret exponent, and computes the public key. The output returned via parameter\r |
662 | PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey\r | |
663 | buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned\r | |
664 | and PublicKeySize is set to the required buffer size to obtain the public key.\r | |
665 | \r | |
666 | @param[in, out] DhContext Pointer to the DH context.\r | |
d1c85a17 | 667 | @param[in] Generator Value of generator.\r |
9166f840 | 668 | @param[in] PrimeLength Length in bits of prime to be generated.\r |
669 | @param[in] Prime Pointer to the buffer to receive the generated\r | |
670 | prime number.\r | |
671 | @param[out] PublicKey Pointer to the buffer to receive generated public key.\r | |
672 | @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes.\r | |
673 | For out, the size of data returned in PublicKey\r | |
674 | buffer in bytes.\r | |
675 | \r | |
d1c85a17 | 676 | @retval EFI_SUCCESS The operation performs successfully.\r |
9166f840 | 677 | @retval Otherwise The operation is failed.\r |
678 | \r | |
679 | **/\r | |
680 | EFI_STATUS\r | |
681 | IpSecCryptoIoDhGetPublicKey (\r | |
682 | IN OUT UINT8 **DhContext,\r | |
683 | IN UINTN Generator,\r | |
684 | IN UINTN PrimeLength,\r | |
685 | IN CONST UINT8 *Prime,\r | |
686 | OUT UINT8 *PublicKey,\r | |
687 | IN OUT UINTN *PublicKeySize\r | |
688 | ) \r | |
689 | {\r | |
690 | EFI_STATUS Status;\r | |
691 | \r | |
692 | *DhContext = DhNew ();\r | |
693 | ASSERT (*DhContext != NULL);\r | |
694 | if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {\r | |
695 | Status = EFI_INVALID_PARAMETER;\r | |
696 | goto Exit;\r | |
697 | }\r | |
698 | \r | |
699 | if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {\r | |
700 | Status = EFI_INVALID_PARAMETER;\r | |
701 | goto Exit;\r | |
702 | }\r | |
703 | return EFI_SUCCESS;\r | |
704 | \r | |
705 | Exit:\r | |
706 | if (*DhContext != NULL) {\r | |
707 | DhFree (*DhContext);\r | |
708 | DhContext = NULL;\r | |
709 | }\r | |
710 | \r | |
711 | return Status;\r | |
712 | }\r | |
713 | \r | |
714 | /**\r | |
715 | Generates exchanged common key.\r | |
716 | \r | |
717 | Given peer's public key, this function computes the exchanged common key, based\r | |
718 | on its own context including value of prime modulus and random secret exponent.\r | |
719 | \r | |
720 | @param[in, out] DhContext Pointer to the DH context.\r | |
721 | @param[in] PeerPublicKey Pointer to the peer's Public Key.\r | |
722 | @param[in] PeerPublicKeySize Size of peer's public key in bytes.\r | |
723 | @param[out] Key Pointer to the buffer to receive generated key.\r | |
724 | @param[in, out] KeySize For in, the size of Key buffer in bytes.\r | |
725 | For out, the size of data returned in Key\r | |
726 | buffer in bytes.\r | |
727 | \r | |
d1c85a17 | 728 | @retval EFI_SUCCESS The operation performs successfully.\r |
9166f840 | 729 | @retval Otherwise The operation is failed.\r |
730 | \r | |
731 | **/\r | |
732 | EFI_STATUS\r | |
733 | IpSecCryptoIoDhComputeKey (\r | |
734 | IN OUT UINT8 *DhContext, \r | |
735 | IN CONST UINT8 *PeerPublicKey,\r | |
736 | IN UINTN PeerPublicKeySize,\r | |
737 | OUT UINT8 *Key,\r | |
738 | IN OUT UINTN *KeySize\r | |
739 | )\r | |
740 | {\r | |
741 | if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {\r | |
742 | return EFI_INVALID_PARAMETER;\r | |
743 | }\r | |
744 | \r | |
745 | return EFI_SUCCESS;\r | |
746 | }\r | |
747 | \r | |
748 | /**\r | |
749 | Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.\r | |
750 | \r | |
751 | @param[in, out] DhContext Pointer to the DH context to be freed.\r | |
752 | \r | |
d1c85a17 | 753 | @retval EFI_SUCCESS The operation performs successfully.\r |
9166f840 | 754 | @retval EFI_INVALID_PARAMETER The DhContext is NULL.\r |
755 | \r | |
756 | **/\r | |
757 | EFI_STATUS\r | |
758 | IpSecCryptoIoFreeDh (\r | |
759 | IN OUT UINT8 **DhContext\r | |
760 | )\r | |
761 | { \r | |
762 | if (*DhContext == NULL) {\r | |
763 | return EFI_INVALID_PARAMETER;\r | |
764 | }\r | |
765 | \r | |
766 | DhFree (*DhContext);\r | |
a3bcde70 HT |
767 | return EFI_SUCCESS;\r |
768 | }\r | |
9166f840 | 769 | \r |
770 | /**\r | |
771 | Generates random numbers of specified size.\r | |
772 | \r | |
773 | If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.\r | |
774 | \r | |
775 | @param[out] OutBuffer Pointer to buffer to receive random value.\r | |
d1c85a17 | 776 | @param[in] Bytes Size of random bytes to generate.\r |
9166f840 | 777 | \r |
d1c85a17 | 778 | @retval EFI_SUCCESS The operation performs successfully.\r |
9166f840 | 779 | @retval Otherwise The operation is failed.\r |
780 | \r | |
781 | **/\r | |
782 | EFI_STATUS\r | |
783 | IpSecCryptoIoGenerateRandomBytes (\r | |
784 | OUT UINT8* OutBuffer,\r | |
785 | IN UINTN Bytes\r | |
786 | )\r | |
787 | {\r | |
788 | if (!mInitialRandomSeed) {\r | |
789 | RandomSeed (NULL, 0);\r | |
790 | mInitialRandomSeed = TRUE;\r | |
791 | }\r | |
792 | if (RandomBytes (OutBuffer, Bytes)) {\r | |
793 | return EFI_SUCCESS;\r | |
794 | } else {\r | |
795 | return EFI_INVALID_PARAMETER;\r | |
796 | }\r | |
797 | }\r | |
798 | \r | |
799 | /**\r | |
800 | Authenticate data with the certificate.\r | |
801 | \r | |
802 | @param[in] InData Pointer to the Data to be signed.\r | |
803 | @param[in] InDataSize InData size in bytes.\r | |
804 | @param[in] PrivateKey Pointer to the private key.\r | |
805 | @param[in] PrivateKeySize The size of Private Key in bytes.\r | |
806 | @param[in] KeyPassWord Pointer to the password for retrieving private key.\r | |
807 | @param[in] KeyPwdSize The size of Key Password in bytes.\r | |
808 | @param[out] OutData The pointer to the signed data.\r | |
809 | @param[in, out] OutDataSize Pointer to contain the size of out data.\r | |
810 | \r | |
811 | **/\r | |
812 | VOID\r | |
813 | IpSecCryptoIoAuthDataWithCertificate (\r | |
814 | IN UINT8 *InData,\r | |
815 | IN UINTN InDataSize,\r | |
816 | IN UINT8 *PrivateKey,\r | |
817 | IN UINTN PrivateKeySize,\r | |
818 | IN UINT8 *KeyPassWord,\r | |
819 | IN UINTN KeyPwdSize,\r | |
820 | OUT UINT8 **OutData,\r | |
821 | IN OUT UINTN *OutDataSize\r | |
822 | )\r | |
823 | {\r | |
824 | UINT8 *RsaContext;\r | |
825 | UINT8 *Signature;\r | |
826 | UINTN SigSize;\r | |
827 | \r | |
828 | SigSize = 0;\r | |
94866d40 ED |
829 | RsaContext = NULL;\r |
830 | \r | |
9166f840 | 831 | //\r |
832 | // Retrieve RSA Private Key from password-protected PEM data\r | |
833 | //\r | |
834 | RsaGetPrivateKeyFromPem (\r | |
835 | (CONST UINT8 *)PrivateKey,\r | |
836 | PrivateKeySize,\r | |
837 | (CONST CHAR8 *)KeyPassWord,\r | |
838 | (VOID **) &RsaContext\r | |
839 | );\r | |
840 | if (RsaContext == NULL) {\r | |
841 | return;\r | |
842 | }\r | |
843 | \r | |
844 | //\r | |
845 | // Sign data\r | |
846 | //\r | |
847 | Signature = NULL; \r | |
848 | if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {\r | |
849 | Signature = AllocateZeroPool (SigSize);\r | |
850 | } else {\r | |
851 | return;\r | |
852 | } \r | |
853 | \r | |
854 | RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);\r | |
855 | \r | |
856 | *OutData = Signature;\r | |
857 | *OutDataSize = SigSize;\r | |
858 | \r | |
859 | if (RsaContext != NULL) {\r | |
860 | RsaFree (RsaContext);\r | |
861 | }\r | |
862 | }\r | |
863 | \r | |
864 | /**\r | |
865 | Verify the singed data with the public key which is contained in a certificate.\r | |
866 | \r | |
867 | @param[in] InCert Pointer to the Certificate which contains the\r | |
868 | public key.\r | |
76389e18 | 869 | @param[in] CertLen The size of Certificate in bytes.\r |
9166f840 | 870 | @param[in] InCa Pointer to the CA certificate\r |
871 | @param[in] CaLen The size of CA certificate in bytes.\r | |
d1c85a17 | 872 | @param[in] InData Pointer to octet message hash to be checked.\r |
9166f840 | 873 | @param[in] InDataSize Size of the message hash in bytes.\r |
d1c85a17 | 874 | @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verified.\r |
9166f840 | 875 | @param[in] SigSize Size of signature in bytes.\r |
876 | \r | |
877 | @retval TRUE Valid signature encoded in PKCS1-v1_5.\r | |
878 | @retval FALSE Invalid signature or invalid RSA context.\r | |
879 | \r | |
880 | **/\r | |
881 | BOOLEAN\r | |
882 | IpSecCryptoIoVerifySignDataByCertificate (\r | |
883 | IN UINT8 *InCert,\r | |
884 | IN UINTN CertLen,\r | |
885 | IN UINT8 *InCa,\r | |
886 | IN UINTN CaLen,\r | |
887 | IN UINT8 *InData,\r | |
888 | IN UINTN InDataSize,\r | |
889 | IN UINT8 *Singnature,\r | |
890 | IN UINTN SigSize\r | |
891 | )\r | |
892 | {\r | |
893 | UINT8 *RsaContext;\r | |
894 | BOOLEAN Status;\r | |
895 | \r | |
896 | //\r | |
897 | // Create the RSA Context\r | |
898 | //\r | |
899 | RsaContext = RsaNew ();\r | |
900 | if (RsaContext == NULL) {\r | |
901 | return FALSE;\r | |
902 | }\r | |
903 | \r | |
904 | //\r | |
905 | // Verify the validity of X509 Certificate\r | |
906 | //\r | |
907 | if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {\r | |
908 | return FALSE;\r | |
909 | }\r | |
910 | \r | |
911 | //\r | |
912 | // Retrieve the RSA public Key from Certificate\r | |
913 | //\r | |
914 | RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);\r | |
915 | \r | |
916 | //\r | |
917 | // Verify data\r | |
918 | //\r | |
919 | Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);\r | |
920 | \r | |
921 | if (RsaContext != NULL) {\r | |
922 | RsaFree (RsaContext);\r | |
923 | }\r | |
924 | \r | |
925 | return Status;\r | |
926 | }\r | |
927 | \r | |
928 | /**\r | |
929 | Retrieves the RSA Public Key from one X509 certificate (DER format only).\r | |
930 | \r | |
931 | @param[in] InCert Pointer to the certificate.\r | |
932 | @param[in] CertLen The size of the certificate in bytes.\r | |
933 | @param[out] PublicKey Pointer to the retrieved public key.\r | |
934 | @param[out] PublicKeyLen Size of Public Key in bytes.\r | |
935 | \r | |
936 | @retval EFI_SUCCESS Successfully get the public Key.\r | |
937 | @retval EFI_INVALID_PARAMETER The certificate is malformed.\r | |
938 | \r | |
939 | **/\r | |
940 | EFI_STATUS\r | |
941 | IpSecCryptoIoGetPublicKeyFromCert (\r | |
942 | IN UINT8 *InCert,\r | |
943 | IN UINTN CertLen,\r | |
944 | OUT UINT8 **PublicKey,\r | |
945 | OUT UINTN *PublicKeyLen\r | |
946 | )\r | |
947 | {\r | |
948 | UINT8 *RsaContext;\r | |
949 | EFI_STATUS Status;\r | |
950 | \r | |
951 | Status = EFI_SUCCESS;\r | |
952 | \r | |
953 | //\r | |
954 | // Create the RSA Context\r | |
955 | //\r | |
956 | RsaContext = RsaNew ();\r | |
957 | \r | |
958 | //\r | |
959 | // Retrieve the RSA public key from CA Certificate\r | |
960 | //\r | |
961 | if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {\r | |
962 | Status = EFI_INVALID_PARAMETER;\r | |
963 | goto EXIT;\r | |
964 | }\r | |
965 | \r | |
966 | *PublicKeyLen = 0;\r | |
967 | \r | |
968 | RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);\r | |
969 | \r | |
970 | *PublicKey = AllocateZeroPool (*PublicKeyLen);\r | |
6b16c9e7 JW |
971 | if (*PublicKey == NULL) {\r |
972 | Status = EFI_OUT_OF_RESOURCES;\r | |
973 | goto EXIT;\r | |
974 | }\r | |
9166f840 | 975 | \r |
976 | if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {\r | |
977 | Status = EFI_INVALID_PARAMETER;\r | |
978 | }\r | |
979 | \r | |
980 | EXIT:\r | |
981 | if (RsaContext != NULL) {\r | |
982 | RsaFree (RsaContext);\r | |
983 | }\r | |
984 | \r | |
985 | return Status;\r | |
986 | }\r | |
987 | \r | |
988 | /**\r | |
989 | Retrieves the subject name from one X509 certificate (DER format only).\r | |
990 | \r | |
991 | @param[in] InCert Pointer to the X509 certificate.\r | |
992 | @param[in] CertSize The size of the X509 certificate in bytes.\r | |
993 | @param[out] CertSubject Pointer to the retrieved certificate subject.\r | |
994 | @param[out] SubjectSize The size of Certificate Subject in bytes.\r | |
995 | \r | |
996 | @retval EFI_SUCCESS Retrieved the certificate subject successfully.\r | |
997 | @retval EFI_INVALID_PARAMETER The certificate is malformed.\r | |
998 | \r | |
999 | **/\r | |
1000 | EFI_STATUS\r | |
1001 | IpSecCryptoIoGetSubjectFromCert (\r | |
1002 | IN UINT8 *InCert,\r | |
1003 | IN UINTN CertSize,\r | |
1004 | OUT UINT8 **CertSubject,\r | |
1005 | OUT UINTN *SubjectSize\r | |
1006 | )\r | |
1007 | {\r | |
1008 | EFI_STATUS Status;\r | |
1009 | \r | |
1010 | Status = EFI_SUCCESS;\r | |
1011 | \r | |
1012 | *SubjectSize = 0;\r | |
1013 | X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);\r | |
1014 | \r | |
1015 | *CertSubject = AllocateZeroPool (*SubjectSize);\r | |
1016 | if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {\r | |
1017 | Status = EFI_INVALID_PARAMETER;\r | |
1018 | }\r | |
1019 | \r | |
1020 | return Status;\r | |
1021 | }\r |