Home | History | Annotate | Download | only in Pk
      1 /** @file
      2   PKCS#7 SignedData Sign Wrapper Implementation over OpenSSL.
      3 
      4 Copyright (c) 2009 - 2015, 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 
     17 #include <openssl/objects.h>
     18 #include <openssl/x509.h>
     19 #include <openssl/pkcs7.h>
     20 
     21 
     22 /**
     23   Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
     24   Syntax Standard, version 1.5". This interface is only intended to be used for
     25   application to perform PKCS#7 functionality validation.
     26 
     27   @param[in]  PrivateKey       Pointer to the PEM-formatted private key data for
     28                                data signing.
     29   @param[in]  PrivateKeySize   Size of the PEM private key data in bytes.
     30   @param[in]  KeyPassword      NULL-terminated passphrase used for encrypted PEM
     31                                key data.
     32   @param[in]  InData           Pointer to the content to be signed.
     33   @param[in]  InDataSize       Size of InData in bytes.
     34   @param[in]  SignCert         Pointer to signer's DER-encoded certificate to sign with.
     35   @param[in]  OtherCerts       Pointer to an optional additional set of certificates to
     36                                include in the PKCS#7 signedData (e.g. any intermediate
     37                                CAs in the chain).
     38   @param[out] SignedData       Pointer to output PKCS#7 signedData.
     39   @param[out] SignedDataSize   Size of SignedData in bytes.
     40 
     41   @retval     TRUE             PKCS#7 data signing succeeded.
     42   @retval     FALSE            PKCS#7 data signing failed.
     43 
     44 **/
     45 BOOLEAN
     46 EFIAPI
     47 Pkcs7Sign (
     48   IN   CONST UINT8  *PrivateKey,
     49   IN   UINTN        PrivateKeySize,
     50   IN   CONST UINT8  *KeyPassword,
     51   IN   UINT8        *InData,
     52   IN   UINTN        InDataSize,
     53   IN   UINT8        *SignCert,
     54   IN   UINT8        *OtherCerts      OPTIONAL,
     55   OUT  UINT8        **SignedData,
     56   OUT  UINTN        *SignedDataSize
     57   )
     58 {
     59   BOOLEAN   Status;
     60   EVP_PKEY  *Key;
     61   BIO       *DataBio;
     62   PKCS7     *Pkcs7;
     63   UINT8     *RsaContext;
     64   UINT8     *P7Data;
     65   UINTN     P7DataSize;
     66   UINT8     *Tmp;
     67 
     68   //
     69   // Check input parameters.
     70   //
     71   if (PrivateKey == NULL || KeyPassword == NULL || InData == NULL ||
     72     SignCert == NULL || SignedData == NULL || SignedDataSize == NULL || InDataSize > INT_MAX) {
     73     return FALSE;
     74   }
     75 
     76   RsaContext = NULL;
     77   Key        = NULL;
     78   Pkcs7      = NULL;
     79   DataBio    = NULL;
     80   Status     = FALSE;
     81 
     82   //
     83   // Retrieve RSA private key from PEM data.
     84   //
     85   Status = RsaGetPrivateKeyFromPem (
     86              PrivateKey,
     87              PrivateKeySize,
     88              (CONST CHAR8 *) KeyPassword,
     89              (VOID **) &RsaContext
     90              );
     91   if (!Status) {
     92     return Status;
     93   }
     94 
     95   Status = FALSE;
     96 
     97   //
     98   // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling
     99   //
    100   if (EVP_add_digest (EVP_md5 ()) == 0) {
    101     goto _Exit;
    102   }
    103   if (EVP_add_digest (EVP_sha1 ()) == 0) {
    104     goto _Exit;
    105   }
    106   if (EVP_add_digest (EVP_sha256 ()) == 0) {
    107     goto _Exit;
    108   }
    109 
    110   RandomSeed (NULL, 0);
    111 
    112   //
    113   // Construct OpenSSL EVP_PKEY for private key.
    114   //
    115   Key = EVP_PKEY_new ();
    116   if (Key == NULL) {
    117     goto _Exit;
    118   }
    119   if (EVP_PKEY_assign_RSA (Key, (RSA *) RsaContext) == 0) {
    120     goto _Exit;
    121   }
    122 
    123   //
    124   // Convert the data to be signed to BIO format.
    125   //
    126   DataBio = BIO_new (BIO_s_mem ());
    127   if (DataBio == NULL) {
    128     goto _Exit;
    129   }
    130 
    131   if (BIO_write (DataBio, InData, (int) InDataSize) <= 0) {
    132     goto _Exit;
    133   }
    134 
    135   //
    136   // Create the PKCS#7 signedData structure.
    137   //
    138   Pkcs7 = PKCS7_sign (
    139             (X509 *) SignCert,
    140             Key,
    141             (STACK_OF(X509) *) OtherCerts,
    142             DataBio,
    143             PKCS7_BINARY | PKCS7_NOATTR | PKCS7_DETACHED
    144             );
    145   if (Pkcs7 == NULL) {
    146     goto _Exit;
    147   }
    148 
    149   //
    150   // Convert PKCS#7 signedData structure into DER-encoded buffer.
    151   //
    152   P7DataSize = i2d_PKCS7 (Pkcs7, NULL);
    153   if (P7DataSize <= 19) {
    154     goto _Exit;
    155   }
    156 
    157   P7Data     = malloc (P7DataSize);
    158   if (P7Data == NULL) {
    159     goto _Exit;
    160   }
    161 
    162   Tmp        = P7Data;
    163   P7DataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &Tmp);
    164   ASSERT (P7DataSize > 19);
    165 
    166   //
    167   // Strip ContentInfo to content only for signeddata. The data be trimmed off
    168   // is totally 19 bytes.
    169   //
    170   *SignedDataSize = P7DataSize - 19;
    171   *SignedData     = malloc (*SignedDataSize);
    172   if (*SignedData == NULL) {
    173     OPENSSL_free (P7Data);
    174     goto _Exit;
    175   }
    176 
    177   CopyMem (*SignedData, P7Data + 19, *SignedDataSize);
    178 
    179   OPENSSL_free (P7Data);
    180 
    181   Status = TRUE;
    182 
    183 _Exit:
    184   //
    185   // Release Resources
    186   //
    187   if (RsaContext != NULL) {
    188     RsaFree (RsaContext);
    189     if (Key != NULL) {
    190       Key->pkey.rsa = NULL;
    191     }
    192   }
    193 
    194   if (Key != NULL) {
    195     EVP_PKEY_free (Key);
    196   }
    197 
    198   if (DataBio != NULL) {
    199     BIO_free (DataBio);
    200   }
    201 
    202   if (Pkcs7 != NULL) {
    203     PKCS7_free (Pkcs7);
    204   }
    205 
    206   return Status;
    207 }
    208