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