From f6933e6d2160acb83ca4aed31ef5e9b57c60fd72 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 27 Dec 2023 11:38:43 -0500 Subject: [PATCH] uthenticode: enforce codeSigning EKU on intermediates (#92) Signed-off-by: William Woodruff --- src/uthenticode.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/uthenticode.cpp b/src/uthenticode.cpp index 4f065fe..4827ad5 100644 --- a/src/uthenticode.cpp +++ b/src/uthenticode.cpp @@ -219,10 +219,11 @@ bool SignedData::verify_signature() const { /* NOTE(ww): Authenticode specification, page 13: the signer must have the * codeSigning EKU, **or** no member of the signer's chain may have it. * - * The check below is more strict than that: **every** signer must have - * the codeSigning EKU, and we don't check the embedded chain (since - * we can't do full chain verification anyways). + * The check below is more strict than that: **every** signer and embedded + * intermediate cert must have the codeSigning EKU. */ + + /* Check all signing certificates. */ for (auto i = 0; i < sk_X509_num(signers_stack.get()); ++i) { auto *signer = sk_X509_value(signers_stack.get(), i); @@ -236,6 +237,16 @@ bool SignedData::verify_signature() const { } } + /* Check all embedded intermediates. */ + for (auto i = 0; i < sk_X509_num(certs); ++i) { + auto *cert = sk_X509_value(certs, i); + + auto xku_flags = X509_get_extended_key_usage(cert); + if (!(xku_flags & XKU_CODE_SIGN)) { + return false; + } + } + /* NOTE(ww): What happens below is a bit dumb: we convert our SpcIndirectDataContent back * into DER form so that we can unwrap its ASN.1 sequence and pass the underlying data * to PKCS7_verify for verification. This displays our intent a little more clearly than