| /** @file | |
| PKCS#7 SignedData Sign Wrapper Implementation over OpenSSL. | |
| Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "InternalCryptLib.h" | |
| #include <openssl/objects.h> | |
| #include <openssl/x509.h> | |
| #include <openssl/pkcs7.h> | |
| /** | |
| Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message | |
| Syntax Standard, version 1.5". This interface is only intended to be used for | |
| application to perform PKCS#7 functionality validation. | |
| @param[in] PrivateKey Pointer to the PEM-formatted private key data for | |
| data signing. | |
| @param[in] PrivateKeySize Size of the PEM private key data in bytes. | |
| @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM | |
| key data. | |
| @param[in] InData Pointer to the content to be signed. | |
| @param[in] InDataSize Size of InData in bytes. | |
| @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with. | |
| @param[in] OtherCerts Pointer to an optional additional set of certificates to | |
| include in the PKCS#7 signedData (e.g. any intermediate | |
| CAs in the chain). | |
| @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's | |
| responsibility to free the buffer with FreePool(). | |
| @param[out] SignedDataSize Size of SignedData in bytes. | |
| @retval TRUE PKCS#7 data signing succeeded. | |
| @retval FALSE PKCS#7 data signing failed. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| Pkcs7Sign ( | |
| IN CONST UINT8 *PrivateKey, | |
| IN UINTN PrivateKeySize, | |
| IN CONST UINT8 *KeyPassword, | |
| IN UINT8 *InData, | |
| IN UINTN InDataSize, | |
| IN UINT8 *SignCert, | |
| IN UINT8 *OtherCerts OPTIONAL, | |
| OUT UINT8 **SignedData, | |
| OUT UINTN *SignedDataSize | |
| ) | |
| { | |
| BOOLEAN Status; | |
| EVP_PKEY *Key; | |
| BIO *DataBio; | |
| PKCS7 *Pkcs7; | |
| UINT8 *RsaContext; | |
| UINT8 *P7Data; | |
| UINTN P7DataSize; | |
| UINT8 *Tmp; | |
| // | |
| // Check input parameters. | |
| // | |
| if (PrivateKey == NULL || KeyPassword == NULL || InData == NULL || | |
| SignCert == NULL || SignedData == NULL || SignedDataSize == NULL || InDataSize > INT_MAX) { | |
| return FALSE; | |
| } | |
| RsaContext = NULL; | |
| Key = NULL; | |
| Pkcs7 = NULL; | |
| DataBio = NULL; | |
| Status = FALSE; | |
| // | |
| // Retrieve RSA private key from PEM data. | |
| // | |
| Status = RsaGetPrivateKeyFromPem ( | |
| PrivateKey, | |
| PrivateKeySize, | |
| (CONST CHAR8 *) KeyPassword, | |
| (VOID **) &RsaContext | |
| ); | |
| if (!Status) { | |
| return Status; | |
| } | |
| Status = FALSE; | |
| // | |
| // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling | |
| // | |
| if (EVP_add_digest (EVP_md5 ()) == 0) { | |
| goto _Exit; | |
| } | |
| if (EVP_add_digest (EVP_sha1 ()) == 0) { | |
| goto _Exit; | |
| } | |
| if (EVP_add_digest (EVP_sha256 ()) == 0) { | |
| goto _Exit; | |
| } | |
| RandomSeed (NULL, 0); | |
| // | |
| // Construct OpenSSL EVP_PKEY for private key. | |
| // | |
| Key = EVP_PKEY_new (); | |
| if (Key == NULL) { | |
| goto _Exit; | |
| } | |
| if (EVP_PKEY_assign_RSA (Key, (RSA *) RsaContext) == 0) { | |
| goto _Exit; | |
| } | |
| // | |
| // Convert the data to be signed to BIO format. | |
| // | |
| DataBio = BIO_new (BIO_s_mem ()); | |
| if (DataBio == NULL) { | |
| goto _Exit; | |
| } | |
| if (BIO_write (DataBio, InData, (int) InDataSize) <= 0) { | |
| goto _Exit; | |
| } | |
| // | |
| // Create the PKCS#7 signedData structure. | |
| // | |
| Pkcs7 = PKCS7_sign ( | |
| (X509 *) SignCert, | |
| Key, | |
| (STACK_OF(X509) *) OtherCerts, | |
| DataBio, | |
| PKCS7_BINARY | PKCS7_NOATTR | PKCS7_DETACHED | |
| ); | |
| if (Pkcs7 == NULL) { | |
| goto _Exit; | |
| } | |
| // | |
| // Convert PKCS#7 signedData structure into DER-encoded buffer. | |
| // | |
| P7DataSize = i2d_PKCS7 (Pkcs7, NULL); | |
| if (P7DataSize <= 19) { | |
| goto _Exit; | |
| } | |
| P7Data = malloc (P7DataSize); | |
| if (P7Data == NULL) { | |
| goto _Exit; | |
| } | |
| Tmp = P7Data; | |
| P7DataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &Tmp); | |
| ASSERT (P7DataSize > 19); | |
| // | |
| // Strip ContentInfo to content only for signeddata. The data be trimmed off | |
| // is totally 19 bytes. | |
| // | |
| *SignedDataSize = P7DataSize - 19; | |
| *SignedData = AllocatePool (*SignedDataSize); | |
| if (*SignedData == NULL) { | |
| OPENSSL_free (P7Data); | |
| goto _Exit; | |
| } | |
| CopyMem (*SignedData, P7Data + 19, *SignedDataSize); | |
| OPENSSL_free (P7Data); | |
| Status = TRUE; | |
| _Exit: | |
| // | |
| // Release Resources | |
| // | |
| if (Key != NULL) { | |
| EVP_PKEY_free (Key); | |
| } | |
| if (DataBio != NULL) { | |
| BIO_free (DataBio); | |
| } | |
| if (Pkcs7 != NULL) { | |
| PKCS7_free (Pkcs7); | |
| } | |
| return Status; | |
| } |