How to enumerate all certificates on a smart card (PowerShell)

Hi all,

 

Some time ago I assisted my colleague Jeff Bowles with the development of a PowerShell script which enumerates all certificates on a smart card. Basically the replacement to CAPICOM.Store.Open CAPICOM_SMART_CARD_USER_STORE.

He developed a sample that returnsSystem.Security.Cryptography.X509Certificates.X509Store object with the certificates in the card. The sample tries to emulate what logonUI.exe does during smart card logon as documented
at Certificate Enumeration

Note that this code is also a great example that shows how we can use PowerShell to call Win32 API the same way we do it with any .NET application through P/Invoke mechanism:

 

 function Get-SCUserStore {



[string]$providerName ="Microsoft Base Smart Card Crypto Provider"



# import CrytoAPI from advapi32.dll

$signature = @"

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]

[return : MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptGetProvParam(

   IntPtr hProv,

   uint dwParam,

   byte[] pbProvData,

   ref uint pdwProvDataLen, 

   uint dwFlags); 



[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]

[return : MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptDestroyKey(

   IntPtr hKey);   

   

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]

[return : MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptAcquireContext(

   ref IntPtr hProv,

   string pszContainer,

   string pszProvider,

   uint dwProvType,

   long dwFlags);

      

[DllImport("advapi32.dll", CharSet=CharSet.Auto)]

[return : MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptGetUserKey(

   IntPtr hProv, 

   uint dwKeySpec,

   ref IntPtr phUserKey);

   

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]

[return: MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptGetKeyParam(

   IntPtr hKey,

   uint dwParam,

   byte[] pbData,

   ref uint pdwDataLen,

   uint dwFlags);

   

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]

[return : MarshalAs(UnmanagedType.Bool)]

public static extern bool CryptReleaseContext(

   IntPtr hProv,

   uint dwFlags);

"@



$CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru



# set some constants for CryptoAPI

$AT_KEYEXCHANGE = 1

$AT_SIGNATURE = 2

$PROV_RSA_FULL = 1

$KP_CERTIFICATE = 26

$PP_ENUMCONTAINERS = 2

$PP_CONTAINER = 6

$PP_USER_CERTSTORE = 42

$CRYPT_FIRST = 1

$CRYPT_NEXT = 2

$CRYPT_VERIFYCONTEXT = 0xF0000000



[System.IntPtr]$hProvParent=0

$contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)



[Uint32]$pdwProvDataLen = 0

[byte[]]$pbProvData = $null

$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)



if($pdwProvDataLen -gt 0) 

  {

    $ProvData = new-Object byte[] $pdwProvDataLen

    $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)

   }

   

$enc = new-object System.Text.UTF8Encoding($null)

$keyContainer = $enc.GetString($ProvData)

 

 write-host " The Default User Key Container:" $keyContainer



[Uint32]$pdwProvDataLen = 0

[byte[]]$pbProvData = $null

$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)



if($pdwProvDataLen -gt 0) 

  {

    $ProvData = new-Object byte[] $pdwProvDataLen

    $GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)

    [uint32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)

    [System.IntPtr]$hwStore = $provdataInt

   }

      

 $store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)

         

# release smart card

$ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)



return $store

}



write-host ((get-WmiObject win32_PnPSignedDriver|where{$_.deviceID -like "*smartcard*"}).devicename) "reports the following certificates;" 



# returns System.Security.Cryptography.X509Certificates.X509Store object representing PP_USER_CERTSTORE on Smart Card

$SCcertStore = Get-SCuserSTore



# enumerate certificates

$SCcertStore.certificates

 

 

 

I hope this helps. And THANKS A LOT JEFF for sharing the final sample with me and the community!!! Kudos!!!

Regards,

 

Alex (Alejandro Campos Magencio)