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.

726 lines
18 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. iisctl.cxx
  5. Abstract:
  6. This module contains the code for the class to deal with Certificate Trust Lists
  7. Author:
  8. Alex Mallet [amallet] 01-09-98
  9. Revision History:
  10. --*/
  11. #include "tcpdllp.hxx"
  12. #pragma hdrstop
  13. #include <dbgutil.h>
  14. #include <buffer.hxx>
  15. #include <ole2.h>
  16. #include <imd.h>
  17. #include <mb.hxx>
  18. #include <iiscert.hxx>
  19. #include <capiutil.hxx>
  20. #include <iisctl.hxx>
  21. IIS_CTL::IIS_CTL( IN IMDCOM *pMBObject,
  22. IN LPTSTR pszMBPath ) :
  23. m_strMBPath( pszMBPath ),
  24. m_pwszListIdentifier( NULL ),
  25. m_hMemoryStore( NULL ),
  26. m_pCTLContext( NULL ),
  27. m_hCryptProv( NULL ),
  28. m_fFoundCerts( FALSE ),
  29. m_pCTLCerts( NULL ),
  30. m_cCertsFound( 0 ),
  31. m_hMyStore( NULL ),
  32. m_hCAStore( NULL ),
  33. m_hRootStore( NULL ),
  34. m_pSignerCert( NULL )
  35. /*++
  36. Routine Description:
  37. Constructor for CTL
  38. Arguments:
  39. pMDObject - pointer to metabase object
  40. pszMBPath - fully qualified path in metabase where CTL identifier is stored
  41. Returns:
  42. Nothing
  43. --*/
  44. {
  45. DBG_ASSERT( pMBObject );
  46. DBG_ASSERT( pszMBPath );
  47. MB mb( pMBObject );
  48. METADATA_HANDLE hInfoHandle = NULL;
  49. POPEN_CERT_STORE_INFO pCertStoreInfo = NULL;
  50. DWORD dwIdentifierSize = 0;
  51. HCRYPTPROV hCryptProv = NULL;
  52. HCERTSTORE hStore = NULL;
  53. m_dwStatus = CERT_ERR_INTERNAL;
  54. if ( !m_strMBPath.IsValid() )
  55. {
  56. m_dwStatus = CERT_ERR_INTERNAL;
  57. SetLastError(ERROR_OUTOFMEMORY);
  58. goto EndCTLConstructor;
  59. }
  60. //
  61. // Read CTL identifier out of MB
  62. //
  63. if ( mb.Open( m_strMBPath.QueryStr(),
  64. METADATA_PERMISSION_READ ))
  65. {
  66. METADATA_RECORD mdr;
  67. MD_SET_DATA_RECORD( &mdr,
  68. MD_SSL_CTL_IDENTIFIER,
  69. METADATA_NO_ATTRIBUTES,
  70. IIS_MD_UT_SERVER,
  71. STRING_METADATA,
  72. NULL,
  73. 0 );
  74. if ( !RetrieveBlobFromMetabase( &mb,
  75. NULL,
  76. &mdr,
  77. 0 ) )
  78. {
  79. m_dwStatus = CERT_ERR_MB;
  80. goto EndCTLConstructor;
  81. }
  82. else
  83. {
  84. #if DBG
  85. DBGPRINTF((DBG_CONTEXT,
  86. "List identifier : %s\n",
  87. (LPSTR) mdr.pbMDData));
  88. #endif
  89. //
  90. // Need to convert the list identifier to a wide-char string
  91. //
  92. dwIdentifierSize = 0;
  93. if ( dwIdentifierSize = MultiByteToWideChar( CP_ACP,
  94. 0,
  95. (LPCSTR) mdr.pbMDData,
  96. mdr.dwMDDataLen,
  97. NULL,
  98. 0 ) )
  99. {
  100. m_pwszListIdentifier = new WCHAR[dwIdentifierSize];
  101. if ( !m_pwszListIdentifier ||
  102. !MultiByteToWideChar( CP_ACP,
  103. 0,
  104. (LPCSTR) mdr.pbMDData,
  105. mdr.dwMDDataLen,
  106. m_pwszListIdentifier,
  107. dwIdentifierSize ) )
  108. {
  109. delete [] mdr.pbMDData;
  110. m_dwStatus = CERT_ERR_INTERNAL;
  111. goto EndCTLConstructor;
  112. }
  113. }
  114. else
  115. {
  116. delete [] mdr.pbMDData;
  117. m_dwStatus = CERT_ERR_INTERNAL;
  118. goto EndCTLConstructor;
  119. }
  120. delete [] mdr.pbMDData;
  121. }
  122. }
  123. mb.Close();
  124. //
  125. // Read cert store info out of MB, and try to reconstruct CTL context
  126. //
  127. if ( (pCertStoreInfo = ReadCertStoreInfoFromMB( pMBObject,
  128. pszMBPath,
  129. TRUE ) ) )
  130. {
  131. #if 0
  132. if ( !CryptAcquireContext( &m_hCryptProv,
  133. pCertStoreInfo->pszContainer,
  134. pCertStoreInfo->pszProvider,
  135. pCertStoreInfo->dwProvType,
  136. pCertStoreInfo->dwFlags ) )
  137. {
  138. m_dwStatus = CERT_ERR_CAPI;
  139. goto EndCTLConstructor;
  140. }
  141. if ( !( hStore = CertOpenSystemStore( m_hCryptProv,
  142. pCertStoreInfo->pszStoreName ) ) )
  143. {
  144. m_dwStatus = CERT_ERR_CAPI;
  145. goto EndCTLConstructor;
  146. }
  147. #else
  148. if ( !( hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  149. 0,
  150. NULL,
  151. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  152. pCertStoreInfo->pszStoreName ) ) )
  153. {
  154. m_dwStatus = CERT_ERR_CAPI;
  155. goto EndCTLConstructor;
  156. }
  157. else
  158. {
  159. if ( ! m_strStoreName.Copy( pCertStoreInfo->pszStoreName ) )
  160. {
  161. SetLastError( ERROR_OUTOFMEMORY );
  162. goto EndCTLConstructor;
  163. }
  164. }
  165. #endif
  166. CTL_FIND_USAGE_PARA CtlFindUsagePara;
  167. memset(&CtlFindUsagePara, 0, sizeof(CtlFindUsagePara));
  168. CtlFindUsagePara.cbSize = sizeof(CtlFindUsagePara);
  169. CtlFindUsagePara.ListIdentifier.cbData = dwIdentifierSize * sizeof(WCHAR);
  170. CtlFindUsagePara.ListIdentifier.pbData = (PBYTE) m_pwszListIdentifier;
  171. //
  172. // Try to find CTL in specified store
  173. //
  174. m_pCTLContext = CertFindCTLInStore( hStore,
  175. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  176. 0,
  177. CTL_FIND_USAGE,
  178. (LPVOID) &CtlFindUsagePara,
  179. NULL );
  180. if ( !m_pCTLContext )
  181. {
  182. m_dwStatus = CERT_ERR_CAPI;
  183. goto EndCTLConstructor;
  184. }
  185. }
  186. else
  187. {
  188. m_dwStatus = CERT_ERR_MB;
  189. goto EndCTLConstructor;
  190. }
  191. //
  192. // Construct the in-memory store that will only contain this CTL, to be passed to
  193. // WinVerifyTrust and add the CTL to the created store
  194. //
  195. m_hMemoryStore = NULL;
  196. m_hMemoryStore = CertOpenStore( CERT_STORE_PROV_MEMORY,
  197. 0,
  198. 0,
  199. 0,
  200. 0 );
  201. if ( !m_hMemoryStore )
  202. {
  203. m_dwStatus = CERT_ERR_CAPI;
  204. goto EndCTLConstructor;
  205. }
  206. if ( !CertAddCTLContextToStore( m_hMemoryStore,
  207. m_pCTLContext,
  208. CERT_STORE_ADD_NEW,
  209. NULL ) )
  210. {
  211. m_dwStatus = CERT_ERR_CAPI;
  212. goto EndCTLConstructor;
  213. }
  214. if ( !( m_hMyStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  215. 0,
  216. NULL,
  217. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  218. MY_STORE_NAME ) ) )
  219. {
  220. m_dwStatus = CERT_ERR_CAPI;
  221. goto EndCTLConstructor;
  222. }
  223. if ( !(m_hCAStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  224. 0,
  225. NULL,
  226. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  227. CA_STORE_NAME ) ) )
  228. {
  229. m_dwStatus = CERT_ERR_CAPI;
  230. goto EndCTLConstructor;
  231. }
  232. if ( !( m_hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
  233. 0,
  234. NULL,
  235. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  236. ROOT_STORE_NAME ) ) )
  237. {
  238. m_dwStatus = CERT_ERR_CAPI;
  239. goto EndCTLConstructor;
  240. }
  241. m_dwStatus = CERT_ERR_NONE;
  242. EndCTLConstructor:
  243. DBG_ASSERT( m_dwStatus< CERT_ERR_END );
  244. //
  245. // Cleanup done only on failure
  246. //
  247. if ( m_dwStatus != CERT_ERR_NONE )
  248. {
  249. DBGPRINTF((DBG_CONTEXT,
  250. "Error in CTL constructor : 0x%x\n",
  251. GetLastError()));
  252. if ( m_pwszListIdentifier )
  253. {
  254. delete [] m_pwszListIdentifier;
  255. m_pwszListIdentifier = NULL;
  256. }
  257. if ( m_pCTLContext )
  258. {
  259. CertFreeCTLContext( m_pCTLContext );
  260. m_pCTLContext = NULL;
  261. }
  262. if ( hStore )
  263. {
  264. CertCloseStore( hStore,
  265. 0 );
  266. hStore = NULL;
  267. }
  268. if ( m_hMemoryStore )
  269. {
  270. CertCloseStore( m_hMemoryStore,
  271. 0 );
  272. m_hMemoryStore = NULL;
  273. }
  274. if ( m_hRootStore )
  275. {
  276. CertCloseStore( m_hRootStore,
  277. 0 );
  278. m_hRootStore = NULL;
  279. }
  280. if ( m_hCAStore )
  281. {
  282. CertCloseStore( m_hCAStore,
  283. 0 );
  284. m_hCAStore = NULL;
  285. }
  286. if ( m_hMyStore )
  287. {
  288. CertCloseStore( m_hMyStore,
  289. 0 );
  290. m_hMyStore = NULL;
  291. }
  292. if ( m_hCryptProv )
  293. {
  294. CryptReleaseContext ( m_hCryptProv,
  295. 0 );
  296. m_hCryptProv = NULL;
  297. }
  298. }
  299. //
  300. //Cleanup done regardless of success/failure
  301. //
  302. DeallocateCertStoreInfo( pCertStoreInfo );
  303. pCertStoreInfo = NULL;
  304. } //IIS_CTL:IIS_CTL
  305. IIS_CTL::~IIS_CTL()
  306. /*++
  307. Routine Description:
  308. Destructor for CTL
  309. Arguments:
  310. None
  311. Returns:
  312. Nothing
  313. --*/
  314. {
  315. if ( m_pwszListIdentifier )
  316. {
  317. delete [] m_pwszListIdentifier;
  318. m_pwszListIdentifier = NULL;
  319. }
  320. if ( m_pCTLContext )
  321. {
  322. CertFreeCTLContext( m_pCTLContext );
  323. m_pCTLContext = NULL;
  324. }
  325. if ( m_hMemoryStore )
  326. {
  327. CertCloseStore( m_hMemoryStore,
  328. 0 );
  329. m_hMemoryStore = NULL;
  330. }
  331. if ( m_hRootStore )
  332. {
  333. CertCloseStore( m_hRootStore,
  334. 0 );
  335. m_hRootStore = NULL;
  336. }
  337. if ( m_hCAStore )
  338. {
  339. CertCloseStore( m_hCAStore,
  340. 0 );
  341. m_hCAStore = NULL;
  342. }
  343. if ( m_hMyStore )
  344. {
  345. CertCloseStore( m_hMyStore,
  346. 0 );
  347. m_hMyStore = NULL;
  348. }
  349. if ( m_hCryptProv )
  350. {
  351. CryptReleaseContext ( m_hCryptProv,
  352. 0 );
  353. m_hCryptProv = NULL;
  354. }
  355. if ( m_cCertsFound && m_pCTLCerts )
  356. {
  357. for ( DWORD i = 0; i < m_cCertsFound; i++ )
  358. {
  359. CertFreeCertificateContext( m_pCTLCerts[i] );
  360. }
  361. delete [] m_pCTLCerts;
  362. m_pCTLCerts = NULL;
  363. m_cCertsFound = 0;
  364. }
  365. }
  366. HCERTSTORE IIS_CTL::GetMemoryStore()
  367. /*++
  368. Routine Description:
  369. Returns a handle to an in-memory store that contains the CTL
  370. Arguments:
  371. None
  372. Returns:
  373. Handle to in-memory store
  374. --*/
  375. {
  376. DBG_ASSERT( m_hMemoryStore );
  377. if ( m_hMemoryStore )
  378. {
  379. return CertDuplicateStore( m_hMemoryStore );
  380. }
  381. return NULL;
  382. }
  383. BOOL IIS_CTL::QuerySignerCert( OUT PCCERT_CONTEXT *ppcSigner )
  384. /*++
  385. Routine Description:
  386. Retrieves the cert that signed this CTL
  387. Arguments:
  388. ppcSigner - pointer to pointer to cert context, updated if successful. Caller's
  389. responsibility to clean it up
  390. Returns:
  391. TRUE if there were no errors encountered in retrieving the signer
  392. --*/
  393. {
  394. DWORD dwNumSigners = 3;
  395. HCERTSTORE ahStores[3];
  396. BOOL fGotRoot = TRUE;
  397. BOOL fGotCA = TRUE;
  398. BOOL fOk = TRUE;
  399. if ( !m_pSignerCert )
  400. {
  401. //
  402. // Look in 3 stores to find signer : store the cert came from, CA and ROOT stores
  403. // for Local Machine
  404. //
  405. ahStores[0] = m_pCTLContext->hCertStore;
  406. ahStores[1] = m_hRootStore;
  407. ahStores[2] = m_hCAStore;
  408. CryptMsgGetAndVerifySigner( (HCRYPTMSG) m_pCTLContext->hCryptMsg,
  409. dwNumSigners,
  410. ahStores,
  411. CMSG_TRUSTED_SIGNER_FLAG,
  412. &m_pSignerCert,
  413. 0 );
  414. }
  415. //
  416. // If we don't have a signer cert at this point, we're just not happy
  417. //
  418. if ( m_pSignerCert )
  419. {
  420. *ppcSigner = CertDuplicateCertificateContext( m_pSignerCert );
  421. }
  422. else
  423. {
  424. fOk = FALSE;
  425. }
  426. return fOk;
  427. }
  428. BOOL IIS_CTL::VerifySignature( IN OPTIONAL HCERTSTORE *phSignerStores,
  429. IN DWORD cSignerStores,
  430. LPBOOL pfTrusted )
  431. /*++
  432. Routine Description:
  433. Verify that this CTL was signed by a certificate in a trusted store.
  434. Arguments:
  435. phSignerStores - optional array of store handles to be used in searching for a cert used
  436. to sign this CTL. If NULL, the stores tried are the CA and ROOT stores for the local machine,
  437. as well as the store the CTL came from.
  438. cSignerStores - number of stores in phSignerStores. Should be zero if phSignerStores == NULL
  439. pfTrusted - pointer to bool, updated with TRUE if CTL signature was verified, FALSE if not.
  440. Returns:
  441. TRUE if there were no errors encountered in checking the CTL, FALSE if not
  442. NB : TRUE does -NOT- mean the CTL signature was verified !!!
  443. --*/
  444. {
  445. DBG_ASSERT( m_pCTLContext );
  446. DWORD dwNumSigners = cSignerStores;
  447. HCERTSTORE *phStores = phSignerStores;
  448. HCERTSTORE ahStores[3];
  449. BOOL fGotRoot = TRUE;
  450. BOOL fGotCA = TRUE;
  451. if ( !phSignerStores )
  452. {
  453. dwNumSigners = 3;
  454. ahStores[0] = m_pCTLContext->hCertStore;
  455. ahStores[1] = m_hRootStore;
  456. ahStores[2] = m_hCAStore;
  457. phStores = ahStores;
  458. }
  459. *pfTrusted = CryptMsgGetAndVerifySigner( (HCRYPTMSG) m_pCTLContext->hCryptMsg,
  460. dwNumSigners,
  461. phStores,
  462. CMSG_TRUSTED_SIGNER_FLAG,
  463. NULL,
  464. 0 );
  465. if ( !*pfTrusted )
  466. {
  467. DBGPRINTF((DBG_CONTEXT, "CTL wasn't verified b'cos 0x%x\n",
  468. GetLastError()));
  469. }
  470. return TRUE;
  471. }
  472. BOOL IIS_CTL::GetContainedCertificates( OUT PCCERT_CONTEXT **pppCertContext,
  473. OUT DWORD *pcCertsFound,
  474. OUT DWORD *pcCertsInCTL )
  475. /*++
  476. Routine Description:
  477. Tries to retrieve CERT_CONTEXT pointers for the certs contained in the Certificate
  478. Trust List.
  479. Arguments:
  480. pppCertContext - pointer to array of CERT_CONTEXT pointers, filled out with the found
  481. CERT_CONTEXTS.
  482. Caller is responsible for releasing the contexts when done with them and deleting
  483. the array used to hold them.
  484. pcCertsFound - pointer to number of cert contexts returned in ppCertContext
  485. pcCertsInCTL - pointer to number of certs in CTL; may differ from *pccCertsFound
  486. if some certificates couldn't be found
  487. Returns:
  488. TRUE if no internal errors occurred, FALSE if NOT
  489. --*/
  490. {
  491. PCTL_INFO pCtlInfo = m_pCTLContext->pCtlInfo;
  492. HCERTSTORE ahStores[3];
  493. DWORD dwNumStores = 3;
  494. DBG_ASSERT( pCtlInfo->cCTLEntry );
  495. //
  496. // Let's be optimistic and allocate as much space as we can possibly
  497. // need
  498. //
  499. *pppCertContext = new PCCERT_CONTEXT[pCtlInfo->cCTLEntry];
  500. if ( !*pppCertContext )
  501. {
  502. SetLastError( ERROR_OUTOFMEMORY );
  503. return FALSE;
  504. }
  505. *pcCertsFound = 0;
  506. *pcCertsInCTL = pCtlInfo->cCTLEntry;
  507. //
  508. // If we haven't searched the stores yet, do so now
  509. //
  510. if ( !m_fFoundCerts )
  511. {
  512. m_pCTLCerts = new PCCERT_CONTEXT[pCtlInfo->cCTLEntry];
  513. m_cCertsFound = 0;
  514. if ( !m_pCTLCerts )
  515. {
  516. SetLastError( ERROR_OUTOFMEMORY );
  517. /* INTRINSA suppress = leaks */
  518. return FALSE;
  519. }
  520. ahStores[0] = m_hMyStore;
  521. ahStores[1] = m_hCAStore;
  522. ahStores[2] = m_hRootStore;
  523. //
  524. // Iterate through the certs in the CTL. For each cert, try to find it
  525. // by SHA1 hash in the supplied stores.
  526. //
  527. DWORD dwIndex = 0;
  528. DWORD dwStoreIndex = 0;
  529. PCCERT_CONTEXT pcCert = NULL;
  530. for ( dwIndex = 0; dwIndex < pCtlInfo->cCTLEntry; dwIndex++ )
  531. {
  532. for ( dwStoreIndex = 0; dwStoreIndex < dwNumStores; dwStoreIndex++ )
  533. {
  534. if ( pcCert = CertFindCertificateInStore( ahStores[dwStoreIndex],
  535. X509_ASN_ENCODING,
  536. 0,
  537. CERT_FIND_SHA1_HASH,
  538. (VOID *) &(pCtlInfo->rgCTLEntry[dwIndex].SubjectIdentifier),
  539. NULL ) )
  540. {
  541. m_pCTLCerts[m_cCertsFound] = pcCert;
  542. (*pppCertContext)[m_cCertsFound] =
  543. CertDuplicateCertificateContext( pcCert );
  544. m_cCertsFound++;
  545. break;
  546. }
  547. }
  548. }
  549. *pcCertsFound = m_cCertsFound;
  550. m_fFoundCerts = TRUE;
  551. } // if ( !m_fFounCerts
  552. //
  553. // Already have the list of certs in the CTL
  554. //
  555. else
  556. {
  557. *pppCertContext = new PCCERT_CONTEXT[m_cCertsFound];
  558. if ( !*pppCertContext )
  559. {
  560. SetLastError( ERROR_OUTOFMEMORY );
  561. return FALSE;
  562. }
  563. for ( DWORD i = 0; i < m_cCertsFound; i++ )
  564. {
  565. (*pppCertContext)[i] = CertDuplicateCertificateContext( m_pCTLCerts[i] );
  566. }
  567. *pcCertsInCTL = pCtlInfo->cCTLEntry;
  568. *pcCertsFound = m_cCertsFound;
  569. }
  570. return TRUE;
  571. }
  572. inline
  573. BOOL IIS_CTL::IsValid()
  574. {
  575. return ( m_dwStatus == CERT_ERR_NONE ? TRUE : FALSE );
  576. }