| /** @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); |