/*
 * An example of using Smart Card certificate in a call to LogonUser
 *
 * Copyright (c) 2009 Mounir IDRASSI <mounir.idrassi@idrix.fr>. All rights reserved.
 *
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * 
 */


#ifndef _WIN32_WINNT		// Allow use of features specific to Windows 2000 or later.                   
#define _WIN32_WINNT 0x0500	// Change this to the appropriate value to target other versions of Windows.
#endif						

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <WinCred.h>

#pragma comment(lib, "Crypt32")


int _tmain(int argc, _TCHAR* argv[])
{
	HCERTSTORE      hStoreHandle = NULL;
	PCCERT_CONTEXT  pCertContext = NULL;   
	CERT_ENHKEY_USAGE keyUsage;
	DWORD dwLogonCertsCount = 0;
	LPCTSTR pszStoreName = _T("MY");
	char szSCLogonOID[64];
	CERT_CREDENTIAL_INFO certInfo;
   HCRYPTPROV hProv;
   HCRYPTHASH hHash;
   BOOL bStatus;
   DWORD dwHashLen = CERT_HASH_LENGTH;
   LPTSTR szMarshaledCred = NULL;
   LPCTSTR szPIN = _T("1234");
   HANDLE hToken;

	// Open the "MY" certificate store
	hStoreHandle = CertOpenSystemStore(NULL, pszStoreName);
	if (hStoreHandle)
	{
		// populate the key usage structure with the Smart Card Logon OID
		strcpy(szSCLogonOID, szOID_KP_SMARTCARD_LOGON);
		keyUsage.cUsageIdentifier = 1;
		keyUsage.rgpszUsageIdentifier = (LPSTR*) LocalAlloc(0, sizeof(LPSTR));
		keyUsage.rgpszUsageIdentifier[0] = &szSCLogonOID[0];

		// Find certificates that contain the Smart Card Logon Enhanced Key Usage
		pCertContext = CertFindCertificateInStore(hStoreHandle,
							X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
							CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
							CERT_FIND_ENHKEY_USAGE,
							&keyUsage,
							pCertContext);
		
		if (pCertContext)
		{
			// we take the first one in our example
         ZeroMemory(&certInfo, sizeof(certInfo));
         certInfo.cbSize = sizeof(certInfo);

         // compute the SHA-1 hash of the certificate
         bStatus = CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
         if (bStatus)
         {
            bStatus = CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash);
            if (bStatus)
            {
               bStatus = CryptHashData(hHash, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, 0);
               if (bStatus)
               {
                  bStatus = CryptGetHashParam(hHash, HP_HASHVAL, certInfo.rgbHashOfCert, &dwHashLen, 0);
               }
               CryptDestroyHash(hHash);
            }
            CryptReleaseContext(hProv, 0);
         }

         if (bStatus)
         {
            bStatus = CredMarshalCredential(CertCredential, &certInfo, &szMarshaledCred);
            if (bStatus)
            {
               bStatus = LogonUser(szMarshaledCred, 
                                   NULL, 
                                   szPIN, 
                                   LOGON32_LOGON_INTERACTIVE, 
                                   LOGON32_PROVIDER_WINNT50, 
                                   &hToken);
               if (bStatus)
               {
                  _tprintf(_T("LogonUser success\n"));
                  CloseHandle(hToken);
               }
               else
               {
                  _tprintf(_T("LogonUser failed with error 0x%.8X\n"), GetLastError());
               }
               CredFree(szMarshaledCred);
            }
            else
            {
               _tprintf(_T("CredMarshalCredential failed with error 0x%.8X\n"), GetLastError());
            }
         }
         else
         {
            _tprintf(_T("Failed to compute logon certificate hash\n"));
         }

         CertFreeCertificateContext(pCertContext);
		}
      else
      {
         _tprintf(_T("No Smart Card Logon certificate found\n"));
      }

		LocalFree(keyUsage.rgpszUsageIdentifier);
		CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);		
	}
	else
	{
		_tprintf(_T("CertOpenSystemStore failed with error 0x%.8X\n"), GetLastError);
	}
			
	return 0;
}
