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.

1975 lines
55 KiB

  1. //
  2. // Certificat.cpp
  3. //
  4. #include "StdAfx.h"
  5. #include "CertWiz.h"
  6. #include "Certificat.h"
  7. #include "certutil.h"
  8. #include <malloc.h>
  9. #include "base64.h"
  10. #include "resource.h"
  11. #include <certupgr.h>
  12. #include <certca.h>
  13. #include "mru.h"
  14. #include "Shlwapi.h"
  15. #include <cryptui.h>
  16. // for certobj object
  17. #include "certobj.h"
  18. #include "certobj_i.c"
  19. const CLSID CLSID_CEnroll =
  20. {0x43F8F289, 0x7A20, 0x11D0, {0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1}};
  21. const IID IID_IEnroll =
  22. {0xacaa7838, 0x4585, 0x11d1, {0xab, 0x57, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  23. const IID IID_ICEnroll2 =
  24. {0x704ca730, 0xc90b, 0x11d1, {0x9b, 0xec, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  25. const CLSID CLSID_CCertRequest =
  26. {0x98aff3f0, 0x5524, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  27. const IID IID_ICertRequest =
  28. {0x014e4840, 0x5523, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  29. WCHAR * bstrEmpty = L"";
  30. extern CCertWizApp theApp;
  31. BOOL
  32. CCryptBlob::Resize(DWORD cb)
  33. {
  34. if (cb > GetSize())
  35. {
  36. if (NULL !=
  37. (m_blob.pbData = Realloc(m_blob.pbData, cb)))
  38. {
  39. m_blob.cbData = cb;
  40. return TRUE;
  41. }
  42. return FALSE;
  43. }
  44. return TRUE;
  45. }
  46. IMPLEMENT_DYNAMIC(CCertificate, CObject)
  47. CCertificate::CCertificate()
  48. : m_CAType(CA_OFFLINE),
  49. m_KeyLength(512),
  50. m_pPendingRequest(NULL),
  51. m_RespCertContext(NULL),
  52. m_pInstalledCert(NULL),
  53. m_pKeyRingCert(NULL),
  54. m_pEnroll(NULL),
  55. m_status_code(-1),
  56. m_CreateDirectory(FALSE),
  57. m_SGCcertificat(FALSE),
  58. m_DefaultCSP(TRUE),
  59. m_DefaultProviderType(PROV_RSA_SCHANNEL),
  60. m_ExportPFXPrivateKey(FALSE),
  61. m_CertObjInstalled(FALSE)
  62. {
  63. }
  64. CCertificate::~CCertificate()
  65. {
  66. if (m_pPendingRequest != NULL)
  67. CertFreeCertificateContext(m_pPendingRequest);
  68. if (m_RespCertContext != NULL)
  69. CertFreeCertificateContext(m_RespCertContext);
  70. if (m_pInstalledCert != NULL)
  71. CertFreeCertificateContext(m_pInstalledCert);
  72. if (m_pKeyRingCert != NULL)
  73. CertFreeCertificateContext(m_pKeyRingCert);
  74. if (m_pEnroll != NULL)
  75. m_pEnroll->Release();
  76. }
  77. const TCHAR szResponseFileName[] = _T("ResponseFileName");
  78. const TCHAR szKeyRingFileName[] = _T("KeyRingFileName");
  79. const TCHAR szRequestFileName[] = _T("RequestFileName");
  80. const TCHAR szCertificateTemplate[] = _T("CertificateTemplate");
  81. const TCHAR szState[] = _T("State");
  82. const TCHAR szStateMRU[] = _T("StateMRU");
  83. const TCHAR szLocality[] = _T("Locality");
  84. const TCHAR szLocalityMRU[] = _T("LocalityMRU");
  85. const TCHAR szOrganization[] = _T("Organization");
  86. const TCHAR szOrganizationMRU[] = _T("OrganizationMRU");
  87. const TCHAR szOrganizationUnit[] = _T("OrganizationUnit");
  88. const TCHAR szOrganizationUnitMRU[] = _T("OrganizationUnitMRU");
  89. const TCHAR szMachineNameRemote[] = _T("MachineNameRemote");
  90. const TCHAR szUserNameRemote[] = _T("UserNameRemote");
  91. const TCHAR szWebSiteInstanceNameRemote[] = _T("WebSiteInstanceNameRemote");
  92. #define QUERY_NAME(x,y)\
  93. do {\
  94. if (ERROR_SUCCESS == RegQueryValueEx(hKey, (x), NULL, &dwType, NULL, &cbData))\
  95. {\
  96. ASSERT(dwType == REG_SZ);\
  97. pName = (BYTE *)(y).GetBuffer(cbData);\
  98. RegQueryValueEx(hKey, (x), NULL, &dwType, pName, &cbData);\
  99. if (pName != NULL)\
  100. {\
  101. (y).ReleaseBuffer();\
  102. pName = NULL;\
  103. }\
  104. }\
  105. } while (0)
  106. BOOL
  107. CCertificate::Init()
  108. {
  109. ASSERT(!m_MachineName.IsEmpty());
  110. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  111. // get web site description from metabase, it could be empty
  112. // do not panic in case of error
  113. if (!GetServerComment(m_MachineName, m_WebSiteInstanceName, m_FriendlyName, &m_hResult))
  114. m_hResult = S_OK;
  115. m_CommonName = m_MachineName;
  116. m_CommonName.MakeLower();
  117. m_MachineName_Remote = m_MachineName;
  118. m_WebSiteInstanceName_Remote = m_WebSiteInstanceName;
  119. HKEY hKey = theApp.RegOpenKeyWizard();
  120. DWORD dwType;
  121. DWORD cbData;
  122. if (hKey != NULL)
  123. {
  124. BYTE * pName = NULL;
  125. QUERY_NAME(szRequestFileName, m_ReqFileName);
  126. QUERY_NAME(szResponseFileName, m_RespFileName);
  127. QUERY_NAME(szKeyRingFileName, m_KeyFileName);
  128. QUERY_NAME(szMachineNameRemote, m_MachineName_Remote);
  129. QUERY_NAME(szUserNameRemote, m_UserName_Remote);
  130. QUERY_NAME(szWebSiteInstanceNameRemote, m_WebSiteInstanceName_Remote);
  131. QUERY_NAME(szCertificateTemplate, m_CertificateTemplate);
  132. QUERY_NAME(szState, m_State);
  133. QUERY_NAME(szLocality, m_Locality);
  134. QUERY_NAME(szOrganization, m_Organization);
  135. QUERY_NAME(szOrganizationUnit, m_OrganizationUnit);
  136. RegCloseKey(hKey);
  137. }
  138. #ifdef _DEBUG
  139. else
  140. {
  141. TRACE(_T("Failed to open Registry key for Wizard parameters\n"));
  142. }
  143. #endif
  144. if (m_CertificateTemplate.IsEmpty())
  145. {
  146. // User didn't defined anything -- use standard name
  147. m_CertificateTemplate = wszCERTTYPE_WEBSERVER;
  148. }
  149. // Set flag to tell if com certobj is installed
  150. m_CertObjInstalled = IsCertObjInstalled();
  151. return TRUE;
  152. }
  153. #define SAVE_NAME(x,y)\
  154. do {\
  155. if (!(y).IsEmpty())\
  156. {\
  157. VERIFY(ERROR_SUCCESS == RegSetValueEx(hKey, (x), 0, REG_SZ, \
  158. (const BYTE *)(LPCTSTR)(y), \
  159. sizeof(TCHAR) * ((y).GetLength() + 1)));\
  160. }\
  161. } while (0)
  162. BOOL
  163. CCertificate::SaveSettings()
  164. {
  165. HKEY hKey = theApp.RegOpenKeyWizard();
  166. if (hKey != NULL)
  167. {
  168. switch (GetStatusCode())
  169. {
  170. case REQUEST_NEW_CERT:
  171. case REQUEST_RENEW_CERT:
  172. SAVE_NAME(szState, m_State);
  173. AddToMRU(szStateMRU, m_State);
  174. SAVE_NAME(szLocality, m_Locality);
  175. AddToMRU(szLocalityMRU, m_Locality);
  176. SAVE_NAME(szOrganization, m_Organization);
  177. AddToMRU(szOrganizationMRU, m_Organization);
  178. SAVE_NAME(szOrganizationUnit, m_OrganizationUnit);
  179. AddToMRU(szOrganizationUnitMRU, m_OrganizationUnit);
  180. SAVE_NAME(szRequestFileName, m_ReqFileName);
  181. break;
  182. case REQUEST_PROCESS_PENDING:
  183. SAVE_NAME(szResponseFileName, m_RespFileName);
  184. break;
  185. case REQUEST_IMPORT_KEYRING:
  186. SAVE_NAME(szKeyRingFileName, m_KeyFileName);
  187. break;
  188. case REQUEST_IMPORT_CERT:
  189. case REQUEST_EXPORT_CERT:
  190. SAVE_NAME(szKeyRingFileName, m_KeyFileName);
  191. break;
  192. case REQUEST_COPY_MOVE_FROM_REMOTE:
  193. case REQUEST_COPY_MOVE_TO_REMOTE:
  194. SAVE_NAME(szKeyRingFileName, m_KeyFileName);
  195. SAVE_NAME(szMachineNameRemote, m_MachineName_Remote);
  196. SAVE_NAME(szUserNameRemote, m_UserName_Remote);
  197. SAVE_NAME(szWebSiteInstanceNameRemote, m_WebSiteInstanceName_Remote);
  198. break;
  199. default:
  200. break;
  201. }
  202. RegCloseKey(hKey);
  203. return TRUE;
  204. }
  205. #ifdef _DEBUG
  206. else
  207. {
  208. TRACE(_T("Failed to open Registry key for Wizard parameters\n"));
  209. }
  210. #endif
  211. return FALSE;
  212. }
  213. BOOL
  214. CCertificate::SetSecuritySettings()
  215. {
  216. long dwGenKeyFlags;
  217. if (SUCCEEDED(GetEnrollObject()->get_GenKeyFlags(&dwGenKeyFlags)))
  218. {
  219. dwGenKeyFlags &= 0x0000FFFF;
  220. dwGenKeyFlags |= (m_KeyLength << 16);
  221. if (m_SGCcertificat)
  222. dwGenKeyFlags |= CRYPT_SGCKEY;
  223. return (SUCCEEDED(GetEnrollObject()->put_GenKeyFlags(dwGenKeyFlags)));
  224. }
  225. return FALSE;
  226. }
  227. // defines taken from the old KeyGen utility
  228. #define MESSAGE_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n"
  229. #define MESSAGE_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n"
  230. BOOL
  231. CCertificate::WriteRequestString(CString& request)
  232. {
  233. ASSERT(!PathIsRelative(m_ReqFileName));
  234. BOOL bRes = FALSE;
  235. try {
  236. CString strPath;
  237. strPath = m_ReqFileName;
  238. LPTSTR pPath = strPath.GetBuffer(strPath.GetLength());
  239. PathRemoveFileSpec(pPath);
  240. if (!PathIsDirectory(pPath))
  241. {
  242. if (!CreateDirectoryFromPath(strPath, NULL))
  243. {
  244. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  245. SetBodyTextID(USE_DEFAULT_CAPTION);
  246. return FALSE;
  247. }
  248. }
  249. strPath.ReleaseBuffer();
  250. HANDLE hFile = ::CreateFile(m_ReqFileName,
  251. GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  252. if (hFile != INVALID_HANDLE_VALUE)
  253. {
  254. DWORD cb = request.GetLength();
  255. char * ascii_buf = (char *)_alloca(cb);
  256. wcstombs(ascii_buf, request, cb);
  257. bRes = ::WriteFile(hFile, ascii_buf, cb, &cb, NULL);
  258. ::CloseHandle(hFile);
  259. }
  260. else
  261. {
  262. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  263. SetBodyTextID(USE_DEFAULT_CAPTION);
  264. }
  265. }
  266. catch (CFileException * e)
  267. {
  268. TCHAR szCause[255];
  269. e->GetErrorMessage(szCause, 255);
  270. TRACE(_T("Got CFileException with error: %s\n"), szCause);
  271. m_hResult = HRESULT_FROM_WIN32(e->m_lOsError);
  272. }
  273. catch (CException * e)
  274. {
  275. TCHAR szCause[255];
  276. e->GetErrorMessage(szCause, 255);
  277. TRACE(_T("Got CException with error: %s\n"), szCause);
  278. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  279. }
  280. return bRes;
  281. }
  282. #define HEADER_SERVER_ _T("Server:\t%s\r\n\r\n")
  283. #define HEADER_COMMON_NAME_ _T("Common-name:\t%s\r\n")
  284. #define HEADER_FRIENDLY_NAME_ _T("Friendly name:\t%s\r\n")
  285. #define HEADER_ORG_UNIT_ _T("Organization Unit:\t%s\r\n")
  286. #define HEADER_ORGANIZATION_ _T("Organization:\t%s\r\n")
  287. #define HEADER_LOCALITY_ _T("Locality:\t%s\r\n")
  288. #define HEADER_STATE_ _T("State:\t%s\r\n")
  289. #define HEADER_COUNTRY_ _T("Country:\t%s\r\n")
  290. static void WRITE_LINE(CString& str, TCHAR * format, CString& data)
  291. {
  292. CString buf;
  293. buf.Format(format, data);
  294. str += buf;
  295. }
  296. void
  297. CCertificate::DumpHeader(CString& str)
  298. {
  299. DumpOnlineHeader(str);
  300. }
  301. void
  302. CCertificate::DumpOnlineHeader(CString& str)
  303. {
  304. WRITE_LINE(str, HEADER_SERVER_, m_CommonName);
  305. WRITE_LINE(str, HEADER_FRIENDLY_NAME_, m_FriendlyName);
  306. WRITE_LINE(str, HEADER_ORG_UNIT_, m_OrganizationUnit);
  307. WRITE_LINE(str, HEADER_ORGANIZATION_, m_Organization);
  308. WRITE_LINE(str, HEADER_LOCALITY_, m_Locality);;
  309. WRITE_LINE(str, HEADER_STATE_, m_State);
  310. WRITE_LINE(str, HEADER_COUNTRY_, m_Country);
  311. }
  312. BOOL
  313. CCertificate::GetSelectedCertDescription(CERT_DESCRIPTION& cd)
  314. {
  315. BOOL bRes = FALSE;
  316. ASSERT(m_pSelectedCertHash != NULL);
  317. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  318. if (hStore != NULL)
  319. {
  320. PCCERT_CONTEXT pCert = CertFindCertificateInStore(hStore,
  321. CRYPT_ASN_ENCODING,
  322. 0,
  323. CERT_FIND_HASH,
  324. m_pSelectedCertHash,
  325. NULL);
  326. if (pCert != NULL)
  327. {
  328. bRes = GetCertDescription(pCert, cd);
  329. CertFreeCertificateContext(pCert);
  330. }
  331. CertCloseStore(hStore, 0);
  332. }
  333. return bRes;
  334. }
  335. void CCertificate::CreateDN(CString& str)
  336. {
  337. str.Empty();
  338. str += _T("CN=") + m_CommonName;
  339. str += _T("\n,OU=") + m_OrganizationUnit;
  340. str += _T("\n,O=") + m_Organization;
  341. str += _T("\n,L=") + m_Locality;
  342. str += _T("\n,S=") + m_State;
  343. str += _T("\n,C=") + m_Country;
  344. }
  345. PCCERT_CONTEXT
  346. CCertificate::GetPendingRequest()
  347. {
  348. if (m_pPendingRequest == NULL)
  349. {
  350. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  351. m_pPendingRequest = GetPendingDummyCert(m_WebSiteInstanceName,
  352. GetEnrollObject(), &m_hResult);
  353. }
  354. return m_pPendingRequest;
  355. }
  356. PCCERT_CONTEXT
  357. CCertificate::GetInstalledCert()
  358. {
  359. if (m_pInstalledCert == NULL)
  360. {
  361. m_pInstalledCert = ::GetInstalledCert(m_MachineName,
  362. m_WebSiteInstanceName,
  363. GetEnrollObject(),
  364. &m_hResult);
  365. }
  366. return m_pInstalledCert;
  367. }
  368. PCCERT_CONTEXT
  369. CCertificate::GetPFXFileCert()
  370. {
  371. ASSERT(!m_KeyFileName.IsEmpty());
  372. ASSERT(!m_KeyPassword.IsEmpty());
  373. IIISCertObj *pTheObject = NULL;
  374. DWORD cbBinaryBufferSize = 0;
  375. char * pbBinaryBuffer = NULL;
  376. BOOL bPleaseDoCoUninit = FALSE;
  377. BOOL bAllowExport = m_MarkAsExportable;
  378. if (FALSE == m_CertObjInstalled)
  379. {
  380. m_pKeyRingCert = NULL;
  381. goto GetPFXFileCert_Exit;
  382. }
  383. if (m_pKeyRingCert == NULL)
  384. {
  385. BSTR bstrFileName = SysAllocString(m_KeyFileName);
  386. BSTR bstrFilePassword = SysAllocString(m_KeyPassword);
  387. VARIANT VtArray;
  388. m_hResult = CoInitialize(NULL);
  389. if(FAILED(m_hResult))
  390. {
  391. return NULL;
  392. }
  393. bPleaseDoCoUninit = TRUE;
  394. // this one seems to work with surrogates..
  395. m_hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
  396. if (FAILED(m_hResult))
  397. {
  398. goto GetPFXFileCert_Exit;
  399. }
  400. // at this point we were able to instantiate the com object on the server (local or remote)
  401. m_hResult = pTheObject->ImportToCertStore(bstrFileName, bstrFilePassword, bAllowExport, &VtArray);
  402. if (FAILED(m_hResult))
  403. {
  404. m_pKeyRingCert = NULL;
  405. goto GetPFXFileCert_Exit;
  406. }
  407. // we have a VtArray now.
  408. // change it back to a binary blob
  409. m_hResult = HereIsVtArrayGimmieBinary(&VtArray,&cbBinaryBufferSize,&pbBinaryBuffer,FALSE);
  410. if (FAILED(m_hResult))
  411. {
  412. m_pKeyRingCert = NULL;
  413. goto GetPFXFileCert_Exit;
  414. }
  415. // we have the hash now.
  416. // we can use it to lookup the cert and get the PCCERT_CONTEXT
  417. // Get the pointer to the cert...
  418. m_pKeyRingCert = GetInstalledCertFromHash(&m_hResult,cbBinaryBufferSize,pbBinaryBuffer);
  419. }
  420. GetPFXFileCert_Exit:
  421. if (pTheObject)
  422. {
  423. pTheObject->Release();
  424. pTheObject = NULL;
  425. }
  426. if (pbBinaryBuffer)
  427. {
  428. CoTaskMemFree(pbBinaryBuffer);
  429. }
  430. if (bPleaseDoCoUninit)
  431. {
  432. CoUninitialize();
  433. }
  434. return m_pKeyRingCert;
  435. }
  436. PCCERT_CONTEXT
  437. CCertificate::GetKeyRingCert()
  438. {
  439. ASSERT(!m_KeyFileName.IsEmpty());
  440. ASSERT(!m_KeyPassword.IsEmpty());
  441. if (m_pKeyRingCert == NULL)
  442. {
  443. int len = m_KeyPassword.GetLength() * 2;
  444. char * ascii_password = (char *)_alloca(len + 1);
  445. ASSERT(ascii_password != NULL);
  446. size_t n;
  447. VERIFY(-1 != (n = wcstombs(ascii_password, m_KeyPassword, len)));
  448. ascii_password[n] = '\0';
  449. m_pKeyRingCert = ::ImportKRBackupToCAPIStore(
  450. (LPTSTR)(LPCTSTR)m_KeyFileName,
  451. ascii_password,
  452. _T("MY"));
  453. if (m_pKeyRingCert == NULL)
  454. {
  455. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  456. }
  457. }
  458. return m_pKeyRingCert;
  459. }
  460. /* INTRINSA suppress=null_pointers, uninitialized */
  461. PCCERT_CONTEXT
  462. CCertificate::GetResponseCert()
  463. {
  464. if (m_RespCertContext == NULL)
  465. {
  466. ASSERT(!m_RespFileName.IsEmpty());
  467. m_RespCertContext = GetCertContextFromPKCS7File(
  468. m_RespFileName,
  469. &GetPendingRequest()->pCertInfo->SubjectPublicKeyInfo,
  470. &m_hResult);
  471. ASSERT(SUCCEEDED(m_hResult));
  472. }
  473. return m_RespCertContext;
  474. }
  475. BOOL
  476. CCertificate::GetResponseCertDescription(CERT_DESCRIPTION& cd)
  477. {
  478. CERT_DESCRIPTION cdReq;
  479. if (GetCertDescription(GetResponseCert(), cd))
  480. {
  481. if (GetCertDescription(GetPendingRequest(), cdReq))
  482. {
  483. cd.m_FriendlyName = cdReq.m_FriendlyName;
  484. }
  485. return TRUE;
  486. }
  487. return FALSE;
  488. }
  489. /*------------------------------------------------------------------------------
  490. IsResponseInstalled
  491. Function checks if certificate from the response file
  492. m_RespFileName was istalled to some server. If possible,
  493. it returns name of this server in str.
  494. Returns FALSE if certificate is not found in MY store or
  495. if this store cannot be opened
  496. */
  497. BOOL
  498. CCertificate::IsResponseInstalled(
  499. CString& str // return server instance name (not yet implemented)
  500. )
  501. {
  502. BOOL bRes = FALSE;
  503. // get cert context from response file
  504. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7File(
  505. m_RespFileName, NULL, &m_hResult);
  506. if (pContext != NULL)
  507. {
  508. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  509. if (hStore != NULL)
  510. {
  511. PCCERT_CONTEXT pCert = NULL;
  512. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  513. {
  514. // do not include installed cert to the list
  515. if (CertCompareCertificate(X509_ASN_ENCODING,
  516. pContext->pCertInfo, pCert->pCertInfo))
  517. {
  518. bRes = TRUE;
  519. // Try to find, where is was installed
  520. break;
  521. }
  522. }
  523. if (pCert != NULL)
  524. CertFreeCertificateContext(pCert);
  525. }
  526. }
  527. return bRes;
  528. }
  529. BOOL
  530. CCertificate::FindInstanceNameForResponse(CString& str)
  531. {
  532. BOOL bRes = FALSE;
  533. // get cert context from response file
  534. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7File(
  535. m_RespFileName, NULL, &m_hResult);
  536. if (pContext != NULL)
  537. {
  538. // find dummy cert in REQUEST store that has public key
  539. // the same as in this context
  540. PCCERT_CONTEXT pReq = GetReqCertByKey(GetEnrollObject(),
  541. &pContext->pCertInfo->SubjectPublicKeyInfo, &m_hResult);
  542. if (pReq != NULL)
  543. {
  544. // get friendly name prop from this dummy cert
  545. if (!GetFriendlyName(pReq, str, &m_hResult))
  546. {
  547. // get instance name prop from this dummy cert
  548. DWORD cb;
  549. BYTE * prop;
  550. if ( CertGetCertificateContextProperty(pReq, CERTWIZ_INSTANCE_NAME_PROP_ID, NULL, &cb)
  551. && (NULL != (prop = (BYTE *)_alloca(cb)))
  552. && CertGetCertificateContextProperty(pReq, CERTWIZ_INSTANCE_NAME_PROP_ID, prop, &cb)
  553. )
  554. {
  555. // decode this instance name property
  556. DWORD cbData = 0;
  557. BYTE * data = NULL;
  558. if ( CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  559. prop, cb, 0, NULL, &cbData)
  560. && (NULL != (data = (BYTE *)_alloca(cbData)))
  561. && CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  562. prop, cb, 0, data, &cbData)
  563. )
  564. {
  565. CERT_NAME_VALUE * p = (CERT_NAME_VALUE *)data;
  566. CString strInstanceName = (LPCTSTR)p->Value.pbData;
  567. // now try to get comment from this server
  568. if (GetServerComment(m_MachineName, strInstanceName, str, &m_hResult))
  569. {
  570. if (str.IsEmpty())
  571. {
  572. // generate something like [Web Site #n]
  573. str.LoadString(IDS_WEB_SITE_N);
  574. int len = strInstanceName.GetLength();
  575. for (int i = len - 1, count = 0; i >= 0; i--, count++)
  576. {
  577. if (!_istdigit(strInstanceName.GetAt(i)))
  578. break;
  579. }
  580. ASSERT(count < len);
  581. AfxFormatString1(str, IDS_WEB_SITE_N, strInstanceName.Right(count));
  582. }
  583. }
  584. m_hResult = S_OK;
  585. bRes = TRUE;
  586. }
  587. }
  588. }
  589. CertFreeCertificateContext(pReq);
  590. }
  591. else
  592. {
  593. // probably this request was deleted from the request store
  594. }
  595. CertFreeCertificateContext(pContext);
  596. }
  597. return bRes;
  598. }
  599. IEnroll *
  600. CCertificate::GetEnrollObject()
  601. {
  602. if (m_pEnroll == NULL)
  603. {
  604. m_hResult = CoCreateInstance(CLSID_CEnroll,
  605. NULL,
  606. CLSCTX_INPROC_SERVER,
  607. IID_IEnroll,
  608. (void **)&m_pEnroll);
  609. // now we need to change defaults for this
  610. // object to LOCAL_MACHINE
  611. if (m_pEnroll != NULL)
  612. {
  613. long dwFlags;
  614. VERIFY(SUCCEEDED(m_pEnroll->get_MyStoreFlags(&dwFlags)));
  615. dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
  616. dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
  617. // following call will change Request store flags also
  618. VERIFY(SUCCEEDED(m_pEnroll->put_MyStoreFlags(dwFlags)));
  619. VERIFY(SUCCEEDED(m_pEnroll->get_GenKeyFlags(&dwFlags)));
  620. dwFlags |= CRYPT_EXPORTABLE;
  621. VERIFY(SUCCEEDED(m_pEnroll->put_GenKeyFlags(dwFlags)));
  622. VERIFY(SUCCEEDED(m_pEnroll->put_KeySpec(AT_KEYEXCHANGE)));
  623. VERIFY(SUCCEEDED(m_pEnroll->put_ProviderType(m_DefaultProviderType)));
  624. VERIFY(SUCCEEDED(m_pEnroll->put_DeleteRequestCert(TRUE)));
  625. }
  626. }
  627. ASSERT(m_pEnroll != NULL);
  628. return m_pEnroll;
  629. }
  630. BOOL
  631. CCertificate::HasInstalledCert()
  632. {
  633. BOOL bResult = FALSE;
  634. CComAuthInfo auth;
  635. CMetaKey key(&auth,
  636. m_WebSiteInstanceName,
  637. METADATA_PERMISSION_READ,
  638. METADATA_MASTER_ROOT_HANDLE
  639. );
  640. if (key.Succeeded())
  641. {
  642. CString store_name;
  643. CBlob blob;
  644. if ( S_OK == key.QueryValue(MD_SSL_CERT_HASH, blob)
  645. && S_OK == key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name)
  646. )
  647. {
  648. bResult = TRUE;
  649. }
  650. }
  651. return bResult;
  652. }
  653. HRESULT
  654. CCertificate::UninstallCert()
  655. {
  656. CComAuthInfo auth;
  657. CMetaKey key(
  658. &auth,
  659. m_WebSiteInstanceName,
  660. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  661. METADATA_MASTER_ROOT_HANDLE
  662. );
  663. if (key.Succeeded())
  664. {
  665. CString store_name;
  666. key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name);
  667. if (SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH)))
  668. {
  669. key.DeleteValue(MD_SSL_CERT_STORE_NAME);
  670. }
  671. }
  672. return m_hResult = key.QueryResult();
  673. }
  674. BOOL CCertificate::WriteRequestBody()
  675. {
  676. ASSERT(!m_ReqFileName.IsEmpty());
  677. HRESULT hr;
  678. BOOL bRes = FALSE;
  679. CString strDN;
  680. CreateDN(strDN);
  681. ASSERT(!strDN.IsEmpty());
  682. CString strUsage(szOID_PKIX_KP_SERVER_AUTH);
  683. CCryptBlobIMalloc request;
  684. GetEnrollObject()->put_ProviderType(m_DefaultCSP ?
  685. m_DefaultProviderType : m_CustomProviderType);
  686. if (!m_DefaultCSP)
  687. {
  688. GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_CspName);
  689. GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
  690. }
  691. if (SUCCEEDED(hr = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,
  692. (LPTSTR)(LPCTSTR)strUsage,
  693. request)))
  694. {
  695. // BASE64 encode pkcs 10
  696. DWORD err, cch;
  697. char * psz;
  698. if ( (err = Base64EncodeA(request.GetData(), request.GetSize(), NULL, &cch)) == ERROR_SUCCESS
  699. && (psz = (char *)_alloca(cch)) != NULL
  700. && (err = Base64EncodeA(request.GetData(), request.GetSize(), psz, &cch)) == ERROR_SUCCESS
  701. )
  702. {
  703. HANDLE hFile = ::CreateFile(m_ReqFileName,
  704. GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  705. if (hFile == INVALID_HANDLE_VALUE)
  706. return FALSE;
  707. DWORD written;
  708. ::SetFilePointer(hFile, 0, NULL, FILE_END);
  709. ::WriteFile(hFile, MESSAGE_HEADER, sizeof(MESSAGE_HEADER) - 1, &written, NULL);
  710. ::WriteFile(hFile, psz, cch, &written, NULL);
  711. ::WriteFile(hFile, MESSAGE_TRAILER, sizeof(MESSAGE_TRAILER) - 1, &written, NULL);
  712. ::CloseHandle(hFile);
  713. // get back request from encoded data
  714. PCERT_REQUEST_INFO req_info;
  715. VERIFY(GetRequestInfoFromPKCS10(request, &req_info, &m_hResult));
  716. // find dummy cert put to request store by createPKCS10 call
  717. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  718. if (hStore != NULL)
  719. {
  720. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  721. CRYPT_ASN_ENCODING,
  722. 0,
  723. CERT_FIND_PUBLIC_KEY,
  724. (void *)&req_info->SubjectPublicKeyInfo,
  725. NULL);
  726. if (pDummyCert != NULL)
  727. {
  728. // now we need to attach web server instance name to this cert
  729. // encode string into data blob
  730. CRYPT_DATA_BLOB name;
  731. CERT_NAME_VALUE name_value;
  732. name_value.dwValueType = CERT_RDN_BMP_STRING;
  733. name_value.Value.cbData = 0;
  734. name_value.Value.pbData = (LPBYTE)(LPCTSTR)m_WebSiteInstanceName;
  735. {
  736. if ( !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  737. &name_value, NULL, &name.cbData)
  738. || (name.pbData = (BYTE *)_alloca(name.cbData)) == NULL
  739. || !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  740. &name_value, name.pbData, &name.cbData)
  741. )
  742. {
  743. ASSERT(FALSE);
  744. }
  745. VERIFY(bRes = CertSetCertificateContextProperty(pDummyCert,
  746. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, &name));
  747. }
  748. // put friendly name to dummy cert -- we will reuse it later
  749. m_FriendlyName.ReleaseBuffer();
  750. AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult);
  751. // we also need to put some flag to show what we are waiting for:
  752. // new sertificate or renewing certificate
  753. CRYPT_DATA_BLOB flag;
  754. if ( !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  755. &m_status_code, NULL, &flag.cbData)
  756. || (flag.pbData = (BYTE *)_alloca(flag.cbData)) == NULL
  757. || !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  758. &m_status_code, flag.pbData, &flag.cbData)
  759. )
  760. {
  761. ASSERT(FALSE);
  762. }
  763. VERIFY(bRes = CertSetCertificateContextProperty(pDummyCert,
  764. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, &flag));
  765. CertFreeCertificateContext(pDummyCert);
  766. }
  767. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  768. }
  769. LocalFree(req_info);
  770. }
  771. bRes = TRUE;
  772. }
  773. return bRes;
  774. }
  775. BOOL
  776. CCertificate::InstallResponseCert()
  777. {
  778. BOOL bRes = FALSE;
  779. CCryptBlobLocal blobRequestText;
  780. // Get all our data attached to dummy cert
  781. GetFriendlyName(GetPendingRequest(), m_FriendlyName, &m_hResult);
  782. ASSERT(!m_FriendlyName.IsEmpty());
  783. GetBlobProperty(GetPendingRequest(),
  784. CERTWIZ_REQUEST_TEXT_PROP_ID, blobRequestText, &m_hResult);
  785. ASSERT(blobRequestText.GetSize() != 0);
  786. CCryptBlobLocal hash_blob;
  787. if (::GetHashProperty(GetResponseCert(), hash_blob, &m_hResult))
  788. {
  789. if (SUCCEEDED(m_hResult = GetEnrollObject()->acceptFilePKCS7WStr(
  790. (LPTSTR)(LPCTSTR)m_RespFileName))
  791. && InstallCertByHash(hash_blob, m_MachineName, m_WebSiteInstanceName,
  792. GetEnrollObject(), &m_hResult)
  793. )
  794. {
  795. // reattach friendly name and request text to installed cert
  796. m_FriendlyName.ReleaseBuffer();
  797. AttachFriendlyName(GetInstalledCert(), m_FriendlyName, &m_hResult);
  798. bRes = CertSetCertificateContextProperty(GetInstalledCert(),
  799. CERTWIZ_REQUEST_TEXT_PROP_ID, 0, blobRequestText);
  800. }
  801. }
  802. if (!bRes)
  803. {
  804. SetBodyTextID(USE_DEFAULT_CAPTION);
  805. }
  806. return bRes;
  807. }
  808. BOOL
  809. CCertificate::InstallCopyMoveFromRemote()
  810. {
  811. ASSERT(!m_KeyFileName.IsEmpty());
  812. ASSERT(!m_KeyPassword.IsEmpty());
  813. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  814. BOOL bRes = FALSE;
  815. BOOL bPleaseDoCoUninit = FALSE;
  816. IIISCertObj *pTheObject = NULL;
  817. VARIANT varUserName;
  818. VARIANT varUserPassword;
  819. VARIANT * pvarUserName = &varUserName;
  820. VARIANT * pvarUserPassword = &varUserPassword;
  821. VariantInit(pvarUserName);
  822. VariantInit(pvarUserPassword);
  823. BOOL bAllowExport = m_MarkAsExportable;
  824. if (FALSE == m_CertObjInstalled)
  825. {
  826. goto InstallCopyMoveFromRemote_Exit;
  827. }
  828. pvarUserName->bstrVal = SysAllocString(_T(""));
  829. pvarUserPassword->bstrVal = SysAllocString(_T(""));
  830. V_VT(pvarUserName) = VT_BSTR;
  831. V_VT(pvarUserPassword) = VT_BSTR;
  832. // set the properties to the remote server's info
  833. // when we call copy, it will connect to the
  834. // remote object and copy it back into our object
  835. // local machine
  836. BSTR bstrServerName = SysAllocString(m_MachineName);
  837. BSTR bstrUserName = SysAllocString(_T(""));
  838. BSTR bstrUserPassword = SysAllocString(_T(""));
  839. BSTR bstrInstanceName = SysAllocString(m_WebSiteInstanceName);
  840. // remote machine
  841. BSTR bstrUserName_Remote = SysAllocString(m_UserName_Remote);
  842. BSTR bstrUserPassword_Remote = SysAllocString(m_UserPassword_Remote);
  843. BSTR bstrServerName_Remote = SysAllocString(m_MachineName_Remote);
  844. BSTR bstrInstanceName_Remote = SysAllocString(m_WebSiteInstanceName_Remote);
  845. m_hResult = CoInitialize(NULL);
  846. if(FAILED(m_hResult))
  847. {
  848. return bRes;
  849. }
  850. bPleaseDoCoUninit = TRUE;
  851. // this one seems to work with surrogates..
  852. m_hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
  853. if (FAILED(m_hResult))
  854. {
  855. goto InstallCopyMoveFromRemote_Exit;
  856. }
  857. // at this point we were able to instantiate the com object on the server (local or remote)
  858. pTheObject->put_ServerName(bstrServerName_Remote);
  859. pTheObject->put_UserName(bstrUserName_Remote);
  860. pTheObject->put_UserPassword(bstrUserPassword_Remote);
  861. pTheObject->put_InstanceName(bstrInstanceName_Remote);
  862. if (m_DeleteAfterCopy)
  863. {
  864. m_hResult = pTheObject->Move(bAllowExport, bstrServerName,bstrInstanceName,varUserName,varUserPassword);
  865. }
  866. else
  867. {
  868. m_hResult = pTheObject->Copy(bAllowExport, bstrServerName,bstrInstanceName,varUserName,varUserPassword);
  869. }
  870. if (FAILED(m_hResult))
  871. {
  872. goto InstallCopyMoveFromRemote_Exit;
  873. }
  874. bRes = TRUE;
  875. InstallCopyMoveFromRemote_Exit:
  876. if (pvarUserName)
  877. {
  878. VariantClear(pvarUserName);
  879. }
  880. if (pvarUserPassword)
  881. {
  882. VariantClear(pvarUserPassword);
  883. }
  884. if (!bRes)
  885. {
  886. SetBodyTextID(USE_DEFAULT_CAPTION);
  887. }
  888. if (pTheObject)
  889. {
  890. pTheObject->Release();
  891. pTheObject = NULL;
  892. }
  893. if (bPleaseDoCoUninit)
  894. {
  895. CoUninitialize();
  896. }
  897. return bRes;
  898. }
  899. BOOL CCertificate::IsCertObjInstalled()
  900. {
  901. BOOL bReturn = FALSE;
  902. HRESULT hRes = E_FAIL;
  903. BOOL bPleaseDoCoUninit = FALSE;
  904. IIISCertObj *pTheObject = NULL;
  905. hRes = CoInitialize(NULL);
  906. if(FAILED(hRes))
  907. {
  908. bReturn = FALSE;
  909. goto IsCertObjInstalled_Exit;
  910. }
  911. bPleaseDoCoUninit = TRUE;
  912. // this one seems to work with surrogates..
  913. hRes = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
  914. if (FAILED(hRes))
  915. {
  916. bReturn = FALSE;
  917. goto IsCertObjInstalled_Exit;
  918. }
  919. if (pTheObject)
  920. {
  921. bReturn = TRUE;
  922. pTheObject->Release();
  923. pTheObject = NULL;
  924. }
  925. IsCertObjInstalled_Exit:
  926. if (bPleaseDoCoUninit)
  927. {
  928. CoUninitialize();
  929. }
  930. return bReturn;
  931. }
  932. BOOL
  933. CCertificate::InstallCopyMoveToRemote()
  934. {
  935. ASSERT(!m_KeyFileName.IsEmpty());
  936. ASSERT(!m_KeyPassword.IsEmpty());
  937. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  938. BOOL bRes = FALSE;
  939. BOOL bPleaseDoCoUninit = FALSE;
  940. IIISCertObj *pTheObject = NULL;
  941. VARIANT varUserName_Remote;
  942. VARIANT varUserPassword_Remote;
  943. VARIANT * pvarUserName_Remote = &varUserName_Remote;
  944. VARIANT * pvarUserPassword_Remote = &varUserPassword_Remote;
  945. VariantInit(pvarUserName_Remote);
  946. VariantInit(pvarUserPassword_Remote);
  947. BOOL bAllowExport = m_MarkAsExportable;
  948. if (FALSE == m_CertObjInstalled)
  949. {
  950. goto InstallCopyMoveToRemote_Exit;
  951. }
  952. pvarUserName_Remote->bstrVal = SysAllocString(m_UserName_Remote);
  953. pvarUserPassword_Remote->bstrVal = SysAllocString(m_UserPassword_Remote);
  954. V_VT(pvarUserName_Remote) = VT_BSTR;
  955. V_VT(pvarUserPassword_Remote) = VT_BSTR;
  956. // set the properties to the remote server's info
  957. // when we call copy, it will connect to the
  958. // remote object and copy it back into our object
  959. // local machine
  960. BSTR bstrServerName = SysAllocString(_T(""));
  961. BSTR bstrUserName = SysAllocString(_T(""));
  962. BSTR bstrUserPassword = SysAllocString(_T(""));
  963. BSTR bstrInstanceName = SysAllocString(m_WebSiteInstanceName);
  964. // remote machine
  965. BSTR bstrServerName_Remote = SysAllocString(m_MachineName_Remote);
  966. BSTR bstrInstanceName_Remote = SysAllocString(m_WebSiteInstanceName_Remote);
  967. m_hResult = CoInitialize(NULL);
  968. if(FAILED(m_hResult))
  969. {
  970. return bRes;
  971. }
  972. bPleaseDoCoUninit = TRUE;
  973. // this one seems to work with surrogates..
  974. m_hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
  975. if (FAILED(m_hResult))
  976. {
  977. goto InstallCopyMoveToRemote_Exit;
  978. }
  979. // at this point we were able to instantiate the com object on the server (local or remote)
  980. pTheObject->put_ServerName(bstrServerName);
  981. pTheObject->put_UserName(bstrUserName);
  982. pTheObject->put_UserPassword(bstrUserPassword);
  983. pTheObject->put_InstanceName(bstrInstanceName);
  984. if (m_DeleteAfterCopy)
  985. {
  986. m_hResult = pTheObject->Move(bAllowExport, bstrServerName_Remote,bstrInstanceName_Remote,varUserName_Remote,varUserPassword_Remote);
  987. }
  988. else
  989. {
  990. m_hResult = pTheObject->Copy(bAllowExport, bstrServerName_Remote,bstrInstanceName_Remote,varUserName_Remote,varUserPassword_Remote);
  991. }
  992. if (FAILED(m_hResult))
  993. {
  994. goto InstallCopyMoveToRemote_Exit;
  995. }
  996. m_hResult = S_OK;
  997. bRes = TRUE;
  998. InstallCopyMoveToRemote_Exit:
  999. if (pvarUserName_Remote)
  1000. {
  1001. VariantClear(pvarUserName_Remote);
  1002. }
  1003. if (pvarUserPassword_Remote)
  1004. {
  1005. VariantClear(pvarUserPassword_Remote);
  1006. }
  1007. if (!bRes)
  1008. {
  1009. SetBodyTextID(USE_DEFAULT_CAPTION);
  1010. }
  1011. if (pTheObject)
  1012. {
  1013. pTheObject->Release();
  1014. pTheObject = NULL;
  1015. }
  1016. if (bPleaseDoCoUninit)
  1017. {
  1018. CoUninitialize();
  1019. }
  1020. return bRes;
  1021. }
  1022. // We don't have initial request for KeyRing certificate, therefore we will
  1023. // not be able to renew this certificate
  1024. //
  1025. BOOL
  1026. CCertificate::InstallExportPFXCert()
  1027. {
  1028. ASSERT(!m_KeyFileName.IsEmpty());
  1029. ASSERT(!m_KeyPassword.IsEmpty());
  1030. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  1031. BOOL bRes = FALSE;
  1032. BOOL bPleaseDoCoUninit = FALSE;
  1033. IIISCertObj *pTheObject = NULL;
  1034. BOOL bExportThePrivateKeyToo = m_ExportPFXPrivateKey;
  1035. if (FALSE == m_CertObjInstalled)
  1036. {
  1037. goto InstallExportPFXCert_Exit;
  1038. }
  1039. // since this is the local machine
  1040. // make sure all this stuff is not set.
  1041. BSTR bstrServerName = SysAllocString(_T(""));
  1042. BSTR bstrUserName = SysAllocString(_T(""));
  1043. BSTR bstrUserPassword = SysAllocString(_T(""));
  1044. // create bstrs for these member cstrings
  1045. BSTR bstrFileName = SysAllocString(m_KeyFileName);
  1046. BSTR bstrFilePassword = SysAllocString(m_KeyPassword);
  1047. BSTR bstrInstanceName = SysAllocString(m_WebSiteInstanceName);
  1048. m_hResult = CoInitialize(NULL);
  1049. if(FAILED(m_hResult))
  1050. {
  1051. return bRes;
  1052. }
  1053. bPleaseDoCoUninit = TRUE;
  1054. // this one seems to work with surrogates..
  1055. m_hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
  1056. if (FAILED(m_hResult))
  1057. {
  1058. goto InstallExportPFXCert_Exit;
  1059. }
  1060. // at this point we were able to instantiate the com object on the server (local or remote)
  1061. pTheObject->put_ServerName(bstrServerName);
  1062. pTheObject->put_UserName(bstrUserName);
  1063. pTheObject->put_UserPassword(bstrUserPassword);
  1064. pTheObject->put_InstanceName(bstrInstanceName);
  1065. m_hResult = pTheObject->Export(bstrFileName,bstrFilePassword,bExportThePrivateKeyToo,FALSE,FALSE);
  1066. if (FAILED(m_hResult))
  1067. {
  1068. goto InstallExportPFXCert_Exit;
  1069. }
  1070. m_hResult = S_OK;
  1071. bRes = TRUE;
  1072. InstallExportPFXCert_Exit:
  1073. if (!bRes)
  1074. {
  1075. SetBodyTextID(USE_DEFAULT_CAPTION);
  1076. }
  1077. if (pTheObject)
  1078. {
  1079. pTheObject->Release();
  1080. pTheObject = NULL;
  1081. }
  1082. if (bPleaseDoCoUninit)
  1083. {
  1084. CoUninitialize();
  1085. }
  1086. return bRes;
  1087. }
  1088. //
  1089. BOOL
  1090. CCertificate::InstallImportPFXCert()
  1091. {
  1092. BOOL bRes = FALSE;
  1093. CCryptBlobLocal hash_blob;
  1094. if (::GetHashProperty(GetKeyRingCert(), hash_blob, &m_hResult))
  1095. {
  1096. HRESULT hr;
  1097. CString name;
  1098. ::GetFriendlyName(GetKeyRingCert(), name, &hr);
  1099. if (CRYPT_E_NOT_FOUND == hr || name.IsEmpty())
  1100. {
  1101. CERT_DESCRIPTION desc;
  1102. if (GetCertDescription(GetKeyRingCert(), desc))
  1103. {
  1104. bRes = AttachFriendlyName(GetKeyRingCert(), desc.m_CommonName, &hr);
  1105. }
  1106. }
  1107. ASSERT(bRes);
  1108. bRes = InstallCertByHash(hash_blob, m_MachineName, m_WebSiteInstanceName,
  1109. GetEnrollObject(), &m_hResult);
  1110. }
  1111. if (!bRes)
  1112. {
  1113. SetBodyTextID(USE_DEFAULT_CAPTION);
  1114. }
  1115. return bRes;
  1116. }
  1117. // We don't have initial request for KeyRing certificate, therefore we will
  1118. // not be able to renew this certificate
  1119. //
  1120. BOOL
  1121. CCertificate::InstallKeyRingCert()
  1122. {
  1123. BOOL bRes = FALSE;
  1124. CCryptBlobLocal hash_blob;
  1125. if (::GetHashProperty(GetKeyRingCert(), hash_blob, &m_hResult))
  1126. {
  1127. HRESULT hr;
  1128. CString name;
  1129. ::GetFriendlyName(GetKeyRingCert(), name, &hr);
  1130. if (CRYPT_E_NOT_FOUND == hr || name.IsEmpty())
  1131. {
  1132. CERT_DESCRIPTION desc;
  1133. if (GetCertDescription(GetKeyRingCert(), desc))
  1134. {
  1135. bRes = AttachFriendlyName(GetKeyRingCert(), desc.m_CommonName, &hr);
  1136. }
  1137. }
  1138. ASSERT(bRes);
  1139. bRes = InstallCertByHash(hash_blob, m_MachineName, m_WebSiteInstanceName,
  1140. GetEnrollObject(), &m_hResult);
  1141. }
  1142. if (!bRes)
  1143. {
  1144. SetBodyTextID(USE_DEFAULT_CAPTION);
  1145. }
  1146. return bRes;
  1147. }
  1148. // Instead of renewal we create new certificate based on parameters
  1149. // from the current one. After creation we install this certificate in place
  1150. // of current one and deleting the old one from store. Even if IIS has an
  1151. // opened SSL connection it should get a notification and update the certificate
  1152. // data.
  1153. //
  1154. BOOL
  1155. CCertificate::SubmitRenewalRequest()
  1156. {
  1157. BOOL bRes = LoadRenewalData();
  1158. if (bRes)
  1159. {
  1160. bRes = SetSecuritySettings();
  1161. if (bRes)
  1162. {
  1163. PCCERT_CONTEXT pCurrent = GetInstalledCert();
  1164. m_pInstalledCert = NULL;
  1165. if (bRes = SubmitRequest())
  1166. {
  1167. CertDeleteCertificateFromStore(pCurrent);
  1168. }
  1169. }
  1170. }
  1171. return bRes;
  1172. }
  1173. BOOL CCertificate::SubmitRequest()
  1174. {
  1175. ASSERT(!m_ConfigCA.IsEmpty());
  1176. BOOL bRes = FALSE;
  1177. ICertRequest * pRequest = NULL;
  1178. if (SUCCEEDED(m_hResult = CoCreateInstance(CLSID_CCertRequest, NULL,
  1179. CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pRequest)))
  1180. {
  1181. CString strDN;
  1182. CreateDN(strDN);
  1183. BSTR request = NULL;
  1184. if (SUCCEEDED(m_hResult = CreateRequest_Base64(
  1185. (BSTR)(LPCTSTR)strDN,
  1186. GetEnrollObject(),
  1187. m_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_CspName,
  1188. m_DefaultCSP ? m_DefaultProviderType : m_CustomProviderType,
  1189. &request)))
  1190. {
  1191. ASSERT(pRequest != NULL);
  1192. CString attrib;
  1193. GetCertificateTemplate(attrib);
  1194. LONG disp;
  1195. m_hResult = pRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10,
  1196. request,
  1197. (BSTR)(LPCTSTR)attrib,
  1198. (LPTSTR)(LPCTSTR)m_ConfigCA,
  1199. &disp);
  1200. #ifdef _DEBUG
  1201. if (FAILED(m_hResult))
  1202. TRACE(_T("Submit request returned HRESULT %x; Disposition %x\n"),
  1203. m_hResult, disp);
  1204. #endif
  1205. if (SUCCEEDED(m_hResult))
  1206. {
  1207. if (disp == CR_DISP_ISSUED)
  1208. {
  1209. BSTR bstrOutCert = NULL;
  1210. if (SUCCEEDED(m_hResult =
  1211. pRequest->GetCertificate(CR_OUT_BASE64 /*| CR_OUT_CHAIN */, &bstrOutCert)))
  1212. {
  1213. CRYPT_DATA_BLOB blob;
  1214. blob.cbData = SysStringByteLen(bstrOutCert);
  1215. blob.pbData = (BYTE *)bstrOutCert;
  1216. m_hResult = GetEnrollObject()->acceptPKCS7Blob(&blob);
  1217. if (SUCCEEDED(m_hResult))
  1218. {
  1219. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7(blob.pbData, blob.cbData,
  1220. NULL, &m_hResult);
  1221. ASSERT(pContext != NULL);
  1222. if (pContext != NULL)
  1223. {
  1224. BYTE HashBuffer[40]; // give it some extra size
  1225. DWORD dwHashSize = sizeof(HashBuffer);
  1226. if (CertGetCertificateContextProperty(pContext,
  1227. CERT_SHA1_HASH_PROP_ID,
  1228. (VOID *) HashBuffer,
  1229. &dwHashSize))
  1230. {
  1231. CRYPT_HASH_BLOB hash_blob = {dwHashSize, HashBuffer};
  1232. if (!(bRes = InstallHashToMetabase(&hash_blob,
  1233. m_MachineName,
  1234. m_WebSiteInstanceName,
  1235. &m_hResult)))
  1236. {
  1237. SetBodyTextID(IDS_CERT_INSTALLATION_FAILURE);
  1238. }
  1239. }
  1240. CertFreeCertificateContext(pContext);
  1241. }
  1242. // now put extra properties to the installed cert
  1243. if (NULL != (pContext = GetInstalledCert()))
  1244. {
  1245. if (!(bRes = AttachFriendlyName(pContext, m_FriendlyName, &m_hResult)))
  1246. {
  1247. SetBodyTextID(IDS_CERT_INSTALLATION_FAILURE);
  1248. }
  1249. }
  1250. }
  1251. if (bstrOutCert){SysFreeString(bstrOutCert);}
  1252. }
  1253. }
  1254. else
  1255. {
  1256. switch (disp)
  1257. {
  1258. case CR_DISP_INCOMPLETE:
  1259. case CR_DISP_ERROR:
  1260. case CR_DISP_DENIED:
  1261. case CR_DISP_ISSUED_OUT_OF_BAND:
  1262. case CR_DISP_UNDER_SUBMISSION:
  1263. {
  1264. BSTR bstr = NULL;
  1265. if (SUCCEEDED(pRequest->GetDispositionMessage(&bstr)))
  1266. {
  1267. SetBodyTextString(CString(bstr));
  1268. if (bstr) {SysFreeString(bstr);}
  1269. }
  1270. m_hResult = !S_OK;
  1271. }
  1272. break;
  1273. default:
  1274. SetBodyTextID(IDS_INTERNAL_ERROR);
  1275. break;
  1276. }
  1277. }
  1278. }
  1279. else // !SUCCEEDED
  1280. {
  1281. // clear out any error IDs and strings
  1282. // we will use default processing of m_hResult
  1283. SetBodyTextID(USE_DEFAULT_CAPTION);
  1284. }
  1285. if (request){SysFreeString(request);}
  1286. }
  1287. pRequest->Release();
  1288. }
  1289. return bRes;
  1290. }
  1291. BOOL
  1292. CCertificate::PrepareRequestString(CString& request_text, CCryptBlob& request_blob)
  1293. {
  1294. CString strDN;
  1295. TCHAR szUsage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
  1296. if (m_status_code == REQUEST_RENEW_CERT)
  1297. {
  1298. if (FALSE == LoadRenewalData())
  1299. {
  1300. return FALSE;
  1301. }
  1302. if (FALSE == SetSecuritySettings())
  1303. {
  1304. return FALSE;
  1305. }
  1306. }
  1307. CreateDN(strDN);
  1308. ASSERT(!strDN.IsEmpty());
  1309. GetEnrollObject()->put_ProviderType(m_DefaultCSP ?
  1310. m_DefaultProviderType : m_CustomProviderType);
  1311. if (!m_DefaultCSP)
  1312. {
  1313. GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_CspName);
  1314. // We are supporting only these two types of CSP, it is pretty safe to
  1315. // have just two options, because we are using the same two types when
  1316. // we are populating CSP selection list.
  1317. if (m_CustomProviderType == PROV_DH_SCHANNEL)
  1318. GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
  1319. else if (m_CustomProviderType == PROV_RSA_SCHANNEL)
  1320. GetEnrollObject()->put_KeySpec(AT_KEYEXCHANGE);
  1321. }
  1322. if (FAILED(m_hResult = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,
  1323. szUsage, request_blob))
  1324. )
  1325. {
  1326. SetBodyTextID(USE_DEFAULT_CAPTION);
  1327. return FALSE;
  1328. }
  1329. // BASE64 encode pkcs 10
  1330. DWORD err, cch;
  1331. char * psz;
  1332. if ( ERROR_SUCCESS != (err = Base64EncodeA(request_blob.GetData(), request_blob.GetSize(), NULL, &cch))
  1333. || NULL == (psz = (char *)_alloca(cch+1))
  1334. || ERROR_SUCCESS != (err = Base64EncodeA(request_blob.GetData(), request_blob.GetSize(), psz, &cch))
  1335. )
  1336. {
  1337. return FALSE;
  1338. }
  1339. psz[cch] = '\0';
  1340. request_text = MESSAGE_HEADER;
  1341. request_text += psz;
  1342. request_text += MESSAGE_TRAILER;
  1343. return TRUE;
  1344. }
  1345. BOOL
  1346. CCertificate::PrepareRequest()
  1347. {
  1348. BOOL bRes = FALSE;
  1349. CString request_text;
  1350. CCryptBlobIMalloc request_blob;
  1351. if (PrepareRequestString(request_text, request_blob))
  1352. {
  1353. if (WriteRequestString(request_text))
  1354. {
  1355. CCryptBlobLocal name_blob, request_store_blob, status_blob;
  1356. // prepare data we want to attach to dummy request
  1357. if ( EncodeString(m_WebSiteInstanceName, name_blob, &m_hResult)
  1358. && EncodeInteger(m_status_code, status_blob, &m_hResult)
  1359. )
  1360. {
  1361. // get back request from encoded data
  1362. PCERT_REQUEST_INFO pReqInfo;
  1363. bRes = GetRequestInfoFromPKCS10(request_blob, &pReqInfo, &m_hResult);
  1364. if (bRes)
  1365. {
  1366. // find dummy cert put to request store by createPKCS10 call
  1367. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  1368. if (hStore != NULL)
  1369. {
  1370. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  1371. CRYPT_ASN_ENCODING,
  1372. 0,
  1373. CERT_FIND_PUBLIC_KEY,
  1374. (void *)&pReqInfo->SubjectPublicKeyInfo,
  1375. NULL);
  1376. if (pDummyCert != NULL)
  1377. {
  1378. if ( CertSetCertificateContextProperty(pDummyCert,
  1379. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob)
  1380. && CertSetCertificateContextProperty(pDummyCert,
  1381. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob)
  1382. // put friendly name to dummy cert -- we will reuse it later
  1383. && AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult)
  1384. )
  1385. {
  1386. bRes = TRUE;
  1387. // put certificate text to the clipboard
  1388. if (OpenClipboard(GetFocus()))
  1389. {
  1390. size_t len = request_text.GetLength() + 1;
  1391. HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
  1392. LPSTR pMem = (LPSTR)GlobalLock(hMem);
  1393. if (pMem != NULL)
  1394. {
  1395. wcstombs(pMem, request_text, len);
  1396. GlobalUnlock(hMem);
  1397. SetClipboardData(CF_TEXT, hMem);
  1398. }
  1399. CloseClipboard();
  1400. }
  1401. }
  1402. else
  1403. {
  1404. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1405. }
  1406. CertFreeCertificateContext(pDummyCert);
  1407. }
  1408. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1409. }
  1410. LocalFree(pReqInfo);
  1411. }
  1412. }
  1413. }
  1414. }
  1415. if (!bRes)
  1416. SetBodyTextID(USE_DEFAULT_CAPTION);
  1417. return bRes;
  1418. }
  1419. BOOL CCertificate::LoadRenewalData()
  1420. {
  1421. // we need to obtain data from the installed cert
  1422. CERT_DESCRIPTION desc;
  1423. ASSERT(GetInstalledCert() != NULL);
  1424. BOOL res = FALSE;
  1425. DWORD cbData;
  1426. BYTE * pByte = NULL;
  1427. DWORD len = 0;
  1428. if (!GetCertDescription(GetInstalledCert(), desc))
  1429. {
  1430. res = FALSE;
  1431. goto ErrorExit;
  1432. }
  1433. m_CommonName = desc.m_CommonName;
  1434. m_FriendlyName = desc.m_FriendlyName;
  1435. m_Country = desc.m_Country;
  1436. m_State = desc.m_State;
  1437. m_Locality = desc.m_Locality;
  1438. m_Organization = desc.m_Organization;
  1439. m_OrganizationUnit = desc.m_OrganizationUnit;
  1440. len = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &GetInstalledCert()->pCertInfo->SubjectPublicKeyInfo);
  1441. if (len == 0)
  1442. {
  1443. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1444. goto ErrorExit;
  1445. }
  1446. m_KeyLength = len;
  1447. // compare property value
  1448. if (CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbData)
  1449. && (NULL != (pByte = (BYTE *)_alloca(cbData)))
  1450. && CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, pByte, &cbData)
  1451. )
  1452. {
  1453. CRYPT_KEY_PROV_INFO * pProvInfo = (CRYPT_KEY_PROV_INFO *)pByte;
  1454. if (pProvInfo->dwProvType != m_DefaultProviderType)
  1455. {
  1456. m_DefaultCSP = FALSE;
  1457. m_CustomProviderType = pProvInfo->dwProvType;
  1458. m_CspName = pProvInfo->pwszProvName;
  1459. }
  1460. CArray<LPCSTR, LPCSTR> uses;
  1461. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1462. uses.Add(szOID_SGC_NETSCAPE);
  1463. m_SGCcertificat = ContainsKeyUsageProperty(GetInstalledCert(), uses, &m_hResult);
  1464. res = TRUE;
  1465. }
  1466. else
  1467. {
  1468. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1469. goto ErrorExit;
  1470. }
  1471. ErrorExit:
  1472. return res;
  1473. }
  1474. #if 0
  1475. BOOL
  1476. CCertificate::WriteRenewalRequest()
  1477. {
  1478. BOOL bRes = FALSE;
  1479. if (GetInstalledCert() != NULL)
  1480. {
  1481. BSTR bstrRequest;
  1482. if ( SUCCEEDED(m_hResult = GetEnrollObject()->put_RenewalCertificate(GetInstalledCert()))
  1483. && SUCCEEDED(m_hResult = CreateRequest_Base64(bstrEmpty,
  1484. GetEnrollObject(),
  1485. m_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_CspName,
  1486. m_DefaultCSP ? m_DefaultProviderType : m_CustomProviderType,
  1487. &bstrRequest))
  1488. )
  1489. {
  1490. CString str = MESSAGE_HEADER;
  1491. str += bstrRequest;
  1492. str += MESSAGE_TRAILER;
  1493. if (WriteRequestString(str))
  1494. {
  1495. CCryptBlobLocal name_blob, status_blob;
  1496. CCryptBlobIMalloc request_blob;
  1497. request_blob.Set(SysStringLen(bstrRequest), (BYTE *)bstrRequest);
  1498. // prepare data we want to attach to dummy request
  1499. if ( EncodeString(m_WebSiteInstanceName, name_blob, &m_hResult)
  1500. && EncodeInteger(m_status_code, status_blob, &m_hResult)
  1501. )
  1502. {
  1503. // get back request from encoded data
  1504. PCERT_REQUEST_INFO req_info;
  1505. if (GetRequestInfoFromPKCS10(request_blob, &req_info, &m_hResult))
  1506. {
  1507. // find dummy cert put to request store by createPKCS10 call
  1508. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  1509. if (hStore != NULL)
  1510. {
  1511. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  1512. CRYPT_ASN_ENCODING,
  1513. 0,
  1514. CERT_FIND_PUBLIC_KEY,
  1515. (void *)&req_info->SubjectPublicKeyInfo,
  1516. NULL);
  1517. if (pDummyCert != NULL)
  1518. {
  1519. if ( CertSetCertificateContextProperty(pDummyCert,
  1520. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob)
  1521. && CertSetCertificateContextProperty(pDummyCert,
  1522. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob)
  1523. // put friendly name to dummy cert -- we will reuse it later
  1524. && AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult)
  1525. )
  1526. {
  1527. bRes = TRUE;
  1528. }
  1529. else
  1530. {
  1531. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1532. }
  1533. CertFreeCertificateContext(pDummyCert);
  1534. }
  1535. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1536. }
  1537. LocalFree(req_info);
  1538. }
  1539. }
  1540. }
  1541. }
  1542. }
  1543. return bRes;
  1544. }
  1545. #endif
  1546. CCertDescList::~CCertDescList()
  1547. {
  1548. POSITION pos = GetHeadPosition();
  1549. while (pos != NULL)
  1550. {
  1551. CERT_DESCRIPTION * pDesc = GetNext(pos);
  1552. delete pDesc;
  1553. }
  1554. }
  1555. BOOL
  1556. CCertificate::GetCertDescription(PCCERT_CONTEXT pCert,
  1557. CERT_DESCRIPTION& desc)
  1558. {
  1559. BOOL bRes = FALSE;
  1560. DWORD cb;
  1561. UINT i, j;
  1562. CERT_NAME_INFO * pNameInfo;
  1563. if (pCert == NULL)
  1564. goto ErrExit;
  1565. if ( !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  1566. pCert->pCertInfo->Subject.pbData,
  1567. pCert->pCertInfo->Subject.cbData,
  1568. 0, NULL, &cb)
  1569. || NULL == (pNameInfo = (CERT_NAME_INFO *)_alloca(cb))
  1570. || !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  1571. pCert->pCertInfo->Subject.pbData,
  1572. pCert->pCertInfo->Subject.cbData,
  1573. 0,
  1574. pNameInfo, &cb)
  1575. )
  1576. {
  1577. goto ErrExit;
  1578. }
  1579. for (i = 0; i < pNameInfo->cRDN; i++)
  1580. {
  1581. CERT_RDN rdn = pNameInfo->rgRDN[i];
  1582. for (j = 0; j < rdn.cRDNAttr; j++)
  1583. {
  1584. CERT_RDN_ATTR attr = rdn.rgRDNAttr[j];
  1585. if (strcmp(attr.pszObjId, szOID_COMMON_NAME) == 0)
  1586. {
  1587. FormatRdnAttr(desc.m_CommonName, attr.dwValueType, attr.Value, FALSE);
  1588. }
  1589. else if (strcmp(attr.pszObjId, szOID_COUNTRY_NAME) == 0)
  1590. {
  1591. FormatRdnAttr(desc.m_Country, attr.dwValueType, attr.Value, TRUE);
  1592. }
  1593. else if (strcmp(attr.pszObjId, szOID_LOCALITY_NAME) == 0)
  1594. {
  1595. FormatRdnAttr(desc.m_Locality, attr.dwValueType, attr.Value, TRUE);
  1596. }
  1597. else if (strcmp(attr.pszObjId, szOID_STATE_OR_PROVINCE_NAME) == 0)
  1598. {
  1599. FormatRdnAttr(desc.m_State, attr.dwValueType, attr.Value, TRUE);
  1600. }
  1601. else if (strcmp(attr.pszObjId, szOID_ORGANIZATION_NAME) == 0)
  1602. {
  1603. FormatRdnAttr(desc.m_Organization, attr.dwValueType, attr.Value, TRUE);
  1604. }
  1605. else if (strcmp(attr.pszObjId, szOID_ORGANIZATIONAL_UNIT_NAME) == 0)
  1606. {
  1607. FormatRdnAttr(desc.m_OrganizationUnit, attr.dwValueType, attr.Value, TRUE);
  1608. }
  1609. }
  1610. }
  1611. // issued to
  1612. if (!GetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG,
  1613. desc.m_CAName, &m_hResult))
  1614. goto ErrExit;
  1615. // expiration date
  1616. if (!FormatDateString(desc.m_ExpirationDate, pCert->pCertInfo->NotAfter, FALSE, FALSE))
  1617. {
  1618. goto ErrExit;
  1619. }
  1620. // purpose
  1621. if (!FormatEnhancedKeyUsageString(desc.m_Usage, pCert, FALSE, FALSE, &m_hResult))
  1622. {
  1623. // According to local experts, we should also use certs without this property set
  1624. ASSERT(FALSE);
  1625. //goto ErrExit;
  1626. }
  1627. // friendly name
  1628. if (!GetFriendlyName(pCert, desc.m_FriendlyName, &m_hResult))
  1629. {
  1630. desc.m_FriendlyName.LoadString(IDS_FRIENDLYNAME_NONE);
  1631. }
  1632. bRes = TRUE;
  1633. ErrExit:
  1634. return bRes;
  1635. }
  1636. int
  1637. CCertificate::MyStoreCertCount()
  1638. {
  1639. int count = 0;
  1640. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  1641. if (hStore != NULL)
  1642. {
  1643. PCCERT_CONTEXT pCert = NULL;
  1644. CArray<LPCSTR, LPCSTR> uses;
  1645. uses.Add(szOID_PKIX_KP_SERVER_AUTH);
  1646. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1647. uses.Add(szOID_SGC_NETSCAPE);
  1648. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  1649. {
  1650. // do not include installed cert to the list
  1651. if ( GetInstalledCert() != NULL
  1652. && CertCompareCertificate(X509_ASN_ENCODING,
  1653. GetInstalledCert()->pCertInfo, pCert->pCertInfo)
  1654. )
  1655. {
  1656. continue;
  1657. }
  1658. //If no EKU, look at basic constraints:
  1659. //If we do not have basic constraints, do display it in the list to pick web server certs from
  1660. //If we do have basic constraints with Subject Type =CA, don't display it in the list to pick web server certs from (this will filter out CA certs)
  1661. //If we do have basic constraints with SubectType !=CA, do display it in the list to pick web server certs from
  1662. if (!ContainsKeyUsageProperty(pCert, uses, &m_hResult))
  1663. {
  1664. // check other stuff
  1665. if (DID_NOT_FIND_CONSTRAINT == CheckCertConstraints(pCert))
  1666. {
  1667. // add it up.
  1668. }
  1669. else if (FOUND_CONSTRAINT_BUT_THIS_IS_A_CA_OR_ITS_NOT_AN_END_ENTITY == CheckCertConstraints(pCert))
  1670. {
  1671. continue;
  1672. }
  1673. else
  1674. {
  1675. continue;
  1676. }
  1677. }
  1678. count++;
  1679. }
  1680. if (pCert != NULL)
  1681. CertFreeCertificateContext(pCert);
  1682. VERIFY(CertCloseStore(hStore, 0));
  1683. }
  1684. return count;
  1685. }
  1686. BOOL
  1687. CCertificate::GetCertDescList(CCertDescList& list)
  1688. {
  1689. ASSERT(list.GetCount() == 0);
  1690. BOOL bRes = FALSE;
  1691. // we are looking to MY store only
  1692. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  1693. if (hStore != NULL)
  1694. {
  1695. PCCERT_CONTEXT pCert = NULL;
  1696. // do not include certs with improper usage
  1697. CArray<LPCSTR, LPCSTR> uses;
  1698. uses.Add(szOID_PKIX_KP_SERVER_AUTH);
  1699. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1700. uses.Add(szOID_SGC_NETSCAPE);
  1701. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  1702. {
  1703. // do not include installed cert to the list
  1704. if ( GetInstalledCert() != NULL
  1705. && CertCompareCertificate(X509_ASN_ENCODING,
  1706. GetInstalledCert()->pCertInfo, pCert->pCertInfo)
  1707. )
  1708. {
  1709. continue;
  1710. }
  1711. //If no EKU, look at basic constraints:
  1712. //If we do not have basic constraints, do display it in the list to pick web server certs from
  1713. //If we do have basic constraints with Subject Type =CA, don't display it in the list to pick web server certs from (this will filter out CA certs)
  1714. //If we do have basic constraints with SubectType !=CA, do display it in the list to pick web server certs from
  1715. if (!ContainsKeyUsageProperty(pCert, uses, &m_hResult))
  1716. {
  1717. // check other stuff
  1718. if (DID_NOT_FIND_CONSTRAINT == CheckCertConstraints(pCert) || FOUND_CONSTRAINT == CheckCertConstraints(pCert))
  1719. {
  1720. // it's okay, add it to the list
  1721. }
  1722. else
  1723. {
  1724. if (SUCCEEDED(m_hResult) || m_hResult == CRYPT_E_NOT_FOUND)
  1725. continue;
  1726. else
  1727. goto ErrExit;
  1728. }
  1729. }
  1730. CERT_DESCRIPTION * pDesc = new CERT_DESCRIPTION;
  1731. pDesc->m_hash_length = CERT_HASH_LENGTH;
  1732. if (!GetCertDescription(pCert, *pDesc))
  1733. {
  1734. delete pDesc;
  1735. if (m_hResult == CRYPT_E_NOT_FOUND)
  1736. continue;
  1737. goto ErrExit;
  1738. }
  1739. if (!CertGetCertificateContextProperty(pCert,
  1740. CERT_SHA1_HASH_PROP_ID,
  1741. (VOID *)pDesc->m_hash,
  1742. &pDesc->m_hash_length))
  1743. {
  1744. delete pDesc;
  1745. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1746. goto ErrExit;
  1747. }
  1748. list.AddTail(pDesc);
  1749. }
  1750. bRes = TRUE;
  1751. ErrExit:
  1752. if (pCert != NULL)
  1753. CertFreeCertificateContext(pCert);
  1754. VERIFY(CertCloseStore(hStore, 0));
  1755. }
  1756. return bRes;
  1757. }
  1758. BOOL
  1759. CCertificate::ReplaceInstalled()
  1760. {
  1761. // Current cert will be left in the store for next use
  1762. // Selected cert will be installed instead
  1763. return InstallSelectedCert();
  1764. }
  1765. BOOL
  1766. CCertificate::CancelRequest()
  1767. {
  1768. // we are just removing dummy cert from the REQUEST store
  1769. if (NULL != GetPendingRequest())
  1770. {
  1771. BOOL bRes = CertDeleteCertificateFromStore(GetPendingRequest());
  1772. if (!bRes)
  1773. {
  1774. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1775. SetBodyTextID(USE_DEFAULT_CAPTION);
  1776. }
  1777. else
  1778. m_pPendingRequest = NULL;
  1779. return bRes;
  1780. }
  1781. return FALSE;
  1782. }
  1783. BOOL
  1784. CCertificate::InstallSelectedCert()
  1785. {
  1786. BOOL bRes = FALSE;
  1787. HRESULT hr;
  1788. // local authorities required that cert should have some
  1789. // friendly name. We will put common name when friendly name is not available
  1790. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &hr);
  1791. if (hStore != NULL)
  1792. {
  1793. PCCERT_CONTEXT pCert = CertFindCertificateInStore(hStore,
  1794. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1795. 0, CERT_FIND_HASH,
  1796. (LPVOID)m_pSelectedCertHash,
  1797. NULL);
  1798. if (pCert != NULL)
  1799. {
  1800. CString name;
  1801. ::GetFriendlyName(pCert, name, &hr);
  1802. if (CRYPT_E_NOT_FOUND == hr || name.IsEmpty())
  1803. {
  1804. CERT_DESCRIPTION desc;
  1805. if (GetCertDescription(pCert, desc))
  1806. {
  1807. bRes = AttachFriendlyName(pCert, desc.m_CommonName, &hr);
  1808. }
  1809. }
  1810. }
  1811. VERIFY(CertCloseStore(hStore, 0));
  1812. }
  1813. ASSERT(bRes);
  1814. // we are just rewriting current settings
  1815. // current cert will be left in MY store
  1816. bRes = ::InstallCertByHash(m_pSelectedCertHash,
  1817. m_MachineName,
  1818. m_WebSiteInstanceName,
  1819. GetEnrollObject(),
  1820. &m_hResult);
  1821. if (!bRes)
  1822. {
  1823. SetBodyTextID(USE_DEFAULT_CAPTION);
  1824. }
  1825. return bRes;
  1826. }