• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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)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