Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1750 lines
41 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. sslinfo.cxx
  5. Abstract:
  6. Implementation of IIS_SSL_INFO class
  7. Author:
  8. Alex Mallet (amallet) 03-Feb-1997
  9. --*/
  10. #include "tcpdllp.hxx"
  11. #pragma hdrstop
  12. #include <wincrypt.h>
  13. #include <dbgutil.h>
  14. #include <buffer.hxx>
  15. #include <ole2.h>
  16. #include <imd.h>
  17. #include <mb.hxx>
  18. #include <eventlog.hxx>
  19. #include <reftrace.h>
  20. #include "iiscert.hxx"
  21. #include "capiutil.hxx"
  22. #include "iisctl.hxx"
  23. #include "certnotf.hxx"
  24. #include "sslinfo.hxx"
  25. #if DBG
  26. #define VALIDATE_HEAP() DBG_ASSERT( RtlValidateHeap( RtlProcessHeap(), 0, NULL ) )
  27. #else
  28. #define VALIDATE_HEAP()
  29. #endif
  30. IIS_SSL_INFO::IIS_SSL_INFO( IN LPTSTR pszMBPath,
  31. IN IMDCOM *pMDObject ) :
  32. m_pCert( NULL ),
  33. m_fDefaultCert( FALSE ),
  34. m_fCertOK( FALSE ),
  35. m_pCTL( NULL ),
  36. m_fDefaultCTL ( FALSE ),
  37. m_fCTLOK( FALSE ),
  38. m_strMBPath( pszMBPath ),
  39. m_pMDObject(pMDObject),
  40. m_hTrustedIssuerStore( NULL ),
  41. m_hRestrictedRoot( NULL ),
  42. m_hRestrictedTrust( NULL ),
  43. m_dwRefCount( 0 ),
  44. m_dwSignature( IIS_SSL_INFO_SIGNATURE ),
  45. m_fUseDSMapper( FALSE ),
  46. m_fCheckedDSMapper( FALSE ),
  47. m_hChainEngine( NULL ),
  48. m_hMyStore( NULL ),
  49. m_hCAStore( NULL ),
  50. m_hRootStore( NULL ),
  51. m_acRootCerts( NULL ),
  52. m_cRootCerts( 0 ),
  53. m_dwCertChainStatus( -1 )
  54. /*++
  55. Description
  56. Constructor; doesn't do anything, really
  57. Arguments:
  58. pszMBPath - path in metabase where SSL-related information is to be found
  59. pMDObject - metabase object to be used for metabase operations
  60. pNotifFnc - function to be called when object destructor is called. May be NULL.
  61. pvArg - argument to pNotifFnc. Ignored if pNotifFnc == NULL
  62. Returns:
  63. Nothing
  64. --*/
  65. {
  66. DBG_ASSERT( pszMBPath );
  67. DBG_ASSERT( pMDObject );
  68. INITIALIZE_CRITICAL_SECTION( &m_CritSec );
  69. m_hMyStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  70. 0,
  71. NULL,
  72. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  73. MY_STORE_NAME );
  74. m_hCAStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  75. 0,
  76. NULL,
  77. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  78. CA_STORE_NAME );
  79. m_hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  80. 0,
  81. NULL,
  82. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  83. ROOT_STORE_NAME );
  84. #if SSLINFO_REF_COUNT
  85. m_pRefTraceLog = CreateRefTraceLog( C_SSLINFO_REFTRACES, 0 );
  86. DBGPRINTF((DBG_CONTEXT,
  87. "Created ref trace object %p for SSL object %p\n",
  88. m_pRefTraceLog, this));
  89. #endif
  90. }
  91. IIS_SSL_INFO::~IIS_SSL_INFO( VOID )
  92. /*++
  93. Description
  94. Destructor
  95. Arguments:
  96. None
  97. Returns:
  98. Nothing
  99. --*/
  100. {
  101. DBG_ASSERT( CheckSignature() );
  102. DBG_ASSERT( m_dwRefCount == 0 );
  103. if ( m_pCert )
  104. {
  105. delete m_pCert;
  106. m_pCert = NULL;
  107. }
  108. if ( m_pCTL )
  109. {
  110. delete m_pCTL;
  111. m_pCTL = NULL;
  112. }
  113. if ( m_hChainEngine )
  114. {
  115. CertFreeCertificateChainEngine( m_hChainEngine );
  116. m_hChainEngine = NULL;
  117. }
  118. if ( m_hTrustedIssuerStore )
  119. {
  120. CertCloseStore( m_hTrustedIssuerStore,
  121. 0 );
  122. m_hTrustedIssuerStore = NULL;
  123. }
  124. if ( m_hRestrictedRoot )
  125. {
  126. CertCloseStore( m_hRestrictedRoot,
  127. 0 );
  128. m_hRestrictedRoot = NULL;
  129. }
  130. if ( m_hRestrictedTrust )
  131. {
  132. CertCloseStore( m_hRestrictedTrust,
  133. 0 );
  134. m_hRestrictedTrust = NULL;
  135. }
  136. if ( m_hRootStore )
  137. {
  138. CertCloseStore( m_hRootStore,
  139. 0 );
  140. m_hRootStore = NULL;
  141. }
  142. if ( m_hCAStore )
  143. {
  144. CertCloseStore( m_hCAStore,
  145. 0 );
  146. m_hCAStore = NULL;
  147. }
  148. if ( m_hMyStore )
  149. {
  150. CertCloseStore( m_hMyStore,
  151. 0 );
  152. m_hMyStore = NULL;
  153. }
  154. if ( m_acRootCerts )
  155. {
  156. for ( DWORD i = 0; i < m_cRootCerts; i++ )
  157. {
  158. CertFreeCertificateContext( m_acRootCerts[i] );
  159. }
  160. delete [] m_acRootCerts;
  161. m_acRootCerts = NULL;
  162. m_cRootCerts = 0;
  163. }
  164. DeleteCriticalSection( &m_CritSec );
  165. m_dwSignature = IIS_SSL_INFO_SIGNATURE_FREE;
  166. #if SSLINFO_REF_COUNT
  167. if ( m_pRefTraceLog )
  168. {
  169. DBGPRINTF((DBG_CONTEXT,
  170. "Deleting ref trace object %p for ssl object %p\n",
  171. m_pRefTraceLog, this));
  172. DestroyRefTraceLog( m_pRefTraceLog );
  173. }
  174. #endif //SSLINFO_REF_COUNT
  175. }
  176. IIS_SSL_INFO *
  177. IIS_SSL_INFO::CreateSSLInfo(
  178. IN LPTSTR pszMBPath,
  179. IN IMDCOM * pMDObject
  180. )
  181. {
  182. return new IIS_SSL_INFO( pszMBPath, pMDObject );
  183. }
  184. IIS_SERVER_CERT* IIS_SSL_INFO::GetCertificate( VOID )
  185. /*++
  186. Description
  187. Returns server certificate for this instance of the server
  188. Arguments:
  189. None
  190. Returns:
  191. ptr to IIS_SERVER_CERT object for this instance, NULL if none can be found/constructed
  192. --*/
  193. {
  194. DBG_ASSERT( CheckSignature() );
  195. BOOL fDefault = FALSE;
  196. LPTSTR pszMDPath = NULL;
  197. BOOL fHasCert = FALSE;
  198. Lock();
  199. if ( !m_pCert )
  200. {
  201. if ( HasCertificate( &fHasCert,
  202. &m_fDefaultCert ) &&
  203. //
  204. // server has cert
  205. //
  206. fHasCert )
  207. {
  208. if ( m_fDefaultCert )
  209. {
  210. pszMDPath = DEFAULT_SERVER_CERT_MD_PATH;
  211. }
  212. else
  213. {
  214. pszMDPath = m_strMBPath.QueryStr();
  215. }
  216. m_pCert = new IIS_SERVER_CERT( m_pMDObject,
  217. pszMDPath );
  218. if ( !m_pCert || !m_pCert->IsValid() )
  219. {
  220. DBGPRINTF((DBG_CONTEXT,
  221. "Failed to construct cert from path %s, error 0x%x\n",
  222. pszMDPath, GetLastError()));
  223. }
  224. }
  225. }
  226. Unlock();
  227. return m_pCert;
  228. }
  229. IIS_CTL*
  230. IIS_SSL_INFO::GetCTL( VOID )
  231. /*++
  232. Description
  233. Returns Certificate Trust List [CTL] for this instance of the server
  234. Arguments:
  235. None
  236. Returns:
  237. ptr to IIS_CTL object for this instance, NULL if none can be found/constructed
  238. --*/
  239. {
  240. DBG_ASSERT( CheckSignature() );
  241. BOOL fDefault = FALSE;
  242. LPTSTR pszMDPath = NULL;
  243. BOOL fHasCTL = FALSE;
  244. Lock();
  245. if ( !m_pCTL )
  246. {
  247. if ( HasCTL( &fHasCTL,
  248. &m_fDefaultCTL ) &&
  249. //
  250. // instance has CTL
  251. //
  252. fHasCTL )
  253. {
  254. if ( m_fDefaultCTL )
  255. {
  256. pszMDPath = DEFAULT_CTL_MD_PATH;
  257. }
  258. else
  259. {
  260. pszMDPath = m_strMBPath.QueryStr();
  261. }
  262. m_pCTL = new IIS_CTL( m_pMDObject,
  263. pszMDPath );
  264. if ( !m_pCTL || !m_pCTL->IsValid() )
  265. {
  266. DBGPRINTF((DBG_CONTEXT,
  267. "Failed to construct CTL from path %s, error 0x%x\n",
  268. pszMDPath, GetLastError()));
  269. }
  270. }
  271. }
  272. Unlock();
  273. return (m_pCTL);
  274. }
  275. BOOL IIS_SSL_INFO::HasCertificate( OUT PBOOL pfHasCert,
  276. OUT PBOOL pfIsDefaultCert )
  277. /*++
  278. Description
  279. Check whether this instance has certificate info in the metabase
  280. Arguments:
  281. pfHasCert - pointer to bool set to TRUE if server has a cert, FALSE if not
  282. pfIsDefaultCert - Pointer to bool that is set to true if the server has a cert and
  283. that cert is the default [global] cert. Not set if the server doesn't have a cert
  284. Returns:
  285. TRUE if check succeeds, FALSE if not
  286. --*/
  287. {
  288. DBG_ASSERT( CheckSignature() );
  289. return CheckCAPIInfo( pfHasCert,
  290. pfIsDefaultCert,
  291. DEFAULT_SERVER_CERT_MD_PATH,
  292. adwMetabaseCertProperties,
  293. cNumCertMetabaseProperties );
  294. }
  295. BOOL IIS_SSL_INFO::HasCTL( OUT PBOOL pfHasCTL,
  296. OUT PBOOL pfIsDefaultCTL )
  297. /*++
  298. Description
  299. Check whether this instance has CTL info in the metabase
  300. Arguments:
  301. pfHasCTL - pointer to bool set to TRUE if server has a CTL, FALSE if not
  302. pfIsDefaultCTL - Pointer to bool that is set to true if the server has a CTL
  303. and that CTL is the default [global] CTL. Not set if the server doesn't have a CTL
  304. Returns:
  305. TRUE if check succeeds, FALSE if not
  306. --*/
  307. {
  308. DBG_ASSERT( CheckSignature() );
  309. return CheckCAPIInfo( pfHasCTL,
  310. pfIsDefaultCTL,
  311. DEFAULT_CTL_MD_PATH,
  312. adwMetabaseCTLProperties,
  313. cNumCTLMetabaseProperties);
  314. }
  315. BOOL IIS_SSL_INFO::CheckCAPIInfo( OUT PBOOL pfHasInfo,
  316. OUT PBOOL pfIsDefaultInfo,
  317. IN LPTSTR pszDefaultPath,
  318. IN DWORD *adwMetabaseProperties,
  319. IN DWORD cProperties )
  320. /*++
  321. Description
  322. Check whether this instance has CAPI info in the metabase
  323. Arguments:
  324. pfHasInfo - pointer to bool set to TRUE if server has CAPI info, FALSE if not
  325. pfIsDefaultInfo - Pointer to bool that is set to true if the server doesn't have
  326. its own copy of the CTL info but is to use the default [global] info. Not set if there
  327. is no CAPI info.
  328. pszDefaultPath - metabase path to default info
  329. adwMetabaseProperties - metabase properties to be checked
  330. cProperties - number of entries in adwMetabaseProperties
  331. Returns:
  332. TRUE if check for info succeeds, FALSE if not
  333. NB : TRUE doesn't mean CAPI info was found, it means there were no internal errors
  334. looking for the info
  335. --*/
  336. {
  337. DBG_ASSERT( CheckSignature() );
  338. MB mb( m_pMDObject );
  339. BOOL fGotCertInfo = FALSE;
  340. m_fDefaultCert = FALSE;
  341. if ( !mb.Open( "/" ) )
  342. {
  343. return FALSE;
  344. }
  345. if ( !( *pfHasInfo = ServerAddressHasCAPIInfo( &mb,
  346. m_strMBPath.QueryStr(),
  347. adwMetabaseProperties,
  348. cProperties ) ) )
  349. {
  350. *pfHasInfo = ServerAddressHasCAPIInfo( &mb,
  351. pszDefaultPath,
  352. adwMetabaseProperties,
  353. cProperties );
  354. if ( *pfHasInfo )
  355. {
  356. *pfIsDefaultInfo = TRUE;
  357. }
  358. }
  359. else
  360. {
  361. *pfIsDefaultInfo = FALSE;
  362. }
  363. mb.Close();
  364. return (TRUE);
  365. }
  366. BOOL IIS_SSL_INFO::GetTrustedIssuerCerts( OUT PCCERT_CONTEXT **ppcCertContext,
  367. OUT DWORD *pdwCertsFound )
  368. /*++
  369. Routine Description:
  370. Tries to retrieve CERT_CONTEXT pointers for the trusted CA certs for the given object.
  371. Trusted CA certs are either retrieved from the appropriate Certificate Trust List or
  372. from the Local Machine Root store.
  373. Arguments:
  374. pppCertContext - pointer to array of CERT_CONTEXT pointers, filled out with the found
  375. CERT_CONTEXTS.
  376. Caller is responsible for releasing the contexts when done with them and deleting
  377. the array used to hold them.
  378. pdwCertsFound - pointer to number of cert contexts returned in ppCertContext
  379. Returns:
  380. TRUE if no internal errors occurred, FALSE if NOT
  381. --*/
  382. {
  383. DBG_ASSERT( CheckSignature() );
  384. BOOL fOk = TRUE;
  385. Lock();
  386. //
  387. // Use the certs in the CTL, if we have metabase information for one, else get the certs
  388. // from the Root store
  389. //
  390. if ( GetCTL() )
  391. {
  392. if ( m_pCTL->IsValid() )
  393. {
  394. DWORD dwCertsInCTL = 0;
  395. fOk = QueryCTL()->GetContainedCertificates( ppcCertContext,
  396. pdwCertsFound,
  397. &dwCertsInCTL );
  398. }
  399. else
  400. {
  401. fOk = FALSE;
  402. }
  403. }
  404. else
  405. {
  406. fOk = GetRootStoreCertificates( ppcCertContext,
  407. pdwCertsFound );
  408. }
  409. Unlock();
  410. return fOk;
  411. }
  412. BOOL IIS_SSL_INFO::GetTrustedIssuerStore( OUT HCERTSTORE *phCertStore )
  413. /*++
  414. Routine Description:
  415. Returns a pointer to a handle to a cert store that contains the certs for all the
  416. trusted CAs for this server instance. If there is a CTL, the store will contain
  417. the certs in the CTL, else it will be a handle to the Local Machine Root store.
  418. Arguments:
  419. phCertStore - pointer to handle to cert store containing trusted issuers. Updated on
  420. success. Caller has to call CertCloseStore() when done with the store handle.
  421. Returns:
  422. TRUE if no internal errors occurred, FALSE if NOT
  423. --*/
  424. {
  425. DBG_ASSERT( CheckSignature() );
  426. Lock();
  427. BOOL fSuccess = FALSE;
  428. DWORD dwIndex = 0;
  429. PCCERT_CONTEXT *rgContexts = NULL;
  430. DWORD cCertsFound = 0;
  431. *phCertStore = NULL;
  432. //
  433. // If there is no CTL configurated, then return NULL for trusted store to
  434. // be used by schannel. When NULL, schannel will use the root store +
  435. // the trusted store to determine trusted CAs (the desired effect)
  436. //
  437. if ( !GetCTL() )
  438. {
  439. Unlock();
  440. return TRUE;
  441. }
  442. if ( !m_hTrustedIssuerStore )
  443. {
  444. //
  445. // If there's no CTL configured, the store that holds our trusted issuers is the
  446. // Root store;
  447. // we could just fall through and call GetTrustedIssuerCerts() [which will read all
  448. // the certs out of the Root store], but that's unnecessary because we can just
  449. // hand back a handle to the Root store.
  450. //
  451. {
  452. if ( !m_pCTL->IsValid() )
  453. {
  454. goto clean_up;
  455. }
  456. //
  457. // Get an in-memory store that will hold all the trusted issuer certs
  458. //
  459. if ( !( m_hTrustedIssuerStore = CertOpenStore( CERT_STORE_PROV_MEMORY,
  460. 0,
  461. 0,
  462. 0,
  463. 0 ) ) )
  464. {
  465. goto clean_up;
  466. }
  467. //
  468. // Try to retrieve all the certs in it and stuff them
  469. // into the in-memory store
  470. //
  471. if ( !GetTrustedIssuerCerts( &rgContexts,
  472. &cCertsFound ) )
  473. {
  474. goto clean_up;
  475. }
  476. for ( dwIndex = 0; dwIndex < cCertsFound ; dwIndex++ )
  477. {
  478. if ( !CertAddCertificateContextToStore( m_hTrustedIssuerStore,
  479. rgContexts[dwIndex],
  480. CERT_STORE_ADD_ALWAYS,
  481. NULL ) )
  482. {
  483. goto clean_up;
  484. }
  485. }
  486. //
  487. // And finally make a copy of the store handle; note that the store will be empty if
  488. // we don't have a valid CTL or we couldn't retrieve the certs in the CTL
  489. //
  490. if ( !(*phCertStore = CertDuplicateStore( m_hTrustedIssuerStore ) ) )
  491. {
  492. goto clean_up;
  493. }
  494. }
  495. fSuccess = TRUE;
  496. clean_up:
  497. //
  498. // cleanup done only on failure
  499. //
  500. if ( !fSuccess )
  501. {
  502. if ( *phCertStore )
  503. {
  504. CertCloseStore( *phCertStore,
  505. 0 );
  506. }
  507. if ( m_hTrustedIssuerStore )
  508. {
  509. CertCloseStore( m_hTrustedIssuerStore,
  510. 0 );
  511. m_hTrustedIssuerStore = NULL;
  512. }
  513. }
  514. //
  515. // cleanup done regardless of success/failure
  516. //
  517. //
  518. // clean up all the cert contexts, because the store has a copy of them
  519. //
  520. if ( rgContexts )
  521. {
  522. for ( dwIndex = 0; dwIndex < cCertsFound; dwIndex++ )
  523. {
  524. if ( rgContexts[dwIndex] )
  525. {
  526. CertFreeCertificateContext( rgContexts[dwIndex] );
  527. }
  528. }
  529. delete [] rgContexts;
  530. }
  531. }
  532. else
  533. {
  534. if ( *phCertStore = CertDuplicateStore(m_hTrustedIssuerStore) )
  535. {
  536. fSuccess = TRUE;
  537. }
  538. }
  539. Unlock();
  540. return fSuccess;
  541. }
  542. BOOL IIS_SSL_INFO::CreateEngineRootStore()
  543. /*++
  544. Description
  545. Sets up the "Restricted Root" store that is passed to the cert chain engine used to
  546. verify client certificates. If there's a CTL attached to this object, the store contains
  547. only the self-signed cert that is at the top of the chain for the cert that signed
  548. the CTL. If there's no CTL, the store is the Local Machine Root store.
  549. Arguments:
  550. None
  551. Returns:
  552. TRUE if successful, FALSE if not
  553. --*/
  554. {
  555. DBG_ASSERT( CheckSignature() );
  556. BOOL fOk = TRUE;
  557. Lock();
  558. if ( !m_hRestrictedRoot )
  559. {
  560. //
  561. // No CTL, we'll just use the Root store
  562. //
  563. if ( !GetCTL() )
  564. {
  565. if ( m_hRootStore )
  566. {
  567. m_hRestrictedRoot = CertDuplicateStore( m_hRootStore );
  568. }
  569. else
  570. {
  571. fOk = FALSE;
  572. }
  573. }
  574. else
  575. {
  576. if ( !m_pCTL->IsValid() )
  577. {
  578. Unlock();
  579. return FALSE;
  580. }
  581. //
  582. // If we're signing our CTLs, the restricted root store should contain the
  583. // top of the chain for the cert that signed the CTL and this cert should be
  584. // in the ROOT store
  585. //
  586. // If we're not signing our CTLs, the restricted root store is just an empty
  587. // store
  588. //
  589. #if SIGNED_CTL
  590. PCCERT_CONTEXT pSigner = NULL;
  591. PCCERT_CONTEXT pIssuerCert = NULL;
  592. DWORD cCerts = 0;
  593. BOOL fTrustedRoot = FALSE;
  594. //
  595. // Get the cert that signed the CTL and try to find the issuers up to a self-signed
  596. // cert in the ROOT store
  597. //
  598. if ( m_pCTL->QuerySignerCert( &pSigner ) &&
  599. pSigner )
  600. {
  601. if ( FindTopOfChain( pSigner,
  602. &pIssuerCert ) &&
  603. IsTrustedRoot( pIssuerCert,
  604. &fTrustedRoot) &&
  605. fTrustedRoot )
  606. {
  607. //
  608. // Create in memory store, put top of chain into it - this is the
  609. // restricted-root store to use.
  610. //
  611. if ( m_hRestrictedRoot = CertOpenStore( CERT_STORE_PROV_MEMORY,
  612. 0,
  613. 0,
  614. 0,
  615. 0 ) )
  616. {
  617. fOk = CertAddCertificateContextToStore( m_hRestrictedRoot,
  618. pIssuerCert,
  619. CERT_STORE_ADD_ALWAYS,
  620. NULL );
  621. }
  622. else
  623. {
  624. fOk = FALSE;
  625. }
  626. }
  627. else
  628. {
  629. fOk = FALSE;
  630. }
  631. } // if ( QueryCTL()->QuerySigner
  632. else
  633. {
  634. fOk = FALSE;
  635. }
  636. #else //SIGNED_CTL
  637. if ( !( m_hRestrictedRoot = CertOpenStore( CERT_STORE_PROV_MEMORY,
  638. 0,
  639. 0,
  640. 0,
  641. 0 ) ) )
  642. {
  643. fOk = FALSE;
  644. }
  645. #endif //SIGNED_CTL
  646. } //else clause for if ( !GetCTL() )
  647. }
  648. Unlock();
  649. return fOk;
  650. }
  651. BOOL IIS_SSL_INFO::CreateEngineTrustStore()
  652. /*++
  653. Description
  654. Sets up the "Restricted Trust" store that is passed to the cert chain engine used to
  655. verify client certificates. If there is a CTL associated with this object, this store
  656. contains only the CTL associated with this object. Else, we'll just leave it as
  657. NULL so that the chain engine uses the default.
  658. Arguments:
  659. None
  660. Returns:
  661. TRUE if successful, FALSE if not
  662. --*/
  663. {
  664. DBG_ASSERT( CheckSignature() );
  665. BOOL fOk = TRUE;
  666. Lock();
  667. if ( !m_hRestrictedTrust )
  668. {
  669. if ( GetCTL() )
  670. {
  671. if ( !m_pCTL->IsValid() )
  672. {
  673. Unlock();
  674. return FALSE;
  675. }
  676. m_hRestrictedTrust = m_pCTL->GetMemoryStore();
  677. if ( !m_hRestrictedTrust )
  678. {
  679. fOk = FALSE;
  680. }
  681. }
  682. else
  683. {
  684. m_hRestrictedTrust = NULL;
  685. }
  686. }
  687. Unlock();
  688. return fOk;
  689. }
  690. DWORD IIS_SSL_INFO::Reference()
  691. /*++
  692. Description
  693. Increases ref count
  694. Arguments:
  695. Returns:
  696. # of outstanding references
  697. --*/
  698. {
  699. DBG_ASSERT( CheckSignature() );
  700. DWORD dwRefCount = 0;
  701. Lock();
  702. dwRefCount = InterlockedIncrement( (LONG *) &m_dwRefCount );
  703. #if SSLINFO_REF_COUNT
  704. if ( m_pRefTraceLog )
  705. {
  706. WriteRefTraceLogEx( m_pRefTraceLog,
  707. dwRefCount,
  708. (PVOID) this,
  709. (PVOID) -1,
  710. (PVOID) -1,
  711. (PVOID) -1 );
  712. }
  713. #endif //SSLINFO_REF_COUNT
  714. Unlock();
  715. return dwRefCount;
  716. }
  717. DWORD IIS_SSL_INFO::Release( PVOID pvParam )
  718. /*++
  719. Description
  720. Decreases ref count; deletes object if zero. Changed to static function to
  721. avoid not-quite-kosher "delete this" call.
  722. Arguments:
  723. pvParam - pointer to IIS_SSL_INFO
  724. Returns:
  725. # of outstanding references
  726. --*/
  727. {
  728. IIS_SSL_INFO *pInfo = (IIS_SSL_INFO *) pvParam;
  729. pInfo->Lock();
  730. DBG_ASSERT( pInfo->m_dwRefCount > 0 );
  731. DWORD dwRefCount = InterlockedDecrement( (LONG *) &(pInfo->m_dwRefCount) );
  732. #if SSLINFO_REF_COUNT
  733. if ( pInfo->m_pRefTraceLog )
  734. {
  735. WriteRefTraceLogEx( pInfo->m_pRefTraceLog,
  736. dwRefCount,
  737. (PVOID) pInfo,
  738. (PVOID) -1,
  739. (PVOID) -1,
  740. (PVOID) -1 );
  741. }
  742. #endif //SSLINFO_REF_COUNT
  743. if ( !dwRefCount )
  744. {
  745. pInfo->Unlock();
  746. delete pInfo;
  747. }
  748. else
  749. {
  750. pInfo->Unlock();
  751. }
  752. return dwRefCount;
  753. }
  754. BOOL IIS_SSL_INFO::UseDSMapper( VOID )
  755. /*++
  756. Description
  757. Checks whether the NT 5 DS mapper is to be used for client certificate mapping
  758. Arguments:
  759. None
  760. Returns:
  761. TRUE if mapper is to be used, false otherwise
  762. --*/
  763. {
  764. DBG_ASSERT( CheckSignature() );
  765. DBG_ASSERT( m_pMDObject );
  766. BOOL fUseMapper = FALSE;
  767. MB mb( m_pMDObject );
  768. if ( !mb.Open("/LM/W3SVC") )
  769. {
  770. return FALSE;
  771. }
  772. Lock();
  773. if ( !m_fCheckedDSMapper )
  774. {
  775. DWORD dwUseMapper = 0;
  776. if ( mb.GetDword( NULL,
  777. MD_SSL_USE_DS_MAPPER,
  778. IIS_MD_UT_SERVER,
  779. &dwUseMapper,
  780. METADATA_NO_ATTRIBUTES ) )
  781. {
  782. m_fUseDSMapper = (BOOL) dwUseMapper;
  783. m_fCheckedDSMapper = TRUE;
  784. }
  785. }
  786. fUseMapper = m_fUseDSMapper;
  787. Unlock();
  788. mb.Close();
  789. return fUseMapper;
  790. }
  791. BOOL IIS_SSL_INFO::GetCertChainEngine( OUT HCERTCHAINENGINE *phEngine )
  792. /*++
  793. Description
  794. Returns a handle to an initialized cert chain engine
  795. Arguments:
  796. pEngine - pointer to engine handle, updated on success
  797. Returns:
  798. TRUE if engine was constructed successfully, FALSE if not
  799. --*/
  800. {
  801. DBG_ASSERT( CheckSignature() );
  802. *phEngine = NULL;
  803. Lock();
  804. if ( !m_hChainEngine )
  805. {
  806. DBG_ASSERT( !m_hRestrictedRoot && !m_hRestrictedTrust );
  807. //
  808. // Set up the "Restricted Root" store, which contains all the certs to be accepted as the
  809. // top of a cert chain for this instance
  810. //
  811. if ( !CreateEngineRootStore() )
  812. {
  813. Unlock();
  814. DBGPRINTF((DBG_CONTEXT,
  815. "Failed to get engine root store : 0x%x\n",
  816. GetLastError()));
  817. return FALSE;
  818. }
  819. //
  820. // Trust store to be used for CTLs
  821. //
  822. if ( !CreateEngineTrustStore() )
  823. {
  824. CertCloseStore( m_hRestrictedRoot,
  825. 0 );
  826. m_hRestrictedRoot = NULL;
  827. Unlock();
  828. DBGPRINTF((DBG_CONTEXT,
  829. "Failed to get engine trust store : 0x%x\n",
  830. GetLastError()));
  831. return FALSE;
  832. }
  833. //
  834. // Initialize cert chain config
  835. //
  836. CERT_CHAIN_ENGINE_CONFIG CCEC;
  837. memset( &CCEC, 0, sizeof(CCEC) );
  838. CCEC.cbSize = sizeof(CCEC);
  839. CCEC.hRestrictedRoot = m_hRestrictedRoot;
  840. CCEC.hRestrictedTrust = m_hRestrictedTrust;
  841. CCEC.dwFlags = CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE;
  842. if( m_hRootStore )
  843. {
  844. //
  845. // Include the root store in the collection of stores
  846. // to search.
  847. //
  848. CCEC.cAdditionalStore = 1;
  849. CCEC.rghAdditionalStore = &m_hRootStore;
  850. }
  851. //
  852. // Get us a chain engine, will you, Jeeves ...
  853. //
  854. if ( !CertCreateCertificateChainEngine( &CCEC,
  855. &m_hChainEngine ) )
  856. {
  857. CertCloseStore( m_hRestrictedRoot,
  858. 0 );
  859. m_hRestrictedRoot = NULL;
  860. CertCloseStore( m_hRestrictedTrust,
  861. 0 );
  862. m_hRestrictedTrust = NULL;
  863. Unlock();
  864. DBGPRINTF((DBG_CONTEXT,
  865. "Failed to create chain engine : 0x%d\n",
  866. GetLastError()));
  867. return FALSE;
  868. }
  869. }
  870. //
  871. // Got this far, everything is cool
  872. //
  873. *phEngine = m_hChainEngine;
  874. Unlock();
  875. return TRUE;
  876. }
  877. BOOL IIS_SSL_INFO::FindTopOfChain( PCCERT_CONTEXT pcLeafCert,
  878. PCCERT_CONTEXT *ppcTopCert )
  879. /*++
  880. Description
  881. Finds the top of the chain for a given cert
  882. Arguments:
  883. pcLeafCert - cert whose chain is to be built
  884. ppcTopCert - pointer to pointer to as far up as we could go in pcLeafCert's hierarchy.
  885. Updated on success. Caller is responsible for cleaning it up.
  886. Returns:
  887. TRUE if search proceeded with no errors, FALSE otherwise
  888. --*/
  889. {
  890. DBG_ASSERT( CheckSignature() );
  891. *ppcTopCert = NULL;
  892. DBG_ASSERT( pcLeafCert );
  893. if( !pcLeafCert )
  894. {
  895. DBGERROR(( DBG_CONTEXT,
  896. "NULL cert context passed to IIS_SSL_INFO::FindTopOfChain\n"
  897. ));
  898. return FALSE;
  899. }
  900. //
  901. // To build the chain, look for issuers in 4 stores : the store the cert came from,
  902. // and the "MY", "CA" and "ROOT" stores, cycling through the stores as necessary
  903. //
  904. PCCERT_CONTEXT pcIssuer = NULL;
  905. PCCERT_CONTEXT pcPresentLeaf = CertDuplicateCertificateContext( pcLeafCert );
  906. DWORD dwFlags = 0;
  907. DWORD dwStoresTried = 0;
  908. BOOL fCompleteChain = FALSE;
  909. HCERTSTORE hPresentStore = pcPresentLeaf->hCertStore;
  910. DWORD cNumCerts = 0;
  911. while ( 1 )
  912. {
  913. //
  914. // Bail when we get to the top of a chain
  915. //
  916. if ( IsSelfSignedCert( pcPresentLeaf ) )
  917. {
  918. fCompleteChain = TRUE;
  919. break;
  920. }
  921. pcIssuer = CertGetIssuerCertificateFromStore( hPresentStore,
  922. pcPresentLeaf,
  923. NULL,
  924. &dwFlags );
  925. //
  926. // Got an issuer in this store
  927. //
  928. if ( pcIssuer )
  929. {
  930. //
  931. // Set up for next round
  932. //
  933. CertFreeCertificateContext( pcPresentLeaf );
  934. pcPresentLeaf = pcIssuer;
  935. dwStoresTried = 0;
  936. cNumCerts++;
  937. }
  938. //
  939. // No issuer in this store, switch to next store to look in
  940. //
  941. else
  942. {
  943. dwStoresTried++;
  944. if ( dwStoresTried == 4 ) //we've tried all the stores, time to bail
  945. {
  946. break;
  947. }
  948. if ( hPresentStore == m_hMyStore )
  949. {
  950. hPresentStore = m_hCAStore;
  951. }
  952. else if ( hPresentStore == m_hCAStore )
  953. {
  954. hPresentStore = m_hRootStore;
  955. }
  956. else if ( hPresentStore == m_hRootStore )
  957. {
  958. hPresentStore = pcPresentLeaf->hCertStore;
  959. }
  960. else
  961. {
  962. hPresentStore = m_hMyStore;
  963. }
  964. }
  965. } //while ( 1 )
  966. *ppcTopCert = pcPresentLeaf;
  967. return TRUE;
  968. }
  969. BOOL IIS_SSL_INFO::IsTrustedRoot( IN PCCERT_CONTEXT pcCert,
  970. OUT BOOL *pfTrustedRoot )
  971. /*++
  972. Description
  973. Checks whether a cert is a trusted root ie in the Local Machine Root store and
  974. self-signed
  975. Arguments:
  976. pcCert - cert to be checked
  977. pfTrustedRoot - pointer to bool that is updated on success
  978. Returns:
  979. TRUE if no errors occured, FALSE otherwise
  980. --*/
  981. {
  982. DBG_ASSERT( CheckSignature() );
  983. //
  984. // if cert isn't self-signed, it's not a trusted root
  985. //
  986. if ( !IsSelfSignedCert( pcCert ) )
  987. {
  988. *pfTrustedRoot = FALSE;
  989. return TRUE;
  990. }
  991. //
  992. // Check if cert can be found in ROOT store
  993. //
  994. #define SHA1_HASH_SIZE 20
  995. BYTE rgbHash[SHA1_HASH_SIZE];
  996. DWORD cbHash = SHA1_HASH_SIZE;
  997. if ( !CertGetCertificateContextProperty( pcCert,
  998. CERT_SHA1_HASH_PROP_ID,
  999. (VOID *) rgbHash,
  1000. &cbHash ) )
  1001. {
  1002. return FALSE;
  1003. }
  1004. CRYPT_HASH_BLOB HashBlob;
  1005. HashBlob.cbData = cbHash;
  1006. HashBlob.pbData = rgbHash;
  1007. if ( !m_hRootStore ||
  1008. !CertFindCertificateInStore( m_hRootStore,
  1009. X509_ASN_ENCODING,
  1010. 0,
  1011. CERT_FIND_SHA1_HASH,
  1012. (VOID *) &HashBlob,
  1013. NULL ) )
  1014. {
  1015. if ( !m_hRootStore ||
  1016. GetLastError() != CRYPT_E_NOT_FOUND )
  1017. {
  1018. return FALSE;
  1019. }
  1020. else
  1021. {
  1022. *pfTrustedRoot = FALSE;
  1023. }
  1024. }
  1025. else
  1026. {
  1027. *pfTrustedRoot = TRUE;
  1028. }
  1029. return TRUE;
  1030. }
  1031. BOOL IIS_SSL_INFO::GetRootStoreCertificates( OUT PCCERT_CONTEXT **ppcCertContext,
  1032. OUT DWORD *pdwCerts )
  1033. /*++
  1034. Routine Description:
  1035. Reads all the certificates out of the Local Machine Root store.
  1036. Arguments:
  1037. pppCertContext - pointer to array of CERT_CONTEXT pointers, filled out with the found
  1038. CERT_CONTEXTS.
  1039. Caller is responsible for releasing the contexts when done with them and deleting
  1040. the array used to hold them.
  1041. pdwCertsFound - pointer to number of cert contexts returned in ppCertContext
  1042. Returns:
  1043. TRUE if no internal errors occurred, FALSE if NOT
  1044. --*/
  1045. {
  1046. DBG_ASSERT( CheckSignature() );
  1047. DWORD i = 0;
  1048. Lock();
  1049. //
  1050. // Whatever the case, make sure we don't accidentally return garbage
  1051. //
  1052. *pdwCerts = 0;
  1053. *ppcCertContext = NULL;
  1054. if ( !m_acRootCerts )
  1055. {
  1056. if ( m_hRootStore )
  1057. {
  1058. *pdwCerts = 0;
  1059. PCCERT_CONTEXT pCert = NULL;
  1060. PCCERT_CONTEXT pPrevCert = NULL;
  1061. m_cRootCerts = 0;
  1062. //
  1063. // In an ideal world, we'd know how many certs there are in the store, but it's not
  1064. // an ideal world, so we have to count them ourselves
  1065. //
  1066. while ( pCert = CertEnumCertificatesInStore( m_hRootStore,
  1067. pPrevCert ) )
  1068. {
  1069. m_cRootCerts++;
  1070. pPrevCert = pCert;
  1071. }
  1072. if ( GetLastError() != CRYPT_E_NOT_FOUND )
  1073. {
  1074. Unlock();
  1075. return FALSE;
  1076. }
  1077. //
  1078. // Guard against nothing being in the Root store. Unlikely, but we're
  1079. // paranoid
  1080. //
  1081. if ( m_cRootCerts == 0 )
  1082. {
  1083. Unlock();
  1084. return TRUE;
  1085. }
  1086. m_acRootCerts = new PCCERT_CONTEXT[m_cRootCerts];
  1087. if ( !m_acRootCerts )
  1088. {
  1089. Unlock();
  1090. return FALSE;
  1091. }
  1092. //
  1093. // Make a copy of all the certs in the root store
  1094. //
  1095. pCert = NULL;
  1096. pPrevCert = NULL;
  1097. while ( pCert = CertEnumCertificatesInStore( m_hRootStore,
  1098. pPrevCert ) )
  1099. {
  1100. m_acRootCerts[i++] = CertDuplicateCertificateContext( pCert );
  1101. pPrevCert = pCert;
  1102. }
  1103. DBG_ASSERT( i == m_cRootCerts );
  1104. if ( GetLastError() != CRYPT_E_NOT_FOUND )
  1105. {
  1106. for ( i = 0; i < m_cRootCerts; i++ )
  1107. {
  1108. CertFreeCertificateContext( m_acRootCerts[i] );
  1109. }
  1110. delete [] m_acRootCerts;
  1111. m_acRootCerts = NULL;
  1112. m_cRootCerts = 0;
  1113. Unlock();
  1114. return FALSE;
  1115. }
  1116. }
  1117. else
  1118. {
  1119. Unlock();
  1120. return FALSE;
  1121. }
  1122. }
  1123. //
  1124. // By this time, m_acRootCerts should have been allocated
  1125. //
  1126. *ppcCertContext = new PCCERT_CONTEXT[m_cRootCerts];
  1127. if ( !*ppcCertContext )
  1128. {
  1129. Unlock();
  1130. return FALSE;
  1131. }
  1132. //
  1133. // Copy the certs
  1134. //
  1135. for ( i = 0; i < m_cRootCerts; i++ )
  1136. {
  1137. (*ppcCertContext)[(*pdwCerts)++] = CertDuplicateCertificateContext( m_acRootCerts[i] );
  1138. }
  1139. Unlock();
  1140. return TRUE;
  1141. }
  1142. BOOL IsSelfSignedCert( IN PCCERT_CONTEXT pCertContext )
  1143. /*++
  1144. Routine Description:
  1145. Determines whether a cert is self-signed ie the top of a hierarchy
  1146. Arguments:
  1147. pCertContext - cert to be checked
  1148. Returns:
  1149. TRUE if cert is self-signed, FALSE otherwise
  1150. --*/
  1151. {
  1152. //
  1153. // Compare subject and issuer.
  1154. //
  1155. if(pCertContext->pCertInfo->Subject.cbData == pCertContext->pCertInfo->Issuer.cbData)
  1156. {
  1157. if(memcmp(pCertContext->pCertInfo->Subject.pbData,
  1158. pCertContext->pCertInfo->Issuer.pbData,
  1159. pCertContext->pCertInfo->Issuer.cbData) == 0)
  1160. {
  1161. return TRUE;
  1162. }
  1163. }
  1164. return FALSE;
  1165. }
  1166. BOOL IIS_SSL_INFO::QueryCertValidity( DWORD *pdwStatus )
  1167. /*++
  1168. Routine Description:
  1169. Retrieves status bits for server certificate ie ie not expired, whether
  1170. it's possible to construct a full chain up to a trusted root, whether it's
  1171. signature-valid etc and writes an entry to the system log if necessary.
  1172. Arguments:
  1173. pdwStatus - pointer to status, updated on success
  1174. Returns:
  1175. TRUE if status check was successful, FALSE if not
  1176. --*/
  1177. {
  1178. *pdwStatus = 0;
  1179. Lock();
  1180. if ( !GetCertificate() || !m_pCert->IsValid() )
  1181. {
  1182. Unlock();
  1183. return FALSE;
  1184. }
  1185. //
  1186. // Should have a valid cert at this point
  1187. //
  1188. DBG_ASSERT( m_pCert );
  1189. if ( m_pCert->IsFortezzaCert() )
  1190. {
  1191. m_dwCertChainStatus = 0;
  1192. }
  1193. if ( m_dwCertChainStatus == -1 )
  1194. {
  1195. //
  1196. // Use the default per-process chain engine to try to build a chain
  1197. //
  1198. CERT_CHAIN_PARA CCP;
  1199. PCCERT_CHAIN_CONTEXT pCertChain = NULL;
  1200. memset( &CCP, 0, sizeof(CCP) );
  1201. CCP.cbSize = sizeof(CCP);
  1202. if ( CertGetCertificateChain( NULL,
  1203. m_pCert->QueryCertContext(),
  1204. NULL,
  1205. m_pCert->QueryCertContext()->hCertStore,
  1206. &CCP,
  1207. 0,
  1208. NULL,
  1209. &pCertChain ) )
  1210. {
  1211. m_dwCertChainStatus = pCertChain->TrustStatus.dwErrorStatus;
  1212. CertFreeCertificateChain( pCertChain );
  1213. pCertChain = NULL;
  1214. }
  1215. else
  1216. {
  1217. Unlock();
  1218. return FALSE;
  1219. }
  1220. }
  1221. *pdwStatus = m_dwCertChainStatus;
  1222. Unlock();
  1223. return TRUE;
  1224. }
  1225. VOID IIS_SSL_INFO::ReleaseFortezzaHandlers( VOID )
  1226. /*++
  1227. Description:
  1228. Uninstalls the context used to verify signatures on Fortezza certs.
  1229. (The context is installed in the IIS_SERVER_CERT constructor)
  1230. Arguments:
  1231. None
  1232. Returns:
  1233. Nothing
  1234. --*/
  1235. {
  1236. if ( IIS_SERVER_CERT::m_hFortezzaCtxt )
  1237. {
  1238. CryptUninstallDefaultContext( IIS_SERVER_CERT::m_hFortezzaCtxt,
  1239. 0,
  1240. NULL );
  1241. IIS_SERVER_CERT::m_hFortezzaCtxt = NULL;
  1242. }
  1243. if ( IIS_SERVER_CERT::m_hFortezzaCSP )
  1244. {
  1245. CryptReleaseContext( IIS_SERVER_CERT::m_hFortezzaCSP,
  1246. 0 );
  1247. IIS_SERVER_CERT::m_hFortezzaCSP = NULL;
  1248. }
  1249. }
  1250. BOOL IIS_SSL_INFO::CTLContainsCert( IN PCCERT_CONTEXT pCert,
  1251. OUT BOOL* pfContains )
  1252. /*++
  1253. Description:
  1254. Checks whether a given cert is in the CTL for this object
  1255. Arguments:
  1256. pCert - certificate to check for in CTL
  1257. pfContains - flag that is set to true/false, if cert is/is not in CTL respectively
  1258. Returns:
  1259. BOOL indicating success/failure of attempt to check
  1260. --*/
  1261. {
  1262. DBG_ASSERT( CheckSignature() );
  1263. PCCERT_CONTEXT *ppCertContext = NULL;
  1264. DWORD dwCertsFound = 0;
  1265. DWORD dwCertsInCTL = 0;
  1266. BOOL fOK = TRUE;
  1267. *pfContains = FALSE;
  1268. if ( GetCTL() &&
  1269. m_pCTL->IsValid() &&
  1270. m_pCTL->GetContainedCertificates( &ppCertContext,
  1271. &dwCertsFound,
  1272. &dwCertsInCTL ) )
  1273. {
  1274. #define SHA1_HASH_SIZE 20
  1275. BYTE rgbCert1Hash[SHA1_HASH_SIZE];
  1276. BYTE rgbCert2Hash[SHA1_HASH_SIZE];
  1277. DWORD cbSize = SHA1_HASH_SIZE;
  1278. if ( !CertGetCertificateContextProperty( pCert,
  1279. CERT_SHA1_HASH_PROP_ID,
  1280. rgbCert1Hash,
  1281. &cbSize ) )
  1282. {
  1283. DBGPRINTF((DBG_CONTEXT,
  1284. "Failed to get cert hash : 0x%d\n",
  1285. GetLastError()));
  1286. fOK = FALSE;
  1287. goto cleanup;
  1288. }
  1289. //
  1290. // Iterate through all the certs in the CTL and compare hashes
  1291. // This is a bit simple-minded
  1292. //
  1293. // CODEWORK : ask the CAPI people how to be smarter about this
  1294. //
  1295. for ( DWORD i = 0; i < dwCertsFound; i++ )
  1296. {
  1297. if ( !CertGetCertificateContextProperty( ppCertContext[i],
  1298. CERT_SHA1_HASH_PROP_ID,
  1299. rgbCert2Hash,
  1300. &cbSize ) )
  1301. {
  1302. DBGPRINTF((DBG_CONTEXT,
  1303. "Failed to get cert hash : 0x%d\n",
  1304. GetLastError()));
  1305. fOK = FALSE;
  1306. goto cleanup;
  1307. }
  1308. if ( !memcmp( rgbCert1Hash, rgbCert2Hash, SHA1_HASH_SIZE ) )
  1309. {
  1310. *pfContains = TRUE;
  1311. break;
  1312. }
  1313. }
  1314. }
  1315. else
  1316. {
  1317. fOK = FALSE;
  1318. }
  1319. cleanup:
  1320. if ( ppCertContext )
  1321. {
  1322. for ( DWORD i = 0; i < dwCertsFound; i++ )
  1323. {
  1324. CertFreeCertificateContext( ppCertContext[i] );
  1325. }
  1326. delete [] ppCertContext;
  1327. }
  1328. return fOK;
  1329. }