Skip to content

Pkcs7 cert chain check fix - Revoke by hash of any cert in signing chain#562

Merged
jyao1 merged 8 commits into
tianocore:UEFI_PQCfrom
jyao1:pkcs7-cert-chain
Jun 16, 2026
Merged

Pkcs7 cert chain check fix - Revoke by hash of any cert in signing chain#562
jyao1 merged 8 commits into
tianocore:UEFI_PQCfrom
jyao1:pkcs7-cert-chain

Conversation

@jyao1

@jyao1 jyao1 commented Jun 16, 2026

Copy link
Copy Markdown

jyao1 added 8 commits June 16, 2026 11:01
Add tests using a 2-cert PKCS#7 chain (leaf signer issued by the root CA)
to cover the case where the signer would be allowed by db but a chain
certificate is revoked in dbx, so the image must be rejected:

  - Chain_LeafInDbAllowsSigner: baseline, leaf signer cert hash in db
    trusts the chain-signed data.
  - Chain_LeafCertHashRevokedByDbx: leaf signer cert hash in dbx revokes.
  - Chain_RootCertRevokedByDbx: the root certificate as a full
    EFI_CERT_X509 entry in dbx revokes (the signature chains to it).
  - Chain_RootInDbxOverridesDbAllow: leaf allowed by db, root revoked in
    dbx; P7CheckRevocation (run before P7CheckTrust by the protocol)
    reports revoked, so the image is rejected.

Note: Pkcs7GetSigners() returns only the signer (leaf) certificate, so a
non-signer chain certificate (intermediate/root) is matched by the
full-certificate revocation path rather than the certificate-hash path.
The new 2-cert vector reuses the existing test key/cert material
(TestCert2 issued by TestCACert) and is documented for reproduction.

All 29 cases pass under the VS2022 host build with AddressSanitizer.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Per UEFI Spec 32.5.3.3 rule B, a dbx EFI_CERT_X509_SHAxxx entry forbids
the image if its hash reflects the To-Be-Signed hash of ANY certificate
in the signing chain - the leaf signer and every issuer up to the root.
The certificate-hash revocation path only inspected the leaf signer
returned by Pkcs7GetSigners() (OpenSSL CMS_get0_signers returns only the
signer), so a revoked intermediate or root certificate hash in dbx did
not reject the image.

Add IsSignerCertChainRevokedByHash(), which retrieves the full signing
chain via Pkcs7GetCertificatesList() and checks each certificate's TBS
hash against the revocation database. If the chain cannot be retrieved,
it fails safe and reports the signedData as revoked (rather than checking
only a subset of the chain). P7CheckRevocation() and
P7CheckRevocationByHash() now use it.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
…tion

Add a 3-level certificate chain (root -> intermediate -> leaf, all
embedded) and tests confirming that a non-signer chain certificate
revoked in dbx by EFI_CERT_X509_SHAxxx hash rejects the image:

  - Chain3_LeafInDbAllowsSigner: baseline, leaf hash in db trusts.
  - Chain3_IntermediateCertHashRevokedByDbx: intermediate hash in dbx
    revokes (V1 and V2 variants).
  - Chain3_RootCertHashRevokedByDbx: root hash in dbx revokes.
  - Chain3_UnrelatedCertHashNotRevoked: unrelated hash does not revoke.

The 3-cert chain reuses the existing root CA (TestCACert) and is built
with openssl; reproduction is documented next to the vector.

All 34 cases pass under the VS2022 host build with AddressSanitizer.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Per UEFI Spec 32.5.3.3 rule B, a dbx EFI_CERT_X509_SHAxxx entry forbids
the image if its hash reflects the To-Be-Signed hash of ANY certificate
in the signing chain - the leaf signer and every issuer up to the root.
IsForbiddenByDbx() only inspected the leaf signer returned by
Pkcs7GetSigners() (OpenSSL CMS_get0_signers returns only the signer), so
a revoked intermediate or root certificate hash in dbx did not forbid
the image.

Retrieve the full signing chain via Pkcs7GetCertificatesList() and check
every certificate's TBS hash against dbx. If the chain cannot be
retrieved, fail safe and treat the image as forbidden (rather than
checking only a subset of the chain).

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
…sh dbx

Add a 3-level certificate chain (root -> intermediate -> leaf, all
embedded) and IsForbiddenByDbx() tests confirming that a non-signer
chain certificate revoked in dbx by EFI_CERT_X509_SHAxxx hash forbids
the image. The dbx variable is provided by mocking gRT->GetVariable:

  - Chain_IntermediateCertHashRevoked: intermediate hash in dbx forbids
    (V1 and V2 variants).
  - Chain_RootCertHashRevoked: root hash in dbx forbids.
  - Chain_LeafCertHashRevoked: leaf signer hash in dbx forbids.
  - Chain_UnrelatedCertHashNotForbidden: unrelated hash does not forbid.

All 23 cases pass under the VS2022 host build with AddressSanitizer.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Replace the ASSERT(FALSE) stub of Pkcs7GetCertificatesList in the MbedTLS
backend with a working implementation. It locates the signer certificate,
walks the issuer chain (matching issuer_raw to a candidate's subject_raw)
to build SignerChainCerts in EFI_CERT_STACK format, and collects the
remaining embedded certificates into UnchainCerts. Two static helpers,
IsCertInCertStack() and MbedTlsAppendCertToStack(), support buffer
construction.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
…atesList

d2i_CMS_ContentInfo() advances the pointer it is given past the consumed
DER, so after decoding NewP7Data no longer points at the start of the
buffer. The cleanup path then calls free() on an interior pointer in the
non-wrapped case, which is undefined behavior.

Decode through a temporary pointer and keep NewP7Data pointing at the
buffer start for free().

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Add the TestVerifyPkcs7GetCertificatesList host test, registered for both
the OpenSSL and MbedTLS suites. It signs with TestCert2 (leaf) embedding
TestCACert (root) via a constructed X509 stack and asserts the returned
chain contains both certificates. All 69 cases pass under the VS2022 host
build with AddressSanitizer on both backends.

Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
@jyao1 jyao1 merged commit d5ddd7b into tianocore:UEFI_PQC Jun 16, 2026
0 of 2 checks passed
@jyao1 jyao1 deleted the pkcs7-cert-chain branch June 16, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant