[fido] add additional Authenticode validation before running the script

* This basically means that the script is validate *TWICE*, using two
  completely independent signatures, before it is allowed to run, which
  should add another mitigation layer against TOCTOU (which we already
  friggin' mitigated against anyway) and other potential vectors of
  attack.
* Also remove -DisableFirstRunCustomize option and the associated cookie
  prompt monitoring, which the latest version of Fido no longer requires.
* Also update WDK version for signtool and flesh out PKI error messages.
This commit is contained in:
Pete Batard 2021-05-27 00:18:05 +01:00
parent 3083324a0e
commit f26fd2fbe3
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
8 changed files with 63 additions and 49 deletions

View file

@ -192,12 +192,24 @@ const char* WinPKIErrorString(void)
return "None of the signers of the cryptographic message or certificate trust list is trusted.";
case CERT_E_UNTRUSTEDROOT:
return "The root certificate is not trusted.";
case TRUST_E_SYSTEM_ERROR:
return "A system-level error occurred while verifying trust.";
case TRUST_E_NO_SIGNER_CERT:
return "The certificate for the signer of the message is invalid or not found.";
case TRUST_E_COUNTER_SIGNER:
return "One of the counter signatures was invalid.";
case TRUST_E_CERT_SIGNATURE:
return "The signature of the certificate cannot be verified.";
case TRUST_E_TIME_STAMP:
return "The timestamp could not be verified.";
case TRUST_E_BAD_DIGEST:
return "The file content has been altered.";
case TRUST_E_BASIC_CONSTRAINTS:
return "A certificate's basic constraint extension has not been observed.";
case TRUST_E_NOSIGNATURE:
return "Not digitally signed.";
case TRUST_E_EXPLICIT_DISTRUST:
return "One of the certificates used was marked as untrusted by the user.";
case TRUST_E_TIME_STAMP:
return "The timestamp could not be verified.";
default:
static_sprintf(error_string, "Unknown PKI error 0x%08lX", error_code);
return error_string;
@ -205,7 +217,7 @@ const char* WinPKIErrorString(void)
}
// Mostly from https://support.microsoft.com/en-us/kb/323809
char* GetSignatureName(const char* path, const char* country_code)
char* GetSignatureName(const char* path, const char* country_code, BOOL bSilent)
{
static char szSubjectName[128];
char szCountry[3] = "__";
@ -308,9 +320,9 @@ char* GetSignatureName(const char* path, const char* country_code)
}
if (szCountry[0] == '_')
uprintf("Binary executable is signed by '%s'", szSubjectName);
suprintf("Binary executable is signed by '%s'", szSubjectName);
else
uprintf("Binary executable is signed by '%s' (%s)", szSubjectName, szCountry);
suprintf("Binary executable is signed by '%s' (%s)", szSubjectName, szCountry);
p = szSubjectName;
out:
@ -572,10 +584,11 @@ LONG ValidateSignature(HWND hDlg, const char* path)
// Check the signature name. Make it specific enough (i.e. don't simply check for "Akeo")
// so that, besides hacking our server, it'll place an extra hurdle on any malicious entity
// into also fooling a C.A. to issue a certificate that passes our test.
signature_name = GetSignatureName(path, cert_country);
signature_name = GetSignatureName(path, cert_country, (hDlg == INVALID_HANDLE_VALUE));
if (signature_name == NULL) {
uprintf("PKI: Could not get signature name");
MessageBoxExU(hDlg, lmprintf(MSG_284), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
if (hDlg != INVALID_HANDLE_VALUE)
MessageBoxExU(hDlg, lmprintf(MSG_284), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
return TRUST_E_NOSIGNATURE;
}
for (i = 0; i < ARRAYSIZE(cert_name); i++) {
@ -584,8 +597,9 @@ LONG ValidateSignature(HWND hDlg, const char* path)
}
if (i >= ARRAYSIZE(cert_name)) {
uprintf("PKI: Signature '%s' is unexpected...", signature_name);
if (MessageBoxExU(hDlg, lmprintf(MSG_285, signature_name), lmprintf(MSG_283),
MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES)
if ((hDlg == INVALID_HANDLE_VALUE) || (MessageBoxExU(hDlg,
lmprintf(MSG_285, signature_name), lmprintf(MSG_283),
MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES))
return TRUST_E_EXPLICIT_DISTRUST;
}
@ -615,6 +629,9 @@ LONG ValidateSignature(HWND hDlg, const char* path)
safe_free(trust_file.pcwszFilePath);
switch (r) {
case ERROR_SUCCESS:
// hDlg = INVALID_HANDLE_VALUE is used when validating the Fido PS1 script
if (hDlg == INVALID_HANDLE_VALUE)
break;
// Verify that the timestamp of the downloaded update is in the future of our current one.
// This is done to prevent the use of an officially signed, but older binary, as potential attack vector.
current_ts = GetSignatureTimeStamp(NULL);
@ -634,11 +651,13 @@ LONG ValidateSignature(HWND hDlg, const char* path)
case TRUST_E_NOSIGNATURE:
// Should already have been reported, but since we have a custom message for it...
uprintf("PKI: File does not appear to be signed: %s", WinPKIErrorString());
MessageBoxExU(hDlg, lmprintf(MSG_284), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
if (hDlg != INVALID_HANDLE_VALUE)
MessageBoxExU(hDlg, lmprintf(MSG_284), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
break;
default:
uprintf("PKI: Failed to validate signature: %s", WinPKIErrorString());
MessageBoxExU(hDlg, lmprintf(MSG_240), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
if (hDlg != INVALID_HANDLE_VALUE)
MessageBoxExU(hDlg, lmprintf(MSG_240), lmprintf(MSG_283), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
break;
}