| /** @file -- Pkcs7EkuVerify.c | |
| * Copyright (c) Microsoft Corporation. | |
| * SPDX-License-Identifier: BSD-2-Clause-Patent | |
| This is an test code which verifies specified | |
| Enhanced Key Usages (EKU)'s are present in the leaf signer | |
| of a PKCS7 formatted signature. | |
| A typical signing certificate chain looks like this: (Could be RSA or ECC). | |
| ------------------------------------------ | |
| | | // Root of trust. ECDSA P521 curve | |
| | TestEKUParsingRoot | // SHA 256 Key Usage: CERT_DIGITAL_SIGNATURE_KEY_USAGE | |
| | | // CERT_KEY_CERT_SIGN_KEY_USAGE | CERT_CRL_SIGN_KEY_USAGE | |
| ------------------------------------------ | |
| ^ | |
| | | |
| ------------------------------------------ | |
| | | // Policy CA. Issues subordinate CAs. ECC P384 curve. | |
| | TestEKUParsingPolicyCA | // SHA 256 Key Usage: | |
| | | // CERT_KEY_CERT_SIGN_KEY_USAGE | CERT_CRL_SIGN_KEY_USAGE | |
| ------------------------------------------ | |
| ^ | |
| | | |
| ------------------------------------------ | |
| | | // Issues end-entity (leaf) signers. ECC P256 curve. | |
| | TestEKUParsingIssuingCA | // SHA 256 Key Usage: CERT_DIGITAL_SIGNATURE_KEY_USAGE | |
| | | // Enhanced Key Usage: | |
| ------------------------------------------ // 1.3.6.1.4.1.311.76.9.21.1 (Surface firmware signing) | |
| ^ | |
| | | |
| -------------------------------------- | |
| / TestEKUParsingLeafSigner && / // Leaf signer, ECC P256 curve. | |
| / TestEKUParsingLeafSignerPid12345 / // SHA 256 Key Usage: CERT_DIGITAL_SIGNATURE_KEY_USAGE | |
| / / // Enhanced Key usages: | |
| -------------------------------------- // 1.3.6.1.4.1.311.76.9.21.1 (Surface firmware signing) | |
| // 1.3.6.1.4.1.311.76.9.21.1.N, N == Product ID. | |
| **/ | |
| #include "TestBaseCryptLib.h" | |
| #include "Pkcs7EkuTestSignatures.h" | |
| EFI_STATUS | |
| EFIAPI | |
| VerifyEKUsInPkcs7Signature ( | |
| IN CONST UINT8 *Pkcs7Signature, | |
| IN CONST UINT32 SignatureSize, | |
| IN CONST CHAR8 *RequiredEKUs[], | |
| IN CONST UINT32 RequiredEKUsSize, | |
| IN BOOLEAN RequireAllPresent | |
| ); | |
| /// ================================================================================================ | |
| /// ================================================================================================ | |
| /// | |
| /// TEST CASES | |
| /// | |
| /// ================================================================================================ | |
| /// ================================================================================================ | |
| CONST CHAR8 FIRMWARE_SIGNER_EKU[] = "1.3.6.1.4.1.311.76.9.21.1"; | |
| /** | |
| TestVerifyEKUsInSignature() | |
| Verify that "1.3.6.1.4.1.311.76.9.21.1" (Firmware signature) is in the | |
| leaf signer certificate. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestVerifyEKUsInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { FIRMWARE_SIGNER_EKU }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| ProductionECCSignature, | |
| ARRAY_SIZE (ProductionECCSignature), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestVerifyEKUsInSignature() | |
| /** | |
| TestVerifyEKUsWith3CertsInSignature() | |
| This PKCS7 signature has 3 certificates in it. (Policy CA, Issuing CA | |
| and leaf signer). It has one firmware signing EKU in it. | |
| "1.3.6.1.4.1.311.76.9.21.1" | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestVerifyEKUsWith3CertsInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { FIRMWARE_SIGNER_EKU }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignEKUsWith3CertsInSignature, | |
| ARRAY_SIZE (TestSignEKUsWith3CertsInSignature), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestVerifyEKUsWith3CertsInSignature() | |
| /** | |
| TestVerifyEKUsWith2CertsInSignature() | |
| This PKCS7 signature has 2 certificates in it. (Issuing CA and leaf signer). | |
| It has one firmware signing EKU in it. "1.3.6.1.4.1.311.76.9.21.1" | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestVerifyEKUsWith2CertsInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { FIRMWARE_SIGNER_EKU }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignEKUsWith2CertsInSignature, | |
| ARRAY_SIZE (TestSignEKUsWith2CertsInSignature), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestVerifyEKUsWith2CertsInSignature() | |
| /** | |
| TestVerifyEKUsWith1CertInSignature() | |
| This PKCS7 signature only has the leaf signer in it. | |
| It has one firmware signing EKU in it. "1.3.6.1.4.1.311.76.9.21.1" | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestVerifyEKUsWith1CertInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { FIRMWARE_SIGNER_EKU }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignEKUsWith1CertInSignature, | |
| ARRAY_SIZE (TestSignEKUsWith1CertInSignature), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestVerifyEKUsWith1CertInSignature() | |
| /** | |
| TestVerifyEKUsWithMultipleEKUsInCert() | |
| This signature has two EKU's in it: | |
| "1.3.6.1.4.1.311.76.9.21.1" | |
| "1.3.6.1.4.1.311.76.9.21.2" | |
| We verify that both EKU's were present in the leaf signer. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestVerifyEKUsWithMultipleEKUsInCert ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { | |
| "1.3.6.1.4.1.311.76.9.21.1", | |
| "1.3.6.1.4.1.311.76.9.21.1.2" | |
| }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithMultipleEKUsInCert, | |
| ARRAY_SIZE (TestSignedWithMultipleEKUsInCert), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestVerifyEKUsWithMultipleEKUsInCert() | |
| /** | |
| TestEkusNotPresentInSignature() | |
| This test verifies that if we send an EKU that is not in the signature, | |
| that we get back an error. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestEkusNotPresentInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| // | |
| // This EKU is not in the signature. | |
| // | |
| CONST CHAR8 *RequiredEKUs[] = { "1.3.6.1.4.1.311.76.9.21.3" }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithMultipleEKUsInCert, | |
| ARRAY_SIZE (TestSignedWithMultipleEKUsInCert), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_NOT_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestEkusNotPresentInSignature() | |
| /** | |
| TestEkusNotPresentInSignature() | |
| This test signature has two EKU's in it: (Product ID is 10001) | |
| "1.3.6.1.4.1.311.76.9.21.1" | |
| "1.3.6.1.4.1.311.76.9.21.1.10001" | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestProductId10001PresentInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| // | |
| // These EKU's are present in the leaf signer certificate. | |
| // | |
| CONST CHAR8 *RequiredEKUs[] = { | |
| "1.3.6.1.4.1.311.76.9.21.1", | |
| "1.3.6.1.4.1.311.76.9.21.1.10001" | |
| }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithProductId10001, | |
| ARRAY_SIZE (TestSignedWithProductId10001), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestProductId10001PresentInSignature() | |
| /** | |
| TestOnlyOneEkuInListRequired() | |
| This test will check the BOOLEAN RequireAllPresent parameter in the | |
| call to VerifyEKUsInPkcs7Signature() behaves properly. The signature | |
| has two EKU's in it: | |
| "1.3.6.1.4.1.311.76.9.21.1" | |
| "1.3.6.1.4.1.311.76.9.21.1.10001" | |
| but we only pass in one of them, and set RequireAllPresent to FALSE. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestOnlyOneEkuInListRequired ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| // | |
| // This will test the flag that specifies it is OK to succeed if | |
| // any one of the EKU's passed in is found. | |
| // | |
| CONST CHAR8 *RequiredEKUs[] = { "1.3.6.1.4.1.311.76.9.21.1.10001" }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithProductId10001, | |
| ARRAY_SIZE (TestSignedWithProductId10001), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| FALSE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestOnlyOneEkuInListRequired() | |
| /** | |
| TestNoEKUsInSignature() | |
| This test uses a signature that was signed with a certificate that does | |
| not contain any EKUs. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestNoEKUsInSignature ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| // | |
| // This EKU is not in the certificate, so it should fail. | |
| // | |
| CONST CHAR8 *RequiredEKUs[] = { "1.3.6.1.4.1.311.76.9.21.1" }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignatureWithNoEKUsPresent, | |
| ARRAY_SIZE (TestSignatureWithNoEKUsPresent), | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_NOT_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestNoEKUsInSignature() | |
| /** | |
| TestInvalidParameters() | |
| Passes the API invalid parameters, and ensures that it does not succeed. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestInvalidParameters ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| CONST CHAR8 *RequiredEKUs[] = { "1.3.6.1.4.1.311.76.9.21.1" }; | |
| // | |
| // Check bad signature. | |
| // | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| NULL, | |
| 0, | |
| (CONST CHAR8 **)RequiredEKUs, | |
| ARRAY_SIZE (RequiredEKUs), | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); | |
| // | |
| // Check invalid EKU's | |
| // | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignatureWithNoEKUsPresent, | |
| ARRAY_SIZE (TestSignatureWithNoEKUsPresent), | |
| (CONST CHAR8 **)NULL, | |
| 0, | |
| TRUE | |
| ); | |
| UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); | |
| return UNIT_TEST_PASSED; | |
| }// TestInvalidParameters() | |
| /** | |
| TestEKUSubStringFails() | |
| Pass the API a sub set and super set of an EKU and ensure that they | |
| don't pass. | |
| @param[in] Framework - Unit-test framework handle. | |
| @param[in] Context - Optional context pointer for this test. | |
| @retval UNIT_TEST_PASSED - The required EKUs were found in the signature. | |
| @retval UNIT_TEST_ERROR_TEST_FAILED - Something failed, check the debug output. | |
| **/ | |
| static | |
| UNIT_TEST_STATUS | |
| EFIAPI | |
| TestEKUSubsetSupersetFails ( | |
| IN UNIT_TEST_CONTEXT Context | |
| ) | |
| { | |
| EFI_STATUS Status = EFI_SUCCESS; | |
| // | |
| // This signature has an EKU of: | |
| // "1.3.6.1.4.1.311.76.9.21.1.10001" | |
| // so ensure that | |
| // "1.3.6.1.4.1.311.76.9.21" | |
| // does not pass. | |
| // | |
| CONST CHAR8 *RequiredEKUs1[] = { "1.3.6.1.4.1.311.76.9.21" }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithProductId10001, | |
| ARRAY_SIZE (TestSignedWithProductId10001), | |
| (CONST CHAR8 **)RequiredEKUs1, | |
| ARRAY_SIZE (RequiredEKUs1), | |
| TRUE | |
| ); | |
| UT_ASSERT_NOT_EQUAL (Status, EFI_SUCCESS); | |
| // | |
| // This signature has an EKU of: | |
| // "1.3.6.1.4.1.311.76.9.21.1.10001" | |
| // so ensure that a super set | |
| // "1.3.6.1.4.1.311.76.9.21.1.10001.1" | |
| // does not pass. | |
| // | |
| CONST CHAR8 *RequiredEKUs2[] = { "1.3.6.1.4.1.311.76.9.21.1.10001.1" }; | |
| Status = VerifyEKUsInPkcs7Signature ( | |
| TestSignedWithProductId10001, | |
| ARRAY_SIZE (TestSignedWithProductId10001), | |
| (CONST CHAR8 **)RequiredEKUs2, | |
| ARRAY_SIZE (RequiredEKUs2), | |
| TRUE | |
| ); | |
| UT_ASSERT_NOT_EQUAL (Status, EFI_SUCCESS); | |
| return UNIT_TEST_PASSED; | |
| }// TestEKUSubsetSupersetFails() | |
| TEST_DESC mPkcs7EkuTest[] = { | |
| // | |
| // -----Description--------------------------------Class----------------------------Function------------------------------Pre---Post--Context | |
| // | |
| { "TestVerifyEKUsInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestVerifyEKUsInSignature, NULL, NULL, NULL }, | |
| { "TestVerifyEKUsWith3CertsInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestVerifyEKUsWith3CertsInSignature, NULL, NULL, NULL }, | |
| { "TestVerifyEKUsWith2CertsInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestVerifyEKUsWith2CertsInSignature, NULL, NULL, NULL }, | |
| { "TestVerifyEKUsWith1CertInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestVerifyEKUsWith1CertInSignature, NULL, NULL, NULL }, | |
| { "TestVerifyEKUsWithMultipleEKUsInCert()", "CryptoPkg.BaseCryptLib.Eku", TestVerifyEKUsWithMultipleEKUsInCert, NULL, NULL, NULL }, | |
| { "TestEkusNotPresentInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestEkusNotPresentInSignature, NULL, NULL, NULL }, | |
| { "TestProductId10001PresentInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestProductId10001PresentInSignature, NULL, NULL, NULL }, | |
| { "TestOnlyOneEkuInListRequired()", "CryptoPkg.BaseCryptLib.Eku", TestOnlyOneEkuInListRequired, NULL, NULL, NULL }, | |
| { "TestNoEKUsInSignature()", "CryptoPkg.BaseCryptLib.Eku", TestNoEKUsInSignature, NULL, NULL, NULL }, | |
| { "TestInvalidParameters()", "CryptoPkg.BaseCryptLib.Eku", TestInvalidParameters, NULL, NULL, NULL }, | |
| { "TestEKUSubsetSupersetFails()", "CryptoPkg.BaseCryptLib.Eku", TestEKUSubsetSupersetFails, NULL, NULL, NULL }, | |
| }; | |
| UINTN mPkcs7EkuTestNum = ARRAY_SIZE (mPkcs7EkuTest); |