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