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.

4145 lines
106 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2001
  3. Module Name:
  4. Windows for Smart Cards Base CSP
  5. Abstract:
  6. Author:
  7. Dan Griffin
  8. Notes:
  9. --*/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <wincrypt.h>
  15. #pragma warning(push)
  16. #pragma warning(disable:4201)
  17. // Disable error C4201 in public header
  18. // nonstandard extension used : nameless struct/union
  19. #include <winscard.h>
  20. #pragma warning(pop)
  21. #include <cspdk.h>
  22. #include <md5.h>
  23. #include <stdlib.h>
  24. #include "basecsp.h"
  25. #include "cardmod.h"
  26. #include "datacach.h"
  27. #include "pincache.h"
  28. #include "pinlib.h"
  29. #include "resource.h"
  30. #include "debug.h"
  31. #include "compress.h"
  32. extern DWORD
  33. WINAPI
  34. Asn1UtilAdjustEncodedLength(
  35. IN const BYTE *pbDER,
  36. IN DWORD cbDER
  37. );
  38. //
  39. // Debugging Macros
  40. //
  41. #define LOG_BEGIN_FUNCTION(x) \
  42. { DebugLog((DEB_TRACE_CSP, "%s: Entering\n", #x)); }
  43. #define LOG_END_FUNCTION(x, y) \
  44. { DebugLog((DEB_TRACE_CSP, "%s: Leaving, status: 0x%x\n", #x, y)); }
  45. #define LOG_BEGIN_CRYPTOAPI(x) \
  46. { DebugLog((DEB_TRACE_CRYPTOAPI, "%s: Entering\n", #x)); }
  47. #define LOG_END_CRYPTOAPI(x, y) \
  48. { DebugLog((DEB_TRACE_CRYPTOAPI, "%s: Leaving, status: 0x%x\n", #x, y)); }
  49. //
  50. // When receiving an encoded certificate from the calling application,
  51. // the current interface doesn't include a length, so we have to try
  52. // to determine the length of the encoded blob ourselves. If there's an
  53. // encoding error, we'll just walk off the end of the buffer, so set this
  54. // maximum.
  55. //
  56. #define cbENCODED_CERT_OVERFLOW 5000 // Bytes
  57. #define PROVPATH "SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\"
  58. #define PROVPATH_LEN sizeof(PROVPATH)
  59. //
  60. // Local structure definitions
  61. //
  62. //
  63. // This is a node for the list of algorithms supported by this CSP and a given
  64. // card.
  65. //
  66. typedef struct _SUPPORTED_ALGORITHM
  67. {
  68. struct _SUPPORTED_ALGORITHM *pNext;
  69. PROV_ENUMALGS_EX EnumalgsEx;
  70. } SUPPORTED_ALGORITHM, *PSUPPORTED_ALGORITHM;
  71. //
  72. // Type: LOCAL_USER_CONTEXT
  73. //
  74. // This is the HCRYPTPROV type for the base CSP.
  75. //
  76. #define LOCAL_USER_CONTEXT_CURRENT_VERSION 1
  77. typedef struct _LOCAL_USER_CONTEXT
  78. {
  79. DWORD dwVersion;
  80. PCARD_STATE pCardState;
  81. CSP_REG_SETTINGS RegSettings;
  82. BOOL fHoldingTransaction;
  83. BYTE bContainerIndex;
  84. // This is a multi-string of all of the container names present on
  85. // the card associated with this context. This member is only used
  86. // by CryptGetProvParam PP_ENUMCONTAINERS. Access is not synchronized.
  87. LPSTR mszEnumContainers;
  88. LPSTR mszCurrentEnumContainer;
  89. // This is a list of algorithms supported by this CSP and card. This is
  90. // only accessed via CryptGetProvParam PP_ENUMALGS and PP_ENUMALGS_EX.
  91. // Access is not synchronized.
  92. PSUPPORTED_ALGORITHM pSupportedAlgs;
  93. PSUPPORTED_ALGORITHM pCurrentAlg;
  94. } LOCAL_USER_CONTEXT, *PLOCAL_USER_CONTEXT;
  95. //
  96. // Type: LOCAL_KEY_CONTEXT
  97. //
  98. // This is the HCRYPTKEY type for the base CSP.
  99. //
  100. typedef struct _LOCAL_KEY_CONTEXT
  101. {
  102. PBYTE pbArchivablePrivateKey;
  103. DWORD cbArchivablePrivateKey;
  104. } LOCAL_KEY_CONTEXT, *PLOCAL_KEY_CONTEXT;
  105. //
  106. // Type: LOCAL_HASH_CONTEXT
  107. //
  108. // This is the HCRYPTHASH type for the base CSP.
  109. //
  110. /*
  111. typedef struct _LOCAL_HASH_CONTEXT
  112. {
  113. //
  114. // Don't need anything here yet.
  115. //
  116. } LOCAL_HASH_CONTEXT, *PLOCAL_HASH_CONTEXT;
  117. */
  118. //
  119. // Global variables
  120. //
  121. CSP_STRING g_Strings [] =
  122. {
  123. { NULL, IDS_PINDIALOG_NEWPIN_MISMATCH },
  124. { NULL, IDS_PINDIALOG_MSGBOX_TITLE },
  125. { NULL, IDS_PINDIALOG_WRONG_PIN },
  126. { NULL, IDS_PINDIALOG_PIN_RETRIES }
  127. };
  128. CSP_STATE g_CspState;
  129. CARD_KEY_SIZES DefaultCardKeySizes =
  130. {
  131. CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0
  132. };
  133. //
  134. // Registry Initialization
  135. //
  136. //
  137. // Function: RegConfigAddEntries
  138. //
  139. DWORD WINAPI RegConfigAddEntries(
  140. IN HKEY hKey)
  141. {
  142. DWORD dwSts = ERROR_SUCCESS;
  143. DWORD iEntry = 0;
  144. for ( iEntry = 0;
  145. iEntry < sizeof(RegConfigValues) / sizeof(RegConfigValues[0]);
  146. iEntry++)
  147. {
  148. dwSts = RegSetValueExW(
  149. hKey,
  150. RegConfigValues[iEntry].wszValueName,
  151. 0L,
  152. REG_DWORD,
  153. (LPBYTE) &RegConfigValues[iEntry].dwDefValue,
  154. sizeof(DWORD));
  155. if (ERROR_SUCCESS != dwSts)
  156. goto Ret;
  157. }
  158. Ret:
  159. return dwSts;
  160. }
  161. //
  162. // Function: RegConfigGetSettings
  163. //
  164. DWORD WINAPI RegConfigGetSettings(
  165. IN OUT PCSP_REG_SETTINGS pRegSettings)
  166. {
  167. DWORD dwSts = ERROR_SUCCESS;
  168. HKEY hKey = 0;
  169. DWORD dwVal = 0;
  170. DWORD cbVal = sizeof(DWORD);
  171. dwSts = RegOpenProviderKey(&hKey, KEY_READ);
  172. if (ERROR_SUCCESS != dwSts)
  173. goto Ret;
  174. dwSts = RegQueryValueExW(
  175. hKey,
  176. wszREG_DEFAULT_KEY_LEN,
  177. NULL,
  178. NULL,
  179. (LPBYTE) &dwVal,
  180. &cbVal);
  181. if (ERROR_SUCCESS != dwSts)
  182. goto Ret;
  183. pRegSettings->cDefaultPrivateKeyLenBits = dwVal;
  184. dwVal = 0;
  185. cbVal = sizeof(DWORD);
  186. dwSts = RegQueryValueExW(
  187. hKey,
  188. wszREG_REQUIRE_CARD_KEY_GEN,
  189. NULL,
  190. NULL,
  191. (LPBYTE) &dwVal,
  192. &cbVal);
  193. if (ERROR_SUCCESS != dwSts)
  194. goto Ret;
  195. pRegSettings->fRequireOnCardPrivateKeyGen = (BOOL) dwVal;
  196. dwVal = 0;
  197. cbVal = sizeof(DWORD);
  198. Ret:
  199. if (hKey)
  200. RegCloseKey(hKey);
  201. return dwSts;
  202. }
  203. //
  204. // CSP State Management Routines
  205. //
  206. //
  207. // Function: DeleteCspState
  208. //
  209. // Purpose: Delete the global state data structure for this CSP.
  210. // Should be called during DLL_PROCESS_DETACH.
  211. //
  212. DWORD DeleteCspState(void)
  213. {
  214. CspDeleteCriticalSection(&g_CspState.cs);
  215. if (0 != g_CspState.hCache)
  216. CacheDeleteCache(g_CspState.hCache);
  217. memset(&g_CspState, 0, sizeof(g_CspState));
  218. return ERROR_SUCCESS;
  219. }
  220. //
  221. // Function: InitializeCspState
  222. //
  223. // Purpose: Setup the global state data structure for this CSP.
  224. // Should be called during DLL_PROCESS_ATTACH.
  225. //
  226. DWORD InitializeCspState(
  227. IN HMODULE hCspModule)
  228. {
  229. DWORD dwSts = ERROR_SUCCESS;
  230. CACHE_INITIALIZE_INFO CacheInitInfo;
  231. BOOL fSuccess = FALSE;
  232. memset(&g_CspState, 0, sizeof(g_CspState));
  233. memset(&CacheInitInfo, 0, sizeof(CacheInitInfo));
  234. g_CspState.hCspModule = hCspModule;
  235. dwSts = CspInitializeCriticalSection(
  236. &g_CspState.cs);
  237. if (ERROR_SUCCESS != dwSts)
  238. goto Ret;
  239. CacheInitInfo.dwType = CACHE_TYPE_IN_PROC;
  240. dwSts = CacheInitializeCache(
  241. &g_CspState.hCache,
  242. &CacheInitInfo);
  243. if (ERROR_SUCCESS != dwSts)
  244. goto Ret;
  245. fSuccess = TRUE;
  246. Ret:
  247. if (FALSE == fSuccess)
  248. DeleteCspState();
  249. return dwSts;
  250. }
  251. //
  252. // Function: GetCspState
  253. //
  254. // Purpose: Acquire a pointer to the global state data structure
  255. // for this CSP. This function should always be used,
  256. // rather than referring to the global object directly.
  257. //
  258. DWORD GetCspState(
  259. IN OUT PCSP_STATE *ppCspState)
  260. {
  261. DWORD dwSts;
  262. dwSts = CspEnterCriticalSection(
  263. &g_CspState.cs);
  264. if (ERROR_SUCCESS != dwSts)
  265. return dwSts;
  266. g_CspState.dwRefCount++;
  267. CspLeaveCriticalSection(
  268. &g_CspState.cs);
  269. *ppCspState = &g_CspState;
  270. return ERROR_SUCCESS;
  271. }
  272. //
  273. // Function: ReleaseCspState
  274. //
  275. // Purpose: Signal that the caller's pointer to the global
  276. // state data structure is no longer being used.
  277. //
  278. DWORD ReleaseCspState(
  279. IN OUT PCSP_STATE *ppCspState)
  280. {
  281. DWORD dwSts;
  282. dwSts = CspEnterCriticalSection(
  283. &g_CspState.cs);
  284. if (ERROR_SUCCESS != dwSts)
  285. return dwSts;
  286. g_CspState.dwRefCount--;
  287. CspLeaveCriticalSection(
  288. &g_CspState.cs);
  289. *ppCspState = NULL;
  290. return ERROR_SUCCESS;
  291. }
  292. //
  293. // Pin Management Routines
  294. //
  295. //
  296. // Struct: VERIFY_PIN_CALLBACK_DATA
  297. //
  298. typedef struct _VERIFY_PIN_CALLBACK_DATA
  299. {
  300. PUSER_CONTEXT pUserCtx;
  301. LPWSTR wszUserId;
  302. } VERIFY_PIN_CALLBACK_DATA, *PVERIFY_PIN_CALLBACK_DATA;
  303. //
  304. // Callback for verifying a submitted pin, or requested pin change, from the
  305. // user via the pin prompt UI.
  306. //
  307. DWORD WINAPI VerifyPinFromUICallback(
  308. IN PPINCACHE_PINS pPins,
  309. IN PVOID pvCallbackCtx)
  310. {
  311. PPIN_SHOW_GET_PIN_UI_INFO pInfo =
  312. (PPIN_SHOW_GET_PIN_UI_INFO) pvCallbackCtx;
  313. PVERIFY_PIN_CALLBACK_DATA pData =
  314. (PVERIFY_PIN_CALLBACK_DATA) pInfo->pvCallbackContext;
  315. PLOCAL_USER_CONTEXT pLocal =
  316. (PLOCAL_USER_CONTEXT) pData->pUserCtx->pvLocalUserContext;
  317. // Determine if a Change Pin operation has been requested
  318. if (NULL != pPins->pbNewPin)
  319. {
  320. // A pin change needs to go through the caching layer to ensure that
  321. // the cache and associated counters get updated.
  322. return CspChangeAuthenticator(
  323. pLocal->pCardState,
  324. pData->wszUserId,
  325. pPins->pbCurrentPin,
  326. pPins->cbCurrentPin,
  327. pPins->pbNewPin,
  328. pPins->cbNewPin,
  329. 0,
  330. &pInfo->cAttemptsRemaining);
  331. }
  332. // For the simple submit pin, this pin is directly from the user, so we
  333. // pass it directly to the card rather than going through the caching
  334. // layer.
  335. return pLocal->pCardState->pCardData->pfnCardSubmitPin(
  336. pLocal->pCardState->pCardData,
  337. pData->wszUserId,
  338. pPins->pbCurrentPin,
  339. pPins->cbCurrentPin,
  340. &pInfo->cAttemptsRemaining);
  341. }
  342. //
  343. // Function: VerifyPinCallback
  344. //
  345. DWORD WINAPI VerifyPinCallback(
  346. IN PPINCACHE_PINS pPins,
  347. IN PVOID pvCallbackCtx)
  348. {
  349. PVERIFY_PIN_CALLBACK_DATA pData =
  350. (PVERIFY_PIN_CALLBACK_DATA) pvCallbackCtx;
  351. PLOCAL_USER_CONTEXT pLocal =
  352. (PLOCAL_USER_CONTEXT) pData->pUserCtx->pvLocalUserContext;
  353. // This pin is from the pin cache, so filter it through the caching layer.
  354. return CspSubmitPin(
  355. pLocal->pCardState,
  356. pData->wszUserId,
  357. pPins->pbCurrentPin,
  358. pPins->cbCurrentPin,
  359. NULL);
  360. }
  361. //
  362. // Function: CspAuthenticateUser
  363. //
  364. DWORD WINAPI CspAuthenticateUser(
  365. IN PUSER_CONTEXT pUserCtx)
  366. {
  367. VERIFY_PIN_CALLBACK_DATA CallbackCtx;
  368. DWORD dwError = ERROR_SUCCESS;
  369. PLOCAL_USER_CONTEXT pLocalUserContext =
  370. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  371. PIN_SHOW_GET_PIN_UI_INFO PinUIInfo;
  372. PINCACHE_PINS Pins;
  373. LOG_BEGIN_FUNCTION(CspAuthenticateUser);
  374. memset(&Pins, 0, sizeof(Pins));
  375. memset(&PinUIInfo, 0, sizeof(PinUIInfo));
  376. memset(&CallbackCtx, 0, sizeof(CallbackCtx));
  377. CallbackCtx.pUserCtx = pUserCtx;
  378. CallbackCtx.wszUserId = wszCARD_USER_USER;
  379. dwError = PinCachePresentPin(
  380. pLocalUserContext->pCardState->hPinCache,
  381. VerifyPinCallback,
  382. (PVOID) &CallbackCtx);
  383. if (SCARD_W_CARD_NOT_AUTHENTICATED == dwError ||
  384. ERROR_EMPTY == dwError ||
  385. SCARD_W_WRONG_CHV == dwError)
  386. {
  387. PinCacheFlush(&pLocalUserContext->pCardState->hPinCache);
  388. // No pin is cached. Is the context "silent"?
  389. if (CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags ||
  390. CRYPT_SILENT & pUserCtx->dwFlags)
  391. {
  392. dwError = (DWORD) NTE_SILENT_CONTEXT;
  393. goto Ret;
  394. }
  395. // Context is not silent. Show UI to let the user enter a pin.
  396. pUserCtx->pVTableW->FuncReturnhWnd(&PinUIInfo.hClientWindow);
  397. PinUIInfo.pStrings = g_Strings;
  398. PinUIInfo.hDlgResourceModule = GetModuleHandle(L"basecsp.dll");
  399. PinUIInfo.wszPrincipal = wszCARD_USER_USER;
  400. PinUIInfo.pfnVerify = VerifyPinFromUICallback;
  401. PinUIInfo.pvCallbackContext = (PVOID) &CallbackCtx;
  402. PinUIInfo.wszCardName =
  403. pLocalUserContext->pCardState->wszSerialNumber;
  404. dwError = PinShowGetPinUI(&PinUIInfo);
  405. if (ERROR_SUCCESS != dwError || NULL == PinUIInfo.pbPin)
  406. goto Ret;
  407. Pins.cbCurrentPin = PinUIInfo.cbPin;
  408. Pins.pbCurrentPin = PinUIInfo.pbPin;
  409. //
  410. // The user entered a pin that has been successfully verified by the
  411. // card. The Pin UI should have already converted the pin from
  412. // string form into bytes that we can send to the card.
  413. // Cache the pin.
  414. //
  415. dwError = PinCacheAdd(
  416. &pLocalUserContext->pCardState->hPinCache,
  417. &Pins,
  418. VerifyPinCallback,
  419. (PVOID) &CallbackCtx);
  420. if (ERROR_SUCCESS != dwError)
  421. goto Ret;
  422. }
  423. pLocalUserContext->pCardState->fAuthenticated = TRUE;
  424. Ret:
  425. if (PinUIInfo.pbPin)
  426. {
  427. RtlSecureZeroMemory(PinUIInfo.pbPin, PinUIInfo.cbPin);
  428. CspFreeH(PinUIInfo.pbPin);
  429. }
  430. LOG_END_FUNCTION(CspAuthenticateUser, dwError);
  431. return dwError;
  432. }
  433. //
  434. // Frees the memory consumed by the supported algorithms list.
  435. //
  436. DWORD FreeSupportedAlgorithmsList(PLOCAL_USER_CONTEXT pLocal)
  437. {
  438. DWORD dwError = ERROR_SUCCESS;
  439. PSUPPORTED_ALGORITHM pCurrent = NULL;
  440. DsysAssert(NULL != pLocal->pSupportedAlgs);
  441. while (NULL != pLocal->pSupportedAlgs)
  442. {
  443. pCurrent = pLocal->pSupportedAlgs;
  444. pLocal->pSupportedAlgs = pCurrent->pNext;
  445. CspFreeH(pCurrent);
  446. }
  447. return ERROR_SUCCESS;
  448. }
  449. //
  450. // Builds a list of algorithms supported by this CSP and smartcard.
  451. //
  452. DWORD BuildSupportedAlgorithmsList(PUSER_CONTEXT pUserCtx)
  453. {
  454. PLOCAL_USER_CONTEXT pLocal = (PLOCAL_USER_CONTEXT)
  455. pUserCtx->pvLocalUserContext;
  456. DWORD dwSts = ERROR_SUCCESS;
  457. CARD_KEY_SIZES CardKeySizes;
  458. PROV_ENUMALGS_EX EnumalgsEx;
  459. DWORD cbData = sizeof(EnumalgsEx);
  460. PSUPPORTED_ALGORITHM pCurrent = NULL;
  461. DWORD dwFlag = CRYPT_FIRST;
  462. DsysAssert(NULL != pLocal);
  463. DsysAssert(NULL == pLocal->pSupportedAlgs);
  464. memset(&CardKeySizes, 0, sizeof(CardKeySizes));
  465. memset(&EnumalgsEx, 0, sizeof(EnumalgsEx));
  466. while (TRUE == CryptGetProvParam(
  467. pUserCtx->hSupportProv,
  468. PP_ENUMALGS_EX,
  469. (PBYTE) &EnumalgsEx,
  470. &cbData,
  471. dwFlag))
  472. {
  473. dwFlag = CRYPT_NEXT;
  474. if (NULL == pCurrent)
  475. {
  476. // First item
  477. pLocal->pSupportedAlgs = (PSUPPORTED_ALGORITHM) CspAllocH(
  478. sizeof(SUPPORTED_ALGORITHM));
  479. LOG_CHECK_ALLOC(pLocal->pSupportedAlgs);
  480. pCurrent = pLocal->pSupportedAlgs;
  481. }
  482. else
  483. {
  484. // Adding an item
  485. pCurrent->pNext = (PSUPPORTED_ALGORITHM) CspAllocH(
  486. sizeof(SUPPORTED_ALGORITHM));
  487. LOG_CHECK_ALLOC(pCurrent->pNext);
  488. pCurrent = pCurrent->pNext;
  489. }
  490. memcpy(
  491. &pCurrent->EnumalgsEx,
  492. &EnumalgsEx,
  493. sizeof(EnumalgsEx));
  494. memset(&EnumalgsEx, 0, sizeof(EnumalgsEx));
  495. // Special handling for public key algs since they depend on what the
  496. // target card actually supports
  497. switch (pCurrent->EnumalgsEx.aiAlgid)
  498. {
  499. case CALG_RSA_KEYX:
  500. // If there's no CARD_STATE in this context, that should mean this
  501. // is a VerifyContext with no card inserted. MMC expects that
  502. // algorithm enumeration is successful without a card, so provide
  503. // some default public key values in that case.
  504. if (NULL == pLocal->pCardState)
  505. {
  506. DsysAssert(CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags);
  507. memcpy(
  508. &CardKeySizes,
  509. &DefaultCardKeySizes,
  510. sizeof(CARD_KEY_SIZES));
  511. break;
  512. }
  513. dwSts = CspQueryKeySizes(
  514. pLocal->pCardState,
  515. AT_KEYEXCHANGE,
  516. 0,
  517. &CardKeySizes);
  518. if (ERROR_SUCCESS != dwSts)
  519. goto Ret;
  520. break;
  521. case CALG_RSA_SIGN:
  522. if (NULL == pLocal->pCardState)
  523. {
  524. DsysAssert(CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags);
  525. memcpy(
  526. &CardKeySizes,
  527. &DefaultCardKeySizes,
  528. sizeof(CARD_KEY_SIZES));
  529. break;
  530. }
  531. dwSts = CspQueryKeySizes(
  532. pLocal->pCardState,
  533. AT_SIGNATURE,
  534. 0,
  535. &CardKeySizes);
  536. if (ERROR_SUCCESS != dwSts)
  537. goto Ret;
  538. break;
  539. default:
  540. // Go to the next alg
  541. continue;
  542. }
  543. pCurrent->EnumalgsEx.dwDefaultLen = CardKeySizes.dwDefaultBitlen;
  544. pCurrent->EnumalgsEx.dwMaxLen = CardKeySizes.dwMaximumBitlen;
  545. pCurrent->EnumalgsEx.dwMinLen = CardKeySizes.dwMinimumBitlen;
  546. memset(&CardKeySizes, 0, sizeof(CardKeySizes));
  547. }
  548. if (ERROR_NO_MORE_ITEMS == (dwSts = GetLastError()))
  549. dwSts = ERROR_SUCCESS;
  550. Ret:
  551. if (ERROR_SUCCESS != dwSts && NULL != pLocal->pSupportedAlgs)
  552. FreeSupportedAlgorithmsList(pLocal);
  553. return dwSts;
  554. }
  555. //
  556. // Function: DeleteLocalUserContext
  557. //
  558. void DeleteLocalUserContext(PLOCAL_USER_CONTEXT pLocalUserCtx)
  559. {
  560. if (NULL != pLocalUserCtx->mszEnumContainers)
  561. {
  562. CspFreeH(pLocalUserCtx->mszEnumContainers);
  563. pLocalUserCtx->mszEnumContainers = NULL;
  564. }
  565. if (NULL != pLocalUserCtx->pSupportedAlgs)
  566. FreeSupportedAlgorithmsList(pLocalUserCtx);
  567. // Don't free the card state here, since those structures are shared.
  568. pLocalUserCtx->pCardState = NULL;
  569. }
  570. //
  571. // Function: CleanupContainerInfo
  572. //
  573. void CleanupContainerInfo(
  574. IN OUT PCONTAINER_INFO pContainerInfo)
  575. {
  576. if (pContainerInfo->pbKeyExPublicKey)
  577. {
  578. CspFreeH(pContainerInfo->pbKeyExPublicKey);
  579. pContainerInfo->pbKeyExPublicKey = NULL;
  580. }
  581. if (pContainerInfo->pbSigPublicKey)
  582. {
  583. CspFreeH(pContainerInfo->pbSigPublicKey);
  584. pContainerInfo->pbSigPublicKey = NULL;
  585. }
  586. }
  587. //
  588. // Function: GetKeyModulusLength
  589. //
  590. DWORD GetKeyModulusLength(
  591. IN PUSER_CONTEXT pUserCtx,
  592. IN DWORD dwKeySpec,
  593. OUT PDWORD pcbModulus)
  594. {
  595. DWORD dwSts = ERROR_SUCCESS;
  596. PLOCAL_USER_CONTEXT pLocal =
  597. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  598. CONTAINER_MAP_RECORD ContainerRecord;
  599. *pcbModulus = 0;
  600. memset(&ContainerRecord, 0, sizeof(ContainerRecord));
  601. wcscpy(ContainerRecord.wszGuid, pUserCtx->wszBaseContainerName);
  602. dwSts = ContainerMapFindContainer(
  603. pLocal->pCardState,
  604. &ContainerRecord,
  605. NULL);
  606. if (ERROR_SUCCESS != dwSts)
  607. goto Ret;
  608. switch (dwKeySpec)
  609. {
  610. case AT_SIGNATURE:
  611. if (0 == ContainerRecord.wSigKeySizeBits)
  612. {
  613. dwSts = (DWORD) NTE_NO_KEY;
  614. goto Ret;
  615. }
  616. *pcbModulus = ContainerRecord.wSigKeySizeBits / 8;
  617. break;
  618. case AT_KEYEXCHANGE:
  619. if (0 == ContainerRecord.wKeyExchangeKeySizeBits)
  620. {
  621. dwSts = (DWORD) NTE_NO_KEY;
  622. goto Ret;
  623. }
  624. *pcbModulus = ContainerRecord.wKeyExchangeKeySizeBits / 8;
  625. break;
  626. default:
  627. dwSts = (DWORD) NTE_BAD_ALGID;
  628. goto Ret;
  629. }
  630. Ret:
  631. return dwSts;
  632. }
  633. //
  634. // Finds the index corresponding to a specified container in the card
  635. // container map file. Returns the contents the container map file.
  636. //
  637. // The container name can optionally be omitted, in which case the map file
  638. // is simply read and returned.
  639. //
  640. DWORD I_ContainerMapFind(
  641. IN PCARD_STATE pCardState,
  642. IN OPTIONAL LPWSTR wszContainerGuid,
  643. OUT OPTIONAL PBYTE pbIndex,
  644. OUT PCONTAINER_MAP_RECORD *ppContainerMapFile,
  645. OUT PBYTE pcContainerMapFile)
  646. {
  647. DWORD dwSts = ERROR_SUCCESS;
  648. DATA_BLOB dbContainerMap;
  649. BYTE iContainer = 0;
  650. memset(&dbContainerMap, 0, sizeof(dbContainerMap));
  651. *ppContainerMapFile = NULL;
  652. *pcContainerMapFile = 0;
  653. // Read the container map file from the card
  654. dwSts = CspReadFile(
  655. pCardState,
  656. wszCONTAINER_MAP_FILE_FULL_PATH,
  657. 0,
  658. &dbContainerMap.pbData,
  659. &dbContainerMap.cbData);
  660. if (ERROR_SUCCESS != dwSts)
  661. goto Ret;
  662. if (0 != dbContainerMap.cbData)
  663. {
  664. // Expect that the file contains an exact multiple of the record size
  665. DsysAssert(0 == (dbContainerMap.cbData % sizeof(CONTAINER_MAP_RECORD)));
  666. *ppContainerMapFile = (PCONTAINER_MAP_RECORD) dbContainerMap.pbData;
  667. *pcContainerMapFile = (BYTE)
  668. (dbContainerMap.cbData / sizeof(CONTAINER_MAP_RECORD));
  669. dbContainerMap.pbData = NULL;
  670. }
  671. // See if caller just wanted us to return the map file contents
  672. if (NULL == wszContainerGuid)
  673. goto Ret;
  674. for ( iContainer = 0;
  675. iContainer < *pcContainerMapFile;
  676. iContainer++)
  677. {
  678. if (0 == wcscmp(
  679. wszContainerGuid,
  680. (*ppContainerMapFile)[iContainer].wszGuid) &&
  681. (CONTAINER_MAP_VALID_CONTAINER &
  682. (*ppContainerMapFile)[iContainer].bFlags))
  683. {
  684. *pbIndex = iContainer;
  685. goto Ret;
  686. }
  687. }
  688. dwSts = NTE_BAD_KEYSET;
  689. Ret:
  690. if (dbContainerMap.pbData)
  691. CspFreeH(dbContainerMap.pbData);
  692. return dwSts;
  693. }
  694. //
  695. // Returns the number of valid containers present on the card. Optionally,
  696. // returns a list of the container names in a multi-string.
  697. //
  698. // The returned *mwszContainers pointer must be freed by the caller.
  699. //
  700. DWORD ContainerMapEnumContainers(
  701. IN PCARD_STATE pCardState,
  702. OUT PBYTE pcContainers,
  703. OUT OPTIONAL LPWSTR *mwszContainers)
  704. {
  705. DWORD dwSts = ERROR_SUCCESS;
  706. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  707. BYTE cContainerMap = 0;
  708. BYTE iContainer = 0;
  709. DWORD cchCurrent = 0;
  710. DWORD cchCumulative = 0;
  711. *pcContainers = 0;
  712. if (NULL != mwszContainers)
  713. *mwszContainers = NULL;
  714. dwSts = I_ContainerMapFind(
  715. pCardState,
  716. NULL,
  717. NULL,
  718. &pContainerMap,
  719. &cContainerMap);
  720. if (ERROR_SUCCESS != dwSts)
  721. goto Ret;
  722. //
  723. // We'll make two passes through the container map file. The first pass
  724. // counts the number of valid containers present. This allows us to make
  725. // a single allocation large enough for a multi-string consisting of all
  726. // of the valid container names. We'll pick up the names in the second
  727. // pass through the file.
  728. //
  729. // Pass 1
  730. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  731. {
  732. if (CONTAINER_MAP_VALID_CONTAINER & pContainerMap[iContainer].bFlags)
  733. *pcContainers += 1;
  734. }
  735. if (0 == *pcContainers || NULL == mwszContainers)
  736. goto Ret;
  737. // Build a big enough buffer
  738. *mwszContainers = (LPWSTR) CspAllocH(
  739. ((*pcContainers * (1 + MAX_CONTAINER_NAME_LEN)) + 1) * sizeof(WCHAR));
  740. // Pass 2
  741. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  742. {
  743. if (CONTAINER_MAP_VALID_CONTAINER & pContainerMap[iContainer].bFlags)
  744. {
  745. cchCurrent = wcslen(pContainerMap[iContainer].wszGuid);
  746. memcpy(
  747. *mwszContainers + cchCumulative,
  748. pContainerMap[iContainer].wszGuid,
  749. cchCurrent * sizeof(WCHAR));
  750. cchCumulative += cchCurrent + 1;
  751. }
  752. }
  753. Ret:
  754. if (pContainerMap)
  755. CspFreeH(pContainerMap);
  756. return dwSts;
  757. }
  758. //
  759. // Searches for the named container on the card. The container to look for
  760. // must be in pContainer->wszGuid. If the container is not found,
  761. // NTE_BAD_KEYSET is returned.
  762. //
  763. DWORD ContainerMapFindContainer(
  764. IN PCARD_STATE pCardState,
  765. IN OUT PCONTAINER_MAP_RECORD pContainer,
  766. OUT OPTIONAL PBYTE pbContainerIndex)
  767. {
  768. DWORD dwSts = ERROR_SUCCESS;
  769. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  770. BYTE bIndex = 0;
  771. BYTE cContainerMap = 0;
  772. dwSts = I_ContainerMapFind(
  773. pCardState,
  774. pContainer->wszGuid,
  775. &bIndex,
  776. &pContainerMap,
  777. &cContainerMap);
  778. if (ERROR_SUCCESS != dwSts)
  779. goto Ret;
  780. memcpy(
  781. (PBYTE) pContainer,
  782. (PBYTE) (pContainerMap + bIndex),
  783. sizeof(CONTAINER_MAP_RECORD));
  784. if (NULL != pbContainerIndex)
  785. *pbContainerIndex = bIndex;
  786. Ret:
  787. if (pContainerMap)
  788. CspFreeH(pContainerMap);
  789. return dwSts;
  790. }
  791. //
  792. // Searches for the default container on the card. If no default container is
  793. // found, NTE_BAD_KEYSET is returned.
  794. //
  795. DWORD ContainerMapGetDefaultContainer(
  796. IN PCARD_STATE pCardState,
  797. OUT PCONTAINER_MAP_RECORD pContainer,
  798. OUT OPTIONAL PBYTE pbContainerIndex)
  799. {
  800. DWORD dwSts = ERROR_SUCCESS;
  801. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  802. BYTE cContainerMap = 0;
  803. BYTE iContainer = 0;
  804. dwSts = I_ContainerMapFind(
  805. pCardState,
  806. NULL,
  807. NULL,
  808. &pContainerMap,
  809. &cContainerMap);
  810. if (ERROR_SUCCESS != dwSts)
  811. goto Ret;
  812. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  813. {
  814. if ((pContainerMap[iContainer].bFlags &
  815. CONTAINER_MAP_VALID_CONTAINER) &&
  816. (pContainerMap[iContainer].bFlags &
  817. CONTAINER_MAP_DEFAULT_CONTAINER))
  818. {
  819. memcpy(
  820. (PBYTE) pContainer,
  821. (PBYTE) (pContainerMap + iContainer),
  822. sizeof(CONTAINER_MAP_RECORD));
  823. if (NULL != pbContainerIndex)
  824. *pbContainerIndex = iContainer;
  825. goto Ret;
  826. }
  827. }
  828. dwSts = NTE_BAD_KEYSET;
  829. Ret:
  830. if (pContainerMap)
  831. CspFreeH(pContainerMap);
  832. return dwSts;
  833. }
  834. //
  835. // Sets the default container on the card.
  836. //
  837. DWORD ContainerMapSetDefaultContainer(
  838. IN PCARD_STATE pCardState,
  839. IN LPWSTR wszContainerGuid)
  840. {
  841. DWORD dwSts = ERROR_SUCCESS;
  842. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  843. BYTE bIndex = 0;
  844. BYTE cContainerMap = 0;
  845. BYTE iContainer = 0;
  846. DATA_BLOB dbContainerMap;
  847. memset(&dbContainerMap, 0, sizeof(dbContainerMap));
  848. dwSts = I_ContainerMapFind(
  849. pCardState,
  850. wszContainerGuid,
  851. &bIndex,
  852. &pContainerMap,
  853. &cContainerMap);
  854. if (ERROR_SUCCESS != dwSts)
  855. goto Ret;
  856. //
  857. // If some other container is currently marked as the default, unmark it.
  858. //
  859. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  860. {
  861. if (pContainerMap[iContainer].bFlags & CONTAINER_MAP_DEFAULT_CONTAINER)
  862. pContainerMap[iContainer].bFlags &= ~CONTAINER_MAP_DEFAULT_CONTAINER;
  863. }
  864. pContainerMap[bIndex].bFlags |= CONTAINER_MAP_DEFAULT_CONTAINER;
  865. dbContainerMap.pbData = (PBYTE) pContainerMap;
  866. dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
  867. // Write the updated map file to the card
  868. dwSts = CspWriteFile(
  869. pCardState,
  870. wszCONTAINER_MAP_FILE_FULL_PATH,
  871. 0,
  872. dbContainerMap.pbData,
  873. dbContainerMap.cbData);
  874. Ret:
  875. if (pContainerMap)
  876. CspFreeH(pContainerMap);
  877. return dwSts;
  878. }
  879. //
  880. // Adds a new container record to the container map. If the specified
  881. // container already exists, replaces the existing keyset (if any) with
  882. // the one provided.
  883. //
  884. // If cKeySizeBits is zero, assumes that a container with no keys is being
  885. // added.
  886. //
  887. DWORD ContainerMapAddContainer(
  888. IN PCARD_STATE pCardState,
  889. IN LPWSTR pwszContainerGuid,
  890. IN DWORD cKeySizeBits,
  891. IN DWORD dwKeySpec,
  892. IN BOOL fGetNameOnly,
  893. OUT PBYTE pbContainerIndex)
  894. {
  895. DWORD dwSts = ERROR_SUCCESS;
  896. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  897. BYTE cContainerMap = 0;
  898. BYTE iContainer = 0;
  899. DATA_BLOB dbContainerMap;
  900. PCONTAINER_MAP_RECORD pNewMap = NULL;
  901. BOOL fExistingContainer = FALSE;
  902. memset(&dbContainerMap, 0, sizeof(dbContainerMap));
  903. // See if this container already exists
  904. dwSts = I_ContainerMapFind(
  905. pCardState,
  906. pwszContainerGuid,
  907. &iContainer,
  908. &pContainerMap,
  909. &cContainerMap);
  910. switch (dwSts)
  911. {
  912. case NTE_BAD_KEYSET:
  913. //
  914. // This is a new container that does not already exist.
  915. // Look for an existing "empty" slot in the container map file
  916. //
  917. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  918. {
  919. if (0 == (pContainerMap[iContainer].bFlags &
  920. CONTAINER_MAP_VALID_CONTAINER))
  921. break;
  922. }
  923. break;
  924. case ERROR_SUCCESS:
  925. //
  926. // This container already exists. The new keyset will be added to it,
  927. // possibly replacing an existing keyset of the same type.
  928. //
  929. fExistingContainer = TRUE;
  930. break;
  931. default:
  932. goto Ret;
  933. }
  934. //
  935. // Pass the container index that we're using back to the caller; that may
  936. // be all that was requested.
  937. //
  938. *pbContainerIndex = iContainer;
  939. if (fGetNameOnly)
  940. goto Ret;
  941. if (iContainer == cContainerMap)
  942. {
  943. //
  944. // No empty slot was found in the container map. We'll have to grow
  945. // the map and add the new container to the end.
  946. //
  947. pNewMap = (PCONTAINER_MAP_RECORD) CspAllocH(
  948. (cContainerMap + 1) * sizeof(CONTAINER_MAP_RECORD));
  949. LOG_CHECK_ALLOC(pNewMap);
  950. memcpy(
  951. (PBYTE) pNewMap,
  952. (PBYTE) pContainerMap,
  953. cContainerMap * sizeof(CONTAINER_MAP_RECORD));
  954. CspFreeH(pContainerMap);
  955. pContainerMap = pNewMap;
  956. pNewMap = NULL;
  957. cContainerMap++;
  958. }
  959. //
  960. // Update the container map file and write it to the card
  961. //
  962. pContainerMap[iContainer].bFlags |= CONTAINER_MAP_VALID_CONTAINER;
  963. if (0 != cKeySizeBits)
  964. {
  965. switch (dwKeySpec)
  966. {
  967. case AT_KEYEXCHANGE:
  968. pContainerMap[iContainer].wKeyExchangeKeySizeBits = (WORD) cKeySizeBits;
  969. break;
  970. case AT_SIGNATURE:
  971. pContainerMap[iContainer].wSigKeySizeBits = (WORD) cKeySizeBits;
  972. break;
  973. default:
  974. dwSts = NTE_BAD_ALGID;
  975. goto Ret;
  976. }
  977. }
  978. if (FALSE == fExistingContainer)
  979. {
  980. wcscpy(
  981. pContainerMap[iContainer].wszGuid,
  982. pwszContainerGuid);
  983. }
  984. dbContainerMap.pbData = (PBYTE) pContainerMap;
  985. dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
  986. dwSts = CspWriteFile(
  987. pCardState,
  988. wszCONTAINER_MAP_FILE_FULL_PATH,
  989. 0,
  990. dbContainerMap.pbData,
  991. dbContainerMap.cbData);
  992. Ret:
  993. if (pContainerMap)
  994. CspFreeH(pContainerMap);
  995. if (pNewMap)
  996. CspFreeH(pNewMap);
  997. return dwSts;
  998. }
  999. //
  1000. // Deletes a container record from the container map. Returns NTE_BAD_KEYSET
  1001. // if the specified container does not exist.
  1002. //
  1003. // If the deleted container was the default, finds the first valid container
  1004. // remaining on the card and marks it as the new default.
  1005. //
  1006. DWORD ContainerMapDeleteContainer(
  1007. IN PCARD_STATE pCardState,
  1008. IN LPWSTR pwszContainerGuid,
  1009. OUT PBYTE pbContainerIndex)
  1010. {
  1011. DWORD dwSts = ERROR_SUCCESS;
  1012. PCONTAINER_MAP_RECORD pContainerMap = NULL;
  1013. BYTE dwIndex = 0;
  1014. BYTE cContainerMap = 0;
  1015. DATA_BLOB dbContainerMap;
  1016. BYTE iContainer = 0;
  1017. memset(&dbContainerMap, 0, sizeof(dbContainerMap));
  1018. //
  1019. // See if this container already exists. If it does, invalidate its entry
  1020. // in the map file and write the file back to the card.
  1021. //
  1022. dwSts = I_ContainerMapFind(
  1023. pCardState,
  1024. pwszContainerGuid,
  1025. &dwIndex,
  1026. &pContainerMap,
  1027. &cContainerMap);
  1028. if (ERROR_SUCCESS != dwSts)
  1029. goto Ret;
  1030. if (CONTAINER_MAP_DEFAULT_CONTAINER & pContainerMap[dwIndex].bFlags)
  1031. {
  1032. // Find a valid container to mark as the new default
  1033. for (iContainer = 0; iContainer < cContainerMap; iContainer++)
  1034. {
  1035. if (CONTAINER_MAP_VALID_CONTAINER &
  1036. pContainerMap[iContainer].bFlags)
  1037. {
  1038. pContainerMap[iContainer].bFlags |=
  1039. CONTAINER_MAP_DEFAULT_CONTAINER;
  1040. break;
  1041. }
  1042. }
  1043. }
  1044. memset(
  1045. (PBYTE) (pContainerMap + dwIndex),
  1046. 0,
  1047. sizeof(CONTAINER_MAP_RECORD));
  1048. *pbContainerIndex = dwIndex;
  1049. //
  1050. // Update the container map file and write it to the card
  1051. //
  1052. dbContainerMap.pbData = (PBYTE) pContainerMap;
  1053. dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
  1054. dwSts = CspWriteFile(
  1055. pCardState,
  1056. wszCONTAINER_MAP_FILE_FULL_PATH,
  1057. 0,
  1058. dbContainerMap.pbData,
  1059. dbContainerMap.cbData);
  1060. Ret:
  1061. if (pContainerMap)
  1062. CspFreeH(pContainerMap);
  1063. return dwSts;
  1064. }
  1065. //
  1066. // Function: ValidateCardHandle
  1067. //
  1068. // Purpose: Verify that the provided SCARDHANDLE is valid. If the handle
  1069. // is not valid, disconnect and flush the pin cache.
  1070. //
  1071. // Assume: pCardState critical section should currently be held by caller.
  1072. //
  1073. DWORD ValidateCardHandle(
  1074. IN PCARD_STATE pCardState,
  1075. IN BOOL fMayReleaseContextHandle,
  1076. OUT OPTIONAL BOOL *pfFlushPinCache)
  1077. {
  1078. DWORD dwSts = ERROR_SUCCESS;
  1079. DWORD dwState = 0;
  1080. DWORD dwProtocol = 0;
  1081. DWORD cch = 0;
  1082. LPWSTR mszReaders = NULL;
  1083. BYTE rgbAtr [cbATR_BUFFER];
  1084. DWORD cbAtr = sizeof(rgbAtr);
  1085. PCARD_DATA pCardData = pCardState->pCardData;
  1086. LOG_BEGIN_FUNCTION(ValidateCardHandle);
  1087. cch = SCARD_AUTOALLOCATE;
  1088. dwSts = SCardStatusW(
  1089. pCardData->hScard,
  1090. (LPWSTR) &mszReaders,
  1091. &cch,
  1092. &dwState,
  1093. &dwProtocol,
  1094. rgbAtr,
  1095. &cbAtr);
  1096. if (mszReaders)
  1097. SCardFreeMemory(pCardData->hScard, mszReaders);
  1098. switch (dwSts)
  1099. {
  1100. case SCARD_W_RESET_CARD:
  1101. dwSts = SCardReconnect(
  1102. pCardData->hScard,
  1103. SCARD_SHARE_SHARED,
  1104. SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
  1105. SCARD_LEAVE_CARD,
  1106. &dwProtocol);
  1107. if (ERROR_SUCCESS == dwSts)
  1108. // We're done if reconnect succeeded
  1109. goto Ret;
  1110. break;
  1111. case ERROR_SUCCESS:
  1112. if (SCARD_SPECIFIC == dwState)
  1113. // The card handle is still valid and ready to use. We're done.
  1114. goto Ret;
  1115. break;
  1116. default:
  1117. // This includes the case where the card status SCARD_W_REMOVED was
  1118. // returned. Nothing to do but disconnect, below.
  1119. break;
  1120. }
  1121. //
  1122. // The card appears to have been withdrawan at some point, or some
  1123. // other problem occurred.
  1124. //
  1125. // We should not attempt to reconnect the card in any case other than
  1126. // RESET, since we wouldn't be sure that it's the same card without
  1127. // further checks. Instead just close the card handle and let the caller
  1128. // find the correct card again.
  1129. //
  1130. SCardDisconnect(
  1131. pCardData->hScard,
  1132. SCARD_LEAVE_CARD);
  1133. pCardData->hScard = 0;
  1134. dwSts = (DWORD) SCARD_E_INVALID_HANDLE;
  1135. if (fMayReleaseContextHandle)
  1136. {
  1137. SCardReleaseContext(
  1138. pCardData->hSCardCtx);
  1139. pCardData->hSCardCtx = 0;
  1140. }
  1141. if (NULL != pfFlushPinCache)
  1142. *pfFlushPinCache = TRUE;
  1143. Ret:
  1144. LOG_END_FUNCTION(ValidateCardHandle, dwSts);
  1145. return dwSts;
  1146. }
  1147. //
  1148. // Function: FindCardBySerialNumber
  1149. //
  1150. // Purpose: Search for an existing card whose serial number is already
  1151. // known. This is necessary for a User Context associated with
  1152. // a card whose handle failed to reconnect.
  1153. //
  1154. DWORD FindCardBySerialNumber(
  1155. IN PUSER_CONTEXT pUserCtx)
  1156. {
  1157. DWORD dwSts = ERROR_SUCCESS;
  1158. CARD_MATCH_DATA CardMatchData;
  1159. PCSP_STATE pCspState = NULL;
  1160. PLOCAL_USER_CONTEXT pLocalUserCtx =
  1161. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1162. memset(&CardMatchData, 0, sizeof(CardMatchData));
  1163. dwSts = GetCspState(&pCspState);
  1164. if (ERROR_SUCCESS != dwSts)
  1165. goto Ret;
  1166. CardMatchData.pwszSerialNumber =
  1167. pLocalUserCtx->pCardState->wszSerialNumber;
  1168. CardMatchData.dwCtxFlags = pUserCtx->dwFlags;
  1169. CardMatchData.dwMatchType = CARD_MATCH_TYPE_SERIAL_NUMBER;
  1170. CardMatchData.cchMatchedCard = MAX_PATH;
  1171. CardMatchData.cchMatchedReader = MAX_PATH;
  1172. CardMatchData.cchMatchedSerialNumber = MAX_PATH;
  1173. CardMatchData.pCspState = pCspState;
  1174. CardMatchData.dwShareMode = SCARD_SHARE_SHARED;
  1175. CardMatchData.dwPreferredProtocols =
  1176. SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
  1177. // As a sanity check, disassociate this user context with its current
  1178. // Card State structure. If we find a match, it will be the same one,
  1179. // because we already know the serial number, but the user context
  1180. // shouldn't maintain this state until then.
  1181. pLocalUserCtx->pCardState = NULL;
  1182. // Try to find a matching card.
  1183. dwSts = FindCard(&CardMatchData);
  1184. if (ERROR_SUCCESS == dwSts)
  1185. pLocalUserCtx->pCardState = CardMatchData.pCardState;
  1186. Ret:
  1187. if (pCspState)
  1188. ReleaseCspState(&pCspState);
  1189. return dwSts;
  1190. }
  1191. //
  1192. // Function: BuildCertificateFilename
  1193. //
  1194. DWORD WINAPI
  1195. BuildCertificateFilename(
  1196. IN PUSER_CONTEXT pUserCtx,
  1197. IN DWORD dwKeySpec,
  1198. OUT LPWSTR *ppszFilename)
  1199. {
  1200. DWORD dwSts = ERROR_SUCCESS;
  1201. BYTE bContainerIndex = 0;
  1202. DWORD cchFilename = 0;
  1203. PLOCAL_USER_CONTEXT pLocal =
  1204. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1205. CONTAINER_MAP_RECORD ContainerRecord;
  1206. LPWSTR wszPrefix = NULL;
  1207. switch(dwKeySpec)
  1208. {
  1209. case AT_SIGNATURE:
  1210. wszPrefix = wszUSER_SIGNATURE_CERT_PREFIX;
  1211. break;
  1212. case AT_KEYEXCHANGE:
  1213. wszPrefix = wszUSER_KEYEXCHANGE_CERT_PREFIX;
  1214. break;
  1215. default:
  1216. dwSts = (DWORD) NTE_BAD_ALGID;
  1217. goto Ret;
  1218. }
  1219. memset(&ContainerRecord, 0, sizeof(ContainerRecord));
  1220. wcscpy(ContainerRecord.wszGuid, pUserCtx->wszBaseContainerName);
  1221. dwSts = ContainerMapFindContainer(
  1222. pLocal->pCardState,
  1223. &ContainerRecord,
  1224. &bContainerIndex);
  1225. cchFilename = wcslen(wszPrefix) + 2 + 1;
  1226. *ppszFilename = (LPWSTR) CspAllocH(sizeof(WCHAR) * cchFilename);
  1227. LOG_CHECK_ALLOC(*ppszFilename);
  1228. wsprintf(
  1229. *ppszFilename,
  1230. L"%s%02X",
  1231. wszPrefix,
  1232. bContainerIndex);
  1233. Ret:
  1234. if (ERROR_SUCCESS != dwSts && *ppszFilename)
  1235. {
  1236. CspFreeH(*ppszFilename);
  1237. *ppszFilename = NULL;
  1238. }
  1239. return dwSts;
  1240. }
  1241. //
  1242. // Function: CspBeginTransaction
  1243. //
  1244. DWORD CspBeginTransaction(
  1245. IN PCARD_STATE pCardState)
  1246. {
  1247. DWORD dwSts = ERROR_SUCCESS;
  1248. dwSts = CspEnterCriticalSection(&pCardState->cs);
  1249. if (ERROR_SUCCESS != dwSts)
  1250. goto Ret;
  1251. dwSts = SCardBeginTransaction(pCardState->pCardData->hScard);
  1252. Ret:
  1253. if (ERROR_SUCCESS != dwSts)
  1254. CspLeaveCriticalSection(&pCardState->cs);
  1255. return dwSts;
  1256. }
  1257. //
  1258. // Function: CspEndTransaction
  1259. //
  1260. DWORD CspEndTransaction(
  1261. IN PCARD_STATE pCardState)
  1262. {
  1263. DWORD dwSts = ERROR_SUCCESS;
  1264. DWORD dwAction =
  1265. pCardState->fAuthenticated ?
  1266. SCARD_RESET_CARD :
  1267. SCARD_LEAVE_CARD;
  1268. if (pCardState->fAuthenticated &&
  1269. pCardState->pCardData->pfnCardDeauthenticate)
  1270. {
  1271. // The card is currently in an authenticated state, and the card
  1272. // module has its own Deauthenticate function. Try to use the
  1273. // cardmod function instead using RESET_CARD in the
  1274. // SCardEndTransaction call. This can be a big perf improvement.
  1275. dwSts = pCardState->pCardData->pfnCardDeauthenticate(
  1276. pCardState->pCardData, wszCARD_USER_USER, 0);
  1277. // If the Deauthenticate succeeded, all that's left to do is release
  1278. // the transaction. If the Deauthenticate failed, we'll try one
  1279. // more time to RESET the card.
  1280. if (ERROR_SUCCESS == dwSts)
  1281. dwAction = SCARD_LEAVE_CARD;
  1282. }
  1283. dwSts = SCardEndTransaction(
  1284. pCardState->pCardData->hScard,
  1285. dwAction);
  1286. if (ERROR_SUCCESS != dwSts)
  1287. {
  1288. // Bad news if we got here. Better try to close the card handle
  1289. // to cleanup.
  1290. SCardDisconnect(pCardState->pCardData->hScard, SCARD_RESET_CARD);
  1291. pCardState->pCardData->hScard = 0;
  1292. SCardReleaseContext(pCardState->pCardData->hSCardCtx);
  1293. pCardState->pCardData->hSCardCtx = 0;
  1294. }
  1295. else
  1296. pCardState->fAuthenticated = FALSE;
  1297. // We've left the transaction, so the "cached" cache file info is no
  1298. // longer reliable.
  1299. pCardState->fCacheFileValid = FALSE;
  1300. CspLeaveCriticalSection(&pCardState->cs);
  1301. return dwSts;
  1302. }
  1303. //
  1304. // Function: BeginCardCapiCall
  1305. //
  1306. // Purpose: Setup the user context and associated card context for a new
  1307. // Crypto API call. This includes:
  1308. // 1) Reconnecting to the card, if necessary.
  1309. // 2) Begin transaction.
  1310. //
  1311. DWORD BeginCardCapiCall(
  1312. IN PUSER_CONTEXT pUserCtx)
  1313. {
  1314. DWORD dwSts = ERROR_SUCCESS;
  1315. PLOCAL_USER_CONTEXT pLocalUserCtx =
  1316. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1317. BOOL fFlushPinCache = FALSE;
  1318. LOG_BEGIN_FUNCTION(BeginCardCapiCall);
  1319. DsysAssert(FALSE == pLocalUserCtx->fHoldingTransaction);
  1320. dwSts = CspEnterCriticalSection(
  1321. &pLocalUserCtx->pCardState->cs);
  1322. if (ERROR_SUCCESS != dwSts)
  1323. return dwSts;
  1324. dwSts = ValidateCardHandle(
  1325. pLocalUserCtx->pCardState, TRUE, &fFlushPinCache);
  1326. if (ERROR_SUCCESS != dwSts || TRUE == fFlushPinCache)
  1327. // Flush the pin cache for this card. Not checking error code
  1328. // since we'll keep processing, anyway.
  1329. CspRemoveCachedPin(pLocalUserCtx->pCardState, wszCARD_USER_USER);
  1330. if (ERROR_SUCCESS != dwSts)
  1331. {
  1332. //
  1333. // Could not connect to the card.
  1334. //
  1335. CspLeaveCriticalSection(
  1336. &pLocalUserCtx->pCardState->cs);
  1337. // Attempt to find the card again,
  1338. // possibly in a different reader.
  1339. dwSts = FindCardBySerialNumber(pUserCtx);
  1340. if (ERROR_SUCCESS != dwSts)
  1341. goto Ret;
  1342. }
  1343. else
  1344. CspLeaveCriticalSection(
  1345. &pLocalUserCtx->pCardState->cs);
  1346. // If the reconnect failed, bail now.
  1347. if (ERROR_SUCCESS != dwSts)
  1348. goto Ret;
  1349. // Now Begin Transaction on the card.
  1350. dwSts = CspBeginTransaction(pLocalUserCtx->pCardState);
  1351. if (ERROR_SUCCESS == dwSts)
  1352. pLocalUserCtx->fHoldingTransaction = TRUE;
  1353. Ret:
  1354. LOG_END_FUNCTION(BeginCardCapiCall, dwSts);
  1355. return dwSts;
  1356. }
  1357. //
  1358. // Function: EndCardCapiCall
  1359. //
  1360. // Purpose: Cleanup the user context and associated card context following
  1361. // the completion of a Crypto API call. This includes ending
  1362. // the transaction on the card.
  1363. //
  1364. DWORD EndCardCapiCall(
  1365. IN PUSER_CONTEXT pUserCtx)
  1366. {
  1367. DWORD dwSts = ERROR_SUCCESS;
  1368. PLOCAL_USER_CONTEXT pLocal =
  1369. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1370. LOG_BEGIN_FUNCTION(EndCardCapiCall);
  1371. if (TRUE == pLocal->fHoldingTransaction)
  1372. {
  1373. dwSts = CspEndTransaction(pLocal->pCardState);
  1374. if (ERROR_SUCCESS != dwSts)
  1375. {
  1376. // Something got screwed up and we weren't able to EndTransaction
  1377. // correctly. Expect that the SCard handles got released as a
  1378. // result.
  1379. DsysAssert(0 == pLocal->pCardState->pCardData->hScard);
  1380. DsysAssert(0 == pLocal->pCardState->pCardData->hSCardCtx);
  1381. }
  1382. // Even if the EndTransaction failed, we expect that the card handles
  1383. // got closed, and we expect that the Card State critsec is no
  1384. // longer held.
  1385. pLocal->fHoldingTransaction = FALSE;
  1386. }
  1387. LOG_END_FUNCTION(EndCardCapiCall, dwSts);
  1388. return dwSts;
  1389. }
  1390. //
  1391. // Function: DeleteContainer
  1392. //
  1393. DWORD DeleteContainer(PUSER_CONTEXT pUserCtx)
  1394. {
  1395. PLOCAL_USER_CONTEXT pLocal =
  1396. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1397. DWORD dwSts = ERROR_SUCCESS;
  1398. LPWSTR wszFilename = NULL;
  1399. BYTE bContainerIndex = 0;
  1400. //
  1401. // Delete the certificate (if any) associated with the signature key
  1402. // (if any).
  1403. //
  1404. dwSts = BuildCertificateFilename(
  1405. pUserCtx, AT_SIGNATURE, &wszFilename);
  1406. if (ERROR_SUCCESS != dwSts)
  1407. goto Ret;
  1408. // Ignore error on this call - there may not be a cert associated
  1409. // with this container and we're just trying to cleanup as much as
  1410. // we can.
  1411. CspDeleteFile(
  1412. pLocal->pCardState,
  1413. 0,
  1414. wszFilename);
  1415. CspFreeH(wszFilename);
  1416. wszFilename = NULL;
  1417. //
  1418. // Delete the key exchange cert (if any)
  1419. //
  1420. dwSts = BuildCertificateFilename(
  1421. pUserCtx, AT_KEYEXCHANGE, &wszFilename);
  1422. if (ERROR_SUCCESS != dwSts)
  1423. goto Ret;
  1424. CspDeleteFile(
  1425. pLocal->pCardState,
  1426. 0,
  1427. wszFilename);
  1428. //
  1429. // Perform the delete operation on the card
  1430. //
  1431. dwSts = CspDeleteContainer(
  1432. pLocal->pCardState,
  1433. pLocal->bContainerIndex,
  1434. 0);
  1435. if (ERROR_SUCCESS != dwSts)
  1436. goto Ret;
  1437. //
  1438. // Remove this container from the container map
  1439. //
  1440. dwSts = ContainerMapDeleteContainer(
  1441. pLocal->pCardState,
  1442. pUserCtx->wszBaseContainerName,
  1443. &bContainerIndex);
  1444. DsysAssert(bContainerIndex == pLocal->bContainerIndex);
  1445. Ret:
  1446. if (wszFilename)
  1447. CspFreeH(wszFilename);
  1448. return dwSts;
  1449. }
  1450. //
  1451. // Determines if the current context was acquired using CRYPT_VERIFYCONTEXT
  1452. // semantics.
  1453. //
  1454. // A VerifyContext is allowed for some calls if and only if the
  1455. // context has been associated with a specific card. The fAllowWithCardAccess
  1456. // param should be set to TRUE in those cases.
  1457. //
  1458. DWORD CheckForVerifyContext(
  1459. IN PUSER_CONTEXT pUserContext,
  1460. IN BOOL fAllowOnlyWithCardAccess)
  1461. {
  1462. PLOCAL_USER_CONTEXT pLocal = (PLOCAL_USER_CONTEXT)
  1463. pUserContext->pvLocalUserContext;
  1464. if (CRYPT_VERIFYCONTEXT & pUserContext->dwFlags)
  1465. {
  1466. if (fAllowOnlyWithCardAccess)
  1467. {
  1468. if (NULL != pLocal && NULL != pLocal->pCardState)
  1469. return ERROR_SUCCESS;
  1470. }
  1471. return NTE_BAD_FLAGS;
  1472. }
  1473. return ERROR_SUCCESS;
  1474. }
  1475. //
  1476. // Function: LocalAcquireContext
  1477. //
  1478. DWORD LocalAcquireContext(
  1479. PUSER_CONTEXT pUserContext,
  1480. PLOCAL_CALL_INFO pLocalCallInfo)
  1481. {
  1482. PLOCAL_USER_CONTEXT pLocalUserContext = NULL;
  1483. DWORD dwSts;
  1484. CARD_MATCH_DATA CardMatchData;
  1485. LPWSTR pwsz = NULL;
  1486. PCSP_STATE pCspState = NULL;
  1487. DWORD cch = 0;
  1488. CONTAINER_MAP_RECORD ContainerRecord;
  1489. LOG_BEGIN_CRYPTOAPI(LocalAcquireContext);
  1490. memset(&CardMatchData, 0, sizeof(CardMatchData));
  1491. memset(&ContainerRecord, 0, sizeof(ContainerRecord));
  1492. SetLocalCallInfo(pLocalCallInfo, FALSE);
  1493. // Determine if any container/reader information
  1494. // has been specified.
  1495. if (pUserContext->wszContainerNameFromCaller)
  1496. {
  1497. pwsz = (LPWSTR) pUserContext->wszContainerNameFromCaller;
  1498. if (0 == wcsncmp(L"\\\\.\\", pwsz, 4))
  1499. {
  1500. // A reader has been specified
  1501. pwsz += wcslen(L"\\\\.\\");
  1502. // pwsz now points to the reader name
  1503. CardMatchData.pwszContainerName =
  1504. wcschr(pwsz, L'\\') + 1;
  1505. cch = (DWORD) (CardMatchData.pwszContainerName - pwsz - 1);
  1506. CardMatchData.pwszReaderName = (LPWSTR) CspAllocH(
  1507. sizeof(WCHAR) * (1 + cch));
  1508. LOG_CHECK_ALLOC(CardMatchData.pwszReaderName);
  1509. memcpy(
  1510. CardMatchData.pwszReaderName,
  1511. pwsz,
  1512. sizeof(WCHAR) * cch);
  1513. }
  1514. else
  1515. {
  1516. CardMatchData.pwszContainerName = pwsz;
  1517. }
  1518. // Check and cleanup the specified container name
  1519. if (CardMatchData.pwszContainerName)
  1520. {
  1521. // Additional backslashes are not allowed.
  1522. if (wcschr(
  1523. CardMatchData.pwszContainerName,
  1524. L'\\'))
  1525. {
  1526. dwSts = (DWORD) NTE_BAD_KEYSET;
  1527. goto Ret;
  1528. }
  1529. // There may have just been a trailing '\'
  1530. // with no following container name, or the
  1531. // specified name may have just been the NULL string.
  1532. if (L'\0' == CardMatchData.pwszContainerName[0])
  1533. {
  1534. CardMatchData.pwszContainerName = NULL;
  1535. }
  1536. }
  1537. // Verify that the final container name isn't too long
  1538. if (NULL != CardMatchData.pwszContainerName &&
  1539. MAX_CONTAINER_NAME_LEN < wcslen(CardMatchData.pwszContainerName))
  1540. {
  1541. dwSts = (DWORD) NTE_BAD_KEYSET;
  1542. goto Ret;
  1543. }
  1544. }
  1545. // Get pointer to global CSP data; includes
  1546. // list of cached card information.
  1547. dwSts = GetCspState(&pCspState);
  1548. if (ERROR_SUCCESS != dwSts)
  1549. goto Ret;
  1550. // Setup the caller's cryptographic context.
  1551. pLocalUserContext = (PLOCAL_USER_CONTEXT) CspAllocH(sizeof(LOCAL_USER_CONTEXT));
  1552. LOG_CHECK_ALLOC(pLocalUserContext);
  1553. pLocalUserContext->dwVersion = LOCAL_USER_CONTEXT_CURRENT_VERSION;
  1554. // Prepare info for matching an available
  1555. // smart card to the caller's request.
  1556. CardMatchData.dwCtxFlags = pUserContext->dwFlags;
  1557. CardMatchData.dwMatchType = CARD_MATCH_TYPE_READER_AND_CONTAINER;
  1558. CardMatchData.cchMatchedCard = MAX_PATH;
  1559. CardMatchData.cchMatchedReader = MAX_PATH;
  1560. CardMatchData.cchMatchedSerialNumber = MAX_PATH;
  1561. CardMatchData.pCspState = pCspState;
  1562. CardMatchData.dwShareMode = SCARD_SHARE_SHARED;
  1563. CardMatchData.dwPreferredProtocols =
  1564. SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
  1565. // Try to find a matching card.
  1566. dwSts = FindCard(&CardMatchData);
  1567. //
  1568. // Check for a VERIFYCONTEXT request in which no container specification
  1569. // has been made. A failed card match is fine in that case since
  1570. // this context will only be used to query generic CSP information.
  1571. //
  1572. if (ERROR_SUCCESS != dwSts &&
  1573. (CRYPT_VERIFYCONTEXT & pUserContext->dwFlags) &&
  1574. NULL == pUserContext->wszContainerNameFromCaller)
  1575. {
  1576. pUserContext->pvLocalUserContext = (PVOID) pLocalUserContext;
  1577. pLocalUserContext = NULL;
  1578. dwSts = ERROR_SUCCESS;
  1579. goto Ret;
  1580. }
  1581. // Any other non-success case is fatal
  1582. if (ERROR_SUCCESS != dwSts)
  1583. goto Ret;
  1584. pLocalUserContext->pCardState = CardMatchData.pCardState;
  1585. pLocalUserContext->bContainerIndex = CardMatchData.bContainerIndex;
  1586. // Read configuration information out of the registry.
  1587. dwSts = RegConfigGetSettings(
  1588. &pLocalUserContext->RegSettings);
  1589. if (ERROR_SUCCESS != dwSts)
  1590. goto Ret;
  1591. //
  1592. // If the caller requested a new container but didn't give a container
  1593. // name, create a Guid name now.
  1594. //
  1595. if (NULL == CardMatchData.pwszContainerName &&
  1596. (CRYPT_NEWKEYSET & pUserContext->dwFlags))
  1597. {
  1598. dwSts = CreateUuidContainerName(pUserContext);
  1599. if (ERROR_SUCCESS != dwSts)
  1600. goto Ret;
  1601. }
  1602. else if (NULL != CardMatchData.pwszContainerName)
  1603. {
  1604. // Caller did give a container name, or the default container is
  1605. // being used and we queried the name from the card during
  1606. // our search. Copy it into the user context.
  1607. pUserContext->wszBaseContainerName = (LPWSTR) CspAllocH(
  1608. sizeof(WCHAR) * (1 + wcslen(CardMatchData.pwszContainerName)));
  1609. LOG_CHECK_ALLOC(pUserContext->wszBaseContainerName);
  1610. wcscpy(
  1611. pUserContext->wszBaseContainerName,
  1612. CardMatchData.pwszContainerName);
  1613. }
  1614. //
  1615. // Associate context information for this CSP
  1616. //
  1617. pUserContext->pvLocalUserContext = (PVOID) pLocalUserContext;
  1618. if (NULL != pUserContext->wszBaseContainerName)
  1619. {
  1620. //
  1621. // Make a copy of the base container name to use as the "unique" container
  1622. // name, since for this CSP they're the same.
  1623. //
  1624. // The only reason we should skip this step is for VERIFY_CONTEXT.
  1625. //
  1626. pUserContext->wszUniqueContainerName = (LPWSTR) CspAllocH(
  1627. sizeof(WCHAR) * (1 + wcslen(pUserContext->wszBaseContainerName)));
  1628. LOG_CHECK_ALLOC(pUserContext->wszUniqueContainerName);
  1629. wcscpy(
  1630. pUserContext->wszUniqueContainerName,
  1631. pUserContext->wszBaseContainerName);
  1632. if (CRYPT_NEWKEYSET & pUserContext->dwFlags)
  1633. {
  1634. //
  1635. // Add-container requires us to
  1636. // authenticate to the card, since we'll need to write the updated
  1637. // container map.
  1638. //
  1639. dwSts = BeginCardCapiCall(pUserContext);
  1640. if (ERROR_SUCCESS != dwSts)
  1641. goto Ret;
  1642. dwSts = CspAuthenticateUser(pUserContext);
  1643. if (ERROR_SUCCESS != dwSts)
  1644. goto Ret;
  1645. dwSts = ContainerMapAddContainer(
  1646. pLocalUserContext->pCardState,
  1647. pUserContext->wszBaseContainerName,
  1648. 0,
  1649. 0,
  1650. FALSE,
  1651. &pLocalUserContext->bContainerIndex);
  1652. //
  1653. // Determine if there is already a "default" container on this
  1654. // card. If not, mark the new one as default.
  1655. //
  1656. dwSts = ContainerMapGetDefaultContainer(
  1657. pLocalUserContext->pCardState,
  1658. &ContainerRecord,
  1659. NULL);
  1660. if (NTE_BAD_KEYSET == dwSts)
  1661. {
  1662. dwSts = ContainerMapSetDefaultContainer(
  1663. pLocalUserContext->pCardState,
  1664. pUserContext->wszBaseContainerName);
  1665. }
  1666. if (ERROR_SUCCESS != dwSts)
  1667. goto Ret;
  1668. }
  1669. }
  1670. else
  1671. {
  1672. DsysAssert(CRYPT_VERIFYCONTEXT & pUserContext->dwFlags);
  1673. }
  1674. //
  1675. // If caller has requested a Delete Keyset, then do that work now
  1676. // and cleanup the local user context at the end.
  1677. //
  1678. if (CRYPT_DELETEKEYSET & pUserContext->dwFlags)
  1679. {
  1680. dwSts = BeginCardCapiCall(pUserContext);
  1681. if (ERROR_SUCCESS != dwSts)
  1682. goto Ret;
  1683. dwSts = CspAuthenticateUser(pUserContext);
  1684. if (ERROR_SUCCESS != dwSts)
  1685. goto Ret;
  1686. dwSts = DeleteContainer(pUserContext);
  1687. if (ERROR_SUCCESS != dwSts)
  1688. goto Ret;
  1689. }
  1690. else
  1691. {
  1692. pLocalUserContext = NULL;
  1693. }
  1694. Ret:
  1695. if (pUserContext->pvLocalUserContext)
  1696. EndCardCapiCall(pUserContext);
  1697. if (pCspState)
  1698. ReleaseCspState(&pCspState);
  1699. if (pLocalUserContext)
  1700. {
  1701. pUserContext->pvLocalUserContext = NULL;
  1702. DeleteLocalUserContext(pLocalUserContext);
  1703. CspFreeH(pLocalUserContext);
  1704. }
  1705. if (CardMatchData.pwszReaderName)
  1706. CspFreeH(CardMatchData.pwszReaderName);
  1707. if (CardMatchData.fFreeContainerName &&
  1708. CardMatchData.pwszContainerName)
  1709. CspFreeH(CardMatchData.pwszContainerName);
  1710. LOG_END_CRYPTOAPI(LocalAcquireContext, dwSts);
  1711. return dwSts;
  1712. }
  1713. //
  1714. // Function: LocalReleaseContext
  1715. //
  1716. DWORD WINAPI
  1717. LocalReleaseContext(
  1718. IN PUSER_CONTEXT pUserCtx,
  1719. IN DWORD dwFlags,
  1720. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  1721. {
  1722. PLOCAL_USER_CONTEXT pLocal =
  1723. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1724. DWORD dwSts = ERROR_SUCCESS;
  1725. UNREFERENCED_PARAMETER(dwFlags);
  1726. LOG_BEGIN_CRYPTOAPI(LocalReleaseContext);
  1727. if (pLocal)
  1728. {
  1729. DeleteLocalUserContext(pLocal);
  1730. CspFreeH(pLocal);
  1731. pUserCtx->pvLocalUserContext = NULL;
  1732. }
  1733. LOG_END_CRYPTOAPI(LocalReleaseContext, dwSts);
  1734. return dwSts;
  1735. }
  1736. //
  1737. // Function: LocalGenKey
  1738. //
  1739. DWORD WINAPI
  1740. LocalGenKey(
  1741. IN PKEY_CONTEXT pKeyCtx,
  1742. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  1743. {
  1744. PUSER_CONTEXT pUserCtx = pKeyCtx->pUserContext;
  1745. PLOCAL_USER_CONTEXT pLocalUserCtx =
  1746. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  1747. DWORD dwSts = ERROR_SUCCESS;
  1748. CARD_CAPABILITIES CardCapabilities;
  1749. HCRYPTKEY hKey = 0;
  1750. PBYTE pbKey = NULL;
  1751. DWORD cbKey = 0;
  1752. PLOCAL_KEY_CONTEXT pLocalKeyCtx = NULL;
  1753. BYTE bContainerIndex = 0;
  1754. LOG_BEGIN_CRYPTOAPI(LocalGenKey);
  1755. memset(&CardCapabilities, 0, sizeof(CardCapabilities));
  1756. if (CALG_RSA_KEYX == pKeyCtx->Algid)
  1757. pKeyCtx->Algid = AT_KEYEXCHANGE;
  1758. else if (CALG_RSA_SIGN == pKeyCtx->Algid)
  1759. pKeyCtx->Algid = AT_SIGNATURE;
  1760. if (AT_SIGNATURE == pKeyCtx->Algid ||
  1761. AT_KEYEXCHANGE == pKeyCtx->Algid)
  1762. {
  1763. // Public key call. Handle this here since we have to talk to the
  1764. // card. All other key algs will be handled in the support CSP.
  1765. SetLocalCallInfo(pLocalCallInfo, FALSE);
  1766. dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
  1767. if (ERROR_SUCCESS != dwSts)
  1768. goto Ret;
  1769. if (CRYPT_EXPORTABLE & pKeyCtx->dwFlags)
  1770. {
  1771. dwSts = NTE_BAD_FLAGS;
  1772. goto Ret;
  1773. }
  1774. dwSts = BeginCardCapiCall(pUserCtx);
  1775. if (ERROR_SUCCESS != dwSts)
  1776. goto Ret;
  1777. dwSts = CspQueryCapabilities(
  1778. pLocalUserCtx->pCardState,
  1779. &CardCapabilities);
  1780. if (ERROR_SUCCESS != dwSts)
  1781. goto Ret;
  1782. if (0 == pKeyCtx->cKeyBits)
  1783. pKeyCtx->cKeyBits = pLocalUserCtx->RegSettings.cDefaultPrivateKeyLenBits;
  1784. //
  1785. // If ARCHIVABLE is set, we don't gen the key on the card, since we
  1786. // don't want to force cards to support exportable private keys.
  1787. //
  1788. if ( CardCapabilities.fKeyGen &&
  1789. 0 == (CRYPT_ARCHIVABLE & pKeyCtx->dwFlags))
  1790. {
  1791. dwSts = CspAuthenticateUser(pUserCtx);
  1792. if (ERROR_SUCCESS != dwSts)
  1793. goto Ret;
  1794. dwSts = CspCreateContainer(
  1795. pLocalUserCtx->pCardState,
  1796. pLocalUserCtx->bContainerIndex,
  1797. CARD_CREATE_CONTAINER_KEY_GEN,
  1798. pKeyCtx->Algid,
  1799. pKeyCtx->cKeyBits,
  1800. NULL);
  1801. if (ERROR_SUCCESS != dwSts)
  1802. goto Ret;
  1803. }
  1804. else
  1805. {
  1806. // This card does not support on-card key generation. See
  1807. // if we're allowed to create our own key blob and import
  1808. // it.
  1809. if (pLocalUserCtx->RegSettings.fRequireOnCardPrivateKeyGen)
  1810. {
  1811. dwSts = (DWORD) SCARD_E_UNSUPPORTED_FEATURE;
  1812. goto Ret;
  1813. }
  1814. //
  1815. // Create a new, exportable private key in the software CSP. Then
  1816. // export it and import it onto the card.
  1817. //
  1818. if (! CryptGenKey(
  1819. pUserCtx->hSupportProv,
  1820. pKeyCtx->Algid,
  1821. CRYPT_EXPORTABLE | (pKeyCtx->cKeyBits << 16),
  1822. &hKey))
  1823. {
  1824. dwSts = GetLastError();
  1825. goto Ret;
  1826. }
  1827. if (! CryptExportKey(
  1828. hKey,
  1829. 0,
  1830. PRIVATEKEYBLOB,
  1831. 0,
  1832. NULL,
  1833. &cbKey))
  1834. {
  1835. dwSts = GetLastError();
  1836. goto Ret;
  1837. }
  1838. pbKey = (PBYTE) CspAllocH(cbKey);
  1839. LOG_CHECK_ALLOC(pbKey);
  1840. if (! CryptExportKey(
  1841. hKey,
  1842. 0,
  1843. PRIVATEKEYBLOB,
  1844. 0,
  1845. pbKey,
  1846. &cbKey))
  1847. {
  1848. dwSts = GetLastError();
  1849. goto Ret;
  1850. }
  1851. dwSts = CspAuthenticateUser(pUserCtx);
  1852. if (ERROR_SUCCESS != dwSts)
  1853. goto Ret;
  1854. dwSts = CspCreateContainer(
  1855. pLocalUserCtx->pCardState,
  1856. pLocalUserCtx->bContainerIndex,
  1857. CARD_CREATE_CONTAINER_KEY_IMPORT,
  1858. pKeyCtx->Algid,
  1859. cbKey,
  1860. pbKey);
  1861. if (ERROR_SUCCESS != dwSts)
  1862. goto Ret;
  1863. //
  1864. // Check for CRYPT_ARCHIVABLE. If it's set, we'll keep a copy of
  1865. // the private key for the lifetime of this key context for the
  1866. // caller to export it.
  1867. //
  1868. if (CRYPT_ARCHIVABLE & pKeyCtx->dwFlags)
  1869. {
  1870. pLocalKeyCtx = (PLOCAL_KEY_CONTEXT) CspAllocH(
  1871. sizeof(LOCAL_KEY_CONTEXT));
  1872. LOG_CHECK_ALLOC(pLocalKeyCtx);
  1873. pLocalKeyCtx->pbArchivablePrivateKey = pbKey;
  1874. pLocalKeyCtx->cbArchivablePrivateKey = cbKey;
  1875. pbKey = NULL;
  1876. pKeyCtx->pvLocalKeyContext = (PVOID) pLocalKeyCtx;
  1877. }
  1878. }
  1879. //
  1880. // Add the new key information for this container to the map file
  1881. //
  1882. dwSts = ContainerMapAddContainer(
  1883. pLocalUserCtx->pCardState,
  1884. pUserCtx->wszBaseContainerName,
  1885. pKeyCtx->cKeyBits,
  1886. pKeyCtx->Algid,
  1887. FALSE,
  1888. &bContainerIndex);
  1889. DsysAssert(bContainerIndex == pLocalUserCtx->bContainerIndex);
  1890. }
  1891. else
  1892. {
  1893. // Not a public key call, so handle in the support CSP.
  1894. SetLocalCallInfo(pLocalCallInfo, TRUE);
  1895. }
  1896. Ret:
  1897. EndCardCapiCall(pUserCtx);
  1898. if (pbKey)
  1899. {
  1900. RtlSecureZeroMemory(pbKey, cbKey);
  1901. CspFreeH(pbKey);
  1902. }
  1903. if (hKey)
  1904. CryptDestroyKey(hKey);
  1905. LOG_END_CRYPTOAPI(LocalGenKey, dwSts);
  1906. return dwSts;
  1907. }
  1908. //
  1909. // Function: LocalDestroyKey
  1910. //
  1911. DWORD WINAPI
  1912. LocalDestroyKey(
  1913. IN OUT PKEY_CONTEXT pKeyContext,
  1914. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  1915. {
  1916. PLOCAL_KEY_CONTEXT pLocalKeyCtx =
  1917. (PLOCAL_KEY_CONTEXT) pKeyContext->pvLocalKeyContext;
  1918. LOG_BEGIN_CRYPTOAPI(LocalDestroyKey);
  1919. if (NULL != pLocalKeyCtx)
  1920. {
  1921. if (NULL != pLocalKeyCtx->pbArchivablePrivateKey)
  1922. {
  1923. RtlSecureZeroMemory(
  1924. pLocalKeyCtx->pbArchivablePrivateKey,
  1925. pLocalKeyCtx->cbArchivablePrivateKey);
  1926. CspFreeH(pLocalKeyCtx->pbArchivablePrivateKey);
  1927. pLocalKeyCtx->pbArchivablePrivateKey = NULL;
  1928. }
  1929. CspFreeH(pLocalKeyCtx);
  1930. pKeyContext->pvLocalKeyContext = NULL;
  1931. }
  1932. LOG_END_CRYPTOAPI(LocalDestroyKey, ERROR_SUCCESS);
  1933. return ERROR_SUCCESS;
  1934. }
  1935. //
  1936. // Determines if an encoded certificate blob contains certain Enhanced Key
  1937. // Usage OIDs. The target OIDs are SmartCard Logon and Enrollment Agent.
  1938. // If either OID is present, the key container associated with this
  1939. // certificate should be considered the new default container on the target
  1940. // card.
  1941. //
  1942. DWORD CheckCertUsageForDefaultContainer(
  1943. PBYTE pbEncodedCert,
  1944. DWORD cbEncodedCert,
  1945. BOOL *pfMakeDefault)
  1946. {
  1947. DWORD dwSts = 0;
  1948. PCCERT_CONTEXT pCertCtx = NULL;
  1949. PCERT_ENHKEY_USAGE pUsage = NULL;
  1950. DWORD cbUsage = 0;
  1951. *pfMakeDefault = FALSE;
  1952. //
  1953. // Build a cert context from the encoded blob
  1954. //
  1955. pCertCtx = CertCreateCertificateContext(
  1956. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1957. pbEncodedCert,
  1958. cbEncodedCert);
  1959. if (NULL == pCertCtx)
  1960. {
  1961. dwSts = GetLastError();
  1962. goto Ret;
  1963. }
  1964. //
  1965. // Get an array of the EKU OIDs present in this cert
  1966. //
  1967. if (! CertGetEnhancedKeyUsage(
  1968. pCertCtx,
  1969. 0,
  1970. NULL,
  1971. &cbUsage))
  1972. {
  1973. dwSts = GetLastError();
  1974. goto Ret;
  1975. }
  1976. pUsage = (PCERT_ENHKEY_USAGE) CspAllocH(cbUsage);
  1977. if (NULL == pUsage)
  1978. {
  1979. dwSts = ERROR_NOT_ENOUGH_MEMORY;
  1980. goto Ret;
  1981. }
  1982. if (! CertGetEnhancedKeyUsage(
  1983. pCertCtx,
  1984. 0,
  1985. pUsage,
  1986. &cbUsage))
  1987. {
  1988. dwSts = GetLastError();
  1989. goto Ret;
  1990. }
  1991. //
  1992. // Look for the two specific OIDs that would make this the new default
  1993. // cert/container
  1994. //
  1995. while (pUsage->cUsageIdentifier)
  1996. {
  1997. pUsage->cUsageIdentifier -= 1;
  1998. if (0 == strcmp(
  1999. szOID_KP_SMARTCARD_LOGON,
  2000. pUsage->rgpszUsageIdentifier[pUsage->cUsageIdentifier]) ||
  2001. 0 == strcmp(
  2002. szOID_ENROLLMENT_AGENT,
  2003. pUsage->rgpszUsageIdentifier[pUsage->cUsageIdentifier]))
  2004. {
  2005. *pfMakeDefault = TRUE;
  2006. }
  2007. }
  2008. Ret:
  2009. if (pUsage)
  2010. CspFreeH(pUsage);
  2011. if (pCertCtx)
  2012. CertFreeCertificateContext(pCertCtx);
  2013. return dwSts;
  2014. }
  2015. //
  2016. // Function: LocalSetKeyParam
  2017. //
  2018. DWORD WINAPI
  2019. LocalSetKeyParam(
  2020. IN PKEY_CONTEXT pKeyCtx,
  2021. IN DWORD dwParam,
  2022. IN CONST BYTE *pbData,
  2023. IN DWORD dwFlags,
  2024. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2025. {
  2026. DWORD dwSts = ERROR_SUCCESS;
  2027. PLOCAL_USER_CONTEXT pLocalUserCtx =
  2028. (PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
  2029. DWORD cbCert = 0;
  2030. DWORD cbCompressed = 0;
  2031. PBYTE pbCompressed = NULL;
  2032. LPWSTR wszCertFilename = NULL;
  2033. CARD_FILE_ACCESS_CONDITION Acl = EveryoneReadUserWriteAc;
  2034. DATA_BLOB CertData;
  2035. CARD_CAPABILITIES CardCapabilities;
  2036. BOOL fMakeDefault = FALSE;
  2037. UNREFERENCED_PARAMETER(dwFlags);
  2038. LOG_BEGIN_CRYPTOAPI(LocalSetKeyParam);
  2039. memset(&CertData, 0, sizeof(CertData));
  2040. memset(&CardCapabilities, 0, sizeof(CardCapabilities));
  2041. switch (dwParam)
  2042. {
  2043. case KP_CERTIFICATE:
  2044. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2045. dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
  2046. if (ERROR_SUCCESS != dwSts)
  2047. goto Ret;
  2048. //
  2049. // Determine how long the encoded cert blob is.
  2050. //
  2051. __try
  2052. {
  2053. cbCert = Asn1UtilAdjustEncodedLength(
  2054. pbData, (DWORD) cbENCODED_CERT_OVERFLOW);
  2055. if (0 == cbCert || cbENCODED_CERT_OVERFLOW == cbCert)
  2056. {
  2057. dwSts = (DWORD) NTE_BAD_DATA;
  2058. goto Ret;
  2059. }
  2060. }
  2061. __except(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode() ?
  2062. EXCEPTION_EXECUTE_HANDLER :
  2063. EXCEPTION_CONTINUE_SEARCH)
  2064. {
  2065. dwSts = (DWORD) NTE_BAD_DATA;
  2066. goto Ret;
  2067. }
  2068. // Begin a transaction and reconnect the card if necessary
  2069. dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
  2070. if (ERROR_SUCCESS != dwSts)
  2071. goto Ret;
  2072. //
  2073. // Build the filename we'll use for this cert
  2074. //
  2075. dwSts = BuildCertificateFilename(
  2076. pKeyCtx->pUserContext, pKeyCtx->Algid, &wszCertFilename);
  2077. if (ERROR_SUCCESS != dwSts)
  2078. goto Ret;
  2079. //
  2080. // Determine if this certificate contains OIDs that should make the
  2081. // associated key container the new default.
  2082. //
  2083. dwSts = CheckCertUsageForDefaultContainer(
  2084. (PBYTE) pbData,
  2085. cbCert,
  2086. &fMakeDefault);
  2087. if (ERROR_SUCCESS != dwSts)
  2088. goto Ret;
  2089. //
  2090. // Determine the capabilities of the target card - we want to know
  2091. // whether it (or its card module) implements its own data
  2092. // compression.
  2093. //
  2094. dwSts = CspQueryCapabilities(
  2095. pLocalUserCtx->pCardState,
  2096. &CardCapabilities);
  2097. if (ERROR_SUCCESS != dwSts)
  2098. goto Ret;
  2099. if (FALSE == CardCapabilities.fCertificateCompression)
  2100. {
  2101. //
  2102. // If this card doesn't implement its own certificate compression
  2103. // then we will compress the cert.
  2104. //
  2105. // Find out how big the compressed cert will be
  2106. //
  2107. dwSts = CompressData(cbCert, NULL, &cbCompressed, NULL);
  2108. if (ERROR_SUCCESS != dwSts)
  2109. goto Ret;
  2110. pbCompressed = CspAllocH(cbCompressed);
  2111. LOG_CHECK_ALLOC(pbCompressed);
  2112. // Compress the cert
  2113. dwSts = CompressData(
  2114. cbCert,
  2115. (PBYTE) pbData,
  2116. &cbCompressed,
  2117. pbCompressed);
  2118. if (ERROR_SUCCESS != dwSts)
  2119. goto Ret;
  2120. CertData.cbData = cbCompressed;
  2121. CertData.pbData = pbCompressed;
  2122. }
  2123. else
  2124. {
  2125. CertData.cbData = cbCert;
  2126. CertData.pbData = (PBYTE) pbData;
  2127. }
  2128. //
  2129. // Authenticate to the card as User
  2130. //
  2131. dwSts = CspAuthenticateUser(pKeyCtx->pUserContext);
  2132. if (ERROR_SUCCESS != dwSts)
  2133. goto Ret;
  2134. //
  2135. // Write the cert to the card.
  2136. //
  2137. dwSts = CspCreateFile(
  2138. pLocalUserCtx->pCardState,
  2139. wszCertFilename,
  2140. Acl);
  2141. if (ERROR_SUCCESS != dwSts)
  2142. goto Ret;
  2143. dwSts = CspWriteFile(
  2144. pLocalUserCtx->pCardState,
  2145. wszCertFilename,
  2146. 0,
  2147. CertData.pbData,
  2148. CertData.cbData);
  2149. if (ERROR_SUCCESS != dwSts)
  2150. goto Ret;
  2151. if (fMakeDefault)
  2152. {
  2153. dwSts = ContainerMapSetDefaultContainer(
  2154. pLocalUserCtx->pCardState,
  2155. pKeyCtx->pUserContext->wszBaseContainerName);
  2156. }
  2157. break;
  2158. default:
  2159. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2160. break;
  2161. }
  2162. Ret:
  2163. EndCardCapiCall(pKeyCtx->pUserContext);
  2164. if (pbCompressed)
  2165. CspFreeH(pbCompressed);
  2166. if (wszCertFilename)
  2167. CspFreeH(wszCertFilename);
  2168. LOG_END_CRYPTOAPI(LocalSetKeyParam, dwSts);
  2169. return dwSts;
  2170. }
  2171. //
  2172. // Function: LocalGetKeyParam
  2173. //
  2174. DWORD WINAPI
  2175. LocalGetKeyParam(
  2176. IN PKEY_CONTEXT pKeyCtx,
  2177. IN DWORD dwParam,
  2178. OUT LPBYTE pbData,
  2179. IN OUT LPDWORD pcbDataLen,
  2180. IN DWORD dwFlags,
  2181. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2182. {
  2183. DWORD dwSts = ERROR_SUCCESS;
  2184. PLOCAL_USER_CONTEXT pLocalUserCtx =
  2185. (PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
  2186. LPWSTR wszCertFilename = NULL;
  2187. DATA_BLOB CertData;
  2188. DWORD cbUncompressed = 0;
  2189. CARD_CAPABILITIES CardCapabilities;
  2190. LOG_BEGIN_CRYPTOAPI(LocalGetKeyParam);
  2191. memset(&CertData, 0, sizeof(CertData));
  2192. memset(&CardCapabilities, 0, sizeof(CardCapabilities));
  2193. switch (dwParam)
  2194. {
  2195. case KP_CERTIFICATE:
  2196. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2197. dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, TRUE);
  2198. if (ERROR_SUCCESS != dwSts)
  2199. goto Ret;
  2200. // Note, reading the certificate files should not require
  2201. // authentication to the card, but we will Enter Transaction
  2202. // to be safe.
  2203. dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
  2204. if (ERROR_SUCCESS != dwSts)
  2205. goto Ret;
  2206. //
  2207. // Get the name of the certificate file to read from the card.
  2208. //
  2209. dwSts = BuildCertificateFilename(
  2210. pKeyCtx->pUserContext, pKeyCtx->Algid, &wszCertFilename);
  2211. if (ERROR_SUCCESS != dwSts)
  2212. goto Ret;
  2213. //
  2214. // Read the file from the card.
  2215. //
  2216. dwSts = CspReadFile(
  2217. pLocalUserCtx->pCardState,
  2218. wszCertFilename,
  2219. 0,
  2220. &CertData.pbData,
  2221. &CertData.cbData);
  2222. if (ERROR_SUCCESS != dwSts)
  2223. {
  2224. if (SCARD_E_FILE_NOT_FOUND == dwSts)
  2225. dwSts = SCARD_E_NO_SUCH_CERTIFICATE;
  2226. goto Ret;
  2227. }
  2228. dwSts = CspQueryCapabilities(
  2229. pLocalUserCtx->pCardState,
  2230. &CardCapabilities);
  2231. if (ERROR_SUCCESS != dwSts)
  2232. goto Ret;
  2233. if (FALSE == CardCapabilities.fCertificateCompression)
  2234. {
  2235. //
  2236. // If this card doesn't implement its own certificate compression,
  2237. // then we expect the cert was compressed by the CSP.
  2238. //
  2239. // Find out how big the uncompressed cert will be
  2240. //
  2241. dwSts = UncompressData(
  2242. CertData.cbData,
  2243. CertData.pbData,
  2244. &cbUncompressed,
  2245. NULL);
  2246. if (ERROR_SUCCESS != dwSts)
  2247. goto Ret;
  2248. //
  2249. // Check the length of the caller's buffer, or if the caller is just
  2250. // querying for size.
  2251. //
  2252. if (*pcbDataLen < cbUncompressed || NULL == pbData)
  2253. {
  2254. *pcbDataLen = cbUncompressed;
  2255. if (NULL != pbData)
  2256. dwSts = ERROR_MORE_DATA;
  2257. goto Ret;
  2258. }
  2259. *pcbDataLen = cbUncompressed;
  2260. // Uncompress the cert into the caller's buffer
  2261. dwSts = UncompressData(
  2262. CertData.cbData,
  2263. CertData.pbData,
  2264. &cbUncompressed,
  2265. pbData);
  2266. if (ERROR_SUCCESS != dwSts)
  2267. {
  2268. if (ERROR_INTERNAL_ERROR == dwSts)
  2269. dwSts = NTE_BAD_DATA;
  2270. goto Ret;
  2271. }
  2272. }
  2273. else
  2274. {
  2275. //
  2276. // This card does implement its own compression, so assume that
  2277. // we have received the cert uncompressed.
  2278. //
  2279. if (*pcbDataLen < CertData.cbData || NULL == pbData)
  2280. {
  2281. *pcbDataLen = CertData.cbData;
  2282. if (NULL != pbData)
  2283. dwSts = ERROR_MORE_DATA;
  2284. goto Ret;
  2285. }
  2286. *pcbDataLen = CertData.cbData;
  2287. memcpy(pbData, CertData.pbData, CertData.cbData);
  2288. }
  2289. break;
  2290. default:
  2291. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2292. break;
  2293. }
  2294. Ret:
  2295. EndCardCapiCall(pKeyCtx->pUserContext);
  2296. if (CertData.pbData)
  2297. CspFreeH(CertData.pbData);
  2298. if (wszCertFilename)
  2299. CspFreeH(wszCertFilename);
  2300. LOG_END_CRYPTOAPI(LocalGetKeyParam, dwSts);
  2301. return dwSts;
  2302. }
  2303. //
  2304. // Function: LocalSetProvParam
  2305. //
  2306. DWORD WINAPI
  2307. LocalSetProvParam(
  2308. IN PUSER_CONTEXT pUserCtx,
  2309. IN DWORD dwParam,
  2310. IN CONST BYTE *pbData,
  2311. IN DWORD dwFlags,
  2312. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2313. {
  2314. DWORD dwSts = ERROR_SUCCESS;
  2315. PLOCAL_USER_CONTEXT pLocalUserCtx =
  2316. (PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
  2317. PINCACHE_PINS Pins;
  2318. PFN_VERIFYPIN_CALLBACK pfnVerify = VerifyPinCallback;
  2319. VERIFY_PIN_CALLBACK_DATA CallbackCtx;
  2320. DWORD iChar = 0;
  2321. LPSTR szPin = NULL;
  2322. LOG_BEGIN_CRYPTOAPI(LocalSetProvParam);
  2323. memset(&Pins, 0, sizeof(Pins));
  2324. memset(&CallbackCtx, 0, sizeof(CallbackCtx));
  2325. switch (dwParam)
  2326. {
  2327. case PP_KEYEXCHANGE_PIN:
  2328. case PP_SIGNATURE_PIN:
  2329. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2330. dwSts = CheckForVerifyContext(pUserCtx, FALSE);
  2331. if (ERROR_SUCCESS != dwSts)
  2332. goto Ret;
  2333. dwSts = PinStringToBytesA(
  2334. (LPSTR) pbData,
  2335. &Pins.cbCurrentPin,
  2336. &Pins.pbCurrentPin);
  2337. if (ERROR_SUCCESS != dwSts)
  2338. goto Ret;
  2339. dwSts = BeginCardCapiCall(pUserCtx);
  2340. if (ERROR_SUCCESS != dwSts)
  2341. goto Ret;
  2342. // Remove any existing cached pin, just in case
  2343. CspRemoveCachedPin(
  2344. pLocalUserCtx->pCardState, wszCARD_USER_USER);
  2345. CallbackCtx.pUserCtx = pUserCtx;
  2346. CallbackCtx.wszUserId = wszCARD_USER_USER;
  2347. dwSts = PinCacheAdd(
  2348. &pLocalUserCtx->pCardState->hPinCache,
  2349. &Pins,
  2350. pfnVerify,
  2351. (PVOID) &CallbackCtx);
  2352. // We're now authenticated to the card if the pin was correct. Make
  2353. // sure we deauthenticate below.
  2354. if (ERROR_SUCCESS == dwSts)
  2355. pLocalUserCtx->pCardState->fAuthenticated = TRUE;
  2356. break;
  2357. default:
  2358. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2359. break;
  2360. }
  2361. Ret:
  2362. EndCardCapiCall(pUserCtx);
  2363. if (Pins.pbCurrentPin)
  2364. CspFreeH(Pins.pbCurrentPin);
  2365. LOG_END_CRYPTOAPI(LocalSetProvParam, dwSts);
  2366. return dwSts;
  2367. }
  2368. //
  2369. // Function: LocalGetProvParam
  2370. //
  2371. DWORD WINAPI
  2372. LocalGetProvParam(
  2373. IN PUSER_CONTEXT pUserContext,
  2374. IN DWORD dwParam,
  2375. OUT PBYTE pbData,
  2376. IN OUT PDWORD pcbDataLen,
  2377. IN DWORD dwFlags,
  2378. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2379. {
  2380. DWORD dwSts = ERROR_SUCCESS;
  2381. PLOCAL_USER_CONTEXT pLocalUserCtx =
  2382. (PLOCAL_USER_CONTEXT) pUserContext->pvLocalUserContext;
  2383. BYTE cContainers = 0;
  2384. LPWSTR mwszContainers = NULL;
  2385. DWORD cbContainers = 0;
  2386. DWORD cchContainers = 0;
  2387. DWORD cbCurrent = 0;
  2388. BOOL fTransacted = FALSE;
  2389. PROV_ENUMALGS *pEnumAlgs = NULL;
  2390. LOG_BEGIN_CRYPTOAPI(LocalGetProvParam);
  2391. switch (dwParam)
  2392. {
  2393. case PP_ENUMALGS_EX:
  2394. case PP_ENUMALGS:
  2395. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2396. // Build the list of supported algorithms if we haven't done so already
  2397. // for this context.
  2398. if (NULL == pLocalUserCtx->pSupportedAlgs)
  2399. {
  2400. dwSts = BuildSupportedAlgorithmsList(pUserContext);
  2401. if (ERROR_SUCCESS != dwSts)
  2402. goto Ret;
  2403. }
  2404. // Reset the enumeration if requested.
  2405. if (CRYPT_FIRST == dwFlags)
  2406. pLocalUserCtx->pCurrentAlg = pLocalUserCtx->pSupportedAlgs;
  2407. // Is the enumeration already done?
  2408. if (NULL == pLocalUserCtx->pCurrentAlg)
  2409. {
  2410. dwSts = ERROR_NO_MORE_ITEMS;
  2411. goto Ret;
  2412. }
  2413. cbCurrent = (PP_ENUMALGS_EX == dwParam) ?
  2414. sizeof(PROV_ENUMALGS_EX) :
  2415. sizeof(PROV_ENUMALGS);
  2416. // Check the size of the caller's buffer or if caller is merely
  2417. // requesting size info.
  2418. if (NULL == pbData || *pcbDataLen < cbCurrent)
  2419. {
  2420. *pcbDataLen = cbCurrent;
  2421. if (NULL != pbData)
  2422. dwSts = ERROR_MORE_DATA;
  2423. goto Ret;
  2424. }
  2425. *pcbDataLen = cbCurrent;
  2426. if (PP_ENUMALGS_EX == dwParam)
  2427. {
  2428. memcpy(pbData, &pLocalUserCtx->pCurrentAlg->EnumalgsEx, cbCurrent);
  2429. }
  2430. else
  2431. {
  2432. // Have to do a member-wise copy of the PROV_ENUMALGS struct since
  2433. // the list we maintain is PROV_ENUMALGS_EX.
  2434. pEnumAlgs = (PROV_ENUMALGS *) pbData;
  2435. pEnumAlgs->aiAlgid =
  2436. pLocalUserCtx->pCurrentAlg->EnumalgsEx.aiAlgid;
  2437. pEnumAlgs->dwBitLen =
  2438. pLocalUserCtx->pCurrentAlg->EnumalgsEx.dwDefaultLen;
  2439. pEnumAlgs->dwNameLen =
  2440. pLocalUserCtx->pCurrentAlg->EnumalgsEx.dwNameLen;
  2441. memcpy(
  2442. pEnumAlgs->szName,
  2443. pLocalUserCtx->pCurrentAlg->EnumalgsEx.szName,
  2444. pEnumAlgs->dwNameLen);
  2445. }
  2446. pLocalUserCtx->pCurrentAlg = pLocalUserCtx->pCurrentAlg->pNext;
  2447. break;
  2448. case PP_ENUMCONTAINERS:
  2449. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2450. dwSts = CheckForVerifyContext(pUserContext, TRUE);
  2451. if (ERROR_SUCCESS != dwSts)
  2452. goto Ret;
  2453. if (NULL == pLocalUserCtx->mszEnumContainers ||
  2454. CRYPT_FIRST == dwFlags)
  2455. {
  2456. //
  2457. // We need to build a new list of containers on this card if we
  2458. // haven't already done so, or if the caller is starting a new
  2459. // container enumeration.
  2460. //
  2461. if (NULL != pLocalUserCtx->mszEnumContainers)
  2462. {
  2463. CspFreeH(pLocalUserCtx->mszEnumContainers);
  2464. pLocalUserCtx->mszEnumContainers = NULL;
  2465. pLocalUserCtx->mszCurrentEnumContainer = NULL;
  2466. }
  2467. dwSts = BeginCardCapiCall(pUserContext);
  2468. if (ERROR_SUCCESS != dwSts)
  2469. goto Ret;
  2470. fTransacted = TRUE;
  2471. dwSts = ContainerMapEnumContainers(
  2472. pLocalUserCtx->pCardState,
  2473. &cContainers,
  2474. &mwszContainers);
  2475. if (ERROR_SUCCESS != dwSts)
  2476. goto Ret;
  2477. cchContainers = CountCharsInMultiSz(mwszContainers);
  2478. cbContainers = WideCharToMultiByte(
  2479. CP_ACP,
  2480. 0,
  2481. mwszContainers,
  2482. cchContainers,
  2483. NULL,
  2484. 0,
  2485. NULL,
  2486. NULL);
  2487. if (0 == cbContainers)
  2488. {
  2489. dwSts = GetLastError();
  2490. goto Ret;
  2491. }
  2492. pLocalUserCtx->mszEnumContainers = (LPSTR) CspAllocH(cbContainers);
  2493. LOG_CHECK_ALLOC(pLocalUserCtx->mszEnumContainers);
  2494. cbContainers = WideCharToMultiByte(
  2495. CP_ACP,
  2496. 0,
  2497. mwszContainers,
  2498. cchContainers,
  2499. pLocalUserCtx->mszEnumContainers,
  2500. cbContainers,
  2501. NULL,
  2502. NULL);
  2503. if (0 == cbContainers)
  2504. {
  2505. dwSts = GetLastError();
  2506. goto Ret;
  2507. }
  2508. pLocalUserCtx->mszCurrentEnumContainer =
  2509. pLocalUserCtx->mszEnumContainers;
  2510. }
  2511. if (NULL == pLocalUserCtx->mszCurrentEnumContainer ||
  2512. '\0' == pLocalUserCtx->mszCurrentEnumContainer[0])
  2513. {
  2514. dwSts = ERROR_NO_MORE_ITEMS;
  2515. goto Ret;
  2516. }
  2517. cbCurrent = (strlen(
  2518. pLocalUserCtx->mszCurrentEnumContainer) + 1) * sizeof(CHAR);
  2519. if (NULL == pbData || *pcbDataLen < cbCurrent)
  2520. {
  2521. *pcbDataLen = cbCurrent;
  2522. if (NULL != pbData)
  2523. dwSts = ERROR_MORE_DATA;
  2524. goto Ret;
  2525. }
  2526. *pcbDataLen = cbCurrent;
  2527. memcpy(
  2528. pbData,
  2529. (PBYTE) pLocalUserCtx->mszCurrentEnumContainer,
  2530. cbCurrent);
  2531. ((PBYTE) pLocalUserCtx->mszCurrentEnumContainer) += cbCurrent;
  2532. break;
  2533. default:
  2534. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2535. break;
  2536. }
  2537. Ret:
  2538. if (fTransacted)
  2539. EndCardCapiCall(pUserContext);
  2540. LOG_END_CRYPTOAPI(LocalGetProvParam, dwSts);
  2541. return dwSts;
  2542. }
  2543. //
  2544. // Function: LocalExportKey
  2545. //
  2546. DWORD WINAPI
  2547. LocalExportKey(
  2548. IN PKEY_CONTEXT pKeyCtx,
  2549. IN PKEY_CONTEXT pPubKeyCtx,
  2550. IN DWORD dwBlobType,
  2551. IN DWORD dwFlags,
  2552. OUT LPBYTE pbData,
  2553. IN OUT LPDWORD pcbDataLen,
  2554. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2555. {
  2556. DWORD dwSts = ERROR_SUCCESS;
  2557. PLOCAL_USER_CONTEXT pLocalUserCtx =
  2558. (PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
  2559. CONTAINER_INFO ContainerInfo;
  2560. DWORD cbKey = 0;
  2561. PBYTE pbKey = 0;
  2562. PLOCAL_KEY_CONTEXT pLocalKeyCtx = NULL;
  2563. LOG_BEGIN_CRYPTOAPI(LocalExportKey);
  2564. memset(&ContainerInfo, 0, sizeof(ContainerInfo));
  2565. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2566. switch (dwBlobType)
  2567. {
  2568. case PRIVATEKEYBLOB:
  2569. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2570. if (NULL != pKeyCtx->pvLocalKeyContext)
  2571. {
  2572. pLocalKeyCtx = (PLOCAL_KEY_CONTEXT) pKeyCtx->pvLocalKeyContext;
  2573. if (NULL != pLocalKeyCtx->pbArchivablePrivateKey)
  2574. {
  2575. if ( *pcbDataLen < pLocalKeyCtx->cbArchivablePrivateKey ||
  2576. NULL == pbData)
  2577. {
  2578. *pcbDataLen = pLocalKeyCtx->cbArchivablePrivateKey;
  2579. if (NULL != pbData)
  2580. dwSts = ERROR_MORE_DATA;
  2581. goto Ret;
  2582. }
  2583. *pcbDataLen = pLocalKeyCtx->cbArchivablePrivateKey;
  2584. memcpy(
  2585. pbData,
  2586. pLocalKeyCtx->pbArchivablePrivateKey,
  2587. pLocalKeyCtx->cbArchivablePrivateKey);
  2588. break;
  2589. }
  2590. }
  2591. dwSts = (DWORD) NTE_BAD_TYPE;
  2592. break;
  2593. case PUBLICKEYBLOB:
  2594. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2595. dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
  2596. if (ERROR_SUCCESS != dwSts)
  2597. goto Ret;
  2598. dwSts = CspGetContainerInfo(
  2599. pLocalUserCtx->pCardState,
  2600. pLocalUserCtx->bContainerIndex,
  2601. 0,
  2602. &ContainerInfo);
  2603. if (ERROR_SUCCESS != dwSts)
  2604. goto Ret;
  2605. switch (pKeyCtx->Algid)
  2606. {
  2607. case AT_SIGNATURE:
  2608. cbKey = ContainerInfo.cbSigPublicKey;
  2609. pbKey = ContainerInfo.pbSigPublicKey;
  2610. break;
  2611. case AT_KEYEXCHANGE:
  2612. cbKey = ContainerInfo.cbKeyExPublicKey;
  2613. pbKey = ContainerInfo.pbKeyExPublicKey;
  2614. break;
  2615. default:
  2616. dwSts = (DWORD) NTE_BAD_KEY;
  2617. goto Ret;
  2618. }
  2619. if (*pcbDataLen < cbKey || NULL == pbData)
  2620. {
  2621. *pcbDataLen = cbKey;
  2622. if (NULL != pbData)
  2623. dwSts = ERROR_MORE_DATA;
  2624. goto Ret;
  2625. }
  2626. *pcbDataLen = cbKey;
  2627. memcpy(pbData, pbKey, cbKey);
  2628. break;
  2629. }
  2630. Ret:
  2631. EndCardCapiCall(pKeyCtx->pUserContext);
  2632. CleanupContainerInfo(&ContainerInfo);
  2633. LOG_END_CRYPTOAPI(LocalExportKey, dwSts);
  2634. return dwSts;
  2635. }
  2636. //
  2637. // Function: LocalImportKey
  2638. //
  2639. DWORD WINAPI
  2640. LocalImportKey(
  2641. IN PKEY_CONTEXT pKeyContext,
  2642. IN PBYTE pbData,
  2643. IN DWORD cbDataLen,
  2644. IN PKEY_CONTEXT pPubKey,
  2645. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2646. {
  2647. DWORD dwSts = ERROR_SUCCESS;
  2648. BLOBHEADER *pBlobHeader = (BLOBHEADER *) pbData;
  2649. PBYTE pbDecrypted = NULL;
  2650. DWORD cbDecrypted = 0;
  2651. CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
  2652. PLOCAL_USER_CONTEXT pLocal =
  2653. (PLOCAL_USER_CONTEXT) pKeyContext->pUserContext->pvLocalUserContext;
  2654. PBYTE pbPlaintextBlob = NULL;
  2655. DWORD cbPlaintextBlob = 0;
  2656. memset(&DecryptInfo, 0, sizeof(DecryptInfo));
  2657. LOG_BEGIN_CRYPTOAPI(LocalImportKey);
  2658. switch (pBlobHeader->bType)
  2659. {
  2660. case SIMPLEBLOB:
  2661. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2662. // Only allow Key Exchange type keys to decrypt other keys
  2663. if (AT_SIGNATURE == pPubKey->Algid)
  2664. {
  2665. dwSts = (DWORD) NTE_BAD_TYPE;
  2666. goto Ret;
  2667. }
  2668. if (CALG_RSA_KEYX != *(ALG_ID *) (pbData + sizeof(BLOBHEADER)))
  2669. {
  2670. dwSts = (DWORD) NTE_BAD_ALGID;
  2671. goto Ret;
  2672. }
  2673. if (pPubKey->pUserContext != pKeyContext->pUserContext)
  2674. {
  2675. dwSts = (DWORD) NTE_BAD_UID;
  2676. goto Ret;
  2677. }
  2678. dwSts = CheckForVerifyContext(pKeyContext->pUserContext, FALSE);
  2679. if (ERROR_SUCCESS != dwSts)
  2680. goto Ret;
  2681. //
  2682. // Decrypt a session key blob using the private key.
  2683. //
  2684. dwSts = BeginCardCapiCall(pKeyContext->pUserContext);
  2685. if (ERROR_SUCCESS != dwSts)
  2686. goto Ret;
  2687. dwSts = CspAuthenticateUser(pKeyContext->pUserContext);
  2688. if (ERROR_SUCCESS != dwSts)
  2689. goto Ret;
  2690. DecryptInfo.cbData = cbDataLen - sizeof(BLOBHEADER) - sizeof(ALG_ID);
  2691. DecryptInfo.dwKeySpec = AT_KEYEXCHANGE;
  2692. DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
  2693. DecryptInfo.pbData = pbData + sizeof(BLOBHEADER) + sizeof(ALG_ID);
  2694. DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
  2695. dwSts = CspPrivateKeyDecrypt(
  2696. pLocal->pCardState,
  2697. &DecryptInfo);
  2698. if (ERROR_SUCCESS != dwSts)
  2699. goto Ret;
  2700. dwSts = VerifyPKCS2Padding(
  2701. DecryptInfo.pbData,
  2702. DecryptInfo.cbData,
  2703. &pbDecrypted,
  2704. &cbDecrypted);
  2705. if (ERROR_SUCCESS != dwSts)
  2706. goto Ret;
  2707. //
  2708. // Now we can build a PLAINTEXTKEYBLOB with the decrypted session key
  2709. // and import it into the helper CSP.
  2710. //
  2711. cbPlaintextBlob = sizeof(BLOBHEADER) + sizeof(DWORD) + cbDecrypted;
  2712. pbPlaintextBlob = CspAllocH(cbPlaintextBlob);
  2713. LOG_CHECK_ALLOC(pbPlaintextBlob);
  2714. ((BLOBHEADER *) pbPlaintextBlob)->aiKeyAlg = pBlobHeader->aiKeyAlg;
  2715. ((BLOBHEADER *) pbPlaintextBlob)->bType = PLAINTEXTKEYBLOB;
  2716. ((BLOBHEADER *) pbPlaintextBlob)->bVersion = CUR_BLOB_VERSION;
  2717. *(DWORD *) (pbPlaintextBlob + sizeof(BLOBHEADER)) = cbDecrypted;
  2718. memcpy(
  2719. pbPlaintextBlob + sizeof(BLOBHEADER) + sizeof(DWORD),
  2720. pbDecrypted,
  2721. cbDecrypted);
  2722. if (! CryptImportKey(
  2723. pKeyContext->pUserContext->hSupportProv,
  2724. pbPlaintextBlob,
  2725. cbPlaintextBlob,
  2726. 0,
  2727. pKeyContext->dwFlags,
  2728. &pKeyContext->hSupportKey))
  2729. {
  2730. dwSts = GetLastError();
  2731. goto Ret;
  2732. }
  2733. pKeyContext->Algid = pBlobHeader->aiKeyAlg;
  2734. pKeyContext->cKeyBits = cbDecrypted * 8;
  2735. break;
  2736. case PRIVATEKEYBLOB:
  2737. // We don't allow importing privatekey blobs into the smartcard
  2738. // CSP, and it doesn't make sense to use the helper CSP for this,
  2739. // so fail.
  2740. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2741. dwSts = (DWORD) NTE_BAD_TYPE;
  2742. break;
  2743. default:
  2744. // For all other blob types, let the helper CSP take a shot.
  2745. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2746. }
  2747. Ret:
  2748. EndCardCapiCall(pKeyContext->pUserContext);
  2749. if (pbDecrypted)
  2750. CspFreeH(pbDecrypted);
  2751. if (pbPlaintextBlob)
  2752. CspFreeH(pbPlaintextBlob);
  2753. LOG_END_CRYPTOAPI(LocalImportKey, dwSts);
  2754. return dwSts;
  2755. }
  2756. //
  2757. // Function: LocalEncrypt
  2758. //
  2759. DWORD WINAPI
  2760. LocalEncrypt(
  2761. IN HCRYPTPROV hProv,
  2762. IN HCRYPTKEY hKey,
  2763. IN HCRYPTHASH hHash,
  2764. IN BOOL fFinal,
  2765. IN DWORD dwFlags,
  2766. IN OUT LPBYTE pbData,
  2767. IN OUT LPDWORD pcbDataLen,
  2768. IN DWORD cbBufLen)
  2769. {
  2770. *pcbDataLen = 0;
  2771. //
  2772. // TODO
  2773. //
  2774. return ERROR_CALL_NOT_IMPLEMENTED;
  2775. }
  2776. //
  2777. // Function: LocalDecrypt
  2778. //
  2779. DWORD WINAPI
  2780. LocalDecrypt(
  2781. IN PKEY_CONTEXT pKeyCtx,
  2782. IN PHASH_CONTEXT pHashCtx,
  2783. IN BOOL fFinal,
  2784. IN DWORD dwFlags,
  2785. IN OUT LPBYTE pbData,
  2786. IN OUT LPDWORD pcbDataLen,
  2787. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2788. {
  2789. DWORD dwSts = ERROR_SUCCESS;
  2790. PBYTE pbDecrypted = NULL;
  2791. DWORD cbDecrypted = 0;
  2792. CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
  2793. PLOCAL_USER_CONTEXT pLocal =
  2794. (PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
  2795. LOG_BEGIN_CRYPTOAPI(LocalDecrypt);
  2796. memset(&DecryptInfo, 0, sizeof(DecryptInfo));
  2797. dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
  2798. if (ERROR_SUCCESS != dwSts)
  2799. goto Ret;
  2800. if (AT_KEYEXCHANGE == pKeyCtx->Algid)
  2801. {
  2802. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2803. }
  2804. else
  2805. {
  2806. SetLocalCallInfo(pLocalCallInfo, TRUE);
  2807. goto Ret;
  2808. }
  2809. dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
  2810. if (ERROR_SUCCESS != dwSts)
  2811. goto Ret;
  2812. dwSts = CspAuthenticateUser(pKeyCtx->pUserContext);
  2813. if (ERROR_SUCCESS != dwSts)
  2814. goto Ret;
  2815. DecryptInfo.cbData = *pcbDataLen;
  2816. DecryptInfo.dwKeySpec = AT_KEYEXCHANGE;
  2817. DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
  2818. DecryptInfo.pbData = pbData;
  2819. DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
  2820. dwSts = CspPrivateKeyDecrypt(
  2821. pLocal->pCardState,
  2822. &DecryptInfo);
  2823. if (ERROR_SUCCESS != dwSts)
  2824. goto Ret;
  2825. dwSts = VerifyPKCS2Padding(
  2826. DecryptInfo.pbData,
  2827. DecryptInfo.cbData,
  2828. &pbDecrypted,
  2829. &cbDecrypted);
  2830. if (ERROR_SUCCESS != dwSts)
  2831. goto Ret;
  2832. memcpy(
  2833. pbData,
  2834. pbDecrypted,
  2835. cbDecrypted);
  2836. *pcbDataLen = cbDecrypted;
  2837. Ret:
  2838. EndCardCapiCall(pKeyCtx->pUserContext);
  2839. if (pbDecrypted)
  2840. CspFreeH(pbDecrypted);
  2841. LOG_END_CRYPTOAPI(LocalDecrypt, dwSts);
  2842. return dwSts;
  2843. }
  2844. //
  2845. // Function: LocalSignHash
  2846. //
  2847. DWORD WINAPI
  2848. LocalSignHash(
  2849. IN PHASH_CONTEXT pHashCtx,
  2850. IN DWORD dwKeySpec,
  2851. IN DWORD dwFlags,
  2852. OUT LPBYTE pbSignature,
  2853. IN OUT LPDWORD pcbSigLen,
  2854. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2855. {
  2856. DWORD dwSts = ERROR_SUCCESS;
  2857. PLOCAL_USER_CONTEXT pLocal =
  2858. (PLOCAL_USER_CONTEXT) pHashCtx->pUserContext->pvLocalUserContext;
  2859. PBYTE pbHash = NULL;
  2860. PBYTE pbSig = NULL;
  2861. DWORD cbHash = 0;
  2862. DWORD cbPrivateKey = 0;
  2863. ALG_ID aiHash = 0;
  2864. DWORD cbData = 0;
  2865. CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
  2866. RSAPUBKEY *pPubKey = NULL;
  2867. LOG_BEGIN_CRYPTOAPI(LocalSignHash);
  2868. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2869. dwSts = CheckForVerifyContext(pHashCtx->pUserContext, FALSE);
  2870. if (ERROR_SUCCESS != dwSts)
  2871. goto Ret;
  2872. memset(&DecryptInfo, 0, sizeof(DecryptInfo));
  2873. dwSts = BeginCardCapiCall(pHashCtx->pUserContext);
  2874. if (ERROR_SUCCESS != dwSts)
  2875. goto Ret;
  2876. //
  2877. // Get the size of the private key that will be used for signing
  2878. //
  2879. dwSts = GetKeyModulusLength(
  2880. pHashCtx->pUserContext, dwKeySpec, &cbPrivateKey);
  2881. if (ERROR_SUCCESS != dwSts)
  2882. goto Ret;
  2883. if (*pcbSigLen < cbPrivateKey || NULL == pbSignature)
  2884. {
  2885. *pcbSigLen = cbPrivateKey;
  2886. if (NULL != pbSignature)
  2887. dwSts = ERROR_MORE_DATA;
  2888. goto Ret;
  2889. }
  2890. //
  2891. // Get the hash value we're going to sign
  2892. //
  2893. if (! CryptGetHashParam(
  2894. pHashCtx->hSupportHash,
  2895. HP_HASHVAL,
  2896. NULL,
  2897. &cbHash,
  2898. 0))
  2899. {
  2900. dwSts = GetLastError();
  2901. goto Ret;
  2902. }
  2903. pbHash = (PBYTE) CspAllocH(cbHash);
  2904. LOG_CHECK_ALLOC(pbHash);
  2905. if (! CryptGetHashParam(
  2906. pHashCtx->hSupportHash,
  2907. HP_HASHVAL,
  2908. pbHash,
  2909. &cbHash,
  2910. 0))
  2911. {
  2912. dwSts = GetLastError();
  2913. goto Ret;
  2914. }
  2915. //
  2916. // Get the algid of this hash so the correct encoding can be applied
  2917. //
  2918. cbData = sizeof(aiHash);
  2919. if (! CryptGetHashParam(
  2920. pHashCtx->hSupportHash,
  2921. HP_ALGID,
  2922. (PBYTE) &aiHash,
  2923. &cbData,
  2924. 0))
  2925. {
  2926. dwSts = GetLastError();
  2927. goto Ret;
  2928. }
  2929. //
  2930. // Apply PKCS1 encoding to this hash data. It gets padded out to the
  2931. // length of the key modulus. The padded buffer is allocated for us.
  2932. //
  2933. dwSts = ApplyPKCS1SigningFormat(
  2934. aiHash,
  2935. pbHash,
  2936. cbHash,
  2937. 0,
  2938. cbPrivateKey,
  2939. &pbSig);
  2940. if (ERROR_SUCCESS != dwSts)
  2941. goto Ret;
  2942. //
  2943. // Private key decrypt the formatted data
  2944. //
  2945. dwSts = CspAuthenticateUser(pHashCtx->pUserContext);
  2946. if (ERROR_SUCCESS != dwSts)
  2947. goto Ret;
  2948. DecryptInfo.cbData = cbPrivateKey;
  2949. DecryptInfo.pbData = pbSig;
  2950. DecryptInfo.dwKeySpec = dwKeySpec;
  2951. DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
  2952. DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
  2953. dwSts = CspPrivateKeyDecrypt(
  2954. pLocal->pCardState,
  2955. &DecryptInfo);
  2956. if (ERROR_SUCCESS != dwSts)
  2957. goto Ret;
  2958. //
  2959. // Copy the completed signature into the caller's buffer
  2960. //
  2961. memcpy(
  2962. pbSignature,
  2963. pbSig,
  2964. cbPrivateKey);
  2965. *pcbSigLen = cbPrivateKey;
  2966. Ret:
  2967. EndCardCapiCall(pHashCtx->pUserContext);
  2968. if (pbSig)
  2969. CspFreeH(pbSig);
  2970. if (pbHash)
  2971. CspFreeH(pbHash);
  2972. LOG_END_CRYPTOAPI(LocalSignHash, dwSts);
  2973. return dwSts;
  2974. }
  2975. //
  2976. // Function: LocalVerifySignature
  2977. //
  2978. DWORD WINAPI
  2979. LocalVerifySignature(
  2980. IN PHASH_CONTEXT pHashCtx,
  2981. IN CONST BYTE *pbSignature,
  2982. IN DWORD cbSigLen,
  2983. IN PKEY_CONTEXT pKeyCtx,
  2984. IN DWORD dwFlags,
  2985. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  2986. {
  2987. DWORD dwSts = ERROR_SUCCESS;
  2988. PLOCAL_USER_CONTEXT pLocal =
  2989. (PLOCAL_USER_CONTEXT) pHashCtx->pUserContext->pvLocalUserContext;
  2990. CONTAINER_INFO ContainerInfo;
  2991. HCRYPTKEY hKey = 0;
  2992. BOOL fSignature = (AT_SIGNATURE == pKeyCtx->Algid);
  2993. LOG_BEGIN_CRYPTOAPI(LocalVerifySignature);
  2994. memset(&ContainerInfo, 0, sizeof(ContainerInfo));
  2995. SetLocalCallInfo(pLocalCallInfo, FALSE);
  2996. dwSts = CheckForVerifyContext(pHashCtx->pUserContext, FALSE);
  2997. if (ERROR_SUCCESS != dwSts)
  2998. goto Ret;
  2999. dwSts = BeginCardCapiCall(pHashCtx->pUserContext);
  3000. if (ERROR_SUCCESS != dwSts)
  3001. goto Ret;
  3002. //
  3003. // Get the public key
  3004. //
  3005. dwSts = CspGetContainerInfo(
  3006. pLocal->pCardState,
  3007. pLocal->bContainerIndex,
  3008. 0,
  3009. &ContainerInfo);
  3010. if (ERROR_SUCCESS != dwSts)
  3011. goto Ret;
  3012. //
  3013. // Import the public key into the helper CSP
  3014. //
  3015. if (! CryptImportKey(
  3016. pHashCtx->pUserContext->hSupportProv,
  3017. fSignature ?
  3018. ContainerInfo.pbSigPublicKey :
  3019. ContainerInfo.pbKeyExPublicKey,
  3020. fSignature ?
  3021. ContainerInfo.cbSigPublicKey :
  3022. ContainerInfo.cbKeyExPublicKey,
  3023. 0,
  3024. 0,
  3025. &hKey))
  3026. {
  3027. dwSts = GetLastError();
  3028. goto Ret;
  3029. }
  3030. //
  3031. // Use the helper CSP to verify the signature
  3032. //
  3033. if (! CryptVerifySignature(
  3034. pHashCtx->hSupportHash,
  3035. pbSignature,
  3036. cbSigLen,
  3037. hKey,
  3038. NULL,
  3039. dwFlags))
  3040. {
  3041. dwSts = GetLastError();
  3042. goto Ret;
  3043. }
  3044. Ret:
  3045. EndCardCapiCall(pHashCtx->pUserContext);
  3046. CleanupContainerInfo(&ContainerInfo);
  3047. if (hKey)
  3048. CryptDestroyKey(hKey);
  3049. LOG_END_CRYPTOAPI(LocalVerifySignature, dwSts);
  3050. return dwSts;
  3051. }
  3052. //
  3053. // Function: LocalGetUserKey
  3054. //
  3055. DWORD WINAPI
  3056. LocalGetUserKey(
  3057. IN PKEY_CONTEXT pKeyCtx,
  3058. OUT PLOCAL_CALL_INFO pLocalCallInfo)
  3059. {
  3060. DWORD dwSts = ERROR_SUCCESS;
  3061. DWORD cbKey = 0;
  3062. LOG_BEGIN_CRYPTOAPI(LocalGetUserKey);
  3063. if (AT_SIGNATURE == pKeyCtx->Algid || AT_KEYEXCHANGE == pKeyCtx->Algid)
  3064. {
  3065. SetLocalCallInfo(pLocalCallInfo, FALSE);
  3066. }
  3067. else
  3068. {
  3069. SetLocalCallInfo(pLocalCallInfo, TRUE);
  3070. goto Ret;
  3071. }
  3072. dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, TRUE);
  3073. if (ERROR_SUCCESS != dwSts)
  3074. goto Ret;
  3075. dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
  3076. if (ERROR_SUCCESS != dwSts)
  3077. goto Ret;
  3078. dwSts = GetKeyModulusLength(
  3079. pKeyCtx->pUserContext,
  3080. pKeyCtx->Algid,
  3081. &cbKey);
  3082. if (ERROR_SUCCESS != dwSts)
  3083. goto Ret;
  3084. if (cbKey)
  3085. {
  3086. pKeyCtx->cKeyBits = cbKey * 8;
  3087. }
  3088. else
  3089. {
  3090. dwSts = (DWORD) NTE_NO_KEY;
  3091. goto Ret;
  3092. }
  3093. Ret:
  3094. EndCardCapiCall(pKeyCtx->pUserContext);
  3095. LOG_END_CRYPTOAPI(LocalGetUserKey, dwSts);
  3096. return dwSts;
  3097. }
  3098. //
  3099. // Function: LocalDuplicateKey
  3100. //
  3101. DWORD WINAPI
  3102. LocalDuplicateKey(
  3103. IN HCRYPTPROV hProv,
  3104. IN HCRYPTKEY hKey,
  3105. IN LPDWORD pdwReserved,
  3106. IN DWORD dwFlags,
  3107. OUT HCRYPTKEY *phKey)
  3108. {
  3109. return ERROR_CALL_NOT_IMPLEMENTED;
  3110. }
  3111. //
  3112. // Function: UnloadStrings
  3113. //
  3114. void
  3115. UnloadStrings(
  3116. IN PCSP_STRING pStrings,
  3117. IN DWORD cStrings)
  3118. {
  3119. DWORD iString = 0;
  3120. for ( iString = 0;
  3121. iString < cStrings;
  3122. iString++)
  3123. {
  3124. if (NULL != pStrings[iString].wszString)
  3125. {
  3126. CspFreeH(pStrings[iString].wszString);
  3127. pStrings[iString].wszString = NULL;
  3128. }
  3129. }
  3130. }
  3131. //
  3132. // Function: LoadStrings
  3133. //
  3134. DWORD
  3135. LoadStrings(
  3136. IN HMODULE hMod,
  3137. IN PCSP_STRING pStrings,
  3138. IN DWORD cStrings)
  3139. {
  3140. DWORD dwSts = ERROR_INTERNAL_ERROR;
  3141. DWORD cch;
  3142. WCHAR wsz[MAX_PATH];
  3143. DWORD iString = 0;
  3144. for ( iString = 0;
  3145. iString < cStrings;
  3146. iString++)
  3147. {
  3148. cch = LoadStringW(
  3149. hMod,
  3150. pStrings[iString].dwResource,
  3151. wsz,
  3152. sizeof(wsz) / sizeof(wsz[0]));
  3153. if (0 == cch)
  3154. {
  3155. dwSts = GetLastError();
  3156. goto ErrorExit;
  3157. }
  3158. pStrings[iString].wszString = (LPWSTR) CspAllocH(sizeof(WCHAR) * (cch + 1));
  3159. if (NULL == pStrings[iString].wszString)
  3160. {
  3161. dwSts = ERROR_NOT_ENOUGH_MEMORY;
  3162. goto ErrorExit;
  3163. }
  3164. wcscpy(
  3165. pStrings[iString].wszString,
  3166. wsz);
  3167. }
  3168. return ERROR_SUCCESS;
  3169. ErrorExit:
  3170. UnloadStrings(pStrings, cStrings);
  3171. return dwSts;
  3172. }
  3173. //
  3174. // Function: LocalDllInitialize
  3175. //
  3176. BOOL WINAPI LocalDllInitialize(
  3177. IN PVOID hmod,
  3178. IN ULONG Reason,
  3179. IN PCONTEXT Context)
  3180. {
  3181. DWORD dwLen = 0;
  3182. static BOOL fLoadedStrings = FALSE;
  3183. static BOOL fInitializedCspState = FALSE;
  3184. BOOL fSuccess = FALSE;
  3185. switch (Reason)
  3186. {
  3187. case DLL_PROCESS_ATTACH:
  3188. // load strings
  3189. if (ERROR_SUCCESS != LoadStrings(
  3190. hmod,
  3191. g_Strings,
  3192. sizeof(g_Strings) / sizeof(g_Strings[0])))
  3193. goto Cleanup;
  3194. fLoadedStrings = TRUE;
  3195. // Initialize global CSP data for this process
  3196. if (ERROR_SUCCESS != InitializeCspState(hmod))
  3197. goto Cleanup;
  3198. fInitializedCspState = TRUE;
  3199. CspInitializeDebug();
  3200. fSuccess = TRUE;
  3201. break;
  3202. case DLL_PROCESS_DETACH:
  3203. CspUnloadDebug();
  3204. fSuccess = TRUE;
  3205. goto Cleanup;
  3206. }
  3207. return fSuccess;
  3208. Cleanup:
  3209. if (fLoadedStrings)
  3210. {
  3211. UnloadStrings(
  3212. g_Strings,
  3213. sizeof(g_Strings) / sizeof(g_Strings[0]));
  3214. fLoadedStrings = FALSE;
  3215. }
  3216. if (fInitializedCspState)
  3217. {
  3218. DeleteCspState();
  3219. fInitializedCspState = FALSE;
  3220. }
  3221. return fSuccess;
  3222. }
  3223. //
  3224. // Function: LocalDllRegisterServer
  3225. //
  3226. DWORD WINAPI LocalDllRegisterServer(void)
  3227. {
  3228. HKEY hKey = 0;
  3229. DWORD dwSts = ERROR_SUCCESS;
  3230. dwSts = RegOpenProviderKey(&hKey, KEY_ALL_ACCESS);
  3231. if (ERROR_SUCCESS != dwSts)
  3232. goto Ret;
  3233. //
  3234. // Add CSP default configuration
  3235. //
  3236. dwSts = RegConfigAddEntries(hKey);
  3237. if (ERROR_SUCCESS != dwSts)
  3238. goto Ret;
  3239. Ret:
  3240. if (hKey)
  3241. RegCloseKey(hKey);
  3242. return dwSts;
  3243. }
  3244. //
  3245. // Declaration of the LOCAL_CSP_INFO structure required by the
  3246. // CSP lib.
  3247. //
  3248. LOCAL_CSP_INFO LocalCspInfo =
  3249. {
  3250. LocalAcquireContext, //pfnLocalAcquireContext;
  3251. LocalReleaseContext, //pfnLocalReleaseContext;
  3252. LocalGenKey, //pfnLocalGenKey;
  3253. NULL, //pfnLocalDeriveKey;
  3254. LocalDestroyKey, //pfnLocalDestroyKey;
  3255. LocalSetKeyParam, //pfnLocalSetKeyParam;
  3256. LocalGetKeyParam, //pfnLocalGetKeyParam;
  3257. LocalSetProvParam, //pfnLocalSetProvParam;
  3258. LocalGetProvParam, //pfnLocalGetProvParam;
  3259. NULL, //pfnLocalSetHashParam;
  3260. NULL, //pfnLocalGetHashParam;
  3261. LocalExportKey, //pfnLocalExportKey;
  3262. LocalImportKey, //pfnLocalImportKey;
  3263. NULL, //pfnLocalEncrypt;
  3264. LocalDecrypt, //pfnLocalDecrypt;
  3265. NULL, //pfnLocalCreateHash;
  3266. NULL, //pfnLocalHashData;
  3267. NULL, //pfnLocalHashSessionKey;
  3268. LocalSignHash, //pfnLocalSignHash;
  3269. NULL, //pfnLocalDestroyHash;
  3270. LocalVerifySignature, //pfnLocalVerifySignature;
  3271. NULL, //pfnLocalGenRandom;
  3272. LocalGetUserKey, //pfnLocalGetUserKey;
  3273. NULL, //pfnLocalDuplicateHash;
  3274. NULL, //pfnLocalDuplicateKey;
  3275. LocalDllInitialize, //pfnLocalDllInitialize;
  3276. LocalDllRegisterServer, //pfnLocalDllRegisterServer;
  3277. NULL, //pfnLocalDllUnregisterServer;
  3278. MS_SCARD_PROV_W, //wszProviderName;
  3279. PROV_RSA_FULL, //dwProviderType;
  3280. CRYPT_IMPL_REMOVABLE,
  3281. MS_STRONG_PROV, //wszSupportProviderName;
  3282. PROV_RSA_FULL //dwSupportProviderType;
  3283. };