I'm writing a class that signs a XML document using x509 certificates. I'm already able to get my SmartCard certificate and sign it.
However, to do this I must look for the x509 certificate in the Windows Keystore, so I must know something about my SmartCard, like the Issuer Name, or the Serial Number. That's nice.
But I want a more convenient approach to get the SmartCard certificate. I had 2 ideas:
- Get all the certificates from the Keystore and look for those who are "coming from a SmartCard". But I dont think i'm able to get such information.
Interop with winscard.dll
and get some information about the SmartCard connected to my computer, so I could use it to find the right certificate, but this isn't working:
[DllImport("winscard.dll")]
public static extern long SCardListCards(
uint hContext, int pbAtr,
int rgguidInterfaces, int cguidInterfaceCount,
[MarshalAs(UnmanagedType.LPTStr)] ref string mszCards,
ref int pcchCards);
[DllImport("winscard.dll")]
public static extern long SCardEstablishContext(uint dwScope,
int pvReserved1,
int pvReserved2,
ref uint phContext);
And here is a test method. The string crds
holds the list of SmartCards.
[TestMethod]
public void TestInterop()
{
uint handle = 0;
Interop.SCardEstablishContext(0, 0, 0, ref handle);
string crds = "";
int pcch = 0;
Interop.SCardListCards(handle, 0, 0, 0, ref crds, ref pcch);
Assert.IsTrue(crds != "");
}
This test fails everytime, because crds
never changes.
If I try to return crds
as a byte[]
:
[DllImport("winscard.dll", EntryPoint = "SCardListCards")]
public static extern long SCardListCardsRetBytes(
uint hContext, int pbAtr,
int rgguidInterfaces, int cguidInterfaceCount,
ref byte[] mszCards,
ref int pcchCards);
My byte[] crds
becomes:
byte[] {171}
when I initialize it with byte[] crds = {};
why 171?
byte[] {0}
when I initialize it with byte[] crds = new byte[32];
and why 0?
How can I get the SmartCard certificate to sign a XML message? And if you want to give me a bonus answer, why this Interop I did isn't working?