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.

606 lines
13 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name :
  4. iisctl.cxx
  5. Abstract:
  6. IIS CTL (Certificate Trust List) handler
  7. This gets used only with SSL client certificates
  8. Author:
  9. Jaroslav Dunajsky
  10. Environment:
  11. Win32 - User Mode
  12. Project:
  13. Stream Filter Worker Process
  14. --*/
  15. #include "precomp.hxx"
  16. IIS_CTL_HASH * IIS_CTL::sm_pIisCtlHash;
  17. IIS_CTL::IIS_CTL(
  18. IN CREDENTIAL_ID * pCredentialId
  19. ) : _pCredentialId( pCredentialId ),
  20. _pCtlContext( NULL ),
  21. _pCtlStore( NULL ),
  22. _cRefs( 1 )
  23. {
  24. _dwSignature = IIS_CTL_SIGNATURE;
  25. }
  26. IIS_CTL::~IIS_CTL()
  27. {
  28. if ( _pCtlContext != NULL )
  29. {
  30. CertFreeCTLContext( _pCtlContext );
  31. _pCtlContext = NULL;
  32. }
  33. if ( _pCtlStore != NULL )
  34. {
  35. _pCtlStore->DereferenceStore();
  36. _pCtlStore = NULL;
  37. }
  38. if ( _pCredentialId != NULL )
  39. {
  40. delete _pCredentialId;
  41. _pCredentialId = NULL;
  42. }
  43. _dwSignature = IIS_CTL_SIGNATURE_FREE;
  44. }
  45. //static
  46. HRESULT
  47. IIS_CTL::Initialize(
  48. VOID
  49. )
  50. /*++
  51. Routine Description:
  52. Initialize IIS CTL globals
  53. Arguments:
  54. None
  55. Return Value:
  56. HRESULT
  57. --*/
  58. {
  59. sm_pIisCtlHash = new IIS_CTL_HASH();
  60. if ( sm_pIisCtlHash == NULL )
  61. {
  62. return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  63. }
  64. return NO_ERROR;
  65. }
  66. //static
  67. VOID
  68. IIS_CTL::Terminate(
  69. VOID
  70. )
  71. /*++
  72. Routine Description:
  73. Cleanup IIS Ctl globals
  74. Arguments:
  75. None
  76. Return Value:
  77. None
  78. --*/
  79. {
  80. if ( sm_pIisCtlHash != NULL )
  81. {
  82. delete sm_pIisCtlHash;
  83. sm_pIisCtlHash = NULL;
  84. }
  85. }
  86. //static
  87. HRESULT
  88. IIS_CTL::GetIisCtl(
  89. IN WCHAR * pszSslCtlIdentifier,
  90. IN WCHAR * pszSslCtlStoreName,
  91. OUT IIS_CTL ** ppIisCtl
  92. )
  93. /*++
  94. Routine Description:
  95. Find a suitable Ctl for use with the site represented by
  96. given site SslConfig
  97. Arguments:
  98. pzsSslCtlIdentifier - identifies CTL
  99. pszSslCtlStoreName - store name where CTL is to be located (in the LOCAL_MACHINE context)
  100. If NULL, then default "CA" store is assumed
  101. ppIisCtl - pointer to IIS CTL
  102. Return Value:
  103. HRESULT
  104. --*/
  105. {
  106. IIS_CTL * pIisCtl = NULL;
  107. CREDENTIAL_ID * pCredentialId = NULL;
  108. HRESULT hr = NO_ERROR;
  109. LK_RETCODE lkrc;
  110. if ( ppIisCtl == NULL )
  111. {
  112. DBG_ASSERT( FALSE );
  113. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  114. }
  115. *ppIisCtl = NULL;
  116. if ( pszSslCtlStoreName == NULL )
  117. {
  118. //
  119. // assume default store name
  120. //
  121. pszSslCtlStoreName = L"CA";
  122. }
  123. //
  124. // First build up a Credential ID to use in looking up in our
  125. // server cert cache
  126. //
  127. pCredentialId = new CREDENTIAL_ID;
  128. if ( pCredentialId == NULL )
  129. {
  130. return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  131. }
  132. hr = IIS_CTL::BuildCredentialId( pszSslCtlIdentifier,
  133. pCredentialId );
  134. if ( FAILED( hr ) )
  135. {
  136. //
  137. // Regardless of error, we are toast because we couldn't find
  138. // a server cert
  139. //
  140. delete pCredentialId;
  141. return hr;
  142. }
  143. DBG_ASSERT( sm_pIisCtlHash != NULL );
  144. lkrc = sm_pIisCtlHash->FindKey( pCredentialId,
  145. &pIisCtl );
  146. if ( lkrc == LK_SUCCESS )
  147. {
  148. //
  149. // Server already contains a credential ID
  150. //
  151. delete pCredentialId;
  152. *ppIisCtl = pIisCtl;
  153. return NO_ERROR;
  154. }
  155. //
  156. // Ok. It wasn't in our case, we need to do it there
  157. //
  158. // if IIS_CTL construction succeeds then IIS_CTL
  159. // takes ownership of pCredentialId and is responsible for freeing it
  160. //
  161. pIisCtl = new IIS_CTL( pCredentialId );
  162. if ( pIisCtl == NULL )
  163. {
  164. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  165. delete pCredentialId;
  166. return hr;
  167. }
  168. hr = pIisCtl->SetupIisCtl( pszSslCtlIdentifier,
  169. pszSslCtlStoreName );
  170. if ( FAILED( hr ) )
  171. {
  172. //
  173. // Server certificate owns the reference to pCredentialId now
  174. //
  175. delete pIisCtl;
  176. return hr;
  177. }
  178. //
  179. // Now try to add cert to hash.
  180. //
  181. lkrc = sm_pIisCtlHash->InsertRecord( pIisCtl );
  182. //
  183. // Ignore the error. If it didn't get added then we will naturally
  184. // clean it up on the callers dereference
  185. //
  186. *ppIisCtl = pIisCtl;
  187. return NO_ERROR;
  188. }
  189. //static
  190. HRESULT
  191. IIS_CTL::BuildCredentialId(
  192. IN WCHAR * pszSslCtlIdentifier,
  193. OUT CREDENTIAL_ID * pCredentialId
  194. )
  195. /*++
  196. Routine Description:
  197. Read the configured server cert and CTL hash. This forms the identifier
  198. for the credentials we need for this site
  199. Arguments:
  200. pszSslCtlIdentifier - CTL identifier
  201. pCredentialId - Filled with credential ID
  202. Return Value:
  203. HRESULT
  204. --*/
  205. {
  206. STACK_BUFFER( buff, 64 );
  207. HRESULT hr = NO_ERROR;
  208. if ( pCredentialId == NULL )
  209. {
  210. DBG_ASSERT( FALSE );
  211. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  212. }
  213. if ( pszSslCtlIdentifier == NULL ||
  214. pszSslCtlIdentifier[0] == '\0' )
  215. {
  216. //
  217. // No CTL
  218. //
  219. return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  220. }
  221. else
  222. {
  223. //
  224. // Add to our credential ID
  225. //
  226. hr = pCredentialId->Append( (BYTE*) pszSslCtlIdentifier,
  227. (DWORD) wcslen( pszSslCtlIdentifier ) * sizeof(WCHAR) );
  228. if ( FAILED( hr ) )
  229. {
  230. return hr;
  231. }
  232. }
  233. return NO_ERROR;
  234. }
  235. //private
  236. //static
  237. HRESULT
  238. IIS_CTL::SetupIisCtl(
  239. IN WCHAR * pszSslCtlIdentifier,
  240. IN WCHAR * pszSslCtlStoreName
  241. )
  242. /*++
  243. Routine Description:
  244. Build CTL context for the site based on SiteSslConfig Info
  245. Arguments:
  246. pszSslCtlIdentifier - identifies CTL
  247. pszSslCtlStoreName - store name where CTL is to be located (in the LOCAL_MACHINE context)
  248. Return Value:
  249. HRESULT
  250. --*/
  251. {
  252. HRESULT hr = E_FAIL;
  253. PCCTL_CONTEXT pCtlContext = NULL;
  254. CERT_STORE * pCertStore = NULL;
  255. STACK_STRU( strStoreName, 256 );
  256. if ( pszSslCtlIdentifier == NULL ||
  257. pszSslCtlStoreName == NULL ||
  258. pszSslCtlStoreName == L'\0' )
  259. {
  260. // CTLs not configured
  261. _pCtlContext = NULL;
  262. return S_OK;
  263. }
  264. //
  265. // First get the desired store and store it away for later!
  266. //
  267. hr = strStoreName.Copy( pszSslCtlStoreName );
  268. if ( FAILED( hr ) )
  269. {
  270. goto Finished;
  271. }
  272. hr = CERT_STORE::OpenStore( strStoreName,
  273. &pCertStore );
  274. if ( FAILED( hr ) )
  275. {
  276. goto Finished;
  277. }
  278. DBG_ASSERT( pCertStore != NULL );
  279. _pCtlStore = pCertStore;
  280. CTL_FIND_USAGE_PARA CtlFindUsagePara;
  281. ZeroMemory( &CtlFindUsagePara,
  282. sizeof(CtlFindUsagePara) );
  283. CtlFindUsagePara.cbSize = sizeof(CtlFindUsagePara);
  284. CtlFindUsagePara.ListIdentifier.cbData =
  285. ( (DWORD) wcslen( pszSslCtlIdentifier ) + 1 ) * sizeof(WCHAR);
  286. CtlFindUsagePara.ListIdentifier.pbData = (PBYTE) pszSslCtlIdentifier;
  287. //
  288. // Try to find CTL in specified store
  289. //
  290. pCtlContext = CertFindCTLInStore( _pCtlStore->QueryStore(),
  291. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  292. 0,
  293. CTL_FIND_USAGE,
  294. (LPVOID) &CtlFindUsagePara,
  295. NULL );
  296. if ( pCtlContext == NULL )
  297. {
  298. hr = HRESULT_FROM_WIN32( GetLastError() );
  299. goto Finished;
  300. }
  301. _pCtlContext = pCtlContext;
  302. hr = S_OK;
  303. Finished:
  304. return hr;
  305. }
  306. //static
  307. LK_PREDICATE
  308. IIS_CTL::CertStorePredicate(
  309. IN IIS_CTL * pIisCtl,
  310. IN void * pvState
  311. )
  312. /*++
  313. Description:
  314. DeleteIf() predicate used to find items which reference the
  315. CERT_STORE pointed to by pvState
  316. Arguments:
  317. pIisCtl - Server cert
  318. pvState - Points to CERT_STORE
  319. Returns:
  320. LK_PREDICATE - LKP_PERFORM indicates removing the current
  321. token from token cache
  322. LKP_NO_ACTION indicates doing nothing.
  323. --*/
  324. {
  325. LK_PREDICATE lkpAction;
  326. CERT_STORE * pCtlStore;
  327. DBG_ASSERT( pIisCtl != NULL );
  328. pCtlStore = (CERT_STORE*) pvState;
  329. DBG_ASSERT( pCtlStore != NULL );
  330. if ( pIisCtl->_pCtlStore == pCtlStore )
  331. {
  332. //
  333. // Before we delete the cert, flush any site which is referencing
  334. // it
  335. //
  336. ENDPOINT_CONFIG::FlushByIisCtl( pIisCtl );
  337. lkpAction = LKP_PERFORM;
  338. }
  339. else
  340. {
  341. lkpAction = LKP_NO_ACTION;
  342. }
  343. return lkpAction;
  344. }
  345. //static
  346. HRESULT
  347. IIS_CTL::FlushByStore(
  348. IN CERT_STORE * pCertStore
  349. )
  350. /*++
  351. Routine Description:
  352. Flush any server certs which reference the given store
  353. Arguments:
  354. pCertStore - Cert store to check
  355. Return Value:
  356. HRESULT
  357. --*/
  358. {
  359. DBG_ASSERT( sm_pIisCtlHash != NULL );
  360. sm_pIisCtlHash->DeleteIf( IIS_CTL::CertStorePredicate,
  361. pCertStore );
  362. return NO_ERROR;
  363. }
  364. HRESULT
  365. IIS_CTL::VerifyContainsCert(
  366. IN PCCERT_CONTEXT pChainTop,
  367. OUT BOOL * pfContainsCert
  368. )
  369. /*++
  370. Routine Description:
  371. Verify is CTL contains given certificate
  372. Arguments:
  373. pChainTop - top certificate of the chain to be found in CTL
  374. pfContainsCert - TRUE if contains, FALSE if it doesn't
  375. (valuse valid only if function returns SUCCESS)
  376. Return Value:
  377. HRESULT
  378. --*/
  379. {
  380. HRESULT hr = E_FAIL;
  381. const int SHA1_HASH_SIZE = 20;
  382. BYTE rgbChainTopHash[ SHA1_HASH_SIZE ];
  383. DWORD cbSize = SHA1_HASH_SIZE;
  384. if ( _pCtlContext == NULL )
  385. {
  386. //
  387. // pCTLContext could be NULL if there was failure in building
  388. // CTL context in the SITE CONFIG setup
  389. //
  390. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  391. }
  392. //
  393. // get hash of the certificate to be verified
  394. //
  395. if ( !CertGetCertificateContextProperty( pChainTop,
  396. CERT_SHA1_HASH_PROP_ID,
  397. rgbChainTopHash,
  398. &cbSize ) )
  399. {
  400. hr = HRESULT_FROM_WIN32( GetLastError() );
  401. DBGPRINTF((DBG_CONTEXT,
  402. "Failed to get cert hash for CTL check: 0x%x\n",
  403. hr));
  404. return hr;
  405. }
  406. //
  407. // Iterate through all the cert hashes in the CTL and compare hashes
  408. //
  409. for ( DWORD dwIndex = 0; dwIndex< _pCtlContext->pCtlInfo->cCTLEntry; dwIndex++ )
  410. {
  411. CRYPT_DATA_BLOB CertInCTLHashBlob =
  412. _pCtlContext->pCtlInfo->rgCTLEntry[dwIndex].SubjectIdentifier;
  413. //
  414. // CODEWORK: checking hash size is a bit simplistic way of
  415. // verifying that SHA1 hash is used in CTL
  416. //
  417. if ( CertInCTLHashBlob.cbData != SHA1_HASH_SIZE ||
  418. CertInCTLHashBlob.pbData == NULL )
  419. {
  420. //
  421. // hash in the CTL is no SHA1 because size is different
  422. // or invalid CTL
  423. //
  424. DBG_ASSERT( FALSE );
  425. return CRYPT_E_NOT_FOUND;
  426. }
  427. if ( memcmp( CertInCTLHashBlob.pbData,
  428. rgbChainTopHash,
  429. SHA1_HASH_SIZE ) == 0 )
  430. {
  431. *pfContainsCert = TRUE;
  432. return S_OK;
  433. }
  434. }
  435. *pfContainsCert = FALSE;
  436. return S_OK;
  437. }
  438. //static
  439. VOID
  440. IIS_CTL::Cleanup(
  441. VOID
  442. )
  443. /*++
  444. Routine Description:
  445. Cleanup must be called before Terminate
  446. Arguments:
  447. none
  448. Return Value:
  449. VOID
  450. --*/
  451. {
  452. sm_pIisCtlHash->Clear();
  453. }