TianoCore EDK2 master
Loading...
Searching...
No Matches
CryptPkcs7VerifyEku.c
Go to the documentation of this file.
1
12#include <Base.h>
13#include "InternalCryptLib.h"
14#include <openssl/x509v3.h>
15#include <openssl/asn1.h>
16#include <openssl/x509.h>
17#include <openssl/bio.h>
18#include <crypto/x509.h>
19#include <openssl/pkcs7.h>
20#include <openssl/bn.h>
21#include <openssl/x509_vfy.h>
22#include <openssl/pem.h>
23#include <openssl/evp.h>
24#include <crypto/asn1.h>
25
68 IN CONST PKCS7 *CertChain,
69 OUT X509 **SignerCert
70 )
71{
72 EFI_STATUS Status;
73
74 STACK_OF (X509) *Signers;
75 INT32 NumberSigners;
76
77 Status = EFI_SUCCESS;
78 Signers = NULL;
79 NumberSigners = 0;
80
81 if ((CertChain == NULL) || (SignerCert == NULL)) {
82 Status = EFI_INVALID_PARAMETER;
83 goto Exit;
84 }
85
86 //
87 // Get the signers from the chain.
88 //
89 Signers = PKCS7_get0_signers ((PKCS7 *)CertChain, NULL, PKCS7_BINARY);
90 if (Signers == NULL) {
91 //
92 // Fail to get signers form PKCS7
93 //
94 Status = EFI_INVALID_PARAMETER;
95 goto Exit;
96 }
97
98 //
99 // There should only be one signer in the PKCS7 stack.
100 //
101 NumberSigners = sk_X509_num (Signers);
102 if (NumberSigners != 1) {
103 //
104 // The number of singers should have been 1
105 //
106 Status = EFI_NOT_FOUND;
107 goto Exit;
108 }
109
110 *SignerCert = sk_X509_value (Signers, 0);
111
112Exit:
113 //
114 // Release Resources
115 //
116 if (Signers != NULL) {
117 sk_X509_free (Signers);
118 }
119
120 return Status;
121}
122
136STATIC
139 IN CONST X509 *Cert,
140 IN ASN1_OBJECT *Asn1ToFind
141 )
142{
143 EFI_STATUS Status;
144 X509 *ClonedCert;
145 X509_EXTENSION *Extension;
146 EXTENDED_KEY_USAGE *Eku;
147 INT32 ExtensionIndex;
148 INTN NumExtensions;
149 ASN1_OBJECT *Asn1InCert;
150 INTN Index;
151
152 Status = EFI_NOT_FOUND;
153 ClonedCert = NULL;
154 Extension = NULL;
155 Eku = NULL;
156 ExtensionIndex = -1;
157 NumExtensions = 0;
158 Asn1InCert = NULL;
159
160 if ((Cert == NULL) || (Asn1ToFind == NULL)) {
161 Status = EFI_INVALID_PARAMETER;
162 goto Exit;
163 }
164
165 //
166 // Clone the certificate. This is required because the Extension API's
167 // only work once per instance of an X509 object.
168 //
169 ClonedCert = X509_dup ((X509 *)Cert);
170 if (ClonedCert == NULL) {
171 //
172 // Fail to duplicate cert.
173 //
174 Status = EFI_INVALID_PARAMETER;
175 goto Exit;
176 }
177
178 //
179 // Look for the extended key usage.
180 //
181 ExtensionIndex = X509_get_ext_by_NID (ClonedCert, NID_ext_key_usage, -1);
182
183 if (ExtensionIndex < 0) {
184 //
185 // Fail to find 'NID_ext_key_usage' in Cert.
186 //
187 goto Exit;
188 }
189
190 Extension = X509_get_ext (ClonedCert, ExtensionIndex);
191 if (Extension == NULL) {
192 //
193 // Fail to get Extension form cert.
194 //
195 goto Exit;
196 }
197
198 Eku = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i (Extension);
199 if (Eku == NULL) {
200 //
201 // Fail to get Eku from extension.
202 //
203 goto Exit;
204 }
205
206 NumExtensions = sk_ASN1_OBJECT_num (Eku);
207
208 //
209 // Now loop through the extensions, looking for the specified Eku.
210 //
211 for (Index = 0; Index < NumExtensions; Index++) {
212 Asn1InCert = sk_ASN1_OBJECT_value (Eku, (INT32)Index);
213 if (Asn1InCert == NULL) {
214 //
215 // Fail to get ASN object from Eku.
216 //
217 goto Exit;
218 }
219
220 if ((Asn1InCert->length == Asn1ToFind->length) &&
221 (CompareMem (Asn1InCert->data, Asn1ToFind->data, Asn1InCert->length) == 0))
222 {
223 //
224 // Found Eku in certificate.
225 //
226 Status = EFI_SUCCESS;
227 goto Exit;
228 }
229 }
230
231Exit:
232
233 //
234 // Release Resources
235 //
236 if (ClonedCert != NULL) {
237 X509_free (ClonedCert);
238 }
239
240 if (Eku != NULL) {
241 sk_ASN1_OBJECT_pop_free (Eku, ASN1_OBJECT_free);
242 }
243
244 return Status;
245}
246
260STATIC
263 IN CONST X509 *SignerCert,
264 IN CONST CHAR8 *RequiredEKUs[],
265 IN CONST UINT32 RequiredEKUsSize,
266 IN BOOLEAN RequireAllPresent
267 )
268{
269 EFI_STATUS Status;
270 ASN1_OBJECT *Asn1ToFind;
271 UINT32 NumEkusFound;
272 UINT32 Index;
273
274 Status = EFI_SUCCESS;
275 Asn1ToFind = NULL;
276 NumEkusFound = 0;
277
278 if ((SignerCert == NULL) || (RequiredEKUs == NULL) || (RequiredEKUsSize == 0)) {
279 Status = EFI_INVALID_PARAMETER;
280 goto Exit;
281 }
282
283 for (Index = 0; Index < RequiredEKUsSize; Index++) {
284 //
285 // Finding required EKU in cert.
286 //
287 if (Asn1ToFind != NULL) {
288 ASN1_OBJECT_free (Asn1ToFind);
289 Asn1ToFind = NULL;
290 }
291
292 Asn1ToFind = OBJ_txt2obj (RequiredEKUs[Index], 0);
293 if (Asn1ToFind == NULL) {
294 //
295 // Fail to convert required EKU to ASN1.
296 //
297 Status = EFI_INVALID_PARAMETER;
298 goto Exit;
299 }
300
301 Status = IsEkuInCertificate (SignerCert, Asn1ToFind);
302 if (Status == EFI_SUCCESS) {
303 NumEkusFound++;
304 if (!RequireAllPresent) {
305 //
306 // Found at least one, so we are done.
307 //
308 goto Exit;
309 }
310 } else {
311 //
312 // Fail to find Eku in cert
313 break;
314 }
315 }
316
317Exit:
318
319 if (Asn1ToFind != NULL) {
320 ASN1_OBJECT_free (Asn1ToFind);
321 }
322
323 if (RequireAllPresent &&
324 (NumEkusFound == RequiredEKUsSize))
325 {
326 //
327 // Found all required EKUs in certificate.
328 //
329 Status = EFI_SUCCESS;
330 }
331
332 return Status;
333}
334
366EFIAPI
368 IN CONST UINT8 *Pkcs7Signature,
369 IN CONST UINT32 SignatureSize,
370 IN CONST CHAR8 *RequiredEKUs[],
371 IN CONST UINT32 RequiredEKUsSize,
372 IN BOOLEAN RequireAllPresent
373 )
374{
375 EFI_STATUS Status;
376 PKCS7 *Pkcs7;
377
378 STACK_OF (X509) *CertChain;
379 INT32 SignatureType;
380 INT32 NumberCertsInSignature;
381 X509 *SignerCert;
382 UINT8 *SignedData;
383 UINT8 *Temp;
384 UINTN SignedDataSize;
385 BOOLEAN IsWrapped;
386 BOOLEAN Ok;
387
388 Status = EFI_SUCCESS;
389 Pkcs7 = NULL;
390 CertChain = NULL;
391 SignatureType = 0;
392 NumberCertsInSignature = 0;
393 SignerCert = NULL;
394 SignedData = NULL;
395 SignedDataSize = 0;
396 IsWrapped = FALSE;
397 Ok = FALSE;
398
399 //
400 // Validate the input parameters.
401 //
402 if ((Pkcs7Signature == NULL) ||
403 (SignatureSize == 0) ||
404 (RequiredEKUs == NULL) ||
405 (RequiredEKUsSize == 0))
406 {
407 Status = EFI_INVALID_PARAMETER;
408 goto Exit;
409 }
410
411 if (RequiredEKUsSize == 1) {
412 RequireAllPresent = TRUE;
413 }
414
415 //
416 // Wrap the PKCS7 data if needed.
417 //
418 Ok = WrapPkcs7Data (
419 Pkcs7Signature,
420 SignatureSize,
421 &IsWrapped,
422 &SignedData,
423 &SignedDataSize
424 );
425 if (!Ok) {
426 //
427 // Fail to Wrap the PKCS7 data.
428 //
429 Status = EFI_INVALID_PARAMETER;
430 goto Exit;
431 }
432
433 Temp = SignedData;
434
435 //
436 // Create the PKCS7 object.
437 //
438 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (INT32)SignedDataSize);
439 if (Pkcs7 == NULL) {
440 //
441 // Fail to read PKCS7 data.
442 //
443 Status = EFI_INVALID_PARAMETER;
444 goto Exit;
445 }
446
447 //
448 // Get the certificate chain.
449 //
450 SignatureType = OBJ_obj2nid (Pkcs7->type);
451 switch (SignatureType) {
452 case NID_pkcs7_signed:
453 if (Pkcs7->d.sign != NULL) {
454 CertChain = Pkcs7->d.sign->cert;
455 }
456
457 break;
458 case NID_pkcs7_signedAndEnveloped:
459 if (Pkcs7->d.signed_and_enveloped != NULL) {
460 CertChain = Pkcs7->d.signed_and_enveloped->cert;
461 }
462
463 break;
464 default:
465 break;
466 }
467
468 //
469 // Ensure we have a certificate stack
470 //
471 if (CertChain == NULL) {
472 //
473 // Fail to get the certificate stack from signature.
474 //
475 Status = EFI_INVALID_PARAMETER;
476 goto Exit;
477 }
478
479 //
480 // Find out how many certificates were in the PKCS7 signature.
481 //
482 NumberCertsInSignature = sk_X509_num (CertChain);
483
484 if (NumberCertsInSignature == 0) {
485 //
486 // Fail to find any certificates in signature.
487 //
488 Status = EFI_INVALID_PARAMETER;
489 goto Exit;
490 }
491
492 //
493 // Get the leaf signer.
494 //
495 Status = GetSignerCertificate (Pkcs7, &SignerCert);
496 if ((Status != EFI_SUCCESS) || (SignerCert == NULL)) {
497 //
498 // Fail to get the end-entity leaf signer certificate.
499 //
500 Status = EFI_INVALID_PARAMETER;
501 goto Exit;
502 }
503
504 Status = CheckEKUs (SignerCert, RequiredEKUs, RequiredEKUsSize, RequireAllPresent);
505 if (Status != EFI_SUCCESS) {
506 goto Exit;
507 }
508
509Exit:
510
511 //
512 // Release Resources
513 //
514 // If the signature was not wrapped, then the call to WrapData() will allocate
515 // the data and add a header to it
516 //
517 if (!IsWrapped && SignedData) {
518 free (SignedData);
519 }
520
521 if (Pkcs7 != NULL) {
522 PKCS7_free (Pkcs7);
523 }
524
525 return Status;
526}
UINT64 UINTN
INT64 INTN
BOOLEAN WrapPkcs7Data(IN CONST UINT8 *P7Data, IN UINTN P7Length, OUT BOOLEAN *WrapFlag, OUT UINT8 **WrapData, OUT UINTN *WrapDataSize)
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
STATIC EFI_STATUS CheckEKUs(IN CONST X509 *SignerCert, IN CONST CHAR8 *RequiredEKUs[], IN CONST UINT32 RequiredEKUsSize, IN BOOLEAN RequireAllPresent)
STATIC EFI_STATUS GetSignerCertificate(IN CONST PKCS7 *CertChain, OUT X509 **SignerCert)
STATIC EFI_STATUS IsEkuInCertificate(IN CONST X509 *Cert, IN ASN1_OBJECT *Asn1ToFind)
EFI_STATUS EFIAPI VerifyEKUsInPkcs7Signature(IN CONST UINT8 *Pkcs7Signature, IN CONST UINT32 SignatureSize, IN CONST CHAR8 *RequiredEKUs[], IN CONST UINT32 RequiredEKUsSize, IN BOOLEAN RequireAllPresent)
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112