Home | History | Annotate | Download | only in IpSecDxe
      1 /** @file
      2   Common interfaces to call Security library.
      3 
      4   Copyright (c) 2009 - 2016, 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 algorithm.
     49 
     50   @param[in]  AlgorithmId          The encryption algorithm ID.
     51 
     52   @return The value of block size.
     53 
     54 **/
     55 UINTN
     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 algorithm.
     73 
     74   @param[in]  AlgorithmId          The encryption algorithm ID.
     75 
     76   @return The value of key length.
     77 
     78 **/
     79 UINTN
     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 algorithm.
     97 
     98   @param[in]  AlgorithmId          The encryption algorithm ID.
     99 
    100   @return The value of IV size.
    101 
    102 **/
    103 UINTN
    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
    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 algorithm.
    148 
    149   @param[in]  AlgorithmId          The Authentication algorithm ID.
    150 
    151   @return The value of ICV size.
    152 
    153 **/
    154 UINTN
    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
    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 algorithm from the mIpsecEncryptAlgorithmList.
    195 
    196   @param[in]  AlgorithmId          The encryption algorithm ID.
    197 
    198   @return the index.
    199 
    200 **/
    201 UINTN
    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 algorithm from the mIpsecAuthAlgorithmList.
    219 
    220   @param[in]  AlgorithmId          The encryption algorithm ID.
    221 
    222   @return the index.
    223 
    224 **/
    225 UINTN
    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 algorithm 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 Algorithm 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 containing the Initialization
    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
    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 algorithm 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 Algorithm 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 containing the Initialization
    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
    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 algorithm 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 algorithm 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
    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 algorithm 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 algorithm 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
    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 primelength, 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       Value 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 performs successfully.
    677   @retval Otherwise               The operation is failed.
    678 
    679 **/
    680 EFI_STATUS
    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 performs successfully.
    729   @retval Otherwise                The operation is failed.
    730 
    731 **/
    732 EFI_STATUS
    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 performs successfully.
    754   @retval EFI_INVALID_PARAMETER    The DhContext is NULL.
    755 
    756 **/
    757 EFI_STATUS
    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 random bytes to generate.
    777 
    778   @retval EFI_SUCCESS              The operation performs successfully.
    779   @retval Otherwise                The operation is failed.
    780 
    781 **/
    782 EFI_STATUS
    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
    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 octet 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 verified.
    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
    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
    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   if (*PublicKey == NULL) {
    972     Status = EFI_OUT_OF_RESOURCES;
    973     goto EXIT;
    974   }
    975 
    976   if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {
    977     Status = EFI_INVALID_PARAMETER;
    978   }
    979 
    980 EXIT:
    981   if (RsaContext != NULL) {
    982     RsaFree (RsaContext);
    983   }
    984 
    985   return Status;
    986 }
    987 
    988 /**
    989   Retrieves the subject name from one X509 certificate (DER format only).
    990 
    991   @param[in]     InCert            Pointer to the X509 certificate.
    992   @param[in]     CertSize          The size of the X509 certificate in bytes.
    993   @param[out]    CertSubject       Pointer to the retrieved certificate subject.
    994   @param[out]    SubjectSize       The size of Certificate Subject in bytes.
    995 
    996   @retval  EFI_SUCCESS            Retrieved the certificate subject successfully.
    997   @retval  EFI_INVALID_PARAMETER  The certificate is malformed.
    998 
    999 **/
   1000 EFI_STATUS
   1001 IpSecCryptoIoGetSubjectFromCert (
   1002   IN     UINT8   *InCert,
   1003   IN     UINTN   CertSize,
   1004   OUT    UINT8   **CertSubject,
   1005   OUT    UINTN   *SubjectSize
   1006   )
   1007 {
   1008   EFI_STATUS    Status;
   1009 
   1010   Status = EFI_SUCCESS;
   1011 
   1012   *SubjectSize = 0;
   1013   X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);
   1014 
   1015   *CertSubject = AllocateZeroPool (*SubjectSize);
   1016   if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {
   1017     Status = EFI_INVALID_PARAMETER;
   1018   }
   1019 
   1020   return Status;
   1021 }
   1022