Thursday, March 5, 2009

How to do windows logon with smartcard

If you try to implement GINA replacement that fully supports all features that native msgina.dll supports , you have to implement smart card login (PKI). And here comes the problem. The information on how to do that is very limited. There is no even correct structures defnition available. It was not documented . Now it is defined in SDK , but not for systems earlier then Vista.(eg :Windows XP ).
I am speaking of

ULONG CspDataLength;
WCHAR pinData[256];

Compare it with msdn definition :

Somewhat different , eh?

typedef struct _KERB_SMARTCARD_CSP_INFO {
DWORD dwCspInfoLen;
DWORD MessageType;
ULONG nCardNameOffset;
ULONG nReaderNameOffset;
ULONG nContainerNameOffset;
ULONG nCSPNameOffset;
TCHAR bBuffer[1024];

Once again Compare it with MSDN definition .

And now the struct that should be supplied to LsaLogonUser as AuthenticationInformation parameter.

struct FullPacket

Note : this is the most mystic thing that spoiled hours and days of debugging:

The LogonDomainName, UserName, and Password members of the MSV1_0_INTERACTIVE_LOGON structure must point to buffers in memory that are contiguous to the structure itself. The value of the AuthenticationInformationLength parameter must take into account the length of these buffers.

Yessss! And all others  , like  CardName, ReaderName,ContainerName,CSPName.

And one more thing ,  despite what  the msdn sais  about  KERB_SMARTCARD_CSP_INFO.MessageType

The type of message being passed. This member must be set to 1.

- for XP  it shold be 0.  I believe it is a version of the structure. 

That  is all  for now.  The clever one  can do the rest  ;)

Note : tested on 32bit  Windows XP & 2k3;


  1. Thanks for posting this. I am trying to do the same thing and am running into mysterious failures and am not entirely sure what I'm doing wrong. I have a few questions for you, if you have the time:

    1) For all the offset parameters in the CSP info struct, did you specify them in terms of characters or bytes (if Unicode)?

    2) Was nCardNameOffset always 0 for you? I can't see any reason why it wouldn't be 0.

    3) Is dwCspInfoLen always 2 * sizeof(DWORD) + 4 * sizeof(ULONG) + 1024 * sizeof(TCHAR) or does it depend on the actual lengths of the buffers provided if the full 1024 characters are not used?

    4) Is CspDataLength always equal to dwCspInfoLen? It seems weird for them to want both parameters if they are always the same thing.

    5) Let's say you have a FullPacket pointer named packet. Am I correct in saying that packet->smartCardLogon.CspData = (DWORD)&(packet->cspInfo) - DWORD)&(packet->smartCardLogon).

    Once again, thanks for any help you can give me.


  2. Nevermind, looks like I was doing everything correctly, but Vista was just not treating my credentials correctly.

    1. I am trying to perform a CP for Windows 7. However with all the documented and undocumented structures, and trying all type of pointers and all. I am still getting the same "Invalid Parameter".

      Are there any recommendations on what I can debug or check?

  3. Does anyone know if it would work als with certificates installed in the Computer/My Store if I pass the right container name and leave CardName and CardReader to an empty string? Any help would be really apreciated.

  4. Adam, Why do you need PKI implementation for Vista. I believe it is native and works ok.
    Anyway the only way to verify if you are doing everything correctly is to dump structure from the native implementation when it is passed to LsaLogonUser. And then compare to yours structure. you can use windbg to do so. I used SoftIce on Xp to diagnose the errors.