Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PE file signature verification

554 views
Skip to first unread message

Joe Mueller

unread,
Feb 21, 2002, 4:47:15 PM2/21/02
to
I'm writing an application in which I would like to verify
the files I'm using have come from my company and have not
been tampered with. The file signing mechanism described
for Authenticode looks like a good match, unfortunately
the documentation for how to verify the signature is
sparse. I do not want the application to prompt the user
for approval of a certificate and I want the application
to verify that the file has been signed with "my"
certificate (and not someone else's). The following code
verifies the file is signed properly (and avoids asking
the user anything), but my understanding is that this
function only verifies the file has a valid signature, not
that it contains "my" signature. It's also unclear what
would happen if there were multiple certificates attached
to the file (can someone tell me?) It looks like I can use
ImageGetCertificateData to retrieve the signature
certificate from the file, but there doesn't appear to be
a way to establish a context for the returned certificate
so I can use CertComparePublicKeyInfo (or some other
function) to see if the public key used to sign the file
matches "my" public key. The certificate returned from
ImageGetCertificateData has a wCertificateType value of
WIN_CERT_TYPE_PKCS_SIGNED_DATA, and a wRevision value of
WIN_CERT_REVISION_2_0 (even though the current msdn says
only revision 1_0 is defined). Can someone please define
the structure of the returned SignedData certificate
and/or point me in the right direction to verify
programatically who signed the file?

Thanks in advance,
Joe Mueller

GUID action_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA trust_data;
WINTRUST_FILE_INFO file_info;

memset(&file_info, 0, sizeof(file_info));
file_info.cbStruct = sizeof(file_info);
file_info.pcwszFilePath = L"C:\\somefile.dll";

memset(&trust_data, 0, sizeof(trust_data));
// fill in the trust data
trust_data.cbStruct = sizeof(trust_data);
trust_data.dwUIChoice = WTD_UI_NONE;
trust_data.fdwRevocationChecks =
WTD_REVOKE_WHOLECHAIN;
trust_data.dwUnionChoice = WTD_CHOICE_FILE;
trust_data.pFile = &file_info;

HRESULT result;
result = WinVerifyTrust((HWND)
INVALID_HANDLE_VALUE, &action_guid, &trust_data);
if (result != ERROR_SUCCESS) {
printf("Verification failed, code: 0x%
x\n", result);
return NULL;
}
// Authenticode check succeeded, now verify the
certificate used to sign the dll is ours
HANDLE dll_handle = CreateFile("C:\\somefile.dll",
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
if (dll_handle == INVALID_HANDLE_VALUE) {
return NULL;
}
DWORD cert_count;
if (!ImageEnumerateCertificates(dll_handle,
CERT_SECTION_TYPE_ANY, &cert_count, NULL, 0)) {
CloseHandle(dll_handle);
return NULL;
}

// there should only be one certificate associated
with this dll, ours
if (cert_count != 1) {
CloseHandle(dll_handle);
return NULL;
}

// assume most certificates will fit into a 1024
byte buffer
DWORD cert_len = 1024;
LPVOID cert = malloc(sizeof(WIN_CERTIFICATE) +
cert_len);
if (cert == NULL) {
CloseHandle(dll_handle);
return NULL;
}

WIN_CERTIFICATE *cert_p = (WIN_CERTIFICATE*)cert;
cert_p->dwLength = cert_len;
cert_p->wRevision = WIN_CERT_REVISION_1_0;
DWORD actual_cert_len;

// first get the certificate header to see if our
certificate structure is large enough, if not,
// grow it to the proper size
if (!ImageGetCertificateHeader(dll_handle, 0,
cert_p)) {
// problem getting certificate
information, return failure
CloseHandle(dll_handle);
free(cert);
return NULL;
}
if (cert_p->dwLength > cert_len) {
// need to grow buffer
cert_len = cert_p->dwLength;
cert = realloc(cert, cert_len);
if (cert == NULL) {
CloseHandle(dll_handle);
return NULL;
}
cert_p->dwLength = cert_len;
cert_p->wRevision = WIN_CERT_REVISION_1_0;
}
actual_cert_len = cert_len; // preserve
certificate buffer length by using new variable
if (!ImageGetCertificateData(dll_handle, 0,
cert_p, &actual_cert_len)) {
// problem getting certificate, return
failure
CloseHandle(dll_handle);
free(cert);
return NULL;
}
// done with file handle, close it
CloseHandle(dll_handle);
// At this point I have the SignedData certificate
pointed to by cert_p, but now what do I do to compare it's
public key information with my public key???

Carlos Lopez

unread,
Feb 25, 2002, 9:27:35 PM2/25/02
to
Microsoft is providing this type of support in CAPICOM 2.0. The beta
version should be released soon. It will be posted on the Microsoft
website. Getting signer information will be straight forward with CAPICOM
2.0.

thanks
Carlos

This posting is provided 'AS IS' with no warranties, and confers no rights.

Joe Mueller

unread,
Apr 9, 2002, 2:33:06 PM4/9/02
to
Actually, there's no need to wait for CAPICOM. I
discovered the way to do what I wanted through a lot of
headscratching and trial and error. Attached is a function
that will verify a signature on a file and insure it was
signed by the appropriate company (In this case YoYoDyne
Corporation)

I counted several queries on how do do this in the
newsgroups, perhaps Microsoft should add this example (or
the other one by Daniel Sie, or both) to MSDN.

I'm posting this in hope that it will help someone else.
Please let me know if you see errors in this solution.

>.
>

verify.txt
0 new messages