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