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.

1832 lines
50 KiB

  1. // IISCertObj.cpp : Implementation of CIISCertObj
  2. #include "stdafx.h"
  3. #include "CertObj.h"
  4. #include "common.h"
  5. #include "IISCertObj.h"
  6. //#ifdef FULL_OBJECT
  7. #include "base64.h"
  8. //#endif
  9. #include <wincrypt.h>
  10. #include <cryptui.h>
  11. HRESULT ShutdownSSL(CString& server_name);
  12. HCERTSTORE OpenMyStore(IEnroll * pEnroll, HRESULT * phResult);
  13. BOOL InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,
  14. BSTR machine_name,
  15. HRESULT * phResult);
  16. BOOL
  17. TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext,
  18. DWORD dwEncoding,
  19. DWORD dwFlags);
  20. BOOL
  21. AddChainToStore(
  22. HCERTSTORE hCertStore,
  23. PCCERT_CONTEXT pCertContext,
  24. DWORD cStores,
  25. HCERTSTORE * rghStores,
  26. BOOL fDontAddRootCert,
  27. CERT_TRUST_STATUS * pChainTrustStatus);
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CIISCertObj
  30. STDMETHODIMP CIISCertObj::put_ServerName(BSTR newVal)
  31. {
  32. m_ServerName = newVal;
  33. return S_OK;
  34. }
  35. STDMETHODIMP CIISCertObj::put_UserName(BSTR newVal)
  36. {
  37. m_UserName = newVal;
  38. return S_OK;
  39. }
  40. STDMETHODIMP CIISCertObj::put_UserPassword(BSTR newVal)
  41. {
  42. m_UserPassword = newVal;
  43. return S_OK;
  44. }
  45. STDMETHODIMP CIISCertObj::put_InstanceName(BSTR newVal)
  46. {
  47. m_InstanceName = newVal;
  48. return S_OK;
  49. }
  50. #ifdef FULL_OBJECT
  51. STDMETHODIMP CIISCertObj::put_Password(BSTR newVal)
  52. {
  53. m_Password = newVal;
  54. return S_OK;
  55. }
  56. STDMETHODIMP CIISCertObj::put_CommonName(BSTR newVal)
  57. {
  58. m_CommonName = newVal;
  59. return S_OK;
  60. }
  61. STDMETHODIMP CIISCertObj::put_FriendlyName(BSTR newVal)
  62. {
  63. m_FriendlyName = newVal;
  64. return S_OK;
  65. }
  66. STDMETHODIMP CIISCertObj::put_Organization(BSTR newVal)
  67. {
  68. m_Organization = newVal;
  69. return S_OK;
  70. }
  71. STDMETHODIMP CIISCertObj::put_OrganizationUnit(BSTR newVal)
  72. {
  73. m_OrganizationUnit = newVal;
  74. return S_OK;
  75. }
  76. STDMETHODIMP CIISCertObj::put_Locality(BSTR newVal)
  77. {
  78. m_Locality = newVal;
  79. return S_OK;
  80. }
  81. STDMETHODIMP CIISCertObj::put_State(BSTR newVal)
  82. {
  83. m_State = newVal;
  84. return S_OK;
  85. }
  86. STDMETHODIMP CIISCertObj::put_Country(BSTR newVal)
  87. {
  88. m_Country = newVal;
  89. return S_OK;
  90. }
  91. STDMETHODIMP CIISCertObj::put_CertAuthority(BSTR newVal)
  92. {
  93. m_CertAuthority = newVal;
  94. return S_OK;
  95. }
  96. STDMETHODIMP CIISCertObj::put_CertTemplate(BSTR newVal)
  97. {
  98. m_CertTemplate = newVal;
  99. return S_OK;
  100. }
  101. STDMETHODIMP CIISCertObj::put_KeySize(int newVal)
  102. {
  103. m_KeySize = newVal;
  104. return S_OK;
  105. }
  106. STDMETHODIMP CIISCertObj::put_SGC_Cert(BOOL newVal)
  107. {
  108. m_SGC_Cert = newVal;
  109. return S_OK;
  110. }
  111. STDMETHODIMP CIISCertObj::LoadSettings(BSTR ApplicationKey, BSTR SettingsKey)
  112. {
  113. return S_OK;
  114. }
  115. STDMETHODIMP CIISCertObj::SaveSettings(BSTR ApplicationKey, BSTR SettingsKey)
  116. {
  117. return S_OK;
  118. }
  119. STDMETHODIMP CIISCertObj::CreateRequest(BSTR FileName)
  120. {
  121. CString dn;
  122. HRESULT hr;
  123. TCHAR usage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
  124. CCryptBlobIMalloc req_blob;
  125. if (FAILED(hr = CreateDNString(dn)))
  126. return hr;
  127. ATLASSERT(dn.length() > 0);
  128. if (FAILED(hr = GetEnroll()->createPKCS10WStr(dn, (LPTSTR)usage, req_blob)))
  129. {
  130. return hr;
  131. }
  132. // BASE64 encode pkcs 10
  133. DWORD cch;
  134. char * psz;
  135. if ( ERROR_SUCCESS != Base64EncodeA(req_blob.GetData(), req_blob.GetSize(), NULL, &cch)
  136. || NULL == (psz = (char *)_alloca(cch+1))
  137. || ERROR_SUCCESS != Base64EncodeA(req_blob.GetData(), req_blob.GetSize(), psz, &cch)
  138. )
  139. {
  140. ATLASSERT(FALSE);
  141. return E_FAIL;
  142. }
  143. return S_OK;
  144. }
  145. STDMETHODIMP CIISCertObj::RequestCert(BSTR CertAuthority)
  146. {
  147. // TODO: Add your implementation code here
  148. return S_OK;
  149. }
  150. STDMETHODIMP CIISCertObj::ProcessResponse(BSTR FileName)
  151. {
  152. // TODO: Add your implementation code here
  153. return S_OK;
  154. }
  155. #endif
  156. STDMETHODIMP CIISCertObj::IsInstalled(
  157. BSTR InstanceName,
  158. VARIANT_BOOL * retval)
  159. {
  160. HRESULT hr = S_OK;
  161. // Check mandatory properties
  162. if ( InstanceName == NULL
  163. || *InstanceName == 0
  164. || retval == NULL
  165. )
  166. return ERROR_INVALID_PARAMETER;
  167. m_InstanceName = InstanceName;
  168. if (!m_ServerName.IsEmpty())
  169. {
  170. //ASSERT(GetObject(&hr) != NULL);
  171. IIISCertObj * pObj;
  172. if (NULL != (pObj = GetObject(&hr)))
  173. {
  174. hr = pObj->put_InstanceName(InstanceName);
  175. hr = pObj->IsInstalledRemote(InstanceName, retval);
  176. }
  177. }
  178. else
  179. {
  180. hr = IsInstalledRemote(InstanceName, retval);
  181. }
  182. return hr;
  183. }
  184. STDMETHODIMP
  185. CIISCertObj::IsInstalledRemote(
  186. BSTR InstanceName,
  187. VARIANT_BOOL * retval)
  188. {
  189. HRESULT hr = S_OK;
  190. CERT_CONTEXT * pCertContext = NULL;
  191. // Check mandatory properties
  192. if (InstanceName == NULL || *InstanceName == 0 || retval == NULL)
  193. return ERROR_INVALID_PARAMETER;
  194. pCertContext = GetInstalledCert(&hr);
  195. if (FAILED(hr) || NULL == pCertContext)
  196. {
  197. hr = S_OK;
  198. *retval = FALSE;
  199. }
  200. else
  201. {
  202. hr = S_OK;
  203. *retval = TRUE;
  204. CertFreeCertificateContext(pCertContext);
  205. }
  206. return hr;
  207. }
  208. STDMETHODIMP
  209. CIISCertObj::RemoveCert(BSTR InstanceName, BOOL bPrivateKey)
  210. {
  211. HRESULT hr = E_FAIL;
  212. PCCERT_CONTEXT pCertContext = NULL;
  213. DWORD cbKpi = 0;
  214. PCRYPT_KEY_PROV_INFO pKpi = NULL ;
  215. HCRYPTPROV hCryptProv = NULL;
  216. do
  217. {
  218. // get the certificate from the server
  219. pCertContext = GetInstalledCert(&hr);
  220. if (NULL == pCertContext)
  221. {
  222. break;
  223. }
  224. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbKpi))
  225. {
  226. hr = HRESULT_FROM_WIN32(GetLastError());
  227. break;
  228. }
  229. pKpi = ( PCRYPT_KEY_PROV_INFO ) malloc( cbKpi );
  230. if ( NULL != pKpi )
  231. {
  232. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, (void *)pKpi, &cbKpi))
  233. {
  234. hr = HRESULT_FROM_WIN32(GetLastError());
  235. break;
  236. }
  237. // Delete the key container
  238. if (!CryptAcquireContext(
  239. &hCryptProv,
  240. pKpi->pwszContainerName,
  241. pKpi->pwszProvName,
  242. pKpi->dwProvType,
  243. pKpi->dwFlags | CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET))
  244. {
  245. hr = HRESULT_FROM_WIN32(GetLastError());
  246. break;
  247. }
  248. if (NULL != pKpi){free(pKpi);}
  249. if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, NULL))
  250. {
  251. hr = HRESULT_FROM_WIN32(GetLastError());
  252. break;
  253. }
  254. }
  255. // uninstall the certificate from the site, reset SSL flag
  256. // if we are exporting the private key, remove the cert from the storage
  257. // and delete private key
  258. UninstallCert();
  259. // remove ssl key from metabase
  260. CString str = InstanceName;
  261. ShutdownSSL(str);
  262. // delete the private key
  263. if (bPrivateKey)
  264. {
  265. PCCERT_CONTEXT pcDup = NULL ;
  266. pcDup = CertDuplicateCertificateContext(pCertContext);
  267. if (pcDup)
  268. {
  269. if (!CertDeleteCertificateFromStore(pcDup))
  270. {
  271. hr = HRESULT_FROM_WIN32(GetLastError());
  272. break;
  273. }
  274. }
  275. else
  276. {
  277. hr = HRESULT_FROM_WIN32(GetLastError());
  278. }
  279. }
  280. hr = ERROR_SUCCESS;
  281. } while (FALSE);
  282. if (pCertContext) {CertFreeCertificateContext(pCertContext);}
  283. return hr;
  284. }
  285. STDMETHODIMP CIISCertObj::Export(
  286. BSTR FileName,
  287. BSTR InstanceName,
  288. BSTR Password,
  289. BOOL bPrivateKey,
  290. BOOL bCertChain,
  291. BOOL bRemoveCert)
  292. {
  293. HRESULT hr = S_OK;
  294. DWORD cbEncodedSize = 0;
  295. char * pszEncodedString = NULL;
  296. BOOL bBase64Encoded = TRUE;
  297. DWORD blob_cbData;
  298. BYTE * blob_pbData = NULL;
  299. BOOL blob_freeme = FALSE;
  300. // Check mandatory properties
  301. if ( FileName == NULL || *FileName == 0
  302. || InstanceName == NULL || *InstanceName == 0
  303. || Password == NULL || *Password == 0
  304. )
  305. {
  306. return ERROR_INVALID_PARAMETER;
  307. }
  308. m_InstanceName = InstanceName;
  309. IIISCertObj * pObj = GetObject(&hr);
  310. if (FAILED(hr))
  311. {
  312. goto Export_Exit;
  313. }
  314. // Call function go get data from the remote/local iis store
  315. // and return it back as a blob. the blob could be returned back as Base64 encoded
  316. // so check that flag
  317. hr = ExportToBlobProxy(pObj, InstanceName, Password, bPrivateKey, bCertChain, &bBase64Encoded, &cbEncodedSize, &pszEncodedString);
  318. if (FAILED(hr))
  319. {
  320. goto Export_Exit;
  321. }
  322. // check if things are kool
  323. if (bRemoveCert)
  324. {
  325. hr = pObj->RemoveCert(InstanceName, bPrivateKey);
  326. if (FAILED(hr))
  327. {
  328. goto Export_Exit;
  329. }
  330. }
  331. if (SUCCEEDED(hr))
  332. {
  333. if (bBase64Encoded)
  334. {
  335. int err;
  336. // The data we got back was Base64 encoded to remove nulls.
  337. // we need to decode it back to it's original format.
  338. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  339. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  340. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  341. {
  342. SetLastError(err);
  343. hr = HRESULT_FROM_WIN32(err);
  344. return hr;
  345. }
  346. blob_freeme = TRUE;
  347. }
  348. else
  349. {
  350. blob_cbData = cbEncodedSize;
  351. blob_pbData = (BYTE*) pszEncodedString;
  352. }
  353. HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  354. if (INVALID_HANDLE_VALUE == hFile)
  355. {
  356. hr = HRESULT_FROM_WIN32(GetLastError());
  357. return hr;
  358. }
  359. DWORD written = 0;
  360. if (!WriteFile(hFile, blob_pbData, blob_cbData, &written, NULL))
  361. {
  362. hr = HRESULT_FROM_WIN32(GetLastError());
  363. }
  364. else
  365. {
  366. hr = S_OK;
  367. }
  368. CloseHandle(hFile);
  369. // Erase the memory that the private key used to be in!!!
  370. ZeroMemory(pszEncodedString, sizeof(cbEncodedSize));
  371. if (bBase64Encoded)
  372. {
  373. ZeroMemory(blob_pbData, sizeof(blob_cbData));
  374. }
  375. }
  376. Export_Exit:
  377. if (pObj != NULL)
  378. {
  379. if (pObj != this)
  380. {
  381. pObj->Release();pObj=NULL;m_pObj = NULL;
  382. }
  383. }
  384. if (blob_freeme){if (blob_pbData != NULL){free(blob_pbData);blob_pbData=NULL;}}
  385. if (pszEncodedString != NULL){CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;}
  386. return hr;
  387. }
  388. //
  389. // Proxy to the real call ExportToBlob()
  390. // this function figures out how much space to allocate, and then calls ExportToBlob().
  391. //
  392. // if succeeded and they get the blob back,
  393. // and the caller must call CoTaskMemFree()
  394. //
  395. HRESULT
  396. CIISCertObj::ExportToBlobProxy(
  397. IIISCertObj * pObj,
  398. BSTR InstanceName,
  399. BSTR Password,
  400. BOOL bPrivateKey,
  401. BOOL bCertChain,
  402. BOOL *bBase64Encoded,
  403. DWORD * pcbSize,
  404. char ** pBlobBinary)
  405. {
  406. HRESULT hr = E_FAIL;
  407. DWORD cbEncodedSize = 0;
  408. char * pszEncodedString = NULL;
  409. * pBlobBinary = _T('\0');
  410. // Guestimate how much space we'll need...
  411. cbEncodedSize = 10;
  412. pszEncodedString = (char *)::CoTaskMemAlloc(cbEncodedSize);
  413. if (pszEncodedString == NULL)
  414. {
  415. hr = E_OUTOFMEMORY;
  416. goto ExportToBlobProxy_Exit;
  417. }
  418. ZeroMemory(pszEncodedString, sizeof(cbEncodedSize));
  419. // if its the local machine, then don't need to encode it since
  420. // it's getting passed in the same memory...
  421. // but if its on the remote machine, then we need to encode it
  422. // since this stuff has nulls in it.
  423. *bBase64Encoded = TRUE;
  424. if (pObj == this){*bBase64Encoded = FALSE;}
  425. // call the remote function that will run on the remote/local machine
  426. // and grab it's certificate from iis and send it back to us
  427. hr = pObj->ExportToBlob(InstanceName, Password, bPrivateKey, bCertChain, *bBase64Encoded, &cbEncodedSize, (char *) pszEncodedString);
  428. if (ERROR_INSUFFICIENT_BUFFER == hr)
  429. {
  430. // free what we previously asked for and allocate more.
  431. ::CoTaskMemFree(pszEncodedString);
  432. pszEncodedString = (char *)::CoTaskMemAlloc(cbEncodedSize);
  433. if (pszEncodedString == NULL)
  434. {
  435. hr = E_OUTOFMEMORY;
  436. goto ExportToBlobProxy_Exit;
  437. }
  438. // i have no idea why it doesn't work it this line is here!
  439. //ZeroMemory(pszEncodedString, sizeof(cbEncodedSize));
  440. hr = pObj->ExportToBlob(InstanceName, Password, bPrivateKey, bCertChain, *bBase64Encoded, &cbEncodedSize, (char *) pszEncodedString);
  441. if (FAILED(hr))
  442. {
  443. ::CoTaskMemFree(pszEncodedString);
  444. goto ExportToBlobProxy_Exit;
  445. }
  446. // otherwise hey, we've got our data!
  447. // copy it back
  448. *pcbSize = cbEncodedSize;
  449. *pBlobBinary = pszEncodedString;
  450. hr = S_OK;
  451. }
  452. ExportToBlobProxy_Exit:
  453. return hr;
  454. }
  455. STDMETHODIMP
  456. CIISCertObj::ExportToBlob(
  457. BSTR InstanceName,
  458. BSTR Password,
  459. BOOL bPrivateKey,
  460. BOOL bCertChain,
  461. BOOL bBase64Encoded,
  462. DWORD *cbBufferSize,
  463. char *pbBuffer
  464. )
  465. {
  466. HRESULT hr = E_FAIL;
  467. PCCERT_CONTEXT pCertContext = NULL;
  468. BOOL bStatus = FALSE;
  469. HCERTSTORE hStore = NULL;
  470. DWORD dwOpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG;
  471. CRYPT_DATA_BLOB DataBlob;
  472. ZeroMemory(&DataBlob, sizeof(CRYPT_DATA_BLOB));
  473. char *pszB64Out = NULL;
  474. DWORD pcchB64Out = 0;
  475. DWORD err;
  476. //
  477. // get the certificate from the server
  478. //
  479. pCertContext = GetInstalledCert(&hr);
  480. if (NULL == pCertContext)
  481. {
  482. *cbBufferSize = 0;
  483. pbBuffer = NULL;
  484. goto ExportToBlob_Exit;
  485. }
  486. //
  487. // Export cert
  488. //
  489. // Open a temporary store to stick the cert in.
  490. hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,dwOpenFlags,NULL);
  491. if(NULL == hStore)
  492. {
  493. *cbBufferSize = 0;
  494. pbBuffer = NULL;
  495. ATLTRACE(_T("PFXExportCert:CertOpenStore() failed Error: %d\n"), GetLastError());
  496. hr = HRESULT_FROM_WIN32(GetLastError());
  497. goto ExportToBlob_Exit;
  498. }
  499. //
  500. // get all the certs in the chain if we need to
  501. //
  502. if (bCertChain)
  503. {
  504. AddChainToStore(hStore, pCertContext, 0, 0, FALSE, NULL);
  505. }
  506. if(!CertAddCertificateContextToStore(hStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  507. {
  508. *cbBufferSize = 0;
  509. pbBuffer = NULL;
  510. ATLTRACE(_T("PFXExportCert:CertAddCertificateContextToStore() failed Error: %d\n"), GetLastError());
  511. hr = HRESULT_FROM_WIN32(GetLastError());
  512. goto ExportToBlob_Exit;
  513. }
  514. // free cert context since we no longer need to hold it
  515. if (pCertContext)
  516. {
  517. CertFreeCertificateContext(pCertContext);pCertContext=NULL;
  518. }
  519. DataBlob.cbData = 0;
  520. DataBlob.pbData = NULL;
  521. if (!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,bPrivateKey ? EXPORT_PRIVATE_KEYS : 0))
  522. {
  523. ATLTRACE(_T("PFXExportCert:1st PFXExportCertStoreEx() failed\n"));
  524. hr = HRESULT_FROM_WIN32(GetLastError());
  525. goto ExportToBlob_Exit;
  526. }
  527. if(DataBlob.cbData <= 0)
  528. {
  529. hr = HRESULT_FROM_WIN32(GetLastError());
  530. goto ExportToBlob_Exit;
  531. }
  532. //
  533. // check if the callers space is big enough...
  534. //
  535. if (bBase64Encoded)
  536. {
  537. pcchB64Out = 0;
  538. // get the size if we had encoded it.
  539. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,NULL,&pcchB64Out);
  540. if (err != ERROR_SUCCESS)
  541. {
  542. hr = E_FAIL;
  543. goto ExportToBlob_Exit;
  544. }
  545. pcchB64Out = pcchB64Out * sizeof(char);
  546. if (*cbBufferSize < pcchB64Out)
  547. {
  548. *cbBufferSize = pcchB64Out;
  549. hr = ERROR_INSUFFICIENT_BUFFER;
  550. goto ExportToBlob_Exit;
  551. }
  552. }
  553. else
  554. {
  555. if (*cbBufferSize < DataBlob.cbData)
  556. {
  557. *cbBufferSize = DataBlob.cbData;
  558. hr = ERROR_INSUFFICIENT_BUFFER;
  559. goto ExportToBlob_Exit;
  560. }
  561. }
  562. // nope looks like they want us to fill in the data.
  563. if(NULL == (DataBlob.pbData = (PBYTE) ::CoTaskMemAlloc(DataBlob.cbData)))
  564. {
  565. hr = E_OUTOFMEMORY;
  566. goto ExportToBlob_Exit;
  567. }
  568. //
  569. // at this point they have allocated enough memory
  570. // let's go and get the cert and put it into DataBlob
  571. //
  572. if(!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,bPrivateKey ? EXPORT_PRIVATE_KEYS : 0))
  573. {
  574. if (DataBlob.pbData){free(DataBlob.pbData);DataBlob.pbData = NULL;}
  575. ATLTRACE(_T("PFXExportCert:2nd PFXExportCertStoreEx() failed Error: %d\n"),GetLastError());
  576. hr = HRESULT_FROM_WIN32(GetLastError());
  577. goto ExportToBlob_Exit;
  578. }
  579. if (bBase64Encoded)
  580. {
  581. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  582. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,NULL,&pcchB64Out);
  583. if (err != ERROR_SUCCESS)
  584. {
  585. hr = E_FAIL;
  586. goto ExportToBlob_Exit;
  587. }
  588. // allocate some space and then try it.
  589. pcchB64Out = pcchB64Out * sizeof(char);
  590. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  591. if (NULL == pszB64Out)
  592. {
  593. hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
  594. goto ExportToBlob_Exit;
  595. }
  596. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,pszB64Out,&pcchB64Out);
  597. if (err != ERROR_SUCCESS)
  598. {
  599. hr = E_FAIL;
  600. goto ExportToBlob_Exit;
  601. }
  602. // copy the new memory to pass back
  603. *cbBufferSize = pcchB64Out;
  604. memcpy(pbBuffer,pszB64Out,pcchB64Out);
  605. }
  606. else
  607. {
  608. // no encoding... this doesn't work right now for the remote case...
  609. // since there are nulls in there..
  610. // copy the new memory to pass back
  611. *cbBufferSize = DataBlob.cbData;
  612. memcpy(pbBuffer,DataBlob.pbData,DataBlob.cbData);
  613. }
  614. hr = ERROR_SUCCESS;
  615. ExportToBlob_Exit:
  616. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);pszB64Out = NULL;}
  617. if (NULL != DataBlob.pbData){::CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;}
  618. if (NULL != hStore){CertCloseStore(hStore, 0);hStore=NULL;}
  619. if (NULL != pCertContext) {CertFreeCertificateContext(pCertContext);pCertContext=NULL;}
  620. return hr;
  621. }
  622. STDMETHODIMP CIISCertObj::Import(
  623. BSTR FileName,
  624. BSTR InstanceName,
  625. BSTR Password)
  626. {
  627. HRESULT hr = S_OK;
  628. BYTE * pbData = NULL;
  629. DWORD actual = 0, cbData = 0;
  630. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  631. if (hFile == INVALID_HANDLE_VALUE)
  632. {
  633. hr = HRESULT_FROM_WIN32(GetLastError());
  634. hFile = NULL;
  635. goto Import_Exit;
  636. }
  637. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  638. {
  639. hr = HRESULT_FROM_WIN32(GetLastError());
  640. goto Import_Exit;
  641. }
  642. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  643. {
  644. hr = E_OUTOFMEMORY;
  645. goto Import_Exit;
  646. }
  647. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  648. {
  649. IIISCertObj * pObj = GetObject(&hr);
  650. if (SUCCEEDED(hr))
  651. {
  652. hr = ImportFromBlobProxy(pObj, InstanceName, Password, actual, pbData);
  653. }
  654. }
  655. else
  656. {
  657. hr = HRESULT_FROM_WIN32(GetLastError());
  658. goto Import_Exit;
  659. }
  660. Import_Exit:
  661. if (pbData != NULL){::CoTaskMemFree(pbData);}
  662. if (hFile != NULL){CloseHandle(hFile);}
  663. return hr;
  664. /*
  665. #if 0
  666. DWORD flags = CRYPTUI_WIZ_NO_UI|CRYPTUI_WIZ_IMPORT_ALLOW_CERT|CRYPTUI_WIZ_IMPORT_TO_LOCALMACHINE;
  667. CRYPTUI_WIZ_IMPORT_SRC_INFO ii;
  668. HRESULT hr = S_OK;
  669. // Check mandatory properties
  670. if ( FileName == NULL || *FileName == 0
  671. || InstanceName == NULL || *InstanceName == 0
  672. || Password == NULL || *Password == 0
  673. )
  674. return ERROR_INVALID_PARAMETER;
  675. // Check metabase properties
  676. CComAuthInfo auth;
  677. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR; // SZ_MBN_WEB SZ_MBN_SEP_STR;
  678. key_path += InstanceName;
  679. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  680. if (!key.Succeeded())
  681. {
  682. return key.QueryResult();
  683. }
  684. HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
  685. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  686. NULL,
  687. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  688. L"MY"
  689. );
  690. HCERTSTORE hTempStore = ::CertOpenStore(
  691. CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_SET_LOCALIZED_NAME_FLAG, NULL);
  692. #if 0
  693. DWORD dwContentType = 0, dwFormatType = 0, dwMsgAndCertEncodingType = 0;
  694. HCERTSTORE hSrcStore = NULL;
  695. HCRYPTMSG hMsg = NULL;
  696. void * pvContext = NULL;
  697. BOOL bRes = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  698. FileName,
  699. CERT_QUERY_CONTENT_FLAG_ALL,
  700. CERT_QUERY_FORMAT_FLAG_ALL,
  701. 0,
  702. &dwMsgAndCertEncodingType,
  703. &dwContentType,
  704. &dwFormatType,
  705. &hSrcStore,
  706. &hMsg,
  707. (const void **)&pvContext);
  708. if (!bRes)
  709. {
  710. hr = GetLastError();
  711. }
  712. #endif
  713. if (hStore != NULL && hTempStore != NULL)
  714. {
  715. ZeroMemory(&ii, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
  716. ii.dwSize = sizeof(ii);
  717. ii.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
  718. ii.pwszFileName = FileName;
  719. ii.pwszPassword = Password;
  720. if (CryptUIWizImport(flags, NULL, NULL, &ii, hTempStore))
  721. {
  722. // Now we need to extract CERT_CONTEXT from this temp store and put it to MY store
  723. // and install to metabase
  724. PCCERT_CONTEXT pCertContext = CertEnumCertificatesInStore(hTempStore, NULL);
  725. if (pCertContext != NULL)
  726. {
  727. // Put it to My store
  728. ii.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
  729. ii.hCertStore = hTempStore;
  730. if (CryptUIWizImport(flags, NULL, NULL, &ii, hStore))
  731. {
  732. // Install to metabase
  733. CRYPT_HASH_BLOB hash;
  734. if ( CertGetCertificateContextProperty(pCertContext,
  735. CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData)
  736. && NULL != (hash.pbData = (BYTE *)_alloca(hash.cbData))
  737. && CertGetCertificateContextProperty(pCertContext,
  738. CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData)
  739. )
  740. {
  741. InstallHashToMetabase(&hash, InstanceName, &hr);
  742. }
  743. else
  744. {
  745. hr = GetLastError();
  746. }
  747. }
  748. else
  749. {
  750. hr = GetLastError();
  751. }
  752. CertFreeCertificateContext(pCertContext);
  753. }
  754. else
  755. {
  756. hr = GetLastError();
  757. }
  758. }
  759. else
  760. {
  761. hr = GetLastError();
  762. }
  763. }
  764. if (NULL != hStore)
  765. CertCloseStore(hStore, 0);
  766. if (NULL != hTempStore)
  767. CertCloseStore(hTempStore, 0);
  768. return hr;
  769. #endif
  770. */
  771. }
  772. HRESULT
  773. CIISCertObj::ImportFromBlobProxy(
  774. IIISCertObj * pObj,
  775. BSTR InstanceName,
  776. BSTR Password,
  777. DWORD actual,
  778. BYTE *pData)
  779. {
  780. HRESULT hr = E_FAIL;
  781. BOOL bBase64Encoded = TRUE;
  782. char *pszB64Out = NULL;
  783. DWORD pcchB64Out = 0;
  784. if (pObj == this){bBase64Encoded = FALSE;}
  785. if (bBase64Encoded)
  786. {
  787. // base64 encode the data for transfer to the remote machine
  788. DWORD err;
  789. pcchB64Out = 0;
  790. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  791. err = Base64EncodeA(pData,actual,NULL,&pcchB64Out);
  792. if (err != ERROR_SUCCESS)
  793. {
  794. hr = E_FAIL;
  795. goto ImportFromBlobProxy_Exit;
  796. }
  797. // allocate some space and then try it.
  798. pcchB64Out = pcchB64Out * sizeof(char);
  799. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  800. if (NULL == pszB64Out)
  801. {
  802. hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
  803. goto ImportFromBlobProxy_Exit;
  804. }
  805. err = Base64EncodeA(pData,actual,pszB64Out,&pcchB64Out);
  806. if (err != ERROR_SUCCESS)
  807. {
  808. hr = E_FAIL;
  809. goto ImportFromBlobProxy_Exit;
  810. }
  811. // the data to send are now in these variables
  812. // pcchB64Out
  813. // pszB64Out
  814. }
  815. else
  816. {
  817. pcchB64Out = actual;
  818. pszB64Out = (char*) pData;
  819. }
  820. hr = pObj->ImportFromBlob(InstanceName, Password, bBase64Encoded, pcchB64Out, pszB64Out);
  821. if (SUCCEEDED(hr))
  822. {
  823. // otherwise hey, The data was imported!
  824. hr = S_OK;
  825. }
  826. ImportFromBlobProxy_Exit:
  827. if (bBase64Encoded)
  828. {
  829. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);}
  830. }
  831. return hr;
  832. }
  833. HRESULT
  834. CIISCertObj::ImportFromBlob(
  835. BSTR InstanceName,
  836. BSTR Password,
  837. BOOL bBase64Encoded,
  838. DWORD count,
  839. char *pData)
  840. {
  841. HRESULT hr = S_OK;
  842. CRYPT_DATA_BLOB blob;
  843. ZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
  844. LPTSTR pPass = Password;
  845. BOOL blob_freeme = FALSE;
  846. if (bBase64Encoded)
  847. {
  848. int err;
  849. // The data we got back was Base64 encoded to remove nulls.
  850. // we need to decode it back to it's original format.
  851. if( (err = Base64DecodeA(pData,count,NULL,&blob.cbData)) != ERROR_SUCCESS ||
  852. (blob.pbData = (BYTE *) malloc(blob.cbData)) == NULL ||
  853. (err = Base64DecodeA(pData,count,blob.pbData,&blob.cbData)) != ERROR_SUCCESS )
  854. {
  855. SetLastError(err);
  856. hr = HRESULT_FROM_WIN32(err);
  857. return hr;
  858. }
  859. blob_freeme = TRUE;
  860. }
  861. else
  862. {
  863. blob.cbData = count;
  864. blob.pbData = (BYTE*) pData;
  865. }
  866. if (!PFXVerifyPassword(&blob, pPass, 0))
  867. {
  868. // Try empty password
  869. if (pPass == NULL)
  870. {
  871. if (!PFXVerifyPassword(&blob, pPass = L'\0', 0))
  872. {
  873. hr = ERROR_INVALID_PARAMETER;
  874. }
  875. }
  876. else
  877. {
  878. hr = ERROR_INVALID_PARAMETER;
  879. }
  880. }
  881. if (SUCCEEDED(hr))
  882. {
  883. HCERTSTORE hStore = PFXImportCertStore(&blob, pPass, CRYPT_MACHINE_KEYSET|CRYPT_EXPORTABLE);
  884. if (hStore != NULL)
  885. {
  886. //add the certificate with private key to my store; and the rest
  887. //to the ca store
  888. PCCERT_CONTEXT pCertContext = NULL;
  889. PCCERT_CONTEXT pCertPre = NULL;
  890. while ( SUCCEEDED(hr)
  891. && NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertPre))
  892. )
  893. {
  894. //check if the certificate has the property on it
  895. //make sure the private key matches the certificate
  896. //search for both machine key and user keys
  897. DWORD dwData = 0;
  898. if ( CertGetCertificateContextProperty(pCertContext,
  899. CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData)
  900. && CryptFindCertificateKeyProvInfo(pCertContext, 0, NULL)
  901. )
  902. {
  903. // This certificate should go to the My store
  904. HCERTSTORE hDestStore = CertOpenStore(
  905. CERT_STORE_PROV_SYSTEM,
  906. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  907. NULL,
  908. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  909. L"MY"
  910. );
  911. if (hDestStore != NULL)
  912. {
  913. // Put it to store
  914. if (CertAddCertificateContextToStore(hDestStore,
  915. pCertContext,
  916. CERT_STORE_ADD_REPLACE_EXISTING,
  917. NULL))
  918. {
  919. // Install to metabase
  920. CRYPT_HASH_BLOB hash;
  921. if ( CertGetCertificateContextProperty(pCertContext,
  922. CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData)
  923. && NULL != (hash.pbData = (BYTE *)_alloca(hash.cbData))
  924. && CertGetCertificateContextProperty(pCertContext,
  925. CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData)
  926. )
  927. {
  928. InstallHashToMetabase(&hash, InstanceName, &hr);
  929. }
  930. else
  931. {
  932. hr = HRESULT_FROM_WIN32(GetLastError());
  933. }
  934. }
  935. else
  936. {
  937. hr = HRESULT_FROM_WIN32(GetLastError());
  938. }
  939. CertCloseStore(hDestStore, 0);
  940. }
  941. else
  942. {
  943. hr = HRESULT_FROM_WIN32(GetLastError());
  944. }
  945. } // my store certificate
  946. //see if the certificate is self-signed.
  947. //if it is selfsigned, goes to the root store
  948. else if (TrustIsCertificateSelfSigned(pCertContext,
  949. pCertContext->dwCertEncodingType, 0))
  950. {
  951. //Put it to the root store
  952. HCERTSTORE hDestStore=CertOpenStore(
  953. CERT_STORE_PROV_SYSTEM,
  954. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  955. NULL,
  956. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  957. L"ROOT");
  958. if (hDestStore != NULL)
  959. {
  960. // Put it to store
  961. if (!CertAddCertificateContextToStore(hDestStore,
  962. pCertContext,
  963. CERT_STORE_ADD_REPLACE_EXISTING,
  964. NULL))
  965. {
  966. hr = HRESULT_FROM_WIN32(GetLastError());
  967. }
  968. CertCloseStore(hDestStore, 0);
  969. }
  970. else
  971. {
  972. hr = HRESULT_FROM_WIN32(GetLastError());
  973. }
  974. }
  975. else
  976. {
  977. //Put it to the CA store
  978. HCERTSTORE hDestStore=CertOpenStore(
  979. CERT_STORE_PROV_SYSTEM,
  980. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  981. NULL,
  982. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  983. L"CA");
  984. if (hDestStore != NULL)
  985. {
  986. // Put it to store
  987. if (!CertAddCertificateContextToStore(hDestStore,
  988. pCertContext,
  989. CERT_STORE_ADD_REPLACE_EXISTING,
  990. NULL))
  991. {
  992. hr = HRESULT_FROM_WIN32(GetLastError());
  993. }
  994. CertCloseStore(hDestStore, 0);
  995. }
  996. else
  997. {
  998. hr = HRESULT_FROM_WIN32(GetLastError());
  999. }
  1000. }
  1001. pCertPre = pCertContext;
  1002. } //while
  1003. CertCloseStore(hStore, 0);
  1004. }
  1005. else
  1006. hr = HRESULT_FROM_WIN32(GetLastError());
  1007. }
  1008. //ImportFromBlob_Exit:
  1009. if (blob_freeme){if (blob.pbData != NULL){free(blob.pbData);blob.pbData=NULL;}}
  1010. return hr;
  1011. }
  1012. //////////////////////////////////////////////////////////////////
  1013. #ifdef FULL_OBJECT
  1014. HRESULT CIISCertObj::Init()
  1015. {
  1016. HRESULT hr;
  1017. if (!m_bInitDone)
  1018. {
  1019. do {
  1020. // setup IEnroll object properly
  1021. DWORD dwFlags;
  1022. if (FAILED(hr = GetEnroll()->get_MyStoreFlags(&dwFlags)))
  1023. break;
  1024. dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
  1025. dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
  1026. // following call will change Request store flags also
  1027. if (FAILED(hr = GetEnroll()->put_MyStoreFlags(dwFlags)))
  1028. break;
  1029. if (FAILED(hr = GetEnroll()->get_GenKeyFlags(&dwFlags)))
  1030. break;
  1031. dwFlags |= CRYPT_EXPORTABLE;
  1032. if ( FAILED(hr = GetEnroll()->put_GenKeyFlags(dwFlags))
  1033. || FAILED(hr = GetEnroll()->put_KeySpec(AT_KEYEXCHANGE))
  1034. || FAILED(hr = GetEnroll()->put_ProviderType(PROV_RSA_SCHANNEL))
  1035. || FAILED(hr = GetEnroll()->put_DeleteRequestCert(TRUE))
  1036. )
  1037. break;
  1038. } while (FALSE);
  1039. m_bInitDone = SUCCEEDED(hr);
  1040. }
  1041. return hr;
  1042. }
  1043. IEnroll *
  1044. CIISCertObj::GetEnroll()
  1045. {
  1046. if (m_pEnroll == NULL)
  1047. {
  1048. HRESULT hr = CoCreateInstance(CLSID_CEnroll,
  1049. NULL,
  1050. CLSCTX_INPROC_SERVER,
  1051. IID_IEnroll,
  1052. (void **)&m_pEnroll);
  1053. }
  1054. return m_pEnroll;
  1055. }
  1056. HCERTSTORE
  1057. OpenMyStore(IEnroll * pEnroll, HRESULT * phResult)
  1058. {
  1059. ASSERT(NULL != phResult);
  1060. HCERTSTORE hStore = NULL;
  1061. hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
  1062. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1063. NULL,
  1064. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1065. L"MY"
  1066. );
  1067. if (hStore == NULL)
  1068. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1069. return hStore;
  1070. }
  1071. #endif
  1072. HRESULT ShutdownSSL(CString& server_name)
  1073. {
  1074. CComAuthInfo auth;
  1075. CString str = server_name;
  1076. str += _T("/root");
  1077. CMetaKey key(&auth, str,
  1078. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  1079. DWORD dwSslAccess;
  1080. if (!key.Succeeded())
  1081. return key.QueryResult();
  1082. if ( SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess))
  1083. && dwSslAccess > 0
  1084. )
  1085. {
  1086. key.SetValue(MD_SSL_ACCESS_PERM, 0);
  1087. }
  1088. // Now we need to remove SSL setting from any virtual directory below
  1089. CError err;
  1090. CStringListEx data_paths;
  1091. DWORD
  1092. dwMDIdentifier,
  1093. dwMDAttributes,
  1094. dwMDUserType,
  1095. dwMDDataType;
  1096. VERIFY(CMetaKey::GetMDFieldDef(
  1097. MD_SSL_ACCESS_PERM,
  1098. dwMDIdentifier,
  1099. dwMDAttributes,
  1100. dwMDUserType,
  1101. dwMDDataType
  1102. ));
  1103. err = key.GetDataPaths(
  1104. data_paths,
  1105. dwMDIdentifier,
  1106. dwMDDataType
  1107. );
  1108. if (err.Succeeded() && !data_paths.empty())
  1109. {
  1110. CStringListEx::iterator it = data_paths.begin();
  1111. while (it != data_paths.end())
  1112. {
  1113. CString& str = (*it++);
  1114. if ( SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess, NULL, str))
  1115. && dwSslAccess > 0
  1116. )
  1117. {
  1118. key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, str);
  1119. }
  1120. }
  1121. }
  1122. return key.QueryResult();
  1123. }
  1124. /*
  1125. InstallHashToMetabase
  1126. Function writes hash array to metabase. After that IIS
  1127. could use certificate with that hash from MY store.
  1128. Function expects server_name in format lm\w3svc\<number>,
  1129. i.e. from root node down to virtual server
  1130. */
  1131. BOOL
  1132. InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,
  1133. BSTR InstanceName,
  1134. HRESULT * phResult)
  1135. {
  1136. BOOL bRes = FALSE;
  1137. CComAuthInfo auth;
  1138. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR; // SZ_MBN_WEB SZ_MBN_SEP_STR;
  1139. key_path += InstanceName;
  1140. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  1141. if (key.Succeeded())
  1142. {
  1143. CBlob blob;
  1144. blob.SetValue(pHash->cbData, pHash->pbData, TRUE);
  1145. bRes = SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_HASH, blob))
  1146. && SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_STORE_NAME, CString(L"MY")));
  1147. }
  1148. else
  1149. {
  1150. ATLTRACE(_T("Failed to open metabase key. Error 0x%x\n"), key.QueryResult());
  1151. *phResult = key.QueryResult();
  1152. }
  1153. return bRes;
  1154. }
  1155. #ifdef FULL_OBJECT
  1156. HRESULT CIISCertObj::CreateDNString(CString& str)
  1157. {
  1158. str = _T("");
  1159. str += _T("CN=") + m_CommonName;
  1160. str += _T("\n,OU=") + m_OrganizationUnit;
  1161. str += _T("\n,O=") + m_Organization;
  1162. str += _T("\n,L=") + m_Locality;
  1163. str += _T("\n,S=") + m_State;
  1164. str += _T("\n,C=") + m_Country;
  1165. return S_OK;
  1166. }
  1167. #endif
  1168. CERT_CONTEXT *
  1169. CIISCertObj::GetInstalledCert(HRESULT * phResult)
  1170. {
  1171. // ATLASSERT(GetEnroll() != NULL);
  1172. ATLASSERT(phResult != NULL);
  1173. CERT_CONTEXT * pCert = NULL;
  1174. *phResult = S_OK;
  1175. CComAuthInfo auth;
  1176. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;// SZ_MBN_WEB SZ_MBN_SEP_STR;
  1177. key_path += m_InstanceName;
  1178. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  1179. if (key.Succeeded())
  1180. {
  1181. CString store_name;
  1182. CBlob hash;
  1183. if ( SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
  1184. && SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash))
  1185. )
  1186. {
  1187. // Open MY store. We assume that store type and flags
  1188. // cannot be changed between installation and unistallation
  1189. // of the sertificate.
  1190. HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
  1191. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1192. NULL,
  1193. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1194. store_name
  1195. );
  1196. ASSERT(hStore != NULL);
  1197. if (hStore != NULL)
  1198. {
  1199. // Now we need to find cert by hash
  1200. CRYPT_HASH_BLOB crypt_hash;
  1201. crypt_hash.cbData = hash.GetSize();
  1202. crypt_hash.pbData = hash.GetData();
  1203. pCert = (CERT_CONTEXT *)CertFindCertificateInStore(hStore,
  1204. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1205. 0, CERT_FIND_HASH, (LPVOID)&crypt_hash, NULL);
  1206. if (pCert == NULL)
  1207. {
  1208. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1209. }
  1210. VERIFY(CertCloseStore(hStore, 0));
  1211. }
  1212. else
  1213. {
  1214. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1215. }
  1216. }
  1217. }
  1218. else
  1219. {
  1220. *phResult = key.QueryResult();
  1221. }
  1222. return pCert;
  1223. }
  1224. HRESULT
  1225. CIISCertObj::UninstallCert()
  1226. {
  1227. CComAuthInfo auth;
  1228. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;// SZ_MBN_WEB SZ_MBN_SEP_STR;
  1229. key_path += m_InstanceName;
  1230. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  1231. if (key.Succeeded())
  1232. {
  1233. CString store_name;
  1234. key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name);
  1235. if (SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH)))
  1236. key.DeleteValue(MD_SSL_CERT_STORE_NAME);
  1237. }
  1238. return key.QueryResult();
  1239. }
  1240. IIISCertObj *
  1241. CIISCertObj::GetObject(HRESULT * phr)
  1242. {
  1243. TCHAR tszTempString[200];
  1244. if (m_pObj == NULL && !m_ServerName.IsEmpty())
  1245. {
  1246. if (IsServerLocal(m_ServerName))
  1247. {
  1248. _stprintf(tszTempString, _T("GetObject:returns:server is local\n"));OutputDebugString(tszTempString);
  1249. return this;
  1250. }
  1251. else
  1252. {
  1253. CComAuthInfo auth(m_ServerName, m_UserName, m_UserPassword);
  1254. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct();
  1255. MULTI_QI res[1] = {
  1256. {&__uuidof(IIISCertObj), NULL, 0}
  1257. };
  1258. _stprintf(tszTempString, _T("GetObject:calling CoCreateInstanceEx\n"));OutputDebugString(tszTempString);
  1259. *phr = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_SERVER,pcsiName,1,res);
  1260. if (SUCCEEDED(*phr))
  1261. {
  1262. m_pObj = (IIISCertObj *)res[0].pItf;
  1263. if (auth.UsesImpersonation())
  1264. {
  1265. OutputDebugString(_T("UsesImpersonation!!!\n"));
  1266. auth.ApplyProxyBlanket(m_pObj);
  1267. }
  1268. else
  1269. {
  1270. OutputDebugString(_T("No use of UsesImpersonation\n"));
  1271. }
  1272. }
  1273. else
  1274. {
  1275. OutputDebugString(_T("CoCreateInstanceEx on CLSID_IISCertObj failed!\n"));
  1276. // *phr that gets returned back is the error...
  1277. }
  1278. auth.FreeServerInfoStruct(pcsiName);
  1279. }
  1280. }
  1281. else
  1282. {
  1283. if (m_ServerName.IsEmpty())
  1284. {
  1285. _stprintf(tszTempString, _T("GetObject:returns:server is local\n"));OutputDebugString(tszTempString);
  1286. // object is null, but it's the local machine, so
  1287. // just return back this pointer
  1288. return this;
  1289. }
  1290. else
  1291. {
  1292. _stprintf(tszTempString, _T("GetObject:returns whatever was already there\n"));OutputDebugString(tszTempString);
  1293. // object is not null so, we don't have to pass anything back
  1294. // the m_pObj already contains something...
  1295. }
  1296. }
  1297. //ASSERT(m_pObj != NULL);
  1298. return m_pObj;
  1299. }
  1300. IIISCertObj *
  1301. CIISCertObj::GetObject(HRESULT * phr, CString csServerName,CString csUserName OPTIONAL,CString csUserPassword OPTIONAL)
  1302. {
  1303. IIISCertObj * pObj = NULL;
  1304. if (!csUserName.IsEmpty())
  1305. {
  1306. if (IsServerLocal(csServerName))
  1307. {
  1308. return this;
  1309. }
  1310. else
  1311. {
  1312. CComAuthInfo auth(csServerName, csUserName, csUserPassword);
  1313. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct();
  1314. MULTI_QI res[1] = {
  1315. {&__uuidof(IIISCertObj), NULL, 0}
  1316. };
  1317. *phr = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_SERVER,pcsiName,1,res);
  1318. if (SUCCEEDED(*phr))
  1319. {
  1320. pObj = (IIISCertObj *)res[0].pItf;
  1321. if (auth.UsesImpersonation())
  1322. {
  1323. auth.ApplyProxyBlanket(pObj);
  1324. }
  1325. }
  1326. auth.FreeServerInfoStruct(pcsiName);
  1327. }
  1328. }
  1329. return pObj;
  1330. }
  1331. BOOL
  1332. AddChainToStore(
  1333. HCERTSTORE hCertStore,
  1334. PCCERT_CONTEXT pCertContext,
  1335. DWORD cStores,
  1336. HCERTSTORE * rghStores,
  1337. BOOL fDontAddRootCert,
  1338. CERT_TRUST_STATUS * pChainTrustStatus)
  1339. {
  1340. DWORD i;
  1341. CERT_CHAIN_ENGINE_CONFIG CertChainEngineConfig;
  1342. HCERTCHAINENGINE hCertChainEngine = NULL;
  1343. PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
  1344. CERT_CHAIN_PARA CertChainPara;
  1345. BOOL fRet = TRUE;
  1346. PCCERT_CONTEXT pTempCertContext = NULL;
  1347. //
  1348. // create a new chain engine, then build the chain
  1349. //
  1350. memset(&CertChainEngineConfig, 0, sizeof(CertChainEngineConfig));
  1351. CertChainEngineConfig.cbSize = sizeof(CertChainEngineConfig);
  1352. CertChainEngineConfig.cAdditionalStore = cStores;
  1353. CertChainEngineConfig.rghAdditionalStore = rghStores;
  1354. CertChainEngineConfig.dwFlags = CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
  1355. if (!CertCreateCertificateChainEngine(&CertChainEngineConfig, &hCertChainEngine))
  1356. {
  1357. goto ErrorReturn;
  1358. }
  1359. memset(&CertChainPara, 0, sizeof(CertChainPara));
  1360. CertChainPara.cbSize = sizeof(CertChainPara);
  1361. if (!CertGetCertificateChain(
  1362. hCertChainEngine,
  1363. pCertContext,
  1364. NULL,
  1365. NULL,
  1366. &CertChainPara,
  1367. 0,
  1368. NULL,
  1369. &pCertChainContext))
  1370. {
  1371. goto ErrorReturn;
  1372. }
  1373. //
  1374. // make sure there is atleast 1 simple chain
  1375. //
  1376. if (pCertChainContext->cChain != 0)
  1377. {
  1378. i = 0;
  1379. while (i < pCertChainContext->rgpChain[0]->cElement)
  1380. {
  1381. //
  1382. // if we are supposed to skip the root cert,
  1383. // and we are on the root cert, then continue
  1384. //
  1385. if (fDontAddRootCert &&
  1386. (pCertChainContext->rgpChain[0]->rgpElement[i]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED))
  1387. {
  1388. i++;
  1389. continue;
  1390. }
  1391. CertAddCertificateContextToStore(
  1392. hCertStore,
  1393. pCertChainContext->rgpChain[0]->rgpElement[i]->pCertContext,
  1394. CERT_STORE_ADD_REPLACE_EXISTING,
  1395. &pTempCertContext);
  1396. //
  1397. // remove any private key property the certcontext may have on it.
  1398. //
  1399. if (pTempCertContext)
  1400. {
  1401. CertSetCertificateContextProperty(
  1402. pTempCertContext,
  1403. CERT_KEY_PROV_INFO_PROP_ID,
  1404. 0,
  1405. NULL);
  1406. CertFreeCertificateContext(pTempCertContext);
  1407. }
  1408. i++;
  1409. }
  1410. }
  1411. else
  1412. {
  1413. goto ErrorReturn;
  1414. }
  1415. //
  1416. // if the caller wants the status, then set it
  1417. //
  1418. if (pChainTrustStatus != NULL)
  1419. {
  1420. pChainTrustStatus->dwErrorStatus = pCertChainContext->TrustStatus.dwErrorStatus;
  1421. pChainTrustStatus->dwInfoStatus = pCertChainContext->TrustStatus.dwInfoStatus;
  1422. }
  1423. Ret:
  1424. if (pCertChainContext != NULL)
  1425. {
  1426. CertFreeCertificateChain(pCertChainContext);
  1427. }
  1428. if (hCertChainEngine != NULL)
  1429. {
  1430. CertFreeCertificateChainEngine(hCertChainEngine);
  1431. }
  1432. return fRet;
  1433. ErrorReturn:
  1434. fRet = FALSE;
  1435. goto Ret;
  1436. }
  1437. // This function is borrowed from trustapi.cpp
  1438. //
  1439. static BOOL
  1440. TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext,
  1441. DWORD dwEncoding,
  1442. DWORD dwFlags)
  1443. {
  1444. if (!(pContext) ||
  1445. (dwFlags != 0))
  1446. {
  1447. SetLastError(ERROR_INVALID_PARAMETER);
  1448. return(FALSE);
  1449. }
  1450. if (!(CertCompareCertificateName(dwEncoding,
  1451. &pContext->pCertInfo->Issuer,
  1452. &pContext->pCertInfo->Subject)))
  1453. {
  1454. return(FALSE);
  1455. }
  1456. DWORD dwFlag;
  1457. dwFlag = CERT_STORE_SIGNATURE_FLAG;
  1458. if (!(CertVerifySubjectCertificateContext(pContext, pContext, &dwFlag)) ||
  1459. (dwFlag & CERT_STORE_SIGNATURE_FLAG))
  1460. {
  1461. return(FALSE);
  1462. }
  1463. return(TRUE);
  1464. }
  1465. STDMETHODIMP
  1466. CIISCertObj::Copy(
  1467. BSTR bstrDestinationServerName,
  1468. BSTR bstrDestinationServerInstance,
  1469. BSTR bstrCertificatePassword,
  1470. VARIANT varDestinationServerUserName,
  1471. VARIANT varDestinationServerPassword)
  1472. {
  1473. return CopyOrMove(FALSE,bstrDestinationServerName,bstrDestinationServerInstance,bstrCertificatePassword,varDestinationServerUserName,varDestinationServerPassword);
  1474. }
  1475. STDMETHODIMP
  1476. CIISCertObj::Move(
  1477. BSTR bstrDestinationServerName,
  1478. BSTR bstrDestinationServerInstance,
  1479. BSTR bstrCertificatePassword,
  1480. VARIANT varDestinationServerUserName,
  1481. VARIANT varDestinationServerPassword)
  1482. {
  1483. return CopyOrMove(TRUE,bstrDestinationServerName,bstrDestinationServerInstance,bstrCertificatePassword,varDestinationServerUserName,varDestinationServerPassword);
  1484. }
  1485. HRESULT
  1486. CIISCertObj::CopyOrMove(
  1487. BOOL bRemoveFromCertAfterCopy,
  1488. BSTR bstrDestinationServerName,
  1489. BSTR bstrDestinationServerInstance,
  1490. BSTR bstrCertificatePassword,
  1491. VARIANT varDestinationServerUserName,
  1492. VARIANT varDestinationServerPassword
  1493. )
  1494. {
  1495. HRESULT hr = E_FAIL;
  1496. DWORD cbEncodedSize = 0;
  1497. char * pszEncodedString = NULL;
  1498. BOOL bBase64Encoded = TRUE;
  1499. BOOL bGuessingUserNamePass = FALSE;
  1500. DWORD blob_cbData;
  1501. BYTE * blob_pbData = NULL;
  1502. BOOL blob_freeme = FALSE;
  1503. BOOL bPrivateKey = TRUE;
  1504. BOOL bCertChain = FALSE;
  1505. CString csDestinationServerName = bstrDestinationServerName;
  1506. CString csDestinationServerUserName;
  1507. CString csDestinationServerUserPassword;
  1508. IIISCertObj * pObj = NULL;
  1509. IIISCertObj * pObj2 = NULL;
  1510. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  1511. TCHAR tszTempString[200];
  1512. _stprintf(tszTempString, _T("Copy:Start\n"));OutputDebugString(tszTempString);
  1513. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1514. if (V_VT(&varDestinationServerUserName) != VT_ERROR)
  1515. {
  1516. _stprintf(tszTempString, _T("Copy:1\n"));OutputDebugString(tszTempString);
  1517. VARIANT varBstrUserName;
  1518. VariantInit(&varBstrUserName);
  1519. HRESULT hr = VariantChangeType(&varBstrUserName, &varDestinationServerUserName, 0, VT_BSTR);
  1520. if (FAILED(hr)){goto Copy_Exit;}
  1521. csDestinationServerUserName = V_BSTR(&varBstrUserName);
  1522. VariantClear(&varBstrUserName);
  1523. }
  1524. else
  1525. {
  1526. _stprintf(tszTempString, _T("Copy:ServerUserName was empty!\n"));OutputDebugString(tszTempString);
  1527. // it's empty so don't use it
  1528. //csDestinationServerUserName = varDestinationServerUserName;
  1529. bGuessingUserNamePass = TRUE;
  1530. csDestinationServerUserName = m_UserName;
  1531. }
  1532. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1533. if (V_VT(&varDestinationServerPassword) != VT_ERROR)
  1534. {
  1535. _stprintf(tszTempString, _T("Copy:3\n"));OutputDebugString(tszTempString);
  1536. VARIANT varBstrUserPassword;
  1537. VariantInit(&varBstrUserPassword);
  1538. HRESULT hr = VariantChangeType(&varBstrUserPassword, &varDestinationServerPassword, 0, VT_BSTR);
  1539. if (FAILED(hr)){goto Copy_Exit;}
  1540. csDestinationServerUserName = V_BSTR(&varBstrUserPassword);
  1541. VariantClear(&varBstrUserPassword);
  1542. }
  1543. else
  1544. {
  1545. _stprintf(tszTempString, _T("Copy:ServerUserPassword was empty!\n"));OutputDebugString(tszTempString);
  1546. if (TRUE == bGuessingUserNamePass)
  1547. {
  1548. csDestinationServerUserPassword = m_UserPassword;
  1549. }
  1550. else
  1551. {
  1552. // maybe the password was intended to be empty!
  1553. }
  1554. }
  1555. // --------------------------
  1556. // step 1.
  1557. // 1st of all check if we have access to
  1558. // both the servers!!!!
  1559. // --------------------------
  1560. // 1st we have to get the certblob from the Server#1
  1561. // so call export to get the data
  1562. _stprintf(tszTempString, _T("Copy:5\n"));OutputDebugString(tszTempString);
  1563. hr = S_OK;
  1564. pObj = GetObject(&hr);
  1565. if (FAILED(hr))
  1566. {
  1567. return(hr);
  1568. }
  1569. // Logon to that server's CertObj.dll with the credentials supplied...
  1570. //
  1571. // if there were no credential's supplied then just use the ones that are in our object....
  1572. //
  1573. // if that doesn't work then try just the logged on user.
  1574. _stprintf(tszTempString, _T("Copy:6\n"));OutputDebugString(tszTempString);
  1575. pObj2 = GetObject(&hr,csDestinationServerName,csDestinationServerUserName,csDestinationServerUserPassword);
  1576. if (FAILED(hr))
  1577. {
  1578. _stprintf(tszTempString, _T("Copy:7\n"));OutputDebugString(tszTempString);
  1579. if (TRUE == bGuessingUserNamePass)
  1580. {
  1581. _stprintf(tszTempString, _T("Copy:8\n"));OutputDebugString(tszTempString);
  1582. // try something else.
  1583. }
  1584. goto Copy_Exit;
  1585. }
  1586. // -----------------------------------
  1587. // step 2.
  1588. // okay we have access to both servers
  1589. // Grab the cert from server #1
  1590. // -----------------------------------
  1591. // Get data from the remote/local iis store return it back as a blob.
  1592. // The blob could be returned back as Base64 encoded so check that flag
  1593. hr = ExportToBlobProxy(pObj, bstrInstanceName, bstrCertificatePassword, bPrivateKey, bCertChain, &bBase64Encoded, &cbEncodedSize, &pszEncodedString);
  1594. if (FAILED(hr))
  1595. {
  1596. goto Copy_Exit;
  1597. }
  1598. // if it's passed back to us a encoded then let's decode it
  1599. if (bBase64Encoded)
  1600. {
  1601. int err;
  1602. // The data we got back was Base64 encoded to remove nulls.
  1603. // we need to decode it back to it's original format.
  1604. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  1605. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  1606. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  1607. {
  1608. SetLastError(err);
  1609. hr = HRESULT_FROM_WIN32(err);
  1610. return hr;
  1611. }
  1612. blob_freeme = TRUE;
  1613. }
  1614. else
  1615. {
  1616. blob_cbData = cbEncodedSize;
  1617. blob_pbData = (BYTE*) pszEncodedString;
  1618. }
  1619. // -----------------------------------
  1620. // step 3.
  1621. // okay we have access to both servers
  1622. // we have the cert blob from server#1 in memory
  1623. // now we need to push this blob into the server#2
  1624. // -----------------------------------
  1625. hr = ImportFromBlobProxy(pObj2, bstrDestinationServerInstance, bstrCertificatePassword, blob_cbData, blob_pbData);
  1626. if (FAILED(hr))
  1627. {
  1628. goto Copy_Exit;
  1629. }
  1630. _stprintf(tszTempString, _T("Copy:ImportFromBlobProxy succeeded\n"));OutputDebugString(tszTempString);
  1631. // we successfully copied the cert from machine #1 to machine #2.
  1632. // lets see if we need to delete the original cert!.
  1633. if (TRUE == bRemoveFromCertAfterCopy)
  1634. {
  1635. hr = pObj->RemoveCert(bstrInstanceName, bPrivateKey);
  1636. if (FAILED(hr))
  1637. {
  1638. goto Copy_Exit;
  1639. }
  1640. }
  1641. hr = S_OK;
  1642. Copy_Exit:
  1643. if (blob_freeme){if (blob_pbData != NULL){free(blob_pbData);blob_pbData=NULL;}}
  1644. if (pszEncodedString != NULL){CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;}
  1645. return hr;
  1646. }