1

What API can I use to get the "Key Usage" from a certificate. I Specifically want to know if a given certificate has "Digital Signature" or not. Below screenshot is the detail of a certificate in windows. I need the API that gives me the "Key Usage". The code is for windows and I am writing my code in C++.

enter image description here

Thank you

Sam

1

2 Answers 2

3

Start with CertOpenStore, then call CertFindCertificateInStore in a loop until you find the certificate you are interested in.

The returned CERT_CONTEXT contains a pointer to a CERT_INFO struct. You will then want to walk the rgExtension member which is an array of CERT_EXTENSION objects. The one you care about has pszObjId set to szOID_KEY_USAGE_RESTRICTION, which will then give you this data: CERT_KEY_USAGE_RESTRICTION_INFO where the RestrictedKeyUsage member has the bit flags you are interested in.

You can also look at the szOID_KEY_USAGE extension, which will use the same bit flags, but the msdn documentation states that those fields are

advisory field[s], only, and does not imply that usage of the key is restricted to the purpose indicated

Depending on what you need the information for, you could use either extension.

Sign up to request clarification or add additional context in comments.

1 Comment

Are you sure I should look for szOID_KEY_USAGE_RESTRICTION and not for szOID_KEY_USAGE?
2

With the help of Josh Poley, I found the answer. Thank you Josh

bool CertHasDigitalSignature(PCCERT_CONTEXT pCert) { bool retVal(false); CERT_EXTENSION* keyUsage; keyUsage = CertFindExtension(szOID_KEY_USAGE, pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension); if(NULL != keyUsage) { DWORD strSz(0); if(CryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, szOID_KEY_USAGE, keyUsage->Value.pbData ,keyUsage->Value.cbData, NULL, &strSz)) { std::wstring Buff; Buff.resize((strSz / sizeof(wchar_t)) + 1); if(CryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, szOID_KEY_USAGE, keyUsage->Value.pbData ,keyUsage->Value.cbData, (void*)Buff.data(), &strSz)) { if (std::wstring::npos != Buff.find(L"Digital Signature")) retVal = true; } } } return retVal; } 

6 Comments

try and __finally do not match. The former is used for C++ exception handling, the latter for SEH exception handling. What's worse, the only operation that can actually raise C++ exceptions is outside your presumed try-catch-block. Since you are using C++, why not go with std::vector<wchar_t> buff(strSz / sizeof(wchar_t) + 1); and buff.data() instead?
More importantly, your string comparison is subject to localization. It may return false negatives on systems, that use a non-English UI language. Besides that, the information is advisory only. Josh Poley provided the steps required to implement a robust solution: Retrieve the CERT_KEY_USAGE_RESTRICTION_INFO structure and check the CERT_DIGITAL_SIGNATURE_KEY_USAGE flag. Bitflags are immune to localization.
Embarcadero C++ compiler (formally known as Borland) uses uses this type of try-finally block. This is the way they have done it from the beginning and still they are doing it the same way. As for Localization issue, you are correct, but since my app is going to be used in one location under strict control, I can be assured It is not going to matter for me. The reason I used szOID_KEY_USAGE instead of szOID_KEY_USAGE_RESTRICTION is because the certificates that I am getting from CAC card (Smart card) only has szOID_KEY_USAGE and szOID_KEY_USAGE_RESTRICTION is not present at all.
Even with the non-standard compiler extension, the code still doesn't make sense. The only operation (operator new) that can throw, is outside the try. The Windows API is exposed through a C interface. There are no exceptions.
The std::vector<wchar_t> buff(strSz / sizeof(wchar_t) + 1); is a good idea. I will probably change my code to use that. Thank you Josh and IInspectable both.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.