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.

5795 lines
149 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. comobj.cxx
  5. Abstract:
  6. This module defines DCOM Admin Ex APIs used for certificate information replication.
  7. Author:
  8. Philippe Choquier ( Phillich ) 23-Jun-97
  9. Alex Mallet (amallet) 17-Feb-1998
  10. --*/
  11. #define UNICODE
  12. extern "C" {
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. }
  17. #include <dbgutil.h>
  18. #include <ole2.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #define USE_CAPI2
  22. #if defined(USE_CAPI2)
  23. #include <wincrypt.h>
  24. #endif
  25. extern "C" {
  26. #define SECURITY_WIN32
  27. #include <sspi.h>
  28. }
  29. #include <spseal.h>
  30. #include <issperr.h>
  31. #include <schnlsp.h>
  32. #include <md5.h>
  33. #include <iadmw.h>
  34. #include <admex.h>
  35. #include <iiscnfgp.h>
  36. #include <mdcommsg.h>
  37. #include <replseed.hxx>
  38. #include <iis64.h>
  39. #include "comobj.hxx"
  40. #define RETURNCODETOHRESULT(rc) \
  41. (((rc) < 0x10000) \
  42. ? HRESULT_FROM_WIN32(rc) \
  43. : (rc))
  44. #define PAD4(a) (((a)+3)&~3)
  45. #define MSB(a) (BYTE) (((a) & 0xFF00) >> 8)
  46. #define LSB(a) (BYTE) ((a) & 0xFF)
  47. #define LENGTH( msb, lsb ) (DWORD) ( (msb << 8) + lsb )
  48. //
  49. // Globals
  50. //
  51. DECLARE_DEBUG_PRINTS_OBJECT();
  52. ULONG g_dwRefCount = 0;
  53. #include <initguid.h>
  54. DEFINE_GUID(IisADMExsGuid,
  55. 0x784d8905, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
  56. CADMEXCOM::CADMEXCOM()
  57. {
  58. m_dwRefCount = 0;
  59. m_pIMSAdminReplication = new CADMEXCOM_IMSAdminReplication(this);
  60. m_pIMSAdminCryptoCapabilities = new CADMEXCOM_IMSAdminCryptoCapabilities( this );
  61. }
  62. CADMEXCOM::~CADMEXCOM()
  63. {
  64. if ( m_pIMSAdminReplication )
  65. {
  66. delete m_pIMSAdminReplication;
  67. }
  68. if ( m_pIMSAdminCryptoCapabilities )
  69. {
  70. delete m_pIMSAdminCryptoCapabilities;
  71. }
  72. }
  73. HRESULT
  74. CADMEXCOM::QueryInterface(
  75. REFIID riid,
  76. void **ppObject)
  77. {
  78. if (riid==IID_IUnknown ) {
  79. *ppObject = (IUnknown *) this;
  80. AddRef();
  81. }
  82. else if ( riid==IID_IMSAdminReplication) {
  83. *ppObject = (IMSAdminReplication *)m_pIMSAdminReplication;
  84. AddRef();
  85. }
  86. else if ( riid==IID_IMSAdminCryptoCapabilities) {
  87. *ppObject = (IMSAdminCryptoCapabilities *)m_pIMSAdminCryptoCapabilities;
  88. AddRef();
  89. }
  90. else {
  91. return E_NOINTERFACE;
  92. }
  93. return NO_ERROR;
  94. }
  95. ULONG
  96. CADMEXCOM::AddRef(
  97. )
  98. {
  99. DWORD dwRefCount;
  100. dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
  101. return dwRefCount;
  102. }
  103. ULONG
  104. CADMEXCOM::Release(
  105. )
  106. {
  107. DWORD dwRefCount;
  108. dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
  109. if( dwRefCount == 0 ) {
  110. delete this;
  111. return 0;
  112. }
  113. return dwRefCount;
  114. }
  115. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  116. SSL Information Replication Interface
  117. In order to determine whether information needs to be replicated between two machines,
  118. the GetSignature() method is called; this is expected to return a "signature" that can be
  119. compared with the "signature" on the other machine - if the signatures match, they
  120. have the same information, else replication needs to occur.
  121. To replicate, the Serialize() method is called to serialize all the config information
  122. into a buffer; this buffer is encrypted with a generated session key [because it contains
  123. the private keys for all the server certificates]. The data to generate the session key
  124. is stored in the metabase, in encrypted format.
  125. Propagate() doesn't do anything.
  126. DeSerialize() on the target machine regenerates the session key out of the metabase, uses it
  127. to decrypt the buffer generated by Serialize() and creates server certificates and
  128. CTLs in the appropriate places.
  129. The actual configuration information in the metabase itself is replicated during
  130. the (separate) metabase replication process.
  131. Each server instance has the following SSL information associated with it that
  132. needs to be replicated :
  133. 1. Server certificate, server private key, cert chain for server certificate
  134. 2. Certificate Trust List, signing cert for CTL
  135. GetSignature() :
  136. ----------------
  137. Identifying info for server certificates :
  138. <hash of cert stored under LM/W3SVC>:(instance_cert_information)?
  139. where instance_cert_information = <instance #>=<hash of leaf cert>,<hash of issuer 1>,
  140. <hash of issuer of issuer 1> .... |
  141. End of instance cert information is marked by "|"
  142. Identifying info for CTL :
  143. [CTL_INFO for CTL stored under /LM/W3SVC]:(<instance #>=CTL_INFO)?
  144. where CTL_INFO = <CTL list identifier>,(<hash of cert in ctl>)+,<hash of CTL signer>
  145. Signature : MD5(Info for server certificates : Info for CTLs)
  146. -----------------------------------------------------------------------------------------------*/
  147. #define MB_ROOT_PATH L"/LM/W3SVC"
  148. #define TIMEOUT_VALUE 30000 //NOTE - magic number !
  149. #define INITIAL_BUFFER_SIZE 2048
  150. #define MY_STORE_NAME L"MY"
  151. #define CA_STORE_NAME L"CA"
  152. #define ROOT_STORE_NAME L"ROOT"
  153. #define TRUST_STORE_NAME L"TRUST"
  154. #define COLON ':'
  155. #define INSTANCE_TRAILER_BYTE '|'
  156. #define CERT_HEADER "CERTS="
  157. #define CERT_HEADER_SIZE (sizeof(CERT_HEADER) - 1)
  158. #define CTL_HEADER "CTL="
  159. #define CTL_HEADER_SIZE (sizeof(CTL_HEADER) - 1)
  160. #define SIGNATURE 0
  161. #define CONFIGURATION 1
  162. #define REPLICATION_SESSION_KEY_CONTAINER L"IIS Replication Session Key"
  163. #define MIN_REPLICATION_INFO_SIZE 4 //> <MSB><LSB>":"<some info>"|"
  164. #define REPL_INTERNAL_ERROR RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER )
  165. // Array holding properties required to reconstruct cert context
  166. static DWORD adwMetabaseCertProperties[] = { MD_SSL_CERT_HASH, BINARY_METADATA,
  167. MD_SSL_CERT_STORE_NAME, STRING_METADATA };
  168. #define cNumCertMetabaseProperties sizeof(adwMetabaseCertProperties)/sizeof(DWORD)
  169. // Array holding properties necessary to reconstruct CTL context
  170. static DWORD adwMetabaseCTLProperties[] = { MD_SSL_CTL_IDENTIFIER, BINARY_METADATA,
  171. MD_SSL_CTL_STORE_NAME, STRING_METADATA };
  172. #define cNumCTLMetabaseProperties sizeof(adwMetabaseCTLProperties)/sizeof(DWORD)
  173. #if DBG
  174. VOID
  175. Dump(
  176. CHAR *pchMessage,
  177. LPBYTE pb,
  178. DWORD dw
  179. )
  180. {
  181. for ( UINT x = 0 ; x < dw ; ++x )
  182. {
  183. sprintf(pchMessage + x*3, "%02x ", pb[x] );
  184. }
  185. sprintf(pchMessage + x*3,"\n");
  186. }
  187. #endif
  188. CADMEXCOM_IMSAdminReplication::CADMEXCOM_IMSAdminReplication( CADMEXCOM *pAdmExCom ) :
  189. m_pAdmExCom( pAdmExCom ),
  190. m_pMB( NULL ),
  191. m_fGotSeed( FALSE )
  192. {
  193. HRESULT hRes;
  194. COSERVERINFO *pcsiParam = NULL;
  195. IClassFactory * pcsfFactory = NULL;
  196. //
  197. // Retrieve class factory for metabase object
  198. //
  199. hRes = CoGetClassObject(CLSID_MSAdminBase_W, CLSCTX_SERVER, pcsiParam,
  200. IID_IClassFactory, ( void ** ) &pcsfFactory );
  201. if ( FAILED(hRes) )
  202. {
  203. DBGPRINTF((DBG_CONTEXT, "CoGetClassObject failed : hRes : %x, Win32 : 0x%x\n",
  204. hRes, HRESULTTOWIN32(hRes)));
  205. return;
  206. }
  207. //
  208. // Retrieve the actual metabase object interface
  209. //
  210. hRes = pcsfFactory->CreateInstance( NULL,
  211. IID_IMSAdminBase,
  212. (void **) &m_pMB );
  213. if ( FAILED(hRes) )
  214. {
  215. DBGPRINTF((DBG_CONTEXT, "CreateInstance failed : hRes : %x, Win32 : 0x%x\n",
  216. hRes, HRESULTTOWIN32(hRes)));
  217. return;
  218. }
  219. pcsfFactory->Release();
  220. }
  221. CADMEXCOM_IMSAdminReplication::~CADMEXCOM_IMSAdminReplication()
  222. {
  223. if ( m_pMB )
  224. {
  225. m_pMB->Release();
  226. m_pMB = NULL;
  227. }
  228. }
  229. HRESULT STDMETHODCALLTYPE
  230. CADMEXCOM_IMSAdminReplication::GetSignature(
  231. /* [in] */ DWORD dwBufferSize,
  232. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  233. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
  234. /*++
  235. Routine Description:
  236. Used to retrieve a "signature" for the certificate information to be retrieved; if the
  237. signatures on two machines match, then it can be assumed that they have identical
  238. SSL configurations.
  239. Arguments:
  240. dwBufferSize - size of buffer passed in
  241. pbBuffer - buffer to be filled in with signature
  242. *pdwMDRequiredBufferSize - size of buffer required for data
  243. Returns:
  244. HRESULT indicating success/failure.
  245. --*/
  246. {
  247. DBGPRINTF((DBG_CONTEXT,
  248. "GetSignature() called for SSL info replication\n"));
  249. HRESULT hRes = S_OK;
  250. hRes = GetConfigurationInformation( SIGNATURE,
  251. NULL,
  252. m_pMB,
  253. pbBuffer,
  254. dwBufferSize,
  255. pdwMDRequiredBufferSize );
  256. #if DBG
  257. if ( FAILED( hRes ) )
  258. {
  259. DBGPRINTF((DBG_CONTEXT,
  260. "GetSignature() failed with Win32 error : 0x%x\n",
  261. HRESULTTOWIN32( hRes )));
  262. }
  263. else
  264. {
  265. CHAR achSig[200];
  266. Dump( achSig, pbBuffer, *pdwMDRequiredBufferSize );
  267. DBGPRINTF((DBG_CONTEXT,
  268. "GetSignature() returned %s\n",
  269. achSig));
  270. }
  271. #endif
  272. return hRes;
  273. } //::GetSignature
  274. HRESULT STDMETHODCALLTYPE
  275. CADMEXCOM_IMSAdminReplication::Serialize(
  276. /* [in] */ DWORD dwBufferSize,
  277. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  278. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
  279. /*++
  280. Routine Description:
  281. Serializes the SSL information for IIS.
  282. Arguments:
  283. dwBufferSize - size of buffer pointed to by pbBuffer
  284. pbBuffer - buffer to receive serialized SSL configuration; can be NULL if
  285. caller wants to determine size of buffer necessary
  286. pdwMDRequiredBufferSize - pointer to size of buffer necessary to hold the
  287. information; updated if pbBuffer is too small to hold the information
  288. Returns:
  289. HRESULT indicating success/failure.
  290. --*/
  291. {
  292. HRESULT hRes = S_OK;
  293. HCRYPTKEY hSessionKey = NULL;
  294. DBGPRINTF((DBG_CONTEXT,
  295. "Serialize() called for SSL info replication\n"));
  296. hRes = RegenerateSessionKey( m_pMB,
  297. &hSessionKey );
  298. if ( S_OK == hRes )
  299. {
  300. m_fGotSeed = TRUE;
  301. hRes = GetConfigurationInformation( CONFIGURATION,
  302. &hSessionKey,
  303. m_pMB,
  304. pbBuffer,
  305. dwBufferSize,
  306. pdwMDRequiredBufferSize );
  307. #if DBG
  308. if ( FAILED( hRes ) )
  309. {
  310. DBGPRINTF((DBG_CONTEXT,
  311. "Serialize() failed with Win32 error : 0x%x\n",
  312. HRESULTTOWIN32( hRes )));
  313. }
  314. #endif
  315. }
  316. return hRes;
  317. } //::Serialize
  318. HRESULT STDMETHODCALLTYPE
  319. CADMEXCOM_IMSAdminReplication::Propagate(
  320. /* [in] */ DWORD dwBufferSize,
  321. /* [size_is][in] */ unsigned char __RPC_FAR *pszBuffer)
  322. /*++
  323. Routine Description:
  324. Propagates data necessary to re-generate session key from metabase on source machine
  325. to metabase on target machine
  326. Arguments:
  327. dwBufferSize - size of buffer pointed to by pbBuffer
  328. pbBuffer - name of target machine
  329. Returns:
  330. HRESULT indicating success/failure.
  331. --*/
  332. {
  333. DBGPRINTF((DBG_CONTEXT,
  334. "Propagate() called for SSL info replication\n"));
  335. if ( !m_fGotSeed )
  336. {
  337. return S_FALSE;
  338. }
  339. else
  340. {
  341. return S_OK;
  342. }
  343. }//::Propagate
  344. HRESULT STDMETHODCALLTYPE
  345. CADMEXCOM_IMSAdminReplication::Propagate2(
  346. /* [in] */ DWORD dwBufferSize,
  347. /* [size_is][in] */ unsigned char __RPC_FAR *pszBuffer,
  348. /* [in] */ DWORD dwSignatureMismatch )
  349. {
  350. return S_OK;
  351. }
  352. HRESULT STDMETHODCALLTYPE
  353. CADMEXCOM_IMSAdminReplication::DeSerialize(
  354. /* [in] */ DWORD dwBufferSize,
  355. /* [size_is][in] */ unsigned char __RPC_FAR *pbBuffer)
  356. /*++
  357. Routine Description:
  358. Deserializes the SSL information produced by Serialize()
  359. Arguments:
  360. dwBufferSize - size of buffer pointed to by pbBuffer
  361. pbBuffer - buffer holding serialized SSL configuration
  362. Returns:
  363. HRESULT indicating success/failure.
  364. Extended Description :
  365. The information for each instance is separate, with instance data being in the
  366. form
  367. <Instance Data> = <MSB of instance #><LSB of instance #>":"<instance SSL info>"|"
  368. <Instance SSL Info> = <server certificate information><CTL information>
  369. <Server certificate information> = "" |
  370. "CERTS="<SHA1 hash of first cert in chain><MSB of length of private key blob>
  371. <LSB of length of private key blob><private key blob of first cert>
  372. <MSB of length of serialized store containing chain><LSB of length of serialized store
  373. containing chain><serialized store>
  374. The SHA1 hash is added so that it's possible to figure out which cert in the store
  375. is the leaf cert when unserializing the buffer.
  376. <CTL information> = "" |
  377. "CTL="<hash of CTL signer><MSB of length of serialized store><LSB of length of serialized
  378. store><serialized store>
  379. The serialized store contains the CTL, the certs in the CTL and the signer of the CTL.
  380. --*/
  381. {
  382. HRESULT hRes = S_OK;
  383. BYTE *pbReplicationInfo = NULL;
  384. BYTE *pbPosition = NULL;
  385. BYTE *pbEnd = NULL;
  386. DWORD dwInstance = 0;
  387. HCRYPTKEY hSessionKey = NULL;
  388. DBGPRINTF((DBG_CONTEXT,
  389. "DeSerialize() called for SSL info replication\n"));
  390. //
  391. // No information to serialize
  392. //
  393. if ( dwBufferSize == 0 )
  394. {
  395. return S_OK;
  396. }
  397. //
  398. // Invalid buffer or buffer size
  399. //
  400. if ( !pbBuffer || dwBufferSize < MIN_REPLICATION_INFO_SIZE )
  401. {
  402. return REPL_INTERNAL_ERROR;
  403. }
  404. //
  405. // Extract the data for the session key under which the buffer is encrypted
  406. //
  407. hRes = RegenerateSessionKey( m_pMB, &hSessionKey );
  408. if ( hSessionKey )
  409. {
  410. //
  411. // Decrypt the buffer
  412. //
  413. hRes = DecryptBuffer( hSessionKey,
  414. pbBuffer,
  415. dwBufferSize,
  416. &pbReplicationInfo,
  417. &pbEnd );
  418. if( FAILED(hRes) )
  419. {
  420. DeleteSessionKey( &hSessionKey );
  421. hSessionKey = NULL;
  422. }
  423. }
  424. if( !hSessionKey )
  425. {
  426. //
  427. // Some of these functions return S_FALSE for some reason,
  428. // preserve this behavior.
  429. //
  430. return (hRes != S_OK) ? hRes : E_FAIL;
  431. }
  432. //
  433. // Deserialize away
  434. //
  435. pbPosition = pbReplicationInfo;
  436. while ( pbPosition < pbEnd &&
  437. !FAILED( hRes = DeserializeInstanceInfo( &pbPosition,
  438. pbEnd,
  439. &dwInstance ) ) )
  440. {
  441. DBGPRINTF((DBG_CONTEXT,
  442. "Successfully deserialized information for instance %d\n",
  443. dwInstance));
  444. }
  445. if ( FAILED( hRes ) )
  446. {
  447. DBGPRINTF((DBG_CONTEXT,
  448. "Failed deserializing information for instance %d\n",
  449. dwInstance));
  450. }
  451. //
  452. // Cleanup
  453. //
  454. if ( pbReplicationInfo )
  455. {
  456. memset( pbReplicationInfo, 0, DIFF(pbEnd - pbReplicationInfo) );
  457. delete [] pbReplicationInfo;
  458. }
  459. DeleteSessionKey( &hSessionKey );
  460. //
  461. // Q : when should we delete the MB info ? Only on successful DeSerialize ?
  462. //
  463. if ( SUCCEEDED( hRes ) )
  464. {
  465. DeleteMBSessionKeyInfo( m_pMB );
  466. }
  467. return hRes;
  468. }//::DeSerialize
  469. HRESULT
  470. GetConfigurationInformation( DWORD dwInfoType,
  471. HCRYPTKEY *phSessionKey,
  472. IMSAdminBase *pMB,
  473. unsigned char __RPC_FAR *pbBuffer,
  474. DWORD dwBufferSize,
  475. DWORD __RPC_FAR *pdwMDRequiredBufferSize )
  476. /*++
  477. Routine Description:
  478. Used to retrieve replication information
  479. Arguments:
  480. dwInfoType - which kind of information to retrieve - signature or configuration
  481. phSessionKey - pointer to session key to be used to encrypt replication info; not
  482. used if dwInfoType == SIGNATURE
  483. pMB - pointer to metabase object
  484. pbBuffer - buffer to be filled in with information
  485. dwBufferSize - size of pbBuffer
  486. *pdwMDRequiredBufferSize - size of buffer required for data
  487. Returns:
  488. HRESULT indicating success/failure.
  489. --*/
  490. {
  491. HRESULT hRes = S_OK;
  492. METADATA_HANDLE hMDHandle;
  493. DWORD dwObjectIndex = 0;
  494. TCHAR achMDName[METADATA_MAX_NAME_LEN];
  495. DWORD dwRepBufferSize = 0;
  496. PBYTE pbReplicationInfo = NULL;
  497. DWORD dwPosition = 0;
  498. BYTE *pbHashBuffer = NULL;
  499. DWORD cbHashSize = 0;
  500. if ( !pMB )
  501. {
  502. return S_FALSE;
  503. }
  504. //
  505. // Make sure we have a pointer to a session key if we need to use it
  506. //
  507. if ( dwInfoType != SIGNATURE && !phSessionKey )
  508. {
  509. return S_FALSE;
  510. }
  511. //
  512. // Signature is MD5 hash of information, so we know the buffer has to be at least
  513. // MD5_HASH_SIZE bytes in size
  514. //
  515. if ( dwInfoType == SIGNATURE )
  516. {
  517. if ( !pbBuffer || dwBufferSize < MD5_HASH_SIZE )
  518. {
  519. *pdwMDRequiredBufferSize = MD5_HASH_SIZE;
  520. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  521. }
  522. }
  523. hRes = pMB->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  524. MB_ROOT_PATH,
  525. METADATA_PERMISSION_READ,
  526. TIMEOUT_VALUE,
  527. &hMDHandle );
  528. if ( FAILED(hRes) )
  529. {
  530. DBGPRINTF((DBG_CONTEXT,
  531. "Failed to open mb path"));
  532. return hRes;
  533. }
  534. //
  535. // Try to retrieve default information stored at /LM/W3SVC
  536. //
  537. //
  538. // Bogus report of null pointer dereference of pbReplicationInfo
  539. // Windows Bug - 117759
  540. //
  541. /* INTRINSA suppress=null_pointers */
  542. if ( FAILED( hRes = GetInstanceReplicationInfo( dwInfoType,
  543. L"",
  544. pMB,
  545. hMDHandle,
  546. &pbReplicationInfo,
  547. &dwRepBufferSize,
  548. &dwPosition ) ) )
  549. {
  550. if ( pbReplicationInfo )
  551. {
  552. delete [] pbReplicationInfo;
  553. }
  554. pMB->CloseKey( hMDHandle );
  555. return hRes;
  556. }
  557. //
  558. // Iterate through all the subkeys of /LM/W3SVC
  559. //
  560. HRESULT hRes2 = S_OK;
  561. while ( SUCCEEDED(hRes2 = pMB->EnumKeys( hMDHandle,
  562. L"",
  563. achMDName,
  564. dwObjectIndex) ) )
  565. {
  566. //
  567. // If the name of the subkey is a number, it's a server instance.
  568. // Construct cert and CTL information
  569. //
  570. if ( IsNumber( achMDName ) )
  571. {
  572. if ( FAILED( hRes = GetInstanceReplicationInfo( dwInfoType,
  573. achMDName,
  574. pMB,
  575. hMDHandle,
  576. &pbReplicationInfo,
  577. &dwRepBufferSize,
  578. &dwPosition ) ) )
  579. {
  580. if ( pbReplicationInfo )
  581. {
  582. memset( pbReplicationInfo, 0, dwRepBufferSize );
  583. delete [] pbReplicationInfo;
  584. }
  585. pMB->CloseKey( hMDHandle );
  586. return hRes;
  587. }
  588. }
  589. dwObjectIndex++;
  590. }
  591. //
  592. // Error while iterating over keys
  593. //
  594. if ( hRes2 != RETURNCODETOHRESULT( ERROR_NO_MORE_ITEMS ) )
  595. {
  596. if ( pbReplicationInfo )
  597. {
  598. memset( pbReplicationInfo, 0, dwRepBufferSize );
  599. delete [] pbReplicationInfo;
  600. }
  601. pMB->CloseKey( hMDHandle );
  602. return hRes2;
  603. }
  604. if ( dwInfoType == SIGNATURE )
  605. {
  606. //
  607. // We have a buffer containing all the information that needs to be converted
  608. // into a signature by applying the MD5 hash algorithm to it
  609. //
  610. if ( !FAILED( hRes = GenerateHash( NULL,
  611. CALG_MD5,
  612. pbReplicationInfo,
  613. dwPosition,
  614. &pbHashBuffer,
  615. &cbHashSize,
  616. NULL ) ) )
  617. {
  618. DBG_ASSERT( cbHashSize == MD5_HASH_SIZE );
  619. memcpy( pbBuffer, pbHashBuffer, cbHashSize );
  620. *pdwMDRequiredBufferSize = cbHashSize;
  621. }
  622. }
  623. else
  624. {
  625. //
  626. // Because the cert information contains a private key, use the
  627. // session key to encrypt the replication buffer
  628. if ( !FAILED( hRes = EncryptBuffer( *phSessionKey,
  629. &pbReplicationInfo,
  630. &dwRepBufferSize,
  631. &dwPosition ) ) )
  632. {
  633. //
  634. // check that output buffer is big enough to hold the encrypted data
  635. //
  636. if ( dwBufferSize >= dwPosition )
  637. {
  638. memcpy( pbBuffer, pbReplicationInfo, dwPosition );
  639. *pdwMDRequiredBufferSize = dwPosition;
  640. }
  641. else
  642. {
  643. *pdwMDRequiredBufferSize = dwPosition;
  644. hRes = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  645. }
  646. }
  647. }
  648. if ( pbReplicationInfo )
  649. {
  650. //
  651. // zero it out, just to be paranoid
  652. //
  653. memset( pbReplicationInfo, 0, dwRepBufferSize );
  654. delete [] pbReplicationInfo;
  655. }
  656. if ( pbHashBuffer )
  657. {
  658. //
  659. // zero it out, just to be paranoid
  660. //
  661. memset( pbHashBuffer, 0, cbHashSize );
  662. delete [] pbHashBuffer;
  663. }
  664. pMB->CloseKey( hMDHandle );
  665. return hRes;
  666. }
  667. HRESULT GetInstanceReplicationInfo( DWORD dwInfoType,
  668. LPCWSTR pszInstanceNum,
  669. IN IMSAdminBase *pMB,
  670. IN METADATA_HANDLE hHandle,
  671. OUT BYTE **ppbReplicationBuffer,
  672. IN OUT DWORD *pdwBufferSize,
  673. IN OUT DWORD *pdwPosition )
  674. /*++
  675. Routine Description:
  676. Used to retrieve a replication information for a particular server instance.
  677. Format of information :
  678. <MSB of instance #><LSB of instance #>:<instance info>|
  679. Arguments:
  680. dwInfoType - type of information - either signature or configuration
  681. pszInstanceNum - string rep of instance number
  682. pMB - metabase object
  683. hHandle - handle to path open for reading
  684. ppbReplicationBuffer - pointer to pointer to buffer that is filled in with info
  685. pdwBufferSize - pointer to current buffer size, updated on success
  686. pdwPosition - pointer to end of data in buffer, updated on success
  687. Returns:
  688. HRESULT indicating success/failure.
  689. --*/
  690. {
  691. #define INSTANCE_HEADER_LEN 3 // <MSB> <LSB> ':'
  692. #define INSTANCE_TRAILER_LEN 1 // '|'
  693. HRESULT hRes = NOERROR;
  694. DWORD dwInstance;
  695. BOOL fHasCTL = FALSE;
  696. BOOL fHasCert = FALSE;
  697. if ( !pMB )
  698. {
  699. return S_FALSE;
  700. }
  701. //
  702. // Special case : null instance string means instance zero ( = /LM/W3SVC )
  703. //
  704. if ( !wcscmp(L"", pszInstanceNum) )
  705. {
  706. dwInstance = 0;
  707. }
  708. else
  709. {
  710. dwInstance = _wtoi( pszInstanceNum );
  711. }
  712. fHasCert = MBPathHasCAPIInfo( pMB,
  713. hHandle,
  714. pszInstanceNum,
  715. adwMetabaseCertProperties,
  716. cNumCertMetabaseProperties );
  717. fHasCTL = MBPathHasCAPIInfo( pMB,
  718. hHandle,
  719. pszInstanceNum,
  720. adwMetabaseCTLProperties,
  721. cNumCTLMetabaseProperties );
  722. if ( fHasCTL || fHasCert )
  723. {
  724. //
  725. // Copy instance information into the buffer
  726. //
  727. if ( ( ( *pdwBufferSize - *pdwPosition ) > INSTANCE_HEADER_LEN ) ||
  728. ResizeBuffer( ppbReplicationBuffer, INSTANCE_HEADER_LEN , pdwBufferSize ) )
  729. {
  730. //
  731. // Instance header
  732. //
  733. (*ppbReplicationBuffer)[(*pdwPosition)++] = MSB(dwInstance);
  734. (*ppbReplicationBuffer)[(*pdwPosition)++] = LSB(dwInstance);
  735. (*ppbReplicationBuffer)[(*pdwPosition)++] = COLON;
  736. //
  737. // Server certificate information
  738. //
  739. if ( fHasCert )
  740. {
  741. if ( FAILED( hRes = GetCertReplicationInfo( dwInfoType,
  742. pMB,
  743. hHandle,
  744. pszInstanceNum,
  745. ppbReplicationBuffer,
  746. pdwBufferSize,
  747. pdwPosition ) ) )
  748. {
  749. return hRes;
  750. }
  751. }
  752. //
  753. // CTL information
  754. //
  755. if ( fHasCTL )
  756. {
  757. if ( FAILED( hRes = GetCTLReplicationInfo( dwInfoType,
  758. pMB,
  759. hHandle,
  760. pszInstanceNum,
  761. ppbReplicationBuffer,
  762. pdwBufferSize,
  763. pdwPosition ) ) )
  764. {
  765. return hRes;
  766. }
  767. }
  768. if ( ( ( *pdwBufferSize - *pdwPosition ) > INSTANCE_TRAILER_LEN ) ||
  769. ResizeBuffer( ppbReplicationBuffer, INSTANCE_TRAILER_LEN, pdwBufferSize ) )
  770. {
  771. //
  772. //Instance trailer
  773. //
  774. (*ppbReplicationBuffer)[(*pdwPosition)++] = INSTANCE_TRAILER_BYTE;
  775. }
  776. else
  777. {
  778. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  779. }
  780. }
  781. else
  782. {
  783. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  784. }
  785. }
  786. return (hRes);
  787. }
  788. HRESULT GetCertReplicationInfo( DWORD dwInfoType,
  789. IN IMSAdminBase *pMB,
  790. IN METADATA_HANDLE hHandle,
  791. IN LPCWSTR pszPath,
  792. OUT BYTE **ppbReplicationBuffer,
  793. IN OUT DWORD *pdwBufferSize,
  794. IN OUT DWORD *pdwPosition )
  795. /*++
  796. Routine Description:
  797. Used to retrieve replication information for a certificate
  798. Arguments:
  799. dwInfoType - type of information to retrieve - signature or configuration
  800. pMB - metabase object
  801. hHandle - handle to path open for reading
  802. pszPath - cert info path relative to hHandle
  803. ppbReplicationBuffer - pointer to pointer to buffer that is filled in with info
  804. pdwBufferSize - pointer to current buffer size, updated on success
  805. pdwPosition - pointer to end of data in buffer, updated on success
  806. Returns:
  807. HRESULT indicating success/failure.
  808. --*/
  809. {
  810. PCCERT_CONTEXT pcServerCert = NULL;
  811. DWORD dwNumCerts = 0;
  812. LIST_ENTRY CertChain;
  813. BOOL fCompleteChain = FALSE;
  814. OPEN_CERT_STORE_INFO *pStoreInfo = NULL;
  815. HRESULT hRes = S_OK;
  816. if ( !pMB )
  817. {
  818. return S_FALSE;
  819. }
  820. InitializeListHead( &CertChain );
  821. //
  822. // try to retrieve the server certificate and its complete cert chain
  823. //
  824. if ( !FAILED( hRes = ReadServerCert( pMB,
  825. hHandle,
  826. pszPath,
  827. &pcServerCert,
  828. &pStoreInfo ) ) &&
  829. pcServerCert &&
  830. IsReplicableCert( pcServerCert ) &&
  831. !FAILED( hRes = ConstructCertChain( pcServerCert,
  832. pStoreInfo->pszStoreName,
  833. &CertChain,
  834. &fCompleteChain ) ) )
  835. {
  836. if ( dwInfoType == SIGNATURE )
  837. {
  838. hRes = GetCertChainSignature( &CertChain,
  839. ppbReplicationBuffer,
  840. pdwBufferSize,
  841. pdwPosition );
  842. }
  843. else
  844. {
  845. hRes = SerializeCertChain( &CertChain,
  846. pStoreInfo,
  847. ppbReplicationBuffer,
  848. pdwBufferSize,
  849. pdwPosition );
  850. }
  851. }
  852. //
  853. // Clean up
  854. //
  855. if ( pcServerCert )
  856. {
  857. CertFreeCertificateContext( pcServerCert );
  858. }
  859. FreeCertChain( &CertChain );
  860. return hRes;
  861. }
  862. HRESULT GetCTLReplicationInfo( DWORD dwInfoType,
  863. IN IMSAdminBase *pMB,
  864. IN METADATA_HANDLE hHandle,
  865. IN LPCWSTR pszPath,
  866. OUT BYTE **ppbReplicationBuffer,
  867. IN OUT DWORD *pdwBufferSize,
  868. IN OUT DWORD *pdwPosition )
  869. /*++
  870. Routine Description:
  871. Used to retrieve replication information for a CTL
  872. Arguments:
  873. dwInfoType - type of information to retrieve - signature or configuration
  874. pMB - metabase object
  875. hHandle - handle to path open for reading
  876. pszPath - cert info path relative to hHandle
  877. ppbReplicationBuffer - pointer to pointer to buffer that is filled in with info
  878. pdwBufferSize - pointer to current buffer size, updated on success
  879. pdwPosition - pointer to end of data in buffer, updated on success
  880. Returns:
  881. HRESULT indicating success/failure.
  882. --*/
  883. {
  884. OPEN_CERT_STORE_INFO *pStoreInfo = NULL;
  885. HRESULT hRes;
  886. PCCTL_CONTEXT pcCTL = NULL;
  887. LIST_ENTRY CtlCerts;
  888. PCCERT_CONTEXT pcSignerCert = NULL;
  889. InitializeListHead( &CtlCerts );
  890. if ( S_OK == ( hRes = ReadServerCTL( pMB,
  891. hHandle,
  892. pszPath,
  893. &pcCTL ) ) &&
  894. !FAILED( hRes = BuildCTLDescription( pcCTL,
  895. &CtlCerts,
  896. &pcSignerCert ) ) )
  897. {
  898. if ( dwInfoType == SIGNATURE )
  899. {
  900. hRes = GetCTLSignature( pcCTL,
  901. &CtlCerts,
  902. pcSignerCert,
  903. ppbReplicationBuffer,
  904. pdwBufferSize,
  905. pdwPosition );
  906. }
  907. else
  908. {
  909. hRes = SerializeCTL( pcCTL,
  910. &CtlCerts,
  911. pcSignerCert,
  912. ppbReplicationBuffer,
  913. pdwBufferSize,
  914. pdwPosition );
  915. }
  916. }
  917. //
  918. // Cleanup
  919. //
  920. if ( pcCTL )
  921. {
  922. CertFreeCTLContext( pcCTL );
  923. }
  924. if ( pcSignerCert )
  925. {
  926. CertFreeCertificateContext( pcSignerCert );
  927. }
  928. FreeCertChain( &CtlCerts );
  929. return (hRes);
  930. }
  931. HRESULT SerializeCertChain( IN LIST_ENTRY *pChain,
  932. IN OPEN_CERT_STORE_INFO *pStoreInfo,
  933. OUT PBYTE *ppbChainBuffer,
  934. IN OUT DWORD *pdwBufferSize,
  935. IN OUT DWORD *pdwPosition )
  936. /*++
  937. Routine Description:
  938. Serializes the metabase information and certificate chain belonging to a server
  939. certificate into a buffer. The first certificate in the chain is the actual server
  940. certificate. It does this by copying the chain into a CAPI store and serializing
  941. the store.
  942. Format of buffer :
  943. CERTS=<SHA1 hash of first cert in chain><MSB of length of private key blob><LSB of length of
  944. private key blob><private key blob of first cert><key container info of private key>
  945. <MSB of length of serialized store containg chain><LSB of length of serialized store
  946. containing chain><serialized store>
  947. The SHA1 hash is added so that it's possible to figure out which cert in the store
  948. is the leaf cert when unserializing the buffer.
  949. Arguments:
  950. pChain - chain of CertChainEntry structures
  951. pStoreInfo - structure containing cert-related metabase information
  952. ppbChainBuffer - pointer to pointer to buffer that will hold the serialized store
  953. on success
  954. pdwBufferSize - pointer to present size of buffer, updated if buffer is resized
  955. pdwPosition - pointer to where information is to be written to in buffer, updated
  956. on success
  957. Returns:
  958. HRESULT indicating success/failure
  959. --*/
  960. {
  961. HCERTSTORE hMemStore;
  962. HRESULT hRes;
  963. HCRYPTPROV hProv = NULL;
  964. HCRYPTKEY hKey = NULL;
  965. DWORD cbPrivateKey = 0;
  966. DWORD cbSpaceLeft = 0;
  967. DWORD cbSpaceRequired = 0;
  968. DWORD dwProvSize = 0;
  969. if ( !pChain )
  970. {
  971. return S_FALSE;
  972. }
  973. //
  974. // The certificates are stuffed into an in-memory store, which is then serialized
  975. //
  976. if ( !( hMemStore = CertOpenStore( CERT_STORE_PROV_MEMORY,
  977. 0,
  978. NULL,
  979. 0,
  980. 0 ) ) )
  981. {
  982. return RETURNCODETOHRESULT( GetLastError() );
  983. }
  984. //
  985. // Go through the list and add each cert to the store
  986. //
  987. LIST_ENTRY *pLink;
  988. CertChainEntry *pChainEntry;
  989. DWORD dwSizeNeeded = 0;
  990. DWORD cCerts = 0;
  991. PCCERT_CONTEXT pcFirstCert = NULL;
  992. for ( pLink = pChain->Flink;
  993. pLink != pChain;
  994. pLink = pLink->Flink )
  995. {
  996. pChainEntry = CONTAINING_RECORD( pLink, CertChainEntry, ListEntry );
  997. if ( !CertAddCertificateContextToStore( hMemStore,
  998. pChainEntry->pcCert,
  999. CERT_STORE_ADD_REPLACE_EXISTING,
  1000. NULL ) )
  1001. {
  1002. hRes = RETURNCODETOHRESULT( GetLastError() );
  1003. goto EndSerializeChain;
  1004. }
  1005. cCerts++;
  1006. if ( cCerts == 1 )
  1007. {
  1008. pcFirstCert = pChainEntry->pcCert;
  1009. }
  1010. }
  1011. if ( !pcFirstCert )
  1012. {
  1013. CertCloseStore( hMemStore,
  1014. 0 );
  1015. return S_FALSE;
  1016. }
  1017. //
  1018. // Calculate space requirements
  1019. //
  1020. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1021. cbSpaceRequired = CERT_HEADER_SIZE + SHA1_HASH_SIZE;
  1022. if ( cbSpaceRequired > cbSpaceLeft &&
  1023. !ResizeBuffer( ppbChainBuffer,
  1024. cbSpaceRequired,
  1025. pdwBufferSize ) )
  1026. {
  1027. CertCloseStore( hMemStore,
  1028. 0 );
  1029. return RETURNCODETOHRESULT(ERROR_OUTOFMEMORY);
  1030. }
  1031. //
  1032. // Append cert header
  1033. //
  1034. memcpy( *ppbChainBuffer + *pdwPosition, CERT_HEADER, CERT_HEADER_SIZE );
  1035. (*pdwPosition) += CERT_HEADER_SIZE;
  1036. //
  1037. // Append the hash of the first cert
  1038. //
  1039. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1040. if ( !CertGetCertificateContextProperty( pcFirstCert,
  1041. CERT_SHA1_HASH_PROP_ID,
  1042. (*ppbChainBuffer) + *pdwPosition,
  1043. &cbSpaceLeft ) )
  1044. {
  1045. hRes = RETURNCODETOHRESULT( GetLastError() );
  1046. goto EndSerializeChain;
  1047. }
  1048. (*pdwPosition) += cbSpaceLeft;
  1049. //
  1050. // Serialize the private key for the cert
  1051. //
  1052. if ( FAILED( hRes = ExportAndSerializeServerPK( pcFirstCert,
  1053. ppbChainBuffer,
  1054. pdwBufferSize,
  1055. pdwPosition ) ) )
  1056. {
  1057. CertCloseStore( hMemStore,
  1058. 0 );
  1059. return (hRes);
  1060. }
  1061. //
  1062. // Figure out how much space we need for the serialized store
  1063. //
  1064. CRYPT_DATA_BLOB StoreBlob;
  1065. StoreBlob.pbData = NULL;
  1066. StoreBlob.cbData = 0;
  1067. if ( !CertSaveStore( hMemStore,
  1068. 0,
  1069. CERT_STORE_SAVE_AS_STORE,
  1070. CERT_STORE_SAVE_TO_MEMORY,
  1071. (VOID *) &StoreBlob,
  1072. 0 ) &&
  1073. GetLastError() != ERROR_MORE_DATA )
  1074. {
  1075. hRes = RETURNCODETOHRESULT( GetLastError() );
  1076. goto EndSerializeChain;
  1077. }
  1078. //
  1079. // Resize the buffer if necessary - space for bytes indicating length of
  1080. // serialized store, serialized store itself
  1081. //
  1082. cbSpaceRequired = 2 + StoreBlob.cbData;
  1083. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1084. if ( cbSpaceRequired > cbSpaceLeft )
  1085. {
  1086. if ( !ResizeBuffer( ppbChainBuffer,
  1087. cbSpaceRequired,
  1088. pdwBufferSize ) )
  1089. {
  1090. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  1091. goto EndSerializeChain;
  1092. }
  1093. }
  1094. //
  1095. // Append the length of the serialized store
  1096. //
  1097. (*ppbChainBuffer)[(*pdwPosition)++] = MSB(StoreBlob.cbData);
  1098. (*ppbChainBuffer)[(*pdwPosition)++] = LSB(StoreBlob.cbData);
  1099. //
  1100. // Actually serialize the store
  1101. //
  1102. StoreBlob.cbData = *pdwBufferSize - *pdwPosition;
  1103. StoreBlob.pbData = *ppbChainBuffer + *pdwPosition;
  1104. if ( !CertSaveStore( hMemStore,
  1105. 0,
  1106. CERT_STORE_SAVE_AS_STORE,
  1107. CERT_STORE_SAVE_TO_MEMORY,
  1108. (VOID *) &StoreBlob,
  1109. 0 ) )
  1110. {
  1111. hRes = RETURNCODETOHRESULT( GetLastError() );
  1112. goto EndSerializeChain;
  1113. }
  1114. (*pdwPosition) += StoreBlob.cbData;
  1115. EndSerializeChain:
  1116. CertCloseStore( hMemStore,
  1117. 0 );
  1118. return (hRes);
  1119. }
  1120. HRESULT SerializeCTL( PCCTL_CONTEXT pcCTL,
  1121. LIST_ENTRY *pCTLCertChain,
  1122. PCCERT_CONTEXT pcSigner,
  1123. PBYTE *ppbReplicationBuffer,
  1124. DWORD *pdwBufferSize,
  1125. DWORD *pdwPosition )
  1126. /*++
  1127. Routine Description:
  1128. Serializes a CTL for replication. First, the CTL, the certs in the CTL and the CTL
  1129. signer are added to an in-memory CAPI store; the store is then serialized to memory.
  1130. Format of buffer :
  1131. CTL=<MSB of length of serialized store><LSB of length of serialized
  1132. store><serialized store>
  1133. Arguments:
  1134. pcCTL - CTL to serialize
  1135. pCTLCertChain - chain of certs in CTL
  1136. pcSigner - cert that signed the CTL
  1137. ppbSignature - pointer to pointer to buffer that will hold the signature on success
  1138. pdwBufferSize - pointer to present size of buffer, updated if buffer is resized
  1139. pdwPosition - pointer to where information is to be written to in buffer, updated
  1140. on success
  1141. Returns:
  1142. HRESULT indicating success/failure
  1143. --*/
  1144. {
  1145. HRESULT hRes = S_OK;
  1146. HCERTSTORE hMemStore = NULL;
  1147. //
  1148. // Create the memory store
  1149. //
  1150. if ( !(hMemStore = CertOpenStore( CERT_STORE_PROV_MEMORY,
  1151. 0,
  1152. NULL,
  1153. 0,
  1154. 0 ) ) )
  1155. {
  1156. return RETURNCODETOHRESULT( GetLastError() );
  1157. }
  1158. //
  1159. // Add the CTL to the store
  1160. //
  1161. if ( !CertAddCTLContextToStore( hMemStore,
  1162. pcCTL,
  1163. CERT_STORE_ADD_ALWAYS,
  1164. NULL ) )
  1165. {
  1166. hRes = RETURNCODETOHRESULT( GetLastError() );
  1167. CertCloseStore( hMemStore,
  1168. 0 );
  1169. return hRes;
  1170. }
  1171. //
  1172. // Add the signer to the store
  1173. //
  1174. if ( !CertAddCertificateContextToStore( hMemStore,
  1175. pcSigner,
  1176. CERT_STORE_ADD_ALWAYS,
  1177. NULL ) )
  1178. {
  1179. hRes = RETURNCODETOHRESULT( GetLastError() );
  1180. CertCloseStore( hMemStore,
  1181. 0 );
  1182. return hRes;
  1183. }
  1184. //
  1185. // Add all the certs in the chain to the store
  1186. //
  1187. LIST_ENTRY *pLink;
  1188. CertChainEntry *pChainEntry;
  1189. PCCERT_CONTEXT pcFirstCert = NULL;
  1190. for ( pLink = pCTLCertChain->Flink;
  1191. pLink != pCTLCertChain;
  1192. pLink = pLink->Flink )
  1193. {
  1194. pChainEntry = CONTAINING_RECORD( pLink, CertChainEntry, ListEntry );
  1195. if ( !CertAddCertificateContextToStore( hMemStore,
  1196. pChainEntry->pcCert,
  1197. CERT_STORE_ADD_REPLACE_EXISTING,
  1198. NULL ) )
  1199. {
  1200. hRes = RETURNCODETOHRESULT( GetLastError() );
  1201. CertCloseStore( hMemStore,
  1202. 0 );
  1203. return ( hRes );
  1204. }
  1205. }
  1206. //
  1207. // Figure out the size of the serialized store
  1208. //
  1209. CRYPT_DATA_BLOB StoreBlob;
  1210. DWORD cbSpaceLeft = 0;
  1211. DWORD cbSpaceNeeded = 0;
  1212. StoreBlob.pbData = NULL;
  1213. StoreBlob.cbData = 0;
  1214. if ( !CertSaveStore( hMemStore,
  1215. 0,
  1216. CERT_STORE_SAVE_AS_STORE,
  1217. CERT_STORE_SAVE_TO_MEMORY,
  1218. (VOID *) &StoreBlob,
  1219. 0 ) &&
  1220. GetLastError() != ERROR_MORE_DATA )
  1221. {
  1222. CertCloseStore( hMemStore,
  1223. 0 );
  1224. return RETURNCODETOHRESULT( GetLastError() );
  1225. }
  1226. //
  1227. // need space for the CTL header, the bytes indicating the size of the store
  1228. // and the store itself
  1229. //
  1230. cbSpaceNeeded = StoreBlob.cbData + CTL_HEADER_SIZE + 2;
  1231. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1232. if ( ( cbSpaceLeft > cbSpaceNeeded ) ||
  1233. ResizeBuffer( ppbReplicationBuffer,
  1234. cbSpaceNeeded,
  1235. pdwBufferSize ) )
  1236. {
  1237. //
  1238. // CTL header
  1239. //
  1240. memcpy( *ppbReplicationBuffer + *pdwPosition, CTL_HEADER, CTL_HEADER_SIZE );
  1241. (*pdwPosition) += CTL_HEADER_SIZE;
  1242. //
  1243. // Bytes indicating length of serialized store
  1244. //
  1245. (*ppbReplicationBuffer)[(*pdwPosition)++] = MSB(StoreBlob.cbData);
  1246. (*ppbReplicationBuffer)[(*pdwPosition)++] = LSB(StoreBlob.cbData);
  1247. //
  1248. // Actually serialize the store
  1249. //
  1250. StoreBlob.cbData = *pdwBufferSize - *pdwPosition;
  1251. StoreBlob.pbData = *ppbReplicationBuffer + *pdwPosition;
  1252. if ( CertSaveStore( hMemStore,
  1253. 0,
  1254. CERT_STORE_SAVE_AS_STORE,
  1255. CERT_STORE_SAVE_TO_MEMORY,
  1256. (VOID *) &StoreBlob,
  1257. 0 ) )
  1258. {
  1259. (*pdwPosition) += StoreBlob.cbData;
  1260. }
  1261. else
  1262. {
  1263. DBGPRINTF((DBG_CONTEXT,
  1264. "Error 0x%x\n", GetLastError()));
  1265. hRes = RETURNCODETOHRESULT( GetLastError() );
  1266. }
  1267. }
  1268. else
  1269. {
  1270. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  1271. }
  1272. if ( hMemStore )
  1273. {
  1274. CertCloseStore( hMemStore,
  1275. 0 );
  1276. }
  1277. return (hRes);
  1278. }
  1279. HRESULT GetCertChainSignature( IN LIST_ENTRY *pChain,
  1280. OUT PBYTE *ppbSignature,
  1281. IN OUT DWORD *pdwBufferSize,
  1282. IN OUT DWORD *pdwPosition )
  1283. /*++
  1284. Routine Description:
  1285. Constructs the signature for a chain of certificates. Signature for a chain is :
  1286. CERTS=<# of certs><hash of C1><hash of C2>...<hash of CN>
  1287. Arguments:
  1288. pChain - chain of CertChainEntry structures
  1289. ppbSignature - pointer to pointer to buffer that will hold the signature on success
  1290. pdwBufferSize - pointer to present size of buffer, updated if buffer is resized
  1291. pdwPosition - pointer to where information is to be written to in buffer, updated
  1292. on success
  1293. Returns:
  1294. HRESULT indicating success/failure
  1295. --*/
  1296. {
  1297. if ( !pChain )
  1298. {
  1299. return S_FALSE;
  1300. }
  1301. //
  1302. // Go through the list and figure out how much space is needed
  1303. //
  1304. LIST_ENTRY *pLink;
  1305. CertChainEntry *pChainEntry;
  1306. DWORD dwSizeNeeded = 0;
  1307. DWORD cCerts = 0;
  1308. for ( pLink = pChain->Flink;
  1309. pLink != pChain;
  1310. pLink = pLink->Flink )
  1311. {
  1312. pChainEntry = CONTAINING_RECORD( pLink, CertChainEntry, ListEntry );
  1313. dwSizeNeeded += SHA1_HASH_SIZE;
  1314. cCerts++;
  1315. }
  1316. dwSizeNeeded += 1; //extra byte to hold # of certs
  1317. dwSizeNeeded += CERT_HEADER_SIZE;
  1318. //
  1319. // Resize the buffer if necessary
  1320. //
  1321. if ( (*pdwBufferSize - *pdwPosition) < dwSizeNeeded )
  1322. {
  1323. if ( !ResizeBuffer( ppbSignature,
  1324. dwSizeNeeded,
  1325. pdwBufferSize ) )
  1326. {
  1327. return RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  1328. }
  1329. }
  1330. //
  1331. // First few bytes are cert header
  1332. //
  1333. memcpy(*ppbSignature + *pdwPosition, CERT_HEADER, CERT_HEADER_SIZE );
  1334. (*pdwPosition) += CERT_HEADER_SIZE;
  1335. //
  1336. // Next byte is # of cert hashes
  1337. //
  1338. (*ppbSignature)[(*pdwPosition)++] = (BYTE) cCerts;
  1339. //
  1340. // Walk the chain and stuff in all the cert hashes
  1341. //
  1342. DWORD dwSize = SHA1_HASH_SIZE;
  1343. DWORD cPresentCert = 0;
  1344. for ( pLink = pChain->Flink;
  1345. pLink != pChain;
  1346. pLink = pLink->Flink )
  1347. {
  1348. pChainEntry = CONTAINING_RECORD( pLink, CertChainEntry, ListEntry );
  1349. if ( !CertGetCertificateContextProperty( pChainEntry->pcCert,
  1350. CERT_SHA1_HASH_PROP_ID,
  1351. (*ppbSignature) + *pdwPosition,
  1352. &dwSize ) )
  1353. {
  1354. return RETURNCODETOHRESULT( GetLastError() );
  1355. }
  1356. cPresentCert++;
  1357. (*pdwPosition) += SHA1_HASH_SIZE;
  1358. }
  1359. return S_OK;
  1360. }
  1361. HRESULT GetCTLSignature( PCCTL_CONTEXT pcCTL,
  1362. LIST_ENTRY *pCTLCertsChain,
  1363. PCCERT_CONTEXT pcSignerCert,
  1364. PBYTE *ppbReplicationBuffer,
  1365. DWORD *pdwBufferSize,
  1366. DWORD *pdwPosition )
  1367. /*++
  1368. Routine Description:
  1369. Constructs the signature for a CTL. Signature for CTL is
  1370. CTL=<hash of signer><hash of CTL>
  1371. Arguments:
  1372. pcCTL - CTL whose signature is to be generated
  1373. pCTLCertsChain - chain of certificates in CTL
  1374. pcSignerCert - certificate that signed the CTL
  1375. ppbReplicationBuffer - pointer to pointer to buffer that will hold the signature on success
  1376. pdwBufferSize - pointer to present size of buffer, updated if buffer is resized
  1377. pdwPosition - pointer to where information is to be written to in buffer, updated
  1378. on success
  1379. Returns:
  1380. HRESULT indicating success/failure
  1381. --*/
  1382. {
  1383. DWORD cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1384. DWORD cbSpaceNeeded = 2*SHA1_HASH_SIZE + CTL_HEADER_SIZE;
  1385. HRESULT hRes = S_OK;
  1386. if ( cbSpaceLeft > cbSpaceNeeded ||
  1387. ResizeBuffer( ppbReplicationBuffer,
  1388. cbSpaceNeeded,
  1389. pdwBufferSize ) )
  1390. {
  1391. //
  1392. //CTL header
  1393. //
  1394. memcpy( *ppbReplicationBuffer + *pdwPosition, CTL_HEADER, CTL_HEADER_SIZE );
  1395. (*pdwPosition) += CTL_HEADER_SIZE;
  1396. //
  1397. // Hash of signer
  1398. //
  1399. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1400. if ( !CertGetCertificateContextProperty( pcSignerCert,
  1401. CERT_SHA1_HASH_PROP_ID,
  1402. *ppbReplicationBuffer + *pdwPosition,
  1403. &cbSpaceLeft ) )
  1404. {
  1405. hRes = RETURNCODETOHRESULT( GetLastError() );
  1406. }
  1407. else
  1408. {
  1409. DBG_ASSERT( cbSpaceLeft == SHA1_HASH_SIZE );
  1410. (*pdwPosition) += cbSpaceLeft;
  1411. //
  1412. // Hash of CTL itself
  1413. //
  1414. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  1415. if ( !CertGetCTLContextProperty( pcCTL,
  1416. CERT_SHA1_HASH_PROP_ID,
  1417. *ppbReplicationBuffer + *pdwPosition,
  1418. &cbSpaceLeft ) )
  1419. {
  1420. hRes = RETURNCODETOHRESULT( GetLastError() );
  1421. }
  1422. else
  1423. {
  1424. DBG_ASSERT( cbSpaceLeft == SHA1_HASH_SIZE );
  1425. (*pdwPosition) += cbSpaceLeft;
  1426. }
  1427. }
  1428. }
  1429. else
  1430. {
  1431. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  1432. }
  1433. return (hRes);
  1434. }
  1435. HRESULT DeserializeInstanceInfo( IN OUT BYTE **ppbPosition,
  1436. IN BYTE *pbEnd,
  1437. OUT DWORD *pdwInstance )
  1438. /*++
  1439. Routine Description:
  1440. Deserializes the SSL information for a single server instance
  1441. Arguments:
  1442. ppbPosition - pointer to pointer to buffer to deserialize; updated after info for
  1443. instance has been deserialized
  1444. pbEnd - pointer to end of serialized information, to avoid running off the end
  1445. pdwInstance - pointer to instance for which info is being deserialized; updated on
  1446. success
  1447. Returns:
  1448. HRESULT indicating success/failure.
  1449. --*/
  1450. {
  1451. HRESULT hRes = S_OK;
  1452. BYTE *pbPresent = NULL;
  1453. BOOL fHasCertInfo = FALSE;
  1454. BOOL fHasCTLInfo = FALSE;
  1455. //
  1456. // Sanity checks on arguments
  1457. //
  1458. if ( !ppbPosition || !*ppbPosition || !pbEnd ||
  1459. pbEnd < *ppbPosition + MIN_REPLICATION_INFO_SIZE )
  1460. {
  1461. return REPL_INTERNAL_ERROR;
  1462. }
  1463. pbPresent = *ppbPosition;
  1464. BYTE bMSB = *(pbPresent++);
  1465. BYTE bLSB = *(pbPresent++);
  1466. *pdwInstance = (DWORD) ( (bMSB << 8) + bLSB );
  1467. DBGPRINTF((DBG_CONTEXT,
  1468. "Deserializing info for instance %d\n",
  1469. *pdwInstance));
  1470. //
  1471. // Next byte should be colon
  1472. //
  1473. if ( !(*pbPresent == COLON) )
  1474. {
  1475. return REPL_INTERNAL_ERROR;
  1476. }
  1477. pbPresent++;
  1478. //
  1479. // Next bit should either be CERT_HEADER or CTL_HEADER
  1480. //
  1481. if ( ( pbEnd > pbPresent + CERT_HEADER_SIZE ) &&
  1482. !memcmp( pbPresent, CERT_HEADER, CERT_HEADER_SIZE ) )
  1483. {
  1484. fHasCertInfo = TRUE;
  1485. //
  1486. //deserialize cert
  1487. //
  1488. if ( FAILED( hRes = DeserializeServerCert( &pbPresent,
  1489. pbEnd ) ) )
  1490. {
  1491. return hRes;
  1492. }
  1493. }
  1494. if ( ( pbEnd > pbPresent + CTL_HEADER_SIZE ) &&
  1495. !memcmp( pbPresent, CTL_HEADER, CTL_HEADER_SIZE ) )
  1496. {
  1497. fHasCTLInfo = TRUE;
  1498. //
  1499. //deserialize CTL
  1500. //
  1501. if ( FAILED( hRes = DeserializeServerCTL( &pbPresent,
  1502. pbEnd ) ) )
  1503. {
  1504. return hRes;
  1505. }
  1506. }
  1507. if ( !fHasCertInfo && !fHasCTLInfo )
  1508. {
  1509. return REPL_INTERNAL_ERROR;
  1510. }
  1511. //
  1512. // Check for trailer byte
  1513. //
  1514. if ( !( *pbPresent == INSTANCE_TRAILER_BYTE ) )
  1515. {
  1516. return REPL_INTERNAL_ERROR;
  1517. }
  1518. pbPresent++;
  1519. //
  1520. // Update pointer to indicate where next deserialization has to
  1521. // start
  1522. //
  1523. *ppbPosition = pbPresent;
  1524. return hRes;
  1525. }
  1526. //
  1527. // This should be more focused, but the current prefix docs are quite vague
  1528. // about some of the suppression options.
  1529. //
  1530. // The error being suppressed is a memory leak on the internal error path
  1531. // see windows bug 48010 for details. Suppressing now, because this is
  1532. // a broken an rarely used code path. And the error case is a virtual
  1533. // impossibility.
  1534. //
  1535. /* #pragma INTRINSA suppress=all */
  1536. HRESULT DeserializeServerCert( IN OUT BYTE **ppbBuffer,
  1537. IN BYTE *pbEnd )
  1538. /*++
  1539. Routine Description:
  1540. Deserializes a server certificate [and its attendant chain] and puts the certs in
  1541. the appropriate stores
  1542. Format of buffer :
  1543. "CERTS="<SHA1 hash of first cert in chain><MSB of length of private key blob>
  1544. <LSB of length of private key blob><private key info of first cert>
  1545. <MSB of length of serialized store containing chain><LSB of length of serialized store
  1546. containing chain><serialized store>
  1547. Arguments:
  1548. ppbBuffer - pointer to pointer to serialized info, updated on success
  1549. pbEnd - pointer to end of buffer, to avoid overruns
  1550. Returns:
  1551. HRESULT indicating success/failure
  1552. --*/
  1553. {
  1554. HRESULT hRes = S_OK;
  1555. BYTE *pbPresent = *ppbBuffer;
  1556. BYTE rgbHash[SHA1_HASH_SIZE];
  1557. DWORD cbPrivateKey = 0;
  1558. DWORD cbStore = 0;
  1559. BYTE bMSB = 0;
  1560. BYTE bLSB = 0;
  1561. HCERTSTORE hMemStore = NULL;
  1562. CRYPT_KEY_PROV_INFO CKPI;
  1563. pbPresent += CERT_HEADER_SIZE;
  1564. if ( pbEnd <= pbPresent + SHA1_HASH_SIZE )
  1565. {
  1566. return REPL_INTERNAL_ERROR;
  1567. }
  1568. //
  1569. // get the hash of the first cert in the chain [server cert]
  1570. //
  1571. memcpy( rgbHash, pbPresent, SHA1_HASH_SIZE );
  1572. pbPresent += SHA1_HASH_SIZE;
  1573. //
  1574. // eXtract the private key
  1575. //
  1576. HCRYPTKEY hPrivateKey = NULL;
  1577. if ( FAILED( hRes = DeserializeAndImportServerPK( &pbPresent,
  1578. pbEnd,
  1579. &hPrivateKey,
  1580. &CKPI ) ) )
  1581. {
  1582. return hRes;
  1583. }
  1584. //
  1585. // figure out length of serialized store
  1586. //
  1587. if ( pbEnd <= pbPresent + 2 ) //two byte header indicating length of serialized store
  1588. {
  1589. return REPL_INTERNAL_ERROR;
  1590. }
  1591. bMSB = *(pbPresent++);
  1592. bLSB = *(pbPresent++);
  1593. cbStore = (DWORD) ( (bMSB << 8 ) + bLSB );
  1594. if ( cbStore <= 0 || pbEnd <= pbPresent + cbStore )
  1595. {
  1596. return REPL_INTERNAL_ERROR;
  1597. }
  1598. //
  1599. // Unserialize the store containing the certs in the chain
  1600. //
  1601. CRYPT_DATA_BLOB cdbSerializedStore;
  1602. cdbSerializedStore.cbData = cbStore;
  1603. cdbSerializedStore.pbData = pbPresent;
  1604. if ( !( hMemStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED,
  1605. 0,
  1606. NULL,
  1607. 0,
  1608. (PVOID) &cdbSerializedStore ) ) )
  1609. {
  1610. return RETURNCODETOHRESULT( GetLastError() );
  1611. }
  1612. pbPresent += cbStore;
  1613. //
  1614. // Deal with certs in the store
  1615. //
  1616. if ( FAILED( hRes = DistributeCerts( hMemStore,
  1617. rgbHash,
  1618. &CKPI ) ) )
  1619. {
  1620. CertCloseStore( hMemStore,
  1621. 0 );
  1622. return hRes;
  1623. }
  1624. //
  1625. // Update
  1626. //
  1627. *ppbBuffer = pbPresent;
  1628. //
  1629. // cleanup
  1630. //
  1631. if ( hPrivateKey )
  1632. {
  1633. CryptDestroyKey( hPrivateKey );
  1634. }
  1635. if ( hMemStore )
  1636. {
  1637. CertCloseStore( hMemStore,
  1638. 0 );
  1639. }
  1640. if ( CKPI.cProvParam && CKPI.rgProvParam )
  1641. {
  1642. delete [] CKPI.rgProvParam;
  1643. }
  1644. return hRes;
  1645. }
  1646. HRESULT DeserializeServerCTL( IN OUT BYTE **ppbBuffer,
  1647. IN BYTE *pbEnd )
  1648. /*++
  1649. Routine Description:
  1650. Deserializes a CTL, the certs in the CTL and the CTL signer and places them into the
  1651. appropriate stores.
  1652. CTL goes into the TRUST store. Signer goes into ROOT store if self-signed
  1653. and MY store if not. Certs in CTL go into CA store.
  1654. NOTE : currently, the signer will always be the IIS server cert, which is replicated
  1655. separately, so we won't bother doing anything with the signer cert
  1656. Format of buffer :
  1657. CTL=<MSB of length of serialized store><LSB of length of serialized
  1658. store><serialized store>
  1659. Arguments:
  1660. ppbBuffer - pointer to pointer to serialized info, updated on success
  1661. pbEnd - pointer to end of buffer, to avoid overruns
  1662. Returns:
  1663. HRESULT indicating success/failure
  1664. --*/
  1665. {
  1666. HRESULT hRes = S_OK;
  1667. BYTE *pbPresent = *ppbBuffer;
  1668. DWORD cbStore = 0;
  1669. BYTE bMSB = 0;
  1670. BYTE bLSB = 0;
  1671. HCERTSTORE hMemStore = NULL;
  1672. HCERTSTORE hTrustStore = NULL;
  1673. HCERTSTORE hCAStore = NULL;
  1674. PCCTL_CONTEXT pCTL = NULL;
  1675. PCCTL_CONTEXT pPrevCTL = NULL;
  1676. DWORD dwNumCTLs = 0;
  1677. PCCERT_CONTEXT pCert = NULL;
  1678. PCCERT_CONTEXT pPrevCert = NULL;
  1679. pbPresent += CTL_HEADER_SIZE;
  1680. if ( pbEnd <= pbPresent + 2 ) //bytes indicating length of serialized store
  1681. {
  1682. return REPL_INTERNAL_ERROR;
  1683. }
  1684. //
  1685. // figure out length of serialized store
  1686. //
  1687. bMSB = *(pbPresent++);
  1688. bLSB = *(pbPresent++);
  1689. cbStore = (DWORD) ( (bMSB << 8 ) + bLSB );
  1690. if ( cbStore <= 0 || pbEnd <= pbPresent + cbStore )
  1691. {
  1692. return REPL_INTERNAL_ERROR;
  1693. }
  1694. //
  1695. // Unserialize the store containing the CTL, certs in the CTL and signer
  1696. //
  1697. CRYPT_DATA_BLOB cdbSerializedStore;
  1698. cdbSerializedStore.cbData = cbStore;
  1699. cdbSerializedStore.pbData = pbPresent;
  1700. if ( !( hMemStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED,
  1701. 0,
  1702. NULL,
  1703. 0,
  1704. (PVOID) &cdbSerializedStore ) ) )
  1705. {
  1706. hRes = RETURNCODETOHRESULT( GetLastError() );
  1707. goto end_deserialize_ctl;
  1708. }
  1709. pbPresent += cbStore;
  1710. if ( !( hTrustStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  1711. 0,
  1712. NULL,
  1713. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1714. TRUST_STORE_NAME ) ) )
  1715. {
  1716. hRes = RETURNCODETOHRESULT( GetLastError() );
  1717. goto end_deserialize_ctl;
  1718. }
  1719. if ( !( hCAStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  1720. 0,
  1721. NULL,
  1722. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1723. CA_STORE_NAME ) ) )
  1724. {
  1725. hRes = RETURNCODETOHRESULT( GetLastError() );
  1726. goto end_deserialize_ctl;
  1727. }
  1728. //
  1729. // Add all the CTLs in the deserialized store to the TRUST store
  1730. //
  1731. while ( ( pCTL = CertEnumCTLsInStore( hMemStore,
  1732. pPrevCTL ) ) )
  1733. {
  1734. if ( !CertAddCTLContextToStore( hTrustStore,
  1735. pCTL,
  1736. CERT_STORE_ADD_REPLACE_EXISTING,
  1737. NULL ) )
  1738. {
  1739. hRes = RETURNCODETOHRESULT( GetLastError() );
  1740. goto end_deserialize_ctl;
  1741. }
  1742. pPrevCTL = pCTL;
  1743. dwNumCTLs++;
  1744. }
  1745. DBG_ASSERT( dwNumCTLs == 1 );
  1746. //
  1747. // Add all the certs in the CTL to the CA store
  1748. //
  1749. while ( pCert = CertEnumCertificatesInStore( hMemStore,
  1750. pPrevCert ) )
  1751. {
  1752. if ( !CertAddCertificateContextToStore( hCAStore,
  1753. pCert,
  1754. CERT_STORE_ADD_NEW,
  1755. NULL ) &&
  1756. GetLastError() != CRYPT_E_EXISTS )
  1757. {
  1758. hRes = RETURNCODETOHRESULT( GetLastError() );
  1759. goto end_deserialize_ctl;
  1760. }
  1761. pPrevCert = pCert;
  1762. }
  1763. //
  1764. // NOTE : in future may want to deal with signer cert as well
  1765. //
  1766. //
  1767. // Update
  1768. //
  1769. *ppbBuffer = pbPresent;
  1770. end_deserialize_ctl:
  1771. //
  1772. // cleanup
  1773. //
  1774. if ( hMemStore )
  1775. {
  1776. CertCloseStore( hMemStore,
  1777. 0 );
  1778. }
  1779. if ( hTrustStore )
  1780. {
  1781. CertCloseStore( hTrustStore,
  1782. 0 );
  1783. }
  1784. if ( hCAStore )
  1785. {
  1786. CertCloseStore( hCAStore,
  1787. 0 );
  1788. }
  1789. return (hRes);
  1790. }
  1791. HRESULT ConstructCertChain( PCCERT_CONTEXT pcLeafCert,
  1792. LPWSTR pszLeafCertStore,
  1793. LIST_ENTRY *pCertChain,
  1794. PBOOL pfCompleteChain )
  1795. /*++
  1796. Routine Description:
  1797. Constructs the complete cert chain for the leaf cert passed in
  1798. Arguments:
  1799. pcLeafCert - cert for which chain is to be constructed
  1800. pszLeafCertStore - name of store from which pcLeafCert came
  1801. pCertChain - pointer to linked list containing cert chain. The first cert in the
  1802. list is pcLeafCert.
  1803. pfCompleteChain - set to TRUE if we constructed a full cert chain ie the constructed chain
  1804. ends with a self-signed cert
  1805. Returns:
  1806. HRESULT indicating success/failure
  1807. Note: 2/18/98 - CAPI2 is supposed to have an API Real Soon Now that will construct a cert chain;
  1808. until then, we'll roll our own.
  1809. --*/
  1810. {
  1811. DBG_ASSERT( pcLeafCert );
  1812. DBG_ASSERT( pCertChain );
  1813. HCERTSTORE hMyStore = NULL;
  1814. HCERTSTORE hCAStore = NULL;
  1815. HCERTSTORE hRootStore = NULL;
  1816. HRESULT hr = NOERROR;
  1817. CertChainEntry * pLink = NULL;
  1818. PCCERT_CONTEXT pcIssuer = NULL;
  1819. PCCERT_CONTEXT pcPresentLeaf = pcLeafCert;
  1820. DWORD dwFlags = 0;
  1821. DWORD dwStoresTried = 0;
  1822. HCERTSTORE hPresentStore = pcPresentLeaf->hCertStore;
  1823. BOOL fSystemStore = FALSE;
  1824. LPWSTR pszPresentStore = pszLeafCertStore;
  1825. *pfCompleteChain = FALSE;
  1826. //
  1827. // Open all the stores we'll search for issuers - MY, CA and ROOT
  1828. //
  1829. hMyStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  1830. 0,
  1831. NULL,
  1832. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1833. MY_STORE_NAME );
  1834. if ( !hMyStore )
  1835. {
  1836. hr = RETURNCODETOHRESULT( GetLastError() );
  1837. goto cleanup;
  1838. }
  1839. hCAStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  1840. 0,
  1841. NULL,
  1842. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1843. CA_STORE_NAME );
  1844. if ( !hCAStore )
  1845. {
  1846. hr = RETURNCODETOHRESULT( GetLastError() );
  1847. goto cleanup;
  1848. }
  1849. hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  1850. 0,
  1851. NULL,
  1852. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1853. ROOT_STORE_NAME );
  1854. if ( !hRootStore )
  1855. {
  1856. hr = RETURNCODETOHRESULT( GetLastError() );
  1857. goto cleanup;
  1858. }
  1859. //
  1860. // First link in the chain is the leaf cert
  1861. //
  1862. pLink = new CertChainEntry;
  1863. if( pLink == NULL )
  1864. {
  1865. hr = RETURNCODETOHRESULT( GetLastError() );
  1866. goto cleanup;
  1867. }
  1868. pLink->pcCert = CertDuplicateCertificateContext( pcLeafCert );
  1869. pLink->pszStoreName = mystrdup( pszLeafCertStore );
  1870. InsertHeadList( pCertChain, &pLink->ListEntry );
  1871. //
  1872. // To build the chain, look for issuers in 4 stores : the store the cert came from,
  1873. // and the "MY", "CA" and "ROOT" stores, cycling through the stores as necessary
  1874. //
  1875. *pfCompleteChain = FALSE;
  1876. DBG_ASSERT( SUCCEEDED(hr) );
  1877. while ( 1 )
  1878. {
  1879. //
  1880. // Bail when we get to the top of a chain
  1881. //
  1882. if ( IsSelfSignedCert( pcPresentLeaf ) )
  1883. {
  1884. *pfCompleteChain = TRUE;
  1885. break;
  1886. }
  1887. pcIssuer = CertGetIssuerCertificateFromStore( hPresentStore,
  1888. pcPresentLeaf,
  1889. NULL,
  1890. &dwFlags );
  1891. //
  1892. // Got an issuer in this store
  1893. //
  1894. if ( pcIssuer )
  1895. {
  1896. //
  1897. // Add it to the list
  1898. //
  1899. pLink = new CertChainEntry;
  1900. if( pLink == NULL )
  1901. {
  1902. hr = RETURNCODETOHRESULT( GetLastError() );
  1903. goto cleanup;
  1904. }
  1905. pLink->pcCert = CertDuplicateCertificateContext( pcIssuer );
  1906. pLink->pszStoreName = (fSystemStore ? pszPresentStore :
  1907. mystrdup( pszPresentStore ) );
  1908. pLink->fDynName = !fSystemStore;
  1909. //
  1910. // Need to insert at the -end- of the list to keep ordering, where
  1911. // first cert is the actual server cert
  1912. //
  1913. InsertTailList( pCertChain, &pLink->ListEntry );
  1914. //
  1915. // Set up for next round
  1916. //
  1917. dwStoresTried = 0;
  1918. pcPresentLeaf = pLink->pcCert;
  1919. }
  1920. //
  1921. // No issuer in this store, switch to next store to look in
  1922. //
  1923. else
  1924. {
  1925. dwStoresTried++;
  1926. if ( dwStoresTried == 4 ) //we've tried all the stores, time to bail
  1927. {
  1928. break;
  1929. }
  1930. if ( hPresentStore == hMyStore )
  1931. {
  1932. hPresentStore = hCAStore;
  1933. pszPresentStore = CA_STORE_NAME;
  1934. fSystemStore = TRUE;
  1935. }
  1936. else if ( hPresentStore == hCAStore )
  1937. {
  1938. hPresentStore = hRootStore;
  1939. pszPresentStore = ROOT_STORE_NAME;
  1940. fSystemStore = TRUE;
  1941. }
  1942. else if ( hPresentStore == hRootStore )
  1943. {
  1944. hPresentStore = pcPresentLeaf->hCertStore;
  1945. pszPresentStore = pszLeafCertStore;
  1946. fSystemStore = FALSE;
  1947. }
  1948. else
  1949. {
  1950. hPresentStore = hMyStore;
  1951. pszPresentStore = MY_STORE_NAME;
  1952. fSystemStore = TRUE;
  1953. }
  1954. }
  1955. } //while ( 1 )
  1956. DBG_ASSERT( SUCCEEDED(hr) );
  1957. cleanup:
  1958. //
  1959. // Cleanup
  1960. //
  1961. if( hMyStore != NULL )
  1962. {
  1963. CertCloseStore( hMyStore, 0 );
  1964. }
  1965. if( hCAStore != NULL )
  1966. {
  1967. CertCloseStore( hCAStore, 0 );
  1968. }
  1969. if( hRootStore != NULL )
  1970. {
  1971. CertCloseStore( hRootStore, 0 );
  1972. }
  1973. return hr;
  1974. }
  1975. HRESULT BuildCTLDescription( IN PCCTL_CONTEXT pcCTL,
  1976. OUT LIST_ENTRY *pCTLCerts,
  1977. OUT PCCERT_CONTEXT *ppcSigner )
  1978. /*++
  1979. Routine Description:
  1980. Builds a full description of a CTL - all the certs in the CTL as well as the CTL
  1981. signer
  1982. Arguments:
  1983. pcCTL - CTL whose description is to be built
  1984. pCTLCerts - linked list that will have the certs in the CTL inserted into it
  1985. ppcSigner - pointer to pointer to cert that signed the CTL
  1986. Returns:
  1987. HRESULT indicating success/failure
  1988. --*/
  1989. {
  1990. //
  1991. // First try to get all the certs in the CTL
  1992. //
  1993. PCTL_INFO pCtlInfo = pcCTL->pCtlInfo;
  1994. HRESULT hRes;
  1995. if ( !pCtlInfo->cCTLEntry )
  1996. {
  1997. DBGPRINTF((DBG_CONTEXT,
  1998. "Herm. Nothing in CTL ? \n"));
  1999. return S_FALSE;
  2000. }
  2001. else
  2002. {
  2003. HCERTSTORE ahStores[3];
  2004. memset( ahStores, 0, sizeof(ahStores) );
  2005. DWORD dwNumStores = sizeof(ahStores)/sizeof(HCERTSTORE);
  2006. PCCERT_CONTEXT pcCert = NULL;
  2007. BOOL fFoundCert = FALSE;
  2008. DWORD dwIndex = 0;
  2009. DWORD dwStoreIndex = 0;
  2010. //
  2011. // Try the MY, CA and ROOT stores for local machine
  2012. //
  2013. if ( !(ahStores[0] = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  2014. 0,
  2015. NULL,
  2016. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2017. MY_STORE_NAME ) ) )
  2018. {
  2019. DBGPRINTF((DBG_CONTEXT,
  2020. "Failed to open MY store : 0x%x\n", GetLastError()));
  2021. hRes = RETURNCODETOHRESULT( GetLastError() );
  2022. goto ctl_cleanup;
  2023. }
  2024. if ( !(ahStores[1] = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  2025. 0,
  2026. NULL,
  2027. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2028. CA_STORE_NAME ) ) )
  2029. {
  2030. DBGPRINTF((DBG_CONTEXT,
  2031. "Failed to open CA store : 0x%x\n", GetLastError()));
  2032. hRes = RETURNCODETOHRESULT( GetLastError() );
  2033. goto ctl_cleanup;
  2034. }
  2035. if ( !(ahStores[2] = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  2036. 0,
  2037. NULL,
  2038. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2039. ROOT_STORE_NAME ) ) )
  2040. {
  2041. DBGPRINTF((DBG_CONTEXT,
  2042. "Failed to open ROOT store : 0x%x\n", GetLastError()));
  2043. hRes = RETURNCODETOHRESULT( GetLastError() );
  2044. goto ctl_cleanup;
  2045. }
  2046. //
  2047. // Iterate through the certs in the CTL. For each cert, try to find it
  2048. // by SHA1 hash in the supplied stores.
  2049. //
  2050. for ( dwIndex = 0; dwIndex < pCtlInfo->cCTLEntry; dwIndex++ )
  2051. {
  2052. fFoundCert = FALSE;
  2053. for ( dwStoreIndex = 0; dwStoreIndex < dwNumStores; dwStoreIndex++ )
  2054. {
  2055. if ( pcCert = CertFindCertificateInStore( ahStores[dwStoreIndex],
  2056. X509_ASN_ENCODING,
  2057. 0,
  2058. CERT_FIND_SHA1_HASH,
  2059. (VOID *) &(pCtlInfo->rgCTLEntry[dwIndex].SubjectIdentifier),
  2060. NULL ) )
  2061. {
  2062. fFoundCert = TRUE;
  2063. break;
  2064. }
  2065. }
  2066. //
  2067. // Couldn't find one of the certs in the CTL, error
  2068. //
  2069. if ( !fFoundCert )
  2070. {
  2071. hRes = RETURNCODETOHRESULT( GetLastError() );
  2072. goto ctl_cleanup;
  2073. }
  2074. else
  2075. {
  2076. CertChainEntry *pEntry = new CertChainEntry;
  2077. if( pEntry == NULL )
  2078. {
  2079. hRes = RETURNCODETOHRESULT( GetLastError() );
  2080. goto ctl_cleanup;
  2081. }
  2082. pEntry->pcCert = pcCert;
  2083. pEntry->fDynName = FALSE;
  2084. switch( dwStoreIndex )
  2085. {
  2086. case 0:
  2087. pEntry->pszStoreName = MY_STORE_NAME;
  2088. break;
  2089. case 1:
  2090. pEntry->pszStoreName = CA_STORE_NAME;
  2091. break;
  2092. case 2:
  2093. pEntry->pszStoreName = ROOT_STORE_NAME;
  2094. break;
  2095. default:
  2096. //
  2097. // should never get here
  2098. DBG_ASSERT( TRUE );
  2099. break;
  2100. }
  2101. InsertTailList( pCTLCerts, &pEntry->ListEntry );
  2102. }
  2103. }
  2104. //
  2105. // Find the CTL signer
  2106. //
  2107. if ( !CryptMsgGetAndVerifySigner( (HCRYPTMSG) pcCTL->hCryptMsg,
  2108. dwNumStores,
  2109. ahStores,
  2110. CMSG_TRUSTED_SIGNER_FLAG | CMSG_SIGNER_ONLY_FLAG,
  2111. ppcSigner,
  2112. NULL ) )
  2113. {
  2114. hRes = RETURNCODETOHRESULT( GetLastError() );
  2115. }
  2116. ctl_cleanup:
  2117. for ( dwStoreIndex = 0; dwStoreIndex < dwNumStores; dwStoreIndex++ )
  2118. {
  2119. if ( ahStores[dwStoreIndex] )
  2120. {
  2121. CertCloseStore( ahStores[dwStoreIndex],
  2122. 0 );
  2123. }
  2124. }
  2125. } //else
  2126. return (hRes);
  2127. }
  2128. VOID FreeCertChain( IN OUT LIST_ENTRY *pChain )
  2129. /*++
  2130. Routine Description:
  2131. Free resources associated with a cert chain
  2132. Arguments:
  2133. pChain - chain to be cleaned up
  2134. Returns:
  2135. Nothing
  2136. --*/
  2137. {
  2138. if ( !pChain )
  2139. {
  2140. return;
  2141. }
  2142. CertChainEntry *pChainEntry;
  2143. while ( !IsListEmpty( pChain ) )
  2144. {
  2145. pChainEntry = CONTAINING_RECORD ( pChain->Flink,
  2146. CertChainEntry,
  2147. ListEntry );
  2148. RemoveEntryList( &(pChainEntry->ListEntry) );
  2149. if ( pChainEntry->pcCert )
  2150. {
  2151. CertFreeCertificateContext( pChainEntry->pcCert );
  2152. }
  2153. if ( pChainEntry->pszStoreName && pChainEntry->fDynName )
  2154. {
  2155. delete [] pChainEntry->pszStoreName;
  2156. }
  2157. }
  2158. }
  2159. BOOL IsSelfSignedCert( IN PCCERT_CONTEXT pCertContext )
  2160. /*++
  2161. Routine Description:
  2162. Determines whether a cert is self-signed ie the top of a hierarchy
  2163. Arguments:
  2164. pCertContext - cert to be checked
  2165. Returns:
  2166. TRUE if cert is self-signed, FALSE otherwise
  2167. --*/
  2168. {
  2169. //
  2170. // Compare subject and issuer.
  2171. //
  2172. if(pCertContext->pCertInfo->Subject.cbData == pCertContext->pCertInfo->Issuer.cbData)
  2173. {
  2174. if(memcmp(pCertContext->pCertInfo->Subject.pbData,
  2175. pCertContext->pCertInfo->Issuer.pbData,
  2176. pCertContext->pCertInfo->Issuer.cbData) == 0)
  2177. {
  2178. return TRUE;
  2179. }
  2180. }
  2181. return FALSE;
  2182. }
  2183. BOOL IsReplicableCert( IN PCCERT_CONTEXT pCert )
  2184. /*++
  2185. Routine Description:
  2186. Checks whether a cert can be replicated or not. Eg Fortezza certs can't be replicated
  2187. because they use a machine-specific hardware token
  2188. Arguments:
  2189. pCert - cert to be checked
  2190. Returns:
  2191. TRUE if cert can be replicated, FALSE if not
  2192. --*/
  2193. {
  2194. if ( IsFortezzaCert( pCert ) )
  2195. {
  2196. return FALSE;
  2197. }
  2198. return TRUE;
  2199. }
  2200. BOOL IsFortezzaCert( IN PCCERT_CONTEXT pCert )
  2201. /*++
  2202. Routine Description:
  2203. Checks whether a cert is a Fortezza certificate.
  2204. Arguments:
  2205. pCert - cert to be checked
  2206. Returns:
  2207. TRUE if it is, FALSE if not
  2208. --*/
  2209. {
  2210. PSTR pszOid = NULL;
  2211. // Q - is there a better way to do this?
  2212. pszOid = pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
  2213. if(pszOid)
  2214. {
  2215. if(strcmp(pszOid, szOID_INFOSEC_mosaicUpdatedSig) == 0 ||
  2216. strcmp(pszOid, szOID_INFOSEC_mosaicKMandUpdSig) == 0)
  2217. {
  2218. return TRUE;
  2219. }
  2220. }
  2221. return FALSE;
  2222. }
  2223. HRESULT ReadServerCTL( IN IMSAdminBase *pMB,
  2224. IN METADATA_HANDLE hHandle,
  2225. IN LPCWSTR pszPath,
  2226. OUT PCCTL_CONTEXT *ppcCTL )
  2227. /*++
  2228. Routine Description:
  2229. Tries to construct a certificate based on information in metabase
  2230. Arguments:
  2231. pMB - pointer to MB object
  2232. hHandle - handle opened for reading
  2233. pszPath - path under which info is stored, relative to hHandle
  2234. ppcCTL - pointer to pointer to CTL context, updated if CTL was found
  2235. Returns:
  2236. HRESULT indicating success/failure
  2237. --*/
  2238. {
  2239. DBG_ASSERT( pMB );
  2240. METADATA_RECORD mdr;
  2241. HRESULT hRes;
  2242. LPWSTR pwszListIdentifier = NULL;
  2243. DWORD dwIdentifierSize = 0;
  2244. OPEN_CERT_STORE_INFO *pCertStoreInfo = NULL;
  2245. HCERTSTORE hStore = NULL;
  2246. //
  2247. // Read CTL list identifier out of metabase
  2248. //
  2249. MD_SET_DATA_RECORD( &mdr, MD_SSL_CTL_IDENTIFIER,
  2250. METADATA_NO_ATTRIBUTES,
  2251. IIS_MD_UT_SERVER, BINARY_METADATA, NULL,
  2252. 0 );
  2253. if ( FAILED( hRes = RetrieveBlobFromMetabase( pMB,
  2254. hHandle,
  2255. pszPath,
  2256. &mdr,
  2257. 0 ) ) )
  2258. {
  2259. return hRes;
  2260. }
  2261. else
  2262. {
  2263. pwszListIdentifier = (LPWSTR) mdr.pbMDData;
  2264. dwIdentifierSize = mdr.dwMDDataLen;
  2265. #if DBG
  2266. CHAR achListId[255];
  2267. if ( WideCharToMultiByte( CP_ACP,
  2268. 0,
  2269. pwszListIdentifier,
  2270. -1,
  2271. achListId,
  2272. 254,
  2273. NULL,
  2274. NULL ) )
  2275. {
  2276. DBGPRINTF((DBG_CONTEXT,
  2277. "List id : %s\n", achListId));
  2278. }
  2279. #endif
  2280. }
  2281. //
  2282. // Read cert store info out of MB, and try to reconstruct CTL context
  2283. //
  2284. if ( (pCertStoreInfo = ReadCertStoreInfoFromMB( pMB,
  2285. hHandle,
  2286. pszPath,
  2287. TRUE ) ) )
  2288. {
  2289. if ( !( hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  2290. 0,
  2291. NULL,
  2292. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2293. pCertStoreInfo->pszStoreName ) ) )
  2294. {
  2295. hRes = RETURNCODETOHRESULT( GetLastError() );
  2296. }
  2297. else
  2298. {
  2299. CTL_FIND_USAGE_PARA CtlFindUsagePara;
  2300. memset(&CtlFindUsagePara, 0, sizeof(CtlFindUsagePara));
  2301. CtlFindUsagePara.cbSize = sizeof(CtlFindUsagePara);
  2302. CtlFindUsagePara.ListIdentifier.cbData = dwIdentifierSize;
  2303. CtlFindUsagePara.ListIdentifier.pbData = (PBYTE) pwszListIdentifier;
  2304. //
  2305. // Try to find CTL in specified store
  2306. //
  2307. *ppcCTL = CertFindCTLInStore( hStore,
  2308. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2309. 0,
  2310. CTL_FIND_USAGE,
  2311. (LPVOID) &CtlFindUsagePara,
  2312. NULL );
  2313. if ( !*ppcCTL )
  2314. {
  2315. hRes = RETURNCODETOHRESULT( GetLastError() );
  2316. }
  2317. }
  2318. }
  2319. else
  2320. {
  2321. hRes = S_FALSE;
  2322. }
  2323. if ( hStore )
  2324. {
  2325. CertCloseStore( hStore,
  2326. 0 );
  2327. }
  2328. if ( pCertStoreInfo )
  2329. {
  2330. DeallocateCertStoreInfo( pCertStoreInfo );
  2331. }
  2332. if ( pwszListIdentifier )
  2333. {
  2334. delete [] pwszListIdentifier;
  2335. }
  2336. return hRes;
  2337. }
  2338. HRESULT ReadServerCert( IN IMSAdminBase *pMB,
  2339. IN METADATA_HANDLE hHandle,
  2340. IN LPCWSTR pszPath,
  2341. OUT PCCERT_CONTEXT *ppcCertContext,
  2342. OUT OPEN_CERT_STORE_INFO **ppStoreInfo )
  2343. /*++
  2344. Routine Description:
  2345. Tries to construct a certificate based on information in metabase
  2346. Arguments:
  2347. pMB - pointer to MB object
  2348. hHandle - handle opened for reading
  2349. pszPath - path under which info is stored, relative to hHandle
  2350. ppcCertContext - pointer to pointer to cert context, updated if cert was found
  2351. ppStoreInfo - pointer to pointer to cert store information stored in metabase; updated if
  2352. successful
  2353. Returns:
  2354. HRESULT indicating success/failure
  2355. --*/
  2356. {
  2357. DBG_ASSERT( pMB );
  2358. METADATA_RECORD mdr;
  2359. PBYTE pbCertHash = NULL;
  2360. DWORD dwHashSize = 0;
  2361. HRESULT hRes;
  2362. //
  2363. // Get the hash of the cert
  2364. //
  2365. MD_SET_DATA_RECORD( &mdr, MD_SSL_CERT_HASH, METADATA_NO_ATTRIBUTES,
  2366. IIS_MD_UT_SERVER, BINARY_METADATA, NULL, 0 );
  2367. if ( FAILED( hRes = RetrieveBlobFromMetabase( pMB,
  2368. hHandle,
  2369. pszPath,
  2370. &mdr,
  2371. SHA1_HASH_SIZE ) ) )
  2372. {
  2373. return hRes;
  2374. }
  2375. else
  2376. {
  2377. DBG_ASSERT( mdr.dwMDDataLen == SHA1_HASH_SIZE );
  2378. pbCertHash = mdr.pbMDData;
  2379. dwHashSize = mdr.dwMDDataLen;
  2380. }
  2381. //
  2382. // Get all the info necessary to open the store in which the cert is
  2383. //
  2384. *ppStoreInfo = ReadCertStoreInfoFromMB( pMB,
  2385. hHandle,
  2386. pszPath,
  2387. FALSE );
  2388. if ( !*ppStoreInfo )
  2389. {
  2390. delete [] pbCertHash;
  2391. return S_FALSE;
  2392. }
  2393. //
  2394. // Got all the info, reconstruct the certificate
  2395. //
  2396. #if 0
  2397. //
  2398. // Open the appropriate store
  2399. //
  2400. if ( !CryptAcquireContext( &m_hCryptProv,
  2401. m_pszContainer,
  2402. m_pszProvider,
  2403. m_dwProvType,
  2404. m_dwFlags ) )
  2405. {
  2406. goto EndReadServerCert;
  2407. }
  2408. if ( !(m_hCertStore = CertOpenSystemStore( m_hCryptProv,
  2409. m_pszStoreName )))
  2410. {
  2411. m_dwStatus = CERT_ERR_CAPI;
  2412. goto EndRetrieveCertContext;
  2413. }
  2414. #else
  2415. if ( !((*ppStoreInfo)->hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  2416. 0,
  2417. NULL,
  2418. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2419. (*ppStoreInfo)->pszStoreName ) ) )
  2420. {
  2421. DeallocateCertStoreInfo( *ppStoreInfo );
  2422. delete [] pbCertHash;
  2423. return S_FALSE;
  2424. }
  2425. #endif
  2426. //
  2427. // Try to find the cert in the store
  2428. //
  2429. CRYPT_HASH_BLOB HashBlob;
  2430. HashBlob.cbData = dwHashSize;
  2431. HashBlob.pbData = pbCertHash;
  2432. *ppcCertContext = CertFindCertificateInStore( (*ppStoreInfo)->hCertStore,
  2433. X509_ASN_ENCODING,
  2434. 0,
  2435. CERT_FIND_SHA1_HASH,
  2436. (VOID *) &HashBlob,
  2437. NULL );
  2438. if ( !*ppcCertContext )
  2439. {
  2440. hRes = RETURNCODETOHRESULT( GetLastError() );
  2441. }
  2442. else
  2443. {
  2444. hRes = S_OK;
  2445. }
  2446. //
  2447. // Clean up
  2448. //
  2449. delete [] pbCertHash;
  2450. return hRes;
  2451. }
  2452. BOOL ResizeBuffer( IN OUT BYTE **ppbBuffer,
  2453. IN DWORD dwMinResize,
  2454. IN OUT DWORD *pdwPresentSize )
  2455. /*++
  2456. Routine Description:
  2457. Used to resize a buffer
  2458. Arguments:
  2459. ppbBuffer - pointer to pointer to buffer to be resized, updated on success
  2460. dwMinResize - minimum amount to resize by
  2461. pdwPresentSize - pointer to buffer size, updated on success
  2462. Returns:
  2463. TRUE if resize succeeds, FALSE if it fails
  2464. --*/
  2465. {
  2466. DWORD dwActualResize = 0;
  2467. DWORD dwDoubleSize = 2* (*pdwPresentSize);
  2468. DWORD dwExtendedSize = *pdwPresentSize + dwMinResize;
  2469. BYTE *pbNewBuffer = NULL;
  2470. //
  2471. // Amt of memory to resize to is maximum of
  2472. // present size + dwMinResize, 2 * present size, INITIAL_BUFFER_SIZE
  2473. //
  2474. dwActualResize = ( INITIAL_BUFFER_SIZE > dwDoubleSize ?
  2475. ( INITIAL_BUFFER_SIZE > dwExtendedSize ?
  2476. INITIAL_BUFFER_SIZE : dwExtendedSize ) :
  2477. ( dwExtendedSize > dwDoubleSize ? dwExtendedSize : dwDoubleSize ) );
  2478. //
  2479. // totally new buffer
  2480. //
  2481. if ( !*ppbBuffer )
  2482. {
  2483. *ppbBuffer = new BYTE[ dwActualResize ];
  2484. if ( !*ppbBuffer )
  2485. {
  2486. SetLastError( ERROR_OUTOFMEMORY );
  2487. return FALSE;
  2488. }
  2489. }
  2490. else // resize of existing buffer
  2491. {
  2492. pbNewBuffer = new BYTE[ dwActualResize ];
  2493. if ( !pbNewBuffer )
  2494. {
  2495. SetLastError( ERROR_OUTOFMEMORY );
  2496. return FALSE;
  2497. }
  2498. //
  2499. // Copy the old buffer
  2500. //
  2501. memcpy( pbNewBuffer, *ppbBuffer, *pdwPresentSize );
  2502. //
  2503. // Zero out the old buffer and delete it
  2504. //
  2505. memset( *ppbBuffer, 0, *pdwPresentSize );
  2506. delete [] *ppbBuffer;
  2507. *ppbBuffer = pbNewBuffer;
  2508. }
  2509. *pdwPresentSize = dwActualResize;
  2510. return TRUE;
  2511. }
  2512. HRESULT RetrieveBlobFromMetabase( IN IMSAdminBase *pMB,
  2513. IN METADATA_HANDLE hHandle,
  2514. IN LPCWSTR pszPath,
  2515. IN OUT PMETADATA_RECORD pMDR,
  2516. IN DWORD dwSizeHint OPTIONAL)
  2517. /*++
  2518. Routine Description:
  2519. Tries to retrieve a value of variable length from the metabase
  2520. Arguments:
  2521. pMB - pointer to MB object
  2522. hHandle - handle open for reading
  2523. pszPath - path relative to hHandle
  2524. pMDR - pointer to metadata record to be used when reading the value. The pbMDData member
  2525. will be updated on success
  2526. dwSizeHint - if caller has idea of how big value might be, can set this to number of
  2527. bytes to try first retrieval call with
  2528. Returns:
  2529. HRESULT indicating whether value was read successfully
  2530. --*/
  2531. {
  2532. HRESULT hRes = S_OK;
  2533. DWORD dwRequiredSize = 0;
  2534. //
  2535. // If caller has a hint about how big the buffer might need to be, let's use it
  2536. //
  2537. if ( dwSizeHint )
  2538. {
  2539. pMDR->pbMDData = new UCHAR[dwSizeHint];
  2540. if ( !(pMDR->pbMDData) )
  2541. {
  2542. return RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  2543. }
  2544. }
  2545. pMDR->dwMDDataLen = (dwSizeHint ? dwSizeHint : 0);
  2546. hRes = pMB->GetData( hHandle,
  2547. pszPath,
  2548. pMDR,
  2549. &dwRequiredSize );
  2550. if ( FAILED(hRes) )
  2551. {
  2552. //
  2553. // If buffer wasn't big enough, let's try again ...
  2554. //
  2555. if ( HRESULTTOWIN32(hRes) == ERROR_INSUFFICIENT_BUFFER )
  2556. {
  2557. //
  2558. // We were brought up well, so we'll clean stuff up
  2559. //
  2560. if ( dwSizeHint )
  2561. {
  2562. delete [] pMDR->pbMDData;
  2563. }
  2564. pMDR->pbMDData = new UCHAR[dwRequiredSize];
  2565. if ( !(pMDR->pbMDData) )
  2566. {
  2567. return RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  2568. }
  2569. pMDR->dwMDDataLen = dwRequiredSize;
  2570. hRes = pMB->GetData( hHandle,
  2571. pszPath,
  2572. pMDR,
  2573. &dwRequiredSize );
  2574. if ( FAILED(hRes) )
  2575. {
  2576. //ah, sod it, can't do anymore
  2577. delete [] pMDR->pbMDData;
  2578. return hRes;
  2579. }
  2580. }
  2581. }
  2582. if ( FAILED(hRes) )
  2583. {
  2584. DBGPRINTF((DBG_CONTEXT,
  2585. "RetrieveBlobFromMB failed, 0x%x\n", HRESULTTOWIN32( hRes )));
  2586. }
  2587. return (hRes);
  2588. } //RetrieveBlobFromMetabase
  2589. OPEN_CERT_STORE_INFO* ReadCertStoreInfoFromMB( IN IMSAdminBase *pMB,
  2590. IN METADATA_HANDLE hHandle,
  2591. IN LPCWSTR pszPath,
  2592. IN BOOL fCTL )
  2593. /*++
  2594. Routine Description:
  2595. Read all the information necessary to open a CAPI store out of the metabase
  2596. Arguments:
  2597. pMDObject - pointer to metabase object
  2598. hHandle - handle opened for reading
  2599. pszPath - path relative to hHandle
  2600. fCTL - bool indicating whether info is to be used to reconstruct a CTL or a cert
  2601. Returns:
  2602. Pointer to filled out OPEN_CERT_STORE_INFO structure on success, NULL on failure.
  2603. Note that only some of the OPEN_CERT_STORE_INFO fields are -required-; currently,
  2604. only the store name is required.
  2605. --*/
  2606. {
  2607. DBG_ASSERT( pMB );
  2608. DBG_ASSERT( pszPath );
  2609. BOOL fSuccess = FALSE;
  2610. OPEN_CERT_STORE_INFO *pCertStoreInfo = NULL;
  2611. pCertStoreInfo = AllocateCertStoreInfo();
  2612. if ( !pCertStoreInfo )
  2613. {
  2614. return NULL;
  2615. }
  2616. DWORD dwReqDataLen = 0;
  2617. METADATA_RECORD mdr;
  2618. //
  2619. //Try to retrieve container
  2620. //
  2621. MD_SET_DATA_RECORD(&mdr,
  2622. (fCTL ? MD_SSL_CTL_CONTAINER : MD_SSL_CERT_CONTAINER),
  2623. METADATA_NO_ATTRIBUTES,
  2624. IIS_MD_UT_SERVER, STRING_METADATA,
  2625. NULL,
  2626. 0);
  2627. if ( !FAILED( RetrieveBlobFromMetabase(pMB,
  2628. hHandle,
  2629. pszPath,
  2630. &mdr) ) )
  2631. {
  2632. //
  2633. // Metabase will return empty string if NULL string is stored
  2634. //
  2635. if ( !wcscmp( (LPWSTR) mdr.pbMDData, TEXT("")) )
  2636. {
  2637. delete [] mdr.pbMDData;
  2638. pCertStoreInfo->pszContainer = NULL;
  2639. }
  2640. else
  2641. {
  2642. pCertStoreInfo->pszContainer = (LPWSTR) mdr.pbMDData;
  2643. }
  2644. }
  2645. //
  2646. //Try to retrieve cert provider
  2647. //
  2648. MD_SET_DATA_RECORD(&mdr,
  2649. (fCTL ? MD_SSL_CTL_PROVIDER : MD_SSL_CERT_PROVIDER),
  2650. METADATA_NO_ATTRIBUTES,
  2651. IIS_MD_UT_SERVER, STRING_METADATA,
  2652. NULL,
  2653. 0);
  2654. if ( !FAILED( RetrieveBlobFromMetabase(pMB,
  2655. hHandle,
  2656. pszPath,
  2657. &mdr) ) )
  2658. {
  2659. //
  2660. // Metabase will return empty string if NULL string is stored
  2661. //
  2662. if ( !wcscmp( (LPWSTR) mdr.pbMDData, TEXT("")) )
  2663. {
  2664. delete [] mdr.pbMDData;
  2665. pCertStoreInfo->pszProvider = NULL;
  2666. }
  2667. else
  2668. {
  2669. pCertStoreInfo->pszProvider = (LPWSTR) mdr.pbMDData;
  2670. }
  2671. }
  2672. //
  2673. //Try to retrieve provider type
  2674. //
  2675. MD_SET_DATA_RECORD(&mdr,
  2676. (fCTL ? MD_SSL_CTL_PROVIDER_TYPE : MD_SSL_CERT_PROVIDER_TYPE),
  2677. METADATA_NO_ATTRIBUTES,
  2678. IIS_MD_UT_SERVER, DWORD_METADATA,
  2679. NULL,
  2680. 0);
  2681. if ( !FAILED( RetrieveBlobFromMetabase( pMB,
  2682. hHandle,
  2683. pszPath,
  2684. &mdr ) ) )
  2685. {
  2686. pCertStoreInfo->dwProvType = * ( (DWORD * ) mdr.pbMDData );
  2687. }
  2688. //
  2689. //Retrieve open flags
  2690. //
  2691. MD_SET_DATA_RECORD( &mdr,
  2692. (fCTL ? MD_SSL_CTL_OPEN_FLAGS : MD_SSL_CERT_OPEN_FLAGS),
  2693. METADATA_NO_ATTRIBUTES,
  2694. IIS_MD_UT_SERVER, DWORD_METADATA,
  2695. NULL,
  2696. 0 );
  2697. if ( !FAILED( RetrieveBlobFromMetabase( pMB,
  2698. hHandle,
  2699. pszPath,
  2700. &mdr ) ) )
  2701. {
  2702. pCertStoreInfo->dwFlags = * ( (DWORD * ) mdr.pbMDData );
  2703. }
  2704. //
  2705. //Try to retrieve store name
  2706. //
  2707. MD_SET_DATA_RECORD(&mdr,
  2708. (fCTL ? MD_SSL_CTL_STORE_NAME : MD_SSL_CERT_STORE_NAME),
  2709. METADATA_NO_ATTRIBUTES,
  2710. IIS_MD_UT_SERVER, STRING_METADATA,
  2711. NULL,
  2712. 0);
  2713. if ( FAILED( RetrieveBlobFromMetabase( pMB,
  2714. hHandle,
  2715. pszPath,
  2716. &mdr ) ) )
  2717. {
  2718. goto EndReadStoreInfo;
  2719. }
  2720. else
  2721. {
  2722. //
  2723. // Metabase will return empty string if NULL string is stored, but
  2724. // empty name is -NOT- valid !
  2725. //
  2726. if ( !wcscmp( (LPWSTR) mdr.pbMDData, TEXT("")) )
  2727. {
  2728. delete [] mdr.pbMDData;
  2729. goto EndReadStoreInfo;
  2730. }
  2731. else
  2732. {
  2733. pCertStoreInfo->pszStoreName = (LPWSTR) mdr.pbMDData;
  2734. }
  2735. }
  2736. //
  2737. // Everything succeeded
  2738. //
  2739. fSuccess = TRUE;
  2740. EndReadStoreInfo:
  2741. if ( !fSuccess )
  2742. {
  2743. DeallocateCertStoreInfo( pCertStoreInfo );
  2744. pCertStoreInfo = NULL;
  2745. }
  2746. return ( pCertStoreInfo );
  2747. }
  2748. HRESULT RegenerateSessionKey( IMSAdminBase *pMB,
  2749. OUT HCRYPTKEY *phKey )
  2750. /*++
  2751. Routine Description:
  2752. Generate a session key to encrypt/decrypt replication information
  2753. Arguments:
  2754. pMB - pointer to metabase object
  2755. phKey - pointer to key, filled in on success
  2756. Returns:
  2757. HRESULT indicating success/failure
  2758. --*/
  2759. {
  2760. #ifdef NO_ENCRYPTION
  2761. return S_OK;
  2762. #else
  2763. HCRYPTPROV hProv = NULL;
  2764. HRESULT hRes = S_OK;
  2765. BYTE *pbHash = NULL;
  2766. DWORD cbHashSize = 0;
  2767. HCRYPTHASH hHash = NULL;
  2768. BOOL fOk = TRUE;
  2769. METADATA_HANDLE hMDHandle;
  2770. ALG_ID aiAlg = 0;
  2771. BYTE *pbSeed = NULL;
  2772. DWORD cbSeed = 0;
  2773. DWORD cbRandomSize = 0;
  2774. BYTE *pbRandom = NULL;
  2775. BYTE bMajor = 0;
  2776. BYTE bMinor = 0;
  2777. DWORD i = 0;
  2778. //
  2779. // Retrieve the key seed
  2780. //
  2781. if ( FAILED( hRes = ReadSessionKeySeed( pMB,
  2782. &pbSeed,
  2783. &cbSeed ) ) ||
  2784. !cbSeed ||
  2785. cbSeed < SEED_HEADER_SIZE + 1 ) //total length must be greater than header
  2786. {
  2787. hRes = S_FALSE;
  2788. goto regenerate_exit;
  2789. }
  2790. bMajor = pbSeed[i++];
  2791. bMinor = pbSeed[i++];
  2792. memcpy( &aiAlg, pbSeed + i, sizeof(ALG_ID) );
  2793. i += sizeof(ALG_ID);
  2794. cbRandomSize = (DWORD) pbSeed[i++];
  2795. pbRandom = pbSeed + i;
  2796. DBG_ASSERT( i == SEED_HEADER_SIZE );
  2797. //
  2798. // Make sure encoded size of random seed is same as the random seed we're actually going
  2799. // to use, and non-zero
  2800. if ( cbRandomSize <= 0 ||
  2801. cbRandomSize != (cbSeed - SEED_HEADER_SIZE) )
  2802. {
  2803. hRes = S_FALSE;
  2804. goto regenerate_exit;
  2805. }
  2806. //
  2807. // clear out any old session keys
  2808. //
  2809. CryptAcquireContext( &hProv,
  2810. REPLICATION_SESSION_KEY_CONTAINER,
  2811. NULL,
  2812. PROV_RSA_FULL,
  2813. CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET );
  2814. if ( fOk = CryptAcquireContext( &hProv,
  2815. REPLICATION_SESSION_KEY_CONTAINER,
  2816. NULL,
  2817. PROV_RSA_FULL,
  2818. CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET ) )
  2819. {
  2820. if ( SUCCEEDED( hRes = GenerateHash( &hProv,
  2821. aiAlg,
  2822. pbRandom,
  2823. cbRandomSize,
  2824. &pbHash,
  2825. &cbHashSize,
  2826. &hHash ) ) )
  2827. {
  2828. fOk = CryptDeriveKey( hProv,
  2829. CALG_RC4,
  2830. hHash,
  2831. 0,
  2832. phKey );
  2833. }
  2834. }
  2835. if ( SUCCEEDED(hRes) && !fOk )
  2836. {
  2837. hRes = (GetLastError() != ERROR_SUCCESS) ?
  2838. RETURNCODETOHRESULT( GetLastError() ) : E_FAIL;
  2839. }
  2840. #if 0
  2841. //
  2842. // Releasing the hProv will invalidate the key
  2843. //
  2844. if ( hProv )
  2845. {
  2846. CryptReleaseContext( hProv,
  2847. 0 );
  2848. }
  2849. #endif
  2850. regenerate_exit:
  2851. if ( hHash )
  2852. {
  2853. CryptDestroyHash( hHash );
  2854. }
  2855. //
  2856. // Clean out seed used to derive key
  2857. //
  2858. if ( pbSeed )
  2859. {
  2860. memset( pbSeed, 0, cbSeed );
  2861. delete [] pbSeed;
  2862. }
  2863. //
  2864. // Hash buffer contains hash of seed used to derive key, so zero it out as well
  2865. //
  2866. if ( pbHash )
  2867. {
  2868. memset( pbHash, 0, cbHashSize );
  2869. delete [] pbHash;
  2870. }
  2871. return hRes;
  2872. #endif // NO_ENCRYPTION
  2873. }
  2874. VOID DeleteSessionKey( IN HCRYPTKEY *phKey )
  2875. {
  2876. #ifndef NO_ENCRYPTION
  2877. DeleteKey( phKey,
  2878. REPLICATION_SESSION_KEY_CONTAINER );
  2879. #endif
  2880. }
  2881. VOID DeleteKey( IN HCRYPTKEY *phKey,
  2882. IN LPCWSTR pszContainer )
  2883. /*++
  2884. Routine Description:
  2885. Delete a key
  2886. Arguments:
  2887. phKey - pointer to key to delete
  2888. pszContainer - name of key container
  2889. Returns:
  2890. Nothing
  2891. --*/
  2892. {
  2893. //
  2894. // delete the key container
  2895. //
  2896. HCRYPTPROV hProv;
  2897. CryptAcquireContext( &hProv,
  2898. pszContainer,
  2899. NULL,
  2900. PROV_RSA_FULL,
  2901. CRYPT_DELETE_KEYSET | CRYPT_MACHINE_KEYSET );
  2902. //
  2903. // delete the actual key
  2904. //
  2905. if ( phKey )
  2906. {
  2907. CryptDestroyKey( *phKey );
  2908. *phKey = NULL;
  2909. }
  2910. }
  2911. HRESULT ReadSessionKeySeed( IN IMSAdminBase *pMB,
  2912. OUT BYTE **ppbSeed,
  2913. OUT DWORD *pcbSeed )
  2914. /*++
  2915. Routine Description:
  2916. Reads session key seed information out of metabase
  2917. Arguments:
  2918. pMB - pointer to metabase interface to use
  2919. ppbSeed - pointer to pointer to buffer updated with session key seed
  2920. pcbSeed - pointer to DWORD holding size of seed
  2921. Returns:
  2922. HRESULT status
  2923. --*/
  2924. {
  2925. HRESULT hRes = S_OK;
  2926. METADATA_HANDLE hMDHandle;
  2927. *pcbSeed = 0;
  2928. if ( FAILED( hRes = pMB->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  2929. MB_ROOT_PATH,
  2930. METADATA_PERMISSION_READ,
  2931. TIMEOUT_VALUE,
  2932. &hMDHandle ) ) )
  2933. {
  2934. return hRes;
  2935. }
  2936. //
  2937. // Figure out the size of the seed
  2938. //
  2939. METADATA_RECORD mdr;
  2940. MD_SET_DATA_RECORD( &mdr,
  2941. MD_SSL_REPLICATION_INFO,
  2942. METADATA_SECURE,
  2943. IIS_MD_UT_SERVER,
  2944. BINARY_METADATA,
  2945. 0,
  2946. NULL );
  2947. hRes = pMB->GetData( hMDHandle,
  2948. MB_REPLICATION_PATH,
  2949. &mdr,
  2950. pcbSeed );
  2951. if ( HRESULTTOWIN32( hRes ) != ERROR_INSUFFICIENT_BUFFER )
  2952. {
  2953. return hRes;
  2954. }
  2955. //
  2956. // We know the size, allocate some memory
  2957. //
  2958. DBG_ASSERT( *pcbSeed );
  2959. *ppbSeed = NULL;
  2960. *ppbSeed = new BYTE[*pcbSeed];
  2961. if ( !(*ppbSeed) )
  2962. {
  2963. return RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  2964. }
  2965. //
  2966. // Get the random seed out of the metabase
  2967. //
  2968. MD_SET_DATA_RECORD( &mdr,
  2969. MD_SSL_REPLICATION_INFO,
  2970. METADATA_SECURE,
  2971. IIS_MD_UT_SERVER,
  2972. BINARY_METADATA,
  2973. *pcbSeed,
  2974. *ppbSeed );
  2975. hRes = pMB->GetData( hMDHandle,
  2976. MB_REPLICATION_PATH,
  2977. &mdr,
  2978. pcbSeed );
  2979. //
  2980. // cleanup
  2981. //
  2982. pMB->CloseKey( hMDHandle );
  2983. return hRes;
  2984. }
  2985. HRESULT DeleteMBSessionKeyInfo ( IN IMSAdminBase *pMB )
  2986. /*++
  2987. Routine Description:
  2988. Delete the metabase information used to derive a session key
  2989. Arguments:
  2990. None
  2991. Returns:
  2992. HRESULT status
  2993. --*/
  2994. {
  2995. #ifdef NO_ENCRYPTION
  2996. return S_OK;
  2997. #else
  2998. METADATA_HANDLE hMDHandle;
  2999. HRESULT hRes = S_OK;
  3000. if ( FAILED( hRes = pMB->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  3001. MB_ROOT_PATH,
  3002. METADATA_PERMISSION_WRITE,
  3003. TIMEOUT_VALUE,
  3004. &hMDHandle ) ) )
  3005. {
  3006. return hRes;
  3007. }
  3008. hRes = pMB->DeleteKey( hMDHandle,
  3009. MB_REPLICATION_PATH );
  3010. pMB->CloseKey( hMDHandle );
  3011. return hRes;
  3012. #endif //NO_ENCRYPTION
  3013. }
  3014. HRESULT ExportAndSerializeServerPK( IN PCCERT_CONTEXT pcCert,
  3015. IN OUT BYTE **ppbChainBuffer,
  3016. IN OUT DWORD *pdwBufferSize,
  3017. IN OUT DWORD *pdwPosition )
  3018. /*++
  3019. Routine Description:
  3020. Export and serialize a private key for a server certificate. Format of serialized buffer :
  3021. <MSB of private key length><LSB of private key length><private key><key container info>
  3022. Arguments:
  3023. pcCert - certificate whose private key is to be exported
  3024. ppbChainBuffer - pointer to pointer to buffer that is to hold serialized key
  3025. pdwBufferSize - size of buffer pointed to by *ppbChainBuffer
  3026. pdwPosition - position in buffer
  3027. Returns:
  3028. HRESULT indicating success/failure
  3029. --*/
  3030. {
  3031. HCRYPTKEY hKey = NULL;
  3032. HCRYPTPROV hProv = NULL;
  3033. DWORD cbSpaceLeft = 0;
  3034. DWORD cbPrivateKey = 0;
  3035. DWORD cbPKInfo = 0;
  3036. DWORD cbSpaceRequired = 0;
  3037. HRESULT hRes = S_OK;
  3038. //
  3039. // Figure out how much space we need for the private key blob; bit of a lengthy
  3040. // procedure - first get the arguments needed to get a handle to the key container,
  3041. // get a handle to the key container, get a handle to the exchange key in the key
  3042. // container and finally figure out the key size.
  3043. //
  3044. CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL;
  3045. DWORD dwProvSize = 0;
  3046. BYTE *pbPKInfo = NULL;
  3047. //
  3048. // Determine how much space we need
  3049. //
  3050. if ( !CertGetCertificateContextProperty( pcCert,
  3051. CERT_KEY_PROV_INFO_PROP_ID,
  3052. NULL,
  3053. &dwProvSize ) &&
  3054. GetLastError() != ERROR_MORE_DATA )
  3055. {
  3056. hRes = RETURNCODETOHRESULT( GetLastError() );
  3057. goto EndSerializePK;
  3058. }
  3059. pbPKInfo = new BYTE[dwProvSize];
  3060. if ( !pbPKInfo )
  3061. {
  3062. hRes = RETURNCODETOHRESULT( GetLastError() );
  3063. goto EndSerializePK;
  3064. }
  3065. pKeyProvInfo = ( CRYPT_KEY_PROV_INFO *) pbPKInfo;
  3066. //
  3067. // Get the private key info
  3068. //
  3069. if ( !CertGetCertificateContextProperty( pcCert,
  3070. CERT_KEY_PROV_INFO_PROP_ID,
  3071. pKeyProvInfo,
  3072. &dwProvSize ) )
  3073. {
  3074. DBGPRINTF((DBG_CONTEXT,
  3075. "Error getting key info : 0x%x\n", GetLastError() ) );
  3076. hRes = RETURNCODETOHRESULT( GetLastError() );
  3077. goto EndSerializePK;
  3078. }
  3079. if ( !CryptAcquireContext( &hProv,
  3080. pKeyProvInfo->pwszContainerName,
  3081. pKeyProvInfo->pwszProvName,
  3082. pKeyProvInfo->dwProvType,
  3083. pKeyProvInfo->dwFlags ) )
  3084. {
  3085. DBGPRINTF((DBG_CONTEXT,
  3086. "Error getting handle to CSP : 0x%x\n", GetLastError() ) );
  3087. hRes = RETURNCODETOHRESULT( GetLastError() );
  3088. goto EndSerializePK;
  3089. }
  3090. if ( !CryptGetUserKey( hProv,
  3091. pKeyProvInfo->dwKeySpec,
  3092. &hKey ) )
  3093. {
  3094. DBGPRINTF((DBG_CONTEXT,
  3095. "Error getting user key : 0x%x\n", GetLastError() ) );
  3096. hRes = RETURNCODETOHRESULT( GetLastError() );
  3097. goto EndSerializePK;
  3098. }
  3099. if ( !CryptExportKey( hKey,
  3100. NULL, //BUGBUGBUG - this needs to be a real session key !
  3101. PRIVATEKEYBLOB,
  3102. 0,
  3103. NULL,
  3104. &cbPrivateKey ) &&
  3105. GetLastError() != ERROR_MORE_DATA )
  3106. {
  3107. DBGPRINTF((DBG_CONTEXT,
  3108. "Error exporting key : 0x%x\n", GetLastError() ) );
  3109. hRes = RETURNCODETOHRESULT( GetLastError() );
  3110. goto EndSerializePK;
  3111. }
  3112. cbPKInfo = SizeOfCKPI( pKeyProvInfo );
  3113. cbSpaceRequired = cbPrivateKey + 2 + //private key + bytes indicating length of key
  3114. cbPKInfo + 2 ; //private key container info + bytes indicating length
  3115. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  3116. if ( cbSpaceLeft < cbSpaceRequired && !ResizeBuffer( ppbChainBuffer,
  3117. cbSpaceRequired,
  3118. pdwPosition ) )
  3119. {
  3120. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  3121. goto EndSerializePK;
  3122. }
  3123. //
  3124. // Append the length of the private key blob
  3125. //
  3126. (*ppbChainBuffer)[(*pdwPosition)++] = MSB(cbPrivateKey);
  3127. (*ppbChainBuffer)[(*pdwPosition)++] = LSB(cbPrivateKey);
  3128. //
  3129. // Add the private key
  3130. //
  3131. cbSpaceLeft = *pdwBufferSize - *pdwPosition;
  3132. if ( !CryptExportKey( hKey,
  3133. NULL, //BUGBUG - this should be a real session key !
  3134. PRIVATEKEYBLOB,
  3135. 0,
  3136. *ppbChainBuffer + *pdwPosition,
  3137. &cbSpaceLeft ) )
  3138. {
  3139. DBGPRINTF((DBG_CONTEXT,
  3140. "Error exporting key : 0x%x\n", GetLastError() ) );
  3141. hRes = RETURNCODETOHRESULT( GetLastError() );
  3142. goto EndSerializePK;
  3143. }
  3144. (*pdwPosition) += cbSpaceLeft;
  3145. //
  3146. // Length of serialized CRYPT_KEY_PROV_INFO structure
  3147. //
  3148. (*ppbChainBuffer)[(*pdwPosition)++] = MSB(cbPKInfo);
  3149. (*ppbChainBuffer)[(*pdwPosition)++] = LSB(cbPKInfo);
  3150. //
  3151. // Add CRYPT_KEY_PROV_INFO structure
  3152. //
  3153. SerializeCKPI( *ppbChainBuffer + *pdwPosition,
  3154. pKeyProvInfo,
  3155. pdwPosition );
  3156. EndSerializePK:
  3157. //
  3158. //Cleanup
  3159. //
  3160. if ( hKey )
  3161. {
  3162. CryptDestroyKey( hKey );
  3163. }
  3164. if ( hProv )
  3165. {
  3166. CryptReleaseContext( hProv,
  3167. 0 );
  3168. }
  3169. if ( pbPKInfo )
  3170. {
  3171. delete [] pbPKInfo;
  3172. }
  3173. return hRes;
  3174. }
  3175. HRESULT DeserializeAndImportServerPK( IN OUT BYTE **ppbBuffer,
  3176. IN BYTE *pbEnd,
  3177. OUT HCRYPTKEY *phKey,
  3178. OUT CRYPT_KEY_PROV_INFO *pCKPI )
  3179. /*++
  3180. Routine Description:
  3181. Deserialize and import the private key for a server certificate.
  3182. Arguments:
  3183. ppbBuffer - pointer to pointer to buffer containing serialized private key; updated on success
  3184. pbEnd - pointer to end of buffer, to avoid overruns
  3185. phKey - pointer to key handle, updated on success
  3186. pCKPI - pointer to CRYPT_KEY_PROV_INFO structure, updated on success
  3187. Returns:
  3188. HRESULT indicating success/failure
  3189. --*/
  3190. {
  3191. HRESULT hRes = S_OK;
  3192. BYTE *pbPresent = *ppbBuffer;
  3193. BYTE bMSB = 0;
  3194. BYTE bLSB = 0;
  3195. DWORD cbPrivateKey = 0;
  3196. DWORD cbPKInfo = 0;
  3197. BYTE *pbPrivateKey = NULL;
  3198. HCRYPTPROV hProv = NULL;
  3199. //
  3200. // figure out length of private key
  3201. //
  3202. if ( pbEnd <= pbPresent + 2 ) //two byte header indicating length of private key
  3203. {
  3204. return REPL_INTERNAL_ERROR;
  3205. }
  3206. bMSB = *(pbPresent++);
  3207. bLSB = *(pbPresent++);
  3208. cbPrivateKey = (DWORD) ( ( bMSB << 8 ) + bLSB );
  3209. if ( cbPrivateKey <= 0 || pbEnd <= pbPresent + cbPrivateKey )
  3210. {
  3211. return REPL_INTERNAL_ERROR;
  3212. }
  3213. pbPrivateKey = pbPresent;
  3214. pbPresent += cbPrivateKey;
  3215. //
  3216. // extract private key container info
  3217. //
  3218. bMSB = *(pbPresent++);
  3219. bLSB = *(pbPresent++);
  3220. cbPKInfo = (DWORD) ( ( bMSB << 8 ) + bLSB );
  3221. if ( cbPKInfo <= 0 || pbEnd <= pbPresent + cbPKInfo )
  3222. {
  3223. return REPL_INTERNAL_ERROR;
  3224. }
  3225. if ( !DeserializeCKPI( &pbPresent,
  3226. pCKPI ) )
  3227. {
  3228. return RETURNCODETOHRESULT( GetLastError() );
  3229. }
  3230. //
  3231. // clean out old key container
  3232. //
  3233. CryptAcquireContext( &hProv,
  3234. pCKPI->pwszContainerName,
  3235. pCKPI->pwszProvName,
  3236. pCKPI->dwProvType,
  3237. pCKPI->dwFlags | CRYPT_DELETEKEYSET );
  3238. //
  3239. // import private key
  3240. //
  3241. if ( CryptAcquireContext( &hProv,
  3242. pCKPI->pwszContainerName,
  3243. pCKPI->pwszProvName,
  3244. pCKPI->dwProvType,
  3245. pCKPI->dwFlags | CRYPT_NEWKEYSET ) )
  3246. {
  3247. if ( !CryptImportKey( hProv,
  3248. pbPrivateKey,
  3249. cbPrivateKey,
  3250. NULL,
  3251. CRYPT_EXPORTABLE,
  3252. phKey ) )
  3253. {
  3254. DBGPRINTF((DBG_CONTEXT,
  3255. "Error : 0x%x\n", GetLastError()));
  3256. hRes = RETURNCODETOHRESULT( GetLastError() );
  3257. }
  3258. else
  3259. {
  3260. //
  3261. // Set the ACL on the private key
  3262. //
  3263. if ( !SetLocalSystemSecurityOnKeyContainer( hProv ) )
  3264. {
  3265. DBGPRINTF((DBG_CONTEXT,
  3266. "Error : 0x%x\n", GetLastError()));
  3267. hRes = RETURNCODETOHRESULT( GetLastError() );
  3268. }
  3269. }
  3270. }
  3271. else
  3272. {
  3273. DBGPRINTF((DBG_CONTEXT,
  3274. "Error : 0x%x\n", GetLastError()));
  3275. hRes = RETURNCODETOHRESULT( GetLastError() );
  3276. }
  3277. //
  3278. // Update
  3279. //
  3280. *ppbBuffer = pbPresent;
  3281. return hRes;
  3282. }
  3283. HRESULT EncryptBuffer( IN HCRYPTKEY hKey,
  3284. IN OUT PBYTE *ppbReplicationInfo,
  3285. IN OUT DWORD *pdwBufferSize,
  3286. IN OUT DWORD *pdwPosition )
  3287. /*++
  3288. Routine Description:
  3289. Encrypt the replication information
  3290. Arguments:
  3291. hKey - handle to key used to encrypt the data
  3292. ppbReplicationInfo - pointer to pointer to buffer that holds data to be encrypted
  3293. pdwBufferSize - pointer to present buffer size
  3294. pdwPosition - pointer to position in buffer
  3295. Returns:
  3296. HRESULT indicating success/failure
  3297. --*/
  3298. {
  3299. #ifdef NO_ENCRYPTION
  3300. return S_OK;
  3301. #else
  3302. DWORD cbOut = *pdwPosition;
  3303. HRESULT hRes = S_OK;
  3304. //
  3305. // Figure out the size of the buffer we need
  3306. //
  3307. CryptEncrypt( hKey,
  3308. NULL,
  3309. TRUE,
  3310. 0,
  3311. NULL,
  3312. &cbOut,
  3313. 0 );
  3314. if ( *pdwBufferSize > cbOut ||
  3315. ResizeBuffer( ppbReplicationInfo, cbOut, pdwBufferSize ) )
  3316. {
  3317. cbOut = *pdwPosition;
  3318. if ( !CryptEncrypt( hKey,
  3319. NULL,
  3320. TRUE,
  3321. 0,
  3322. *ppbReplicationInfo, //encryption is in-place
  3323. &cbOut,
  3324. *pdwPosition ) )
  3325. {
  3326. hRes = RETURNCODETOHRESULT( GetLastError() );
  3327. }
  3328. else
  3329. {
  3330. *pdwPosition = cbOut;
  3331. }
  3332. }
  3333. else
  3334. {
  3335. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  3336. }
  3337. return hRes;
  3338. #endif // NO_ENCRYPTION
  3339. }
  3340. HRESULT DecryptBuffer( IN HCRYPTKEY hKey,
  3341. IN PBYTE pbEncrypted,
  3342. IN DWORD cbEncrypted,
  3343. OUT BYTE **ppbDecrypted,
  3344. OUT BYTE **ppbEndDecrypted )
  3345. /*++
  3346. Routine Description:
  3347. Encrypt the replication information
  3348. Arguments:
  3349. hKey - handle to key to be used to decrypt the data
  3350. pbEncrypted - buffer holding encrypted data
  3351. cbEncrypted - size of buffer pointed to by pbEncrypted
  3352. ppbDecrypted - pointer to pointer to buffer to hold decrypted data. Allocated by
  3353. this function, caller has to clean it up by calling delete []
  3354. ppbEndDecrypted - pointer to pointer to end of ppbDecrypted
  3355. Returns:
  3356. HRESULT indicating success/failure
  3357. --*/
  3358. {
  3359. #ifdef NO_ENCRYPTION
  3360. *ppbDecrypted = new BYTE[cbEncrypted];
  3361. memcpy( *ppbDecrypted, pbEncrypted, cbEncrypted );
  3362. *ppbEndDecrypted = (*ppbDecrypted) + cbEncrypted;
  3363. return S_OK;
  3364. #else
  3365. HRESULT hRes = S_OK;
  3366. *ppbDecrypted = NULL;
  3367. DWORD cbDecrypted = 0;
  3368. //
  3369. // Decryption is done in-place, so make a copy of the encrypted buffer
  3370. //
  3371. *ppbDecrypted = new BYTE[cbEncrypted];
  3372. if ( !*ppbDecrypted )
  3373. {
  3374. return ( RETURNCODETOHRESULT( ERROR_OUTOFMEMORY ) );
  3375. }
  3376. memcpy( *ppbDecrypted, pbEncrypted, cbEncrypted );
  3377. cbDecrypted = cbEncrypted;
  3378. //
  3379. // Decrypt the data
  3380. //
  3381. if ( !CryptDecrypt( hKey,
  3382. NULL,
  3383. TRUE,
  3384. 0,
  3385. *ppbDecrypted,
  3386. &cbDecrypted ) )
  3387. {
  3388. memset( *ppbDecrypted, 0, cbEncrypted );
  3389. delete [] *ppbDecrypted;
  3390. return (GetLastError() != ERROR_SUCCESS) ?
  3391. RETURNCODETOHRESULT( GetLastError() ) : E_FAIL;
  3392. }
  3393. else
  3394. {
  3395. *ppbEndDecrypted = *ppbDecrypted + cbDecrypted;
  3396. }
  3397. return hRes;
  3398. #endif //NO_ENCRYPTION
  3399. }
  3400. OPEN_CERT_STORE_INFO* AllocateCertStoreInfo()
  3401. /*++
  3402. Routine Description:
  3403. Allocate and initialize the structure used to hold info about cert stores
  3404. Arguments:
  3405. None
  3406. Returns:
  3407. Allocated and initialized structure that should be cleaned up with a call to
  3408. DeallocateCertStoreInfo()
  3409. --*/
  3410. {
  3411. OPEN_CERT_STORE_INFO *pStoreInfo = new OPEN_CERT_STORE_INFO;
  3412. if ( pStoreInfo )
  3413. {
  3414. memset(pStoreInfo, 0, sizeof(OPEN_CERT_STORE_INFO));
  3415. }
  3416. return pStoreInfo;
  3417. }
  3418. VOID DeallocateCertStoreInfo( OPEN_CERT_STORE_INFO *pInfo )
  3419. /*++
  3420. Routine Description:
  3421. Clean up the structure used to track information about a cert store
  3422. Arguments:
  3423. pInfo - pointer to OPEN_CERT_STORE_INFO structure to be cleaned up
  3424. Returns:
  3425. Nothing
  3426. --*/
  3427. {
  3428. if ( !pInfo )
  3429. {
  3430. return ;
  3431. }
  3432. if ( pInfo->pszContainer )
  3433. {
  3434. delete [] pInfo->pszContainer;
  3435. pInfo->pszContainer = NULL;
  3436. }
  3437. if ( pInfo->pszProvider )
  3438. {
  3439. delete [] pInfo->pszProvider;
  3440. pInfo->pszProvider = NULL;
  3441. }
  3442. if ( pInfo->pszStoreName )
  3443. {
  3444. delete [] pInfo->pszStoreName;
  3445. pInfo->pszStoreName = NULL;
  3446. }
  3447. if ( pInfo->hCertStore )
  3448. {
  3449. CertCloseStore( pInfo->hCertStore,
  3450. 0 );
  3451. pInfo->hCertStore = NULL;
  3452. }
  3453. delete pInfo;
  3454. }
  3455. LPWSTR mystrdup(LPWSTR pszIn IN)
  3456. /*++
  3457. Routine Description:
  3458. Makes a copy of string passed in using new[]
  3459. Arguments:
  3460. pszIn - string to be copied
  3461. Returns:
  3462. Pointer to copy of string on success, NULL on failure
  3463. --*/
  3464. {
  3465. DBG_ASSERT( pszIn );
  3466. LPWSTR pszOut = new WCHAR[ (wcslen(pszIn) + 1 ) * sizeof(WCHAR)];
  3467. if ( !pszOut )
  3468. {
  3469. return NULL;
  3470. }
  3471. memcpy( pszOut, pszIn, ( wcslen(pszIn) + 1 ) * sizeof( WCHAR ) );
  3472. return ( pszOut );
  3473. } //mystrdup
  3474. BOOL MBPathHasCAPIInfo( IN IMSAdminBase *pMB,
  3475. METADATA_HANDLE hHandle,
  3476. IN LPCWSTR pszPath,
  3477. IN DWORD *adwProperties,
  3478. IN DWORD cProperties )
  3479. /*++
  3480. Routine Description:
  3481. Checks whether the given MB path has info associated with it necessary to
  3482. reconstruct a particular CAPI structure eg certificate context, CTL context
  3483. Arguments:
  3484. pMB - pointer to metabase object
  3485. hHandle - handle open for reading
  3486. pszPath - path to where CAPI info would be stored, relative to hHandle
  3487. adwProperties - array of metabase properties that must exist and be readable for the
  3488. given CAPI object
  3489. cProperties - number of elements in pdwProperties array [ = 2 * # of properties]
  3490. Returns:
  3491. TRUE if cert info exists, FALSE if not
  3492. --*/
  3493. {
  3494. DBG_ASSERT( pMB );
  3495. DBG_ASSERT( pszPath );
  3496. BOOL fAllData = TRUE;
  3497. HRESULT hRes;
  3498. //
  3499. // Iterate through each property, trying to retrieve it with a buffer size of zero;
  3500. // If retrieving a property fails for any reason other than a buffer that's too
  3501. // small, assume the property doesn't exist
  3502. //
  3503. for (DWORD i = 0; i < cProperties/2; i++)
  3504. {
  3505. DWORD dwSize = 0;
  3506. METADATA_RECORD mdr;
  3507. MD_SET_DATA_RECORD( &mdr,
  3508. adwProperties[2 * i],
  3509. METADATA_NO_ATTRIBUTES,
  3510. IIS_MD_UT_SERVER,
  3511. adwProperties[2*i + 1],
  3512. NULL,
  3513. 0 );
  3514. hRes = pMB->GetData( hHandle,
  3515. pszPath,
  3516. &mdr,
  3517. &dwSize );
  3518. if ( HRESULTTOWIN32(hRes) != ERROR_INSUFFICIENT_BUFFER )
  3519. {
  3520. fAllData = FALSE;
  3521. break;
  3522. }
  3523. }
  3524. return fAllData;
  3525. }
  3526. HRESULT GenerateHash( IN OPTIONAL HCRYPTPROV *phProv,
  3527. IN ALG_ID aiAlg,
  3528. IN PBYTE pbData,
  3529. IN DWORD cbData,
  3530. OUT BYTE **ppbHashBuffer,
  3531. OUT DWORD *pcbHash,
  3532. OUT OPTIONAL HCRYPTHASH *phHash )
  3533. /*++
  3534. Routine Description:
  3535. Generates a hash of input data
  3536. Arguments:
  3537. phProv - pointer to provider to be used; can be set to NULL
  3538. aiAlg - hash algorithm to use
  3539. pbData - buffer of data to be hashed
  3540. cbData - size of data to be hashed
  3541. ppbHashBuffer - pointer to pointer to buffer that receives the actual hash
  3542. pcbHash - pointer to size of *ppbHashBuffer
  3543. phHash - pointer to CRYPTHASH object, updated on sucess, ignored if NULL
  3544. Returns:
  3545. HRESULT indicating success/failure
  3546. --*/
  3547. {
  3548. HCRYPTPROV hProv = NULL;
  3549. HCRYPTHASH hHash = NULL;
  3550. HRESULT hRes = S_OK;
  3551. DWORD cbSize = 0;
  3552. if ( !phProv )
  3553. {
  3554. //
  3555. // Get a handle to the CSP that will create the
  3556. // hash
  3557. if ( !CryptAcquireContext( &hProv,
  3558. NULL,
  3559. NULL,
  3560. PROV_RSA_FULL,
  3561. CRYPT_VERIFYCONTEXT ) )
  3562. {
  3563. hRes = RETURNCODETOHRESULT( GetLastError() );
  3564. goto EndCreateHash;
  3565. }
  3566. }
  3567. else
  3568. {
  3569. hProv = *phProv;
  3570. }
  3571. //
  3572. // Get a handle to a hash object
  3573. //
  3574. if ( !CryptCreateHash( hProv,
  3575. aiAlg,
  3576. 0,
  3577. 0,
  3578. &hHash ) )
  3579. {
  3580. hRes = RETURNCODETOHRESULT( GetLastError() );
  3581. goto EndCreateHash;
  3582. }
  3583. //
  3584. // Hash the data
  3585. //
  3586. if ( !CryptHashData( hHash,
  3587. pbData,
  3588. cbData,
  3589. 0 ) )
  3590. {
  3591. hRes = RETURNCODETOHRESULT( GetLastError() );
  3592. goto EndCreateHash;
  3593. }
  3594. //
  3595. // Retrieve the size of the hash
  3596. //
  3597. cbSize = sizeof(DWORD);
  3598. if ( !CryptGetHashParam( hHash,
  3599. HP_HASHSIZE,
  3600. (BYTE *) pcbHash,
  3601. &cbSize,
  3602. 0 ) )
  3603. {
  3604. hRes = RETURNCODETOHRESULT( GetLastError() );
  3605. goto EndCreateHash;
  3606. }
  3607. DBG_ASSERT( *pcbHash > 0 );
  3608. *ppbHashBuffer = new BYTE[*pcbHash];
  3609. if ( !*ppbHashBuffer )
  3610. {
  3611. hRes = RETURNCODETOHRESULT( ERROR_OUTOFMEMORY );
  3612. goto EndCreateHash;
  3613. }
  3614. //
  3615. // Retrieve the actual hashed data
  3616. //
  3617. if ( !CryptGetHashParam( hHash,
  3618. HP_HASHVAL,
  3619. *ppbHashBuffer,
  3620. pcbHash,
  3621. 0 ) )
  3622. {
  3623. hRes = RETURNCODETOHRESULT( GetLastError() );
  3624. goto EndCreateHash;
  3625. }
  3626. if ( phHash )
  3627. {
  3628. *phHash = hHash;
  3629. }
  3630. EndCreateHash:
  3631. //
  3632. //Cleanup
  3633. //
  3634. if ( hRes != S_OK )
  3635. {
  3636. if ( *ppbHashBuffer )
  3637. {
  3638. delete [] *ppbHashBuffer;
  3639. }
  3640. }
  3641. if ( !phHash && hHash )
  3642. {
  3643. CryptDestroyHash( hHash );
  3644. }
  3645. if ( !phProv && hProv )
  3646. {
  3647. CryptReleaseContext( hProv,
  3648. 0 );
  3649. }
  3650. return hRes;
  3651. }
  3652. HRESULT GenerateMD5Hash( IN OPTIONAL HCRYPTPROV *phProv,
  3653. IN PBYTE pbData,
  3654. IN DWORD cbData,
  3655. OUT PBYTE pbHashBuffer,
  3656. IN OUT DWORD *pdwHashBufferSize,
  3657. OUT OPTIONAL HCRYPTHASH *pHashObj )
  3658. /*++
  3659. Routine Description:
  3660. Generates MD5 hash of data
  3661. Arguments:
  3662. phProv - pointer to provider to be used; can be set to NULL
  3663. pbData - buffer of data to be hashed
  3664. cbData - size of data to be hashed
  3665. pbHashBuffer - buffer to receive hash
  3666. pdwHashBufferSize - size of pbHashBuffer
  3667. pHashObj - pointer to CRYPTHASH object, updated on sucess, ignored if NULL
  3668. Returns:
  3669. HRESULT indicating success/failure
  3670. --*/
  3671. {
  3672. HCRYPTPROV hProv = NULL;
  3673. HCRYPTHASH hHash = NULL;
  3674. HRESULT hRes = S_OK;
  3675. if ( !phProv )
  3676. {
  3677. //
  3678. // Get a handle to the CSP that will create the
  3679. // hash
  3680. if ( !CryptAcquireContext( &hProv,
  3681. NULL,
  3682. NULL,
  3683. PROV_RSA_FULL,
  3684. CRYPT_VERIFYCONTEXT ) )
  3685. {
  3686. hRes = RETURNCODETOHRESULT( GetLastError() );
  3687. goto EndCreateHash;
  3688. }
  3689. }
  3690. else
  3691. {
  3692. hProv = *phProv;
  3693. }
  3694. //
  3695. // Get a handle to an MD5 hash object
  3696. //
  3697. if ( !CryptCreateHash( hProv,
  3698. CALG_MD5,
  3699. 0,
  3700. 0,
  3701. &hHash ) )
  3702. {
  3703. hRes = RETURNCODETOHRESULT( GetLastError() );
  3704. goto EndCreateHash;
  3705. }
  3706. //
  3707. // Hash the data
  3708. //
  3709. if ( !CryptHashData( hHash,
  3710. pbData,
  3711. cbData,
  3712. 0 ) )
  3713. {
  3714. hRes = RETURNCODETOHRESULT( GetLastError() );
  3715. goto EndCreateHash;
  3716. }
  3717. //
  3718. // Retrieve the hash
  3719. //
  3720. if ( !CryptGetHashParam( hHash,
  3721. HP_HASHVAL,
  3722. pbHashBuffer,
  3723. pdwHashBufferSize,
  3724. 0 ) )
  3725. {
  3726. hRes = RETURNCODETOHRESULT( GetLastError() );
  3727. goto EndCreateHash;
  3728. }
  3729. if ( pHashObj )
  3730. {
  3731. *pHashObj = hHash;
  3732. }
  3733. EndCreateHash:
  3734. //
  3735. //Cleanup
  3736. //
  3737. if ( !pHashObj && hHash )
  3738. {
  3739. CryptDestroyHash( hHash );
  3740. }
  3741. if ( !phProv && hProv )
  3742. {
  3743. CryptReleaseContext( hProv,
  3744. 0 );
  3745. }
  3746. return hRes;
  3747. }
  3748. BOOL IsNumber( LPCWSTR pszName )
  3749. {
  3750. return ( _wtoi( pszName) > 0 ? TRUE : FALSE );
  3751. }
  3752. VOID SerializeCKPI( OUT BYTE *pbBuffer,
  3753. IN CRYPT_KEY_PROV_INFO *pInfo,
  3754. OUT DWORD *pdwPosition )
  3755. /*++
  3756. Routine Description:
  3757. Serializes a CRYPT_KEY_PROV_INFO structure
  3758. Arguments:
  3759. pbBuffer - pointer to buffer that holds serialized info
  3760. pInfo - pointer to CRYPT_KEY_PROV_INFO structure to be serialized
  3761. pdwPosition - position in pbBuffer, updated after serialization
  3762. Returns:
  3763. Nothing
  3764. --*/
  3765. {
  3766. DWORD cbPos = 0;
  3767. BYTE bMSB = 0;
  3768. BYTE bLSB = 0;
  3769. DWORD cbStr = 0;
  3770. //
  3771. // First bit : [MSB of length][LSB of length][pwszContainerName]
  3772. //
  3773. if ( pInfo->pwszContainerName )
  3774. {
  3775. cbStr = wcslen( pInfo->pwszContainerName ) * sizeof(WCHAR) + 2 ; //trailing nulls
  3776. pbBuffer[cbPos++] = MSB(cbStr);
  3777. pbBuffer[cbPos++] = LSB(cbStr);
  3778. memcpy( pbBuffer + cbPos, pInfo->pwszContainerName, cbStr);
  3779. cbPos += cbStr;
  3780. }
  3781. else
  3782. {
  3783. pbBuffer[cbPos++] = 0;
  3784. pbBuffer[cbPos++] = 0;
  3785. }
  3786. //
  3787. // [MSB of length][LSB of length][pwszProvName]
  3788. //
  3789. if ( pInfo->pwszProvName )
  3790. {
  3791. cbStr = wcslen( pInfo->pwszProvName ) * sizeof(WCHAR) + 2 ; //trailing nulls
  3792. pbBuffer[cbPos++] = MSB(cbStr);
  3793. pbBuffer[cbPos++] = LSB(cbStr);
  3794. memcpy( pbBuffer + cbPos, pInfo->pwszProvName, cbStr);
  3795. cbPos += cbStr;
  3796. }
  3797. else
  3798. {
  3799. pbBuffer[cbPos++] = 0;
  3800. pbBuffer[cbPos++] = 0;
  3801. }
  3802. //
  3803. // dwProvType
  3804. //
  3805. memcpy( pbBuffer + cbPos, &(pInfo->dwProvType), sizeof(DWORD) );
  3806. cbPos += sizeof(DWORD);
  3807. //
  3808. // dwFlags
  3809. //
  3810. memcpy( pbBuffer + cbPos, &(pInfo->dwFlags), sizeof(DWORD) );
  3811. cbPos += sizeof(DWORD);
  3812. //
  3813. // cProvParam
  3814. //
  3815. memcpy( pbBuffer + cbPos, &(pInfo->cProvParam), sizeof(DWORD) );
  3816. cbPos += sizeof(DWORD);
  3817. //
  3818. // Each of the rgProvParam entries
  3819. //
  3820. for ( DWORD dwIndex = 0; dwIndex < pInfo->cProvParam; dwIndex++ )
  3821. {
  3822. CRYPT_KEY_PROV_PARAM ckpParam = pInfo->rgProvParam[dwIndex];
  3823. //
  3824. // dwParam
  3825. //
  3826. memcpy( pbBuffer + cbPos, &(ckpParam.dwParam), sizeof(DWORD) );
  3827. cbPos += sizeof(DWORD);
  3828. //
  3829. // cbData
  3830. //
  3831. memcpy( pbBuffer + cbPos, &(ckpParam.cbData), sizeof(DWORD) );
  3832. cbPos += sizeof(DWORD);
  3833. //
  3834. // pbData
  3835. //
  3836. memcpy( pbBuffer + cbPos, ckpParam.pbData, ckpParam.cbData );
  3837. cbPos += ckpParam.cbData;
  3838. //
  3839. // dwFlags
  3840. //
  3841. memcpy( pbBuffer + cbPos, &(ckpParam.dwFlags), sizeof(DWORD) );
  3842. cbPos += sizeof(DWORD);
  3843. }
  3844. //
  3845. // dwKeySpec
  3846. //
  3847. memcpy( pbBuffer + cbPos, &(pInfo->dwKeySpec), sizeof(DWORD) );
  3848. cbPos += sizeof(DWORD);
  3849. (*pdwPosition) += cbPos;
  3850. }
  3851. BOOL DeserializeCKPI( IN OUT BYTE **ppbBuffer,
  3852. OUT CRYPT_KEY_PROV_INFO *pInfo )
  3853. /*++
  3854. Routine Description:
  3855. Deserializes a CRYPT_KEY_PROV_INFO structure
  3856. Arguments:
  3857. pBuffer - pointer to pointer to buffer containing serialized information, updated while
  3858. processing occurs
  3859. ppInfo - pointer to CRYPT_KEY_PROV_INFO structure to be deserialized, updated during
  3860. processing
  3861. Returns:
  3862. TRUE if successful, FALSE if not
  3863. --*/
  3864. {
  3865. BYTE bMSB = 0;
  3866. BYTE bLSB = 0;
  3867. DWORD dwLength;
  3868. BYTE *pbPresent = *ppbBuffer;
  3869. //
  3870. // [MSB of length][LSB of length][pwszContainerName]
  3871. //
  3872. bMSB = *(pbPresent++);
  3873. bLSB = *(pbPresent++);
  3874. dwLength = LENGTH( bMSB, bLSB );
  3875. if ( dwLength )
  3876. {
  3877. pInfo->pwszContainerName = (LPWSTR) pbPresent;
  3878. pbPresent += dwLength;
  3879. }
  3880. else
  3881. {
  3882. pInfo->pwszContainerName = NULL;
  3883. }
  3884. //
  3885. // [MSB of length][LSB of length][pwszProvName]
  3886. //
  3887. bMSB = *(pbPresent++);
  3888. bLSB = *(pbPresent++);
  3889. dwLength = LENGTH( bMSB, bLSB );
  3890. if ( dwLength )
  3891. {
  3892. pInfo->pwszProvName = (LPWSTR) pbPresent;
  3893. pbPresent += dwLength;
  3894. }
  3895. else
  3896. {
  3897. pInfo->pwszProvName = NULL;
  3898. }
  3899. //
  3900. // dwProvType
  3901. //
  3902. pInfo->dwProvType = *( (DWORD *) pbPresent );
  3903. pbPresent += sizeof(DWORD);
  3904. //
  3905. // dwFlags
  3906. //
  3907. pInfo->dwFlags = *( (DWORD *) pbPresent );
  3908. pbPresent += sizeof(DWORD);
  3909. //
  3910. // cProvParam
  3911. //
  3912. pInfo->cProvParam = *( (DWORD *) pbPresent );
  3913. pbPresent += sizeof(DWORD);
  3914. //
  3915. // Each of the rgProvParam entries
  3916. //
  3917. if ( pInfo->cProvParam )
  3918. {
  3919. pInfo->rgProvParam = new CRYPT_KEY_PROV_PARAM[pInfo->cProvParam];
  3920. if ( !pInfo->rgProvParam )
  3921. {
  3922. return FALSE;
  3923. }
  3924. for ( DWORD dwIndex = 0; dwIndex < pInfo->cProvParam; dwIndex++ )
  3925. {
  3926. CRYPT_KEY_PROV_PARAM ckpParam = pInfo->rgProvParam[dwIndex];
  3927. ckpParam.dwParam = *((DWORD *) pbPresent);
  3928. pbPresent += sizeof(DWORD);
  3929. ckpParam.cbData = *((DWORD *) pbPresent);
  3930. pbPresent += sizeof(DWORD);
  3931. ckpParam.pbData = pbPresent;
  3932. pbPresent += ckpParam.cbData;
  3933. ckpParam.dwFlags = *((DWORD *) pbPresent);
  3934. pbPresent += sizeof(DWORD);
  3935. }
  3936. }
  3937. else
  3938. {
  3939. pInfo->rgProvParam = NULL;
  3940. }
  3941. //
  3942. // dwKeySpec
  3943. //
  3944. pInfo->dwKeySpec = *( (DWORD *) pbPresent);
  3945. pbPresent += sizeof(DWORD);
  3946. //
  3947. // Update
  3948. //
  3949. *ppbBuffer = pbPresent;
  3950. return TRUE;
  3951. }
  3952. DWORD SizeOfCKPI( IN CRYPT_KEY_PROV_INFO *pInfo )
  3953. /*++
  3954. Routine Description:
  3955. Calculates the amount of space needed to contain the information for
  3956. a key container
  3957. Arguments:
  3958. pInfo - pointer to CRYPT_KEY_PROV_INFO structure whose space requirements are to
  3959. be calculated
  3960. Returns:
  3961. Number of bytes required to hold CRYPT_KEY_PROV_INFO structure
  3962. --*/
  3963. {
  3964. if ( !pInfo )
  3965. {
  3966. return 0;
  3967. }
  3968. DWORD cb = 0;
  3969. if ( pInfo->pwszContainerName )
  3970. {
  3971. //trailing nulls, length bytes
  3972. cb += ( wcslen(pInfo->pwszContainerName) * sizeof(WCHAR) ) + 2 + 2;
  3973. }
  3974. else
  3975. {
  3976. cb += 2; //length bytes
  3977. }
  3978. if ( pInfo->pwszProvName )
  3979. {
  3980. //trailing nulls, length bytes
  3981. cb += ( wcslen(pInfo->pwszProvName) * sizeof(WCHAR) ) + 2 + 2;
  3982. }
  3983. else
  3984. {
  3985. cb += 2; //length bytes
  3986. }
  3987. cb += 4*sizeof(DWORD); // cProvParam, dwProvType, dwFlags, dwKeySpec
  3988. for ( DWORD dwIndex = 0 ; dwIndex < pInfo->cProvParam; dwIndex++ )
  3989. {
  3990. cb += ( pInfo->rgProvParam[dwIndex].cbData + 3 * sizeof(DWORD) );
  3991. }
  3992. return cb;
  3993. }
  3994. HRESULT DistributeCerts( IN HCERTSTORE hMemStore,
  3995. IN BYTE *rgbCertHash,
  3996. IN PCRYPT_KEY_PROV_INFO pCKPI )
  3997. /*++
  3998. Routine Description:
  3999. Takes the certs in an in-memory store and distributes them to the appropriate
  4000. system stores.
  4001. Self-signed certs go into the ROOT store, intermediate certs into the CA store and the
  4002. server cert into the MY store. It's possible that the server cert is self-signed, in
  4003. which case it goes into both the ROOT and MY stores.
  4004. Arguments:
  4005. hMemStore - handle to in-memory store containing certs to be distributed
  4006. rgbCertHash - buffer containing hash of server cert
  4007. hServerPK - private key for server certificate
  4008. Returns:
  4009. HRESULT indicating success/failure
  4010. --*/
  4011. {
  4012. HCERTSTORE hMyStore = NULL;
  4013. HCERTSTORE hCAStore = NULL;
  4014. HCERTSTORE hRootStore = NULL;
  4015. HRESULT hRes = S_OK;
  4016. //
  4017. // Open all the stores we'll use
  4018. //
  4019. hMyStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  4020. 0,
  4021. NULL,
  4022. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  4023. MY_STORE_NAME );
  4024. if ( !hMyStore )
  4025. {
  4026. return RETURNCODETOHRESULT( GetLastError() );
  4027. }
  4028. hCAStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  4029. 0,
  4030. NULL,
  4031. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  4032. CA_STORE_NAME );
  4033. if ( !hCAStore )
  4034. {
  4035. CertCloseStore( hMyStore,
  4036. 0 );
  4037. return RETURNCODETOHRESULT( GetLastError() );
  4038. }
  4039. hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W,
  4040. 0,
  4041. NULL,
  4042. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  4043. ROOT_STORE_NAME );
  4044. if ( !hRootStore )
  4045. {
  4046. CertCloseStore( hMyStore,
  4047. 0 );
  4048. CertCloseStore( hCAStore,
  4049. 0 );
  4050. return RETURNCODETOHRESULT( GetLastError() );
  4051. }
  4052. //
  4053. // Iterate through all the certs in the in-memory store, putting them into the
  4054. // appropriate place
  4055. //
  4056. PCCERT_CONTEXT pCert = NULL;
  4057. PCCERT_CONTEXT pPrevCert = NULL;
  4058. while ( pCert = CertEnumCertificatesInStore( hMemStore,
  4059. pPrevCert ) )
  4060. {
  4061. BOOL fSelfSigned = FALSE;
  4062. BOOL fServerCert = FALSE;
  4063. //
  4064. // Self-signed certs go into the Root store
  4065. //
  4066. if ( IsSelfSignedCert( pCert ) )
  4067. {
  4068. fSelfSigned = TRUE;
  4069. if ( !CertAddCertificateContextToStore( hRootStore,
  4070. pCert,
  4071. CERT_STORE_ADD_NEW,
  4072. NULL ) &&
  4073. GetLastError() != CRYPT_E_EXISTS )
  4074. {
  4075. hRes = RETURNCODETOHRESULT( GetLastError() );
  4076. break;
  4077. }
  4078. }
  4079. //
  4080. // Server cert goes into MY store
  4081. //
  4082. if ( CertMatchesHash( pCert,
  4083. rgbCertHash,
  4084. &fServerCert) )
  4085. {
  4086. if ( fServerCert )
  4087. {
  4088. //
  4089. // Add private key to cert context and stuff cert into MY store
  4090. //
  4091. if ( !CertSetCertificateContextProperty( pCert,
  4092. CERT_KEY_PROV_INFO_PROP_ID,
  4093. 0,
  4094. (PVOID) pCKPI ) ||
  4095. !CertAddCertificateContextToStore( hMyStore,
  4096. pCert,
  4097. CERT_STORE_ADD_REPLACE_EXISTING,
  4098. NULL ) )
  4099. {
  4100. hRes = RETURNCODETOHRESULT( GetLastError() );
  4101. break;
  4102. }
  4103. }
  4104. }
  4105. else
  4106. {
  4107. hRes = RETURNCODETOHRESULT( GetLastError() );
  4108. break;
  4109. }
  4110. //
  4111. // Everything else goes into the CA store
  4112. //
  4113. if ( !fSelfSigned && !fServerCert )
  4114. {
  4115. if ( !CertAddCertificateContextToStore( hCAStore,
  4116. pCert,
  4117. CERT_STORE_ADD_NEW,
  4118. NULL ) &&
  4119. GetLastError() != CRYPT_E_EXISTS )
  4120. {
  4121. hRes = RETURNCODETOHRESULT( GetLastError() );
  4122. break;
  4123. }
  4124. }
  4125. pPrevCert = pCert;
  4126. }
  4127. //
  4128. // clean up
  4129. //
  4130. if ( hMyStore )
  4131. {
  4132. CertCloseStore( hMyStore,
  4133. 0 );
  4134. }
  4135. if ( hCAStore )
  4136. {
  4137. CertCloseStore( hCAStore,
  4138. 0 );
  4139. }
  4140. if ( hRootStore )
  4141. {
  4142. CertCloseStore( hRootStore,
  4143. 0 );
  4144. }
  4145. return hRes;
  4146. }
  4147. BOOL CertMatchesHash( IN PCCERT_CONTEXT pCert,
  4148. IN BYTE *rgbHash,
  4149. OUT BOOL *pfMatch)
  4150. /*++
  4151. Routine Description:
  4152. Checks whether a cert has the same hash as the hash passed in
  4153. Arguments:
  4154. pCert - cert to be checked
  4155. rgbHash - hash pCert is to be checked against
  4156. pfMatch - bool that is set to TRUE if cert matches, FALSE if not
  4157. Returns:
  4158. TRUE if check was successful, FALSE if not
  4159. --*/
  4160. {
  4161. *pfMatch = FALSE;
  4162. BYTE rgbCertHash[SHA1_HASH_SIZE];
  4163. DWORD dwSize = SHA1_HASH_SIZE;
  4164. if ( CertGetCertificateContextProperty( pCert,
  4165. CERT_SHA1_HASH_PROP_ID,
  4166. rgbCertHash,
  4167. &dwSize ) )
  4168. {
  4169. *pfMatch = ( memcmp( rgbCertHash, rgbHash, SHA1_HASH_SIZE ) ? FALSE : TRUE );
  4170. return TRUE;
  4171. }
  4172. else
  4173. {
  4174. return FALSE;
  4175. }
  4176. }
  4177. //////////////
  4178. CADMEXCOM_IMSAdminCryptoCapabilities::CADMEXCOM_IMSAdminCryptoCapabilities(
  4179. CADMEXCOM* pAdmExCom
  4180. )
  4181. {
  4182. m_pAdmExCom = pAdmExCom;
  4183. m_hSchannel = NULL;
  4184. m_hSspi = NULL;
  4185. m_fHasCredHandle = FALSE;
  4186. }
  4187. CADMEXCOM_IMSAdminCryptoCapabilities::~CADMEXCOM_IMSAdminCryptoCapabilities( )
  4188. {
  4189. if ( m_fHasCredHandle )
  4190. {
  4191. m_pfnFreeCredentialsHandle( &m_hCred );
  4192. }
  4193. if ( m_hSchannel != NULL )
  4194. {
  4195. FreeLibrary( m_hSchannel );
  4196. }
  4197. if ( m_hSspi != NULL )
  4198. {
  4199. FreeLibrary( m_hSspi );
  4200. }
  4201. }
  4202. HRESULT STDMETHODCALLTYPE
  4203. CADMEXCOM_IMSAdminCryptoCapabilities::GetProtocols(
  4204. /* [in] */ DWORD dwBufferSize,
  4205. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  4206. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
  4207. {
  4208. SecPkgCred_SupportedProtocols SupportedProtocols;
  4209. SECURITY_STATUS scRet;
  4210. *pdwMDRequiredBufferSize = sizeof(DWORD);
  4211. if ( dwBufferSize < sizeof(DWORD) )
  4212. {
  4213. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  4214. }
  4215. if ( !LoadSchannel() )
  4216. {
  4217. return RETURNCODETOHRESULT( GetLastError() );
  4218. }
  4219. if ( FAILED( scRet = m_pfnQueryCredentialsAttributes( &m_hCred,
  4220. SECPKG_ATTR_SUPPORTED_PROTOCOLS,
  4221. &SupportedProtocols ) ) )
  4222. {
  4223. return scRet;
  4224. }
  4225. *(LPDWORD)pbBuffer = SupportedProtocols.grbitProtocol;
  4226. return S_OK;
  4227. }
  4228. BOOL
  4229. CADMEXCOM_IMSAdminCryptoCapabilities::LoadSchannel()
  4230. {
  4231. SECURITY_STATUS scRet;
  4232. TimeStamp tsExpiry;
  4233. OSVERSIONINFO osv;
  4234. BOOL fT;
  4235. BOOL fWinNT;
  4236. if ( m_hSchannel == NULL )
  4237. {
  4238. // Check the OS we are running on
  4239. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  4240. fT = GetVersionEx( &osv );
  4241. fWinNT = ( osv.dwPlatformId == VER_PLATFORM_WIN32_NT );
  4242. if ( (m_hSchannel = LoadLibrary(L"schannel.dll")) != NULL )
  4243. {
  4244. m_pfnGetDefaultIssuers = (PFN_SSLGETDEFAULTISSUERS)GetProcAddress( m_hSchannel,
  4245. "SslGetDefaultIssuers" );
  4246. if ( m_pfnGetDefaultIssuers &&
  4247. ((m_hSspi = LoadLibrary( fWinNT ? L"security.dll" : L"secur32.dll" )) != NULL) )
  4248. {
  4249. m_pfnAcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN_W)
  4250. GetProcAddress( m_hSspi, "AcquireCredentialsHandleW" );
  4251. m_pfnFreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN)
  4252. GetProcAddress( m_hSspi, "FreeCredentialsHandle" );
  4253. m_pfnFreeContextBuffer = (FREE_CONTEXT_BUFFER_FN)
  4254. GetProcAddress( m_hSspi, "FreeContextBuffer" );
  4255. m_pfnQueryCredentialsAttributes = (QUERY_CREDENTIALS_ATTRIBUTES_FN)
  4256. GetProcAddress( m_hSspi, "QueryCredentialsAttributesA" );
  4257. if ( m_pfnAcquireCredentialsHandle &&
  4258. m_pfnFreeCredentialsHandle &&
  4259. m_pfnFreeContextBuffer &&
  4260. m_pfnQueryCredentialsAttributes )
  4261. {
  4262. scRet = m_pfnAcquireCredentialsHandle(
  4263. NULL, // My name (ignored)
  4264. UNISP_NAME_W, // Package
  4265. SECPKG_CRED_INBOUND,// Use
  4266. NULL, // Logon Id (ign.)
  4267. NULL, // auth data
  4268. NULL, // dce-stuff
  4269. NULL, // dce-stuff
  4270. &m_hCred, // Handle
  4271. &tsExpiry );
  4272. if ( !FAILED(scRet) )
  4273. {
  4274. m_fHasCredHandle = TRUE;
  4275. return TRUE;
  4276. }
  4277. }
  4278. FreeLibrary( m_hSspi );
  4279. m_hSspi = NULL;
  4280. }
  4281. FreeLibrary( m_hSchannel );
  4282. m_hSchannel = NULL;
  4283. }
  4284. return FALSE;
  4285. }
  4286. return TRUE;
  4287. }
  4288. HRESULT STDMETHODCALLTYPE
  4289. CADMEXCOM_IMSAdminCryptoCapabilities::GetMaximumCipherStrength(
  4290. /* [out] */ LPDWORD pdwMaximumCipherStrength )
  4291. {
  4292. SecPkgCred_CipherStrengths CipherStrengths;
  4293. SECURITY_STATUS scRet;
  4294. if ( !LoadSchannel() )
  4295. {
  4296. return RETURNCODETOHRESULT( GetLastError() );
  4297. }
  4298. if ( FAILED( scRet = m_pfnQueryCredentialsAttributes( &m_hCred,
  4299. SECPKG_ATTR_CIPHER_STRENGTHS,
  4300. &CipherStrengths ) ) )
  4301. {
  4302. return scRet;
  4303. }
  4304. *pdwMaximumCipherStrength = CipherStrengths.dwMaximumCipherStrength;
  4305. return S_OK;
  4306. }
  4307. HRESULT STDMETHODCALLTYPE
  4308. CADMEXCOM_IMSAdminCryptoCapabilities::GetRootCertificates(
  4309. /* [in] */ DWORD dwBufferSize,
  4310. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  4311. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
  4312. {
  4313. DWORD dwLen;
  4314. if ( !LoadSchannel() ||
  4315. !m_pfnGetDefaultIssuers( NULL, &dwLen ) )
  4316. {
  4317. return RETURNCODETOHRESULT( GetLastError() );
  4318. }
  4319. if ( dwBufferSize < dwLen )
  4320. {
  4321. *pdwMDRequiredBufferSize = dwLen;
  4322. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  4323. }
  4324. if ( m_pfnGetDefaultIssuers( pbBuffer, &dwLen ) )
  4325. {
  4326. *pdwMDRequiredBufferSize = dwLen;
  4327. return S_OK;
  4328. }
  4329. return RETURNCODETOHRESULT( GetLastError() );
  4330. }
  4331. HRESULT STDMETHODCALLTYPE
  4332. CADMEXCOM_IMSAdminCryptoCapabilities::GetSupportedAlgs(
  4333. /* [in] */ DWORD dwBufferSize,
  4334. /* [size_is][out] */ DWORD __RPC_FAR *pbBuffer,
  4335. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize)
  4336. {
  4337. DWORD dwLen;
  4338. SecPkgCred_SupportedAlgs SupportedAlgs;
  4339. SECURITY_STATUS scRet;
  4340. if ( !LoadSchannel() )
  4341. {
  4342. return RETURNCODETOHRESULT( GetLastError() );
  4343. }
  4344. if ( FAILED( scRet = m_pfnQueryCredentialsAttributes( &m_hCred,
  4345. SECPKG_ATTR_SUPPORTED_ALGS,
  4346. &SupportedAlgs ) ) )
  4347. {
  4348. return scRet;
  4349. }
  4350. *pdwMDRequiredBufferSize = sizeof(ALG_ID) * SupportedAlgs.cSupportedAlgs;
  4351. if ( dwBufferSize < *pdwMDRequiredBufferSize )
  4352. {
  4353. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  4354. }
  4355. memcpy( pbBuffer, SupportedAlgs.palgSupportedAlgs, *pdwMDRequiredBufferSize );
  4356. return S_OK;
  4357. }
  4358. HRESULT STDMETHODCALLTYPE
  4359. CADMEXCOM_IMSAdminCryptoCapabilities::SetCAList(
  4360. /*[in] */ DWORD dwBufferSize,
  4361. /*[in, size_is(dwBufferSize)] */ unsigned char __RPC_FAR *pbBuffer )
  4362. {
  4363. #if defined(USE_CAPI2)
  4364. HCERTSTORE hStore = NULL;
  4365. HKEY hKey = NULL;
  4366. PCCERT_CONTEXT pCtx;
  4367. DWORD cCert;
  4368. PCCERT_CONTEXT* rgpCert;
  4369. HRESULT hRes = S_OK;
  4370. DWORD dwValueLen;
  4371. //
  4372. // WARNING: this relies on a security hole in CAPI2, as we want to add certs to
  4373. // ROOT store w/o any UI, and the only way to do this ( at least currently ) is
  4374. // to access the ROOT store as a registry store instead of system store.
  4375. // CAPI2 team may change this in the future, but they MUST provide a way to control
  4376. // the CA list used by schannel, currently in HKCU ROOT store.
  4377. //
  4378. if ( RegOpenKeyEx(
  4379. HKEY_CURRENT_USER,
  4380. L"Software\\Microsoft\\SystemCertificates\\ROOT",
  4381. 0,
  4382. KEY_ALL_ACCESS,
  4383. &hKey ) == ERROR_SUCCESS )
  4384. {
  4385. if ( (hStore = CertOpenStore( CERT_STORE_PROV_REG,
  4386. 0,
  4387. NULL,
  4388. 0,
  4389. (const void*)hKey )) == NULL )
  4390. {
  4391. RegCloseKey( hKey );
  4392. hKey = NULL;
  4393. }
  4394. }
  4395. if ( hStore )
  4396. {
  4397. //
  4398. // delete existing certs
  4399. //
  4400. for ( pCtx = NULL, cCert = 0 ;
  4401. pCtx = CertEnumCertificatesInStore( hStore, pCtx ) ; )
  4402. {
  4403. ++cCert;
  4404. }
  4405. if ( cCert && ( rgpCert = (PCCERT_CONTEXT*)LocalAlloc( LMEM_FIXED,
  4406. cCert * sizeof(PCCERT_CONTEXT) ) ) )
  4407. {
  4408. for ( pCtx = NULL, cCert = 0 ;
  4409. pCtx = CertEnumCertificatesInStore( hStore, pCtx ) ; )
  4410. {
  4411. rgpCert[cCert++] = pCtx;
  4412. }
  4413. while ( cCert-- )
  4414. {
  4415. CertDeleteCertificateFromStore( rgpCert[cCert] );
  4416. }
  4417. LocalFree( rgpCert );
  4418. }
  4419. }
  4420. else
  4421. {
  4422. hRes = RETURNCODETOHRESULT( GetLastError() );
  4423. }
  4424. if ( SUCCEEDED( hRes ) )
  4425. {
  4426. //
  4427. // deserialize certs
  4428. //
  4429. for ( ; dwBufferSize ; )
  4430. {
  4431. dwValueLen = *(LPDWORD)pbBuffer;
  4432. if ( CertAddSerializedElementToStore( hStore,
  4433. pbBuffer + sizeof(DWORD),
  4434. dwValueLen,
  4435. CERT_STORE_ADD_REPLACE_EXISTING,
  4436. 0,
  4437. CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
  4438. NULL,
  4439. NULL ) == FALSE )
  4440. {
  4441. hRes = RETURNCODETOHRESULT( GetLastError() );
  4442. break;
  4443. }
  4444. pbBuffer += sizeof(DWORD) + PAD4(dwValueLen);
  4445. dwBufferSize -= sizeof(DWORD) + PAD4(dwValueLen);
  4446. }
  4447. }
  4448. if ( hStore )
  4449. {
  4450. CertCloseStore( hStore, CERT_CLOSE_STORE_FORCE_FLAG );
  4451. RegCloseKey( hKey );
  4452. }
  4453. #else
  4454. HKEY hKey;
  4455. int iV;
  4456. CHAR achName[128];
  4457. DWORD dwNameLen;
  4458. DWORD dwValueLen;
  4459. LPSTR pszName;
  4460. DWORD dwType;
  4461. HRESULT hRes = S_OK;
  4462. DWORD dwErr;
  4463. if ( (dwErr = RegOpenKeyEx( HKEY_CURRENT_USER,
  4464. "Software\\Microsoft\\SystemCertificates\\ROOT\\Certificates",
  4465. 0,
  4466. KEY_WRITE|KEY_READ,
  4467. &hKey )) == ERROR_SUCCESS )
  4468. {
  4469. //
  4470. // delete existing values
  4471. //
  4472. for ( iV = 0 ; ; /*++iV*/ )
  4473. {
  4474. dwNameLen = sizeof( achName );
  4475. if ( RegEnumValue( hKey,
  4476. iV,
  4477. achName,
  4478. &dwNameLen,
  4479. NULL,
  4480. &dwType,
  4481. NULL,
  4482. NULL ) != ERROR_SUCCESS )
  4483. {
  4484. break;
  4485. }
  4486. if ( RegDeleteValue( hKey, achName ) != ERROR_SUCCESS )
  4487. {
  4488. hRes = RETURNCODETOHRESULT( GetLastError() );
  4489. break;
  4490. }
  4491. }
  4492. if ( SUCCEEDED( hRes ) )
  4493. {
  4494. for ( ; dwBufferSize ; )
  4495. {
  4496. dwNameLen = *(LPDWORD)pbBuffer;
  4497. pszName = (LPSTR)(pbBuffer + sizeof(DWORD));
  4498. dwValueLen = *(LPDWORD)(pbBuffer += sizeof(DWORD) + PAD4(dwNameLen));
  4499. if ( RegSetValueEx( hKey,
  4500. (LPSTR)pszName,
  4501. NULL,
  4502. REG_BINARY,
  4503. pbBuffer + sizeof(DWORD),
  4504. dwValueLen ) != ERROR_SUCCESS )
  4505. {
  4506. hRes = RETURNCODETOHRESULT( GetLastError() );
  4507. break;
  4508. }
  4509. pbBuffer += sizeof(DWORD) + PAD4(dwValueLen);
  4510. dwBufferSize -= sizeof(DWORD) + PAD4(dwNameLen) + sizeof(DWORD) + PAD4(dwValueLen);
  4511. }
  4512. }
  4513. RegCloseKey( hKey );
  4514. }
  4515. else
  4516. {
  4517. hRes = RETURNCODETOHRESULT( dwErr );
  4518. }
  4519. #endif
  4520. return hRes;
  4521. }
  4522. BOOL
  4523. SetLocalSystemSecurityOnKeyContainer( IN HCRYPTPROV hProv )
  4524. /*++
  4525. The function applies security to the key containers associated
  4526. with the HCRYPTPROV which is passed in such that only
  4527. Local System has Full Control. Note that the owner
  4528. is not set, which results in a default owner of Administrators.
  4529. NB : This function was inherited wholesale from Jeff Spelman [jeffspel] in the CAPI
  4530. group.
  4531. --*/
  4532. {
  4533. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  4534. PSID pLocalSystemSid = NULL;
  4535. SECURITY_DESCRIPTOR sd;
  4536. PACL pDacl = NULL;
  4537. PACCESS_ALLOWED_ACE pAce = NULL;
  4538. DWORD dwAclSize = 0;
  4539. LONG lRetCode = 0;
  4540. BOOL bSuccess = FALSE; // assume this function fails
  4541. //
  4542. // prepare a Sid representing the Local System account
  4543. //
  4544. if( !AllocateAndInitializeSid( &sia,
  4545. 1,
  4546. SECURITY_LOCAL_SYSTEM_RID,
  4547. 0, 0, 0, 0, 0, 0, 0,
  4548. &pLocalSystemSid ) )
  4549. {
  4550. goto cleanup;
  4551. }
  4552. //
  4553. // compute size of new acl
  4554. //
  4555. dwAclSize = sizeof(ACL) +
  4556. 1 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  4557. GetLengthSid(pLocalSystemSid) ;
  4558. //
  4559. // allocate storage for Acl
  4560. //
  4561. if ( !(pDacl = (PACL) new BYTE [dwAclSize]) )
  4562. {
  4563. goto cleanup;
  4564. }
  4565. if( !InitializeAcl( pDacl,
  4566. dwAclSize,
  4567. ACL_REVISION ) )
  4568. {
  4569. goto cleanup;
  4570. }
  4571. if( !AddAccessAllowedAce( pDacl,
  4572. ACL_REVISION,
  4573. KEY_ALL_ACCESS,
  4574. pLocalSystemSid ) )
  4575. {
  4576. goto cleanup;
  4577. }
  4578. //
  4579. // make it container inherit.
  4580. //
  4581. if( !GetAce( pDacl,
  4582. 0,
  4583. (LPVOID *) &pAce ) )
  4584. {
  4585. goto cleanup;
  4586. }
  4587. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE;
  4588. if( !InitializeSecurityDescriptor( &sd,
  4589. SECURITY_DESCRIPTOR_REVISION ) )
  4590. {
  4591. goto cleanup;
  4592. }
  4593. if( !SetSecurityDescriptorDacl( &sd,
  4594. TRUE,
  4595. pDacl,
  4596. FALSE ) )
  4597. {
  4598. goto cleanup;
  4599. }
  4600. //
  4601. // apply the security descriptor to the key container
  4602. //
  4603. if ( !CryptSetProvParam( hProv,
  4604. PP_KEYSET_SEC_DESCR,
  4605. (BYTE*)&sd,
  4606. (DWORD)DACL_SECURITY_INFORMATION ) )
  4607. {
  4608. goto cleanup;
  4609. }
  4610. bSuccess = TRUE; // indicate success
  4611. cleanup:
  4612. //
  4613. // free allocated resources
  4614. //
  4615. if( pDacl != NULL )
  4616. {
  4617. delete [] pDacl;
  4618. }
  4619. if( pLocalSystemSid != NULL )
  4620. {
  4621. FreeSid( pLocalSystemSid );
  4622. }
  4623. return bSuccess;
  4624. }
  4625. extern "C" BOOL WINAPI
  4626. DllMain(
  4627. HANDLE hModule,
  4628. DWORD dwReason,
  4629. LPVOID pV
  4630. )
  4631. /*++
  4632. Routine Description:
  4633. DLL init/terminate notification function
  4634. Arguments:
  4635. hModule - DLL handle
  4636. dwReason - notification type
  4637. LPVOID - not used
  4638. Returns:
  4639. TRUE if success, FALSE if failure
  4640. --*/
  4641. {
  4642. switch ( dwReason )
  4643. {
  4644. case DLL_PROCESS_ATTACH:
  4645. #ifdef _NO_TRACING_
  4646. CREATE_DEBUG_PRINT_OBJECT( "ADMEXS" );
  4647. #else
  4648. CREATE_DEBUG_PRINT_OBJECT( "ADMEXS" , IisADMExsGuid);
  4649. #endif
  4650. break;
  4651. case DLL_PROCESS_DETACH:
  4652. DELETE_DEBUG_PRINT_OBJECT( );
  4653. break;
  4654. }
  4655. return TRUE;
  4656. }