Click to Rate and Give Feedback
MSDN
MSDN Library
Windows Development
Cryptography
Using Cryptography
 Example C Program: Verifying the Si...
Example C Program: Verifying the Signature of a PE File

The WinVerifyTrust API can be used to verify the signature of a portable executable file.

The following example shows how to use the WinVerifyTrust API to verify the signature of a signed portable executable file.

C++
//-------------------------------------------------------------------
// Copyright (C) Microsoft.  All rights reserved.
// Example of verifying the embedded signature of a PE file by using 
// the WinVerifyTrust function.

#define _UNICODE 1
#define UNICODE 1

#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <Softpub.h>
#include <wincrypt.h>
#include <wintrust.h>

// Link with the Wintrust.lib file.
#pragma comment (lib, "wintrust")

BOOL VerifyEmbeddedSignature(LPCWSTR pwszSourceFile)
{
    LONG lStatus;
    DWORD dwLastError;

    // Initialize the WINTRUST_FILE_INFO structure.

    WINTRUST_FILE_INFO FileData;
    memset(&FileData, 0, sizeof(FileData));
    FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
    FileData.pcwszFilePath = pwszSourceFile;
    FileData.hFile = NULL;
    FileData.pgKnownSubject = NULL;

    /*
    WVTPolicyGUID specifies the policy to apply on the file
    WINTRUST_ACTION_GENERIC_VERIFY_V2 policy checks:
    
    1) The certificate used to sign the file chains up to a root 
    certificate located in the trusted root certificate store. This 
    implies that the identity of the publisher has been verified by 
    a certification authority.
    
    2) In cases where user interface is displayed (which this example
    does not do), WinVerifyTrust will check for whether the  
    end entity certificate is stored in the trusted publisher store,  
    implying that the user trusts content from this publisher.
    
    3) The end entity certificate has sufficient permission to sign 
    code, as indicated by the presence of a code signing EKU or no 
    EKU.
    */

    GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
    WINTRUST_DATA WinTrustData;

    // Initialize the WinVerifyTrust input data structure.

    // Default all fields to 0.
    memset(&WinTrustData, 0, sizeof(WinTrustData));

    WinTrustData.cbStruct = sizeof(WinTrustData);
    
    // Use default code signing EKU.
    WinTrustData.pPolicyCallbackData = NULL;

    // No data to pass to SIP.
    WinTrustData.pSIPClientData = NULL;

    // Disable WVT UI.
    WinTrustData.dwUIChoice = WTD_UI_NONE;

    // No revocation checking.
    WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE; 

    // Verify an embedded signature on a file.
    WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;

    // Default verification.
    WinTrustData.dwStateAction = 0;

    // Not applicable for default verification of embedded signature.
    WinTrustData.hWVTStateData = NULL;

    // Not used.
    WinTrustData.pwszURLReference = NULL;

    // This is not applicable if there is no UI because it changes 
    // the UI to accommodate running applications instead of 
    // installing applications.
    WinTrustData.dwUIContext = 0;

    // Set pFile.
    WinTrustData.pFile = &FileData;

    // WinVerifyTrust verifies signatures as specified by the GUID 
    // and Wintrust_Data.
    lStatus = WinVerifyTrust(
        NULL,
        &WVTPolicyGUID,
        &WinTrustData);

    switch (lStatus) 
    {
        case ERROR_SUCCESS:
            /*
            Signed file:
                - Hash that represents the subject is trusted.

                - Trusted publisher without any verification errors.

                - UI was disabled in dwUIChoice. No publisher or 
                    time stamp chain errors.

                - UI was enabled in dwUIChoice and the user clicked 
                    "Yes" when asked to install and run the signed 
                    subject.
            */
            wprintf_s(L"The file \"%s\" is signed and the signature "
                L"was verified.\n",
                pwszSourceFile);
            break;
        
        case TRUST_E_NOSIGNATURE:
            // The file was not signed or had a signature 
            // that was not valid.

            // Get the reason for no signature.
            dwLastError = GetLastError();
            if (TRUST_E_NOSIGNATURE == dwLastError ||
                    TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError ||
                    TRUST_E_PROVIDER_UNKNOWN == dwLastError) 
            {
                // The file was not signed.
                wprintf_s(L"The file \"%s\" is not signed.\n",
                    pwszSourceFile);
            } 
            else 
            {
                // The signature was not valid or there was an error 
                // opening the file.
                wprintf_s(L"An unknown error occurred trying to "
                    L"verify the signature of the \"%s\" file.\n",
                    pwszSourceFile);
            }

            break;

        case TRUST_E_EXPLICIT_DISTRUST:
            // The hash that represents the subject or the publisher 
            // is not allowed by the admin or user.
            wprintf_s(L"The signature is present, but specifically "
                L"disallowed.\n");
            break;

        case TRUST_E_SUBJECT_NOT_TRUSTED:
            // The user clicked "No" when asked to install and run.
            wprintf_s(L"The signature is present, but not "
                L"trusted.\n");
            break;

        case CRYPT_E_SECURITY_SETTINGS:
            /*
            The hash that represents the subject or the publisher 
            was not explicitly trusted by the admin and the 
            admin policy has disabled user trust. No signature, 
            publisher or time stamp errors.
            */
            wprintf_s(L"CRYPT_E_SECURITY_SETTINGS - The hash "
                L"representing the subject or the publisher wasn't "
                L"explicitly trusted by the admin and admin policy "
                L"has disabled user trust. No signature, publisher "
                L"or timestamp errors.\n");
            break;

        default:
            // The UI was disabled in dwUIChoice or the admin policy 
            // has disabled user trust. lStatus contains the 
            // publisher or time stamp chain error.
            wprintf_s(L"Error is: 0x%x.\n",
                lStatus);
            break;
    }

    return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if(argc > 1)
    {
        VerifyEmbeddedSignature(argv[1]);
    }

    return 0;
}


 

 

Send comments about this topic to Microsoft

Build date: 3/6/2012

Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Great Example      Wolferajd_fur   |   Edit   |   Show History

This code is wonderful, I had no problems applying it into my application.

To everyone having troubles, you have to make sure you have typedef of WinVerifyTrust, that your program actually does load wintrust.dll and that you included wintrust.h. Entire procedure can be easly customized after someone bothers to read http://msdn.microsoft.com/en-us/library/windows/desktop/aa388205(v=vs.85).aspx 

I've personally prefered to modify procedure to return (lResults) which is more prefered behavior for me as that way I can call this procedure from any place of my program or even export it to other programs.

Tags What's this?: Add a tag
Flag as ContentBug
Catalog Traversal missing      Deep [MSFT]   |   Edit   |   Show History
@Oren

The reason you find many things not not appearing signed could be because the above code does not go and validate signatures provided through catalog files. I recommend the above sample be updated to handle catalogs as well although sample code for enhancing the above to traverse catalogs exist in sysinternals forums.
Tags What's this?: Add a tag
Flag as ContentBug
doesn't compile...      snickered   |   Edit   |   Show History
Need working code for noobies that can't code. I get: $0$0 $0 $0"error C2275: 'GUID' : illegal use of this type as an expression"$0 $0$0 $0 $0 $0$0 $0 $0
Tags What's this?: Add a tag
Flag as ContentBug
Fails to verify most files      Oren_Slidigo   |   Edit   |   Show History
Running this sample on most files in the windows directory (explorer.exe, Notepad.exe, DLLs, etc.) returns:
"The file "c:\Windows\explorer.exe" is not signed."

Other utilities such as process explorer report explorer.exe as signed.

[OS = Win 7 32 and Win 7 64 bit]

I guess there is something missing (in my understanding or in the example code)
Tags What's this?: Add a tag
Flag as ContentBug
Example flawed      Mike Hudgell ... vladplus   |   Edit   |   Show History
The example should be modified so that it returns false in the event of failure, not true as it currently always does.
Processing
© 2012 Microsoft. All rights reserved. Terms of Use | Trademarks | Privacy Statement
Page view tracker