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.

1590 lines
46 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,BSTR machine_name,HRESULT * phResult);
  14. CERT_CONTEXT * GetInstalledCert(HRESULT * phResult, CString csKeyPath);
  15. BOOL TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext,DWORD dwEncoding, DWORD dwFlags);
  16. BOOL AddChainToStore(HCERTSTORE hCertStore,PCCERT_CONTEXT pCertContext,DWORD cStores,HCERTSTORE * rghStores,BOOL fDontAddRootCert,CERT_TRUST_STATUS* pChainTrustStatus);
  17. HRESULT UninstallCert(CString csInstanceName);
  18. DWORD CreateGoodPassword(BYTE *szPwd,DWORD dwLen);
  19. LPTSTR CreatePassword(int iSize);
  20. #define TEMP_PASSWORD_LENGTH 50
  21. //#define DEBUG_FLAG
  22. #ifdef DEBUG_FLAG
  23. inline void _cdecl DebugTrace(LPTSTR lpszFormat, ...)
  24. {
  25. int nBuf;
  26. TCHAR szBuffer[512];
  27. va_list args;
  28. va_start(args, lpszFormat);
  29. nBuf = _vsntprintf(szBuffer, sizeof(szBuffer), lpszFormat, args);
  30. ASSERT(nBuf < sizeof(szBuffer)); //Output truncated as it was > sizeof(szBuffer)
  31. OutputDebugString(szBuffer);
  32. va_end(args);
  33. }
  34. #else
  35. inline void _cdecl DebugTrace(LPTSTR , ...){}
  36. #endif
  37. #define IISDebugOutput DebugTrace
  38. /////////////////////////////////////////////////////////////////////////////
  39. // CIISCertObj
  40. STDMETHODIMP CIISCertObj::put_ServerName(BSTR newVal)
  41. {
  42. m_ServerName = newVal;
  43. return S_OK;
  44. }
  45. STDMETHODIMP CIISCertObj::put_UserName(BSTR newVal)
  46. {
  47. m_UserName = newVal;
  48. return S_OK;
  49. }
  50. STDMETHODIMP CIISCertObj::put_UserPassword(BSTR newVal)
  51. {
  52. m_UserPassword = newVal;
  53. return S_OK;
  54. }
  55. STDMETHODIMP CIISCertObj::put_InstanceName(BSTR newVal)
  56. {
  57. m_InstanceName = newVal;
  58. return S_OK;
  59. }
  60. #ifdef FULL_OBJECT
  61. STDMETHODIMP CIISCertObj::put_Password(BSTR newVal)
  62. {
  63. m_Password = newVal;
  64. return S_OK;
  65. }
  66. STDMETHODIMP CIISCertObj::put_CommonName(BSTR newVal)
  67. {
  68. m_CommonName = newVal;
  69. return S_OK;
  70. }
  71. STDMETHODIMP CIISCertObj::put_FriendlyName(BSTR newVal)
  72. {
  73. m_FriendlyName = newVal;
  74. return S_OK;
  75. }
  76. STDMETHODIMP CIISCertObj::put_Organization(BSTR newVal)
  77. {
  78. m_Organization = newVal;
  79. return S_OK;
  80. }
  81. STDMETHODIMP CIISCertObj::put_OrganizationUnit(BSTR newVal)
  82. {
  83. m_OrganizationUnit = newVal;
  84. return S_OK;
  85. }
  86. STDMETHODIMP CIISCertObj::put_Locality(BSTR newVal)
  87. {
  88. m_Locality = newVal;
  89. return S_OK;
  90. }
  91. STDMETHODIMP CIISCertObj::put_State(BSTR newVal)
  92. {
  93. m_State = newVal;
  94. return S_OK;
  95. }
  96. STDMETHODIMP CIISCertObj::put_Country(BSTR newVal)
  97. {
  98. m_Country = newVal;
  99. return S_OK;
  100. }
  101. STDMETHODIMP CIISCertObj::put_CertAuthority(BSTR newVal)
  102. {
  103. m_CertAuthority = newVal;
  104. return S_OK;
  105. }
  106. STDMETHODIMP CIISCertObj::put_CertTemplate(BSTR newVal)
  107. {
  108. m_CertTemplate = newVal;
  109. return S_OK;
  110. }
  111. STDMETHODIMP CIISCertObj::put_KeySize(int newVal)
  112. {
  113. m_KeySize = newVal;
  114. return S_OK;
  115. }
  116. STDMETHODIMP CIISCertObj::put_SGC_Cert(BOOL newVal)
  117. {
  118. m_SGC_Cert = newVal;
  119. return S_OK;
  120. }
  121. STDMETHODIMP CIISCertObj::LoadSettings(BSTR ApplicationKey, BSTR SettingsKey)
  122. {
  123. return S_OK;
  124. }
  125. STDMETHODIMP CIISCertObj::SaveSettings(BSTR ApplicationKey, BSTR SettingsKey)
  126. {
  127. return S_OK;
  128. }
  129. STDMETHODIMP CIISCertObj::CreateRequest(BSTR FileName)
  130. {
  131. CString dn;
  132. HRESULT hr;
  133. TCHAR usage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
  134. CCryptBlobIMalloc req_blob;
  135. if (FAILED(hr = CreateDNString(dn)))
  136. return hr;
  137. ATLASSERT(dn.length() > 0);
  138. if (FAILED(hr = GetEnroll()->createPKCS10WStr(dn, (LPTSTR)usage, req_blob)))
  139. {
  140. return hr;
  141. }
  142. // BASE64 encode pkcs 10
  143. DWORD cch;
  144. char * psz;
  145. if ( ERROR_SUCCESS != Base64EncodeA(req_blob.GetData(), req_blob.GetSize(), NULL, &cch)
  146. || NULL == (psz = (char *)_alloca(cch+1))
  147. || ERROR_SUCCESS != Base64EncodeA(req_blob.GetData(), req_blob.GetSize(), psz, &cch)
  148. )
  149. {
  150. ATLASSERT(FALSE);
  151. return E_FAIL;
  152. }
  153. return S_OK;
  154. }
  155. STDMETHODIMP CIISCertObj::RequestCert(BSTR CertAuthority)
  156. {
  157. // TODO: Add your implementation code here
  158. return S_OK;
  159. }
  160. STDMETHODIMP CIISCertObj::ProcessResponse(BSTR FileName)
  161. {
  162. // TODO: Add your implementation code here
  163. return S_OK;
  164. }
  165. #endif
  166. STDMETHODIMP CIISCertObj::IsInstalled(BSTR InstanceName, VARIANT_BOOL * retval)
  167. {
  168. HRESULT hr = S_OK;
  169. // Check mandatory properties
  170. if (InstanceName == NULL || *InstanceName == 0 || retval == NULL)
  171. {
  172. return ERROR_INVALID_PARAMETER;
  173. }
  174. m_InstanceName = InstanceName;
  175. CString csServerName = m_ServerName;
  176. if (csServerName.IsEmpty())
  177. {
  178. hr = IsInstalledRemote(InstanceName, retval);
  179. goto IsInstalled_Exit;
  180. }
  181. // There is a servername specified...
  182. // check if it's the local machine that was specified!
  183. if (IsServerLocal(csServerName))
  184. {
  185. hr = IsInstalledRemote(InstanceName, retval);
  186. goto IsInstalled_Exit;
  187. }
  188. // this must be a remote machine
  189. {
  190. //ASSERT(GetObject(&hr) != NULL);
  191. IIISCertObj * pObj;
  192. if (NULL != (pObj = GetObject(&hr)))
  193. {
  194. hr = pObj->put_InstanceName(InstanceName);
  195. hr = pObj->IsInstalledRemote(InstanceName, retval);
  196. }
  197. }
  198. IsInstalled_Exit:
  199. return hr;
  200. }
  201. STDMETHODIMP CIISCertObj::IsInstalledRemote(BSTR InstanceName,VARIANT_BOOL * retval)
  202. {
  203. HRESULT hr = S_OK;
  204. CERT_CONTEXT * pCertContext = NULL;
  205. // Check mandatory properties
  206. if (InstanceName == NULL || *InstanceName == 0 || retval == NULL)
  207. {
  208. return ERROR_INVALID_PARAMETER;
  209. }
  210. pCertContext = GetInstalledCert(&hr,InstanceName);
  211. if (FAILED(hr) || NULL == pCertContext)
  212. {
  213. hr = S_OK;
  214. *retval = FALSE;
  215. }
  216. else
  217. {
  218. hr = S_OK;
  219. *retval = TRUE;
  220. CertFreeCertificateContext(pCertContext);
  221. }
  222. return hr;
  223. }
  224. HRESULT CIISCertObj::RemoveCertProxy(IIISCertObj * pObj,BSTR InstanceName, BOOL bPrivateKey)
  225. {
  226. HRESULT hr = E_FAIL;
  227. if (pObj)
  228. {
  229. hr = pObj->RemoveCert(InstanceName,bPrivateKey);
  230. }
  231. return hr;
  232. }
  233. STDMETHODIMP CIISCertObj::RemoveCert(BSTR InstanceName, BOOL bPrivateKey)
  234. {
  235. HRESULT hr = E_FAIL;
  236. PCCERT_CONTEXT pCertContext = NULL;
  237. DWORD cbKpi = 0;
  238. PCRYPT_KEY_PROV_INFO pKpi = NULL ;
  239. HCRYPTPROV hCryptProv = NULL;
  240. do
  241. {
  242. // get the certificate from the server
  243. pCertContext = GetInstalledCert(&hr,InstanceName);
  244. if (NULL == pCertContext)
  245. {
  246. break;
  247. }
  248. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbKpi))
  249. {
  250. hr = HRESULT_FROM_WIN32(GetLastError());
  251. break;
  252. }
  253. pKpi = ( PCRYPT_KEY_PROV_INFO ) malloc( cbKpi );
  254. if ( NULL != pKpi )
  255. {
  256. if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, (void *)pKpi, &cbKpi))
  257. {
  258. hr = HRESULT_FROM_WIN32(GetLastError());
  259. break;
  260. }
  261. // Delete the key container
  262. if (!CryptAcquireContext(&hCryptProv,pKpi->pwszContainerName,pKpi->pwszProvName,pKpi->dwProvType,pKpi->dwFlags | CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET))
  263. {
  264. hr = HRESULT_FROM_WIN32(GetLastError());
  265. break;
  266. }
  267. if (NULL != pKpi){free(pKpi);}
  268. if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, NULL))
  269. {
  270. hr = HRESULT_FROM_WIN32(GetLastError());
  271. break;
  272. }
  273. }
  274. // uninstall the certificate from the site, reset SSL flag
  275. // if we are exporting the private key, remove the cert from the storage
  276. // and delete private key
  277. UninstallCert(InstanceName);
  278. // remove ssl key from metabase
  279. CString str = InstanceName;
  280. ShutdownSSL(str);
  281. // delete the private key
  282. if (bPrivateKey)
  283. {
  284. PCCERT_CONTEXT pcDup = NULL ;
  285. pcDup = CertDuplicateCertificateContext(pCertContext);
  286. if (pcDup)
  287. {
  288. if (!CertDeleteCertificateFromStore(pcDup))
  289. {
  290. hr = HRESULT_FROM_WIN32(GetLastError());
  291. break;
  292. }
  293. }
  294. else
  295. {
  296. hr = HRESULT_FROM_WIN32(GetLastError());
  297. }
  298. }
  299. hr = ERROR_SUCCESS;
  300. } while (FALSE);
  301. if (pCertContext) {CertFreeCertificateContext(pCertContext);}
  302. return hr;
  303. }
  304. STDMETHODIMP CIISCertObj::Export(BSTR FileName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,BOOL bRemoveCert)
  305. {
  306. HRESULT hr = S_OK;
  307. DWORD cbEncodedSize = 0;
  308. char * pszEncodedString = NULL;
  309. DWORD blob_cbData = 0;
  310. BYTE * blob_pbData = NULL;
  311. BOOL blob_freeme = FALSE;
  312. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  313. // Check mandatory properties
  314. if ( FileName == NULL || *FileName == 0
  315. || Password == NULL || *Password == 0
  316. || bstrInstanceName == NULL || *bstrInstanceName == 0)
  317. {
  318. return ERROR_INVALID_PARAMETER;
  319. }
  320. IIISCertObj * pObj = GetObject(&hr);
  321. if (FAILED(hr))
  322. {
  323. goto Export_Exit;
  324. }
  325. // Call function go get data from the remote/local iis store
  326. // and return it back as a blob. the blob could be returned back as Base64 encoded
  327. // so check that flag
  328. hr = ExportToBlobProxy(pObj, bstrInstanceName, Password, bPrivateKey, bCertChain, &cbEncodedSize, &pszEncodedString);
  329. if (FAILED(hr))
  330. {
  331. goto Export_Exit;
  332. }
  333. // check if things are kool
  334. if (bRemoveCert)
  335. {
  336. hr = RemoveCertProxy(pObj,bstrInstanceName, bPrivateKey);
  337. if (FAILED(hr))
  338. {
  339. goto Export_Exit;
  340. }
  341. }
  342. if (SUCCEEDED(hr))
  343. {
  344. int err;
  345. // The data we got back was Base64 encoded to remove nulls.
  346. // we need to decode it back to it's original format.
  347. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  348. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  349. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  350. {
  351. SetLastError(err);
  352. hr = HRESULT_FROM_WIN32(err);
  353. return hr;
  354. }
  355. blob_freeme = TRUE;
  356. HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  357. if (INVALID_HANDLE_VALUE == hFile)
  358. {
  359. hr = HRESULT_FROM_WIN32(GetLastError());
  360. return hr;
  361. }
  362. DWORD written = 0;
  363. if (!WriteFile(hFile, blob_pbData, blob_cbData, &written, NULL))
  364. {
  365. hr = HRESULT_FROM_WIN32(GetLastError());
  366. }
  367. else
  368. {
  369. hr = S_OK;
  370. }
  371. CloseHandle(hFile);
  372. // Erase the memory that the private key used to be in!!!
  373. ZeroMemory(pszEncodedString, sizeof(cbEncodedSize));
  374. ZeroMemory(blob_pbData, sizeof(blob_cbData));
  375. }
  376. Export_Exit:
  377. if (pObj != NULL)
  378. {
  379. if (pObj != this)
  380. {
  381. pObj->Release();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 ExportToBlobProxy(IIISCertObj * pObj,BSTR InstanceName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,DWORD * pcbSize,char ** pBlobBinary)
  396. {
  397. HRESULT hr = E_FAIL;
  398. DWORD cbEncodedSize = 0;
  399. char * pszEncodedString = NULL;
  400. * pBlobBinary = _T('\0');
  401. // call the remote function that will run on the remote/local machine
  402. // and grab it's certificate from iis and send it back to us
  403. hr = pObj->ExportToBlob(InstanceName, Password, bPrivateKey, bCertChain, &cbEncodedSize, (char **) &pszEncodedString);
  404. if (ERROR_SUCCESS == hr)
  405. {
  406. // otherwise hey, we've got our data!
  407. // copy it back
  408. *pcbSize = cbEncodedSize;
  409. *pBlobBinary = pszEncodedString;
  410. hr = S_OK;
  411. }
  412. return hr;
  413. }
  414. STDMETHODIMP CIISCertObj::ExportToBlob(BSTR InstanceName,BSTR Password,BOOL bPrivateKey,BOOL bCertChain,DWORD *cbBufferSize,char **pbBuffer)
  415. {
  416. HRESULT hr = E_FAIL;
  417. PCCERT_CONTEXT pCertContext = NULL;
  418. BOOL bStatus = FALSE;
  419. HCERTSTORE hStore = NULL;
  420. DWORD dwOpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG;
  421. CRYPT_DATA_BLOB DataBlob;
  422. ZeroMemory(&DataBlob, sizeof(CRYPT_DATA_BLOB));
  423. char *pszB64Out = NULL;
  424. DWORD pcchB64Out = 0;
  425. DWORD err;
  426. //
  427. // get the certificate from the server
  428. //
  429. pCertContext = GetInstalledCert(&hr,InstanceName);
  430. if (NULL == pCertContext)
  431. {
  432. *cbBufferSize = 0;
  433. pbBuffer = NULL;
  434. goto ExportToBlob_Exit;
  435. }
  436. //
  437. // Export cert
  438. //
  439. // Open a temporary store to stick the cert in.
  440. hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,dwOpenFlags,NULL);
  441. if(NULL == hStore)
  442. {
  443. *cbBufferSize = 0;
  444. pbBuffer = NULL;
  445. hr = HRESULT_FROM_WIN32(GetLastError());
  446. goto ExportToBlob_Exit;
  447. }
  448. //
  449. // get all the certs in the chain if we need to
  450. //
  451. if (bCertChain)
  452. {
  453. AddChainToStore(hStore, pCertContext, 0, 0, FALSE, NULL);
  454. }
  455. if(!CertAddCertificateContextToStore(hStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  456. {
  457. *cbBufferSize = 0;
  458. pbBuffer = NULL;
  459. hr = HRESULT_FROM_WIN32(GetLastError());
  460. goto ExportToBlob_Exit;
  461. }
  462. // free cert context since we no longer need to hold it
  463. if (pCertContext)
  464. {
  465. CertFreeCertificateContext(pCertContext);pCertContext=NULL;
  466. }
  467. DataBlob.cbData = 0;
  468. DataBlob.pbData = NULL;
  469. if (!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,bPrivateKey ? EXPORT_PRIVATE_KEYS : 0))
  470. {
  471. hr = HRESULT_FROM_WIN32(GetLastError());
  472. goto ExportToBlob_Exit;
  473. }
  474. if(DataBlob.cbData <= 0)
  475. {
  476. hr = HRESULT_FROM_WIN32(GetLastError());
  477. goto ExportToBlob_Exit;
  478. }
  479. if(NULL == (DataBlob.pbData = (PBYTE) ::CoTaskMemAlloc(DataBlob.cbData)))
  480. {
  481. hr = E_OUTOFMEMORY;
  482. goto ExportToBlob_Exit;
  483. }
  484. //
  485. // at this point they have allocated enough memory
  486. // let's go and get the cert and put it into DataBlob
  487. //
  488. if(!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,bPrivateKey ? EXPORT_PRIVATE_KEYS : 0))
  489. {
  490. if (DataBlob.pbData){CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;}
  491. hr = HRESULT_FROM_WIN32(GetLastError());
  492. goto ExportToBlob_Exit;
  493. }
  494. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  495. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,NULL,&pcchB64Out);
  496. if (err != ERROR_SUCCESS)
  497. {
  498. hr = E_FAIL;
  499. goto ExportToBlob_Exit;
  500. }
  501. // allocate some space and then try it.
  502. pcchB64Out = pcchB64Out * sizeof(char);
  503. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  504. if (NULL == pszB64Out)
  505. {
  506. hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
  507. goto ExportToBlob_Exit;
  508. }
  509. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,pszB64Out,&pcchB64Out);
  510. if (err != ERROR_SUCCESS)
  511. {
  512. hr = E_FAIL;
  513. goto ExportToBlob_Exit;
  514. }
  515. // copy the new memory to pass back
  516. *cbBufferSize = pcchB64Out;
  517. *pbBuffer = (char *)::CoTaskMemAlloc(pcchB64Out);
  518. if (*pbBuffer == NULL)
  519. {
  520. hr = E_OUTOFMEMORY;
  521. goto ExportToBlob_Exit;
  522. }
  523. //strcpy(*pbBuffer,pszB64Out);
  524. memcpy(*pbBuffer,pszB64Out,pcchB64Out);
  525. hr = ERROR_SUCCESS;
  526. ExportToBlob_Exit:
  527. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);pszB64Out = NULL;}
  528. if (NULL != DataBlob.pbData){::CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;}
  529. if (NULL != hStore){CertCloseStore(hStore, 0);hStore=NULL;}
  530. if (NULL != pCertContext) {CertFreeCertificateContext(pCertContext);pCertContext=NULL;}
  531. return hr;
  532. }
  533. STDMETHODIMP CIISCertObj::Import(BSTR FileName, BSTR Password)
  534. {
  535. HRESULT hr = S_OK;
  536. BYTE * pbData = NULL;
  537. DWORD actual = 0, cbData = 0;
  538. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  539. // Check mandatory properties
  540. if ( FileName == NULL || *FileName == 0
  541. || Password == NULL || *Password == 0
  542. || bstrInstanceName == NULL || *bstrInstanceName == 0)
  543. {
  544. return ERROR_INVALID_PARAMETER;
  545. }
  546. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  547. if (hFile == INVALID_HANDLE_VALUE)
  548. {
  549. hr = HRESULT_FROM_WIN32(GetLastError());
  550. hFile = NULL;
  551. goto Import_Exit;
  552. }
  553. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  554. {
  555. hr = HRESULT_FROM_WIN32(GetLastError());
  556. goto Import_Exit;
  557. }
  558. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  559. {
  560. hr = E_OUTOFMEMORY;
  561. goto Import_Exit;
  562. }
  563. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  564. {
  565. IIISCertObj * pObj = GetObject(&hr);
  566. if (SUCCEEDED(hr))
  567. {
  568. hr = ImportFromBlobProxy(pObj, bstrInstanceName, Password, actual, pbData);
  569. }
  570. }
  571. else
  572. {
  573. hr = HRESULT_FROM_WIN32(GetLastError());
  574. goto Import_Exit;
  575. }
  576. Import_Exit:
  577. if (pbData != NULL){::CoTaskMemFree(pbData);}
  578. if (hFile != NULL){CloseHandle(hFile);}
  579. return hr;
  580. }
  581. HRESULT ImportFromBlobProxy(IIISCertObj * pObj,BSTR InstanceName,BSTR Password,DWORD actual,BYTE *pData)
  582. {
  583. HRESULT hr = E_FAIL;
  584. char *pszB64Out = NULL;
  585. DWORD pcchB64Out = 0;
  586. // base64 encode the data for transfer to the remote machine
  587. DWORD err;
  588. pcchB64Out = 0;
  589. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  590. err = Base64EncodeA(pData,actual,NULL,&pcchB64Out);
  591. if (err != ERROR_SUCCESS)
  592. {
  593. hr = E_FAIL;
  594. goto ImportFromBlobProxy_Exit;
  595. }
  596. // allocate some space and then try it.
  597. pcchB64Out = pcchB64Out * sizeof(char);
  598. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  599. if (NULL == pszB64Out)
  600. {
  601. hr = HRESULT_FROM_WIN32(E_OUTOFMEMORY);
  602. goto ImportFromBlobProxy_Exit;
  603. }
  604. err = Base64EncodeA(pData,actual,pszB64Out,&pcchB64Out);
  605. if (err != ERROR_SUCCESS)
  606. {
  607. hr = E_FAIL;
  608. goto ImportFromBlobProxy_Exit;
  609. }
  610. // the data to send are now in these variables
  611. // pcchB64Out
  612. // pszB64Out
  613. hr = pObj->ImportFromBlob(InstanceName, Password, pcchB64Out, pszB64Out);
  614. if (SUCCEEDED(hr))
  615. {
  616. // otherwise hey, The data was imported!
  617. hr = S_OK;
  618. }
  619. ImportFromBlobProxy_Exit:
  620. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);}
  621. return hr;
  622. }
  623. HRESULT CIISCertObj::ImportFromBlob(BSTR InstanceName,BSTR Password,DWORD count,char *pData)
  624. {
  625. HRESULT hr = S_OK;
  626. CRYPT_DATA_BLOB blob;
  627. ZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
  628. LPTSTR pPass = Password;
  629. BOOL blob_freeme = FALSE;
  630. int err;
  631. // The data we got back was Base64 encoded to remove nulls.
  632. // we need to decode it back to it's original format.
  633. if( (err = Base64DecodeA(pData,count,NULL,&blob.cbData)) != ERROR_SUCCESS ||
  634. (blob.pbData = (BYTE *) malloc(blob.cbData)) == NULL ||
  635. (err = Base64DecodeA(pData,count,blob.pbData,&blob.cbData)) != ERROR_SUCCESS )
  636. {
  637. SetLastError(err);
  638. hr = HRESULT_FROM_WIN32(err);
  639. return hr;
  640. }
  641. blob_freeme = TRUE;
  642. if (!PFXVerifyPassword(&blob, pPass, 0))
  643. {
  644. // Try empty password
  645. if (pPass == NULL)
  646. {
  647. if (!PFXVerifyPassword(&blob, pPass = L'\0', 0))
  648. {
  649. hr = ERROR_INVALID_PARAMETER;
  650. }
  651. }
  652. else
  653. {
  654. hr = ERROR_INVALID_PARAMETER;
  655. }
  656. }
  657. if (SUCCEEDED(hr))
  658. {
  659. HCERTSTORE hStore = PFXImportCertStore(&blob, pPass, CRYPT_MACHINE_KEYSET|CRYPT_EXPORTABLE);
  660. if (hStore != NULL)
  661. {
  662. //add the certificate with private key to my store; and the rest
  663. //to the ca store
  664. PCCERT_CONTEXT pCertContext = NULL;
  665. PCCERT_CONTEXT pCertPre = NULL;
  666. while ( SUCCEEDED(hr)
  667. && NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertPre))
  668. )
  669. {
  670. //check if the certificate has the property on it
  671. //make sure the private key matches the certificate
  672. //search for both machine key and user keys
  673. DWORD dwData = 0;
  674. if (CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData) && CryptFindCertificateKeyProvInfo(pCertContext, 0, NULL))
  675. {
  676. // This certificate should go to the My store
  677. HCERTSTORE hDestStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"MY");
  678. if (hDestStore != NULL)
  679. {
  680. // Put it to store
  681. if (CertAddCertificateContextToStore(hDestStore,pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  682. {
  683. // Install to metabase
  684. CRYPT_HASH_BLOB hash;
  685. if ( CertGetCertificateContextProperty(pCertContext,CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData)
  686. && NULL != (hash.pbData = (BYTE *)_alloca(hash.cbData))
  687. && CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData))
  688. {
  689. InstallHashToMetabase(&hash, InstanceName, &hr);
  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. hr = HRESULT_FROM_WIN32(GetLastError());
  751. }
  752. //ImportFromBlob_Exit:
  753. if (blob_freeme){if (blob.pbData != NULL){free(blob.pbData);blob.pbData=NULL;}}
  754. return hr;
  755. }
  756. //////////////////////////////////////////////////////////////////
  757. #ifdef FULL_OBJECT
  758. HRESULT CIISCertObj::Init()
  759. {
  760. HRESULT hr;
  761. if (!m_bInitDone)
  762. {
  763. do
  764. {
  765. // setup IEnroll object properly
  766. DWORD dwFlags;
  767. if (FAILED(hr = GetEnroll()->get_MyStoreFlags(&dwFlags)))
  768. {
  769. break;
  770. }
  771. dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
  772. dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
  773. // following call will change Request store flags also
  774. if (FAILED(hr = GetEnroll()->put_MyStoreFlags(dwFlags)))
  775. {
  776. break;
  777. }
  778. if (FAILED(hr = GetEnroll()->get_GenKeyFlags(&dwFlags)))
  779. {
  780. break;
  781. }
  782. dwFlags |= CRYPT_EXPORTABLE;
  783. if (FAILED(hr = GetEnroll()->put_GenKeyFlags(dwFlags))
  784. || FAILED(hr = GetEnroll()->put_KeySpec(AT_KEYEXCHANGE))
  785. || FAILED(hr = GetEnroll()->put_ProviderType(PROV_RSA_SCHANNEL))
  786. || FAILED(hr = GetEnroll()->put_DeleteRequestCert(TRUE)))
  787. {
  788. break;
  789. }
  790. } while (FALSE);
  791. m_bInitDone = SUCCEEDED(hr);
  792. }
  793. return hr;
  794. }
  795. IEnroll * CIISCertObj::GetEnroll()
  796. {
  797. if (m_pEnroll == NULL)
  798. {
  799. HRESULT hr = CoCreateInstance(CLSID_CEnroll,NULL,CLSCTX_INPROC_SERVER,IID_IEnroll,(void **)&m_pEnroll);
  800. }
  801. return m_pEnroll;
  802. }
  803. HCERTSTORE OpenMyStore(IEnroll * pEnroll, HRESULT * phResult)
  804. {
  805. ASSERT(NULL != phResult);
  806. HCERTSTORE hStore = NULL;
  807. hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"MY");
  808. if (hStore == NULL)
  809. {
  810. *phResult = HRESULT_FROM_WIN32(GetLastError());
  811. }
  812. return hStore;
  813. }
  814. #endif
  815. HRESULT ShutdownSSL(CString& server_name)
  816. {
  817. CComAuthInfo auth;
  818. CString str = server_name;
  819. str += _T("/root");
  820. CMetaKey key(&auth, str,
  821. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  822. DWORD dwSslAccess;
  823. if (!key.Succeeded())
  824. {
  825. return key.QueryResult();
  826. }
  827. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess)) && dwSslAccess > 0)
  828. {
  829. key.SetValue(MD_SSL_ACCESS_PERM, 0);
  830. }
  831. // Now we need to remove SSL setting from any virtual directory below
  832. CError err;
  833. CStringListEx data_paths;
  834. DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
  835. VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_ACCESS_PERM, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
  836. err = key.GetDataPaths( data_paths,dwMDIdentifier,dwMDDataType);
  837. if (err.Succeeded() && !data_paths.empty())
  838. {
  839. CStringListEx::iterator it = data_paths.begin();
  840. while (it != data_paths.end())
  841. {
  842. CString& str = (*it++);
  843. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess, NULL, str)) && dwSslAccess > 0)
  844. {
  845. key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, str);
  846. }
  847. }
  848. }
  849. return key.QueryResult();
  850. }
  851. /*
  852. InstallHashToMetabase
  853. Function writes hash array to metabase. After that IIS
  854. could use certificate with that hash from MY store.
  855. Function expects server_name in format lm\w3svc\<number>,
  856. i.e. from root node down to virtual server
  857. */
  858. BOOL InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,BSTR InstanceName,HRESULT * phResult)
  859. {
  860. BOOL bRes = FALSE;
  861. CComAuthInfo auth;
  862. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR; // SZ_MBN_WEB SZ_MBN_SEP_STR;
  863. key_path += InstanceName;
  864. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  865. if (key.Succeeded())
  866. {
  867. CBlob blob;
  868. blob.SetValue(pHash->cbData, pHash->pbData, TRUE);
  869. bRes = SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_HASH, blob))
  870. && SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_STORE_NAME, CString(L"MY")));
  871. }
  872. else
  873. {
  874. *phResult = key.QueryResult();
  875. }
  876. return bRes;
  877. }
  878. #ifdef FULL_OBJECT
  879. HRESULT CIISCertObj::CreateDNString(CString& str)
  880. {
  881. str = _T("");
  882. str += _T("CN=") + m_CommonName;
  883. str += _T("\n,OU=") + m_OrganizationUnit;
  884. str += _T("\n,O=") + m_Organization;
  885. str += _T("\n,L=") + m_Locality;
  886. str += _T("\n,S=") + m_State;
  887. str += _T("\n,C=") + m_Country;
  888. return S_OK;
  889. }
  890. #endif
  891. CERT_CONTEXT * GetInstalledCert(HRESULT * phResult, CString csKeyPath)
  892. {
  893. // ATLASSERT(GetEnroll() != NULL);
  894. ATLASSERT(phResult != NULL);
  895. CERT_CONTEXT * pCert = NULL;
  896. *phResult = S_OK;
  897. CComAuthInfo auth;
  898. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;// SZ_MBN_WEB SZ_MBN_SEP_STR;
  899. key_path += csKeyPath;
  900. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  901. if (key.Succeeded())
  902. {
  903. CString store_name;
  904. CBlob hash;
  905. if (SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name)) &&
  906. SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash)))
  907. {
  908. // Open MY store. We assume that store type and flags
  909. // cannot be changed between installation and unistallation
  910. // of the sertificate.
  911. HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,store_name);
  912. ASSERT(hStore != NULL);
  913. if (hStore != NULL)
  914. {
  915. // Now we need to find cert by hash
  916. CRYPT_HASH_BLOB crypt_hash;
  917. crypt_hash.cbData = hash.GetSize();
  918. crypt_hash.pbData = hash.GetData();
  919. pCert = (CERT_CONTEXT *)CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,CERT_FIND_HASH,(LPVOID)&crypt_hash,NULL);
  920. if (pCert == NULL)
  921. {
  922. *phResult = HRESULT_FROM_WIN32(GetLastError());
  923. }
  924. VERIFY(CertCloseStore(hStore, 0));
  925. }
  926. else
  927. {
  928. *phResult = HRESULT_FROM_WIN32(GetLastError());
  929. }
  930. }
  931. }
  932. else
  933. {
  934. *phResult = key.QueryResult();
  935. }
  936. return pCert;
  937. }
  938. HRESULT UninstallCert(CString csInstanceName)
  939. {
  940. CComAuthInfo auth;
  941. CString key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;// SZ_MBN_WEB SZ_MBN_SEP_STR;
  942. key_path += csInstanceName;
  943. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  944. if (key.Succeeded())
  945. {
  946. CString store_name;
  947. key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name);
  948. if (SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH)))
  949. {
  950. key.DeleteValue(MD_SSL_CERT_STORE_NAME);
  951. }
  952. }
  953. return key.QueryResult();
  954. }
  955. IIISCertObj * CIISCertObj::GetObject(HRESULT * phr)
  956. {
  957. IIISCertObj * pObj = NULL;
  958. pObj = GetObject(phr,m_ServerName,m_UserName,m_UserPassword);
  959. return pObj;
  960. }
  961. IIISCertObj * CIISCertObj::GetObject(HRESULT * phr,CString csServerName,CString csUserName,CString csUserPassword)
  962. {
  963. if (csServerName.IsEmpty())
  964. {
  965. // object is null, but it's the local machine, so just return back this pointer
  966. m_pObj = this;
  967. goto GetObject_Exit;
  968. }
  969. // There is a servername specified...
  970. // check if it's the local machine that was specified!
  971. if (IsServerLocal(csServerName))
  972. {
  973. m_pObj = this;
  974. goto GetObject_Exit;
  975. }
  976. else
  977. {
  978. // there is a remote servername specified
  979. // let's see if the machine has the com object that we want....
  980. // we are using the user/name password that are in this object
  981. // so were probably on the local machine
  982. CComAuthInfo auth(csServerName,csUserName,csUserPassword);
  983. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct();
  984. MULTI_QI res[1] =
  985. {
  986. {&__uuidof(IIISCertObj), NULL, 0}
  987. };
  988. // Try to instantiante the object on the remote server...
  989. // with the supplied authentication info (pcsiName)
  990. //#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)
  991. //#define CLSCTX_ALL (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER)
  992. // this one seems to work with surrogates..
  993. *phr = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
  994. if (FAILED(*phr))
  995. {
  996. //IISDebugOutput(_T("CoCreateInstanceEx on CLSID_IISCertObj failed! code=0x%x\n"),*phr);
  997. goto GetObject_Exit;
  998. }
  999. // at this point we were able to instantiate the com object on the server (local or remote)
  1000. m_pObj = (IIISCertObj *)res[0].pItf;
  1001. if (auth.UsesImpersonation())
  1002. {
  1003. *phr = auth.ApplyProxyBlanket(m_pObj);
  1004. }
  1005. auth.FreeServerInfoStruct(pcsiName);
  1006. }
  1007. GetObject_Exit:
  1008. //ASSERT(m_pObj != NULL);
  1009. return m_pObj;
  1010. }
  1011. BOOL AddChainToStore(HCERTSTORE hCertStore,PCCERT_CONTEXT pCertContext,DWORD cStores,HCERTSTORE * rghStores,BOOL fDontAddRootCert,CERT_TRUST_STATUS * pChainTrustStatus)
  1012. {
  1013. DWORD i;
  1014. CERT_CHAIN_ENGINE_CONFIG CertChainEngineConfig;
  1015. HCERTCHAINENGINE hCertChainEngine = NULL;
  1016. PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
  1017. CERT_CHAIN_PARA CertChainPara;
  1018. BOOL fRet = TRUE;
  1019. PCCERT_CONTEXT pTempCertContext = NULL;
  1020. //
  1021. // create a new chain engine, then build the chain
  1022. //
  1023. memset(&CertChainEngineConfig, 0, sizeof(CertChainEngineConfig));
  1024. CertChainEngineConfig.cbSize = sizeof(CertChainEngineConfig);
  1025. CertChainEngineConfig.cAdditionalStore = cStores;
  1026. CertChainEngineConfig.rghAdditionalStore = rghStores;
  1027. CertChainEngineConfig.dwFlags = CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
  1028. if (!CertCreateCertificateChainEngine(&CertChainEngineConfig, &hCertChainEngine))
  1029. {
  1030. goto AddChainToStore_Error;
  1031. }
  1032. memset(&CertChainPara, 0, sizeof(CertChainPara));
  1033. CertChainPara.cbSize = sizeof(CertChainPara);
  1034. if (!CertGetCertificateChain(hCertChainEngine,pCertContext,NULL,NULL,&CertChainPara,0,NULL,&pCertChainContext))
  1035. {
  1036. goto AddChainToStore_Error;
  1037. }
  1038. //
  1039. // make sure there is atleast 1 simple chain
  1040. //
  1041. if (pCertChainContext->cChain != 0)
  1042. {
  1043. i = 0;
  1044. while (i < pCertChainContext->rgpChain[0]->cElement)
  1045. {
  1046. //
  1047. // if we are supposed to skip the root cert,
  1048. // and we are on the root cert, then continue
  1049. //
  1050. if (fDontAddRootCert && (pCertChainContext->rgpChain[0]->rgpElement[i]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED))
  1051. {
  1052. i++;
  1053. continue;
  1054. }
  1055. CertAddCertificateContextToStore(hCertStore,pCertChainContext->rgpChain[0]->rgpElement[i]->pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,&pTempCertContext);
  1056. //
  1057. // remove any private key property the certcontext may have on it.
  1058. //
  1059. if (pTempCertContext)
  1060. {
  1061. CertSetCertificateContextProperty(pTempCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, NULL);
  1062. CertFreeCertificateContext(pTempCertContext);
  1063. }
  1064. i++;
  1065. }
  1066. }
  1067. else
  1068. {
  1069. goto AddChainToStore_Error;
  1070. }
  1071. //
  1072. // if the caller wants the status, then set it
  1073. //
  1074. if (pChainTrustStatus != NULL)
  1075. {
  1076. pChainTrustStatus->dwErrorStatus = pCertChainContext->TrustStatus.dwErrorStatus;
  1077. pChainTrustStatus->dwInfoStatus = pCertChainContext->TrustStatus.dwInfoStatus;
  1078. }
  1079. AddChainToStore_Exit:
  1080. if (pCertChainContext != NULL)
  1081. {
  1082. CertFreeCertificateChain(pCertChainContext);
  1083. }
  1084. if (hCertChainEngine != NULL)
  1085. {
  1086. CertFreeCertificateChainEngine(hCertChainEngine);
  1087. }
  1088. return fRet;
  1089. AddChainToStore_Error:
  1090. fRet = FALSE;
  1091. goto AddChainToStore_Exit;
  1092. }
  1093. // This function is borrowed from trustapi.cpp
  1094. static BOOL TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext,DWORD dwEncoding, DWORD dwFlags)
  1095. {
  1096. if (!(pContext) || (dwFlags != 0))
  1097. {
  1098. SetLastError(ERROR_INVALID_PARAMETER);
  1099. return(FALSE);
  1100. }
  1101. if (!(CertCompareCertificateName(dwEncoding,&pContext->pCertInfo->Issuer,&pContext->pCertInfo->Subject)))
  1102. {
  1103. return(FALSE);
  1104. }
  1105. DWORD dwFlag;
  1106. dwFlag = CERT_STORE_SIGNATURE_FLAG;
  1107. if (!(CertVerifySubjectCertificateContext(pContext, pContext, &dwFlag)) ||
  1108. (dwFlag & CERT_STORE_SIGNATURE_FLAG))
  1109. {
  1110. return(FALSE);
  1111. }
  1112. return(TRUE);
  1113. }
  1114. STDMETHODIMP CIISCertObj::Copy(BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1115. {
  1116. return CopyOrMove(FALSE,bstrDestinationServerName,bstrDestinationServerInstance,varDestinationServerUserName,varDestinationServerPassword);
  1117. }
  1118. STDMETHODIMP CIISCertObj::Move(BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1119. {
  1120. return CopyOrMove(TRUE,bstrDestinationServerName,bstrDestinationServerInstance,varDestinationServerUserName,varDestinationServerPassword);
  1121. }
  1122. HRESULT CIISCertObj::CopyOrMove(BOOL bRemoveFromCertAfterCopy,BSTR bstrDestinationServerName,BSTR bstrDestinationServerInstance,VARIANT varDestinationServerUserName, VARIANT varDestinationServerPassword)
  1123. {
  1124. HRESULT hr = E_FAIL;
  1125. DWORD cbEncodedSize = 0;
  1126. char * pszEncodedString = NULL;
  1127. BOOL bGuessingUserNamePass = FALSE;
  1128. DWORD blob_cbData;
  1129. BYTE * blob_pbData = NULL;
  1130. BOOL blob_freeme = FALSE;
  1131. BOOL bPrivateKey = TRUE;
  1132. BOOL bCertChain = FALSE;
  1133. CString csDestinationServerName = bstrDestinationServerName;
  1134. CString csDestinationServerUserName;
  1135. CString csDestinationServerUserPassword;
  1136. CString csTempPassword;
  1137. IIISCertObj * pObj = NULL;
  1138. IIISCertObj * pObj2 = NULL;
  1139. BSTR bstrInstanceName = SysAllocString(m_InstanceName);
  1140. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1141. if (V_VT(&varDestinationServerUserName) != VT_ERROR)
  1142. {
  1143. VARIANT varBstrUserName;
  1144. VariantInit(&varBstrUserName);
  1145. HRESULT hr = VariantChangeType(&varBstrUserName, &varDestinationServerUserName, 0, VT_BSTR);
  1146. if (FAILED(hr)){goto Copy_Exit;}
  1147. csDestinationServerUserName = V_BSTR(&varBstrUserName);
  1148. VariantClear(&varBstrUserName);
  1149. }
  1150. else
  1151. {
  1152. // it's empty so don't use it
  1153. //csDestinationServerUserName = varDestinationServerUserName;
  1154. bGuessingUserNamePass = TRUE;
  1155. csDestinationServerUserName = m_UserName;
  1156. }
  1157. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1158. if (V_VT(&varDestinationServerPassword) != VT_ERROR)
  1159. {
  1160. VARIANT varBstrUserPassword;
  1161. VariantInit(&varBstrUserPassword);
  1162. HRESULT hr = VariantChangeType(&varBstrUserPassword, &varDestinationServerPassword, 0, VT_BSTR);
  1163. if (FAILED(hr)){goto Copy_Exit;}
  1164. csDestinationServerUserPassword = V_BSTR(&varBstrUserPassword);
  1165. VariantClear(&varBstrUserPassword);
  1166. }
  1167. else
  1168. {
  1169. if (TRUE == bGuessingUserNamePass)
  1170. {
  1171. csDestinationServerUserPassword = m_UserPassword;
  1172. }
  1173. else
  1174. {
  1175. // maybe the password was intended to be empty!
  1176. }
  1177. }
  1178. // --------------------------
  1179. // step 1.
  1180. // 1st of all check if we have access to
  1181. // both the servers!!!!
  1182. // --------------------------
  1183. // 1st we have to get the certblob from the Server#1
  1184. // so call export to get the data
  1185. hr = S_OK;
  1186. pObj = GetObject(&hr);
  1187. if (FAILED(hr))
  1188. {
  1189. return(hr);
  1190. }
  1191. // Logon to that server's CertObj.dll with the credentials supplied...
  1192. //
  1193. // if there were no credential's supplied then just use the ones that are in our object....
  1194. //
  1195. // if that doesn't work then try just the logged on user.
  1196. pObj2 = GetObject(&hr,csDestinationServerName,csDestinationServerUserName,csDestinationServerUserPassword);
  1197. if (FAILED(hr))
  1198. {
  1199. if (TRUE == bGuessingUserNamePass)
  1200. {
  1201. // try something else.
  1202. }
  1203. goto Copy_Exit;
  1204. }
  1205. //
  1206. // Create a unique password
  1207. //
  1208. // use the new secure password generator
  1209. // unfortunately this baby doesn't use unicode.
  1210. // so we'll call it and then convert it to unicode afterwards.
  1211. WCHAR * pwszPassword = CreatePassword(TEMP_PASSWORD_LENGTH);
  1212. // if its null -- ah, we can still use that...
  1213. BSTR bstrPassword = SysAllocString(pwszPassword);
  1214. // -----------------------------------
  1215. // step 2.
  1216. // okay we have access to both servers
  1217. // Grab the cert from server #1
  1218. // -----------------------------------
  1219. // Get data from the remote/local iis store return it back as a blob.
  1220. // The blob could be returned back as Base64 encoded so check that flag
  1221. hr = ExportToBlobProxy(pObj, bstrInstanceName, bstrPassword, bPrivateKey, bCertChain, &cbEncodedSize, &pszEncodedString);
  1222. if (FAILED(hr))
  1223. {
  1224. goto Copy_Exit;
  1225. }
  1226. int err;
  1227. // The data we got back was Base64 encoded to remove nulls.
  1228. // we need to decode it back to it's original format.
  1229. if( (err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS ||
  1230. (blob_pbData = (BYTE *) malloc(blob_cbData)) == NULL ||
  1231. (err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  1232. {
  1233. SetLastError(err);
  1234. hr = HRESULT_FROM_WIN32(err);
  1235. return hr;
  1236. }
  1237. blob_freeme = TRUE;
  1238. // -----------------------------------
  1239. // step 3.
  1240. // okay we have access to both servers
  1241. // we have the cert blob from server#1 in memory
  1242. // now we need to push this blob into the server#2
  1243. // -----------------------------------
  1244. hr = ImportFromBlobProxy(pObj2, bstrDestinationServerInstance, bstrPassword, blob_cbData, blob_pbData);
  1245. if (FAILED(hr))
  1246. {
  1247. goto Copy_Exit;
  1248. }
  1249. // we successfully copied the cert from machine #1 to machine #2.
  1250. // lets see if we need to delete the original cert!.
  1251. if (TRUE == bRemoveFromCertAfterCopy)
  1252. {
  1253. hr = pObj->RemoveCert(bstrInstanceName, bPrivateKey);
  1254. if (FAILED(hr))
  1255. {
  1256. goto Copy_Exit;
  1257. }
  1258. }
  1259. hr = S_OK;
  1260. Copy_Exit:
  1261. if (pwszPassword) {GlobalFree(pwszPassword);pwszPassword=NULL;}
  1262. if (blob_freeme){if (blob_pbData != NULL){free(blob_pbData);blob_pbData=NULL;}}
  1263. if (pszEncodedString != NULL){CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;}
  1264. return hr;
  1265. }
  1266. // password categories
  1267. enum {STRONG_PWD_UPPER=0,STRONG_PWD_LOWER,STRONG_PWD_NUM,STRONG_PWD_PUNC};
  1268. #define STRONG_PWD_CATS (STRONG_PWD_PUNC + 1)
  1269. #define NUM_LETTERS 26
  1270. #define NUM_NUMBERS 10
  1271. #define MIN_PWD_LEN 8
  1272. // password must contain at least one each of:
  1273. // uppercase, lowercase, punctuation and numbers
  1274. DWORD CreateGoodPassword(BYTE *szPwd, DWORD dwLen)
  1275. {
  1276. if (dwLen-1 < MIN_PWD_LEN)
  1277. {
  1278. return ERROR_PASSWORD_RESTRICTION;
  1279. }
  1280. HCRYPTPROV hProv;
  1281. DWORD dwErr = 0;
  1282. if (CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT) == FALSE)
  1283. {
  1284. return GetLastError();
  1285. }
  1286. // zero it out and decrement the size to allow for trailing '\0'
  1287. ZeroMemory(szPwd,dwLen);
  1288. dwLen--;
  1289. // generate a pwd pattern, each byte is in the range
  1290. // (0..255) mod STRONG_PWD_CATS
  1291. // this indicates which character pool to take a char from
  1292. BYTE *pPwdPattern = new BYTE[dwLen];
  1293. BOOL fFound[STRONG_PWD_CATS];
  1294. do
  1295. {
  1296. // bug!bug! does CGR() ever fail?
  1297. CryptGenRandom(hProv,dwLen,pPwdPattern);
  1298. fFound[STRONG_PWD_UPPER] =
  1299. fFound[STRONG_PWD_LOWER] =
  1300. fFound[STRONG_PWD_PUNC] =
  1301. fFound[STRONG_PWD_NUM] = FALSE;
  1302. for (DWORD i=0; i < dwLen; i++)
  1303. {
  1304. fFound[pPwdPattern[i] % STRONG_PWD_CATS] = TRUE;
  1305. }
  1306. // check that each character category is in the pattern
  1307. } while (!fFound[STRONG_PWD_UPPER] || !fFound[STRONG_PWD_LOWER] || !fFound[STRONG_PWD_PUNC] || !fFound[STRONG_PWD_NUM]);
  1308. // populate password with random data
  1309. // this, in conjunction with pPwdPattern, is
  1310. // used to determine the actual data
  1311. CryptGenRandom(hProv,dwLen,szPwd);
  1312. for (DWORD i=0; i < dwLen; i++)
  1313. {
  1314. BYTE bChar = 0;
  1315. // there is a bias in each character pool because of the % function
  1316. switch (pPwdPattern[i] % STRONG_PWD_CATS)
  1317. {
  1318. case STRONG_PWD_UPPER : bChar = 'A' + szPwd[i] % NUM_LETTERS;
  1319. break;
  1320. case STRONG_PWD_LOWER : bChar = 'a' + szPwd[i] % NUM_LETTERS;
  1321. break;
  1322. case STRONG_PWD_NUM : bChar = '0' + szPwd[i] % NUM_NUMBERS;
  1323. break;
  1324. case STRONG_PWD_PUNC :
  1325. default:
  1326. char *szPunc="!@#$%^&*()_-+=[{]};:\'\"<>,./?\\|~`";
  1327. DWORD dwLenPunc = lstrlenA(szPunc);
  1328. bChar = szPunc[szPwd[i] % dwLenPunc];
  1329. break;
  1330. }
  1331. szPwd[i] = bChar;
  1332. }
  1333. delete pPwdPattern;
  1334. if (hProv != NULL)
  1335. {
  1336. CryptReleaseContext(hProv,0);
  1337. }
  1338. return dwErr;
  1339. }
  1340. // Creates a secure password
  1341. // caller must GlobalFree Return pointer
  1342. // iSize = size of password to create
  1343. LPTSTR CreatePassword(int iSize)
  1344. {
  1345. LPTSTR pszPassword = NULL;
  1346. BYTE *szPwd = new BYTE[iSize];
  1347. DWORD dwPwdLen = iSize;
  1348. int i = 0;
  1349. // use the new secure password generator
  1350. // unfortunately this baby doesn't use unicode.
  1351. // so we'll call it and then convert it to unicode afterwards.
  1352. if (0 == CreateGoodPassword(szPwd,dwPwdLen))
  1353. {
  1354. #if defined(UNICODE) || defined(_UNICODE)
  1355. // convert it to unicode and copy it back into our unicode buffer.
  1356. // compute the length
  1357. i = MultiByteToWideChar(CP_ACP, 0, (LPSTR) szPwd, -1, NULL, 0);
  1358. if (i <= 0)
  1359. {goto CreatePassword_Exit;}
  1360. pszPassword = (LPTSTR) GlobalAlloc(GPTR, i * sizeof(TCHAR));
  1361. if (!pszPassword)
  1362. {goto CreatePassword_Exit;}
  1363. i = MultiByteToWideChar(CP_ACP, 0, (LPSTR) szPwd, -1, pszPassword, i);
  1364. if (i <= 0)
  1365. {
  1366. GlobalFree(pszPassword);
  1367. pszPassword = NULL;
  1368. goto CreatePassword_Exit;
  1369. }
  1370. // make sure ends with null
  1371. pszPassword[i - 1] = 0;
  1372. #else
  1373. pszPassword = (LPSTR) GlobalAlloc(GPTR, _tcslen((LPTSTR) szPwd) * sizeof(TCHAR));
  1374. #endif
  1375. }
  1376. CreatePassword_Exit:
  1377. if (szPwd){delete szPwd;szPwd=NULL;}
  1378. return pszPassword;
  1379. }