Skip to content

Commit 9b07fcd

Browse files
committed
SecurityPkg: Add Integration Shell Test
1 parent 1dcce3c commit 9b07fcd

9 files changed

Lines changed: 7872 additions & 0 deletions

File tree

SecurityPkg/Test/ShellTest/ImageValidationTestApp/Aarch64/TestData.c

Lines changed: 3000 additions & 0 deletions
Large diffs are not rendered by default.

SecurityPkg/Test/ShellTest/ImageValidationTestApp/GenTestData.py

Lines changed: 434 additions & 0 deletions
Large diffs are not rendered by default.

SecurityPkg/Test/ShellTest/ImageValidationTestApp/ImageValidationTestApp.c

Lines changed: 867 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/** @file
2+
Header for the Image Validation unit test application.
3+
4+
Defines the data structures and helpers used to drive high level secure boot image
5+
validation scenarios. Each scenario points the GetVariable() hook at a `db` / `dbx`
6+
signature database, selects one of the built-in PE/COFF images, calls gBS->LoadImage(),
7+
and asserts the EFI_STATUS LoadImage() returns.
8+
9+
Copyright (c) Microsoft Corporation.
10+
SPDX-License-Identifier: BSD-2-Clause-Patent
11+
12+
**/
13+
14+
#ifndef IMAGE_VALIDATION_TEST_APP_H_
15+
#define IMAGE_VALIDATION_TEST_APP_H_
16+
17+
#include <Uefi.h>
18+
#include <Library/UnitTestLib.h>
19+
20+
///
21+
/// Selects which built-in PE/COFF image a scenario loads. The scenario runner converts this
22+
/// into the corresponding image buffer and size.
23+
///
24+
typedef enum {
25+
IMAGE_TYPE_UNSIGNED, ///< A valid but unsigned PE/COFF image.
26+
IMAGE_TYPE_SIGNED, ///< An Authenticode-signed image (one signature).
27+
IMAGE_TYPE_DUAL_SIGNED, ///< An image carrying two signatures.
28+
IMAGE_TYPE_MAX
29+
} IMAGE_TYPE;
30+
31+
///
32+
/// Bit flags describing the contents of a `db` or `dbx` signature database. The scenario
33+
/// runner builds a serialized set of EFI_SIGNATURE_LISTs from these flags.
34+
///
35+
#define DB_STATE_EMPTY 0x00000000 ///< No signature lists (absent variable).
36+
#define DB_STATE_IMAGE_DIGEST 0x00000001 ///< Include the loaded image's digest (EFI_CERT_SHA256_GUID).
37+
#define DB_STATE_SIGNER1_LEAF_CERT 0x00000002 ///< Include signer 1 leaf certificate (EFI_CERT_X509_GUID).
38+
#define DB_STATE_SIGNER1_INTERMEDIATE_CERT 0x00000004 ///< Include signer 1 intermediate (inner) CA certificate.
39+
#define DB_STATE_SIGNER1_ROOT_CERT 0x00000008 ///< Include signer 1 root CA certificate.
40+
#define DB_STATE_SIGNER2_CERT 0x00000010 ///< Include signer 2 certificate (dual-signed only).
41+
42+
///
43+
/// Describes a single secure boot image validation scenario.
44+
///
45+
typedef struct {
46+
///
47+
/// Which built-in image to load (see IMAGE_TYPE).
48+
///
49+
IMAGE_TYPE ImageType;
50+
///
51+
/// DB_STATE_* flags describing the contents of the `db` database to build.
52+
///
53+
UINT32 DbState;
54+
///
55+
/// DB_STATE_* flags describing the contents of the `dbx` database to build.
56+
///
57+
UINT32 DbxState;
58+
///
59+
/// EFI_STATUS gBS->LoadImage() is expected to return for this scenario.
60+
///
61+
EFI_STATUS ExpectedStatus;
62+
} SECURE_BOOT_IMAGE_TEST_SCENARIO;
63+
64+
/**
65+
Convenience initializer for a SECURE_BOOT_IMAGE_TEST_SCENARIO.
66+
67+
Scenario descriptions are always auto-generated from DbState, DbxState, and
68+
ExpectedStatus at test-suite registration time. This macro keeps scenario definitions
69+
concise while preserving tabular readability.
70+
**/
71+
#define TEST_SCENARIO(ImageType, DbState, DbxState, ExpectedStatus) \
72+
{ \
73+
(ImageType), \
74+
(DbState), \
75+
(DbxState), \
76+
(ExpectedStatus) \
77+
}
78+
79+
///
80+
/// A named group of scenarios registered together as one unit test suite. The suites (one
81+
/// per image type) are defined in Scenarios.c.
82+
///
83+
typedef struct {
84+
///
85+
/// Suite title shown in the report (user presentation).
86+
///
87+
CONST CHAR8 *Title;
88+
///
89+
/// Suite class name for xUnit-style reporting (e.g. "SecurityPkg.ImageValidation.Signed").
90+
///
91+
CONST CHAR8 *ClassName;
92+
///
93+
/// The scenarios that belong to this suite.
94+
///
95+
CONST SECURE_BOOT_IMAGE_TEST_SCENARIO *Scenarios;
96+
///
97+
/// Number of entries in Scenarios.
98+
///
99+
UINTN ScenarioCount;
100+
} SECURE_BOOT_TEST_SUITE;
101+
102+
//
103+
// The image validation suites (unsigned, signed, dual-signed), defined in Scenarios.c.
104+
//
105+
extern CONST SECURE_BOOT_TEST_SUITE mTestSuites[];
106+
extern CONST UINTN mTestSuiteCount;
107+
108+
/**
109+
Unit test body that drives a single secure boot image validation scenario.
110+
111+
This function is registered as the test case routine for every scenario. It reads the
112+
SECURE_BOOT_IMAGE_TEST_SCENARIO passed through Context, resolves the image from ImageType,
113+
builds `db` / `dbx` from the DbState / DbxState flags, points the GetVariable() hook at
114+
those databases, calls gBS->LoadImage() on the image, unloads the image if it loaded, and
115+
asserts that the returned EFI_STATUS matches SECURE_BOOT_IMAGE_TEST_SCENARIO.ExpectedStatus.
116+
117+
@param[in] Context A pointer to the SECURE_BOOT_IMAGE_TEST_SCENARIO that describes the
118+
inputs and expected result.
119+
120+
@retval UNIT_TEST_PASSED LoadImage() returned the expected status.
121+
@retval UNIT_TEST_ERROR_TEST_FAILED LoadImage() returned an unexpected status.
122+
**/
123+
UNIT_TEST_STATUS
124+
EFIAPI
125+
RunImageValidationScenario (
126+
IN UNIT_TEST_CONTEXT Context
127+
);
128+
129+
#endif // IMAGE_VALIDATION_TEST_APP_H_
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## @file
2+
# Unit test application for high level secure boot image Validation.
3+
#
4+
# Drives the platform image Validation handler through a series of secure boot
5+
# scenarios by injecting per-test `db` / `dbx` signature databases via a
6+
# GetVariable() hook and presenting built-in PE/COFF images for Validation.
7+
#
8+
# Copyright (c) Microsoft Corporation.
9+
# SPDX-License-Identifier: BSD-2-Clause-Patent
10+
#
11+
##
12+
13+
[Defines]
14+
INF_VERSION = 0x00010006
15+
BASE_NAME = ImageValidationTestApp
16+
FILE_GUID = 7B1A6E2C-3C4D-4F5A-9E2B-1D6F0C8A4E11
17+
MODULE_TYPE = UEFI_APPLICATION
18+
VERSION_STRING = 1.0
19+
ENTRY_POINT = DxeEntryPoint
20+
21+
#
22+
# The following information is for reference only and not required by the build tools.
23+
#
24+
# VALID_ARCHITECTURES = X64 AARCH64
25+
#
26+
27+
[Sources]
28+
ImageValidationTestApp.c
29+
ImageValidationTestApp.h
30+
Scenarios.c
31+
TestData.h
32+
33+
[Sources.X64]
34+
X64/TestData.c
35+
36+
[Sources.AARCH64]
37+
Aarch64/TestDat.c
38+
39+
[Packages]
40+
MdePkg/MdePkg.dec
41+
SecurityPkg/SecurityPkg.dec
42+
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
43+
44+
[LibraryClasses]
45+
UefiApplicationEntryPoint
46+
BaseLib
47+
BaseMemoryLib
48+
MemoryAllocationLib
49+
DebugLib
50+
UefiLib
51+
UefiBootServicesTableLib
52+
UefiRuntimeServicesTableLib
53+
UnitTestLib
54+
TimerLib
55+
56+
[Guids]
57+
gEfiImageSecurityDatabaseGuid ## CONSUMES
58+
gEfiGlobalVariableGuid ## CONSUMES
59+
gEfiCertSha256Guid ## CONSUMES
60+
gEfiCertX509Guid ## CONSUMES
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# ImageValidationTestApp
2+
3+
## Overview
4+
5+
`ImageValidationTestApp` is a UEFI shell test application that validates image authentication
6+
behavior before loading an image. Its purpose is to ensure the platform image validation handler
7+
(invoked by `LoadImage`) meets UEFI specification Secure Boot requirements based on the provided
8+
inputs:
9+
10+
- Image type (unisgned, signed, dual-signed)
11+
- `db` (allowed signatures/hashes)
12+
- `dbx` (revoked signatures/hashes)
13+
14+
## Test Framework
15+
16+
A simple framework was created so that each test scenario specifies the image type, `db`/`dbx`
17+
contents, and the expected output. The framework itself follows the same flow for each test
18+
scenario:
19+
20+
1. Build synthetic `db` and `dbx` databases from scenario bit flags.
21+
2. Hook `GetVariable` so reads the following variables return scenario controlled values:
22+
- `db`
23+
- `dbx`
24+
- `SecureBoot`
25+
3. Call `LoadImage` on the scenario-selected built-in image buffer.
26+
4. Compare the returned `EFI_STATUS` to the scenario's expected result.
27+
28+
The `GetVariable` hook exists only for the duration of test execution and is
29+
restored afterward.
30+
31+
## Supported Image Types
32+
33+
The test supports three image classes:
34+
35+
1. `IMAGE_TYPE_UNSIGNED`
36+
- Unsigned PE/COFF image.
37+
38+
2. `IMAGE_TYPE_SIGNED`
39+
- Single PKCS#7 Authenticode signature (`WIN_CERTIFICATE`).
40+
- Signature chain includes signer 1 certificates:
41+
- `SIGNER1_ROOT`
42+
- `SIGNER1_INTERMEDIATE`
43+
- `SIGNER1_LEAF`
44+
45+
3. `IMAGE_TYPE_DUAL_SIGNED`
46+
- Two PKCS#7 Authenticode signatures.
47+
- Signature 1 is the same signer 1 chain as `IMAGE_TYPE_SIGNED`.
48+
- Signature 2 is a signer chain only containing `SIGNER2`.
49+
50+
## DB / DBX Scenario Flags
51+
52+
Scenario inputs use `DB_STATE_*` bit flags. These flags describe what is added
53+
to the generated `db` or `dbx` EFI signature database for that scenario.
54+
55+
`db` and `dbx` use the same flags. The meaning of a flag is identical in both;
56+
only whether it allows (`db`) or revokes (`dbx`) changes behavior.
57+
58+
### Flag Definitions
59+
60+
Flags can be OR-combined to place multiple signature lists into one database.
61+
62+
1. `DB_STATE_EMPTY`
63+
- `GetVariable` returns `EFI_NOT_FOUND`
64+
65+
2. `DB_STATE_IMAGE_DIGEST`
66+
- Add the image's Authenticode SHA-256 digest as an `EFI_CERT_SHA256_GUID` entry.
67+
68+
3. `DB_STATE_SIGNER1_LEAF_CERT`
69+
- Add signer 1 leaf X.509 certificate (`EFI_CERT_X509_GUID`).
70+
71+
4. `DB_STATE_SIGNER1_INTERMEDIATE_CERT`
72+
- Add signer 1 intermediate X.509 certificate.
73+
74+
5. `DB_STATE_SIGNER1_ROOT_CERT`
75+
- Add signer 1 root X.509 certificate.
76+
77+
6. `DB_STATE_SIGNER2_CERT`
78+
- Add signer 2 X.509 certificate (used by dual-signed image scenarios).
79+
80+
## GenTestData.py
81+
82+
`GenTestData.py` generates architecture-specific test data from input EFI
83+
images. It signs images, computes Authenticode digests, and emits C source data
84+
used by this test app.
85+
86+
### Inputs
87+
88+
- `--x64-image <path>`: unsigned X64 EFI image
89+
- `--aarch64-image <path>`: unsigned AARCH64 EFI image
90+
91+
Provide one or both.
92+
93+
### Outputs
94+
95+
Generated files are written to:
96+
97+
- `X64/TestData.c`
98+
- `Aarch64/TestData.c`
99+
100+
These files include:
101+
102+
- Unsigned, signed, and dual-signed image bytes
103+
- Authenticode SHA-256 digests for each image form
104+
- DER certificates for signer 1 chain and signer 2
105+
106+
### Tool Requirements
107+
108+
`GenTestData.py` requires:
109+
110+
- `openssl`
111+
- `sbsign` (from `sbsigntool` / `sbsigntools` package)
112+
- Python 3
113+
114+
On Ubuntu/Debian:
115+
116+
```bash
117+
sudo apt update
118+
sudo apt install -y python3 openssl sbsigntool
119+
```
120+
121+
Verify tools:
122+
123+
```bash
124+
which python3
125+
which openssl
126+
which sbsign
127+
```
128+
129+
### Typical Linux Usage
130+
131+
Run from this directory:
132+
133+
```bash
134+
python3 GenTestData.py \
135+
--x64-image X64/HelloWorld.efi \
136+
--aarch64-image Aarch64/HelloWorld.efi
137+
```
138+
139+
Generate only one architecture:
140+
141+
```bash
142+
python3 GenTestData.py --x64-image X64/HelloWorld.efi
143+
python3 GenTestData.py --aarch64-image Aarch64/HelloWorld.efi
144+
```
145+
146+
### Windows With WSL
147+
148+
Because signing tools are Linux-native in this workflow, run the script inside
149+
WSL.
150+
151+
Example from PowerShell:
152+
153+
```powershell
154+
wsl bash -lc "python3 GenTestData.py --x64-image X64/HelloWorld.efi --aarch64-image Aarch64/HelloWorld.efi"
155+
```
156+
157+
## Notes
158+
159+
- Scenario definitions live in `Scenarios.c`.
160+
- Scenario data structures and `DB_STATE_*` definitions are in
161+
`ImageValidationTestApp.h`.
162+
- Runtime test behavior and database synthesis are in `ImageValidationTestApp.c`.

0 commit comments

Comments
 (0)