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.

594 lines
13 KiB

  1. /*
  2. Copyright (c) 1997, Microsoft Corporation, all rights reserved
  3. Description:
  4. Smart card helper functions.
  5. History:
  6. 13 Dec 1997: Amanda Matlosz created original version.
  7. 12 May 1998: Vijay Baliga moved things around.
  8. */
  9. #undef UNICODE
  10. #include <winscard.h>
  11. #include <wincrypt.h>
  12. #include <rtutils.h>
  13. #include "resource.h"
  14. HINSTANCE
  15. GetHInstance(
  16. VOID
  17. );
  18. WCHAR*
  19. WszFromId(
  20. IN HINSTANCE hInstance,
  21. IN DWORD dwStringId
  22. );
  23. VOID
  24. EapTlsTrace(
  25. IN CHAR* Format,
  26. ...
  27. );
  28. typedef
  29. WINSCARDAPI LONG
  30. (WINAPI *GETOPENCARDNAMEA)(
  31. OPENCARDNAMEA*
  32. );
  33. GETOPENCARDNAMEA g_fnGetOpenCardNameA = NULL;
  34. HINSTANCE g_hInstanceScardDlg = NULL;
  35. /*
  36. Returns:
  37. Notes:
  38. */
  39. DWORD
  40. LoadScardDlgDll(
  41. VOID
  42. )
  43. {
  44. DWORD dwErr = NO_ERROR;
  45. if (NULL == g_hInstanceScardDlg)
  46. {
  47. g_hInstanceScardDlg = LoadLibrary("scarddlg.dll");
  48. }
  49. if (NULL == g_hInstanceScardDlg)
  50. {
  51. dwErr = GetLastError();
  52. EapTlsTrace("LoadLibrary(scarddlg.dll) failed and returned 0x%x",
  53. dwErr);
  54. goto LDone;
  55. }
  56. if (NULL == g_fnGetOpenCardNameA)
  57. {
  58. g_fnGetOpenCardNameA = (GETOPENCARDNAMEA)
  59. GetProcAddress(g_hInstanceScardDlg, "GetOpenCardNameA");
  60. }
  61. if (NULL == g_fnGetOpenCardNameA)
  62. {
  63. dwErr = GetLastError();
  64. EapTlsTrace("GetProcAddress(GetOpenCardNameA) failed and returned 0x%x",
  65. dwErr);
  66. goto LDone;
  67. }
  68. LDone:
  69. return(dwErr);
  70. }
  71. /*
  72. Returns:
  73. Notes:
  74. */
  75. VOID
  76. FreeScardDlgDll(
  77. VOID
  78. )
  79. {
  80. if (NULL != g_hInstanceScardDlg)
  81. {
  82. FreeLibrary(g_hInstanceScardDlg);
  83. g_hInstanceScardDlg = NULL;
  84. g_fnGetOpenCardNameA = NULL;
  85. }
  86. }
  87. /*
  88. Returns:
  89. Notes:
  90. */
  91. DWORD
  92. LocalCryptGetProvParamW(
  93. IN HCRYPTPROV hProv,
  94. IN DWORD dwParam,
  95. OUT WCHAR** ppwsz
  96. )
  97. {
  98. CHAR* psz = NULL;
  99. WCHAR* pwszTemp = NULL;
  100. DWORD cb;
  101. int count;
  102. BOOL fSuccess;
  103. DWORD dwErr = NO_ERROR;
  104. fSuccess = CryptGetProvParam(hProv, dwParam, NULL, &cb, 0);
  105. if (!fSuccess)
  106. {
  107. dwErr = GetLastError();
  108. EapTlsTrace("CryptGetProvParam failed and returned 0x%x", dwErr);
  109. goto LDone;
  110. }
  111. psz = (CHAR*)LocalAlloc(LPTR, cb);
  112. if (NULL == psz)
  113. {
  114. dwErr = GetLastError();
  115. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  116. goto LDone;
  117. }
  118. fSuccess = CryptGetProvParam(hProv, dwParam, (BYTE*)psz, &cb, 0);
  119. if (!fSuccess)
  120. {
  121. dwErr = GetLastError();
  122. EapTlsTrace("CryptGetProvParam failed and returned 0x%x", dwErr);
  123. goto LDone;
  124. }
  125. count = MultiByteToWideChar(CP_UTF8, 0, psz, -1, NULL, 0);
  126. if (0 == count)
  127. {
  128. dwErr = GetLastError();
  129. EapTlsTrace("MultiByteToWideChar(%s) failed: %d", psz, dwErr);
  130. goto LDone;
  131. }
  132. pwszTemp = (WCHAR*)LocalAlloc(LPTR, count * sizeof(WCHAR));
  133. if (NULL == pwszTemp)
  134. {
  135. dwErr = GetLastError();
  136. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  137. goto LDone;
  138. }
  139. count = MultiByteToWideChar(CP_UTF8, 0, psz, -1, pwszTemp, count);
  140. if (0 == count)
  141. {
  142. dwErr = GetLastError();
  143. EapTlsTrace("MultiByteToWideChar(%s) failed: %d", psz, dwErr);
  144. goto LDone;
  145. }
  146. *ppwsz = pwszTemp;
  147. pwszTemp = NULL;
  148. LDone:
  149. LocalFree(pwszTemp);
  150. LocalFree(psz);
  151. return(dwErr);
  152. }
  153. /*
  154. Returns:
  155. Notes:
  156. This internal routine generates a certificate context with (static)
  157. keyprov info suitable for CertStore-based operations.
  158. */
  159. DWORD
  160. BuildCertContext(
  161. IN HCRYPTPROV hProv,
  162. IN BYTE* pbCert,
  163. IN DWORD dwCertLen,
  164. OUT PCCERT_CONTEXT* ppCertContext
  165. )
  166. {
  167. CRYPT_KEY_PROV_INFO KeyProvInfo;
  168. WCHAR* pwszContainerName = NULL;
  169. WCHAR* pwszProviderName = NULL;
  170. BOOL fCertContextCreated = FALSE;
  171. BOOL fSuccess;
  172. DWORD dwErr = NO_ERROR;
  173. if ( (0 == hProv)
  174. || (NULL == pbCert)
  175. || (0 == dwCertLen))
  176. {
  177. dwErr = ERROR_INVALID_PARAMETER;
  178. goto LDone;
  179. }
  180. RTASSERT(NULL != ppCertContext);
  181. // Convert the certificate into a cert context.
  182. *ppCertContext = CertCreateCertificateContext(
  183. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  184. pbCert, dwCertLen);
  185. if (NULL == *ppCertContext)
  186. {
  187. dwErr = GetLastError();
  188. EapTlsTrace("CertCreateCertificateContext failed and returned 0x%x",
  189. dwErr);
  190. goto LDone;
  191. }
  192. fCertContextCreated = TRUE;
  193. // Associate cryptprovider w/ the private key property of this cert
  194. dwErr = LocalCryptGetProvParamW(hProv, PP_CONTAINER, &pwszContainerName);
  195. if (NO_ERROR != dwErr)
  196. {
  197. goto LDone;
  198. }
  199. EapTlsTrace("Container: %ws", pwszContainerName);
  200. dwErr = LocalCryptGetProvParamW(hProv, PP_NAME, &pwszProviderName);
  201. if (NO_ERROR != dwErr)
  202. {
  203. goto LDone;
  204. }
  205. EapTlsTrace("Provider: %ws", pwszProviderName);
  206. // Set the cert context properties to reflect the prov info
  207. KeyProvInfo.pwszContainerName = pwszContainerName;
  208. KeyProvInfo.pwszProvName = pwszProviderName;
  209. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  210. KeyProvInfo.dwFlags = 0;
  211. KeyProvInfo.cProvParam = 0;
  212. KeyProvInfo.rgProvParam = NULL;
  213. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  214. fSuccess = CertSetCertificateContextProperty(
  215. *ppCertContext,
  216. CERT_KEY_PROV_INFO_PROP_ID,
  217. 0,
  218. (void *)&KeyProvInfo);
  219. if (!fSuccess)
  220. {
  221. dwErr = GetLastError();
  222. EapTlsTrace("CertSetCertificateContextProperty failed and returned "
  223. "0x%x", dwErr);
  224. goto LDone;
  225. }
  226. LDone:
  227. if (NO_ERROR != dwErr)
  228. {
  229. if (fCertContextCreated)
  230. {
  231. CertFreeCertificateContext(*ppCertContext);
  232. }
  233. *ppCertContext = NULL;
  234. }
  235. LocalFree(pwszContainerName);
  236. LocalFree(pwszProviderName);
  237. return(dwErr);
  238. }
  239. /*
  240. Returns:
  241. Notes:
  242. The "Select Card" common dialog is raised, then the certificate is read
  243. from the card, a certificate context complete with key prov info is
  244. migrated to the cert store and also returned to the caller.
  245. */
  246. DWORD
  247. GetCertFromCard(
  248. OUT PCCERT_CONTEXT* ppCertContext
  249. )
  250. {
  251. CHAR* pszReader = NULL;
  252. CHAR* pszCard = NULL;
  253. DWORD cbReaderOrCard = MAX_PATH;
  254. SCARDCONTEXT hContext = 0;
  255. OPENCARDNAMEA OpenCardName;
  256. CHAR* pszProviderName = NULL;
  257. DWORD cchProvider;
  258. HCRYPTPROV hProv = 0;
  259. HCRYPTKEY hKey = 0;
  260. DWORD cbCertLen;
  261. BYTE* pbCert = NULL;
  262. HCERTSTORE hCertStore = NULL;
  263. BOOL fSuccess;
  264. LONG lErr;
  265. DWORD dwErr = NO_ERROR;
  266. LPWSTR lpwszTitle = NULL;
  267. CHAR szTitle[50] = {0}; //We know the size of title will not be
  268. //greater than this.
  269. EapTlsTrace("GetCertFromCard");
  270. RTASSERT(NULL != ppCertContext);
  271. dwErr = LoadScardDlgDll();
  272. if (NO_ERROR != dwErr)
  273. {
  274. goto LDone;
  275. }
  276. pszReader = (BYTE*)LocalAlloc(LPTR, cbReaderOrCard);
  277. if (NULL == pszReader)
  278. {
  279. dwErr = GetLastError();
  280. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  281. goto LDone;
  282. }
  283. pszCard = (BYTE*)LocalAlloc(LPTR, cbReaderOrCard);
  284. if (NULL == pszCard)
  285. {
  286. dwErr = GetLastError();
  287. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  288. goto LDone;
  289. }
  290. lErr = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
  291. if (SCARD_S_SUCCESS != lErr)
  292. {
  293. dwErr = lErr;
  294. EapTlsTrace("SCardEstablishContext failed and returned 0x%x", dwErr);
  295. goto LDone;
  296. }
  297. ZeroMemory(&OpenCardName, sizeof(OpenCardName));
  298. lpwszTitle = WszFromId(GetHInstance(),IDS_SCARD_TITLE );
  299. WideCharToMultiByte(CP_ACP,
  300. 0,
  301. lpwszTitle,
  302. -1,
  303. szTitle,
  304. 50,
  305. NULL,
  306. NULL
  307. );
  308. OpenCardName.dwStructSize = sizeof(OpenCardName);
  309. OpenCardName.hSCardContext = hContext;
  310. OpenCardName.lpstrCardNames = NULL;
  311. OpenCardName.lpstrRdr = pszReader;
  312. OpenCardName.nMaxRdr = cbReaderOrCard;
  313. OpenCardName.lpstrCard = pszCard;
  314. OpenCardName.nMaxCard = cbReaderOrCard;
  315. OpenCardName.lpstrTitle = szTitle;
  316. OpenCardName.dwFlags = SC_DLG_MINIMAL_UI;
  317. OpenCardName.dwShareMode = 0;
  318. OpenCardName.dwPreferredProtocols = 0;
  319. lErr = g_fnGetOpenCardNameA(&OpenCardName);
  320. if (SCARD_S_SUCCESS != lErr)
  321. {
  322. dwErr = lErr;
  323. EapTlsTrace("GetOpenCardNameA failed and returned 0x%x", dwErr);
  324. goto LDone;
  325. }
  326. EapTlsTrace("Reader: %s, Card: %s", pszReader, pszCard);
  327. RTASSERT(0 == OpenCardName.hCardHandle);
  328. pszProviderName = NULL;
  329. cchProvider = SCARD_AUTOALLOCATE;
  330. lErr = SCardGetCardTypeProviderNameA(hContext, OpenCardName.lpstrCard,
  331. SCARD_PROVIDER_CSP, (CHAR*) &pszProviderName, &cchProvider);
  332. if (SCARD_S_SUCCESS != lErr)
  333. {
  334. dwErr = lErr;
  335. EapTlsTrace("SCardGetCardTypeProviderNameA failed and returned 0x%x",
  336. dwErr);
  337. goto LDone;
  338. }
  339. if (NULL != pszProviderName)
  340. {
  341. EapTlsTrace("Provider: %s", pszProviderName);
  342. }
  343. // Load the CSP
  344. fSuccess = CryptAcquireContext(&hProv, NULL /* default container */,
  345. pszProviderName, PROV_RSA_FULL,
  346. CRYPT_SILENT /* or 0, to show CSP UI as needed */);
  347. if (!fSuccess)
  348. {
  349. dwErr = GetLastError();
  350. EapTlsTrace("CryptAcquireContext failed and returned 0x%x", dwErr);
  351. goto LDone;
  352. }
  353. // Get the key handle.
  354. fSuccess = CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKey);
  355. if (!fSuccess)
  356. {
  357. dwErr = GetLastError();
  358. EapTlsTrace("CryptGetUserKey failed and returned 0x%x", dwErr);
  359. goto LDone;
  360. }
  361. // Upload the certificate.
  362. cbCertLen = 0;
  363. fSuccess = CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &cbCertLen, 0);
  364. if (!fSuccess)
  365. {
  366. dwErr = GetLastError();
  367. if (ERROR_MORE_DATA != dwErr)
  368. {
  369. EapTlsTrace("CryptGetKeyParam(KP_CERTIFICATE) failed and returned "
  370. "0x%x", dwErr);
  371. goto LDone;
  372. }
  373. dwErr = NO_ERROR;
  374. }
  375. pbCert = (BYTE*)LocalAlloc(LPTR, cbCertLen);
  376. if (NULL == pbCert)
  377. {
  378. dwErr = GetLastError();
  379. EapTlsTrace("LocalAlloc failed and returned %d", dwErr);
  380. goto LDone;
  381. }
  382. fSuccess = CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCert, &cbCertLen, 0);
  383. if (!fSuccess)
  384. {
  385. dwErr = GetLastError();
  386. EapTlsTrace("CryptGetKeyParam(KP_CERTIFICATE) failed and returned "
  387. "0x%x", dwErr);
  388. goto LDone;
  389. }
  390. // Get the cert context...
  391. dwErr = BuildCertContext(hProv, pbCert, cbCertLen, ppCertContext);
  392. if (NO_ERROR != dwErr)
  393. {
  394. goto LDone;
  395. }
  396. // ...and migrate it to the My store
  397. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
  398. CERT_SYSTEM_STORE_CURRENT_USER, "MY");
  399. if (NULL == hCertStore)
  400. {
  401. dwErr = GetLastError();
  402. EapTlsTrace("CertOpenStore failed and returned 0x%x", dwErr);
  403. goto LDone;
  404. }
  405. fSuccess = CertAddCertificateContextToStore(hCertStore, *ppCertContext,
  406. CERT_STORE_ADD_REPLACE_EXISTING, NULL);
  407. if (!fSuccess)
  408. {
  409. // This is OK. Don't return an error.
  410. EapTlsTrace("CertAddCertificateContextToStore failed and returned 0x%x",
  411. GetLastError());
  412. }
  413. LDone:
  414. LocalFree (lpwszTitle);
  415. LocalFree(pszReader);
  416. LocalFree(pszCard);
  417. LocalFree(pbCert);
  418. if (0 != hProv)
  419. {
  420. CryptReleaseContext(hProv, 0);
  421. }
  422. if (NULL != hCertStore)
  423. {
  424. CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  425. }
  426. if (NULL != pszProviderName)
  427. {
  428. SCardFreeMemory(hContext, pszProviderName);
  429. }
  430. if (0 != hContext)
  431. {
  432. SCardReleaseContext(hContext);
  433. }
  434. if (0 != hKey)
  435. {
  436. CryptDestroyKey(hKey);
  437. }
  438. RTASSERT( (NO_ERROR == dwErr)
  439. || (NULL == *ppCertContext));
  440. if ( (NULL == *ppCertContext)
  441. && (NO_ERROR == dwErr))
  442. {
  443. EapTlsTrace("CertContext is NULL. Returning E_FAIL");
  444. dwErr = E_FAIL;
  445. }
  446. if ( (SCARD_W_CANCELLED_BY_USER == dwErr)
  447. || (SCARD_E_NO_READERS_AVAILABLE == dwErr))
  448. {
  449. dwErr = ERROR_CANCELLED;
  450. }
  451. return(dwErr);
  452. }