Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

837 lines
25 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: SmartCard.cpp
  4. Content: Implementation of helper routines for accessing certificates in
  5. smart card. Functions in this module require that the Smart Card Base
  6. Component v1.1 to be installed.
  7. History: 12-06-2001 dsie created
  8. ------------------------------------------------------------------------------*/
  9. #include "StdAfx.h"
  10. #include "CAPICOM.h"
  11. #include "SmartCard.h"
  12. //
  13. // typedefs for SCardXXX APIs.
  14. //
  15. typedef WINSCARDAPI LONG (WINAPI * PFNSCARDESTABLISHCONTEXT) (
  16. IN DWORD dwScope,
  17. IN LPCVOID pvReserved1,
  18. IN LPCVOID pvReserved2,
  19. OUT LPSCARDCONTEXT phContext);
  20. typedef WINSCARDAPI LONG (WINAPI * PFNSCARDLISTREADERSA) (
  21. IN SCARDCONTEXT hContext,
  22. IN LPCSTR mszGroups,
  23. OUT LPSTR mszReaders,
  24. IN OUT LPDWORD pcchReaders);
  25. typedef WINSCARDAPI LONG (WINAPI * PFNSCARDGETSTATUSCHANGEA) (
  26. IN SCARDCONTEXT hContext,
  27. IN DWORD dwTimeout,
  28. IN OUT LPSCARD_READERSTATE_A rgReaderStates,
  29. IN DWORD cReaders);
  30. typedef WINSCARDAPI LONG (WINAPI * PFNSCARDLISTCARDSA) (
  31. IN SCARDCONTEXT hContext,
  32. IN LPCBYTE pbAtr,
  33. IN LPCGUID rgquidInterfaces,
  34. IN DWORD cguidInterfaceCount,
  35. OUT LPSTR mszCards,
  36. IN OUT LPDWORD pcchCards);
  37. typedef WINSCARDAPI LONG (WINAPI* PFNSCARDGETCARDTYPEPROVIDERNAMEA) (
  38. IN SCARDCONTEXT hContext,
  39. IN LPCSTR szCardName,
  40. IN DWORD dwProviderId,
  41. OUT LPSTR szProvider,
  42. IN OUT LPDWORD pcchProvider);
  43. typedef WINSCARDAPI LONG (WINAPI* PFNSCARDFREEMEMORY) (
  44. IN SCARDCONTEXT hContext,
  45. IN LPVOID pvMem);
  46. typedef WINSCARDAPI LONG (WINAPI * PFNSCARDRELEASECONTEXT) (
  47. IN SCARDCONTEXT hContext);
  48. //
  49. // Function pointer to SCardXXX APIs.
  50. //
  51. static PFNSCARDESTABLISHCONTEXT pfnSCardEstablishContext = NULL;
  52. static PFNSCARDLISTREADERSA pfnSCardListReadersA = NULL;
  53. static PFNSCARDGETSTATUSCHANGEA pfnSCardGetStatusChangeA = NULL;
  54. static PFNSCARDLISTCARDSA pfnSCardListCardsA = NULL;
  55. static PFNSCARDGETCARDTYPEPROVIDERNAMEA pfnSCardGetCardTypeProviderNameA = NULL;
  56. static PFNSCARDFREEMEMORY pfnSCardFreeMemory = NULL;
  57. static PFNSCARDRELEASECONTEXT pfnSCardReleaseContext = NULL;
  58. ////////////////////////////////////////////////////////////////////////////////
  59. //
  60. // Local functions.
  61. //
  62. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  63. Function : AddCert
  64. Synopsis : Add the specified certificate to the specified store.
  65. Parameter: - IN LPCSTR szCSPName
  66. CSP name string.
  67. - IN LPCSTR szContainerName
  68. Key container name string.
  69. - IN DWORD dwKeySpec
  70. AT_KEYEXCHANGZE or AT_SIGNATURE.
  71. - IN LPBYTE pbEncodedCert
  72. Pointer to encoded cert data to be added.
  73. - IN DWORD cbEncodedCert
  74. Length of encoded cert data.
  75. - IN HCERTSTORE hCertStore
  76. Handle of cert store where the cert will be added.
  77. Remarks :
  78. ------------------------------------------------------------------------------*/
  79. static HRESULT AddCert (IN LPCSTR szCSPName,
  80. IN LPCSTR szContainerName,
  81. IN DWORD dwKeySpec,
  82. IN LPBYTE pbEncodedCert,
  83. IN DWORD cbEncodedCert,
  84. IN HCERTSTORE hCertStore)
  85. {
  86. HRESULT hr = S_OK;
  87. PCCERT_CONTEXT pCertContext = NULL;
  88. CComBSTR bstrCSPName;
  89. CComBSTR bstrContainerName;
  90. CRYPT_KEY_PROV_INFO KeyProvInfo;
  91. DebugTrace("Entering AddCert().\n");
  92. //
  93. // Sanity check.
  94. //
  95. ATLASSERT(szCSPName);
  96. ATLASSERT(szContainerName);
  97. ATLASSERT(pbEncodedCert);
  98. ATLASSERT(cbEncodedCert);
  99. ATLASSERT(hCertStore);
  100. //
  101. // Create certificate context for the specified certificate.
  102. //
  103. if (!(pCertContext = ::CertCreateCertificateContext(CAPICOM_ASN_ENCODING,
  104. pbEncodedCert,
  105. cbEncodedCert)))
  106. {
  107. hr = HRESULT_FROM_WIN32(::GetLastError());
  108. DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
  109. goto ErrorExit;
  110. }
  111. //
  112. // Convert strings to UNICODE.
  113. //
  114. if (!(bstrCSPName = szCSPName))
  115. {
  116. hr = E_OUTOFMEMORY;
  117. DebugTrace("Error [%#x]: bstrCSPName = szCSPName failed.\n", hr);
  118. goto ErrorExit;
  119. }
  120. if (!(bstrContainerName = szContainerName))
  121. {
  122. hr = E_OUTOFMEMORY;
  123. DebugTrace("Error [%#x]: bstrContainerName = szContainerName failed.\n", hr);
  124. goto ErrorExit;
  125. }
  126. //
  127. // Add the CSP & key container info. This is used by CAPI to load the
  128. // CSP and find the keyset when the user indicates this certificate.
  129. //
  130. ::ZeroMemory((LPVOID) &KeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO));
  131. KeyProvInfo.pwszContainerName = (LPWSTR) bstrContainerName;
  132. KeyProvInfo.pwszProvName = (LPWSTR) bstrCSPName;
  133. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  134. KeyProvInfo.dwFlags = 0;
  135. KeyProvInfo.dwKeySpec = dwKeySpec;
  136. if (!::CertSetCertificateContextProperty(pCertContext,
  137. CERT_KEY_PROV_INFO_PROP_ID,
  138. 0,
  139. (const void *) &KeyProvInfo))
  140. {
  141. hr = HRESULT_FROM_WIN32(::GetLastError());
  142. DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
  143. goto ErrorExit;
  144. }
  145. //
  146. // Put the cert in the store!
  147. //
  148. if (!::CertAddCertificateContextToStore(hCertStore,
  149. pCertContext,
  150. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, // or CERT_STORE_ADD_NEW
  151. NULL))
  152. {
  153. hr = HRESULT_FROM_WIN32(::GetLastError());
  154. DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
  155. goto ErrorExit;
  156. }
  157. CommonExit:
  158. //
  159. // Free resources.
  160. //
  161. if (pCertContext != NULL)
  162. {
  163. CertFreeCertificateContext(pCertContext);
  164. }
  165. DebugTrace("Leaving AddCert().\n");
  166. return hr;
  167. ErrorExit:
  168. //
  169. // Sanity check.
  170. //
  171. ATLASSERT(FAILED(hr));
  172. goto CommonExit;
  173. }
  174. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  175. Function : GetCert
  176. Synopsis : Get the cert from the specified CSP for the specified key type.
  177. Parameter: - IN HCRYPTPROV hCryptProv
  178. Crypto context returned by CryptAcquireContext().
  179. - IN DWORD dwKeySpec
  180. AT_KEYEXCHANGZE or AT_SIGNATURE.
  181. - OUT LPBYTE * ppbEncodedCert
  182. Ponter to pointer to encoded cert data. Upon success, the buffer
  183. is automatically allocated and must be later freed by
  184. CoTaskMemFree().
  185. - OUT DWORD * pcbEncodedCert
  186. Pointer to encoded cert data length. Upon success, receive the
  187. length of the encoded cert data.
  188. Remarks :
  189. ------------------------------------------------------------------------------*/
  190. static HRESULT GetCert (IN HCRYPTPROV hCryptProv,
  191. IN DWORD dwKeySpec,
  192. OUT LPBYTE * ppbEncodedCert,
  193. OUT DWORD * pcbEncodedCert)
  194. {
  195. HRESULT hr = S_OK;
  196. HCRYPTKEY hCryptKey = NULL;
  197. LPBYTE pbEncodedCert = NULL;
  198. DWORD cbEncodedCert = 0;
  199. DebugTrace("Entering GetCert().\n");
  200. //
  201. // Sanity check.
  202. //
  203. ATLASSERT(hCryptProv);
  204. ATLASSERT(ppbEncodedCert);
  205. ATLASSERT(pcbEncodedCert);
  206. //
  207. // Get key handle.
  208. //
  209. if (!::CryptGetUserKey(hCryptProv, dwKeySpec, &hCryptKey))
  210. {
  211. hr = HRESULT_FROM_WIN32(::GetLastError());
  212. DebugTrace("Error [%#x]: CryptGetUserKey() failed.\n", hr);
  213. goto ErrorExit;
  214. }
  215. //
  216. // Query certificate data length.
  217. //
  218. if (!::CryptGetKeyParam(hCryptKey,
  219. KP_CERTIFICATE,
  220. NULL, // NULL to query certificate data length
  221. &cbEncodedCert,
  222. 0))
  223. {
  224. hr = HRESULT_FROM_WIN32(::GetLastError());
  225. DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
  226. goto ErrorExit;
  227. }
  228. //
  229. // Allocate memory for certificate data.
  230. //
  231. if (!(pbEncodedCert = (LPBYTE) ::CoTaskMemAlloc(cbEncodedCert)))
  232. {
  233. hr = E_OUTOFMEMORY;
  234. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  235. goto ErrorExit;
  236. }
  237. //
  238. // Now read the certificate data.
  239. //
  240. if (!::CryptGetKeyParam(hCryptKey,
  241. KP_CERTIFICATE,
  242. pbEncodedCert,
  243. &cbEncodedCert,
  244. 0))
  245. {
  246. hr = HRESULT_FROM_WIN32(::GetLastError());
  247. DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
  248. goto ErrorExit;
  249. }
  250. //
  251. // Return encoded cert to caller.
  252. //
  253. *ppbEncodedCert = pbEncodedCert;
  254. *pcbEncodedCert = cbEncodedCert;
  255. CommonExit:
  256. //
  257. // Free resources.
  258. //
  259. if (hCryptKey)
  260. {
  261. ::CryptDestroyKey(hCryptKey);
  262. }
  263. DebugTrace("Leaving GetCert().\n");
  264. return hr;
  265. ErrorExit:
  266. //
  267. // Sanity check.
  268. //
  269. ATLASSERT(FAILED(hr));
  270. //
  271. // Free resources.
  272. //
  273. if (pbEncodedCert)
  274. {
  275. ::CoTaskMemFree((LPVOID) pbEncodedCert);
  276. }
  277. goto CommonExit;
  278. }
  279. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  280. Function : PropCert
  281. Synopsis : Propagate the digital certificate associated with the specified
  282. CSP and container name to the soecified store.
  283. Parameter: - IN LPCSTR szCSPName
  284. Pointer to Crypto Service Provider name string.
  285. - IN LPCTSTR szContainerName
  286. Pointer to key container name string.
  287. - IN HCERTSTORE hCertStore
  288. Handle of store to add the certificate to.
  289. Remarks :
  290. ------------------------------------------------------------------------------*/
  291. static HRESULT PropCert (IN LPCSTR szCSPName,
  292. IN LPCSTR szContainerName,
  293. IN HCERTSTORE hCertStore)
  294. {
  295. HRESULT hr = S_OK;
  296. HCRYPTPROV hCryptProv = NULL;
  297. DWORD rgdwKeys[] = {AT_KEYEXCHANGE, AT_SIGNATURE};
  298. DWORD cbEncodedCert = 0;
  299. LPBYTE pbEncodedCert = NULL;
  300. DWORD i;
  301. DebugTrace("Entering PropCert().\n");
  302. //
  303. // Sanity check.
  304. //
  305. ATLASSERT(szCSPName);
  306. ATLASSERT(szContainerName);
  307. ATLASSERT(hCertStore);
  308. //
  309. // Obtain the crypto context.
  310. //
  311. // CRYPT_SILENT forces the CSP to raise no UI. The fully qualified
  312. // container name indicates which reader to connect to, so the
  313. // user should not be prompted to insert or select a card.
  314. //
  315. if (!::CryptAcquireContextA(&hCryptProv,
  316. szContainerName,
  317. szCSPName,
  318. PROV_RSA_FULL,
  319. CRYPT_SILENT))
  320. {
  321. hr = HRESULT_FROM_WIN32(::GetLastError());
  322. DebugTrace("Error [%#x]: CryptAcquireContextA() failed.\n", hr);
  323. goto ErrorExit;
  324. }
  325. //
  326. // For each key pair found in the smart card, store the corresponding
  327. // digital certificate to the specified store.
  328. //
  329. for (i = 0; i < ARRAYSIZE(rgdwKeys); i++)
  330. {
  331. //
  332. // Get the certificate data.
  333. //
  334. if (FAILED(hr = ::GetCert(hCryptProv,
  335. rgdwKeys[i],
  336. &pbEncodedCert,
  337. &cbEncodedCert)))
  338. {
  339. if (HRESULT_FROM_WIN32(NTE_NO_KEY) == hr)
  340. {
  341. //
  342. // We are OK if there is no key of such type.
  343. //
  344. hr = S_OK;
  345. continue;
  346. }
  347. DebugTrace("Error [%#x]: GetCert() failed.\n", hr);
  348. goto ErrorExit;
  349. }
  350. //
  351. // Add the certificate to the specified store.
  352. //
  353. if (FAILED(hr = ::AddCert(szCSPName,
  354. szContainerName,
  355. rgdwKeys[i],
  356. pbEncodedCert,
  357. cbEncodedCert,
  358. hCertStore)))
  359. {
  360. DebugTrace("Error [%#x]: AddCert() failed.\n", hr);
  361. goto ErrorExit;
  362. }
  363. //
  364. // Free resources.
  365. //
  366. if (pbEncodedCert)
  367. {
  368. ::CoTaskMemFree((LPVOID) pbEncodedCert), pbEncodedCert = NULL;
  369. }
  370. }
  371. CommonExit:
  372. //
  373. // Free resources.
  374. //
  375. if (pbEncodedCert)
  376. {
  377. ::CoTaskMemFree((LPVOID) pbEncodedCert);
  378. }
  379. if (hCryptProv)
  380. {
  381. ::CryptReleaseContext(hCryptProv, 0);
  382. }
  383. DebugTrace("Leaving PropCert().\n");
  384. return hr;
  385. ErrorExit:
  386. //
  387. // Sanity check.
  388. //
  389. ATLASSERT(FAILED(hr));
  390. goto CommonExit;
  391. }
  392. ////////////////////////////////////////////////////////////////////////////////
  393. //
  394. // Exported functions.
  395. //
  396. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  397. Function : LoadFromSmartCard
  398. Synopsis : Load all certificates from all smart card readers.
  399. Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
  400. receive all the certificates.
  401. Remark :
  402. ------------------------------------------------------------------------------*/
  403. HRESULT LoadFromSmartCard (HCERTSTORE hCertStore)
  404. {
  405. HRESULT hr = S_OK;
  406. LONG lResult = 0;
  407. DWORD dwNumReaders = 0;
  408. DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
  409. SCARDCONTEXT hContext = NULL;
  410. LPSTR szReaderName = NULL;
  411. LPSTR mszReaderNames = NULL;
  412. LPSTR szCardName = NULL;
  413. LPSTR szCSPName = NULL;
  414. LPSTR szContainerName = NULL;
  415. HMODULE hWinSCardDll = NULL;
  416. LPSCARD_READERSTATE lpReaderStates = NULL;
  417. DebugTrace("Entering LoadFromSmartCard().\n");
  418. //
  419. // Sanity check.
  420. //
  421. ATLASSERT(hCertStore);
  422. //
  423. // Load WinSCard.dll.
  424. //
  425. if (!(hWinSCardDll = ::LoadLibrary("WinSCard.dll")))
  426. {
  427. hr = CAPICOM_E_NOT_SUPPORTED;
  428. DebugTrace("Error [%#x]: Smart Card Base Component (WinSCard.dll) not installed.\n", hr);
  429. goto ErrorExit;
  430. }
  431. //
  432. // Load all SCard APIs used.
  433. //
  434. if (!(pfnSCardEstablishContext = (PFNSCARDESTABLISHCONTEXT)
  435. ::GetProcAddress(hWinSCardDll, "SCardEstablishContext")))
  436. {
  437. hr = HRESULT_FROM_WIN32(::GetLastError());
  438. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardEstablishContext.\n", hr);
  439. goto ErrorExit;
  440. }
  441. if (!(pfnSCardListReadersA = (PFNSCARDLISTREADERSA)
  442. ::GetProcAddress(hWinSCardDll, "SCardListReadersA")))
  443. {
  444. hr = HRESULT_FROM_WIN32(::GetLastError());
  445. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardListReadersA.\n", hr);
  446. goto ErrorExit;
  447. }
  448. if (!(pfnSCardGetStatusChangeA = (PFNSCARDGETSTATUSCHANGEA)
  449. ::GetProcAddress(hWinSCardDll, "SCardGetStatusChangeA")))
  450. {
  451. hr = HRESULT_FROM_WIN32(::GetLastError());
  452. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardStatusChangeA.\n", hr);
  453. goto ErrorExit;
  454. }
  455. if (!(pfnSCardListCardsA = (PFNSCARDLISTCARDSA)
  456. ::GetProcAddress(hWinSCardDll, "SCardListCardsA")))
  457. {
  458. hr = HRESULT_FROM_WIN32(::GetLastError());
  459. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardListCardsA.\n", hr);
  460. goto ErrorExit;
  461. }
  462. if (!(pfnSCardGetCardTypeProviderNameA = (PFNSCARDGETCARDTYPEPROVIDERNAMEA)
  463. ::GetProcAddress(hWinSCardDll, "SCardGetCardTypeProviderNameA")))
  464. {
  465. hr = HRESULT_FROM_WIN32(::GetLastError());
  466. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardGetCardTypeProviderNameA.\n", hr);
  467. goto ErrorExit;
  468. }
  469. if (!(pfnSCardFreeMemory = (PFNSCARDFREEMEMORY)
  470. ::GetProcAddress(hWinSCardDll, "SCardFreeMemory")))
  471. {
  472. hr = HRESULT_FROM_WIN32(::GetLastError());
  473. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardFreeMemory.\n", hr);
  474. goto ErrorExit;
  475. }
  476. if (!(pfnSCardReleaseContext = (PFNSCARDRELEASECONTEXT)
  477. ::GetProcAddress(hWinSCardDll, "SCardReleaseContext")))
  478. {
  479. hr = HRESULT_FROM_WIN32(::GetLastError());
  480. DebugTrace("Error [%#x]: GetProcAddress() failed for SCardReleaseContext.\n", hr);
  481. goto ErrorExit;
  482. }
  483. //
  484. // Establish context with the resource manager.
  485. //
  486. if (SCARD_S_SUCCESS != (lResult = pfnSCardEstablishContext(SCARD_SCOPE_USER,
  487. NULL,
  488. NULL,
  489. &hContext)))
  490. {
  491. hr = HRESULT_FROM_WIN32(lResult);
  492. DebugTrace("Error [%#x]: SCardEstablishContext() failed.\n", hr);
  493. goto ErrorExit;
  494. }
  495. //
  496. // Get the list of all reader(s).
  497. // Note: The buffer is automatically allocated and must be freed
  498. // by SCardFreeMemory().
  499. //
  500. if (SCARD_S_SUCCESS != (lResult = pfnSCardListReadersA(hContext,
  501. NULL,
  502. (LPSTR) &mszReaderNames,
  503. &dwAutoAllocate)))
  504. {
  505. hr = HRESULT_FROM_WIN32(lResult);
  506. DebugTrace("Error [%#x]: SCardListReadersA() failed.\n", hr);
  507. goto ErrorExit;
  508. }
  509. //
  510. // Count number of readers.
  511. //
  512. for (dwNumReaders = 0, szReaderName = mszReaderNames; *szReaderName; dwNumReaders++)
  513. {
  514. szReaderName += ::strlen(szReaderName) + 1;
  515. }
  516. //
  517. // Nothing to do if no reader.
  518. //
  519. if (0 < dwNumReaders)
  520. {
  521. DWORD i;
  522. //
  523. // Allocate memory for SCARD_READERSTATE array.
  524. //
  525. if (!(lpReaderStates = (LPSCARD_READERSTATE)
  526. ::CoTaskMemAlloc(dwNumReaders * sizeof(SCARD_READERSTATE))))
  527. {
  528. hr = E_OUTOFMEMORY;
  529. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  530. goto ErrorExit;
  531. }
  532. //
  533. // Prepare state array.
  534. //
  535. ::ZeroMemory((LPVOID) lpReaderStates, dwNumReaders * sizeof(SCARD_READERSTATE));
  536. for (i = 0, szReaderName = mszReaderNames; i < dwNumReaders; i++)
  537. {
  538. lpReaderStates[i].szReader = (LPCSTR) szReaderName;
  539. lpReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
  540. szReaderName += ::strlen(szReaderName) + 1;
  541. }
  542. //
  543. // Initialize card status.
  544. //
  545. if (SCARD_S_SUCCESS != (lResult = pfnSCardGetStatusChangeA(hContext,
  546. INFINITE,
  547. lpReaderStates,
  548. dwNumReaders)))
  549. {
  550. hr = HRESULT_FROM_WIN32(lResult);
  551. DebugTrace("Error [%#x]: SCardGetStatusChangeA() failed.\n", hr);
  552. goto ErrorExit;
  553. }
  554. //
  555. // For each card found, find the proper CSP and propagate the
  556. // certificate(s) to the specified store.
  557. //
  558. for (i = 0; i < dwNumReaders; i++)
  559. {
  560. //
  561. // Card in this reader?
  562. //
  563. if (!(lpReaderStates[i].dwEventState & SCARD_STATE_PRESENT))
  564. {
  565. //
  566. // No card in this reader.
  567. //
  568. continue;
  569. }
  570. //
  571. // Get card name.
  572. //
  573. dwAutoAllocate = SCARD_AUTOALLOCATE;
  574. if (SCARD_S_SUCCESS != (lResult = pfnSCardListCardsA(hContext,
  575. lpReaderStates[i].rgbAtr,
  576. NULL,
  577. 0,
  578. (LPSTR) &szCardName,
  579. &dwAutoAllocate)))
  580. {
  581. hr = HRESULT_FROM_WIN32(lResult);
  582. DebugTrace("Error [%#x]: SCardListCardsA() failed.\n", hr);
  583. goto ErrorExit;
  584. }
  585. //
  586. // Get card's CSP name.
  587. //
  588. dwAutoAllocate = SCARD_AUTOALLOCATE;
  589. if (SCARD_S_SUCCESS != (lResult = pfnSCardGetCardTypeProviderNameA(hContext,
  590. szCardName,
  591. SCARD_PROVIDER_CSP,
  592. (LPSTR) &szCSPName,
  593. &dwAutoAllocate)))
  594. {
  595. hr = HRESULT_FROM_WIN32(lResult);
  596. DebugTrace("Error [%#x]: SCardGetCardTypeProviderNameA() failed.\n", hr);
  597. goto ErrorExit;
  598. }
  599. //
  600. // Prepare fully qualified container name.
  601. //
  602. if (!(szContainerName = (LPSTR) ::CoTaskMemAlloc(sizeof("\\\\.\\") + 1 +
  603. ::strlen(lpReaderStates[i].szReader))))
  604. {
  605. hr = E_OUTOFMEMORY;
  606. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  607. goto ErrorExit;
  608. }
  609. wsprintfA(szContainerName, "\\\\.\\%s\\", lpReaderStates[i].szReader);
  610. //
  611. // Propagate the cert.
  612. //
  613. if (FAILED(hr = ::PropCert(szCSPName, szContainerName, hCertStore)))
  614. {
  615. DebugTrace("Error [%#x]: PropCert() failed.\n", hr);
  616. goto ErrorExit;
  617. }
  618. //
  619. // Free resources.
  620. //
  621. if (szContainerName)
  622. {
  623. ::CoTaskMemFree((LPVOID) szContainerName), szContainerName = NULL;
  624. }
  625. if (szCSPName)
  626. {
  627. pfnSCardFreeMemory(hContext, (LPVOID) szCSPName), szCSPName = NULL;
  628. }
  629. if (szCardName)
  630. {
  631. pfnSCardFreeMemory(hContext, (LPVOID) szCardName), szCardName = NULL;
  632. }
  633. }
  634. }
  635. CommonExit:
  636. //
  637. // Free resource.
  638. //
  639. if (szContainerName)
  640. {
  641. ::CoTaskMemFree((LPVOID) szContainerName);
  642. }
  643. if (szCSPName)
  644. {
  645. pfnSCardFreeMemory(hContext, (LPVOID) szCSPName);
  646. }
  647. if (szCardName)
  648. {
  649. pfnSCardFreeMemory(hContext, (LPVOID) szCardName);
  650. }
  651. if (lpReaderStates)
  652. {
  653. ::CoTaskMemFree((LPVOID) lpReaderStates);
  654. }
  655. if (mszReaderNames)
  656. {
  657. pfnSCardFreeMemory(hContext, (LPVOID) mszReaderNames);
  658. }
  659. if (hContext)
  660. {
  661. pfnSCardReleaseContext(hContext);
  662. }
  663. if (hWinSCardDll)
  664. {
  665. ::FreeLibrary(hWinSCardDll);
  666. }
  667. DebugTrace("Leaving LoadFromSmartCard().\n");
  668. return hr;
  669. ErrorExit:
  670. //
  671. // Sanity check.
  672. //
  673. ATLASSERT(FAILED(hr));
  674. goto CommonExit;
  675. }