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