]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/IpSecDxe/IpSecCryptIo.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecCryptIo.c
... / ...
CommitLineData
1/** @file\r
2 Common interfaces to call Security library.\r
3\r
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "IpSecCryptIo.h"\r
11//\r
12// The informations for the supported Encrypt/Decrpt Alogrithm.\r
13//\r
14GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
15 {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r
16 {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},\r
17 {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},\r
18 {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}\r
19};\r
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
30//\r
31// The information for the supported Hash aglorithm\r
32//\r
33GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {\r
34 {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
35 {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
36 {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}\r
37};\r
38\r
39BOOLEAN mInitialRandomSeed = FALSE;\r
40\r
41/**\r
42 Get the block size of specified encryption algorithm.\r
43\r
44 @param[in] AlgorithmId The encryption algorithm ID.\r
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
58 return mIpsecEncryptAlgorithmList[Index].BlockSize;\r
59 }\r
60 }\r
61\r
62 return (UINTN) -1;\r
63}\r
64\r
65/**\r
66 Get the key length of the specified encryption algorithm.\r
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
90 Get the IV size of the specified encryption algorithm.\r
91\r
92 @param[in] AlgorithmId The encryption algorithm ID.\r
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
106 return mIpsecEncryptAlgorithmList[Index].IvLength;\r
107 }\r
108 }\r
109\r
110 return (UINTN) -1;\r
111}\r
112\r
113/**\r
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
141 Get the ICV size of the specified Authenticaion algorithm.\r
142\r
143 @param[in] AlgorithmId The Authentication algorithm ID.\r
144\r
145 @return The value of ICV size.\r
146\r
147**/\r
148UINTN\r
149IpSecGetIcvLength (\r
150 IN UINT8 AlgorithmId\r
151 )\r
152{\r
153 UINT8 Index;\r
154\r
155 for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
156 if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
157 return mIpsecAuthAlgorithmList[Index].IcvLength;\r
158 }\r
159 }\r
160\r
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
169 @param[in] IvSize The IV size in bytes.\r
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
181 return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r
182 }\r
183\r
184 return EFI_SUCCESS;\r
185}\r
186\r
187/**\r
188 Get index of the specified encryption algorithm from the mIpsecEncryptAlgorithmList.\r
189\r
190 @param[in] AlgorithmId The encryption algorithm ID.\r
191\r
192 @return the index.\r
193\r
194**/\r
195UINTN\r
196IpSecGetIndexFromEncList (\r
197 IN UINT8 AlgorithmId\r
198 )\r
199{\r
200 UINT8 Index;\r
201\r
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
207\r
208 return (UINTN) -1;\r
209}\r
210\r
211/**\r
212 Get index of the specified encryption algorithm from the mIpsecAuthAlgorithmList.\r
213\r
214 @param[in] AlgorithmId The encryption algorithm ID.\r
215\r
216 @return the index.\r
217\r
218**/\r
219UINTN\r
220IpSecGetIndexFromAuthList (\r
221 IN UINT8 AlgorithmId\r
222 )\r
223{\r
224 UINT8 Index;\r
225\r
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
234\r
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
242 the input algorithm ID. The InData should be multiple of block size. This function\r
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
246 @param[in] AlgorithmId The Algorithm identification defined in RFC.\r
247 @param[in] Key Pointer to the buffer containing encrypting key.\r
248 @param[in] KeyBits The length of the key in bits.\r
249 @param[in] Ivec Point to the buffer containing the Initialization\r
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
272{\r
273 UINTN Index;\r
274 UINTN ContextSize;\r
275 UINT8 *Context;\r
276 EFI_STATUS Status;\r
277\r
278 Status = EFI_UNSUPPORTED;\r
279\r
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
302 //\r
303 // Initiate Context\r
304 //\r
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
320\r
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
328 the input algorithm ID. The InData should be multiple of block size. This function\r
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
332 @param[in] AlgorithmId The Algorithm identification defined in RFC.\r
333 @param[in] Key Pointer to the buffer containing encrypting key.\r
334 @param[in] KeyBits The length of the key in bits.\r
335 @param[in] Ivec Point to the buffer containing the Initialization\r
336 Vector (IV) data.\r
337 @param[in] InData Point to the buffer containing the data to be\r
338 decrypted.\r
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
358{\r
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
371 return EFI_SUCCESS;\r
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
394 Status = EFI_SUCCESS;\r
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
405 }\r
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
414 the input algorithm ID. It computes all datas from InDataFragment and output\r
415 the result into the OutData buffer. If the OutDataSize is larger than the related\r
416 HMAC algorithm output size, return EFI_INVALID_PARAMETER.\r
417\r
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
516 }\r
517\r
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
537 the input algorithm ID. It computes all datas from InDataFragment and output\r
538 the result into the OutData buffer. If the OutDataSize is larger than the related\r
539 Hash algorithm output size, return EFI_INVALID_PARAMETER.\r
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
574\r
575 OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
576 //\r
577 // If the expected hash data size is larger than the related Hash algorithm\r
578 // output length, return EFI_INVALID_PARAMETER.\r
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
587\r
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
608\r
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
628 CopyMem (OutData, OutHashData, OutDataSize);\r
629 Status = EFI_SUCCESS;\r
630 }\r
631\r
632 goto Exit;\r
633 }\r
634\r
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
654 the prime and primelength, at end call the DhGenerateKey() to generates random\r
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
661 @param[in] Generator Value of generator.\r
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
670 @retval EFI_SUCCESS The operation performs successfully.\r
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
682 )\r
683{\r
684 EFI_STATUS Status;\r
685\r
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
704\r
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
722 @retval EFI_SUCCESS The operation performs successfully.\r
723 @retval Otherwise The operation is failed.\r
724\r
725**/\r
726EFI_STATUS\r
727IpSecCryptoIoDhComputeKey (\r
728 IN OUT UINT8 *DhContext,\r
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
747 @retval EFI_SUCCESS The operation performs successfully.\r
748 @retval EFI_INVALID_PARAMETER The DhContext is NULL.\r
749\r
750**/\r
751EFI_STATUS\r
752IpSecCryptoIoFreeDh (\r
753 IN OUT UINT8 **DhContext\r
754 )\r
755{\r
756 if (*DhContext == NULL) {\r
757 return EFI_INVALID_PARAMETER;\r
758 }\r
759\r
760 DhFree (*DhContext);\r
761 return EFI_SUCCESS;\r
762}\r
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
770 @param[in] Bytes Size of random bytes to generate.\r
771\r
772 @retval EFI_SUCCESS The operation performs successfully.\r
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
804\r
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
821\r
822 SigSize = 0;\r
823 RsaContext = NULL;\r
824\r
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
841 Signature = NULL;\r
842 if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {\r
843 Signature = AllocateZeroPool (SigSize);\r
844 } else {\r
845 return;\r
846 }\r
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
863 @param[in] CertLen The size of Certificate in bytes.\r
864 @param[in] InCa Pointer to the CA certificate\r
865 @param[in] CaLen The size of CA certificate in bytes.\r
866 @param[in] InData Pointer to octet message hash to be checked.\r
867 @param[in] InDataSize Size of the message hash in bytes.\r
868 @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verified.\r
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
873\r
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
909\r
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
961\r
962 RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);\r
963\r
964 *PublicKey = AllocateZeroPool (*PublicKeyLen);\r
965 if (*PublicKey == NULL) {\r
966 Status = EFI_OUT_OF_RESOURCES;\r
967 goto EXIT;\r
968 }\r
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
989\r
990 @retval EFI_SUCCESS Retrieved the certificate subject successfully.\r
991 @retval EFI_INVALID_PARAMETER The certificate is malformed.\r
992\r
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