1 /** @file
2 
3   This library registers CRC32 guided section handler
4   to parse CRC32 encapsulation section and extract raw data.
5 
6 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include <PiPei.h>
18 #include <Guid/Crc32GuidedSectionExtraction.h>
19 #include <Library/ExtractGuidedSectionLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 
23 ///
24 /// CRC32 Guided Section header
25 ///
26 typedef struct {
27   EFI_GUID_DEFINED_SECTION  GuidedSectionHeader; ///< EFI guided section header
28   UINT32                    CRC32Checksum;       ///< 32bit CRC check sum
29 } CRC32_SECTION_HEADER;
30 
31 typedef struct {
32   EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
33   UINT32                    CRC32Checksum;       ///< 32bit CRC check sum
34 } CRC32_SECTION2_HEADER;
35 
36 /**
37   This internal function reverses bits for 32bit data.
38 
39   @param  Value                 The data to be reversed.
40 
41   @return                       Data reversed.
42 
43 **/
44 UINT32
PeiCrc32GuidedSectionExtractLibReverseBits(UINT32 Value)45 PeiCrc32GuidedSectionExtractLibReverseBits (
46   UINT32  Value
47   )
48 {
49   UINTN   Index;
50   UINT32  NewValue;
51 
52   NewValue = 0;
53   for (Index = 0; Index < 32; Index++) {
54     if ((Value & (1 << Index)) != 0) {
55       NewValue = NewValue | (1 << (31 - Index));
56     }
57   }
58 
59   return NewValue;
60 }
61 
62 /**
63   Calculate CRC32 for target data.
64 
65   @param  Data                  The target data.
66   @param  DataSize              The target data size.
67   @param  CrcOut                The CRC32 for target data.
68 
69   @retval EFI_SUCCESS           The CRC32 for target data is calculated successfully.
70   @retval EFI_INVALID_PARAMETER Some parameter is not valid, so the CRC32 is not
71                                 calculated.
72 
73 **/
74 EFI_STATUS
75 EFIAPI
PeiCrc32GuidedSectionExtractLibCalculateCrc32(IN VOID * Data,IN UINTN DataSize,OUT UINT32 * CrcOut)76 PeiCrc32GuidedSectionExtractLibCalculateCrc32 (
77   IN  VOID    *Data,
78   IN  UINTN   DataSize,
79   OUT UINT32  *CrcOut
80   )
81 {
82   UINT32  CrcTable[256];
83   UINTN   TableEntry;
84   UINTN   Index;
85   UINT32  Value;
86   UINT32  Crc;
87   UINT8   *Ptr;
88 
89   if (Data == NULL || DataSize == 0 || CrcOut == NULL) {
90     return EFI_INVALID_PARAMETER;
91   }
92 
93   //
94   // Initialize CRC32 table.
95   //
96   for (TableEntry = 0; TableEntry < 256; TableEntry++) {
97     Value = PeiCrc32GuidedSectionExtractLibReverseBits ((UINT32) TableEntry);
98     for (Index = 0; Index < 8; Index++) {
99       if ((Value & 0x80000000) != 0) {
100         Value = (Value << 1) ^ 0x04c11db7;
101       } else {
102         Value = Value << 1;
103       }
104     }
105     CrcTable[TableEntry] = PeiCrc32GuidedSectionExtractLibReverseBits (Value);
106   }
107 
108   //
109   // Compute CRC
110   //
111   Crc = 0xffffffff;
112   for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) {
113     Crc = (Crc >> 8) ^ CrcTable[(UINT8) Crc ^ *Ptr];
114   }
115 
116   *CrcOut = Crc ^ 0xffffffff;
117   return EFI_SUCCESS;
118 }
119 
120 /**
121 
122   GetInfo gets raw data size and attribute of the input guided section.
123   It first checks whether the input guid section is supported.
124   If not, EFI_INVALID_PARAMETER will return.
125 
126   @param InputSection       Buffer containing the input GUIDed section to be processed.
127   @param OutputBufferSize   The size of OutputBuffer.
128   @param ScratchBufferSize  The size of ScratchBuffer.
129   @param SectionAttribute   The attribute of the input guided section.
130 
131   @retval EFI_SUCCESS            The size of destination buffer, the size of scratch buffer and
132                                  the attribute of the input section are successfully retrieved.
133   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
134 
135 **/
136 EFI_STATUS
137 EFIAPI
Crc32GuidedSectionGetInfo(IN CONST VOID * InputSection,OUT UINT32 * OutputBufferSize,OUT UINT32 * ScratchBufferSize,OUT UINT16 * SectionAttribute)138 Crc32GuidedSectionGetInfo (
139   IN  CONST VOID  *InputSection,
140   OUT UINT32      *OutputBufferSize,
141   OUT UINT32      *ScratchBufferSize,
142   OUT UINT16      *SectionAttribute
143   )
144 {
145   if (IS_SECTION2 (InputSection)) {
146     //
147     // Check whether the input guid section is recognized.
148     //
149     if (!CompareGuid (
150         &gEfiCrc32GuidedSectionExtractionGuid,
151         &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
152       return EFI_INVALID_PARAMETER;
153     }
154     //
155     // Retrieve the size and attribute of the input section data.
156     //
157     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
158     *ScratchBufferSize = 0;
159     *OutputBufferSize  = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
160   } else {
161     //
162     // Check whether the input guid section is recognized.
163     //
164     if (!CompareGuid (
165         &gEfiCrc32GuidedSectionExtractionGuid,
166         &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
167       return EFI_INVALID_PARAMETER;
168     }
169     //
170     // Retrieve the size and attribute of the input section data.
171     //
172     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
173     *ScratchBufferSize = 0;
174     *OutputBufferSize  = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
175   }
176 
177   return EFI_SUCCESS;
178 }
179 
180 /**
181 
182   Extraction handler tries to extract raw data from the input guided section.
183   It also does authentication check for 32bit CRC value in the input guided section.
184   It first checks whether the input guid section is supported.
185   If not, EFI_INVALID_PARAMETER will return.
186 
187   @param InputSection    Buffer containing the input GUIDed section to be processed.
188   @param OutputBuffer    Buffer to contain the output raw data allocated by the caller.
189   @param ScratchBuffer   A pointer to a caller-allocated buffer for function internal use.
190   @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
191                               authentication status of the output buffer.
192 
193   @retval EFI_SUCCESS            Section Data and Auth Status is extracted successfully.
194   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
195 
196 **/
197 EFI_STATUS
198 EFIAPI
Crc32GuidedSectionHandler(IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,IN VOID * ScratchBuffer,OPTIONAL OUT UINT32 * AuthenticationStatus)199 Crc32GuidedSectionHandler (
200   IN CONST  VOID    *InputSection,
201   OUT       VOID    **OutputBuffer,
202   IN        VOID    *ScratchBuffer,        OPTIONAL
203   OUT       UINT32  *AuthenticationStatus
204   )
205 {
206   EFI_STATUS  Status;
207   UINT32      SectionCrc32Checksum;
208   UINT32      Crc32Checksum;
209   UINT32      OutputBufferSize;
210 
211   if (IS_SECTION2 (InputSection)) {
212     //
213     // Check whether the input guid section is recognized.
214     //
215     if (!CompareGuid (
216         &gEfiCrc32GuidedSectionExtractionGuid,
217         &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
218       return EFI_INVALID_PARAMETER;
219     }
220 
221     //
222     // Get section Crc32 checksum.
223     //
224     SectionCrc32Checksum = ((CRC32_SECTION2_HEADER *) InputSection)->CRC32Checksum;
225     *OutputBuffer      = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
226     OutputBufferSize   = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
227 
228     //
229     // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
230     //
231     ASSERT (((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
232     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
233   } else {
234     //
235     // Check whether the input guid section is recognized.
236     //
237     if (!CompareGuid (
238         &gEfiCrc32GuidedSectionExtractionGuid,
239         &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
240       return EFI_INVALID_PARAMETER;
241     }
242 
243     //
244     // Get section Crc32 checksum.
245     //
246     SectionCrc32Checksum = ((CRC32_SECTION_HEADER *) InputSection)->CRC32Checksum;
247     *OutputBuffer      = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
248     OutputBufferSize   = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
249 
250     //
251     // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
252     //
253     ASSERT (((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
254     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
255   }
256 
257   //
258   // Init Checksum value to Zero.
259   //
260   Crc32Checksum = 0;
261 
262   //
263   // Calculate CRC32 Checksum of Image
264   //
265   Status = PeiCrc32GuidedSectionExtractLibCalculateCrc32 (*OutputBuffer, OutputBufferSize, &Crc32Checksum);
266   if (Status == EFI_SUCCESS) {
267     if (Crc32Checksum != SectionCrc32Checksum) {
268       //
269       // If Crc32 checksum is not matched, AUTH tested failed bit is set.
270       //
271       *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
272     }
273   } else {
274     //
275     // If Crc32 checksum is not calculated, AUTH not tested bit is set.
276     //
277     *AuthenticationStatus |= EFI_AUTH_STATUS_NOT_TESTED;
278   }
279 
280   //
281   // Temp solution until PeiCore checks AUTH Status.
282   //
283   if ((*AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
284     return EFI_ACCESS_DENIED;
285   }
286 
287   return EFI_SUCCESS;
288 }
289 
290 /**
291   Register the handler to extract CRC32 guided section.
292 
293   @param  FileHandle   The handle of FFS header the loaded driver.
294   @param  PeiServices  The pointer to the PEI services.
295 
296   @retval  EFI_SUCCESS           Register successfully.
297   @retval  EFI_OUT_OF_RESOURCES  Not enough memory to register this handler.
298 
299 **/
300 EFI_STATUS
301 EFIAPI
PeiCrc32GuidedSectionExtractLibConstructor(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)302 PeiCrc32GuidedSectionExtractLibConstructor (
303   IN EFI_PEI_FILE_HANDLE        FileHandle,
304   IN CONST EFI_PEI_SERVICES     **PeiServices
305   )
306 {
307   return ExtractGuidedSectionRegisterHandlers (
308           &gEfiCrc32GuidedSectionExtractionGuid,
309           Crc32GuidedSectionGetInfo,
310           Crc32GuidedSectionHandler
311           );
312 }
313