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

CertEnumCertificatesInStore Doesn't Return all Certificates

791 views
Skip to first unread message

coretrace

unread,
Dec 8, 2009, 1:23:02 PM12/8/09
to
I'm attempting to iterate over each of the signing certificates embedded
within an executable. I use the CryptQueryObject to get the HCERTSTORE and
then use that HCERTSTORE to enumerate over the certificates in the file. It
works most of the time but occasionally it does not return the root
certificate. It will always fail on the same file and will return some of the
certificates but not all.

When I inspect the files with SignTool the certificates are present, but the
CertEnumCertificatesInStore does not always return all of the certificates.


Code fragment below

list <CertificateInfo *>getSigningCertsFromStore2(HCERTSTORE store) {
PCCERT_CONTEXT currContext = NULL;
list < CertificateInfo * >ret;
while( currContext = CertEnumCertificatesInStore( store, currContext ) ) {
if( currContext != NULL ) {
CertificateInfo *cert = new CertificateInfo(
currContext->pbCertEncoded, currContext->cbCertEncoded );
if( isSigningBased(currContext) ) {
ret.push_back( cert );
} else {
// TO verify that we didn't reject the root cert.
printf("Rejected Cert, Subject=%s\n",
cert->getSubject().c_str());
}
}
} while( currContext != NULL );
ret = orderCerts(ret);
return ret;
}

list < CertificateInfo * >getEmbeddedCertificateFromFile( const char
*filepath )
{
HCERTSTORE store = NULL;
HCRYPTMSG msg = NULL;
DWORD encoding,
content,
format;

list < CertificateInfo * >ret;
WCHAR wideFilePath[MAX_PATH];

MultiByteToWideChar( CP_ACP, 0, filepath, -1, wideFilePath, MAX_PATH );
if ( CryptQueryObject( CERT_QUERY_OBJECT_FILE,
wideFilePath,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&encoding,
&content,
&format,
&store,
&msg,
NULL ) != 0 ) {
ret = getSigningCertsFromStore2(store);
}
if( store != NULL ) {
CertCloseStore( store, 0);
}
if ( msg != NULL ) {
CryptMsgClose( msg );
}
return ret;
}


Stardust

unread,
Dec 10, 2009, 4:34:01 PM12/10/09
to
A local list is returned from the function. The list you have now is
allocated on the stack and accessing the variables allocated on the stack is
a logic error. You would have to allocate the list on the heap. Something
like:

list <certificateinfo*> pList = new list <>

and return this.

Also you can simplifly your code:
a) You don't need "if( currContext != NULL )" since you won't enter the
first "while loop" unless the above condition is true.

b) You don't need the second while loop. Remove it.

Other than the above, I don't see anything wrong with the code in the "while
loop" except I don't know what orderCerts is doing. It's highly UNLIKELY that
CertEnumCertificateStore is not returning your cert. Remember that it is a
highly tested method.

Also put a print statement as soon as you got a certificate from the Store,
it should be as follows:

while( currContext = CertEnumCertificatesInStore( store, currContext ) ) {

print the subject name, serial number of the ceritificate
...
}

And make sure it is returning it.

Hope this helps.

coretrace

unread,
Dec 11, 2009, 12:49:01 PM12/11/09
to
The local list returned on the stack is handled by STL, but that's not the
issue. The code I've used was just to shorten the source and as an example
and is not part of my actual product code.

The fundamental problem is that CertEnumCertificatesInStore is not returning
all of the certs. If I single step within the debugger it only returns 2 out
of 3 of the certificates that the Properties in the file explorer. I can use
other methods such as the following code, and it too only returns 2 of the 3
certificates. Is there some sort of initialization or other steps prior to
these calls that need to be executed?

list <CertificateInfo *>getSigningCertsFromStore(HCERTSTORE store) {
PCCERT_CONTEXT currContext = NULL;
CERT_ENHKEY_USAGE usage;
list < CertificateInfo * >ret;

memset(&usage, 0, sizeof(usage));
usage.cUsageIdentifier = 1;
usage.rgpszUsageIdentifier = new char *[1];
usage.rgpszUsageIdentifier[0] = szOID_PKIX_KP_CODE_SIGNING;
do {
currContext = CertFindCertificateInStore( store, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING , 0, CERT_FIND_ANY, &usage, currContext);
if( currContext != NULL ) {
if( isSigningBased(currContext) ) {


CertificateInfo *cert = new CertificateInfo(
currContext->pbCertEncoded, currContext->cbCertEncoded );

ret.push_back( cert );
}
CertFreeCertificateContext( currContext );


}
} while( currContext != NULL );

delete usage.rgpszUsageIdentifier;
return ret;

Stardust

unread,
Jan 22, 2010, 8:35:01 PM1/22/10
to
Don't free the currContext explicitly. The API frees it automatically. That
could be the reason why you are seeing this issue.

From MSDN "A non-NULLCERT_CONTEXT that CertFindCertificateInStore returns
must be freed by CertFreeCertificateContext or by being passed as the
pPrevCertContext parameter on a subsequent call to
CertFindCertificateInStore."

It can't be both. Also I am not sure whether you have noticed but when you
say CERT_FIND_ANY the API ignores usage variable.

CERT_FIND_ANY - "Data type of pvFindPara: NULL, not used."

0 new messages