Skip to content

Example to use OpenSC with Microsoft CNG and CryptoAPI

Frank Morgner edited this page Aug 27, 2018 · 1 revision

OpenSC and Microsoft CNG

It is possible to use the Smartcard via OpenSC with the Microsoft CNG library. CNG can be used together with CryptoAPI.

Example: Read the x509 Certificate from connected Smartcard

With the CNG its easy to use the smartcard like a normal pkcs12 container or something similar.

#include <Windows.h>
#include <wincrypt.h>

#include <functional>
#include <memory>
#include <vector>

template <typename T>
using raii_ptr = std::unique_ptr<T, std::function<void(T *)>>;

// Read the x509 from connected smartcard
int main() {
  NCRYPT_PROV_HANDLE provider = NULL;
  raii_ptr<NCRYPT_PROV_HANDLE> hProvider(&provider,
                                         [](NCRYPT_PROV_HANDLE *handle) {
                                           if (handle)
                                             NCryptFreeObject(*handle);
                                         });
  NCryptOpenStorageProvider(hProvider.get(), MS_SMART_CARD_KEY_STORAGE_PROVIDER,
                            0);

  NCryptKeyName *pKeyName = nullptr;
  PVOID pState = nullptr;

  auto status = NCryptEnumKeys(*hProvider, 0, &pKeyName, &pState, 0);
  if (status == NTE_NO_MORE_ITEMS)
    return 0;

  if (status != ERROR_SUCCESS && status != ERROR_SUCCESS) {
    printf("Error: NCryptEnumKeys : 0x%x\n", status);
    return 0;
  }
  printf("Ok: NCryptEnumKeys : 0x%x\n", status);

  NCRYPT_KEY_HANDLE key = NULL;
  raii_ptr<NCRYPT_KEY_HANDLE> hKey(&key, [](NCRYPT_KEY_HANDLE *handle) {
    if (handle)
      NCryptFreeObject(*handle);
  });
  status = NCryptOpenKey(*hProvider, hKey.get(), pKeyName->pszName,
                         pKeyName->dwLegacyKeySpec, 0);

  wprintf(L"Ok: NCryptOpenKey : 0x%x, Key Name: %s\n", status,
          pKeyName->pszName);
  wprintf(L"Using key : %s\n", pKeyName->pszName);

  DWORD size = 0;
  NCryptGetProperty(*hKey, NCRYPT_CERTIFICATE_PROPERTY, nullptr, 0, &size, 0);
  std::vector<BYTE> cert;
  cert.resize(size);
  NCryptGetProperty(*hKey, NCRYPT_CERTIFICATE_PROPERTY, &cert[0], size, &size,
                    0);

  DWORD nDestinationSize;
  if (CryptBinaryToString(reinterpret_cast<const BYTE *>(&cert[0]), cert.size(),
                          CRYPT_STRING_BASE64, nullptr, &nDestinationSize)) {
    LPTSTR pszDestination = static_cast<LPTSTR>(HeapAlloc(
        GetProcessHeap(), HEAP_NO_SERIALIZE, nDestinationSize * sizeof(TCHAR)));
    if (pszDestination) {
      if (CryptBinaryToString(reinterpret_cast<const BYTE *>(&cert[0]),
                              cert.size(), CRYPT_STRING_BASE64, pszDestination,
                              &nDestinationSize)) {

        printf(pszDestination);
      }
      HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pszDestination);
    }
  }
  return 0;
}

Important functions

Clone this wiki locally