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.

2486 lines
68 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. security.cpp
  5. Abstract:
  6. This module contains definition for the CSecurityCtx class.
  7. Author:
  8. Johnson Apacible (JohnsonA) 18-Sept-1995
  9. Revision History:
  10. --*/
  11. #if !defined(dllexp)
  12. #define dllexp __declspec( dllexport )
  13. #endif // !defined( dllexp )
  14. /*
  15. #include <dbgutil.h>
  16. #include <tcpdll.hxx>
  17. #include <tcpsvcs.h>
  18. #include <tcpdebug.h>
  19. #include <tsvcinfo.hxx>
  20. #include <inetdata.h>
  21. */
  22. extern "C" {
  23. #include <nt.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. }
  27. #include <windows.h>
  28. #include <wincrypt.h>
  29. #include <stdlib.h>
  30. #include <dbgtrace.h>
  31. #include <inetinfo.h>
  32. //
  33. // SSL and SSPI related include files
  34. //
  35. #include <dbgutil.h>
  36. #include <buffer.hxx>
  37. #include <ole2.h>
  38. #include <imd.h>
  39. #include <iadm.h>
  40. #include <mb.hxx>
  41. #define DEFINE_SIMSSL_GLOBAL
  42. extern "C" {
  43. #define SECURITY_WIN32
  44. #include <sspi.h>
  45. #include <ntsecapi.h>
  46. #include <spseal.h>
  47. //#include <sslsp.h>
  48. #include <schnlsp.h>
  49. #include ".\credcach.hxx"
  50. }
  51. #include <certnotf.hxx>
  52. //#include "sslmsgs.h"
  53. #include "simssl2.h"
  54. #define CORE_SSL_KEY_LIST_SECRET L"%S_KEY_LIST"
  55. //
  56. // try/finally macros
  57. //
  58. #define START_TRY __try {
  59. #define END_TRY }
  60. #define TRY_EXCEPT } __except(EXCEPTION_EXECUTE_HANDLER) {
  61. #define START_FINALLY } __finally {
  62. //
  63. // tracing
  64. //
  65. #define ENTER( _x_ ) TraceFunctEnter( _x_ );
  66. #define LEAVE TraceFunctLeave( );
  67. #define MAX_SECRET_NAME 255
  68. #define MAX_ADDRESS_LEN 64
  69. typedef VOID (WINAPI FAR *PFN_SCHANNEL_INVALIDATE_CACHE)(
  70. VOID
  71. );
  72. VOID WINAPI NotifySslChanges(
  73. DWORD dwNotifyType,
  74. LPVOID pInstance
  75. );
  76. //
  77. // The list of encryption packages we support. PCT goes first since it's a
  78. // superset of SSL
  79. //
  80. struct _ENC_PROVIDER EncProviders[] =
  81. {
  82. UNISP_NAME_W, ENC_CAPS_PCT|ENC_CAPS_SSL, FALSE,
  83. PCT1SP_NAME_W, ENC_CAPS_PCT, FALSE,
  84. SSL3SP_NAME_W, ENC_CAPS_SSL, FALSE,
  85. SSL2SP_NAME_W, ENC_CAPS_SSL, FALSE,
  86. NULL, FALSE, FALSE
  87. };
  88. struct _ENC_PROVIDER EncLsaProviders[] =
  89. {
  90. UNISP_NAME_W L" X", ENC_CAPS_PCT|ENC_CAPS_SSL, FALSE,
  91. PCT1SP_NAME_W L" X", ENC_CAPS_PCT, FALSE,
  92. SSL3SP_NAME_W L" X", ENC_CAPS_SSL, FALSE,
  93. SSL2SP_NAME_W L" X", ENC_CAPS_SSL, FALSE,
  94. NULL, FALSE, FALSE
  95. };
  96. struct _ENC_PROVIDER* pEncProviders = EncProviders;
  97. //
  98. // service specific string names
  99. //
  100. WCHAR CEncryptCtx::wszServiceName[16];
  101. //char CEncryptCtx::szLsaPrefix[16];
  102. BOOL CEncryptCtx::m_IsSecureCapable = FALSE;
  103. //
  104. // hSecurity - NULL when security.dll/secur32.dll is not loaded
  105. //
  106. HINSTANCE CEncryptCtx::m_hSecurity = NULL;
  107. HINSTANCE CEncryptCtx::m_hLsa = NULL;
  108. PVOID CEncryptCtx::m_psmcMapContext = NULL;
  109. //
  110. // g_pSecFuncTable - Pointer to Global Structure of Pointers that are used
  111. // for storing the entry points into the SCHANNEL.dll
  112. //
  113. PSecurityFunctionTableW g_pSecFuncTableW = NULL;
  114. HINSTANCE g_hSchannel = NULL;
  115. //
  116. // NB : Under NT 5, the SslEmptyCache function is no longer supported
  117. //
  118. PFN_SCHANNEL_INVALIDATE_CACHE g_pfnFlushSchannelCache = NULL;
  119. #if 0
  120. LSAOPENPOLICY g_LsaOpenPolicy = NULL;
  121. LSARETRIEVEPRIVATEDATA g_LsaRetrievePrivateData = NULL;
  122. LSACLOSE g_LsaClose = NULL;
  123. LSANTSTATUSTOWINERROR g_LsaNtStatusToWinError = NULL;
  124. LSAFREEMEMORY g_LsaFreeMemory = NULL;
  125. #endif
  126. VOID
  127. AsciiStringToUnicode(
  128. IN LPWSTR UnicodeString,
  129. IN LPSTR AsciiString
  130. )
  131. {
  132. while ( (*UnicodeString++ = (WCHAR)*AsciiString++) != (WCHAR)'\0');
  133. } // AsciiStringToUnicode
  134. BOOL
  135. CEncryptCtx::Initialize(
  136. LPSTR pszServiceName,
  137. IMDCOM* pImdcom,
  138. PVOID psmcMapContext,
  139. PVOID pvAdminBase
  140. //LPSTR pszLsaPrefix
  141. )
  142. /*++
  143. Routine Description:
  144. Activates the security package
  145. Arguments:
  146. None.
  147. Return Value:
  148. TRUE, if successful. FALSE, otherwise.
  149. --*/
  150. {
  151. ENTER("CEncryptCtx::Initialize")
  152. BOOL fSuccess = FALSE;
  153. DWORD cb;
  154. SECURITY_STATUS ss;
  155. PSecPkgInfoW pPackageInfo = NULL;
  156. ULONG cPackages;
  157. ULONG i;
  158. ULONG fCaps;
  159. DWORD dwEncFlags = ENC_CAPS_DEFAULT;
  160. DWORD cProviders = 0;
  161. #if 0
  162. UNICODE_STRING* punitmp;
  163. WCHAR achSecretName[MAX_SECRET_NAME+1];
  164. #endif
  165. OSVERSIONINFO os;
  166. PSERVICE_MAPPING_CONTEXT psmc = (PSERVICE_MAPPING_CONTEXT)psmcMapContext;
  167. extern IMDCOM* pMDObject ;
  168. extern IMSAdminBaseW* pAdminObject ;
  169. pMDObject = pImdcom ;
  170. m_psmcMapContext = psmcMapContext ;
  171. pAdminObject = (IMSAdminBaseW*)pvAdminBase ;
  172. //
  173. // deal with different security packages DLL on different platforms
  174. //
  175. INITSECURITYINTERFACE pfInitSecurityInterfaceW = NULL;
  176. _ASSERT( m_hSecurity == NULL );
  177. _ASSERT( m_hLsa == NULL );
  178. //
  179. // load dll.
  180. //
  181. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  182. _VERIFY( GetVersionEx( &os ) );
  183. if ( os.dwPlatformId == VER_PLATFORM_WIN32_NT )
  184. {
  185. m_hSecurity = LoadLibrary("security");
  186. }
  187. else
  188. {
  189. m_hSecurity = LoadLibrary("secur32");
  190. }
  191. if ( m_hSecurity == NULL )
  192. {
  193. ErrorTrace( 0, "LoadLibrary failed: %d", GetLastError() );
  194. goto quit;
  195. }
  196. //
  197. // only on NT get the LSA function pointers
  198. //
  199. if ( os.dwPlatformId == VER_PLATFORM_WIN32_NT )
  200. {
  201. #if 0
  202. m_hLsa = LoadLibrary("advapi32");
  203. if ( m_hLsa == NULL )
  204. {
  205. ErrorTrace( 0, "LoadLibrary ADVAPI32 failed: %d", GetLastError() );
  206. goto quit;
  207. }
  208. g_LsaOpenPolicy = (LSAOPENPOLICY)
  209. GetProcAddress( m_hLsa, "LsaOpenPolicy" );
  210. if ( g_LsaOpenPolicy == NULL )
  211. {
  212. ErrorTrace( 0, "LsaOpenPolicy GetProcAddress failed: %d", GetLastError() );
  213. goto quit;
  214. }
  215. g_LsaRetrievePrivateData = (LSARETRIEVEPRIVATEDATA)
  216. GetProcAddress( m_hLsa, "LsaRetrievePrivateData" );
  217. if ( g_LsaRetrievePrivateData == NULL )
  218. {
  219. ErrorTrace( 0, "LsaRetrievePrivateData GetProcAddress failed: %d", GetLastError() );
  220. goto quit;
  221. }
  222. g_LsaClose = (LSACLOSE)
  223. GetProcAddress( m_hLsa, "LsaClose" );
  224. if ( g_LsaClose == NULL )
  225. {
  226. ErrorTrace( 0, "LsaClose GetProcAddress failed: %d", GetLastError() );
  227. goto quit;
  228. }
  229. g_LsaNtStatusToWinError = (LSANTSTATUSTOWINERROR)
  230. GetProcAddress( m_hLsa, "LsaNtStatusToWinError" );
  231. if ( g_LsaNtStatusToWinError == NULL )
  232. {
  233. ErrorTrace( 0, "LsaNtStatusToWinError GetProcAddress failed: %d", GetLastError() );
  234. goto quit;
  235. }
  236. g_LsaFreeMemory = (LSAFREEMEMORY)
  237. GetProcAddress( m_hLsa, "LsaFreeMemory" );
  238. if ( g_LsaFreeMemory == NULL )
  239. {
  240. ErrorTrace( 0, "LsaFreeMemory GetProcAddress failed: %d", GetLastError() );
  241. goto quit;
  242. }
  243. #endif
  244. }
  245. //
  246. // get function addresses for ansi entries.
  247. //
  248. pfInitSecurityInterfaceW = (INITSECURITYINTERFACE)
  249. GetProcAddress( m_hSecurity, SECURITY_ENTRYPOINTW );
  250. if ( pfInitSecurityInterfaceW == NULL )
  251. {
  252. ErrorTrace( 0, "GetProcAddress failed: %d", GetLastError() );
  253. goto quit;
  254. }
  255. g_pSecFuncTableW = (SecurityFunctionTableW*)((*pfInitSecurityInterfaceW)());
  256. if ( g_pSecFuncTableW == NULL )
  257. {
  258. ErrorTrace( 0, "SecurityFunctionTable failed: %d", GetLastError() );
  259. goto quit;
  260. }
  261. //
  262. // Initialize cached credential data
  263. //
  264. InitializeCriticalSection( &csGlobalLock );
  265. InitCredCache();
  266. if ( g_hSchannel = LoadLibrary( "schannel.dll" ) )
  267. {
  268. g_pfnFlushSchannelCache = (PFN_SCHANNEL_INVALIDATE_CACHE)GetProcAddress(
  269. g_hSchannel, "SslEmptyCache" );
  270. }
  271. //
  272. // Client implementations do not require Lsa secrets
  273. //
  274. if ( pszServiceName )
  275. {
  276. cb = lstrlen( pszServiceName ) + 1;
  277. if ( cb*2 > sizeof( wszServiceName ) )
  278. {
  279. ErrorTrace( 0, "szServiceName too long" );
  280. goto quit;
  281. }
  282. //CopyMemory( szServiceName, pszServiceName, cb );
  283. AsciiStringToUnicode( wszServiceName, pszServiceName );
  284. }
  285. #if 0
  286. if ( pszLsaPrefix )
  287. {
  288. cb = lstrlen( pszLsaPrefix ) + 1;
  289. if ( cb > sizeof( szLsaPrefix ) )
  290. {
  291. ErrorTrace( 0, "szLsaPrefix too long" );
  292. goto quit;
  293. }
  294. CopyMemory( szLsaPrefix, pszLsaPrefix, cb );
  295. }
  296. #endif
  297. //
  298. // Get the list of security packages on this machine
  299. //
  300. ss = g_EnumerateSecurityPackages( &cPackages, &pPackageInfo );
  301. if ( ss != STATUS_SUCCESS )
  302. {
  303. ErrorTrace( 0, "g_EnumerateSecurityPackages failed: 0x%08X", ss );
  304. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  305. goto quit;
  306. }
  307. for ( i = 0; i < cPackages ; i++ )
  308. {
  309. //
  310. // We'll only use the security package if it supports connection
  311. // oriented security and it supports the appropriate side (client
  312. // or server)
  313. //
  314. fCaps = pPackageInfo[i].fCapabilities;
  315. if ( fCaps & SECPKG_FLAG_STREAM )
  316. {
  317. if ( fCaps & SECPKG_FLAG_CLIENT_ONLY ||
  318. !(fCaps & SECPKG_FLAG_PRIVACY ))
  319. {
  320. continue;
  321. }
  322. //
  323. // Does it match one of our known packages and are we configured
  324. // to use it?
  325. //
  326. for ( int j = 0; pEncProviders[j].pszName != NULL; j++ )
  327. {
  328. if ( !wcscmp( pPackageInfo[i].Name, pEncProviders[j].pszName ) &&
  329. pEncProviders[j].dwFlags & dwEncFlags )
  330. {
  331. pEncProviders[j].fEnabled = TRUE;
  332. cProviders++;
  333. }
  334. }
  335. }
  336. }
  337. g_FreeContextBuffer( pPackageInfo );
  338. if ( !cProviders )
  339. {
  340. //
  341. // The package wasn't found, fail this filter's load
  342. //
  343. ErrorTrace( 0, "No security packages were found" );
  344. SetLastError( (DWORD) SEC_E_SECPKG_NOT_FOUND );
  345. //
  346. // not a fatal error
  347. //
  348. fSuccess = TRUE;
  349. goto quit;
  350. }
  351. #if 0
  352. //
  353. // The package is installed. Check to see if there are any keys
  354. // installed
  355. //
  356. if ( os.dwPlatformId == VER_PLATFORM_WIN32_NT && pszLsaPrefix )
  357. {
  358. wsprintfW( achSecretName,
  359. CORE_SSL_KEY_LIST_SECRET,
  360. szLsaPrefix );
  361. if ( !GetSecretW( achSecretName, &punitmp ) )
  362. {
  363. ErrorTrace( 0, "GetSecretW returned error %d", GetLastError() );
  364. //
  365. // Looks like no secrets are installed, fail to load, don't log an
  366. // event
  367. //
  368. SetLastError( NO_ERROR );
  369. //
  370. // not a fatal error
  371. //
  372. fSuccess = TRUE;
  373. goto quit;
  374. }
  375. g_LsaFreeMemory( punitmp );
  376. }
  377. #endif
  378. if ( psmc )
  379. {
  380. if (!psmc->ServerSupportFunction(
  381. NULL,
  382. (LPVOID)NotifySslChanges,
  383. (UINT)SIMSSL_NOTIFY_MAPPER_CERT11_CHANGED ) ||
  384. !psmc->ServerSupportFunction(
  385. NULL,
  386. (LPVOID)NotifySslChanges,
  387. (UINT)SIMSSL_NOTIFY_MAPPER_CERTW_CHANGED ) ||
  388. !psmc->ServerSupportFunction(
  389. NULL,
  390. (LPVOID)NotifySslChanges,
  391. (UINT)SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED ))
  392. {
  393. _ASSERT( FALSE );
  394. fSuccess = FALSE;
  395. goto quit;
  396. }
  397. }
  398. //
  399. // if we got here everything is cool for secure communications
  400. //
  401. fSuccess = m_IsSecureCapable = TRUE;
  402. quit:
  403. if ( fSuccess == FALSE )
  404. {
  405. if ( m_hSecurity != NULL )
  406. {
  407. FreeLibrary( m_hSecurity );
  408. m_hSecurity = NULL;
  409. }
  410. if ( m_hLsa != NULL )
  411. {
  412. FreeLibrary( m_hLsa );
  413. m_hLsa = NULL;
  414. }
  415. }
  416. LEAVE
  417. return fSuccess;
  418. } // Initialize
  419. VOID
  420. CEncryptCtx::Terminate(
  421. VOID
  422. )
  423. /*++
  424. Routine Description:
  425. Terminates the security package
  426. Arguments:
  427. None.
  428. Return Value:
  429. None.
  430. --*/
  431. {
  432. ENTER("CEncryptCtx::Terminate")
  433. PSERVICE_MAPPING_CONTEXT psmc = (PSERVICE_MAPPING_CONTEXT)m_psmcMapContext;
  434. //
  435. // Close cached credential handles
  436. //
  437. FreeCredCache();
  438. //
  439. // NB : Under NT 5, the SslEmptyCache function is no longer supported
  440. //
  441. #if 0
  442. if ( g_pfnFlushSchannelCache )
  443. {
  444. (g_pfnFlushSchannelCache)();
  445. }
  446. #endif
  447. if ( g_hSchannel )
  448. {
  449. FreeLibrary( g_hSchannel );
  450. }
  451. if ( psmc )
  452. {
  453. if (!psmc->ServerSupportFunction(
  454. NULL,
  455. (LPVOID)NULL,
  456. (UINT)SIMSSL_NOTIFY_MAPPER_CERT11_CHANGED ) ||
  457. !psmc->ServerSupportFunction(
  458. NULL,
  459. (LPVOID)NULL,
  460. (UINT)SIMSSL_NOTIFY_MAPPER_CERTW_CHANGED ) ||
  461. !psmc->ServerSupportFunction(
  462. NULL,
  463. (LPVOID)NULL,
  464. (UINT)SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED ))
  465. {
  466. _ASSERT( FALSE );
  467. }
  468. }
  469. DeleteCriticalSection( &csGlobalLock );
  470. if ( m_hSecurity != NULL )
  471. {
  472. FreeLibrary( m_hSecurity );
  473. m_hSecurity = NULL;
  474. }
  475. if ( m_hLsa != NULL )
  476. {
  477. FreeLibrary( m_hLsa );
  478. m_hLsa = NULL;
  479. }
  480. LEAVE
  481. return;
  482. } // Terminate
  483. CEncryptCtx::CEncryptCtx( BOOL IsClient, DWORD dwSslAccessPerms ) :
  484. m_IsClient( IsClient ),
  485. m_haveSSLCtxtHandle( FALSE ),
  486. m_cbSealHeaderSize( 0 ),
  487. m_cbSealTrailerSize( 0 ),
  488. m_IsAuthenticated( FALSE ),
  489. m_IsNewSSLSession( TRUE ),
  490. m_IsEncrypted( FALSE ),
  491. m_phCredInUse( NULL ),
  492. m_iCredInUse( 0 ),
  493. m_phCreds( NULL ),
  494. m_dwSslAccessPerms( dwSslAccessPerms ),
  495. m_hSSPToken( NULL ),
  496. m_dwKeySize( 0 )
  497. /*++
  498. Routine Description:
  499. Class constructor
  500. Arguments:
  501. None.
  502. Return Value:
  503. None
  504. --*/
  505. {
  506. ZeroMemory( (PVOID)&m_hSealCtxt, sizeof(m_hSealCtxt) );
  507. } // CEncryptCtx
  508. CEncryptCtx::~CEncryptCtx(
  509. VOID
  510. )
  511. /*++
  512. Routine Description:
  513. Class destructor
  514. Arguments:
  515. None.
  516. Return Value:
  517. None
  518. --*/
  519. {
  520. Reset();
  521. } // ~CEncryptCtx
  522. VOID
  523. CEncryptCtx::Reset(
  524. VOID
  525. )
  526. /*++
  527. Routine Description:
  528. resets the instance to reauth user
  529. Arguments:
  530. None.
  531. Return Value:
  532. None
  533. --*/
  534. {
  535. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::Reset" );
  536. m_cbSealHeaderSize = 0;
  537. m_cbSealTrailerSize = 0;
  538. m_IsAuthenticated = FALSE;
  539. m_IsNewSSLSession = TRUE;
  540. m_IsEncrypted = FALSE;
  541. m_phCredInUse = NULL;
  542. m_iCredInUse = 0;
  543. if ( m_haveSSLCtxtHandle == TRUE )
  544. {
  545. g_DeleteSecurityContext( &m_hSealCtxt );
  546. m_haveSSLCtxtHandle = FALSE;
  547. }
  548. ZeroMemory( (PVOID)&m_hSealCtxt, sizeof(m_hSealCtxt) );
  549. //mikeswa 4/1/99
  550. //According to JBanes, it is not legal to Free the credentials
  551. //handle before deleting the associated security context.
  552. //Moving release to after delete just in case this is the
  553. //final release.
  554. if (m_phCreds != NULL) {
  555. ((CRED_CACHE_ITEM *) m_phCreds)->Release();
  556. }
  557. m_phCreds = NULL;
  558. //
  559. // Close the NT token obtained during cert mapping
  560. //
  561. if( m_hSSPToken )
  562. {
  563. _ASSERT( m_dwSslAccessPerms & MD_ACCESS_MAP_CERT );
  564. _VERIFY( CloseHandle( m_hSSPToken ) );
  565. m_hSSPToken = NULL;
  566. }
  567. } // ~CEncryptCtx
  568. BOOL
  569. CEncryptCtx::SealMessage(
  570. IN LPBYTE Message,
  571. IN DWORD cbMessage,
  572. OUT LPBYTE pBuffOut,
  573. OUT DWORD *pcbBuffOut
  574. )
  575. /*++
  576. Routine Description:
  577. Encrypt message
  578. Arguments:
  579. Message - message to be encrypted
  580. cbMessage - size of message to be encrypted
  581. Return Value:
  582. Status of operation
  583. --*/
  584. {
  585. SECURITY_STATUS ss = ERROR_NOT_SUPPORTED;
  586. SecBufferDesc inputBuffer;
  587. SecBuffer inBuffers[3];
  588. DWORD encryptedLength;
  589. DWORD iBuff = 0;
  590. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::SealMessage");
  591. if ( m_haveSSLCtxtHandle ) {
  592. encryptedLength = cbMessage + GetSealHeaderSize() + GetSealTrailerSize();
  593. DebugTrace( (LPARAM)this,
  594. "InBuf: 0x%08X, OutBuf: 0x%08X, in: %d, max: %d, out: %d",
  595. Message, pBuffOut, cbMessage,
  596. *pcbBuffOut, encryptedLength );
  597. //
  598. // don't do the MoveMemory if the app is SSL/PCT buffer aware
  599. //
  600. if ( Message != pBuffOut + GetSealHeaderSize() )
  601. {
  602. MoveMemory( pBuffOut + GetSealHeaderSize(),
  603. Message,
  604. cbMessage );
  605. }
  606. if ( GetSealHeaderSize() )
  607. {
  608. inBuffers[iBuff].pvBuffer = pBuffOut;
  609. inBuffers[iBuff].cbBuffer = GetSealHeaderSize();
  610. inBuffers[iBuff].BufferType = SECBUFFER_TOKEN;
  611. iBuff++;
  612. }
  613. inBuffers[iBuff].pvBuffer = pBuffOut + GetSealHeaderSize();
  614. inBuffers[iBuff].cbBuffer = cbMessage;
  615. inBuffers[iBuff].BufferType = SECBUFFER_DATA;
  616. iBuff++;
  617. if ( GetSealTrailerSize() )
  618. {
  619. inBuffers[iBuff].pvBuffer = pBuffOut + GetSealHeaderSize() + cbMessage;
  620. inBuffers[iBuff].cbBuffer = GetSealTrailerSize();
  621. inBuffers[iBuff].BufferType = SECBUFFER_TOKEN;
  622. iBuff++;
  623. }
  624. inputBuffer.cBuffers = iBuff;
  625. inputBuffer.pBuffers = inBuffers;
  626. inputBuffer.ulVersion = SECBUFFER_VERSION;
  627. ss = g_SealMessage(
  628. &m_hSealCtxt,
  629. 0,
  630. &inputBuffer,
  631. 0
  632. );
  633. *pcbBuffOut = encryptedLength;
  634. DebugTrace( (LPARAM)this, "SealMessage returned: %d, 0x%08X", ss, ss );
  635. }
  636. SetLastError(ss);
  637. return (ss == STATUS_SUCCESS);
  638. } // SealMessage
  639. BOOL
  640. CEncryptCtx::UnsealMessage(
  641. IN LPBYTE Message,
  642. IN DWORD cbMessage,
  643. OUT LPBYTE *DecryptedMessage,
  644. OUT PDWORD DecryptedMessageSize,
  645. OUT PDWORD ExpectedMessageSize,
  646. OUT LPBYTE *NextSealMessage
  647. )
  648. /*++
  649. Routine Description:
  650. Decrypt message
  651. Arguments:
  652. Message - message to be encrypted
  653. cbMessage - size of message to be encrypted
  654. Return Value:
  655. Status of operation
  656. --*/
  657. {
  658. SECURITY_STATUS ss;
  659. SecBufferDesc inputBuffer;
  660. SecBuffer inBuffers[4];
  661. DWORD qOP;
  662. //
  663. // if the app wants to know the start of the next seal msg init to NULL
  664. //
  665. if ( NextSealMessage != NULL )
  666. {
  667. *NextSealMessage = NULL;
  668. }
  669. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::UnsealMessage");
  670. DebugTrace( (LPARAM)this,
  671. "initial ptr: 0x%08X, count: %d",
  672. Message, cbMessage );
  673. if ( m_haveSSLCtxtHandle ) {
  674. inBuffers[0].pvBuffer = Message;
  675. inBuffers[0].cbBuffer = cbMessage;
  676. inBuffers[0].BufferType = SECBUFFER_DATA;
  677. inBuffers[1].pvBuffer = NULL;
  678. inBuffers[1].cbBuffer = 0;
  679. inBuffers[1].BufferType = SECBUFFER_EMPTY;
  680. inBuffers[2].pvBuffer = NULL;
  681. inBuffers[2].cbBuffer = 0;
  682. inBuffers[2].BufferType = SECBUFFER_EMPTY;
  683. inBuffers[3].pvBuffer = NULL;
  684. inBuffers[3].cbBuffer = 0;
  685. inBuffers[3].BufferType = SECBUFFER_EMPTY;
  686. //
  687. // one for the data and one for the head and/or tail
  688. //
  689. inputBuffer.cBuffers = 4;
  690. // if ( GetSealHeaderSize() ) inputBuffer.cBuffers++;
  691. // if ( GetSealTrailerSize() ) inputBuffer.cBuffers++;
  692. // if ( NextSealMessage ) inputBuffer.cBuffers++;
  693. inputBuffer.pBuffers = inBuffers;
  694. inputBuffer.ulVersion = SECBUFFER_VERSION;
  695. ss = g_UnsealMessage(
  696. &m_hSealCtxt,
  697. &inputBuffer,
  698. 0,
  699. &qOP
  700. );
  701. if(ss == SEC_I_RENEGOTIATE)
  702. {
  703. //
  704. // We do not support renegotiation. Renegotiation makes no sense
  705. // in the context of an SMTP/NNTP client - because there should be
  706. // no need to change TLS session parameters in mid-stream. Only
  707. // applications that require different security-levels for different
  708. // transactions within the same session have use for renegotiation.
  709. //
  710. SetLastError(ss);
  711. TraceFunctLeaveEx((LPARAM)this);
  712. return FALSE;
  713. }
  714. if ( NT_SUCCESS(ss) )
  715. {
  716. for (DWORD i=0;i<inputBuffer.cBuffers;i++)
  717. {
  718. if ( inBuffers[i].BufferType == SECBUFFER_DATA )
  719. {
  720. *DecryptedMessage = (LPBYTE)inBuffers[i].pvBuffer;
  721. *DecryptedMessageSize = inBuffers[i].cbBuffer;
  722. DebugTrace( (LPARAM)this,
  723. "unsealed ptr: 0x%08X, count: %d",
  724. *DecryptedMessage, *DecryptedMessageSize );
  725. //
  726. // if the app wants to know the start of the next seal msg
  727. //
  728. if ( NextSealMessage != NULL )
  729. {
  730. for ( ;i<inputBuffer.cBuffers;i++ )
  731. {
  732. if ( inBuffers[i].BufferType == SECBUFFER_EXTRA )
  733. {
  734. *NextSealMessage = (LPBYTE)inBuffers[i].pvBuffer;
  735. DebugTrace( (LPARAM)this,
  736. "Found extra buffer: 0x%08X",
  737. *NextSealMessage );
  738. break;
  739. }
  740. }
  741. }
  742. return TRUE;
  743. }
  744. }
  745. return FALSE;
  746. }
  747. else if( ss == SEC_E_INCOMPLETE_MESSAGE )
  748. {
  749. for( DWORD i=0; i<inputBuffer.cBuffers;i++ )
  750. {
  751. if( inBuffers[i].BufferType == SECBUFFER_MISSING )
  752. {
  753. *ExpectedMessageSize = inBuffers[i].cbBuffer;
  754. }
  755. }
  756. }
  757. SetLastError(ss);
  758. }
  759. return FALSE;
  760. } // UnsealMessage
  761. //
  762. // set this define to allow schannel to allocate responses in InitializeSecurityContext
  763. //
  764. #define SSPI_ALLOCATE_MEMORY
  765. DWORD
  766. CEncryptCtx::EncryptConverse(
  767. IN PVOID InBuffer,
  768. IN DWORD InBufferSize,
  769. OUT LPBYTE OutBuffer,
  770. IN OUT PDWORD OutBufferSize,
  771. OUT PBOOL MoreBlobsExpected,
  772. IN CredHandle* pCredHandle,
  773. OUT PULONG pcbExtra
  774. )
  775. {
  776. /*++
  777. Routine Description:
  778. Internal private routine for attempting to use a given protocol
  779. Arguments:
  780. InBuffer: ptr to apps input buffer
  781. InBufferSize: count of input buffer
  782. OutBuffer: ptr to apps output buffer
  783. OutBuffer: ptr to apps max size of output buffer and resultant output count
  784. MoreBlobsExpected: expect more data from the client ?
  785. pCredHandle: ptr to the credential handle to use
  786. pcbExtra: Sometimes, even after the handshake succeeds, all the data in InBuffer
  787. may not be used up. This is because the other side may have started sending
  788. non-handshake (application) data. The param returns the length of this unprocessed
  789. "tail" which should be processed using Decrypt functions.
  790. Return Value:
  791. TRUE if negotiation succeeded.
  792. FALSE if negotiation failed.
  793. --*/
  794. SECURITY_STATUS ss;
  795. DWORD error = NO_ERROR;
  796. SecBufferDesc inBuffDesc;
  797. SecBuffer inSecBuff[2];
  798. SecBufferDesc outBuffDesc;
  799. SecBuffer outSecBuff;
  800. PCtxtHandle pCtxtHandle;
  801. DWORD contextAttributes = 0 ;
  802. TimeStamp lifeTime;
  803. DWORD dwMaxBuffer = *OutBufferSize;
  804. SECURITY_STATUS sc;
  805. SECURITY_STATUS scR;
  806. HANDLE hSSPToken = NULL;
  807. PCCERT_CONTEXT pClientCert = NULL;
  808. // Init vars used to check/return the number of bytes unprocessed by SSL handshake
  809. _ASSERT (pcbExtra);
  810. inSecBuff[1].BufferType = SECBUFFER_EMPTY;
  811. *pcbExtra = 0;
  812. BOOL fCert = TRUE;
  813. SecPkgContext_StreamSizes sizes;
  814. #ifdef DEBUG
  815. SecPkgContext_ProtoInfo spcPInfo;
  816. SECURITY_STATUS ssProto;
  817. #endif
  818. SecPkgContext_KeyInfo spcKInfo;
  819. SECURITY_STATUS ssInfo;
  820. //
  821. // See if we have enough data
  822. //
  823. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::EncryptConverse");
  824. pCtxtHandle = &m_hSealCtxt;
  825. _ASSERT(OutBuffer != NULL && "Must pass in an OutBuffer");
  826. if(NULL == OutBuffer) {
  827. ss = E_INVALIDARG;
  828. goto error_exit;
  829. }
  830. ScanNextPacket:
  831. outBuffDesc.ulVersion = 0;
  832. outBuffDesc.cBuffers = 1;
  833. outBuffDesc.pBuffers = &outSecBuff;
  834. //
  835. // need to set cbBuffer to zero because sslsspi will leave it
  836. // uninitialized when the converse completes
  837. //
  838. outSecBuff.cbBuffer = dwMaxBuffer;
  839. outSecBuff.BufferType = SECBUFFER_TOKEN;
  840. outSecBuff.pvBuffer = OutBuffer;
  841. //
  842. // Prepare our Input buffer - Note the server is expecting the client's
  843. // negotiation packet on the first call
  844. //
  845. if ( ARGUMENT_PRESENT(InBuffer) )
  846. {
  847. inBuffDesc.ulVersion = 0;
  848. inBuffDesc.cBuffers = 2;
  849. inBuffDesc.pBuffers = &inSecBuff[0];
  850. inSecBuff[0].cbBuffer = InBufferSize;
  851. inSecBuff[0].BufferType = SECBUFFER_TOKEN;
  852. inSecBuff[0].pvBuffer = InBuffer;
  853. inSecBuff[1].cbBuffer = 0;
  854. inSecBuff[1].BufferType = SECBUFFER_EMPTY;
  855. inSecBuff[1].pvBuffer = NULL;
  856. }
  857. if ( m_IsClient ) {
  858. DWORD contextAttributes;
  859. LPVOID pvBuffer;
  860. DWORD cbBuffer;
  861. //
  862. // Note the client will return success when its done but we still
  863. // need to send the out buffer if there are bytes to send
  864. //
  865. #ifdef SSPI_ALLOCATE_MEMORY
  866. pvBuffer = outSecBuff.pvBuffer;
  867. cbBuffer = outSecBuff.cbBuffer;
  868. outSecBuff.pvBuffer = NULL;
  869. outSecBuff.cbBuffer = 0;
  870. #endif
  871. DWORD dwIscReq = ISC_REQ_STREAM |
  872. ISC_REQ_SEQUENCE_DETECT |
  873. ISC_REQ_REPLAY_DETECT |
  874. ISC_REQ_EXTENDED_ERROR |
  875. ISC_REQ_MANUAL_CRED_VALIDATION | // to remove implicit call to WinVerifyTRust
  876. #ifdef SSPI_ALLOCATE_MEMORY
  877. ISC_REQ_ALLOCATE_MEMORY |
  878. #endif
  879. ISC_REQ_CONFIDENTIALITY;
  880. if( ( m_dwSslAccessPerms & MD_ACCESS_NEGO_CERT ) ||
  881. ( m_dwSslAccessPerms & MD_ACCESS_REQUIRE_CERT) ||
  882. ( m_dwSslAccessPerms & MD_ACCESS_MAP_CERT ) ) {
  883. dwIscReq |= ISC_REQ_MUTUAL_AUTH;
  884. }
  885. if (m_IsNewSSLSession) {
  886. dwIscReq |= ISC_REQ_USE_SUPPLIED_CREDS;
  887. }
  888. ss = g_InitializeSecurityContext(
  889. pCredHandle,
  890. m_IsNewSSLSession ? NULL : pCtxtHandle,
  891. wszServiceName,
  892. dwIscReq,
  893. 0,
  894. SECURITY_NATIVE_DREP,
  895. m_IsNewSSLSession ? NULL : &inBuffDesc,
  896. 0,
  897. pCtxtHandle,
  898. &outBuffDesc,
  899. &contextAttributes,
  900. &lifeTime
  901. );
  902. #ifdef SSPI_ALLOCATE_MEMORY
  903. if ( NT_SUCCESS( ss ) && outSecBuff.pvBuffer )
  904. {
  905. DebugTrace( (LPARAM)this,
  906. "Output %d bytes, Maximum %d bytes",
  907. outSecBuff.cbBuffer,
  908. cbBuffer );
  909. if ( outSecBuff.cbBuffer <= cbBuffer )
  910. {
  911. CopyMemory( pvBuffer, outSecBuff.pvBuffer, outSecBuff.cbBuffer );
  912. }
  913. else
  914. {
  915. ss = SEC_E_INSUFFICIENT_MEMORY;
  916. }
  917. g_FreeContextBuffer( outSecBuff.pvBuffer );
  918. }
  919. #endif
  920. } else {
  921. //
  922. // This is the server side
  923. //
  924. DWORD dwAscReq = ASC_REQ_STREAM |
  925. ASC_REQ_CONFIDENTIALITY |
  926. ASC_REQ_EXTENDED_ERROR |
  927. ASC_REQ_SEQUENCE_DETECT |
  928. ASC_REQ_REPLAY_DETECT;
  929. //
  930. // Set the mutual auth attribute if we are configured
  931. // to negotiate, require or map client certs
  932. //
  933. if( ( m_dwSslAccessPerms & MD_ACCESS_NEGO_CERT ) ||
  934. ( m_dwSslAccessPerms & MD_ACCESS_REQUIRE_CERT) ||
  935. ( m_dwSslAccessPerms & MD_ACCESS_MAP_CERT ) ) {
  936. dwAscReq |= ASC_REQ_MUTUAL_AUTH;
  937. }
  938. ss = g_AcceptSecurityContext(
  939. pCredHandle,
  940. m_IsNewSSLSession ? NULL : pCtxtHandle,
  941. &inBuffDesc,
  942. dwAscReq,
  943. SECURITY_NATIVE_DREP,
  944. pCtxtHandle,
  945. &outBuffDesc,
  946. &contextAttributes,
  947. &lifeTime
  948. );
  949. DebugTrace((LPARAM)this,
  950. "AcceptSecurityContext returned win32 error %d (%x)",
  951. ss, ss);
  952. if( outSecBuff.pvBuffer != OutBuffer && outSecBuff.cbBuffer ) {
  953. //
  954. // SSPI workaround - if the buffer got allocated by SSPI
  955. // copy it over and free it..
  956. //
  957. if ( outSecBuff.cbBuffer <= dwMaxBuffer )
  958. {
  959. CopyMemory( OutBuffer, outSecBuff.pvBuffer, outSecBuff.cbBuffer );
  960. }
  961. else
  962. {
  963. ss = SEC_E_INSUFFICIENT_MEMORY;
  964. }
  965. g_FreeContextBuffer( outSecBuff.pvBuffer );
  966. }
  967. }
  968. //
  969. // Negotiation succeeded, there is extra stuff left in the buffer
  970. // Return the number of the unused bytes.
  971. //
  972. if( ss == SEC_E_OK && inSecBuff[1].BufferType == SECBUFFER_EXTRA ) {
  973. *pcbExtra = inSecBuff[1].cbBuffer;
  974. } else if( ss == SEC_I_CONTINUE_NEEDED && inBuffDesc.pBuffers[1].cbBuffer ) {
  975. //
  976. // Need to process next SSL packet by calling Init/AcceptSecurityContext again
  977. // Should ASSERT that InBuffer <= OrigInBuffer + OrigInBufferSize
  978. //
  979. _ASSERT( !outSecBuff.cbBuffer );
  980. InBuffer = (LPSTR)InBuffer + InBufferSize - inBuffDesc.pBuffers[1].cbBuffer;
  981. InBufferSize = inBuffDesc.pBuffers[1].cbBuffer;
  982. goto ScanNextPacket;
  983. } else if ( ss == SEC_E_INCOMPLETE_MESSAGE ) {
  984. //
  985. // Not enough data from server... need to read more before proceeding
  986. // If there is unconsumed data, the new data is to be appended to it
  987. //
  988. *pcbExtra = InBufferSize;
  989. } else if ( !NT_SUCCESS( ss ) ) {
  990. ErrorTrace( (LPARAM)this,"%s failed with %x\n",
  991. m_IsClient ?
  992. "InitializeSecurityContext" :
  993. "AcceptSecurityContext",
  994. ss );
  995. if ( ss == SEC_E_LOGON_DENIED ) {
  996. ss = ERROR_LOGON_FAILURE;
  997. }
  998. goto error_exit;
  999. }
  1000. //
  1001. // Only query the context attributes if this is a new session, and the
  1002. // Accept/Initialize have returned SEC_E_OK (ie, the channel has been fully
  1003. // established)
  1004. //
  1005. if( ss == SEC_E_OK ) {
  1006. ssInfo = g_QueryContextAttributes(
  1007. pCtxtHandle,
  1008. SECPKG_ATTR_KEY_INFO,
  1009. &spcKInfo
  1010. );
  1011. if ( ssInfo != SEC_E_OK ) {
  1012. ErrorTrace( (LPARAM)this,
  1013. "Cannot get SSL\\PCT Key Info. Err %x",ssInfo );
  1014. //goto error_exit;
  1015. } else {
  1016. // Note the key size
  1017. m_dwKeySize = spcKInfo.KeySize;
  1018. if ( spcKInfo.sSignatureAlgorithmName )
  1019. g_FreeContextBuffer( spcKInfo.sSignatureAlgorithmName );
  1020. if ( spcKInfo.sEncryptAlgorithmName )
  1021. g_FreeContextBuffer( spcKInfo.sEncryptAlgorithmName );
  1022. }
  1023. }
  1024. m_haveSSLCtxtHandle = TRUE;
  1025. //
  1026. // Now we just need to complete the token (if requested) and prepare
  1027. // it for shipping to the other side if needed
  1028. //
  1029. if ( (ss == SEC_I_COMPLETE_NEEDED) ||
  1030. (ss == SEC_I_COMPLETE_AND_CONTINUE) ) {
  1031. ss = g_CompleteAuthToken( pCtxtHandle, &outBuffDesc );
  1032. if ( !NT_SUCCESS( ss )) {
  1033. ErrorTrace( (LPARAM)this,
  1034. "CompleteAuthToken failed. Err %x",ss );
  1035. goto error_exit;
  1036. }
  1037. }
  1038. *OutBufferSize = outSecBuff.cbBuffer;
  1039. *MoreBlobsExpected= (ss == SEC_I_CONTINUE_NEEDED) ||
  1040. (ss == SEC_I_COMPLETE_AND_CONTINUE) ||
  1041. (ss == SEC_E_INCOMPLETE_MESSAGE);
  1042. if ( *MoreBlobsExpected == FALSE )
  1043. {
  1044. //
  1045. // HACK: SSLSSPI leaves outSecBuff.cbBuffer uninitialized
  1046. // after final successful call for client side connections
  1047. //
  1048. if ( m_IsClient && *OutBufferSize == dwMaxBuffer )
  1049. {
  1050. *OutBufferSize = 0;
  1051. }
  1052. //
  1053. // we're done so get the SSPI header/trailer sizes for SealMessage
  1054. //
  1055. ss = g_QueryContextAttributes(
  1056. pCtxtHandle,
  1057. SECPKG_ATTR_STREAM_SIZES,
  1058. &sizes
  1059. );
  1060. if ( ss != SEC_E_OK ) {
  1061. ErrorTrace( (LPARAM)this,
  1062. "Cannot get SSL\\PCT Header Length. Err %x",ss );
  1063. goto error_exit;
  1064. }
  1065. m_cbSealHeaderSize = sizes.cbHeader;
  1066. m_cbSealTrailerSize = sizes.cbTrailer;
  1067. DebugTrace( (LPARAM)this, "Header: %d, Trailer: %d",
  1068. m_cbSealHeaderSize, m_cbSealTrailerSize );
  1069. if(!m_IsClient)
  1070. {
  1071. scR = g_QueryContextAttributes( pCtxtHandle,
  1072. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  1073. &pClientCert );
  1074. if ( !NT_SUCCESS( scR ) || !pClientCert )
  1075. {
  1076. fCert = FALSE;
  1077. }
  1078. else
  1079. {
  1080. CertFreeCertificateContext( pClientCert);
  1081. DebugTrace((LPARAM)this, "[OnAuthorizationInfo] Certificate available!\n");
  1082. }
  1083. //
  1084. // check if client authentication available
  1085. //
  1086. if ( 1 /*|| pssc->IsMap()*/ )
  1087. {
  1088. sc = g_QuerySecurityContextToken( pCtxtHandle,
  1089. &hSSPToken );
  1090. if ( !NT_SUCCESS( sc ) || (hSSPToken == (HANDLE)0x00000001) )
  1091. {
  1092. hSSPToken = NULL;
  1093. }
  1094. }
  1095. if ( !fCert && hSSPToken != NULL )
  1096. {
  1097. CloseHandle( hSSPToken );
  1098. hSSPToken = NULL;
  1099. }
  1100. if( !(m_dwSslAccessPerms & MD_ACCESS_MAP_CERT) && hSSPToken != NULL )
  1101. {
  1102. DebugTrace( (LPARAM)this,"NT token not required - closing");
  1103. CloseHandle( hSSPToken );
  1104. hSSPToken = NULL;
  1105. }
  1106. if( (m_dwSslAccessPerms & MD_ACCESS_REQUIRE_CERT) && !fCert )
  1107. {
  1108. //
  1109. // We require client cert - bail !
  1110. // Converse will return ERROR_ACCESS_DENIED
  1111. //
  1112. _ASSERT( !hSSPToken );
  1113. return FALSE;
  1114. }
  1115. if( hSSPToken )
  1116. {
  1117. _ASSERT( fCert );
  1118. m_hSSPToken = hSSPToken;
  1119. m_IsAuthenticated = TRUE;
  1120. } else if(m_dwSslAccessPerms & MD_ACCESS_MAP_CERT) {
  1121. //
  1122. // We need to map cert to token - but token is NULL
  1123. //
  1124. return FALSE;
  1125. }
  1126. }
  1127. }
  1128. return TRUE;
  1129. error_exit:
  1130. SetLastError(ss);
  1131. return FALSE;
  1132. } // EncryptConverse
  1133. DWORD
  1134. CEncryptCtx::Converse(
  1135. IN PVOID InBuffer,
  1136. IN DWORD InBufferSize,
  1137. OUT LPBYTE OutBuffer,
  1138. OUT PDWORD OutBufferSize,
  1139. OUT PBOOL MoreBlobsExpected,
  1140. IN LPSTR LocalIpAddr,
  1141. IN LPSTR LocalPort,
  1142. IN LPVOID lpvInstance,
  1143. IN DWORD dwInstance,
  1144. OUT PULONG pcbExtra
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. Internal private routine for attempting to use a given protocol
  1149. Arguments:
  1150. InBuffer: ptr to apps input buffer
  1151. InBufferSize: count of input buffer
  1152. OutBuffer: ptr to apps output buffer
  1153. OutBuffer: ptr to apps max size of output buffer and resultant output count
  1154. MoreBlobsExpected: expect more data from the client ?
  1155. LocalIpAddr: stringized local IP addr for the connection
  1156. pcbExtra: See description of EncryptConverse
  1157. Return Value:
  1158. Win32/SSPI error code
  1159. --*/
  1160. {
  1161. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::Converse");
  1162. DWORD dwMaxBuffer = *OutBufferSize;
  1163. DWORD i, cbCreds;
  1164. CredHandle* pCredArray = NULL;
  1165. if ( m_IsNewSSLSession )
  1166. {
  1167. if ( m_IsClient )
  1168. {
  1169. //
  1170. // Get the credentials for the client
  1171. //
  1172. LockGlobals();
  1173. if ( !LookupClientCredential(
  1174. wszServiceName,
  1175. (BOOL)m_dwSslAccessPerms,
  1176. (CRED_CACHE_ITEM**)&m_phCreds ) )
  1177. {
  1178. ErrorTrace( (LPARAM)this,
  1179. "LookupClientCredential failed, error 0x%lx",
  1180. GetLastError() );
  1181. UnlockGlobals();
  1182. goto error_exit;
  1183. }
  1184. UnlockGlobals();
  1185. }
  1186. else
  1187. {
  1188. DebugTrace( (LPARAM)this,
  1189. "LookupCredential for %S on %s",
  1190. wszServiceName, LocalIpAddr );
  1191. //
  1192. // Get the credentials for this IP address
  1193. //
  1194. LockGlobals();
  1195. if ( !LookupFullyQualifiedCredential(
  1196. wszServiceName,
  1197. LocalIpAddr,
  1198. lstrlen(LocalIpAddr),
  1199. LocalPort,
  1200. lstrlen(LocalPort),
  1201. lpvInstance,
  1202. (CRED_CACHE_ITEM**)&m_phCreds,
  1203. m_psmcMapContext,
  1204. dwInstance ))
  1205. {
  1206. ErrorTrace( (LPARAM)this,
  1207. "LookupCredential failed, error 0x%lx",
  1208. GetLastError() );
  1209. UnlockGlobals();
  1210. goto error_exit;
  1211. }
  1212. UnlockGlobals();
  1213. }
  1214. //
  1215. // run thru all initialized credentials look for a package which
  1216. // will accept this connection
  1217. //
  1218. CRED_CACHE_ITEM* phCreds = (CRED_CACHE_ITEM*)m_phCreds;
  1219. //
  1220. // For server: Need to use SSL access perms
  1221. // to figure out whether to use CredMap or Cred
  1222. //
  1223. if( !m_IsClient && (m_dwSslAccessPerms & MD_ACCESS_MAP_CERT) )
  1224. {
  1225. cbCreds = phCreds->m_cCredMap;
  1226. pCredArray = phCreds->m_ahCredMap;
  1227. } else {
  1228. cbCreds = phCreds->m_cCred;
  1229. pCredArray = phCreds->m_ahCred;
  1230. }
  1231. }
  1232. else
  1233. {
  1234. //
  1235. // hack to only allow one pass thru the loop
  1236. //
  1237. cbCreds = 1;
  1238. pCredArray = m_phCredInUse;
  1239. }
  1240. //
  1241. // Do the conversation
  1242. //
  1243. for ( i=0; i<cbCreds; i++, pCredArray++ )
  1244. {
  1245. if ( EncryptConverse(InBuffer,
  1246. InBufferSize,
  1247. OutBuffer,
  1248. OutBufferSize,
  1249. MoreBlobsExpected,
  1250. pCredArray,
  1251. pcbExtra ) )
  1252. {
  1253. if ( m_IsNewSSLSession )
  1254. {
  1255. //
  1256. // if the first time remember which credential succeeded.
  1257. //
  1258. m_phCredInUse = pCredArray;
  1259. m_iCredInUse = i;
  1260. m_IsNewSSLSession = FALSE;
  1261. }
  1262. return NO_ERROR;
  1263. }
  1264. }
  1265. //
  1266. // We failed
  1267. //
  1268. error_exit:
  1269. if(OutBuffer)
  1270. *OutBuffer = 0;
  1271. if(OutBufferSize)
  1272. *OutBufferSize = 0;
  1273. DWORD error = GetLastError();
  1274. if ( error == NO_ERROR ) {
  1275. error = ERROR_ACCESS_DENIED;
  1276. }
  1277. return error;
  1278. } // Converse
  1279. //+---------------------------------------------------------------
  1280. //
  1281. // Function: DecryptInputBuffer
  1282. //
  1283. // Synopsis: decrypted input read from the client
  1284. //
  1285. // Arguments: pBuffer: ptr to the input/output buffer
  1286. // cbInBuffer: initial input length of the buffer
  1287. // pcbOutBuffer: total length of decrypted/remaining
  1288. // data. pcbOutBuffer - pcbParsable is
  1289. // the length of offset for next read
  1290. // pcbParsable: length of decrypted data
  1291. // pcbExpected: length of remaining unread data for
  1292. // full SSL message
  1293. //
  1294. // Returns: DWORD Win32/SSPI error core
  1295. //
  1296. //----------------------------------------------------------------
  1297. DWORD CEncryptCtx::DecryptInputBuffer(
  1298. IN LPBYTE pBuffer,
  1299. IN DWORD cbInBuffer,
  1300. OUT DWORD* pcbOutBuffer,
  1301. OUT DWORD* pcbParsable,
  1302. OUT DWORD* pcbExpected
  1303. )
  1304. {
  1305. LPBYTE pDecrypted;
  1306. DWORD cbDecrypted;
  1307. DWORD cbParsable = 0;
  1308. LPBYTE pNextSeal;
  1309. LPBYTE pStartBuffer = pBuffer;
  1310. BOOL fRet;
  1311. //
  1312. // initialize to zero so app does not inadvertently post large read
  1313. //
  1314. *pcbExpected = 0;
  1315. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::DecryptInputBuffer" );
  1316. while( fRet = UnsealMessage(pBuffer,
  1317. cbInBuffer,
  1318. &pDecrypted,
  1319. &cbDecrypted,
  1320. pcbExpected,
  1321. &pNextSeal ) )
  1322. {
  1323. DebugTrace( (LPARAM)this,
  1324. "Decrypted %d bytes at offset %d",
  1325. cbDecrypted,
  1326. pDecrypted - pStartBuffer );
  1327. //
  1328. // move the decrypted data to the front of buffer
  1329. //
  1330. MoveMemory( pStartBuffer + cbParsable,
  1331. pDecrypted,
  1332. cbDecrypted );
  1333. //
  1334. // increment where the next parsing should take place
  1335. //
  1336. cbParsable += cbDecrypted;
  1337. //
  1338. // move to the next potential seal buffer
  1339. //
  1340. if ( pNextSeal != NULL )
  1341. {
  1342. _ASSERT( pNextSeal >= pStartBuffer );
  1343. _ASSERT( pNextSeal <= pBuffer + cbInBuffer );
  1344. //
  1345. // remove header, body and trailer from input buffer length
  1346. //
  1347. cbInBuffer -= (DWORD)(pNextSeal - pBuffer);
  1348. pBuffer = pNextSeal;
  1349. }
  1350. else
  1351. {
  1352. //
  1353. // in this case we received a seal message at the boundary
  1354. // of the IO buffer
  1355. //
  1356. cbInBuffer = 0;
  1357. break;
  1358. }
  1359. }
  1360. *pcbParsable = cbParsable;
  1361. *pcbOutBuffer= cbParsable + cbInBuffer;
  1362. if ( fRet == FALSE )
  1363. {
  1364. DWORD dwError = GetLastError();
  1365. DebugTrace( (LPARAM)this,
  1366. "UnsealMessage returned: 0x%08X",
  1367. GetLastError() );
  1368. //
  1369. // deal with seal fragments at the end of the IO buffer
  1370. //
  1371. if ( dwError == SEC_E_INCOMPLETE_MESSAGE )
  1372. {
  1373. _ASSERT( cbInBuffer != 0 );
  1374. //
  1375. // move the remaining memory forward
  1376. //
  1377. MoveMemory( pStartBuffer + cbParsable,
  1378. pBuffer,
  1379. cbInBuffer );
  1380. DebugTrace( (LPARAM)this,
  1381. "Seal fragment remaining: %d bytes",
  1382. cbInBuffer );
  1383. }
  1384. else
  1385. {
  1386. return dwError;
  1387. }
  1388. }
  1389. return NO_ERROR;
  1390. }
  1391. //+---------------------------------------------------------------
  1392. //
  1393. // Function: IsEncryptionPermitted
  1394. //
  1395. // Synopsis: This routine checks whether encryption is getting
  1396. // the system default LCID and checking whether the
  1397. // country code is CTRY_FRANCE.
  1398. //
  1399. // Arguments: void
  1400. //
  1401. // Returns: BOOL: supported
  1402. //
  1403. //----------------------------------------------------------------
  1404. BOOL
  1405. IsEncryptionPermitted(void)
  1406. {
  1407. LCID DefaultLcid;
  1408. CHAR CountryCode[10];
  1409. CHAR FranceCode[10];
  1410. DefaultLcid = GetSystemDefaultLCID();
  1411. //
  1412. // Check if the default language is Standard French
  1413. //
  1414. if ( LANGIDFROMLCID( DefaultLcid ) == 0x40c )
  1415. {
  1416. return FALSE;
  1417. }
  1418. //
  1419. // Check if the users's country is set to FRANCE
  1420. //
  1421. if ( GetLocaleInfo( DefaultLcid,
  1422. LOCALE_ICOUNTRY,
  1423. CountryCode,
  1424. sizeof(CountryCode) ) == 0 )
  1425. {
  1426. return FALSE;
  1427. }
  1428. wsprintf( FranceCode, "%d", CTRY_FRANCE );
  1429. //
  1430. // if the country codes matches France return FALSE
  1431. //
  1432. return lstrcmpi( CountryCode, FranceCode ) == 0 ? FALSE : TRUE ;
  1433. }
  1434. //+---------------------------------------------------------------
  1435. //
  1436. // Function: GetAdminInfoEncryptCaps
  1437. //
  1438. // Synopsis: sets the magical buts to send the IIS admin program
  1439. //
  1440. // Arguments: PDWORD: ptr to the dword bitmask
  1441. //
  1442. // Returns: void
  1443. //
  1444. //----------------------------------------------------------------
  1445. VOID CEncryptCtx::GetAdminInfoEncryptCaps( PDWORD pdwEncCaps )
  1446. {
  1447. *pdwEncCaps = 0;
  1448. if ( m_IsSecureCapable == FALSE )
  1449. {
  1450. *pdwEncCaps |= (IsEncryptionPermitted() ?
  1451. ENC_CAPS_NOT_INSTALLED :
  1452. ENC_CAPS_DISABLED );
  1453. }
  1454. else
  1455. {
  1456. //
  1457. // for all enabled encryption providers set the flags bit
  1458. //
  1459. for ( int j = 0; EncProviders[j].pszName != NULL; j++ )
  1460. {
  1461. if ( TRUE == EncProviders[j].fEnabled )
  1462. {
  1463. *pdwEncCaps |= EncProviders[j].dwFlags;
  1464. }
  1465. }
  1466. }
  1467. }
  1468. /////////////////////////////////////////////////////////////////////////////
  1469. //
  1470. // From here to the end of the file is code stolen from the Athena group from
  1471. // the file called thorsspi.cpp
  1472. //
  1473. // minor mods have been made to incorporate msntrace functionality and to
  1474. // fit in the CEncryptCtx class definition
  1475. //
  1476. /////////////////////////////////////////////////////////////////////////////
  1477. //
  1478. // CompareDNStoCommonName()
  1479. //
  1480. // Description:
  1481. // Compare a DNS name to a common name field value
  1482. //
  1483. // Parameters:
  1484. // pDNS - string containing DNS name - *WARNING* will be munged
  1485. // pCN - string containing common name field value
  1486. //
  1487. // Return:
  1488. // TRUE if they match
  1489. //
  1490. // Comments:
  1491. // There are two ways for these two strings to match. The first is that
  1492. // they contain exactly the same characters. The second involved the use
  1493. // of a single wildcard character in the common name field value. This
  1494. // wildcard character ('*') can only be used once, and if used must be
  1495. // the first character of the field.
  1496. //
  1497. // ASSUMES: the caller will allow pDNS and pCN to be uppercased and changed.
  1498. //
  1499. BOOL CompareDNStoCommonName(LPSTR pDNS, LPSTR pCN)
  1500. {
  1501. int nCountPeriods = 1; // start of DNS amount to virtual '.' as prefix
  1502. BOOL fExactMatch = TRUE;
  1503. LPSTR pBakDNS = pDNS;
  1504. LPSTR pBakCN = pCN;
  1505. _ASSERT(pDNS);
  1506. _ASSERT(pCN);
  1507. CharUpper(pDNS);
  1508. CharUpper(pCN);
  1509. while ((*pDNS == *pCN || *pCN == '*') && *pDNS && *pCN)
  1510. {
  1511. if (*pDNS != *pCN)
  1512. fExactMatch = FALSE;
  1513. if (*pCN == '*')
  1514. {
  1515. nCountPeriods = 0;
  1516. if (*pDNS == '.')
  1517. pCN++;
  1518. else
  1519. pDNS++;
  1520. }
  1521. else
  1522. {
  1523. if (*pDNS == '.')
  1524. nCountPeriods++;
  1525. pDNS++;
  1526. pCN++;
  1527. }
  1528. }
  1529. // if they are sized 0, we make sure not to say they match.
  1530. if (pBakDNS == pDNS || pBakCN == pCN)
  1531. fExactMatch = FALSE;
  1532. return (*pDNS == 0) && (*pCN == 0) && ((nCountPeriods >= 2) || fExactMatch);
  1533. }
  1534. /////////////////////////////////////////////////////////////////////////////
  1535. //
  1536. // CompareDNStoMultiCommonName()
  1537. //
  1538. // Description:
  1539. // Compare a DNS name to a comma delimited list of common name fields.
  1540. //
  1541. // Parameters:
  1542. // pDNS - string containing DNS name - *WARNING* will munge
  1543. // pCN - string containing common name field value - *WARNING* will munge
  1544. //
  1545. // Return:
  1546. // TRUE if they match
  1547. //
  1548. // ASSUMES: the caller will allow pDNS and pCN to be uppercased and changed.
  1549. //
  1550. BOOL CompareDNStoMultiCommonName(LPSTR pDNS, LPSTR pCN)
  1551. {
  1552. LPSTR pComma;
  1553. LPSTR lpszCommonName;
  1554. BOOL retval = FALSE; // assume we won't find a match
  1555. BOOL done = FALSE; // assume we're not done
  1556. lpszCommonName = pCN;
  1557. do {
  1558. // If there is a space, turn it into a null terminator to isolate the first
  1559. // DNS name in the string
  1560. lpszCommonName = strstr(lpszCommonName, "CN=");
  1561. if (lpszCommonName)
  1562. {
  1563. // jump past "CN=" string
  1564. lpszCommonName += 3;
  1565. pComma = strchr(lpszCommonName, ',');
  1566. if (pComma)
  1567. *pComma = 0;
  1568. // See if this component is a match
  1569. retval = CompareDNStoCommonName(pDNS, lpszCommonName);
  1570. // Now restore the comma (if any) that was overwritten
  1571. if (pComma)
  1572. {
  1573. *pComma = ',';
  1574. lpszCommonName = pComma + 1;
  1575. }
  1576. else
  1577. {
  1578. // If there were no more commas, then we're done
  1579. done = TRUE;
  1580. }
  1581. }
  1582. } while (!retval && !done && lpszCommonName && *lpszCommonName);
  1583. return retval;
  1584. }
  1585. //-----------------------------------------------------------------------------
  1586. // Description:
  1587. // This function checks if pDns is a subdomain of pCn.
  1588. // Basic rule: A wildcard character '*' at the beginning of a DNS name
  1589. // matches any number of components. i.e. a wildcard implies that we will
  1590. // match all subdomains of a given domain.
  1591. //
  1592. // microsoft.com == microsoft.com
  1593. // *.microsoft.com == microsoft.com
  1594. // *.microsoft.com == foo.microsoft.com
  1595. // *.microsoft.com == foo.bar.microsoft.com
  1596. //
  1597. // Note that the arguments are modified (converted to uppercase).
  1598. // Arguments:
  1599. // pDns - DNS name to which we are trying to connect
  1600. // pCn - Common name in certificate
  1601. // Returns:
  1602. // TRUE if subdomain, FALSE otherwise
  1603. //-----------------------------------------------------------------------------
  1604. BOOL MatchSubDomain (LPSTR pDns, LPSTR pCn)
  1605. {
  1606. LPSTR pCnBegin = NULL;
  1607. int cbDns = 0;
  1608. int cbCn = 0;
  1609. _ASSERT (pDns);
  1610. _ASSERT (pCn);
  1611. CharUpper(pDns);
  1612. CharUpper(pCn);
  1613. cbDns = lstrlen (pDns);
  1614. cbCn = lstrlen (pCn);
  1615. // check if we have an initial wildcard: this is only allowed as "*.restofdomain"
  1616. if (cbCn >= 2 && *pCn == '*') {
  1617. pCn++; // we have a wildcard, try to get parent domain
  1618. if (*pCn != '.')
  1619. return FALSE; // Bad syntax, '.' must follow wildcard
  1620. else
  1621. pCn++; // Skip wildcard, get to parent domain part
  1622. cbCn -= 2; // Update string length
  1623. }
  1624. if (cbDns < cbCn) // subdomains must be >= parent domains in length
  1625. return FALSE;
  1626. //
  1627. // If subdomain is > parent domain, verify that there is a '.' between
  1628. // the subdomain part and parent domain part. This is to guard from matching
  1629. // *.microsoft.com with foobarmicrosoft.com since all we do after this
  1630. // line of code is check that the parent is a substring of the subdomain
  1631. // at the end.
  1632. //
  1633. if (cbDns != cbCn && pDns[cbDns - cbCn - 1] != '.')
  1634. return FALSE;
  1635. pCnBegin = pCn;
  1636. pCn += cbCn;
  1637. pDns += cbDns;
  1638. // Walk backwards doing matching
  1639. for (; pCnBegin <= pCn && *pCn == *pDns; pCn--, pDns--);
  1640. //
  1641. // Check if we terminated without a mismatch,
  1642. //
  1643. return (pCnBegin > pCn);
  1644. }
  1645. #define CompareCertTime(ft1, ft2) (((*(LONGLONG *)&ft1) > (*(LONGLONG *)&ft2)) \
  1646. ? 1 \
  1647. : (((*(LONGLONG *)&ft1) == (*(LONGLONG *)&ft2)) ? 0 : -1 ))
  1648. //+---------------------------------------------------------------
  1649. //
  1650. // Function: CheckCertificateCommonName
  1651. //
  1652. // Synopsis: verifies the intended host name matches the
  1653. // the name contained in the certificate
  1654. // This function, checks a given hostname against the current certificate
  1655. // stored in an active SSPI Context Handle. If the certificate containts
  1656. // a common name, and it matches the passed in hostname, this function
  1657. // will return TRUE
  1658. //
  1659. // Arguments: IN LPSTR: DNS host name
  1660. //
  1661. // Returns: BOOL
  1662. //
  1663. //----------------------------------------------------------------
  1664. BOOL CEncryptCtx::CheckCertificateCommonName( IN LPSTR pszHostName )
  1665. {
  1666. DWORD dwErr;
  1667. BOOL fIsCertGood = FALSE;
  1668. SecPkgContext_Names CertNames;
  1669. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::CheckCertificateCommonName" );
  1670. CertNames.sUserName = NULL;
  1671. if ( !pszHostName )
  1672. {
  1673. goto quit;
  1674. }
  1675. dwErr = g_QueryContextAttributes(&m_hSealCtxt,
  1676. SECPKG_ATTR_NAMES,
  1677. (PVOID)&CertNames);
  1678. if (dwErr != ERROR_SUCCESS)
  1679. {
  1680. ErrorTrace( (LPARAM)this,
  1681. "QueryContextAttributes failed to retrieve CN, returned %#x",
  1682. dwErr );
  1683. goto quit;
  1684. }
  1685. DebugTrace( (LPARAM)this,
  1686. "QueryContextAttributes returned CN=%.200s",
  1687. CertNames.sUserName );
  1688. fIsCertGood = CompareDNStoMultiCommonName(pszHostName, CertNames.sUserName);
  1689. quit:
  1690. if ( CertNames.sUserName )
  1691. {
  1692. LocalFree( CertNames.sUserName );
  1693. }
  1694. return fIsCertGood;
  1695. }
  1696. //-------------------------------------------------------------------------
  1697. // Description:
  1698. // Verifies that the subject of the certificate matches the FQDN of
  1699. // the server we are talking to. Does some wildcard matching if there
  1700. // are '*' characters at the beginning of the cert subject.
  1701. // Arguments:
  1702. // pCtxtHandle The context of an established SSL connection
  1703. // pszServerFqdn FQDN of server to which we are talking (from who we
  1704. // received the certificate).
  1705. // Returns:
  1706. // TRUE match found, FALSE unmatched
  1707. //-------------------------------------------------------------------------
  1708. BOOL CEncryptCtx::CheckCertificateSubjectName (IN LPSTR pszServerFqdn)
  1709. {
  1710. CHAR pszSubjectStackBuf[256];
  1711. LPSTR pszSubject = NULL;
  1712. PCCERT_CONTEXT pCertContext = NULL;
  1713. DWORD dwErr = ERROR_SUCCESS;
  1714. DWORD cSize = 0;
  1715. DWORD cSubject = 0;
  1716. BOOL fRet = FALSE;
  1717. TraceFunctEnterEx ((LPARAM) this, "CEncryptCtx::VerifySubject");
  1718. _ASSERT (pszServerFqdn);
  1719. dwErr = g_QueryContextAttributes(
  1720. &m_hSealCtxt,
  1721. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  1722. &pCertContext);
  1723. if (dwErr != SEC_E_OK) {
  1724. StateTrace ((LPARAM) this, "Cannot get Context Handle %x", dwErr);
  1725. goto Exit;
  1726. }
  1727. //
  1728. // Check the size of the buffer needed, if it's small enough we'll
  1729. // just use the fixed size stack buffer, otherwise allocate on heap.
  1730. //
  1731. cSize = CertGetNameString (
  1732. pCertContext,
  1733. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  1734. 0,
  1735. NULL,
  1736. NULL,
  1737. 0);
  1738. if (cSize <= sizeof(pszSubjectStackBuf)) {
  1739. pszSubject = pszSubjectStackBuf;
  1740. cSubject = sizeof (pszSubjectStackBuf);
  1741. } else {
  1742. pszSubject = new CHAR [cSize];
  1743. if (NULL == pszSubject) {
  1744. ErrorTrace ((LPARAM) this, "No memory to alloc subject string.");
  1745. goto Exit;
  1746. }
  1747. cSubject = cSize;
  1748. }
  1749. //
  1750. // Get the subject of the certificate
  1751. //
  1752. cSize = CertGetNameString (
  1753. pCertContext,
  1754. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  1755. 0,
  1756. NULL,
  1757. pszSubject,
  1758. cSubject);
  1759. if (cSize == 1 && pszSubject[0] == '\0') {
  1760. //
  1761. // If the CERT_NAME_SIMPLE_DISPLAY_TYPE could not be found in the cert,
  1762. // the API returns a zero length NULL terminated string.
  1763. //
  1764. StateTrace ((LPARAM) this, "Certificate subject not found");
  1765. goto Exit;
  1766. }
  1767. StateTrace ((LPARAM) this, "Certificate subject: %s, FQDN: %s",
  1768. pszSubject, pszServerFqdn);
  1769. if (MatchSubDomain(pszServerFqdn, pszSubject)) {
  1770. //
  1771. // Certificate matches the server FQDN we're talking to
  1772. //
  1773. fRet = TRUE;
  1774. }
  1775. Exit:
  1776. //
  1777. // Delete the Subject buffer if we were using the heap
  1778. //
  1779. if (pszSubject != pszSubjectStackBuf)
  1780. delete [] pszSubject;
  1781. if (pCertContext)
  1782. CertFreeCertificateContext (pCertContext);
  1783. StateTrace ((LPARAM) this, "Returning: %s", fRet ? "TRUE" : "FALSE");
  1784. TraceFunctLeaveEx ((LPARAM) this);
  1785. return fRet;
  1786. }
  1787. //---------------------------------------------------------------------
  1788. // Description:
  1789. // Checks if the certificate for this CEncryptCtx chains up to a
  1790. // trusted CA.
  1791. // Returns:
  1792. // TRUE if certificate is trusted.
  1793. // FALSE if the certificate is untrusted or if trust could not be
  1794. // verified (temporary errors can cause this).
  1795. // Source:
  1796. // MSDN sample
  1797. //---------------------------------------------------------------------
  1798. BOOL CEncryptCtx::CheckCertificateTrust ()
  1799. {
  1800. BOOL fRet = FALSE;
  1801. DWORD dwErr = SEC_E_OK;
  1802. DWORD dwFlags = 0;
  1803. PCCERT_CONTEXT pCertContext = NULL;
  1804. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1805. CERT_ENHKEY_USAGE EnhkeyUsage;
  1806. CERT_USAGE_MATCH CertUsage;
  1807. CERT_CHAIN_PARA ChainPara;
  1808. TraceFunctEnterEx ((LPARAM) this, "CEncryptCtx::CheckCertificateTrust");
  1809. dwErr = g_QueryContextAttributes (
  1810. &m_hSealCtxt,
  1811. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  1812. &pCertContext);
  1813. if (SEC_E_OK != dwErr) {
  1814. ErrorTrace ((LPARAM) this, "g_QueryContextAttributes failed, err - %8x", dwErr);
  1815. fRet = FALSE;
  1816. goto Exit;
  1817. }
  1818. //
  1819. // ChainPara is a struct used to match specific certificates using OIDs
  1820. // We don't need this and initialize it to empty (no OIDs)
  1821. //
  1822. EnhkeyUsage.cUsageIdentifier = 0;
  1823. EnhkeyUsage.rgpszUsageIdentifier = NULL;
  1824. CertUsage.dwType = USAGE_MATCH_TYPE_AND;
  1825. CertUsage.Usage = EnhkeyUsage;
  1826. ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
  1827. ChainPara.RequestedUsage = CertUsage;
  1828. dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_CACHE_END_CERT;
  1829. fRet = CertGetCertificateChain (
  1830. NULL, // Use the default chaining engine
  1831. pCertContext, // The end certificate to be checked
  1832. NULL, // Expiration checking... use currenttime
  1833. NULL, // Additional cert stores: none
  1834. &ChainPara, // Chaining criteria: none, this is an empty struct
  1835. dwFlags, // Options: how to check chain
  1836. NULL, // reserved param
  1837. &pChainContext);// Returned chain context
  1838. if (!fRet) {
  1839. dwErr = GetLastError ();
  1840. ErrorTrace ((LPARAM) this, "Unable to create certificate chain, err - %8x", dwErr);
  1841. goto Exit;
  1842. }
  1843. DebugTrace ((LPARAM) this, "Status of certificate chain - %8x",
  1844. pChainContext->TrustStatus.dwErrorStatus);
  1845. if (CERT_TRUST_NO_ERROR == pChainContext->TrustStatus.dwErrorStatus) {
  1846. DebugTrace ((LPARAM) this, "Certificate trust verified");
  1847. fRet = TRUE;
  1848. } else {
  1849. ErrorTrace ((LPARAM) this, "Certificate is untrusted, status - %8x",
  1850. pChainContext->TrustStatus.dwErrorStatus);
  1851. fRet = FALSE;
  1852. }
  1853. Exit:
  1854. if (pCertContext)
  1855. CertFreeCertificateContext (pCertContext);
  1856. if (pChainContext)
  1857. CertFreeCertificateChain (pChainContext);
  1858. TraceFunctLeaveEx ((LPARAM) this);
  1859. return fRet;
  1860. }
  1861. //+---------------------------------------------------------------
  1862. //
  1863. // Function: CheckCertificateExpired
  1864. //
  1865. // Synopsis: verifies the ccertificate has not expired
  1866. // returns TRUE if the cert is valid
  1867. //
  1868. // Arguments: void
  1869. //
  1870. // Returns: BOOL cert is good
  1871. //
  1872. //----------------------------------------------------------------
  1873. BOOL CEncryptCtx::CheckCertificateExpired( void )
  1874. {
  1875. SYSTEMTIME st;
  1876. FILETIME ftCurTime;
  1877. DWORD dwErr;
  1878. SecPkgContext_Lifespan CertLifeSpan;
  1879. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::CheckCertificateExpired" );
  1880. GetSystemTime(&st);
  1881. if (!SystemTimeToFileTime(&st, &ftCurTime)) return FALSE;
  1882. dwErr = g_QueryContextAttributes(&m_hSealCtxt,
  1883. SECPKG_ATTR_LIFESPAN,
  1884. (PVOID)&CertLifeSpan);
  1885. if ( dwErr != ERROR_SUCCESS )
  1886. {
  1887. ErrorTrace( (LPARAM)this,
  1888. "QueryContextAttributes failed to retrieve cert lifespan, returned %#x",
  1889. dwErr);
  1890. return FALSE;
  1891. }
  1892. return CompareCertTime( CertLifeSpan.tsStart, ftCurTime ) < 0 &&
  1893. CompareCertTime( CertLifeSpan.tsExpiry, ftCurTime) > 0 ;
  1894. }
  1895. //+----------------------------------------------------------------------------
  1896. //
  1897. // Function: CheckServerCert
  1898. //
  1899. // Synopsis: Checks to see if a server cert has been installed.
  1900. //
  1901. // Arguments: [LocalIpAddr] -- IP Address of virtual server
  1902. // [LocalPort] -- Port of virtual server
  1903. // [lpvInstance] -- Pointer to IIS_SERVER_INSTANCE object
  1904. // [dwInstance] -- Virtual server id
  1905. //
  1906. // Returns: TRUE if there is a cert for this virtual server
  1907. //
  1908. //-----------------------------------------------------------------------------
  1909. BOOL CEncryptCtx::CheckServerCert(
  1910. IN LPSTR LocalIpAddr,
  1911. IN LPSTR LocalPort,
  1912. IN LPVOID lpvInstance,
  1913. IN DWORD dwInstance)
  1914. {
  1915. TraceFunctEnterEx( (LPARAM)this, "CEncryptCtx::CheckServerCert" );
  1916. BOOL fRet = FALSE;
  1917. CRED_CACHE_ITEM *pCCI;
  1918. DebugTrace( (LPARAM)this,
  1919. "CheckServerCert for %S on %s",
  1920. wszServiceName, LocalIpAddr );
  1921. //
  1922. // Get the credentials for this IP address
  1923. //
  1924. LockGlobals();
  1925. if ( fRet = LookupFullyQualifiedCredential(
  1926. wszServiceName,
  1927. LocalIpAddr,
  1928. lstrlen(LocalIpAddr),
  1929. LocalPort,
  1930. lstrlen(LocalPort),
  1931. lpvInstance,
  1932. &pCCI,
  1933. m_psmcMapContext,
  1934. dwInstance ))
  1935. {
  1936. IIS_SERVER_CERT *pCert = pCCI->m_pSslInfo->GetCertificate();
  1937. // Log the status of the cert if we got one
  1938. if ( pCert )
  1939. {
  1940. fRet = TRUE;
  1941. }
  1942. else
  1943. fRet = FALSE;
  1944. pCCI->Release();
  1945. } else {
  1946. ErrorTrace( (LPARAM)this,
  1947. "LookupCredential failed, error 0x%lx",
  1948. GetLastError() );
  1949. }
  1950. UnlockGlobals();
  1951. TraceFunctLeave();
  1952. return( fRet );
  1953. }
  1954. //+---------------------------------------------------------------
  1955. //
  1956. // Function: NotifySslChanges
  1957. //
  1958. // Synopsis: This is called when SSL settings change
  1959. //
  1960. // Arguments: dwNotifyType
  1961. // pInstance
  1962. //
  1963. // Returns: VOID
  1964. //
  1965. //----------------------------------------------------------------
  1966. VOID WINAPI NotifySslChanges(
  1967. DWORD dwNotifyType,
  1968. LPVOID pInstance
  1969. )
  1970. {
  1971. LockGlobals();
  1972. if ( dwNotifyType == SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED )
  1973. {
  1974. FreeCredCache();
  1975. //
  1976. // NB : Under NT 5, the SslEmptyCache function is no longer supported
  1977. //
  1978. #if 0
  1979. if ( g_pfnFlushSchannelCache )
  1980. {
  1981. (g_pfnFlushSchannelCache)();
  1982. }
  1983. #endif
  1984. }
  1985. else if ( dwNotifyType == SIMSSL_NOTIFY_MAPPER_CERT11_CHANGED ||
  1986. dwNotifyType == SIMSSL_NOTIFY_MAPPER_CERTW_CHANGED )
  1987. {
  1988. FreeCredCache();
  1989. }
  1990. else if ( dwNotifyType == SIMSSL_NOTIFY_MAPPER_CERT11_TOUCHED )
  1991. {
  1992. //
  1993. // NB : Under NT 5, the SslEmptyCache function is no longer supported
  1994. //
  1995. #if 0
  1996. if ( g_pfnFlushSchannelCache )
  1997. {
  1998. (g_pfnFlushSchannelCache)();
  1999. }
  2000. #endif
  2001. //SSPI_FILTER_CONTEXT::FlushOnDelete();
  2002. }
  2003. else
  2004. {
  2005. _ASSERT( FALSE );
  2006. }
  2007. UnlockGlobals();
  2008. }