Home | History | Annotate | Download | only in Pem
      1 /** @file
      2   PEM (Privacy Enhanced Mail) Format Handler Wrapper Implementation over OpenSSL.
      3 
      4 Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "InternalCryptLib.h"
     16 #include <openssl/pem.h>
     17 
     18 /**
     19   Callback function for password phrase conversion used for retrieving the encrypted PEM.
     20 
     21   @param[out]  Buf      Pointer to the buffer to write the passphrase to.
     22   @param[in]   Size     Maximum length of the passphrase (i.e. the size of Buf).
     23   @param[in]   Flag     A flag which is set to 0 when reading and 1 when writing.
     24   @param[in]   Key      Key data to be passed to the callback routine.
     25 
     26   @retval  The number of characters in the passphrase or 0 if an error occurred.
     27 
     28 **/
     29 INTN
     30 PasswordCallback (
     31   OUT  CHAR8  *Buf,
     32   IN   INTN   Size,
     33   IN   INTN   Flag,
     34   IN   VOID   *Key
     35   )
     36 {
     37   INTN  KeyLength;
     38 
     39   ZeroMem ((VOID *) Buf, (UINTN) Size);
     40   if (Key != NULL) {
     41     //
     42     // Duplicate key phrase directly.
     43     //
     44     KeyLength = (INTN) AsciiStrLen ((CHAR8 *)Key);
     45     KeyLength = (KeyLength > Size ) ? Size : KeyLength;
     46     CopyMem (Buf, Key, (UINTN) KeyLength);
     47     return KeyLength;
     48   } else {
     49     return 0;
     50   }
     51 }
     52 
     53 /**
     54   Retrieve the RSA Private Key from the password-protected PEM key data.
     55 
     56   @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
     57   @param[in]  PemSize      Size of the PEM key data in bytes.
     58   @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
     59   @param[out] RsaContext   Pointer to new-generated RSA context which contain the retrieved
     60                            RSA private key component. Use RsaFree() function to free the
     61                            resource.
     62 
     63   If PemData is NULL, then return FALSE.
     64   If RsaContext is NULL, then return FALSE.
     65 
     66   @retval  TRUE   RSA Private Key was retrieved successfully.
     67   @retval  FALSE  Invalid PEM key data or incorrect password.
     68 
     69 **/
     70 BOOLEAN
     71 EFIAPI
     72 RsaGetPrivateKeyFromPem (
     73   IN   CONST UINT8  *PemData,
     74   IN   UINTN        PemSize,
     75   IN   CONST CHAR8  *Password,
     76   OUT  VOID         **RsaContext
     77   )
     78 {
     79   BOOLEAN  Status;
     80   BIO      *PemBio;
     81 
     82   //
     83   // Check input parameters.
     84   //
     85   if (PemData == NULL || RsaContext == NULL || PemSize > INT_MAX) {
     86     return FALSE;
     87   }
     88 
     89   //
     90   // Add possible block-cipher descriptor for PEM data decryption.
     91   // NOTE: Only support most popular ciphers (3DES, AES) for the encrypted PEM.
     92   //
     93   if (EVP_add_cipher (EVP_des_ede3_cbc ()) == 0) {
     94     return FALSE;
     95   }
     96   if (EVP_add_cipher (EVP_aes_128_cbc ()) == 0) {
     97     return FALSE;
     98   }
     99   if (EVP_add_cipher (EVP_aes_192_cbc ()) == 0) {
    100     return FALSE;
    101   }
    102   if (EVP_add_cipher (EVP_aes_256_cbc ()) == 0) {
    103     return FALSE;
    104   }
    105 
    106   Status = FALSE;
    107 
    108   //
    109   // Read encrypted PEM Data.
    110   //
    111   PemBio = BIO_new (BIO_s_mem ());
    112   if (PemBio == NULL) {
    113     goto _Exit;
    114   }
    115 
    116   if (BIO_write (PemBio, PemData, (int) PemSize) <= 0) {
    117     goto _Exit;
    118   }
    119 
    120   //
    121   // Retrieve RSA Private Key from encrypted PEM data.
    122   //
    123   *RsaContext = PEM_read_bio_RSAPrivateKey (PemBio, NULL, (pem_password_cb *) &PasswordCallback, (void *) Password);
    124   if (*RsaContext != NULL) {
    125     Status = TRUE;
    126   }
    127 
    128 _Exit:
    129   //
    130   // Release Resources.
    131   //
    132   BIO_free (PemBio);
    133 
    134   return Status;
    135 }
    136