smartcard_certificates implementation
Given a provider name NCryptEnumKeys
can be used to retrieve all the keys known to that provider. Since the KSP provider is shared across all cards associated to it, the keys from all associated cards will be returned.
Here is a function that uses NCryptEnumKeys
and NCryptGetProperty
to retrieve the keys and certificates from a KSP provider name.
struct KeyWithCertificate {
std::wstring key;
std::vector<BYTE> cert;
};
typedef
std::vector<KeyWithCertificate>
KeyWithCertificateVector;
inline
std::pair<unique_winerror, KeyWithCertificateVector>
smartcard_certificates(
const std::wstring& kspstring
)
{
unique_winerror winerror;
KeyWithCertificateVector output;
NCRYPT_PROV_HANDLE provider = NULL;
ON_UNWIND_AUTO(
[&] {
if (provider) {
NCryptFreeObject(provider);
}
}
);
winerror.reset(
NCryptOpenStorageProvider(
&provider,
kspstring.c_str(),
0
)
);
if (!winerror) {
return std::make_pair(winerror, std::move(output));
}
NCryptKeyName* keyname = nullptr;
ON_UNWIND_AUTO(
[&] {
if (keyname) {
NCryptFreeBuffer(keyname);
}
}
);
void* enumstate = nullptr;
ON_UNWIND_AUTO(
[&] {
if (enumstate) {
NCryptFreeBuffer(enumstate);
}
}
);
for (;;) {
winerror.reset(
NCryptEnumKeys(
provider,
NULL,
&keyname,
&enumstate,
NCRYPT_SILENT_FLAG
)
);
if (winerror == winerror_cast(NTE_NO_MORE_ITEMS)) {
winerror.suppress().release();
break;
}
if (!winerror) {
return std::make_pair(winerror, std::move(output));
}
KeyWithCertificate keystate;
keystate.key = keyname->pszName;
NCRYPT_KEY_HANDLE key = NULL;
ON_UNWIND_AUTO(
[&] {
if (key) {
NCryptFreeObject(key);
}
}
);
winerror.reset(
NCryptOpenKey(
provider,
&key,
keyname->pszName,
keyname->dwLegacyKeySpec,
NCRYPT_SILENT_FLAG
)
);
if (!winerror) {
return std::make_pair(winerror, std::move(output));
}
DWORD sizecert = 0;
for (bool getsize = true; ; getsize = false) {
winerror.reset(
NCryptGetProperty(
key,
NCRYPT_CERTIFICATE_PROPERTY,
getsize ? nullptr : &keystate.cert[0],
sizecert,
&sizecert,
0
)
);
if (!winerror) {
return std::make_pair(winerror, std::move(output));
}
if (getsize) {
keystate.cert.resize(sizecert);
} else {
break;
}
}
output.push_back(keystate);
}
return std::make_pair(winerror, std::move(output));
}