Old 22nd October 2009, 21:21   #1
nsnb
Senior Member
 
Join Date: Jul 2008
Posts: 157
Question Test for a Valid Certificate?

Is there a way (or plugin) to test a digitally signed installer (with a code signing certificate), from within that installer, that the digital signature exists and valid?

That is, the the file has not been tampered with after it was signed?

I know how to do it visually, by looking at the corresponding Properties tab. Is it possible to do this programmatically from within the installer?

Thanks.
nsnb is offline   Reply With Quote
Old 23rd October 2009, 07:08   #2
MSG
Major Dude
 
Join Date: Oct 2006
Posts: 1,892
Wouldn't this be a chicken-egg problem? You can't enter the checksum in the installer without changing the installer's checksum...

Though I do seem to recall some signing solutions existing. Maybe someone else knows.
MSG is offline   Reply With Quote
Old 26th October 2009, 04:56   #3
nsnb
Senior Member
 
Join Date: Jul 2008
Posts: 157
Quote:
Originally posted by MSG
Wouldn't this be a chicken-egg problem? You can't enter the checksum in the installer without changing the installer's checksum...
Not really a chicken-and-egg because I don't expect to read the installer's checksum for that: The digital certificate is appended and itself includes a stronger hashing of the entire file.

The nice thing about those digital certificates is that if anyone modifies anything inside the file (e.g. infecting with a virus), one could see immediately from the tab that it is no longer signed by so called "verified publisher".

So, all we really need is a way to look at this "tab" and tell go/no-go.

Any idea how to do that?
nsnb is offline   Reply With Quote
Old 26th October 2009, 08:53   #4
820815
Junior Member
 
Join Date: Apr 2009
Location: St. Petersburg, Russia
Posts: 25
Quote:
Originally posted by MSG
You can't enter the checksum in the installer without changing the installer's checksum...
There's not a problem to fix its last four bytes.
820815 is offline   Reply With Quote
Old 26th October 2009, 09:37   #5
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 4,980
There is really no point to do this, NSIS already checks itself with a CRC (And "pirates" will get around it anyways, or just extract the files without running the installer)

If you really want to do this, call Wintrust::CryptCATAdminCalcHashFromFileHandle (and WTHelperGetProvSignerFromChain or CryptCATAdminEnumCatalogFromHash?) and WinVerifyTrust with the system plugin

See also:
http://forum.sysinternals.com/forum_posts.asp?TID=19404
http://forum.sysinternals.com/forum_...6893&PID=83634
http://forum.sysinternals.com/forum_posts.asp?TID=19247

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 26th October 2016, 10:11   #6
systracer
Junior Member
 
Join Date: Apr 2014
Posts: 12
Anders, sorry for raising old topic, but how it can be done? I'll try this:

FileOpen $R0 "C:\Test.exe" r
System::Call 'Kernel32::LoadLibrary(t "wintrust.dll")i.r0'
System::Call 'Kernel32::GetProcAddress(i r0, m "CryptCATAdminCalcHashFromFileHandle")i.r1'
System::Call "::$1(i R0, i 0, *i r2, i 0)?e"
Pop $0
FileClose $R0

But $2 has no hash. Please help with this, if you can...
systracer is offline   Reply With Quote
Old 26th October 2016, 19:22   #7
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 4,980
You don't have to manually call LoadLibrary.

The parameters should look like (i,*i,i,i0). First call it as (i $handle,*i.r2,i0,i0) and $2 will contain the size. Then allocate and call again with the third parameter set to the address of the memory you allocated.

If you are using NSIS3 you can try calling it once with something like System::Call 'wintrust::CryptCATAdminCalcHashFromFileHandle(p $handle,*i 999, @r3, i0)'

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 26th October 2016, 21:53   #8
systracer
Junior Member
 
Join Date: Apr 2014
Posts: 12
Thank you, your answer really helped!
systracer is offline   Reply With Quote
Old 23rd January 2019, 23:12   #9
systracer
Junior Member
 
Join Date: Apr 2014
Posts: 12
Good day! Can't figure out the CryptCATAdminEnumCatalogFromHash function. If you can, please tell me what my mistake is. I simplified the code, there is no error checking.

FileOpen $0 "C:\test.exe" r
System::Call 'wintrust::CryptCATAdminCalcHashFromFileHandle(p r0, *i 20, @r1, i0)'
FileClose $0
;$1 has hash
System::Call 'wintrust::CryptCATAdminAcquireContext(*i r0, i0, i0)'
System::Call 'wintrust::CryptCATAdminEnumCatalogFromHash(i r0, *p r1, i 20, i0, i0)i.r2'
System::Call 'wintrust::CryptCATAdminReleaseContext(i r0)'

$2 is always 0, i.e. not return handle to the catalog context. Thank you.
systracer is offline   Reply With Quote
Old 24th January 2019, 19:52   #10
systracer
Junior Member
 
Join Date: Apr 2014
Posts: 12
Maybe this helps, or this code:
code:
bool CheckByCat(const wchar_t *pwFileName)
{
HANDLE hCat;
if (!CryptCATAdminAcquireContext(&hCat, NULL, 0))
return false;

bool out = false;


HANDLE f = CreateFile(
pwFileName, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);


if (f != INVALID_HANDLE_VALUE)
{
BYTE hash[1024];
DWORD cb = sizeof(hash);
if (CryptCATAdminCalcHashFromFileHandle(f, &cb, hash, 0))
{
if(CryptCATAdminEnumCatalogFromHash(hCat, hash, cb, 0, 0))
out = true;
}
}

CryptCATAdminReleaseContext(hCat, 0);
::CloseHandle(f);

return out;
}

bool CheckByWinVerifyTrust(const wchar_t *pwFileName)
{
WINTRUST_FILE_INFO wfi={sizeof(WINTRUST_FILE_INFO), 0};
wfi.pcwszFilePath = pwFileName;
wfi.hFile = NULL;

WINTRUST_DATA wtd={sizeof(WINTRUST_DATA),0};
wtd.dwUIChoice = WTD_UI_NONE;
wtd.fdwRevocationChecks = WTD_REVOKE_NONE;
wtd.dwUnionChoice = WTD_CHOICE_FILE;
wtd.pFile = &wfi;

GUID g = WINTRUST_ACTION_GENERIC_VERIFY_V2;
LONG r = WinVerifyTrust(NULL, &g, &wtd);
return (r==ERROR_SUCCESS);
}

systracer is offline   Reply With Quote
Old 24th January 2019, 22:19   #11
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 4,980
PHP Code:
!include LogicLib.nsh
!define /ifndef MAX_PATH 260
Section 
FileOpen 
$"$windir\explorer.exe" r
System
::Call 'wintrust::CryptCATAdminCalcHashFromFileHandle(p r0, *i 666 r3, @r1, i0)i.r2'
FileClose $0
DetailPrint 
"succ=$2 size=$3"
System::Call 'wintrust::CryptCATAdminAcquireContext(*p 0 r0, p0, i0)i.r2'
${If} $<> 0
    System
::Call 'wintrust::CryptCATAdminEnumCatalogFromHash(p r0, p r1, i r3, i0, p0)p.r2 ?e'
    
Pop $4
    
${If} $2 P<> 0
        DetailPrint 
"Catalog context handle: $2"
        
System::Call '*$1(&l4,&w${MAX_PATH})' NoteOverwriting the hash data hereallocate new memory here if you still need the hash data
        System
::Call 'wintrust::CryptCATCatalogInfoFromContext(pr2, pr1, i0)i.r4'
        
${If} $<> 0
            System
::Call '*$1(&l4,&w${MAX_PATH}.r5)'
            
DetailPrint "Catalog path: $5"
        
${EndIf}
        
System::Call 'wintrust::CryptCATAdminReleaseCatalogContext(pr0, pr2, i0)'
    
${Else}
        
DetailPrint "wintrust::CryptCATAdminEnumCatalogFromHash failed with error $4"
    
${EndIf}
    
System::Call 'wintrust::CryptCATAdminReleaseContext(p r0, i0)'
${EndIf}
SectionEnd 
If there is a catalog you can call WinVerifyTrust with WTD_CHOICE_CATALOG and WINTRUST_CATALOG_INFO data.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 25th January 2019, 08:43   #12
systracer
Junior Member
 
Join Date: Apr 2014
Posts: 12
Anders, thank you very much, you are a genius!
systracer is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
cert, security, wintrust

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump