Source code of Windows XP (NT5)
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.

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