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.

3177 lines
74 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. ScLogon
  5. Abstract:
  6. This module provides helper functions for use by winlogon (GINA, Kerberos)
  7. Author:
  8. Amanda Matlosz (amatlosz) 10/22/1997
  9. Environment:
  10. Win32, C++ w/ Exceptions
  11. Notes:
  12. 03-11-98 Wrap calls to GetLastError() to workaround bug where LastErr gets
  13. clobbered. Added event logging to make logon smoother.
  14. 04-02-98 Removed all references to WinVerifyTrust; this is something
  15. Kerberos itself is responsible for.
  16. --*/
  17. /////////////////////////////////////////////////////////////////////////////
  18. //
  19. // Includes
  20. #if !defined(_AMD64_) && !defined(_X86_) && !defined(_IA64_)
  21. #define _X86_ 1
  22. #endif
  23. #ifndef _WIN32_WINNT
  24. #define _WIN32_WINNT 0x0400
  25. #ifndef UNICODE
  26. #define UNICODE
  27. #endif
  28. #endif
  29. #ifndef WIN32_LEAN_AND_MEAN
  30. #define WIN32_LEAN_AND_MEAN 1
  31. #endif
  32. extern "C" {
  33. #include <nt.h>
  34. #include <ntrtl.h>
  35. #include <nturtl.h>
  36. #include <ntlsa.h>
  37. }
  38. #include <windows.h>
  39. #include <winscard.h>
  40. #include <wincrypt.h>
  41. #include <softpub.h>
  42. #include <stddef.h>
  43. #include <crtdbg.h>
  44. #include "sclogon.h"
  45. #include "unicodes.h"
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <time.h>
  49. #include <tchar.h>
  50. #ifndef KP_KEYEXCHANGE_PIN
  51. #define KP_KEYEXCHANGE_PIN 32
  52. #else
  53. #if 32 != KP_KEYEXCHANGE_PIN
  54. #error Invalid KP_KEYEXCHANGE_PIN assumption
  55. #endif
  56. #endif
  57. #ifndef CRYPT_SILENT
  58. #define CRYPT_SILENT 0x40
  59. #else
  60. #if 0x40 != CRYPT_SILENT
  61. #error Duplicate CRYPT_SILENT definition
  62. #endif
  63. #endif
  64. #ifndef SCARD_PROVIDER_CSP
  65. #define SCARD_PROVIDER_CSP 2
  66. #else
  67. #if 2 != SCARD_PROVIDER_CSP
  68. #error Invalid SCARD_PROVIDER_CSP definition
  69. #endif
  70. #endif
  71. #if defined(DBG) || defined(DEBUG)
  72. BOOL SCDebug = TRUE;
  73. #define DebugPrint(a) _DebugPrint a
  74. void
  75. __cdecl
  76. _DebugPrint(
  77. LPCSTR szFormat,
  78. ...
  79. )
  80. {
  81. if (SCDebug) {
  82. CHAR szBuffer[512];
  83. va_list ap;
  84. va_start(ap, szFormat);
  85. vsprintf(szBuffer, szFormat, ap);
  86. OutputDebugStringA(szBuffer);
  87. }
  88. }
  89. #else
  90. #define DebugPrint(a)
  91. #endif
  92. // TODO: The following logging is still proving useful.
  93. // TODO: leave in for B3: integrate more tightly w/ winlogon/kerberos ??
  94. #include <sclmsg.h>
  95. // A Global class used to maintain internal state.
  96. class CSCLogonInit
  97. {
  98. public:
  99. // Runs at image creation
  100. CSCLogonInit(
  101. BOOL *pfResult)
  102. {
  103. m_hCrypt = NULL;
  104. *pfResult = TRUE;
  105. };
  106. // Runs at image termination
  107. ~CSCLogonInit()
  108. {
  109. Release();
  110. };
  111. // Cleans up current state.
  112. void
  113. Release(
  114. void)
  115. {
  116. if (NULL != m_hCrypt)
  117. {
  118. CryptReleaseContext(m_hCrypt, 0);
  119. m_hCrypt = NULL;
  120. }
  121. }
  122. // Relinquish control of the crypto context.
  123. HCRYPTPROV
  124. RelinquishCryptCtx(
  125. LogonInfo* pLogon)
  126. {
  127. HCRYPTPROV hProv;
  128. hProv = CryptCtx(pLogon);
  129. m_hCrypt = NULL;
  130. return hProv;
  131. };
  132. // Get the crypto context, creating it if it's not there.
  133. HCRYPTPROV
  134. CryptCtx(
  135. LogonInfo* pLogon)
  136. {
  137. HCRYPTPROV hProv;
  138. LPCTSTR szRdr = NULL;
  139. LPCTSTR szCntr = NULL;
  140. LPTSTR szFQCN = NULL;
  141. LONG lLen = 0;
  142. if (NULL == m_hCrypt)
  143. {
  144. BOOL fSts;
  145. // Prepare FullyQualifiedContainerName for CryptAcCntx call
  146. szRdr = GetReaderName((LPBYTE)pLogon);
  147. szCntr = GetContainerName((LPBYTE)pLogon);
  148. lLen = (lstrlen(szRdr) + lstrlen(szCntr) + 10)*sizeof(TCHAR);
  149. szFQCN = (LPTSTR)LocalAlloc(LPTR, lLen);
  150. if (NULL != szFQCN)
  151. {
  152. wsprintf(szFQCN, TEXT("\\\\.\\%s\\%s"), szRdr, szCntr);
  153. fSts = CryptAcquireContext(
  154. &m_hCrypt,
  155. szFQCN,
  156. GetCSPName((LPBYTE)pLogon),
  157. PROV_RSA_FULL, // ?TODO? from pbLogonInfo
  158. CRYPT_SILENT | CRYPT_MACHINE_KEYSET
  159. );
  160. LocalFree(szFQCN);
  161. }
  162. else
  163. {
  164. fSts = FALSE;
  165. }
  166. }
  167. hProv = m_hCrypt;
  168. return hProv;
  169. }
  170. protected:
  171. HCRYPTPROV m_hCrypt;
  172. };
  173. NTSTATUS ScNtStatusTranslation(NTSTATUS NtErr, DWORD *pdwErr)
  174. {
  175. //
  176. // Convert the error back to a Win32 error
  177. //
  178. switch (NtErr)
  179. {
  180. case STATUS_INVALID_PARAMETER:
  181. *pdwErr = ERROR_INVALID_DATA;
  182. break;
  183. case STATUS_SMARTCARD_SUBSYSTEM_FAILURE:
  184. // A Cryptxxx API just failed
  185. *pdwErr = GetLastError();
  186. switch (*pdwErr)
  187. {
  188. case SCARD_W_WRONG_CHV:
  189. case SCARD_E_INVALID_CHV:
  190. NtErr = STATUS_SMARTCARD_WRONG_PIN;
  191. break;
  192. case SCARD_W_CHV_BLOCKED:
  193. NtErr = STATUS_SMARTCARD_CARD_BLOCKED;
  194. break;
  195. case SCARD_W_REMOVED_CARD:
  196. case SCARD_E_NO_SMARTCARD:
  197. NtErr = STATUS_SMARTCARD_NO_CARD;
  198. break;
  199. case NTE_BAD_KEYSET:
  200. case NTE_KEYSET_NOT_DEF:
  201. NtErr = STATUS_SMARTCARD_NO_KEY_CONTAINER;
  202. break;
  203. case SCARD_E_NO_SUCH_CERTIFICATE:
  204. case SCARD_E_CERTIFICATE_UNAVAILABLE:
  205. NtErr = STATUS_SMARTCARD_NO_CERTIFICATE;
  206. break;
  207. case NTE_NO_KEY:
  208. NtErr = STATUS_SMARTCARD_NO_KEYSET;
  209. break;
  210. case SCARD_E_TIMEOUT:
  211. case SCARD_F_COMM_ERROR:
  212. case SCARD_E_COMM_DATA_LOST:
  213. NtErr = STATUS_SMARTCARD_IO_ERROR;
  214. break;
  215. case NTE_SILENT_CONTEXT:
  216. NtErr = STATUS_SMARTCARD_SILENT_CONTEXT;
  217. break;
  218. //default:
  219. // Nothing, leave NtErr unchanged
  220. }
  221. break;
  222. case STATUS_INSUFFICIENT_RESOURCES:
  223. case STATUS_NO_MEMORY:
  224. *pdwErr = ERROR_OUTOFMEMORY;
  225. break;
  226. case STATUS_BUFFER_TOO_SMALL:
  227. *pdwErr = SEC_E_BUFFER_TOO_SMALL;
  228. break;
  229. default:
  230. *pdwErr = SCARD_E_UNEXPECTED;
  231. }
  232. return NtErr;
  233. }
  234. // For tracing errors in ScHelper*
  235. NTSTATUS LogEvent(NTSTATUS NtErr, DWORD dwEventID)
  236. {
  237. DWORD dwErr;
  238. //
  239. // Convert the error back to a Win32 error
  240. //
  241. NtErr = ScNtStatusTranslation(NtErr, &dwErr);
  242. if (0 == dwErr)
  243. {
  244. return NtErr;
  245. }
  246. //
  247. // Initialize log as necessary
  248. //
  249. HKEY hKey;
  250. DWORD disp;
  251. long err = RegCreateKeyEx(
  252. HKEY_LOCAL_MACHINE,
  253. TEXT("System\\CurrentControlSet\\Services\\EventLog\\Application\\Smart Card Logon"),
  254. 0,
  255. TEXT(""),
  256. REG_OPTION_NON_VOLATILE,
  257. KEY_WRITE,
  258. NULL,
  259. &hKey,
  260. &disp
  261. );
  262. if (ERROR_SUCCESS != err)
  263. {
  264. return NtErr;
  265. }
  266. if (disp == REG_CREATED_NEW_KEY)
  267. {
  268. PBYTE l_szModulePath = (PBYTE)TEXT("%SystemRoot%\\System32\\scarddlg.dll");
  269. ULONG l_uLen = (_tcslen((LPCTSTR)l_szModulePath) + 1)*sizeof(TCHAR);
  270. RegSetValueEx(
  271. hKey,
  272. TEXT("EventMessageFile"),
  273. 0,
  274. REG_EXPAND_SZ,
  275. l_szModulePath,
  276. l_uLen
  277. );
  278. disp = (DWORD)(
  279. EVENTLOG_ERROR_TYPE |
  280. EVENTLOG_WARNING_TYPE |
  281. EVENTLOG_INFORMATION_TYPE
  282. );
  283. RegSetValueEx(
  284. hKey,
  285. TEXT("TypesSupported"),
  286. 0,
  287. REG_DWORD,
  288. (PBYTE) &disp,
  289. sizeof(DWORD)
  290. );
  291. }
  292. RegCloseKey(hKey);
  293. HANDLE hEventSource = RegisterEventSource(
  294. NULL,
  295. TEXT("Smart Card Logon")
  296. );
  297. if (NULL != hEventSource)
  298. {
  299. DWORD dwLen = 0;
  300. LPTSTR szErrorString = NULL;
  301. TCHAR szBuffer[2+8+1]; // Enough for "0x????????"
  302. dwLen = FormatMessage(
  303. FORMAT_MESSAGE_ALLOCATE_BUFFER
  304. | FORMAT_MESSAGE_FROM_SYSTEM,
  305. NULL,
  306. dwErr,
  307. LANG_NEUTRAL,
  308. (LPTSTR)&szErrorString,
  309. 0,
  310. NULL);
  311. if (dwLen == 0)
  312. {
  313. _stprintf(szBuffer, _T("0x%08lX"), dwErr);
  314. szErrorString = szBuffer;
  315. }
  316. ReportEvent(
  317. hEventSource,
  318. EVENTLOG_ERROR_TYPE,
  319. 0, // event category
  320. dwEventID, // event identifier // resourceID for the messagetable entry...
  321. NULL, // user security identifier (optional)
  322. 1, // number of strings to merge with message
  323. sizeof(long), // size of binary data, in bytes
  324. (LPCTSTR*)&szErrorString, // array of strings to merge with message
  325. (LPVOID)&dwErr // address of binary data
  326. );
  327. DeregisterEventSource(hEventSource);
  328. if ((NULL != szErrorString) && (szErrorString != szBuffer))
  329. {
  330. LocalFree((LPVOID)szErrorString);
  331. }
  332. }
  333. return NtErr;
  334. }
  335. //////////////////////////////////////////////////////////////////////////////
  336. //
  337. // Structs
  338. //////////////////////////////////////////////////////////////////////////////
  339. //
  340. // Functions
  341. //
  342. // Internal helpers: called by the ScLogon APIs to perform certain tedious work
  343. /*++
  344. GetReaderName:
  345. GetCardName:
  346. GetContainerName:
  347. GetCSPName:
  348. : Intended for accessing the LogonInformation glob
  349. Author:
  350. Amanda Matlosz
  351. Note:
  352. Some of these are made available to outside callers; see sclogon.h
  353. --*/
  354. extern "C"
  355. PBYTE
  356. WINAPI
  357. ScBuildLogonInfo(
  358. LPCTSTR szCard,
  359. LPCTSTR szReader,
  360. LPCTSTR szContainer,
  361. LPCTSTR szCSP)
  362. {
  363. // No assumptions are made regarding the values of the incoming parameters;
  364. // At this point, it is legal for them all to be empty.
  365. // It is also possible that NULL values are being passed in -- if this is the case,
  366. // they must be replaced with empty strings.
  367. LPCTSTR szCardI = TEXT("");
  368. LPCTSTR szReaderI = TEXT("");
  369. LPCTSTR szContainerI = TEXT("");
  370. LPCTSTR szCSPI = TEXT("");
  371. if (NULL != szCard)
  372. {
  373. szCardI = szCard;
  374. }
  375. if (NULL != szReader)
  376. {
  377. szReaderI = szReader;
  378. }
  379. if (NULL != szContainer)
  380. {
  381. szContainerI = szContainer;
  382. }
  383. if (NULL != szCSP)
  384. {
  385. szCSPI = szCSP;
  386. }
  387. //
  388. // Build the LogonInfo glob using strings (or empty strings)
  389. //
  390. DWORD cbLi = offsetof(LogonInfo, bBuffer)
  391. + (lstrlen(szCardI) + 1) * sizeof(TCHAR)
  392. + (lstrlen(szReaderI) + 1) * sizeof(TCHAR)
  393. + (lstrlen(szContainerI) + 1) * sizeof(TCHAR)
  394. + (lstrlen(szCSPI) + 1) * sizeof(TCHAR);
  395. LogonInfo* pLI = (LogonInfo*)LocalAlloc(LPTR, cbLi);
  396. if (NULL == pLI)
  397. {
  398. return NULL;
  399. }
  400. pLI->ContextInformation = NULL;
  401. pLI->dwLogonInfoLen = cbLi;
  402. LPTSTR pBuffer = pLI->bBuffer;
  403. pLI->nCardNameOffset = 0;
  404. lstrcpy(pBuffer, szCardI);
  405. pBuffer += (lstrlen(szCardI)+1);
  406. pLI->nReaderNameOffset = (ULONG) (pBuffer-pLI->bBuffer);
  407. lstrcpy(pBuffer, szReaderI);
  408. pBuffer += (lstrlen(szReaderI)+1);
  409. pLI->nContainerNameOffset = (ULONG) (pBuffer-pLI->bBuffer);
  410. lstrcpy(pBuffer, szContainerI);
  411. pBuffer += (lstrlen(szContainerI)+1);
  412. pLI->nCSPNameOffset = (ULONG) (pBuffer-pLI->bBuffer);
  413. lstrcpy(pBuffer, szCSPI);
  414. pBuffer += (lstrlen(szCSPI)+1);
  415. _ASSERTE(cbLi == (DWORD)((LPBYTE)pBuffer - (LPBYTE)pLI));
  416. return (PBYTE)pLI;
  417. }
  418. LPCTSTR WINAPI GetReaderName(PBYTE pbLogonInfo)
  419. {
  420. LogonInfo* pLI = (LogonInfo*)pbLogonInfo;
  421. if (NULL == pLI)
  422. {
  423. return NULL;
  424. }
  425. return &pLI->bBuffer[pLI->nReaderNameOffset];
  426. };
  427. LPCTSTR WINAPI GetCardName(PBYTE pbLogonInfo)
  428. {
  429. LogonInfo* pLI = (LogonInfo*)pbLogonInfo;
  430. if (NULL == pLI)
  431. {
  432. return NULL;
  433. }
  434. return &pLI->bBuffer[pLI->nCardNameOffset];
  435. };
  436. LPCTSTR WINAPI GetContainerName(PBYTE pbLogonInfo)
  437. {
  438. LogonInfo* pLI = (LogonInfo*)pbLogonInfo;
  439. if (NULL == pLI)
  440. {
  441. return NULL;
  442. }
  443. return &pLI->bBuffer[pLI->nContainerNameOffset];
  444. };
  445. LPCTSTR WINAPI GetCSPName(PBYTE pbLogonInfo)
  446. {
  447. LogonInfo* pLI = (LogonInfo*)pbLogonInfo;
  448. if (NULL == pLI)
  449. {
  450. return NULL;
  451. }
  452. return &pLI->bBuffer[pLI->nCSPNameOffset];
  453. };
  454. /*++
  455. BuildCertContext:
  456. Generates a certificate context with (static) keyprov info suitable for
  457. CertStore-based operations.
  458. If the PIN is provided, it is assumed the hProv (if provided) has not had the
  459. PIN parameter set...
  460. Arguments:
  461. hProv -- must be a valid HCRYPTPROV
  462. pucPIN -- may be empty; used to set the PIN for hProv
  463. pbCert -- assumed to be a valid certificate; must not be NULL
  464. dwCertLen
  465. CertificateContext -- pointer to a pointer to the resultant CertContext
  466. Return Value:
  467. NTSTATUS indicating STATUS_SUCCESS or error (see winerror.h or scarderr.h)
  468. Author:
  469. Amanda Matlosz
  470. Note:
  471. --*/
  472. NTSTATUS
  473. BuildCertContext(
  474. IN HCRYPTPROV hProv,
  475. IN PUNICODE_STRING pucPIN,
  476. IN PBYTE pbCert,
  477. IN DWORD dwCertLen,
  478. OUT PCCERT_CONTEXT *CertificateContext
  479. )
  480. {
  481. NTSTATUS lResult = STATUS_SUCCESS;
  482. BOOL fSts = FALSE;
  483. CRYPT_KEY_PROV_INFO KeyProvInfo;
  484. LPSTR szContainerName = NULL;
  485. LPSTR szProvName = NULL;
  486. CUnicodeString wszContainerName, wszProvName;
  487. DWORD cbContainerName, cbProvName;
  488. //
  489. // Check params
  490. //
  491. if ((NULL == hProv) || (NULL == pbCert || 0 == dwCertLen))
  492. {
  493. ASSERT(FALSE);
  494. lResult = STATUS_INVALID_PARAMETER;
  495. goto ErrorExit;
  496. }
  497. //
  498. // Convert the certificate into a Cert Context.
  499. //
  500. *CertificateContext = CertCreateCertificateContext(
  501. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  502. pbCert,
  503. dwCertLen);
  504. if (NULL == *CertificateContext)
  505. {
  506. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  507. goto ErrorExit;
  508. }
  509. //
  510. // Associate cryptprovider w/ the private key property of this cert
  511. //
  512. // ... need the container name
  513. fSts = CryptGetProvParam(
  514. hProv,
  515. PP_CONTAINER,
  516. NULL, // out
  517. &cbContainerName, // in/out
  518. 0);
  519. if (!fSts)
  520. {
  521. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  522. goto ErrorExit;
  523. }
  524. szContainerName = (LPSTR)LocalAlloc(LPTR, cbContainerName);
  525. if (NULL == szContainerName)
  526. {
  527. lResult = STATUS_INSUFFICIENT_RESOURCES;
  528. goto ErrorExit;
  529. }
  530. fSts = CryptGetProvParam(
  531. hProv,
  532. PP_CONTAINER,
  533. (PBYTE)szContainerName, // out
  534. &cbContainerName, // in/out
  535. 0);
  536. if (!fSts)
  537. {
  538. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  539. goto ErrorExit;
  540. }
  541. wszContainerName = szContainerName;
  542. // ... need the provider name
  543. fSts = CryptGetProvParam(
  544. hProv,
  545. PP_NAME,
  546. NULL, // out
  547. &cbProvName, // in/out
  548. 0);
  549. if (!fSts)
  550. {
  551. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  552. goto ErrorExit;
  553. }
  554. szProvName = (LPSTR)LocalAlloc(LPTR, cbProvName);
  555. if (NULL == szProvName)
  556. {
  557. lResult = STATUS_INSUFFICIENT_RESOURCES;
  558. goto ErrorExit;
  559. }
  560. fSts = CryptGetProvParam(
  561. hProv,
  562. PP_NAME,
  563. (PBYTE)szProvName, // out
  564. &cbProvName, // in/out
  565. 0);
  566. if (!fSts)
  567. {
  568. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  569. goto ErrorExit;
  570. }
  571. wszProvName = szProvName;
  572. //
  573. // Set the cert context properties to reflect the prov info
  574. //
  575. KeyProvInfo.pwszContainerName = (LPWSTR)(LPCWSTR)wszContainerName;
  576. KeyProvInfo.pwszProvName = (LPWSTR)(LPCWSTR)wszProvName;
  577. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  578. KeyProvInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
  579. KeyProvInfo.cProvParam = 0;
  580. KeyProvInfo.rgProvParam = NULL;
  581. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  582. KeyProvInfo.dwFlags |= CERT_SET_KEY_CONTEXT_PROP_ID;
  583. fSts = CertSetCertificateContextProperty(
  584. *CertificateContext,
  585. CERT_KEY_PROV_INFO_PROP_ID,
  586. 0,
  587. (void *)&KeyProvInfo);
  588. if (!fSts)
  589. {
  590. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  591. // the cert's been incorrectly created -- scrap it.
  592. CertFreeCertificateContext(*CertificateContext);
  593. *CertificateContext = NULL;
  594. goto ErrorExit;
  595. }
  596. CERT_KEY_CONTEXT certKeyContext;
  597. certKeyContext.cbSize = sizeof(CERT_KEY_CONTEXT);
  598. certKeyContext.hCryptProv = hProv;
  599. certKeyContext.dwKeySpec = KeyProvInfo.dwKeySpec;
  600. fSts = CertSetCertificateContextProperty(
  601. *CertificateContext,
  602. CERT_KEY_CONTEXT_PROP_ID,
  603. 0,
  604. (void *)&certKeyContext);
  605. if (!fSts)
  606. {
  607. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  608. // the cert's been incorrectly created -- scrap it.
  609. CertFreeCertificateContext(*CertificateContext);
  610. *CertificateContext = NULL;
  611. goto ErrorExit;
  612. }
  613. ErrorExit:
  614. if(NULL != szContainerName)
  615. {
  616. LocalFree(szContainerName);
  617. szContainerName = NULL;
  618. }
  619. if(NULL != szProvName)
  620. {
  621. LocalFree(szProvName);
  622. szProvName = NULL;
  623. }
  624. if (!NT_SUCCESS(lResult))
  625. {
  626. lResult = LogEvent(lResult, (DWORD)EVENT_ID_BUILDCC);
  627. }
  628. return lResult;
  629. }
  630. ///////////////////////////////////////////////////////////////////////////////
  631. //
  632. // ScLogon APIs
  633. //
  634. /*++
  635. ScHelperInitializeContext:
  636. Prepares contextual information to be used by LSA while handling this
  637. smart card session.
  638. Arguments:
  639. None.
  640. Return Value:
  641. None
  642. Author:
  643. Richard Ward
  644. Note:
  645. Used by LSA.
  646. --*/
  647. NTSTATUS WINAPI
  648. ScHelperInitializeContext(
  649. IN OUT PBYTE pbLogonInfo,
  650. IN ULONG cbLogonInfo
  651. )
  652. {
  653. ULONG AllowedSize;
  654. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  655. if ((cbLogonInfo < sizeof(ULONG)) ||
  656. (cbLogonInfo != pLI->dwLogonInfoLen))
  657. {
  658. return(STATUS_INVALID_PARAMETER);
  659. }
  660. AllowedSize = (cbLogonInfo - sizeof(LogonInfo) ) / sizeof(TCHAR) + sizeof(DWORD) ;
  661. //
  662. // Verify the other fields of the logon info
  663. //
  664. if ((pLI->nCardNameOffset > pLI->nReaderNameOffset) ||
  665. (pLI->bBuffer[pLI->nReaderNameOffset-1] != TEXT('\0')))
  666. {
  667. return(STATUS_INVALID_PARAMETER);
  668. }
  669. if ((pLI->nReaderNameOffset > pLI->nContainerNameOffset) ||
  670. (pLI->bBuffer[pLI->nContainerNameOffset-1] != TEXT('\0')))
  671. {
  672. return(STATUS_INVALID_PARAMETER);
  673. }
  674. if ((pLI->nContainerNameOffset > pLI->nCSPNameOffset) ||
  675. (pLI->bBuffer[pLI->nCSPNameOffset-1] != TEXT('\0')))
  676. {
  677. return(STATUS_INVALID_PARAMETER);
  678. }
  679. if ((pLI->nCSPNameOffset > AllowedSize) ||
  680. (pLI->bBuffer[AllowedSize-1] != TEXT('\0')))
  681. {
  682. return(STATUS_INVALID_PARAMETER);
  683. }
  684. _ASSERTE(pLI->ContextInformation == NULL);
  685. BOOL fResult = 0;
  686. pLI->ContextInformation = new CSCLogonInit(&fResult);
  687. if (pLI->ContextInformation == NULL)
  688. {
  689. return(STATUS_INSUFFICIENT_RESOURCES);
  690. }
  691. else
  692. {
  693. if (!fResult)
  694. {
  695. delete pLI->ContextInformation;
  696. pLI->ContextInformation = NULL;
  697. return(STATUS_INSUFFICIENT_RESOURCES);
  698. }
  699. }
  700. return(STATUS_SUCCESS);
  701. }
  702. /*++
  703. ScHelperRelease:
  704. Releases contextual information used by LSA while handling this
  705. smart card session.
  706. Arguments:
  707. None.
  708. Return Value:
  709. None
  710. Author:
  711. Richard Ward
  712. Note:
  713. Used by LSA.
  714. --*/
  715. VOID WINAPI
  716. ScHelperRelease(
  717. IN OUT PBYTE pbLogonInfo
  718. )
  719. {
  720. _ASSERTE(NULL != pbLogonInfo);
  721. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  722. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  723. if (LogonInit != NULL)
  724. {
  725. LogonInit->Release();
  726. delete LogonInit;
  727. pLI->ContextInformation = NULL;
  728. }
  729. }
  730. /*++
  731. ScHelperGetCertFromLogonInfo:
  732. Returns a CertificateContext for the cert on the card specified by the
  733. LogonInfo. Creates the cert context by calling BuildCertContext,
  734. which generates a certificate context with (static) keyprov info
  735. suitable for CertStore-based operations.
  736. Arguments:
  737. pucPIN may need the PIN to get a cert off certain SCs
  738. Return Value:
  739. None
  740. Author:
  741. Amanda Matlosz
  742. Note:
  743. Used by LSA.
  744. --*/
  745. NTSTATUS WINAPI
  746. ScHelperGetCertFromLogonInfo(
  747. IN PBYTE pbLogonInfo,
  748. IN PUNICODE_STRING pucPIN,
  749. OUT PCCERT_CONTEXT *CertificateContext
  750. )
  751. {
  752. _ASSERTE(NULL != pbLogonInfo);
  753. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  754. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  755. BOOL fSts;
  756. NTSTATUS lResult = STATUS_SUCCESS;
  757. PCCERT_CONTEXT pCertCtx = NULL;
  758. HCRYPTPROV hProv = NULL;
  759. HCRYPTKEY hKey = NULL;
  760. LPBYTE pbCert = NULL;
  761. DWORD cbCertLen;
  762. //
  763. // Make sure we've got a Crypto Provider up and running.
  764. //
  765. hProv = LogonInit->RelinquishCryptCtx(pLI);
  766. if (NULL == hProv)
  767. {
  768. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  769. goto ErrorExit;
  770. }
  771. //
  772. // Get the key handle.
  773. //
  774. fSts = CryptGetUserKey(
  775. hProv,
  776. AT_KEYEXCHANGE,
  777. &hKey);
  778. if (!fSts)
  779. {
  780. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  781. goto ErrorExit;
  782. }
  783. //
  784. // Upload the certificate.
  785. //
  786. fSts = CryptGetKeyParam(
  787. hKey,
  788. KP_CERTIFICATE,
  789. NULL,
  790. &cbCertLen,
  791. 0);
  792. if (!fSts)
  793. {
  794. DWORD dwGLE = GetLastError();
  795. if (ERROR_MORE_DATA != dwGLE)
  796. {
  797. if (NTE_NOT_FOUND == dwGLE)
  798. {
  799. SetLastError(SCARD_E_NO_SUCH_CERTIFICATE);
  800. }
  801. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  802. goto ErrorExit;
  803. }
  804. }
  805. pbCert = (LPBYTE)LocalAlloc(LPTR, cbCertLen);
  806. if (NULL == pbCert)
  807. {
  808. lResult = STATUS_NO_MEMORY;
  809. goto ErrorExit;
  810. }
  811. fSts = CryptGetKeyParam(
  812. hKey,
  813. KP_CERTIFICATE,
  814. pbCert,
  815. &cbCertLen,
  816. 0);
  817. if (!fSts)
  818. {
  819. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  820. goto ErrorExit;
  821. }
  822. lResult = BuildCertContext(
  823. hProv,
  824. pucPIN,
  825. pbCert,
  826. cbCertLen,
  827. &pCertCtx);
  828. if (NT_SUCCESS(lResult))
  829. {
  830. // The cert context will take care of the crypt context now.
  831. hProv = NULL;
  832. }
  833. //
  834. // Clean up and return.
  835. //
  836. ErrorExit:
  837. *CertificateContext = pCertCtx;
  838. // Do this early so GetLastError is not clobbered
  839. if (!NT_SUCCESS(lResult))
  840. {
  841. lResult = LogEvent(lResult, (DWORD)EVENT_ID_GETCERT);
  842. }
  843. if (NULL != hKey)
  844. {
  845. CryptDestroyKey(hKey);
  846. }
  847. if (NULL != hProv)
  848. {
  849. CryptReleaseContext(hProv, 0);
  850. }
  851. if (NULL != pbCert)
  852. {
  853. LocalFree(pbCert);
  854. }
  855. return lResult;
  856. }
  857. /*++
  858. ScHelperGetProvParam:
  859. This API wraps the CryptGetProvParam routine for use with a smart card.
  860. Arguments:
  861. pucPIN supplies a Unicode string containing the card's PIN.
  862. pbLogonInfo supplies the information required to identify the card, csp,
  863. etc. It cannot be NULL.
  864. The other parameters are identical to CryptGetProvParam
  865. Return Value:
  866. A STATUS_SUCECSS for success, or an error
  867. --*/
  868. NTSTATUS WINAPI
  869. ScHelperGetProvParam(
  870. IN PUNICODE_STRING pucPIN,
  871. IN PBYTE pbLogonInfo,
  872. IN HCRYPTPROV hProv,
  873. DWORD dwParam,
  874. BYTE*pbData,
  875. DWORD *pdwDataLen,
  876. DWORD dwFlags
  877. )
  878. {
  879. LogonInfo *pLI;
  880. CSCLogonInit *LogonInit;
  881. NTSTATUS lResult = STATUS_SUCCESS;
  882. HCRYPTPROV h = NULL;
  883. BOOL fSts;
  884. if (hProv != NULL)
  885. {
  886. h = hProv;
  887. }
  888. else
  889. {
  890. pLI = (LogonInfo *) pbLogonInfo;
  891. LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  892. h = LogonInit->CryptCtx(pLI);
  893. if (NULL == h)
  894. {
  895. return LogEvent(STATUS_SMARTCARD_SUBSYSTEM_FAILURE, (DWORD)EVENT_ID_GETPROVPARAM);
  896. }
  897. }
  898. fSts = CryptGetProvParam(
  899. h,
  900. dwParam,
  901. pbData,
  902. pdwDataLen,
  903. dwFlags
  904. );
  905. if (!fSts)
  906. {
  907. if (GetLastError() == ERROR_NO_MORE_ITEMS)
  908. {
  909. return (STATUS_NO_MORE_ENTRIES);
  910. }
  911. else
  912. {
  913. return LogEvent(STATUS_SMARTCARD_SUBSYSTEM_FAILURE, (DWORD)EVENT_ID_GETPROVPARAM);
  914. }
  915. }
  916. return(STATUS_SUCCESS);
  917. }
  918. /*++
  919. ScHelperVerifyCard:
  920. This API provides an easy way to verify the integrity of the card
  921. identified by pbLogonInfo (ie, that it has the private key associated
  922. w/ the public key contained in the certificate it returned via
  923. ScHelperGetCertFromLogonInfo) and, in so doing, authenticates the user
  924. to the card.
  925. Arguments:
  926. pucPIN supplies a Unicode string containing the card's PIN.
  927. CertificateContext supplies the cert context received via
  928. ScHelperGetCertFromLogonInfo.
  929. hCertStore supplies the handle of a cert store which contains a CTL to
  930. use during certificate verification, or NULL to use the system default
  931. store.
  932. pbLogonInfo supplies the information required to identify the card, csp,
  933. etc. It cannot be NULL.
  934. Return Value:
  935. A 32-bit value indicating whether or not the service completed successfully.
  936. STATUS_SUCCESS is returned on successful completion. Otherwise, the value
  937. represents an error condition.
  938. --*/
  939. NTSTATUS WINAPI
  940. ScHelperVerifyCard(
  941. IN PUNICODE_STRING pucPIN,
  942. IN PCCERT_CONTEXT CertificateContext,
  943. IN HCERTSTORE hCertStore,
  944. IN PBYTE pbLogonInfo
  945. )
  946. {
  947. _ASSERTE(NULL != pbLogonInfo);
  948. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  949. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  950. NTSTATUS lResult = STATUS_SUCCESS;
  951. HCRYPTHASH hHash = NULL;
  952. HCRYPTPROV hProv = NULL;
  953. HCRYPTKEY hKey = NULL;
  954. PBYTE pbBlob = NULL;
  955. ULONG ulBlobLen = 32;
  956. PBYTE pbSignature = NULL;
  957. ULONG ulSigLen = 0;
  958. BOOL fSts;
  959. //
  960. // Make sure we've got a Crypto Provider up and running.
  961. //
  962. hProv = LogonInit->CryptCtx(pLI);
  963. if (NULL == hProv)
  964. {
  965. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  966. goto ErrorExit;
  967. }
  968. //
  969. // Generate a random key blob as the message to sign
  970. //
  971. pbBlob = (LPBYTE)LocalAlloc(LPTR, ulBlobLen);
  972. if (NULL == pbBlob)
  973. {
  974. lResult = STATUS_INSUFFICIENT_RESOURCES;
  975. goto ErrorExit;
  976. }
  977. fSts = CryptGenRandom(hProv, ulBlobLen, pbBlob);
  978. if (!fSts)
  979. {
  980. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  981. goto ErrorExit;
  982. }
  983. //
  984. // The card signs a hash of the message...
  985. //
  986. lResult = ScHelperSignMessage(
  987. pucPIN,
  988. pbLogonInfo,
  989. NULL,
  990. CALG_MD5,
  991. pbBlob,
  992. ulBlobLen,
  993. pbSignature,
  994. &ulSigLen);
  995. if (STATUS_BUFFER_TOO_SMALL != lResult)
  996. {
  997. goto ErrorExit;
  998. }
  999. pbSignature = (LPBYTE)LocalAlloc(LPTR, ulSigLen);
  1000. if (NULL == pbSignature)
  1001. {
  1002. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1003. goto ErrorExit;
  1004. }
  1005. lResult = ScHelperSignMessage(
  1006. pucPIN,
  1007. pbLogonInfo,
  1008. NULL,
  1009. CALG_MD5,
  1010. pbBlob,
  1011. ulBlobLen,
  1012. pbSignature,
  1013. &ulSigLen);
  1014. if (!NT_SUCCESS(lResult))
  1015. {
  1016. goto ErrorExit;
  1017. }
  1018. //
  1019. // Verify the signature is correct
  1020. //
  1021. lResult = ScHelperVerifyMessage(
  1022. pbLogonInfo,
  1023. NULL,
  1024. CertificateContext,
  1025. CALG_MD5,
  1026. pbBlob,
  1027. ulBlobLen,
  1028. pbSignature,
  1029. ulSigLen);
  1030. //
  1031. // Clean up and return.
  1032. //
  1033. ErrorExit:
  1034. // Do this early so GetLastError is not clobbered
  1035. if (!NT_SUCCESS(lResult))
  1036. {
  1037. lResult = LogEvent(lResult, (DWORD)EVENT_ID_VERIFYCARD);
  1038. }
  1039. if (NULL != hKey)
  1040. {
  1041. CryptDestroyKey(hKey);
  1042. }
  1043. if (NULL != pbSignature)
  1044. {
  1045. LocalFree(pbSignature);
  1046. }
  1047. if (NULL != pbBlob)
  1048. {
  1049. LocalFree(pbBlob);
  1050. }
  1051. return lResult;
  1052. }
  1053. NTSTATUS WINAPI
  1054. ScHelperGenRandBits(
  1055. IN PBYTE pbLogonInfo,
  1056. IN OUT ScHelper_RandomCredBits* psc_rcb
  1057. )
  1058. {
  1059. _ASSERTE(NULL != pbLogonInfo);
  1060. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  1061. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  1062. NTSTATUS lResult = STATUS_SUCCESS;
  1063. HCRYPTPROV hProv = NULL;
  1064. BOOL fSts = FALSE;
  1065. //
  1066. // Make sure we've got a Crypto Provider up and running.
  1067. //
  1068. hProv = LogonInit->CryptCtx(pLI);
  1069. if (NULL == hProv)
  1070. {
  1071. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1072. goto ErrorExit;
  1073. }
  1074. memset(psc_rcb, 0, sizeof(*psc_rcb));
  1075. fSts = CryptGenRandom(hProv, 32, psc_rcb->bR1);
  1076. if (fSts)
  1077. {
  1078. fSts = CryptGenRandom(hProv, 32, psc_rcb->bR2);
  1079. }
  1080. if (!fSts)
  1081. {
  1082. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1083. }
  1084. ErrorExit:
  1085. if (!NT_SUCCESS(lResult))
  1086. {
  1087. lResult = LogEvent(lResult, (DWORD)EVENT_ID_GENRANDBITS);
  1088. }
  1089. return lResult;
  1090. }
  1091. /*++
  1092. ScHelperCreateCredKeys:
  1093. This routine (called by ScHelperVerifyCardAndCreds and
  1094. ScHelperEncryptCredentials) munges a R1 and R2 to derive symmetric keys
  1095. for encrypting and decrypting KDC creds, and or genearting an HMAC.
  1096. Arguments:
  1097. pucPIN supplies a Unicode string containing the card's PIN.
  1098. pbLogonInfo supplies the information required to identify the card, csp,
  1099. etc. It cannot be NULL.
  1100. psc_rcb supplies the R1 and R2, previously generated by a call to
  1101. ScHelperGenRandBits.
  1102. phHmacKey recieves the generated HMAC key.
  1103. phRc4Key receives the generated RC4 key.
  1104. Return Value:
  1105. A 32-bit value indicating whether or not the service completed successfully.
  1106. STATUS_SUCCESS is returned on successful completion. Otherwise, the value
  1107. represents an error condition.
  1108. Remarks:
  1109. You may supply a value of NULL to EncryptedData to receive only the
  1110. required size of the EncryptedData buffer.
  1111. Author:
  1112. Amanda Matlosz (amatlosz) 6/23/1999
  1113. --*/
  1114. NTSTATUS WINAPI
  1115. ScHelperCreateCredKeys(
  1116. IN PUNICODE_STRING pucPIN,
  1117. IN PBYTE pbLogonInfo,
  1118. IN ScHelper_RandomCredBits* psc_rcb,
  1119. IN OUT HCRYPTKEY* phHmacKey,
  1120. IN OUT HCRYPTKEY* phRc4Key,
  1121. IN OUT HCRYPTPROV* phProv
  1122. )
  1123. {
  1124. NTSTATUS lResult = STATUS_SUCCESS;
  1125. HCRYPTHASH hHash = NULL;
  1126. HCRYPTPROV hProv = NULL;
  1127. PBYTE pbR1Sig = NULL;
  1128. DWORD dwR1SigLen = 0;
  1129. HCRYPTHASH hKHash = NULL;
  1130. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  1131. CUnicodeString szPin(pucPIN);
  1132. BOOL fSts = FALSE;
  1133. *phProv = NULL;
  1134. // check params
  1135. if (NULL == psc_rcb || NULL == phHmacKey || NULL == phRc4Key)
  1136. {
  1137. return(STATUS_INVALID_PARAMETER);
  1138. }
  1139. // Get hProv for smart card
  1140. if (NULL != pucPIN)
  1141. {
  1142. if (!szPin.Valid())
  1143. {
  1144. return(STATUS_INSUFFICIENT_RESOURCES);
  1145. }
  1146. }
  1147. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  1148. hProv = LogonInit->CryptCtx(pLI);
  1149. if (NULL == hProv)
  1150. {
  1151. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1152. goto ErrorExit;
  1153. }
  1154. // Sign R1 w/ smart card
  1155. fSts = CryptCreateHash(
  1156. hProv,
  1157. CALG_SHA1,
  1158. NULL,
  1159. NULL,
  1160. &hHash);
  1161. if (!fSts)
  1162. {
  1163. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1164. goto ErrorExit;
  1165. }
  1166. fSts = CryptHashData(
  1167. hHash,
  1168. psc_rcb->bR1,
  1169. 32, // TODO: const
  1170. 0);
  1171. if (!fSts)
  1172. {
  1173. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1174. goto ErrorExit;
  1175. }
  1176. //
  1177. // Declare the PIN.
  1178. //
  1179. if (NULL != pucPIN)
  1180. {
  1181. fSts = CryptSetProvParam(
  1182. hProv,
  1183. PP_KEYEXCHANGE_PIN,
  1184. (LPBYTE)((LPCSTR)szPin),
  1185. 0);
  1186. if (!fSts)
  1187. {
  1188. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1189. goto ErrorExit;
  1190. }
  1191. }
  1192. fSts = CryptSignHash(
  1193. hHash,
  1194. AT_KEYEXCHANGE,
  1195. NULL,
  1196. 0,
  1197. NULL,
  1198. &dwR1SigLen);
  1199. // if (fSts || ERROR_MORE_DATA != GetLastError())
  1200. if (0 >= dwR1SigLen)
  1201. {
  1202. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1203. goto ErrorExit;
  1204. }
  1205. pbR1Sig = (LPBYTE)LocalAlloc(LPTR, dwR1SigLen);
  1206. if (NULL == pbR1Sig)
  1207. {
  1208. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1209. goto ErrorExit;
  1210. }
  1211. fSts = CryptSignHash(
  1212. hHash,
  1213. AT_KEYEXCHANGE,
  1214. NULL,
  1215. 0,
  1216. pbR1Sig,
  1217. &dwR1SigLen);
  1218. if (!fSts)
  1219. {
  1220. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1221. goto ErrorExit;
  1222. }
  1223. // TODO: sigR1 is the key to hash R2 with;
  1224. // for now, just hash 'em together; use generic CSP
  1225. fSts = CryptAcquireContext(
  1226. phProv,
  1227. NULL,
  1228. NULL,
  1229. PROV_RSA_FULL,
  1230. CRYPT_VERIFYCONTEXT
  1231. );
  1232. if (!fSts)
  1233. {
  1234. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1235. goto ErrorExit;
  1236. }
  1237. fSts = CryptCreateHash(
  1238. *phProv,
  1239. CALG_SHA1,
  1240. NULL,
  1241. NULL,
  1242. &hKHash
  1243. );
  1244. if (!fSts)
  1245. {
  1246. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1247. goto ErrorExit;
  1248. }
  1249. fSts = CryptHashData(
  1250. hKHash,
  1251. pbR1Sig,
  1252. dwR1SigLen,
  1253. NULL
  1254. );
  1255. if (!fSts)
  1256. {
  1257. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1258. goto ErrorExit;
  1259. }
  1260. fSts = CryptHashData(
  1261. hKHash,
  1262. psc_rcb->bR2,
  1263. 32, // TODO: use a const
  1264. NULL
  1265. );
  1266. if (!fSts)
  1267. {
  1268. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1269. goto ErrorExit;
  1270. }
  1271. // create the rc4 key for the cred&hmac encryption
  1272. fSts = CryptDeriveKey(
  1273. *phProv,
  1274. CALG_RC4, // stream cipher,
  1275. hKHash,
  1276. NULL,
  1277. phRc4Key
  1278. );
  1279. if (!fSts)
  1280. {
  1281. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1282. goto ErrorExit;
  1283. }
  1284. // create the key for the HMAC from the hash of R1&2
  1285. fSts = CryptDeriveKey(
  1286. *phProv,
  1287. CALG_RC2,
  1288. hKHash,
  1289. NULL,
  1290. phHmacKey
  1291. );
  1292. if (!fSts)
  1293. {
  1294. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1295. goto ErrorExit;
  1296. }
  1297. ErrorExit:
  1298. //
  1299. // cleanup
  1300. //
  1301. if (NULL != hHash)
  1302. {
  1303. CryptDestroyHash(hHash);
  1304. }
  1305. if (NULL != hKHash)
  1306. {
  1307. CryptDestroyHash(hKHash);
  1308. }
  1309. if (NULL != pbR1Sig)
  1310. {
  1311. LocalFree(pbR1Sig);
  1312. }
  1313. return lResult;
  1314. }
  1315. NTSTATUS WINAPI
  1316. ScHelperCreateCredHMAC(
  1317. IN HCRYPTPROV hProv,
  1318. IN HCRYPTKEY hHmacKey,
  1319. IN PBYTE CleartextData,
  1320. IN ULONG CleartextDataSize,
  1321. IN OUT PBYTE* ppbHmac,
  1322. IN OUT DWORD* pdwHmacLen
  1323. )
  1324. {
  1325. NTSTATUS lResult = STATUS_SUCCESS;
  1326. HCRYPTHASH hHMAC = NULL;
  1327. HMAC_INFO hmac_info;
  1328. BOOL fSts = FALSE;
  1329. fSts = CryptCreateHash(
  1330. hProv,
  1331. CALG_HMAC,
  1332. hHmacKey,
  1333. NULL,
  1334. &hHMAC
  1335. );
  1336. if (!fSts)
  1337. {
  1338. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1339. goto ErrorExit;
  1340. }
  1341. memset(&hmac_info, 0, sizeof(HMAC_INFO));
  1342. hmac_info.HashAlgid = CALG_SHA1;
  1343. fSts = CryptSetHashParam(
  1344. hHMAC,
  1345. HP_HMAC_INFO,
  1346. (PBYTE)&hmac_info,
  1347. NULL
  1348. );
  1349. if (!fSts)
  1350. {
  1351. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1352. goto ErrorExit;
  1353. }
  1354. fSts = CryptHashData(
  1355. hHMAC,
  1356. CleartextData,
  1357. CleartextDataSize,
  1358. NULL);
  1359. if (!fSts)
  1360. {
  1361. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1362. goto ErrorExit;
  1363. }
  1364. fSts = CryptGetHashParam(
  1365. hHMAC,
  1366. HP_HASHVAL,
  1367. *ppbHmac,
  1368. pdwHmacLen,
  1369. NULL
  1370. );
  1371. if (0 >= *pdwHmacLen)
  1372. {
  1373. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1374. goto ErrorExit;
  1375. }
  1376. *ppbHmac = (PBYTE)LocalAlloc(LPTR, *pdwHmacLen);
  1377. if (NULL == *ppbHmac)
  1378. {
  1379. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1380. goto ErrorExit;
  1381. }
  1382. fSts = CryptGetHashParam(
  1383. hHMAC,
  1384. HP_HASHVAL,
  1385. *ppbHmac,
  1386. pdwHmacLen,
  1387. NULL
  1388. );
  1389. if (!fSts)
  1390. {
  1391. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1392. goto ErrorExit;
  1393. }
  1394. ErrorExit:
  1395. if (NULL != hHMAC)
  1396. {
  1397. CryptDestroyHash(hHMAC);
  1398. }
  1399. return lResult;
  1400. }
  1401. /*++
  1402. ScHelperVerifyCardAndCreds:
  1403. This routine combines Card Verification and Credential Decryption.
  1404. Arguments:
  1405. pucPIN supplies a Unicode string containing the card's PIN.
  1406. CertificateContext supplies the cert context received via
  1407. ScHelperGetCertFromLogonInfo.
  1408. hCertStore supplies the handle of a cert store which contains a CTL to
  1409. use during certificate verification, or NULL to use the system
  1410. default store.
  1411. pbLogonInfo supplies the information required to identify the card, csp,
  1412. etc. It cannot be NULL.
  1413. EncryptedData receives the encrypted credential blob.
  1414. EncryptedDataSize supplies the size of the EncryptedData buffer in
  1415. bytes, and receives the actual size of the encrypted blob.
  1416. CleartextData supplies a credential blob to be encrypted.
  1417. CleartextDataSize supplies the size of the blob, in bytes.
  1418. Return Value:
  1419. A 32-bit value indicating whether or not the service completed successfully.
  1420. STATUS_SUCCESS is returned on successful completion. Otherwise, the value
  1421. represents an error condition.
  1422. Remarks:
  1423. You may supply a value of NULL to EncryptedData to receive only the
  1424. required size of the EncryptedData buffer.
  1425. Author:
  1426. Doug Barlow (dbarlow) 5/24/1999
  1427. --*/
  1428. NTSTATUS WINAPI
  1429. ScHelperVerifyCardAndCreds(
  1430. IN PUNICODE_STRING pucPIN,
  1431. IN PCCERT_CONTEXT CertificateContext,
  1432. IN HCERTSTORE hCertStore,
  1433. IN PBYTE pbLogonInfo,
  1434. IN PBYTE EncryptedData,
  1435. IN ULONG EncryptedDataSize,
  1436. OUT OPTIONAL PBYTE CleartextData,
  1437. OUT PULONG CleartextDataSize
  1438. )
  1439. {
  1440. NTSTATUS lResult = STATUS_SUCCESS;
  1441. // Verify the Card
  1442. lResult = ScHelperVerifyCard(
  1443. pucPIN,
  1444. CertificateContext,
  1445. hCertStore,
  1446. pbLogonInfo);
  1447. // Decrypt the Creds
  1448. if (NT_SUCCESS(lResult))
  1449. {
  1450. lResult = ScHelperDecryptCredentials(
  1451. pucPIN,
  1452. CertificateContext,
  1453. hCertStore,
  1454. pbLogonInfo,
  1455. EncryptedData,
  1456. EncryptedDataSize,
  1457. CleartextData,
  1458. CleartextDataSize);
  1459. }
  1460. return lResult;
  1461. }
  1462. /*++
  1463. ScHelperDecryptCredentials:
  1464. This routine decrypts an encrypted credential blob.
  1465. Arguments:
  1466. pucPIN supplies a Unicode string containing the card's PIN.
  1467. CertificateContext supplies the cert context received via
  1468. ScHelperGetCertFromLogonInfo.
  1469. hCertStore supplies the handle of a cert store which contains a CTL to
  1470. use during certificate verification, or NULL to use the system
  1471. default store.
  1472. EncryptedData supplies the encrypted credential blob.
  1473. EncryptedDataSize supplies the length of the encrypted credential blob,
  1474. in bytes.
  1475. CleartextData receives the decrypted credential blob.
  1476. CleartextDataSize supplies the length of the CleartextData buffer, and
  1477. receives the actual length of returned decrypted credential blob.
  1478. Return Value:
  1479. A 32-bit value indicating whether or not the service completed successfully.
  1480. STATUS_SUCCESS is returned on successful completion. Otherwise, the value
  1481. represents an error condition.
  1482. Remarks:
  1483. You may supply a value of NULL to CleartextData to receive only the
  1484. required size of the buffer in CleartextDataSize.
  1485. Author:
  1486. Doug Barlow (dbarlow) 5/24/1999
  1487. --*/
  1488. NTSTATUS WINAPI
  1489. ScHelperDecryptCredentials(
  1490. IN PUNICODE_STRING pucPIN,
  1491. IN PCCERT_CONTEXT CertificateContext,
  1492. IN HCERTSTORE hCertStore,
  1493. IN PBYTE pbLogonInfo,
  1494. IN PBYTE EncryptedData,
  1495. IN ULONG EncryptedDataSize,
  1496. OUT OPTIONAL PBYTE CleartextData,
  1497. OUT PULONG CleartextDataSize)
  1498. {
  1499. NTSTATUS lResult = STATUS_SUCCESS;
  1500. PBYTE pbCredBlob = NULL;
  1501. DWORD dwCredBlobSize = 0;
  1502. PBYTE pbHmac = NULL; // the HMAC stored with the cred blob
  1503. DWORD dwHmacSize = NULL; // size of HMAC stored with cred blob
  1504. PBYTE pbNewHmac = NULL; // HMAC generated from cred blob for verify
  1505. DWORD dwNewHmacSize = 0; // size of gen'd HMAC
  1506. PBYTE pb = NULL;
  1507. DWORD dw = 0;
  1508. PBYTE pbPlainCred = NULL;
  1509. DWORD dwPlainCredSize = 0;
  1510. HCRYPTKEY hHmacKey = NULL;
  1511. HCRYPTKEY hRc4Key = NULL;
  1512. HCRYPTPROV hGenProv = NULL;
  1513. BOOL fSts = FALSE;
  1514. // pull the SCH_RCB out of the EncryptedData blob
  1515. ScHelper_RandomCredBits* psch_rcb = (ScHelper_RandomCredBits*)EncryptedData;
  1516. // and build a private copy of the blob itself
  1517. dwCredBlobSize = EncryptedDataSize - sizeof(ScHelper_RandomCredBits);
  1518. pbCredBlob = (PBYTE)LocalAlloc(LPTR, dwCredBlobSize);
  1519. if (NULL == pbCredBlob)
  1520. {
  1521. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1522. goto ErrorExit;
  1523. }
  1524. pb = EncryptedData + sizeof(ScHelper_RandomCredBits);
  1525. CopyMemory(pbCredBlob, pb, dwCredBlobSize);
  1526. //
  1527. // Fetch the keys we need to decrypt & verify the cred blob
  1528. //
  1529. lResult = ScHelperCreateCredKeys(
  1530. pucPIN,
  1531. pbLogonInfo,
  1532. psch_rcb,
  1533. &hHmacKey,
  1534. &hRc4Key,
  1535. &hGenProv
  1536. );
  1537. if (!NT_SUCCESS(lResult))
  1538. {
  1539. goto ErrorExit;
  1540. }
  1541. //
  1542. // Decrypt the cred blob
  1543. //
  1544. fSts = CryptDecrypt(
  1545. hRc4Key,
  1546. NULL,
  1547. TRUE,
  1548. NULL,
  1549. pbCredBlob,
  1550. &dwCredBlobSize);
  1551. if (!fSts)
  1552. {
  1553. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1554. goto ErrorExit;
  1555. }
  1556. //
  1557. // pull the HMAC out & verify it
  1558. //
  1559. dwHmacSize = (DWORD)*pbCredBlob;
  1560. pbHmac = pbCredBlob + sizeof(DWORD);
  1561. pbPlainCred = pbCredBlob + dwHmacSize + sizeof(DWORD);
  1562. dwPlainCredSize = dwCredBlobSize - dwHmacSize - sizeof(DWORD);
  1563. lResult = ScHelperCreateCredHMAC(
  1564. hGenProv,
  1565. hHmacKey,
  1566. pbPlainCred,
  1567. dwPlainCredSize,
  1568. &pbNewHmac,
  1569. &dwNewHmacSize);
  1570. if (!NT_SUCCESS(lResult))
  1571. {
  1572. goto ErrorExit;
  1573. }
  1574. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1575. if (dwNewHmacSize == dwHmacSize)
  1576. {
  1577. for (dw = 0;
  1578. (dw < dwNewHmacSize) && ((BYTE)*(pbHmac+dw)==(BYTE)*(pbNewHmac+dw));
  1579. dw++);
  1580. if (dwNewHmacSize == dw)
  1581. {
  1582. // verification succeeded!
  1583. lResult = STATUS_SUCCESS;
  1584. }
  1585. }
  1586. if (!NT_SUCCESS(lResult))
  1587. {
  1588. goto ErrorExit;
  1589. }
  1590. //
  1591. // return the decrypted blob or just its length, as necessary
  1592. //
  1593. if ((NULL != CleartextData) && (0 < *CleartextDataSize))
  1594. {
  1595. if (*CleartextDataSize >= dwPlainCredSize)
  1596. {
  1597. CopyMemory(CleartextData, pbPlainCred, dwPlainCredSize);
  1598. }
  1599. else
  1600. lResult = STATUS_BUFFER_TOO_SMALL;
  1601. }
  1602. else
  1603. {
  1604. lResult = STATUS_BUFFER_TOO_SMALL;
  1605. }
  1606. *CleartextDataSize = dwPlainCredSize;
  1607. //
  1608. // Cleanup and return
  1609. //
  1610. ErrorExit:
  1611. if (NULL != pbNewHmac)
  1612. {
  1613. LocalFree(pbNewHmac);
  1614. }
  1615. if (NULL != hHmacKey)
  1616. {
  1617. CryptDestroyKey(hHmacKey);
  1618. }
  1619. if (NULL != hRc4Key)
  1620. {
  1621. CryptDestroyKey(hRc4Key);
  1622. }
  1623. if (NULL != hGenProv)
  1624. {
  1625. CryptReleaseContext(hGenProv, NULL);
  1626. }
  1627. return lResult;
  1628. }
  1629. /*++
  1630. ScHelperEncryptCredentials:
  1631. This routine encrypts a credential blob.
  1632. Arguments:
  1633. pucPIN supplies a Unicode string containing the card's PIN.
  1634. CertificateContext supplies the cert context received via
  1635. ScHelperGetCertFromLogonInfo.
  1636. hCertStore supplies the handle of a cert store which contains a CTL to
  1637. use during certificate verification, or NULL to use the system
  1638. default store.
  1639. CleartextData supplies the cleartext credential blob.
  1640. CleartextDataSize supplies the length of the cleartext credential blob,
  1641. in bytes.
  1642. EncryptedData receives the encrypted credential blob.
  1643. EncryptedDataSize supplies the length of the EncryptedData buffer, and
  1644. receives the actual length of returned encrypted credential blob.
  1645. Return Value:
  1646. A 32-bit value indicating whether or not the service completed successfully.
  1647. STATUS_SUCCESS is returned on successful completion. Otherwise, the value
  1648. represents an error condition.
  1649. Remarks:
  1650. You may supply a value of NULL to EncryptedData to receive only the
  1651. required size of the buffer in EncryptedDataSize.
  1652. Author:
  1653. Doug Barlow (dbarlow) 5/24/1999
  1654. --*/
  1655. NTSTATUS WINAPI
  1656. ScHelperEncryptCredentials(
  1657. IN PUNICODE_STRING pucPIN,
  1658. IN PCCERT_CONTEXT CertificateContext,
  1659. IN HCERTSTORE hCertStore,
  1660. IN ScHelper_RandomCredBits* psch_rcb,
  1661. IN PBYTE pbLogonInfo,
  1662. IN PBYTE CleartextData,
  1663. IN ULONG CleartextDataSize,
  1664. OUT OPTIONAL PBYTE EncryptedData,
  1665. OUT PULONG EncryptedDataSize)
  1666. {
  1667. NTSTATUS lResult = STATUS_SUCCESS;
  1668. HCRYPTPROV hProv = NULL;
  1669. BOOL fSts;
  1670. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  1671. ULONG SignedEncryptedCredSize = 0;
  1672. PBYTE SignedEncryptedCred = NULL; // encrypted cred&sig, !including R1+R2
  1673. HCRYPTKEY hHmacKey = NULL;
  1674. HCRYPTKEY hRc4Key = NULL;
  1675. PBYTE pbHmac = NULL;
  1676. DWORD dwHmacLen = 0;
  1677. PBYTE pbCredsAndHmac = NULL;
  1678. DWORD dwCredsAndHmacLen = 0;
  1679. DWORD dwEncryptedCredSize = 0;
  1680. PBYTE pb = NULL;
  1681. // parameter checking?
  1682. //
  1683. // do stuff to determine size required for SignedEncryptedCred
  1684. //
  1685. lResult = ScHelperCreateCredKeys(
  1686. pucPIN,
  1687. pbLogonInfo,
  1688. psch_rcb,
  1689. &hHmacKey,
  1690. &hRc4Key,
  1691. &hProv
  1692. );
  1693. if (!NT_SUCCESS(lResult))
  1694. {
  1695. goto ErrorExit;
  1696. }
  1697. // HMAC creds
  1698. lResult = ScHelperCreateCredHMAC(
  1699. hProv,
  1700. hHmacKey,
  1701. CleartextData,
  1702. CleartextDataSize,
  1703. &pbHmac,
  1704. &dwHmacLen);
  1705. if (!NT_SUCCESS(lResult))
  1706. {
  1707. goto ErrorExit;
  1708. }
  1709. // make a buffer with creds and HMAC
  1710. pbCredsAndHmac = NULL;
  1711. dwCredsAndHmacLen = dwHmacLen + CleartextDataSize + sizeof(DWORD);
  1712. pbCredsAndHmac = (PBYTE)LocalAlloc(LPTR, dwCredsAndHmacLen);
  1713. if (NULL == pbCredsAndHmac)
  1714. {
  1715. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1716. goto ErrorExit;
  1717. }
  1718. pb = pbCredsAndHmac;
  1719. CopyMemory(pb, &dwHmacLen, sizeof(DWORD));
  1720. pb += sizeof(DWORD);
  1721. CopyMemory(pb, pbHmac, dwHmacLen);
  1722. pb += dwHmacLen;
  1723. CopyMemory(pb, CleartextData, CleartextDataSize);
  1724. // Encrypt creds+HMAC
  1725. dwEncryptedCredSize = dwCredsAndHmacLen;
  1726. // After CryptEncrypt, dwCredsAndHmacLen describes the length of the data
  1727. // to encrypt and dwEncryptedCredSize describes the req'd buffer length
  1728. // TODO: VERIFY THE HANDLING OF dwEncryptedCredSize and dwCresAndHmacLen
  1729. fSts = CryptEncrypt(
  1730. hRc4Key,
  1731. NULL,
  1732. TRUE,
  1733. NULL,
  1734. pbCredsAndHmac,
  1735. &dwEncryptedCredSize,
  1736. dwCredsAndHmacLen
  1737. );
  1738. if (!fSts)
  1739. {
  1740. if (GetLastError() != ERROR_MORE_DATA)
  1741. {
  1742. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1743. goto ErrorExit;
  1744. }
  1745. }
  1746. //
  1747. // Create the final blob for return, or inform user of size, as necessary
  1748. //
  1749. if ((NULL != EncryptedData) && (0 < *EncryptedDataSize))
  1750. {
  1751. if (*EncryptedDataSize >= dwEncryptedCredSize + sizeof(ScHelper_RandomCredBits))
  1752. {
  1753. // the user gave us enough space for the whole thing.
  1754. // if the previous CryptEncrypt failed with ERROR_MORE_DATA
  1755. // we can now do something about it...
  1756. if (!fSts)
  1757. {
  1758. // resize pbCredsAndHmac
  1759. LocalFree(pbCredsAndHmac);
  1760. pbCredsAndHmac = (PBYTE)LocalAlloc(LPTR, dwCredsAndHmacLen);
  1761. if (NULL == pbCredsAndHmac)
  1762. {
  1763. lResult = STATUS_INSUFFICIENT_RESOURCES;
  1764. goto ErrorExit;
  1765. }
  1766. // reset pbCredsAndHmac
  1767. pb = pbCredsAndHmac;
  1768. CopyMemory(pb, &dwHmacLen, sizeof(DWORD));
  1769. pb += sizeof(DWORD);
  1770. CopyMemory(pb, pbHmac, dwHmacLen);
  1771. pb += dwHmacLen;
  1772. CopyMemory(pb, CleartextData, CleartextDataSize);
  1773. // re-encrypt CredsAndHmac
  1774. fSts = CryptEncrypt(
  1775. hRc4Key,
  1776. NULL,
  1777. TRUE,
  1778. NULL,
  1779. pbCredsAndHmac,
  1780. &dwCredsAndHmacLen, // length of data
  1781. dwEncryptedCredSize // length of buffer
  1782. );
  1783. if (!fSts)
  1784. {
  1785. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1786. goto ErrorExit;
  1787. }
  1788. }
  1789. pb = EncryptedData;
  1790. CopyMemory(pb, (PBYTE)psch_rcb, sizeof(ScHelper_RandomCredBits));
  1791. pb += sizeof(ScHelper_RandomCredBits);
  1792. CopyMemory(pb, pbCredsAndHmac, dwCredsAndHmacLen);
  1793. }
  1794. else
  1795. {
  1796. lResult = STATUS_BUFFER_TOO_SMALL;
  1797. }
  1798. }
  1799. else
  1800. {
  1801. lResult = STATUS_BUFFER_TOO_SMALL;
  1802. }
  1803. *EncryptedDataSize = dwEncryptedCredSize + sizeof(ScHelper_RandomCredBits);
  1804. ErrorExit:
  1805. // clean up!
  1806. if (NULL != pbCredsAndHmac)
  1807. {
  1808. LocalFree(pbCredsAndHmac);
  1809. }
  1810. if (NULL != pbHmac)
  1811. {
  1812. LocalFree(pbHmac);
  1813. }
  1814. if (NULL != hRc4Key)
  1815. {
  1816. CryptDestroyKey(hRc4Key);
  1817. }
  1818. if (NULL != hHmacKey)
  1819. {
  1820. CryptDestroyKey(hHmacKey);
  1821. }
  1822. if (NULL != hProv)
  1823. {
  1824. CryptReleaseContext(hProv, NULL);
  1825. }
  1826. return lResult;
  1827. }
  1828. /*++
  1829. ScHelperSignMessage:
  1830. ScHelperSignMessage() needs the logoninfo and PIN in order to find the card
  1831. that will do the signing...
  1832. Arguments:
  1833. pucPIN may need the PIN to get a cert off certain SCs
  1834. Return Value:
  1835. "success" or "failure"
  1836. Author:
  1837. Amanda Matlosz
  1838. Note:
  1839. Used by LSA.
  1840. --*/
  1841. NTSTATUS WINAPI
  1842. ScHelperSignMessage(
  1843. IN PUNICODE_STRING pucPIN,
  1844. IN OPTIONAL PBYTE pbLogonInfo,
  1845. IN OPTIONAL HCRYPTPROV Provider,
  1846. IN ULONG Algorithm,
  1847. IN PBYTE Buffer,
  1848. IN ULONG BufferLength,
  1849. OUT PBYTE Signature,
  1850. OUT PULONG SignatureLength
  1851. )
  1852. {
  1853. NTSTATUS lResult = STATUS_SUCCESS;
  1854. HCRYPTHASH hHash = NULL;
  1855. HCRYPTPROV hProv = NULL;
  1856. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  1857. CUnicodeString szPin(pucPIN);
  1858. BOOL fSts;
  1859. //
  1860. // Make sure we've got a Crypto Provider up and running.
  1861. //
  1862. if (ARGUMENT_PRESENT(Provider))
  1863. {
  1864. hProv = Provider;
  1865. }
  1866. else
  1867. {
  1868. if (NULL != pucPIN)
  1869. {
  1870. if (!szPin.Valid())
  1871. {
  1872. return(STATUS_INSUFFICIENT_RESOURCES);
  1873. }
  1874. }
  1875. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  1876. hProv = LogonInit->CryptCtx(pLI);
  1877. if (NULL == hProv)
  1878. {
  1879. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1880. goto ErrorExit;
  1881. }
  1882. }
  1883. //
  1884. // We'll need a hash handle, too.
  1885. //
  1886. fSts = CryptCreateHash(
  1887. hProv,
  1888. Algorithm,
  1889. NULL, // HCRYPTKEY (used for keyed algs, like block ciphers
  1890. 0, // reserved for future use
  1891. &hHash);
  1892. if (!fSts)
  1893. {
  1894. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1895. goto ErrorExit;
  1896. }
  1897. //
  1898. // Hash the input data.
  1899. //
  1900. fSts = CryptHashData(
  1901. hHash,
  1902. Buffer,
  1903. BufferLength,
  1904. 0);
  1905. if (!fSts)
  1906. {
  1907. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1908. goto ErrorExit;
  1909. }
  1910. if (!ARGUMENT_PRESENT(Provider))
  1911. {
  1912. //
  1913. // Declare the PIN.
  1914. //
  1915. if (NULL != pucPIN)
  1916. {
  1917. fSts = CryptSetProvParam(
  1918. hProv,
  1919. PP_KEYEXCHANGE_PIN,
  1920. (LPBYTE)((LPCSTR)szPin),
  1921. 0);
  1922. if (!fSts)
  1923. {
  1924. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1925. goto ErrorExit;
  1926. }
  1927. }
  1928. }
  1929. //
  1930. // OK, sign it with the exchange key from the smart card or the supplied signature key. ????
  1931. //
  1932. fSts = CryptSignHash(
  1933. hHash,
  1934. AT_KEYEXCHANGE,
  1935. NULL,
  1936. 0,
  1937. Signature,
  1938. SignatureLength);
  1939. if (!fSts)
  1940. {
  1941. if (GetLastError() == ERROR_MORE_DATA)
  1942. {
  1943. lResult = STATUS_BUFFER_TOO_SMALL;
  1944. }
  1945. else
  1946. {
  1947. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  1948. }
  1949. }
  1950. //
  1951. // All done, clean up and return.
  1952. //
  1953. ErrorExit:
  1954. // Do this early so GetLastError is not clobbered
  1955. if (!NT_SUCCESS(lResult))
  1956. {
  1957. lResult = LogEvent(
  1958. lResult,
  1959. (DWORD)((ARGUMENT_PRESENT(Provider))?EVENT_ID_SIGNMSG_NOSC:EVENT_ID_SIGNMSG)
  1960. );
  1961. }
  1962. if (NULL != hHash)
  1963. {
  1964. CryptDestroyHash(hHash);
  1965. }
  1966. return lResult;
  1967. }
  1968. /*++
  1969. ScHelperVerifyMessage:
  1970. // ScHelperVerifyMessage() returns STATUS_SUCCESS if the signature provided is
  1971. // the hash of the buffer encrypted by the owner of the cert.
  1972. Arguments:
  1973. pucPIN may need the PIN to get a cert off certain SCs
  1974. Return Value:
  1975. "success" or "failure"
  1976. Author:
  1977. Amanda Matlosz
  1978. Note:
  1979. Used by LSA.
  1980. --*/
  1981. NTSTATUS WINAPI
  1982. ScHelperVerifyMessage(
  1983. IN OPTIONAL PBYTE pbLogonInfo,
  1984. IN OPTIONAL HCRYPTPROV Provider,
  1985. IN PCCERT_CONTEXT CertificateContext,
  1986. IN ULONG Algorithm,
  1987. IN PBYTE Buffer,
  1988. IN ULONG BufferLength,
  1989. IN PBYTE Signature,
  1990. IN ULONG SignatureLength
  1991. )
  1992. {
  1993. HCRYPTPROV hProv = NULL;
  1994. HCRYPTKEY hKey = NULL;
  1995. HCRYPTHASH hHash = NULL;
  1996. PCERT_PUBLIC_KEY_INFO pInfo = NULL;
  1997. BOOL fSts;
  1998. NTSTATUS lResult = STATUS_SUCCESS;
  1999. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  2000. //
  2001. // Make sure we've got a Crypto Provider up and running.
  2002. //
  2003. if (ARGUMENT_PRESENT(Provider))
  2004. {
  2005. hProv = Provider;
  2006. }
  2007. else
  2008. {
  2009. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  2010. hProv = LogonInit->CryptCtx(pLI);
  2011. if (NULL == hProv)
  2012. {
  2013. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2014. goto ErrorExit;
  2015. }
  2016. }
  2017. //
  2018. // Convert the certificate handle into a Public Key handle.
  2019. //
  2020. fSts = CryptImportPublicKeyInfo(
  2021. hProv,
  2022. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2023. &CertificateContext->pCertInfo->SubjectPublicKeyInfo,
  2024. &hKey);
  2025. if (!fSts)
  2026. {
  2027. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2028. goto ErrorExit;
  2029. }
  2030. //
  2031. // We'll need a hash handle, too.
  2032. //
  2033. fSts = CryptCreateHash(
  2034. hProv,
  2035. Algorithm,
  2036. NULL, // HCRYPTKEY (used for keyed algs, like block ciphers
  2037. 0, // reserved for future use
  2038. &hHash);
  2039. if (!fSts)
  2040. {
  2041. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2042. goto ErrorExit;
  2043. }
  2044. //
  2045. // Hash the input data.
  2046. //
  2047. fSts = CryptHashData(
  2048. hHash,
  2049. Buffer,
  2050. BufferLength,
  2051. 0);
  2052. if (!fSts)
  2053. {
  2054. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2055. goto ErrorExit;
  2056. }
  2057. //
  2058. // So is this signature any good?
  2059. //
  2060. fSts = CryptVerifySignature(
  2061. hHash,
  2062. Signature,
  2063. SignatureLength,
  2064. hKey,
  2065. NULL,
  2066. 0);
  2067. if (!fSts)
  2068. {
  2069. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2070. goto ErrorExit;
  2071. }
  2072. //
  2073. // All done, clean up and return.
  2074. //
  2075. ErrorExit:
  2076. // Do this early so GetLastError is not clobbered
  2077. if (!NT_SUCCESS(lResult))
  2078. {
  2079. lResult = LogEvent(
  2080. lResult,
  2081. (DWORD)((ARGUMENT_PRESENT(Provider))?EVENT_ID_VERIFYMSG_NOSC:EVENT_ID_VERIFYMSG)
  2082. );
  2083. }
  2084. if (NULL != hHash)
  2085. {
  2086. CryptDestroyHash(hHash);
  2087. }
  2088. if (NULL != hKey)
  2089. {
  2090. CryptDestroyKey(hKey);
  2091. }
  2092. return lResult;
  2093. }
  2094. /*++
  2095. ScHelperSignPkcsMessage:
  2096. ScHelperSignMessage() needs the logoninfo and PIN in order to find the card
  2097. that will do the signing...
  2098. Arguments:
  2099. pucPIN may need the PIN to get a cert off certain SCs
  2100. Return Value:
  2101. "success" or "failure"
  2102. Author:
  2103. Amanda Matlosz
  2104. Note:
  2105. Used by LSA.
  2106. --*/
  2107. NTSTATUS WINAPI
  2108. ScHelperSignPkcsMessage(
  2109. IN OPTIONAL PUNICODE_STRING pucPIN,
  2110. IN OPTIONAL PBYTE pbLogonInfo,
  2111. IN OPTIONAL HCRYPTPROV Provider,
  2112. IN PCCERT_CONTEXT Certificate,
  2113. IN PCRYPT_ALGORITHM_IDENTIFIER Algorithm,
  2114. IN DWORD dwSignMessageFlags,
  2115. IN PBYTE Buffer,
  2116. IN ULONG BufferLength,
  2117. OUT OPTIONAL PBYTE SignedBuffer,
  2118. OUT OPTIONAL PULONG SignedBufferLength
  2119. )
  2120. {
  2121. NTSTATUS lResult = STATUS_SUCCESS;
  2122. HCRYPTPROV hProv = NULL;
  2123. BOOL fSts;
  2124. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  2125. CRYPT_SIGN_MESSAGE_PARA Parameter = {0};
  2126. CUnicodeString szPin(pucPIN);
  2127. const BYTE * BufferArray = Buffer;
  2128. if (NULL != pucPIN)
  2129. {
  2130. if (!szPin.Valid())
  2131. {
  2132. return(STATUS_INSUFFICIENT_RESOURCES);
  2133. }
  2134. }
  2135. //
  2136. // Make sure we've got a Crypto Provider up and running.
  2137. //
  2138. if (ARGUMENT_PRESENT(Provider))
  2139. {
  2140. hProv = Provider;
  2141. }
  2142. else
  2143. {
  2144. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  2145. hProv = LogonInit->CryptCtx(pLI);
  2146. if (NULL == hProv)
  2147. {
  2148. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2149. goto ErrorExit;
  2150. }
  2151. //
  2152. // Declare the PIN.
  2153. //
  2154. if (NULL != pucPIN)
  2155. {
  2156. fSts = CryptSetProvParam(
  2157. hProv,
  2158. PP_KEYEXCHANGE_PIN,
  2159. (LPBYTE)((LPCSTR)szPin),
  2160. 0);
  2161. if (!fSts)
  2162. {
  2163. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2164. goto ErrorExit;
  2165. }
  2166. }
  2167. }
  2168. //
  2169. // Sign the message
  2170. //
  2171. Parameter.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
  2172. Parameter.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
  2173. Parameter.pSigningCert = Certificate;
  2174. Parameter.HashAlgorithm = *Algorithm;
  2175. Parameter.cMsgCert = 1;
  2176. Parameter.rgpMsgCert = &Certificate;
  2177. Parameter.dwFlags = dwSignMessageFlags;
  2178. fSts = CryptSignMessage(
  2179. &Parameter,
  2180. FALSE, // no detached signature
  2181. 1, // one buffer to sign
  2182. &BufferArray,
  2183. &BufferLength,
  2184. SignedBuffer,
  2185. SignedBufferLength);
  2186. if (!fSts)
  2187. {
  2188. switch (GetLastError())
  2189. {
  2190. case ERROR_MORE_DATA:
  2191. lResult = STATUS_BUFFER_TOO_SMALL;
  2192. break;
  2193. case NTE_SILENT_CONTEXT:
  2194. lResult = STATUS_SMARTCARD_SILENT_CONTEXT;
  2195. break;
  2196. default:
  2197. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2198. }
  2199. goto ErrorExit;
  2200. }
  2201. //
  2202. // All done, clean up and return.
  2203. //
  2204. ErrorExit:
  2205. if (!NT_SUCCESS(lResult))
  2206. {
  2207. lResult = LogEvent(lResult, (DWORD)EVENT_ID_SIGNMSG);
  2208. }
  2209. return lResult;
  2210. }
  2211. /*++
  2212. ScHelperVerifyPkcsMessage:
  2213. // ScHelperVerifyMessage() returns STATUS_SUCCESS if the signature provided is
  2214. // the hash of the buffer encrypted by the owner of the cert.
  2215. Arguments:
  2216. pucPIN may need the PIN to get a cert off certain SCs
  2217. Return Value:
  2218. "success" or "failure"
  2219. Author:
  2220. Amanda Matlosz
  2221. Note:
  2222. Used by LSA.
  2223. --*/
  2224. NTSTATUS WINAPI
  2225. ScHelperVerifyPkcsMessage(
  2226. IN OPTIONAL PBYTE pbLogonInfo,
  2227. IN OPTIONAL HCRYPTPROV Provider,
  2228. IN PBYTE Buffer,
  2229. IN ULONG BufferLength,
  2230. OUT OPTIONAL PBYTE DecodedBuffer,
  2231. OUT OPTIONAL PULONG DecodedBufferLength,
  2232. OUT OPTIONAL PCCERT_CONTEXT * CertificateContext
  2233. )
  2234. {
  2235. CRYPT_VERIFY_MESSAGE_PARA Parameter = {0};
  2236. BOOL fSts;
  2237. NTSTATUS lResult = STATUS_SUCCESS;
  2238. Parameter.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
  2239. Parameter.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
  2240. Parameter.hCryptProv = NULL;
  2241. //
  2242. // Indicate that we want to get the certificate from the message
  2243. // cert store.
  2244. //
  2245. Parameter.pfnGetSignerCertificate = NULL;
  2246. fSts = CryptVerifyMessageSignature(
  2247. &Parameter,
  2248. 0, // only check first signer
  2249. Buffer,
  2250. BufferLength,
  2251. DecodedBuffer,
  2252. DecodedBufferLength,
  2253. CertificateContext
  2254. );
  2255. if (!fSts)
  2256. {
  2257. if (GetLastError() == ERROR_MORE_DATA)
  2258. {
  2259. lResult = STATUS_BUFFER_TOO_SMALL;
  2260. }
  2261. else
  2262. {
  2263. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2264. }
  2265. goto ErrorExit;
  2266. }
  2267. //
  2268. // All done, clean up and return.
  2269. //
  2270. ErrorExit:
  2271. if (!NT_SUCCESS(lResult))
  2272. {
  2273. lResult = LogEvent(lResult, (DWORD)EVENT_ID_VERIFYMSG);
  2274. }
  2275. return lResult;
  2276. }
  2277. /*++
  2278. ScHelperEncryptMessage:
  2279. Encrypts a message with the public key associated w/ the provided
  2280. certificate. The resultant encoding is PKCS-7 compliant.
  2281. Arguments:
  2282. pucPIN may need the PIN to get a cert off certain SCs
  2283. Return Value:
  2284. "success" or "failure"
  2285. Author:
  2286. Amanda Matlosz (AMatlosz) 1-06-98
  2287. Note:
  2288. Either pbLogonInfo or Provided must be set; if both are set,
  2289. Provider is used.
  2290. Algorithm expects a CRYPT_ALGORITHM_IDENTIFIER cai;
  2291. If there are no parameters to the alg, cai.Parameters.cbData *must* be 0;
  2292. CALG_RC4, no parameters:
  2293. cai.pszObjId = szOID_RSA_RC4;
  2294. cai.Parameters.cbData = 0;
  2295. Used by LSA.
  2296. --*/
  2297. NTSTATUS WINAPI
  2298. ScHelperEncryptMessage(
  2299. IN OPTIONAL PBYTE pbLogonInfo,
  2300. IN OPTIONAL HCRYPTPROV Provider,
  2301. IN PCCERT_CONTEXT CertificateContext,
  2302. IN PCRYPT_ALGORITHM_IDENTIFIER Algorithm,
  2303. IN PBYTE Buffer, // The data to encrypt
  2304. IN ULONG BufferLength, // The length of that data
  2305. OUT PBYTE CipherText, // Receives the formatted CipherText
  2306. IN PULONG pCipherLength // Supplies size of CipherText buffer
  2307. ) // Receives length of actual CipherText
  2308. {
  2309. NTSTATUS lResult = STATUS_SUCCESS;
  2310. HCRYPTPROV hProv = NULL;
  2311. BOOL fSts;
  2312. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  2313. CRYPT_ENCRYPT_MESSAGE_PARA EncryptPara;
  2314. DWORD cbEncryptParaSize = 0;
  2315. //
  2316. // Make sure we've got a Crypto Provider up and running.
  2317. //
  2318. if (ARGUMENT_PRESENT(Provider))
  2319. {
  2320. hProv = Provider;
  2321. }
  2322. else
  2323. {
  2324. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  2325. hProv = LogonInit->CryptCtx(pLI);
  2326. if (NULL == hProv)
  2327. {
  2328. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2329. goto ErrorExit;
  2330. }
  2331. }
  2332. //
  2333. // Encrypt the message
  2334. //
  2335. cbEncryptParaSize = sizeof(EncryptPara);
  2336. memset(&EncryptPara, 0, cbEncryptParaSize);
  2337. EncryptPara.cbSize = cbEncryptParaSize;
  2338. EncryptPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
  2339. EncryptPara.hCryptProv = hProv;
  2340. EncryptPara.ContentEncryptionAlgorithm = *Algorithm;
  2341. fSts = CryptEncryptMessage(
  2342. &EncryptPara,
  2343. 1,
  2344. &CertificateContext,
  2345. Buffer,
  2346. BufferLength,
  2347. CipherText,
  2348. pCipherLength);
  2349. if (!fSts)
  2350. {
  2351. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2352. goto ErrorExit;
  2353. }
  2354. ErrorExit:
  2355. if (!NT_SUCCESS(lResult))
  2356. {
  2357. lResult = LogEvent(
  2358. lResult,
  2359. (DWORD)((ARGUMENT_PRESENT(Provider))?EVENT_ID_ENCMSG_NOSC:EVENT_ID_ENCMSG)
  2360. );
  2361. }
  2362. return lResult;
  2363. }
  2364. /*++
  2365. ScHelperDecryptMessage :
  2366. Deciphers a PKCS-7 encoded message with the private key associated
  2367. w/ the provided certificate.
  2368. Arguments:
  2369. Either pbLogonInfo or Provider must be set; if both are set,
  2370. Provider is used.
  2371. Return Value:
  2372. "success" or "failure"
  2373. Author:
  2374. Amanda Matlosz (AMatlosz) 1-06-98
  2375. Note:
  2376. ** CertificateContext subtleties: **
  2377. CryptDecryptMessage takes as a parameter a pointer to a certificate store;
  2378. it will use the first appropriate certificate context it finds in that
  2379. store to perform the decryption. In order to make this call, we create a
  2380. CertificateStore in memory, and add the provided CertificateContext to it.
  2381. CertAddCertificateContextToStore actually places a copy of the certificate
  2382. context in the store. In so doing, it strips off any properties that are
  2383. not permanent -- if a HCRYPTPROV is associated with the KeyContext of the
  2384. source CertificateContext, it will NOT be associated with the KeyContext
  2385. of the cert context in the store.
  2386. Although this is appropriate behavior in most cases, we need that property
  2387. to be kept intact when dealing with Smart Card CSPs (to avoid surprise
  2388. "Insert PIN" dialogs), so after adding the CertificateContext to the store,
  2389. we turn around and get the CERT_KEY_CONTEXT_PROP_ID from the source
  2390. certcontext and (re)set it on the certcontext in the memory store.
  2391. ** Algorithm notes: **
  2392. Algorithm expects a CRYPT_ALGORITHM_IDENTIFIER cai;
  2393. If there are no parameters to the alg, cai.Parameters.cbData *must* be 0;
  2394. for example: CALG_RC4, no parameters:
  2395. cai.pszObjId = szOID_RSA_RC4;
  2396. cai.Parameters.cbData = 0;
  2397. Used by LSA.
  2398. --*/
  2399. NTSTATUS WINAPI
  2400. ScHelperDecryptMessage(
  2401. IN PUNICODE_STRING pucPIN,
  2402. IN OPTIONAL PBYTE pbLogonInfo,
  2403. IN OPTIONAL HCRYPTPROV Provider,
  2404. IN PCCERT_CONTEXT CertificateContext,
  2405. IN PBYTE CipherText, // Supplies formatted CipherText
  2406. IN ULONG CipherLength, // Supplies the length of the CiperText
  2407. OUT PBYTE ClearText, // Receives decrypted message
  2408. IN OUT PULONG pClearLength // Supplies length of buffer, receives actual length
  2409. )
  2410. {
  2411. NTSTATUS lResult = STATUS_SUCCESS;
  2412. HCRYPTPROV hProv = NULL;
  2413. PCCERT_CONTEXT pStoreCertContext = NULL;
  2414. HCERTSTORE hCertStore = NULL;
  2415. LogonInfo *pLI = (LogonInfo *)pbLogonInfo;
  2416. CUnicodeString szPin(pucPIN);
  2417. CERT_KEY_CONTEXT CertKeyContext;
  2418. DWORD cbData = sizeof(CERT_KEY_CONTEXT); // PhilH swears this will not grow!
  2419. BOOL fSts;
  2420. //
  2421. // Make sure we've got a Crypto Provider up and running.
  2422. //
  2423. if (ARGUMENT_PRESENT(Provider))
  2424. {
  2425. hProv = Provider;
  2426. }
  2427. else
  2428. {
  2429. if (NULL != pucPIN)
  2430. {
  2431. if (!szPin.Valid())
  2432. {
  2433. return(STATUS_INSUFFICIENT_RESOURCES);
  2434. }
  2435. }
  2436. CSCLogonInit * LogonInit = (CSCLogonInit *) pLI->ContextInformation;
  2437. hProv = LogonInit->CryptCtx(pLI);
  2438. if (NULL == hProv)
  2439. {
  2440. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2441. goto ErrorExit;
  2442. }
  2443. //
  2444. // Declare the PIN.
  2445. //
  2446. if (NULL != pucPIN )
  2447. {
  2448. fSts = CryptSetProvParam(
  2449. hProv,
  2450. PP_KEYEXCHANGE_PIN,
  2451. (LPBYTE)((LPCSTR)szPin),
  2452. 0);
  2453. if (!fSts)
  2454. {
  2455. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2456. goto ErrorExit;
  2457. }
  2458. }
  2459. }
  2460. //
  2461. // Open a temporary certstore to hold this certcontext
  2462. //
  2463. hCertStore = CertOpenStore(
  2464. CERT_STORE_PROV_MEMORY,
  2465. 0, // not applicable
  2466. hProv,
  2467. CERT_STORE_NO_CRYPT_RELEASE_FLAG, // auto-release hProv NOT OK
  2468. NULL);
  2469. if (NULL == hCertStore)
  2470. {
  2471. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2472. goto ErrorExit;
  2473. }
  2474. fSts = CertAddCertificateContextToStore(
  2475. hCertStore,
  2476. CertificateContext,
  2477. CERT_STORE_ADD_ALWAYS,
  2478. &pStoreCertContext);
  2479. //
  2480. // NOW WE NEED TO RESET THE KEY CONTEXT PROPERTY ON THIS CERTCONTEXT
  2481. // IN THE MEMORY STORE (see function header/notes) AS APPROPRIATE
  2482. //
  2483. // ie, IFF the certcontext we were give has the key_context property,
  2484. // reset it (and fail if the resetting doesn't work)
  2485. //
  2486. fSts = CertGetCertificateContextProperty(
  2487. CertificateContext,
  2488. CERT_KEY_CONTEXT_PROP_ID,
  2489. (void *)&CertKeyContext,
  2490. &cbData);
  2491. if (TRUE == fSts)
  2492. {
  2493. fSts = CertSetCertificateContextProperty(
  2494. pStoreCertContext,
  2495. CERT_KEY_CONTEXT_PROP_ID,
  2496. CERT_STORE_NO_CRYPT_RELEASE_FLAG, // no auto-release hProv!
  2497. (void *)&CertKeyContext);
  2498. if (!fSts)
  2499. {
  2500. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2501. goto ErrorExit;
  2502. }
  2503. }
  2504. //
  2505. // Decrypt the message
  2506. //
  2507. CRYPT_DECRYPT_MESSAGE_PARA DecryptPara;
  2508. DecryptPara.cbSize = sizeof(DecryptPara);
  2509. DecryptPara.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
  2510. DecryptPara.cCertStore = 1;
  2511. DecryptPara.rghCertStore = &hCertStore;
  2512. fSts = CryptDecryptMessage(
  2513. &DecryptPara,
  2514. CipherText,
  2515. CipherLength,
  2516. ClearText,
  2517. pClearLength,
  2518. NULL);
  2519. if (!fSts)
  2520. {
  2521. if (GetLastError() == ERROR_MORE_DATA)
  2522. {
  2523. lResult = STATUS_BUFFER_TOO_SMALL;
  2524. }
  2525. else
  2526. {
  2527. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2528. }
  2529. goto ErrorExit;
  2530. }
  2531. ErrorExit:
  2532. // Do this early so GetLastError is not clobbered
  2533. if (!NT_SUCCESS(lResult))
  2534. {
  2535. lResult = LogEvent(
  2536. lResult,
  2537. (DWORD)((ARGUMENT_PRESENT(Provider))?EVENT_ID_DECMSG_NOSC:EVENT_ID_DECMSG)
  2538. );
  2539. }
  2540. if (hCertStore != NULL)
  2541. {
  2542. fSts = CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  2543. if (!fSts)
  2544. {
  2545. if (!NT_SUCCESS(lResult))
  2546. lResult = STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  2547. }
  2548. }
  2549. return lResult;
  2550. }