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