Sysinternals Homepage
Forum Home Forum Home > Windows Discussions > Development
  New Posts New Posts RSS Feed - HOWTO: Verify the digital signature of a file
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

Topic ClosedHOWTO: Verify the digital signature of a file

 Post Reply Post Reply
Author
Message
a_d_13 View Drop Down
Senior Member
Senior Member
Avatar

Joined: 08 September 2007
Status: Offline
Points: 268
Direct Link To This Post Topic: HOWTO: Verify the digital signature of a file
    Posted: 09 June 2009 at 11:08pm
Hello all,

Well, I recently implemented digital signature verification into RootRepeal.  I found out that there's not any good examples of how to do this out on the Internet.  So, here's some sample code that shows how to properly verify the digital signature on a file.  This seems to work, based on what I've seen, but it's mostly a result of reversing, so I may have missed something.  It also hasn't been tested extensively on all system configurations, but it seems to work on Windows 2000+.

BOOLEAN IsFileDigitallySigned(PWCHAR FilePath)
{
    //Author: AD, 2009
    PVOID Context;
    HANDLE FileHandle;
    DWORD HashSize = 0;
    PBYTE Buffer;
    PVOID CatalogContext;
    CATALOG_INFO InfoStruct;
    WINTRUST_DATA WintrustStructure;
    WINTRUST_CATALOG_INFO WintrustCatalogStructure;
    WINTRUST_FILE_INFO WintrustFileStructure;
    PWCHAR MemberTag;
    BOOLEAN ReturnFlag = FALSE;
    ULONG ReturnVal;
    GUID ActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;

    //Zero our structures.
    memset(&InfoStruct, 0, sizeof(CATALOG_INFO));
    InfoStruct.cbStruct = sizeof(CATALOG_INFO);
    memset(&WintrustCatalogStructure, 0, sizeof(WINTRUST_CATALOG_INFO));
    WintrustCatalogStructure.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
    memset(&WintrustFileStructure, 0, sizeof(WINTRUST_FILE_INFO));
    WintrustFileStructure.cbStruct = sizeof(WINTRUST_FILE_INFO);

    //Get a context for signature verification.
    if( !CryptCATAdminAcquireContext(&Context, NULL, 0) )
    {
        return FALSE;
    }

    //Open file.
    FileHandle = CreateFileW(FilePath, GENERIC_READ, 7, NULL, OPEN_EXISTING, 0, NULL);
    if( INVALID_HANDLE_VALUE == FileHandle )
    {
        CryptCATAdminReleaseContext(Context, 0);
        return FALSE;
    }

    //Get the size we need for our hash.
    CryptCATAdminCalcHashFromFileHandle(FileHandle, &HashSize, NULL, 0);
    if( HashSize == 0 )
    {
        //0-sized has means error!
        CryptCATAdminReleaseContext(Context, 0);
        CloseHandle(FileHandle);
        return FALSE;
    }

    //Allocate memory.
    Buffer = (PBYTE)calloc(HashSize, 1);

    //Actually calculate the hash
    if( !CryptCATAdminCalcHashFromFileHandle(FileHandle, &HashSize, Buffer, 0) )
    {
        CryptCATAdminReleaseContext(Context, 0);
        free(Buffer);
        CloseHandle(FileHandle);
        return FALSE;
    }

    //Convert the hash to a string.
    MemberTag = (PWCHAR)calloc((HashSize * 2) + 1, sizeof(WCHAR));
    for( unsigned int i = 0; i < HashSize; i++ )
    {
        swprintf(&MemberTag[i * 2], L"%02X", Buffer[i ]);
    }

    //Get catalog for our context.
    CatalogContext = CryptCATAdminEnumCatalogFromHash(Context, Buffer, HashSize, 0, NULL);
    if ( CatalogContext )
    {
        //If we couldn't get information
        if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
        {
            //Release the context and set the context to null so it gets picked up below.
            CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
            CatalogContext = NULL;
        }
    }
       
    //If we have a valid context, we got our info. 
    //Otherwise, we attempt to verify the internal signature.
    if( !CatalogContext )
    {
        WintrustFileStructure.cbStruct = sizeof(WINTRUST_FILE_INFO);
        WintrustFileStructure.pcwszFilePath = FilePath;
        WintrustFileStructure.hFile = NULL;
        WintrustFileStructure.pgKnownSubject = NULL;

        WintrustStructure.cbStruct = sizeof(WINTRUST_DATA);
        WintrustStructure.dwUnionChoice = WTD_CHOICE_FILE;
        WintrustStructure.pFile = &WintrustFileStructure;
        WintrustStructure.dwUIChoice = WTD_UI_NONE;
        WintrustStructure.fdwRevocationChecks = WTD_REVOKE_NONE;
        WintrustStructure.dwStateAction = WTD_STATEACTION_IGNORE;
        WintrustStructure.dwProvFlags = WTD_SAFER_FLAG;
        WintrustStructure.hWVTStateData = NULL;
        WintrustStructure.pwszURLReference = NULL;
    } else
    {
        //If we get here, we have catalog info!  Verify it.
        WintrustStructure.cbStruct = sizeof(WINTRUST_DATA);
        WintrustStructure.pPolicyCallbackData = 0;
        WintrustStructure.pSIPClientData = 0;
        WintrustStructure.dwUIChoice = WTD_UI_NONE;
        WintrustStructure.fdwRevocationChecks = WTD_REVOKE_NONE;
        WintrustStructure.dwUnionChoice = WTD_CHOICE_CATALOG;
        WintrustStructure.pCatalog = &WintrustCatalogStructure;
        WintrustStructure.dwStateAction = WTD_STATEACTION_VERIFY;
        WintrustStructure.hWVTStateData = NULL;
        WintrustStructure.pwszURLReference = NULL;
        WintrustStructure.dwProvFlags = 0;
        WintrustStructure.dwUIContext = WTD_UICONTEXT_EXECUTE;

        //Fill in catalog info structure.
        WintrustCatalogStructure.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
        WintrustCatalogStructure.dwCatalogVersion = 0;
        WintrustCatalogStructure.pcwszCatalogFilePath = InfoStruct.wszCatalogFile;
        WintrustCatalogStructure.pcwszMemberTag = MemberTag;
        WintrustCatalogStructure.pcwszMemberFilePath = FilePath;
        WintrustCatalogStructure.hMemberFile = NULL;
    }

    //Call our verification function.
    ReturnVal = WinVerifyTrust(0, &ActionGuid, &WintrustStructure);

    //Check return.
    ReturnFlag = SUCCEEDED(ReturnVal);

    //Free context.
    if( CatalogContext )
        CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);

    //If we successfully verified, we need to free.
    if( ReturnFlag )
    {
        WintrustStructure.dwStateAction = WTD_STATEACTION_CLOSE;
        WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
    }

    //Free memory.
    free(MemberTag);
    free(Buffer);
    CloseHandle(FileHandle);
    CryptCATAdminReleaseContext(Context, 0);

    return ReturnFlag;
}


To make this work, you need to include the following headers:
#include <Softpub.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <mscat.h>
#include <wchar.h>


You also need to link with wintrust.lib - you can do this with:
#pragma comment(lib, "wintrust")


If you have any problems with this code, or if I've missed something, please let me know!  As usual, please use at your own risk, etc.

Thanks,
--AD

EDIT: Spelling.


Edited by a_d_13 - 09 June 2009 at 11:09pm
Back to Top
molotov View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 04 October 2006
Status: Offline
Points: 17531
Direct Link To This Post Posted: 24 June 2009 at 11:54am
Please discuss this topic here:
Discuss: HOWTO: Verify digital signature of a file
Daily affirmation:
net helpmsg 4006
Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down

Forum Software by Web Wiz Forums® version 11.06
Copyright ©2001-2016 Web Wiz Ltd.