I'm writing a program to do encryption things, using certificates stored on hardware devices (smart cards).
- The program must use .Net Framework 4.5.2 :( Changing this isn't possible.
- The crypto things I perform haven't problems :)
Preamble
As far as I understood, when a smart card, containing one or more certificates, is connected to the computer, the certificates appears on the Windows certificates store (CurrentUser/My).
This is managed by the smartcard software, that must be installed.
Since my software must work with any hardware device, the easiest solution is to popup a window, and making the user to choose the certificate to use.
First problem
I don't want to show all the certificates that are on CurrentUser/My, but only the ones that have an associated hardware connected to the computer.
This is, more or less, the code that I'm using:
X509Store storeObject = new X509Store(StoreName.My, StoreLocation.CurrentUser);
storeObject.Open(OpenFlags.ReadOnly);
foreach (var certificate in storeObject.Certificates)
{
bool isValid = false;
if (certificate.HasPrivateKey)
{
try
{
var rsaKey = certificate.PrivateKey as RSACryptoServiceProvider;
if (rsaKey.CspKeyContainerInfo.HardwareDevice)
{
isValid = true;
}
}
catch (Exception ex)
{
// just log
}
}
}
Despite this solution is very ugly, it's the best I came up.
The certificate belongs to a smart card if:
- HasPrivateKey is true.
- The cast of PrivateKey to RSACryptoServiceProvider didn't throw an exception if the smart card is connected.
- HardwareDevice then is true.
The problem is on the PrivateKey cast: it seems that lot of things are performed by the CryptoApi system during this cast (that includes calls - of course - to the smart card software).
This is very slow, and if the smartcard software has some kind of failures, uncontrollable error messages are shown, ...
Question
Is there any other way to determine if the certificate belongs to an hardware device? And to determine if the hardware is currently connected?
Second problem
The certificate may require a PIN.
I must (it's a prerequisite) avoid the Windows input box asking for the PIN.
It's not a problem for me to collect the PIN, and to use it during my crypto operations.
My problem is to understand if the PIN is required or not.
ANY example I found online assume that if rsaKey.CspKeyContainerInfo.HardwareDevice == true then a PIN is required.
But I'm not sure about that.
Question
Is there any way I can determine if a certificate requires a PIN code?
Conclusion
I also like external libraries, as long as they are free (preferably open source) and/or come from Microsoft.
Thank you very much!