'How to enumerate all possible keys that exist on a smartcard that is present in a reader with just UWP APIs?

Here are the constraints for my question: How to enumerate all possible keys that exist on a smartcard that is present in a reader with UWP APIs?

  1. Use just Universal Windows Program (UWP) APIs

I do have a C++ approach using NCryptOpenStorageProvider(MS_SMART_CARD_KEY_STORAGE_PROVIDER) and NCryptEnumKeys https://docs.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptenumkeys

  1. I want to exclude keys that belong to a smartcard that is not physically present in a reader.

    Generally approaches that iterate through certificates in Cert stores have failed for me because Windows pops up a dialog asking for a card to be inserted which is no longer available. Maybe there is a way to exclude certificates like that, but I don't know the way.

Consequently it seems that an approach of iterating the keys through a provider makes more sense.

oldnewthing (who deserves thanks for helpful posts through the years) has a https://github.com/microsoft/Windows-universal-samples/tree/main/Samples/SmartCard but it does not show this exact functionality.

https://docs.microsoft.com/en-us/windows/uwp/security/smart-cards explains how UWP can interact with smartcards, including APDU transfer, but does not explain how to iterate the asymmetric keys at a high level.

Thanks for advice in advance...

p.s. here is the type of code that looks at the Cert Store, and gets a key.

            X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            X509Certificate2Collection certs = (X509Certificate2Collection)store.Certificates;
            int n = certs.Count;
            msg += " has " + n.ToString() + " keys: ";

            foreach (X509Certificate2 cert in certs)
            {
                if (!cert.HasPrivateKey) continue;

                RSACng rsaCng = (RSACng)cert.GetRSAPrivateKey();
                if (null == rsaCng) continue;
                if (rsaCng.Key.Provider != CngProvider.MicrosoftSmartCardKeyStorageProvider) continue;
                msg += rsaCng.Key.KeyName + ", ";
            }

but I don't know how to restrict it to just keys that are currently present.



Solution 1:[1]

You can enumerate the readers using SCard* functions, then set the pszScope argument of the NCryptEnumKeys() call to L"\\\\.\\<ReaderName>\\".

Caution: this parameter is documented as "unused; set to NULL" in MSDN!

See https://social.msdn.microsoft.com/Forums/en-US/e99d3980-ae4f-4632-8dad-565e098dc6dd/how-to-enumerate-keys-on-all-connected-smart-cards-using-cng

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Beat Bolli