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