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.

1302 lines
33 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. secinit.cxx
  5. Abstract:
  6. Contains load function for security.dll on NT and secur32.dll on win95
  7. Also handles WinTrust.dll function loading.
  8. Author:
  9. Sophia Chung (sophiac) 6-Feb-1996
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include <wininetp.h>
  15. //
  16. // InitializationLock - protects against multiple threads loading security.dll
  17. // (secur32.dll) and entry points
  18. //
  19. CRITICAL_SECTION InitializationSecLock = {0};
  20. CRITICAL_SECTION InitFortezzaLock = {0};
  21. HCRYPTPROV GlobalFortezzaCryptProv;
  22. //
  23. // GlobalSecFuncTable - Pointer to Global Structure of Pointers that are used
  24. // for storing the entry points into the SCHANNEL.dll
  25. //
  26. PSecurityFunctionTable GlobalSecFuncTable = NULL;
  27. //
  28. // pWinVerifyTrust - Pointer to Entry Point in WINTRUST.DLL
  29. //
  30. WIN_VERIFY_TRUST_FN pWinVerifyTrust;
  31. WT_HELPER_PROV_DATA_FROM_STATE_DATA_FN pWTHelperProvDataFromStateData;
  32. //
  33. // pSslCrackCertificate - Pointer to SCHANNEL.dll utility function that
  34. // is used for parsing X509 certificates.
  35. //
  36. SSL_CRACK_CERTIFICATE_FN pSslCrackCertificate;
  37. //
  38. // pSslFreeCertificate - Pointer to Schannel.dll function for freeing Certs
  39. //
  40. SSL_FREE_CERTIFICATE_FN pSslFreeCertificate;
  41. //
  42. // hSecurity - NULL when security.dll/secur32.dll is not loaded
  43. //
  44. HINSTANCE hSecurity = NULL;
  45. //
  46. // hWinTrust - NULL when WinTrust DLL is not loaded.
  47. //
  48. HINSTANCE hWinTrust = NULL;
  49. BOOL g_fDoSpecialMagicForSGCCerts = FALSE;
  50. HCERTSTORE g_hMyCertStore = NULL;
  51. BOOL g_bOpenMyCertStore = FALSE;
  52. BOOL g_bFortezzaInstalled = FALSE;
  53. BOOL g_bCheckedForFortezza = FALSE;
  54. BOOL g_bAttemptedFortezzaLogin = FALSE;
  55. CRYPT_INSTALL_DEFAULT_CONTEXT_FN g_CryptInstallDefaultContext = NULL;
  56. CRYPT_UNINSTALL_DEFAULT_CONTEXT_FN g_CryptUninstallDefaultContext = NULL;
  57. CERT_FIND_CHAIN_IN_STORE_FN g_CertFindChainInStore = NULL;
  58. CERT_FREE_CERTIFICATE_CHAIN_FN g_CertFreeCertificateChain = NULL;
  59. #define LOCK_FORTEZZA() EnterCriticalSection( &InitFortezzaLock )
  60. #define UNLOCK_FORTEZZA() LeaveCriticalSection( &InitFortezzaLock )
  61. DWORD
  62. LoadWinTrust(
  63. VOID
  64. )
  65. /*++
  66. Routine Description:
  67. This function loads the WinTrust.DLL and binds a pointer to a function
  68. that is needed in the WinTrust DLL.
  69. Arguments:
  70. NONE.
  71. Return Value:
  72. WINDOWS Error Code.
  73. --*/
  74. {
  75. DWORD error = ERROR_SUCCESS;
  76. LOCK_SECURITY();
  77. if( hWinTrust == NULL )
  78. {
  79. LPSTR lpszDllFileName = WINTRUST_DLLNAME;
  80. pWinVerifyTrust = NULL;
  81. //
  82. // Load the DLL
  83. //
  84. hWinTrust = LoadLibrary(lpszDllFileName);
  85. if ( hWinTrust )
  86. {
  87. pWinVerifyTrust = (WIN_VERIFY_TRUST_FN)
  88. GetProcAddress(hWinTrust, WIN_VERIFY_TRUST_NAME);
  89. pWTHelperProvDataFromStateData = (WT_HELPER_PROV_DATA_FROM_STATE_DATA_FN)
  90. GetProcAddress(hWinTrust, WT_HELPER_PROV_DATA_FROM_STATE_DATA_NAME);
  91. }
  92. if ( !hWinTrust || !pWinVerifyTrust )
  93. {
  94. error = GetLastError();
  95. if ( error == ERROR_SUCCESS )
  96. {
  97. error = ERROR_INTERNET_INTERNAL_ERROR;
  98. }
  99. }
  100. {
  101. // To show SGC certificates we need to do some special magic (see schnlui.cxx) which
  102. // depends on some fixes in Wintrust.dll. We have
  103. // Figure out the version info for WinTrust.dll
  104. TCHAR rgchWinTrustFileName[MAX_PATH];
  105. g_fDoSpecialMagicForSGCCerts = FALSE;
  106. if (GetModuleFileName(hWinTrust, rgchWinTrustFileName, ARRAY_ELEMENTS(rgchWinTrustFileName)) != 0)
  107. {
  108. DWORD cbFileVersionBufSize;
  109. DWORD dwTemp = 0;
  110. if ((cbFileVersionBufSize = GetFileVersionInfoSize(rgchWinTrustFileName, &dwTemp)) != 0)
  111. {
  112. BYTE* pVerBuffer = NULL;
  113. pVerBuffer = (BYTE *) _alloca(cbFileVersionBufSize);
  114. if ( (pVerBuffer != NULL) &&
  115. (GetFileVersionInfo(rgchWinTrustFileName, 0, cbFileVersionBufSize, pVerBuffer) != 0))
  116. {
  117. VS_FIXEDFILEINFO *lpVSFixedFileInfo;
  118. unsigned uiLength;
  119. if( VerQueryValue( pVerBuffer, TEXT("\\"),(LPVOID*)&lpVSFixedFileInfo, &uiLength) != 0
  120. && uiLength != 0)
  121. {
  122. // NT5 Beta3 wintrust version is 5.131.2001.0 which is the Min version we need.
  123. // 0x50083 ==> 5.131
  124. // 0x7db0000 ==> 2001.0
  125. if ((lpVSFixedFileInfo->dwFileVersionMS > 0x50083)
  126. || (lpVSFixedFileInfo->dwFileVersionMS == 0x50083 && lpVSFixedFileInfo->dwFileVersionLS >= 0x07db0000))
  127. g_fDoSpecialMagicForSGCCerts = TRUE;
  128. }
  129. }
  130. }
  131. }
  132. }
  133. }
  134. INET_ASSERT(pWinVerifyTrust);
  135. if ( error != ERROR_SUCCESS )
  136. {
  137. if (hWinTrust)
  138. {
  139. FreeLibrary(hWinTrust);
  140. hWinTrust = NULL;
  141. }
  142. }
  143. UNLOCK_SECURITY();
  144. return error;
  145. }
  146. VOID
  147. SecurityInitialize(
  148. VOID
  149. )
  150. /*++
  151. Routine Description:
  152. This function initializes the global lock required for the security
  153. pkgs.
  154. Arguments:
  155. NONE.
  156. Return Value:
  157. WINDOWS Error Code.
  158. --*/
  159. {
  160. InitializeCriticalSection( &InitializationSecLock );
  161. InitializeCriticalSection( &InitFortezzaLock );
  162. }
  163. VOID
  164. SecurityTerminate(
  165. VOID
  166. )
  167. /*++
  168. Routine Description:
  169. This function Deletes the global lock required for the security
  170. pkgs.
  171. Arguments:
  172. NONE.
  173. Return Value:
  174. WINDOWS Error Code.
  175. --*/
  176. {
  177. DeleteCriticalSection(&InitializationSecLock);
  178. DeleteCriticalSection(&InitFortezzaLock);
  179. }
  180. VOID
  181. UnloadSecurity(
  182. VOID
  183. )
  184. /*++
  185. Routine Description:
  186. This function terminates the global data required for the security
  187. pkgs and dynamically unloads security APIs from security.dll (NT)
  188. or secur32.dll (WIN95).
  189. Arguments:
  190. NONE.
  191. Return Value:
  192. WINDOWS Error Code.
  193. --*/
  194. {
  195. DWORD i;
  196. LOCK_SECURITY();
  197. //
  198. // free all security pkg credential handles
  199. //
  200. for (i = 0; SecProviders[i].pszName != NULL; i++) {
  201. if (SecProviders[i].fEnabled) {
  202. if (SecProviders[i].pCertCtxt == NULL && !IsCredClear(SecProviders[i].hCreds)) {
  203. // Beta1 Hack. Because of some circular dependency between dlls
  204. // both crypt32 and schannel's PROCESS_DETACH gets called before wininet.
  205. // This is catastrophic if we have a cert context attached to the credentials
  206. // handle. In this case we will just leak the handle since the process is dying
  207. // anyway. We really need to fix this.
  208. g_FreeCredentialsHandle(&SecProviders[i].hCreds);
  209. }
  210. }
  211. #if 0 // See comments above.
  212. if (SecProviders[i].pCertCtxt != NULL) {
  213. CertFreeCertificateContext(SecProviders[i].pCertCtxt);
  214. SecProviders[i].pCertCtxt = NULL;
  215. }
  216. #endif
  217. }
  218. //
  219. // close cert store. Protect against fault if DLL already unloaded
  220. //
  221. __try {
  222. if (g_hMyCertStore != NULL) {
  223. CertCloseStore(g_hMyCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  224. }
  225. } __except(EXCEPTION_EXECUTE_HANDLER) {
  226. }
  227. ENDEXCEPT
  228. g_hMyCertStore = NULL;
  229. g_bOpenMyCertStore = FALSE;
  230. // IMPORTANT : Don't free GlobalFortezzaCryptProv. When we free the cert context
  231. // from the SecProviders[] array above it gets freed automatically.
  232. if (GlobalFortezzaCryptProv != NULL)
  233. {
  234. GlobalFortezzaCryptProv = NULL;
  235. }
  236. //
  237. // unload dll
  238. //
  239. if (hSecurity != NULL) {
  240. FreeLibrary(hSecurity);
  241. hSecurity = NULL;
  242. }
  243. UNLOCK_SECURITY();
  244. }
  245. //
  246. DWORD
  247. ReopenMyCertStore(
  248. VOID
  249. )
  250. {
  251. DWORD Error = ERROR_SUCCESS;
  252. LOCK_SECURITY();
  253. if (g_hMyCertStore == NULL) {
  254. //
  255. // CRYPT32.DLL is delayloaded. Need SEH in case it fails
  256. //
  257. __try {
  258. g_hMyCertStore = CertOpenSystemStore(0, "MY");
  259. } __except(EXCEPTION_EXECUTE_HANDLER) {
  260. Error = GetLastError();
  261. }
  262. ENDEXCEPT
  263. }
  264. UNLOCK_SECURITY();
  265. return Error;
  266. }
  267. DWORD
  268. CloseMyCertStore(
  269. VOID
  270. )
  271. {
  272. DWORD Error = ERROR_SUCCESS;
  273. LOCK_SECURITY();
  274. //
  275. // close cert store. Protect against fault if DLL already unloaded
  276. //
  277. __try {
  278. if (g_hMyCertStore != NULL) {
  279. CertCloseStore(g_hMyCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  280. }
  281. } __except(EXCEPTION_EXECUTE_HANDLER) {
  282. }
  283. ENDEXCEPT
  284. g_hMyCertStore = NULL;
  285. UNLOCK_SECURITY();
  286. return Error;
  287. }
  288. DWORD
  289. LoadSecurity(
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. This function dynamically loads security APIs from security.dll (NT)
  295. or secur32.dll (WIN95).
  296. Arguments:
  297. NONE.
  298. Return Value:
  299. WINDOWS Error Code.
  300. --*/
  301. {
  302. DWORD Error = ERROR_SUCCESS;
  303. INITSECURITYINTERFACE pfInitSecurityInterface = NULL;
  304. LOCK_SECURITY();
  305. if (g_hMyCertStore == NULL) {
  306. //
  307. // CRYPT32.DLL is delayloaded. Need SEH in case it fails
  308. //
  309. __try {
  310. g_hMyCertStore = CertOpenSystemStore(0, "MY");
  311. } __except(EXCEPTION_EXECUTE_HANDLER) {
  312. Error = GetLastError();
  313. }
  314. ENDEXCEPT
  315. }
  316. if( g_hMyCertStore != NULL)
  317. g_bOpenMyCertStore = TRUE;
  318. if (Error == ERROR_SUCCESS) {
  319. Error = LoadWinTrust();
  320. }
  321. if ( Error != ERROR_SUCCESS )
  322. {
  323. goto quit;
  324. }
  325. if( hSecurity != NULL )
  326. {
  327. goto quit;
  328. }
  329. //
  330. // load dll.
  331. //
  332. //
  333. // This is better for performance. Rather than call through
  334. // SSPI, we go right to the DLL doing the work.
  335. //
  336. hSecurity = LoadLibrary( "schannel" );
  337. if ( hSecurity == NULL ) {
  338. Error = GetLastError();
  339. goto quit;
  340. }
  341. //
  342. // get function addresses.
  343. //
  344. #ifdef UNICODE
  345. pfInitSecurityInterface =
  346. (INITSECURITYINTERFACE) GetProcAddress( hSecurity,
  347. "InitSecurityInterfaceW" );
  348. #else
  349. pfInitSecurityInterface =
  350. (INITSECURITYINTERFACE) GetProcAddress( hSecurity,
  351. "InitSecurityInterfaceA" );
  352. #endif
  353. if ( pfInitSecurityInterface == NULL )
  354. {
  355. Error = GetLastError();
  356. goto quit;
  357. }
  358. //
  359. // Get SslCrackCertificate func pointer,
  360. // utility function declared in SCHANNEL that
  361. // is used for parsing X509 certificates.
  362. //
  363. pSslCrackCertificate =
  364. (SSL_CRACK_CERTIFICATE_FN) GetProcAddress( hSecurity,
  365. SSL_CRACK_CERTIFICATE_NAME );
  366. if ( pSslCrackCertificate == NULL )
  367. {
  368. Error = GetLastError();
  369. goto quit;
  370. }
  371. pSslFreeCertificate =
  372. (SSL_FREE_CERTIFICATE_FN) GetProcAddress( hSecurity,
  373. SSL_FREE_CERTIFICATE_NAME );
  374. if ( pSslFreeCertificate == NULL )
  375. {
  376. Error = GetLastError();
  377. goto quit;
  378. }
  379. GlobalSecFuncTable = (SecurityFunctionTable*) ((*pfInitSecurityInterface) ());
  380. if ( GlobalSecFuncTable == NULL ) {
  381. Error = GetLastError(); // BUGBUG does this work?
  382. goto quit;
  383. }
  384. HMODULE hCrypt32;
  385. hCrypt32 = GetModuleHandle("crypt32");
  386. INET_ASSERT(hCrypt32 != NULL);
  387. // We don't error out here because not finding these entry points
  388. // just affects Fortezza. The rest will still work fine.
  389. if (hCrypt32)
  390. {
  391. if (FALSE == GlobalPlatformVersion5)
  392. {
  393. TCHAR rgchCrypt32FileName[MAX_PATH];
  394. g_fDoSpecialMagicForSGCCerts = FALSE;
  395. if (GetModuleFileName(hCrypt32, rgchCrypt32FileName, ARRAY_ELEMENTS(rgchCrypt32FileName)) != 0)
  396. {
  397. DWORD cbFileVersionBufSize;
  398. DWORD dwTemp = 0;
  399. if ((cbFileVersionBufSize = GetFileVersionInfoSize(rgchCrypt32FileName, &dwTemp)) != 0)
  400. {
  401. BYTE* pVerBuffer = NULL;
  402. pVerBuffer = (BYTE *) _alloca(cbFileVersionBufSize);
  403. if ( (pVerBuffer != NULL) &&
  404. (GetFileVersionInfo(rgchCrypt32FileName, 0, cbFileVersionBufSize, pVerBuffer) != 0))
  405. {
  406. VS_FIXEDFILEINFO *lpVSFixedFileInfo;
  407. unsigned uiLength;
  408. if( VerQueryValue( pVerBuffer, TEXT("\\"),(LPVOID*)&lpVSFixedFileInfo, &uiLength) != 0
  409. && uiLength != 0)
  410. {
  411. // Crypt32.dll version is 5.131.1877.9 which is the Min version we need.
  412. // 0x50083 ==> 5.131
  413. // 0x07550009 ==> 1877.9
  414. if ((lpVSFixedFileInfo->dwFileVersionMS > 0x50083)
  415. || (lpVSFixedFileInfo->dwFileVersionMS == 0x50083 && lpVSFixedFileInfo->dwFileVersionLS >= 0x07550009))
  416. g_fDoSpecialMagicForSGCCerts = TRUE;
  417. }
  418. }
  419. }
  420. }
  421. }
  422. g_CryptInstallDefaultContext = (CRYPT_INSTALL_DEFAULT_CONTEXT_FN)
  423. GetProcAddress(hCrypt32, CRYPT_INSTALL_DEFAULT_CONTEXT_NAME);
  424. g_CryptUninstallDefaultContext = (CRYPT_UNINSTALL_DEFAULT_CONTEXT_FN)
  425. GetProcAddress(hCrypt32, CRYPT_UNINSTALL_DEFAULT_CONTEXT_NAME);
  426. g_CertFindChainInStore = (CERT_FIND_CHAIN_IN_STORE_FN)
  427. GetProcAddress(hCrypt32, CERT_FIND_CHAIN_IN_STORE_NAME);
  428. g_CertFreeCertificateChain = (CERT_FREE_CERTIFICATE_CHAIN_FN)
  429. GetProcAddress(hCrypt32, CERT_FREE_CERTIFICATE_CHAIN_NAME);
  430. }
  431. quit:
  432. if ( Error != ERROR_SUCCESS )
  433. {
  434. FreeLibrary( hSecurity );
  435. hSecurity = NULL;
  436. }
  437. UNLOCK_SECURITY();
  438. return( Error );
  439. }
  440. // Fortezza related functionality.
  441. //Private functions used by the Fortezza implementation.
  442. static PCCERT_CONTEXT GetCurrentFortezzaCertContext();
  443. static BOOL SetCurrentFortezzaCertContext(PCCERT_CONTEXT);
  444. static DWORD AcquireFortezzaCryptProv(HWND, HCRYPTPROV *);
  445. static DWORD ReleaseFortezzaCryptProv(HCRYPTPROV, BOOL);
  446. static DWORD AcquireFortezzaCertContext(HCRYPTPROV, PCCERT_CONTEXT*);
  447. // Should we do anything regarding Fortezza.
  448. BOOL IsFortezzaInstalled ( )
  449. {
  450. LOCK_FORTEZZA( );
  451. if (!g_bCheckedForFortezza)
  452. {
  453. g_bCheckedForFortezza = TRUE;
  454. g_bFortezzaInstalled = FALSE;
  455. // Try and get the Fortezza CSP context to see if it is present.
  456. HCRYPTPROV hCryptProv = NULL;
  457. if (GlobalEnableFortezza)
  458. {
  459. if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_FORTEZZA, CRYPT_SILENT))
  460. {
  461. // Weird: we should not be allowed to get the context without putting up UI.
  462. // But we will assume Fortezza is enabled.
  463. g_bFortezzaInstalled = TRUE;
  464. CryptReleaseContext(hCryptProv, 0);
  465. }
  466. else
  467. {
  468. DWORD dwError = GetLastError();
  469. // If the last error was NTE_PROV_TYPE_NOT_DEF it means that Fortezza CSP is not
  470. // installed and we should not be trying to get a Fortezza context.
  471. g_bFortezzaInstalled = ((dwError != NTE_PROV_TYPE_NOT_DEF) && (dwError != NTE_PROV_TYPE_NO_MATCH));
  472. }
  473. }
  474. }
  475. UNLOCK_FORTEZZA( );
  476. return g_bFortezzaInstalled;
  477. }
  478. BOOL AttemptedFortezzaLogin( )
  479. {
  480. BOOL bRet ;
  481. LOCK_FORTEZZA();
  482. bRet = g_bAttemptedFortezzaLogin;
  483. UNLOCK_FORTEZZA();
  484. return bRet;
  485. }
  486. // Log's on to the fortezza card. Returns success if you are already logged on.
  487. DWORD FortezzaLogOn(HWND hwnd)
  488. {
  489. DWORD dwError;
  490. LOCK_FORTEZZA();
  491. // If we are already logged on, don't bother. Just succeed.
  492. if (GetCurrentFortezzaCertContext() != NULL)
  493. {
  494. INET_ASSERT(g_bAttemptedFortezzaLogin);
  495. INET_ASSERT(GlobalFortezzaCryptProv);
  496. dwError = ERROR_SUCCESS;
  497. }
  498. else
  499. {
  500. HCRYPTPROV hProv;
  501. g_bAttemptedFortezzaLogin = TRUE;
  502. INET_ASSERT(GlobalFortezzaCryptProv == NULL);
  503. dwError = AcquireFortezzaCryptProv(hwnd, &GlobalFortezzaCryptProv);
  504. if (dwError == ERROR_SUCCESS)
  505. {
  506. INET_ASSERT(GlobalFortezzaCryptProv != NULL);
  507. PCCERT_CONTEXT pCertContext = NULL;
  508. dwError = AcquireFortezzaCertContext(GlobalFortezzaCryptProv, &pCertContext);
  509. if (dwError == ERROR_SUCCESS)
  510. {
  511. //Logged in succesfully.
  512. SetCurrentFortezzaCertContext(pCertContext);
  513. }
  514. }
  515. if (dwError != ERROR_SUCCESS && GlobalFortezzaCryptProv != NULL)
  516. {
  517. ReleaseFortezzaCryptProv(GlobalFortezzaCryptProv, FALSE);
  518. GlobalFortezzaCryptProv = NULL;
  519. }
  520. }
  521. if (dwError == ERROR_SUCCESS)
  522. {
  523. INET_ASSERT(GetCurrentFortezzaCertContext());
  524. INET_ASSERT(GlobalFortezzaCryptProv != NULL);
  525. }
  526. UNLOCK_FORTEZZA( );
  527. return dwError;
  528. }
  529. DWORD FortezzaLogOff(HWND /* hwnd */)
  530. {
  531. LOCK_FORTEZZA();
  532. BOOL bGotCertContext = (GetCurrentFortezzaCertContext() != NULL);
  533. SetCurrentFortezzaCertContext(NULL);
  534. ReleaseFortezzaCryptProv(GlobalFortezzaCryptProv, bGotCertContext);
  535. GlobalFortezzaCryptProv = NULL;
  536. UNLOCK_FORTEZZA( );
  537. return ERROR_SUCCESS;
  538. }
  539. DWORD FortezzaChangePersonality(HWND hwnd)
  540. {
  541. DWORD dwError = ERROR_SUCCESS;
  542. LOCK_FORTEZZA( );
  543. PCCERT_CONTEXT pOldCertContext = GetCurrentFortezzaCertContext( );
  544. if (pOldCertContext != NULL)
  545. {
  546. INET_ASSERT(GlobalFortezzaCryptProv != NULL);
  547. HCRYPTPROV hNewCryptProv = NULL;
  548. PCCERT_CONTEXT pNewCertContext = NULL;
  549. // For the change personality to work we need to get a new handle to a
  550. // Fortezza crypt provider without freeing the old one. ,
  551. // If we free the old one first it will re-prompt the user for the password.
  552. dwError = AcquireFortezzaCryptProv(hwnd, &hNewCryptProv);
  553. if (dwError == ERROR_SUCCESS)
  554. {
  555. dwError = AcquireFortezzaCertContext(hNewCryptProv, &pNewCertContext);
  556. if (dwError == ERROR_SUCCESS)
  557. {
  558. // free up the old CryptProv context
  559. ReleaseFortezzaCryptProv(GlobalFortezzaCryptProv, TRUE);
  560. GlobalFortezzaCryptProv = hNewCryptProv;
  561. // This will automatically free the old cert context.
  562. SetCurrentFortezzaCertContext(pNewCertContext);
  563. }
  564. else
  565. {
  566. ReleaseFortezzaCryptProv(hNewCryptProv, FALSE);
  567. }
  568. }
  569. }
  570. else
  571. {
  572. // We are trying to change personalities when not logged on.
  573. // This is not allowed.
  574. dwError = ERROR_INVALID_PARAMETER;
  575. }
  576. UNLOCK_FORTEZZA( );
  577. return dwError;
  578. }
  579. // Entry points exported outside wininet.
  580. INTERNETAPI_(BOOL) InternetQueryFortezzaStatus(DWORD * pdwStatus, DWORD_PTR dwReserved)
  581. {
  582. DEBUG_ENTER_API((DBG_API,
  583. Bool,
  584. "InternetQueryFortezzaStatus",
  585. "%#x %#x",
  586. pdwStatus, dwReserved
  587. ));
  588. BOOL bRet;
  589. DWORD dwError = ERROR_SUCCESS;
  590. // Initialize the GlobalData since this is an exported entry point.
  591. if (dwReserved!=0)
  592. {
  593. dwError = ERROR_INVALID_PARAMETER;
  594. }
  595. else if (!GlobalDataInitialized)
  596. {
  597. dwError = GlobalDataInitialize( );
  598. }
  599. if (dwError != ERROR_SUCCESS)
  600. {
  601. bRet = FALSE;
  602. }
  603. else if (pdwStatus == NULL)
  604. {
  605. bRet = FALSE;
  606. dwError = ERROR_INVALID_PARAMETER;
  607. }
  608. else
  609. {
  610. if (IsFortezzaInstalled( ))
  611. {
  612. *pdwStatus |= (FORTSTAT_INSTALLED);
  613. }
  614. if (GetCurrentFortezzaCertContext() != NULL)
  615. {
  616. *pdwStatus |= (FORTSTAT_LOGGEDON);
  617. }
  618. bRet = TRUE;
  619. }
  620. if (!bRet)
  621. {
  622. SetLastError(dwError);
  623. DEBUG_ERROR(INET, dwError);
  624. }
  625. DEBUG_LEAVE_API(bRet);
  626. return bRet;
  627. }
  628. INTERNETAPI_(BOOL) InternetFortezzaCommand(DWORD dwCommand, HWND hwnd, DWORD_PTR dwReserved)
  629. {
  630. DEBUG_ENTER_API((DBG_API,
  631. Bool,
  632. "InternetFortezzaCommand",
  633. "%d, %#x, %#x",
  634. dwCommand, hwnd, dwReserved
  635. ));
  636. BOOL bRet = TRUE;
  637. DWORD dwError = ERROR_SUCCESS;
  638. // Initialize the GlobalData since this is an exported entry point.
  639. if (dwReserved!=0)
  640. {
  641. dwError = ERROR_INVALID_PARAMETER;
  642. }
  643. else if (!GlobalDataInitialized)
  644. {
  645. dwError = GlobalDataInitialize( );
  646. }
  647. // Next make sure that the security dlls are loaded.
  648. if (dwError == ERROR_SUCCESS)
  649. dwError = LoadSecurity( );
  650. // If all is fine, then try the actual command.
  651. if (dwError == ERROR_SUCCESS)
  652. {
  653. // Dispatch based on the command.
  654. switch (dwCommand)
  655. {
  656. case FORTCMD_LOGON:
  657. dwError = FortezzaLogOn(hwnd);
  658. break;
  659. case FORTCMD_LOGOFF:
  660. dwError = FortezzaLogOff(hwnd);
  661. break;
  662. case FORTCMD_CHG_PERSONALITY:
  663. dwError = FortezzaChangePersonality(hwnd);
  664. break;
  665. default:
  666. dwError = ERROR_INVALID_PARAMETER;
  667. }
  668. }
  669. if (dwError != ERROR_SUCCESS)
  670. {
  671. bRet = FALSE;
  672. DEBUG_ERROR(INET, dwError);
  673. SetLastError(dwError);
  674. }
  675. else
  676. {
  677. LOCK_SECURITY( );
  678. // If we were successful to this point we should re-init the security packages so
  679. // we acquire a credentials handle with the new cert context selected correctly.
  680. // The Last error will be set by SecurityPkgInitialize if it fails.
  681. bRet = SecurityPkgInitialize(TRUE);
  682. UNLOCK_SECURITY( );
  683. }
  684. DEBUG_LEAVE_API(bRet);
  685. return bRet;
  686. }
  687. /*++
  688. Gets the cert context being used for Fortezza connections.
  689. Routine description
  690. Returns:
  691. pCertContext if one is in use. NULL otherwise.
  692. */
  693. PCCERT_CONTEXT GetCurrentFortezzaCertContext()
  694. {
  695. PCCERT_CONTEXT pCertContext = NULL;
  696. DWORD dwIndex;
  697. LOCK_FORTEZZA( );
  698. // Find the unified service provider entry.
  699. for ( dwIndex = 0 ; SecProviders[dwIndex].pszName != NULL ; dwIndex++ )
  700. {
  701. if (0 == stricmp(UNISP_NAME, SecProviders[dwIndex].pszName))
  702. {
  703. pCertContext = SecProviders[dwIndex].pCertCtxt ;
  704. break;
  705. }
  706. }
  707. // Something is wrong if we didn't find the Unified Service provider in our list.
  708. INET_ASSERT(SecProviders[dwIndex].pszName != NULL);
  709. UNLOCK_FORTEZZA( );
  710. return pCertContext;
  711. }
  712. /*++
  713. Sets the passed in cert context to be the one that is used for Fortezza
  714. connections.
  715. Routine description
  716. This function simply takes a Fortezza context and remembers it on the unified
  717. secure providers table.
  718. Arguments:
  719. pCertContext - The cert context to be saved away.
  720. */
  721. BOOL SetCurrentFortezzaCertContext(PCCERT_CONTEXT pCertContext)
  722. {
  723. DWORD dwIndex;
  724. LOCK_FORTEZZA( );
  725. // Find the unified service provider entry.
  726. for ( dwIndex = 0 ; SecProviders[dwIndex].pszName != NULL ; dwIndex++ )
  727. {
  728. if (0 == stricmp(UNISP_NAME, SecProviders[dwIndex].pszName))
  729. {
  730. if (SecProviders[dwIndex].pCertCtxt)
  731. CertFreeCertificateContext(SecProviders[dwIndex].pCertCtxt);
  732. SecProviders[dwIndex].pCertCtxt = pCertContext;
  733. break;
  734. }
  735. }
  736. // Something is wrong if we didn't find the Unified Service provider in our list.
  737. INET_ASSERT(SecProviders[dwIndex].pszName != NULL);
  738. UNLOCK_FORTEZZA( );
  739. return TRUE;
  740. }
  741. /*++
  742. Acquire a fortezza crypt provider.
  743. Routine Description
  744. This function calls the Fortezza CSP which might prompt the end-user for
  745. the PIN # to read the certificates of the Fortezza card. If the user is
  746. already logged on to the card the logon UI will not be shown.
  747. Arguments:
  748. hwnd - used to put up the pin UI.
  749. pCryptProv - returns a handle to a crypt provider if succesful.
  750. Return Value:
  751. WINDOWS Error Code.
  752. --*/
  753. DWORD AcquireFortezzaCryptProv(HWND hwnd, HCRYPTPROV *pCryptProv)
  754. {
  755. DWORD dwError = NOERROR;
  756. BOOL bResethwnd = FALSE;
  757. if (pCryptProv == NULL)
  758. {
  759. return ERROR_INVALID_PARAMETER;
  760. }
  761. // Set up to do the UI.
  762. if ( CryptSetProvParam(NULL, PP_CLIENT_HWND, (BYTE *)&hwnd, 0))
  763. {
  764. bResethwnd = TRUE;
  765. }
  766. //
  767. // Attempt to log on to Fortezza card. This call will typically
  768. // display a dialog box.
  769. //
  770. // Note that within the CryptAcquireContext function, the Fortezza
  771. // CSP populated the MY store with the Fortezza certificate chain.
  772. // At least, it will once it's finished.
  773. //
  774. if(!CryptAcquireContext(pCryptProv, NULL, NULL, PROV_FORTEZZA, 0))
  775. {
  776. dwError = GetLastError();
  777. }
  778. if (bResethwnd)
  779. {
  780. CryptSetProvParam(NULL, PP_CLIENT_HWND, NULL, 0);
  781. }
  782. return(dwError);
  783. }
  784. /*++
  785. Releases the Fortezza Crypt Provider
  786. Routine Description:
  787. Frees the crypt provider if the second argument is FALSE.
  788. Does nothing if the second argument is TRUE.
  789. The crypto API has this strange behavior ( i am being gracious
  790. in my description here) where when a hCryptProv is passed into
  791. CertSetCertificateContextProperty it holds on to the pointer but does not increment the
  792. refcount. When the cert context is freed it does free the hCryptProv.
  793. To workaround this behavior we never free the hCryptProv, just the Fortezza cert context.
  794. Arguments:
  795. hCryptProv - The CryptProv to free.
  796. bGotCertContext - did we get a Fortezza Cert Context using this provider.
  797. **/
  798. DWORD ReleaseFortezzaCryptProv(HCRYPTPROV hCryptProv, BOOL bGotCertContext )
  799. {
  800. DWORD dwError;
  801. if (hCryptProv==NULL)
  802. {
  803. dwError = NOERROR;
  804. }
  805. else
  806. {
  807. if (!CryptReleaseContext(hCryptProv, 0))
  808. dwError = GetLastError();
  809. else
  810. dwError = NOERROR;
  811. }
  812. return dwError;
  813. }
  814. DWORD AcquireFortezzaCertContext(HCRYPTPROV hFortezzaCryptProv, PCCERT_CONTEXT *ppCertContext)
  815. /*++
  816. Routine Description:
  817. This function calls the Fortezza CSP which will prompt the
  818. user for the PIN # to read the certificates off the Fortezza
  819. card.
  820. Arguments:
  821. [IN] hCryptProv - Handle to the Fortezza Crypt Provider.
  822. [OUT] ppCertContext - will have the cert context if returns succesfully.
  823. Return Value:
  824. WINDOWS Error Code.
  825. --*/
  826. {
  827. DWORD error = ERROR_SUCCESS; // Return code.
  828. DWORD status = ERROR_SUCCESS; // Error value if one of the crypto APIs failed.
  829. CRYPT_HASH_BLOB HashBlob;
  830. BYTE rgbHash[20];
  831. DWORD cbHash;
  832. PBYTE pbChain = NULL;
  833. DWORD cbChain;
  834. PBYTE pbCert;
  835. DWORD cbCert;
  836. PCCERT_CONTEXT pCertContext = NULL;
  837. BOOL bResethwnd = FALSE;
  838. DWORD dwIndex;
  839. DEBUG_ENTER((DBG_HTTP,
  840. Dword,
  841. "AcquireFortezzaContext",
  842. "%#x",
  843. hFortezzaCryptProv
  844. ));
  845. if (hFortezzaCryptProv == NULL || ppCertContext == NULL)
  846. {
  847. return ERROR_INVALID_PARAMETER;
  848. }
  849. LOCK_FORTEZZA();
  850. if (!IsFortezzaInstalled( ))
  851. {
  852. INET_ASSERT(FALSE); // Should not get called if Fortezza is not installed.
  853. goto done; // Just ignore the request.
  854. }
  855. if(g_bOpenMyCertStore && g_hMyCertStore == NULL)
  856. ReopenMyCertStore();
  857. if(g_hMyCertStore == NULL)
  858. {
  859. status = SEC_E_NO_CREDENTIALS;
  860. goto done;
  861. }
  862. //
  863. // Read the appropriate leaf certificate from the card, and
  864. // obtain its MD5 thumbprint.
  865. //
  866. // Get length of certificate chain.
  867. if(!CryptGetProvParam(hFortezzaCryptProv, PP_CERTCHAIN, NULL, &cbChain, 0))
  868. {
  869. status = GetLastError();
  870. DEBUG_PRINT(API,
  871. ERROR,
  872. ("**** Error 0x%x reading certificate from CSP\n",
  873. status
  874. ));
  875. goto done;
  876. }
  877. // Allocate memory for certificate chain.
  878. pbChain = (BYTE *)ALLOCATE_MEMORY(LMEM_FIXED | LMEM_ZEROINIT, cbChain);
  879. if(pbChain == NULL)
  880. {
  881. status = ERROR_NOT_ENOUGH_MEMORY;
  882. DEBUG_PRINT(API,
  883. ERROR,
  884. ("**** Out of memory\n"));
  885. goto done;
  886. }
  887. // Download certificate chain from CSP.
  888. if(!CryptGetProvParam(hFortezzaCryptProv, PP_CERTCHAIN, pbChain, &cbChain, 0))
  889. {
  890. status = GetLastError();
  891. DEBUG_PRINT(API,
  892. ERROR,
  893. ("**** Error 0x%x reading certificate from CSP\n",
  894. status
  895. ));
  896. goto done;
  897. }
  898. // Parse out the leaf certificate.
  899. cbCert = *(PDWORD)pbChain;
  900. pbCert = pbChain + sizeof(DWORD);
  901. // Decode the leaf certificate.
  902. pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING,
  903. pbCert,
  904. cbCert);
  905. if(pCertContext == NULL)
  906. {
  907. status = GetLastError();
  908. DEBUG_PRINT(API,
  909. ERROR,
  910. ("**** Error 0x%x parsing certificate\n",
  911. status
  912. ));
  913. goto done;
  914. }
  915. // Get thumbprint of certificate.
  916. cbHash = sizeof(rgbHash);
  917. if(!CertGetCertificateContextProperty(pCertContext,
  918. CERT_MD5_HASH_PROP_ID,
  919. rgbHash,
  920. &cbHash))
  921. {
  922. status = GetLastError();
  923. DEBUG_PRINT(API,
  924. ERROR,
  925. ("**** Error 0x%x reading MD5 property\n",
  926. status
  927. ));
  928. goto done;
  929. }
  930. // Free certificate chain.
  931. FREE_MEMORY(pbChain);
  932. pbChain = NULL;
  933. // Free certificate context.
  934. CertFreeCertificateContext(pCertContext);
  935. pCertContext = NULL;
  936. //
  937. // Search the "MY" certificate store for the certificate with
  938. // the matching thumbprint.
  939. //
  940. HashBlob.cbData = cbHash;
  941. HashBlob.pbData = rgbHash;
  942. if(g_bOpenMyCertStore && g_hMyCertStore == NULL)
  943. ReopenMyCertStore();
  944. pCertContext = CertFindCertificateInStore(g_hMyCertStore,
  945. X509_ASN_ENCODING,
  946. 0,
  947. CERT_FIND_MD5_HASH,
  948. &HashBlob,
  949. NULL);
  950. if(pCertContext == NULL)
  951. {
  952. DEBUG_PRINT(API,
  953. ERROR,
  954. ("**** Leaf certificate not found in MY store\n"));
  955. status = SEC_E_NO_CREDENTIALS;
  956. goto done;
  957. }
  958. //
  959. // Attach the Fortezza hProv to the certificate context.
  960. //
  961. if(!CertSetCertificateContextProperty(
  962. pCertContext,
  963. CERT_KEY_PROV_HANDLE_PROP_ID,
  964. 0,
  965. (PVOID)hFortezzaCryptProv))
  966. {
  967. status = GetLastError();
  968. DEBUG_PRINT(API,
  969. ERROR,
  970. ("**** Error 0x%x setting KEY_PROV_HANDLE property\n",
  971. status
  972. ));
  973. goto done;
  974. }
  975. INET_ASSERT(pCertContext != NULL);
  976. *ppCertContext = pCertContext;
  977. pCertContext = NULL;
  978. status = SEC_E_OK;
  979. done:
  980. if(pbChain) FREE_MEMORY(pbChain);
  981. if(pCertContext) CertFreeCertificateContext(pCertContext);
  982. UNLOCK_FORTEZZA();
  983. DEBUG_LEAVE(error);
  984. return error;
  985. }