]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c
bc804015624d91468e02b12d03b60f202ac23113
[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 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 Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
23 Syntax Standard, version 1.5". This interface is only intended to be used for
24 application to perform PKCS#7 functionality validation.
25
26 @param[in] PrivateKey Pointer to the PEM-formatted private key data for
27 data signing.
28 @param[in] PrivateKeySize Size of the PEM private key data in bytes.
29 @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM
30 key data.
31 @param[in] InData Pointer to the content to be signed.
32 @param[in] InDataSize Size of InData in bytes.
33 @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.
34 @param[in] OtherCerts Pointer to an optional additional set of certificates to
35 include in the PKCS#7 signedData (e.g. any intermediate
36 CAs in the chain).
37 @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's
38 responsibility to free the buffer with FreePool().
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 = AllocatePool (*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 (Key != NULL) {
188 EVP_PKEY_free (Key);
189 }
190
191 if (DataBio != NULL) {
192 BIO_free (DataBio);
193 }
194
195 if (Pkcs7 != NULL) {
196 PKCS7_free (Pkcs7);
197 }
198
199 return Status;
200 }