I'm a newbie to the cryptoAPI so forgive me my ignorance.
How do you verify that a digitally signed executable has not been
hacked? I was thinking that by comparing the hashvalue of the
executable with the hash value in the signature you'd be able to do
this.
I cannot use CAPICOM as the target systems are likely not to have
CAPICOM installed. I cannot use WinVerifyTrust as this function takes
several seconds to return, generates unwanted network activity and
temporarily hogs the CPU and memory of the target system.
If anyone is able to outline the function calls or provide a code
snippet for my task I'd be very grateful. I was thinking that functions
such as CryptVerifyCertificateSignature or CryptVerifySignature would
be useful for this. However, there are no good examples on the MSDN on
how to do this.
thanks,
Rob
Paul
<rob...@oeffner.net> wrote in message
news:1129321315.8...@f14g2000cwb.googlegroups.com...
thanks,
Rob
thanks,
Rob
What do you mean by "hashvalue stored in the CERTIFICATE" ??
You surely mean the hash value (of the indirect exe content) contained in
the signature blob within the signed exe?
At the minimum, you need a process that verifies the signature and that recognizes
the signature signer as someone you know and implicitly trust. Network access
might be related to checking the cert. revocation. Otherwise there should be no
network access.
- Mitch Gallant
MVP Security
www.jensign.com
<rob...@oeffner.net> wrote in message news:1129326037....@g49g2000cwa.googlegroups.com...
This is my (perhaps mistaken) understanding of the subject.
1) A digital signature is a file containing a public key that
identifies the signer.
2) Signing an executable file with this signature amounts to computing
a hash value of the file, encrypting this value with the signers
private key and concatenating the signature file to the end of the
executable file.
3) The signature also contains the encrypted hash value of the
executable.
4) Another user can now use the public key to decrypt the encrypted
hash value in the signature and then compare it against the actual hash
value of the executable file. If they differ s/he knows that the
executable file has been hacked.
I was hoping that functions like CryptVerifyCertificateSignature or
CryptVerifySignature could do step 4 for me here.
In my code I tried calling
CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerInfo,
&dn);
so that I could use pSignerInfo->SubjectPublicKeyInfo as an argument
for CryptVerifyCertificateSignature. However, the
pSignerInfo->SubjectPublicKeyInfo member is not initialised after
calling CryptMsgGetParam so this doesn't work.
In short (assuming my above understanding is correct) my question is
therefore how do I get the signers public key of a signature on an
executable file.
Thanks,
Rob
[Usually the public key that is used is (in a completely different process) contained
in a standard X.509v3 certificate. This certificate, in turn has it's OWN signature
contained therein ... signed by the issuing CA's private key.]
Now the basic PKCS#1 signature (encrypted hash) is often encapsulated in another
"higher-level" format called a PKCS#7 signature. Most of the capi "Signed Message"
documentation refers to this CMS/PKCS#7 signature. The PKCS#7 typically includes some
full certificates (typically including the one whose public key was used to generate
the included pkcs#1 signature). This PKCS#7 signature may, or may NOT contain
the actual data that was signed; in the later case, the pkcs#7 signature is called a
"detached" signature. Here is a screen-shot which might help in visualization what
is contained in such pkcs#7 signatures:
http://www.jensign.com/JavaScience/sigview
Now, an Authenticode signature (on a PE file) is built on these ideas. It is a PE
file where the exe data AND the PKCS#7 signature over SOME of the PE data is merged.
You want to verify the signature contained in the signed PE file. If you read my original
pointer to the article on authencode details, you'll see that the exe signature is
actually a DETACHED PKCS#7 signature appended to the tail-end of the Authenticode
signed PE file. If you read that article, you know that it should be possible (with
CAPI functions and parsing of the exe headers) to extract the signature, get the public
key from the included signer's certificate, decrypt the encrypted hash, get the content
that is what is covered by the signature and recalculate the hash. It is just more complicated.
WinVerifyTrust api takes care of these details. CAPICOM SignedCode.Verify() does that also,
(probably invoking underlying WinVerifyTrust api).
I think you can probably change the Authenticode verification policy (used by WinVerifyTrust)
to avoid CRL /network access checking .. but that is (I believe) a system policy setting and
not good to tamper with that.
- Mitch Gallant
MVP Security
<rob...@oeffner.net> wrote in message news:1129397027.6...@g49g2000cwa.googlegroups.com...
Thanks,
Rob
// first get the certificate header to get the proper size for
certificate structure
WIN_CERTIFICATE certHead;
certHead.dwLength = 0;
certHead.wRevision = WIN_CERT_REVISION_1_0;
HANDLE dll_handle = CreateFile("MyExefile.exe", GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
if (!ImageGetCertificateHeader(dll_handle, 0, &certHead))
{
// problem getting certificate information, return
failure
CloseHandle(dll_handle);
return false;
}
// allocate memory for certificate
DWORD cert_len = certHead.dwLength;
char* cert = new char[sizeof(WIN_CERTIFICATE) + cert_len];
WIN_CERTIFICATE *cert_p = (WIN_CERTIFICATE*)cert;
cert_p->dwLength = cert_len;
cert_p->wRevision = WIN_CERT_REVISION_1_0;
if (!ImageGetCertificateData(dll_handle, 0, cert_p, &cert_len))
{
// problem getting certificate, return failure
CloseHandle(dll_handle);
delete [] cert;
return false;
}
DWORD decodesize = 0;
PCCERT_CONTEXT pCertContext;
CRYPT_VERIFY_MESSAGE_PARA vPara;
memset(&vPara, 0, sizeof(vPara));
vPara.cbSize = sizeof(vPara);
vPara.dwMsgAndCertEncodingType = X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING;
DWORD nret = CryptVerifyMessageSignature(&vPara, 0,
cert_p->bCertificate,
cert_p->dwLength, NULL, &decodesize, &pCertContext);
HCRYPTPROV hProv;
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))
err= GetLastError();
HCRYPTKEY hpubKey;
if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
&pCertContext->pCertInfo->SubjectPublicKeyInfo,
&hpubKey))
err= GetLastError();
HCRYPTHASH hHash;
if(!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
err= GetLastError();
// Compute the cryptographic hash of the buffer.
CRYPT_DATA_BLOB blob;
blob.cbData = GetFileSize(dll_handle, 0);
blob.pbData = new BYTE[GetFileSize(dll_handle, 0)];
unsigned long nrd;
ReadFile(dll_handle, blob.pbData, blob.cbData, &nrd, NULL);
if(!CryptHashData(hHash, blob.pbData, blob.cbData, 0))
err= GetLastError();
//little endian the signature
BYTE* bsign = new BYTE[cert_p->dwLength];
for (int i=0; i<cert_p->dwLength; i++)
bsign[i] =
((BYTE*)cert_p->bCertificate)[cert_p->dwLength-i];
if(!CryptVerifySignature(hHash, bsign, cert_p->dwLength,
(HCRYPTKEY)pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
"", 0))
err= GetLastError();
As I said before, you need to look in detail at the how the data (which is what
is hashed) is indirectly (detached signature) configured in the head of a signed PE file
as documented (unofficially) here:
http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
Just go through that article and spend the time required to understand it.
- Mitch
<rob...@oeffner.net> wrote in message news:1129462550.0...@g49g2000cwa.googlegroups.com...
> So to verify a signature on an executable file you create a hash value
> and verify it against the signature by using the public key of the
> signer or to be more explicitly by calling CryptVerifySignature. In the
> code below I think the problem is with what I'm hashing. GetLastError
> after CryptVerifySignature reports ERROR_INVALID_PARAMETER.
> Does anyone know what arguments I should pass into CryptHashData?
>
> Thanks,
>
> Rob
>
- snip
I now know much more about certificates than I'll ever want or need. It
would be good if Microsoft could issue a couple of more examples on
this subject. The huge documentation could do with some revision. It
took me a while to appreciate the differences between a pkcs1 signature
(a hash value) and a pkcs7 signature, let alone the missing
documentation about the need to reverse bytes when calling
CryptVerifySignature, unacceptable in my opinion.
Thanks for your patience,
rob
Agree with MSDN docs on crypto (byte-reversal .. pkcs1 vs pkcs7 sigs).
Unfortunately many learn this through lots of hands on experience :-)
- Mitch
<rob...@oeffner.net> wrote in message news:1129550422.3...@f14g2000cwb.googlegroups.com...
- Mitch
"Michel Gallant" <neu...@istar.ca> wrote in message news:uhT8yJy0...@TK2MSFTNGP12.phx.gbl...
Rob
<rob...@oeffner.net> wrote in message news:1129585912.3...@g47g2000cwa.googlegroups.com...
I'm wondering what data in a certificate is unique and immutable
throughout each renewal of a certificate. The plain name is obviously
not good enough.
Rob
Paul
<rob...@oeffner.net> wrote in message
news:1129326037....@g49g2000cwa.googlegroups.com...
Paul
"Paul Baker" <pa...@online.rochester.rr.com> wrote in message
news:%238fkAAC...@TK2MSFTNGP10.phx.gbl...