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.

1621 lines
51 KiB

  1. // IISCertObj.cpp : Implementation of CIISCertObj
  2. #include "stdafx.h"
  3. #include "common.h"
  4. #include "CertObj.h"
  5. #include "IISCertObj.h"
  6. #include "base64.h"
  7. #include "password.h"
  8. #include "certutil.h"
  9. #include "certobjlog.h"
  10. #include "certlog.h"
  11. #define TEMP_PASSWORD_LENGTH 50
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CIISCertObj
  14. STDMETHODIMP CIISCertObj::put_ServerName(BSTR newVal)
  15. {
  16. // buffer overflow paranoia, make sure it's less than 255 characters long
  17. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  18. m_ServerName = newVal;
  19. return S_OK;
  20. }
  21. STDMETHODIMP CIISCertObj::put_UserName(BSTR newVal)
  22. {
  23. // buffer overflow paranoia, make sure it's less than 255 characters long
  24. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  25. m_UserName = newVal;
  26. return S_OK;
  27. }
  28. STDMETHODIMP CIISCertObj::put_UserPassword(BSTR newVal)
  29. {
  30. // buffer overflow paranoia, make sure it's less than 255 characters long
  31. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  32. m_UserPassword = newVal;
  33. return S_OK;
  34. }
  35. STDMETHODIMP CIISCertObj::put_InstanceName(BSTR newVal)
  36. {
  37. // buffer overflow paranoia, make sure it's less than 255 characters long
  38. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  39. m_InstanceName = newVal;
  40. return S_OK;
  41. }
  42. IIISCertObj * CIISCertObj::GetObject(HRESULT * phr)
  43. {
  44. IIISCertObj * pObj = NULL;
  45. pObj = GetObject(phr,m_ServerName,m_UserName,m_UserPassword);
  46. return pObj;
  47. }
  48. IIISCertObj * CIISCertObj::GetObject(HRESULT * phr,CString csServerName,CString csUserName,CString csUserPassword)
  49. {
  50. if (csServerName.IsEmpty())
  51. {
  52. // object is null, but it's the local machine, so just return back this pointer
  53. m_pObj = this;
  54. goto GetObject_Exit;
  55. }
  56. // There is a servername specified...
  57. // check if it's the local machine that was specified!
  58. if (IsServerLocal(csServerName))
  59. {
  60. m_pObj = this;
  61. goto GetObject_Exit;
  62. }
  63. else
  64. {
  65. // there is a remote servername specified
  66. // let's see if the machine has the com object that we want....
  67. // we are using the user/name password that are in this object
  68. // so were probably on the local machine
  69. CComAuthInfo auth(csServerName,csUserName,csUserPassword);
  70. // RPC_C_AUTHN_LEVEL_DEFAULT 0
  71. // RPC_C_AUTHN_LEVEL_NONE 1
  72. // RPC_C_AUTHN_LEVEL_CONNECT 2
  73. // RPC_C_AUTHN_LEVEL_CALL 3
  74. // RPC_C_AUTHN_LEVEL_PKT 4
  75. // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
  76. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
  77. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  78. MULTI_QI res[1] =
  79. {
  80. {&__uuidof(IIISCertObj), NULL, 0}
  81. };
  82. // Try to instantiante the object on the remote server...
  83. // with the supplied authentication info (pcsiName)
  84. //#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)
  85. //#define CLSCTX_ALL (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER)
  86. //if (NULL == pcsiName){IISDebugOutput(_T("CIISCertObj::GetObject:pcsiName=NULL failed!!!\n"));}
  87. // this one seems to work with surrogates..
  88. *phr = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
  89. if (FAILED(*phr))
  90. {
  91. //IISDebugOutput(_T("CoCreateInstanceEx on CLSID_IISCertObj failed! code=0x%x\n"),*phr);
  92. IISDebugOutput(_T("CIISCertObj::GetObject:CoCreateInstanceEx failed:0x%x, csServerName=%s,csUserName=%s,csUserPassword=%s\n"),*phr,(LPCTSTR) csServerName,(LPCTSTR) csUserName,(LPCTSTR) csUserPassword);
  93. goto GetObject_Exit;
  94. }
  95. // at this point we were able to instantiate the com object on the server (local or remote)
  96. m_pObj = (IIISCertObj *)res[0].pItf;
  97. if (auth.UsesImpersonation())
  98. {
  99. *phr = auth.ApplyProxyBlanket(m_pObj);
  100. }
  101. auth.FreeServerInfoStruct(pcsiName);
  102. }
  103. GetObject_Exit:
  104. //ASSERT(m_pObj != NULL);
  105. return m_pObj;
  106. }
  107. STDMETHODIMP CIISCertObj::IsInstalled(VARIANT_BOOL * retval)
  108. {
  109. HRESULT hr = S_OK;
  110. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  111. // Check mandatory properties
  112. if (bstrInstanceName == NULL || *bstrInstanceName == 0 || retval == NULL)
  113. {
  114. return ERROR_INVALID_PARAMETER;
  115. }
  116. // ------------------------
  117. // buffer overflow paranoia
  118. // check all parameters...
  119. // ------------------------
  120. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  121. CString csServerName = m_ServerName;
  122. if (csServerName.IsEmpty())
  123. {
  124. hr = IsInstalledRemote(retval);
  125. goto IsInstalled_Exit;
  126. }
  127. // There is a servername specified...
  128. // check if it's the local machine that was specified!
  129. if (IsServerLocal(csServerName))
  130. {
  131. hr = IsInstalledRemote(retval);
  132. goto IsInstalled_Exit;
  133. }
  134. // this must be a remote machine
  135. {
  136. //ASSERT(GetObject(&hr) != NULL);
  137. IIISCertObj * pObj;
  138. if (NULL != (pObj = GetObject(&hr)))
  139. {
  140. hr = pObj->put_InstanceName(bstrInstanceName);
  141. if (SUCCEEDED(hr))
  142. {
  143. hr = pObj->IsInstalledRemote(retval);
  144. }
  145. }
  146. }
  147. IsInstalled_Exit:
  148. return hr;
  149. }
  150. STDMETHODIMP CIISCertObj::IsInstalledRemote(VARIANT_BOOL * retval)
  151. {
  152. HRESULT hr = S_OK;
  153. CERT_CONTEXT * pCertContext = NULL;
  154. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  155. // Check mandatory properties
  156. if (bstrInstanceName == NULL || *bstrInstanceName == 0 || retval == NULL)
  157. {
  158. return ERROR_INVALID_PARAMETER;
  159. }
  160. // ------------------------
  161. // buffer overflow paranoia
  162. // check all parameters...
  163. // ------------------------
  164. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  165. pCertContext = GetInstalledCert(&hr,bstrInstanceName);
  166. if (FAILED(hr) || NULL == pCertContext)
  167. {
  168. hr = S_OK;
  169. *retval = FALSE;
  170. }
  171. else
  172. {
  173. hr = S_OK;
  174. *retval = TRUE;
  175. CertFreeCertificateContext(pCertContext);
  176. }
  177. return hr;
  178. }
  179. STDMETHODIMP CIISCertObj::IsExportable(VARIANT_BOOL * retval)
  180. {
  181. HRESULT hr = S_OK;
  182. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  183. // Check mandatory properties
  184. if (bstrInstanceName == NULL || *bstrInstanceName == 0 || retval == NULL)
  185. {
  186. return ERROR_INVALID_PARAMETER;
  187. }
  188. // ------------------------
  189. // buffer overflow paranoia
  190. // check all parameters...
  191. // ------------------------
  192. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  193. CString csServerName = m_ServerName;
  194. if (csServerName.IsEmpty())
  195. {
  196. hr = IsExportableRemote(retval);
  197. goto IsExportable_Exit;
  198. }
  199. // There is a servername specified...
  200. // check if it's the local machine that was specified!
  201. if (IsServerLocal(csServerName))
  202. {
  203. hr = IsExportableRemote(retval);
  204. goto IsExportable_Exit;
  205. }
  206. // this must be a remote machine
  207. {
  208. //ASSERT(GetObject(&hr) != NULL);
  209. IIISCertObj * pObj;
  210. if (NULL != (pObj = GetObject(&hr)))
  211. {
  212. hr = pObj->put_InstanceName(bstrInstanceName);
  213. if (SUCCEEDED(hr))
  214. {
  215. hr = pObj->IsExportableRemote(retval);
  216. }
  217. }
  218. }
  219. IsExportable_Exit:
  220. return hr;
  221. }
  222. STDMETHODIMP CIISCertObj::IsExportableRemote(VARIANT_BOOL * retval)
  223. {
  224. HRESULT hr = S_OK;
  225. CERT_CONTEXT * pCertContext = NULL;
  226. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  227. // Check mandatory properties
  228. if (bstrInstanceName == NULL || *bstrInstanceName == 0 || retval == NULL)
  229. {
  230. return ERROR_INVALID_PARAMETER;
  231. }
  232. // ------------------------
  233. // buffer overflow paranoia
  234. // check all parameters...
  235. // ------------------------
  236. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  237. pCertContext = GetInstalledCert(&hr,bstrInstanceName);
  238. if (FAILED(hr) || NULL == pCertContext)
  239. {
  240. hr = S_OK;
  241. *retval = FALSE;
  242. }
  243. else
  244. {
  245. // check if it's exportable!
  246. hr = S_OK;
  247. if (TRUE == IsCertExportable(pCertContext))
  248. {
  249. *retval = TRUE;
  250. }
  251. else
  252. {
  253. *retval = FALSE;
  254. }
  255. if (pCertContext) {CertFreeCertificateContext(pCertContext);}
  256. }
  257. return hr;
  258. }
  259. STDMETHODIMP CIISCertObj::GetCertInfo(VARIANT * pVtArray)
  260. {
  261. HRESULT hr = ERROR_CALL_NOT_IMPLEMENTED;
  262. CERT_CONTEXT * pCertContext = NULL;
  263. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  264. // Check mandatory properties
  265. if (bstrInstanceName == NULL || *bstrInstanceName == 0)
  266. {
  267. return ERROR_INVALID_PARAMETER;
  268. }
  269. // ------------------------
  270. // buffer overflow paranoia
  271. // check all parameters...
  272. // ------------------------
  273. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  274. CString csServerName = m_ServerName;
  275. if (csServerName.IsEmpty())
  276. {
  277. hr = GetCertInfoRemote(pVtArray);
  278. goto GetCertInfo_Exit;
  279. }
  280. // There is a servername specified...
  281. // check if it's the local machine that was specified!
  282. if (IsServerLocal(csServerName))
  283. {
  284. hr = GetCertInfoRemote(pVtArray);
  285. goto GetCertInfo_Exit;
  286. }
  287. // this must be a remote machine
  288. {
  289. //ASSERT(GetObject(&hr) != NULL);
  290. IIISCertObj * pObj;
  291. if (NULL != (pObj = GetObject(&hr)))
  292. {
  293. hr = pObj->put_InstanceName(bstrInstanceName);
  294. if (SUCCEEDED(hr))
  295. {
  296. hr = pObj->GetCertInfoRemote(pVtArray);
  297. }
  298. }
  299. }
  300. GetCertInfo_Exit:
  301. return hr;
  302. }
  303. STDMETHODIMP CIISCertObj::GetCertInfoRemote(VARIANT * pVtArray)
  304. {
  305. HRESULT hr = ERROR_CALL_NOT_IMPLEMENTED;
  306. CERT_CONTEXT * pCertContext = NULL;
  307. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  308. // Check mandatory properties
  309. if (bstrInstanceName == NULL || *bstrInstanceName == 0)
  310. {
  311. return ERROR_INVALID_PARAMETER;
  312. }
  313. // ------------------------
  314. // buffer overflow paranoia
  315. // check all parameters...
  316. // ------------------------
  317. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  318. pCertContext = GetInstalledCert(&hr,bstrInstanceName);
  319. if (FAILED(hr) || NULL == pCertContext)
  320. {
  321. hr = S_FALSE;
  322. }
  323. else
  324. {
  325. DWORD cb = 0;
  326. LPWSTR pwszText = NULL;
  327. if (TRUE == GetCertDescription(pCertContext,&pwszText,&cb,TRUE))
  328. {
  329. hr = S_OK;
  330. hr = HereIsBinaryGimmieVtArray(cb * sizeof(WCHAR),(char *) pwszText,pVtArray,FALSE);
  331. }
  332. else
  333. {
  334. hr = S_FALSE;
  335. }
  336. }
  337. if (pCertContext) {CertFreeCertificateContext(pCertContext);}
  338. return hr;
  339. }
  340. STDMETHODIMP CIISCertObj::RemoveCert(BOOL bPrivateKey)
  341. {
  342. HRESULT hr = E_FAIL;
  343. PCCERT_CONTEXT pCertContext = NULL;
  344. DWORD cbKpi = 0;
  345. PCRYPT_KEY_PROV_INFO pKpi = NULL ;
  346. HCRYPTPROV hCryptProv = NULL;
  347. BOOL bPleaseLogFailure = FALSE;
  348. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  349. // Check mandatory properties
  350. if (bstrInstanceName == NULL || *bstrInstanceName == 0)
  351. {
  352. return ERROR_INVALID_PARAMETER;
  353. }
  354. // ------------------------
  355. // buffer overflow paranoia
  356. // check all parameters...
  357. // ------------------------
  358. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  359. do
  360. {
  361. // get the certificate from the server
  362. pCertContext = GetInstalledCert(&hr,bstrInstanceName);
  363. if (NULL == pCertContext)
  364. {
  365. break;
  366. }
  367. bPleaseLogFailure = TRUE;
  368. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbKpi))
  369. {
  370. hr = HRESULT_FROM_WIN32(GetLastError());
  371. break;
  372. }
  373. pKpi = ( PCRYPT_KEY_PROV_INFO ) malloc( cbKpi );
  374. if ( NULL != pKpi )
  375. {
  376. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, (void *)pKpi, &cbKpi))
  377. {
  378. hr = HRESULT_FROM_WIN32(GetLastError());
  379. break;
  380. }
  381. // Delete the key container
  382. if (!CryptAcquireContext(&hCryptProv,pKpi->pwszContainerName,pKpi->pwszProvName,pKpi->dwProvType,pKpi->dwFlags | CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET))
  383. {
  384. hr = HRESULT_FROM_WIN32(GetLastError());
  385. break;
  386. }
  387. if (NULL != pKpi){free(pKpi);}
  388. if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, NULL))
  389. {
  390. hr = HRESULT_FROM_WIN32(GetLastError());
  391. break;
  392. }
  393. }
  394. // uninstall the certificate from the site, reset SSL flag
  395. // if we are exporting the private key, remove the cert from the storage
  396. // and delete private key
  397. UninstallCert(bstrInstanceName);
  398. // remove ssl key from metabase
  399. CString str = bstrInstanceName;
  400. ShutdownSSL(str);
  401. // delete the private key
  402. if (bPrivateKey)
  403. {
  404. PCCERT_CONTEXT pcDup = NULL ;
  405. pcDup = CertDuplicateCertificateContext(pCertContext);
  406. if (pcDup)
  407. {
  408. if (!CertDeleteCertificateFromStore(pcDup))
  409. {
  410. hr = HRESULT_FROM_WIN32(GetLastError());
  411. break;
  412. }
  413. }
  414. else
  415. {
  416. hr = HRESULT_FROM_WIN32(GetLastError());
  417. }
  418. }
  419. hr = ERROR_SUCCESS;
  420. ReportIt(CERTOBJ_CERT_REMOVE_SUCCEED, bstrInstanceName);
  421. bPleaseLogFailure = FALSE;
  422. } while (FALSE);
  423. if (bPleaseLogFailure)
  424. {
  425. ReportIt(CERTOBJ_CERT_REMOVE_FAILED, bstrInstanceName);
  426. }
  427. if (pCertContext) {CertFreeCertificateContext(pCertContext);}
  428. return hr;
  429. }
  430. STDMETHODIMP CIISCertObj::Import(BSTR FileName, BSTR Password, BOOL bAllowExport)
  431. {
  432. HRESULT hr = S_OK;
  433. BYTE * pbData = NULL;
  434. DWORD actual = 0, cbData = 0;
  435. BOOL bPleaseLogFailure = FALSE;
  436. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  437. // Check mandatory properties
  438. if ( FileName == NULL || *FileName == 0
  439. || Password == NULL || *Password == 0
  440. || bstrInstanceName == NULL || *bstrInstanceName == 0)
  441. {
  442. return ERROR_INVALID_PARAMETER;
  443. }
  444. // ------------------------
  445. // buffer overflow paranoia
  446. // check all parameters...
  447. // ------------------------
  448. if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  449. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  450. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  451. if (hFile == INVALID_HANDLE_VALUE)
  452. {
  453. hr = HRESULT_FROM_WIN32(GetLastError());
  454. hFile = NULL;
  455. goto Import_Exit;
  456. }
  457. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  458. {
  459. hr = HRESULT_FROM_WIN32(GetLastError());
  460. goto Import_Exit;
  461. }
  462. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  463. {
  464. hr = E_OUTOFMEMORY;
  465. goto Import_Exit;
  466. }
  467. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  468. {
  469. IIISCertObj * pObj = GetObject(&hr);
  470. if (SUCCEEDED(hr))
  471. {
  472. bPleaseLogFailure = TRUE;
  473. hr = ImportFromBlobProxy(pObj, bstrInstanceName, Password, TRUE, bAllowExport, actual, pbData, 0, NULL);
  474. if (SUCCEEDED(hr))
  475. {
  476. ReportIt(CERTOBJ_CERT_IMPORT_SUCCEED, bstrInstanceName);
  477. bPleaseLogFailure = FALSE;
  478. }
  479. }
  480. }
  481. else
  482. {
  483. hr = HRESULT_FROM_WIN32(GetLastError());
  484. goto Import_Exit;
  485. }
  486. if (bPleaseLogFailure)
  487. {
  488. ReportIt(CERTOBJ_CERT_EXPORT_FAILED, bstrInstanceName);
  489. }
  490. Import_Exit:
  491. if (pbData != NULL)
  492. {
  493. ZeroMemory(pbData, cbData);
  494. ::CoTaskMemFree(pbData);
  495. }
  496. if (hFile != NULL){CloseHandle(hFile);}
  497. return hr;
  498. }
  499. STDMETHODIMP CIISCertObj::ImportToCertStore(BSTR FileName, BSTR Password, BOOL bAllowExport, VARIANT * pVtArray)
  500. {
  501. HRESULT hr = S_OK;
  502. BYTE * pbData = NULL;
  503. DWORD actual = 0, cbData = 0;
  504. BOOL bPleaseLogFailure = FALSE;
  505. BSTR bstrInstanceName = SysAllocString(_T("none"));
  506. // Check mandatory properties
  507. if ( FileName == NULL || *FileName == 0
  508. || Password == NULL || *Password == 0)
  509. {
  510. return ERROR_INVALID_PARAMETER;
  511. }
  512. // ------------------------
  513. // buffer overflow paranoia
  514. // check all parameters...
  515. // ------------------------
  516. if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  517. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  518. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  519. if (hFile == INVALID_HANDLE_VALUE)
  520. {
  521. hr = HRESULT_FROM_WIN32(GetLastError());
  522. hFile = NULL;
  523. goto Import_Exit;
  524. }
  525. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  526. {
  527. hr = HRESULT_FROM_WIN32(GetLastError());
  528. goto Import_Exit;
  529. }
  530. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  531. {
  532. hr = E_OUTOFMEMORY;
  533. goto Import_Exit;
  534. }
  535. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  536. {
  537. IIISCertObj * pObj = GetObject(&hr);
  538. if (SUCCEEDED(hr))
  539. {
  540. DWORD cbHashBufferSize = 0;
  541. char * pszHashBuffer = NULL;
  542. bPleaseLogFailure = TRUE;
  543. hr = ImportFromBlobProxy(pObj, bstrInstanceName, Password, FALSE, bAllowExport, actual, pbData, &cbHashBufferSize, &pszHashBuffer);
  544. if (SUCCEEDED(hr))
  545. {
  546. //ReportIt(CERTOBJ_CERT_IMPORT_CERT_STORE_SUCCEED, bstrInstanceName);
  547. bPleaseLogFailure = FALSE;
  548. //IISDebugOutput(_T("ImportFromBlobProxy: returned %d,%p\n"),cbHashBufferSize,pszHashBuffer);
  549. hr = HereIsBinaryGimmieVtArray(cbHashBufferSize,pszHashBuffer,pVtArray,FALSE);
  550. }
  551. // free the memory that was alloced for us
  552. if (0 != cbHashBufferSize)
  553. {
  554. if (pszHashBuffer)
  555. {
  556. ::CoTaskMemFree(pszHashBuffer);
  557. }
  558. }
  559. }
  560. }
  561. else
  562. {
  563. hr = HRESULT_FROM_WIN32(GetLastError());
  564. goto Import_Exit;
  565. }
  566. Import_Exit:
  567. if (bPleaseLogFailure)
  568. {
  569. //ReportIt(CERTOBJ_CERT_IMPORT_CERT_STORE_FAILED, bstrInstanceName);
  570. }
  571. if (pbData != NULL)
  572. {
  573. ZeroMemory(pbData, cbData);
  574. ::CoTaskMemFree(pbData);
  575. }
  576. if (hFile != NULL){CloseHandle(hFile);}
  577. return hr;
  578. }
  579. HRESULT ImportFromBlobWork(BSTR InstanceName,BSTR Password,BOOL bInstallToMetabase,BOOL bAllowExport, DWORD count,char *pData,DWORD *cbHashBufferSize,char **pbHashBuffer)
  580. {
  581. HRESULT hr = S_OK;
  582. CRYPT_DATA_BLOB blob;
  583. ZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
  584. LPTSTR pPass = Password;
  585. BOOL blob_freeme = FALSE;
  586. int err;
  587. // Check mandatory properties
  588. if ( Password == NULL || *Password == 0
  589. || InstanceName == NULL || *InstanceName == 0)
  590. {
  591. return ERROR_INVALID_PARAMETER;
  592. }
  593. // ------------------------
  594. // buffer overflow paranoia
  595. // check all parameters...
  596. // ------------------------
  597. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  598. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  599. // The data we got back was Base64 encoded to remove nulls.
  600. // we need to decode it back to it's original format.
  601. if( (err = Base64DecodeA(pData,count,NULL,&blob.cbData)) != ERROR_SUCCESS ||
  602. (blob.pbData = (BYTE *) malloc(blob.cbData)) == NULL ||
  603. (err = Base64DecodeA(pData,count,blob.pbData,&blob.cbData)) != ERROR_SUCCESS )
  604. {
  605. SetLastError(err);
  606. hr = HRESULT_FROM_WIN32(err);
  607. return hr;
  608. }
  609. blob_freeme = TRUE;
  610. if (!PFXVerifyPassword(&blob, pPass, 0))
  611. {
  612. // Try empty password
  613. if (pPass == NULL)
  614. {
  615. if (!PFXVerifyPassword(&blob, pPass = L'\0', 0))
  616. {
  617. hr = ERROR_INVALID_PARAMETER;
  618. }
  619. }
  620. else
  621. {
  622. hr = ERROR_INVALID_PARAMETER;
  623. }
  624. }
  625. if (SUCCEEDED(hr))
  626. {
  627. // CRYPT_EXPORTABLE - which would then specify that any imported keys should
  628. // be marked as exportable (see documentation on CryptImportKey)
  629. // CRYPT_USER_PROTECTED - (see documentation on CryptImportKey)
  630. // PKCS12_NO_DATA_COMMIT - will unpack the pfx blob but does not persist its contents.
  631. // In this case, returns BOOL indicating successful unpack.
  632. // CRYPT_MACHINE_KEYSET - used to force the private key to be stored in the
  633. // the local machine and not the current user.
  634. // CRYPT_USER_KEYSET - used to force the private key to be stored in the
  635. // the current user and not the local machine, even if
  636. // the pfx blob specifies that it should go into local machine.
  637. HCERTSTORE hStore = PFXImportCertStore(&blob, pPass, (bAllowExport ? CRYPT_MACHINE_KEYSET|CRYPT_EXPORTABLE : CRYPT_MACHINE_KEYSET));
  638. if (hStore != NULL)
  639. {
  640. //add the certificate with private key to my store; and the rest
  641. //to the ca store
  642. PCCERT_CONTEXT pCertContext = NULL;
  643. PCCERT_CONTEXT pCertPre = NULL;
  644. while ( SUCCEEDED(hr)
  645. && NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertPre))
  646. )
  647. {
  648. //check if the certificate has the property on it
  649. //make sure the private key matches the certificate
  650. //search for both machine key and user keys
  651. DWORD dwData = 0;
  652. if (CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData) && CryptFindCertificateKeyProvInfo(pCertContext, 0, NULL))
  653. {
  654. // This certificate should go to the My store
  655. HCERTSTORE hDestStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"MY");
  656. if (hDestStore != NULL)
  657. {
  658. // Put it to store
  659. if (CertAddCertificateContextToStore(hDestStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  660. {
  661. // Succeeded to put it to the storage
  662. hr = S_OK;
  663. // Install to metabase
  664. CRYPT_HASH_BLOB hash;
  665. if ( CertGetCertificateContextProperty(pCertContext,CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData)
  666. && NULL != (hash.pbData = (BYTE *)_alloca(hash.cbData))
  667. && CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData))
  668. {
  669. if (TRUE == bInstallToMetabase)
  670. {
  671. // returns error code in hr
  672. InstallHashToMetabase(&hash, InstanceName, &hr);
  673. }
  674. // check if we need to return back the hash
  675. if (NULL != pbHashBuffer)
  676. {
  677. *pbHashBuffer = (char *) ::CoTaskMemAlloc(hash.cbData);
  678. if (NULL == *pbHashBuffer)
  679. {
  680. hr = E_OUTOFMEMORY;
  681. *pbHashBuffer = NULL;
  682. *cbHashBufferSize = 0;
  683. }
  684. else
  685. {
  686. *cbHashBufferSize = hash.cbData;
  687. memcpy(*pbHashBuffer,hash.pbData,hash.cbData);
  688. }
  689. }
  690. }
  691. else
  692. {
  693. hr = HRESULT_FROM_WIN32(GetLastError());
  694. }
  695. }
  696. else
  697. {
  698. hr = HRESULT_FROM_WIN32(GetLastError());
  699. }
  700. CertCloseStore(hDestStore, 0);
  701. }
  702. else
  703. {
  704. hr = HRESULT_FROM_WIN32(GetLastError());
  705. }
  706. } // my store certificate
  707. //see if the certificate is self-signed.
  708. //if it is selfsigned, goes to the root store
  709. else if (TrustIsCertificateSelfSigned(pCertContext,pCertContext->dwCertEncodingType, 0))
  710. {
  711. //Put it to the root store
  712. HCERTSTORE hDestStore=CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"ROOT");
  713. if (hDestStore != NULL)
  714. {
  715. // Put it to store
  716. if (!CertAddCertificateContextToStore(hDestStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  717. {
  718. hr = HRESULT_FROM_WIN32(GetLastError());
  719. }
  720. CertCloseStore(hDestStore, 0);
  721. }
  722. else
  723. {
  724. hr = HRESULT_FROM_WIN32(GetLastError());
  725. }
  726. }
  727. else
  728. {
  729. //Put it to the CA store
  730. HCERTSTORE hDestStore=CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"CA");
  731. if (hDestStore != NULL)
  732. {
  733. // Put it to store
  734. if (!CertAddCertificateContextToStore(hDestStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  735. {
  736. hr = HRESULT_FROM_WIN32(GetLastError());
  737. }
  738. CertCloseStore(hDestStore, 0);
  739. }
  740. else
  741. {
  742. hr = HRESULT_FROM_WIN32(GetLastError());
  743. }
  744. }
  745. pCertPre = pCertContext;
  746. } //while
  747. CertCloseStore(hStore, 0);
  748. }
  749. else
  750. {
  751. hr = HRESULT_FROM_WIN32(GetLastError());
  752. }
  753. }
  754. //ImportFromBlobWork_Exit:
  755. if (blob_freeme)
  756. {
  757. if (blob.pbData != NULL)
  758. {
  759. ZeroMemory(blob.pbData, blob.cbData);
  760. free(blob.pbData);blob.pbData=NULL;
  761. }
  762. }
  763. return hr;
  764. }
  765. HRESULT CIISCertObj::ImportFromBlob(BSTR InstanceName,BSTR Password,BOOL bInstallToMetabase,BOOL bAllowExport,DWORD count,char *pData)
  766. {
  767. HRESULT hr;
  768. // Check mandatory properties
  769. if ( Password == NULL || *Password == 0
  770. || InstanceName == NULL || *InstanceName == 0)
  771. {
  772. return ERROR_INVALID_PARAMETER;
  773. }
  774. // ------------------------
  775. // buffer overflow paranoia
  776. // check all parameters...
  777. // ------------------------
  778. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  779. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  780. hr = ImportFromBlobWork(InstanceName,Password,bInstallToMetabase,bAllowExport,count,pData,0,NULL);
  781. return hr;
  782. }
  783. HRESULT CIISCertObj::ImportFromBlobGetHash(BSTR InstanceName,BSTR Password,BOOL bInstallToMetabase,BOOL bAllowExport,DWORD count,char *pData,DWORD *cbHashBufferSize,char **pbHashBuffer)
  784. {
  785. HRESULT hr;
  786. // Check mandatory properties
  787. if ( Password == NULL || *Password == 0
  788. || InstanceName == NULL || *InstanceName == 0)
  789. {
  790. return ERROR_INVALID_PARAMETER;
  791. }
  792. // ------------------------
  793. // buffer overflow paranoia
  794. // check all parameters...
  795. // ------------------------
  796. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  797. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  798. hr = ImportFromBlobWork(InstanceName,Password,bInstallToMetabase,bAllowExport,count,pData,cbHashBufferSize,pbHashBuffer);
  799. return hr;
  800. }
  801. STDMETHODIMP CIISCertObj::Export(BSTR FileName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,BOOL bRemoveCert)
  802. {
  803. HRESULT hr = S_OK;
  804. DWORD cbEncodedSize = 0;
  805. char * pszEncodedString = NULL;
  806. DWORD blob_cbData = 0;
  807. BYTE * blob_pbData = NULL;
  808. BOOL blob_freeme = FALSE;
  809. BOOL bPleaseLogFailure = FALSE;
  810. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  811. // Check mandatory properties
  812. if ( FileName == NULL || *FileName == 0
  813. || Password == NULL || *Password == 0
  814. || bstrInstanceName == NULL || *bstrInstanceName == 0)
  815. {
  816. return ERROR_INVALID_PARAMETER;
  817. }
  818. // ------------------------
  819. // buffer overflow paranoia
  820. // check all parameters...
  821. // ------------------------
  822. if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  823. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  824. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  825. IIISCertObj * pObj = GetObject(&hr);
  826. if (FAILED(hr))
  827. {
  828. goto Export_Exit;
  829. }
  830. // Call function go get data from the remote/local iis store
  831. // and return it back as a blob. the blob could be returned back as Base64 encoded
  832. // so check that flag
  833. hr = ExportToBlobProxy(pObj, bstrInstanceName, Password, bPrivateKey, bCertChain, &cbEncodedSize, &pszEncodedString);
  834. if (FAILED(hr))
  835. {
  836. goto Export_Exit;
  837. }
  838. // check if things are kool
  839. if (bRemoveCert)
  840. {
  841. hr = RemoveCertProxy(pObj,bstrInstanceName, bPrivateKey);
  842. if (FAILED(hr))
  843. {
  844. goto Export_Exit;
  845. }
  846. }
  847. if (SUCCEEDED(hr))
  848. {
  849. int err;
  850. bPleaseLogFailure = TRUE;
  851. // The data we got back was Base64 encoded to remove nulls.
  852. // we need to decode it back to it's original format.
  853. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  854. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  855. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  856. {
  857. SetLastError(err);
  858. hr = HRESULT_FROM_WIN32(err);
  859. return hr;
  860. }
  861. blob_freeme = TRUE;
  862. HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  863. if (INVALID_HANDLE_VALUE == hFile)
  864. {
  865. hr = HRESULT_FROM_WIN32(GetLastError());
  866. return hr;
  867. }
  868. DWORD written = 0;
  869. if (!WriteFile(hFile, blob_pbData, blob_cbData, &written, NULL))
  870. {
  871. hr = HRESULT_FROM_WIN32(GetLastError());
  872. }
  873. else
  874. {
  875. hr = S_OK;
  876. ReportIt(CERTOBJ_CERT_EXPORT_SUCCEED, bstrInstanceName);
  877. bPleaseLogFailure = FALSE;
  878. }
  879. CloseHandle(hFile);
  880. }
  881. Export_Exit:
  882. if (bPleaseLogFailure)
  883. {
  884. ReportIt(CERTOBJ_CERT_EXPORT_FAILED, bstrInstanceName);
  885. }
  886. if (pObj != NULL)
  887. {
  888. if (pObj != this)
  889. {
  890. pObj->Release();pObj=NULL;
  891. }
  892. }
  893. if (blob_freeme)
  894. {
  895. if (blob_pbData != NULL)
  896. {
  897. // Erase the memory that the private key used to be in!!!
  898. ZeroMemory(blob_pbData, blob_cbData);
  899. free(blob_pbData);blob_pbData=NULL;
  900. }
  901. }
  902. if (pszEncodedString != NULL)
  903. {
  904. // Erase the memory that the private key used to be in!!!
  905. ZeroMemory(pszEncodedString, cbEncodedSize);
  906. CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;
  907. }
  908. return hr;
  909. }
  910. STDMETHODIMP CIISCertObj::ExportToBlob(BSTR InstanceName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,DWORD *cbBufferSize,char **pbBuffer)
  911. {
  912. HRESULT hr = E_FAIL;
  913. PCCERT_CONTEXT pCertContext = NULL;
  914. BOOL bStatus = FALSE;
  915. HCERTSTORE hStore = NULL;
  916. DWORD dwOpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG;
  917. CRYPT_DATA_BLOB DataBlob;
  918. ZeroMemory(&DataBlob, sizeof(CRYPT_DATA_BLOB));
  919. char *pszB64Out = NULL;
  920. DWORD pcchB64Out = 0;
  921. DWORD err;
  922. DWORD dwExportFlags = EXPORT_PRIVATE_KEYS| REPORT_NO_PRIVATE_KEY;
  923. // Check mandatory properties
  924. if ( Password == NULL || *Password == 0
  925. || InstanceName == NULL || *InstanceName == 0)
  926. {
  927. return ERROR_INVALID_PARAMETER;
  928. }
  929. // ------------------------
  930. // buffer overflow paranoia
  931. // check all parameters...
  932. // ------------------------
  933. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  934. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  935. //
  936. // get the certificate from the server
  937. //
  938. pCertContext = GetInstalledCert(&hr,InstanceName);
  939. if (NULL == pCertContext)
  940. {
  941. *cbBufferSize = 0;
  942. pbBuffer = NULL;
  943. goto ExportToBlob_Exit;
  944. }
  945. //
  946. // Export cert
  947. //
  948. // Open a temporary store to stick the cert in.
  949. hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,dwOpenFlags,NULL);
  950. if(NULL == hStore)
  951. {
  952. *cbBufferSize = 0;
  953. pbBuffer = NULL;
  954. hr = HRESULT_FROM_WIN32(GetLastError());
  955. goto ExportToBlob_Exit;
  956. }
  957. //
  958. // get all the certs in the chain if we need to
  959. //
  960. if (bCertChain)
  961. {
  962. AddChainToStore(hStore, pCertContext, 0, 0, FALSE, NULL);
  963. }
  964. if(!CertAddCertificateContextToStore(hStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  965. {
  966. *cbBufferSize = 0;
  967. pbBuffer = NULL;
  968. hr = HRESULT_FROM_WIN32(GetLastError());
  969. goto ExportToBlob_Exit;
  970. }
  971. // free cert context since we no longer need to hold it
  972. if (pCertContext)
  973. {
  974. CertFreeCertificateContext(pCertContext);pCertContext=NULL;
  975. }
  976. DataBlob.cbData = 0;
  977. DataBlob.pbData = NULL;
  978. if (!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL, (bPrivateKey ? dwExportFlags : 0 ) | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY) )
  979. {
  980. hr = HRESULT_FROM_WIN32(GetLastError());
  981. goto ExportToBlob_Exit;
  982. }
  983. if(DataBlob.cbData <= 0)
  984. {
  985. hr = HRESULT_FROM_WIN32(GetLastError());
  986. goto ExportToBlob_Exit;
  987. }
  988. if(NULL == (DataBlob.pbData = (PBYTE) ::CoTaskMemAlloc(DataBlob.cbData)))
  989. {
  990. hr = E_OUTOFMEMORY;
  991. goto ExportToBlob_Exit;
  992. }
  993. //
  994. // at this point they have allocated enough memory
  995. // let's go and get the cert and put it into DataBlob
  996. //
  997. if(!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,(bPrivateKey ? dwExportFlags : 0 ) | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
  998. {
  999. if (DataBlob.pbData){CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;}
  1000. hr = HRESULT_FROM_WIN32(GetLastError());
  1001. goto ExportToBlob_Exit;
  1002. }
  1003. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  1004. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,NULL,&pcchB64Out);
  1005. if (err != ERROR_SUCCESS)
  1006. {
  1007. hr = E_FAIL;
  1008. goto ExportToBlob_Exit;
  1009. }
  1010. // allocate some space and then try it.
  1011. pcchB64Out = pcchB64Out * sizeof(char);
  1012. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  1013. if (NULL == pszB64Out)
  1014. {
  1015. hr = E_OUTOFMEMORY;
  1016. goto ExportToBlob_Exit;
  1017. }
  1018. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,pszB64Out,&pcchB64Out);
  1019. if (err != ERROR_SUCCESS)
  1020. {
  1021. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);pszB64Out = NULL;}
  1022. hr = E_FAIL;
  1023. goto ExportToBlob_Exit;
  1024. }
  1025. // copy the new memory to pass back
  1026. *cbBufferSize = pcchB64Out;
  1027. *pbBuffer = pszB64Out;
  1028. hr = ERROR_SUCCESS;
  1029. ExportToBlob_Exit:
  1030. if (NULL != DataBlob.pbData)
  1031. {
  1032. // perhaspse will this up with zeros...
  1033. ZeroMemory(DataBlob.pbData, DataBlob.cbData);
  1034. ::CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;
  1035. }
  1036. if (NULL != hStore){CertCloseStore(hStore, 0);hStore=NULL;}
  1037. if (NULL != pCertContext) {CertFreeCertificateContext(pCertContext);pCertContext=NULL;}
  1038. return hr;
  1039. }
  1040. STDMETHODIMP CIISCertObj::CopyToCertStore(BOOL bAllowExport,BSTR bstrDestinationServerName,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword,VARIANT * pVtArray)
  1041. {
  1042. // Check mandatory properties
  1043. if (bstrDestinationServerName == NULL || *bstrDestinationServerName == 0)
  1044. {
  1045. return ERROR_INVALID_PARAMETER;
  1046. }
  1047. // ------------------------
  1048. // buffer overflow paranoia
  1049. // check all parameters...
  1050. // ------------------------
  1051. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1052. return CopyOrMove(FALSE,TRUE,bAllowExport,pVtArray,bstrDestinationServerName,L"none",varDestinationServerUserName,varDestinationServerPassword);
  1053. }
  1054. STDMETHODIMP CIISCertObj::Copy(BOOL bAllowExport, BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1055. {
  1056. VARIANT VtArray;
  1057. // Check mandatory properties
  1058. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1059. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1060. {
  1061. return ERROR_INVALID_PARAMETER;
  1062. }
  1063. // ------------------------
  1064. // buffer overflow paranoia
  1065. // check all parameters...
  1066. // ------------------------
  1067. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1068. if (wcslen(bstrDestinationServerInstance) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1069. return CopyOrMove(FALSE,FALSE,bAllowExport,&VtArray,bstrDestinationServerName,bstrDestinationServerInstance,varDestinationServerUserName,varDestinationServerPassword);
  1070. }
  1071. STDMETHODIMP CIISCertObj::Move(BOOL bAllowExport, BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1072. {
  1073. VARIANT VtArray;
  1074. // Check mandatory properties
  1075. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1076. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1077. {
  1078. return ERROR_INVALID_PARAMETER;
  1079. }
  1080. // ------------------------
  1081. // buffer overflow paranoia
  1082. // check all parameters...
  1083. // ------------------------
  1084. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1085. if (wcslen(bstrDestinationServerInstance) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1086. return CopyOrMove(TRUE,FALSE,bAllowExport,&VtArray,bstrDestinationServerName,bstrDestinationServerInstance,varDestinationServerUserName,varDestinationServerPassword);
  1087. }
  1088. HRESULT CIISCertObj::CopyOrMove(BOOL bRemoveFromCertAfterCopy,BOOL bCopyCertDontInstallRetHash,BOOL bAllowExport, VARIANT * pVtArray, BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1089. {
  1090. HRESULT hr = E_FAIL;
  1091. DWORD cbEncodedSize = 0;
  1092. char * pszEncodedString = NULL;
  1093. BOOL bGuessingUserNamePass = FALSE;
  1094. DWORD blob_cbData;
  1095. BYTE * blob_pbData = NULL;
  1096. BOOL blob_freeme = FALSE;
  1097. BOOL bPrivateKey = TRUE;
  1098. BOOL bCertChain = FALSE;
  1099. CString csDestinationServerName = bstrDestinationServerName;
  1100. CString csDestinationServerUserName;
  1101. CString csDestinationServerUserPassword;
  1102. CString csTempPassword;
  1103. IIISCertObj * pObj = NULL;
  1104. IIISCertObj * pObj2 = NULL;
  1105. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  1106. // Check mandatory properties
  1107. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1108. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1109. {
  1110. return ERROR_INVALID_PARAMETER;
  1111. }
  1112. // ------------------------
  1113. // buffer overflow paranoia
  1114. // check all parameters...
  1115. // ------------------------
  1116. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1117. if (wcslen(bstrDestinationServerInstance) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1118. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1119. if (V_VT(&varDestinationServerUserName) != VT_ERROR)
  1120. {
  1121. VARIANT varBstrUserName;
  1122. VariantInit(&varBstrUserName);
  1123. HRESULT hr = VariantChangeType(&varBstrUserName, &varDestinationServerUserName, 0, VT_BSTR);
  1124. if (FAILED(hr)){goto Copy_Exit;}
  1125. csDestinationServerUserName = V_BSTR(&varBstrUserName);
  1126. VariantClear(&varBstrUserName);
  1127. }
  1128. else
  1129. {
  1130. // it's empty so don't use it
  1131. //csDestinationServerUserName = varDestinationServerUserName;
  1132. bGuessingUserNamePass = TRUE;
  1133. csDestinationServerUserName = m_UserName;
  1134. }
  1135. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1136. if (V_VT(&varDestinationServerPassword) != VT_ERROR)
  1137. {
  1138. VARIANT varBstrUserPassword;
  1139. VariantInit(&varBstrUserPassword);
  1140. HRESULT hr = VariantChangeType(&varBstrUserPassword, &varDestinationServerPassword, 0, VT_BSTR);
  1141. if (FAILED(hr)){goto Copy_Exit;}
  1142. csDestinationServerUserPassword = V_BSTR(&varBstrUserPassword);
  1143. VariantClear(&varBstrUserPassword);
  1144. }
  1145. else
  1146. {
  1147. if (TRUE == bGuessingUserNamePass)
  1148. {
  1149. csDestinationServerUserPassword = m_UserPassword;
  1150. }
  1151. else
  1152. {
  1153. // maybe the password was intended to be empty!
  1154. }
  1155. }
  1156. // --------------------------
  1157. // step 1.
  1158. // 1st of all check if we have access to
  1159. // both the servers!!!!
  1160. // --------------------------
  1161. // 1st we have to get the certblob from the Server#1
  1162. // so call export to get the data
  1163. hr = S_OK;
  1164. pObj = GetObject(&hr);
  1165. if (FAILED(hr))
  1166. {
  1167. IISDebugOutput(_T("CIISCertObj::CopyOrMove:Copy GetObject:0x%x\n"),hr);
  1168. return(hr);
  1169. }
  1170. // Logon to that server's CertObj.dll with the credentials supplied...
  1171. //
  1172. // if there were no credential's supplied then just use the ones that are in our object....
  1173. //
  1174. // if that doesn't work then try just the logged on user.
  1175. pObj2 = GetObject(&hr,csDestinationServerName,csDestinationServerUserName,csDestinationServerUserPassword);
  1176. if (FAILED(hr))
  1177. {
  1178. IISDebugOutput(_T("CIISCertObj::CopyOrMove:Copy GetObject (remote):0x%x\n"),hr);
  1179. IISDebugOutput(_T("CIISCertObj::CopyOrMove:Copy csDestinationServerName=%s,csDestinationServerUserName=%s,csDestinationServerUserPassword=%s\n"),(LPCTSTR) csDestinationServerName,(LPCTSTR) csDestinationServerUserName,(LPCTSTR) csDestinationServerUserPassword);
  1180. if (TRUE == bGuessingUserNamePass)
  1181. {
  1182. // try something else.
  1183. }
  1184. goto Copy_Exit;
  1185. }
  1186. //
  1187. // Create a unique password
  1188. //
  1189. // use the new secure password generator
  1190. // unfortunately this baby doesn't use unicode.
  1191. // so we'll call it and then convert it to unicode afterwards.
  1192. WCHAR * pwszPassword = CreatePassword(TEMP_PASSWORD_LENGTH);
  1193. // if its null -- ah, we can still use that...
  1194. BSTR bstrPassword = SysAllocString(pwszPassword);
  1195. // -----------------------------------
  1196. // step 2.
  1197. // okay we have access to both servers
  1198. // Grab the cert from server #1
  1199. // -----------------------------------
  1200. // Get data from the remote/local iis store return it back as a blob.
  1201. // The blob could be returned back as Base64 encoded so check that flag
  1202. hr = ExportToBlobProxy(pObj, bstrInstanceName, bstrPassword, bPrivateKey, bCertChain, &cbEncodedSize, &pszEncodedString);
  1203. if (FAILED(hr))
  1204. {
  1205. goto Copy_Exit;
  1206. }
  1207. int err;
  1208. // The data we got back was Base64 encoded to remove nulls.
  1209. // we need to decode it back to it's original format.
  1210. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  1211. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  1212. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  1213. {
  1214. SetLastError(err);
  1215. hr = HRESULT_FROM_WIN32(err);
  1216. return hr;
  1217. }
  1218. blob_freeme = TRUE;
  1219. // -----------------------------------
  1220. // step 3.
  1221. // okay we have access to both servers
  1222. // we have the cert blob from server#1 in memory
  1223. // now we need to push this blob into the server#2
  1224. // -----------------------------------
  1225. if (bCopyCertDontInstallRetHash)
  1226. {
  1227. DWORD cbHashBufferSize = 0;
  1228. char * pszHashBuffer = NULL;
  1229. BSTR bstrInstanceNameDummy = SysAllocString(_T("none"));
  1230. hr = ImportFromBlobProxy(pObj2, bstrInstanceNameDummy, bstrPassword, FALSE, bAllowExport, blob_cbData, blob_pbData, &cbHashBufferSize, &pszHashBuffer);
  1231. if (SUCCEEDED(hr))
  1232. {
  1233. hr = HereIsBinaryGimmieVtArray(cbHashBufferSize,pszHashBuffer,pVtArray,FALSE);
  1234. }
  1235. // free the memory that was alloced for us
  1236. if (0 != cbHashBufferSize)
  1237. {
  1238. if (pszHashBuffer)
  1239. {
  1240. ::CoTaskMemFree(pszHashBuffer);
  1241. }
  1242. }
  1243. }
  1244. else
  1245. {
  1246. hr = ImportFromBlobProxy(pObj2, bstrDestinationServerInstance, bstrPassword, TRUE, bAllowExport, blob_cbData, blob_pbData, 0, NULL);
  1247. }
  1248. if (FAILED(hr))
  1249. {
  1250. goto Copy_Exit;
  1251. }
  1252. // we successfully copied the cert from machine #1 to machine #2.
  1253. // lets see if we need to delete the original cert!.
  1254. if (TRUE == bRemoveFromCertAfterCopy)
  1255. {
  1256. hr = pObj->put_InstanceName(bstrInstanceName);
  1257. if (SUCCEEDED(hr))
  1258. {
  1259. hr = pObj->RemoveCert(bPrivateKey);
  1260. if (FAILED(hr))
  1261. {goto Copy_Exit;}
  1262. }
  1263. }
  1264. hr = S_OK;
  1265. Copy_Exit:
  1266. if (pwszPassword) {GlobalFree(pwszPassword);pwszPassword=NULL;}
  1267. if (blob_freeme)
  1268. {
  1269. if (blob_pbData != NULL)
  1270. {
  1271. ZeroMemory(blob_pbData, blob_cbData);
  1272. free(blob_pbData);blob_pbData=NULL;
  1273. }
  1274. }
  1275. if (pszEncodedString != NULL)
  1276. {
  1277. ZeroMemory(pszEncodedString,cbEncodedSize);
  1278. CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;
  1279. }
  1280. return hr;
  1281. }
  1282. //////////////////////////////////////////////////
  1283. // These are not part of the class
  1284. HRESULT RemoveCertProxy(IIISCertObj * pObj,BSTR bstrInstanceName, BOOL bPrivateKey)
  1285. {
  1286. HRESULT hr = E_FAIL;
  1287. // Check mandatory properties
  1288. if (bstrInstanceName == NULL || *bstrInstanceName == 0)
  1289. {
  1290. return ERROR_INVALID_PARAMETER;
  1291. }
  1292. // ------------------------
  1293. // buffer overflow paranoia
  1294. // check all parameters...
  1295. // ------------------------
  1296. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1297. if (pObj)
  1298. {
  1299. hr = pObj->put_InstanceName(bstrInstanceName);
  1300. if (SUCCEEDED(hr))
  1301. {
  1302. hr = pObj->RemoveCert(bPrivateKey);
  1303. }
  1304. }
  1305. return hr;
  1306. }
  1307. HRESULT ImportFromBlobProxy(IIISCertObj * pObj,BSTR InstanceName,BSTR Password,BOOL bInstallToMetabase,BOOL bAllowExport, DWORD actual,BYTE *pData,DWORD *cbHashBufferSize,char **pbHashBuffer)
  1308. {
  1309. HRESULT hr = E_FAIL;
  1310. char *pszB64Out = NULL;
  1311. DWORD pcchB64Out = 0;
  1312. // base64 encode the data for transfer to the remote machine
  1313. DWORD err;
  1314. pcchB64Out = 0;
  1315. // Check mandatory properties
  1316. if (InstanceName == NULL || *InstanceName == 0)
  1317. {
  1318. return ERROR_INVALID_PARAMETER;
  1319. }
  1320. // ------------------------
  1321. // buffer overflow paranoia
  1322. // check all parameters...
  1323. // ------------------------
  1324. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1325. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  1326. err = Base64EncodeA(pData,actual,NULL,&pcchB64Out);
  1327. if (err != ERROR_SUCCESS)
  1328. {
  1329. hr = E_FAIL;
  1330. goto ImportFromBlobProxy_Exit;
  1331. }
  1332. // allocate some space and then try it.
  1333. pcchB64Out = pcchB64Out * sizeof(char);
  1334. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  1335. if (NULL == pszB64Out)
  1336. {
  1337. hr = E_OUTOFMEMORY;
  1338. goto ImportFromBlobProxy_Exit;
  1339. }
  1340. err = Base64EncodeA(pData,actual,pszB64Out,&pcchB64Out);
  1341. if (err != ERROR_SUCCESS)
  1342. {
  1343. hr = E_FAIL;
  1344. goto ImportFromBlobProxy_Exit;
  1345. }
  1346. // the data to send are now in these variables
  1347. // pcchB64Out
  1348. // pszB64Out
  1349. if (NULL == pbHashBuffer)
  1350. {
  1351. hr = pObj->ImportFromBlob(InstanceName, Password, bInstallToMetabase, bAllowExport, pcchB64Out, pszB64Out);
  1352. }
  1353. else
  1354. {
  1355. hr = pObj->ImportFromBlobGetHash(InstanceName, Password, bInstallToMetabase, bAllowExport, pcchB64Out, pszB64Out, cbHashBufferSize, pbHashBuffer);
  1356. }
  1357. if (SUCCEEDED(hr))
  1358. {
  1359. // otherwise hey, The data was imported!
  1360. hr = S_OK;
  1361. }
  1362. ImportFromBlobProxy_Exit:
  1363. if (NULL != pszB64Out)
  1364. {
  1365. ZeroMemory(pszB64Out,pcchB64Out);
  1366. CoTaskMemFree(pszB64Out);
  1367. }
  1368. return hr;
  1369. }
  1370. //
  1371. // Proxy to the real call ExportToBlob()
  1372. // this function figures out how much space to allocate, and then calls ExportToBlob().
  1373. //
  1374. // if succeeded and they get the blob back,
  1375. // and the caller must call CoTaskMemFree()
  1376. //
  1377. HRESULT ExportToBlobProxy(IIISCertObj * pObj,BSTR InstanceName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,DWORD * pcbSize,char ** pBlobBinary)
  1378. {
  1379. HRESULT hr = E_FAIL;
  1380. DWORD cbEncodedSize = 0;
  1381. char * pszEncodedString = NULL;
  1382. * pBlobBinary = _T('\0');
  1383. // Check mandatory properties
  1384. if ( InstanceName == NULL || *InstanceName == 0
  1385. || Password == NULL || *Password == 0
  1386. )
  1387. {
  1388. return ERROR_INVALID_PARAMETER;
  1389. }
  1390. // ------------------------
  1391. // buffer overflow paranoia
  1392. // check all parameters...
  1393. // ------------------------
  1394. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1395. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1396. // call the remote function that will run on the remote/local machine
  1397. // and grab it's certificate from iis and send it back to us
  1398. hr = pObj->ExportToBlob(InstanceName, Password, bPrivateKey, bCertChain, &cbEncodedSize, (char **) &pszEncodedString);
  1399. if (ERROR_SUCCESS == hr)
  1400. {
  1401. // otherwise hey, we've got our data!
  1402. // copy it back
  1403. *pcbSize = cbEncodedSize;
  1404. *pBlobBinary = pszEncodedString;
  1405. hr = S_OK;
  1406. }
  1407. return hr;
  1408. }