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