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