1 /** @file
2 
3   This library registers RSA 2048 SHA 256 guided section handler
4   to parse RSA 2048 SHA 256 encapsulation section and extract raw data.
5   It uses the BaseCryptLib based on OpenSSL to authenticate the signature.
6 
7 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include <PiPei.h>
13 #include <Protocol/Hash.h>
14 #include <Library/ExtractGuidedSectionLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <Guid/WinCertificate.h>
20 #include <Library/BaseCryptLib.h>
21 #include <Library/PerformanceLib.h>
22 #include <Guid/SecurityPkgTokenSpace.h>
23 
24 ///
25 /// RSA 2048 SHA 256 Guided Section header
26 ///
27 typedef struct {
28   EFI_GUID_DEFINED_SECTION        GuidedSectionHeader;     ///< EFI guided section header
29   EFI_CERT_BLOCK_RSA_2048_SHA256  CertBlockRsa2048Sha256;  ///< RSA 2048-bit Signature
30 } RSA_2048_SHA_256_SECTION_HEADER;
31 
32 typedef struct {
33   EFI_GUID_DEFINED_SECTION2       GuidedSectionHeader;     ///< EFI guided section header
34   EFI_CERT_BLOCK_RSA_2048_SHA256  CertBlockRsa2048Sha256;  ///< RSA 2048-bit Signature
35 } RSA_2048_SHA_256_SECTION2_HEADER;
36 
37 ///
38 /// Public Exponent of RSA Key.
39 ///
40 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
41 
42 /**
43 
44   GetInfo gets raw data size and attribute of the input guided section.
45   It first checks whether the input guid section is supported.
46   If not, EFI_INVALID_PARAMETER will return.
47 
48   @param InputSection       Buffer containing the input GUIDed section to be processed.
49   @param OutputBufferSize   The size of OutputBuffer.
50   @param ScratchBufferSize  The size of ScratchBuffer.
51   @param SectionAttribute   The attribute of the input guided section.
52 
53   @retval EFI_SUCCESS            The size of destination buffer, the size of scratch buffer and
54                                  the attribute of the input section are successfully retrieved.
55   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
56 
57 **/
58 EFI_STATUS
59 EFIAPI
Rsa2048Sha256GuidedSectionGetInfo(IN CONST VOID * InputSection,OUT UINT32 * OutputBufferSize,OUT UINT32 * ScratchBufferSize,OUT UINT16 * SectionAttribute)60 Rsa2048Sha256GuidedSectionGetInfo (
61   IN  CONST VOID  *InputSection,
62   OUT UINT32      *OutputBufferSize,
63   OUT UINT32      *ScratchBufferSize,
64   OUT UINT16      *SectionAttribute
65   )
66 {
67   if (IS_SECTION2 (InputSection)) {
68     //
69     // Check whether the input guid section is recognized.
70     //
71     if (!CompareGuid (
72         &gEfiCertTypeRsa2048Sha256Guid,
73         &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
74       return EFI_INVALID_PARAMETER;
75     }
76     //
77     // Retrieve the size and attribute of the input section data.
78     //
79     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
80     *ScratchBufferSize = 0;
81     *OutputBufferSize  = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER);
82   } else {
83     //
84     // Check whether the input guid section is recognized.
85     //
86     if (!CompareGuid (
87         &gEfiCertTypeRsa2048Sha256Guid,
88         &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
89       return EFI_INVALID_PARAMETER;
90     }
91     //
92     // Retrieve the size and attribute of the input section data.
93     //
94     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
95     *ScratchBufferSize = 0;
96     *OutputBufferSize  = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER);
97   }
98 
99   return EFI_SUCCESS;
100 }
101 
102 /**
103 
104   Extraction handler tries to extract raw data from the input guided section.
105   It also does authentication check for RSA 2048 SHA 256 signature in the input guided section.
106   It first checks whether the input guid section is supported.
107   If not, EFI_INVALID_PARAMETER will return.
108 
109   @param InputSection    Buffer containing the input GUIDed section to be processed.
110   @param OutputBuffer    Buffer to contain the output raw data allocated by the caller.
111   @param ScratchBuffer   A pointer to a caller-allocated buffer for function internal use.
112   @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
113                               authentication status of the output buffer.
114 
115   @retval EFI_SUCCESS            Section Data and Auth Status is extracted successfully.
116   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
117 
118 **/
119 EFI_STATUS
120 EFIAPI
Rsa2048Sha256GuidedSectionHandler(IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,IN VOID * ScratchBuffer,OPTIONAL OUT UINT32 * AuthenticationStatus)121 Rsa2048Sha256GuidedSectionHandler (
122   IN CONST  VOID    *InputSection,
123   OUT       VOID    **OutputBuffer,
124   IN        VOID    *ScratchBuffer,        OPTIONAL
125   OUT       UINT32  *AuthenticationStatus
126   )
127 {
128   EFI_STATUS                      Status;
129   UINT32                          OutputBufferSize;
130   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlockRsa2048Sha256;
131   BOOLEAN                         CryptoStatus;
132   UINT8                           Digest[SHA256_DIGEST_SIZE];
133   UINT8                           *PublicKey;
134   UINTN                           PublicKeyBufferSize;
135   VOID                            *HashContext;
136   VOID                            *Rsa;
137 
138   HashContext = NULL;
139   Rsa         = NULL;
140 
141   if (IS_SECTION2 (InputSection)) {
142     //
143     // Check whether the input guid section is recognized.
144     //
145     if (!CompareGuid (
146         &gEfiCertTypeRsa2048Sha256Guid,
147         &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) {
148       return EFI_INVALID_PARAMETER;
149     }
150 
151     //
152     // Get the RSA 2048 SHA 256 information.
153     //
154     CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256;
155     OutputBufferSize       = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
156     if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
157       PERF_INMODULE_BEGIN ("PeiRsaCopy");
158       CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize);
159       PERF_INMODULE_END ("PeiRsaCopy");
160     } else {
161       *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
162     }
163 
164     //
165     // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
166     //
167     ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
168     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
169   } else {
170     //
171     // Check whether the input guid section is recognized.
172     //
173     if (!CompareGuid (
174         &gEfiCertTypeRsa2048Sha256Guid,
175         &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) {
176       return EFI_INVALID_PARAMETER;
177     }
178 
179     //
180     // Get the RSA 2048 SHA 256 information.
181     //
182     CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256;
183     OutputBufferSize       = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER);
184     if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
185       PERF_INMODULE_BEGIN ("PeiRsaCopy");
186       CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize);
187       PERF_INMODULE_END ("PeiRsaCopy");
188     } else {
189       *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER);
190     }
191 
192     //
193     // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
194     //
195     ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
196     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
197   }
198 
199   //
200   // All paths from here return EFI_SUCCESS and result is returned in AuthenticationStatus
201   //
202   Status = EFI_SUCCESS;
203 
204   //
205   // Fail if the HashType is not SHA 256
206   //
207   if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) {
208     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: HASH type of section is not supported\n"));
209     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
210     goto Done;
211   }
212 
213   //
214   // Allocate hash context buffer required for SHA 256
215   //
216   HashContext = AllocatePool (Sha256GetContextSize ());
217   if (HashContext == NULL) {
218     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Can not allocate hash context\n"));
219     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
220     goto Done;
221   }
222 
223   //
224   // Hash public key from data payload with SHA256.
225   //
226   ZeroMem (Digest, SHA256_DIGEST_SIZE);
227   CryptoStatus = Sha256Init (HashContext);
228   if (!CryptoStatus) {
229     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
230     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
231     goto Done;
232   }
233   CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
234   if (!CryptoStatus) {
235     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
236     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
237     goto Done;
238   }
239   CryptoStatus  = Sha256Final (HashContext, Digest);
240   if (!CryptoStatus) {
241     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
242     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
243     goto Done;
244   }
245 
246   //
247   // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
248   //
249   PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);
250   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey));
251   ASSERT (PublicKey != NULL);
252   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer)));
253   PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer);
254   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize));
255   ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0);
256   CryptoStatus = FALSE;
257   while (PublicKeyBufferSize != 0) {
258     if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
259       CryptoStatus = TRUE;
260       break;
261     }
262     PublicKey = PublicKey + SHA256_DIGEST_SIZE;
263     PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
264   }
265   if (!CryptoStatus) {
266     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Public key in section is not supported\n"));
267     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
268     goto Done;
269   }
270 
271   //
272   // Generate & Initialize RSA Context.
273   //
274   Rsa = RsaNew ();
275   if (Rsa == NULL) {
276     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaNew() failed\n"));
277     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
278     goto Done;
279   }
280 
281   //
282   // Set RSA Key Components.
283   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
284   //
285   CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
286   if (!CryptoStatus) {
287     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
288     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
289     goto Done;
290   }
291   CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
292   if (!CryptoStatus) {
293     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
294     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
295     goto Done;
296   }
297 
298   //
299   // Hash data payload with SHA256.
300   //
301   ZeroMem (Digest, SHA256_DIGEST_SIZE);
302   CryptoStatus = Sha256Init (HashContext);
303   if (!CryptoStatus) {
304     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
305     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
306     goto Done;
307   }
308   PERF_INMODULE_BEGIN ("PeiRsaShaData");
309   CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize);
310   PERF_INMODULE_END ("PeiRsaShaData");
311   if (!CryptoStatus) {
312     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
313     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
314     goto Done;
315   }
316   CryptoStatus  = Sha256Final (HashContext, Digest);
317   if (!CryptoStatus) {
318     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
319     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
320     goto Done;
321   }
322 
323   //
324   // Verify the RSA 2048 SHA 256 signature.
325   //
326   PERF_INMODULE_BEGIN ("PeiRsaVerify");
327   CryptoStatus = RsaPkcs1Verify (
328                    Rsa,
329                    Digest,
330                    SHA256_DIGEST_SIZE,
331                    CertBlockRsa2048Sha256->Signature,
332                    sizeof (CertBlockRsa2048Sha256->Signature)
333                    );
334   PERF_INMODULE_END ("PeiRsaVerify");
335   if (!CryptoStatus) {
336     //
337     // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
338     //
339     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaPkcs1Verify() failed\n"));
340     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
341   }
342 
343 Done:
344   //
345   // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
346   //
347   if (Rsa != NULL) {
348     RsaFree (Rsa);
349   }
350   if (HashContext != NULL) {
351     FreePool (HashContext);
352   }
353 
354   DEBUG ((DEBUG_VERBOSE, "PeiRsa2048Sha256: Status = %r  AuthenticationStatus = %08x\n", Status, *AuthenticationStatus));
355 
356   return Status;
357 }
358 
359 /**
360   Register the handler to extract RSA 2048 SHA 256 guided section.
361 
362   @param  FileHandle   The handle of FFS header the loaded driver.
363   @param  PeiServices  The pointer to the PEI services.
364 
365   @retval  EFI_SUCCESS           Register successfully.
366   @retval  EFI_OUT_OF_RESOURCES  Not enough memory to register this handler.
367 
368 **/
369 EFI_STATUS
370 EFIAPI
PeiRsa2048Sha256GuidedSectionExtractLibConstructor(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)371 PeiRsa2048Sha256GuidedSectionExtractLibConstructor (
372   IN EFI_PEI_FILE_HANDLE        FileHandle,
373   IN CONST EFI_PEI_SERVICES     **PeiServices
374   )
375 {
376   return ExtractGuidedSectionRegisterHandlers (
377            &gEfiCertTypeRsa2048Sha256Guid,
378            Rsa2048Sha256GuidedSectionGetInfo,
379            Rsa2048Sha256GuidedSectionHandler
380            );
381 }
382